From 26a1df23b3a2c147a8c30aefb8b5cf23a602b81d Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 10:11:53 -0400 Subject: [PATCH 01/26] use object for headings, not a Map --- .gitignore | 1 + package.json | 8 +-- scratch.js | 26 ++++---- scripts/test.js | 2 +- scripts/watch.js | 54 +++++++++++++++ src/index.js | 66 +++++++++++-------- tests/{misc_tests.js => misc.test.js} | 12 ++-- tests/{page_tests.js => page.test.js} | 36 +++++----- tests/{template_tests.js => template.test.js} | 0 tests/{unit_tests.js => unit.test.js} | 0 10 files changed, 138 insertions(+), 67 deletions(-) create mode 100644 scripts/watch.js rename tests/{misc_tests.js => misc.test.js} (72%) rename tests/{page_tests.js => page.test.js} (73%) rename tests/{template_tests.js => template.test.js} (100%) rename tests/{unit_tests.js => unit.test.js} (100%) diff --git a/.gitignore b/.gitignore index a7ac55dd..7eddce23 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ node_modules coverage viz npm-debug.log +package-lock.json \ No newline at end of file diff --git a/package.json b/package.json index 603be505..e6935f9d 100644 --- a/package.json +++ b/package.json @@ -12,20 +12,18 @@ "start": "node ./scripts/demo.js", "test": "node ./scripts/test.js", "browserTest": "node ./scripts/browserTest.js", + "watch": "node ./scripts/watch.js", "build": "node ./scripts/build.js" }, "bin": { "wikipedia": "./bin/parse.js", "wikipedia_plaintext": "./bin/plaintext.js" }, - "files":[ + "files": [ "builds", "src", "bin" ], - "engines": [ - "node >= 0.4.0" - ], "keywords": [ "wikipedia", "wikimedia", @@ -51,4 +49,4 @@ "shelljs": "^0.7.2" }, "license": "MIT" -} +} \ No newline at end of file diff --git a/scratch.js b/scratch.js index bcbb5f4d..949107f6 100644 --- a/scratch.js +++ b/scratch.js @@ -1,39 +1,39 @@ 'use strict'; const wtf = require('./src/index'); -// const wtf_wikipedia = require('./builds/wtf_wikipedia'); -// const wtf_wikipedia = require('./build'); +// const wtf = require('./builds/wtf_wikipedia'); +// const wtf = require('./build'); // let parse = wtf.parse; // wtf.from_api("Tomb_Raider_(2013_video_game)", 'en', function(s) { -// console.log(wtf_wikipedia.parse(s).infobox) +// console.log(wtf.parse(s).infobox) // }) // // wtf.from_api('Raoul Dautry', 'fr',function(page) { -// var parsed = wtf_wikipedia.parse(page); // causes the crash +// var parsed = wtf.parse(page); // causes the crash // console.log(parsed.text.get('Intro')); // }); -// function from_file(page){ -// let str = require('fs').readFileSync('./tests/cache/' + page.toLowerCase() + '.txt', 'utf-8'); -// // return wtf_wikipedia.plaintext(str) -// return wtf_wikipedia.parse(str); -// } +function from_file(page) { + let str = require('fs').readFileSync('./tests/cache/' + page.toLowerCase() + '.txt', 'utf-8'); + // return wtf.plaintext(str) + console.log(wtf.parse(str).text); +} // from_file("list") // from_file("Toronto") // from_file('Toronto_Star'); // from_file('royal_cinema'); -// from_file("Jodie_Emery") +from_file('Jodie_Emery'); // from_file("Redirect") // from_file("Africaans") -// from_file("Anarchism") +// from_file('Anarchism'); // wtf.from_api('Paris', 'en', function(markup) { // var obj = wtf.parse(markup); // console.log(obj); // }); -let str = `hello {{nowrap|{{small|(1995–present)}}}} world`; +// let str = `hello {{nowrap|{{small|(1995–present)}}}} world`; // let str = `hello {{small|(1995–present)}} world`; //and a fair amount of sunshine.{{sfn|Lawrence|Gondrand|2010|p=309}} Each year, however, there are a few days where the temperature rises above {{convert|32|C}}. Some years have even witnessed long periods of harsh summer weather, such as the [[2003 European heat wave|heat wave of 2003]] when temperatures exceeded {{convert|30|°C}} for weeks, surged up to {{convert|40|°C}} on some days and seldom cooled down at night.`; -console.log(wtf.parse(str).text); +// console.log(wtf.parse(str)); diff --git a/scripts/test.js b/scripts/test.js index 1c86c26b..bf2529a4 100644 --- a/scripts/test.js +++ b/scripts/test.js @@ -3,4 +3,4 @@ var tape = './node_modules/tape/bin/tape'; var tapSpec = './node_modules/tap-spec/bin/cmd.js --color'; //run tests server-side -exec(tape + ' ./tests/*_tests.js | ' + tapSpec); +exec(tape + ' ./tests/*.test.js | ' + tapSpec); diff --git a/scripts/watch.js b/scripts/watch.js new file mode 100644 index 00000000..9bac1d90 --- /dev/null +++ b/scripts/watch.js @@ -0,0 +1,54 @@ +require('shelljs/global'); +var gaze = require('gaze'); +var chalk = require('chalk'); +//this is a nice way to 'hot-reload' compromise, while debugging something from ./scratch.js + +var options = { + interval: 1, + ignoreDotFiles: true, + wait: 2 +}; + +var banner = function() { + var emojis = { + lemon: chalk.yellow('🍋'), + flower: chalk.red('🌼'), + check: chalk.green('✅'), + boat: chalk.blue('⛵ '), + sun: chalk.yellow('🌞 '), + sprout: chalk.green('🌱 '), + time: chalk.green('🕙 '), + shirt: chalk.blue('👕 '), + hat: chalk.magenta('🎩 '), + orange: chalk.red('🍑 '), + candy: chalk.magenta('🍬 '), + lollypop: chalk.red('🍭 '), + dress: chalk.red('👗 '), + happy: chalk.green('😊 '), + trumpet: chalk.yellow('🎺 ') + }; + var keys = Object.keys(emojis); + var r = parseInt(Math.random() * keys.length - 1, 10); + return emojis[keys[r]]; +}; + +var run = function() { + console.log(banner()); + exec('node ./scratch.js --debug --color'); + console.log('\n\n\n\n\n\n\n'); +}; + +run(); + +gaze(['./scripts/watch.js', './src/**/*.js', './scratch.js'], options, function(err) { + if (err) { + console.log(err); + } + this.on('added', function(filepath) { + console.log(filepath + ' was added'); + }); + // // On changed/added/deleted + this.on('all', function() { + run(); + }); +}); diff --git a/src/index.js b/src/index.js index afe11e8a..16dc8d94 100644 --- a/src/index.js +++ b/src/index.js @@ -43,7 +43,8 @@ var wtf_wikipedia = (function() { } //detect if page is disambiguator page var template_reg = new RegExp('\\{\\{ ?(' + i18n.disambigs.join('|') + ')(\\|[a-z =]*?)? ?\\}\\}', 'i'); - if (wiki.match(template_reg)) { //|| wiki.match(/^.{3,25} may refer to/i)|| wiki.match(/^.{3,25} ist der Name mehrerer /i) + if (wiki.match(template_reg)) { + //|| wiki.match(/^.{3,25} may refer to/i)|| wiki.match(/^.{3,25} ist der Name mehrerer /i) return parse_disambig(wiki); } //parse templates like {{currentday}} @@ -61,7 +62,7 @@ var wtf_wikipedia = (function() { //reduce the scary recursive situations //remove {{template {{}} }} recursions var matches = recursive_matches('{', '}', wiki); - var infobox_reg = new RegExp('\{\{(' + i18n.infoboxes.join('|') + ')[: \n]', 'ig'); + var infobox_reg = new RegExp('{{(' + i18n.infoboxes.join('|') + ')[: \n]', 'ig'); matches.forEach(function(s) { if (s.match(infobox_reg, 'ig') && Object.keys(infobox).length === 0) { infobox = parse_infobox(s); @@ -112,13 +113,13 @@ var wtf_wikipedia = (function() { var cats = parse_categories(wiki); //next, map each line into a parsable sentence // var output = {}; - var output = new Map(); + var output = {}; var lines = wiki.replace(/\r/g, '').split(/\n/); var section = 'Intro'; var sectionStack = []; // only relevant when appendSectionLabelsWithParent === true var number = 1; // Turns = Intro = into 1, == Summary == into 2 etc; - var countHeaderNumber = function (section) { + var countHeaderNumber = function(section) { var aSection = section.match(/^={1,5}/); if (Array.isArray(aSection) && aSection.length !== 0) { @@ -126,16 +127,19 @@ var wtf_wikipedia = (function() { } else { return null; } - } + }; - var isEmptyParentSection = function (section, potentialParent) { - if (countHeaderNumber(section.sectionNameWithEquals) - 1 === countHeaderNumber(potentialParent.sectionNameWithEquals)) { - return !potentialParent.hasText; - } else { - return false; - } - return - } + var isEmptyParentSection = function(section, potentialParent) { + if ( + countHeaderNumber(section.sectionNameWithEquals) - 1 === + countHeaderNumber(potentialParent.sectionNameWithEquals) + ) { + return !potentialParent.hasText; + } else { + return false; + } + return; + }; lines.forEach(function(part) { if (!section) { @@ -201,13 +205,22 @@ var wtf_wikipedia = (function() { } // Don't get influenced by siblings, remove the siblings from the stack till we find a parent node - while (sectionStack.length > 1 && countHeaderNumber(sectionStack[sectionStack.length - 1].sectionNameWithEquals) === countHeaderNumber(sectionStack[sectionStack.length - 2].sectionNameWithEquals)) { + while ( + sectionStack.length > 1 && + countHeaderNumber(sectionStack[sectionStack.length - 1].sectionNameWithEquals) === + countHeaderNumber(sectionStack[sectionStack.length - 2].sectionNameWithEquals) + ) { sectionStack.splice(-2, 1); } // Check our previous (now) non-sibling node, is it without content text and exactly one level up? Then append the section label with it - if (options.appendSectionLabelsWithParent === true && sectionStack.length > 1 && isEmptyParentSection(sectionStack[sectionStack.length - 1], sectionStack[sectionStack.length - 2])) { - sectionLabel = sectionStack[sectionStack.length - 2].name + " : " + sectionStack[sectionStack.length - 1].name; + if ( + options.appendSectionLabelsWithParent === true && + sectionStack.length > 1 && + isEmptyParentSection(sectionStack[sectionStack.length - 1], sectionStack[sectionStack.length - 2]) + ) { + sectionLabel = + sectionStack[sectionStack.length - 2].name + ' : ' + sectionStack[sectionStack.length - 1].name; } } @@ -217,19 +230,22 @@ var wtf_wikipedia = (function() { if (line && line.text) { // if (!output[section]) { - if (!output.get(sectionLabel)) { + if (!output[sectionLabel]) { // output[section] = []; - output.set(sectionLabel, []); + output[sectionLabel] = []; } // output[section].push(line); - output.get(sectionLabel).push(line); + output[sectionLabel].push(line); } }); }); //add additional image from infobox, if applicable if (infobox['image'] && infobox['image'].text) { var img = infobox['image'].text || ''; - if (typeof img === 'string' && !img.match(new RegExp('^(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'))) { + if ( + typeof img === 'string' && + !img.match(new RegExp('^(' + i18n.images.concat(i18n.files).join('|') + ')', 'i')) + ) { img = 'File:' + img; } images.push(img); @@ -246,7 +262,6 @@ var wtf_wikipedia = (function() { tables: tables, translations: translations }; - }; var from_api = function(page_identifier, lang_or_wikiid, cb) { @@ -256,7 +271,8 @@ var wtf_wikipedia = (function() { } cb = cb || function() {}; lang_or_wikiid = lang_or_wikiid || 'en'; - if (!fetch) { //no http method, on the client side + if (!fetch) { + //no http method, on the client side return cb(null); } return fetch(page_identifier, lang_or_wikiid, cb); @@ -266,10 +282,8 @@ var wtf_wikipedia = (function() { var data = main(str) || {}; data.text = data.text || []; var text = ''; - data.text.forEach(function (v) { - text += v.map(function(a) { - return a.text; - }).join(' ') + '\n'; + Object.keys(data.text).forEach(function(k) { + text += data.text[k].map(a => a.text).join(' ') + '\n'; }); return text; }; diff --git a/tests/misc_tests.js b/tests/misc.test.js similarity index 72% rename from tests/misc_tests.js rename to tests/misc.test.js index 1d9e568d..d89165a0 100644 --- a/tests/misc_tests.js +++ b/tests/misc.test.js @@ -2,7 +2,7 @@ var test = require('tape'); const wtf = require('../src/index'); -test('small headings', (t) => { +test('small headings', t => { let str = ` ===gdbserver=== hi there @@ -14,14 +14,14 @@ Displays memory at the specified virtual address using the specified format. here too `; let text = wtf.parse(str).text; - t.ok(text.get('gdbserver'), 'first heading exists'); - t.ok(text.get('x'), 'x exists'); - t.ok(text.get('xp'), 'xp exists'); - t.equal(text.get('foo'), undefined, 'foo doesnt exist'); + t.ok(text['gdbserver'], 'first heading exists'); + t.ok(text['x'], 'x exists'); + t.ok(text['xp'], 'xp exists'); + t.equal(text['foo'], undefined, 'foo doesnt exist'); t.end(); }); -test('font-size', (t) => { +test('font-size', t => { let str = 'hello {{small|(1995-1997)}} world'; t.equal(wtf.plaintext(str), 'hello (1995-1997) world\n', '{{small}}'); diff --git a/tests/page_tests.js b/tests/page.test.js similarity index 73% rename from tests/page_tests.js rename to tests/page.test.js index f3a003d1..5ccbe35e 100644 --- a/tests/page_tests.js +++ b/tests/page.test.js @@ -5,7 +5,7 @@ var test = require('tape'); const wtf_wikipedia = require('../src/index'); const str_equal = function(have, want, t) { - var msg = '\'' + have + '\' == \'' + want + '\''; + var msg = "'" + have + "' == '" + want + "'"; t.equal(have, want, msg); return; }; @@ -15,38 +15,38 @@ var fetch = function(file) { return fs.readFileSync(path.join(__dirname, 'cache', file + '.txt'), 'utf-8'); }; -test('royal_cinema', (t) => { +test('royal_cinema', t => { var data = wtf_wikipedia.parse(fetch('royal_cinema')); str_equal(data.infobox.opened.text, 1939, t); str_equal(data.infobox_template, 'venue', t); // str_equal(data.text.Intro.length, 10, t); - str_equal(data.text.get('Intro').length, 10, t); + str_equal(data.text['Intro'].length, 10, t); str_equal(data.categories.length, 4, t); t.end(); }); -test('toronto_star', (t) => { +test('toronto_star', t => { var data = wtf_wikipedia.parse(fetch('toronto_star')); str_equal(data.infobox.publisher.text, 'John D. Cruickshank', t); str_equal(data.infobox_template, 'newspaper', t); // str_equal(data.text.History.length, 21, t); - str_equal(data.text.get('History').length, 21, t); + str_equal(data.text['History'].length, 21, t); str_equal(data.categories.length, 6, t); - str_equal(data.text.get('Notable cartoonists'), undefined, t); + str_equal(data.text['Notable cartoonists'], undefined, t); t.end(); }); -test('toronto_star with list', (t) => { - var data = wtf_wikipedia.parse(fetch('toronto_star'), {ignoreLists: false}); +test('toronto_star with list', t => { + var data = wtf_wikipedia.parse(fetch('toronto_star'), { ignoreLists: false }); str_equal(data.infobox.publisher.text, 'John D. Cruickshank', t); str_equal(data.infobox_template, 'newspaper', t); - str_equal(data.text.get('History').length, 21, t); + str_equal(data.text['History'].length, 21, t); str_equal(data.categories.length, 6, t); - str_equal(data.text.get('Notable cartoonists').length, 10, t); + str_equal(data.text['Notable cartoonists'].length, 10, t); t.end(); }); -test('jodie_emery', (t) => { +test('jodie_emery', t => { var data = wtf_wikipedia.parse(fetch('jodie_emery')); str_equal(data.infobox.nationality.text, 'Canadian', t); str_equal(data.infobox_template, 'person', t); @@ -57,7 +57,7 @@ test('jodie_emery', (t) => { t.end(); }); -test('redirect', (t) => { +test('redirect', t => { var data = wtf_wikipedia.parse(fetch('redirect')); str_equal(data.type, 'redirect', t); str_equal(data.redirect, 'Toronto', t); @@ -66,7 +66,7 @@ test('redirect', (t) => { t.end(); }); -test('statoil', (t) => { +test('statoil', t => { var data = wtf_wikipedia.parse(fetch('statoil')); str_equal(data.infobox.namn.text, 'Statoil ASA', t); str_equal(data.infobox_template, 'verksemd', t); @@ -78,12 +78,16 @@ test('statoil', (t) => { t.end(); }); -test('raith rovers', (t) => { +test('raith rovers', t => { var data = wtf_wikipedia.parse(fetch('raith_rovers')); str_equal(data.infobox.clubname.text, 'Raith Rovers', t); str_equal(data.categories.length, 10, t); str_equal(data.images.length, 2, t); - str_equal(data.images[0].file, 'File:Stark\'s Park - geograph.org.uk - 204446.jpg', t); - str_equal(data.images[0].url, 'https://upload.wikimedia.org/wikipedia/commons/3/38/Stark\'s_Park_-_geograph.org.uk_-_204446.jpg', t); + str_equal(data.images[0].file, "File:Stark's Park - geograph.org.uk - 204446.jpg", t); + str_equal( + data.images[0].url, + "https://upload.wikimedia.org/wikipedia/commons/3/38/Stark's_Park_-_geograph.org.uk_-_204446.jpg", + t + ); t.end(); }); diff --git a/tests/template_tests.js b/tests/template.test.js similarity index 100% rename from tests/template_tests.js rename to tests/template.test.js diff --git a/tests/unit_tests.js b/tests/unit.test.js similarity index 100% rename from tests/unit_tests.js rename to tests/unit.test.js From 222d08c91c79df59f2bbbf9c6f9bc8d05fb11f6f Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 10:16:38 -0400 Subject: [PATCH 02/26] temporarily remove appendSectionTitleThing --- scratch.js | 2 +- src/index.js | 52 +--------------------------------------------------- 2 files changed, 2 insertions(+), 52 deletions(-) diff --git a/scratch.js b/scratch.js index 949107f6..3b905860 100644 --- a/scratch.js +++ b/scratch.js @@ -16,7 +16,7 @@ const wtf = require('./src/index'); function from_file(page) { let str = require('fs').readFileSync('./tests/cache/' + page.toLowerCase() + '.txt', 'utf-8'); // return wtf.plaintext(str) - console.log(wtf.parse(str).text); + console.log(wtf.parse(str, {}).text); } // from_file("list") diff --git a/src/index.js b/src/index.js index 16dc8d94..36528c76 100644 --- a/src/index.js +++ b/src/index.js @@ -23,8 +23,7 @@ var wtf_wikipedia = (function() { // options var defaultParseOptions = { - ignoreLists: true, - appendSectionLabelsWithParent: false + ignoreLists: true }; //some xml elements are just junk, and demand full inglorious death by regular exp @@ -118,28 +117,6 @@ var wtf_wikipedia = (function() { var section = 'Intro'; var sectionStack = []; // only relevant when appendSectionLabelsWithParent === true var number = 1; - // Turns = Intro = into 1, == Summary == into 2 etc; - var countHeaderNumber = function(section) { - var aSection = section.match(/^={1,5}/); - - if (Array.isArray(aSection) && aSection.length !== 0) { - return aSection[0].length; - } else { - return null; - } - }; - - var isEmptyParentSection = function(section, potentialParent) { - if ( - countHeaderNumber(section.sectionNameWithEquals) - 1 === - countHeaderNumber(potentialParent.sectionNameWithEquals) - ) { - return !potentialParent.hasText; - } else { - return false; - } - return; - }; lines.forEach(function(part) { if (!section) { @@ -197,33 +174,6 @@ var wtf_wikipedia = (function() { var sectionLabel = section; - // Potential to expand the section label, if the option is turned on and the right circumstances apply - if (options.appendSectionLabelsWithParent === true) { - // We've made it to content text, mark that the last section has text (and will not be used as a parent marker) - if (sectionStack.length > 0) { - sectionStack[sectionStack.length - 1].hasText = true; - } - - // Don't get influenced by siblings, remove the siblings from the stack till we find a parent node - while ( - sectionStack.length > 1 && - countHeaderNumber(sectionStack[sectionStack.length - 1].sectionNameWithEquals) === - countHeaderNumber(sectionStack[sectionStack.length - 2].sectionNameWithEquals) - ) { - sectionStack.splice(-2, 1); - } - - // Check our previous (now) non-sibling node, is it without content text and exactly one level up? Then append the section label with it - if ( - options.appendSectionLabelsWithParent === true && - sectionStack.length > 1 && - isEmptyParentSection(sectionStack[sectionStack.length - 1], sectionStack[sectionStack.length - 2]) - ) { - sectionLabel = - sectionStack[sectionStack.length - 2].name + ' : ' + sectionStack[sectionStack.length - 1].name; - } - } - //still alive, add it to the section sentence_parser(part).forEach(function(line) { line = parse_line(line); From e9224f7aa324515f66933cf939024ac50bd54b67 Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 10:23:46 -0400 Subject: [PATCH 03/26] seperate main method --- src/index.js | 278 ++++++--------------------------------------------- src/main.js | 200 ++++++++++++++++++++++++++++++++++++ 2 files changed, 229 insertions(+), 249 deletions(-) create mode 100644 src/main.js diff --git a/src/index.js b/src/index.js index 36528c76..d82fd397 100644 --- a/src/index.js +++ b/src/index.js @@ -1,254 +1,34 @@ //turns wikimedia script into json // https://github.com/spencermountain/wtf_wikipedia //@spencermountain -var wtf_wikipedia = (function() { - var sentence_parser = require('./lib/sentence_parser'); - var fetch = require('./lib/fetch_text'); - var make_image = require('./lib/make_image'); - var i18n = require('./data/i18n'); - var helpers = require('./lib/helpers'); - var languages = require('./data/languages'); - //parsers - var redirects = require('./parse/parse_redirects'); - var parse_table = require('./parse/parse_table'); - var parse_line = require('./parse/parse_line'); - var parse_categories = require('./parse/parse_categories'); - var parse_disambig = require('./parse/parse_disambig'); - var parse_infobox = require('./parse/parse_infobox'); - var parse_infobox_template = require('./parse/parse_infobox_template'); - var parse_image = require('./parse/parse_image'); - var recursive_matches = require('./recursive_matches'); - var preprocess = require('./parse/cleanup_misc'); - var word_templates = require('./word_templates'); +const main = require('./main'); - // options - var defaultParseOptions = { - ignoreLists: true - }; - - //some xml elements are just junk, and demand full inglorious death by regular exp - //other xml elements, like , are plucked out afterwards - var main = function(wiki, options) { - options = Object.assign({}, defaultParseOptions, options); - var infobox = {}; - var infobox_template = ''; - var images = []; - var tables; - var translations = {}; - wiki = wiki || ''; - //detect if page is just redirect, and return - if (redirects.is_redirect(wiki)) { - return redirects.parse_redirect(wiki); - } - //detect if page is disambiguator page - var template_reg = new RegExp('\\{\\{ ?(' + i18n.disambigs.join('|') + ')(\\|[a-z =]*?)? ?\\}\\}', 'i'); - if (wiki.match(template_reg)) { - //|| wiki.match(/^.{3,25} may refer to/i)|| wiki.match(/^.{3,25} ist der Name mehrerer /i) - return parse_disambig(wiki); - } - //parse templates like {{currentday}} - wiki = word_templates(wiki); - //kill off th3 craziness - wiki = preprocess(wiki); - //find tables - tables = wiki.match(/\{\|[\s\S]{1,8000}?\|\}/g, '') || []; - tables = tables.map(function(s) { - return parse_table(s); - }); - //remove tables - wiki = wiki.replace(/\{\|[\s\S]{1,8000}?\|\}/g, ''); - - //reduce the scary recursive situations - //remove {{template {{}} }} recursions - var matches = recursive_matches('{', '}', wiki); - var infobox_reg = new RegExp('{{(' + i18n.infoboxes.join('|') + ')[: \n]', 'ig'); - matches.forEach(function(s) { - if (s.match(infobox_reg, 'ig') && Object.keys(infobox).length === 0) { - infobox = parse_infobox(s); - infobox_template = parse_infobox_template(s); - } - if (s.match(infobox_reg)) { - wiki = wiki.replace(s, ''); - } - //rest of them... - if (s.match(/^\{\{/)) { - //support nowrap - var nowrap = s.match(/^\{\{nowrap\|(.*?)\}\}$/); - if (nowrap) { - wiki = wiki.replace(s, nowrap[1]); - return; - } - //if it's not a known template, but it's recursive, remove it - //(because it will be misread later-on) - wiki = wiki.replace(s, ''); - } - }); - - //second, remove [[file:...[[]] ]] recursions - matches = recursive_matches('[', ']', wiki); - matches.forEach(function(s) { - if (s.match(new RegExp('\\[\\[(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'))) { - images.push(parse_image(s)); - wiki = wiki.replace(s, ''); - } - }); - //third, wiktionary-style interlanguage links - matches.forEach(function(s) { - if (s.match(/\[\[([a-z][a-z]):(.*?)\]\]/i) !== null) { - var lang = s.match(/\[\[([a-z][a-z]):/i)[1]; - if (lang && languages[lang]) { - translations[lang] = s.match(/\[\[([a-z][a-z]):(.*?)\]\]/i)[2]; - } - wiki = wiki.replace(s, ''); - } - }); - - //now that the scary recursion issues are gone, we can trust simple regex methods - - //kill the rest of templates - wiki = wiki.replace(/\{\{.*?\}\}/g, ''); - - //get list of links, categories - var cats = parse_categories(wiki); - //next, map each line into a parsable sentence - // var output = {}; - var output = {}; - var lines = wiki.replace(/\r/g, '').split(/\n/); - var section = 'Intro'; - var sectionStack = []; // only relevant when appendSectionLabelsWithParent === true - var number = 1; - - lines.forEach(function(part) { - if (!section) { - return; - } - //add # numberings formatting - if (part.match(/^ ?\#[^:,\|]{4}/i)) { - part = part.replace(/^ ?#*/, number + ') '); - part = part + '\n'; - number += 1; - } else { - number = 1; - } - //add bullet-points formatting - if (part.match(/^\*+[^:,\|]{4}/)) { - part = part + '\n'; - } - //remove some nonsense wp lines - - if (options.ignoreLists) { - //ignore list - if (part.match(/^[#\*:;\|]/)) { - return; - } - } - - //ignore only-punctuation - if (!part.match(/[a-z0-9]/i)) { - return; - } - //headings - var ban_headings = new RegExp('^ ?(' + i18n.sources.join('|') + ') ?$', 'i'); //remove things like 'external links' - if (part.match(/^={1,5}[^=]{1,200}={1,5}$/)) { - var sectionNameWithEquals; - - section = part.match(/^={1,5}([^=]{1,200}?)={1,5}$/) || []; - sectionNameWithEquals = section[0]; // used to keep track how deep this section is - section = section[1] || ''; - section = section.replace(/\./g, ' '); // this is necessary for mongo, i'm sorry - section = helpers.trim_whitespace(section); - //ban some sections - if (section && section.match(ban_headings)) { - section = undefined; - } - - // helps keep track who the parent section is, in case options.appendSectionLabelsWithParent === true - sectionStack.push({ - sectionNameWithEquals: sectionNameWithEquals, - name: section, - hasText: false - }); - - return; - } - - var sectionLabel = section; - - //still alive, add it to the section - sentence_parser(part).forEach(function(line) { - line = parse_line(line); - - if (line && line.text) { - // if (!output[section]) { - if (!output[sectionLabel]) { - // output[section] = []; - output[sectionLabel] = []; - } - // output[section].push(line); - output[sectionLabel].push(line); - } - }); - }); - //add additional image from infobox, if applicable - if (infobox['image'] && infobox['image'].text) { - var img = infobox['image'].text || ''; - if ( - typeof img === 'string' && - !img.match(new RegExp('^(' + i18n.images.concat(i18n.files).join('|') + ')', 'i')) - ) { - img = 'File:' + img; - } - images.push(img); - } - //add url, etc to image - images = images.map(make_image); - return { - type: 'page', - text: output, - categories: cats, - images: images, - infobox: infobox, - infobox_template: infobox_template, - tables: tables, - translations: translations - }; - }; - - var from_api = function(page_identifier, lang_or_wikiid, cb) { - if (typeof lang_or_wikiid === 'function') { - cb = lang_or_wikiid; - lang_or_wikiid = 'en'; - } - cb = cb || function() {}; - lang_or_wikiid = lang_or_wikiid || 'en'; - if (!fetch) { - //no http method, on the client side - return cb(null); - } - return fetch(page_identifier, lang_or_wikiid, cb); - }; - - var plaintext = function(str) { - var data = main(str) || {}; - data.text = data.text || []; - var text = ''; - Object.keys(data.text).forEach(function(k) { - text += data.text[k].map(a => a.text).join(' ') + '\n'; - }); - return text; - }; - - var methods = { - from_api: from_api, - parse: main, - plaintext: plaintext - }; - - if (typeof module !== 'undefined' && module.exports) { - module.exports = methods; +const from_api = function(page_identifier, lang_or_wikiid, cb) { + if (typeof lang_or_wikiid === 'function') { + cb = lang_or_wikiid; + lang_or_wikiid = 'en'; } - - return methods; -})(); - -module.exports = wtf_wikipedia; + cb = cb || function() {}; + lang_or_wikiid = lang_or_wikiid || 'en'; + if (!fetch) { + //no http method, on the client side + return cb(null); + } + return fetch(page_identifier, lang_or_wikiid, cb); +}; + +const plaintext = function(str) { + var data = main(str) || {}; + data.text = data.text || []; + var text = ''; + Object.keys(data.text).forEach(function(k) { + text += data.text[k].map(a => a.text).join(' ') + '\n'; + }); + return text; +}; + +module.exports = { + from_api: from_api, + parse: main, + plaintext: plaintext +}; diff --git a/src/main.js b/src/main.js new file mode 100644 index 00000000..3890ee7a --- /dev/null +++ b/src/main.js @@ -0,0 +1,200 @@ +const sentence_parser = require('./lib/sentence_parser'); +const fetch = require('./lib/fetch_text'); +const make_image = require('./lib/make_image'); +const i18n = require('./data/i18n'); +const helpers = require('./lib/helpers'); +const languages = require('./data/languages'); +//parsers +const redirects = require('./parse/parse_redirects'); +const parse_table = require('./parse/parse_table'); +const parse_line = require('./parse/parse_line'); +const parse_categories = require('./parse/parse_categories'); +const parse_disambig = require('./parse/parse_disambig'); +const parse_infobox = require('./parse/parse_infobox'); +const parse_infobox_template = require('./parse/parse_infobox_template'); +const parse_image = require('./parse/parse_image'); +const recursive_matches = require('./recursive_matches'); +const preprocess = require('./parse/cleanup_misc'); +const word_templates = require('./word_templates'); + +//regexs +const template_reg = new RegExp('\\{\\{ ?(' + i18n.disambigs.join('|') + ')(\\|[a-z =]*?)? ?\\}\\}', 'i'); +const infobox_reg = new RegExp('{{(' + i18n.infoboxes.join('|') + ')[: \n]', 'ig'); +const ban_headings = new RegExp('^ ?(' + i18n.sources.join('|') + ') ?$', 'i'); //remove things like 'external links' + +// options +const defaultParseOptions = { + ignoreLists: true +}; + +//some xml elements are just junk, and demand full inglorious death by regular exp +//other xml elements, like , are plucked out afterwards +const main = function(wiki, options) { + options = Object.assign({}, defaultParseOptions, options); + let infobox = {}; + let infobox_template = ''; + let images = []; + let tables; + let translations = {}; + wiki = wiki || ''; + //detect if page is just redirect, and return + if (redirects.is_redirect(wiki)) { + return redirects.parse_redirect(wiki); + } + //detect if page is disambiguator page + if (wiki.match(template_reg)) { + //|| wiki.match(/^.{3,25} may refer to/i)|| wiki.match(/^.{3,25} ist der Name mehrerer /i) + return parse_disambig(wiki); + } + //parse templates like {{currentday}} + wiki = word_templates(wiki); + //kill off th3 craziness + wiki = preprocess(wiki); + //find tables + tables = wiki.match(/\{\|[\s\S]{1,8000}?\|\}/g, '') || []; + tables = tables.map(function(s) { + return parse_table(s); + }); + //remove tables + wiki = wiki.replace(/\{\|[\s\S]{1,8000}?\|\}/g, ''); + + //reduce the scary recursive situations + //remove {{template {{}} }} recursions + let matches = recursive_matches('{', '}', wiki); + matches.forEach(function(s) { + if (s.match(infobox_reg, 'ig') && Object.keys(infobox).length === 0) { + infobox = parse_infobox(s); + infobox_template = parse_infobox_template(s); + } + if (s.match(infobox_reg)) { + wiki = wiki.replace(s, ''); + } + //rest of them... + if (s.match(/^\{\{/)) { + //support nowrap + const nowrap = s.match(/^\{\{nowrap\|(.*?)\}\}$/); + if (nowrap) { + wiki = wiki.replace(s, nowrap[1]); + return; + } + //if it's not a known template, but it's recursive, remove it + //(because it will be misread later-on) + wiki = wiki.replace(s, ''); + } + }); + + //second, remove [[file:...[[]] ]] recursions + matches = recursive_matches('[', ']', wiki); + matches.forEach(function(s) { + if (s.match(new RegExp('\\[\\[(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'))) { + images.push(parse_image(s)); + wiki = wiki.replace(s, ''); + } + }); + //third, wiktionary-style interlanguage links + matches.forEach(function(s) { + if (s.match(/\[\[([a-z][a-z]):(.*?)\]\]/i) !== null) { + const lang = s.match(/\[\[([a-z][a-z]):/i)[1]; + if (lang && languages[lang]) { + translations[lang] = s.match(/\[\[([a-z][a-z]):(.*?)\]\]/i)[2]; + } + wiki = wiki.replace(s, ''); + } + }); + + //now that the scary recursion issues are gone, we can trust simple regex methods + + //kill the rest of templates + wiki = wiki.replace(/\{\{.*?\}\}/g, ''); + + //get list of links, categories + const cats = parse_categories(wiki); + //next, map each line into a parsable sentence + // const output = {}; + let output = {}; + const lines = wiki.replace(/\r/g, '').split(/\n/); + let section = 'Intro'; + let number = 1; + + lines.forEach(function(part) { + if (!section) { + return; + } + //add # numberings formatting + if (part.match(/^ ?\#[^:,\|]{4}/i)) { + part = part.replace(/^ ?#*/, number + ') '); + part = part + '\n'; + number += 1; + } else { + number = 1; + } + //add bullet-points formatting + if (part.match(/^\*+[^:,\|]{4}/)) { + part = part + '\n'; + } + //remove some nonsense wp lines + + if (options.ignoreLists) { + //ignore list + if (part.match(/^[#\*:;\|]/)) { + return; + } + } + + //ignore only-punctuation + if (!part.match(/[a-z0-9]/i)) { + return; + } + //headings + if (part.match(/^={1,5}[^=]{1,200}={1,5}$/)) { + section = part.match(/^={1,5}([^=]{1,200}?)={1,5}$/) || []; + section = section[1] || ''; + section = section.replace(/\./g, ' '); // this is necessary for mongo, i'm sorry + section = helpers.trim_whitespace(section); + //ban some sections + if (section && section.match(ban_headings)) { + section = undefined; + } + return; + } + + const sectionLabel = section; + + //still alive, add it to the section + sentence_parser(part).forEach(function(line) { + line = parse_line(line); + + if (line && line.text) { + // if (!output[section]) { + if (!output[sectionLabel]) { + // output[section] = []; + output[sectionLabel] = []; + } + // output[section].push(line); + output[sectionLabel].push(line); + } + }); + }); + //add additional image from infobox, if applicable + if (infobox['image'] && infobox['image'].text) { + let img = infobox['image'].text || ''; + if (typeof img === 'string' && !img.match(new RegExp('^(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'))) { + img = 'File:' + img; + } + images.push(img); + } + //add url, etc to image + images = images.map(make_image); + return { + type: 'page', + text: output, + categories: cats, + images: images, + infobox: infobox, + infobox_template: infobox_template, + tables: tables, + translations: translations + }; +}; + +module.exports = main; From 835d71b66a92dadc0c13d1e6441ce6e26d115d04 Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 10:29:33 -0400 Subject: [PATCH 04/26] move regexes to top --- src/index.js | 7 +++++-- src/main.js | 17 ++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/index.js b/src/index.js index d82fd397..66ff1fa0 100644 --- a/src/index.js +++ b/src/index.js @@ -1,8 +1,10 @@ //turns wikimedia script into json // https://github.com/spencermountain/wtf_wikipedia //@spencermountain +const fetch = require('./lib/fetch_text'); const main = require('./main'); +//from a page title or id, fetch the wikiscript const from_api = function(page_identifier, lang_or_wikiid, cb) { if (typeof lang_or_wikiid === 'function') { cb = lang_or_wikiid; @@ -17,10 +19,11 @@ const from_api = function(page_identifier, lang_or_wikiid, cb) { return fetch(page_identifier, lang_or_wikiid, cb); }; +//turn wiki-markup into a nicely-formatted text const plaintext = function(str) { - var data = main(str) || {}; + let data = main(str) || {}; data.text = data.text || []; - var text = ''; + let text = ''; Object.keys(data.text).forEach(function(k) { text += data.text[k].map(a => a.text).join(' ') + '\n'; }); diff --git a/src/main.js b/src/main.js index 3890ee7a..43758b1b 100644 --- a/src/main.js +++ b/src/main.js @@ -1,5 +1,4 @@ const sentence_parser = require('./lib/sentence_parser'); -const fetch = require('./lib/fetch_text'); const make_image = require('./lib/make_image'); const i18n = require('./data/i18n'); const helpers = require('./lib/helpers'); @@ -21,6 +20,8 @@ const word_templates = require('./word_templates'); const template_reg = new RegExp('\\{\\{ ?(' + i18n.disambigs.join('|') + ')(\\|[a-z =]*?)? ?\\}\\}', 'i'); const infobox_reg = new RegExp('{{(' + i18n.infoboxes.join('|') + ')[: \n]', 'ig'); const ban_headings = new RegExp('^ ?(' + i18n.sources.join('|') + ') ?$', 'i'); //remove things like 'external links' +const fileRegex = new RegExp('\\[\\[(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'); +const img_regex = new RegExp('^(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'); // options const defaultParseOptions = { @@ -86,7 +87,7 @@ const main = function(wiki, options) { //second, remove [[file:...[[]] ]] recursions matches = recursive_matches('[', ']', wiki); matches.forEach(function(s) { - if (s.match(new RegExp('\\[\\[(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'))) { + if (s.match(fileRegex)) { images.push(parse_image(s)); wiki = wiki.replace(s, ''); } @@ -112,7 +113,7 @@ const main = function(wiki, options) { //next, map each line into a parsable sentence // const output = {}; let output = {}; - const lines = wiki.replace(/\r/g, '').split(/\n/); + let lines = wiki.replace(/\r/g, '').split(/\n/); let section = 'Intro'; let number = 1; @@ -158,27 +159,25 @@ const main = function(wiki, options) { return; } - const sectionLabel = section; - //still alive, add it to the section sentence_parser(part).forEach(function(line) { line = parse_line(line); if (line && line.text) { // if (!output[section]) { - if (!output[sectionLabel]) { + if (!output[section]) { // output[section] = []; - output[sectionLabel] = []; + output[section] = []; } // output[section].push(line); - output[sectionLabel].push(line); + output[section].push(line); } }); }); //add additional image from infobox, if applicable if (infobox['image'] && infobox['image'].text) { let img = infobox['image'].text || ''; - if (typeof img === 'string' && !img.match(new RegExp('^(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'))) { + if (typeof img === 'string' && !img.match(img_regex)) { img = 'File:' + img; } images.push(img); From 693243d4f04741cbfc74a23c012049386afcb003 Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 10:37:38 -0400 Subject: [PATCH 05/26] control state in one object --- src/main.js | 61 +++++++++++++++++++++++------------------------------ 1 file changed, 26 insertions(+), 35 deletions(-) diff --git a/src/main.js b/src/main.js index 43758b1b..cd884aae 100644 --- a/src/main.js +++ b/src/main.js @@ -32,11 +32,16 @@ const defaultParseOptions = { //other xml elements, like , are plucked out afterwards const main = function(wiki, options) { options = Object.assign({}, defaultParseOptions, options); - let infobox = {}; - let infobox_template = ''; - let images = []; - let tables; - let translations = {}; + let r = { + type: 'page', + text: {}, + categories: [], + images: [], + infobox: {}, + infobox_template: {}, + tables: [], + translations: {} + }; wiki = wiki || ''; //detect if page is just redirect, and return if (redirects.is_redirect(wiki)) { @@ -52,8 +57,8 @@ const main = function(wiki, options) { //kill off th3 craziness wiki = preprocess(wiki); //find tables - tables = wiki.match(/\{\|[\s\S]{1,8000}?\|\}/g, '') || []; - tables = tables.map(function(s) { + r.tables = wiki.match(/\{\|[\s\S]{1,8000}?\|\}/g, '') || []; + r.tables = r.tables.map(function(s) { return parse_table(s); }); //remove tables @@ -63,9 +68,9 @@ const main = function(wiki, options) { //remove {{template {{}} }} recursions let matches = recursive_matches('{', '}', wiki); matches.forEach(function(s) { - if (s.match(infobox_reg, 'ig') && Object.keys(infobox).length === 0) { - infobox = parse_infobox(s); - infobox_template = parse_infobox_template(s); + if (s.match(infobox_reg, 'ig') && Object.keys(r.infobox).length === 0) { + r.infobox = parse_infobox(s); + r.infobox_template = parse_infobox_template(s); } if (s.match(infobox_reg)) { wiki = wiki.replace(s, ''); @@ -88,7 +93,7 @@ const main = function(wiki, options) { matches = recursive_matches('[', ']', wiki); matches.forEach(function(s) { if (s.match(fileRegex)) { - images.push(parse_image(s)); + r.images.push(parse_image(s)); wiki = wiki.replace(s, ''); } }); @@ -97,7 +102,7 @@ const main = function(wiki, options) { if (s.match(/\[\[([a-z][a-z]):(.*?)\]\]/i) !== null) { const lang = s.match(/\[\[([a-z][a-z]):/i)[1]; if (lang && languages[lang]) { - translations[lang] = s.match(/\[\[([a-z][a-z]):(.*?)\]\]/i)[2]; + r.translations[lang] = s.match(/\[\[([a-z][a-z]):(.*?)\]\]/i)[2]; } wiki = wiki.replace(s, ''); } @@ -109,10 +114,8 @@ const main = function(wiki, options) { wiki = wiki.replace(/\{\{.*?\}\}/g, ''); //get list of links, categories - const cats = parse_categories(wiki); + r.categories = parse_categories(wiki); //next, map each line into a parsable sentence - // const output = {}; - let output = {}; let lines = wiki.replace(/\r/g, '').split(/\n/); let section = 'Intro'; let number = 1; @@ -164,36 +167,24 @@ const main = function(wiki, options) { line = parse_line(line); if (line && line.text) { - // if (!output[section]) { - if (!output[section]) { - // output[section] = []; - output[section] = []; + if (!r.text[section]) { + r.text[section] = []; } - // output[section].push(line); - output[section].push(line); + r.text[section].push(line); } }); }); //add additional image from infobox, if applicable - if (infobox['image'] && infobox['image'].text) { - let img = infobox['image'].text || ''; + if (r.infobox['image'] && r.infobox['image'].text) { + let img = r.infobox['image'].text || ''; if (typeof img === 'string' && !img.match(img_regex)) { img = 'File:' + img; } - images.push(img); + r.images.push(img); } //add url, etc to image - images = images.map(make_image); - return { - type: 'page', - text: output, - categories: cats, - images: images, - infobox: infobox, - infobox_template: infobox_template, - tables: tables, - translations: translations - }; + r.images = r.images.map(make_image); + return r; }; module.exports = main; From 2007e04ca225d6403da8feadc18de7d74c6b3d98 Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 10:53:34 -0400 Subject: [PATCH 06/26] code cleanup --- src/main.js | 27 +++---- src/parse/cleanup_misc.js | 21 +++--- src/parse/kill_xml.js | 9 ++- src/parse/parse_categories.js | 20 +++--- src/parse/parse_disambig.js | 20 +++--- src/parse/parse_image.js | 12 ++-- src/parse/parse_infobox.js | 106 +++++++++++++--------------- src/parse/parse_infobox_template.js | 12 ++-- src/parse/parse_line.js | 30 +++----- src/parse/parse_links.js | 82 +++++++++++---------- src/parse/parse_redirects.js | 19 +++-- src/parse/parse_table.js | 47 ++++++------ 12 files changed, 201 insertions(+), 204 deletions(-) diff --git a/src/main.js b/src/main.js index cd884aae..6d337504 100644 --- a/src/main.js +++ b/src/main.js @@ -22,6 +22,8 @@ const infobox_reg = new RegExp('{{(' + i18n.infoboxes.join('|') + ')[: \n]', 'ig const ban_headings = new RegExp('^ ?(' + i18n.sources.join('|') + ') ?$', 'i'); //remove things like 'external links' const fileRegex = new RegExp('\\[\\[(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'); const img_regex = new RegExp('^(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'); +const table_reg = /\{\|[\s\S]{1,8000}?\|\}/g; +const noWrap_reg = /^\{\{nowrap\|(.*?)\}\}$/; // options const defaultParseOptions = { @@ -31,7 +33,18 @@ const defaultParseOptions = { //some xml elements are just junk, and demand full inglorious death by regular exp //other xml elements, like , are plucked out afterwards const main = function(wiki, options) { + wiki = wiki || ''; options = Object.assign({}, defaultParseOptions, options); + //detect if page is just redirect, and return + if (redirects.is_redirect(wiki)) { + return redirects.parse_redirect(wiki); + } + //detect if page is disambiguator page + if (wiki.match(template_reg)) { + //|| wiki.match(/^.{3,25} may refer to/i)|| wiki.match(/^.{3,25} ist der Name mehrerer /i) + return parse_disambig(wiki); + } + let r = { type: 'page', text: {}, @@ -42,22 +55,12 @@ const main = function(wiki, options) { tables: [], translations: {} }; - wiki = wiki || ''; - //detect if page is just redirect, and return - if (redirects.is_redirect(wiki)) { - return redirects.parse_redirect(wiki); - } - //detect if page is disambiguator page - if (wiki.match(template_reg)) { - //|| wiki.match(/^.{3,25} may refer to/i)|| wiki.match(/^.{3,25} ist der Name mehrerer /i) - return parse_disambig(wiki); - } //parse templates like {{currentday}} wiki = word_templates(wiki); //kill off th3 craziness wiki = preprocess(wiki); //find tables - r.tables = wiki.match(/\{\|[\s\S]{1,8000}?\|\}/g, '') || []; + r.tables = wiki.match(table_reg, '') || []; r.tables = r.tables.map(function(s) { return parse_table(s); }); @@ -78,7 +81,7 @@ const main = function(wiki, options) { //rest of them... if (s.match(/^\{\{/)) { //support nowrap - const nowrap = s.match(/^\{\{nowrap\|(.*?)\}\}$/); + const nowrap = s.match(noWrap_reg); if (nowrap) { wiki = wiki.replace(s, nowrap[1]); return; diff --git a/src/parse/cleanup_misc.js b/src/parse/cleanup_misc.js index a5c6cd36..c4a44528 100644 --- a/src/parse/cleanup_misc.js +++ b/src/parse/cleanup_misc.js @@ -1,25 +1,24 @@ - -var kill_xml = require("./kill_xml"); +const kill_xml = require('./kill_xml'); function cleanup_misc(wiki) { //the dump requires us to unescape xml //remove comments - wiki = wiki.replace(//g, ""); - wiki = wiki.replace(/__(NOTOC|NOEDITSECTION|FORCETOC|TOC)__/ig, ""); + wiki = wiki.replace(//g, ''); + wiki = wiki.replace(/__(NOTOC|NOEDITSECTION|FORCETOC|TOC)__/gi, ''); //signitures - wiki = wiki.replace(/~~{1,3}/, ""); + wiki = wiki.replace(/~~{1,3}/, ''); //horizontal rule - wiki = wiki.replace(/--{1,3}/, ""); + wiki = wiki.replace(/--{1,3}/, ''); //space - wiki = wiki.replace(/ /g, " "); + wiki = wiki.replace(/ /g, ' '); //kill off interwiki links - wiki = wiki.replace(/\[\[([a-z][a-z]|simple|war|ceb|min):.{2,60}\]\]/i, ""); + wiki = wiki.replace(/\[\[([a-z][a-z]|simple|war|ceb|min):.{2,60}\]\]/i, ''); //bold and italics combined - wiki = wiki.replace(/''{4}([^']{0,200})''{4}/g, "$1"); + wiki = wiki.replace(/''{4}([^']{0,200})''{4}/g, '$1'); //bold - wiki = wiki.replace(/''{2}([^']{0,200})''{2}/g, "$1"); + wiki = wiki.replace(/''{2}([^']{0,200})''{2}/g, '$1'); //italic - wiki = wiki.replace(/''([^']{0,200})''/g, "$1"); + wiki = wiki.replace(/''([^']{0,200})''/g, '$1'); //give it the inglorious send-off it deserves.. wiki = kill_xml(wiki); diff --git a/src/parse/kill_xml.js b/src/parse/kill_xml.js index 3c784c87..fe04042b 100644 --- a/src/parse/kill_xml.js +++ b/src/parse/kill_xml.js @@ -1,14 +1,17 @@ //okay, i know you're not supposed to regex html, but... //https://en.wikipedia.org/wiki/Help:HTML_in_wikitext -var kill_xml = function(wiki) { +const kill_xml = function(wiki) { //luckily, refs can't be recursive.. wiki = wiki.replace(/ ?[\s\S]{0,750}?<\/ref> ?/gi, ' '); // wiki = wiki.replace(/ ?]{0,200}?\/> ?/gi, ' '); // - wiki = wiki.replace(/ ?]{0,200}?>[\s\S]{0,500}?<\/ref> ?/ig, ' '); // + wiki = wiki.replace(/ ?]{0,200}?>[\s\S]{0,500}?<\/ref> ?/gi, ' '); // //other types of xml that we want to trash completely - wiki = wiki.replace(/< ?(table|code|score|data|categorytree|charinsert|gallery|hiero|imagemap|inputbox|math|nowiki|poem|references|source|syntaxhighlight|timeline) ?[^>]{0,200}?>[\s\S]{0,700}< ?\/ ?(table|code|score|data|categorytree|charinsert|gallery|hiero|imagemap|inputbox|math|nowiki|poem|references|source|syntaxhighlight|timeline) ?>/gi, ' '); // hi
+ wiki = wiki.replace( + /< ?(table|code|score|data|categorytree|charinsert|gallery|hiero|imagemap|inputbox|math|nowiki|poem|references|source|syntaxhighlight|timeline) ?[^>]{0,200}?>[\s\S]{0,700}< ?\/ ?(table|code|score|data|categorytree|charinsert|gallery|hiero|imagemap|inputbox|math|nowiki|poem|references|source|syntaxhighlight|timeline) ?>/gi, + ' ' + ); // hi
//some xml-like fragments we can also kill // diff --git a/src/parse/parse_categories.js b/src/parse/parse_categories.js index c88ea010..43803f14 100644 --- a/src/parse/parse_categories.js +++ b/src/parse/parse_categories.js @@ -1,20 +1,20 @@ -var i18n = require("../data/i18n"); +const i18n = require('../data/i18n'); +const cat_reg = new RegExp('\\[\\[:?(' + i18n.categories.join('|') + '):(.{2,60}?)]](w{0,10})', 'ig'); +const cat_remove_reg = new RegExp('^\\[\\[:?(' + i18n.categories.join('|') + '):', 'ig'); -function parse_categories(wiki) { - var cats = []; - var reg = new RegExp("\\[\\[:?(" + i18n.categories.join("|") + "):(.{2,60}?)\]\](\w{0,10})", "ig"); - var tmp = wiki.match(reg); //regular links +const parse_categories = function(wiki) { + let cats = []; + let tmp = wiki.match(cat_reg); //regular links if (tmp) { - var reg2 = new RegExp("^\\[\\[:?(" + i18n.categories.join("|") + "):", "ig"); tmp.forEach(function(c) { - c = c.replace(reg2, ""); - c = c.replace(/\|?[ \*]?\]\]$/i, ""); //parse fancy onces.. - c = c.replace(/\|.*/, ""); //everything after the '|' is metadata + c = c.replace(cat_remove_reg, ''); + c = c.replace(/\|?[ \*]?\]\]$/i, ''); //parse fancy onces.. + c = c.replace(/\|.*/, ''); //everything after the '|' is metadata if (c && !c.match(/[\[\]]/)) { cats.push(c); } }); } return cats; -} +}; module.exports = parse_categories; diff --git a/src/parse/parse_disambig.js b/src/parse/parse_disambig.js index 3127f46f..77f231f3 100644 --- a/src/parse/parse_disambig.js +++ b/src/parse/parse_disambig.js @@ -1,21 +1,21 @@ -var parse_links = require("./parse_links"); +const parse_links = require('./parse_links'); //return a list of probable pages for this disambig page -var parse_disambig = function (wiki) { - var pages = []; - var lines = wiki.replace(/\r/g, '').split(/\n/); - lines.forEach(function (str) { +const parse_disambig = function(wiki) { + let pages = []; + let lines = wiki.replace(/\r/g, '').split(/\n/); + lines.forEach(function(str) { //if there's an early link in the list - if(str.match(/^\*.{0,40}\[\[.*\]\]/)) { - var links = parse_links(str); - if(links && links[0] && links[0].page) { + if (str.match(/^\*.{0,40}\[\[.*\]\]/)) { + let links = parse_links(str); + if (links && links[0] && links[0].page) { pages.push(links[0].page); } } }); return { - type: "disambiguation", + type: 'disambiguation', pages: pages - } + }; }; module.exports = parse_disambig; diff --git a/src/parse/parse_image.js b/src/parse/parse_image.js index 818d1321..aba6d7f1 100644 --- a/src/parse/parse_image.js +++ b/src/parse/parse_image.js @@ -1,12 +1,12 @@ -var i18n = require("../data/i18n"); +const i18n = require('../data/i18n'); +const file_reg = new RegExp('(' + i18n.images.concat(i18n.files).join('|') + '):.*?[\\|\\]]', 'i'); //images are usually [[image:my_pic.jpg]] -function parse_image(img) { - var reg = new RegExp("(" + i18n.images.concat(i18n.files).join("|") + "):.*?[\\|\\]]", "i"); - img = img.match(reg) || [""]; - img = img[0].replace(/[\|\]]$/, ""); +const parse_image = function(img) { + img = img.match(file_reg) || ['']; + img = img[0].replace(/[\|\]]$/, ''); return img; -} +}; module.exports = parse_image; // console.log(parse_image("[[image:my_pic.jpg]]")); diff --git a/src/parse/parse_infobox.js b/src/parse/parse_infobox.js index 5a779f4e..9a57e937 100644 --- a/src/parse/parse_infobox.js +++ b/src/parse/parse_infobox.js @@ -1,66 +1,56 @@ -"use strict"; - -var helpers = require("../lib/helpers"); -var parse_line = require("./parse_line"); - -function parse_infobox(str) { - var obj = {}; - - if (str) { - //this collapsible list stuff is just a headache - str = str.replace(/\{\{Collapsible list[^}]{10,1000}\}\}/g, ""); - - - let stringBuilder = []; - - let lastChar; - let parDepth = -2; // first two {{ - for (let i = 0, len = str.length; i < len; i++) { - - if ((parDepth === 0) && str[i] === '|' && lastChar !== '\n') { - stringBuilder.push('\n'); - } - - if (str[i] === '{' || str[i] === '[') { - parDepth++; - } else if (str[i] === '}' || str[i] === ']') { - parDepth--; - } - - lastChar = str[i]; - stringBuilder.push(lastChar); - - } - - str = stringBuilder.join(''); - - var regex = /\n *\|([^=]*)=(.*)/g; - - var regexMatch; - while ((regexMatch = regex.exec(str)) !== null) { +'use strict'; +const helpers = require('../lib/helpers'); +const parse_line = require('./parse_line'); + +const line_reg = /\n *\|([^=]*)=(.*)/g; + +const parse_infobox = function(str) { + let obj = {}; + + if (str) { + let stringBuilder = []; + let lastChar; + + //this collapsible list stuff is just a headache + str = str.replace(/\{\{Collapsible list[^}]{10,1000}\}\}/g, ''); + + let parDepth = -2; // first two {{ + for (let i = 0, len = str.length; i < len; i++) { + if (parDepth === 0 && str[i] === '|' && lastChar !== '\n') { + stringBuilder.push('\n'); + } + if (str[i] === '{' || str[i] === '[') { + parDepth++; + } else if (str[i] === '}' || str[i] === ']') { + parDepth--; + } + lastChar = str[i]; + stringBuilder.push(lastChar); + } - let key = helpers.trim_whitespace(regexMatch[1] || "") || ""; - let value = helpers.trim_whitespace(regexMatch[2] || "") || ""; + str = stringBuilder.join(''); - //this is necessary for mongodb, im sorry - if (key && key.match(/[\.]/)) { - key = null; - } + let regexMatch; + while ((regexMatch = line_reg.exec(str)) !== null) { + let key = helpers.trim_whitespace(regexMatch[1] || '') || ''; + let value = helpers.trim_whitespace(regexMatch[2] || '') || ''; - if (key && value) { - obj[key] = parse_line(value); - //turn number strings into integers - if (obj[key].text && obj[key].text.match(/^[0-9,]*$/)) { - obj[key].text = obj[key].text.replace(/,/, ''); - obj[key].text = parseInt(obj[key].text, 10); - } - } + //this is necessary for mongodb, im sorry + if (key && key.match(/[\.]/)) { + key = null; + } + if (key && value) { + obj[key] = parse_line(value); + //turn number strings into integers + if (obj[key].text && obj[key].text.match(/^[0-9,]*$/)) { + obj[key].text = obj[key].text.replace(/,/, ''); + obj[key].text = parseInt(obj[key].text, 10); } - + } } + } - return obj; -} + return obj; +}; module.exports = parse_infobox; - diff --git a/src/parse/parse_infobox_template.js b/src/parse/parse_infobox_template.js index dd955cd9..3281ea83 100644 --- a/src/parse/parse_infobox_template.js +++ b/src/parse/parse_infobox_template.js @@ -1,11 +1,11 @@ -var i18n = require("../data/i18n"); +const i18n = require('../data/i18n'); +const infobox_template_reg = new RegExp('{{(?:' + i18n.infoboxes.join('|') + ')\\s*(.*)', 'i'); function parse_infobox_template(str) { - var template = ''; - if(str) { - var infobox_template_reg = new RegExp("\{\{(?:" + i18n.infoboxes.join("|") + ")\\s*(.*)", "i"); - var matches = str.match(infobox_template_reg); - if(matches && matches.length > 1) { + let template = ''; + if (str) { + const matches = str.match(infobox_template_reg); + if (matches && matches.length > 1) { template = matches[1]; } } diff --git a/src/parse/parse_line.js b/src/parse/parse_line.js index c4ba9c0a..b3b131c3 100644 --- a/src/parse/parse_line.js +++ b/src/parse/parse_line.js @@ -1,39 +1,32 @@ -var helpers = require("../lib/helpers"); -var parse_links = require("./parse_links"); -var i18n = require("../data/i18n"); +const helpers = require('../lib/helpers'); +const parse_links = require('./parse_links'); +const i18n = require('../data/i18n'); +const cat_reg = new RegExp('\\[\\[:?(' + i18n.categories.join('|') + '):[^\\]\\]]{2,80}\\]\\]', 'gi'); //return only rendered text of wiki links -function resolve_links(line) { +const resolve_links = function(line) { // categories, images, files - var re = new RegExp("\\[\\[:?(" + i18n.categories.join("|") + "):[^\\]\\]]{2,80}\\]\\]", "gi"); - line = line.replace(re, ""); - + line = line.replace(cat_reg, ''); // [[Common links]] - line = line.replace(/\[\[:?([^|]{2,80}?)\]\](\w{0,5})/g, "$1$2"); + line = line.replace(/\[\[:?([^|]{2,80}?)\]\](\w{0,5})/g, '$1$2'); // [[File:with|Size]] - line = line.replace(/\[\[File:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g, "$1"); + line = line.replace(/\[\[File:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g, '$1'); // [[Replaced|Links]] - line = line.replace(/\[\[:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g, "$2$3"); + line = line.replace(/\[\[:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g, '$2$3'); // External links - line = line.replace(/\[(https?|news|ftp|mailto|gopher|irc):\/\/[^\]\| ]{4,1500}([\| ].*?)?\]/g, "$2"); + line = line.replace(/\[(https?|news|ftp|mailto|gopher|irc):\/\/[^\]\| ]{4,1500}([\| ].*?)?\]/g, '$2'); return line; -} +}; // console.log(resolve_links("[http://www.whistler.ca www.whistler.ca]")) function postprocess(line) { - //fix links line = resolve_links(line); //oops, recursive image bug if (line.match(/^(thumb|right|left)\|/i)) { return null; } - line = helpers.trim_whitespace(line); - - // put new lines back in - // line=line+"\n"; - return line; } @@ -44,5 +37,4 @@ function parse_line(line) { }; } -// console.log(fetch_links("it is [[Tony Hawk|Tony]]s moher in [[Toronto]]s")) module.exports = parse_line; diff --git a/src/parse/parse_links.js b/src/parse/parse_links.js index b90348d6..6e3b2744 100644 --- a/src/parse/parse_links.js +++ b/src/parse/parse_links.js @@ -1,45 +1,49 @@ -var helpers = require("../lib/helpers"); +const helpers = require('../lib/helpers'); +const link_reg = /\[\[(.{2,80}?)\]\](\w{0,10})/g; +const ignore_links = /^:?(category|catégorie|Kategorie|Categoría|Categoria|Categorie|Kategoria|تصنيف|image|file|image|fichier|datei|media|special|wp|wikipedia|help|user|mediawiki|portal|talk|template|book|draft|module|topic|wiktionary|wikisource):/i; + //grab an array of internal links in the text -var parse_links = function (str) { - var links = []; - var tmp = str.match(/\[\[(.{2,80}?)\]\](\w{0,10})/g); //regular links - if(tmp) { - tmp.forEach(function (s) { - var link, txt; - if(s.match(/\|/)) { //replacement link [[link|text]] - s = s.replace(/\[\[(.{2,80}?)\]\](\w{0,10})/g, "$1$2"); //remove ['s and keep suffix - link = s.replace(/(.{2,60})\|.{0,200}/, "$1"); //replaced links - txt = s.replace(/.{2,60}?\|/, ''); - //handle funky case of [[toronto|]] - if(!txt && link.match(/\|$/)) { - link = link.replace(/\|$/, ''); - txt = link - } - } else { // standard link [[link]] - link = s.replace(/\[\[(.{2,60}?)\]\](\w{0,10})/g, "$1"); //remove ['s +const parse_links = function(str) { + let links = []; + const all = str.match(link_reg) || []; //regular links + all.forEach(function(s) { + var link, txt; + if (s.match(/\|/)) { + //replacement link [[link|text]] + s = s.replace(/\[\[(.{2,80}?)\]\](\w{0,10})/g, '$1$2'); //remove ['s and keep suffix + link = s.replace(/(.{2,60})\|.{0,200}/, '$1'); //replaced links + txt = s.replace(/.{2,60}?\|/, ''); + //handle funky case of [[toronto|]] + if (!txt && link.match(/\|$/)) { + link = link.replace(/\|$/, ''); + txt = link; } - //kill off non-wikipedia namespaces - if(link.match(/^:?(category|catégorie|Kategorie|Categoría|Categoria|Categorie|Kategoria|تصنيف|image|file|image|fichier|datei|media|special|wp|wikipedia|help|user|mediawiki|portal|talk|template|book|draft|module|topic|wiktionary|wikisource):/i)) { - return - } - //kill off just anchor links [[#history]] - if(link.match(/^#/i)) { - return - } - //remove anchors from end [[toronto#history]] - link = link.replace(/#[^ ]{1,100}/, ''); - link = helpers.capitalise(link); - var obj = { - page: link, - src: txt - }; - links.push(obj) - }) - } + } else { + // standard link [[link]] + link = s.replace(/\[\[(.{2,60}?)\]\](\w{0,10})/g, '$1'); //remove ['s + } + //kill off non-wikipedia namespaces + if (link.match(ignore_links)) { + return; + } + //kill off just anchor links [[#history]] + if (link.match(/^#/i)) { + return; + } + //remove anchors from end [[toronto#history]] + link = link.replace(/#[^ ]{1,100}/, ''); + link = helpers.capitalise(link); + var obj = { + page: link, + src: txt + }; + links.push(obj); + }); + //remove duplicates links = links.filter(helpers.onlyUnique); - if(links.length === 0) { - return undefined + if (links.length === 0) { + return undefined; } - return links + return links; }; module.exports = parse_links; diff --git a/src/parse/parse_redirects.js b/src/parse/parse_redirects.js index dd70fc89..7b7412a3 100644 --- a/src/parse/parse_redirects.js +++ b/src/parse/parse_redirects.js @@ -1,16 +1,21 @@ -var i18n = require("../data/i18n"); +const i18n = require('../data/i18n'); //pulls target link out of redirect page -var REDIRECT_REGEX = new RegExp("^ ?#(" + i18n.redirects.join("|") + ") *?\\[\\[(.{2,60}?)\\]\\]", "i"); +const REDIRECT_REGEX = new RegExp('^ ?#(' + i18n.redirects.join('|') + ') *?\\[\\[(.{2,60}?)\\]\\]', 'i'); -exports.is_redirect = function(wiki) { +const is_redirect = function(wiki) { return wiki.match(REDIRECT_REGEX); }; -exports.parse_redirect = function(wiki) { - var article = (wiki.match(REDIRECT_REGEX) || [])[2] || ""; - article = article.replace(/#.*/, ""); +const parse_redirect = function(wiki) { + let article = (wiki.match(REDIRECT_REGEX) || [])[2] || ''; + article = article.replace(/#.*/, ''); return { - type: "redirect", + type: 'redirect', redirect: article }; }; + +module.exports = { + is_redirect: is_redirect, + parse_redirect: parse_redirect +}; diff --git a/src/parse/parse_table.js b/src/parse/parse_table.js index bf0be2a7..cd7542af 100644 --- a/src/parse/parse_table.js +++ b/src/parse/parse_table.js @@ -1,41 +1,42 @@ -var helpers = require("../lib/helpers"); +const helpers = require('../lib/helpers'); + //turn a {|...table string into an array of arrays -var parse_table = function (wiki) { - var table = []; - var lines = wiki.replace(/\r/g, '').split(/\n/); - lines.forEach(function (str) { - //die - if(str.match(/^\|\}/)) { - return +const parse_table = function(wiki) { + let table = []; + const lines = wiki.replace(/\r/g, '').split(/\n/); + lines.forEach(function(str) { + //die here + if (str.match(/^\|\}/)) { + return; } //make new row - if(str.match(/^\|-/)) { + if (str.match(/^\|-/)) { table.push([]); - return + return; } //this is some kind of comment - if(str.match(/^\|\+/)) { - return + if (str.match(/^\|\+/)) { + return; } //juicy line - if(str.match(/^[\!\|]/)) { + if (str.match(/^[\!\|]/)) { //make a new row - if(!table[table.length - 1]) { - table[table.length - 1] = [] + if (!table[table.length - 1]) { + table[table.length - 1] = []; } - var want = (str.match(/\|(.*)/) || [])[1] || ''; + let want = (str.match(/\|(.*)/) || [])[1] || ''; want = helpers.trim_whitespace(want) || ''; - //handle the || shorthand.. - if(want.match(/[!\|]{2}/)) { - want.split(/[!\|]{2}/g).forEach(function (s) { + //handle the || shorthand.. + if (want.match(/[!\|]{2}/)) { + want.split(/[!\|]{2}/g).forEach(function(s) { s = helpers.trim_whitespace(s); - table[table.length - 1].push(s) - }) + table[table.length - 1].push(s); + }); } else { - table[table.length - 1].push(want) + table[table.length - 1].push(want); } } }); - return table + return table; }; module.exports = parse_table; From 2981d1e371cc038a3d000172eed6325ec4205aa1 Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 11:02:06 -0400 Subject: [PATCH 07/26] more code-cleanup --- package.json | 3 +- src/data/abbreviations.js | 147 +++ src/data/i18n.js | 27 +- src/data/languages.js | 2488 ++++++++++++++++++------------------ src/data/site_map.js | 1602 +++++++++++------------ src/lib/fetch_text.js | 54 +- src/lib/hashes.js | 1765 ------------------------- src/lib/make_image.js | 3 +- src/lib/sentence_parser.js | 32 +- 9 files changed, 2250 insertions(+), 3871 deletions(-) create mode 100644 src/data/abbreviations.js delete mode 100644 src/lib/hashes.js diff --git a/package.json b/package.json index e6935f9d..4c843f48 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "wikiscript" ], "dependencies": { + "jshashes": "^1.0.6", "superagent": "^3.5.2" }, "devDependencies": { @@ -49,4 +50,4 @@ "shelljs": "^0.7.2" }, "license": "MIT" -} \ No newline at end of file +} diff --git a/src/data/abbreviations.js b/src/data/abbreviations.js new file mode 100644 index 00000000..349a7b76 --- /dev/null +++ b/src/data/abbreviations.js @@ -0,0 +1,147 @@ +//these are used for the sentence-splitter +module.exports = [ + 'jr', + 'mr', + 'mrs', + 'ms', + 'dr', + 'prof', + 'sr', + 'sen', + 'corp', + 'calif', + 'rep', + 'gov', + 'atty', + 'supt', + 'det', + 'rev', + 'col', + 'gen', + 'lt', + 'cmdr', + 'adm', + 'capt', + 'sgt', + 'cpl', + 'maj', + 'dept', + 'univ', + 'assn', + 'bros', + 'inc', + 'ltd', + 'co', + 'corp', + 'arc', + 'al', + 'ave', + 'blvd', + 'cl', + 'ct', + 'cres', + 'exp', + 'rd', + 'st', + 'dist', + 'mt', + 'ft', + 'fy', + 'hwy', + 'la', + 'pd', + 'pl', + 'plz', + 'tce', + 'Ala', + 'Ariz', + 'Ark', + 'Cal', + 'Calif', + 'Col', + 'Colo', + 'Conn', + 'Del', + 'Fed', + 'Fla', + 'Ga', + 'Ida', + 'Id', + 'Ill', + 'Ind', + 'Ia', + 'Kan', + 'Kans', + 'Ken', + 'Ky', + 'La', + 'Me', + 'Md', + 'Mass', + 'Mich', + 'Minn', + 'Miss', + 'Mo', + 'Mont', + 'Neb', + 'Nebr', + 'Nev', + 'Mex', + 'Okla', + 'Ok', + 'Ore', + 'Penna', + 'Penn', + 'Pa', + 'Dak', + 'Tenn', + 'Tex', + 'Ut', + 'Vt', + 'Va', + 'Wash', + 'Wis', + 'Wisc', + 'Wy', + 'Wyo', + 'USAFA', + 'Alta', + 'Ont', + 'QuÔøΩ', + 'Sask', + 'Yuk', + 'jan', + 'feb', + 'mar', + 'apr', + 'jun', + 'jul', + 'aug', + 'sep', + 'oct', + 'nov', + 'dec', + 'sept', + 'vs', + 'etc', + 'esp', + 'llb', + 'md', + 'bl', + 'phd', + 'ma', + 'ba', + 'miss', + 'misses', + 'mister', + 'sir', + 'esq', + 'mstr', + 'lit', + 'fl', + 'ex', + 'eg', + 'sep', + 'sept', + '..' +]; diff --git a/src/data/i18n.js b/src/data/i18n.js index e31d72b7..3cc4ff90 100644 --- a/src/data/i18n.js +++ b/src/data/i18n.js @@ -1,7 +1,7 @@ // wikipedia special terms lifted and augmented from parsoid parser april 2015 // (not even close to being complete) -var i18n = { - 'files': [ +const i18n = { + files: [ 'файл', 'fitxer', 'soubor', @@ -11,17 +11,15 @@ var i18n = { 'پرونده', 'tiedosto', 'mynd', - 'su\'wret', + "su'wret", 'fichier', 'bestand', 'датотека', 'dosya', 'fil' ], - 'images': [ - 'image' - ], - 'templates': [ + images: ['image'], + templates: [ 'шаблён', 'plantilla', 'šablona', @@ -36,7 +34,7 @@ var i18n = { 'шаблон', 'şablon' ], - 'categories': [ + categories: [ 'катэгорыя', 'categoria', 'kategorie', @@ -53,7 +51,7 @@ var i18n = { 'kategoria', 'تصنيف' ], - 'redirects': [ + redirects: [ 'перанакіраваньне', 'redirect', 'přesměruj', @@ -83,7 +81,7 @@ var i18n = { 'перанакіраваньне', 'yönlendirme' ], - 'specials': [ + specials: [ 'спэцыяльныя', 'especial', 'speciální', @@ -98,7 +96,7 @@ var i18n = { 'посебно', 'özel' ], - 'users': [ + users: [ 'удзельнік', 'usuari', 'uživatel', @@ -114,7 +112,7 @@ var i18n = { 'корисник', 'kullanıcı' ], - 'disambigs': [ + disambigs: [ 'disambig', //en 'disambiguation', //en 'dab', //en @@ -131,7 +129,7 @@ var i18n = { 'неоднозначность', //ru 'anlam ayrımı' //tr ], - 'infoboxes': [ + infoboxes: [ 'infobox', 'ficha', 'канадский', @@ -142,7 +140,8 @@ var i18n = { 'yerleşim bilgi kutusu', 'infoboks' //nn, no ], - 'sources': [ //blacklist these headings, as they're not plain-text + sources: [ + //blacklist these headings, as they're not plain-text 'references', 'see also', 'external links', diff --git a/src/data/languages.js b/src/data/languages.js index 330e1632..6958b53c 100644 --- a/src/data/languages.js +++ b/src/data/languages.js @@ -1,1267 +1,1267 @@ module.exports = { - 'aa': { - 'english_title': 'Afar', - 'direction': 'ltr', - 'local_title': 'Afar' - }, - 'ab': { - 'english_title': 'Abkhazian', - 'direction': 'ltr', - 'local_title': 'Аҧсуа' - }, - 'af': { - 'english_title': 'Afrikaans', - 'direction': 'ltr', - 'local_title': 'Afrikaans' - }, - 'ak': { - 'english_title': 'Akan', - 'direction': 'ltr', - 'local_title': 'Akana' - }, - 'als': { - 'english_title': 'Alemannic', - 'direction': 'ltr', - 'local_title': 'Alemannisch' - }, - 'am': { - 'english_title': 'Amharic', - 'direction': 'ltr', - 'local_title': 'አማርኛ' - }, - 'an': { - 'english_title': 'Aragonese', - 'direction': 'ltr', - 'local_title': 'Aragonés' - }, - 'ang': { - 'english_title': 'Anglo-Saxon', - 'direction': 'ltr', - 'local_title': 'Englisc' - }, - 'ar': { - 'english_title': 'Arabic', - 'direction': 'rtl', - 'local_title': 'العربية' - }, - 'arc': { - 'english_title': 'Aramaic', - 'direction': 'rtl', - 'local_title': 'ܣܘܪܬ' - }, - 'as': { - 'english_title': 'Assamese', - 'direction': 'ltr', - 'local_title': 'অসমীয়া' - }, - 'ast': { - 'english_title': 'Asturian', - 'direction': 'ltr', - 'local_title': 'Asturianu' - }, - 'av': { - 'english_title': 'Avar', - 'direction': 'ltr', - 'local_title': 'Авар' - }, - 'ay': { - 'english_title': 'Aymara', - 'direction': 'ltr', - 'local_title': 'Aymar' - }, - 'az': { - 'english_title': 'Azerbaijani', - 'direction': 'ltr', - 'local_title': 'Azərbaycanca' - }, - 'ba': { - 'english_title': 'Bashkir', - 'direction': 'ltr', - 'local_title': 'Башҡорт' - }, - 'bar': { - 'english_title': 'Bavarian', - 'direction': 'ltr', - 'local_title': 'Boarisch' + aa: { + english_title: 'Afar', + direction: 'ltr', + local_title: 'Afar' + }, + ab: { + english_title: 'Abkhazian', + direction: 'ltr', + local_title: 'Аҧсуа' + }, + af: { + english_title: 'Afrikaans', + direction: 'ltr', + local_title: 'Afrikaans' + }, + ak: { + english_title: 'Akan', + direction: 'ltr', + local_title: 'Akana' + }, + als: { + english_title: 'Alemannic', + direction: 'ltr', + local_title: 'Alemannisch' + }, + am: { + english_title: 'Amharic', + direction: 'ltr', + local_title: 'አማርኛ' + }, + an: { + english_title: 'Aragonese', + direction: 'ltr', + local_title: 'Aragonés' + }, + ang: { + english_title: 'Anglo-Saxon', + direction: 'ltr', + local_title: 'Englisc' + }, + ar: { + english_title: 'Arabic', + direction: 'rtl', + local_title: 'العربية' + }, + arc: { + english_title: 'Aramaic', + direction: 'rtl', + local_title: 'ܣܘܪܬ' + }, + as: { + english_title: 'Assamese', + direction: 'ltr', + local_title: 'অসমীয়া' + }, + ast: { + english_title: 'Asturian', + direction: 'ltr', + local_title: 'Asturianu' + }, + av: { + english_title: 'Avar', + direction: 'ltr', + local_title: 'Авар' + }, + ay: { + english_title: 'Aymara', + direction: 'ltr', + local_title: 'Aymar' + }, + az: { + english_title: 'Azerbaijani', + direction: 'ltr', + local_title: 'Azərbaycanca' + }, + ba: { + english_title: 'Bashkir', + direction: 'ltr', + local_title: 'Башҡорт' + }, + bar: { + english_title: 'Bavarian', + direction: 'ltr', + local_title: 'Boarisch' }, 'bat-smg': { - 'english_title': 'Samogitian', - 'direction': 'ltr', - 'local_title': 'Žemaitėška' + english_title: 'Samogitian', + direction: 'ltr', + local_title: 'Žemaitėška' }, - 'bcl': { - 'english_title': 'Bikol', - 'direction': 'ltr', - 'local_title': 'Bikol' + bcl: { + english_title: 'Bikol', + direction: 'ltr', + local_title: 'Bikol' }, - 'be': { - 'english_title': 'Belarusian', - 'direction': 'ltr', - 'local_title': 'Беларуская' + be: { + english_title: 'Belarusian', + direction: 'ltr', + local_title: 'Беларуская' }, 'be-x-old': { - 'english_title': 'Belarusian', - 'direction': '(Taraškievica)', - 'local_title': 'ltr' - }, - 'bg': { - 'english_title': 'Bulgarian', - 'direction': 'ltr', - 'local_title': 'Български' - }, - 'bh': { - 'english_title': 'Bihari', - 'direction': 'ltr', - 'local_title': 'भोजपुरी' - }, - 'bi': { - 'english_title': 'Bislama', - 'direction': 'ltr', - 'local_title': 'Bislama' - }, - 'bm': { - 'english_title': 'Bambara', - 'direction': 'ltr', - 'local_title': 'Bamanankan' - }, - 'bn': { - 'english_title': 'Bengali', - 'direction': 'ltr', - 'local_title': 'বাংলা' - }, - 'bo': { - 'english_title': 'Tibetan', - 'direction': 'ltr', - 'local_title': 'བོད་ཡིག' - }, - 'bpy': { - 'english_title': 'Bishnupriya', - 'direction': 'Manipuri', - 'local_title': 'ltr' - }, - 'br': { - 'english_title': 'Breton', - 'direction': 'ltr', - 'local_title': 'Brezhoneg' - }, - 'bs': { - 'english_title': 'Bosnian', - 'direction': 'ltr', - 'local_title': 'Bosanski' - }, - 'bug': { - 'english_title': 'Buginese', - 'direction': 'ltr', - 'local_title': 'ᨅᨔ' - }, - 'bxr': { - 'english_title': 'Buriat', - 'direction': '(Russia)', - 'local_title': 'ltr' - }, - 'ca': { - 'english_title': 'Catalan', - 'direction': 'ltr', - 'local_title': 'Català' - }, - 'cdo': { - 'english_title': 'Min', - 'direction': 'Dong', - 'local_title': 'Chinese' - }, - 'ce': { - 'english_title': 'Chechen', - 'direction': 'ltr', - 'local_title': 'Нохчийн' - }, - 'ceb': { - 'english_title': 'Cebuano', - 'direction': 'ltr', - 'local_title': 'Sinugboanong' - }, - 'ch': { - 'english_title': 'Chamorro', - 'direction': 'ltr', - 'local_title': 'Chamoru' - }, - 'cho': { - 'english_title': 'Choctaw', - 'direction': 'ltr', - 'local_title': 'Choctaw' - }, - 'chr': { - 'english_title': 'Cherokee', - 'direction': 'ltr', - 'local_title': 'ᏣᎳᎩ' - }, - 'chy': { - 'english_title': 'Cheyenne', - 'direction': 'ltr', - 'local_title': 'Tsetsêhestâhese' - }, - 'co': { - 'english_title': 'Corsican', - 'direction': 'ltr', - 'local_title': 'Corsu' - }, - 'cr': { - 'english_title': 'Cree', - 'direction': 'ltr', - 'local_title': 'Nehiyaw' - }, - 'cs': { - 'english_title': 'Czech', - 'direction': 'ltr', - 'local_title': 'Česky' - }, - 'csb': { - 'english_title': 'Kashubian', - 'direction': 'ltr', - 'local_title': 'Kaszëbsczi' - }, - 'cu': { - 'english_title': 'Old', - 'direction': 'Church', - 'local_title': 'Slavonic' - }, - 'cv': { - 'english_title': 'Chuvash', - 'direction': 'ltr', - 'local_title': 'Чăваш' - }, - 'cy': { - 'english_title': 'Welsh', - 'direction': 'ltr', - 'local_title': 'Cymraeg' - }, - 'da': { - 'english_title': 'Danish', - 'direction': 'ltr', - 'local_title': 'Dansk' - }, - 'de': { - 'english_title': 'German', - 'direction': 'ltr', - 'local_title': 'Deutsch' - }, - 'diq': { - 'english_title': 'Dimli', - 'direction': 'ltr', - 'local_title': 'Zazaki' - }, - 'dsb': { - 'english_title': 'Lower', - 'direction': 'Sorbian', - 'local_title': 'ltr' - }, - 'dv': { - 'english_title': 'Divehi', - 'direction': 'rtl', - 'local_title': 'ދިވެހިބަސް' - }, - 'dz': { - 'english_title': 'Dzongkha', - 'direction': 'ltr', - 'local_title': 'ཇོང་ཁ' - }, - 'ee': { - 'english_title': 'Ewe', - 'direction': 'ltr', - 'local_title': 'Ɛʋɛ' - }, - 'far': { - 'english_title': 'Farsi', - 'direction': 'ltr', - 'local_title': 'فارسی' - }, - 'el': { - 'english_title': 'Greek', - 'direction': 'ltr', - 'local_title': 'Ελληνικά' - }, - 'en': { - 'english_title': 'English', - 'direction': 'ltr', - 'local_title': 'English' - }, - 'eo': { - 'english_title': 'Esperanto', - 'direction': 'ltr', - 'local_title': 'Esperanto' - }, - 'es': { - 'english_title': 'Spanish', - 'direction': 'ltr', - 'local_title': 'Español' - }, - 'et': { - 'english_title': 'Estonian', - 'direction': 'ltr', - 'local_title': 'Eesti' - }, - 'eu': { - 'english_title': 'Basque', - 'direction': 'ltr', - 'local_title': 'Euskara' - }, - 'ext': { - 'english_title': 'Extremaduran', - 'direction': 'ltr', - 'local_title': 'Estremeñu' - }, - 'ff': { - 'english_title': 'Peul', - 'direction': 'ltr', - 'local_title': 'Fulfulde' - }, - 'fi': { - 'english_title': 'Finnish', - 'direction': 'ltr', - 'local_title': 'Suomi' + english_title: 'Belarusian', + direction: '(Taraškievica)', + local_title: 'ltr' + }, + bg: { + english_title: 'Bulgarian', + direction: 'ltr', + local_title: 'Български' + }, + bh: { + english_title: 'Bihari', + direction: 'ltr', + local_title: 'भोजपुरी' + }, + bi: { + english_title: 'Bislama', + direction: 'ltr', + local_title: 'Bislama' + }, + bm: { + english_title: 'Bambara', + direction: 'ltr', + local_title: 'Bamanankan' + }, + bn: { + english_title: 'Bengali', + direction: 'ltr', + local_title: 'বাংলা' + }, + bo: { + english_title: 'Tibetan', + direction: 'ltr', + local_title: 'བོད་ཡིག' + }, + bpy: { + english_title: 'Bishnupriya', + direction: 'Manipuri', + local_title: 'ltr' + }, + br: { + english_title: 'Breton', + direction: 'ltr', + local_title: 'Brezhoneg' + }, + bs: { + english_title: 'Bosnian', + direction: 'ltr', + local_title: 'Bosanski' + }, + bug: { + english_title: 'Buginese', + direction: 'ltr', + local_title: 'ᨅᨔ' + }, + bxr: { + english_title: 'Buriat', + direction: '(Russia)', + local_title: 'ltr' + }, + ca: { + english_title: 'Catalan', + direction: 'ltr', + local_title: 'Català' + }, + cdo: { + english_title: 'Min', + direction: 'Dong', + local_title: 'Chinese' + }, + ce: { + english_title: 'Chechen', + direction: 'ltr', + local_title: 'Нохчийн' + }, + ceb: { + english_title: 'Cebuano', + direction: 'ltr', + local_title: 'Sinugboanong' + }, + ch: { + english_title: 'Chamorro', + direction: 'ltr', + local_title: 'Chamoru' + }, + cho: { + english_title: 'Choctaw', + direction: 'ltr', + local_title: 'Choctaw' + }, + chr: { + english_title: 'Cherokee', + direction: 'ltr', + local_title: 'ᏣᎳᎩ' + }, + chy: { + english_title: 'Cheyenne', + direction: 'ltr', + local_title: 'Tsetsêhestâhese' + }, + co: { + english_title: 'Corsican', + direction: 'ltr', + local_title: 'Corsu' + }, + cr: { + english_title: 'Cree', + direction: 'ltr', + local_title: 'Nehiyaw' + }, + cs: { + english_title: 'Czech', + direction: 'ltr', + local_title: 'Česky' + }, + csb: { + english_title: 'Kashubian', + direction: 'ltr', + local_title: 'Kaszëbsczi' + }, + cu: { + english_title: 'Old', + direction: 'Church', + local_title: 'Slavonic' + }, + cv: { + english_title: 'Chuvash', + direction: 'ltr', + local_title: 'Чăваш' + }, + cy: { + english_title: 'Welsh', + direction: 'ltr', + local_title: 'Cymraeg' + }, + da: { + english_title: 'Danish', + direction: 'ltr', + local_title: 'Dansk' + }, + de: { + english_title: 'German', + direction: 'ltr', + local_title: 'Deutsch' + }, + diq: { + english_title: 'Dimli', + direction: 'ltr', + local_title: 'Zazaki' + }, + dsb: { + english_title: 'Lower', + direction: 'Sorbian', + local_title: 'ltr' + }, + dv: { + english_title: 'Divehi', + direction: 'rtl', + local_title: 'ދިވެހިބަސް' + }, + dz: { + english_title: 'Dzongkha', + direction: 'ltr', + local_title: 'ཇོང་ཁ' + }, + ee: { + english_title: 'Ewe', + direction: 'ltr', + local_title: 'Ɛʋɛ' + }, + far: { + english_title: 'Farsi', + direction: 'ltr', + local_title: 'فارسی' + }, + el: { + english_title: 'Greek', + direction: 'ltr', + local_title: 'Ελληνικά' + }, + en: { + english_title: 'English', + direction: 'ltr', + local_title: 'English' + }, + eo: { + english_title: 'Esperanto', + direction: 'ltr', + local_title: 'Esperanto' + }, + es: { + english_title: 'Spanish', + direction: 'ltr', + local_title: 'Español' + }, + et: { + english_title: 'Estonian', + direction: 'ltr', + local_title: 'Eesti' + }, + eu: { + english_title: 'Basque', + direction: 'ltr', + local_title: 'Euskara' + }, + ext: { + english_title: 'Extremaduran', + direction: 'ltr', + local_title: 'Estremeñu' + }, + ff: { + english_title: 'Peul', + direction: 'ltr', + local_title: 'Fulfulde' + }, + fi: { + english_title: 'Finnish', + direction: 'ltr', + local_title: 'Suomi' }, 'fiu-vro': { - 'english_title': 'Võro', - 'direction': 'ltr', - 'local_title': 'Võro' - }, - 'fj': { - 'english_title': 'Fijian', - 'direction': 'ltr', - 'local_title': 'Na' - }, - 'fo': { - 'english_title': 'Faroese', - 'direction': 'ltr', - 'local_title': 'Føroyskt' - }, - 'fr': { - 'english_title': 'French', - 'direction': 'ltr', - 'local_title': 'Français' - }, - 'frp': { - 'english_title': 'Arpitan', - 'direction': 'ltr', - 'local_title': 'Arpitan' - }, - 'fur': { - 'english_title': 'Friulian', - 'direction': 'ltr', - 'local_title': 'Furlan' - }, - 'fy': { - 'english_title': 'West', - 'direction': 'Frisian', - 'local_title': 'ltr' - }, - 'ga': { - 'english_title': 'Irish', - 'direction': 'ltr', - 'local_title': 'Gaeilge' - }, - 'gan': { - 'english_title': 'Gan', - 'direction': 'Chinese', - 'local_title': 'ltr' - }, - 'gd': { - 'english_title': 'Scottish', - 'direction': 'Gaelic', - 'local_title': 'ltr' - }, - 'gil': { - 'english_title': 'Gilbertese', - 'direction': 'ltr', - 'local_title': 'Taetae' - }, - 'gl': { - 'english_title': 'Galician', - 'direction': 'ltr', - 'local_title': 'Galego' - }, - 'gn': { - 'english_title': 'Guarani', - 'direction': 'ltr', - 'local_title': 'Avañe\'ẽ' - }, - 'got': { - 'english_title': 'Gothic', - 'direction': 'ltr', - 'local_title': 'gutisk' - }, - 'gu': { - 'english_title': 'Gujarati', - 'direction': 'ltr', - 'local_title': 'ગુજરાતી' - }, - 'gv': { - 'english_title': 'Manx', - 'direction': 'ltr', - 'local_title': 'Gaelg' - }, - 'ha': { - 'english_title': 'Hausa', - 'direction': 'rtl', - 'local_title': 'هَوُسَ' - }, - 'hak': { - 'english_title': 'Hakka', - 'direction': 'Chinese', - 'local_title': 'ltr' - }, - 'haw': { - 'english_title': 'Hawaiian', - 'direction': 'ltr', - 'local_title': 'Hawai`i' - }, - 'he': { - 'english_title': 'Hebrew', - 'direction': 'rtl', - 'local_title': 'עברית' - }, - 'hi': { - 'english_title': 'Hindi', - 'direction': 'ltr', - 'local_title': 'हिन्दी' - }, - 'ho': { - 'english_title': 'Hiri', - 'direction': 'Motu', - 'local_title': 'ltr' - }, - 'hr': { - 'english_title': 'Croatian', - 'direction': 'ltr', - 'local_title': 'Hrvatski' - }, - 'ht': { - 'english_title': 'Haitian', - 'direction': 'ltr', - 'local_title': 'Krèyol' - }, - 'hu': { - 'english_title': 'Hungarian', - 'direction': 'ltr', - 'local_title': 'Magyar' - }, - 'hy': { - 'english_title': 'Armenian', - 'direction': 'ltr', - 'local_title': 'Հայերեն' - }, - 'hz': { - 'english_title': 'Herero', - 'direction': 'ltr', - 'local_title': 'Otsiherero' - }, - 'ia': { - 'english_title': 'Interlingua', - 'direction': 'ltr', - 'local_title': 'Interlingua' - }, - 'id': { - 'english_title': 'Indonesian', - 'direction': 'ltr', - 'local_title': 'Bahasa' - }, - 'ie': { - 'english_title': 'Interlingue', - 'direction': 'ltr', - 'local_title': 'Interlingue' - }, - 'ig': { - 'english_title': 'Igbo', - 'direction': 'ltr', - 'local_title': 'Igbo' - }, - 'ii': { - 'english_title': 'Sichuan', - 'direction': 'Yi', - 'local_title': 'ltr' - }, - 'ik': { - 'english_title': 'Inupiak', - 'direction': 'ltr', - 'local_title': 'Iñupiak' - }, - 'ilo': { - 'english_title': 'Ilokano', - 'direction': 'ltr', - 'local_title': 'Ilokano' - }, - 'io': { - 'english_title': 'Ido', - 'direction': 'ltr', - 'local_title': 'Ido' - }, - 'is': { - 'english_title': 'Icelandic', - 'direction': 'ltr', - 'local_title': 'Íslenska' - }, - 'it': { - 'english_title': 'Italian', - 'direction': 'ltr', - 'local_title': 'Italiano' - }, - 'iu': { - 'english_title': 'Inuktitut', - 'direction': 'ltr', - 'local_title': 'ᐃᓄᒃᑎᑐᑦ' - }, - 'ja': { - 'english_title': 'Japanese', - 'direction': 'ltr', - 'local_title': '日本語' - }, - 'jbo': { - 'english_title': 'Lojban', - 'direction': 'ltr', - 'local_title': 'Lojban' - }, - 'jv': { - 'english_title': 'Javanese', - 'direction': 'ltr', - 'local_title': 'Basa' - }, - 'ka': { - 'english_title': 'Georgian', - 'direction': 'ltr', - 'local_title': 'ქართული' - }, - 'kg': { - 'english_title': 'Kongo', - 'direction': 'ltr', - 'local_title': 'KiKongo' - }, - 'ki': { - 'english_title': 'Kikuyu', - 'direction': 'ltr', - 'local_title': 'Gĩkũyũ' - }, - 'kj': { - 'english_title': 'Kuanyama', - 'direction': 'ltr', - 'local_title': 'Kuanyama' - }, - 'kk': { - 'english_title': 'Kazakh', - 'direction': 'ltr', - 'local_title': 'Қазақша' - }, - 'kl': { - 'english_title': 'Greenlandic', - 'direction': 'ltr', - 'local_title': 'Kalaallisut' - }, - 'km': { - 'english_title': 'Cambodian', - 'direction': 'ltr', - 'local_title': 'ភាសាខ្មែរ' - }, - 'kn': { - 'english_title': 'Kannada', - 'direction': 'ltr', - 'local_title': 'ಕನ್ನಡ' - }, - 'khw': { - 'english_title': 'Khowar', - 'direction': 'rtl', - 'local_title': 'کھوار' - }, - 'ko': { - 'english_title': 'Korean', - 'direction': 'ltr', - 'local_title': '한국어' - }, - 'kr': { - 'english_title': 'Kanuri', - 'direction': 'ltr', - 'local_title': 'Kanuri' - }, - 'ks': { - 'english_title': 'Kashmiri', - 'direction': 'rtl', - 'local_title': 'कश्मीरी' - }, - 'ksh': { - 'english_title': 'Ripuarian', - 'direction': 'ltr', - 'local_title': 'Ripoarisch' - }, - 'ku': { - 'english_title': 'Kurdish', - 'direction': 'rtl', - 'local_title': 'Kurdî' - }, - 'kv': { - 'english_title': 'Komi', - 'direction': 'ltr', - 'local_title': 'Коми' - }, - 'kw': { - 'english_title': 'Cornish', - 'direction': 'ltr', - 'local_title': 'Kernewek' - }, - 'ky': { - 'english_title': 'Kirghiz', - 'direction': 'ltr', - 'local_title': 'Kırgızca' - }, - 'la': { - 'english_title': 'Latin', - 'direction': 'ltr', - 'local_title': 'Latina' - }, - 'lad': { - 'english_title': 'Ladino', - 'direction': 'ltr', - 'local_title': 'Dzhudezmo' - }, - 'lan': { - 'english_title': 'Lango', - 'direction': 'ltr', - 'local_title': 'Leb' - }, - 'lb': { - 'english_title': 'Luxembourgish', - 'direction': 'ltr', - 'local_title': 'Lëtzebuergesch' - }, - 'lg': { - 'english_title': 'Ganda', - 'direction': 'ltr', - 'local_title': 'Luganda' - }, - 'li': { - 'english_title': 'Limburgian', - 'direction': 'ltr', - 'local_title': 'Limburgs' - }, - 'lij': { - 'english_title': 'Ligurian', - 'direction': 'ltr', - 'local_title': 'Líguru' - }, - 'lmo': { - 'english_title': 'Lombard', - 'direction': 'ltr', - 'local_title': 'Lumbaart' - }, - 'ln': { - 'english_title': 'Lingala', - 'direction': 'ltr', - 'local_title': 'Lingála' - }, - 'lo': { - 'english_title': 'Laotian', - 'direction': 'ltr', - 'local_title': 'ລາວ' - }, - 'lt': { - 'english_title': 'Lithuanian', - 'direction': 'ltr', - 'local_title': 'Lietuvių' - }, - 'lv': { - 'english_title': 'Latvian', - 'direction': 'ltr', - 'local_title': 'Latviešu' + english_title: 'Võro', + direction: 'ltr', + local_title: 'Võro' + }, + fj: { + english_title: 'Fijian', + direction: 'ltr', + local_title: 'Na' + }, + fo: { + english_title: 'Faroese', + direction: 'ltr', + local_title: 'Føroyskt' + }, + fr: { + english_title: 'French', + direction: 'ltr', + local_title: 'Français' + }, + frp: { + english_title: 'Arpitan', + direction: 'ltr', + local_title: 'Arpitan' + }, + fur: { + english_title: 'Friulian', + direction: 'ltr', + local_title: 'Furlan' + }, + fy: { + english_title: 'West', + direction: 'Frisian', + local_title: 'ltr' + }, + ga: { + english_title: 'Irish', + direction: 'ltr', + local_title: 'Gaeilge' + }, + gan: { + english_title: 'Gan', + direction: 'Chinese', + local_title: 'ltr' + }, + gd: { + english_title: 'Scottish', + direction: 'Gaelic', + local_title: 'ltr' + }, + gil: { + english_title: 'Gilbertese', + direction: 'ltr', + local_title: 'Taetae' + }, + gl: { + english_title: 'Galician', + direction: 'ltr', + local_title: 'Galego' + }, + gn: { + english_title: 'Guarani', + direction: 'ltr', + local_title: "Avañe'ẽ" + }, + got: { + english_title: 'Gothic', + direction: 'ltr', + local_title: 'gutisk' + }, + gu: { + english_title: 'Gujarati', + direction: 'ltr', + local_title: 'ગુજરાતી' + }, + gv: { + english_title: 'Manx', + direction: 'ltr', + local_title: 'Gaelg' + }, + ha: { + english_title: 'Hausa', + direction: 'rtl', + local_title: 'هَوُسَ' + }, + hak: { + english_title: 'Hakka', + direction: 'Chinese', + local_title: 'ltr' + }, + haw: { + english_title: 'Hawaiian', + direction: 'ltr', + local_title: 'Hawai`i' + }, + he: { + english_title: 'Hebrew', + direction: 'rtl', + local_title: 'עברית' + }, + hi: { + english_title: 'Hindi', + direction: 'ltr', + local_title: 'हिन्दी' + }, + ho: { + english_title: 'Hiri', + direction: 'Motu', + local_title: 'ltr' + }, + hr: { + english_title: 'Croatian', + direction: 'ltr', + local_title: 'Hrvatski' + }, + ht: { + english_title: 'Haitian', + direction: 'ltr', + local_title: 'Krèyol' + }, + hu: { + english_title: 'Hungarian', + direction: 'ltr', + local_title: 'Magyar' + }, + hy: { + english_title: 'Armenian', + direction: 'ltr', + local_title: 'Հայերեն' + }, + hz: { + english_title: 'Herero', + direction: 'ltr', + local_title: 'Otsiherero' + }, + ia: { + english_title: 'Interlingua', + direction: 'ltr', + local_title: 'Interlingua' + }, + id: { + english_title: 'Indonesian', + direction: 'ltr', + local_title: 'Bahasa' + }, + ie: { + english_title: 'Interlingue', + direction: 'ltr', + local_title: 'Interlingue' + }, + ig: { + english_title: 'Igbo', + direction: 'ltr', + local_title: 'Igbo' + }, + ii: { + english_title: 'Sichuan', + direction: 'Yi', + local_title: 'ltr' + }, + ik: { + english_title: 'Inupiak', + direction: 'ltr', + local_title: 'Iñupiak' + }, + ilo: { + english_title: 'Ilokano', + direction: 'ltr', + local_title: 'Ilokano' + }, + io: { + english_title: 'Ido', + direction: 'ltr', + local_title: 'Ido' + }, + is: { + english_title: 'Icelandic', + direction: 'ltr', + local_title: 'Íslenska' + }, + it: { + english_title: 'Italian', + direction: 'ltr', + local_title: 'Italiano' + }, + iu: { + english_title: 'Inuktitut', + direction: 'ltr', + local_title: 'ᐃᓄᒃᑎᑐᑦ' + }, + ja: { + english_title: 'Japanese', + direction: 'ltr', + local_title: '日本語' + }, + jbo: { + english_title: 'Lojban', + direction: 'ltr', + local_title: 'Lojban' + }, + jv: { + english_title: 'Javanese', + direction: 'ltr', + local_title: 'Basa' + }, + ka: { + english_title: 'Georgian', + direction: 'ltr', + local_title: 'ქართული' + }, + kg: { + english_title: 'Kongo', + direction: 'ltr', + local_title: 'KiKongo' + }, + ki: { + english_title: 'Kikuyu', + direction: 'ltr', + local_title: 'Gĩkũyũ' + }, + kj: { + english_title: 'Kuanyama', + direction: 'ltr', + local_title: 'Kuanyama' + }, + kk: { + english_title: 'Kazakh', + direction: 'ltr', + local_title: 'Қазақша' + }, + kl: { + english_title: 'Greenlandic', + direction: 'ltr', + local_title: 'Kalaallisut' + }, + km: { + english_title: 'Cambodian', + direction: 'ltr', + local_title: 'ភាសាខ្មែរ' + }, + kn: { + english_title: 'Kannada', + direction: 'ltr', + local_title: 'ಕನ್ನಡ' + }, + khw: { + english_title: 'Khowar', + direction: 'rtl', + local_title: 'کھوار' + }, + ko: { + english_title: 'Korean', + direction: 'ltr', + local_title: '한국어' + }, + kr: { + english_title: 'Kanuri', + direction: 'ltr', + local_title: 'Kanuri' + }, + ks: { + english_title: 'Kashmiri', + direction: 'rtl', + local_title: 'कश्मीरी' + }, + ksh: { + english_title: 'Ripuarian', + direction: 'ltr', + local_title: 'Ripoarisch' + }, + ku: { + english_title: 'Kurdish', + direction: 'rtl', + local_title: 'Kurdî' + }, + kv: { + english_title: 'Komi', + direction: 'ltr', + local_title: 'Коми' + }, + kw: { + english_title: 'Cornish', + direction: 'ltr', + local_title: 'Kernewek' + }, + ky: { + english_title: 'Kirghiz', + direction: 'ltr', + local_title: 'Kırgızca' + }, + la: { + english_title: 'Latin', + direction: 'ltr', + local_title: 'Latina' + }, + lad: { + english_title: 'Ladino', + direction: 'ltr', + local_title: 'Dzhudezmo' + }, + lan: { + english_title: 'Lango', + direction: 'ltr', + local_title: 'Leb' + }, + lb: { + english_title: 'Luxembourgish', + direction: 'ltr', + local_title: 'Lëtzebuergesch' + }, + lg: { + english_title: 'Ganda', + direction: 'ltr', + local_title: 'Luganda' + }, + li: { + english_title: 'Limburgian', + direction: 'ltr', + local_title: 'Limburgs' + }, + lij: { + english_title: 'Ligurian', + direction: 'ltr', + local_title: 'Líguru' + }, + lmo: { + english_title: 'Lombard', + direction: 'ltr', + local_title: 'Lumbaart' + }, + ln: { + english_title: 'Lingala', + direction: 'ltr', + local_title: 'Lingála' + }, + lo: { + english_title: 'Laotian', + direction: 'ltr', + local_title: 'ລາວ' + }, + lt: { + english_title: 'Lithuanian', + direction: 'ltr', + local_title: 'Lietuvių' + }, + lv: { + english_title: 'Latvian', + direction: 'ltr', + local_title: 'Latviešu' }, 'map-bms': { - 'english_title': 'Banyumasan', - 'direction': 'ltr', - 'local_title': 'Basa' - }, - 'mg': { - 'english_title': 'Malagasy', - 'direction': 'ltr', - 'local_title': 'Malagasy' - }, - 'man': { - 'english_title': 'Mandarin', - 'direction': 'ltr', - 'local_title': '官話' - }, - 'mh': { - 'english_title': 'Marshallese', - 'direction': 'ltr', - 'local_title': 'Kajin' - }, - 'mi': { - 'english_title': 'Maori', - 'direction': 'ltr', - 'local_title': 'Māori' - }, - 'min': { - 'english_title': 'Minangkabau', - 'direction': 'ltr', - 'local_title': 'Minangkabau' - }, - 'mk': { - 'english_title': 'Macedonian', - 'direction': 'ltr', - 'local_title': 'Македонски' - }, - 'ml': { - 'english_title': 'Malayalam', - 'direction': 'ltr', - 'local_title': 'മലയാളം' - }, - 'mn': { - 'english_title': 'Mongolian', - 'direction': 'ltr', - 'local_title': 'Монгол' - }, - 'mo': { - 'english_title': 'Moldovan', - 'direction': 'ltr', - 'local_title': 'Moldovenească' - }, - 'mr': { - 'english_title': 'Marathi', - 'direction': 'ltr', - 'local_title': 'मराठी' - }, - 'ms': { - 'english_title': 'Malay', - 'direction': 'ltr', - 'local_title': 'Bahasa' - }, - 'mt': { - 'english_title': 'Maltese', - 'direction': 'ltr', - 'local_title': 'bil-Malti' - }, - 'mus': { - 'english_title': 'Creek', - 'direction': 'ltr', - 'local_title': 'Muskogee' - }, - 'my': { - 'english_title': 'Burmese', - 'direction': 'ltr', - 'local_title': 'Myanmasa' - }, - 'na': { - 'english_title': 'Nauruan', - 'direction': 'ltr', - 'local_title': 'Dorerin' - }, - 'nah': { - 'english_title': 'Nahuatl', - 'direction': 'ltr', - 'local_title': 'Nahuatl' - }, - 'nap': { - 'english_title': 'Neapolitan', - 'direction': 'ltr', - 'local_title': 'Nnapulitano' - }, - 'nd': { - 'english_title': 'North', - 'direction': 'Ndebele', - 'local_title': 'ltr' - }, - 'nds': { - 'english_title': 'Low German', - 'direction': 'ltr', - 'local_title': 'Plattdüütsch' + english_title: 'Banyumasan', + direction: 'ltr', + local_title: 'Basa' + }, + mg: { + english_title: 'Malagasy', + direction: 'ltr', + local_title: 'Malagasy' + }, + man: { + english_title: 'Mandarin', + direction: 'ltr', + local_title: '官話' + }, + mh: { + english_title: 'Marshallese', + direction: 'ltr', + local_title: 'Kajin' + }, + mi: { + english_title: 'Maori', + direction: 'ltr', + local_title: 'Māori' + }, + min: { + english_title: 'Minangkabau', + direction: 'ltr', + local_title: 'Minangkabau' + }, + mk: { + english_title: 'Macedonian', + direction: 'ltr', + local_title: 'Македонски' + }, + ml: { + english_title: 'Malayalam', + direction: 'ltr', + local_title: 'മലയാളം' + }, + mn: { + english_title: 'Mongolian', + direction: 'ltr', + local_title: 'Монгол' + }, + mo: { + english_title: 'Moldovan', + direction: 'ltr', + local_title: 'Moldovenească' + }, + mr: { + english_title: 'Marathi', + direction: 'ltr', + local_title: 'मराठी' + }, + ms: { + english_title: 'Malay', + direction: 'ltr', + local_title: 'Bahasa' + }, + mt: { + english_title: 'Maltese', + direction: 'ltr', + local_title: 'bil-Malti' + }, + mus: { + english_title: 'Creek', + direction: 'ltr', + local_title: 'Muskogee' + }, + my: { + english_title: 'Burmese', + direction: 'ltr', + local_title: 'Myanmasa' + }, + na: { + english_title: 'Nauruan', + direction: 'ltr', + local_title: 'Dorerin' + }, + nah: { + english_title: 'Nahuatl', + direction: 'ltr', + local_title: 'Nahuatl' + }, + nap: { + english_title: 'Neapolitan', + direction: 'ltr', + local_title: 'Nnapulitano' + }, + nd: { + english_title: 'North', + direction: 'Ndebele', + local_title: 'ltr' + }, + nds: { + english_title: 'Low German', + direction: 'ltr', + local_title: 'Plattdüütsch' }, 'nds-nl': { - 'english_title': 'Dutch', - 'direction': 'Low', - 'local_title': 'Saxon' - }, - 'ne': { - 'english_title': 'Nepali', - 'direction': 'ltr', - 'local_title': 'नेपाली' - }, - 'new': { - 'english_title': 'Newar', - 'direction': 'ltr', - 'local_title': 'नेपालभाषा' - }, - 'ng': { - 'english_title': 'Ndonga', - 'direction': 'ltr', - 'local_title': 'Oshiwambo' - }, - 'nl': { - 'english_title': 'Dutch', - 'direction': 'ltr', - 'local_title': 'Nederlands' - }, - 'nn': { - 'english_title': 'Norwegian', - 'direction': 'Nynorsk', - 'local_title': 'ltr' - }, - 'no': { - 'english_title': 'Norwegian', - 'direction': 'ltr', - 'local_title': 'Norsk' - }, - 'nr': { - 'english_title': 'South', - 'direction': 'Ndebele', - 'local_title': 'ltr' - }, - 'nso': { - 'english_title': 'Northern', - 'direction': 'Sotho', - 'local_title': 'ltr' - }, - 'nrm': { - 'english_title': 'Norman', - 'direction': 'ltr', - 'local_title': 'Nouormand' - }, - 'nv': { - 'english_title': 'Navajo', - 'direction': 'ltr', - 'local_title': 'Diné' - }, - 'ny': { - 'english_title': 'Chichewa', - 'direction': 'ltr', - 'local_title': 'Chi-Chewa' - }, - 'oc': { - 'english_title': 'Occitan', - 'direction': 'ltr', - 'local_title': 'Occitan' - }, - 'oj': { - 'english_title': 'Ojibwa', - 'direction': 'ltr', - 'local_title': 'ᐊᓂᔑᓈᐯᒧᐎᓐ' - }, - 'om': { - 'english_title': 'Oromo', - 'direction': 'ltr', - 'local_title': 'Oromoo' - }, - 'or': { - 'english_title': 'Oriya', - 'direction': 'ltr', - 'local_title': 'ଓଡ଼ିଆ' - }, - 'os': { - 'english_title': 'Ossetian', - 'direction': 'ltr', - 'local_title': 'Иронау' - }, - 'pa': { - 'english_title': 'Panjabi', - 'direction': 'ltr', - 'local_title': 'ਪੰਜਾਬੀ' - }, - 'pag': { - 'english_title': 'Pangasinan', - 'direction': 'ltr', - 'local_title': 'Pangasinan' - }, - 'pam': { - 'english_title': 'Kapampangan', - 'direction': 'ltr', - 'local_title': 'Kapampangan' - }, - 'pap': { - 'english_title': 'Papiamentu', - 'direction': 'ltr', - 'local_title': 'Papiamentu' - }, - 'pdc': { - 'english_title': 'Pennsylvania', - 'direction': 'German', - 'local_title': 'ltr' - }, - 'pi': { - 'english_title': 'Pali', - 'direction': 'ltr', - 'local_title': 'Pāli' - }, - 'pih': { - 'english_title': 'Norfolk', - 'direction': 'ltr', - 'local_title': 'Norfuk' - }, - 'pl': { - 'english_title': 'Polish', - 'direction': 'ltr', - 'local_title': 'Polski' - }, - 'pms': { - 'english_title': 'Piedmontese', - 'direction': 'ltr', - 'local_title': 'Piemontèis' - }, - 'ps': { - 'english_title': 'Pashto', - 'direction': 'rtl', - 'local_title': 'پښتو' - }, - 'pt': { - 'english_title': 'Portuguese', - 'direction': 'ltr', - 'local_title': 'Português' - }, - 'qu': { - 'english_title': 'Quechua', - 'direction': 'ltr', - 'local_title': 'Runa' - }, - 'rm': { - 'english_title': 'Raeto', - 'direction': 'Romance', - 'local_title': 'ltr' - }, - 'rmy': { - 'english_title': 'Romani', - 'direction': 'ltr', - 'local_title': 'Romani' - }, - 'rn': { - 'english_title': 'Kirundi', - 'direction': 'ltr', - 'local_title': 'Kirundi' - }, - 'ro': { - 'english_title': 'Romanian', - 'direction': 'ltr', - 'local_title': 'Română' + english_title: 'Dutch', + direction: 'Low', + local_title: 'Saxon' + }, + ne: { + english_title: 'Nepali', + direction: 'ltr', + local_title: 'नेपाली' + }, + new: { + english_title: 'Newar', + direction: 'ltr', + local_title: 'नेपालभाषा' + }, + ng: { + english_title: 'Ndonga', + direction: 'ltr', + local_title: 'Oshiwambo' + }, + nl: { + english_title: 'Dutch', + direction: 'ltr', + local_title: 'Nederlands' + }, + nn: { + english_title: 'Norwegian', + direction: 'Nynorsk', + local_title: 'ltr' + }, + no: { + english_title: 'Norwegian', + direction: 'ltr', + local_title: 'Norsk' + }, + nr: { + english_title: 'South', + direction: 'Ndebele', + local_title: 'ltr' + }, + nso: { + english_title: 'Northern', + direction: 'Sotho', + local_title: 'ltr' + }, + nrm: { + english_title: 'Norman', + direction: 'ltr', + local_title: 'Nouormand' + }, + nv: { + english_title: 'Navajo', + direction: 'ltr', + local_title: 'Diné' + }, + ny: { + english_title: 'Chichewa', + direction: 'ltr', + local_title: 'Chi-Chewa' + }, + oc: { + english_title: 'Occitan', + direction: 'ltr', + local_title: 'Occitan' + }, + oj: { + english_title: 'Ojibwa', + direction: 'ltr', + local_title: 'ᐊᓂᔑᓈᐯᒧᐎᓐ' + }, + om: { + english_title: 'Oromo', + direction: 'ltr', + local_title: 'Oromoo' + }, + or: { + english_title: 'Oriya', + direction: 'ltr', + local_title: 'ଓଡ଼ିଆ' + }, + os: { + english_title: 'Ossetian', + direction: 'ltr', + local_title: 'Иронау' + }, + pa: { + english_title: 'Panjabi', + direction: 'ltr', + local_title: 'ਪੰਜਾਬੀ' + }, + pag: { + english_title: 'Pangasinan', + direction: 'ltr', + local_title: 'Pangasinan' + }, + pam: { + english_title: 'Kapampangan', + direction: 'ltr', + local_title: 'Kapampangan' + }, + pap: { + english_title: 'Papiamentu', + direction: 'ltr', + local_title: 'Papiamentu' + }, + pdc: { + english_title: 'Pennsylvania', + direction: 'German', + local_title: 'ltr' + }, + pi: { + english_title: 'Pali', + direction: 'ltr', + local_title: 'Pāli' + }, + pih: { + english_title: 'Norfolk', + direction: 'ltr', + local_title: 'Norfuk' + }, + pl: { + english_title: 'Polish', + direction: 'ltr', + local_title: 'Polski' + }, + pms: { + english_title: 'Piedmontese', + direction: 'ltr', + local_title: 'Piemontèis' + }, + ps: { + english_title: 'Pashto', + direction: 'rtl', + local_title: 'پښتو' + }, + pt: { + english_title: 'Portuguese', + direction: 'ltr', + local_title: 'Português' + }, + qu: { + english_title: 'Quechua', + direction: 'ltr', + local_title: 'Runa' + }, + rm: { + english_title: 'Raeto', + direction: 'Romance', + local_title: 'ltr' + }, + rmy: { + english_title: 'Romani', + direction: 'ltr', + local_title: 'Romani' + }, + rn: { + english_title: 'Kirundi', + direction: 'ltr', + local_title: 'Kirundi' + }, + ro: { + english_title: 'Romanian', + direction: 'ltr', + local_title: 'Română' }, 'roa-rup': { - 'english_title': 'Aromanian', - 'direction': 'ltr', - 'local_title': 'Armâneashti' - }, - 'ru': { - 'english_title': 'Russian', - 'direction': 'ltr', - 'local_title': 'Русский' - }, - 'rw': { - 'english_title': 'Rwandi', - 'direction': 'ltr', - 'local_title': 'Kinyarwandi' - }, - 'sa': { - 'english_title': 'Sanskrit', - 'direction': 'ltr', - 'local_title': 'संस्कृतम्' - }, - 'sc': { - 'english_title': 'Sardinian', - 'direction': 'ltr', - 'local_title': 'Sardu' - }, - 'scn': { - 'english_title': 'Sicilian', - 'direction': 'ltr', - 'local_title': 'Sicilianu' - }, - 'sco': { - 'english_title': 'Scots', - 'direction': 'ltr', - 'local_title': 'Scots' - }, - 'sd': { - 'english_title': 'Sindhi', - 'direction': 'ltr', - 'local_title': 'सिनधि' - }, - 'se': { - 'english_title': 'Northern', - 'direction': 'Sami', - 'local_title': 'ltr' - }, - 'sg': { - 'english_title': 'Sango', - 'direction': 'ltr', - 'local_title': 'Sängö' - }, - 'sh': { - 'english_title': 'Serbo-Croatian', - 'direction': 'ltr', - 'local_title': 'Srpskohrvatski' - }, - 'si': { - 'english_title': 'Sinhalese', - 'direction': 'ltr', - 'local_title': 'සිංහල' - }, - 'simple': { - 'english_title': 'Simple', - 'direction': 'English', - 'local_title': 'ltr' - }, - 'sk': { - 'english_title': 'Slovak', - 'direction': 'ltr', - 'local_title': 'Slovenčina' - }, - 'sl': { - 'english_title': 'Slovenian', - 'direction': 'ltr', - 'local_title': 'Slovenščina' - }, - 'sm': { - 'english_title': 'Samoan', - 'direction': 'ltr', - 'local_title': 'Gagana' - }, - 'sn': { - 'english_title': 'Shona', - 'direction': 'ltr', - 'local_title': 'chiShona' - }, - 'so': { - 'english_title': 'Somalia', - 'direction': 'ltr', - 'local_title': 'Soomaaliga' - }, - 'sq': { - 'english_title': 'Albanian', - 'direction': 'ltr', - 'local_title': 'Shqip' - }, - 'sr': { - 'english_title': 'Serbian', - 'direction': 'ltr', - 'local_title': 'Српски' - }, - 'ss': { - 'english_title': 'Swati', - 'direction': 'ltr', - 'local_title': 'SiSwati' - }, - 'st': { - 'english_title': 'Southern', - 'direction': 'Sotho', - 'local_title': 'ltr' - }, - 'su': { - 'english_title': 'Sundanese', - 'direction': 'ltr', - 'local_title': 'Basa' - }, - 'sv': { - 'english_title': 'Swedish', - 'direction': 'ltr', - 'local_title': 'Svenska' - }, - 'sw': { - 'english_title': 'Swahili', - 'direction': 'ltr', - 'local_title': 'Kiswahili' - }, - 'ta': { - 'english_title': 'Tamil', - 'direction': 'ltr', - 'local_title': 'தமிழ்' - }, - 'te': { - 'english_title': 'Telugu', - 'direction': 'ltr', - 'local_title': 'తెలుగు' - }, - 'tet': { - 'english_title': 'Tetum', - 'direction': 'ltr', - 'local_title': 'Tetun' - }, - 'tg': { - 'english_title': 'Tajik', - 'direction': 'ltr', - 'local_title': 'Тоҷикӣ' - }, - 'th': { - 'english_title': 'Thai', - 'direction': 'ltr', - 'local_title': 'ไทย' - }, - 'ti': { - 'english_title': 'Tigrinya', - 'direction': 'ltr', - 'local_title': 'ትግርኛ' - }, - 'tk': { - 'english_title': 'Turkmen', - 'direction': 'ltr', - 'local_title': 'Туркмен' - }, - 'tl': { - 'english_title': 'Tagalog', - 'direction': 'ltr', - 'local_title': 'Tagalog' - }, - 'tlh': { - 'english_title': 'Klingon', - 'direction': 'ltr', - 'local_title': 'tlhIngan-Hol' - }, - 'tn': { - 'english_title': 'Tswana', - 'direction': 'ltr', - 'local_title': 'Setswana' - }, - 'to': { - 'english_title': 'Tonga', - 'direction': 'ltr', - 'local_title': 'Lea' - }, - 'tpi': { - 'english_title': 'Tok', - 'direction': 'Pisin', - 'local_title': 'ltr' - }, - 'tr': { - 'english_title': 'Turkish', - 'direction': 'ltr', - 'local_title': 'Türkçe' - }, - 'ts': { - 'english_title': 'Tsonga', - 'direction': 'ltr', - 'local_title': 'Xitsonga' - }, - 'tt': { - 'english_title': 'Tatar', - 'direction': 'ltr', - 'local_title': 'Tatarça' - }, - 'tum': { - 'english_title': 'Tumbuka', - 'direction': 'ltr', - 'local_title': 'chiTumbuka' - }, - 'tw': { - 'english_title': 'Twi', - 'direction': 'ltr', - 'local_title': 'Twi' - }, - 'ty': { - 'english_title': 'Tahitian', - 'direction': 'ltr', - 'local_title': 'Reo' - }, - 'udm': { - 'english_title': 'Udmurt', - 'direction': 'ltr', - 'local_title': 'Удмурт' - }, - 'ug': { - 'english_title': 'Uyghur', - 'direction': 'ltr', - 'local_title': 'Uyƣurqə' - }, - 'uk': { - 'english_title': 'Ukrainian', - 'direction': 'ltr', - 'local_title': 'Українська' - }, - 'ur': { - 'english_title': 'Urdu', - 'direction': 'rtl', - 'local_title': 'اردو' - }, - 'uz': { - 'english_title': 'Uzbek', - 'direction': 'ltr', - 'local_title': 'Ўзбек' - }, - 've': { - 'english_title': 'Venda', - 'direction': 'ltr', - 'local_title': 'Tshivenḓa' - }, - 'vi': { - 'english_title': 'Vietnamese', - 'direction': 'ltr', - 'local_title': 'Việtnam' - }, - 'vec': { - 'english_title': 'Venetian', - 'direction': 'ltr', - 'local_title': 'Vèneto' - }, - 'vls': { - 'english_title': 'West', - 'direction': 'Flemish', - 'local_title': 'ltr' - }, - 'vo': { - 'english_title': 'Volapük', - 'direction': 'ltr', - 'local_title': 'Volapük' - }, - 'wa': { - 'english_title': 'Walloon', - 'direction': 'ltr', - 'local_title': 'Walon' - }, - 'war': { - 'english_title': 'Waray-Waray', - 'direction': 'ltr', - 'local_title': 'Winaray' - }, - 'wo': { - 'english_title': 'Wolof', - 'direction': 'ltr', - 'local_title': 'Wollof' - }, - 'xal': { - 'english_title': 'Kalmyk', - 'direction': 'ltr', - 'local_title': 'Хальмг' - }, - 'xh': { - 'english_title': 'Xhosa', - 'direction': 'ltr', - 'local_title': 'isiXhosa' - }, - 'yi': { - 'english_title': 'Yiddish', - 'direction': 'rtl', - 'local_title': 'ייִדיש' - }, - 'yo': { - 'english_title': 'Yoruba', - 'direction': 'ltr', - 'local_title': 'Yorùbá' - }, - 'za': { - 'english_title': 'Zhuang', - 'direction': 'ltr', - 'local_title': 'Cuengh' - }, - 'zh': { - 'english_title': 'Chinese', - 'direction': 'ltr', - 'local_title': '中文' + english_title: 'Aromanian', + direction: 'ltr', + local_title: 'Armâneashti' + }, + ru: { + english_title: 'Russian', + direction: 'ltr', + local_title: 'Русский' + }, + rw: { + english_title: 'Rwandi', + direction: 'ltr', + local_title: 'Kinyarwandi' + }, + sa: { + english_title: 'Sanskrit', + direction: 'ltr', + local_title: 'संस्कृतम्' + }, + sc: { + english_title: 'Sardinian', + direction: 'ltr', + local_title: 'Sardu' + }, + scn: { + english_title: 'Sicilian', + direction: 'ltr', + local_title: 'Sicilianu' + }, + sco: { + english_title: 'Scots', + direction: 'ltr', + local_title: 'Scots' + }, + sd: { + english_title: 'Sindhi', + direction: 'ltr', + local_title: 'सिनधि' + }, + se: { + english_title: 'Northern', + direction: 'Sami', + local_title: 'ltr' + }, + sg: { + english_title: 'Sango', + direction: 'ltr', + local_title: 'Sängö' + }, + sh: { + english_title: 'Serbo-Croatian', + direction: 'ltr', + local_title: 'Srpskohrvatski' + }, + si: { + english_title: 'Sinhalese', + direction: 'ltr', + local_title: 'සිංහල' + }, + simple: { + english_title: 'Simple', + direction: 'English', + local_title: 'ltr' + }, + sk: { + english_title: 'Slovak', + direction: 'ltr', + local_title: 'Slovenčina' + }, + sl: { + english_title: 'Slovenian', + direction: 'ltr', + local_title: 'Slovenščina' + }, + sm: { + english_title: 'Samoan', + direction: 'ltr', + local_title: 'Gagana' + }, + sn: { + english_title: 'Shona', + direction: 'ltr', + local_title: 'chiShona' + }, + so: { + english_title: 'Somalia', + direction: 'ltr', + local_title: 'Soomaaliga' + }, + sq: { + english_title: 'Albanian', + direction: 'ltr', + local_title: 'Shqip' + }, + sr: { + english_title: 'Serbian', + direction: 'ltr', + local_title: 'Српски' + }, + ss: { + english_title: 'Swati', + direction: 'ltr', + local_title: 'SiSwati' + }, + st: { + english_title: 'Southern', + direction: 'Sotho', + local_title: 'ltr' + }, + su: { + english_title: 'Sundanese', + direction: 'ltr', + local_title: 'Basa' + }, + sv: { + english_title: 'Swedish', + direction: 'ltr', + local_title: 'Svenska' + }, + sw: { + english_title: 'Swahili', + direction: 'ltr', + local_title: 'Kiswahili' + }, + ta: { + english_title: 'Tamil', + direction: 'ltr', + local_title: 'தமிழ்' + }, + te: { + english_title: 'Telugu', + direction: 'ltr', + local_title: 'తెలుగు' + }, + tet: { + english_title: 'Tetum', + direction: 'ltr', + local_title: 'Tetun' + }, + tg: { + english_title: 'Tajik', + direction: 'ltr', + local_title: 'Тоҷикӣ' + }, + th: { + english_title: 'Thai', + direction: 'ltr', + local_title: 'ไทย' + }, + ti: { + english_title: 'Tigrinya', + direction: 'ltr', + local_title: 'ትግርኛ' + }, + tk: { + english_title: 'Turkmen', + direction: 'ltr', + local_title: 'Туркмен' + }, + tl: { + english_title: 'Tagalog', + direction: 'ltr', + local_title: 'Tagalog' + }, + tlh: { + english_title: 'Klingon', + direction: 'ltr', + local_title: 'tlhIngan-Hol' + }, + tn: { + english_title: 'Tswana', + direction: 'ltr', + local_title: 'Setswana' + }, + to: { + english_title: 'Tonga', + direction: 'ltr', + local_title: 'Lea' + }, + tpi: { + english_title: 'Tok', + direction: 'Pisin', + local_title: 'ltr' + }, + tr: { + english_title: 'Turkish', + direction: 'ltr', + local_title: 'Türkçe' + }, + ts: { + english_title: 'Tsonga', + direction: 'ltr', + local_title: 'Xitsonga' + }, + tt: { + english_title: 'Tatar', + direction: 'ltr', + local_title: 'Tatarça' + }, + tum: { + english_title: 'Tumbuka', + direction: 'ltr', + local_title: 'chiTumbuka' + }, + tw: { + english_title: 'Twi', + direction: 'ltr', + local_title: 'Twi' + }, + ty: { + english_title: 'Tahitian', + direction: 'ltr', + local_title: 'Reo' + }, + udm: { + english_title: 'Udmurt', + direction: 'ltr', + local_title: 'Удмурт' + }, + ug: { + english_title: 'Uyghur', + direction: 'ltr', + local_title: 'Uyƣurqə' + }, + uk: { + english_title: 'Ukrainian', + direction: 'ltr', + local_title: 'Українська' + }, + ur: { + english_title: 'Urdu', + direction: 'rtl', + local_title: 'اردو' + }, + uz: { + english_title: 'Uzbek', + direction: 'ltr', + local_title: 'Ўзбек' + }, + ve: { + english_title: 'Venda', + direction: 'ltr', + local_title: 'Tshivenḓa' + }, + vi: { + english_title: 'Vietnamese', + direction: 'ltr', + local_title: 'Việtnam' + }, + vec: { + english_title: 'Venetian', + direction: 'ltr', + local_title: 'Vèneto' + }, + vls: { + english_title: 'West', + direction: 'Flemish', + local_title: 'ltr' + }, + vo: { + english_title: 'Volapük', + direction: 'ltr', + local_title: 'Volapük' + }, + wa: { + english_title: 'Walloon', + direction: 'ltr', + local_title: 'Walon' + }, + war: { + english_title: 'Waray-Waray', + direction: 'ltr', + local_title: 'Winaray' + }, + wo: { + english_title: 'Wolof', + direction: 'ltr', + local_title: 'Wollof' + }, + xal: { + english_title: 'Kalmyk', + direction: 'ltr', + local_title: 'Хальмг' + }, + xh: { + english_title: 'Xhosa', + direction: 'ltr', + local_title: 'isiXhosa' + }, + yi: { + english_title: 'Yiddish', + direction: 'rtl', + local_title: 'ייִדיש' + }, + yo: { + english_title: 'Yoruba', + direction: 'ltr', + local_title: 'Yorùbá' + }, + za: { + english_title: 'Zhuang', + direction: 'ltr', + local_title: 'Cuengh' + }, + zh: { + english_title: 'Chinese', + direction: 'ltr', + local_title: '中文' }, 'zh-classical': { - 'english_title': 'Classical', - 'direction': 'Chinese', - 'local_title': 'ltr' + english_title: 'Classical', + direction: 'Chinese', + local_title: 'ltr' }, 'zh-min-nan': { - 'english_title': 'Minnan', - 'direction': 'ltr', - 'local_title': 'Bân-lâm-gú' + english_title: 'Minnan', + direction: 'ltr', + local_title: 'Bân-lâm-gú' }, 'zh-yue': { - 'english_title': 'Cantonese', - 'direction': 'ltr', - 'local_title': '粵語' - }, - 'zu': { - 'english_title': 'Zulu', - 'direction': 'ltr', - 'local_title': 'isiZulu' + english_title: 'Cantonese', + direction: 'ltr', + local_title: '粵語' + }, + zu: { + english_title: 'Zulu', + direction: 'ltr', + local_title: 'isiZulu' } }; diff --git a/src/data/site_map.js b/src/data/site_map.js index a9cc3167..64066ed9 100644 --- a/src/data/site_map.js +++ b/src/data/site_map.js @@ -1,805 +1,805 @@ //from https://en.wikipedia.org/w/api.php?action=sitematrix&format=json -var site_map = { - 'aawiki': 'https://aa.wikipedia.org', - 'aawiktionary': 'https://aa.wiktionary.org', - 'aawikibooks': 'https://aa.wikibooks.org', - 'abwiki': 'https://ab.wikipedia.org', - 'abwiktionary': 'https://ab.wiktionary.org', - 'acewiki': 'https://ace.wikipedia.org', - 'afwiki': 'https://af.wikipedia.org', - 'afwiktionary': 'https://af.wiktionary.org', - 'afwikibooks': 'https://af.wikibooks.org', - 'afwikiquote': 'https://af.wikiquote.org', - 'akwiki': 'https://ak.wikipedia.org', - 'akwiktionary': 'https://ak.wiktionary.org', - 'akwikibooks': 'https://ak.wikibooks.org', - 'alswiki': 'https://als.wikipedia.org', - 'alswiktionary': 'https://als.wiktionary.org', - 'alswikibooks': 'https://als.wikibooks.org', - 'alswikiquote': 'https://als.wikiquote.org', - 'amwiki': 'https://am.wikipedia.org', - 'amwiktionary': 'https://am.wiktionary.org', - 'amwikiquote': 'https://am.wikiquote.org', - 'anwiki': 'https://an.wikipedia.org', - 'anwiktionary': 'https://an.wiktionary.org', - 'angwiki': 'https://ang.wikipedia.org', - 'angwiktionary': 'https://ang.wiktionary.org', - 'angwikibooks': 'https://ang.wikibooks.org', - 'angwikiquote': 'https://ang.wikiquote.org', - 'angwikisource': 'https://ang.wikisource.org', - 'arwiki': 'https://ar.wikipedia.org', - 'arwiktionary': 'https://ar.wiktionary.org', - 'arwikibooks': 'https://ar.wikibooks.org', - 'arwikinews': 'https://ar.wikinews.org', - 'arwikiquote': 'https://ar.wikiquote.org', - 'arwikisource': 'https://ar.wikisource.org', - 'arwikiversity': 'https://ar.wikiversity.org', - 'arcwiki': 'https://arc.wikipedia.org', - 'arzwiki': 'https://arz.wikipedia.org', - 'aswiki': 'https://as.wikipedia.org', - 'aswiktionary': 'https://as.wiktionary.org', - 'aswikibooks': 'https://as.wikibooks.org', - 'aswikisource': 'https://as.wikisource.org', - 'astwiki': 'https://ast.wikipedia.org', - 'astwiktionary': 'https://ast.wiktionary.org', - 'astwikibooks': 'https://ast.wikibooks.org', - 'astwikiquote': 'https://ast.wikiquote.org', - 'avwiki': 'https://av.wikipedia.org', - 'avwiktionary': 'https://av.wiktionary.org', - 'aywiki': 'https://ay.wikipedia.org', - 'aywiktionary': 'https://ay.wiktionary.org', - 'aywikibooks': 'https://ay.wikibooks.org', - 'azwiki': 'https://az.wikipedia.org', - 'azwiktionary': 'https://az.wiktionary.org', - 'azwikibooks': 'https://az.wikibooks.org', - 'azwikiquote': 'https://az.wikiquote.org', - 'azwikisource': 'https://az.wikisource.org', - 'bawiki': 'https://ba.wikipedia.org', - 'bawikibooks': 'https://ba.wikibooks.org', - 'barwiki': 'https://bar.wikipedia.org', - 'bat_smgwiki': 'https://bat-smg.wikipedia.org', - 'bclwiki': 'https://bcl.wikipedia.org', - 'bewiki': 'https://be.wikipedia.org', - 'bewiktionary': 'https://be.wiktionary.org', - 'bewikibooks': 'https://be.wikibooks.org', - 'bewikiquote': 'https://be.wikiquote.org', - 'bewikisource': 'https://be.wikisource.org', - 'be_x_oldwiki': 'https://be-x-old.wikipedia.org', - 'bgwiki': 'https://bg.wikipedia.org', - 'bgwiktionary': 'https://bg.wiktionary.org', - 'bgwikibooks': 'https://bg.wikibooks.org', - 'bgwikinews': 'https://bg.wikinews.org', - 'bgwikiquote': 'https://bg.wikiquote.org', - 'bgwikisource': 'https://bg.wikisource.org', - 'bhwiki': 'https://bh.wikipedia.org', - 'bhwiktionary': 'https://bh.wiktionary.org', - 'biwiki': 'https://bi.wikipedia.org', - 'biwiktionary': 'https://bi.wiktionary.org', - 'biwikibooks': 'https://bi.wikibooks.org', - 'bjnwiki': 'https://bjn.wikipedia.org', - 'bmwiki': 'https://bm.wikipedia.org', - 'bmwiktionary': 'https://bm.wiktionary.org', - 'bmwikibooks': 'https://bm.wikibooks.org', - 'bmwikiquote': 'https://bm.wikiquote.org', - 'bnwiki': 'https://bn.wikipedia.org', - 'bnwiktionary': 'https://bn.wiktionary.org', - 'bnwikibooks': 'https://bn.wikibooks.org', - 'bnwikisource': 'https://bn.wikisource.org', - 'bowiki': 'https://bo.wikipedia.org', - 'bowiktionary': 'https://bo.wiktionary.org', - 'bowikibooks': 'https://bo.wikibooks.org', - 'bpywiki': 'https://bpy.wikipedia.org', - 'brwiki': 'https://br.wikipedia.org', - 'brwiktionary': 'https://br.wiktionary.org', - 'brwikiquote': 'https://br.wikiquote.org', - 'brwikisource': 'https://br.wikisource.org', - 'bswiki': 'https://bs.wikipedia.org', - 'bswiktionary': 'https://bs.wiktionary.org', - 'bswikibooks': 'https://bs.wikibooks.org', - 'bswikinews': 'https://bs.wikinews.org', - 'bswikiquote': 'https://bs.wikiquote.org', - 'bswikisource': 'https://bs.wikisource.org', - 'bugwiki': 'https://bug.wikipedia.org', - 'bxrwiki': 'https://bxr.wikipedia.org', - 'cawiki': 'https://ca.wikipedia.org', - 'cawiktionary': 'https://ca.wiktionary.org', - 'cawikibooks': 'https://ca.wikibooks.org', - 'cawikinews': 'https://ca.wikinews.org', - 'cawikiquote': 'https://ca.wikiquote.org', - 'cawikisource': 'https://ca.wikisource.org', - 'cbk_zamwiki': 'https://cbk-zam.wikipedia.org', - 'cdowiki': 'https://cdo.wikipedia.org', - 'cewiki': 'https://ce.wikipedia.org', - 'cebwiki': 'https://ceb.wikipedia.org', - 'chwiki': 'https://ch.wikipedia.org', - 'chwiktionary': 'https://ch.wiktionary.org', - 'chwikibooks': 'https://ch.wikibooks.org', - 'chowiki': 'https://cho.wikipedia.org', - 'chrwiki': 'https://chr.wikipedia.org', - 'chrwiktionary': 'https://chr.wiktionary.org', - 'chywiki': 'https://chy.wikipedia.org', - 'ckbwiki': 'https://ckb.wikipedia.org', - 'cowiki': 'https://co.wikipedia.org', - 'cowiktionary': 'https://co.wiktionary.org', - 'cowikibooks': 'https://co.wikibooks.org', - 'cowikiquote': 'https://co.wikiquote.org', - 'crwiki': 'https://cr.wikipedia.org', - 'crwiktionary': 'https://cr.wiktionary.org', - 'crwikiquote': 'https://cr.wikiquote.org', - 'crhwiki': 'https://crh.wikipedia.org', - 'cswiki': 'https://cs.wikipedia.org', - 'cswiktionary': 'https://cs.wiktionary.org', - 'cswikibooks': 'https://cs.wikibooks.org', - 'cswikinews': 'https://cs.wikinews.org', - 'cswikiquote': 'https://cs.wikiquote.org', - 'cswikisource': 'https://cs.wikisource.org', - 'cswikiversity': 'https://cs.wikiversity.org', - 'csbwiki': 'https://csb.wikipedia.org', - 'csbwiktionary': 'https://csb.wiktionary.org', - 'cuwiki': 'https://cu.wikipedia.org', - 'cvwiki': 'https://cv.wikipedia.org', - 'cvwikibooks': 'https://cv.wikibooks.org', - 'cywiki': 'https://cy.wikipedia.org', - 'cywiktionary': 'https://cy.wiktionary.org', - 'cywikibooks': 'https://cy.wikibooks.org', - 'cywikiquote': 'https://cy.wikiquote.org', - 'cywikisource': 'https://cy.wikisource.org', - 'dawiki': 'https://da.wikipedia.org', - 'dawiktionary': 'https://da.wiktionary.org', - 'dawikibooks': 'https://da.wikibooks.org', - 'dawikiquote': 'https://da.wikiquote.org', - 'dawikisource': 'https://da.wikisource.org', - 'dewiki': 'https://de.wikipedia.org', - 'dewiktionary': 'https://de.wiktionary.org', - 'dewikibooks': 'https://de.wikibooks.org', - 'dewikinews': 'https://de.wikinews.org', - 'dewikiquote': 'https://de.wikiquote.org', - 'dewikisource': 'https://de.wikisource.org', - 'dewikiversity': 'https://de.wikiversity.org', - 'dewikivoyage': 'https://de.wikivoyage.org', - 'diqwiki': 'https://diq.wikipedia.org', - 'dsbwiki': 'https://dsb.wikipedia.org', - 'dvwiki': 'https://dv.wikipedia.org', - 'dvwiktionary': 'https://dv.wiktionary.org', - 'dzwiki': 'https://dz.wikipedia.org', - 'dzwiktionary': 'https://dz.wiktionary.org', - 'eewiki': 'https://ee.wikipedia.org', - 'elwiki': 'https://el.wikipedia.org', - 'elwiktionary': 'https://el.wiktionary.org', - 'elwikibooks': 'https://el.wikibooks.org', - 'elwikinews': 'https://el.wikinews.org', - 'elwikiquote': 'https://el.wikiquote.org', - 'elwikisource': 'https://el.wikisource.org', - 'elwikiversity': 'https://el.wikiversity.org', - 'elwikivoyage': 'https://el.wikivoyage.org', - 'emlwiki': 'https://eml.wikipedia.org', - 'enwiki': 'https://en.wikipedia.org', - 'enwiktionary': 'https://en.wiktionary.org', - 'enwikibooks': 'https://en.wikibooks.org', - 'enwikinews': 'https://en.wikinews.org', - 'enwikiquote': 'https://en.wikiquote.org', - 'enwikisource': 'https://en.wikisource.org', - 'enwikiversity': 'https://en.wikiversity.org', - 'enwikivoyage': 'https://en.wikivoyage.org', - 'eowiki': 'https://eo.wikipedia.org', - 'eowiktionary': 'https://eo.wiktionary.org', - 'eowikibooks': 'https://eo.wikibooks.org', - 'eowikinews': 'https://eo.wikinews.org', - 'eowikiquote': 'https://eo.wikiquote.org', - 'eowikisource': 'https://eo.wikisource.org', - 'eswiki': 'https://es.wikipedia.org', - 'eswiktionary': 'https://es.wiktionary.org', - 'eswikibooks': 'https://es.wikibooks.org', - 'eswikinews': 'https://es.wikinews.org', - 'eswikiquote': 'https://es.wikiquote.org', - 'eswikisource': 'https://es.wikisource.org', - 'eswikiversity': 'https://es.wikiversity.org', - 'eswikivoyage': 'https://es.wikivoyage.org', - 'etwiki': 'https://et.wikipedia.org', - 'etwiktionary': 'https://et.wiktionary.org', - 'etwikibooks': 'https://et.wikibooks.org', - 'etwikiquote': 'https://et.wikiquote.org', - 'etwikisource': 'https://et.wikisource.org', - 'euwiki': 'https://eu.wikipedia.org', - 'euwiktionary': 'https://eu.wiktionary.org', - 'euwikibooks': 'https://eu.wikibooks.org', - 'euwikiquote': 'https://eu.wikiquote.org', - 'extwiki': 'https://ext.wikipedia.org', - 'fawiki': 'https://fa.wikipedia.org', - 'fawiktionary': 'https://fa.wiktionary.org', - 'fawikibooks': 'https://fa.wikibooks.org', - 'fawikinews': 'https://fa.wikinews.org', - 'fawikiquote': 'https://fa.wikiquote.org', - 'fawikisource': 'https://fa.wikisource.org', - 'fawikivoyage': 'https://fa.wikivoyage.org', - 'ffwiki': 'https://ff.wikipedia.org', - 'fiwiki': 'https://fi.wikipedia.org', - 'fiwiktionary': 'https://fi.wiktionary.org', - 'fiwikibooks': 'https://fi.wikibooks.org', - 'fiwikinews': 'https://fi.wikinews.org', - 'fiwikiquote': 'https://fi.wikiquote.org', - 'fiwikisource': 'https://fi.wikisource.org', - 'fiwikiversity': 'https://fi.wikiversity.org', - 'fiu_vrowiki': 'https://fiu-vro.wikipedia.org', - 'fjwiki': 'https://fj.wikipedia.org', - 'fjwiktionary': 'https://fj.wiktionary.org', - 'fowiki': 'https://fo.wikipedia.org', - 'fowiktionary': 'https://fo.wiktionary.org', - 'fowikisource': 'https://fo.wikisource.org', - 'frwiki': 'https://fr.wikipedia.org', - 'frwiktionary': 'https://fr.wiktionary.org', - 'frwikibooks': 'https://fr.wikibooks.org', - 'frwikinews': 'https://fr.wikinews.org', - 'frwikiquote': 'https://fr.wikiquote.org', - 'frwikisource': 'https://fr.wikisource.org', - 'frwikiversity': 'https://fr.wikiversity.org', - 'frwikivoyage': 'https://fr.wikivoyage.org', - 'frpwiki': 'https://frp.wikipedia.org', - 'frrwiki': 'https://frr.wikipedia.org', - 'furwiki': 'https://fur.wikipedia.org', - 'fywiki': 'https://fy.wikipedia.org', - 'fywiktionary': 'https://fy.wiktionary.org', - 'fywikibooks': 'https://fy.wikibooks.org', - 'gawiki': 'https://ga.wikipedia.org', - 'gawiktionary': 'https://ga.wiktionary.org', - 'gawikibooks': 'https://ga.wikibooks.org', - 'gawikiquote': 'https://ga.wikiquote.org', - 'gagwiki': 'https://gag.wikipedia.org', - 'ganwiki': 'https://gan.wikipedia.org', - 'gdwiki': 'https://gd.wikipedia.org', - 'gdwiktionary': 'https://gd.wiktionary.org', - 'glwiki': 'https://gl.wikipedia.org', - 'glwiktionary': 'https://gl.wiktionary.org', - 'glwikibooks': 'https://gl.wikibooks.org', - 'glwikiquote': 'https://gl.wikiquote.org', - 'glwikisource': 'https://gl.wikisource.org', - 'glkwiki': 'https://glk.wikipedia.org', - 'gnwiki': 'https://gn.wikipedia.org', - 'gnwiktionary': 'https://gn.wiktionary.org', - 'gnwikibooks': 'https://gn.wikibooks.org', - 'gotwiki': 'https://got.wikipedia.org', - 'gotwikibooks': 'https://got.wikibooks.org', - 'guwiki': 'https://gu.wikipedia.org', - 'guwiktionary': 'https://gu.wiktionary.org', - 'guwikibooks': 'https://gu.wikibooks.org', - 'guwikiquote': 'https://gu.wikiquote.org', - 'guwikisource': 'https://gu.wikisource.org', - 'gvwiki': 'https://gv.wikipedia.org', - 'gvwiktionary': 'https://gv.wiktionary.org', - 'hawiki': 'https://ha.wikipedia.org', - 'hawiktionary': 'https://ha.wiktionary.org', - 'hakwiki': 'https://hak.wikipedia.org', - 'hawwiki': 'https://haw.wikipedia.org', - 'hewiki': 'https://he.wikipedia.org', - 'hewiktionary': 'https://he.wiktionary.org', - 'hewikibooks': 'https://he.wikibooks.org', - 'hewikinews': 'https://he.wikinews.org', - 'hewikiquote': 'https://he.wikiquote.org', - 'hewikisource': 'https://he.wikisource.org', - 'hewikivoyage': 'https://he.wikivoyage.org', - 'hiwiki': 'https://hi.wikipedia.org', - 'hiwiktionary': 'https://hi.wiktionary.org', - 'hiwikibooks': 'https://hi.wikibooks.org', - 'hiwikiquote': 'https://hi.wikiquote.org', - 'hifwiki': 'https://hif.wikipedia.org', - 'howiki': 'https://ho.wikipedia.org', - 'hrwiki': 'https://hr.wikipedia.org', - 'hrwiktionary': 'https://hr.wiktionary.org', - 'hrwikibooks': 'https://hr.wikibooks.org', - 'hrwikiquote': 'https://hr.wikiquote.org', - 'hrwikisource': 'https://hr.wikisource.org', - 'hsbwiki': 'https://hsb.wikipedia.org', - 'hsbwiktionary': 'https://hsb.wiktionary.org', - 'htwiki': 'https://ht.wikipedia.org', - 'htwikisource': 'https://ht.wikisource.org', - 'huwiki': 'https://hu.wikipedia.org', - 'huwiktionary': 'https://hu.wiktionary.org', - 'huwikibooks': 'https://hu.wikibooks.org', - 'huwikinews': 'https://hu.wikinews.org', - 'huwikiquote': 'https://hu.wikiquote.org', - 'huwikisource': 'https://hu.wikisource.org', - 'hywiki': 'https://hy.wikipedia.org', - 'hywiktionary': 'https://hy.wiktionary.org', - 'hywikibooks': 'https://hy.wikibooks.org', - 'hywikiquote': 'https://hy.wikiquote.org', - 'hywikisource': 'https://hy.wikisource.org', - 'hzwiki': 'https://hz.wikipedia.org', - 'iawiki': 'https://ia.wikipedia.org', - 'iawiktionary': 'https://ia.wiktionary.org', - 'iawikibooks': 'https://ia.wikibooks.org', - 'idwiki': 'https://id.wikipedia.org', - 'idwiktionary': 'https://id.wiktionary.org', - 'idwikibooks': 'https://id.wikibooks.org', - 'idwikiquote': 'https://id.wikiquote.org', - 'idwikisource': 'https://id.wikisource.org', - 'iewiki': 'https://ie.wikipedia.org', - 'iewiktionary': 'https://ie.wiktionary.org', - 'iewikibooks': 'https://ie.wikibooks.org', - 'igwiki': 'https://ig.wikipedia.org', - 'iiwiki': 'https://ii.wikipedia.org', - 'ikwiki': 'https://ik.wikipedia.org', - 'ikwiktionary': 'https://ik.wiktionary.org', - 'ilowiki': 'https://ilo.wikipedia.org', - 'iowiki': 'https://io.wikipedia.org', - 'iowiktionary': 'https://io.wiktionary.org', - 'iswiki': 'https://is.wikipedia.org', - 'iswiktionary': 'https://is.wiktionary.org', - 'iswikibooks': 'https://is.wikibooks.org', - 'iswikiquote': 'https://is.wikiquote.org', - 'iswikisource': 'https://is.wikisource.org', - 'itwiki': 'https://it.wikipedia.org', - 'itwiktionary': 'https://it.wiktionary.org', - 'itwikibooks': 'https://it.wikibooks.org', - 'itwikinews': 'https://it.wikinews.org', - 'itwikiquote': 'https://it.wikiquote.org', - 'itwikisource': 'https://it.wikisource.org', - 'itwikiversity': 'https://it.wikiversity.org', - 'itwikivoyage': 'https://it.wikivoyage.org', - 'iuwiki': 'https://iu.wikipedia.org', - 'iuwiktionary': 'https://iu.wiktionary.org', - 'jawiki': 'https://ja.wikipedia.org', - 'jawiktionary': 'https://ja.wiktionary.org', - 'jawikibooks': 'https://ja.wikibooks.org', - 'jawikinews': 'https://ja.wikinews.org', - 'jawikiquote': 'https://ja.wikiquote.org', - 'jawikisource': 'https://ja.wikisource.org', - 'jawikiversity': 'https://ja.wikiversity.org', - 'jbowiki': 'https://jbo.wikipedia.org', - 'jbowiktionary': 'https://jbo.wiktionary.org', - 'jvwiki': 'https://jv.wikipedia.org', - 'jvwiktionary': 'https://jv.wiktionary.org', - 'kawiki': 'https://ka.wikipedia.org', - 'kawiktionary': 'https://ka.wiktionary.org', - 'kawikibooks': 'https://ka.wikibooks.org', - 'kawikiquote': 'https://ka.wikiquote.org', - 'kaawiki': 'https://kaa.wikipedia.org', - 'kabwiki': 'https://kab.wikipedia.org', - 'kbdwiki': 'https://kbd.wikipedia.org', - 'kgwiki': 'https://kg.wikipedia.org', - 'kiwiki': 'https://ki.wikipedia.org', - 'kjwiki': 'https://kj.wikipedia.org', - 'kkwiki': 'https://kk.wikipedia.org', - 'kkwiktionary': 'https://kk.wiktionary.org', - 'kkwikibooks': 'https://kk.wikibooks.org', - 'kkwikiquote': 'https://kk.wikiquote.org', - 'klwiki': 'https://kl.wikipedia.org', - 'klwiktionary': 'https://kl.wiktionary.org', - 'kmwiki': 'https://km.wikipedia.org', - 'kmwiktionary': 'https://km.wiktionary.org', - 'kmwikibooks': 'https://km.wikibooks.org', - 'knwiki': 'https://kn.wikipedia.org', - 'knwiktionary': 'https://kn.wiktionary.org', - 'knwikibooks': 'https://kn.wikibooks.org', - 'knwikiquote': 'https://kn.wikiquote.org', - 'knwikisource': 'https://kn.wikisource.org', - 'kowiki': 'https://ko.wikipedia.org', - 'kowiktionary': 'https://ko.wiktionary.org', - 'kowikibooks': 'https://ko.wikibooks.org', - 'kowikinews': 'https://ko.wikinews.org', - 'kowikiquote': 'https://ko.wikiquote.org', - 'kowikisource': 'https://ko.wikisource.org', - 'kowikiversity': 'https://ko.wikiversity.org', - 'koiwiki': 'https://koi.wikipedia.org', - 'krwiki': 'https://kr.wikipedia.org', - 'krwikiquote': 'https://kr.wikiquote.org', - 'krcwiki': 'https://krc.wikipedia.org', - 'kswiki': 'https://ks.wikipedia.org', - 'kswiktionary': 'https://ks.wiktionary.org', - 'kswikibooks': 'https://ks.wikibooks.org', - 'kswikiquote': 'https://ks.wikiquote.org', - 'kshwiki': 'https://ksh.wikipedia.org', - 'kuwiki': 'https://ku.wikipedia.org', - 'kuwiktionary': 'https://ku.wiktionary.org', - 'kuwikibooks': 'https://ku.wikibooks.org', - 'kuwikiquote': 'https://ku.wikiquote.org', - 'kvwiki': 'https://kv.wikipedia.org', - 'kwwiki': 'https://kw.wikipedia.org', - 'kwwiktionary': 'https://kw.wiktionary.org', - 'kwwikiquote': 'https://kw.wikiquote.org', - 'kywiki': 'https://ky.wikipedia.org', - 'kywiktionary': 'https://ky.wiktionary.org', - 'kywikibooks': 'https://ky.wikibooks.org', - 'kywikiquote': 'https://ky.wikiquote.org', - 'lawiki': 'https://la.wikipedia.org', - 'lawiktionary': 'https://la.wiktionary.org', - 'lawikibooks': 'https://la.wikibooks.org', - 'lawikiquote': 'https://la.wikiquote.org', - 'lawikisource': 'https://la.wikisource.org', - 'ladwiki': 'https://lad.wikipedia.org', - 'lbwiki': 'https://lb.wikipedia.org', - 'lbwiktionary': 'https://lb.wiktionary.org', - 'lbwikibooks': 'https://lb.wikibooks.org', - 'lbwikiquote': 'https://lb.wikiquote.org', - 'lbewiki': 'https://lbe.wikipedia.org', - 'lezwiki': 'https://lez.wikipedia.org', - 'lgwiki': 'https://lg.wikipedia.org', - 'liwiki': 'https://li.wikipedia.org', - 'liwiktionary': 'https://li.wiktionary.org', - 'liwikibooks': 'https://li.wikibooks.org', - 'liwikiquote': 'https://li.wikiquote.org', - 'liwikisource': 'https://li.wikisource.org', - 'lijwiki': 'https://lij.wikipedia.org', - 'lmowiki': 'https://lmo.wikipedia.org', - 'lnwiki': 'https://ln.wikipedia.org', - 'lnwiktionary': 'https://ln.wiktionary.org', - 'lnwikibooks': 'https://ln.wikibooks.org', - 'lowiki': 'https://lo.wikipedia.org', - 'lowiktionary': 'https://lo.wiktionary.org', - 'ltwiki': 'https://lt.wikipedia.org', - 'ltwiktionary': 'https://lt.wiktionary.org', - 'ltwikibooks': 'https://lt.wikibooks.org', - 'ltwikiquote': 'https://lt.wikiquote.org', - 'ltwikisource': 'https://lt.wikisource.org', - 'ltgwiki': 'https://ltg.wikipedia.org', - 'lvwiki': 'https://lv.wikipedia.org', - 'lvwiktionary': 'https://lv.wiktionary.org', - 'lvwikibooks': 'https://lv.wikibooks.org', - 'maiwiki': 'https://mai.wikipedia.org', - 'map_bmswiki': 'https://map-bms.wikipedia.org', - 'mdfwiki': 'https://mdf.wikipedia.org', - 'mgwiki': 'https://mg.wikipedia.org', - 'mgwiktionary': 'https://mg.wiktionary.org', - 'mgwikibooks': 'https://mg.wikibooks.org', - 'mhwiki': 'https://mh.wikipedia.org', - 'mhwiktionary': 'https://mh.wiktionary.org', - 'mhrwiki': 'https://mhr.wikipedia.org', - 'miwiki': 'https://mi.wikipedia.org', - 'miwiktionary': 'https://mi.wiktionary.org', - 'miwikibooks': 'https://mi.wikibooks.org', - 'minwiki': 'https://min.wikipedia.org', - 'mkwiki': 'https://mk.wikipedia.org', - 'mkwiktionary': 'https://mk.wiktionary.org', - 'mkwikibooks': 'https://mk.wikibooks.org', - 'mkwikisource': 'https://mk.wikisource.org', - 'mlwiki': 'https://ml.wikipedia.org', - 'mlwiktionary': 'https://ml.wiktionary.org', - 'mlwikibooks': 'https://ml.wikibooks.org', - 'mlwikiquote': 'https://ml.wikiquote.org', - 'mlwikisource': 'https://ml.wikisource.org', - 'mnwiki': 'https://mn.wikipedia.org', - 'mnwiktionary': 'https://mn.wiktionary.org', - 'mnwikibooks': 'https://mn.wikibooks.org', - 'mowiki': 'https://mo.wikipedia.org', - 'mowiktionary': 'https://mo.wiktionary.org', - 'mrwiki': 'https://mr.wikipedia.org', - 'mrwiktionary': 'https://mr.wiktionary.org', - 'mrwikibooks': 'https://mr.wikibooks.org', - 'mrwikiquote': 'https://mr.wikiquote.org', - 'mrwikisource': 'https://mr.wikisource.org', - 'mrjwiki': 'https://mrj.wikipedia.org', - 'mswiki': 'https://ms.wikipedia.org', - 'mswiktionary': 'https://ms.wiktionary.org', - 'mswikibooks': 'https://ms.wikibooks.org', - 'mtwiki': 'https://mt.wikipedia.org', - 'mtwiktionary': 'https://mt.wiktionary.org', - 'muswiki': 'https://mus.wikipedia.org', - 'mwlwiki': 'https://mwl.wikipedia.org', - 'mywiki': 'https://my.wikipedia.org', - 'mywiktionary': 'https://my.wiktionary.org', - 'mywikibooks': 'https://my.wikibooks.org', - 'myvwiki': 'https://myv.wikipedia.org', - 'mznwiki': 'https://mzn.wikipedia.org', - 'nawiki': 'https://na.wikipedia.org', - 'nawiktionary': 'https://na.wiktionary.org', - 'nawikibooks': 'https://na.wikibooks.org', - 'nawikiquote': 'https://na.wikiquote.org', - 'nahwiki': 'https://nah.wikipedia.org', - 'nahwiktionary': 'https://nah.wiktionary.org', - 'nahwikibooks': 'https://nah.wikibooks.org', - 'napwiki': 'https://nap.wikipedia.org', - 'ndswiki': 'https://nds.wikipedia.org', - 'ndswiktionary': 'https://nds.wiktionary.org', - 'ndswikibooks': 'https://nds.wikibooks.org', - 'ndswikiquote': 'https://nds.wikiquote.org', - 'nds_nlwiki': 'https://nds-nl.wikipedia.org', - 'newiki': 'https://ne.wikipedia.org', - 'newiktionary': 'https://ne.wiktionary.org', - 'newikibooks': 'https://ne.wikibooks.org', - 'newwiki': 'https://new.wikipedia.org', - 'ngwiki': 'https://ng.wikipedia.org', - 'nlwiki': 'https://nl.wikipedia.org', - 'nlwiktionary': 'https://nl.wiktionary.org', - 'nlwikibooks': 'https://nl.wikibooks.org', - 'nlwikinews': 'https://nl.wikinews.org', - 'nlwikiquote': 'https://nl.wikiquote.org', - 'nlwikisource': 'https://nl.wikisource.org', - 'nlwikivoyage': 'https://nl.wikivoyage.org', - 'nnwiki': 'https://nn.wikipedia.org', - 'nnwiktionary': 'https://nn.wiktionary.org', - 'nnwikiquote': 'https://nn.wikiquote.org', - 'nowiki': 'https://no.wikipedia.org', - 'nowiktionary': 'https://no.wiktionary.org', - 'nowikibooks': 'https://no.wikibooks.org', - 'nowikinews': 'https://no.wikinews.org', - 'nowikiquote': 'https://no.wikiquote.org', - 'nowikisource': 'https://no.wikisource.org', - 'novwiki': 'https://nov.wikipedia.org', - 'nrmwiki': 'https://nrm.wikipedia.org', - 'nsowiki': 'https://nso.wikipedia.org', - 'nvwiki': 'https://nv.wikipedia.org', - 'nywiki': 'https://ny.wikipedia.org', - 'ocwiki': 'https://oc.wikipedia.org', - 'ocwiktionary': 'https://oc.wiktionary.org', - 'ocwikibooks': 'https://oc.wikibooks.org', - 'omwiki': 'https://om.wikipedia.org', - 'omwiktionary': 'https://om.wiktionary.org', - 'orwiki': 'https://or.wikipedia.org', - 'orwiktionary': 'https://or.wiktionary.org', - 'orwikisource': 'https://or.wikisource.org', - 'oswiki': 'https://os.wikipedia.org', - 'pawiki': 'https://pa.wikipedia.org', - 'pawiktionary': 'https://pa.wiktionary.org', - 'pawikibooks': 'https://pa.wikibooks.org', - 'pagwiki': 'https://pag.wikipedia.org', - 'pamwiki': 'https://pam.wikipedia.org', - 'papwiki': 'https://pap.wikipedia.org', - 'pcdwiki': 'https://pcd.wikipedia.org', - 'pdcwiki': 'https://pdc.wikipedia.org', - 'pflwiki': 'https://pfl.wikipedia.org', - 'piwiki': 'https://pi.wikipedia.org', - 'piwiktionary': 'https://pi.wiktionary.org', - 'pihwiki': 'https://pih.wikipedia.org', - 'plwiki': 'https://pl.wikipedia.org', - 'plwiktionary': 'https://pl.wiktionary.org', - 'plwikibooks': 'https://pl.wikibooks.org', - 'plwikinews': 'https://pl.wikinews.org', - 'plwikiquote': 'https://pl.wikiquote.org', - 'plwikisource': 'https://pl.wikisource.org', - 'plwikivoyage': 'https://pl.wikivoyage.org', - 'pmswiki': 'https://pms.wikipedia.org', - 'pnbwiki': 'https://pnb.wikipedia.org', - 'pnbwiktionary': 'https://pnb.wiktionary.org', - 'pntwiki': 'https://pnt.wikipedia.org', - 'pswiki': 'https://ps.wikipedia.org', - 'pswiktionary': 'https://ps.wiktionary.org', - 'pswikibooks': 'https://ps.wikibooks.org', - 'ptwiki': 'https://pt.wikipedia.org', - 'ptwiktionary': 'https://pt.wiktionary.org', - 'ptwikibooks': 'https://pt.wikibooks.org', - 'ptwikinews': 'https://pt.wikinews.org', - 'ptwikiquote': 'https://pt.wikiquote.org', - 'ptwikisource': 'https://pt.wikisource.org', - 'ptwikiversity': 'https://pt.wikiversity.org', - 'ptwikivoyage': 'https://pt.wikivoyage.org', - 'quwiki': 'https://qu.wikipedia.org', - 'quwiktionary': 'https://qu.wiktionary.org', - 'quwikibooks': 'https://qu.wikibooks.org', - 'quwikiquote': 'https://qu.wikiquote.org', - 'rmwiki': 'https://rm.wikipedia.org', - 'rmwiktionary': 'https://rm.wiktionary.org', - 'rmwikibooks': 'https://rm.wikibooks.org', - 'rmywiki': 'https://rmy.wikipedia.org', - 'rnwiki': 'https://rn.wikipedia.org', - 'rnwiktionary': 'https://rn.wiktionary.org', - 'rowiki': 'https://ro.wikipedia.org', - 'rowiktionary': 'https://ro.wiktionary.org', - 'rowikibooks': 'https://ro.wikibooks.org', - 'rowikinews': 'https://ro.wikinews.org', - 'rowikiquote': 'https://ro.wikiquote.org', - 'rowikisource': 'https://ro.wikisource.org', - 'rowikivoyage': 'https://ro.wikivoyage.org', - 'roa_rupwiki': 'https://roa-rup.wikipedia.org', - 'roa_rupwiktionary': 'https://roa-rup.wiktionary.org', - 'roa_tarawiki': 'https://roa-tara.wikipedia.org', - 'ruwiki': 'https://ru.wikipedia.org', - 'ruwiktionary': 'https://ru.wiktionary.org', - 'ruwikibooks': 'https://ru.wikibooks.org', - 'ruwikinews': 'https://ru.wikinews.org', - 'ruwikiquote': 'https://ru.wikiquote.org', - 'ruwikisource': 'https://ru.wikisource.org', - 'ruwikiversity': 'https://ru.wikiversity.org', - 'ruwikivoyage': 'https://ru.wikivoyage.org', - 'ruewiki': 'https://rue.wikipedia.org', - 'rwwiki': 'https://rw.wikipedia.org', - 'rwwiktionary': 'https://rw.wiktionary.org', - 'sawiki': 'https://sa.wikipedia.org', - 'sawiktionary': 'https://sa.wiktionary.org', - 'sawikibooks': 'https://sa.wikibooks.org', - 'sawikiquote': 'https://sa.wikiquote.org', - 'sawikisource': 'https://sa.wikisource.org', - 'sahwiki': 'https://sah.wikipedia.org', - 'sahwikisource': 'https://sah.wikisource.org', - 'scwiki': 'https://sc.wikipedia.org', - 'scwiktionary': 'https://sc.wiktionary.org', - 'scnwiki': 'https://scn.wikipedia.org', - 'scnwiktionary': 'https://scn.wiktionary.org', - 'scowiki': 'https://sco.wikipedia.org', - 'sdwiki': 'https://sd.wikipedia.org', - 'sdwiktionary': 'https://sd.wiktionary.org', - 'sdwikinews': 'https://sd.wikinews.org', - 'sewiki': 'https://se.wikipedia.org', - 'sewikibooks': 'https://se.wikibooks.org', - 'sgwiki': 'https://sg.wikipedia.org', - 'sgwiktionary': 'https://sg.wiktionary.org', - 'shwiki': 'https://sh.wikipedia.org', - 'shwiktionary': 'https://sh.wiktionary.org', - 'siwiki': 'https://si.wikipedia.org', - 'siwiktionary': 'https://si.wiktionary.org', - 'siwikibooks': 'https://si.wikibooks.org', - 'simplewiki': 'https://simple.wikipedia.org', - 'simplewiktionary': 'https://simple.wiktionary.org', - 'simplewikibooks': 'https://simple.wikibooks.org', - 'simplewikiquote': 'https://simple.wikiquote.org', - 'skwiki': 'https://sk.wikipedia.org', - 'skwiktionary': 'https://sk.wiktionary.org', - 'skwikibooks': 'https://sk.wikibooks.org', - 'skwikiquote': 'https://sk.wikiquote.org', - 'skwikisource': 'https://sk.wikisource.org', - 'slwiki': 'https://sl.wikipedia.org', - 'slwiktionary': 'https://sl.wiktionary.org', - 'slwikibooks': 'https://sl.wikibooks.org', - 'slwikiquote': 'https://sl.wikiquote.org', - 'slwikisource': 'https://sl.wikisource.org', - 'slwikiversity': 'https://sl.wikiversity.org', - 'smwiki': 'https://sm.wikipedia.org', - 'smwiktionary': 'https://sm.wiktionary.org', - 'snwiki': 'https://sn.wikipedia.org', - 'snwiktionary': 'https://sn.wiktionary.org', - 'sowiki': 'https://so.wikipedia.org', - 'sowiktionary': 'https://so.wiktionary.org', - 'sqwiki': 'https://sq.wikipedia.org', - 'sqwiktionary': 'https://sq.wiktionary.org', - 'sqwikibooks': 'https://sq.wikibooks.org', - 'sqwikinews': 'https://sq.wikinews.org', - 'sqwikiquote': 'https://sq.wikiquote.org', - 'srwiki': 'https://sr.wikipedia.org', - 'srwiktionary': 'https://sr.wiktionary.org', - 'srwikibooks': 'https://sr.wikibooks.org', - 'srwikinews': 'https://sr.wikinews.org', - 'srwikiquote': 'https://sr.wikiquote.org', - 'srwikisource': 'https://sr.wikisource.org', - 'srnwiki': 'https://srn.wikipedia.org', - 'sswiki': 'https://ss.wikipedia.org', - 'sswiktionary': 'https://ss.wiktionary.org', - 'stwiki': 'https://st.wikipedia.org', - 'stwiktionary': 'https://st.wiktionary.org', - 'stqwiki': 'https://stq.wikipedia.org', - 'suwiki': 'https://su.wikipedia.org', - 'suwiktionary': 'https://su.wiktionary.org', - 'suwikibooks': 'https://su.wikibooks.org', - 'suwikiquote': 'https://su.wikiquote.org', - 'svwiki': 'https://sv.wikipedia.org', - 'svwiktionary': 'https://sv.wiktionary.org', - 'svwikibooks': 'https://sv.wikibooks.org', - 'svwikinews': 'https://sv.wikinews.org', - 'svwikiquote': 'https://sv.wikiquote.org', - 'svwikisource': 'https://sv.wikisource.org', - 'svwikiversity': 'https://sv.wikiversity.org', - 'svwikivoyage': 'https://sv.wikivoyage.org', - 'swwiki': 'https://sw.wikipedia.org', - 'swwiktionary': 'https://sw.wiktionary.org', - 'swwikibooks': 'https://sw.wikibooks.org', - 'szlwiki': 'https://szl.wikipedia.org', - 'tawiki': 'https://ta.wikipedia.org', - 'tawiktionary': 'https://ta.wiktionary.org', - 'tawikibooks': 'https://ta.wikibooks.org', - 'tawikinews': 'https://ta.wikinews.org', - 'tawikiquote': 'https://ta.wikiquote.org', - 'tawikisource': 'https://ta.wikisource.org', - 'tewiki': 'https://te.wikipedia.org', - 'tewiktionary': 'https://te.wiktionary.org', - 'tewikibooks': 'https://te.wikibooks.org', - 'tewikiquote': 'https://te.wikiquote.org', - 'tewikisource': 'https://te.wikisource.org', - 'tetwiki': 'https://tet.wikipedia.org', - 'tgwiki': 'https://tg.wikipedia.org', - 'tgwiktionary': 'https://tg.wiktionary.org', - 'tgwikibooks': 'https://tg.wikibooks.org', - 'thwiki': 'https://th.wikipedia.org', - 'thwiktionary': 'https://th.wiktionary.org', - 'thwikibooks': 'https://th.wikibooks.org', - 'thwikinews': 'https://th.wikinews.org', - 'thwikiquote': 'https://th.wikiquote.org', - 'thwikisource': 'https://th.wikisource.org', - 'tiwiki': 'https://ti.wikipedia.org', - 'tiwiktionary': 'https://ti.wiktionary.org', - 'tkwiki': 'https://tk.wikipedia.org', - 'tkwiktionary': 'https://tk.wiktionary.org', - 'tkwikibooks': 'https://tk.wikibooks.org', - 'tkwikiquote': 'https://tk.wikiquote.org', - 'tlwiki': 'https://tl.wikipedia.org', - 'tlwiktionary': 'https://tl.wiktionary.org', - 'tlwikibooks': 'https://tl.wikibooks.org', - 'tnwiki': 'https://tn.wikipedia.org', - 'tnwiktionary': 'https://tn.wiktionary.org', - 'towiki': 'https://to.wikipedia.org', - 'towiktionary': 'https://to.wiktionary.org', - 'tpiwiki': 'https://tpi.wikipedia.org', - 'tpiwiktionary': 'https://tpi.wiktionary.org', - 'trwiki': 'https://tr.wikipedia.org', - 'trwiktionary': 'https://tr.wiktionary.org', - 'trwikibooks': 'https://tr.wikibooks.org', - 'trwikinews': 'https://tr.wikinews.org', - 'trwikiquote': 'https://tr.wikiquote.org', - 'trwikisource': 'https://tr.wikisource.org', - 'tswiki': 'https://ts.wikipedia.org', - 'tswiktionary': 'https://ts.wiktionary.org', - 'ttwiki': 'https://tt.wikipedia.org', - 'ttwiktionary': 'https://tt.wiktionary.org', - 'ttwikibooks': 'https://tt.wikibooks.org', - 'ttwikiquote': 'https://tt.wikiquote.org', - 'tumwiki': 'https://tum.wikipedia.org', - 'twwiki': 'https://tw.wikipedia.org', - 'twwiktionary': 'https://tw.wiktionary.org', - 'tywiki': 'https://ty.wikipedia.org', - 'tyvwiki': 'https://tyv.wikipedia.org', - 'udmwiki': 'https://udm.wikipedia.org', - 'ugwiki': 'https://ug.wikipedia.org', - 'ugwiktionary': 'https://ug.wiktionary.org', - 'ugwikibooks': 'https://ug.wikibooks.org', - 'ugwikiquote': 'https://ug.wikiquote.org', - 'ukwiki': 'https://uk.wikipedia.org', - 'ukwiktionary': 'https://uk.wiktionary.org', - 'ukwikibooks': 'https://uk.wikibooks.org', - 'ukwikinews': 'https://uk.wikinews.org', - 'ukwikiquote': 'https://uk.wikiquote.org', - 'ukwikisource': 'https://uk.wikisource.org', - 'ukwikivoyage': 'https://uk.wikivoyage.org', - 'urwiki': 'https://ur.wikipedia.org', - 'urwiktionary': 'https://ur.wiktionary.org', - 'urwikibooks': 'https://ur.wikibooks.org', - 'urwikiquote': 'https://ur.wikiquote.org', - 'uzwiki': 'https://uz.wikipedia.org', - 'uzwiktionary': 'https://uz.wiktionary.org', - 'uzwikibooks': 'https://uz.wikibooks.org', - 'uzwikiquote': 'https://uz.wikiquote.org', - 'vewiki': 'https://ve.wikipedia.org', - 'vecwiki': 'https://vec.wikipedia.org', - 'vecwiktionary': 'https://vec.wiktionary.org', - 'vecwikisource': 'https://vec.wikisource.org', - 'vepwiki': 'https://vep.wikipedia.org', - 'viwiki': 'https://vi.wikipedia.org', - 'viwiktionary': 'https://vi.wiktionary.org', - 'viwikibooks': 'https://vi.wikibooks.org', - 'viwikiquote': 'https://vi.wikiquote.org', - 'viwikisource': 'https://vi.wikisource.org', - 'viwikivoyage': 'https://vi.wikivoyage.org', - 'vlswiki': 'https://vls.wikipedia.org', - 'vowiki': 'https://vo.wikipedia.org', - 'vowiktionary': 'https://vo.wiktionary.org', - 'vowikibooks': 'https://vo.wikibooks.org', - 'vowikiquote': 'https://vo.wikiquote.org', - 'wawiki': 'https://wa.wikipedia.org', - 'wawiktionary': 'https://wa.wiktionary.org', - 'wawikibooks': 'https://wa.wikibooks.org', - 'warwiki': 'https://war.wikipedia.org', - 'wowiki': 'https://wo.wikipedia.org', - 'wowiktionary': 'https://wo.wiktionary.org', - 'wowikiquote': 'https://wo.wikiquote.org', - 'wuuwiki': 'https://wuu.wikipedia.org', - 'xalwiki': 'https://xal.wikipedia.org', - 'xhwiki': 'https://xh.wikipedia.org', - 'xhwiktionary': 'https://xh.wiktionary.org', - 'xhwikibooks': 'https://xh.wikibooks.org', - 'xmfwiki': 'https://xmf.wikipedia.org', - 'yiwiki': 'https://yi.wikipedia.org', - 'yiwiktionary': 'https://yi.wiktionary.org', - 'yiwikisource': 'https://yi.wikisource.org', - 'yowiki': 'https://yo.wikipedia.org', - 'yowiktionary': 'https://yo.wiktionary.org', - 'yowikibooks': 'https://yo.wikibooks.org', - 'zawiki': 'https://za.wikipedia.org', - 'zawiktionary': 'https://za.wiktionary.org', - 'zawikibooks': 'https://za.wikibooks.org', - 'zawikiquote': 'https://za.wikiquote.org', - 'zeawiki': 'https://zea.wikipedia.org', - 'zhwiki': 'https://zh.wikipedia.org', - 'zhwiktionary': 'https://zh.wiktionary.org', - 'zhwikibooks': 'https://zh.wikibooks.org', - 'zhwikinews': 'https://zh.wikinews.org', - 'zhwikiquote': 'https://zh.wikiquote.org', - 'zhwikisource': 'https://zh.wikisource.org', - 'zhwikivoyage': 'https://zh.wikivoyage.org', - 'zh_classicalwiki': 'https://zh-classical.wikipedia.org', - 'zh_min_nanwiki': 'https://zh-min-nan.wikipedia.org', - 'zh_min_nanwiktionary': 'https://zh-min-nan.wiktionary.org', - 'zh_min_nanwikibooks': 'https://zh-min-nan.wikibooks.org', - 'zh_min_nanwikiquote': 'https://zh-min-nan.wikiquote.org', - 'zh_min_nanwikisource': 'https://zh-min-nan.wikisource.org', - 'zh_yuewiki': 'https://zh-yue.wikipedia.org', - 'zuwiki': 'https://zu.wikipedia.org', - 'zuwiktionary': 'https://zu.wiktionary.org', - 'zuwikibooks': 'https://zu.wikibooks.org' +const site_map = { + aawiki: 'https://aa.wikipedia.org', + aawiktionary: 'https://aa.wiktionary.org', + aawikibooks: 'https://aa.wikibooks.org', + abwiki: 'https://ab.wikipedia.org', + abwiktionary: 'https://ab.wiktionary.org', + acewiki: 'https://ace.wikipedia.org', + afwiki: 'https://af.wikipedia.org', + afwiktionary: 'https://af.wiktionary.org', + afwikibooks: 'https://af.wikibooks.org', + afwikiquote: 'https://af.wikiquote.org', + akwiki: 'https://ak.wikipedia.org', + akwiktionary: 'https://ak.wiktionary.org', + akwikibooks: 'https://ak.wikibooks.org', + alswiki: 'https://als.wikipedia.org', + alswiktionary: 'https://als.wiktionary.org', + alswikibooks: 'https://als.wikibooks.org', + alswikiquote: 'https://als.wikiquote.org', + amwiki: 'https://am.wikipedia.org', + amwiktionary: 'https://am.wiktionary.org', + amwikiquote: 'https://am.wikiquote.org', + anwiki: 'https://an.wikipedia.org', + anwiktionary: 'https://an.wiktionary.org', + angwiki: 'https://ang.wikipedia.org', + angwiktionary: 'https://ang.wiktionary.org', + angwikibooks: 'https://ang.wikibooks.org', + angwikiquote: 'https://ang.wikiquote.org', + angwikisource: 'https://ang.wikisource.org', + arwiki: 'https://ar.wikipedia.org', + arwiktionary: 'https://ar.wiktionary.org', + arwikibooks: 'https://ar.wikibooks.org', + arwikinews: 'https://ar.wikinews.org', + arwikiquote: 'https://ar.wikiquote.org', + arwikisource: 'https://ar.wikisource.org', + arwikiversity: 'https://ar.wikiversity.org', + arcwiki: 'https://arc.wikipedia.org', + arzwiki: 'https://arz.wikipedia.org', + aswiki: 'https://as.wikipedia.org', + aswiktionary: 'https://as.wiktionary.org', + aswikibooks: 'https://as.wikibooks.org', + aswikisource: 'https://as.wikisource.org', + astwiki: 'https://ast.wikipedia.org', + astwiktionary: 'https://ast.wiktionary.org', + astwikibooks: 'https://ast.wikibooks.org', + astwikiquote: 'https://ast.wikiquote.org', + avwiki: 'https://av.wikipedia.org', + avwiktionary: 'https://av.wiktionary.org', + aywiki: 'https://ay.wikipedia.org', + aywiktionary: 'https://ay.wiktionary.org', + aywikibooks: 'https://ay.wikibooks.org', + azwiki: 'https://az.wikipedia.org', + azwiktionary: 'https://az.wiktionary.org', + azwikibooks: 'https://az.wikibooks.org', + azwikiquote: 'https://az.wikiquote.org', + azwikisource: 'https://az.wikisource.org', + bawiki: 'https://ba.wikipedia.org', + bawikibooks: 'https://ba.wikibooks.org', + barwiki: 'https://bar.wikipedia.org', + bat_smgwiki: 'https://bat-smg.wikipedia.org', + bclwiki: 'https://bcl.wikipedia.org', + bewiki: 'https://be.wikipedia.org', + bewiktionary: 'https://be.wiktionary.org', + bewikibooks: 'https://be.wikibooks.org', + bewikiquote: 'https://be.wikiquote.org', + bewikisource: 'https://be.wikisource.org', + be_x_oldwiki: 'https://be-x-old.wikipedia.org', + bgwiki: 'https://bg.wikipedia.org', + bgwiktionary: 'https://bg.wiktionary.org', + bgwikibooks: 'https://bg.wikibooks.org', + bgwikinews: 'https://bg.wikinews.org', + bgwikiquote: 'https://bg.wikiquote.org', + bgwikisource: 'https://bg.wikisource.org', + bhwiki: 'https://bh.wikipedia.org', + bhwiktionary: 'https://bh.wiktionary.org', + biwiki: 'https://bi.wikipedia.org', + biwiktionary: 'https://bi.wiktionary.org', + biwikibooks: 'https://bi.wikibooks.org', + bjnwiki: 'https://bjn.wikipedia.org', + bmwiki: 'https://bm.wikipedia.org', + bmwiktionary: 'https://bm.wiktionary.org', + bmwikibooks: 'https://bm.wikibooks.org', + bmwikiquote: 'https://bm.wikiquote.org', + bnwiki: 'https://bn.wikipedia.org', + bnwiktionary: 'https://bn.wiktionary.org', + bnwikibooks: 'https://bn.wikibooks.org', + bnwikisource: 'https://bn.wikisource.org', + bowiki: 'https://bo.wikipedia.org', + bowiktionary: 'https://bo.wiktionary.org', + bowikibooks: 'https://bo.wikibooks.org', + bpywiki: 'https://bpy.wikipedia.org', + brwiki: 'https://br.wikipedia.org', + brwiktionary: 'https://br.wiktionary.org', + brwikiquote: 'https://br.wikiquote.org', + brwikisource: 'https://br.wikisource.org', + bswiki: 'https://bs.wikipedia.org', + bswiktionary: 'https://bs.wiktionary.org', + bswikibooks: 'https://bs.wikibooks.org', + bswikinews: 'https://bs.wikinews.org', + bswikiquote: 'https://bs.wikiquote.org', + bswikisource: 'https://bs.wikisource.org', + bugwiki: 'https://bug.wikipedia.org', + bxrwiki: 'https://bxr.wikipedia.org', + cawiki: 'https://ca.wikipedia.org', + cawiktionary: 'https://ca.wiktionary.org', + cawikibooks: 'https://ca.wikibooks.org', + cawikinews: 'https://ca.wikinews.org', + cawikiquote: 'https://ca.wikiquote.org', + cawikisource: 'https://ca.wikisource.org', + cbk_zamwiki: 'https://cbk-zam.wikipedia.org', + cdowiki: 'https://cdo.wikipedia.org', + cewiki: 'https://ce.wikipedia.org', + cebwiki: 'https://ceb.wikipedia.org', + chwiki: 'https://ch.wikipedia.org', + chwiktionary: 'https://ch.wiktionary.org', + chwikibooks: 'https://ch.wikibooks.org', + chowiki: 'https://cho.wikipedia.org', + chrwiki: 'https://chr.wikipedia.org', + chrwiktionary: 'https://chr.wiktionary.org', + chywiki: 'https://chy.wikipedia.org', + ckbwiki: 'https://ckb.wikipedia.org', + cowiki: 'https://co.wikipedia.org', + cowiktionary: 'https://co.wiktionary.org', + cowikibooks: 'https://co.wikibooks.org', + cowikiquote: 'https://co.wikiquote.org', + crwiki: 'https://cr.wikipedia.org', + crwiktionary: 'https://cr.wiktionary.org', + crwikiquote: 'https://cr.wikiquote.org', + crhwiki: 'https://crh.wikipedia.org', + cswiki: 'https://cs.wikipedia.org', + cswiktionary: 'https://cs.wiktionary.org', + cswikibooks: 'https://cs.wikibooks.org', + cswikinews: 'https://cs.wikinews.org', + cswikiquote: 'https://cs.wikiquote.org', + cswikisource: 'https://cs.wikisource.org', + cswikiversity: 'https://cs.wikiversity.org', + csbwiki: 'https://csb.wikipedia.org', + csbwiktionary: 'https://csb.wiktionary.org', + cuwiki: 'https://cu.wikipedia.org', + cvwiki: 'https://cv.wikipedia.org', + cvwikibooks: 'https://cv.wikibooks.org', + cywiki: 'https://cy.wikipedia.org', + cywiktionary: 'https://cy.wiktionary.org', + cywikibooks: 'https://cy.wikibooks.org', + cywikiquote: 'https://cy.wikiquote.org', + cywikisource: 'https://cy.wikisource.org', + dawiki: 'https://da.wikipedia.org', + dawiktionary: 'https://da.wiktionary.org', + dawikibooks: 'https://da.wikibooks.org', + dawikiquote: 'https://da.wikiquote.org', + dawikisource: 'https://da.wikisource.org', + dewiki: 'https://de.wikipedia.org', + dewiktionary: 'https://de.wiktionary.org', + dewikibooks: 'https://de.wikibooks.org', + dewikinews: 'https://de.wikinews.org', + dewikiquote: 'https://de.wikiquote.org', + dewikisource: 'https://de.wikisource.org', + dewikiversity: 'https://de.wikiversity.org', + dewikivoyage: 'https://de.wikivoyage.org', + diqwiki: 'https://diq.wikipedia.org', + dsbwiki: 'https://dsb.wikipedia.org', + dvwiki: 'https://dv.wikipedia.org', + dvwiktionary: 'https://dv.wiktionary.org', + dzwiki: 'https://dz.wikipedia.org', + dzwiktionary: 'https://dz.wiktionary.org', + eewiki: 'https://ee.wikipedia.org', + elwiki: 'https://el.wikipedia.org', + elwiktionary: 'https://el.wiktionary.org', + elwikibooks: 'https://el.wikibooks.org', + elwikinews: 'https://el.wikinews.org', + elwikiquote: 'https://el.wikiquote.org', + elwikisource: 'https://el.wikisource.org', + elwikiversity: 'https://el.wikiversity.org', + elwikivoyage: 'https://el.wikivoyage.org', + emlwiki: 'https://eml.wikipedia.org', + enwiki: 'https://en.wikipedia.org', + enwiktionary: 'https://en.wiktionary.org', + enwikibooks: 'https://en.wikibooks.org', + enwikinews: 'https://en.wikinews.org', + enwikiquote: 'https://en.wikiquote.org', + enwikisource: 'https://en.wikisource.org', + enwikiversity: 'https://en.wikiversity.org', + enwikivoyage: 'https://en.wikivoyage.org', + eowiki: 'https://eo.wikipedia.org', + eowiktionary: 'https://eo.wiktionary.org', + eowikibooks: 'https://eo.wikibooks.org', + eowikinews: 'https://eo.wikinews.org', + eowikiquote: 'https://eo.wikiquote.org', + eowikisource: 'https://eo.wikisource.org', + eswiki: 'https://es.wikipedia.org', + eswiktionary: 'https://es.wiktionary.org', + eswikibooks: 'https://es.wikibooks.org', + eswikinews: 'https://es.wikinews.org', + eswikiquote: 'https://es.wikiquote.org', + eswikisource: 'https://es.wikisource.org', + eswikiversity: 'https://es.wikiversity.org', + eswikivoyage: 'https://es.wikivoyage.org', + etwiki: 'https://et.wikipedia.org', + etwiktionary: 'https://et.wiktionary.org', + etwikibooks: 'https://et.wikibooks.org', + etwikiquote: 'https://et.wikiquote.org', + etwikisource: 'https://et.wikisource.org', + euwiki: 'https://eu.wikipedia.org', + euwiktionary: 'https://eu.wiktionary.org', + euwikibooks: 'https://eu.wikibooks.org', + euwikiquote: 'https://eu.wikiquote.org', + extwiki: 'https://ext.wikipedia.org', + fawiki: 'https://fa.wikipedia.org', + fawiktionary: 'https://fa.wiktionary.org', + fawikibooks: 'https://fa.wikibooks.org', + fawikinews: 'https://fa.wikinews.org', + fawikiquote: 'https://fa.wikiquote.org', + fawikisource: 'https://fa.wikisource.org', + fawikivoyage: 'https://fa.wikivoyage.org', + ffwiki: 'https://ff.wikipedia.org', + fiwiki: 'https://fi.wikipedia.org', + fiwiktionary: 'https://fi.wiktionary.org', + fiwikibooks: 'https://fi.wikibooks.org', + fiwikinews: 'https://fi.wikinews.org', + fiwikiquote: 'https://fi.wikiquote.org', + fiwikisource: 'https://fi.wikisource.org', + fiwikiversity: 'https://fi.wikiversity.org', + fiu_vrowiki: 'https://fiu-vro.wikipedia.org', + fjwiki: 'https://fj.wikipedia.org', + fjwiktionary: 'https://fj.wiktionary.org', + fowiki: 'https://fo.wikipedia.org', + fowiktionary: 'https://fo.wiktionary.org', + fowikisource: 'https://fo.wikisource.org', + frwiki: 'https://fr.wikipedia.org', + frwiktionary: 'https://fr.wiktionary.org', + frwikibooks: 'https://fr.wikibooks.org', + frwikinews: 'https://fr.wikinews.org', + frwikiquote: 'https://fr.wikiquote.org', + frwikisource: 'https://fr.wikisource.org', + frwikiversity: 'https://fr.wikiversity.org', + frwikivoyage: 'https://fr.wikivoyage.org', + frpwiki: 'https://frp.wikipedia.org', + frrwiki: 'https://frr.wikipedia.org', + furwiki: 'https://fur.wikipedia.org', + fywiki: 'https://fy.wikipedia.org', + fywiktionary: 'https://fy.wiktionary.org', + fywikibooks: 'https://fy.wikibooks.org', + gawiki: 'https://ga.wikipedia.org', + gawiktionary: 'https://ga.wiktionary.org', + gawikibooks: 'https://ga.wikibooks.org', + gawikiquote: 'https://ga.wikiquote.org', + gagwiki: 'https://gag.wikipedia.org', + ganwiki: 'https://gan.wikipedia.org', + gdwiki: 'https://gd.wikipedia.org', + gdwiktionary: 'https://gd.wiktionary.org', + glwiki: 'https://gl.wikipedia.org', + glwiktionary: 'https://gl.wiktionary.org', + glwikibooks: 'https://gl.wikibooks.org', + glwikiquote: 'https://gl.wikiquote.org', + glwikisource: 'https://gl.wikisource.org', + glkwiki: 'https://glk.wikipedia.org', + gnwiki: 'https://gn.wikipedia.org', + gnwiktionary: 'https://gn.wiktionary.org', + gnwikibooks: 'https://gn.wikibooks.org', + gotwiki: 'https://got.wikipedia.org', + gotwikibooks: 'https://got.wikibooks.org', + guwiki: 'https://gu.wikipedia.org', + guwiktionary: 'https://gu.wiktionary.org', + guwikibooks: 'https://gu.wikibooks.org', + guwikiquote: 'https://gu.wikiquote.org', + guwikisource: 'https://gu.wikisource.org', + gvwiki: 'https://gv.wikipedia.org', + gvwiktionary: 'https://gv.wiktionary.org', + hawiki: 'https://ha.wikipedia.org', + hawiktionary: 'https://ha.wiktionary.org', + hakwiki: 'https://hak.wikipedia.org', + hawwiki: 'https://haw.wikipedia.org', + hewiki: 'https://he.wikipedia.org', + hewiktionary: 'https://he.wiktionary.org', + hewikibooks: 'https://he.wikibooks.org', + hewikinews: 'https://he.wikinews.org', + hewikiquote: 'https://he.wikiquote.org', + hewikisource: 'https://he.wikisource.org', + hewikivoyage: 'https://he.wikivoyage.org', + hiwiki: 'https://hi.wikipedia.org', + hiwiktionary: 'https://hi.wiktionary.org', + hiwikibooks: 'https://hi.wikibooks.org', + hiwikiquote: 'https://hi.wikiquote.org', + hifwiki: 'https://hif.wikipedia.org', + howiki: 'https://ho.wikipedia.org', + hrwiki: 'https://hr.wikipedia.org', + hrwiktionary: 'https://hr.wiktionary.org', + hrwikibooks: 'https://hr.wikibooks.org', + hrwikiquote: 'https://hr.wikiquote.org', + hrwikisource: 'https://hr.wikisource.org', + hsbwiki: 'https://hsb.wikipedia.org', + hsbwiktionary: 'https://hsb.wiktionary.org', + htwiki: 'https://ht.wikipedia.org', + htwikisource: 'https://ht.wikisource.org', + huwiki: 'https://hu.wikipedia.org', + huwiktionary: 'https://hu.wiktionary.org', + huwikibooks: 'https://hu.wikibooks.org', + huwikinews: 'https://hu.wikinews.org', + huwikiquote: 'https://hu.wikiquote.org', + huwikisource: 'https://hu.wikisource.org', + hywiki: 'https://hy.wikipedia.org', + hywiktionary: 'https://hy.wiktionary.org', + hywikibooks: 'https://hy.wikibooks.org', + hywikiquote: 'https://hy.wikiquote.org', + hywikisource: 'https://hy.wikisource.org', + hzwiki: 'https://hz.wikipedia.org', + iawiki: 'https://ia.wikipedia.org', + iawiktionary: 'https://ia.wiktionary.org', + iawikibooks: 'https://ia.wikibooks.org', + idwiki: 'https://id.wikipedia.org', + idwiktionary: 'https://id.wiktionary.org', + idwikibooks: 'https://id.wikibooks.org', + idwikiquote: 'https://id.wikiquote.org', + idwikisource: 'https://id.wikisource.org', + iewiki: 'https://ie.wikipedia.org', + iewiktionary: 'https://ie.wiktionary.org', + iewikibooks: 'https://ie.wikibooks.org', + igwiki: 'https://ig.wikipedia.org', + iiwiki: 'https://ii.wikipedia.org', + ikwiki: 'https://ik.wikipedia.org', + ikwiktionary: 'https://ik.wiktionary.org', + ilowiki: 'https://ilo.wikipedia.org', + iowiki: 'https://io.wikipedia.org', + iowiktionary: 'https://io.wiktionary.org', + iswiki: 'https://is.wikipedia.org', + iswiktionary: 'https://is.wiktionary.org', + iswikibooks: 'https://is.wikibooks.org', + iswikiquote: 'https://is.wikiquote.org', + iswikisource: 'https://is.wikisource.org', + itwiki: 'https://it.wikipedia.org', + itwiktionary: 'https://it.wiktionary.org', + itwikibooks: 'https://it.wikibooks.org', + itwikinews: 'https://it.wikinews.org', + itwikiquote: 'https://it.wikiquote.org', + itwikisource: 'https://it.wikisource.org', + itwikiversity: 'https://it.wikiversity.org', + itwikivoyage: 'https://it.wikivoyage.org', + iuwiki: 'https://iu.wikipedia.org', + iuwiktionary: 'https://iu.wiktionary.org', + jawiki: 'https://ja.wikipedia.org', + jawiktionary: 'https://ja.wiktionary.org', + jawikibooks: 'https://ja.wikibooks.org', + jawikinews: 'https://ja.wikinews.org', + jawikiquote: 'https://ja.wikiquote.org', + jawikisource: 'https://ja.wikisource.org', + jawikiversity: 'https://ja.wikiversity.org', + jbowiki: 'https://jbo.wikipedia.org', + jbowiktionary: 'https://jbo.wiktionary.org', + jvwiki: 'https://jv.wikipedia.org', + jvwiktionary: 'https://jv.wiktionary.org', + kawiki: 'https://ka.wikipedia.org', + kawiktionary: 'https://ka.wiktionary.org', + kawikibooks: 'https://ka.wikibooks.org', + kawikiquote: 'https://ka.wikiquote.org', + kaawiki: 'https://kaa.wikipedia.org', + kabwiki: 'https://kab.wikipedia.org', + kbdwiki: 'https://kbd.wikipedia.org', + kgwiki: 'https://kg.wikipedia.org', + kiwiki: 'https://ki.wikipedia.org', + kjwiki: 'https://kj.wikipedia.org', + kkwiki: 'https://kk.wikipedia.org', + kkwiktionary: 'https://kk.wiktionary.org', + kkwikibooks: 'https://kk.wikibooks.org', + kkwikiquote: 'https://kk.wikiquote.org', + klwiki: 'https://kl.wikipedia.org', + klwiktionary: 'https://kl.wiktionary.org', + kmwiki: 'https://km.wikipedia.org', + kmwiktionary: 'https://km.wiktionary.org', + kmwikibooks: 'https://km.wikibooks.org', + knwiki: 'https://kn.wikipedia.org', + knwiktionary: 'https://kn.wiktionary.org', + knwikibooks: 'https://kn.wikibooks.org', + knwikiquote: 'https://kn.wikiquote.org', + knwikisource: 'https://kn.wikisource.org', + kowiki: 'https://ko.wikipedia.org', + kowiktionary: 'https://ko.wiktionary.org', + kowikibooks: 'https://ko.wikibooks.org', + kowikinews: 'https://ko.wikinews.org', + kowikiquote: 'https://ko.wikiquote.org', + kowikisource: 'https://ko.wikisource.org', + kowikiversity: 'https://ko.wikiversity.org', + koiwiki: 'https://koi.wikipedia.org', + krwiki: 'https://kr.wikipedia.org', + krwikiquote: 'https://kr.wikiquote.org', + krcwiki: 'https://krc.wikipedia.org', + kswiki: 'https://ks.wikipedia.org', + kswiktionary: 'https://ks.wiktionary.org', + kswikibooks: 'https://ks.wikibooks.org', + kswikiquote: 'https://ks.wikiquote.org', + kshwiki: 'https://ksh.wikipedia.org', + kuwiki: 'https://ku.wikipedia.org', + kuwiktionary: 'https://ku.wiktionary.org', + kuwikibooks: 'https://ku.wikibooks.org', + kuwikiquote: 'https://ku.wikiquote.org', + kvwiki: 'https://kv.wikipedia.org', + kwwiki: 'https://kw.wikipedia.org', + kwwiktionary: 'https://kw.wiktionary.org', + kwwikiquote: 'https://kw.wikiquote.org', + kywiki: 'https://ky.wikipedia.org', + kywiktionary: 'https://ky.wiktionary.org', + kywikibooks: 'https://ky.wikibooks.org', + kywikiquote: 'https://ky.wikiquote.org', + lawiki: 'https://la.wikipedia.org', + lawiktionary: 'https://la.wiktionary.org', + lawikibooks: 'https://la.wikibooks.org', + lawikiquote: 'https://la.wikiquote.org', + lawikisource: 'https://la.wikisource.org', + ladwiki: 'https://lad.wikipedia.org', + lbwiki: 'https://lb.wikipedia.org', + lbwiktionary: 'https://lb.wiktionary.org', + lbwikibooks: 'https://lb.wikibooks.org', + lbwikiquote: 'https://lb.wikiquote.org', + lbewiki: 'https://lbe.wikipedia.org', + lezwiki: 'https://lez.wikipedia.org', + lgwiki: 'https://lg.wikipedia.org', + liwiki: 'https://li.wikipedia.org', + liwiktionary: 'https://li.wiktionary.org', + liwikibooks: 'https://li.wikibooks.org', + liwikiquote: 'https://li.wikiquote.org', + liwikisource: 'https://li.wikisource.org', + lijwiki: 'https://lij.wikipedia.org', + lmowiki: 'https://lmo.wikipedia.org', + lnwiki: 'https://ln.wikipedia.org', + lnwiktionary: 'https://ln.wiktionary.org', + lnwikibooks: 'https://ln.wikibooks.org', + lowiki: 'https://lo.wikipedia.org', + lowiktionary: 'https://lo.wiktionary.org', + ltwiki: 'https://lt.wikipedia.org', + ltwiktionary: 'https://lt.wiktionary.org', + ltwikibooks: 'https://lt.wikibooks.org', + ltwikiquote: 'https://lt.wikiquote.org', + ltwikisource: 'https://lt.wikisource.org', + ltgwiki: 'https://ltg.wikipedia.org', + lvwiki: 'https://lv.wikipedia.org', + lvwiktionary: 'https://lv.wiktionary.org', + lvwikibooks: 'https://lv.wikibooks.org', + maiwiki: 'https://mai.wikipedia.org', + map_bmswiki: 'https://map-bms.wikipedia.org', + mdfwiki: 'https://mdf.wikipedia.org', + mgwiki: 'https://mg.wikipedia.org', + mgwiktionary: 'https://mg.wiktionary.org', + mgwikibooks: 'https://mg.wikibooks.org', + mhwiki: 'https://mh.wikipedia.org', + mhwiktionary: 'https://mh.wiktionary.org', + mhrwiki: 'https://mhr.wikipedia.org', + miwiki: 'https://mi.wikipedia.org', + miwiktionary: 'https://mi.wiktionary.org', + miwikibooks: 'https://mi.wikibooks.org', + minwiki: 'https://min.wikipedia.org', + mkwiki: 'https://mk.wikipedia.org', + mkwiktionary: 'https://mk.wiktionary.org', + mkwikibooks: 'https://mk.wikibooks.org', + mkwikisource: 'https://mk.wikisource.org', + mlwiki: 'https://ml.wikipedia.org', + mlwiktionary: 'https://ml.wiktionary.org', + mlwikibooks: 'https://ml.wikibooks.org', + mlwikiquote: 'https://ml.wikiquote.org', + mlwikisource: 'https://ml.wikisource.org', + mnwiki: 'https://mn.wikipedia.org', + mnwiktionary: 'https://mn.wiktionary.org', + mnwikibooks: 'https://mn.wikibooks.org', + mowiki: 'https://mo.wikipedia.org', + mowiktionary: 'https://mo.wiktionary.org', + mrwiki: 'https://mr.wikipedia.org', + mrwiktionary: 'https://mr.wiktionary.org', + mrwikibooks: 'https://mr.wikibooks.org', + mrwikiquote: 'https://mr.wikiquote.org', + mrwikisource: 'https://mr.wikisource.org', + mrjwiki: 'https://mrj.wikipedia.org', + mswiki: 'https://ms.wikipedia.org', + mswiktionary: 'https://ms.wiktionary.org', + mswikibooks: 'https://ms.wikibooks.org', + mtwiki: 'https://mt.wikipedia.org', + mtwiktionary: 'https://mt.wiktionary.org', + muswiki: 'https://mus.wikipedia.org', + mwlwiki: 'https://mwl.wikipedia.org', + mywiki: 'https://my.wikipedia.org', + mywiktionary: 'https://my.wiktionary.org', + mywikibooks: 'https://my.wikibooks.org', + myvwiki: 'https://myv.wikipedia.org', + mznwiki: 'https://mzn.wikipedia.org', + nawiki: 'https://na.wikipedia.org', + nawiktionary: 'https://na.wiktionary.org', + nawikibooks: 'https://na.wikibooks.org', + nawikiquote: 'https://na.wikiquote.org', + nahwiki: 'https://nah.wikipedia.org', + nahwiktionary: 'https://nah.wiktionary.org', + nahwikibooks: 'https://nah.wikibooks.org', + napwiki: 'https://nap.wikipedia.org', + ndswiki: 'https://nds.wikipedia.org', + ndswiktionary: 'https://nds.wiktionary.org', + ndswikibooks: 'https://nds.wikibooks.org', + ndswikiquote: 'https://nds.wikiquote.org', + nds_nlwiki: 'https://nds-nl.wikipedia.org', + newiki: 'https://ne.wikipedia.org', + newiktionary: 'https://ne.wiktionary.org', + newikibooks: 'https://ne.wikibooks.org', + newwiki: 'https://new.wikipedia.org', + ngwiki: 'https://ng.wikipedia.org', + nlwiki: 'https://nl.wikipedia.org', + nlwiktionary: 'https://nl.wiktionary.org', + nlwikibooks: 'https://nl.wikibooks.org', + nlwikinews: 'https://nl.wikinews.org', + nlwikiquote: 'https://nl.wikiquote.org', + nlwikisource: 'https://nl.wikisource.org', + nlwikivoyage: 'https://nl.wikivoyage.org', + nnwiki: 'https://nn.wikipedia.org', + nnwiktionary: 'https://nn.wiktionary.org', + nnwikiquote: 'https://nn.wikiquote.org', + nowiki: 'https://no.wikipedia.org', + nowiktionary: 'https://no.wiktionary.org', + nowikibooks: 'https://no.wikibooks.org', + nowikinews: 'https://no.wikinews.org', + nowikiquote: 'https://no.wikiquote.org', + nowikisource: 'https://no.wikisource.org', + novwiki: 'https://nov.wikipedia.org', + nrmwiki: 'https://nrm.wikipedia.org', + nsowiki: 'https://nso.wikipedia.org', + nvwiki: 'https://nv.wikipedia.org', + nywiki: 'https://ny.wikipedia.org', + ocwiki: 'https://oc.wikipedia.org', + ocwiktionary: 'https://oc.wiktionary.org', + ocwikibooks: 'https://oc.wikibooks.org', + omwiki: 'https://om.wikipedia.org', + omwiktionary: 'https://om.wiktionary.org', + orwiki: 'https://or.wikipedia.org', + orwiktionary: 'https://or.wiktionary.org', + orwikisource: 'https://or.wikisource.org', + oswiki: 'https://os.wikipedia.org', + pawiki: 'https://pa.wikipedia.org', + pawiktionary: 'https://pa.wiktionary.org', + pawikibooks: 'https://pa.wikibooks.org', + pagwiki: 'https://pag.wikipedia.org', + pamwiki: 'https://pam.wikipedia.org', + papwiki: 'https://pap.wikipedia.org', + pcdwiki: 'https://pcd.wikipedia.org', + pdcwiki: 'https://pdc.wikipedia.org', + pflwiki: 'https://pfl.wikipedia.org', + piwiki: 'https://pi.wikipedia.org', + piwiktionary: 'https://pi.wiktionary.org', + pihwiki: 'https://pih.wikipedia.org', + plwiki: 'https://pl.wikipedia.org', + plwiktionary: 'https://pl.wiktionary.org', + plwikibooks: 'https://pl.wikibooks.org', + plwikinews: 'https://pl.wikinews.org', + plwikiquote: 'https://pl.wikiquote.org', + plwikisource: 'https://pl.wikisource.org', + plwikivoyage: 'https://pl.wikivoyage.org', + pmswiki: 'https://pms.wikipedia.org', + pnbwiki: 'https://pnb.wikipedia.org', + pnbwiktionary: 'https://pnb.wiktionary.org', + pntwiki: 'https://pnt.wikipedia.org', + pswiki: 'https://ps.wikipedia.org', + pswiktionary: 'https://ps.wiktionary.org', + pswikibooks: 'https://ps.wikibooks.org', + ptwiki: 'https://pt.wikipedia.org', + ptwiktionary: 'https://pt.wiktionary.org', + ptwikibooks: 'https://pt.wikibooks.org', + ptwikinews: 'https://pt.wikinews.org', + ptwikiquote: 'https://pt.wikiquote.org', + ptwikisource: 'https://pt.wikisource.org', + ptwikiversity: 'https://pt.wikiversity.org', + ptwikivoyage: 'https://pt.wikivoyage.org', + quwiki: 'https://qu.wikipedia.org', + quwiktionary: 'https://qu.wiktionary.org', + quwikibooks: 'https://qu.wikibooks.org', + quwikiquote: 'https://qu.wikiquote.org', + rmwiki: 'https://rm.wikipedia.org', + rmwiktionary: 'https://rm.wiktionary.org', + rmwikibooks: 'https://rm.wikibooks.org', + rmywiki: 'https://rmy.wikipedia.org', + rnwiki: 'https://rn.wikipedia.org', + rnwiktionary: 'https://rn.wiktionary.org', + rowiki: 'https://ro.wikipedia.org', + rowiktionary: 'https://ro.wiktionary.org', + rowikibooks: 'https://ro.wikibooks.org', + rowikinews: 'https://ro.wikinews.org', + rowikiquote: 'https://ro.wikiquote.org', + rowikisource: 'https://ro.wikisource.org', + rowikivoyage: 'https://ro.wikivoyage.org', + roa_rupwiki: 'https://roa-rup.wikipedia.org', + roa_rupwiktionary: 'https://roa-rup.wiktionary.org', + roa_tarawiki: 'https://roa-tara.wikipedia.org', + ruwiki: 'https://ru.wikipedia.org', + ruwiktionary: 'https://ru.wiktionary.org', + ruwikibooks: 'https://ru.wikibooks.org', + ruwikinews: 'https://ru.wikinews.org', + ruwikiquote: 'https://ru.wikiquote.org', + ruwikisource: 'https://ru.wikisource.org', + ruwikiversity: 'https://ru.wikiversity.org', + ruwikivoyage: 'https://ru.wikivoyage.org', + ruewiki: 'https://rue.wikipedia.org', + rwwiki: 'https://rw.wikipedia.org', + rwwiktionary: 'https://rw.wiktionary.org', + sawiki: 'https://sa.wikipedia.org', + sawiktionary: 'https://sa.wiktionary.org', + sawikibooks: 'https://sa.wikibooks.org', + sawikiquote: 'https://sa.wikiquote.org', + sawikisource: 'https://sa.wikisource.org', + sahwiki: 'https://sah.wikipedia.org', + sahwikisource: 'https://sah.wikisource.org', + scwiki: 'https://sc.wikipedia.org', + scwiktionary: 'https://sc.wiktionary.org', + scnwiki: 'https://scn.wikipedia.org', + scnwiktionary: 'https://scn.wiktionary.org', + scowiki: 'https://sco.wikipedia.org', + sdwiki: 'https://sd.wikipedia.org', + sdwiktionary: 'https://sd.wiktionary.org', + sdwikinews: 'https://sd.wikinews.org', + sewiki: 'https://se.wikipedia.org', + sewikibooks: 'https://se.wikibooks.org', + sgwiki: 'https://sg.wikipedia.org', + sgwiktionary: 'https://sg.wiktionary.org', + shwiki: 'https://sh.wikipedia.org', + shwiktionary: 'https://sh.wiktionary.org', + siwiki: 'https://si.wikipedia.org', + siwiktionary: 'https://si.wiktionary.org', + siwikibooks: 'https://si.wikibooks.org', + simplewiki: 'https://simple.wikipedia.org', + simplewiktionary: 'https://simple.wiktionary.org', + simplewikibooks: 'https://simple.wikibooks.org', + simplewikiquote: 'https://simple.wikiquote.org', + skwiki: 'https://sk.wikipedia.org', + skwiktionary: 'https://sk.wiktionary.org', + skwikibooks: 'https://sk.wikibooks.org', + skwikiquote: 'https://sk.wikiquote.org', + skwikisource: 'https://sk.wikisource.org', + slwiki: 'https://sl.wikipedia.org', + slwiktionary: 'https://sl.wiktionary.org', + slwikibooks: 'https://sl.wikibooks.org', + slwikiquote: 'https://sl.wikiquote.org', + slwikisource: 'https://sl.wikisource.org', + slwikiversity: 'https://sl.wikiversity.org', + smwiki: 'https://sm.wikipedia.org', + smwiktionary: 'https://sm.wiktionary.org', + snwiki: 'https://sn.wikipedia.org', + snwiktionary: 'https://sn.wiktionary.org', + sowiki: 'https://so.wikipedia.org', + sowiktionary: 'https://so.wiktionary.org', + sqwiki: 'https://sq.wikipedia.org', + sqwiktionary: 'https://sq.wiktionary.org', + sqwikibooks: 'https://sq.wikibooks.org', + sqwikinews: 'https://sq.wikinews.org', + sqwikiquote: 'https://sq.wikiquote.org', + srwiki: 'https://sr.wikipedia.org', + srwiktionary: 'https://sr.wiktionary.org', + srwikibooks: 'https://sr.wikibooks.org', + srwikinews: 'https://sr.wikinews.org', + srwikiquote: 'https://sr.wikiquote.org', + srwikisource: 'https://sr.wikisource.org', + srnwiki: 'https://srn.wikipedia.org', + sswiki: 'https://ss.wikipedia.org', + sswiktionary: 'https://ss.wiktionary.org', + stwiki: 'https://st.wikipedia.org', + stwiktionary: 'https://st.wiktionary.org', + stqwiki: 'https://stq.wikipedia.org', + suwiki: 'https://su.wikipedia.org', + suwiktionary: 'https://su.wiktionary.org', + suwikibooks: 'https://su.wikibooks.org', + suwikiquote: 'https://su.wikiquote.org', + svwiki: 'https://sv.wikipedia.org', + svwiktionary: 'https://sv.wiktionary.org', + svwikibooks: 'https://sv.wikibooks.org', + svwikinews: 'https://sv.wikinews.org', + svwikiquote: 'https://sv.wikiquote.org', + svwikisource: 'https://sv.wikisource.org', + svwikiversity: 'https://sv.wikiversity.org', + svwikivoyage: 'https://sv.wikivoyage.org', + swwiki: 'https://sw.wikipedia.org', + swwiktionary: 'https://sw.wiktionary.org', + swwikibooks: 'https://sw.wikibooks.org', + szlwiki: 'https://szl.wikipedia.org', + tawiki: 'https://ta.wikipedia.org', + tawiktionary: 'https://ta.wiktionary.org', + tawikibooks: 'https://ta.wikibooks.org', + tawikinews: 'https://ta.wikinews.org', + tawikiquote: 'https://ta.wikiquote.org', + tawikisource: 'https://ta.wikisource.org', + tewiki: 'https://te.wikipedia.org', + tewiktionary: 'https://te.wiktionary.org', + tewikibooks: 'https://te.wikibooks.org', + tewikiquote: 'https://te.wikiquote.org', + tewikisource: 'https://te.wikisource.org', + tetwiki: 'https://tet.wikipedia.org', + tgwiki: 'https://tg.wikipedia.org', + tgwiktionary: 'https://tg.wiktionary.org', + tgwikibooks: 'https://tg.wikibooks.org', + thwiki: 'https://th.wikipedia.org', + thwiktionary: 'https://th.wiktionary.org', + thwikibooks: 'https://th.wikibooks.org', + thwikinews: 'https://th.wikinews.org', + thwikiquote: 'https://th.wikiquote.org', + thwikisource: 'https://th.wikisource.org', + tiwiki: 'https://ti.wikipedia.org', + tiwiktionary: 'https://ti.wiktionary.org', + tkwiki: 'https://tk.wikipedia.org', + tkwiktionary: 'https://tk.wiktionary.org', + tkwikibooks: 'https://tk.wikibooks.org', + tkwikiquote: 'https://tk.wikiquote.org', + tlwiki: 'https://tl.wikipedia.org', + tlwiktionary: 'https://tl.wiktionary.org', + tlwikibooks: 'https://tl.wikibooks.org', + tnwiki: 'https://tn.wikipedia.org', + tnwiktionary: 'https://tn.wiktionary.org', + towiki: 'https://to.wikipedia.org', + towiktionary: 'https://to.wiktionary.org', + tpiwiki: 'https://tpi.wikipedia.org', + tpiwiktionary: 'https://tpi.wiktionary.org', + trwiki: 'https://tr.wikipedia.org', + trwiktionary: 'https://tr.wiktionary.org', + trwikibooks: 'https://tr.wikibooks.org', + trwikinews: 'https://tr.wikinews.org', + trwikiquote: 'https://tr.wikiquote.org', + trwikisource: 'https://tr.wikisource.org', + tswiki: 'https://ts.wikipedia.org', + tswiktionary: 'https://ts.wiktionary.org', + ttwiki: 'https://tt.wikipedia.org', + ttwiktionary: 'https://tt.wiktionary.org', + ttwikibooks: 'https://tt.wikibooks.org', + ttwikiquote: 'https://tt.wikiquote.org', + tumwiki: 'https://tum.wikipedia.org', + twwiki: 'https://tw.wikipedia.org', + twwiktionary: 'https://tw.wiktionary.org', + tywiki: 'https://ty.wikipedia.org', + tyvwiki: 'https://tyv.wikipedia.org', + udmwiki: 'https://udm.wikipedia.org', + ugwiki: 'https://ug.wikipedia.org', + ugwiktionary: 'https://ug.wiktionary.org', + ugwikibooks: 'https://ug.wikibooks.org', + ugwikiquote: 'https://ug.wikiquote.org', + ukwiki: 'https://uk.wikipedia.org', + ukwiktionary: 'https://uk.wiktionary.org', + ukwikibooks: 'https://uk.wikibooks.org', + ukwikinews: 'https://uk.wikinews.org', + ukwikiquote: 'https://uk.wikiquote.org', + ukwikisource: 'https://uk.wikisource.org', + ukwikivoyage: 'https://uk.wikivoyage.org', + urwiki: 'https://ur.wikipedia.org', + urwiktionary: 'https://ur.wiktionary.org', + urwikibooks: 'https://ur.wikibooks.org', + urwikiquote: 'https://ur.wikiquote.org', + uzwiki: 'https://uz.wikipedia.org', + uzwiktionary: 'https://uz.wiktionary.org', + uzwikibooks: 'https://uz.wikibooks.org', + uzwikiquote: 'https://uz.wikiquote.org', + vewiki: 'https://ve.wikipedia.org', + vecwiki: 'https://vec.wikipedia.org', + vecwiktionary: 'https://vec.wiktionary.org', + vecwikisource: 'https://vec.wikisource.org', + vepwiki: 'https://vep.wikipedia.org', + viwiki: 'https://vi.wikipedia.org', + viwiktionary: 'https://vi.wiktionary.org', + viwikibooks: 'https://vi.wikibooks.org', + viwikiquote: 'https://vi.wikiquote.org', + viwikisource: 'https://vi.wikisource.org', + viwikivoyage: 'https://vi.wikivoyage.org', + vlswiki: 'https://vls.wikipedia.org', + vowiki: 'https://vo.wikipedia.org', + vowiktionary: 'https://vo.wiktionary.org', + vowikibooks: 'https://vo.wikibooks.org', + vowikiquote: 'https://vo.wikiquote.org', + wawiki: 'https://wa.wikipedia.org', + wawiktionary: 'https://wa.wiktionary.org', + wawikibooks: 'https://wa.wikibooks.org', + warwiki: 'https://war.wikipedia.org', + wowiki: 'https://wo.wikipedia.org', + wowiktionary: 'https://wo.wiktionary.org', + wowikiquote: 'https://wo.wikiquote.org', + wuuwiki: 'https://wuu.wikipedia.org', + xalwiki: 'https://xal.wikipedia.org', + xhwiki: 'https://xh.wikipedia.org', + xhwiktionary: 'https://xh.wiktionary.org', + xhwikibooks: 'https://xh.wikibooks.org', + xmfwiki: 'https://xmf.wikipedia.org', + yiwiki: 'https://yi.wikipedia.org', + yiwiktionary: 'https://yi.wiktionary.org', + yiwikisource: 'https://yi.wikisource.org', + yowiki: 'https://yo.wikipedia.org', + yowiktionary: 'https://yo.wiktionary.org', + yowikibooks: 'https://yo.wikibooks.org', + zawiki: 'https://za.wikipedia.org', + zawiktionary: 'https://za.wiktionary.org', + zawikibooks: 'https://za.wikibooks.org', + zawikiquote: 'https://za.wikiquote.org', + zeawiki: 'https://zea.wikipedia.org', + zhwiki: 'https://zh.wikipedia.org', + zhwiktionary: 'https://zh.wiktionary.org', + zhwikibooks: 'https://zh.wikibooks.org', + zhwikinews: 'https://zh.wikinews.org', + zhwikiquote: 'https://zh.wikiquote.org', + zhwikisource: 'https://zh.wikisource.org', + zhwikivoyage: 'https://zh.wikivoyage.org', + zh_classicalwiki: 'https://zh-classical.wikipedia.org', + zh_min_nanwiki: 'https://zh-min-nan.wikipedia.org', + zh_min_nanwiktionary: 'https://zh-min-nan.wiktionary.org', + zh_min_nanwikibooks: 'https://zh-min-nan.wikibooks.org', + zh_min_nanwikiquote: 'https://zh-min-nan.wikiquote.org', + zh_min_nanwikisource: 'https://zh-min-nan.wikisource.org', + zh_yuewiki: 'https://zh-yue.wikipedia.org', + zuwiki: 'https://zu.wikipedia.org', + zuwiktionary: 'https://zu.wiktionary.org', + zuwikibooks: 'https://zu.wikibooks.org' }; if (typeof module !== 'undefined' && module.exports) { module.exports = site_map; diff --git a/src/lib/fetch_text.js b/src/lib/fetch_text.js index 6532305f..65a62ac1 100644 --- a/src/lib/fetch_text.js +++ b/src/lib/fetch_text.js @@ -1,16 +1,16 @@ 'use strict'; //grab the content of any article, off the api -var request = require('superagent'); -var site_map = require('../data/site_map'); -var redirects = require('../parse/parse_redirects'); +const request = require('superagent'); +const site_map = require('../data/site_map'); +const redirects = require('../parse/parse_redirects'); -var fetch = function(page_identifier, lang_or_wikiid, cb) { +const fetch = function(page_identifier, lang_or_wikiid, cb) { lang_or_wikiid = lang_or_wikiid || 'en'; var identifier_type = 'titles'; if (page_identifier.match(/^[0-9]*$/) && page_identifier.length > 3) { identifier_type = 'curid'; } - var url; + let url; if (site_map[lang_or_wikiid]) { url = site_map[lang_or_wikiid] + '/w/api.php'; } else { @@ -20,31 +20,29 @@ var fetch = function(page_identifier, lang_or_wikiid, cb) { url += '?action=query&prop=revisions&rvlimit=1&rvprop=content&format=json&origin=*'; url += '&' + identifier_type + '=' + encodeURIComponent(page_identifier); - request - .get(url) - .end(function(err, res) { - if (err) { - console.warn(err); - cb(null); - return; - } - var pages = res.body.query.pages || {}; - var id = Object.keys(pages)[0]; - if (id) { - var page = pages[id]; - if (page && page.revisions && page.revisions[0]) { - var text = page.revisions[0]['*']; - if (redirects.is_redirect(text)) { - var result = redirects.parse_redirect(text); - fetch(result.redirect, lang_or_wikiid, cb); //recursive - return; - } - cb(text); - } else { - cb(null); + request.get(url).end(function(err, res) { + if (err) { + console.warn(err); + cb(null); + return; + } + var pages = res.body.query.pages || {}; + var id = Object.keys(pages)[0]; + if (id) { + var page = pages[id]; + if (page && page.revisions && page.revisions[0]) { + var text = page.revisions[0]['*']; + if (redirects.is_redirect(text)) { + var result = redirects.parse_redirect(text); + fetch(result.redirect, lang_or_wikiid, cb); //recursive + return; } + cb(text); + } else { + cb(null); } - }); + } + }); }; module.exports = fetch; diff --git a/src/lib/hashes.js b/src/lib/hashes.js deleted file mode 100644 index 3d3755a2..00000000 --- a/src/lib/hashes.js +++ /dev/null @@ -1,1765 +0,0 @@ -/** - * jshashes - https://github.com/h2non/jshashes - * Released under the "New BSD" license - * - * Algorithms specification: - * - * MD5 - http://www.ietf.org/rfc/rfc1321.txt - * RIPEMD-160 - http://homes.esat.kuleuven.be/~bosselae/ripemd160.html - * SHA1 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf - * SHA256 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf - * SHA512 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf - * HMAC - http://www.ietf.org/rfc/rfc2104.txt - */ -(function() { - var Hashes; - - function utf8Encode(str) { - var x, y, output = '', - i = -1, - l; - - if (str && str.length) { - l = str.length; - while ((i += 1) < l) { - /* Decode utf-16 surrogate pairs */ - x = str.charCodeAt(i); - y = i + 1 < l ? str.charCodeAt(i + 1) : 0; - if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) { - x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF); - i += 1; - } - /* Encode output as utf-8 */ - if (x <= 0x7F) { - output += String.fromCharCode(x); - } else if (x <= 0x7FF) { - output += String.fromCharCode(0xC0 | ((x >>> 6) & 0x1F), - 0x80 | (x & 0x3F)); - } else if (x <= 0xFFFF) { - output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F), - 0x80 | ((x >>> 6) & 0x3F), - 0x80 | (x & 0x3F)); - } else if (x <= 0x1FFFFF) { - output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07), - 0x80 | ((x >>> 12) & 0x3F), - 0x80 | ((x >>> 6) & 0x3F), - 0x80 | (x & 0x3F)); - } - } - } - return output; - } - - function utf8Decode(str) { - var i, ac, c1, c2, c3, arr = [], - l; - i = ac = c1 = c2 = c3 = 0; - - if (str && str.length) { - l = str.length; - str += ''; - - while (i < l) { - c1 = str.charCodeAt(i); - ac += 1; - if (c1 < 128) { - arr[ac] = String.fromCharCode(c1); - i += 1; - } else if (c1 > 191 && c1 < 224) { - c2 = str.charCodeAt(i + 1); - arr[ac] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63)); - i += 2; - } else { - c2 = str.charCodeAt(i + 1); - c3 = str.charCodeAt(i + 2); - arr[ac] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); - i += 3; - } - } - } - return arr.join(''); - } - - /** - * Add integers, wrapping at 2^32. This uses 16-bit operations internally - * to work around bugs in some JS interpreters. - */ - - function safe_add(x, y) { - var lsw = (x & 0xFFFF) + (y & 0xFFFF), - msw = (x >> 16) + (y >> 16) + (lsw >> 16); - return (msw << 16) | (lsw & 0xFFFF); - } - - /** - * Bitwise rotate a 32-bit number to the left. - */ - - function bit_rol(num, cnt) { - return (num << cnt) | (num >>> (32 - cnt)); - } - - /** - * Convert a raw string to a hex string - */ - - function rstr2hex(input, hexcase) { - var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef', - output = '', - x, i = 0, - l = input.length; - for (; i < l; i += 1) { - x = input.charCodeAt(i); - output += hex_tab.charAt((x >>> 4) & 0x0F) + hex_tab.charAt(x & 0x0F); - } - return output; - } - - /** - * Encode a string as utf-16 - */ - - function str2rstr_utf16le(input) { - var i, l = input.length, - output = ''; - for (i = 0; i < l; i += 1) { - output += String.fromCharCode(input.charCodeAt(i) & 0xFF, (input.charCodeAt(i) >>> 8) & 0xFF); - } - return output; - } - - function str2rstr_utf16be(input) { - var i, l = input.length, - output = ''; - for (i = 0; i < l; i += 1) { - output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF, input.charCodeAt(i) & 0xFF); - } - return output; - } - - /** - * Convert an array of big-endian words to a string - */ - - function binb2rstr(input) { - var i, l = input.length * 32, - output = ''; - for (i = 0; i < l; i += 8) { - output += String.fromCharCode((input[i >> 5] >>> (24 - i % 32)) & 0xFF); - } - return output; - } - - /** - * Convert an array of little-endian words to a string - */ - - function binl2rstr(input) { - var i, l = input.length * 32, - output = ''; - for (i = 0; i < l; i += 8) { - output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF); - } - return output; - } - - /** - * Convert a raw string to an array of little-endian words - * Characters >255 have their high-byte silently ignored. - */ - - function rstr2binl(input) { - var i, l = input.length * 8, - output = Array(input.length >> 2), - lo = output.length; - for (i = 0; i < lo; i += 1) { - output[i] = 0; - } - for (i = 0; i < l; i += 8) { - output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32); - } - return output; - } - - /** - * Convert a raw string to an array of big-endian words - * Characters >255 have their high-byte silently ignored. - */ - - function rstr2binb(input) { - var i, l = input.length * 8, - output = Array(input.length >> 2), - lo = output.length; - for (i = 0; i < lo; i += 1) { - output[i] = 0; - } - for (i = 0; i < l; i += 8) { - output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32); - } - return output; - } - - /** - * Convert a raw string to an arbitrary string encoding - */ - - function rstr2any(input, encoding) { - var divisor = encoding.length, - remainders = Array(), - i, q, x, ld, quotient, dividend, output, full_length; - - /* Convert to an array of 16-bit big-endian values, forming the dividend */ - dividend = Array(Math.ceil(input.length / 2)); - ld = dividend.length; - for (i = 0; i < ld; i += 1) { - dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1); - } - - /** - * Repeatedly perform a long division. The binary array forms the dividend, - * the length of the encoding is the divisor. Once computed, the quotient - * forms the dividend for the next step. We stop when the dividend is zerHashes. - * All remainders are stored for later use. - */ - while (dividend.length > 0) { - quotient = Array(); - x = 0; - for (i = 0; i < dividend.length; i += 1) { - x = (x << 16) + dividend[i]; - q = Math.floor(x / divisor); - x -= q * divisor; - if (quotient.length > 0 || q > 0) { - quotient[quotient.length] = q; - } - } - remainders[remainders.length] = x; - dividend = quotient; - } - - /* Convert the remainders to the output string */ - output = ''; - for (i = remainders.length - 1; i >= 0; i--) { - output += encoding.charAt(remainders[i]); - } - - /* Append leading zero equivalents */ - full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2))); - for (i = output.length; i < full_length; i += 1) { - output = encoding[0] + output; - } - return output; - } - - /** - * Convert a raw string to a base-64 string - */ - - function rstr2b64(input, b64pad) { - var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', - output = '', - len = input.length, - i, j, triplet; - b64pad = b64pad || '='; - for (i = 0; i < len; i += 3) { - triplet = (input.charCodeAt(i) << 16) | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0); - for (j = 0; j < 4; j += 1) { - if (i * 8 + j * 6 > input.length * 8) { - output += b64pad; - } else { - output += tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F); - } - } - } - return output; - } - - Hashes = { - /** - * @property {String} version - * @readonly - */ - VERSION: '1.0.5', - /** - * @member Hashes - * @class Base64 - * @constructor - */ - Base64: function() { - // private properties - var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', - pad = '=', // default pad according with the RFC standard - url = false, // URL encoding support @todo - utf8 = true; // by default enable UTF-8 support encoding - - // public method for encoding - this.encode = function(input) { - var i, j, triplet, - output = '', - len = input.length; - - pad = pad || '='; - input = (utf8) ? utf8Encode(input) : input; - - for (i = 0; i < len; i += 3) { - triplet = (input.charCodeAt(i) << 16) | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0); - for (j = 0; j < 4; j += 1) { - if (i * 8 + j * 6 > len * 8) { - output += pad; - } else { - output += tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F); - } - } - } - return output; - }; - - // public method for decoding - this.decode = function(input) { - // var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; - var i, o1, o2, o3, h1, h2, h3, h4, bits, ac, - dec = '', - arr = []; - if (!input) { - return input; - } - - i = ac = 0; - input = input.replace(new RegExp('\\' + pad, 'gi'), ''); // use '=' - //input += ''; - - do { // unpack four hexets into three octets using index points in b64 - h1 = tab.indexOf(input.charAt(i += 1)); - h2 = tab.indexOf(input.charAt(i += 1)); - h3 = tab.indexOf(input.charAt(i += 1)); - h4 = tab.indexOf(input.charAt(i += 1)); - - bits = h1 << 18 | h2 << 12 | h3 << 6 | h4; - - o1 = bits >> 16 & 0xff; - o2 = bits >> 8 & 0xff; - o3 = bits & 0xff; - ac += 1; - - if (h3 === 64) { - arr[ac] = String.fromCharCode(o1); - } else if (h4 === 64) { - arr[ac] = String.fromCharCode(o1, o2); - } else { - arr[ac] = String.fromCharCode(o1, o2, o3); - } - } while (i < input.length); - - dec = arr.join(''); - dec = (utf8) ? utf8Decode(dec) : dec; - - return dec; - }; - - // set custom pad string - this.setPad = function(str) { - pad = str || pad; - return this; - }; - // set custom tab string characters - this.setTab = function(str) { - tab = str || tab; - return this; - }; - this.setUTF8 = function(bool) { - if (typeof bool === 'boolean') { - utf8 = bool; - } - return this; - }; - }, - - /** - * CRC-32 calculation - * @member Hashes - * @method CRC32 - * @static - * @param {String} str Input String - * @return {String} - */ - CRC32: function(str) { - var crc = 0, - x = 0, - y = 0, - table, i, iTop; - str = utf8Encode(str); - - table = [ - '00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 ', - '79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 ', - '84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F ', - '63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD ', - 'A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC ', - '51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 ', - 'B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 ', - '06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 ', - 'E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 ', - '12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 ', - 'D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 ', - '33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 ', - 'CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 ', - '9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E ', - '7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D ', - '806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 ', - '60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA ', - 'AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 ', - '5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 ', - 'B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 ', - '05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 ', - 'F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA ', - '11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 ', - 'D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F ', - '30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E ', - 'C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D' - ].join(''); - - crc = crc ^ (-1); - for (i = 0, iTop = str.length; i < iTop; i += 1) { - y = (crc ^ str.charCodeAt(i)) & 0xFF; - x = '0x' + table.substr(y * 9, 8); - crc = (crc >>> 8) ^ x; - } - // always return a positive number (that's what >>> 0 does) - return (crc ^ (-1)) >>> 0; - }, - /** - * @member Hashes - * @class MD5 - * @constructor - * @param {Object} [config] - * - * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message - * Digest Algorithm, as defined in RFC 1321. - * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 - * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet - * See for more infHashes. - */ - MD5: function(options) { - /** - * Private config properties. You may need to tweak these to be compatible with - * the server-side, but the defaults work in most cases. - * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase} - */ - var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase - b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance - utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding - - // privileged (public) methods - this.hex = function(s) { - return rstr2hex(rstr(s, utf8), hexcase); - }; - this.b64 = function(s) { - return rstr2b64(rstr(s), b64pad); - }; - this.any = function(s, e) { - return rstr2any(rstr(s, utf8), e); - }; - this.raw = function(s) { - return rstr(s, utf8); - }; - this.hex_hmac = function(k, d) { - return rstr2hex(rstr_hmac(k, d), hexcase); - }; - this.b64_hmac = function(k, d) { - return rstr2b64(rstr_hmac(k, d), b64pad); - }; - this.any_hmac = function(k, d, e) { - return rstr2any(rstr_hmac(k, d), e); - }; - /** - * Perform a simple self-test to see if the VM is working - * @return {String} Hexadecimal hash sample - */ - this.vm_test = function() { - return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72'; - }; - /** - * Enable/disable uppercase hexadecimal returned string - * @param {Boolean} - * @return {Object} this - */ - this.setUpperCase = function(a) { - if (typeof a === 'boolean') { - hexcase = a; - } - return this; - }; - /** - * Defines a base64 pad string - * @param {String} Pad - * @return {Object} this - */ - this.setPad = function(a) { - b64pad = a || b64pad; - return this; - }; - /** - * Defines a base64 pad string - * @param {Boolean} - * @return {Object} [this] - */ - this.setUTF8 = function(a) { - if (typeof a === 'boolean') { - utf8 = a; - } - return this; - }; - - // private methods - - /** - * Calculate the MD5 of a raw string - */ - - function rstr(s) { - s = (utf8) ? utf8Encode(s) : s; - return binl2rstr(binl(rstr2binl(s), s.length * 8)); - } - - /** - * Calculate the HMAC-MD5, of a key and some data (raw strings) - */ - - function rstr_hmac(key, data) { - var bkey, ipad, opad, hash, i; - - key = (utf8) ? utf8Encode(key) : key; - data = (utf8) ? utf8Encode(data) : data; - bkey = rstr2binl(key); - if (bkey.length > 16) { - bkey = binl(bkey, key.length * 8); - } - - ipad = Array(16), opad = Array(16); - for (i = 0; i < 16; i += 1) { - ipad[i] = bkey[i] ^ 0x36363636; - opad[i] = bkey[i] ^ 0x5C5C5C5C; - } - hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8); - return binl2rstr(binl(opad.concat(hash), 512 + 128)); - } - - /** - * Calculate the MD5 of an array of little-endian words, and a bit length. - */ - - function binl(x, len) { - var i, olda, oldb, oldc, oldd, - a = 1732584193, - b = -271733879, - c = -1732584194, - d = 271733878; - - /* append padding */ - x[len >> 5] |= 0x80 << ((len) % 32); - x[(((len + 64) >>> 9) << 4) + 14] = len; - - for (i = 0; i < x.length; i += 16) { - olda = a; - oldb = b; - oldc = c; - oldd = d; - - a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936); - d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586); - c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819); - b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330); - a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897); - d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426); - c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341); - b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983); - a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416); - d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417); - c = md5_ff(c, d, a, b, x[i + 10], 17, -42063); - b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162); - a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682); - d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101); - c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290); - b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329); - - a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510); - d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632); - c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713); - b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302); - a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691); - d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083); - c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335); - b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848); - a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438); - d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690); - c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961); - b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501); - a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467); - d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784); - c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473); - b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734); - - a = md5_hh(a, b, c, d, x[i + 5], 4, -378558); - d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463); - c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562); - b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556); - a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060); - d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353); - c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632); - b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640); - a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174); - d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222); - c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979); - b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189); - a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487); - d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835); - c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520); - b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651); - - a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844); - d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415); - c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905); - b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055); - a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571); - d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606); - c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523); - b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799); - a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359); - d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744); - c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380); - b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649); - a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070); - d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379); - c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259); - b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551); - - a = safe_add(a, olda); - b = safe_add(b, oldb); - c = safe_add(c, oldc); - d = safe_add(d, oldd); - } - return Array(a, b, c, d); - } - - /** - * These functions implement the four basic operations the algorithm uses. - */ - - function md5_cmn(q, a, b, x, s, t) { - return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b); - } - - function md5_ff(a, b, c, d, x, s, t) { - return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); - } - - function md5_gg(a, b, c, d, x, s, t) { - return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); - } - - function md5_hh(a, b, c, d, x, s, t) { - return md5_cmn(b ^ c ^ d, a, b, x, s, t); - } - - function md5_ii(a, b, c, d, x, s, t) { - return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); - } - }, - /** - * @member Hashes - * @class Hashes.SHA1 - * @param {Object} [config] - * @constructor - * - * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS 180-1 - * Version 2.2 Copyright Paul Johnston 2000 - 2009. - * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet - * See http://pajhome.org.uk/crypt/md5 for details. - */ - SHA1: function(options) { - /** - * Private config properties. You may need to tweak these to be compatible with - * the server-side, but the defaults work in most cases. - * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase} - */ - var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase - b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance - utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding - - // public methods - this.hex = function(s) { - return rstr2hex(rstr(s, utf8), hexcase); - }; - this.b64 = function(s) { - return rstr2b64(rstr(s, utf8), b64pad); - }; - this.any = function(s, e) { - return rstr2any(rstr(s, utf8), e); - }; - this.raw = function(s) { - return rstr(s, utf8); - }; - this.hex_hmac = function(k, d) { - return rstr2hex(rstr_hmac(k, d)); - }; - this.b64_hmac = function(k, d) { - return rstr2b64(rstr_hmac(k, d), b64pad); - }; - this.any_hmac = function(k, d, e) { - return rstr2any(rstr_hmac(k, d), e); - }; - /** - * Perform a simple self-test to see if the VM is working - * @return {String} Hexadecimal hash sample - * @public - */ - this.vm_test = function() { - return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72'; - }; - /** - * @description Enable/disable uppercase hexadecimal returned string - * @param {boolean} - * @return {Object} this - * @public - */ - this.setUpperCase = function(a) { - if (typeof a === 'boolean') { - hexcase = a; - } - return this; - }; - /** - * @description Defines a base64 pad string - * @param {string} Pad - * @return {Object} this - * @public - */ - this.setPad = function(a) { - b64pad = a || b64pad; - return this; - }; - /** - * @description Defines a base64 pad string - * @param {boolean} - * @return {Object} this - * @public - */ - this.setUTF8 = function(a) { - if (typeof a === 'boolean') { - utf8 = a; - } - return this; - }; - - // private methods - - /** - * Calculate the SHA-512 of a raw string - */ - - function rstr(s) { - s = (utf8) ? utf8Encode(s) : s; - return binb2rstr(binb(rstr2binb(s), s.length * 8)); - } - - /** - * Calculate the HMAC-SHA1 of a key and some data (raw strings) - */ - - function rstr_hmac(key, data) { - var bkey, ipad, opad, i, hash; - key = (utf8) ? utf8Encode(key) : key; - data = (utf8) ? utf8Encode(data) : data; - bkey = rstr2binb(key); - - if (bkey.length > 16) { - bkey = binb(bkey, key.length * 8); - } - ipad = Array(16), opad = Array(16); - for (i = 0; i < 16; i += 1) { - ipad[i] = bkey[i] ^ 0x36363636; - opad[i] = bkey[i] ^ 0x5C5C5C5C; - } - hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8); - return binb2rstr(binb(opad.concat(hash), 512 + 160)); - } - - /** - * Calculate the SHA-1 of an array of big-endian words, and a bit length - */ - - function binb(x, len) { - var i, j, t, olda, oldb, oldc, oldd, olde, - w = Array(80), - a = 1732584193, - b = -271733879, - c = -1732584194, - d = 271733878, - e = -1009589776; - - /* append padding */ - x[len >> 5] |= 0x80 << (24 - len % 32); - x[((len + 64 >> 9) << 4) + 15] = len; - - for (i = 0; i < x.length; i += 16) { - olda = a, - oldb = b; - oldc = c; - oldd = d; - olde = e; - - for (j = 0; j < 80; j += 1) { - if (j < 16) { - w[j] = x[i + j]; - } else { - w[j] = bit_rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1); - } - t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)), - safe_add(safe_add(e, w[j]), sha1_kt(j))); - e = d; - d = c; - c = bit_rol(b, 30); - b = a; - a = t; - } - - a = safe_add(a, olda); - b = safe_add(b, oldb); - c = safe_add(c, oldc); - d = safe_add(d, oldd); - e = safe_add(e, olde); - } - return Array(a, b, c, d, e); - } - - /** - * Perform the appropriate triplet combination function for the current - * iteration - */ - - function sha1_ft(t, b, c, d) { - if (t < 20) { - return (b & c) | ((~b) & d); - } - if (t < 40) { - return b ^ c ^ d; - } - if (t < 60) { - return (b & c) | (b & d) | (c & d); - } - return b ^ c ^ d; - } - - /** - * Determine the appropriate additive constant for the current iteration - */ - - function sha1_kt(t) { - return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : - (t < 60) ? -1894007588 : -899497514; - } - }, - /** - * @class Hashes.SHA256 - * @param {config} - * - * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined in FIPS 180-2 - * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009. - * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet - * See http://pajhome.org.uk/crypt/md5 for details. - * Also http://anmar.eu.org/projects/jssha2/ - */ - SHA256: function(options) { - /** - * Private properties configuration variables. You may need to tweak these to be compatible with - * the server-side, but the defaults work in most cases. - * @see this.setUpperCase() method - * @see this.setPad() method - */ - var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase */ - b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', - /* base-64 pad character. Default '=' for strict RFC compliance */ - utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, - /* enable/disable utf8 encoding */ - sha256_K; - - /* privileged (public) methods */ - this.hex = function(s) { - return rstr2hex(rstr(s, utf8)); - }; - this.b64 = function(s) { - return rstr2b64(rstr(s, utf8), b64pad); - }; - this.any = function(s, e) { - return rstr2any(rstr(s, utf8), e); - }; - this.raw = function(s) { - return rstr(s, utf8); - }; - this.hex_hmac = function(k, d) { - return rstr2hex(rstr_hmac(k, d)); - }; - this.b64_hmac = function(k, d) { - return rstr2b64(rstr_hmac(k, d), b64pad); - }; - this.any_hmac = function(k, d, e) { - return rstr2any(rstr_hmac(k, d), e); - }; - /** - * Perform a simple self-test to see if the VM is working - * @return {String} Hexadecimal hash sample - * @public - */ - this.vm_test = function() { - return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72'; - }; - /** - * Enable/disable uppercase hexadecimal returned string - * @param {boolean} - * @return {Object} this - * @public - */ - this.setUpperCase = function(a) { - if (typeof a === 'boolean') { - hexcase = a; - } - return this; - }; - /** - * @description Defines a base64 pad string - * @param {string} Pad - * @return {Object} this - * @public - */ - this.setPad = function(a) { - b64pad = a || b64pad; - return this; - }; - /** - * Defines a base64 pad string - * @param {boolean} - * @return {Object} this - * @public - */ - this.setUTF8 = function(a) { - if (typeof a === 'boolean') { - utf8 = a; - } - return this; - }; - - // private methods - - /** - * Calculate the SHA-512 of a raw string - */ - - function rstr(s, utf8) { - s = (utf8) ? utf8Encode(s) : s; - return binb2rstr(binb(rstr2binb(s), s.length * 8)); - } - - /** - * Calculate the HMAC-sha256 of a key and some data (raw strings) - */ - - function rstr_hmac(key, data) { - key = (utf8) ? utf8Encode(key) : key; - data = (utf8) ? utf8Encode(data) : data; - var hash, i = 0, - bkey = rstr2binb(key), - ipad = Array(16), - opad = Array(16); - - if (bkey.length > 16) { - bkey = binb(bkey, key.length * 8); - } - - for (; i < 16; i += 1) { - ipad[i] = bkey[i] ^ 0x36363636; - opad[i] = bkey[i] ^ 0x5C5C5C5C; - } - - hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8); - return binb2rstr(binb(opad.concat(hash), 512 + 256)); - } - - /* - * Main sha256 function, with its support functions - */ - - function sha256_S(X, n) { - return (X >>> n) | (X << (32 - n)); - } - - function sha256_R(X, n) { - return (X >>> n); - } - - function sha256_Ch(x, y, z) { - return ((x & y) ^ ((~x) & z)); - } - - function sha256_Maj(x, y, z) { - return ((x & y) ^ (x & z) ^ (y & z)); - } - - function sha256_Sigma0256(x) { - return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22)); - } - - function sha256_Sigma1256(x) { - return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25)); - } - - function sha256_Gamma0256(x) { - return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3)); - } - - function sha256_Gamma1256(x) { - return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10)); - } - - function sha256_Sigma0512(x) { - return (sha256_S(x, 28) ^ sha256_S(x, 34) ^ sha256_S(x, 39)); - } - - function sha256_Sigma1512(x) { - return (sha256_S(x, 14) ^ sha256_S(x, 18) ^ sha256_S(x, 41)); - } - - function sha256_Gamma0512(x) { - return (sha256_S(x, 1) ^ sha256_S(x, 8) ^ sha256_R(x, 7)); - } - - function sha256_Gamma1512(x) { - return (sha256_S(x, 19) ^ sha256_S(x, 61) ^ sha256_R(x, 6)); - } - - sha256_K = [ - 1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993, -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987, - 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522, - 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585, - 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291, - 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885, -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344, - 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218, - 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872, -1866530822, -1538233109, -1090935817, -965641998 - ]; - - function binb(m, l) { - var HASH = [1779033703, -1150833019, 1013904242, -1521486534, - 1359893119, -1694144372, 528734635, 1541459225 - ]; - var W = new Array(64); - var a, b, c, d, e, f, g, h; - var i, j, T1, T2; - - /* append padding */ - m[l >> 5] |= 0x80 << (24 - l % 32); - m[((l + 64 >> 9) << 4) + 15] = l; - - for (i = 0; i < m.length; i += 16) { - a = HASH[0]; - b = HASH[1]; - c = HASH[2]; - d = HASH[3]; - e = HASH[4]; - f = HASH[5]; - g = HASH[6]; - h = HASH[7]; - - for (j = 0; j < 64; j += 1) { - if (j < 16) { - W[j] = m[j + i]; - } else { - W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]), - sha256_Gamma0256(W[j - 15])), W[j - 16]); - } - - T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)), - sha256_K[j]), W[j]); - T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c)); - h = g; - g = f; - f = e; - e = safe_add(d, T1); - d = c; - c = b; - b = a; - a = safe_add(T1, T2); - } - - HASH[0] = safe_add(a, HASH[0]); - HASH[1] = safe_add(b, HASH[1]); - HASH[2] = safe_add(c, HASH[2]); - HASH[3] = safe_add(d, HASH[3]); - HASH[4] = safe_add(e, HASH[4]); - HASH[5] = safe_add(f, HASH[5]); - HASH[6] = safe_add(g, HASH[6]); - HASH[7] = safe_add(h, HASH[7]); - } - return HASH; - } - - }, - - /** - * @class Hashes.SHA512 - * @param {config} - * - * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined in FIPS 180-2 - * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009. - * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet - * See http://pajhome.org.uk/crypt/md5 for details. - */ - SHA512: function(options) { - /** - * Private properties configuration variables. You may need to tweak these to be compatible with - * the server-side, but the defaults work in most cases. - * @see this.setUpperCase() method - * @see this.setPad() method - */ - var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, - /* hexadecimal output case format. false - lowercase; true - uppercase */ - b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', - /* base-64 pad character. Default '=' for strict RFC compliance */ - utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, - /* enable/disable utf8 encoding */ - sha512_k; - - /* privileged (public) methods */ - this.hex = function(s) { - return rstr2hex(rstr(s)); - }; - this.b64 = function(s) { - return rstr2b64(rstr(s), b64pad); - }; - this.any = function(s, e) { - return rstr2any(rstr(s), e); - }; - this.raw = function(s) { - return rstr(s, utf8); - }; - this.hex_hmac = function(k, d) { - return rstr2hex(rstr_hmac(k, d)); - }; - this.b64_hmac = function(k, d) { - return rstr2b64(rstr_hmac(k, d), b64pad); - }; - this.any_hmac = function(k, d, e) { - return rstr2any(rstr_hmac(k, d), e); - }; - /** - * Perform a simple self-test to see if the VM is working - * @return {String} Hexadecimal hash sample - * @public - */ - this.vm_test = function() { - return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72'; - }; - /** - * @description Enable/disable uppercase hexadecimal returned string - * @param {boolean} - * @return {Object} this - * @public - */ - this.setUpperCase = function(a) { - if (typeof a === 'boolean') { - hexcase = a; - } - return this; - }; - /** - * @description Defines a base64 pad string - * @param {string} Pad - * @return {Object} this - * @public - */ - this.setPad = function(a) { - b64pad = a || b64pad; - return this; - }; - /** - * @description Defines a base64 pad string - * @param {boolean} - * @return {Object} this - * @public - */ - this.setUTF8 = function(a) { - if (typeof a === 'boolean') { - utf8 = a; - } - return this; - }; - - /* private methods */ - - /** - * Calculate the SHA-512 of a raw string - */ - - function rstr(s) { - s = (utf8) ? utf8Encode(s) : s; - return binb2rstr(binb(rstr2binb(s), s.length * 8)); - } - /* - * Calculate the HMAC-SHA-512 of a key and some data (raw strings) - */ - - function rstr_hmac(key, data) { - key = (utf8) ? utf8Encode(key) : key; - data = (utf8) ? utf8Encode(data) : data; - - var hash, i = 0, - bkey = rstr2binb(key), - ipad = Array(32), - opad = Array(32); - - if (bkey.length > 32) { - bkey = binb(bkey, key.length * 8); - } - - for (; i < 32; i += 1) { - ipad[i] = bkey[i] ^ 0x36363636; - opad[i] = bkey[i] ^ 0x5C5C5C5C; - } - - hash = binb(ipad.concat(rstr2binb(data)), 1024 + data.length * 8); - return binb2rstr(binb(opad.concat(hash), 1024 + 512)); - } - - /** - * Calculate the SHA-512 of an array of big-endian dwords, and a bit length - */ - - function binb(x, len) { - var j, i, l, - W = new Array(80), - hash = new Array(16), - //Initial hash values - H = [ - new int64(0x6a09e667, -205731576), - new int64(-1150833019, -2067093701), - new int64(0x3c6ef372, -23791573), - new int64(-1521486534, 0x5f1d36f1), - new int64(0x510e527f, -1377402159), - new int64(-1694144372, 0x2b3e6c1f), - new int64(0x1f83d9ab, -79577749), - new int64(0x5be0cd19, 0x137e2179) - ], - T1 = new int64(0, 0), - T2 = new int64(0, 0), - a = new int64(0, 0), - b = new int64(0, 0), - c = new int64(0, 0), - d = new int64(0, 0), - e = new int64(0, 0), - f = new int64(0, 0), - g = new int64(0, 0), - h = new int64(0, 0), - //Temporary variables not specified by the document - s0 = new int64(0, 0), - s1 = new int64(0, 0), - Ch = new int64(0, 0), - Maj = new int64(0, 0), - r1 = new int64(0, 0), - r2 = new int64(0, 0), - r3 = new int64(0, 0); - - if (sha512_k === undefined) { - //SHA512 constants - sha512_k = [ - new int64(0x428a2f98, -685199838), new int64(0x71374491, 0x23ef65cd), - new int64(-1245643825, -330482897), new int64(-373957723, -2121671748), - new int64(0x3956c25b, -213338824), new int64(0x59f111f1, -1241133031), - new int64(-1841331548, -1357295717), new int64(-1424204075, -630357736), - new int64(-670586216, -1560083902), new int64(0x12835b01, 0x45706fbe), - new int64(0x243185be, 0x4ee4b28c), new int64(0x550c7dc3, -704662302), - new int64(0x72be5d74, -226784913), new int64(-2132889090, 0x3b1696b1), - new int64(-1680079193, 0x25c71235), new int64(-1046744716, -815192428), - new int64(-459576895, -1628353838), new int64(-272742522, 0x384f25e3), - new int64(0xfc19dc6, -1953704523), new int64(0x240ca1cc, 0x77ac9c65), - new int64(0x2de92c6f, 0x592b0275), new int64(0x4a7484aa, 0x6ea6e483), - new int64(0x5cb0a9dc, -1119749164), new int64(0x76f988da, -2096016459), - new int64(-1740746414, -295247957), new int64(-1473132947, 0x2db43210), - new int64(-1341970488, -1728372417), new int64(-1084653625, -1091629340), - new int64(-958395405, 0x3da88fc2), new int64(-710438585, -1828018395), - new int64(0x6ca6351, -536640913), new int64(0x14292967, 0xa0e6e70), - new int64(0x27b70a85, 0x46d22ffc), new int64(0x2e1b2138, 0x5c26c926), - new int64(0x4d2c6dfc, 0x5ac42aed), new int64(0x53380d13, -1651133473), - new int64(0x650a7354, -1951439906), new int64(0x766a0abb, 0x3c77b2a8), - new int64(-2117940946, 0x47edaee6), new int64(-1838011259, 0x1482353b), - new int64(-1564481375, 0x4cf10364), new int64(-1474664885, -1136513023), - new int64(-1035236496, -789014639), new int64(-949202525, 0x654be30), - new int64(-778901479, -688958952), new int64(-694614492, 0x5565a910), - new int64(-200395387, 0x5771202a), new int64(0x106aa070, 0x32bbd1b8), - new int64(0x19a4c116, -1194143544), new int64(0x1e376c08, 0x5141ab53), - new int64(0x2748774c, -544281703), new int64(0x34b0bcb5, -509917016), - new int64(0x391c0cb3, -976659869), new int64(0x4ed8aa4a, -482243893), - new int64(0x5b9cca4f, 0x7763e373), new int64(0x682e6ff3, -692930397), - new int64(0x748f82ee, 0x5defb2fc), new int64(0x78a5636f, 0x43172f60), - new int64(-2067236844, -1578062990), new int64(-1933114872, 0x1a6439ec), - new int64(-1866530822, 0x23631e28), new int64(-1538233109, -561857047), - new int64(-1090935817, -1295615723), new int64(-965641998, -479046869), - new int64(-903397682, -366583396), new int64(-779700025, 0x21c0c207), - new int64(-354779690, -840897762), new int64(-176337025, -294727304), - new int64(0x6f067aa, 0x72176fba), new int64(0xa637dc5, -1563912026), - new int64(0x113f9804, -1090974290), new int64(0x1b710b35, 0x131c471b), - new int64(0x28db77f5, 0x23047d84), new int64(0x32caab7b, 0x40c72493), - new int64(0x3c9ebe0a, 0x15c9bebc), new int64(0x431d67c4, -1676669620), - new int64(0x4cc5d4be, -885112138), new int64(0x597f299c, -60457430), - new int64(0x5fcb6fab, 0x3ad6faec), new int64(0x6c44198c, 0x4a475817) - ]; - } - - for (i = 0; i < 80; i += 1) { - W[i] = new int64(0, 0); - } - - // append padding to the source string. The format is described in the FIPS. - x[len >> 5] |= 0x80 << (24 - (len & 0x1f)); - x[((len + 128 >> 10) << 5) + 31] = len; - l = x.length; - for (i = 0; i < l; i += 32) { //32 dwords is the block size - int64copy(a, H[0]); - int64copy(b, H[1]); - int64copy(c, H[2]); - int64copy(d, H[3]); - int64copy(e, H[4]); - int64copy(f, H[5]); - int64copy(g, H[6]); - int64copy(h, H[7]); - - for (j = 0; j < 16; j += 1) { - W[j].h = x[i + 2 * j]; - W[j].l = x[i + 2 * j + 1]; - } - - for (j = 16; j < 80; j += 1) { - //sigma1 - int64rrot(r1, W[j - 2], 19); - int64revrrot(r2, W[j - 2], 29); - int64shr(r3, W[j - 2], 6); - s1.l = r1.l ^ r2.l ^ r3.l; - s1.h = r1.h ^ r2.h ^ r3.h; - //sigma0 - int64rrot(r1, W[j - 15], 1); - int64rrot(r2, W[j - 15], 8); - int64shr(r3, W[j - 15], 7); - s0.l = r1.l ^ r2.l ^ r3.l; - s0.h = r1.h ^ r2.h ^ r3.h; - - int64add4(W[j], s1, W[j - 7], s0, W[j - 16]); - } - - for (j = 0; j < 80; j += 1) { - //Ch - Ch.l = (e.l & f.l) ^ (~e.l & g.l); - Ch.h = (e.h & f.h) ^ (~e.h & g.h); - - //Sigma1 - int64rrot(r1, e, 14); - int64rrot(r2, e, 18); - int64revrrot(r3, e, 9); - s1.l = r1.l ^ r2.l ^ r3.l; - s1.h = r1.h ^ r2.h ^ r3.h; - - //Sigma0 - int64rrot(r1, a, 28); - int64revrrot(r2, a, 2); - int64revrrot(r3, a, 7); - s0.l = r1.l ^ r2.l ^ r3.l; - s0.h = r1.h ^ r2.h ^ r3.h; - - //Maj - Maj.l = (a.l & b.l) ^ (a.l & c.l) ^ (b.l & c.l); - Maj.h = (a.h & b.h) ^ (a.h & c.h) ^ (b.h & c.h); - - int64add5(T1, h, s1, Ch, sha512_k[j], W[j]); - int64add(T2, s0, Maj); - - int64copy(h, g); - int64copy(g, f); - int64copy(f, e); - int64add(e, d, T1); - int64copy(d, c); - int64copy(c, b); - int64copy(b, a); - int64add(a, T1, T2); - } - int64add(H[0], H[0], a); - int64add(H[1], H[1], b); - int64add(H[2], H[2], c); - int64add(H[3], H[3], d); - int64add(H[4], H[4], e); - int64add(H[5], H[5], f); - int64add(H[6], H[6], g); - int64add(H[7], H[7], h); - } - - //represent the hash as an array of 32-bit dwords - for (i = 0; i < 8; i += 1) { - hash[2 * i] = H[i].h; - hash[2 * i + 1] = H[i].l; - } - return hash; - } - - //A constructor for 64-bit numbers - - function int64(h, l) { - this.h = h; - this.l = l; - //this.toString = int64toString; - } - - //Copies src into dst, assuming both are 64-bit numbers - - function int64copy(dst, src) { - dst.h = src.h; - dst.l = src.l; - } - - //Right-rotates a 64-bit number by shift - //Won't handle cases of shift>=32 - //The function revrrot() is for that - - function int64rrot(dst, x, shift) { - dst.l = (x.l >>> shift) | (x.h << (32 - shift)); - dst.h = (x.h >>> shift) | (x.l << (32 - shift)); - } - - //Reverses the dwords of the source and then rotates right by shift. - //This is equivalent to rotation by 32+shift - - function int64revrrot(dst, x, shift) { - dst.l = (x.h >>> shift) | (x.l << (32 - shift)); - dst.h = (x.l >>> shift) | (x.h << (32 - shift)); - } - - //Bitwise-shifts right a 64-bit number by shift - //Won't handle shift>=32, but it's never needed in SHA512 - - function int64shr(dst, x, shift) { - dst.l = (x.l >>> shift) | (x.h << (32 - shift)); - dst.h = (x.h >>> shift); - } - - //Adds two 64-bit numbers - //Like the original implementation, does not rely on 32-bit operations - - function int64add(dst, x, y) { - var w0 = (x.l & 0xffff) + (y.l & 0xffff); - var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16); - var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16); - var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16); - dst.l = (w0 & 0xffff) | (w1 << 16); - dst.h = (w2 & 0xffff) | (w3 << 16); - } - - //Same, except with 4 addends. Works faster than adding them one by one. - - function int64add4(dst, a, b, c, d) { - var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff); - var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16); - var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16); - var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16); - dst.l = (w0 & 0xffff) | (w1 << 16); - dst.h = (w2 & 0xffff) | (w3 << 16); - } - - //Same, except with 5 addends - - function int64add5(dst, a, b, c, d, e) { - var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff), - w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16), - w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16), - w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16); - dst.l = (w0 & 0xffff) | (w1 << 16); - dst.h = (w2 & 0xffff) | (w3 << 16); - } - }, - /** - * @class Hashes.RMD160 - * @constructor - * @param {Object} [config] - * - * A JavaScript implementation of the RIPEMD-160 Algorithm - * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009. - * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet - * See http://pajhome.org.uk/crypt/md5 for details. - * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/ - */ - RMD160: function(options) { - /** - * Private properties configuration variables. You may need to tweak these to be compatible with - * the server-side, but the defaults work in most cases. - * @see this.setUpperCase() method - * @see this.setPad() method - */ - var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, - /* hexadecimal output case format. false - lowercase; true - uppercase */ - b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', - /* base-64 pad character. Default '=' for strict RFC compliance */ - utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, - /* enable/disable utf8 encoding */ - rmd160_r1 = [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, - 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, - 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, - 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 - ], - rmd160_r2 = [ - 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, - 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, - 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, - 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, - 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 - ], - rmd160_s1 = [ - 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, - 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, - 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, - 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, - 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 - ], - rmd160_s2 = [ - 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, - 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, - 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, - 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, - 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 - ]; - - /* privileged (public) methods */ - this.hex = function(s) { - return rstr2hex(rstr(s, utf8)); - }; - this.b64 = function(s) { - return rstr2b64(rstr(s, utf8), b64pad); - }; - this.any = function(s, e) { - return rstr2any(rstr(s, utf8), e); - }; - this.raw = function(s) { - return rstr(s, utf8); - }; - this.hex_hmac = function(k, d) { - return rstr2hex(rstr_hmac(k, d)); - }; - this.b64_hmac = function(k, d) { - return rstr2b64(rstr_hmac(k, d), b64pad); - }; - this.any_hmac = function(k, d, e) { - return rstr2any(rstr_hmac(k, d), e); - }; - /** - * Perform a simple self-test to see if the VM is working - * @return {String} Hexadecimal hash sample - * @public - */ - this.vm_test = function() { - return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72'; - }; - /** - * @description Enable/disable uppercase hexadecimal returned string - * @param {boolean} - * @return {Object} this - * @public - */ - this.setUpperCase = function(a) { - if (typeof a === 'boolean') { - hexcase = a; - } - return this; - }; - /** - * @description Defines a base64 pad string - * @param {string} Pad - * @return {Object} this - * @public - */ - this.setPad = function(a) { - if (typeof a !== 'undefined') { - b64pad = a; - } - return this; - }; - /** - * @description Defines a base64 pad string - * @param {boolean} - * @return {Object} this - * @public - */ - this.setUTF8 = function(a) { - if (typeof a === 'boolean') { - utf8 = a; - } - return this; - }; - - /* private methods */ - - /** - * Calculate the rmd160 of a raw string - */ - - function rstr(s) { - s = (utf8) ? utf8Encode(s) : s; - return binl2rstr(binl(rstr2binl(s), s.length * 8)); - } - - /** - * Calculate the HMAC-rmd160 of a key and some data (raw strings) - */ - - function rstr_hmac(key, data) { - key = (utf8) ? utf8Encode(key) : key; - data = (utf8) ? utf8Encode(data) : data; - var i, hash, - bkey = rstr2binl(key), - ipad = Array(16), - opad = Array(16); - - if (bkey.length > 16) { - bkey = binl(bkey, key.length * 8); - } - - for (i = 0; i < 16; i += 1) { - ipad[i] = bkey[i] ^ 0x36363636; - opad[i] = bkey[i] ^ 0x5C5C5C5C; - } - hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8); - return binl2rstr(binl(opad.concat(hash), 512 + 160)); - } - - /** - * Convert an array of little-endian words to a string - */ - - function binl2rstr(input) { - var i, output = '', - l = input.length * 32; - for (i = 0; i < l; i += 8) { - output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF); - } - return output; - } - - /** - * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length. - */ - - function binl(x, len) { - var T, j, i, l, - h0 = 0x67452301, - h1 = 0xefcdab89, - h2 = 0x98badcfe, - h3 = 0x10325476, - h4 = 0xc3d2e1f0, - A1, B1, C1, D1, E1, - A2, B2, C2, D2, E2; - - /* append padding */ - x[len >> 5] |= 0x80 << (len % 32); - x[(((len + 64) >>> 9) << 4) + 14] = len; - l = x.length; - - for (i = 0; i < l; i += 16) { - A1 = A2 = h0; - B1 = B2 = h1; - C1 = C2 = h2; - D1 = D2 = h3; - E1 = E2 = h4; - for (j = 0; j <= 79; j += 1) { - T = safe_add(A1, rmd160_f(j, B1, C1, D1)); - T = safe_add(T, x[i + rmd160_r1[j]]); - T = safe_add(T, rmd160_K1(j)); - T = safe_add(bit_rol(T, rmd160_s1[j]), E1); - A1 = E1; - E1 = D1; - D1 = bit_rol(C1, 10); - C1 = B1; - B1 = T; - T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2)); - T = safe_add(T, x[i + rmd160_r2[j]]); - T = safe_add(T, rmd160_K2(j)); - T = safe_add(bit_rol(T, rmd160_s2[j]), E2); - A2 = E2; - E2 = D2; - D2 = bit_rol(C2, 10); - C2 = B2; - B2 = T; - } - - T = safe_add(h1, safe_add(C1, D2)); - h1 = safe_add(h2, safe_add(D1, E2)); - h2 = safe_add(h3, safe_add(E1, A2)); - h3 = safe_add(h4, safe_add(A1, B2)); - h4 = safe_add(h0, safe_add(B1, C2)); - h0 = T; - } - return [h0, h1, h2, h3, h4]; - } - - // specific algorithm methods - - function rmd160_f(j, x, y, z) { - return (0 <= j && j <= 15) ? (x ^ y ^ z) : - (16 <= j && j <= 31) ? (x & y) | (~x & z) : - (32 <= j && j <= 47) ? (x | ~y) ^ z : - (48 <= j && j <= 63) ? (x & z) | (y & ~z) : - (64 <= j && j <= 79) ? x ^ (y | ~z) : - 'rmd160_f: j out of range'; - } - - function rmd160_K1(j) { - return (0 <= j && j <= 15) ? 0x00000000 : - (16 <= j && j <= 31) ? 0x5a827999 : - (32 <= j && j <= 47) ? 0x6ed9eba1 : - (48 <= j && j <= 63) ? 0x8f1bbcdc : - (64 <= j && j <= 79) ? 0xa953fd4e : - 'rmd160_K1: j out of range'; - } - - function rmd160_K2(j) { - return (0 <= j && j <= 15) ? 0x50a28be6 : - (16 <= j && j <= 31) ? 0x5c4dd124 : - (32 <= j && j <= 47) ? 0x6d703ef3 : - (48 <= j && j <= 63) ? 0x7a6d76e9 : - (64 <= j && j <= 79) ? 0x00000000 : - 'rmd160_K2: j out of range'; - } - } - }; - - // exposes Hashes - (function(window, undefined) { - var freeExports = false; - if (typeof exports === 'object') { - freeExports = exports; - if (exports && typeof global === 'object' && global && global === global.global) { - window = global; - } - } - - if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) { - // define as an anonymous module, so, through path mapping, it can be aliased - define(function() { - return Hashes; - }); - } else if (freeExports) { - // in Node.js or RingoJS v0.8.0+ - if (typeof module === 'object' && module && module.exports === freeExports) { - module.exports = Hashes; - } - // in Narwhal or RingoJS v0.7.0- - else { - freeExports.Hashes = Hashes; - } - } else { - // in a browser or Rhino - window.Hashes = Hashes; - } - }(this)); -}()); // IIFE diff --git a/src/lib/make_image.js b/src/lib/make_image.js index 069123eb..b1c60d8a 100644 --- a/src/lib/make_image.js +++ b/src/lib/make_image.js @@ -1,5 +1,5 @@ 'use strict'; -const Hashes = require('./hashes'); +const Hashes = require('jshashes'); //the wikimedia image url is a little silly: //https://commons.wikimedia.org/wiki/Commons:FAQ#What_are_the_strangely_named_components_in_file_paths.3F @@ -9,6 +9,7 @@ const make_image = function(file) { title = title.charAt(0).toUpperCase() + title.substring(1); //spaces to underscores title = title.replace(/ /g, '_'); + let hash = new Hashes.MD5().hex(title); let path = hash.substr(0, 1) + '/' + hash.substr(0, 2) + '/'; title = encodeURIComponent(title); diff --git a/src/lib/sentence_parser.js b/src/lib/sentence_parser.js index 1b0015dc..5cb25be7 100644 --- a/src/lib/sentence_parser.js +++ b/src/lib/sentence_parser.js @@ -5,7 +5,10 @@ // Ignore periods/questions/exclamations used in acronyms/abbreviations/numbers, etc. // @spencermountain 2015 MIT 'use strict'; -let abbreviations = ['jr', 'mr', 'mrs', 'ms', 'dr', 'prof', 'sr', 'sen', 'corp', 'calif', 'rep', 'gov', 'atty', 'supt', 'det', 'rev', 'col', 'gen', 'lt', 'cmdr', 'adm', 'capt', 'sgt', 'cpl', 'maj', 'dept', 'univ', 'assn', 'bros', 'inc', 'ltd', 'co', 'corp', 'arc', 'al', 'ave', 'blvd', 'cl', 'ct', 'cres', 'exp', 'rd', 'st', 'dist', 'mt', 'ft', 'fy', 'hwy', 'la', 'pd', 'pl', 'plz', 'tce', 'Ala', 'Ariz', 'Ark', 'Cal', 'Calif', 'Col', 'Colo', 'Conn', 'Del', 'Fed', 'Fla', 'Ga', 'Ida', 'Id', 'Ill', 'Ind', 'Ia', 'Kan', 'Kans', 'Ken', 'Ky', 'La', 'Me', 'Md', 'Mass', 'Mich', 'Minn', 'Miss', 'Mo', 'Mont', 'Neb', 'Nebr', 'Nev', 'Mex', 'Okla', 'Ok', 'Ore', 'Penna', 'Penn', 'Pa', 'Dak', 'Tenn', 'Tex', 'Ut', 'Vt', 'Va', 'Wash', 'Wis', 'Wisc', 'Wy', 'Wyo', 'USAFA', 'Alta', 'Ont', 'QuÔøΩ', 'Sask', 'Yuk', 'jan', 'feb', 'mar', 'apr', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec', 'sept', 'vs', 'etc', 'esp', 'llb', 'md', 'bl', 'phd', 'ma', 'ba', 'miss', 'misses', 'mister', 'sir', 'esq', 'mstr', 'lit', 'fl', 'ex', 'eg', 'sep', 'sept', '..']; +const abbreviations = require('../data/abbreviations'); +const abbrev_reg = new RegExp('(^| )(' + abbreviations.join('|') + ')[.!?] ?$', 'i'); +const acronym_reg = new RegExp('[ |.][A-Z].? +?$', 'i'); +const elipses_reg = new RegExp('\\.\\.\\.* +?$'); //turn a nested array into one array const flatten = function(arr) { @@ -27,16 +30,16 @@ const naiive_split = function(text) { }; // if this looks like a period within a wikipedia link, return false -var isBalanced = function(str) { +const isBalanced = function(str) { str = str || ''; - var open = str.split(/\[\[/) || []; - var closed = str.split(/\]\]/) || []; + const open = str.split(/\[\[/) || []; + const closed = str.split(/\]\]/) || []; if (open.length > closed.length) { return false; } //make sure quotes are closed too - var quotes = str.match(/"/g); - if (quotes && (quotes.length % 2) !== 0 && str.length < 900) { + const quotes = str.match(/"/g); + if (quotes && quotes.length % 2 !== 0 && str.length < 900) { return false; } return true; @@ -66,21 +69,17 @@ const sentence_parser = function(text) { if (chunks[chunks.length - 1]) { chunks[chunks.length - 1] += s; continue; - } else if (splits[i + 1]) { //add it to the next one + } else if (splits[i + 1]) { + //add it to the next one splits[i + 1] = s + splits[i + 1]; continue; } - //else, only whitespace, no terms, no sentence + //else, only whitespace, no terms, no sentence } chunks.push(s); } //detection of non-sentence chunks - // const abbrev_reg = new RegExp('\\b(' + abbreviations.join('|') + ')[.!?] ?$', 'i'); - const abbrev_reg = new RegExp('(^| )(' + abbreviations.join('|') + ')[.!?] ?$', 'i'); - const acronym_reg = new RegExp('[ |\.][A-Z]\.? +?$', 'i'); - const elipses_reg = new RegExp('\\.\\.\\.* +?$'); - const isSentence = function(hmm) { if (hmm.match(abbrev_reg) || hmm.match(acronym_reg) || hmm.match(elipses_reg)) { return false; @@ -95,12 +94,12 @@ const sentence_parser = function(text) { for (let i = 0; i < chunks.length; i++) { //should this chunk be combined with the next one? if (chunks[i + 1] && !isSentence(chunks[i])) { - chunks[i + 1] = (chunks[i] + (chunks[i + 1] || '')); //.replace(/ +/g, ' '); - } else if (chunks[i] && chunks[i].length > 0) { //this chunk is a proper sentence.. + chunks[i + 1] = chunks[i] + (chunks[i + 1] || ''); //.replace(/ +/g, ' '); + } else if (chunks[i] && chunks[i].length > 0) { + //this chunk is a proper sentence.. sentences.push(chunks[i]); chunks[i] = ''; } - } //if we never got a sentence, return the given text if (sentences.length === 0) { @@ -109,6 +108,5 @@ const sentence_parser = function(text) { return sentences; }; - module.exports = sentence_parser; // console.log(sentence_parser('Tony is nice. He lives in Japan.').length === 2); From 68def808f12d329b9173f0696b08fb65c5576757 Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 11:12:22 -0400 Subject: [PATCH 08/26] more refactoring folders --- src/index.js | 6 +- src/parse/{ => cleanup}/kill_xml.js | 0 .../{cleanup_misc.js => cleanup/misc.js} | 0 src/{ => parse/cleanup}/recursive_matches.js | 0 src/{ => parse/cleanup}/word_templates.js | 36 +++++++---- src/{main.js => parse/index.js} | 36 +++++------ tests/unit.test.js | 60 +++++++++---------- 7 files changed, 77 insertions(+), 61 deletions(-) rename src/parse/{ => cleanup}/kill_xml.js (100%) rename src/parse/{cleanup_misc.js => cleanup/misc.js} (100%) rename src/{ => parse/cleanup}/recursive_matches.js (100%) rename src/{ => parse/cleanup}/word_templates.js (78%) rename src/{main.js => parse/index.js} (85%) diff --git a/src/index.js b/src/index.js index 66ff1fa0..8c3d836e 100644 --- a/src/index.js +++ b/src/index.js @@ -2,7 +2,7 @@ // https://github.com/spencermountain/wtf_wikipedia //@spencermountain const fetch = require('./lib/fetch_text'); -const main = require('./main'); +const parse = require('./parse'); //from a page title or id, fetch the wikiscript const from_api = function(page_identifier, lang_or_wikiid, cb) { @@ -21,7 +21,7 @@ const from_api = function(page_identifier, lang_or_wikiid, cb) { //turn wiki-markup into a nicely-formatted text const plaintext = function(str) { - let data = main(str) || {}; + let data = parse(str) || {}; data.text = data.text || []; let text = ''; Object.keys(data.text).forEach(function(k) { @@ -32,6 +32,6 @@ const plaintext = function(str) { module.exports = { from_api: from_api, - parse: main, + parse: parse, plaintext: plaintext }; diff --git a/src/parse/kill_xml.js b/src/parse/cleanup/kill_xml.js similarity index 100% rename from src/parse/kill_xml.js rename to src/parse/cleanup/kill_xml.js diff --git a/src/parse/cleanup_misc.js b/src/parse/cleanup/misc.js similarity index 100% rename from src/parse/cleanup_misc.js rename to src/parse/cleanup/misc.js diff --git a/src/recursive_matches.js b/src/parse/cleanup/recursive_matches.js similarity index 100% rename from src/recursive_matches.js rename to src/parse/cleanup/recursive_matches.js diff --git a/src/word_templates.js b/src/parse/cleanup/word_templates.js similarity index 78% rename from src/word_templates.js rename to src/parse/cleanup/word_templates.js index a9ad9dbb..5f8142fe 100644 --- a/src/word_templates.js +++ b/src/parse/cleanup/word_templates.js @@ -1,19 +1,32 @@ -var languages = require('./data/languages'); +const languages = require('../../data/languages'); +const months = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December' +]; +const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; // templates that need parsing and replacing for inline text //https://en.wikipedia.org/wiki/Category:Magic_word_templates -var word_templates = function(wiki) { +const word_templates = function(wiki) { //we can be sneaky with this template, as it's often found inside other templates wiki = wiki.replace(/\{\{URL\|([^ ]{4,100}?)\}\}/gi, '$1'); //this one needs to be handled manually wiki = wiki.replace(/\{\{convert\|([0-9]*?)\|([^\|]*?)\}\}/gi, '$1 $2'); //TODO: support https://en.wikipedia.org/wiki/Template:Convert#Ranges_of_values //date-time templates - var d = new Date(); + let d = new Date(); wiki = wiki.replace(/\{\{(CURRENT|LOCAL)DAY(2)?\}\}/gi, d.getDate()); - var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; wiki = wiki.replace(/\{\{(CURRENT|LOCAL)MONTH(NAME|ABBREV)?\}\}/gi, months[d.getMonth()]); wiki = wiki.replace(/\{\{(CURRENT|LOCAL)YEAR\}\}/gi, d.getFullYear()); - var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; wiki = wiki.replace(/\{\{(CURRENT|LOCAL)DAYNAME\}\}/gi, days[d.getDay()]); //formatting templates wiki = wiki.replace(/\{\{(lc|uc|formatnum):(.*?)\}\}/gi, '$2'); @@ -25,7 +38,7 @@ var word_templates = function(wiki) { //{{font|size=x%|text}} if (wiki.match(/\{\{dts\|/)) { - var date = (wiki.match(/\{\{dts\|(.*?)[\}\|]/) || [])[1] || ''; + let date = (wiki.match(/\{\{dts\|(.*?)[\}\|]/) || [])[1] || ''; date = new Date(date); if (date && date.getTime()) { wiki = wiki.replace(/\{\{dts\|.*?\}\}/gi, date.toDateString()); @@ -34,17 +47,18 @@ var word_templates = function(wiki) { } } if (wiki.match(/\{\{date\|.*?\}\}/)) { - var date = (wiki.match(/\{\{date\|(.*?)\|(.*?)\|(.*?)\}\}/) || []) || []; - var dateString = date[1] + ' ' + date[2] + ' ' + date[3]; + let date = wiki.match(/\{\{date\|(.*?)\|(.*?)\|(.*?)\}\}/) || [] || []; + let dateString = date[1] + ' ' + date[2] + ' ' + date[3]; wiki = wiki.replace(/\{\{date\|.*?\}\}/gi, dateString); } //common templates in wiktionary - wiki = wiki.replace(/\{\{term\|(.*?)\|.*?\}\}/gi, '\'$1\''); + wiki = wiki.replace(/\{\{term\|(.*?)\|.*?\}\}/gi, "'$1'"); wiki = wiki.replace(/\{\{IPA\|(.*?)\|.*?\}\}/gi, '$1'); wiki = wiki.replace(/\{\{sense\|(.*?)\|?.*?\}\}/gi, '($1)'); - wiki = wiki.replace(/\{\{t\+?\|...?\|(.*?)(\|.*)?\}\}/gi, '\'$1\''); + wiki = wiki.replace(/\{\{t\+?\|...?\|(.*?)(\|.*)?\}\}/gi, "'$1'"); //replace languages in 'etyl' tags - if (wiki.match(/\{\{etyl\|/)) { //doesn't support multiple-ones per sentence.. + if (wiki.match(/\{\{etyl\|/)) { + //doesn't support multiple-ones per sentence.. var lang = wiki.match(/\{\{etyl\|(.*?)\|.*?\}\}/i)[1] || ''; lang = lang.toLowerCase(); if (lang && languages[lang]) { diff --git a/src/main.js b/src/parse/index.js similarity index 85% rename from src/main.js rename to src/parse/index.js index 6d337504..f1f70841 100644 --- a/src/main.js +++ b/src/parse/index.js @@ -1,20 +1,22 @@ -const sentence_parser = require('./lib/sentence_parser'); -const make_image = require('./lib/make_image'); -const i18n = require('./data/i18n'); -const helpers = require('./lib/helpers'); -const languages = require('./data/languages'); -//parsers -const redirects = require('./parse/parse_redirects'); -const parse_table = require('./parse/parse_table'); -const parse_line = require('./parse/parse_line'); -const parse_categories = require('./parse/parse_categories'); -const parse_disambig = require('./parse/parse_disambig'); -const parse_infobox = require('./parse/parse_infobox'); -const parse_infobox_template = require('./parse/parse_infobox_template'); -const parse_image = require('./parse/parse_image'); -const recursive_matches = require('./recursive_matches'); -const preprocess = require('./parse/cleanup_misc'); -const word_templates = require('./word_templates'); +const i18n = require('../data/i18n'); +const languages = require('../data/languages'); +const sentence_parser = require('../lib/sentence_parser'); +const make_image = require('../lib/make_image'); +const helpers = require('../lib/helpers'); + +//parsing functions +const redirects = require('./parse_redirects'); +const parse_table = require('./parse_table'); +const parse_line = require('./parse_line'); +const parse_categories = require('./parse_categories'); +const parse_disambig = require('./parse_disambig'); +const parse_infobox = require('./parse_infobox'); +const parse_infobox_template = require('./parse_infobox_template'); +const parse_image = require('./parse_image'); + +const word_templates = require('./cleanup/word_templates'); +const recursive_matches = require('./cleanup/recursive_matches'); +const preprocess = require('./cleanup/misc'); //regexs const template_reg = new RegExp('\\{\\{ ?(' + i18n.disambigs.join('|') + ')(\\|[a-z =]*?)? ?\\}\\}', 'i'); diff --git a/tests/unit.test.js b/tests/unit.test.js index 0d0bcfe5..66159aac 100644 --- a/tests/unit.test.js +++ b/tests/unit.test.js @@ -3,23 +3,26 @@ var test = require('tape'); var redirects = require('../src/parse/parse_redirects'); var parse_line = require('../src/parse/parse_line'); var parse_categories = require('../src/parse/parse_categories'); -var cleanup_misc = require('../src/parse/cleanup_misc'); +var cleanup_misc = require('../src/parse/cleanup/misc'); var parse_image = require('../src/parse/parse_image'); var sentence_parser = require('../src/lib/sentence_parser'); -var kill_xml = require('../src/parse/kill_xml'); +var kill_xml = require('../src/parse/cleanup/kill_xml'); -test('sentence parser', (t) => { +test('sentence parser', t => { [ ['Tony is nice. He lives in Japan.', 2], ['I like that Color', 1], ['Soviet bonds to be sold in the U.S. market. Everyone wins.', 2], - ['Hi there Dr. Joe, the price is 4.59 for N.A.S.A. Ph.Ds. I hope that\'s fine, etc. and you can attend Feb. 8th. Bye', 3], + [ + "Hi there Dr. Joe, the price is 4.59 for N.A.S.A. Ph.Ds. I hope that's fine, etc. and you can attend Feb. 8th. Bye", + 3 + ], ['Mount Sinai Hospital, [[St. Michaels Hospital (Toronto)|St. Michaels Hospital]], North York', 1], ['he said ... oh yeah. I did', 2], ['32 C', 1], ['dom, kon. XIX w.', 2], - ['a staged reenactment of [[Perry v. Brown]] world', 1], - ].forEach((a) => { + ['a staged reenactment of [[Perry v. Brown]] world', 1] + ].forEach(a => { let s = sentence_parser(a[0]); let msg = a[1] + ' sentences - "' + a[0] + '"'; t.equal(s.length, a[1], msg); @@ -27,19 +30,14 @@ test('sentence parser', (t) => { t.end(); }); - -test('misc cleanup', (t) => { - [ - ['hi [[as:Plancton]] there', 'hi there'], - ['hello
world', 'hello world'] - ].forEach((a) => { +test('misc cleanup', t => { + [['hi [[as:Plancton]] there', 'hi there'], ['hello
world', 'hello world']].forEach(a => { let s = cleanup_misc(a[0]); t.equal(s, a[1]); }); t.end(); }); - test('redirects', t => { [ ['#REDIRECT[[Tony Danza]]', 'Tony Danza'], @@ -49,15 +47,15 @@ test('redirects', t => { ['#redirect [[Tony Danza#funfun]] ', 'Tony Danza'], ['#přesměruj [[Tony Danza#funfun]] ', 'Tony Danza'], ['#تغییر_مسیر [[Farming]] ', 'Farming'] - ].forEach((a) => { + ].forEach(a => { let o = redirects.parse_redirect(a[0]); - var msg = '\'' + a[0] + '\' -> \'' + o.redirect + '\''; + var msg = "'" + a[0] + "' -> '" + o.redirect + "'"; t.equal(o.redirect, a[1], msg); }); t.end(); }); -test('parse_line_text', (t) => { +test('parse_line_text', t => { [ ['tony hawk', 'tony hawk'], [' tony hawk ', 'tony hawk'], @@ -67,54 +65,56 @@ test('parse_line_text', (t) => { ['tony hawk [http://www.whistler.ca]', 'tony hawk'], ['tony hawk in [http://www.whistler.ca whistler]', 'tony hawk in whistler'], ['it is [[Tony Hawk|Tony]]s mother in [[Toronto]]s', 'it is Tonys mother in Torontos'] - ].forEach((a) => { + ].forEach(a => { let o = parse_line(a[0]); - var msg = '\'' + a[0] + '\' -> \'' + o.text + '\''; + var msg = "'" + a[0] + "' -> '" + o.text + "'"; t.equal(o.text, a[1], msg); }); t.end(); }); -test('parse_categories', (t) => { +test('parse_categories', t => { [ ['[[Category:Tony Danza]]', ['Tony Danza']], ['[[Category:Tony Danza]][[Category:Formal Wear]]', ['Tony Danza', 'Formal Wear']], [' [[Category:Tony Danza]] [[Category:Formal Wear]] ', ['Tony Danza', 'Formal Wear']], [' [[Category:Tony Danza|metadata]] [[category:Formal Wear]] ', ['Tony Danza', 'Formal Wear']], ['[[categoría:Tony Danza|metadata]] ', ['Tony Danza']] - ].forEach((a) => { + ].forEach(a => { let o = parse_categories(a[0]); t.deepEqual(o, a[1]); }); t.end(); }); -test('parse_image', (t) => { +test('parse_image', t => { [ ['[[File:Tony Danza]]', 'File:Tony Danza'], ['[[Image:Tony Danza]]', 'Image:Tony Danza'], ['[[Image:Tony Danza|left]]', 'Image:Tony Danza'], - ['[[Image:Edouard Recon (2002).jpg|right|thumb|200px|Tropical Storm Edouard seen by [[Hurricane Hunters]]]]', 'Image:Edouard Recon (2002).jpg'] - ].forEach((a) => { + [ + '[[Image:Edouard Recon (2002).jpg|right|thumb|200px|Tropical Storm Edouard seen by [[Hurricane Hunters]]]]', + 'Image:Edouard Recon (2002).jpg' + ] + ].forEach(a => { let o = parse_image(a[0]); t.deepEqual(o, a[1]); }); t.end(); }); - -test('xml', (t) => { +test('xml', t => { [ ['North America, and one of', 'North America, and one of'], ['North America,
and one of', 'North America, and one of'], ['hello

world

', 'hello world'], [`hello world5, nono man`, 'hello world5, man'], ['hello nono! world1.', 'hello world1.'], - ['hello nono! world2.', 'hello world2.'], - ['hello world3.', 'hello world3.'], - ['hello
hinono!
world4.', 'hello world4.'], - ['hello world5', 'hello world5'] - ].forEach((a) => { + ["hello nono! world2.", 'hello world2.'], + ["hello world3.", 'hello world3.'], + ["hello
hinono!
world4.", 'hello world4.'], + ["hello world5", 'hello world5'] + ].forEach(a => { let s = kill_xml(a[0]); t.equal(s, a[1]); }); From 9b0ffe074a54ecfd07c9ad580f5ff2e8e5aac9e4 Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 11:19:11 -0400 Subject: [PATCH 09/26] more code cleanup --- src/lib/fetch_text.js | 2 +- .../{parse_categories.js => categories.js} | 0 src/parse/{parse_disambig.js => disambig.js} | 2 +- src/parse/{parse_image.js => image.js} | 0 src/parse/index.js | 17 +++--- src/parse/infobox.js | 54 ++++++++++++++++++ ...nfobox_template.js => infobox_template.js} | 0 src/parse/parse_infobox.js | 56 ------------------- .../{parse_redirects.js => redirects.js} | 0 src/parse/{parse_table.js => table.js} | 0 src/parse/{parse_line.js => text/line.js} | 6 +- src/parse/{parse_links.js => text/links.js} | 2 +- tests/template.test.js | 7 +-- tests/unit.test.js | 8 +-- 14 files changed, 75 insertions(+), 79 deletions(-) rename src/parse/{parse_categories.js => categories.js} (100%) rename src/parse/{parse_disambig.js => disambig.js} (91%) rename src/parse/{parse_image.js => image.js} (100%) create mode 100644 src/parse/infobox.js rename src/parse/{parse_infobox_template.js => infobox_template.js} (100%) delete mode 100644 src/parse/parse_infobox.js rename src/parse/{parse_redirects.js => redirects.js} (100%) rename src/parse/{parse_table.js => table.js} (100%) rename src/parse/{parse_line.js => text/line.js} (89%) rename src/parse/{parse_links.js => text/links.js} (97%) diff --git a/src/lib/fetch_text.js b/src/lib/fetch_text.js index 65a62ac1..608292be 100644 --- a/src/lib/fetch_text.js +++ b/src/lib/fetch_text.js @@ -2,7 +2,7 @@ //grab the content of any article, off the api const request = require('superagent'); const site_map = require('../data/site_map'); -const redirects = require('../parse/parse_redirects'); +const redirects = require('../parse/redirects'); const fetch = function(page_identifier, lang_or_wikiid, cb) { lang_or_wikiid = lang_or_wikiid || 'en'; diff --git a/src/parse/parse_categories.js b/src/parse/categories.js similarity index 100% rename from src/parse/parse_categories.js rename to src/parse/categories.js diff --git a/src/parse/parse_disambig.js b/src/parse/disambig.js similarity index 91% rename from src/parse/parse_disambig.js rename to src/parse/disambig.js index 77f231f3..99ce7ddb 100644 --- a/src/parse/parse_disambig.js +++ b/src/parse/disambig.js @@ -1,4 +1,4 @@ -const parse_links = require('./parse_links'); +const parse_links = require('./text/links'); //return a list of probable pages for this disambig page const parse_disambig = function(wiki) { diff --git a/src/parse/parse_image.js b/src/parse/image.js similarity index 100% rename from src/parse/parse_image.js rename to src/parse/image.js diff --git a/src/parse/index.js b/src/parse/index.js index f1f70841..2b36eb74 100644 --- a/src/parse/index.js +++ b/src/parse/index.js @@ -5,15 +5,14 @@ const make_image = require('../lib/make_image'); const helpers = require('../lib/helpers'); //parsing functions -const redirects = require('./parse_redirects'); -const parse_table = require('./parse_table'); -const parse_line = require('./parse_line'); -const parse_categories = require('./parse_categories'); -const parse_disambig = require('./parse_disambig'); -const parse_infobox = require('./parse_infobox'); -const parse_infobox_template = require('./parse_infobox_template'); -const parse_image = require('./parse_image'); - +const redirects = require('./redirects'); +const parse_table = require('./table'); +const parse_categories = require('./categories'); +const parse_disambig = require('./disambig'); +const parse_infobox = require('./infobox'); +const parse_infobox_template = require('./infobox_template'); +const parse_image = require('./image'); +const parse_line = require('./text/line'); const word_templates = require('./cleanup/word_templates'); const recursive_matches = require('./cleanup/recursive_matches'); const preprocess = require('./cleanup/misc'); diff --git a/src/parse/infobox.js b/src/parse/infobox.js new file mode 100644 index 00000000..718e2fde --- /dev/null +++ b/src/parse/infobox.js @@ -0,0 +1,54 @@ +'use strict'; +const helpers = require('../lib/helpers'); +const parse_line = require('./text/line'); + +const line_reg = /\n *\|([^=]*)=(.*)/g; + +const parse_infobox = function(str) { + if (!str) { + return {}; + } + let obj = {}; + let stringBuilder = []; + let lastChar; + //this collapsible list stuff is just a headache + str = str.replace(/\{\{Collapsible list[^}]{10,1000}\}\}/g, ''); + + let parDepth = -2; // first two {{ + for (let i = 0, len = str.length; i < len; i++) { + if (parDepth === 0 && str[i] === '|' && lastChar !== '\n') { + stringBuilder.push('\n'); + } + if (str[i] === '{' || str[i] === '[') { + parDepth++; + } else if (str[i] === '}' || str[i] === ']') { + parDepth--; + } + lastChar = str[i]; + stringBuilder.push(lastChar); + } + + str = stringBuilder.join(''); + + let regexMatch; + while ((regexMatch = line_reg.exec(str)) !== null) { + let key = helpers.trim_whitespace(regexMatch[1] || '') || ''; + let value = helpers.trim_whitespace(regexMatch[2] || '') || ''; + + //this is necessary for mongodb, im sorry + if (key && key.match(/[\.]/)) { + key = null; + } + + if (key && value) { + obj[key] = parse_line(value); + //turn number strings into integers + if (obj[key].text && obj[key].text.match(/^[0-9,]*$/)) { + obj[key].text = obj[key].text.replace(/,/, ''); + obj[key].text = parseInt(obj[key].text, 10); + } + } + } + return obj; +}; +module.exports = parse_infobox; diff --git a/src/parse/parse_infobox_template.js b/src/parse/infobox_template.js similarity index 100% rename from src/parse/parse_infobox_template.js rename to src/parse/infobox_template.js diff --git a/src/parse/parse_infobox.js b/src/parse/parse_infobox.js deleted file mode 100644 index 9a57e937..00000000 --- a/src/parse/parse_infobox.js +++ /dev/null @@ -1,56 +0,0 @@ -'use strict'; -const helpers = require('../lib/helpers'); -const parse_line = require('./parse_line'); - -const line_reg = /\n *\|([^=]*)=(.*)/g; - -const parse_infobox = function(str) { - let obj = {}; - - if (str) { - let stringBuilder = []; - let lastChar; - - //this collapsible list stuff is just a headache - str = str.replace(/\{\{Collapsible list[^}]{10,1000}\}\}/g, ''); - - let parDepth = -2; // first two {{ - for (let i = 0, len = str.length; i < len; i++) { - if (parDepth === 0 && str[i] === '|' && lastChar !== '\n') { - stringBuilder.push('\n'); - } - if (str[i] === '{' || str[i] === '[') { - parDepth++; - } else if (str[i] === '}' || str[i] === ']') { - parDepth--; - } - lastChar = str[i]; - stringBuilder.push(lastChar); - } - - str = stringBuilder.join(''); - - let regexMatch; - while ((regexMatch = line_reg.exec(str)) !== null) { - let key = helpers.trim_whitespace(regexMatch[1] || '') || ''; - let value = helpers.trim_whitespace(regexMatch[2] || '') || ''; - - //this is necessary for mongodb, im sorry - if (key && key.match(/[\.]/)) { - key = null; - } - - if (key && value) { - obj[key] = parse_line(value); - //turn number strings into integers - if (obj[key].text && obj[key].text.match(/^[0-9,]*$/)) { - obj[key].text = obj[key].text.replace(/,/, ''); - obj[key].text = parseInt(obj[key].text, 10); - } - } - } - } - - return obj; -}; -module.exports = parse_infobox; diff --git a/src/parse/parse_redirects.js b/src/parse/redirects.js similarity index 100% rename from src/parse/parse_redirects.js rename to src/parse/redirects.js diff --git a/src/parse/parse_table.js b/src/parse/table.js similarity index 100% rename from src/parse/parse_table.js rename to src/parse/table.js diff --git a/src/parse/parse_line.js b/src/parse/text/line.js similarity index 89% rename from src/parse/parse_line.js rename to src/parse/text/line.js index b3b131c3..a4be6052 100644 --- a/src/parse/parse_line.js +++ b/src/parse/text/line.js @@ -1,6 +1,6 @@ -const helpers = require('../lib/helpers'); -const parse_links = require('./parse_links'); -const i18n = require('../data/i18n'); +const helpers = require('../../lib/helpers'); +const parse_links = require('./links'); +const i18n = require('../../data/i18n'); const cat_reg = new RegExp('\\[\\[:?(' + i18n.categories.join('|') + '):[^\\]\\]]{2,80}\\]\\]', 'gi'); //return only rendered text of wiki links diff --git a/src/parse/parse_links.js b/src/parse/text/links.js similarity index 97% rename from src/parse/parse_links.js rename to src/parse/text/links.js index 6e3b2744..e7b784f1 100644 --- a/src/parse/parse_links.js +++ b/src/parse/text/links.js @@ -1,4 +1,4 @@ -const helpers = require('../lib/helpers'); +const helpers = require('../../lib/helpers'); const link_reg = /\[\[(.{2,80}?)\]\](\w{0,10})/g; const ignore_links = /^:?(category|catégorie|Kategorie|Categoría|Categoria|Categorie|Kategoria|تصنيف|image|file|image|fichier|datei|media|special|wp|wikipedia|help|user|mediawiki|portal|talk|template|book|draft|module|topic|wiktionary|wikisource):/i; diff --git a/tests/template.test.js b/tests/template.test.js index be00eac7..40ab67e5 100644 --- a/tests/template.test.js +++ b/tests/template.test.js @@ -1,7 +1,7 @@ 'use strict'; -var parse_table = require('../src/parse/parse_table'); -var parse_disambig = require('../src/parse/parse_disambig'); -var parse_infobox = require('../src/parse/parse_infobox'); +var parse_table = require('../src/parse/table'); +var parse_disambig = require('../src/parse/disambig'); +var parse_infobox = require('../src/parse/infobox'); var test = require('tape'); let boloZenden = `{{Infobox football biography @@ -94,7 +94,6 @@ test('parkplace disambig', function(t) { t.end(); }); - let bluejays = ` {| border="1" cellpadding="2" cellspacing="0" class="wikitable" |- diff --git a/tests/unit.test.js b/tests/unit.test.js index 66159aac..279a86ac 100644 --- a/tests/unit.test.js +++ b/tests/unit.test.js @@ -1,10 +1,10 @@ 'use strict'; var test = require('tape'); -var redirects = require('../src/parse/parse_redirects'); -var parse_line = require('../src/parse/parse_line'); -var parse_categories = require('../src/parse/parse_categories'); +var redirects = require('../src/parse/redirects'); +var parse_line = require('../src/parse/text/line'); +var parse_categories = require('../src/parse/categories'); var cleanup_misc = require('../src/parse/cleanup/misc'); -var parse_image = require('../src/parse/parse_image'); +var parse_image = require('../src/parse/image'); var sentence_parser = require('../src/lib/sentence_parser'); var kill_xml = require('../src/parse/cleanup/kill_xml'); From 7181f67e0c2289e1fb975b6bb05c1e6cdf03eb96 Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 11:22:20 -0400 Subject: [PATCH 10/26] page/disambig move --- src/lib/fetch_text.js | 2 +- src/parse/index.js | 5 +++-- src/parse/{ => page}/disambig.js | 2 +- src/parse/{ => page}/redirects.js | 2 +- tests/template.test.js | 2 +- tests/unit.test.js | 2 +- 6 files changed, 8 insertions(+), 7 deletions(-) rename src/parse/{ => page}/disambig.js (91%) rename src/parse/{ => page}/redirects.js (92%) diff --git a/src/lib/fetch_text.js b/src/lib/fetch_text.js index 608292be..4d38204d 100644 --- a/src/lib/fetch_text.js +++ b/src/lib/fetch_text.js @@ -2,7 +2,7 @@ //grab the content of any article, off the api const request = require('superagent'); const site_map = require('../data/site_map'); -const redirects = require('../parse/redirects'); +const redirects = require('../parse/page/redirects'); const fetch = function(page_identifier, lang_or_wikiid, cb) { lang_or_wikiid = lang_or_wikiid || 'en'; diff --git a/src/parse/index.js b/src/parse/index.js index 2b36eb74..d7261b8e 100644 --- a/src/parse/index.js +++ b/src/parse/index.js @@ -5,13 +5,14 @@ const make_image = require('../lib/make_image'); const helpers = require('../lib/helpers'); //parsing functions -const redirects = require('./redirects'); const parse_table = require('./table'); const parse_categories = require('./categories'); -const parse_disambig = require('./disambig'); const parse_infobox = require('./infobox'); const parse_infobox_template = require('./infobox_template'); const parse_image = require('./image'); + +const redirects = require('./page/redirects'); +const parse_disambig = require('./page/disambig'); const parse_line = require('./text/line'); const word_templates = require('./cleanup/word_templates'); const recursive_matches = require('./cleanup/recursive_matches'); diff --git a/src/parse/disambig.js b/src/parse/page/disambig.js similarity index 91% rename from src/parse/disambig.js rename to src/parse/page/disambig.js index 99ce7ddb..fcd3fa65 100644 --- a/src/parse/disambig.js +++ b/src/parse/page/disambig.js @@ -1,4 +1,4 @@ -const parse_links = require('./text/links'); +const parse_links = require('../text/links'); //return a list of probable pages for this disambig page const parse_disambig = function(wiki) { diff --git a/src/parse/redirects.js b/src/parse/page/redirects.js similarity index 92% rename from src/parse/redirects.js rename to src/parse/page/redirects.js index 7b7412a3..bd47916e 100644 --- a/src/parse/redirects.js +++ b/src/parse/page/redirects.js @@ -1,4 +1,4 @@ -const i18n = require('../data/i18n'); +const i18n = require('../../data/i18n'); //pulls target link out of redirect page const REDIRECT_REGEX = new RegExp('^ ?#(' + i18n.redirects.join('|') + ') *?\\[\\[(.{2,60}?)\\]\\]', 'i'); diff --git a/tests/template.test.js b/tests/template.test.js index 40ab67e5..8ed2ec17 100644 --- a/tests/template.test.js +++ b/tests/template.test.js @@ -1,6 +1,6 @@ 'use strict'; var parse_table = require('../src/parse/table'); -var parse_disambig = require('../src/parse/disambig'); +var parse_disambig = require('../src/parse/page/disambig'); var parse_infobox = require('../src/parse/infobox'); var test = require('tape'); diff --git a/tests/unit.test.js b/tests/unit.test.js index 279a86ac..2eefec11 100644 --- a/tests/unit.test.js +++ b/tests/unit.test.js @@ -1,6 +1,6 @@ 'use strict'; var test = require('tape'); -var redirects = require('../src/parse/redirects'); +var redirects = require('../src/parse/page/redirects'); var parse_line = require('../src/parse/text/line'); var parse_categories = require('../src/parse/categories'); var cleanup_misc = require('../src/parse/cleanup/misc'); From 6c699087c1167fc9abdb683f157818d5997cded6 Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 11:31:57 -0400 Subject: [PATCH 11/26] refactor table parsing --- src/parse/index.js | 14 ++++---------- src/parse/table.js | 13 ++++++++++++- tests/template.test.js | 15 +++++++-------- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/parse/index.js b/src/parse/index.js index d7261b8e..03de4036 100644 --- a/src/parse/index.js +++ b/src/parse/index.js @@ -5,7 +5,7 @@ const make_image = require('../lib/make_image'); const helpers = require('../lib/helpers'); //parsing functions -const parse_table = require('./table'); +const parse_tables = require('./table'); const parse_categories = require('./categories'); const parse_infobox = require('./infobox'); const parse_infobox_template = require('./infobox_template'); @@ -24,7 +24,6 @@ const infobox_reg = new RegExp('{{(' + i18n.infoboxes.join('|') + ')[: \n]', 'ig const ban_headings = new RegExp('^ ?(' + i18n.sources.join('|') + ') ?$', 'i'); //remove things like 'external links' const fileRegex = new RegExp('\\[\\[(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'); const img_regex = new RegExp('^(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'); -const table_reg = /\{\|[\s\S]{1,8000}?\|\}/g; const noWrap_reg = /^\{\{nowrap\|(.*?)\}\}$/; // options @@ -59,15 +58,10 @@ const main = function(wiki, options) { }; //parse templates like {{currentday}} wiki = word_templates(wiki); - //kill off th3 craziness + //kill off (some) craziness wiki = preprocess(wiki); - //find tables - r.tables = wiki.match(table_reg, '') || []; - r.tables = r.tables.map(function(s) { - return parse_table(s); - }); - //remove tables - wiki = wiki.replace(/\{\|[\s\S]{1,8000}?\|\}/g, ''); + //parse the tables + wiki = parse_tables(r, wiki); //reduce the scary recursive situations //remove {{template {{}} }} recursions diff --git a/src/parse/table.js b/src/parse/table.js index cd7542af..ca29b292 100644 --- a/src/parse/table.js +++ b/src/parse/table.js @@ -1,4 +1,5 @@ const helpers = require('../lib/helpers'); +const table_reg = /\{\|[\s\S]{1,8000}?\|\}/g; //turn a {|...table string into an array of arrays const parse_table = function(wiki) { @@ -39,4 +40,14 @@ const parse_table = function(wiki) { }); return table; }; -module.exports = parse_table; + +const findTables = function(r, wiki) { + r.tables = wiki.match(table_reg, '') || []; + r.tables = r.tables.map(function(str) { + return parse_table(str); + }); + //remove tables + wiki = wiki.replace(/\{\|[\s\S]{1,8000}?\|\}/g, ''); + return wiki; +}; +module.exports = findTables; diff --git a/tests/template.test.js b/tests/template.test.js index 8ed2ec17..ceec8e58 100644 --- a/tests/template.test.js +++ b/tests/template.test.js @@ -1,7 +1,5 @@ 'use strict'; -var parse_table = require('../src/parse/table'); -var parse_disambig = require('../src/parse/page/disambig'); -var parse_infobox = require('../src/parse/infobox'); +var wtf = require('../src/'); var test = require('tape'); let boloZenden = `{{Infobox football biography @@ -30,8 +28,9 @@ let boloZenden = `{{Infobox football biography | manageryears1 = 2012–2013 |managerclubs1 = [[Chelsea F.C.|Chelsea]] (assistant manager) | manageryears2 = 2013– |managerclubs2 = [[Jong PSV]] (assistant manager) }}`; + test('boloZenden infobox', function(t) { - let o = parse_infobox(boloZenden); + let o = wtf.parse(boloZenden).infobox; t.equal(o.years1.text, '1993–1998'); t.equal(o.clubs1.text, 'PSV'); t.equal(o.youthyears1.text, '1985–1987'); @@ -63,7 +62,7 @@ let hurricane = `{{Infobox Hurricane | Hurricane season=[[2002 Atlantic hurricane season]] }}`; test('hurricane infobox', function(t) { - let o = parse_infobox(hurricane); + let o = wtf.parse(hurricane).infobox; t.equal(o.Name.text, 'Tropical Storm Edouard'); t.equal(o.Dissipated.text, 'September 6, 2002'); t.equal(o['Hurricane season'].text, '2002 Atlantic hurricane season'); @@ -87,7 +86,7 @@ let park_place = ` {{disambiguation}} `; test('parkplace disambig', function(t) { - let o = parse_disambig(park_place); + let o = wtf.parse(park_place); t.equal(o.type, 'disambiguation'); t.equal(o.pages.length, 4); t.equal(o.pages[0], 'Park Place (TV series)'); @@ -105,7 +104,7 @@ let bluejays = ` |} `; test('bluejays table', function(t) { - let arr = parse_table(bluejays); + let arr = wtf.parse(bluejays).tables[0]; t.equal(arr.length, 3); t.equal(arr[0][0], '#'); t.equal(arr[1][0], '1'); @@ -143,7 +142,7 @@ let alabama = ` }} `; test('Alabama infobox', function(t) { - let infobox = parse_infobox(alabama); + let infobox = wtf.parse(alabama).infobox; t.equal(infobox.athletics.text, 'NCAA Division I – SEC', 'athletics =' + infobox.athletics.text); t.equal(infobox.country.text, 'U.S.', 'country =' + infobox.country.text); t.equal(infobox.president.text, 'Stuart R. Bell', 'president =' + infobox.president.text); From a59e64e5be8efc17955d1e3ddbe01b18eb96ffc6 Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 11:36:47 -0400 Subject: [PATCH 12/26] seperate cursive step --- src/parse/index.js | 54 ++------------------------------------- src/parse/recursion.js | 58 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 52 deletions(-) create mode 100644 src/parse/recursion.js diff --git a/src/parse/index.js b/src/parse/index.js index 03de4036..c0cca24d 100644 --- a/src/parse/index.js +++ b/src/parse/index.js @@ -1,5 +1,4 @@ const i18n = require('../data/i18n'); -const languages = require('../data/languages'); const sentence_parser = require('../lib/sentence_parser'); const make_image = require('../lib/make_image'); const helpers = require('../lib/helpers'); @@ -7,24 +6,18 @@ const helpers = require('../lib/helpers'); //parsing functions const parse_tables = require('./table'); const parse_categories = require('./categories'); -const parse_infobox = require('./infobox'); -const parse_infobox_template = require('./infobox_template'); -const parse_image = require('./image'); +const parse_recursion = require('./recursion'); const redirects = require('./page/redirects'); const parse_disambig = require('./page/disambig'); const parse_line = require('./text/line'); const word_templates = require('./cleanup/word_templates'); -const recursive_matches = require('./cleanup/recursive_matches'); const preprocess = require('./cleanup/misc'); //regexs const template_reg = new RegExp('\\{\\{ ?(' + i18n.disambigs.join('|') + ')(\\|[a-z =]*?)? ?\\}\\}', 'i'); -const infobox_reg = new RegExp('{{(' + i18n.infoboxes.join('|') + ')[: \n]', 'ig'); const ban_headings = new RegExp('^ ?(' + i18n.sources.join('|') + ') ?$', 'i'); //remove things like 'external links' -const fileRegex = new RegExp('\\[\\[(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'); const img_regex = new RegExp('^(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'); -const noWrap_reg = /^\{\{nowrap\|(.*?)\}\}$/; // options const defaultParseOptions = { @@ -63,50 +56,7 @@ const main = function(wiki, options) { //parse the tables wiki = parse_tables(r, wiki); - //reduce the scary recursive situations - //remove {{template {{}} }} recursions - let matches = recursive_matches('{', '}', wiki); - matches.forEach(function(s) { - if (s.match(infobox_reg, 'ig') && Object.keys(r.infobox).length === 0) { - r.infobox = parse_infobox(s); - r.infobox_template = parse_infobox_template(s); - } - if (s.match(infobox_reg)) { - wiki = wiki.replace(s, ''); - } - //rest of them... - if (s.match(/^\{\{/)) { - //support nowrap - const nowrap = s.match(noWrap_reg); - if (nowrap) { - wiki = wiki.replace(s, nowrap[1]); - return; - } - //if it's not a known template, but it's recursive, remove it - //(because it will be misread later-on) - wiki = wiki.replace(s, ''); - } - }); - - //second, remove [[file:...[[]] ]] recursions - matches = recursive_matches('[', ']', wiki); - matches.forEach(function(s) { - if (s.match(fileRegex)) { - r.images.push(parse_image(s)); - wiki = wiki.replace(s, ''); - } - }); - //third, wiktionary-style interlanguage links - matches.forEach(function(s) { - if (s.match(/\[\[([a-z][a-z]):(.*?)\]\]/i) !== null) { - const lang = s.match(/\[\[([a-z][a-z]):/i)[1]; - if (lang && languages[lang]) { - r.translations[lang] = s.match(/\[\[([a-z][a-z]):(.*?)\]\]/i)[2]; - } - wiki = wiki.replace(s, ''); - } - }); - + wiki = parse_recursion(r, wiki); //now that the scary recursion issues are gone, we can trust simple regex methods //kill the rest of templates diff --git a/src/parse/recursion.js b/src/parse/recursion.js new file mode 100644 index 00000000..c2a0ed2c --- /dev/null +++ b/src/parse/recursion.js @@ -0,0 +1,58 @@ +const i18n = require('../data/i18n'); +const parse_infobox = require('./infobox'); +const parse_infobox_template = require('./infobox_template'); +const parse_image = require('./image'); +const languages = require('../data/languages'); +const recursive_matches = require('./cleanup/recursive_matches'); +const infobox_reg = new RegExp('{{(' + i18n.infoboxes.join('|') + ')[: \n]', 'ig'); +const fileRegex = new RegExp('\\[\\[(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'); +const noWrap_reg = /^\{\{nowrap\|(.*?)\}\}$/; + +//reduce the scary recursive situations +const parse_recursive = function(r, wiki) { + //remove {{template {{}} }} recursions + let matches = recursive_matches('{', '}', wiki); + matches.forEach(function(s) { + if (s.match(infobox_reg, 'ig') && Object.keys(r.infobox).length === 0) { + r.infobox = parse_infobox(s); + r.infobox_template = parse_infobox_template(s); + } + if (s.match(infobox_reg)) { + wiki = wiki.replace(s, ''); + } + //rest of them... + if (s.match(/^\{\{/)) { + //support nowrap + const nowrap = s.match(noWrap_reg); + if (nowrap) { + wiki = wiki.replace(s, nowrap[1]); + return; + } + //if it's not a known template, but it's recursive, remove it + //(because it will be misread later-on) + wiki = wiki.replace(s, ''); + } + }); + + //second, remove [[file:...[[]] ]] recursions + matches = recursive_matches('[', ']', wiki); + matches.forEach(function(s) { + if (s.match(fileRegex)) { + r.images.push(parse_image(s)); + wiki = wiki.replace(s, ''); + } + }); + //third, wiktionary-style interlanguage links + matches.forEach(function(s) { + if (s.match(/\[\[([a-z][a-z]):(.*?)\]\]/i) !== null) { + const lang = s.match(/\[\[([a-z][a-z]):/i)[1]; + if (lang && languages[lang]) { + r.translations[lang] = s.match(/\[\[([a-z][a-z]):(.*?)\]\]/i)[2]; + } + wiki = wiki.replace(s, ''); + } + }); + return wiki; +}; + +module.exports = parse_recursive; From 120359819351f8638eab7d479660adc659300675 Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 11:48:24 -0400 Subject: [PATCH 13/26] change behaviour of list parsing option --- src/parse/index.js | 80 +++++------------------------------------ src/parse/recursion.js | 8 +++-- src/parse/text/index.js | 73 +++++++++++++++++++++++++++++++++++++ tests/page.test.js | 2 +- 4 files changed, 88 insertions(+), 75 deletions(-) create mode 100644 src/parse/text/index.js diff --git a/src/parse/index.js b/src/parse/index.js index c0cca24d..ca26639c 100644 --- a/src/parse/index.js +++ b/src/parse/index.js @@ -1,7 +1,5 @@ const i18n = require('../data/i18n'); -const sentence_parser = require('../lib/sentence_parser'); const make_image = require('../lib/make_image'); -const helpers = require('../lib/helpers'); //parsing functions const parse_tables = require('./table'); @@ -10,25 +8,19 @@ const parse_recursion = require('./recursion'); const redirects = require('./page/redirects'); const parse_disambig = require('./page/disambig'); -const parse_line = require('./text/line'); +const parse_text = require('./text'); const word_templates = require('./cleanup/word_templates'); const preprocess = require('./cleanup/misc'); //regexs const template_reg = new RegExp('\\{\\{ ?(' + i18n.disambigs.join('|') + ')(\\|[a-z =]*?)? ?\\}\\}', 'i'); -const ban_headings = new RegExp('^ ?(' + i18n.sources.join('|') + ') ?$', 'i'); //remove things like 'external links' const img_regex = new RegExp('^(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'); -// options -const defaultParseOptions = { - ignoreLists: true -}; - //some xml elements are just junk, and demand full inglorious death by regular exp //other xml elements, like , are plucked out afterwards -const main = function(wiki, options) { +const main = function(wiki) { wiki = wiki || ''; - options = Object.assign({}, defaultParseOptions, options); + // options = Object.assign({}, defaultParseOptions, options); //detect if page is just redirect, and return if (redirects.is_redirect(wiki)) { return redirects.parse_redirect(wiki); @@ -55,74 +47,18 @@ const main = function(wiki, options) { wiki = preprocess(wiki); //parse the tables wiki = parse_tables(r, wiki); - + //parse+remove scary '[[ [[]] ]]' stuff wiki = parse_recursion(r, wiki); - //now that the scary recursion issues are gone, we can trust simple regex methods + + //ok, now that the scary recursion issues are gone, we can trust simple regex methods.. //kill the rest of templates wiki = wiki.replace(/\{\{.*?\}\}/g, ''); - //get list of links, categories r.categories = parse_categories(wiki); - //next, map each line into a parsable sentence - let lines = wiki.replace(/\r/g, '').split(/\n/); - let section = 'Intro'; - let number = 1; - - lines.forEach(function(part) { - if (!section) { - return; - } - //add # numberings formatting - if (part.match(/^ ?\#[^:,\|]{4}/i)) { - part = part.replace(/^ ?#*/, number + ') '); - part = part + '\n'; - number += 1; - } else { - number = 1; - } - //add bullet-points formatting - if (part.match(/^\*+[^:,\|]{4}/)) { - part = part + '\n'; - } - //remove some nonsense wp lines - - if (options.ignoreLists) { - //ignore list - if (part.match(/^[#\*:;\|]/)) { - return; - } - } - - //ignore only-punctuation - if (!part.match(/[a-z0-9]/i)) { - return; - } - //headings - if (part.match(/^={1,5}[^=]{1,200}={1,5}$/)) { - section = part.match(/^={1,5}([^=]{1,200}?)={1,5}$/) || []; - section = section[1] || ''; - section = section.replace(/\./g, ' '); // this is necessary for mongo, i'm sorry - section = helpers.trim_whitespace(section); - //ban some sections - if (section && section.match(ban_headings)) { - section = undefined; - } - return; - } - - //still alive, add it to the section - sentence_parser(part).forEach(function(line) { - line = parse_line(line); + //parse all the headings, and their texts + wiki = parse_text(r, wiki); - if (line && line.text) { - if (!r.text[section]) { - r.text[section] = []; - } - r.text[section].push(line); - } - }); - }); //add additional image from infobox, if applicable if (r.infobox['image'] && r.infobox['image'].text) { let img = r.infobox['image'].text || ''; diff --git a/src/parse/recursion.js b/src/parse/recursion.js index c2a0ed2c..fa97f520 100644 --- a/src/parse/recursion.js +++ b/src/parse/recursion.js @@ -1,9 +1,11 @@ const i18n = require('../data/i18n'); +const languages = require('../data/languages'); +const recursive_matches = require('./cleanup/recursive_matches'); + const parse_infobox = require('./infobox'); const parse_infobox_template = require('./infobox_template'); const parse_image = require('./image'); -const languages = require('../data/languages'); -const recursive_matches = require('./cleanup/recursive_matches'); + const infobox_reg = new RegExp('{{(' + i18n.infoboxes.join('|') + ')[: \n]', 'ig'); const fileRegex = new RegExp('\\[\\[(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'); const noWrap_reg = /^\{\{nowrap\|(.*?)\}\}$/; @@ -42,6 +44,7 @@ const parse_recursive = function(r, wiki) { wiki = wiki.replace(s, ''); } }); + //third, wiktionary-style interlanguage links matches.forEach(function(s) { if (s.match(/\[\[([a-z][a-z]):(.*?)\]\]/i) !== null) { @@ -52,6 +55,7 @@ const parse_recursive = function(r, wiki) { wiki = wiki.replace(s, ''); } }); + return wiki; }; diff --git a/src/parse/text/index.js b/src/parse/text/index.js new file mode 100644 index 00000000..bc3df369 --- /dev/null +++ b/src/parse/text/index.js @@ -0,0 +1,73 @@ +const i18n = require('../../data/i18n'); +const sentence_parser = require('../../lib/sentence_parser'); +const helpers = require('../../lib/helpers'); +const parse_line = require('./line'); +const ban_headings = new RegExp('^ ?(' + i18n.sources.join('|') + ') ?$', 'i'); //remove things like 'external links' +const list_reg = /^[#\*:;\|]+/; + +const parseText = function(r, wiki) { + //next, map each line into a parsable sentence + let lines = wiki.replace(/\r/g, '').split(/\n/); + let section = 'Intro'; + let number = 1; + + lines.forEach(function(part) { + if (!section) { + return; + } + //add # numberings formatting + if (part.match(/^ ?\#[^:,\|]{4}/i)) { + part = part.replace(/^ ?#*/, number + ') '); + part = part + '\n'; + number += 1; + } else { + number = 1; + } + //add bullet-points formatting + if (part.match(/^\*+[^:,\|]{4}/)) { + part = part + '\n'; + } + //remove some nonsense wp lines + + //parse lists + if (part.match(list_reg)) { + part = part.replace(list_reg, ''); + if (part.length < 10) { + //not a full sentence + return; + } + } + + //ignore only-punctuation + if (!part.match(/[a-z0-9]/i)) { + return; + } + //headings + if (part.match(/^={1,5}[^=]{1,200}={1,5}$/)) { + section = part.match(/^={1,5}([^=]{1,200}?)={1,5}$/) || []; + section = section[1] || ''; + section = section.replace(/\./g, ' '); // this is necessary for mongo, i'm sorry + section = helpers.trim_whitespace(section); + //ban some sections + if (section && section.match(ban_headings)) { + section = undefined; + } + return; + } + + //still alive, add it to the section + sentence_parser(part).forEach(function(line) { + line = parse_line(line); + + if (line && line.text) { + if (!r.text[section]) { + r.text[section] = []; + } + r.text[section].push(line); + } + }); + }); + return wiki; +}; + +module.exports = parseText; diff --git a/tests/page.test.js b/tests/page.test.js index 5ccbe35e..c8bb6d64 100644 --- a/tests/page.test.js +++ b/tests/page.test.js @@ -32,7 +32,7 @@ test('toronto_star', t => { // str_equal(data.text.History.length, 21, t); str_equal(data.text['History'].length, 21, t); str_equal(data.categories.length, 6, t); - str_equal(data.text['Notable cartoonists'], undefined, t); + // str_equal(data.text['Notable cartoonists'], undefined, t); t.end(); }); From 616107db374dde94a517fe112d3a646986418b19 Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 11:57:51 -0400 Subject: [PATCH 14/26] further cleanup --- scratch.js | 2 +- src/parse/categories.js | 8 ++++---- src/parse/index.js | 25 ++++++++++--------------- src/parse/page/disambig.js | 11 ++++++++++- tests/unit.test.js | 6 +++--- 5 files changed, 28 insertions(+), 24 deletions(-) diff --git a/scratch.js b/scratch.js index 3b905860..82030888 100644 --- a/scratch.js +++ b/scratch.js @@ -16,7 +16,7 @@ const wtf = require('./src/index'); function from_file(page) { let str = require('fs').readFileSync('./tests/cache/' + page.toLowerCase() + '.txt', 'utf-8'); // return wtf.plaintext(str) - console.log(wtf.parse(str, {}).text); + console.log(wtf.parse(str, {})); } // from_file("list") diff --git a/src/parse/categories.js b/src/parse/categories.js index 43803f14..37dfdd66 100644 --- a/src/parse/categories.js +++ b/src/parse/categories.js @@ -2,8 +2,8 @@ const i18n = require('../data/i18n'); const cat_reg = new RegExp('\\[\\[:?(' + i18n.categories.join('|') + '):(.{2,60}?)]](w{0,10})', 'ig'); const cat_remove_reg = new RegExp('^\\[\\[:?(' + i18n.categories.join('|') + '):', 'ig'); -const parse_categories = function(wiki) { - let cats = []; +const parse_categories = function(r, wiki) { + r.categories = []; let tmp = wiki.match(cat_reg); //regular links if (tmp) { tmp.forEach(function(c) { @@ -11,10 +11,10 @@ const parse_categories = function(wiki) { c = c.replace(/\|?[ \*]?\]\]$/i, ''); //parse fancy onces.. c = c.replace(/\|.*/, ''); //everything after the '|' is metadata if (c && !c.match(/[\[\]]/)) { - cats.push(c); + r.categories.push(c); } }); } - return cats; + return wiki; }; module.exports = parse_categories; diff --git a/src/parse/index.js b/src/parse/index.js index ca26639c..495d420a 100644 --- a/src/parse/index.js +++ b/src/parse/index.js @@ -2,33 +2,31 @@ const i18n = require('../data/i18n'); const make_image = require('../lib/make_image'); //parsing functions +const redirects = require('./page/redirects'); +const disambig = require('./page/disambig'); + +const word_templates = require('./cleanup/word_templates'); +const preprocess = require('./cleanup/misc'); + const parse_tables = require('./table'); const parse_categories = require('./categories'); const parse_recursion = require('./recursion'); - -const redirects = require('./page/redirects'); -const parse_disambig = require('./page/disambig'); const parse_text = require('./text'); -const word_templates = require('./cleanup/word_templates'); -const preprocess = require('./cleanup/misc'); //regexs -const template_reg = new RegExp('\\{\\{ ?(' + i18n.disambigs.join('|') + ')(\\|[a-z =]*?)? ?\\}\\}', 'i'); const img_regex = new RegExp('^(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'); //some xml elements are just junk, and demand full inglorious death by regular exp //other xml elements, like , are plucked out afterwards const main = function(wiki) { wiki = wiki || ''; - // options = Object.assign({}, defaultParseOptions, options); //detect if page is just redirect, and return if (redirects.is_redirect(wiki)) { return redirects.parse_redirect(wiki); } - //detect if page is disambiguator page - if (wiki.match(template_reg)) { - //|| wiki.match(/^.{3,25} may refer to/i)|| wiki.match(/^.{3,25} ist der Name mehrerer /i) - return parse_disambig(wiki); + //detect if page is just disambiguator page, and return + if (disambig.is_disambig(wiki)) { + return disambig.parse_disambig(wiki); } let r = { @@ -49,16 +47,13 @@ const main = function(wiki) { wiki = parse_tables(r, wiki); //parse+remove scary '[[ [[]] ]]' stuff wiki = parse_recursion(r, wiki); - //ok, now that the scary recursion issues are gone, we can trust simple regex methods.. - //kill the rest of templates wiki = wiki.replace(/\{\{.*?\}\}/g, ''); //get list of links, categories - r.categories = parse_categories(wiki); + wiki = parse_categories(r, wiki); //parse all the headings, and their texts wiki = parse_text(r, wiki); - //add additional image from infobox, if applicable if (r.infobox['image'] && r.infobox['image'].text) { let img = r.infobox['image'].text || ''; diff --git a/src/parse/page/disambig.js b/src/parse/page/disambig.js index fcd3fa65..8ff7983a 100644 --- a/src/parse/page/disambig.js +++ b/src/parse/page/disambig.js @@ -1,4 +1,10 @@ +const i18n = require('../../data/i18n'); const parse_links = require('../text/links'); +const template_reg = new RegExp('\\{\\{ ?(' + i18n.disambigs.join('|') + ')(\\|[a-z =]*?)? ?\\}\\}', 'i'); + +const is_disambig = function(wiki) { + return template_reg.test(wiki); +}; //return a list of probable pages for this disambig page const parse_disambig = function(wiki) { @@ -18,4 +24,7 @@ const parse_disambig = function(wiki) { pages: pages }; }; -module.exports = parse_disambig; +module.exports = { + is_disambig: is_disambig, + parse_disambig: parse_disambig +}; diff --git a/tests/unit.test.js b/tests/unit.test.js index 2eefec11..1463c87c 100644 --- a/tests/unit.test.js +++ b/tests/unit.test.js @@ -2,7 +2,7 @@ var test = require('tape'); var redirects = require('../src/parse/page/redirects'); var parse_line = require('../src/parse/text/line'); -var parse_categories = require('../src/parse/categories'); +var wtf = require('../src/'); var cleanup_misc = require('../src/parse/cleanup/misc'); var parse_image = require('../src/parse/image'); var sentence_parser = require('../src/lib/sentence_parser'); @@ -81,8 +81,8 @@ test('parse_categories', t => { [' [[Category:Tony Danza|metadata]] [[category:Formal Wear]] ', ['Tony Danza', 'Formal Wear']], ['[[categoría:Tony Danza|metadata]] ', ['Tony Danza']] ].forEach(a => { - let o = parse_categories(a[0]); - t.deepEqual(o, a[1]); + let cats = wtf.parse(a[0]).categories; + t.deepEqual(cats, a[1]); }); t.end(); }); From f953b993e9ebca68422699d4549ce16e1a4d34f7 Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 12:03:13 -0400 Subject: [PATCH 15/26] recursive directory --- src/parse/index.js | 2 +- src/parse/{ => recursive}/image.js | 2 +- src/parse/{recursion.js => recursive/index.js} | 6 +++--- src/parse/{ => recursive}/infobox.js | 4 ++-- src/parse/{ => recursive}/infobox_template.js | 2 +- src/parse/{cleanup => recursive}/recursive_matches.js | 0 tests/unit.test.js | 8 +++----- 7 files changed, 11 insertions(+), 13 deletions(-) rename src/parse/{ => recursive}/image.js (89%) rename src/parse/{recursion.js => recursive/index.js} (92%) rename src/parse/{ => recursive}/infobox.js (93%) rename src/parse/{ => recursive}/infobox_template.js (89%) rename src/parse/{cleanup => recursive}/recursive_matches.js (100%) diff --git a/src/parse/index.js b/src/parse/index.js index 495d420a..74264d83 100644 --- a/src/parse/index.js +++ b/src/parse/index.js @@ -10,7 +10,7 @@ const preprocess = require('./cleanup/misc'); const parse_tables = require('./table'); const parse_categories = require('./categories'); -const parse_recursion = require('./recursion'); +const parse_recursion = require('./recursive'); const parse_text = require('./text'); //regexs diff --git a/src/parse/image.js b/src/parse/recursive/image.js similarity index 89% rename from src/parse/image.js rename to src/parse/recursive/image.js index aba6d7f1..0f7581d7 100644 --- a/src/parse/image.js +++ b/src/parse/recursive/image.js @@ -1,4 +1,4 @@ -const i18n = require('../data/i18n'); +const i18n = require('../../data/i18n'); const file_reg = new RegExp('(' + i18n.images.concat(i18n.files).join('|') + '):.*?[\\|\\]]', 'i'); //images are usually [[image:my_pic.jpg]] diff --git a/src/parse/recursion.js b/src/parse/recursive/index.js similarity index 92% rename from src/parse/recursion.js rename to src/parse/recursive/index.js index fa97f520..061105f3 100644 --- a/src/parse/recursion.js +++ b/src/parse/recursive/index.js @@ -1,6 +1,6 @@ -const i18n = require('../data/i18n'); -const languages = require('../data/languages'); -const recursive_matches = require('./cleanup/recursive_matches'); +const i18n = require('../../data/i18n'); +const languages = require('../../data/languages'); +const recursive_matches = require('./recursive_matches'); const parse_infobox = require('./infobox'); const parse_infobox_template = require('./infobox_template'); diff --git a/src/parse/infobox.js b/src/parse/recursive/infobox.js similarity index 93% rename from src/parse/infobox.js rename to src/parse/recursive/infobox.js index 718e2fde..56114823 100644 --- a/src/parse/infobox.js +++ b/src/parse/recursive/infobox.js @@ -1,6 +1,6 @@ 'use strict'; -const helpers = require('../lib/helpers'); -const parse_line = require('./text/line'); +const helpers = require('../../lib/helpers'); +const parse_line = require('../text/line'); const line_reg = /\n *\|([^=]*)=(.*)/g; diff --git a/src/parse/infobox_template.js b/src/parse/recursive/infobox_template.js similarity index 89% rename from src/parse/infobox_template.js rename to src/parse/recursive/infobox_template.js index 3281ea83..0518fd30 100644 --- a/src/parse/infobox_template.js +++ b/src/parse/recursive/infobox_template.js @@ -1,4 +1,4 @@ -const i18n = require('../data/i18n'); +const i18n = require('../../data/i18n'); const infobox_template_reg = new RegExp('{{(?:' + i18n.infoboxes.join('|') + ')\\s*(.*)', 'i'); function parse_infobox_template(str) { diff --git a/src/parse/cleanup/recursive_matches.js b/src/parse/recursive/recursive_matches.js similarity index 100% rename from src/parse/cleanup/recursive_matches.js rename to src/parse/recursive/recursive_matches.js diff --git a/tests/unit.test.js b/tests/unit.test.js index 1463c87c..b1a41690 100644 --- a/tests/unit.test.js +++ b/tests/unit.test.js @@ -1,10 +1,8 @@ 'use strict'; var test = require('tape'); -var redirects = require('../src/parse/page/redirects'); var parse_line = require('../src/parse/text/line'); var wtf = require('../src/'); var cleanup_misc = require('../src/parse/cleanup/misc'); -var parse_image = require('../src/parse/image'); var sentence_parser = require('../src/lib/sentence_parser'); var kill_xml = require('../src/parse/cleanup/kill_xml'); @@ -48,7 +46,7 @@ test('redirects', t => { ['#přesměruj [[Tony Danza#funfun]] ', 'Tony Danza'], ['#تغییر_مسیر [[Farming]] ', 'Farming'] ].forEach(a => { - let o = redirects.parse_redirect(a[0]); + let o = wtf.parse(a[0]); var msg = "'" + a[0] + "' -> '" + o.redirect + "'"; t.equal(o.redirect, a[1], msg); }); @@ -97,8 +95,8 @@ test('parse_image', t => { 'Image:Edouard Recon (2002).jpg' ] ].forEach(a => { - let o = parse_image(a[0]); - t.deepEqual(o, a[1]); + let arr = wtf.parse(a[0]).images.map(o => o.file); + t.deepEqual(arr[0], a[1]); }); t.end(); }); From 7757aef01bf5206101122ff58a5e75bf58d7d436 Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 12:07:59 -0400 Subject: [PATCH 16/26] no ending newline --- src/index.js | 7 +++---- tests/misc.test.js | 6 +++--- tests/unit.test.js | 7 +++---- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/index.js b/src/index.js index 8c3d836e..0e21c5ee 100644 --- a/src/index.js +++ b/src/index.js @@ -23,11 +23,10 @@ const from_api = function(page_identifier, lang_or_wikiid, cb) { const plaintext = function(str) { let data = parse(str) || {}; data.text = data.text || []; - let text = ''; - Object.keys(data.text).forEach(function(k) { - text += data.text[k].map(a => a.text).join(' ') + '\n'; + let arr = Object.keys(data.text).map(k => { + return data.text[k].map(a => a.text).join(' '); }); - return text; + return arr.join('\n'); }; module.exports = { diff --git a/tests/misc.test.js b/tests/misc.test.js index d89165a0..8c82eab5 100644 --- a/tests/misc.test.js +++ b/tests/misc.test.js @@ -23,12 +23,12 @@ here too test('font-size', t => { let str = 'hello {{small|(1995-1997)}} world'; - t.equal(wtf.plaintext(str), 'hello (1995-1997) world\n', '{{small}}'); + t.equal(wtf.plaintext(str), 'hello (1995-1997) world', '{{small}}'); str = 'hello {{huge|world}}'; - t.equal(wtf.plaintext(str), 'hello world\n', '{{huge}}'); + t.equal(wtf.plaintext(str), 'hello world', '{{huge}}'); str = `hello {{nowrap|{{small|(1995–present)}}}} world`; - t.equal(wtf.plaintext(str), 'hello (1995–present) world\n', '{{nowrap}}'); + t.equal(wtf.plaintext(str), 'hello (1995–present) world', '{{nowrap}}'); t.end(); }); diff --git a/tests/unit.test.js b/tests/unit.test.js index b1a41690..6609ea63 100644 --- a/tests/unit.test.js +++ b/tests/unit.test.js @@ -1,10 +1,9 @@ 'use strict'; var test = require('tape'); -var parse_line = require('../src/parse/text/line'); var wtf = require('../src/'); +var parse_line = require('../src/parse/text/line'); var cleanup_misc = require('../src/parse/cleanup/misc'); var sentence_parser = require('../src/lib/sentence_parser'); -var kill_xml = require('../src/parse/cleanup/kill_xml'); test('sentence parser', t => { [ @@ -110,10 +109,10 @@ test('xml', t => { ['hello nono! world1.', 'hello world1.'], ["hello nono! world2.", 'hello world2.'], ["hello world3.", 'hello world3.'], - ["hello
hinono!
world4.", 'hello world4.'], + ["hello
hinono!
world4.", 'hello world4.'], ["hello world5", 'hello world5'] ].forEach(a => { - let s = kill_xml(a[0]); + let s = wtf.plaintext(a[0]); t.equal(s, a[1]); }); t.end(); From f171a5dd29681dff9145eb6b2482987fab5f686f Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 13:24:23 -0400 Subject: [PATCH 17/26] move last cruft from main function --- src/parse/index.js | 24 ++----------------- .../{recursive_matches.js => find.js} | 8 +++---- src/parse/recursive/image.js | 3 +++ src/parse/recursive/index.js | 16 ++++++++++--- src/parse/table.js | 2 +- 5 files changed, 23 insertions(+), 30 deletions(-) rename src/parse/recursive/{recursive_matches.js => find.js} (76%) diff --git a/src/parse/index.js b/src/parse/index.js index 74264d83..36a0b4cb 100644 --- a/src/parse/index.js +++ b/src/parse/index.js @@ -1,23 +1,13 @@ -const i18n = require('../data/i18n'); -const make_image = require('../lib/make_image'); - -//parsing functions const redirects = require('./page/redirects'); const disambig = require('./page/disambig'); - const word_templates = require('./cleanup/word_templates'); const preprocess = require('./cleanup/misc'); - const parse_tables = require('./table'); const parse_categories = require('./categories'); const parse_recursion = require('./recursive'); const parse_text = require('./text'); -//regexs -const img_regex = new RegExp('^(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'); - -//some xml elements are just junk, and demand full inglorious death by regular exp -//other xml elements, like , are plucked out afterwards +//convert wikiscript markup lang to json const main = function(wiki) { wiki = wiki || ''; //detect if page is just redirect, and return @@ -28,7 +18,6 @@ const main = function(wiki) { if (disambig.is_disambig(wiki)) { return disambig.parse_disambig(wiki); } - let r = { type: 'page', text: {}, @@ -54,16 +43,7 @@ const main = function(wiki) { wiki = parse_categories(r, wiki); //parse all the headings, and their texts wiki = parse_text(r, wiki); - //add additional image from infobox, if applicable - if (r.infobox['image'] && r.infobox['image'].text) { - let img = r.infobox['image'].text || ''; - if (typeof img === 'string' && !img.match(img_regex)) { - img = 'File:' + img; - } - r.images.push(img); - } - //add url, etc to image - r.images = r.images.map(make_image); + return r; }; diff --git a/src/parse/recursive/recursive_matches.js b/src/parse/recursive/find.js similarity index 76% rename from src/parse/recursive/recursive_matches.js rename to src/parse/recursive/find.js index 636a29ae..ceb47f44 100644 --- a/src/parse/recursive/recursive_matches.js +++ b/src/parse/recursive/find.js @@ -1,7 +1,7 @@ //find all the pairs of '[[...[[..]]...]]' in the text //used to properly root out recursive template calls, [[.. [[...]] ]] //basically just adds open tags, and subtracts closing tags -function recursive_matches(opener, closer, text) { +function find_recursive(opener, closer, text) { var out = []; var last = []; var chars = text.split(''); @@ -40,7 +40,7 @@ function recursive_matches(opener, closer, text) { } return out; } -module.exports = recursive_matches; +module.exports = find_recursive; -// console.log(recursive_matches('{', '}', 'he is president. {{nowrap|{{small|(1995–present)}}}} he lives in texas')); -// console.log(recursive_matches("{", "}", "this is fun {{nowrap{{small1995–present}}}} and it works")) +// console.log(find_recursive('{', '}', 'he is president. {{nowrap|{{small|(1995–present)}}}} he lives in texas')); +// console.log(find_recursive("{", "}", "this is fun {{nowrap{{small1995–present}}}} and it works")) diff --git a/src/parse/recursive/image.js b/src/parse/recursive/image.js index 0f7581d7..441b9fc2 100644 --- a/src/parse/recursive/image.js +++ b/src/parse/recursive/image.js @@ -1,10 +1,13 @@ const i18n = require('../../data/i18n'); +const make_image = require('../../lib/make_image'); const file_reg = new RegExp('(' + i18n.images.concat(i18n.files).join('|') + '):.*?[\\|\\]]', 'i'); //images are usually [[image:my_pic.jpg]] const parse_image = function(img) { img = img.match(file_reg) || ['']; img = img[0].replace(/[\|\]]$/, ''); + //add url, etc to image + img = make_image(img); return img; }; module.exports = parse_image; diff --git a/src/parse/recursive/index.js b/src/parse/recursive/index.js index 061105f3..7d06e2c0 100644 --- a/src/parse/recursive/index.js +++ b/src/parse/recursive/index.js @@ -1,6 +1,6 @@ const i18n = require('../../data/i18n'); const languages = require('../../data/languages'); -const recursive_matches = require('./recursive_matches'); +const find_recursive = require('./find'); const parse_infobox = require('./infobox'); const parse_infobox_template = require('./infobox_template'); @@ -8,12 +8,13 @@ const parse_image = require('./image'); const infobox_reg = new RegExp('{{(' + i18n.infoboxes.join('|') + ')[: \n]', 'ig'); const fileRegex = new RegExp('\\[\\[(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'); +const img_regex = new RegExp('^(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'); const noWrap_reg = /^\{\{nowrap\|(.*?)\}\}$/; //reduce the scary recursive situations const parse_recursive = function(r, wiki) { //remove {{template {{}} }} recursions - let matches = recursive_matches('{', '}', wiki); + let matches = find_recursive('{', '}', wiki); matches.forEach(function(s) { if (s.match(infobox_reg, 'ig') && Object.keys(r.infobox).length === 0) { r.infobox = parse_infobox(s); @@ -37,7 +38,7 @@ const parse_recursive = function(r, wiki) { }); //second, remove [[file:...[[]] ]] recursions - matches = recursive_matches('[', ']', wiki); + matches = find_recursive('[', ']', wiki); matches.forEach(function(s) { if (s.match(fileRegex)) { r.images.push(parse_image(s)); @@ -56,6 +57,15 @@ const parse_recursive = function(r, wiki) { } }); + //add additional image from infobox, if applicable + if (r.infobox['image'] && r.infobox['image'].text) { + let img = r.infobox['image'].text || ''; + if (typeof img === 'string' && !img.match(img_regex)) { + img = 'File:' + img; + } + r.images.push(img); + } + return wiki; }; diff --git a/src/parse/table.js b/src/parse/table.js index ca29b292..6ae524b1 100644 --- a/src/parse/table.js +++ b/src/parse/table.js @@ -47,7 +47,7 @@ const findTables = function(r, wiki) { return parse_table(str); }); //remove tables - wiki = wiki.replace(/\{\|[\s\S]{1,8000}?\|\}/g, ''); + wiki = wiki.replace(table_reg, ''); return wiki; }; module.exports = findTables; From 90b95455acd10727da543ea08d85e95edff59032 Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 15:04:43 -0400 Subject: [PATCH 18/26] parse Sections --- scratch.js | 2 +- src/parse/text/index.js | 101 ++++++++++++++----------------------- src/parse/text/lists.js | 34 +++++++++++++ src/parse/text/sections.js | 40 +++++++++++++++ 4 files changed, 114 insertions(+), 63 deletions(-) create mode 100644 src/parse/text/lists.js create mode 100644 src/parse/text/sections.js diff --git a/scratch.js b/scratch.js index 82030888..3b905860 100644 --- a/scratch.js +++ b/scratch.js @@ -16,7 +16,7 @@ const wtf = require('./src/index'); function from_file(page) { let str = require('fs').readFileSync('./tests/cache/' + page.toLowerCase() + '.txt', 'utf-8'); // return wtf.plaintext(str) - console.log(wtf.parse(str, {})); + console.log(wtf.parse(str, {}).text); } // from_file("list") diff --git a/src/parse/text/index.js b/src/parse/text/index.js index bc3df369..5ed5099e 100644 --- a/src/parse/text/index.js +++ b/src/parse/text/index.js @@ -1,72 +1,49 @@ -const i18n = require('../../data/i18n'); -const sentence_parser = require('../../lib/sentence_parser'); -const helpers = require('../../lib/helpers'); -const parse_line = require('./line'); -const ban_headings = new RegExp('^ ?(' + i18n.sources.join('|') + ') ?$', 'i'); //remove things like 'external links' -const list_reg = /^[#\*:;\|]+/; +// const i18n = require('../../data/i18n'); +// const sentence_parser = require('../../lib/sentence_parser'); +// const helpers = require('../../lib/helpers'); +// const parse_line = require('./line'); +// const ban_headings = new RegExp('^ ?(' + i18n.sources.join('|') + ') ?$', 'i'); //remove things like 'external links' +const sections = require('./sections'); const parseText = function(r, wiki) { //next, map each line into a parsable sentence let lines = wiki.replace(/\r/g, '').split(/\n/); - let section = 'Intro'; - let number = 1; + r.text = sections(lines); - lines.forEach(function(part) { - if (!section) { - return; - } - //add # numberings formatting - if (part.match(/^ ?\#[^:,\|]{4}/i)) { - part = part.replace(/^ ?#*/, number + ') '); - part = part + '\n'; - number += 1; - } else { - number = 1; - } - //add bullet-points formatting - if (part.match(/^\*+[^:,\|]{4}/)) { - part = part + '\n'; - } - //remove some nonsense wp lines + // lines.forEach(function(part) { + // if (!section) { + // return; + // } + // //ignore lines with only-punctuation + // if (!part.match(/[a-z0-9]/i)) { + // return; + // } + // //headings + // if (part.match(heading_reg)) { + // section = part.match(/^={1,5}([^=]{1,200}?)={1,5}$/) || []; + // section = section[1] || ''; + // section = section.replace(/\./g, ' '); // this is necessary for mongo, i'm sorry + // section = helpers.trim_whitespace(section); + // //ban some sections + // if (section && section.match(ban_headings)) { + // section = undefined; + // } + // return; + // } - //parse lists - if (part.match(list_reg)) { - part = part.replace(list_reg, ''); - if (part.length < 10) { - //not a full sentence - return; - } - } + // //still alive, add it to the section + // let sentences = sentence_parser(part); + // sentences.forEach(function(line) { + // line = parse_line(line); - //ignore only-punctuation - if (!part.match(/[a-z0-9]/i)) { - return; - } - //headings - if (part.match(/^={1,5}[^=]{1,200}={1,5}$/)) { - section = part.match(/^={1,5}([^=]{1,200}?)={1,5}$/) || []; - section = section[1] || ''; - section = section.replace(/\./g, ' '); // this is necessary for mongo, i'm sorry - section = helpers.trim_whitespace(section); - //ban some sections - if (section && section.match(ban_headings)) { - section = undefined; - } - return; - } - - //still alive, add it to the section - sentence_parser(part).forEach(function(line) { - line = parse_line(line); - - if (line && line.text) { - if (!r.text[section]) { - r.text[section] = []; - } - r.text[section].push(line); - } - }); - }); + // if (line && line.text) { + // if (!r.text[section]) { + // r.text[section] = []; + // } + // r.text[section].push(line); + // } + // }); + // }); return wiki; }; diff --git a/src/parse/text/lists.js b/src/parse/text/lists.js new file mode 100644 index 00000000..b89bc54b --- /dev/null +++ b/src/parse/text/lists.js @@ -0,0 +1,34 @@ +const list_reg = /^[#\*:;\|]+/; +const bullet_reg = /^\*+[^:,\|]{4}/; +const number_reg = /^ ?\#[^:,\|]{4}/; + +//add implicit numberings to # formatting +const handleLists = function(lines) { + let number = 1; + lines.forEach(function(line) { + //add # numberings formatting + if (line.match(number_reg)) { + line = line.replace(/^ ?#*/, number + ') '); + line = line + '\n'; + number += 1; + return; + } else { + number = 1; + } + //support bullet-points formatting + if (line.match(bullet_reg)) { + line = line + '\n'; + } + //support lists + if (line.match(list_reg)) { + line = line.replace(list_reg, ''); + } + }); + return lines; +}; + +const parseLists = function(r, wiki) { + return wiki; +}; + +module.exports = parseLists; diff --git a/src/parse/text/sections.js b/src/parse/text/sections.js new file mode 100644 index 00000000..178725d3 --- /dev/null +++ b/src/parse/text/sections.js @@ -0,0 +1,40 @@ +const heading_reg = /^(={1,5})([^=]{1,200}?)={1,5}$/; + +//interpret ==heading== lines + +const isHeading = function(line) { + return heading_reg.test(line); +}; + +const parseHeading = function(line) { + let head = line.match(heading_reg) || []; + let depth = 1; + if (head[1]) { + depth = head[1].length; + } + return { + title: head[2] || '', + depth: depth, + sentences: [] + }; +}; + +const sections = function(lines) { + let arr = [parseHeading('')]; + for (var i = 0; i < lines.length; i++) { + let line = lines[i]; + //empty lines + if (!line) { + continue; + } + //handle new ==headings== + if (isHeading(line)) { + arr.push(parseHeading(line)); + continue; + } + arr[arr.length - 1].sentences.push(line); + } + return arr; +}; + +module.exports = sections; From 0f45d480cb1705a59c5429cec1636e4e729e4a86 Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 15:36:29 -0400 Subject: [PATCH 19/26] start parsing into lines --- scratch.js | 3 ++- src/parse/index.js | 8 ++++---- src/parse/{text => lines}/index.js | 3 ++- src/parse/{text => lines}/lists.js | 0 src/parse/{text => lines}/sections.js | 26 ++++++++++++-------------- 5 files changed, 20 insertions(+), 20 deletions(-) rename src/parse/{text => lines}/index.js (97%) rename src/parse/{text => lines}/lists.js (100%) rename src/parse/{text => lines}/sections.js (55%) diff --git a/scratch.js b/scratch.js index 3b905860..ac58cdc2 100644 --- a/scratch.js +++ b/scratch.js @@ -16,7 +16,8 @@ const wtf = require('./src/index'); function from_file(page) { let str = require('fs').readFileSync('./tests/cache/' + page.toLowerCase() + '.txt', 'utf-8'); // return wtf.plaintext(str) - console.log(wtf.parse(str, {}).text); + let r = wtf.parse(str, {}); + console.log(r.sections); } // from_file("list") diff --git a/src/parse/index.js b/src/parse/index.js index 36a0b4cb..7a688064 100644 --- a/src/parse/index.js +++ b/src/parse/index.js @@ -5,7 +5,7 @@ const preprocess = require('./cleanup/misc'); const parse_tables = require('./table'); const parse_categories = require('./categories'); const parse_recursion = require('./recursive'); -const parse_text = require('./text'); +const parse_lines = require('./lines'); //convert wikiscript markup lang to json const main = function(wiki) { @@ -20,7 +20,7 @@ const main = function(wiki) { } let r = { type: 'page', - text: {}, + sections: {}, categories: [], images: [], infobox: {}, @@ -41,8 +41,8 @@ const main = function(wiki) { wiki = wiki.replace(/\{\{.*?\}\}/g, ''); //get list of links, categories wiki = parse_categories(r, wiki); - //parse all the headings, and their texts - wiki = parse_text(r, wiki); + //parse all the headings, and their texts/sentences + wiki = parse_lines(r, wiki); return r; }; diff --git a/src/parse/text/index.js b/src/parse/lines/index.js similarity index 97% rename from src/parse/text/index.js rename to src/parse/lines/index.js index 5ed5099e..1cb30dac 100644 --- a/src/parse/text/index.js +++ b/src/parse/lines/index.js @@ -8,7 +8,8 @@ const sections = require('./sections'); const parseText = function(r, wiki) { //next, map each line into a parsable sentence let lines = wiki.replace(/\r/g, '').split(/\n/); - r.text = sections(lines); + + r.sections = sections(lines); // lines.forEach(function(part) { // if (!section) { diff --git a/src/parse/text/lists.js b/src/parse/lines/lists.js similarity index 100% rename from src/parse/text/lists.js rename to src/parse/lines/lists.js diff --git a/src/parse/text/sections.js b/src/parse/lines/sections.js similarity index 55% rename from src/parse/text/sections.js rename to src/parse/lines/sections.js index 178725d3..602fac13 100644 --- a/src/parse/text/sections.js +++ b/src/parse/lines/sections.js @@ -1,26 +1,23 @@ -const heading_reg = /^(={1,5})([^=]{1,200}?)={1,5}$/; - //interpret ==heading== lines +const fns = require('../../lib/helpers'); +const heading_reg = /^(={1,5})([^=]{1,200}?)={1,5}$/; -const isHeading = function(line) { - return heading_reg.test(line); -}; - -const parseHeading = function(line) { - let head = line.match(heading_reg) || []; +const parseHeading = function(head) { + let title = head[2] || ''; + title = fns.trim_whitespace(title); let depth = 1; if (head[1]) { depth = head[1].length; } return { - title: head[2] || '', + title: title, depth: depth, - sentences: [] + lines: [] }; }; const sections = function(lines) { - let arr = [parseHeading('')]; + let arr = [parseHeading([])]; for (var i = 0; i < lines.length; i++) { let line = lines[i]; //empty lines @@ -28,11 +25,12 @@ const sections = function(lines) { continue; } //handle new ==headings== - if (isHeading(line)) { - arr.push(parseHeading(line)); + let header = line.match(heading_reg); + if (header !== null) { + arr.push(parseHeading(header)); continue; } - arr[arr.length - 1].sentences.push(line); + arr[arr.length - 1].lines.push(line); } return arr; }; From e7c30c15b179cf338bfdc731b10f2387ad2294b3 Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 17:13:02 -0400 Subject: [PATCH 20/26] internal-links, external-links --- scratch.js | 12 ++++---- src/parse/lines/index.js | 39 ++--------------------- src/parse/lines/lists.js | 33 +++++++++----------- src/parse/lines/sections.js | 22 +++++++++++-- src/parse/lines/sentence.js | 12 ++++++++ src/parse/recursive/infobox.js | 2 +- src/parse/text/{line.js => index.js} | 0 src/parse/text/links.js | 46 ++++++++++++++++++++-------- 8 files changed, 90 insertions(+), 76 deletions(-) create mode 100644 src/parse/lines/sentence.js rename src/parse/text/{line.js => index.js} (100%) diff --git a/scratch.js b/scratch.js index ac58cdc2..5f35b4ca 100644 --- a/scratch.js +++ b/scratch.js @@ -17,14 +17,15 @@ function from_file(page) { let str = require('fs').readFileSync('./tests/cache/' + page.toLowerCase() + '.txt', 'utf-8'); // return wtf.plaintext(str) let r = wtf.parse(str, {}); - console.log(r.sections); + console.log(r.sections[5]); + // console.log(JSON.stringify(r.sections, null, 2)); } // from_file("list") // from_file("Toronto") // from_file('Toronto_Star'); // from_file('royal_cinema'); -from_file('Jodie_Emery'); +// from_file('Jodie_Emery'); // from_file("Redirect") // from_file("Africaans") // from_file('Anarchism'); @@ -34,7 +35,6 @@ from_file('Jodie_Emery'); // console.log(obj); // }); -// let str = `hello {{nowrap|{{small|(1995–present)}}}} world`; -// let str = `hello {{small|(1995–present)}} world`; -//and a fair amount of sunshine.{{sfn|Lawrence|Gondrand|2010|p=309}} Each year, however, there are a few days where the temperature rises above {{convert|32|C}}. Some years have even witnessed long periods of harsh summer weather, such as the [[2003 European heat wave|heat wave of 2003]] when temperatures exceeded {{convert|30|°C}} for weeks, surged up to {{convert|40|°C}} on some days and seldom cooled down at night.`; -// console.log(wtf.parse(str)); +let str = `he is [http://cool.com really nice] and [[fun|weird]] [[everyday]].`; +let doc = wtf.parse(str); +console.log(JSON.stringify(doc.sections, null, 2)); diff --git a/src/parse/lines/index.js b/src/parse/lines/index.js index 1cb30dac..8c14c59f 100644 --- a/src/parse/lines/index.js +++ b/src/parse/lines/index.js @@ -3,48 +3,15 @@ // const helpers = require('../../lib/helpers'); // const parse_line = require('./line'); // const ban_headings = new RegExp('^ ?(' + i18n.sources.join('|') + ') ?$', 'i'); //remove things like 'external links' -const sections = require('./sections'); +const parseSections = require('./sections'); +// const parseLists = require('./lists'); const parseText = function(r, wiki) { //next, map each line into a parsable sentence let lines = wiki.replace(/\r/g, '').split(/\n/); - r.sections = sections(lines); + r.sections = parseSections(lines); - // lines.forEach(function(part) { - // if (!section) { - // return; - // } - // //ignore lines with only-punctuation - // if (!part.match(/[a-z0-9]/i)) { - // return; - // } - // //headings - // if (part.match(heading_reg)) { - // section = part.match(/^={1,5}([^=]{1,200}?)={1,5}$/) || []; - // section = section[1] || ''; - // section = section.replace(/\./g, ' '); // this is necessary for mongo, i'm sorry - // section = helpers.trim_whitespace(section); - // //ban some sections - // if (section && section.match(ban_headings)) { - // section = undefined; - // } - // return; - // } - - // //still alive, add it to the section - // let sentences = sentence_parser(part); - // sentences.forEach(function(line) { - // line = parse_line(line); - - // if (line && line.text) { - // if (!r.text[section]) { - // r.text[section] = []; - // } - // r.text[section].push(line); - // } - // }); - // }); return wiki; }; diff --git a/src/parse/lines/lists.js b/src/parse/lines/lists.js index b89bc54b..dc2cb7d9 100644 --- a/src/parse/lines/lists.js +++ b/src/parse/lines/lists.js @@ -1,34 +1,31 @@ const list_reg = /^[#\*:;\|]+/; const bullet_reg = /^\*+[^:,\|]{4}/; const number_reg = /^ ?\#[^:,\|]{4}/; +const parseLine = require('../text'); -//add implicit numberings to # formatting -const handleLists = function(lines) { +const isList = function(line) { + return list_reg.test(line) || bullet_reg.test(line) || number_reg.test(line); +}; + +const cleanList = function(list) { let number = 1; - lines.forEach(function(line) { + for (var i = 0; i < list.length; i++) { + var line = list[i]; //add # numberings formatting if (line.match(number_reg)) { line = line.replace(/^ ?#*/, number + ') '); line = line + '\n'; number += 1; - return; - } else { + } else if (line.match(list_reg)) { number = 1; - } - //support bullet-points formatting - if (line.match(bullet_reg)) { - line = line + '\n'; - } - //support lists - if (line.match(list_reg)) { line = line.replace(list_reg, ''); } - }); - return lines; + list[i] = parseLine(line); + } + return list; }; -const parseLists = function(r, wiki) { - return wiki; +module.exports = { + isList: isList, + cleanList: cleanList }; - -module.exports = parseLists; diff --git a/src/parse/lines/sections.js b/src/parse/lines/sections.js index 602fac13..6c122154 100644 --- a/src/parse/lines/sections.js +++ b/src/parse/lines/sections.js @@ -1,5 +1,7 @@ //interpret ==heading== lines const fns = require('../../lib/helpers'); +const list = require('./lists'); +const parseSentences = require('./sentence'); const heading_reg = /^(={1,5})([^=]{1,200}?)={1,5}$/; const parseHeading = function(head) { @@ -12,13 +14,13 @@ const parseHeading = function(head) { return { title: title, depth: depth, - lines: [] + sentences: [] }; }; const sections = function(lines) { let arr = [parseHeading([])]; - for (var i = 0; i < lines.length; i++) { + for (let i = 0; i < lines.length; i++) { let line = lines[i]; //empty lines if (!line) { @@ -30,7 +32,21 @@ const sections = function(lines) { arr.push(parseHeading(header)); continue; } - arr[arr.length - 1].lines.push(line); + //list or sentence? + let section = arr[arr.length - 1]; + if (line && list.isList(line)) { + section.list = section.list || []; + section.list.push(line); + } else { + let sentenceArr = parseSentences(line); + section.sentences = section.sentences.concat(sentenceArr); + } + } + for (let i = 0; i < arr.length; i++) { + var section = arr[i]; + if (section.list) { + section.list = list.cleanList(section.list); + } } return arr; }; diff --git a/src/parse/lines/sentence.js b/src/parse/lines/sentence.js new file mode 100644 index 00000000..06d1468a --- /dev/null +++ b/src/parse/lines/sentence.js @@ -0,0 +1,12 @@ +const sentence_parser = require('../../lib/sentence_parser'); +const parseLine = require('../text'); + +const parseSentences = function(line) { + let arr = []; + let sentences = sentence_parser(line); + sentences.forEach(function(str) { + arr.push(parseLine(str)); + }); + return arr; +}; +module.exports = parseSentences; diff --git a/src/parse/recursive/infobox.js b/src/parse/recursive/infobox.js index 56114823..0515043c 100644 --- a/src/parse/recursive/infobox.js +++ b/src/parse/recursive/infobox.js @@ -1,6 +1,6 @@ 'use strict'; const helpers = require('../../lib/helpers'); -const parse_line = require('../text/line'); +const parse_line = require('../text'); const line_reg = /\n *\|([^=]*)=(.*)/g; diff --git a/src/parse/text/line.js b/src/parse/text/index.js similarity index 100% rename from src/parse/text/line.js rename to src/parse/text/index.js diff --git a/src/parse/text/links.js b/src/parse/text/links.js index e7b784f1..8503c416 100644 --- a/src/parse/text/links.js +++ b/src/parse/text/links.js @@ -1,12 +1,25 @@ const helpers = require('../../lib/helpers'); const link_reg = /\[\[(.{2,80}?)\]\](\w{0,10})/g; const ignore_links = /^:?(category|catégorie|Kategorie|Categoría|Categoria|Categorie|Kategoria|تصنيف|image|file|image|fichier|datei|media|special|wp|wikipedia|help|user|mediawiki|portal|talk|template|book|draft|module|topic|wiktionary|wikisource):/i; +const external_link = /\[(https?|news|ftp|mailto|gopher|irc):\/\/[^\]\| ]{4,1500}([\| ].*?)?\]/g; -//grab an array of internal links in the text -const parse_links = function(str) { - let links = []; - const all = str.match(link_reg) || []; //regular links - all.forEach(function(s) { +const external_links = function(links, str) { + str.replace(external_link, function(link, protocol, text) { + let m = link.match(/\[([^\| ]+)/); + if (m && m[1]) { + links.push({ + site: m[1], + text: text.replace(/^[\| ]/, '') + }); + } + return text; + }); + return links; +}; + +const internal_links = function(links, str) { + //regular links + str.replace(link_reg, function(_, s) { var link, txt; if (s.match(/\|/)) { //replacement link [[link|text]] @@ -24,23 +37,32 @@ const parse_links = function(str) { } //kill off non-wikipedia namespaces if (link.match(ignore_links)) { - return; + return s; } //kill off just anchor links [[#history]] if (link.match(/^#/i)) { - return; + return s; } //remove anchors from end [[toronto#history]] link = link.replace(/#[^ ]{1,100}/, ''); - link = helpers.capitalise(link); var obj = { - page: link, - src: txt + page: helpers.capitalise(link), + text: txt || link }; links.push(obj); + return s; }); - //remove duplicates - links = links.filter(helpers.onlyUnique); + return links; +}; + +//grab an array of internal links in the text +const parse_links = function(str) { + let links = []; + //first, parse external links + links = external_links(links, str); + //internal links + links = internal_links(links, str); + if (links.length === 0) { return undefined; } From 33d8497bf2b320308cae9a40c8bbc741017b732a Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 18:34:33 -0400 Subject: [PATCH 21/26] some tests passing --- scratch.js | 12 ++++---- src/index.js | 7 ++--- src/parse/lines/index.js | 59 ++++++++++++++++++++++++++++++++----- src/parse/lines/sections.js | 54 --------------------------------- src/parse/text/links.js | 1 + tests/misc.test.js | 11 +++---- tests/page.test.js | 19 ++++++++---- 7 files changed, 82 insertions(+), 81 deletions(-) delete mode 100644 src/parse/lines/sections.js diff --git a/scratch.js b/scratch.js index 5f35b4ca..420d1dce 100644 --- a/scratch.js +++ b/scratch.js @@ -15,15 +15,15 @@ const wtf = require('./src/index'); function from_file(page) { let str = require('fs').readFileSync('./tests/cache/' + page.toLowerCase() + '.txt', 'utf-8'); - // return wtf.plaintext(str) + // console.log(wtf.plaintext(str)); let r = wtf.parse(str, {}); - console.log(r.sections[5]); + console.log(r.sections); // console.log(JSON.stringify(r.sections, null, 2)); } // from_file("list") // from_file("Toronto") -// from_file('Toronto_Star'); +from_file('Toronto_Star'); // from_file('royal_cinema'); // from_file('Jodie_Emery'); // from_file("Redirect") @@ -35,6 +35,6 @@ function from_file(page) { // console.log(obj); // }); -let str = `he is [http://cool.com really nice] and [[fun|weird]] [[everyday]].`; -let doc = wtf.parse(str); -console.log(JSON.stringify(doc.sections, null, 2)); +// let str = `he is [http://cool.com really nice] and [[fun|weird]] [[everyday]].`; +// let doc = wtf.parse(str); +// console.log(JSON.stringify(doc.sections, null, 2)); diff --git a/src/index.js b/src/index.js index 0e21c5ee..131bacb9 100644 --- a/src/index.js +++ b/src/index.js @@ -22,11 +22,10 @@ const from_api = function(page_identifier, lang_or_wikiid, cb) { //turn wiki-markup into a nicely-formatted text const plaintext = function(str) { let data = parse(str) || {}; - data.text = data.text || []; - let arr = Object.keys(data.text).map(k => { - return data.text[k].map(a => a.text).join(' '); + let arr = Object.keys(data.sections).map(k => { + return data.sections[k].sentences.map(a => a.text).join(' '); }); - return arr.join('\n'); + return arr.join('\n\n'); }; module.exports = { diff --git a/src/parse/lines/index.js b/src/parse/lines/index.js index 8c14c59f..5b382165 100644 --- a/src/parse/lines/index.js +++ b/src/parse/lines/index.js @@ -1,10 +1,55 @@ -// const i18n = require('../../data/i18n'); -// const sentence_parser = require('../../lib/sentence_parser'); -// const helpers = require('../../lib/helpers'); -// const parse_line = require('./line'); -// const ban_headings = new RegExp('^ ?(' + i18n.sources.join('|') + ') ?$', 'i'); //remove things like 'external links' -const parseSections = require('./sections'); -// const parseLists = require('./lists'); +//interpret ==heading== lines +const fns = require('../../lib/helpers'); +const list = require('./lists'); +const parseSentences = require('./sentence'); +const heading_reg = /^(={1,5})([^=]{1,200}?)={1,5}$/; + +const parseHeading = function(head) { + let title = head[2] || ''; + title = fns.trim_whitespace(title); + let depth = 1; + if (head[1]) { + depth = head[1].length; + } + return { + title: title, + depth: depth, + sentences: [] + }; +}; + +const parseSections = function(lines) { + let arr = [parseHeading([])]; + for (let i = 0; i < lines.length; i++) { + let line = lines[i]; + //empty lines + if (!line) { + continue; + } + //handle new ==headings== + let header = line.match(heading_reg); + if (header !== null) { + arr.push(parseHeading(header)); + continue; + } + //list or sentence? + let section = arr[arr.length - 1]; + if (line && list.isList(line)) { + section.list = section.list || []; + section.list.push(line); + } else { + let sentenceArr = parseSentences(line); + section.sentences = section.sentences.concat(sentenceArr); + } + } + for (let i = 0; i < arr.length; i++) { + var section = arr[i]; + if (section.list) { + section.list = list.cleanList(section.list); + } + } + return arr; +}; const parseText = function(r, wiki) { //next, map each line into a parsable sentence diff --git a/src/parse/lines/sections.js b/src/parse/lines/sections.js deleted file mode 100644 index 6c122154..00000000 --- a/src/parse/lines/sections.js +++ /dev/null @@ -1,54 +0,0 @@ -//interpret ==heading== lines -const fns = require('../../lib/helpers'); -const list = require('./lists'); -const parseSentences = require('./sentence'); -const heading_reg = /^(={1,5})([^=]{1,200}?)={1,5}$/; - -const parseHeading = function(head) { - let title = head[2] || ''; - title = fns.trim_whitespace(title); - let depth = 1; - if (head[1]) { - depth = head[1].length; - } - return { - title: title, - depth: depth, - sentences: [] - }; -}; - -const sections = function(lines) { - let arr = [parseHeading([])]; - for (let i = 0; i < lines.length; i++) { - let line = lines[i]; - //empty lines - if (!line) { - continue; - } - //handle new ==headings== - let header = line.match(heading_reg); - if (header !== null) { - arr.push(parseHeading(header)); - continue; - } - //list or sentence? - let section = arr[arr.length - 1]; - if (line && list.isList(line)) { - section.list = section.list || []; - section.list.push(line); - } else { - let sentenceArr = parseSentences(line); - section.sentences = section.sentences.concat(sentenceArr); - } - } - for (let i = 0; i < arr.length; i++) { - var section = arr[i]; - if (section.list) { - section.list = list.cleanList(section.list); - } - } - return arr; -}; - -module.exports = sections; diff --git a/src/parse/text/links.js b/src/parse/text/links.js index 8503c416..954b52d8 100644 --- a/src/parse/text/links.js +++ b/src/parse/text/links.js @@ -8,6 +8,7 @@ const external_links = function(links, str) { let m = link.match(/\[([^\| ]+)/); if (m && m[1]) { links.push({ + type: 'external', site: m[1], text: text.replace(/^[\| ]/, '') }); diff --git a/tests/misc.test.js b/tests/misc.test.js index 8c82eab5..4553e115 100644 --- a/tests/misc.test.js +++ b/tests/misc.test.js @@ -4,6 +4,7 @@ const wtf = require('../src/index'); test('small headings', t => { let str = ` +hello ===gdbserver=== hi there @@ -13,11 +14,11 @@ Displays memory at the specified virtual address using the specified format. ===xp=== here too `; - let text = wtf.parse(str).text; - t.ok(text['gdbserver'], 'first heading exists'); - t.ok(text['x'], 'x exists'); - t.ok(text['xp'], 'xp exists'); - t.equal(text['foo'], undefined, 'foo doesnt exist'); + let sections = wtf.parse(str).sections; + t.equal(sections[1].title, 'gdbserver', 'first heading exists'); + t.equal(sections[2].title, 'x', 'x exists'); + t.ok(sections[3].title, 'xp', 'xp exists'); + t.equal(sections[4], undefined, 'foo doesnt exist'); t.end(); }); diff --git a/tests/page.test.js b/tests/page.test.js index c8bb6d64..37ba3dd7 100644 --- a/tests/page.test.js +++ b/tests/page.test.js @@ -15,12 +15,18 @@ var fetch = function(file) { return fs.readFileSync(path.join(__dirname, 'cache', file + '.txt'), 'utf-8'); }; +var findSection = function(data, title) { + return data.sections.find(function(s) { + return s.title === title; + }); +}; + test('royal_cinema', t => { var data = wtf_wikipedia.parse(fetch('royal_cinema')); str_equal(data.infobox.opened.text, 1939, t); str_equal(data.infobox_template, 'venue', t); // str_equal(data.text.Intro.length, 10, t); - str_equal(data.text['Intro'].length, 10, t); + str_equal(data.sections[0].sentences.length, 10, t); str_equal(data.categories.length, 4, t); t.end(); }); @@ -30,7 +36,8 @@ test('toronto_star', t => { str_equal(data.infobox.publisher.text, 'John D. Cruickshank', t); str_equal(data.infobox_template, 'newspaper', t); // str_equal(data.text.History.length, 21, t); - str_equal(data.text['History'].length, 21, t); + var section = findSection(data, 'History'); + str_equal(section.sentences.length, 21, t); str_equal(data.categories.length, 6, t); // str_equal(data.text['Notable cartoonists'], undefined, t); t.end(); @@ -40,9 +47,11 @@ test('toronto_star with list', t => { var data = wtf_wikipedia.parse(fetch('toronto_star'), { ignoreLists: false }); str_equal(data.infobox.publisher.text, 'John D. Cruickshank', t); str_equal(data.infobox_template, 'newspaper', t); - str_equal(data.text['History'].length, 21, t); - str_equal(data.categories.length, 6, t); - str_equal(data.text['Notable cartoonists'].length, 10, t); + var section = findSection(data, 'History'); + t.equal(section.sentences.length, 21, 'history-length'); + t.equal(data.categories.length, 6, 'cat-length'); + section = findSection(data, 'Notable cartoonists'); + t.equal(section.list.length, 10, 'cartoonist-length'); t.end(); }); From cbb6ace8de739c718e3610d6712d11c3e9a22c38 Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 18:49:59 -0400 Subject: [PATCH 22/26] tests passing --- scratch.js | 8 ++++---- src/parse/text/links.js | 16 +++++++++------- tests/template.test.js | 2 +- tests/unit.test.js | 8 ++++---- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/scratch.js b/scratch.js index 420d1dce..40e20e5e 100644 --- a/scratch.js +++ b/scratch.js @@ -23,7 +23,7 @@ function from_file(page) { // from_file("list") // from_file("Toronto") -from_file('Toronto_Star'); +// from_file('Toronto_Star'); // from_file('royal_cinema'); // from_file('Jodie_Emery'); // from_file("Redirect") @@ -35,6 +35,6 @@ from_file('Toronto_Star'); // console.log(obj); // }); -// let str = `he is [http://cool.com really nice] and [[fun|weird]] [[everyday]].`; -// let doc = wtf.parse(str); -// console.log(JSON.stringify(doc.sections, null, 2)); +let str = `tony hawk [http://www.whistler.ca]`; +let doc = wtf.parse(str); +console.log(JSON.stringify(doc.sections, null, 2)); diff --git a/src/parse/text/links.js b/src/parse/text/links.js index 954b52d8..8700d5bc 100644 --- a/src/parse/text/links.js +++ b/src/parse/text/links.js @@ -1,18 +1,20 @@ const helpers = require('../../lib/helpers'); const link_reg = /\[\[(.{2,80}?)\]\](\w{0,10})/g; const ignore_links = /^:?(category|catégorie|Kategorie|Categoría|Categoria|Categorie|Kategoria|تصنيف|image|file|image|fichier|datei|media|special|wp|wikipedia|help|user|mediawiki|portal|talk|template|book|draft|module|topic|wiktionary|wikisource):/i; -const external_link = /\[(https?|news|ftp|mailto|gopher|irc):\/\/[^\]\| ]{4,1500}([\| ].*?)?\]/g; +const external_link = /\[(https?|news|ftp|mailto|gopher|irc)(:\/\/[^\]\| ]{4,1500})([\| ].*?)?\]/g; const external_links = function(links, str) { - str.replace(external_link, function(link, protocol, text) { + str.replace(external_link, function(all, protocol, link) { + let text = ''; let m = link.match(/\[([^\| ]+)/); if (m && m[1]) { - links.push({ - type: 'external', - site: m[1], - text: text.replace(/^[\| ]/, '') - }); + text = m[1]; } + links.push({ + type: 'external', + site: protocol + link, + text: text + }); return text; }); return links; diff --git a/tests/template.test.js b/tests/template.test.js index ceec8e58..8c276fb7 100644 --- a/tests/template.test.js +++ b/tests/template.test.js @@ -38,7 +38,7 @@ test('boloZenden infobox', function(t) { t.equal(o.nationalyears1.text, '1997–2004'); t.equal(o.nationalteam1.text, 'Netherlands'); t.equal(o.nationalteam1.links[0].page, 'Netherlands national football team'); - t.equal(o.nationalteam1.links[0].src, 'Netherlands'); + t.equal(o.nationalteam1.links[0].text, 'Netherlands'); t.equal(o.nationalcaps1.text, 54); t.equal(o.nationalgoals1.text, 7); t.end(); diff --git a/tests/unit.test.js b/tests/unit.test.js index 6609ea63..a980572b 100644 --- a/tests/unit.test.js +++ b/tests/unit.test.js @@ -1,7 +1,7 @@ 'use strict'; var test = require('tape'); var wtf = require('../src/'); -var parse_line = require('../src/parse/text/line'); +var parse_line = require('../src/parse/text'); var cleanup_misc = require('../src/parse/cleanup/misc'); var sentence_parser = require('../src/lib/sentence_parser'); @@ -63,9 +63,9 @@ test('parse_line_text', t => { ['tony hawk in [http://www.whistler.ca whistler]', 'tony hawk in whistler'], ['it is [[Tony Hawk|Tony]]s mother in [[Toronto]]s', 'it is Tonys mother in Torontos'] ].forEach(a => { - let o = parse_line(a[0]); - var msg = "'" + a[0] + "' -> '" + o.text + "'"; - t.equal(o.text, a[1], msg); + let text = wtf.plaintext(a[0]); + var msg = "'" + a[0] + "' -> '" + text + "'"; + t.equal(text, a[1], msg); }); t.end(); }); From 62211c7e1743db4df223db780e2ea53be25f47ac Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 19:07:34 -0400 Subject: [PATCH 23/26] alpha 1.0 builds --- README.md | 176 +- builds/wtf_wikipedia.js | 11478 ++++++++++++++++++---------------- builds/wtf_wikipedia.min.js | 10 +- package.json | 4 +- 4 files changed, 6089 insertions(+), 5579 deletions(-) diff --git a/README.md b/README.md index 5e7d27e8..ffff5bee 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ then: var wtf_wikipedia = require("wtf_wikipedia") wtf_wikipedia.parse(someWikiScript) -// {text:[...], infobox:{}, categories:[...], images:[] } +// {sections:[...], infobox:{}, categories:[...], images:[] } //fetch wikipedia markup from api.. wtf_wikipedia.from_api("Toronto", "en", function(markup){ @@ -101,122 +101,94 @@ $ wikipedia Toronto Blue Jays Sample output for [Royal Cinema](https://en.wikipedia.org/wiki/Royal_Cinema) ````javascript { - "text": { - "Intro": [ - { - "text": "The Royal Cinema is an Art Moderne event venue and cinema in Toronto, Canada.", - "links": [ - { - "page": "Art Moderne" - }, - { - "page": "Movie theater", - "src": "cinema" - }, - { - "page": "Toronto" - } - ] - }, - ... - { - "text": "The Royal was featured in the 2013 film The F Word.", - "links": [ - { - "page": "The F Word (2013 film)", - "src": "The F Word" - } - ] - } - ] - }, - "categories": [ - "National Historic Sites in Ontario", - "Cinemas and movie theatres in Toronto", - "Streamline Moderne architecture in Canada", - "Theatres completed in 1939" + type: 'page', + sections: [ + { + title: '',//(intro) + depth: 1, + sentences: [ + { + text: 'The Royal Cinema is an Art Moderne event venue and cinema in Toronto, Canada.', + links: [ + { + page: 'Streamline Moderne', // (a href) + text: 'Art Moderne' // (link text) + }, + { + page: 'Toronto', + text: 'Toronto' + }, + { + page: 'Canada', + text: 'Canada' + } + ] + }, + { + text: 'It was built in 1939 and owned by Miss Ray Levinsky.' + } + ] + }, + { + title: 'History', + depth: 1, + sentences: [ + { + text: + 'When it was built in 1939, it was called The Pylon, with an accompanying large sign at the front of the theatre.' + } + ] + } ], - "images": [ - "Royal_Cinema.JPG" + categories: [ + 'National Historic Sites in Ontario', + 'Cinemas and movie theatres in Toronto', + 'Streamline Moderne architecture in Canada', + 'Theatres completed in 1939' ], - "infobox": { - "former_name": { - "text": "The Pylon, The Golden Princess" + images: ['Royal_Cinema.JPG'], + infobox: { + former_name: { + text: 'The Pylon, The Golden Princess' }, - "address": { - "text": "608 College Street", - "links": [ + address: { + text: '608 College Street', + links: [ { - "page": "College Street (Toronto)", - "src": "College Street" + page: 'College Street (Toronto)', + src: 'College Street' } ] }, - "opened": { - "text": 1939 - }, - ... + opened: { + text: 1939 + } + // ... } -} +}; ```` -Sample Output for [Whistling]() +Sample Output for [Whistling](https://en.wikipedia.org/w/index.php?title=Whistling) ````javascript { type: 'page', - text: - { 'Intro': [ [Object], [Object], [Object], [Object] ], - 'Musical/melodic whistling': - [ [Object], - [Object], - [Object], - [Object], - [Object], - [Object], - [Object], - [Object], - [Object], - [Object], - [Object], - [Object], - [Object] ], - 'Functional whistling': [ [Object], [Object], [Object], [Object], [Object], [Object] ], - 'Whistling as a form of communication': - [ [Object], - [Object], - [Object], - [Object], - [Object], - [Object], - [Object], - [Object], - [Object], - [Object], - [Object], - [Object], - [Object] ], - 'Sport': [ [Object], [Object], [Object], [Object], [Object] ], - 'Superstition': - [ [Object], - [Object], - [Object], - [Object], - [Object], - [Object], - [Object], - [Object], - [Object], - [Object], - [Object] ], - ' Whistling competitions': [ [Object], [Object], [Object], [Object] ] - }, - 'categories': [ 'Oral communication', 'Vocal music', 'Vocal skills' ], - 'images': [ 'Image:Duveneck Whistling Boy.jpg' ], - 'infobox': {} } + sections:[ + { title:'Intro', depth:1, sentences: [ [Object], [Object], [Object], [Object] ]}, + { title:'Musical/melodic whistling', depth:1, sentences: [ [Object], [Object], [Object], [Object] ]}, + { title:'Functional whistling', depth:1, sentences: [ [Object], [Object], [Object], [Object] ]}, + { title:'Whistling as a form of communication', depth:2, sentences: [ [Object], [Object], [Object], [Object] ]}, + { title:'Sport', depth:2, sentences: [ [Object], [Object], [Object], [Object] ]}, + { title:'See Also', depth:1, list: [ [Object], [Object] ]}, + ], + categories: [ 'Oral communication', 'Vocal music', 'Vocal skills' ], + images: [ 'Image:Duveneck Whistling Boy.jpg' ], + infobox: {} +} ```` ## Contributing -Never-ender projects like these need all-hands, and I'm a pretty friendly dude. -``` +Never-ender projects like these need all-hands, and I'm a pretty friendly maintainer. (promise) + +```bash npm install npm test npm run build #to package-up client-side diff --git a/builds/wtf_wikipedia.js b/builds/wtf_wikipedia.js index f39f6308..60af84df 100644 --- a/builds/wtf_wikipedia.js +++ b/builds/wtf_wikipedia.js @@ -1,4 +1,4 @@ -/* wtf_wikipedia v0.8.7 +/* wtf_wikipedia v1.0.0 github.com/spencermountain/wtf_wikipedia MIT */ @@ -168,5540 +168,5789 @@ Emitter.prototype.hasListeners = function(event){ }; },{}],2:[function(_dereq_,module,exports){ +(function (global){ /** - * Root reference for iframes. + * jshashes - https://github.com/h2non/jshashes + * Released under the "New BSD" license + * + * Algorithms specification: + * + * MD5 - http://www.ietf.org/rfc/rfc1321.txt + * RIPEMD-160 - http://homes.esat.kuleuven.be/~bosselae/ripemd160.html + * SHA1 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf + * SHA256 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf + * SHA512 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf + * HMAC - http://www.ietf.org/rfc/rfc2104.txt */ +(function() { + var Hashes; -var root; -if (typeof window !== 'undefined') { // Browser window - root = window; -} else if (typeof self !== 'undefined') { // Web Worker - root = self; -} else { // Other environments - console.warn("Using browser-only version of superagent in non-browser environment"); - root = this; -} - -var Emitter = _dereq_('emitter'); -var requestBase = _dereq_('./request-base'); -var isObject = _dereq_('./is-object'); + function utf8Encode(str) { + var x, y, output = '', + i = -1, + l; -/** - * Noop. - */ + if (str && str.length) { + l = str.length; + while ((i += 1) < l) { + /* Decode utf-16 surrogate pairs */ + x = str.charCodeAt(i); + y = i + 1 < l ? str.charCodeAt(i + 1) : 0; + if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) { + x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF); + i += 1; + } + /* Encode output as utf-8 */ + if (x <= 0x7F) { + output += String.fromCharCode(x); + } else if (x <= 0x7FF) { + output += String.fromCharCode(0xC0 | ((x >>> 6) & 0x1F), + 0x80 | (x & 0x3F)); + } else if (x <= 0xFFFF) { + output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F), + 0x80 | ((x >>> 6) & 0x3F), + 0x80 | (x & 0x3F)); + } else if (x <= 0x1FFFFF) { + output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07), + 0x80 | ((x >>> 12) & 0x3F), + 0x80 | ((x >>> 6) & 0x3F), + 0x80 | (x & 0x3F)); + } + } + } + return output; + } -function noop(){}; + function utf8Decode(str) { + var i, ac, c1, c2, c3, arr = [], + l; + i = ac = c1 = c2 = c3 = 0; -/** - * Expose `request`. - */ + if (str && str.length) { + l = str.length; + str += ''; -var request = module.exports = _dereq_('./request').bind(null, Request); + while (i < l) { + c1 = str.charCodeAt(i); + ac += 1; + if (c1 < 128) { + arr[ac] = String.fromCharCode(c1); + i += 1; + } else if (c1 > 191 && c1 < 224) { + c2 = str.charCodeAt(i + 1); + arr[ac] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63)); + i += 2; + } else { + c2 = str.charCodeAt(i + 1); + c3 = str.charCodeAt(i + 2); + arr[ac] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); + i += 3; + } + } + } + return arr.join(''); + } -/** - * Determine XHR. - */ + /** + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ -request.getXHR = function () { - if (root.XMLHttpRequest - && (!root.location || 'file:' != root.location.protocol - || !root.ActiveXObject)) { - return new XMLHttpRequest; - } else { - try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {} - try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {} - try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {} - try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {} + function safe_add(x, y) { + var lsw = (x & 0xFFFF) + (y & 0xFFFF), + msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); } - throw Error("Browser-only verison of superagent could not find XHR"); -}; -/** - * Removes leading and trailing whitespace, added to support IE. - * - * @param {String} s - * @return {String} - * @api private - */ + /** + * Bitwise rotate a 32-bit number to the left. + */ -var trim = ''.trim - ? function(s) { return s.trim(); } - : function(s) { return s.replace(/(^\s*|\s*$)/g, ''); }; + function bit_rol(num, cnt) { + return (num << cnt) | (num >>> (32 - cnt)); + } -/** - * Serialize the given `obj`. - * - * @param {Object} obj - * @return {String} - * @api private - */ + /** + * Convert a raw string to a hex string + */ -function serialize(obj) { - if (!isObject(obj)) return obj; - var pairs = []; - for (var key in obj) { - pushEncodedKeyValuePair(pairs, key, obj[key]); + function rstr2hex(input, hexcase) { + var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef', + output = '', + x, i = 0, + l = input.length; + for (; i < l; i += 1) { + x = input.charCodeAt(i); + output += hex_tab.charAt((x >>> 4) & 0x0F) + hex_tab.charAt(x & 0x0F); + } + return output; } - return pairs.join('&'); -} -/** - * Helps 'serialize' with serializing arrays. - * Mutates the pairs array. - * - * @param {Array} pairs - * @param {String} key - * @param {Mixed} val - */ + /** + * Encode a string as utf-16 + */ -function pushEncodedKeyValuePair(pairs, key, val) { - if (val != null) { - if (Array.isArray(val)) { - val.forEach(function(v) { - pushEncodedKeyValuePair(pairs, key, v); - }); - } else if (isObject(val)) { - for(var subkey in val) { - pushEncodedKeyValuePair(pairs, key + '[' + subkey + ']', val[subkey]); - } - } else { - pairs.push(encodeURIComponent(key) - + '=' + encodeURIComponent(val)); + function str2rstr_utf16le(input) { + var i, l = input.length, + output = ''; + for (i = 0; i < l; i += 1) { + output += String.fromCharCode(input.charCodeAt(i) & 0xFF, (input.charCodeAt(i) >>> 8) & 0xFF); } - } else if (val === null) { - pairs.push(encodeURIComponent(key)); + return output; } -} -/** - * Expose serialization method. - */ + function str2rstr_utf16be(input) { + var i, l = input.length, + output = ''; + for (i = 0; i < l; i += 1) { + output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF, input.charCodeAt(i) & 0xFF); + } + return output; + } - request.serializeObject = serialize; + /** + * Convert an array of big-endian words to a string + */ - /** - * Parse the given x-www-form-urlencoded `str`. - * - * @param {String} str - * @return {Object} - * @api private - */ + function binb2rstr(input) { + var i, l = input.length * 32, + output = ''; + for (i = 0; i < l; i += 8) { + output += String.fromCharCode((input[i >> 5] >>> (24 - i % 32)) & 0xFF); + } + return output; + } -function parseString(str) { - var obj = {}; - var pairs = str.split('&'); - var pair; - var pos; + /** + * Convert an array of little-endian words to a string + */ - for (var i = 0, len = pairs.length; i < len; ++i) { - pair = pairs[i]; - pos = pair.indexOf('='); - if (pos == -1) { - obj[decodeURIComponent(pair)] = ''; - } else { - obj[decodeURIComponent(pair.slice(0, pos))] = - decodeURIComponent(pair.slice(pos + 1)); + function binl2rstr(input) { + var i, l = input.length * 32, + output = ''; + for (i = 0; i < l; i += 8) { + output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF); } + return output; } - return obj; -} + /** + * Convert a raw string to an array of little-endian words + * Characters >255 have their high-byte silently ignored. + */ -/** - * Expose parser. - */ + function rstr2binl(input) { + var i, l = input.length * 8, + output = Array(input.length >> 2), + lo = output.length; + for (i = 0; i < lo; i += 1) { + output[i] = 0; + } + for (i = 0; i < l; i += 8) { + output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32); + } + return output; + } -request.parseString = parseString; + /** + * Convert a raw string to an array of big-endian words + * Characters >255 have their high-byte silently ignored. + */ -/** - * Default MIME type map. - * - * superagent.types.xml = 'application/xml'; - * - */ + function rstr2binb(input) { + var i, l = input.length * 8, + output = Array(input.length >> 2), + lo = output.length; + for (i = 0; i < lo; i += 1) { + output[i] = 0; + } + for (i = 0; i < l; i += 8) { + output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32); + } + return output; + } -request.types = { - html: 'text/html', - json: 'application/json', - xml: 'application/xml', - urlencoded: 'application/x-www-form-urlencoded', - 'form': 'application/x-www-form-urlencoded', - 'form-data': 'application/x-www-form-urlencoded' -}; + /** + * Convert a raw string to an arbitrary string encoding + */ -/** - * Default serialization map. - * - * superagent.serialize['application/xml'] = function(obj){ - * return 'generated xml here'; - * }; - * - */ - - request.serialize = { - 'application/x-www-form-urlencoded': serialize, - 'application/json': JSON.stringify - }; + function rstr2any(input, encoding) { + var divisor = encoding.length, + remainders = Array(), + i, q, x, ld, quotient, dividend, output, full_length; - /** - * Default parsers. - * - * superagent.parse['application/xml'] = function(str){ - * return { object parsed from str }; - * }; - * - */ + /* Convert to an array of 16-bit big-endian values, forming the dividend */ + dividend = Array(Math.ceil(input.length / 2)); + ld = dividend.length; + for (i = 0; i < ld; i += 1) { + dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1); + } -request.parse = { - 'application/x-www-form-urlencoded': parseString, - 'application/json': JSON.parse -}; + /** + * Repeatedly perform a long division. The binary array forms the dividend, + * the length of the encoding is the divisor. Once computed, the quotient + * forms the dividend for the next step. We stop when the dividend is zerHashes. + * All remainders are stored for later use. + */ + while (dividend.length > 0) { + quotient = Array(); + x = 0; + for (i = 0; i < dividend.length; i += 1) { + x = (x << 16) + dividend[i]; + q = Math.floor(x / divisor); + x -= q * divisor; + if (quotient.length > 0 || q > 0) { + quotient[quotient.length] = q; + } + } + remainders[remainders.length] = x; + dividend = quotient; + } -/** - * Parse the given header `str` into - * an object containing the mapped fields. - * - * @param {String} str - * @return {Object} - * @api private - */ + /* Convert the remainders to the output string */ + output = ''; + for (i = remainders.length - 1; i >= 0; i--) { + output += encoding.charAt(remainders[i]); + } -function parseHeader(str) { - var lines = str.split(/\r?\n/); - var fields = {}; - var index; - var line; - var field; - var val; + /* Append leading zero equivalents */ + full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2))); + for (i = output.length; i < full_length; i += 1) { + output = encoding[0] + output; + } + return output; + } - lines.pop(); // trailing CRLF + /** + * Convert a raw string to a base-64 string + */ - for (var i = 0, len = lines.length; i < len; ++i) { - line = lines[i]; - index = line.indexOf(':'); - field = line.slice(0, index).toLowerCase(); - val = trim(line.slice(index + 1)); - fields[field] = val; + function rstr2b64(input, b64pad) { + var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', + output = '', + len = input.length, + i, j, triplet; + b64pad = b64pad || '='; + for (i = 0; i < len; i += 3) { + triplet = (input.charCodeAt(i) << 16) | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0); + for (j = 0; j < 4; j += 1) { + if (i * 8 + j * 6 > input.length * 8) { + output += b64pad; + } else { + output += tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F); + } + } + } + return output; } - return fields; -} + Hashes = { + /** + * @property {String} version + * @readonly + */ + VERSION: '1.0.6', + /** + * @member Hashes + * @class Base64 + * @constructor + */ + Base64: function() { + // private properties + var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', + pad = '=', // default pad according with the RFC standard + url = false, // URL encoding support @todo + utf8 = true; // by default enable UTF-8 support encoding -/** - * Check if `mime` is json or has +json structured syntax suffix. - * - * @param {String} mime - * @return {Boolean} - * @api private - */ + // public method for encoding + this.encode = function(input) { + var i, j, triplet, + output = '', + len = input.length; -function isJSON(mime) { - return /[\/+]json\b/.test(mime); -} + pad = pad || '='; + input = (utf8) ? utf8Encode(input) : input; -/** - * Return the mime type for the given `str`. - * - * @param {String} str - * @return {String} - * @api private - */ + for (i = 0; i < len; i += 3) { + triplet = (input.charCodeAt(i) << 16) | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0); + for (j = 0; j < 4; j += 1) { + if (i * 8 + j * 6 > len * 8) { + output += pad; + } else { + output += tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F); + } + } + } + return output; + }; -function type(str){ - return str.split(/ *; */).shift(); -}; + // public method for decoding + this.decode = function(input) { + // var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + var i, o1, o2, o3, h1, h2, h3, h4, bits, ac, + dec = '', + arr = []; + if (!input) { + return input; + } -/** - * Return header field parameters. - * - * @param {String} str - * @return {Object} - * @api private - */ + i = ac = 0; + input = input.replace(new RegExp('\\' + pad, 'gi'), ''); // use '=' + //input += ''; -function params(str){ - return str.split(/ *; */).reduce(function(obj, str){ - var parts = str.split(/ *= */), - key = parts.shift(), - val = parts.shift(); + do { // unpack four hexets into three octets using index points in b64 + h1 = tab.indexOf(input.charAt(i += 1)); + h2 = tab.indexOf(input.charAt(i += 1)); + h3 = tab.indexOf(input.charAt(i += 1)); + h4 = tab.indexOf(input.charAt(i += 1)); - if (key && val) obj[key] = val; - return obj; - }, {}); -}; + bits = h1 << 18 | h2 << 12 | h3 << 6 | h4; -/** - * Initialize a new `Response` with the given `xhr`. - * - * - set flags (.ok, .error, etc) - * - parse header - * - * Examples: - * - * Aliasing `superagent` as `request` is nice: - * - * request = superagent; - * - * We can use the promise-like API, or pass callbacks: - * - * request.get('/').end(function(res){}); - * request.get('/', function(res){}); - * - * Sending data can be chained: - * - * request - * .post('/user') - * .send({ name: 'tj' }) - * .end(function(res){}); - * - * Or passed to `.send()`: - * - * request - * .post('/user') - * .send({ name: 'tj' }, function(res){}); - * - * Or passed to `.post()`: - * - * request - * .post('/user', { name: 'tj' }) - * .end(function(res){}); - * - * Or further reduced to a single call for simple cases: - * - * request - * .post('/user', { name: 'tj' }, function(res){}); - * - * @param {XMLHTTPRequest} xhr - * @param {Object} options - * @api private - */ + o1 = bits >> 16 & 0xff; + o2 = bits >> 8 & 0xff; + o3 = bits & 0xff; + ac += 1; -function Response(req, options) { - options = options || {}; - this.req = req; - this.xhr = this.req.xhr; - // responseText is accessible only if responseType is '' or 'text' and on older browsers - this.text = ((this.req.method !='HEAD' && (this.xhr.responseType === '' || this.xhr.responseType === 'text')) || typeof this.xhr.responseType === 'undefined') - ? this.xhr.responseText - : null; - this.statusText = this.req.xhr.statusText; - this._setStatusProperties(this.xhr.status); - this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders()); - // getAllResponseHeaders sometimes falsely returns "" for CORS requests, but - // getResponseHeader still works. so we get content-type even if getting - // other headers fails. - this.header['content-type'] = this.xhr.getResponseHeader('content-type'); - this._setHeaderProperties(this.header); - this.body = this.req.method != 'HEAD' - ? this._parseBody(this.text ? this.text : this.xhr.response) - : null; -} + if (h3 === 64) { + arr[ac] = String.fromCharCode(o1); + } else if (h4 === 64) { + arr[ac] = String.fromCharCode(o1, o2); + } else { + arr[ac] = String.fromCharCode(o1, o2, o3); + } + } while (i < input.length); -/** - * Get case-insensitive `field` value. - * - * @param {String} field - * @return {String} - * @api public - */ + dec = arr.join(''); + dec = (utf8) ? utf8Decode(dec) : dec; -Response.prototype.get = function(field){ - return this.header[field.toLowerCase()]; -}; + return dec; + }; -/** - * Set header related properties: - * - * - `.type` the content type without params - * - * A response of "Content-Type: text/plain; charset=utf-8" - * will provide you with a `.type` of "text/plain". - * - * @param {Object} header - * @api private - */ - -Response.prototype._setHeaderProperties = function(header){ - // content-type - var ct = this.header['content-type'] || ''; - this.type = type(ct); - - // params - var obj = params(ct); - for (var key in obj) this[key] = obj[key]; -}; + // set custom pad string + this.setPad = function(str) { + pad = str || pad; + return this; + }; + // set custom tab string characters + this.setTab = function(str) { + tab = str || tab; + return this; + }; + this.setUTF8 = function(bool) { + if (typeof bool === 'boolean') { + utf8 = bool; + } + return this; + }; + }, -/** - * Parse the given body `str`. - * - * Used for auto-parsing of bodies. Parsers - * are defined on the `superagent.parse` object. - * - * @param {String} str - * @return {Mixed} - * @api private - */ + /** + * CRC-32 calculation + * @member Hashes + * @method CRC32 + * @static + * @param {String} str Input String + * @return {String} + */ + CRC32: function(str) { + var crc = 0, + x = 0, + y = 0, + table, i, iTop; + str = utf8Encode(str); -Response.prototype._parseBody = function(str){ - var parse = request.parse[this.type]; - if (!parse && isJSON(this.type)) { - parse = request.parse['application/json']; - } - return parse && str && (str.length || str instanceof Object) - ? parse(str) - : null; -}; + table = [ + '00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 ', + '79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 ', + '84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F ', + '63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD ', + 'A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC ', + '51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 ', + 'B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 ', + '06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 ', + 'E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 ', + '12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 ', + 'D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 ', + '33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 ', + 'CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 ', + '9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E ', + '7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D ', + '806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 ', + '60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA ', + 'AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 ', + '5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 ', + 'B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 ', + '05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 ', + 'F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA ', + '11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 ', + 'D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F ', + '30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E ', + 'C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D' + ].join(''); + + crc = crc ^ (-1); + for (i = 0, iTop = str.length; i < iTop; i += 1) { + y = (crc ^ str.charCodeAt(i)) & 0xFF; + x = '0x' + table.substr(y * 9, 8); + crc = (crc >>> 8) ^ x; + } + // always return a positive number (that's what >>> 0 does) + return (crc ^ (-1)) >>> 0; + }, + /** + * @member Hashes + * @class MD5 + * @constructor + * @param {Object} [config] + * + * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message + * Digest Algorithm, as defined in RFC 1321. + * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * See for more infHashes. + */ + MD5: function(options) { + /** + * Private config properties. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase} + */ + var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase + b64pad = (options && typeof options.pad === 'string') ? options.pad : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance + utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding -/** - * Set flags such as `.ok` based on `status`. - * - * For example a 2xx response will give you a `.ok` of __true__ - * whereas 5xx will be __false__ and `.error` will be __true__. The - * `.clientError` and `.serverError` are also available to be more - * specific, and `.statusType` is the class of error ranging from 1..5 - * sometimes useful for mapping respond colors etc. - * - * "sugar" properties are also defined for common cases. Currently providing: - * - * - .noContent - * - .badRequest - * - .unauthorized - * - .notAcceptable - * - .notFound - * - * @param {Number} status - * @api private - */ + // privileged (public) methods + this.hex = function(s) { + return rstr2hex(rstr(s, utf8), hexcase); + }; + this.b64 = function(s) { + return rstr2b64(rstr(s), b64pad); + }; + this.any = function(s, e) { + return rstr2any(rstr(s, utf8), e); + }; + this.raw = function(s) { + return rstr(s, utf8); + }; + this.hex_hmac = function(k, d) { + return rstr2hex(rstr_hmac(k, d), hexcase); + }; + this.b64_hmac = function(k, d) { + return rstr2b64(rstr_hmac(k, d), b64pad); + }; + this.any_hmac = function(k, d, e) { + return rstr2any(rstr_hmac(k, d), e); + }; + /** + * Perform a simple self-test to see if the VM is working + * @return {String} Hexadecimal hash sample + */ + this.vm_test = function() { + return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72'; + }; + /** + * Enable/disable uppercase hexadecimal returned string + * @param {Boolean} + * @return {Object} this + */ + this.setUpperCase = function(a) { + if (typeof a === 'boolean') { + hexcase = a; + } + return this; + }; + /** + * Defines a base64 pad string + * @param {String} Pad + * @return {Object} this + */ + this.setPad = function(a) { + b64pad = a || b64pad; + return this; + }; + /** + * Defines a base64 pad string + * @param {Boolean} + * @return {Object} [this] + */ + this.setUTF8 = function(a) { + if (typeof a === 'boolean') { + utf8 = a; + } + return this; + }; -Response.prototype._setStatusProperties = function(status){ - // handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request - if (status === 1223) { - status = 204; - } + // private methods - var type = status / 100 | 0; - - // status / class - this.status = this.statusCode = status; - this.statusType = type; - - // basics - this.info = 1 == type; - this.ok = 2 == type; - this.clientError = 4 == type; - this.serverError = 5 == type; - this.error = (4 == type || 5 == type) - ? this.toError() - : false; - - // sugar - this.accepted = 202 == status; - this.noContent = 204 == status; - this.badRequest = 400 == status; - this.unauthorized = 401 == status; - this.notAcceptable = 406 == status; - this.notFound = 404 == status; - this.forbidden = 403 == status; -}; + /** + * Calculate the MD5 of a raw string + */ -/** - * Return an `Error` representative of this response. - * - * @return {Error} - * @api public - */ + function rstr(s) { + s = (utf8) ? utf8Encode(s) : s; + return binl2rstr(binl(rstr2binl(s), s.length * 8)); + } -Response.prototype.toError = function(){ - var req = this.req; - var method = req.method; - var url = req.url; + /** + * Calculate the HMAC-MD5, of a key and some data (raw strings) + */ - var msg = 'cannot ' + method + ' ' + url + ' (' + this.status + ')'; - var err = new Error(msg); - err.status = this.status; - err.method = method; - err.url = url; + function rstr_hmac(key, data) { + var bkey, ipad, opad, hash, i; - return err; -}; + key = (utf8) ? utf8Encode(key) : key; + data = (utf8) ? utf8Encode(data) : data; + bkey = rstr2binl(key); + if (bkey.length > 16) { + bkey = binl(bkey, key.length * 8); + } -/** - * Expose `Response`. - */ + ipad = Array(16), opad = Array(16); + for (i = 0; i < 16; i += 1) { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8); + return binl2rstr(binl(opad.concat(hash), 512 + 128)); + } -request.Response = Response; + /** + * Calculate the MD5 of an array of little-endian words, and a bit length. + */ -/** - * Initialize a new `Request` with the given `method` and `url`. - * - * @param {String} method - * @param {String} url - * @api public - */ + function binl(x, len) { + var i, olda, oldb, oldc, oldd, + a = 1732584193, + b = -271733879, + c = -1732584194, + d = 271733878; -function Request(method, url) { - var self = this; - this._query = this._query || []; - this.method = method; - this.url = url; - this.header = {}; // preserves header name case - this._header = {}; // coerces header names to lowercase - this.on('end', function(){ - var err = null; - var res = null; + /* append padding */ + x[len >> 5] |= 0x80 << ((len) % 32); + x[(((len + 64) >>> 9) << 4) + 14] = len; - try { - res = new Response(self); - } catch(e) { - err = new Error('Parser is unable to parse the response'); - err.parse = true; - err.original = e; - // issue #675: return the raw response if the response parsing fails - err.rawResponse = self.xhr && self.xhr.responseText ? self.xhr.responseText : null; - // issue #876: return the http status code if the response parsing fails - err.statusCode = self.xhr && self.xhr.status ? self.xhr.status : null; - return self.callback(err); - } + for (i = 0; i < x.length; i += 16) { + olda = a; + oldb = b; + oldc = c; + oldd = d; - self.emit('response', res); + a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936); + d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586); + c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819); + b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330); + a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897); + d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426); + c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341); + b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983); + a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416); + d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417); + c = md5_ff(c, d, a, b, x[i + 10], 17, -42063); + b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162); + a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682); + d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101); + c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290); + b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329); - var new_err; - try { - if (res.status < 200 || res.status >= 300) { - new_err = new Error(res.statusText || 'Unsuccessful HTTP response'); - new_err.original = err; - new_err.response = res; - new_err.status = res.status; - } - } catch(e) { - new_err = e; // #985 touching res may cause INVALID_STATE_ERR on old Android - } + a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510); + d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632); + c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713); + b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302); + a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691); + d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083); + c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335); + b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848); + a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438); + d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690); + c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961); + b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501); + a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467); + d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784); + c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473); + b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734); - // #1000 don't catch errors from the callback to avoid double calling it - if (new_err) { - self.callback(new_err, res); - } else { - self.callback(null, res); - } - }); -} + a = md5_hh(a, b, c, d, x[i + 5], 4, -378558); + d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463); + c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562); + b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556); + a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060); + d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353); + c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632); + b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640); + a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174); + d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222); + c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979); + b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189); + a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487); + d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835); + c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520); + b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651); -/** - * Mixin `Emitter` and `requestBase`. - */ + a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844); + d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415); + c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905); + b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055); + a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571); + d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606); + c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523); + b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799); + a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359); + d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744); + c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380); + b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649); + a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070); + d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379); + c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259); + b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551); -Emitter(Request.prototype); -for (var key in requestBase) { - Request.prototype[key] = requestBase[key]; -} + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + } + return Array(a, b, c, d); + } -/** - * Set Content-Type to `type`, mapping values from `request.types`. - * - * Examples: - * - * superagent.types.xml = 'application/xml'; - * - * request.post('/') - * .type('xml') - * .send(xmlstring) - * .end(callback); - * - * request.post('/') - * .type('application/xml') - * .send(xmlstring) - * .end(callback); - * - * @param {String} type - * @return {Request} for chaining - * @api public - */ + /** + * These functions implement the four basic operations the algorithm uses. + */ -Request.prototype.type = function(type){ - this.set('Content-Type', request.types[type] || type); - return this; -}; + function md5_cmn(q, a, b, x, s, t) { + return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b); + } -/** - * Set responseType to `val`. Presently valid responseTypes are 'blob' and - * 'arraybuffer'. - * - * Examples: - * - * req.get('/') - * .responseType('blob') - * .end(callback); - * - * @param {String} val - * @return {Request} for chaining - * @api public - */ + function md5_ff(a, b, c, d, x, s, t) { + return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); + } -Request.prototype.responseType = function(val){ - this._responseType = val; - return this; -}; + function md5_gg(a, b, c, d, x, s, t) { + return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); + } -/** - * Set Accept to `type`, mapping values from `request.types`. - * - * Examples: - * - * superagent.types.json = 'application/json'; - * - * request.get('/agent') - * .accept('json') - * .end(callback); - * - * request.get('/agent') - * .accept('application/json') - * .end(callback); - * - * @param {String} accept - * @return {Request} for chaining - * @api public - */ + function md5_hh(a, b, c, d, x, s, t) { + return md5_cmn(b ^ c ^ d, a, b, x, s, t); + } -Request.prototype.accept = function(type){ - this.set('Accept', request.types[type] || type); - return this; -}; + function md5_ii(a, b, c, d, x, s, t) { + return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); + } + }, + /** + * @member Hashes + * @class Hashes.SHA1 + * @param {Object} [config] + * @constructor + * + * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS 180-1 + * Version 2.2 Copyright Paul Johnston 2000 - 2009. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * See http://pajhome.org.uk/crypt/md5 for details. + */ + SHA1: function(options) { + /** + * Private config properties. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase} + */ + var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase + b64pad = (options && typeof options.pad === 'string') ? options.pad : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance + utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding -/** - * Set Authorization field value with `user` and `pass`. - * - * @param {String} user - * @param {String} pass - * @param {Object} options with 'type' property 'auto' or 'basic' (default 'basic') - * @return {Request} for chaining - * @api public - */ + // public methods + this.hex = function(s) { + return rstr2hex(rstr(s, utf8), hexcase); + }; + this.b64 = function(s) { + return rstr2b64(rstr(s, utf8), b64pad); + }; + this.any = function(s, e) { + return rstr2any(rstr(s, utf8), e); + }; + this.raw = function(s) { + return rstr(s, utf8); + }; + this.hex_hmac = function(k, d) { + return rstr2hex(rstr_hmac(k, d)); + }; + this.b64_hmac = function(k, d) { + return rstr2b64(rstr_hmac(k, d), b64pad); + }; + this.any_hmac = function(k, d, e) { + return rstr2any(rstr_hmac(k, d), e); + }; + /** + * Perform a simple self-test to see if the VM is working + * @return {String} Hexadecimal hash sample + * @public + */ + this.vm_test = function() { + return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72'; + }; + /** + * @description Enable/disable uppercase hexadecimal returned string + * @param {boolean} + * @return {Object} this + * @public + */ + this.setUpperCase = function(a) { + if (typeof a === 'boolean') { + hexcase = a; + } + return this; + }; + /** + * @description Defines a base64 pad string + * @param {string} Pad + * @return {Object} this + * @public + */ + this.setPad = function(a) { + b64pad = a || b64pad; + return this; + }; + /** + * @description Defines a base64 pad string + * @param {boolean} + * @return {Object} this + * @public + */ + this.setUTF8 = function(a) { + if (typeof a === 'boolean') { + utf8 = a; + } + return this; + }; -Request.prototype.auth = function(user, pass, options){ - if (!options) { - options = { - type: 'basic' - } - } + // private methods - switch (options.type) { - case 'basic': - var str = btoa(user + ':' + pass); - this.set('Authorization', 'Basic ' + str); - break; + /** + * Calculate the SHA-512 of a raw string + */ - case 'auto': - this.username = user; - this.password = pass; - break; - } - return this; -}; + function rstr(s) { + s = (utf8) ? utf8Encode(s) : s; + return binb2rstr(binb(rstr2binb(s), s.length * 8)); + } -/** -* Add query-string `val`. -* -* Examples: -* -* request.get('/shoes') -* .query('size=10') -* .query({ color: 'blue' }) -* -* @param {Object|String} val -* @return {Request} for chaining -* @api public -*/ + /** + * Calculate the HMAC-SHA1 of a key and some data (raw strings) + */ -Request.prototype.query = function(val){ - if ('string' != typeof val) val = serialize(val); - if (val) this._query.push(val); - return this; -}; + function rstr_hmac(key, data) { + var bkey, ipad, opad, i, hash; + key = (utf8) ? utf8Encode(key) : key; + data = (utf8) ? utf8Encode(data) : data; + bkey = rstr2binb(key); -/** - * Queue the given `file` as an attachment to the specified `field`, - * with optional `filename`. - * - * ``` js - * request.post('/upload') - * .attach('content', new Blob(['hey!'], { type: "text/html"})) - * .end(callback); - * ``` - * - * @param {String} field - * @param {Blob|File} file - * @param {String} filename - * @return {Request} for chaining - * @api public - */ + if (bkey.length > 16) { + bkey = binb(bkey, key.length * 8); + } + ipad = Array(16), opad = Array(16); + for (i = 0; i < 16; i += 1) { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8); + return binb2rstr(binb(opad.concat(hash), 512 + 160)); + } + + /** + * Calculate the SHA-1 of an array of big-endian words, and a bit length + */ + + function binb(x, len) { + var i, j, t, olda, oldb, oldc, oldd, olde, + w = Array(80), + a = 1732584193, + b = -271733879, + c = -1732584194, + d = 271733878, + e = -1009589776; + + /* append padding */ + x[len >> 5] |= 0x80 << (24 - len % 32); + x[((len + 64 >> 9) << 4) + 15] = len; + + for (i = 0; i < x.length; i += 16) { + olda = a, + oldb = b; + oldc = c; + oldd = d; + olde = e; + + for (j = 0; j < 80; j += 1) { + if (j < 16) { + w[j] = x[i + j]; + } else { + w[j] = bit_rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1); + } + t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)), + safe_add(safe_add(e, w[j]), sha1_kt(j))); + e = d; + d = c; + c = bit_rol(b, 30); + b = a; + a = t; + } + + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + e = safe_add(e, olde); + } + return Array(a, b, c, d, e); + } + + /** + * Perform the appropriate triplet combination function for the current + * iteration + */ + + function sha1_ft(t, b, c, d) { + if (t < 20) { + return (b & c) | ((~b) & d); + } + if (t < 40) { + return b ^ c ^ d; + } + if (t < 60) { + return (b & c) | (b & d) | (c & d); + } + return b ^ c ^ d; + } + + /** + * Determine the appropriate additive constant for the current iteration + */ + + function sha1_kt(t) { + return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : + (t < 60) ? -1894007588 : -899497514; + } + }, + /** + * @class Hashes.SHA256 + * @param {config} + * + * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined in FIPS 180-2 + * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * See http://pajhome.org.uk/crypt/md5 for details. + * Also http://anmar.eu.org/projects/jssha2/ + */ + SHA256: function(options) { + /** + * Private properties configuration variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + * @see this.setUpperCase() method + * @see this.setPad() method + */ + var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase */ + b64pad = (options && typeof options.pad === 'string') ? options.pad : '=', + /* base-64 pad character. Default '=' for strict RFC compliance */ + utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, + /* enable/disable utf8 encoding */ + sha256_K; + + /* privileged (public) methods */ + this.hex = function(s) { + return rstr2hex(rstr(s, utf8)); + }; + this.b64 = function(s) { + return rstr2b64(rstr(s, utf8), b64pad); + }; + this.any = function(s, e) { + return rstr2any(rstr(s, utf8), e); + }; + this.raw = function(s) { + return rstr(s, utf8); + }; + this.hex_hmac = function(k, d) { + return rstr2hex(rstr_hmac(k, d)); + }; + this.b64_hmac = function(k, d) { + return rstr2b64(rstr_hmac(k, d), b64pad); + }; + this.any_hmac = function(k, d, e) { + return rstr2any(rstr_hmac(k, d), e); + }; + /** + * Perform a simple self-test to see if the VM is working + * @return {String} Hexadecimal hash sample + * @public + */ + this.vm_test = function() { + return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72'; + }; + /** + * Enable/disable uppercase hexadecimal returned string + * @param {boolean} + * @return {Object} this + * @public + */ + this.setUpperCase = function(a) { + if (typeof a === 'boolean') { + hexcase = a; + } + return this; + }; + /** + * @description Defines a base64 pad string + * @param {string} Pad + * @return {Object} this + * @public + */ + this.setPad = function(a) { + b64pad = a || b64pad; + return this; + }; + /** + * Defines a base64 pad string + * @param {boolean} + * @return {Object} this + * @public + */ + this.setUTF8 = function(a) { + if (typeof a === 'boolean') { + utf8 = a; + } + return this; + }; + + // private methods + + /** + * Calculate the SHA-512 of a raw string + */ + + function rstr(s, utf8) { + s = (utf8) ? utf8Encode(s) : s; + return binb2rstr(binb(rstr2binb(s), s.length * 8)); + } + + /** + * Calculate the HMAC-sha256 of a key and some data (raw strings) + */ + + function rstr_hmac(key, data) { + key = (utf8) ? utf8Encode(key) : key; + data = (utf8) ? utf8Encode(data) : data; + var hash, i = 0, + bkey = rstr2binb(key), + ipad = Array(16), + opad = Array(16); + + if (bkey.length > 16) { + bkey = binb(bkey, key.length * 8); + } + + for (; i < 16; i += 1) { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + + hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8); + return binb2rstr(binb(opad.concat(hash), 512 + 256)); + } + + /* + * Main sha256 function, with its support functions + */ + + function sha256_S(X, n) { + return (X >>> n) | (X << (32 - n)); + } + + function sha256_R(X, n) { + return (X >>> n); + } + + function sha256_Ch(x, y, z) { + return ((x & y) ^ ((~x) & z)); + } -Request.prototype.attach = function(field, file, filename){ - this._getFormData().append(field, file, filename || file.name); - return this; -}; + function sha256_Maj(x, y, z) { + return ((x & y) ^ (x & z) ^ (y & z)); + } -Request.prototype._getFormData = function(){ - if (!this._formData) { - this._formData = new root.FormData(); - } - return this._formData; -}; + function sha256_Sigma0256(x) { + return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22)); + } -/** - * Invoke the callback with `err` and `res` - * and handle arity check. - * - * @param {Error} err - * @param {Response} res - * @api private - */ + function sha256_Sigma1256(x) { + return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25)); + } -Request.prototype.callback = function(err, res){ - var fn = this._callback; - this.clearTimeout(); - fn(err, res); -}; + function sha256_Gamma0256(x) { + return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3)); + } -/** - * Invoke callback with x-domain error. - * - * @api private - */ + function sha256_Gamma1256(x) { + return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10)); + } -Request.prototype.crossDomainError = function(){ - var err = new Error('Request has been terminated\nPossible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.'); - err.crossDomain = true; + function sha256_Sigma0512(x) { + return (sha256_S(x, 28) ^ sha256_S(x, 34) ^ sha256_S(x, 39)); + } - err.status = this.status; - err.method = this.method; - err.url = this.url; + function sha256_Sigma1512(x) { + return (sha256_S(x, 14) ^ sha256_S(x, 18) ^ sha256_S(x, 41)); + } - this.callback(err); -}; + function sha256_Gamma0512(x) { + return (sha256_S(x, 1) ^ sha256_S(x, 8) ^ sha256_R(x, 7)); + } -/** - * Invoke callback with timeout error. - * - * @api private - */ + function sha256_Gamma1512(x) { + return (sha256_S(x, 19) ^ sha256_S(x, 61) ^ sha256_R(x, 6)); + } -Request.prototype._timeoutError = function(){ - var timeout = this._timeout; - var err = new Error('timeout of ' + timeout + 'ms exceeded'); - err.timeout = timeout; - this.callback(err); -}; + sha256_K = [ + 1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993, -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987, + 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522, + 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585, + 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291, + 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885, -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344, + 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218, + 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872, -1866530822, -1538233109, -1090935817, -965641998 + ]; -/** - * Compose querystring to append to req.url - * - * @api private - */ + function binb(m, l) { + var HASH = [1779033703, -1150833019, 1013904242, -1521486534, + 1359893119, -1694144372, 528734635, 1541459225 + ]; + var W = new Array(64); + var a, b, c, d, e, f, g, h; + var i, j, T1, T2; -Request.prototype._appendQueryString = function(){ - var query = this._query.join('&'); - if (query) { - this.url += ~this.url.indexOf('?') - ? '&' + query - : '?' + query; - } -}; + /* append padding */ + m[l >> 5] |= 0x80 << (24 - l % 32); + m[((l + 64 >> 9) << 4) + 15] = l; -/** - * Initiate request, invoking callback `fn(res)` - * with an instanceof `Response`. - * - * @param {Function} fn - * @return {Request} for chaining - * @api public - */ + for (i = 0; i < m.length; i += 16) { + a = HASH[0]; + b = HASH[1]; + c = HASH[2]; + d = HASH[3]; + e = HASH[4]; + f = HASH[5]; + g = HASH[6]; + h = HASH[7]; -Request.prototype.end = function(fn){ - var self = this; - var xhr = this.xhr = request.getXHR(); - var timeout = this._timeout; - var data = this._formData || this._data; + for (j = 0; j < 64; j += 1) { + if (j < 16) { + W[j] = m[j + i]; + } else { + W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]), + sha256_Gamma0256(W[j - 15])), W[j - 16]); + } - // store callback - this._callback = fn || noop; + T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)), + sha256_K[j]), W[j]); + T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c)); + h = g; + g = f; + f = e; + e = safe_add(d, T1); + d = c; + c = b; + b = a; + a = safe_add(T1, T2); + } - // state change - xhr.onreadystatechange = function(){ - if (4 != xhr.readyState) return; + HASH[0] = safe_add(a, HASH[0]); + HASH[1] = safe_add(b, HASH[1]); + HASH[2] = safe_add(c, HASH[2]); + HASH[3] = safe_add(d, HASH[3]); + HASH[4] = safe_add(e, HASH[4]); + HASH[5] = safe_add(f, HASH[5]); + HASH[6] = safe_add(g, HASH[6]); + HASH[7] = safe_add(h, HASH[7]); + } + return HASH; + } - // In IE9, reads to any property (e.g. status) off of an aborted XHR will - // result in the error "Could not complete the operation due to error c00c023f" - var status; - try { status = xhr.status } catch(e) { status = 0; } + }, - if (0 == status) { - if (self.timedout) return self._timeoutError(); - if (self._aborted) return; - return self.crossDomainError(); - } - self.emit('end'); - }; + /** + * @class Hashes.SHA512 + * @param {config} + * + * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined in FIPS 180-2 + * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * See http://pajhome.org.uk/crypt/md5 for details. + */ + SHA512: function(options) { + /** + * Private properties configuration variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + * @see this.setUpperCase() method + * @see this.setPad() method + */ + var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, + /* hexadecimal output case format. false - lowercase; true - uppercase */ + b64pad = (options && typeof options.pad === 'string') ? options.pad : '=', + /* base-64 pad character. Default '=' for strict RFC compliance */ + utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, + /* enable/disable utf8 encoding */ + sha512_k; - // progress - var handleProgress = function(direction, e) { - if (e.total > 0) { - e.percent = e.loaded / e.total * 100; - } - e.direction = direction; - self.emit('progress', e); - } - if (this.hasListeners('progress')) { - try { - xhr.onprogress = handleProgress.bind(null, 'download'); - if (xhr.upload) { - xhr.upload.onprogress = handleProgress.bind(null, 'upload'); + /* privileged (public) methods */ + this.hex = function(s) { + return rstr2hex(rstr(s)); + }; + this.b64 = function(s) { + return rstr2b64(rstr(s), b64pad); + }; + this.any = function(s, e) { + return rstr2any(rstr(s), e); + }; + this.raw = function(s) { + return rstr(s, utf8); + }; + this.hex_hmac = function(k, d) { + return rstr2hex(rstr_hmac(k, d)); + }; + this.b64_hmac = function(k, d) { + return rstr2b64(rstr_hmac(k, d), b64pad); + }; + this.any_hmac = function(k, d, e) { + return rstr2any(rstr_hmac(k, d), e); + }; + /** + * Perform a simple self-test to see if the VM is working + * @return {String} Hexadecimal hash sample + * @public + */ + this.vm_test = function() { + return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72'; + }; + /** + * @description Enable/disable uppercase hexadecimal returned string + * @param {boolean} + * @return {Object} this + * @public + */ + this.setUpperCase = function(a) { + if (typeof a === 'boolean') { + hexcase = a; + } + return this; + }; + /** + * @description Defines a base64 pad string + * @param {string} Pad + * @return {Object} this + * @public + */ + this.setPad = function(a) { + b64pad = a || b64pad; + return this; + }; + /** + * @description Defines a base64 pad string + * @param {boolean} + * @return {Object} this + * @public + */ + this.setUTF8 = function(a) { + if (typeof a === 'boolean') { + utf8 = a; + } + return this; + }; + + /* private methods */ + + /** + * Calculate the SHA-512 of a raw string + */ + + function rstr(s) { + s = (utf8) ? utf8Encode(s) : s; + return binb2rstr(binb(rstr2binb(s), s.length * 8)); } - } catch(e) { - // Accessing xhr.upload fails in IE from a web worker, so just pretend it doesn't exist. - // Reported here: - // https://connect.microsoft.com/IE/feedback/details/837245/xmlhttprequest-upload-throws-invalid-argument-when-used-from-web-worker-context - } - } + /* + * Calculate the HMAC-SHA-512 of a key and some data (raw strings) + */ - // timeout - if (timeout && !this._timer) { - this._timer = setTimeout(function(){ - self.timedout = true; - self.abort(); - }, timeout); - } + function rstr_hmac(key, data) { + key = (utf8) ? utf8Encode(key) : key; + data = (utf8) ? utf8Encode(data) : data; - // querystring - this._appendQueryString(); + var hash, i = 0, + bkey = rstr2binb(key), + ipad = Array(32), + opad = Array(32); - // initiate request - if (this.username && this.password) { - xhr.open(this.method, this.url, true, this.username, this.password); - } else { - xhr.open(this.method, this.url, true); - } + if (bkey.length > 32) { + bkey = binb(bkey, key.length * 8); + } - // CORS - if (this._withCredentials) xhr.withCredentials = true; + for (; i < 32; i += 1) { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + + hash = binb(ipad.concat(rstr2binb(data)), 1024 + data.length * 8); + return binb2rstr(binb(opad.concat(hash), 1024 + 512)); + } - // body - if ('GET' != this.method && 'HEAD' != this.method && 'string' != typeof data && !this._isHost(data)) { - // serialize stuff - var contentType = this._header['content-type']; - var serialize = this._serializer || request.serialize[contentType ? contentType.split(';')[0] : '']; - if (!serialize && isJSON(contentType)) serialize = request.serialize['application/json']; - if (serialize) data = serialize(data); - } + /** + * Calculate the SHA-512 of an array of big-endian dwords, and a bit length + */ - // set header fields - for (var field in this.header) { - if (null == this.header[field]) continue; - xhr.setRequestHeader(field, this.header[field]); - } + function binb(x, len) { + var j, i, l, + W = new Array(80), + hash = new Array(16), + //Initial hash values + H = [ + new int64(0x6a09e667, -205731576), + new int64(-1150833019, -2067093701), + new int64(0x3c6ef372, -23791573), + new int64(-1521486534, 0x5f1d36f1), + new int64(0x510e527f, -1377402159), + new int64(-1694144372, 0x2b3e6c1f), + new int64(0x1f83d9ab, -79577749), + new int64(0x5be0cd19, 0x137e2179) + ], + T1 = new int64(0, 0), + T2 = new int64(0, 0), + a = new int64(0, 0), + b = new int64(0, 0), + c = new int64(0, 0), + d = new int64(0, 0), + e = new int64(0, 0), + f = new int64(0, 0), + g = new int64(0, 0), + h = new int64(0, 0), + //Temporary variables not specified by the document + s0 = new int64(0, 0), + s1 = new int64(0, 0), + Ch = new int64(0, 0), + Maj = new int64(0, 0), + r1 = new int64(0, 0), + r2 = new int64(0, 0), + r3 = new int64(0, 0); - if (this._responseType) { - xhr.responseType = this._responseType; - } + if (sha512_k === undefined) { + //SHA512 constants + sha512_k = [ + new int64(0x428a2f98, -685199838), new int64(0x71374491, 0x23ef65cd), + new int64(-1245643825, -330482897), new int64(-373957723, -2121671748), + new int64(0x3956c25b, -213338824), new int64(0x59f111f1, -1241133031), + new int64(-1841331548, -1357295717), new int64(-1424204075, -630357736), + new int64(-670586216, -1560083902), new int64(0x12835b01, 0x45706fbe), + new int64(0x243185be, 0x4ee4b28c), new int64(0x550c7dc3, -704662302), + new int64(0x72be5d74, -226784913), new int64(-2132889090, 0x3b1696b1), + new int64(-1680079193, 0x25c71235), new int64(-1046744716, -815192428), + new int64(-459576895, -1628353838), new int64(-272742522, 0x384f25e3), + new int64(0xfc19dc6, -1953704523), new int64(0x240ca1cc, 0x77ac9c65), + new int64(0x2de92c6f, 0x592b0275), new int64(0x4a7484aa, 0x6ea6e483), + new int64(0x5cb0a9dc, -1119749164), new int64(0x76f988da, -2096016459), + new int64(-1740746414, -295247957), new int64(-1473132947, 0x2db43210), + new int64(-1341970488, -1728372417), new int64(-1084653625, -1091629340), + new int64(-958395405, 0x3da88fc2), new int64(-710438585, -1828018395), + new int64(0x6ca6351, -536640913), new int64(0x14292967, 0xa0e6e70), + new int64(0x27b70a85, 0x46d22ffc), new int64(0x2e1b2138, 0x5c26c926), + new int64(0x4d2c6dfc, 0x5ac42aed), new int64(0x53380d13, -1651133473), + new int64(0x650a7354, -1951439906), new int64(0x766a0abb, 0x3c77b2a8), + new int64(-2117940946, 0x47edaee6), new int64(-1838011259, 0x1482353b), + new int64(-1564481375, 0x4cf10364), new int64(-1474664885, -1136513023), + new int64(-1035236496, -789014639), new int64(-949202525, 0x654be30), + new int64(-778901479, -688958952), new int64(-694614492, 0x5565a910), + new int64(-200395387, 0x5771202a), new int64(0x106aa070, 0x32bbd1b8), + new int64(0x19a4c116, -1194143544), new int64(0x1e376c08, 0x5141ab53), + new int64(0x2748774c, -544281703), new int64(0x34b0bcb5, -509917016), + new int64(0x391c0cb3, -976659869), new int64(0x4ed8aa4a, -482243893), + new int64(0x5b9cca4f, 0x7763e373), new int64(0x682e6ff3, -692930397), + new int64(0x748f82ee, 0x5defb2fc), new int64(0x78a5636f, 0x43172f60), + new int64(-2067236844, -1578062990), new int64(-1933114872, 0x1a6439ec), + new int64(-1866530822, 0x23631e28), new int64(-1538233109, -561857047), + new int64(-1090935817, -1295615723), new int64(-965641998, -479046869), + new int64(-903397682, -366583396), new int64(-779700025, 0x21c0c207), + new int64(-354779690, -840897762), new int64(-176337025, -294727304), + new int64(0x6f067aa, 0x72176fba), new int64(0xa637dc5, -1563912026), + new int64(0x113f9804, -1090974290), new int64(0x1b710b35, 0x131c471b), + new int64(0x28db77f5, 0x23047d84), new int64(0x32caab7b, 0x40c72493), + new int64(0x3c9ebe0a, 0x15c9bebc), new int64(0x431d67c4, -1676669620), + new int64(0x4cc5d4be, -885112138), new int64(0x597f299c, -60457430), + new int64(0x5fcb6fab, 0x3ad6faec), new int64(0x6c44198c, 0x4a475817) + ]; + } - // send stuff - this.emit('request', this); + for (i = 0; i < 80; i += 1) { + W[i] = new int64(0, 0); + } - // IE11 xhr.send(undefined) sends 'undefined' string as POST payload (instead of nothing) - // We need null here if data is undefined - xhr.send(typeof data !== 'undefined' ? data : null); - return this; -}; + // append padding to the source string. The format is described in the FIPS. + x[len >> 5] |= 0x80 << (24 - (len & 0x1f)); + x[((len + 128 >> 10) << 5) + 31] = len; + l = x.length; + for (i = 0; i < l; i += 32) { //32 dwords is the block size + int64copy(a, H[0]); + int64copy(b, H[1]); + int64copy(c, H[2]); + int64copy(d, H[3]); + int64copy(e, H[4]); + int64copy(f, H[5]); + int64copy(g, H[6]); + int64copy(h, H[7]); + for (j = 0; j < 16; j += 1) { + W[j].h = x[i + 2 * j]; + W[j].l = x[i + 2 * j + 1]; + } -/** - * Expose `Request`. - */ + for (j = 16; j < 80; j += 1) { + //sigma1 + int64rrot(r1, W[j - 2], 19); + int64revrrot(r2, W[j - 2], 29); + int64shr(r3, W[j - 2], 6); + s1.l = r1.l ^ r2.l ^ r3.l; + s1.h = r1.h ^ r2.h ^ r3.h; + //sigma0 + int64rrot(r1, W[j - 15], 1); + int64rrot(r2, W[j - 15], 8); + int64shr(r3, W[j - 15], 7); + s0.l = r1.l ^ r2.l ^ r3.l; + s0.h = r1.h ^ r2.h ^ r3.h; -request.Request = Request; + int64add4(W[j], s1, W[j - 7], s0, W[j - 16]); + } -/** - * GET `url` with optional callback `fn(res)`. - * - * @param {String} url - * @param {Mixed|Function} [data] or fn - * @param {Function} [fn] - * @return {Request} - * @api public - */ + for (j = 0; j < 80; j += 1) { + //Ch + Ch.l = (e.l & f.l) ^ (~e.l & g.l); + Ch.h = (e.h & f.h) ^ (~e.h & g.h); -request.get = function(url, data, fn){ - var req = request('GET', url); - if ('function' == typeof data) fn = data, data = null; - if (data) req.query(data); - if (fn) req.end(fn); - return req; -}; + //Sigma1 + int64rrot(r1, e, 14); + int64rrot(r2, e, 18); + int64revrrot(r3, e, 9); + s1.l = r1.l ^ r2.l ^ r3.l; + s1.h = r1.h ^ r2.h ^ r3.h; -/** - * HEAD `url` with optional callback `fn(res)`. - * - * @param {String} url - * @param {Mixed|Function} [data] or fn - * @param {Function} [fn] - * @return {Request} - * @api public - */ + //Sigma0 + int64rrot(r1, a, 28); + int64revrrot(r2, a, 2); + int64revrrot(r3, a, 7); + s0.l = r1.l ^ r2.l ^ r3.l; + s0.h = r1.h ^ r2.h ^ r3.h; -request.head = function(url, data, fn){ - var req = request('HEAD', url); - if ('function' == typeof data) fn = data, data = null; - if (data) req.send(data); - if (fn) req.end(fn); - return req; -}; + //Maj + Maj.l = (a.l & b.l) ^ (a.l & c.l) ^ (b.l & c.l); + Maj.h = (a.h & b.h) ^ (a.h & c.h) ^ (b.h & c.h); -/** - * OPTIONS query to `url` with optional callback `fn(res)`. - * - * @param {String} url - * @param {Mixed|Function} [data] or fn - * @param {Function} [fn] - * @return {Request} - * @api public - */ + int64add5(T1, h, s1, Ch, sha512_k[j], W[j]); + int64add(T2, s0, Maj); -request.options = function(url, data, fn){ - var req = request('OPTIONS', url); - if ('function' == typeof data) fn = data, data = null; - if (data) req.send(data); - if (fn) req.end(fn); - return req; -}; + int64copy(h, g); + int64copy(g, f); + int64copy(f, e); + int64add(e, d, T1); + int64copy(d, c); + int64copy(c, b); + int64copy(b, a); + int64add(a, T1, T2); + } + int64add(H[0], H[0], a); + int64add(H[1], H[1], b); + int64add(H[2], H[2], c); + int64add(H[3], H[3], d); + int64add(H[4], H[4], e); + int64add(H[5], H[5], f); + int64add(H[6], H[6], g); + int64add(H[7], H[7], h); + } -/** - * DELETE `url` with optional callback `fn(res)`. - * - * @param {String} url - * @param {Function} [fn] - * @return {Request} - * @api public - */ + //represent the hash as an array of 32-bit dwords + for (i = 0; i < 8; i += 1) { + hash[2 * i] = H[i].h; + hash[2 * i + 1] = H[i].l; + } + return hash; + } -function del(url, fn){ - var req = request('DELETE', url); - if (fn) req.end(fn); - return req; -}; + //A constructor for 64-bit numbers -request['del'] = del; -request['delete'] = del; + function int64(h, l) { + this.h = h; + this.l = l; + //this.toString = int64toString; + } -/** - * PATCH `url` with optional `data` and callback `fn(res)`. - * - * @param {String} url - * @param {Mixed} [data] - * @param {Function} [fn] - * @return {Request} - * @api public - */ + //Copies src into dst, assuming both are 64-bit numbers -request.patch = function(url, data, fn){ - var req = request('PATCH', url); - if ('function' == typeof data) fn = data, data = null; - if (data) req.send(data); - if (fn) req.end(fn); - return req; -}; + function int64copy(dst, src) { + dst.h = src.h; + dst.l = src.l; + } -/** - * POST `url` with optional `data` and callback `fn(res)`. - * - * @param {String} url - * @param {Mixed} [data] - * @param {Function} [fn] - * @return {Request} - * @api public - */ + //Right-rotates a 64-bit number by shift + //Won't handle cases of shift>=32 + //The function revrrot() is for that -request.post = function(url, data, fn){ - var req = request('POST', url); - if ('function' == typeof data) fn = data, data = null; - if (data) req.send(data); - if (fn) req.end(fn); - return req; -}; + function int64rrot(dst, x, shift) { + dst.l = (x.l >>> shift) | (x.h << (32 - shift)); + dst.h = (x.h >>> shift) | (x.l << (32 - shift)); + } -/** - * PUT `url` with optional `data` and callback `fn(res)`. - * - * @param {String} url - * @param {Mixed|Function} [data] or fn - * @param {Function} [fn] - * @return {Request} - * @api public - */ + //Reverses the dwords of the source and then rotates right by shift. + //This is equivalent to rotation by 32+shift -request.put = function(url, data, fn){ - var req = request('PUT', url); - if ('function' == typeof data) fn = data, data = null; - if (data) req.send(data); - if (fn) req.end(fn); - return req; -}; + function int64revrrot(dst, x, shift) { + dst.l = (x.h >>> shift) | (x.l << (32 - shift)); + dst.h = (x.l >>> shift) | (x.h << (32 - shift)); + } -},{"./is-object":3,"./request":5,"./request-base":4,"emitter":1}],3:[function(_dereq_,module,exports){ -/** - * Check if `obj` is an object. - * - * @param {Object} obj - * @return {Boolean} - * @api private - */ + //Bitwise-shifts right a 64-bit number by shift + //Won't handle shift>=32, but it's never needed in SHA512 -function isObject(obj) { - return null !== obj && 'object' === typeof obj; -} + function int64shr(dst, x, shift) { + dst.l = (x.l >>> shift) | (x.h << (32 - shift)); + dst.h = (x.h >>> shift); + } -module.exports = isObject; + //Adds two 64-bit numbers + //Like the original implementation, does not rely on 32-bit operations -},{}],4:[function(_dereq_,module,exports){ -/** - * Module of mixed-in functions shared between node and client code - */ -var isObject = _dereq_('./is-object'); + function int64add(dst, x, y) { + var w0 = (x.l & 0xffff) + (y.l & 0xffff); + var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16); + var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16); + var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16); + dst.l = (w0 & 0xffff) | (w1 << 16); + dst.h = (w2 & 0xffff) | (w3 << 16); + } -/** - * Clear previous timeout. - * - * @return {Request} for chaining - * @api public - */ + //Same, except with 4 addends. Works faster than adding them one by one. -exports.clearTimeout = function _clearTimeout(){ - this._timeout = 0; - clearTimeout(this._timer); - return this; -}; + function int64add4(dst, a, b, c, d) { + var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff); + var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16); + var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16); + var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16); + dst.l = (w0 & 0xffff) | (w1 << 16); + dst.h = (w2 & 0xffff) | (w3 << 16); + } -/** - * Override default response body parser - * - * This function will be called to convert incoming data into request.body - * - * @param {Function} - * @api public - */ + //Same, except with 5 addends -exports.parse = function parse(fn){ - this._parser = fn; - return this; -}; + function int64add5(dst, a, b, c, d, e) { + var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff), + w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16), + w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16), + w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16); + dst.l = (w0 & 0xffff) | (w1 << 16); + dst.h = (w2 & 0xffff) | (w3 << 16); + } + }, + /** + * @class Hashes.RMD160 + * @constructor + * @param {Object} [config] + * + * A JavaScript implementation of the RIPEMD-160 Algorithm + * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * See http://pajhome.org.uk/crypt/md5 for details. + * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/ + */ + RMD160: function(options) { + /** + * Private properties configuration variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + * @see this.setUpperCase() method + * @see this.setPad() method + */ + var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, + /* hexadecimal output case format. false - lowercase; true - uppercase */ + b64pad = (options && typeof options.pad === 'string') ? options.pa : '=', + /* base-64 pad character. Default '=' for strict RFC compliance */ + utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, + /* enable/disable utf8 encoding */ + rmd160_r1 = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, + 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 + ], + rmd160_r2 = [ + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, + 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 + ], + rmd160_s1 = [ + 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, + 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 + ], + rmd160_s2 = [ + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, + 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 + ]; -/** - * Override default request body serializer - * - * This function will be called to convert data set via .send or .attach into payload to send - * - * @param {Function} - * @api public - */ + /* privileged (public) methods */ + this.hex = function(s) { + return rstr2hex(rstr(s, utf8)); + }; + this.b64 = function(s) { + return rstr2b64(rstr(s, utf8), b64pad); + }; + this.any = function(s, e) { + return rstr2any(rstr(s, utf8), e); + }; + this.raw = function(s) { + return rstr(s, utf8); + }; + this.hex_hmac = function(k, d) { + return rstr2hex(rstr_hmac(k, d)); + }; + this.b64_hmac = function(k, d) { + return rstr2b64(rstr_hmac(k, d), b64pad); + }; + this.any_hmac = function(k, d, e) { + return rstr2any(rstr_hmac(k, d), e); + }; + /** + * Perform a simple self-test to see if the VM is working + * @return {String} Hexadecimal hash sample + * @public + */ + this.vm_test = function() { + return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72'; + }; + /** + * @description Enable/disable uppercase hexadecimal returned string + * @param {boolean} + * @return {Object} this + * @public + */ + this.setUpperCase = function(a) { + if (typeof a === 'boolean') { + hexcase = a; + } + return this; + }; + /** + * @description Defines a base64 pad string + * @param {string} Pad + * @return {Object} this + * @public + */ + this.setPad = function(a) { + if (typeof a !== 'undefined') { + b64pad = a; + } + return this; + }; + /** + * @description Defines a base64 pad string + * @param {boolean} + * @return {Object} this + * @public + */ + this.setUTF8 = function(a) { + if (typeof a === 'boolean') { + utf8 = a; + } + return this; + }; -exports.serialize = function serialize(fn){ - this._serializer = fn; - return this; -}; + /* private methods */ -/** - * Set timeout to `ms`. - * - * @param {Number} ms - * @return {Request} for chaining - * @api public - */ + /** + * Calculate the rmd160 of a raw string + */ -exports.timeout = function timeout(ms){ - this._timeout = ms; - return this; -}; + function rstr(s) { + s = (utf8) ? utf8Encode(s) : s; + return binl2rstr(binl(rstr2binl(s), s.length * 8)); + } -/** - * Promise support - * - * @param {Function} resolve - * @param {Function} reject - * @return {Request} - */ + /** + * Calculate the HMAC-rmd160 of a key and some data (raw strings) + */ -exports.then = function then(resolve, reject) { - if (!this._fullfilledPromise) { - var self = this; - this._fullfilledPromise = new Promise(function(innerResolve, innerReject){ - self.end(function(err, res){ - if (err) innerReject(err); else innerResolve(res); - }); - }); - } - return this._fullfilledPromise.then(resolve, reject); -} + function rstr_hmac(key, data) { + key = (utf8) ? utf8Encode(key) : key; + data = (utf8) ? utf8Encode(data) : data; + var i, hash, + bkey = rstr2binl(key), + ipad = Array(16), + opad = Array(16); -exports.catch = function(cb) { - return this.then(undefined, cb); -}; + if (bkey.length > 16) { + bkey = binl(bkey, key.length * 8); + } -/** - * Allow for extension - */ + for (i = 0; i < 16; i += 1) { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8); + return binl2rstr(binl(opad.concat(hash), 512 + 160)); + } -exports.use = function use(fn) { - fn(this); - return this; -} + /** + * Convert an array of little-endian words to a string + */ + function binl2rstr(input) { + var i, output = '', + l = input.length * 32; + for (i = 0; i < l; i += 8) { + output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF); + } + return output; + } -/** - * Get request header `field`. - * Case-insensitive. - * - * @param {String} field - * @return {String} - * @api public - */ + /** + * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length. + */ -exports.get = function(field){ - return this._header[field.toLowerCase()]; -}; + function binl(x, len) { + var T, j, i, l, + h0 = 0x67452301, + h1 = 0xefcdab89, + h2 = 0x98badcfe, + h3 = 0x10325476, + h4 = 0xc3d2e1f0, + A1, B1, C1, D1, E1, + A2, B2, C2, D2, E2; -/** - * Get case-insensitive header `field` value. - * This is a deprecated internal API. Use `.get(field)` instead. - * - * (getHeader is no longer used internally by the superagent code base) - * - * @param {String} field - * @return {String} - * @api private - * @deprecated - */ + /* append padding */ + x[len >> 5] |= 0x80 << (len % 32); + x[(((len + 64) >>> 9) << 4) + 14] = len; + l = x.length; -exports.getHeader = exports.get; + for (i = 0; i < l; i += 16) { + A1 = A2 = h0; + B1 = B2 = h1; + C1 = C2 = h2; + D1 = D2 = h3; + E1 = E2 = h4; + for (j = 0; j <= 79; j += 1) { + T = safe_add(A1, rmd160_f(j, B1, C1, D1)); + T = safe_add(T, x[i + rmd160_r1[j]]); + T = safe_add(T, rmd160_K1(j)); + T = safe_add(bit_rol(T, rmd160_s1[j]), E1); + A1 = E1; + E1 = D1; + D1 = bit_rol(C1, 10); + C1 = B1; + B1 = T; + T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2)); + T = safe_add(T, x[i + rmd160_r2[j]]); + T = safe_add(T, rmd160_K2(j)); + T = safe_add(bit_rol(T, rmd160_s2[j]), E2); + A2 = E2; + E2 = D2; + D2 = bit_rol(C2, 10); + C2 = B2; + B2 = T; + } -/** - * Set header `field` to `val`, or multiple fields with one object. - * Case-insensitive. - * - * Examples: - * - * req.get('/') - * .set('Accept', 'application/json') - * .set('X-API-Key', 'foobar') - * .end(callback); - * - * req.get('/') - * .set({ Accept: 'application/json', 'X-API-Key': 'foobar' }) - * .end(callback); - * - * @param {String|Object} field - * @param {String} val - * @return {Request} for chaining - * @api public - */ + T = safe_add(h1, safe_add(C1, D2)); + h1 = safe_add(h2, safe_add(D1, E2)); + h2 = safe_add(h3, safe_add(E1, A2)); + h3 = safe_add(h4, safe_add(A1, B2)); + h4 = safe_add(h0, safe_add(B1, C2)); + h0 = T; + } + return [h0, h1, h2, h3, h4]; + } -exports.set = function(field, val){ - if (isObject(field)) { - for (var key in field) { - this.set(key, field[key]); - } - return this; - } - this._header[field.toLowerCase()] = val; - this.header[field] = val; - return this; -}; + // specific algorithm methods -/** - * Remove header `field`. - * Case-insensitive. - * - * Example: - * - * req.get('/') - * .unset('User-Agent') - * .end(callback); - * - * @param {String} field - */ -exports.unset = function(field){ - delete this._header[field.toLowerCase()]; - delete this.header[field]; - return this; -}; + function rmd160_f(j, x, y, z) { + return (0 <= j && j <= 15) ? (x ^ y ^ z) : + (16 <= j && j <= 31) ? (x & y) | (~x & z) : + (32 <= j && j <= 47) ? (x | ~y) ^ z : + (48 <= j && j <= 63) ? (x & z) | (y & ~z) : + (64 <= j && j <= 79) ? x ^ (y | ~z) : + 'rmd160_f: j out of range'; + } -/** - * Write the field `name` and `val`, or multiple fields with one object - * for "multipart/form-data" request bodies. - * - * ``` js - * request.post('/upload') - * .field('foo', 'bar') - * .end(callback); - * - * request.post('/upload') - * .field({ foo: 'bar', baz: 'qux' }) - * .end(callback); - * ``` - * - * @param {String|Object} name - * @param {String|Blob|File|Buffer|fs.ReadStream} val - * @return {Request} for chaining - * @api public - */ -exports.field = function(name, val) { + function rmd160_K1(j) { + return (0 <= j && j <= 15) ? 0x00000000 : + (16 <= j && j <= 31) ? 0x5a827999 : + (32 <= j && j <= 47) ? 0x6ed9eba1 : + (48 <= j && j <= 63) ? 0x8f1bbcdc : + (64 <= j && j <= 79) ? 0xa953fd4e : + 'rmd160_K1: j out of range'; + } - // name should be either a string or an object. - if (null === name || undefined === name) { - throw new Error('.field(name, val) name can not be empty'); - } + function rmd160_K2(j) { + return (0 <= j && j <= 15) ? 0x50a28be6 : + (16 <= j && j <= 31) ? 0x5c4dd124 : + (32 <= j && j <= 47) ? 0x6d703ef3 : + (48 <= j && j <= 63) ? 0x7a6d76e9 : + (64 <= j && j <= 79) ? 0x00000000 : + 'rmd160_K2: j out of range'; + } + } + }; - if (isObject(name)) { - for (var key in name) { - this.field(key, name[key]); + // exposes Hashes + (function(window, undefined) { + var freeExports = false; + if (typeof exports === 'object') { + freeExports = exports; + if (exports && typeof global === 'object' && global && global === global.global) { + window = global; + } } - return this; - } - // val should be defined now - if (null === val || undefined === val) { - throw new Error('.field(name, val) val can not be empty'); - } - this._getFormData().append(name, val); - return this; -}; + if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) { + // define as an anonymous module, so, through path mapping, it can be aliased + define(function() { + return Hashes; + }); + } else if (freeExports) { + // in Node.js or RingoJS v0.8.0+ + if (typeof module === 'object' && module && module.exports === freeExports) { + module.exports = Hashes; + } + // in Narwhal or RingoJS v0.7.0- + else { + freeExports.Hashes = Hashes; + } + } else { + // in a browser or Rhino + window.Hashes = Hashes; + } + }(this)); +}()); // IIFE +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],3:[function(_dereq_,module,exports){ /** - * Abort the request, and clear potential timeout. - * - * @return {Request} - * @api public + * Root reference for iframes. */ -exports.abort = function(){ - if (this._aborted) { - return this; - } - this._aborted = true; - this.xhr && this.xhr.abort(); // browser - this.req && this.req.abort(); // node - this.clearTimeout(); - this.emit('abort'); - return this; -}; + +var root; +if (typeof window !== 'undefined') { // Browser window + root = window; +} else if (typeof self !== 'undefined') { // Web Worker + root = self; +} else { // Other environments + console.warn("Using browser-only version of superagent in non-browser environment"); + root = this; +} + +var Emitter = _dereq_('component-emitter'); +var RequestBase = _dereq_('./request-base'); +var isObject = _dereq_('./is-object'); +var isFunction = _dereq_('./is-function'); +var ResponseBase = _dereq_('./response-base'); +var shouldRetry = _dereq_('./should-retry'); /** - * Enable transmission of cookies with x-domain requests. - * - * Note that for this to work the origin must not be - * using "Access-Control-Allow-Origin" with a wildcard, - * and also must set "Access-Control-Allow-Credentials" - * to "true". - * - * @api public + * Noop. */ -exports.withCredentials = function(){ - // This is browser-only functionality. Node side is no-op. - this._withCredentials = true; - return this; -}; +function noop(){}; /** - * Set the max redirects to `n`. Does noting in browser XHR implementation. - * - * @param {Number} n - * @return {Request} for chaining - * @api public + * Expose `request`. */ -exports.redirects = function(n){ - this._maxRedirects = n; - return this; -}; +var request = exports = module.exports = function(method, url) { + // callback + if ('function' == typeof url) { + return new exports.Request('GET', method).end(url); + } + + // url first + if (1 == arguments.length) { + return new exports.Request('GET', method); + } + + return new exports.Request(method, url); +} + +exports.Request = Request; /** - * Convert to a plain javascript object (not JSON string) of scalar properties. - * Note as this method is designed to return a useful non-this value, - * it cannot be chained. - * - * @return {Object} describing method, url, and data of this request - * @api public + * Determine XHR. */ -exports.toJSON = function(){ - return { - method: this.method, - url: this.url, - data: this._data, - headers: this._header - }; +request.getXHR = function () { + if (root.XMLHttpRequest + && (!root.location || 'file:' != root.location.protocol + || !root.ActiveXObject)) { + return new XMLHttpRequest; + } else { + try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {} + try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {} + try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {} + try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {} + } + throw Error("Browser-only verison of superagent could not find XHR"); }; /** - * Check if `obj` is a host object, - * we don't want to serialize these :) - * - * TODO: future proof, move to compoent land + * Removes leading and trailing whitespace, added to support IE. * - * @param {Object} obj - * @return {Boolean} + * @param {String} s + * @return {String} * @api private */ -exports._isHost = function _isHost(obj) { - var str = {}.toString.call(obj); - - switch (str) { - case '[object File]': - case '[object Blob]': - case '[object FormData]': - return true; - default: - return false; - } -} +var trim = ''.trim + ? function(s) { return s.trim(); } + : function(s) { return s.replace(/(^\s*|\s*$)/g, ''); }; /** - * Send `data` as the request body, defaulting the `.type()` to "json" when - * an object is given. - * - * Examples: - * - * // manual json - * request.post('/user') - * .type('json') - * .send('{"name":"tj"}') - * .end(callback) - * - * // auto json - * request.post('/user') - * .send({ name: 'tj' }) - * .end(callback) - * - * // manual x-www-form-urlencoded - * request.post('/user') - * .type('form') - * .send('name=tj') - * .end(callback) - * - * // auto x-www-form-urlencoded - * request.post('/user') - * .type('form') - * .send({ name: 'tj' }) - * .end(callback) - * - * // defaults to x-www-form-urlencoded - * request.post('/user') - * .send('name=tobi') - * .send('species=ferret') - * .end(callback) + * Serialize the given `obj`. * - * @param {String|Object} data - * @return {Request} for chaining - * @api public + * @param {Object} obj + * @return {String} + * @api private */ -exports.send = function(data){ - var obj = isObject(data); - var type = this._header['content-type']; - - // merge - if (obj && isObject(this._data)) { - for (var key in data) { - this._data[key] = data[key]; - } - } else if ('string' == typeof data) { - // default to x-www-form-urlencoded - if (!type) this.type('form'); - type = this._header['content-type']; - if ('application/x-www-form-urlencoded' == type) { - this._data = this._data - ? this._data + '&' + data - : data; - } else { - this._data = (this._data || '') + data; - } - } else { - this._data = data; +function serialize(obj) { + if (!isObject(obj)) return obj; + var pairs = []; + for (var key in obj) { + pushEncodedKeyValuePair(pairs, key, obj[key]); } + return pairs.join('&'); +} - if (!obj || this._isHost(data)) return this; - - // default to json - if (!type) this.type('json'); - return this; -}; - -},{"./is-object":3}],5:[function(_dereq_,module,exports){ -// The node and browser modules expose versions of this with the -// appropriate constructor function bound as first argument /** - * Issue a request: - * - * Examples: - * - * request('GET', '/users').end(callback) - * request('/users').end(callback) - * request('/users', callback) + * Helps 'serialize' with serializing arrays. + * Mutates the pairs array. * - * @param {String} method - * @param {String|Function} url or callback - * @return {Request} - * @api public + * @param {Array} pairs + * @param {String} key + * @param {Mixed} val */ -function request(RequestConstructor, method, url) { - // callback - if ('function' == typeof url) { - return new RequestConstructor('GET', method).end(url); +function pushEncodedKeyValuePair(pairs, key, val) { + if (val != null) { + if (Array.isArray(val)) { + val.forEach(function(v) { + pushEncodedKeyValuePair(pairs, key, v); + }); + } else if (isObject(val)) { + for(var subkey in val) { + pushEncodedKeyValuePair(pairs, key + '[' + subkey + ']', val[subkey]); + } + } else { + pairs.push(encodeURIComponent(key) + + '=' + encodeURIComponent(val)); + } + } else if (val === null) { + pairs.push(encodeURIComponent(key)); } +} - // url first - if (2 == arguments.length) { - return new RequestConstructor('GET', method); - } +/** + * Expose serialization method. + */ - return new RequestConstructor(method, url); -} + request.serializeObject = serialize; -module.exports = request; + /** + * Parse the given x-www-form-urlencoded `str`. + * + * @param {String} str + * @return {Object} + * @api private + */ -},{}],6:[function(_dereq_,module,exports){ -'use strict'; +function parseString(str) { + var obj = {}; + var pairs = str.split('&'); + var pair; + var pos; -// wikipedia special terms lifted and augmented from parsoid parser april 2015 -// (not even close to being complete) -var i18n = { - 'files': ['файл', 'fitxer', 'soubor', 'datei', 'file', 'archivo', 'پرونده', 'tiedosto', 'mynd', 'su\'wret', 'fichier', 'bestand', 'датотека', 'dosya', 'fil'], - 'images': ['image'], - 'templates': ['шаблён', 'plantilla', 'šablona', 'vorlage', 'template', 'الگو', 'malline', 'snið', 'shablon', 'modèle', 'sjabloon', 'шаблон', 'şablon'], - 'categories': ['катэгорыя', 'categoria', 'kategorie', 'category', 'categoría', 'رده', 'luokka', 'flokkur', 'kategoriya', 'catégorie', 'categorie', 'категорија', 'kategori', 'kategoria', 'تصنيف'], - 'redirects': ['перанакіраваньне', 'redirect', 'přesměruj', 'weiterleitung', 'redirección', 'redireccion', 'تغییر_مسیر', 'تغییرمسیر', 'ohjaus', 'uudelleenohjaus', 'tilvísun', 'aýdaw', 'айдау', 'redirection', 'doorverwijzing', 'преусмери', 'преусмјери', 'yönlendi̇rme', 'yönlendi̇r', '重定向', 'redirección', 'redireccion', '重定向', 'yönlendirm?e?', 'تغییر_مسیر', 'تغییرمسیر', 'перанакіраваньне', 'yönlendirme'], - 'specials': ['спэцыяльныя', 'especial', 'speciální', 'spezial', 'special', 'ویژه', 'toiminnot', 'kerfissíða', 'arnawlı', 'spécial', 'speciaal', 'посебно', 'özel'], - 'users': ['удзельнік', 'usuari', 'uživatel', 'benutzer', 'user', 'usuario', 'کاربر', 'käyttäjä', 'notandi', 'paydalanıwshı', 'utilisateur', 'gebruiker', 'корисник', 'kullanıcı'], - 'disambigs': ['disambig', //en - 'disambiguation', //en - 'dab', //en - 'disamb', //en - 'begriffsklärung', //de - 'ujednoznacznienie', //pl - 'doorverwijspagina', //nl - '消歧义', //zh - 'desambiguación', //es - 'dubbelsinnig', //af - 'disambigua', //it - 'desambiguação', //pt - 'homonymie', //fr - 'неоднозначность', //ru - 'anlam ayrımı' //tr - ], - 'infoboxes': ['infobox', 'ficha', 'канадский', 'inligtingskas', 'inligtingskas3', //af - 'لغة', 'bilgi kutusu', //tr - 'yerleşim bilgi kutusu', 'infoboks' //nn, no - ], - 'sources': [//blacklist these headings, as they're not plain-text - 'references', 'see also', 'external links', 'further reading', 'notes et références', 'voir aussi', 'liens externes'] -}; + for (var i = 0, len = pairs.length; i < len; ++i) { + pair = pairs[i]; + pos = pair.indexOf('='); + if (pos == -1) { + obj[decodeURIComponent(pair)] = ''; + } else { + obj[decodeURIComponent(pair.slice(0, pos))] = + decodeURIComponent(pair.slice(pos + 1)); + } + } -if (typeof module !== 'undefined' && module.exports) { - module.exports = i18n; + return obj; } -},{}],7:[function(_dereq_,module,exports){ -'use strict'; +/** + * Expose parser. + */ -module.exports = { - 'aa': { - 'english_title': 'Afar', - 'direction': 'ltr', - 'local_title': 'Afar' - }, - 'ab': { - 'english_title': 'Abkhazian', - 'direction': 'ltr', - 'local_title': 'Аҧсуа' - }, - 'af': { - 'english_title': 'Afrikaans', - 'direction': 'ltr', - 'local_title': 'Afrikaans' - }, - 'ak': { - 'english_title': 'Akan', - 'direction': 'ltr', - 'local_title': 'Akana' - }, - 'als': { - 'english_title': 'Alemannic', - 'direction': 'ltr', - 'local_title': 'Alemannisch' - }, - 'am': { - 'english_title': 'Amharic', - 'direction': 'ltr', - 'local_title': 'አማርኛ' - }, - 'an': { - 'english_title': 'Aragonese', - 'direction': 'ltr', - 'local_title': 'Aragonés' - }, - 'ang': { - 'english_title': 'Anglo-Saxon', - 'direction': 'ltr', - 'local_title': 'Englisc' - }, - 'ar': { - 'english_title': 'Arabic', - 'direction': 'rtl', - 'local_title': 'العربية' - }, - 'arc': { - 'english_title': 'Aramaic', - 'direction': 'rtl', - 'local_title': 'ܣܘܪܬ' - }, - 'as': { - 'english_title': 'Assamese', - 'direction': 'ltr', - 'local_title': 'অসমীয়া' - }, - 'ast': { - 'english_title': 'Asturian', - 'direction': 'ltr', - 'local_title': 'Asturianu' - }, - 'av': { - 'english_title': 'Avar', - 'direction': 'ltr', - 'local_title': 'Авар' - }, - 'ay': { - 'english_title': 'Aymara', - 'direction': 'ltr', - 'local_title': 'Aymar' - }, - 'az': { - 'english_title': 'Azerbaijani', - 'direction': 'ltr', - 'local_title': 'Azərbaycanca' - }, - 'ba': { - 'english_title': 'Bashkir', - 'direction': 'ltr', - 'local_title': 'Башҡорт' - }, - 'bar': { - 'english_title': 'Bavarian', - 'direction': 'ltr', - 'local_title': 'Boarisch' - }, - 'bat-smg': { - 'english_title': 'Samogitian', - 'direction': 'ltr', - 'local_title': 'Žemaitėška' - }, - 'bcl': { - 'english_title': 'Bikol', - 'direction': 'ltr', - 'local_title': 'Bikol' - }, - 'be': { - 'english_title': 'Belarusian', - 'direction': 'ltr', - 'local_title': 'Беларуская' - }, - 'be-x-old': { - 'english_title': 'Belarusian', - 'direction': '(Taraškievica)', - 'local_title': 'ltr' - }, - 'bg': { - 'english_title': 'Bulgarian', - 'direction': 'ltr', - 'local_title': 'Български' - }, - 'bh': { - 'english_title': 'Bihari', - 'direction': 'ltr', - 'local_title': 'भोजपुरी' - }, - 'bi': { - 'english_title': 'Bislama', - 'direction': 'ltr', - 'local_title': 'Bislama' - }, - 'bm': { - 'english_title': 'Bambara', - 'direction': 'ltr', - 'local_title': 'Bamanankan' - }, - 'bn': { - 'english_title': 'Bengali', - 'direction': 'ltr', - 'local_title': 'বাংলা' - }, - 'bo': { - 'english_title': 'Tibetan', - 'direction': 'ltr', - 'local_title': 'བོད་ཡིག' - }, - 'bpy': { - 'english_title': 'Bishnupriya', - 'direction': 'Manipuri', - 'local_title': 'ltr' - }, - 'br': { - 'english_title': 'Breton', - 'direction': 'ltr', - 'local_title': 'Brezhoneg' - }, - 'bs': { - 'english_title': 'Bosnian', - 'direction': 'ltr', - 'local_title': 'Bosanski' - }, - 'bug': { - 'english_title': 'Buginese', - 'direction': 'ltr', - 'local_title': 'ᨅᨔ' - }, - 'bxr': { - 'english_title': 'Buriat', - 'direction': '(Russia)', - 'local_title': 'ltr' - }, - 'ca': { - 'english_title': 'Catalan', - 'direction': 'ltr', - 'local_title': 'Català' - }, - 'cdo': { - 'english_title': 'Min', - 'direction': 'Dong', - 'local_title': 'Chinese' - }, - 'ce': { - 'english_title': 'Chechen', - 'direction': 'ltr', - 'local_title': 'Нохчийн' - }, - 'ceb': { - 'english_title': 'Cebuano', - 'direction': 'ltr', - 'local_title': 'Sinugboanong' - }, - 'ch': { - 'english_title': 'Chamorro', - 'direction': 'ltr', - 'local_title': 'Chamoru' - }, - 'cho': { - 'english_title': 'Choctaw', - 'direction': 'ltr', - 'local_title': 'Choctaw' - }, - 'chr': { - 'english_title': 'Cherokee', - 'direction': 'ltr', - 'local_title': 'ᏣᎳᎩ' - }, - 'chy': { - 'english_title': 'Cheyenne', - 'direction': 'ltr', - 'local_title': 'Tsetsêhestâhese' - }, - 'co': { - 'english_title': 'Corsican', - 'direction': 'ltr', - 'local_title': 'Corsu' - }, - 'cr': { - 'english_title': 'Cree', - 'direction': 'ltr', - 'local_title': 'Nehiyaw' - }, - 'cs': { - 'english_title': 'Czech', - 'direction': 'ltr', - 'local_title': 'Česky' - }, - 'csb': { - 'english_title': 'Kashubian', - 'direction': 'ltr', - 'local_title': 'Kaszëbsczi' - }, - 'cu': { - 'english_title': 'Old', - 'direction': 'Church', - 'local_title': 'Slavonic' - }, - 'cv': { - 'english_title': 'Chuvash', - 'direction': 'ltr', - 'local_title': 'Чăваш' - }, - 'cy': { - 'english_title': 'Welsh', - 'direction': 'ltr', - 'local_title': 'Cymraeg' - }, - 'da': { - 'english_title': 'Danish', - 'direction': 'ltr', - 'local_title': 'Dansk' - }, - 'de': { - 'english_title': 'German', - 'direction': 'ltr', - 'local_title': 'Deutsch' - }, - 'diq': { - 'english_title': 'Dimli', - 'direction': 'ltr', - 'local_title': 'Zazaki' - }, - 'dsb': { - 'english_title': 'Lower', - 'direction': 'Sorbian', - 'local_title': 'ltr' - }, - 'dv': { - 'english_title': 'Divehi', - 'direction': 'rtl', - 'local_title': 'ދިވެހިބަސް' - }, - 'dz': { - 'english_title': 'Dzongkha', - 'direction': 'ltr', - 'local_title': 'ཇོང་ཁ' - }, - 'ee': { - 'english_title': 'Ewe', - 'direction': 'ltr', - 'local_title': 'Ɛʋɛ' - }, - 'far': { - 'english_title': 'Farsi', - 'direction': 'ltr', - 'local_title': 'فارسی' - }, - 'el': { - 'english_title': 'Greek', - 'direction': 'ltr', - 'local_title': 'Ελληνικά' - }, - 'en': { - 'english_title': 'English', - 'direction': 'ltr', - 'local_title': 'English' - }, - 'eo': { - 'english_title': 'Esperanto', - 'direction': 'ltr', - 'local_title': 'Esperanto' - }, - 'es': { - 'english_title': 'Spanish', - 'direction': 'ltr', - 'local_title': 'Español' - }, - 'et': { - 'english_title': 'Estonian', - 'direction': 'ltr', - 'local_title': 'Eesti' - }, - 'eu': { - 'english_title': 'Basque', - 'direction': 'ltr', - 'local_title': 'Euskara' - }, - 'ext': { - 'english_title': 'Extremaduran', - 'direction': 'ltr', - 'local_title': 'Estremeñu' - }, - 'ff': { - 'english_title': 'Peul', - 'direction': 'ltr', - 'local_title': 'Fulfulde' - }, - 'fi': { - 'english_title': 'Finnish', - 'direction': 'ltr', - 'local_title': 'Suomi' - }, - 'fiu-vro': { - 'english_title': 'Võro', - 'direction': 'ltr', - 'local_title': 'Võro' - }, - 'fj': { - 'english_title': 'Fijian', - 'direction': 'ltr', - 'local_title': 'Na' - }, - 'fo': { - 'english_title': 'Faroese', - 'direction': 'ltr', - 'local_title': 'Føroyskt' - }, - 'fr': { - 'english_title': 'French', - 'direction': 'ltr', - 'local_title': 'Français' - }, - 'frp': { - 'english_title': 'Arpitan', - 'direction': 'ltr', - 'local_title': 'Arpitan' - }, - 'fur': { - 'english_title': 'Friulian', - 'direction': 'ltr', - 'local_title': 'Furlan' - }, - 'fy': { - 'english_title': 'West', - 'direction': 'Frisian', - 'local_title': 'ltr' - }, - 'ga': { - 'english_title': 'Irish', - 'direction': 'ltr', - 'local_title': 'Gaeilge' - }, - 'gan': { - 'english_title': 'Gan', - 'direction': 'Chinese', - 'local_title': 'ltr' - }, - 'gd': { - 'english_title': 'Scottish', - 'direction': 'Gaelic', - 'local_title': 'ltr' - }, - 'gil': { - 'english_title': 'Gilbertese', - 'direction': 'ltr', - 'local_title': 'Taetae' - }, - 'gl': { - 'english_title': 'Galician', - 'direction': 'ltr', - 'local_title': 'Galego' - }, - 'gn': { - 'english_title': 'Guarani', - 'direction': 'ltr', - 'local_title': 'Avañe\'ẽ' - }, - 'got': { - 'english_title': 'Gothic', - 'direction': 'ltr', - 'local_title': 'gutisk' - }, - 'gu': { - 'english_title': 'Gujarati', - 'direction': 'ltr', - 'local_title': 'ગુજરાતી' - }, - 'gv': { - 'english_title': 'Manx', - 'direction': 'ltr', - 'local_title': 'Gaelg' - }, - 'ha': { - 'english_title': 'Hausa', - 'direction': 'rtl', - 'local_title': 'هَوُسَ' - }, - 'hak': { - 'english_title': 'Hakka', - 'direction': 'Chinese', - 'local_title': 'ltr' - }, - 'haw': { - 'english_title': 'Hawaiian', - 'direction': 'ltr', - 'local_title': 'Hawai`i' - }, - 'he': { - 'english_title': 'Hebrew', - 'direction': 'rtl', - 'local_title': 'עברית' - }, - 'hi': { - 'english_title': 'Hindi', - 'direction': 'ltr', - 'local_title': 'हिन्दी' - }, - 'ho': { - 'english_title': 'Hiri', - 'direction': 'Motu', - 'local_title': 'ltr' - }, - 'hr': { - 'english_title': 'Croatian', - 'direction': 'ltr', - 'local_title': 'Hrvatski' - }, - 'ht': { - 'english_title': 'Haitian', - 'direction': 'ltr', - 'local_title': 'Krèyol' - }, - 'hu': { - 'english_title': 'Hungarian', - 'direction': 'ltr', - 'local_title': 'Magyar' - }, - 'hy': { - 'english_title': 'Armenian', - 'direction': 'ltr', - 'local_title': 'Հայերեն' - }, - 'hz': { - 'english_title': 'Herero', - 'direction': 'ltr', - 'local_title': 'Otsiherero' - }, - 'ia': { - 'english_title': 'Interlingua', - 'direction': 'ltr', - 'local_title': 'Interlingua' - }, - 'id': { - 'english_title': 'Indonesian', - 'direction': 'ltr', - 'local_title': 'Bahasa' - }, - 'ie': { - 'english_title': 'Interlingue', - 'direction': 'ltr', - 'local_title': 'Interlingue' - }, - 'ig': { - 'english_title': 'Igbo', - 'direction': 'ltr', - 'local_title': 'Igbo' - }, - 'ii': { - 'english_title': 'Sichuan', - 'direction': 'Yi', - 'local_title': 'ltr' - }, - 'ik': { - 'english_title': 'Inupiak', - 'direction': 'ltr', - 'local_title': 'Iñupiak' - }, - 'ilo': { - 'english_title': 'Ilokano', - 'direction': 'ltr', - 'local_title': 'Ilokano' - }, - 'io': { - 'english_title': 'Ido', - 'direction': 'ltr', - 'local_title': 'Ido' - }, - 'is': { - 'english_title': 'Icelandic', - 'direction': 'ltr', - 'local_title': 'Íslenska' - }, - 'it': { - 'english_title': 'Italian', - 'direction': 'ltr', - 'local_title': 'Italiano' - }, - 'iu': { - 'english_title': 'Inuktitut', - 'direction': 'ltr', - 'local_title': 'ᐃᓄᒃᑎᑐᑦ' - }, - 'ja': { - 'english_title': 'Japanese', - 'direction': 'ltr', - 'local_title': '日本語' - }, - 'jbo': { - 'english_title': 'Lojban', - 'direction': 'ltr', - 'local_title': 'Lojban' - }, - 'jv': { - 'english_title': 'Javanese', - 'direction': 'ltr', - 'local_title': 'Basa' - }, - 'ka': { - 'english_title': 'Georgian', - 'direction': 'ltr', - 'local_title': 'ქართული' - }, - 'kg': { - 'english_title': 'Kongo', - 'direction': 'ltr', - 'local_title': 'KiKongo' - }, - 'ki': { - 'english_title': 'Kikuyu', - 'direction': 'ltr', - 'local_title': 'Gĩkũyũ' - }, - 'kj': { - 'english_title': 'Kuanyama', - 'direction': 'ltr', - 'local_title': 'Kuanyama' - }, - 'kk': { - 'english_title': 'Kazakh', - 'direction': 'ltr', - 'local_title': 'Қазақша' - }, - 'kl': { - 'english_title': 'Greenlandic', - 'direction': 'ltr', - 'local_title': 'Kalaallisut' - }, - 'km': { - 'english_title': 'Cambodian', - 'direction': 'ltr', - 'local_title': 'ភាសាខ្មែរ' - }, - 'kn': { - 'english_title': 'Kannada', - 'direction': 'ltr', - 'local_title': 'ಕನ್ನಡ' - }, - 'khw': { - 'english_title': 'Khowar', - 'direction': 'rtl', - 'local_title': 'کھوار' - }, - 'ko': { - 'english_title': 'Korean', - 'direction': 'ltr', - 'local_title': '한국어' - }, - 'kr': { - 'english_title': 'Kanuri', - 'direction': 'ltr', - 'local_title': 'Kanuri' - }, - 'ks': { - 'english_title': 'Kashmiri', - 'direction': 'rtl', - 'local_title': 'कश्मीरी' - }, - 'ksh': { - 'english_title': 'Ripuarian', - 'direction': 'ltr', - 'local_title': 'Ripoarisch' - }, - 'ku': { - 'english_title': 'Kurdish', - 'direction': 'rtl', - 'local_title': 'Kurdî' - }, - 'kv': { - 'english_title': 'Komi', - 'direction': 'ltr', - 'local_title': 'Коми' - }, - 'kw': { - 'english_title': 'Cornish', - 'direction': 'ltr', - 'local_title': 'Kernewek' - }, - 'ky': { - 'english_title': 'Kirghiz', - 'direction': 'ltr', - 'local_title': 'Kırgızca' - }, - 'la': { - 'english_title': 'Latin', - 'direction': 'ltr', - 'local_title': 'Latina' - }, - 'lad': { - 'english_title': 'Ladino', - 'direction': 'ltr', - 'local_title': 'Dzhudezmo' - }, - 'lan': { - 'english_title': 'Lango', - 'direction': 'ltr', - 'local_title': 'Leb' - }, - 'lb': { - 'english_title': 'Luxembourgish', - 'direction': 'ltr', - 'local_title': 'Lëtzebuergesch' - }, - 'lg': { - 'english_title': 'Ganda', - 'direction': 'ltr', - 'local_title': 'Luganda' - }, - 'li': { - 'english_title': 'Limburgian', - 'direction': 'ltr', - 'local_title': 'Limburgs' - }, - 'lij': { - 'english_title': 'Ligurian', - 'direction': 'ltr', - 'local_title': 'Líguru' - }, - 'lmo': { - 'english_title': 'Lombard', - 'direction': 'ltr', - 'local_title': 'Lumbaart' - }, - 'ln': { - 'english_title': 'Lingala', - 'direction': 'ltr', - 'local_title': 'Lingála' - }, - 'lo': { - 'english_title': 'Laotian', - 'direction': 'ltr', - 'local_title': 'ລາວ' - }, - 'lt': { - 'english_title': 'Lithuanian', - 'direction': 'ltr', - 'local_title': 'Lietuvių' - }, - 'lv': { - 'english_title': 'Latvian', - 'direction': 'ltr', - 'local_title': 'Latviešu' - }, - 'map-bms': { - 'english_title': 'Banyumasan', - 'direction': 'ltr', - 'local_title': 'Basa' - }, - 'mg': { - 'english_title': 'Malagasy', - 'direction': 'ltr', - 'local_title': 'Malagasy' - }, - 'man': { - 'english_title': 'Mandarin', - 'direction': 'ltr', - 'local_title': '官話' - }, - 'mh': { - 'english_title': 'Marshallese', - 'direction': 'ltr', - 'local_title': 'Kajin' - }, - 'mi': { - 'english_title': 'Maori', - 'direction': 'ltr', - 'local_title': 'Māori' - }, - 'min': { - 'english_title': 'Minangkabau', - 'direction': 'ltr', - 'local_title': 'Minangkabau' - }, - 'mk': { - 'english_title': 'Macedonian', - 'direction': 'ltr', - 'local_title': 'Македонски' - }, - 'ml': { - 'english_title': 'Malayalam', - 'direction': 'ltr', - 'local_title': 'മലയാളം' - }, - 'mn': { - 'english_title': 'Mongolian', - 'direction': 'ltr', - 'local_title': 'Монгол' - }, - 'mo': { - 'english_title': 'Moldovan', - 'direction': 'ltr', - 'local_title': 'Moldovenească' - }, - 'mr': { - 'english_title': 'Marathi', - 'direction': 'ltr', - 'local_title': 'मराठी' - }, - 'ms': { - 'english_title': 'Malay', - 'direction': 'ltr', - 'local_title': 'Bahasa' - }, - 'mt': { - 'english_title': 'Maltese', - 'direction': 'ltr', - 'local_title': 'bil-Malti' - }, - 'mus': { - 'english_title': 'Creek', - 'direction': 'ltr', - 'local_title': 'Muskogee' - }, - 'my': { - 'english_title': 'Burmese', - 'direction': 'ltr', - 'local_title': 'Myanmasa' - }, - 'na': { - 'english_title': 'Nauruan', - 'direction': 'ltr', - 'local_title': 'Dorerin' - }, - 'nah': { - 'english_title': 'Nahuatl', - 'direction': 'ltr', - 'local_title': 'Nahuatl' - }, - 'nap': { - 'english_title': 'Neapolitan', - 'direction': 'ltr', - 'local_title': 'Nnapulitano' - }, - 'nd': { - 'english_title': 'North', - 'direction': 'Ndebele', - 'local_title': 'ltr' - }, - 'nds': { - 'english_title': 'Low German', - 'direction': 'ltr', - 'local_title': 'Plattdüütsch' - }, - 'nds-nl': { - 'english_title': 'Dutch', - 'direction': 'Low', - 'local_title': 'Saxon' - }, - 'ne': { - 'english_title': 'Nepali', - 'direction': 'ltr', - 'local_title': 'नेपाली' - }, - 'new': { - 'english_title': 'Newar', - 'direction': 'ltr', - 'local_title': 'नेपालभाषा' - }, - 'ng': { - 'english_title': 'Ndonga', - 'direction': 'ltr', - 'local_title': 'Oshiwambo' - }, - 'nl': { - 'english_title': 'Dutch', - 'direction': 'ltr', - 'local_title': 'Nederlands' - }, - 'nn': { - 'english_title': 'Norwegian', - 'direction': 'Nynorsk', - 'local_title': 'ltr' - }, - 'no': { - 'english_title': 'Norwegian', - 'direction': 'ltr', - 'local_title': 'Norsk' - }, - 'nr': { - 'english_title': 'South', - 'direction': 'Ndebele', - 'local_title': 'ltr' - }, - 'nso': { - 'english_title': 'Northern', - 'direction': 'Sotho', - 'local_title': 'ltr' - }, - 'nrm': { - 'english_title': 'Norman', - 'direction': 'ltr', - 'local_title': 'Nouormand' - }, - 'nv': { - 'english_title': 'Navajo', - 'direction': 'ltr', - 'local_title': 'Diné' - }, - 'ny': { - 'english_title': 'Chichewa', - 'direction': 'ltr', - 'local_title': 'Chi-Chewa' - }, - 'oc': { - 'english_title': 'Occitan', - 'direction': 'ltr', - 'local_title': 'Occitan' - }, - 'oj': { - 'english_title': 'Ojibwa', - 'direction': 'ltr', - 'local_title': 'ᐊᓂᔑᓈᐯᒧᐎᓐ' - }, - 'om': { - 'english_title': 'Oromo', - 'direction': 'ltr', - 'local_title': 'Oromoo' - }, - 'or': { - 'english_title': 'Oriya', - 'direction': 'ltr', - 'local_title': 'ଓଡ଼ିଆ' - }, - 'os': { - 'english_title': 'Ossetian', - 'direction': 'ltr', - 'local_title': 'Иронау' - }, - 'pa': { - 'english_title': 'Panjabi', - 'direction': 'ltr', - 'local_title': 'ਪੰਜਾਬੀ' - }, - 'pag': { - 'english_title': 'Pangasinan', - 'direction': 'ltr', - 'local_title': 'Pangasinan' - }, - 'pam': { - 'english_title': 'Kapampangan', - 'direction': 'ltr', - 'local_title': 'Kapampangan' - }, - 'pap': { - 'english_title': 'Papiamentu', - 'direction': 'ltr', - 'local_title': 'Papiamentu' - }, - 'pdc': { - 'english_title': 'Pennsylvania', - 'direction': 'German', - 'local_title': 'ltr' - }, - 'pi': { - 'english_title': 'Pali', - 'direction': 'ltr', - 'local_title': 'Pāli' - }, - 'pih': { - 'english_title': 'Norfolk', - 'direction': 'ltr', - 'local_title': 'Norfuk' - }, - 'pl': { - 'english_title': 'Polish', - 'direction': 'ltr', - 'local_title': 'Polski' - }, - 'pms': { - 'english_title': 'Piedmontese', - 'direction': 'ltr', - 'local_title': 'Piemontèis' - }, - 'ps': { - 'english_title': 'Pashto', - 'direction': 'rtl', - 'local_title': 'پښتو' - }, - 'pt': { - 'english_title': 'Portuguese', - 'direction': 'ltr', - 'local_title': 'Português' - }, - 'qu': { - 'english_title': 'Quechua', - 'direction': 'ltr', - 'local_title': 'Runa' - }, - 'rm': { - 'english_title': 'Raeto', - 'direction': 'Romance', - 'local_title': 'ltr' - }, - 'rmy': { - 'english_title': 'Romani', - 'direction': 'ltr', - 'local_title': 'Romani' - }, - 'rn': { - 'english_title': 'Kirundi', - 'direction': 'ltr', - 'local_title': 'Kirundi' - }, - 'ro': { - 'english_title': 'Romanian', - 'direction': 'ltr', - 'local_title': 'Română' - }, - 'roa-rup': { - 'english_title': 'Aromanian', - 'direction': 'ltr', - 'local_title': 'Armâneashti' - }, - 'ru': { - 'english_title': 'Russian', - 'direction': 'ltr', - 'local_title': 'Русский' - }, - 'rw': { - 'english_title': 'Rwandi', - 'direction': 'ltr', - 'local_title': 'Kinyarwandi' - }, - 'sa': { - 'english_title': 'Sanskrit', - 'direction': 'ltr', - 'local_title': 'संस्कृतम्' - }, - 'sc': { - 'english_title': 'Sardinian', - 'direction': 'ltr', - 'local_title': 'Sardu' - }, - 'scn': { - 'english_title': 'Sicilian', - 'direction': 'ltr', - 'local_title': 'Sicilianu' - }, - 'sco': { - 'english_title': 'Scots', - 'direction': 'ltr', - 'local_title': 'Scots' - }, - 'sd': { - 'english_title': 'Sindhi', - 'direction': 'ltr', - 'local_title': 'सिनधि' - }, - 'se': { - 'english_title': 'Northern', - 'direction': 'Sami', - 'local_title': 'ltr' - }, - 'sg': { - 'english_title': 'Sango', - 'direction': 'ltr', - 'local_title': 'Sängö' - }, - 'sh': { - 'english_title': 'Serbo-Croatian', - 'direction': 'ltr', - 'local_title': 'Srpskohrvatski' - }, - 'si': { - 'english_title': 'Sinhalese', - 'direction': 'ltr', - 'local_title': 'සිංහල' - }, - 'simple': { - 'english_title': 'Simple', - 'direction': 'English', - 'local_title': 'ltr' - }, - 'sk': { - 'english_title': 'Slovak', - 'direction': 'ltr', - 'local_title': 'Slovenčina' - }, - 'sl': { - 'english_title': 'Slovenian', - 'direction': 'ltr', - 'local_title': 'Slovenščina' - }, - 'sm': { - 'english_title': 'Samoan', - 'direction': 'ltr', - 'local_title': 'Gagana' - }, - 'sn': { - 'english_title': 'Shona', - 'direction': 'ltr', - 'local_title': 'chiShona' - }, - 'so': { - 'english_title': 'Somalia', - 'direction': 'ltr', - 'local_title': 'Soomaaliga' - }, - 'sq': { - 'english_title': 'Albanian', - 'direction': 'ltr', - 'local_title': 'Shqip' - }, - 'sr': { - 'english_title': 'Serbian', - 'direction': 'ltr', - 'local_title': 'Српски' - }, - 'ss': { - 'english_title': 'Swati', - 'direction': 'ltr', - 'local_title': 'SiSwati' - }, - 'st': { - 'english_title': 'Southern', - 'direction': 'Sotho', - 'local_title': 'ltr' - }, - 'su': { - 'english_title': 'Sundanese', - 'direction': 'ltr', - 'local_title': 'Basa' - }, - 'sv': { - 'english_title': 'Swedish', - 'direction': 'ltr', - 'local_title': 'Svenska' - }, - 'sw': { - 'english_title': 'Swahili', - 'direction': 'ltr', - 'local_title': 'Kiswahili' - }, - 'ta': { - 'english_title': 'Tamil', - 'direction': 'ltr', - 'local_title': 'தமிழ்' - }, - 'te': { - 'english_title': 'Telugu', - 'direction': 'ltr', - 'local_title': 'తెలుగు' - }, - 'tet': { - 'english_title': 'Tetum', - 'direction': 'ltr', - 'local_title': 'Tetun' - }, - 'tg': { - 'english_title': 'Tajik', - 'direction': 'ltr', - 'local_title': 'Тоҷикӣ' - }, - 'th': { - 'english_title': 'Thai', - 'direction': 'ltr', - 'local_title': 'ไทย' - }, - 'ti': { - 'english_title': 'Tigrinya', - 'direction': 'ltr', - 'local_title': 'ትግርኛ' - }, - 'tk': { - 'english_title': 'Turkmen', - 'direction': 'ltr', - 'local_title': 'Туркмен' - }, - 'tl': { - 'english_title': 'Tagalog', - 'direction': 'ltr', - 'local_title': 'Tagalog' - }, - 'tlh': { - 'english_title': 'Klingon', - 'direction': 'ltr', - 'local_title': 'tlhIngan-Hol' - }, - 'tn': { - 'english_title': 'Tswana', - 'direction': 'ltr', - 'local_title': 'Setswana' - }, - 'to': { - 'english_title': 'Tonga', - 'direction': 'ltr', - 'local_title': 'Lea' - }, - 'tpi': { - 'english_title': 'Tok', - 'direction': 'Pisin', - 'local_title': 'ltr' - }, - 'tr': { - 'english_title': 'Turkish', - 'direction': 'ltr', - 'local_title': 'Türkçe' - }, - 'ts': { - 'english_title': 'Tsonga', - 'direction': 'ltr', - 'local_title': 'Xitsonga' - }, - 'tt': { - 'english_title': 'Tatar', - 'direction': 'ltr', - 'local_title': 'Tatarça' - }, - 'tum': { - 'english_title': 'Tumbuka', - 'direction': 'ltr', - 'local_title': 'chiTumbuka' - }, - 'tw': { - 'english_title': 'Twi', - 'direction': 'ltr', - 'local_title': 'Twi' - }, - 'ty': { - 'english_title': 'Tahitian', - 'direction': 'ltr', - 'local_title': 'Reo' - }, - 'udm': { - 'english_title': 'Udmurt', - 'direction': 'ltr', - 'local_title': 'Удмурт' - }, - 'ug': { - 'english_title': 'Uyghur', - 'direction': 'ltr', - 'local_title': 'Uyƣurqə' - }, - 'uk': { - 'english_title': 'Ukrainian', - 'direction': 'ltr', - 'local_title': 'Українська' - }, - 'ur': { - 'english_title': 'Urdu', - 'direction': 'rtl', - 'local_title': 'اردو' - }, - 'uz': { - 'english_title': 'Uzbek', - 'direction': 'ltr', - 'local_title': 'Ўзбек' - }, - 've': { - 'english_title': 'Venda', - 'direction': 'ltr', - 'local_title': 'Tshivenḓa' - }, - 'vi': { - 'english_title': 'Vietnamese', - 'direction': 'ltr', - 'local_title': 'Việtnam' - }, - 'vec': { - 'english_title': 'Venetian', - 'direction': 'ltr', - 'local_title': 'Vèneto' - }, - 'vls': { - 'english_title': 'West', - 'direction': 'Flemish', - 'local_title': 'ltr' - }, - 'vo': { - 'english_title': 'Volapük', - 'direction': 'ltr', - 'local_title': 'Volapük' - }, - 'wa': { - 'english_title': 'Walloon', - 'direction': 'ltr', - 'local_title': 'Walon' - }, - 'war': { - 'english_title': 'Waray-Waray', - 'direction': 'ltr', - 'local_title': 'Winaray' - }, - 'wo': { - 'english_title': 'Wolof', - 'direction': 'ltr', - 'local_title': 'Wollof' - }, - 'xal': { - 'english_title': 'Kalmyk', - 'direction': 'ltr', - 'local_title': 'Хальмг' - }, - 'xh': { - 'english_title': 'Xhosa', - 'direction': 'ltr', - 'local_title': 'isiXhosa' - }, - 'yi': { - 'english_title': 'Yiddish', - 'direction': 'rtl', - 'local_title': 'ייִדיש' - }, - 'yo': { - 'english_title': 'Yoruba', - 'direction': 'ltr', - 'local_title': 'Yorùbá' - }, - 'za': { - 'english_title': 'Zhuang', - 'direction': 'ltr', - 'local_title': 'Cuengh' - }, - 'zh': { - 'english_title': 'Chinese', - 'direction': 'ltr', - 'local_title': '中文' - }, - 'zh-classical': { - 'english_title': 'Classical', - 'direction': 'Chinese', - 'local_title': 'ltr' - }, - 'zh-min-nan': { - 'english_title': 'Minnan', - 'direction': 'ltr', - 'local_title': 'Bân-lâm-gú' - }, - 'zh-yue': { - 'english_title': 'Cantonese', - 'direction': 'ltr', - 'local_title': '粵語' - }, - 'zu': { - 'english_title': 'Zulu', - 'direction': 'ltr', - 'local_title': 'isiZulu' - } -}; +request.parseString = parseString; -},{}],8:[function(_dereq_,module,exports){ -'use strict'; +/** + * Default MIME type map. + * + * superagent.types.xml = 'application/xml'; + * + */ -//from https://en.wikipedia.org/w/api.php?action=sitematrix&format=json -var site_map = { - 'aawiki': 'https://aa.wikipedia.org', - 'aawiktionary': 'https://aa.wiktionary.org', - 'aawikibooks': 'https://aa.wikibooks.org', - 'abwiki': 'https://ab.wikipedia.org', - 'abwiktionary': 'https://ab.wiktionary.org', - 'acewiki': 'https://ace.wikipedia.org', - 'afwiki': 'https://af.wikipedia.org', - 'afwiktionary': 'https://af.wiktionary.org', - 'afwikibooks': 'https://af.wikibooks.org', - 'afwikiquote': 'https://af.wikiquote.org', - 'akwiki': 'https://ak.wikipedia.org', - 'akwiktionary': 'https://ak.wiktionary.org', - 'akwikibooks': 'https://ak.wikibooks.org', - 'alswiki': 'https://als.wikipedia.org', - 'alswiktionary': 'https://als.wiktionary.org', - 'alswikibooks': 'https://als.wikibooks.org', - 'alswikiquote': 'https://als.wikiquote.org', - 'amwiki': 'https://am.wikipedia.org', - 'amwiktionary': 'https://am.wiktionary.org', - 'amwikiquote': 'https://am.wikiquote.org', - 'anwiki': 'https://an.wikipedia.org', - 'anwiktionary': 'https://an.wiktionary.org', - 'angwiki': 'https://ang.wikipedia.org', - 'angwiktionary': 'https://ang.wiktionary.org', - 'angwikibooks': 'https://ang.wikibooks.org', - 'angwikiquote': 'https://ang.wikiquote.org', - 'angwikisource': 'https://ang.wikisource.org', - 'arwiki': 'https://ar.wikipedia.org', - 'arwiktionary': 'https://ar.wiktionary.org', - 'arwikibooks': 'https://ar.wikibooks.org', - 'arwikinews': 'https://ar.wikinews.org', - 'arwikiquote': 'https://ar.wikiquote.org', - 'arwikisource': 'https://ar.wikisource.org', - 'arwikiversity': 'https://ar.wikiversity.org', - 'arcwiki': 'https://arc.wikipedia.org', - 'arzwiki': 'https://arz.wikipedia.org', - 'aswiki': 'https://as.wikipedia.org', - 'aswiktionary': 'https://as.wiktionary.org', - 'aswikibooks': 'https://as.wikibooks.org', - 'aswikisource': 'https://as.wikisource.org', - 'astwiki': 'https://ast.wikipedia.org', - 'astwiktionary': 'https://ast.wiktionary.org', - 'astwikibooks': 'https://ast.wikibooks.org', - 'astwikiquote': 'https://ast.wikiquote.org', - 'avwiki': 'https://av.wikipedia.org', - 'avwiktionary': 'https://av.wiktionary.org', - 'aywiki': 'https://ay.wikipedia.org', - 'aywiktionary': 'https://ay.wiktionary.org', - 'aywikibooks': 'https://ay.wikibooks.org', - 'azwiki': 'https://az.wikipedia.org', - 'azwiktionary': 'https://az.wiktionary.org', - 'azwikibooks': 'https://az.wikibooks.org', - 'azwikiquote': 'https://az.wikiquote.org', - 'azwikisource': 'https://az.wikisource.org', - 'bawiki': 'https://ba.wikipedia.org', - 'bawikibooks': 'https://ba.wikibooks.org', - 'barwiki': 'https://bar.wikipedia.org', - 'bat_smgwiki': 'https://bat-smg.wikipedia.org', - 'bclwiki': 'https://bcl.wikipedia.org', - 'bewiki': 'https://be.wikipedia.org', - 'bewiktionary': 'https://be.wiktionary.org', - 'bewikibooks': 'https://be.wikibooks.org', - 'bewikiquote': 'https://be.wikiquote.org', - 'bewikisource': 'https://be.wikisource.org', - 'be_x_oldwiki': 'https://be-x-old.wikipedia.org', - 'bgwiki': 'https://bg.wikipedia.org', - 'bgwiktionary': 'https://bg.wiktionary.org', - 'bgwikibooks': 'https://bg.wikibooks.org', - 'bgwikinews': 'https://bg.wikinews.org', - 'bgwikiquote': 'https://bg.wikiquote.org', - 'bgwikisource': 'https://bg.wikisource.org', - 'bhwiki': 'https://bh.wikipedia.org', - 'bhwiktionary': 'https://bh.wiktionary.org', - 'biwiki': 'https://bi.wikipedia.org', - 'biwiktionary': 'https://bi.wiktionary.org', - 'biwikibooks': 'https://bi.wikibooks.org', - 'bjnwiki': 'https://bjn.wikipedia.org', - 'bmwiki': 'https://bm.wikipedia.org', - 'bmwiktionary': 'https://bm.wiktionary.org', - 'bmwikibooks': 'https://bm.wikibooks.org', - 'bmwikiquote': 'https://bm.wikiquote.org', - 'bnwiki': 'https://bn.wikipedia.org', - 'bnwiktionary': 'https://bn.wiktionary.org', - 'bnwikibooks': 'https://bn.wikibooks.org', - 'bnwikisource': 'https://bn.wikisource.org', - 'bowiki': 'https://bo.wikipedia.org', - 'bowiktionary': 'https://bo.wiktionary.org', - 'bowikibooks': 'https://bo.wikibooks.org', - 'bpywiki': 'https://bpy.wikipedia.org', - 'brwiki': 'https://br.wikipedia.org', - 'brwiktionary': 'https://br.wiktionary.org', - 'brwikiquote': 'https://br.wikiquote.org', - 'brwikisource': 'https://br.wikisource.org', - 'bswiki': 'https://bs.wikipedia.org', - 'bswiktionary': 'https://bs.wiktionary.org', - 'bswikibooks': 'https://bs.wikibooks.org', - 'bswikinews': 'https://bs.wikinews.org', - 'bswikiquote': 'https://bs.wikiquote.org', - 'bswikisource': 'https://bs.wikisource.org', - 'bugwiki': 'https://bug.wikipedia.org', - 'bxrwiki': 'https://bxr.wikipedia.org', - 'cawiki': 'https://ca.wikipedia.org', - 'cawiktionary': 'https://ca.wiktionary.org', - 'cawikibooks': 'https://ca.wikibooks.org', - 'cawikinews': 'https://ca.wikinews.org', - 'cawikiquote': 'https://ca.wikiquote.org', - 'cawikisource': 'https://ca.wikisource.org', - 'cbk_zamwiki': 'https://cbk-zam.wikipedia.org', - 'cdowiki': 'https://cdo.wikipedia.org', - 'cewiki': 'https://ce.wikipedia.org', - 'cebwiki': 'https://ceb.wikipedia.org', - 'chwiki': 'https://ch.wikipedia.org', - 'chwiktionary': 'https://ch.wiktionary.org', - 'chwikibooks': 'https://ch.wikibooks.org', - 'chowiki': 'https://cho.wikipedia.org', - 'chrwiki': 'https://chr.wikipedia.org', - 'chrwiktionary': 'https://chr.wiktionary.org', - 'chywiki': 'https://chy.wikipedia.org', - 'ckbwiki': 'https://ckb.wikipedia.org', - 'cowiki': 'https://co.wikipedia.org', - 'cowiktionary': 'https://co.wiktionary.org', - 'cowikibooks': 'https://co.wikibooks.org', - 'cowikiquote': 'https://co.wikiquote.org', - 'crwiki': 'https://cr.wikipedia.org', - 'crwiktionary': 'https://cr.wiktionary.org', - 'crwikiquote': 'https://cr.wikiquote.org', - 'crhwiki': 'https://crh.wikipedia.org', - 'cswiki': 'https://cs.wikipedia.org', - 'cswiktionary': 'https://cs.wiktionary.org', - 'cswikibooks': 'https://cs.wikibooks.org', - 'cswikinews': 'https://cs.wikinews.org', - 'cswikiquote': 'https://cs.wikiquote.org', - 'cswikisource': 'https://cs.wikisource.org', - 'cswikiversity': 'https://cs.wikiversity.org', - 'csbwiki': 'https://csb.wikipedia.org', - 'csbwiktionary': 'https://csb.wiktionary.org', - 'cuwiki': 'https://cu.wikipedia.org', - 'cvwiki': 'https://cv.wikipedia.org', - 'cvwikibooks': 'https://cv.wikibooks.org', - 'cywiki': 'https://cy.wikipedia.org', - 'cywiktionary': 'https://cy.wiktionary.org', - 'cywikibooks': 'https://cy.wikibooks.org', - 'cywikiquote': 'https://cy.wikiquote.org', - 'cywikisource': 'https://cy.wikisource.org', - 'dawiki': 'https://da.wikipedia.org', - 'dawiktionary': 'https://da.wiktionary.org', - 'dawikibooks': 'https://da.wikibooks.org', - 'dawikiquote': 'https://da.wikiquote.org', - 'dawikisource': 'https://da.wikisource.org', - 'dewiki': 'https://de.wikipedia.org', - 'dewiktionary': 'https://de.wiktionary.org', - 'dewikibooks': 'https://de.wikibooks.org', - 'dewikinews': 'https://de.wikinews.org', - 'dewikiquote': 'https://de.wikiquote.org', - 'dewikisource': 'https://de.wikisource.org', - 'dewikiversity': 'https://de.wikiversity.org', - 'dewikivoyage': 'https://de.wikivoyage.org', - 'diqwiki': 'https://diq.wikipedia.org', - 'dsbwiki': 'https://dsb.wikipedia.org', - 'dvwiki': 'https://dv.wikipedia.org', - 'dvwiktionary': 'https://dv.wiktionary.org', - 'dzwiki': 'https://dz.wikipedia.org', - 'dzwiktionary': 'https://dz.wiktionary.org', - 'eewiki': 'https://ee.wikipedia.org', - 'elwiki': 'https://el.wikipedia.org', - 'elwiktionary': 'https://el.wiktionary.org', - 'elwikibooks': 'https://el.wikibooks.org', - 'elwikinews': 'https://el.wikinews.org', - 'elwikiquote': 'https://el.wikiquote.org', - 'elwikisource': 'https://el.wikisource.org', - 'elwikiversity': 'https://el.wikiversity.org', - 'elwikivoyage': 'https://el.wikivoyage.org', - 'emlwiki': 'https://eml.wikipedia.org', - 'enwiki': 'https://en.wikipedia.org', - 'enwiktionary': 'https://en.wiktionary.org', - 'enwikibooks': 'https://en.wikibooks.org', - 'enwikinews': 'https://en.wikinews.org', - 'enwikiquote': 'https://en.wikiquote.org', - 'enwikisource': 'https://en.wikisource.org', - 'enwikiversity': 'https://en.wikiversity.org', - 'enwikivoyage': 'https://en.wikivoyage.org', - 'eowiki': 'https://eo.wikipedia.org', - 'eowiktionary': 'https://eo.wiktionary.org', - 'eowikibooks': 'https://eo.wikibooks.org', - 'eowikinews': 'https://eo.wikinews.org', - 'eowikiquote': 'https://eo.wikiquote.org', - 'eowikisource': 'https://eo.wikisource.org', - 'eswiki': 'https://es.wikipedia.org', - 'eswiktionary': 'https://es.wiktionary.org', - 'eswikibooks': 'https://es.wikibooks.org', - 'eswikinews': 'https://es.wikinews.org', - 'eswikiquote': 'https://es.wikiquote.org', - 'eswikisource': 'https://es.wikisource.org', - 'eswikiversity': 'https://es.wikiversity.org', - 'eswikivoyage': 'https://es.wikivoyage.org', - 'etwiki': 'https://et.wikipedia.org', - 'etwiktionary': 'https://et.wiktionary.org', - 'etwikibooks': 'https://et.wikibooks.org', - 'etwikiquote': 'https://et.wikiquote.org', - 'etwikisource': 'https://et.wikisource.org', - 'euwiki': 'https://eu.wikipedia.org', - 'euwiktionary': 'https://eu.wiktionary.org', - 'euwikibooks': 'https://eu.wikibooks.org', - 'euwikiquote': 'https://eu.wikiquote.org', - 'extwiki': 'https://ext.wikipedia.org', - 'fawiki': 'https://fa.wikipedia.org', - 'fawiktionary': 'https://fa.wiktionary.org', - 'fawikibooks': 'https://fa.wikibooks.org', - 'fawikinews': 'https://fa.wikinews.org', - 'fawikiquote': 'https://fa.wikiquote.org', - 'fawikisource': 'https://fa.wikisource.org', - 'fawikivoyage': 'https://fa.wikivoyage.org', - 'ffwiki': 'https://ff.wikipedia.org', - 'fiwiki': 'https://fi.wikipedia.org', - 'fiwiktionary': 'https://fi.wiktionary.org', - 'fiwikibooks': 'https://fi.wikibooks.org', - 'fiwikinews': 'https://fi.wikinews.org', - 'fiwikiquote': 'https://fi.wikiquote.org', - 'fiwikisource': 'https://fi.wikisource.org', - 'fiwikiversity': 'https://fi.wikiversity.org', - 'fiu_vrowiki': 'https://fiu-vro.wikipedia.org', - 'fjwiki': 'https://fj.wikipedia.org', - 'fjwiktionary': 'https://fj.wiktionary.org', - 'fowiki': 'https://fo.wikipedia.org', - 'fowiktionary': 'https://fo.wiktionary.org', - 'fowikisource': 'https://fo.wikisource.org', - 'frwiki': 'https://fr.wikipedia.org', - 'frwiktionary': 'https://fr.wiktionary.org', - 'frwikibooks': 'https://fr.wikibooks.org', - 'frwikinews': 'https://fr.wikinews.org', - 'frwikiquote': 'https://fr.wikiquote.org', - 'frwikisource': 'https://fr.wikisource.org', - 'frwikiversity': 'https://fr.wikiversity.org', - 'frwikivoyage': 'https://fr.wikivoyage.org', - 'frpwiki': 'https://frp.wikipedia.org', - 'frrwiki': 'https://frr.wikipedia.org', - 'furwiki': 'https://fur.wikipedia.org', - 'fywiki': 'https://fy.wikipedia.org', - 'fywiktionary': 'https://fy.wiktionary.org', - 'fywikibooks': 'https://fy.wikibooks.org', - 'gawiki': 'https://ga.wikipedia.org', - 'gawiktionary': 'https://ga.wiktionary.org', - 'gawikibooks': 'https://ga.wikibooks.org', - 'gawikiquote': 'https://ga.wikiquote.org', - 'gagwiki': 'https://gag.wikipedia.org', - 'ganwiki': 'https://gan.wikipedia.org', - 'gdwiki': 'https://gd.wikipedia.org', - 'gdwiktionary': 'https://gd.wiktionary.org', - 'glwiki': 'https://gl.wikipedia.org', - 'glwiktionary': 'https://gl.wiktionary.org', - 'glwikibooks': 'https://gl.wikibooks.org', - 'glwikiquote': 'https://gl.wikiquote.org', - 'glwikisource': 'https://gl.wikisource.org', - 'glkwiki': 'https://glk.wikipedia.org', - 'gnwiki': 'https://gn.wikipedia.org', - 'gnwiktionary': 'https://gn.wiktionary.org', - 'gnwikibooks': 'https://gn.wikibooks.org', - 'gotwiki': 'https://got.wikipedia.org', - 'gotwikibooks': 'https://got.wikibooks.org', - 'guwiki': 'https://gu.wikipedia.org', - 'guwiktionary': 'https://gu.wiktionary.org', - 'guwikibooks': 'https://gu.wikibooks.org', - 'guwikiquote': 'https://gu.wikiquote.org', - 'guwikisource': 'https://gu.wikisource.org', - 'gvwiki': 'https://gv.wikipedia.org', - 'gvwiktionary': 'https://gv.wiktionary.org', - 'hawiki': 'https://ha.wikipedia.org', - 'hawiktionary': 'https://ha.wiktionary.org', - 'hakwiki': 'https://hak.wikipedia.org', - 'hawwiki': 'https://haw.wikipedia.org', - 'hewiki': 'https://he.wikipedia.org', - 'hewiktionary': 'https://he.wiktionary.org', - 'hewikibooks': 'https://he.wikibooks.org', - 'hewikinews': 'https://he.wikinews.org', - 'hewikiquote': 'https://he.wikiquote.org', - 'hewikisource': 'https://he.wikisource.org', - 'hewikivoyage': 'https://he.wikivoyage.org', - 'hiwiki': 'https://hi.wikipedia.org', - 'hiwiktionary': 'https://hi.wiktionary.org', - 'hiwikibooks': 'https://hi.wikibooks.org', - 'hiwikiquote': 'https://hi.wikiquote.org', - 'hifwiki': 'https://hif.wikipedia.org', - 'howiki': 'https://ho.wikipedia.org', - 'hrwiki': 'https://hr.wikipedia.org', - 'hrwiktionary': 'https://hr.wiktionary.org', - 'hrwikibooks': 'https://hr.wikibooks.org', - 'hrwikiquote': 'https://hr.wikiquote.org', - 'hrwikisource': 'https://hr.wikisource.org', - 'hsbwiki': 'https://hsb.wikipedia.org', - 'hsbwiktionary': 'https://hsb.wiktionary.org', - 'htwiki': 'https://ht.wikipedia.org', - 'htwikisource': 'https://ht.wikisource.org', - 'huwiki': 'https://hu.wikipedia.org', - 'huwiktionary': 'https://hu.wiktionary.org', - 'huwikibooks': 'https://hu.wikibooks.org', - 'huwikinews': 'https://hu.wikinews.org', - 'huwikiquote': 'https://hu.wikiquote.org', - 'huwikisource': 'https://hu.wikisource.org', - 'hywiki': 'https://hy.wikipedia.org', - 'hywiktionary': 'https://hy.wiktionary.org', - 'hywikibooks': 'https://hy.wikibooks.org', - 'hywikiquote': 'https://hy.wikiquote.org', - 'hywikisource': 'https://hy.wikisource.org', - 'hzwiki': 'https://hz.wikipedia.org', - 'iawiki': 'https://ia.wikipedia.org', - 'iawiktionary': 'https://ia.wiktionary.org', - 'iawikibooks': 'https://ia.wikibooks.org', - 'idwiki': 'https://id.wikipedia.org', - 'idwiktionary': 'https://id.wiktionary.org', - 'idwikibooks': 'https://id.wikibooks.org', - 'idwikiquote': 'https://id.wikiquote.org', - 'idwikisource': 'https://id.wikisource.org', - 'iewiki': 'https://ie.wikipedia.org', - 'iewiktionary': 'https://ie.wiktionary.org', - 'iewikibooks': 'https://ie.wikibooks.org', - 'igwiki': 'https://ig.wikipedia.org', - 'iiwiki': 'https://ii.wikipedia.org', - 'ikwiki': 'https://ik.wikipedia.org', - 'ikwiktionary': 'https://ik.wiktionary.org', - 'ilowiki': 'https://ilo.wikipedia.org', - 'iowiki': 'https://io.wikipedia.org', - 'iowiktionary': 'https://io.wiktionary.org', - 'iswiki': 'https://is.wikipedia.org', - 'iswiktionary': 'https://is.wiktionary.org', - 'iswikibooks': 'https://is.wikibooks.org', - 'iswikiquote': 'https://is.wikiquote.org', - 'iswikisource': 'https://is.wikisource.org', - 'itwiki': 'https://it.wikipedia.org', - 'itwiktionary': 'https://it.wiktionary.org', - 'itwikibooks': 'https://it.wikibooks.org', - 'itwikinews': 'https://it.wikinews.org', - 'itwikiquote': 'https://it.wikiquote.org', - 'itwikisource': 'https://it.wikisource.org', - 'itwikiversity': 'https://it.wikiversity.org', - 'itwikivoyage': 'https://it.wikivoyage.org', - 'iuwiki': 'https://iu.wikipedia.org', - 'iuwiktionary': 'https://iu.wiktionary.org', - 'jawiki': 'https://ja.wikipedia.org', - 'jawiktionary': 'https://ja.wiktionary.org', - 'jawikibooks': 'https://ja.wikibooks.org', - 'jawikinews': 'https://ja.wikinews.org', - 'jawikiquote': 'https://ja.wikiquote.org', - 'jawikisource': 'https://ja.wikisource.org', - 'jawikiversity': 'https://ja.wikiversity.org', - 'jbowiki': 'https://jbo.wikipedia.org', - 'jbowiktionary': 'https://jbo.wiktionary.org', - 'jvwiki': 'https://jv.wikipedia.org', - 'jvwiktionary': 'https://jv.wiktionary.org', - 'kawiki': 'https://ka.wikipedia.org', - 'kawiktionary': 'https://ka.wiktionary.org', - 'kawikibooks': 'https://ka.wikibooks.org', - 'kawikiquote': 'https://ka.wikiquote.org', - 'kaawiki': 'https://kaa.wikipedia.org', - 'kabwiki': 'https://kab.wikipedia.org', - 'kbdwiki': 'https://kbd.wikipedia.org', - 'kgwiki': 'https://kg.wikipedia.org', - 'kiwiki': 'https://ki.wikipedia.org', - 'kjwiki': 'https://kj.wikipedia.org', - 'kkwiki': 'https://kk.wikipedia.org', - 'kkwiktionary': 'https://kk.wiktionary.org', - 'kkwikibooks': 'https://kk.wikibooks.org', - 'kkwikiquote': 'https://kk.wikiquote.org', - 'klwiki': 'https://kl.wikipedia.org', - 'klwiktionary': 'https://kl.wiktionary.org', - 'kmwiki': 'https://km.wikipedia.org', - 'kmwiktionary': 'https://km.wiktionary.org', - 'kmwikibooks': 'https://km.wikibooks.org', - 'knwiki': 'https://kn.wikipedia.org', - 'knwiktionary': 'https://kn.wiktionary.org', - 'knwikibooks': 'https://kn.wikibooks.org', - 'knwikiquote': 'https://kn.wikiquote.org', - 'knwikisource': 'https://kn.wikisource.org', - 'kowiki': 'https://ko.wikipedia.org', - 'kowiktionary': 'https://ko.wiktionary.org', - 'kowikibooks': 'https://ko.wikibooks.org', - 'kowikinews': 'https://ko.wikinews.org', - 'kowikiquote': 'https://ko.wikiquote.org', - 'kowikisource': 'https://ko.wikisource.org', - 'kowikiversity': 'https://ko.wikiversity.org', - 'koiwiki': 'https://koi.wikipedia.org', - 'krwiki': 'https://kr.wikipedia.org', - 'krwikiquote': 'https://kr.wikiquote.org', - 'krcwiki': 'https://krc.wikipedia.org', - 'kswiki': 'https://ks.wikipedia.org', - 'kswiktionary': 'https://ks.wiktionary.org', - 'kswikibooks': 'https://ks.wikibooks.org', - 'kswikiquote': 'https://ks.wikiquote.org', - 'kshwiki': 'https://ksh.wikipedia.org', - 'kuwiki': 'https://ku.wikipedia.org', - 'kuwiktionary': 'https://ku.wiktionary.org', - 'kuwikibooks': 'https://ku.wikibooks.org', - 'kuwikiquote': 'https://ku.wikiquote.org', - 'kvwiki': 'https://kv.wikipedia.org', - 'kwwiki': 'https://kw.wikipedia.org', - 'kwwiktionary': 'https://kw.wiktionary.org', - 'kwwikiquote': 'https://kw.wikiquote.org', - 'kywiki': 'https://ky.wikipedia.org', - 'kywiktionary': 'https://ky.wiktionary.org', - 'kywikibooks': 'https://ky.wikibooks.org', - 'kywikiquote': 'https://ky.wikiquote.org', - 'lawiki': 'https://la.wikipedia.org', - 'lawiktionary': 'https://la.wiktionary.org', - 'lawikibooks': 'https://la.wikibooks.org', - 'lawikiquote': 'https://la.wikiquote.org', - 'lawikisource': 'https://la.wikisource.org', - 'ladwiki': 'https://lad.wikipedia.org', - 'lbwiki': 'https://lb.wikipedia.org', - 'lbwiktionary': 'https://lb.wiktionary.org', - 'lbwikibooks': 'https://lb.wikibooks.org', - 'lbwikiquote': 'https://lb.wikiquote.org', - 'lbewiki': 'https://lbe.wikipedia.org', - 'lezwiki': 'https://lez.wikipedia.org', - 'lgwiki': 'https://lg.wikipedia.org', - 'liwiki': 'https://li.wikipedia.org', - 'liwiktionary': 'https://li.wiktionary.org', - 'liwikibooks': 'https://li.wikibooks.org', - 'liwikiquote': 'https://li.wikiquote.org', - 'liwikisource': 'https://li.wikisource.org', - 'lijwiki': 'https://lij.wikipedia.org', - 'lmowiki': 'https://lmo.wikipedia.org', - 'lnwiki': 'https://ln.wikipedia.org', - 'lnwiktionary': 'https://ln.wiktionary.org', - 'lnwikibooks': 'https://ln.wikibooks.org', - 'lowiki': 'https://lo.wikipedia.org', - 'lowiktionary': 'https://lo.wiktionary.org', - 'ltwiki': 'https://lt.wikipedia.org', - 'ltwiktionary': 'https://lt.wiktionary.org', - 'ltwikibooks': 'https://lt.wikibooks.org', - 'ltwikiquote': 'https://lt.wikiquote.org', - 'ltwikisource': 'https://lt.wikisource.org', - 'ltgwiki': 'https://ltg.wikipedia.org', - 'lvwiki': 'https://lv.wikipedia.org', - 'lvwiktionary': 'https://lv.wiktionary.org', - 'lvwikibooks': 'https://lv.wikibooks.org', - 'maiwiki': 'https://mai.wikipedia.org', - 'map_bmswiki': 'https://map-bms.wikipedia.org', - 'mdfwiki': 'https://mdf.wikipedia.org', - 'mgwiki': 'https://mg.wikipedia.org', - 'mgwiktionary': 'https://mg.wiktionary.org', - 'mgwikibooks': 'https://mg.wikibooks.org', - 'mhwiki': 'https://mh.wikipedia.org', - 'mhwiktionary': 'https://mh.wiktionary.org', - 'mhrwiki': 'https://mhr.wikipedia.org', - 'miwiki': 'https://mi.wikipedia.org', - 'miwiktionary': 'https://mi.wiktionary.org', - 'miwikibooks': 'https://mi.wikibooks.org', - 'minwiki': 'https://min.wikipedia.org', - 'mkwiki': 'https://mk.wikipedia.org', - 'mkwiktionary': 'https://mk.wiktionary.org', - 'mkwikibooks': 'https://mk.wikibooks.org', - 'mkwikisource': 'https://mk.wikisource.org', - 'mlwiki': 'https://ml.wikipedia.org', - 'mlwiktionary': 'https://ml.wiktionary.org', - 'mlwikibooks': 'https://ml.wikibooks.org', - 'mlwikiquote': 'https://ml.wikiquote.org', - 'mlwikisource': 'https://ml.wikisource.org', - 'mnwiki': 'https://mn.wikipedia.org', - 'mnwiktionary': 'https://mn.wiktionary.org', - 'mnwikibooks': 'https://mn.wikibooks.org', - 'mowiki': 'https://mo.wikipedia.org', - 'mowiktionary': 'https://mo.wiktionary.org', - 'mrwiki': 'https://mr.wikipedia.org', - 'mrwiktionary': 'https://mr.wiktionary.org', - 'mrwikibooks': 'https://mr.wikibooks.org', - 'mrwikiquote': 'https://mr.wikiquote.org', - 'mrwikisource': 'https://mr.wikisource.org', - 'mrjwiki': 'https://mrj.wikipedia.org', - 'mswiki': 'https://ms.wikipedia.org', - 'mswiktionary': 'https://ms.wiktionary.org', - 'mswikibooks': 'https://ms.wikibooks.org', - 'mtwiki': 'https://mt.wikipedia.org', - 'mtwiktionary': 'https://mt.wiktionary.org', - 'muswiki': 'https://mus.wikipedia.org', - 'mwlwiki': 'https://mwl.wikipedia.org', - 'mywiki': 'https://my.wikipedia.org', - 'mywiktionary': 'https://my.wiktionary.org', - 'mywikibooks': 'https://my.wikibooks.org', - 'myvwiki': 'https://myv.wikipedia.org', - 'mznwiki': 'https://mzn.wikipedia.org', - 'nawiki': 'https://na.wikipedia.org', - 'nawiktionary': 'https://na.wiktionary.org', - 'nawikibooks': 'https://na.wikibooks.org', - 'nawikiquote': 'https://na.wikiquote.org', - 'nahwiki': 'https://nah.wikipedia.org', - 'nahwiktionary': 'https://nah.wiktionary.org', - 'nahwikibooks': 'https://nah.wikibooks.org', - 'napwiki': 'https://nap.wikipedia.org', - 'ndswiki': 'https://nds.wikipedia.org', - 'ndswiktionary': 'https://nds.wiktionary.org', - 'ndswikibooks': 'https://nds.wikibooks.org', - 'ndswikiquote': 'https://nds.wikiquote.org', - 'nds_nlwiki': 'https://nds-nl.wikipedia.org', - 'newiki': 'https://ne.wikipedia.org', - 'newiktionary': 'https://ne.wiktionary.org', - 'newikibooks': 'https://ne.wikibooks.org', - 'newwiki': 'https://new.wikipedia.org', - 'ngwiki': 'https://ng.wikipedia.org', - 'nlwiki': 'https://nl.wikipedia.org', - 'nlwiktionary': 'https://nl.wiktionary.org', - 'nlwikibooks': 'https://nl.wikibooks.org', - 'nlwikinews': 'https://nl.wikinews.org', - 'nlwikiquote': 'https://nl.wikiquote.org', - 'nlwikisource': 'https://nl.wikisource.org', - 'nlwikivoyage': 'https://nl.wikivoyage.org', - 'nnwiki': 'https://nn.wikipedia.org', - 'nnwiktionary': 'https://nn.wiktionary.org', - 'nnwikiquote': 'https://nn.wikiquote.org', - 'nowiki': 'https://no.wikipedia.org', - 'nowiktionary': 'https://no.wiktionary.org', - 'nowikibooks': 'https://no.wikibooks.org', - 'nowikinews': 'https://no.wikinews.org', - 'nowikiquote': 'https://no.wikiquote.org', - 'nowikisource': 'https://no.wikisource.org', - 'novwiki': 'https://nov.wikipedia.org', - 'nrmwiki': 'https://nrm.wikipedia.org', - 'nsowiki': 'https://nso.wikipedia.org', - 'nvwiki': 'https://nv.wikipedia.org', - 'nywiki': 'https://ny.wikipedia.org', - 'ocwiki': 'https://oc.wikipedia.org', - 'ocwiktionary': 'https://oc.wiktionary.org', - 'ocwikibooks': 'https://oc.wikibooks.org', - 'omwiki': 'https://om.wikipedia.org', - 'omwiktionary': 'https://om.wiktionary.org', - 'orwiki': 'https://or.wikipedia.org', - 'orwiktionary': 'https://or.wiktionary.org', - 'orwikisource': 'https://or.wikisource.org', - 'oswiki': 'https://os.wikipedia.org', - 'pawiki': 'https://pa.wikipedia.org', - 'pawiktionary': 'https://pa.wiktionary.org', - 'pawikibooks': 'https://pa.wikibooks.org', - 'pagwiki': 'https://pag.wikipedia.org', - 'pamwiki': 'https://pam.wikipedia.org', - 'papwiki': 'https://pap.wikipedia.org', - 'pcdwiki': 'https://pcd.wikipedia.org', - 'pdcwiki': 'https://pdc.wikipedia.org', - 'pflwiki': 'https://pfl.wikipedia.org', - 'piwiki': 'https://pi.wikipedia.org', - 'piwiktionary': 'https://pi.wiktionary.org', - 'pihwiki': 'https://pih.wikipedia.org', - 'plwiki': 'https://pl.wikipedia.org', - 'plwiktionary': 'https://pl.wiktionary.org', - 'plwikibooks': 'https://pl.wikibooks.org', - 'plwikinews': 'https://pl.wikinews.org', - 'plwikiquote': 'https://pl.wikiquote.org', - 'plwikisource': 'https://pl.wikisource.org', - 'plwikivoyage': 'https://pl.wikivoyage.org', - 'pmswiki': 'https://pms.wikipedia.org', - 'pnbwiki': 'https://pnb.wikipedia.org', - 'pnbwiktionary': 'https://pnb.wiktionary.org', - 'pntwiki': 'https://pnt.wikipedia.org', - 'pswiki': 'https://ps.wikipedia.org', - 'pswiktionary': 'https://ps.wiktionary.org', - 'pswikibooks': 'https://ps.wikibooks.org', - 'ptwiki': 'https://pt.wikipedia.org', - 'ptwiktionary': 'https://pt.wiktionary.org', - 'ptwikibooks': 'https://pt.wikibooks.org', - 'ptwikinews': 'https://pt.wikinews.org', - 'ptwikiquote': 'https://pt.wikiquote.org', - 'ptwikisource': 'https://pt.wikisource.org', - 'ptwikiversity': 'https://pt.wikiversity.org', - 'ptwikivoyage': 'https://pt.wikivoyage.org', - 'quwiki': 'https://qu.wikipedia.org', - 'quwiktionary': 'https://qu.wiktionary.org', - 'quwikibooks': 'https://qu.wikibooks.org', - 'quwikiquote': 'https://qu.wikiquote.org', - 'rmwiki': 'https://rm.wikipedia.org', - 'rmwiktionary': 'https://rm.wiktionary.org', - 'rmwikibooks': 'https://rm.wikibooks.org', - 'rmywiki': 'https://rmy.wikipedia.org', - 'rnwiki': 'https://rn.wikipedia.org', - 'rnwiktionary': 'https://rn.wiktionary.org', - 'rowiki': 'https://ro.wikipedia.org', - 'rowiktionary': 'https://ro.wiktionary.org', - 'rowikibooks': 'https://ro.wikibooks.org', - 'rowikinews': 'https://ro.wikinews.org', - 'rowikiquote': 'https://ro.wikiquote.org', - 'rowikisource': 'https://ro.wikisource.org', - 'rowikivoyage': 'https://ro.wikivoyage.org', - 'roa_rupwiki': 'https://roa-rup.wikipedia.org', - 'roa_rupwiktionary': 'https://roa-rup.wiktionary.org', - 'roa_tarawiki': 'https://roa-tara.wikipedia.org', - 'ruwiki': 'https://ru.wikipedia.org', - 'ruwiktionary': 'https://ru.wiktionary.org', - 'ruwikibooks': 'https://ru.wikibooks.org', - 'ruwikinews': 'https://ru.wikinews.org', - 'ruwikiquote': 'https://ru.wikiquote.org', - 'ruwikisource': 'https://ru.wikisource.org', - 'ruwikiversity': 'https://ru.wikiversity.org', - 'ruwikivoyage': 'https://ru.wikivoyage.org', - 'ruewiki': 'https://rue.wikipedia.org', - 'rwwiki': 'https://rw.wikipedia.org', - 'rwwiktionary': 'https://rw.wiktionary.org', - 'sawiki': 'https://sa.wikipedia.org', - 'sawiktionary': 'https://sa.wiktionary.org', - 'sawikibooks': 'https://sa.wikibooks.org', - 'sawikiquote': 'https://sa.wikiquote.org', - 'sawikisource': 'https://sa.wikisource.org', - 'sahwiki': 'https://sah.wikipedia.org', - 'sahwikisource': 'https://sah.wikisource.org', - 'scwiki': 'https://sc.wikipedia.org', - 'scwiktionary': 'https://sc.wiktionary.org', - 'scnwiki': 'https://scn.wikipedia.org', - 'scnwiktionary': 'https://scn.wiktionary.org', - 'scowiki': 'https://sco.wikipedia.org', - 'sdwiki': 'https://sd.wikipedia.org', - 'sdwiktionary': 'https://sd.wiktionary.org', - 'sdwikinews': 'https://sd.wikinews.org', - 'sewiki': 'https://se.wikipedia.org', - 'sewikibooks': 'https://se.wikibooks.org', - 'sgwiki': 'https://sg.wikipedia.org', - 'sgwiktionary': 'https://sg.wiktionary.org', - 'shwiki': 'https://sh.wikipedia.org', - 'shwiktionary': 'https://sh.wiktionary.org', - 'siwiki': 'https://si.wikipedia.org', - 'siwiktionary': 'https://si.wiktionary.org', - 'siwikibooks': 'https://si.wikibooks.org', - 'simplewiki': 'https://simple.wikipedia.org', - 'simplewiktionary': 'https://simple.wiktionary.org', - 'simplewikibooks': 'https://simple.wikibooks.org', - 'simplewikiquote': 'https://simple.wikiquote.org', - 'skwiki': 'https://sk.wikipedia.org', - 'skwiktionary': 'https://sk.wiktionary.org', - 'skwikibooks': 'https://sk.wikibooks.org', - 'skwikiquote': 'https://sk.wikiquote.org', - 'skwikisource': 'https://sk.wikisource.org', - 'slwiki': 'https://sl.wikipedia.org', - 'slwiktionary': 'https://sl.wiktionary.org', - 'slwikibooks': 'https://sl.wikibooks.org', - 'slwikiquote': 'https://sl.wikiquote.org', - 'slwikisource': 'https://sl.wikisource.org', - 'slwikiversity': 'https://sl.wikiversity.org', - 'smwiki': 'https://sm.wikipedia.org', - 'smwiktionary': 'https://sm.wiktionary.org', - 'snwiki': 'https://sn.wikipedia.org', - 'snwiktionary': 'https://sn.wiktionary.org', - 'sowiki': 'https://so.wikipedia.org', - 'sowiktionary': 'https://so.wiktionary.org', - 'sqwiki': 'https://sq.wikipedia.org', - 'sqwiktionary': 'https://sq.wiktionary.org', - 'sqwikibooks': 'https://sq.wikibooks.org', - 'sqwikinews': 'https://sq.wikinews.org', - 'sqwikiquote': 'https://sq.wikiquote.org', - 'srwiki': 'https://sr.wikipedia.org', - 'srwiktionary': 'https://sr.wiktionary.org', - 'srwikibooks': 'https://sr.wikibooks.org', - 'srwikinews': 'https://sr.wikinews.org', - 'srwikiquote': 'https://sr.wikiquote.org', - 'srwikisource': 'https://sr.wikisource.org', - 'srnwiki': 'https://srn.wikipedia.org', - 'sswiki': 'https://ss.wikipedia.org', - 'sswiktionary': 'https://ss.wiktionary.org', - 'stwiki': 'https://st.wikipedia.org', - 'stwiktionary': 'https://st.wiktionary.org', - 'stqwiki': 'https://stq.wikipedia.org', - 'suwiki': 'https://su.wikipedia.org', - 'suwiktionary': 'https://su.wiktionary.org', - 'suwikibooks': 'https://su.wikibooks.org', - 'suwikiquote': 'https://su.wikiquote.org', - 'svwiki': 'https://sv.wikipedia.org', - 'svwiktionary': 'https://sv.wiktionary.org', - 'svwikibooks': 'https://sv.wikibooks.org', - 'svwikinews': 'https://sv.wikinews.org', - 'svwikiquote': 'https://sv.wikiquote.org', - 'svwikisource': 'https://sv.wikisource.org', - 'svwikiversity': 'https://sv.wikiversity.org', - 'svwikivoyage': 'https://sv.wikivoyage.org', - 'swwiki': 'https://sw.wikipedia.org', - 'swwiktionary': 'https://sw.wiktionary.org', - 'swwikibooks': 'https://sw.wikibooks.org', - 'szlwiki': 'https://szl.wikipedia.org', - 'tawiki': 'https://ta.wikipedia.org', - 'tawiktionary': 'https://ta.wiktionary.org', - 'tawikibooks': 'https://ta.wikibooks.org', - 'tawikinews': 'https://ta.wikinews.org', - 'tawikiquote': 'https://ta.wikiquote.org', - 'tawikisource': 'https://ta.wikisource.org', - 'tewiki': 'https://te.wikipedia.org', - 'tewiktionary': 'https://te.wiktionary.org', - 'tewikibooks': 'https://te.wikibooks.org', - 'tewikiquote': 'https://te.wikiquote.org', - 'tewikisource': 'https://te.wikisource.org', - 'tetwiki': 'https://tet.wikipedia.org', - 'tgwiki': 'https://tg.wikipedia.org', - 'tgwiktionary': 'https://tg.wiktionary.org', - 'tgwikibooks': 'https://tg.wikibooks.org', - 'thwiki': 'https://th.wikipedia.org', - 'thwiktionary': 'https://th.wiktionary.org', - 'thwikibooks': 'https://th.wikibooks.org', - 'thwikinews': 'https://th.wikinews.org', - 'thwikiquote': 'https://th.wikiquote.org', - 'thwikisource': 'https://th.wikisource.org', - 'tiwiki': 'https://ti.wikipedia.org', - 'tiwiktionary': 'https://ti.wiktionary.org', - 'tkwiki': 'https://tk.wikipedia.org', - 'tkwiktionary': 'https://tk.wiktionary.org', - 'tkwikibooks': 'https://tk.wikibooks.org', - 'tkwikiquote': 'https://tk.wikiquote.org', - 'tlwiki': 'https://tl.wikipedia.org', - 'tlwiktionary': 'https://tl.wiktionary.org', - 'tlwikibooks': 'https://tl.wikibooks.org', - 'tnwiki': 'https://tn.wikipedia.org', - 'tnwiktionary': 'https://tn.wiktionary.org', - 'towiki': 'https://to.wikipedia.org', - 'towiktionary': 'https://to.wiktionary.org', - 'tpiwiki': 'https://tpi.wikipedia.org', - 'tpiwiktionary': 'https://tpi.wiktionary.org', - 'trwiki': 'https://tr.wikipedia.org', - 'trwiktionary': 'https://tr.wiktionary.org', - 'trwikibooks': 'https://tr.wikibooks.org', - 'trwikinews': 'https://tr.wikinews.org', - 'trwikiquote': 'https://tr.wikiquote.org', - 'trwikisource': 'https://tr.wikisource.org', - 'tswiki': 'https://ts.wikipedia.org', - 'tswiktionary': 'https://ts.wiktionary.org', - 'ttwiki': 'https://tt.wikipedia.org', - 'ttwiktionary': 'https://tt.wiktionary.org', - 'ttwikibooks': 'https://tt.wikibooks.org', - 'ttwikiquote': 'https://tt.wikiquote.org', - 'tumwiki': 'https://tum.wikipedia.org', - 'twwiki': 'https://tw.wikipedia.org', - 'twwiktionary': 'https://tw.wiktionary.org', - 'tywiki': 'https://ty.wikipedia.org', - 'tyvwiki': 'https://tyv.wikipedia.org', - 'udmwiki': 'https://udm.wikipedia.org', - 'ugwiki': 'https://ug.wikipedia.org', - 'ugwiktionary': 'https://ug.wiktionary.org', - 'ugwikibooks': 'https://ug.wikibooks.org', - 'ugwikiquote': 'https://ug.wikiquote.org', - 'ukwiki': 'https://uk.wikipedia.org', - 'ukwiktionary': 'https://uk.wiktionary.org', - 'ukwikibooks': 'https://uk.wikibooks.org', - 'ukwikinews': 'https://uk.wikinews.org', - 'ukwikiquote': 'https://uk.wikiquote.org', - 'ukwikisource': 'https://uk.wikisource.org', - 'ukwikivoyage': 'https://uk.wikivoyage.org', - 'urwiki': 'https://ur.wikipedia.org', - 'urwiktionary': 'https://ur.wiktionary.org', - 'urwikibooks': 'https://ur.wikibooks.org', - 'urwikiquote': 'https://ur.wikiquote.org', - 'uzwiki': 'https://uz.wikipedia.org', - 'uzwiktionary': 'https://uz.wiktionary.org', - 'uzwikibooks': 'https://uz.wikibooks.org', - 'uzwikiquote': 'https://uz.wikiquote.org', - 'vewiki': 'https://ve.wikipedia.org', - 'vecwiki': 'https://vec.wikipedia.org', - 'vecwiktionary': 'https://vec.wiktionary.org', - 'vecwikisource': 'https://vec.wikisource.org', - 'vepwiki': 'https://vep.wikipedia.org', - 'viwiki': 'https://vi.wikipedia.org', - 'viwiktionary': 'https://vi.wiktionary.org', - 'viwikibooks': 'https://vi.wikibooks.org', - 'viwikiquote': 'https://vi.wikiquote.org', - 'viwikisource': 'https://vi.wikisource.org', - 'viwikivoyage': 'https://vi.wikivoyage.org', - 'vlswiki': 'https://vls.wikipedia.org', - 'vowiki': 'https://vo.wikipedia.org', - 'vowiktionary': 'https://vo.wiktionary.org', - 'vowikibooks': 'https://vo.wikibooks.org', - 'vowikiquote': 'https://vo.wikiquote.org', - 'wawiki': 'https://wa.wikipedia.org', - 'wawiktionary': 'https://wa.wiktionary.org', - 'wawikibooks': 'https://wa.wikibooks.org', - 'warwiki': 'https://war.wikipedia.org', - 'wowiki': 'https://wo.wikipedia.org', - 'wowiktionary': 'https://wo.wiktionary.org', - 'wowikiquote': 'https://wo.wikiquote.org', - 'wuuwiki': 'https://wuu.wikipedia.org', - 'xalwiki': 'https://xal.wikipedia.org', - 'xhwiki': 'https://xh.wikipedia.org', - 'xhwiktionary': 'https://xh.wiktionary.org', - 'xhwikibooks': 'https://xh.wikibooks.org', - 'xmfwiki': 'https://xmf.wikipedia.org', - 'yiwiki': 'https://yi.wikipedia.org', - 'yiwiktionary': 'https://yi.wiktionary.org', - 'yiwikisource': 'https://yi.wikisource.org', - 'yowiki': 'https://yo.wikipedia.org', - 'yowiktionary': 'https://yo.wiktionary.org', - 'yowikibooks': 'https://yo.wikibooks.org', - 'zawiki': 'https://za.wikipedia.org', - 'zawiktionary': 'https://za.wiktionary.org', - 'zawikibooks': 'https://za.wikibooks.org', - 'zawikiquote': 'https://za.wikiquote.org', - 'zeawiki': 'https://zea.wikipedia.org', - 'zhwiki': 'https://zh.wikipedia.org', - 'zhwiktionary': 'https://zh.wiktionary.org', - 'zhwikibooks': 'https://zh.wikibooks.org', - 'zhwikinews': 'https://zh.wikinews.org', - 'zhwikiquote': 'https://zh.wikiquote.org', - 'zhwikisource': 'https://zh.wikisource.org', - 'zhwikivoyage': 'https://zh.wikivoyage.org', - 'zh_classicalwiki': 'https://zh-classical.wikipedia.org', - 'zh_min_nanwiki': 'https://zh-min-nan.wikipedia.org', - 'zh_min_nanwiktionary': 'https://zh-min-nan.wiktionary.org', - 'zh_min_nanwikibooks': 'https://zh-min-nan.wikibooks.org', - 'zh_min_nanwikiquote': 'https://zh-min-nan.wikiquote.org', - 'zh_min_nanwikisource': 'https://zh-min-nan.wikisource.org', - 'zh_yuewiki': 'https://zh-yue.wikipedia.org', - 'zuwiki': 'https://zu.wikipedia.org', - 'zuwiktionary': 'https://zu.wiktionary.org', - 'zuwikibooks': 'https://zu.wikibooks.org' +request.types = { + html: 'text/html', + json: 'application/json', + xml: 'application/xml', + urlencoded: 'application/x-www-form-urlencoded', + 'form': 'application/x-www-form-urlencoded', + 'form-data': 'application/x-www-form-urlencoded' }; -if (typeof module !== 'undefined' && module.exports) { - module.exports = site_map; -} -},{}],9:[function(_dereq_,module,exports){ -'use strict'; +/** + * Default serialization map. + * + * superagent.serialize['application/xml'] = function(obj){ + * return 'generated xml here'; + * }; + * + */ -//turns wikimedia script into json -// https://github.com/spencermountain/wtf_wikipedia -//@spencermountain -var wtf_wikipedia = function () { - var sentence_parser = _dereq_('./lib/sentence_parser'); - var fetch = _dereq_('./lib/fetch_text'); - var make_image = _dereq_('./lib/make_image'); - var i18n = _dereq_('./data/i18n'); - var helpers = _dereq_('./lib/helpers'); - var languages = _dereq_('./data/languages'); - //parsers - var redirects = _dereq_('./parse/parse_redirects'); - var parse_table = _dereq_('./parse/parse_table'); - var parse_line = _dereq_('./parse/parse_line'); - var parse_categories = _dereq_('./parse/parse_categories'); - var parse_disambig = _dereq_('./parse/parse_disambig'); - var parse_infobox = _dereq_('./parse/parse_infobox'); - var parse_infobox_template = _dereq_('./parse/parse_infobox_template'); - var parse_image = _dereq_('./parse/parse_image'); - var recursive_matches = _dereq_('./recursive_matches'); - var preprocess = _dereq_('./parse/cleanup_misc'); - var word_templates = _dereq_('./word_templates'); - - // options - var defaultParseOptions = { - ignoreLists: true - }; + request.serialize = { + 'application/x-www-form-urlencoded': serialize, + 'application/json': JSON.stringify + }; - //some xml elements are just junk, and demand full inglorious death by regular exp - //other xml elements, like , are plucked out afterwards - var main = function main(wiki, options) { - options = Object.assign({}, defaultParseOptions, options); - var infobox = {}; - var infobox_template = ''; - var images = []; - var tables; - var translations = {}; - wiki = wiki || ''; - //detect if page is just redirect, and return - if (redirects.is_redirect(wiki)) { - return redirects.parse_redirect(wiki); - } - //detect if page is disambiguator page - var template_reg = new RegExp('\\{\\{ ?(' + i18n.disambigs.join('|') + ')(\\|[a-z =]*?)? ?\\}\\}', 'i'); - if (wiki.match(template_reg)) { - //|| wiki.match(/^.{3,25} may refer to/i)|| wiki.match(/^.{3,25} ist der Name mehrerer /i) - return parse_disambig(wiki); - } - //parse templates like {{currentday}} - wiki = word_templates(wiki); - //kill off th3 craziness - wiki = preprocess(wiki); - //find tables - tables = wiki.match(/\{\|[\s\S]{1,8000}?\|\}/g, '') || []; - tables = tables.map(function (s) { - return parse_table(s); - }); - //remove tables - wiki = wiki.replace(/\{\|[\s\S]{1,8000}?\|\}/g, ''); - - //reduce the scary recursive situations - //remove {{template {{}} }} recursions - var matches = recursive_matches('{', '}', wiki); - var infobox_reg = new RegExp('\{\{(' + i18n.infoboxes.join('|') + ')[: \n]', 'ig'); - matches.forEach(function (s) { - if (s.match(infobox_reg, 'ig') && Object.keys(infobox).length === 0) { - infobox = parse_infobox(s); - infobox_template = parse_infobox_template(s); - } - if (s.match(infobox_reg)) { - wiki = wiki.replace(s, ''); - } - //rest of them... - if (s.match(/^\{\{/)) { - //support nowrap - var nowrap = s.match(/^\{\{nowrap\|(.*?)\}\}$/); - if (nowrap) { - wiki = wiki.replace(s, nowrap[1]); - return; - } - //if it's not a known template, but it's recursive, remove it - //(because it will be misread later-on) - wiki = wiki.replace(s, ''); - } - }); + /** + * Default parsers. + * + * superagent.parse['application/xml'] = function(str){ + * return { object parsed from str }; + * }; + * + */ - //second, remove [[file:...[[]] ]] recursions - matches = recursive_matches('[', ']', wiki); - matches.forEach(function (s) { - if (s.match(new RegExp('\\[\\[(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'))) { - images.push(parse_image(s)); - wiki = wiki.replace(s, ''); - } - }); - //third, wiktionary-style interlanguage links - matches.forEach(function (s) { - if (s.match(/\[\[([a-z][a-z]):(.*?)\]\]/i) !== null) { - var lang = s.match(/\[\[([a-z][a-z]):/i)[1]; - if (lang && languages[lang]) { - translations[lang] = s.match(/\[\[([a-z][a-z]):(.*?)\]\]/i)[2]; - } - wiki = wiki.replace(s, ''); - } - }); +request.parse = { + 'application/x-www-form-urlencoded': parseString, + 'application/json': JSON.parse +}; - //now that the scary recursion issues are gone, we can trust simple regex methods - - //kill the rest of templates - wiki = wiki.replace(/\{\{.*?\}\}/g, ''); - - //get list of links, categories - var cats = parse_categories(wiki); - //next, map each line into a parsable sentence - // var output = {}; - var output = new Map(); - var lines = wiki.replace(/\r/g, '').split(/\n/); - var section = 'Intro'; - var number = 1; - lines.forEach(function (part) { - if (!section) { - return; - } - //add # numberings formatting - if (part.match(/^ ?\#[^:,\|]{4}/i)) { - part = part.replace(/^ ?#*/, number + ') '); - part = part + '\n'; - number += 1; - } else { - number = 1; - } - //add bullet-points formatting - if (part.match(/^\*+[^:,\|]{4}/)) { - part = part + '\n'; - } - //remove some nonsense wp lines +/** + * Parse the given header `str` into + * an object containing the mapped fields. + * + * @param {String} str + * @return {Object} + * @api private + */ - if (options.ignoreLists) { - //ignore list - if (part.match(/^[#\*:;\|]/)) { - return; - } - } +function parseHeader(str) { + var lines = str.split(/\r?\n/); + var fields = {}; + var index; + var line; + var field; + var val; - //ignore only-punctuation - if (!part.match(/[a-z0-9]/i)) { - return; - } - //headings - var ban_headings = new RegExp('^ ?(' + i18n.sources.join('|') + ') ?$', 'i'); //remove things like 'external links' - if (part.match(/^={1,5}[^=]{1,200}={1,5}$/)) { - section = part.match(/^={1,5}([^=]{1,200}?)={1,5}$/) || []; - section = section[1] || ''; - section = section.replace(/\./g, ' '); // this is necessary for mongo, i'm sorry - section = helpers.trim_whitespace(section); - //ban some sections - if (section && section.match(ban_headings)) { - section = undefined; - } - return; - } - //still alive, add it to the section - sentence_parser(part).forEach(function (line) { - line = parse_line(line); - if (line && line.text) { - // if (!output[section]) { - if (!output.get(section)) { - // output[section] = []; - output.set(section, []); - } - // output[section].push(line); - output.get(section).push(line); - } - }); - }); - //add additional image from infobox, if applicable - if (infobox['image'] && infobox['image'].text) { - var img = infobox['image'].text || ''; - if (typeof img === 'string' && !img.match(new RegExp('^(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'))) { - img = 'File:' + img; - } - images.push(img); - } - //add url, etc to image - images = images.map(make_image); - return { - type: 'page', - text: output, - categories: cats, - images: images, - infobox: infobox, - infobox_template: infobox_template, - tables: tables, - translations: translations - }; - }; + lines.pop(); // trailing CRLF - var from_api = function from_api(page_identifier, lang_or_wikiid, cb) { - if (typeof lang_or_wikiid === 'function') { - cb = lang_or_wikiid; - lang_or_wikiid = 'en'; - } - cb = cb || function () {}; - lang_or_wikiid = lang_or_wikiid || 'en'; - if (!fetch) { - //no http method, on the client side - return cb(null); - } - return fetch(page_identifier, lang_or_wikiid, cb); - }; + for (var i = 0, len = lines.length; i < len; ++i) { + line = lines[i]; + index = line.indexOf(':'); + field = line.slice(0, index).toLowerCase(); + val = trim(line.slice(index + 1)); + fields[field] = val; + } - var plaintext = function plaintext(str) { - var data = main(str) || {}; - data.text = data.text || []; - var text = ''; - data.text.forEach(function (v) { - text += v.map(function (a) { - return a.text; - }).join(' ') + '\n'; - }); - return text; - }; + return fields; +} - var methods = { - from_api: from_api, - parse: main, - plaintext: plaintext - }; +/** + * Check if `mime` is json or has +json structured syntax suffix. + * + * @param {String} mime + * @return {Boolean} + * @api private + */ + +function isJSON(mime) { + return /[\/+]json\b/.test(mime); +} + +/** + * Initialize a new `Response` with the given `xhr`. + * + * - set flags (.ok, .error, etc) + * - parse header + * + * Examples: + * + * Aliasing `superagent` as `request` is nice: + * + * request = superagent; + * + * We can use the promise-like API, or pass callbacks: + * + * request.get('/').end(function(res){}); + * request.get('/', function(res){}); + * + * Sending data can be chained: + * + * request + * .post('/user') + * .send({ name: 'tj' }) + * .end(function(res){}); + * + * Or passed to `.send()`: + * + * request + * .post('/user') + * .send({ name: 'tj' }, function(res){}); + * + * Or passed to `.post()`: + * + * request + * .post('/user', { name: 'tj' }) + * .end(function(res){}); + * + * Or further reduced to a single call for simple cases: + * + * request + * .post('/user', { name: 'tj' }, function(res){}); + * + * @param {XMLHTTPRequest} xhr + * @param {Object} options + * @api private + */ - if (typeof module !== 'undefined' && module.exports) { - module.exports = methods; +function Response(req) { + this.req = req; + this.xhr = this.req.xhr; + // responseText is accessible only if responseType is '' or 'text' and on older browsers + this.text = ((this.req.method !='HEAD' && (this.xhr.responseType === '' || this.xhr.responseType === 'text')) || typeof this.xhr.responseType === 'undefined') + ? this.xhr.responseText + : null; + this.statusText = this.req.xhr.statusText; + var status = this.xhr.status; + // handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request + if (status === 1223) { + status = 204; } + this._setStatusProperties(status); + this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders()); + // getAllResponseHeaders sometimes falsely returns "" for CORS requests, but + // getResponseHeader still works. so we get content-type even if getting + // other headers fails. + this.header['content-type'] = this.xhr.getResponseHeader('content-type'); + this._setHeaderProperties(this.header); - return methods; -}(); - -module.exports = wtf_wikipedia; + if (null === this.text && req._responseType) { + this.body = this.xhr.response; + } else { + this.body = this.req.method != 'HEAD' + ? this._parseBody(this.text ? this.text : this.xhr.response) + : null; + } +} -},{"./data/i18n":6,"./data/languages":7,"./lib/fetch_text":10,"./lib/helpers":12,"./lib/make_image":13,"./lib/sentence_parser":14,"./parse/cleanup_misc":15,"./parse/parse_categories":17,"./parse/parse_disambig":18,"./parse/parse_image":19,"./parse/parse_infobox":20,"./parse/parse_infobox_template":21,"./parse/parse_line":22,"./parse/parse_redirects":24,"./parse/parse_table":25,"./recursive_matches":26,"./word_templates":27}],10:[function(_dereq_,module,exports){ -'use strict'; -//grab the content of any article, off the api +ResponseBase(Response.prototype); -var request = _dereq_('superagent'); -var site_map = _dereq_('../data/site_map'); -var redirects = _dereq_('../parse/parse_redirects'); +/** + * Parse the given body `str`. + * + * Used for auto-parsing of bodies. Parsers + * are defined on the `superagent.parse` object. + * + * @param {String} str + * @return {Mixed} + * @api private + */ -var fetch = function fetch(page_identifier, lang_or_wikiid, cb) { - lang_or_wikiid = lang_or_wikiid || 'en'; - var identifier_type = 'titles'; - if (page_identifier.match(/^[0-9]*$/) && page_identifier.length > 3) { - identifier_type = 'curid'; +Response.prototype._parseBody = function(str){ + var parse = request.parse[this.type]; + if(this.req._parser) { + return this.req._parser(this, str); } - var url; - if (site_map[lang_or_wikiid]) { - url = site_map[lang_or_wikiid] + '/w/api.php'; - } else { - url = 'https://' + lang_or_wikiid + '.wikipedia.org/w/api.php'; + if (!parse && isJSON(this.type)) { + parse = request.parse['application/json']; } - //we use the 'revisions' api here, instead of the Raw api, for its CORS-rules.. - url += '?action=query&prop=revisions&rvlimit=1&rvprop=content&format=json&origin=*'; - url += '&' + identifier_type + '=' + page_identifier; - - request.get(url).end(function (err, res) { - if (err) { - console.warn(err); - cb(null); - return; - } - var pages = res.body.query.pages || {}; - var id = Object.keys(pages)[0]; - if (id) { - var page = pages[id]; - if (page && page.revisions && page.revisions[0]) { - var text = page.revisions[0]['*']; - if (redirects.is_redirect(text)) { - var result = redirects.parse_redirect(text); - fetch(result.redirect, lang_or_wikiid, cb); //recursive - return; - } - cb(text); - } - } - }); + return parse && str && (str.length || str instanceof Object) + ? parse(str) + : null; }; -module.exports = fetch; - -// fetch('On_A_Friday', 'en', function(r) { // 'afwiki' -// console.log(JSON.stringify(r, null, 2)); -// }); - -},{"../data/site_map":8,"../parse/parse_redirects":24,"superagent":2}],11:[function(_dereq_,module,exports){ -(function (global){ -'use strict'; - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - /** - * jshashes - https://github.com/h2non/jshashes - * Released under the "New BSD" license - * - * Algorithms specification: + * Return an `Error` representative of this response. * - * MD5 - http://www.ietf.org/rfc/rfc1321.txt - * RIPEMD-160 - http://homes.esat.kuleuven.be/~bosselae/ripemd160.html - * SHA1 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf - * SHA256 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf - * SHA512 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf - * HMAC - http://www.ietf.org/rfc/rfc2104.txt + * @return {Error} + * @api public */ -(function () { - var Hashes; - function utf8Encode(str) { - var x, - y, - output = '', - i = -1, - l; +Response.prototype.toError = function(){ + var req = this.req; + var method = req.method; + var url = req.url; - if (str && str.length) { - l = str.length; - while ((i += 1) < l) { - /* Decode utf-16 surrogate pairs */ - x = str.charCodeAt(i); - y = i + 1 < l ? str.charCodeAt(i + 1) : 0; - if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) { - x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF); - i += 1; - } - /* Encode output as utf-8 */ - if (x <= 0x7F) { - output += String.fromCharCode(x); - } else if (x <= 0x7FF) { - output += String.fromCharCode(0xC0 | x >>> 6 & 0x1F, 0x80 | x & 0x3F); - } else if (x <= 0xFFFF) { - output += String.fromCharCode(0xE0 | x >>> 12 & 0x0F, 0x80 | x >>> 6 & 0x3F, 0x80 | x & 0x3F); - } else if (x <= 0x1FFFFF) { - output += String.fromCharCode(0xF0 | x >>> 18 & 0x07, 0x80 | x >>> 12 & 0x3F, 0x80 | x >>> 6 & 0x3F, 0x80 | x & 0x3F); - } - } - } - return output; - } + var msg = 'cannot ' + method + ' ' + url + ' (' + this.status + ')'; + var err = new Error(msg); + err.status = this.status; + err.method = method; + err.url = url; - function utf8Decode(str) { - var i, - ac, - c1, - c2, - c3, - arr = [], - l; - i = ac = c1 = c2 = c3 = 0; + return err; +}; - if (str && str.length) { - l = str.length; - str += ''; +/** + * Expose `Response`. + */ - while (i < l) { - c1 = str.charCodeAt(i); - ac += 1; - if (c1 < 128) { - arr[ac] = String.fromCharCode(c1); - i += 1; - } else if (c1 > 191 && c1 < 224) { - c2 = str.charCodeAt(i + 1); - arr[ac] = String.fromCharCode((c1 & 31) << 6 | c2 & 63); - i += 2; - } else { - c2 = str.charCodeAt(i + 1); - c3 = str.charCodeAt(i + 2); - arr[ac] = String.fromCharCode((c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63); - i += 3; - } - } - } - return arr.join(''); - } +request.Response = Response; - /** - * Add integers, wrapping at 2^32. This uses 16-bit operations internally - * to work around bugs in some JS interpreters. - */ +/** + * Initialize a new `Request` with the given `method` and `url`. + * + * @param {String} method + * @param {String} url + * @api public + */ - function safe_add(x, y) { - var lsw = (x & 0xFFFF) + (y & 0xFFFF), - msw = (x >> 16) + (y >> 16) + (lsw >> 16); - return msw << 16 | lsw & 0xFFFF; - } +function Request(method, url) { + var self = this; + this._query = this._query || []; + this.method = method; + this.url = url; + this.header = {}; // preserves header name case + this._header = {}; // coerces header names to lowercase + this.on('end', function(){ + var err = null; + var res = null; - /** - * Bitwise rotate a 32-bit number to the left. - */ + try { + res = new Response(self); + } catch(e) { + err = new Error('Parser is unable to parse the response'); + err.parse = true; + err.original = e; + // issue #675: return the raw response if the response parsing fails + if (self.xhr) { + // ie9 doesn't have 'response' property + err.rawResponse = typeof self.xhr.responseType == 'undefined' ? self.xhr.responseText : self.xhr.response; + // issue #876: return the http status code if the response parsing fails + err.status = self.xhr.status ? self.xhr.status : null; + err.statusCode = err.status; // backwards-compat only + } else { + err.rawResponse = null; + err.status = null; + } - function bit_rol(num, cnt) { - return num << cnt | num >>> 32 - cnt; - } + return self.callback(err); + } - /** - * Convert a raw string to a hex string - */ + self.emit('response', res); - function rstr2hex(input, hexcase) { - var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef', - output = '', - x, - i = 0, - l = input.length; - for (; i < l; i += 1) { - x = input.charCodeAt(i); - output += hex_tab.charAt(x >>> 4 & 0x0F) + hex_tab.charAt(x & 0x0F); + var new_err; + try { + if (!self._isResponseOK(res)) { + new_err = new Error(res.statusText || 'Unsuccessful HTTP response'); + new_err.original = err; + new_err.response = res; + new_err.status = res.status; + } + } catch(e) { + new_err = e; // #985 touching res may cause INVALID_STATE_ERR on old Android } - return output; - } - - /** - * Encode a string as utf-16 - */ - function str2rstr_utf16le(input) { - var i, - l = input.length, - output = ''; - for (i = 0; i < l; i += 1) { - output += String.fromCharCode(input.charCodeAt(i) & 0xFF, input.charCodeAt(i) >>> 8 & 0xFF); + // #1000 don't catch errors from the callback to avoid double calling it + if (new_err) { + self.callback(new_err, res); + } else { + self.callback(null, res); } - return output; - } + }); +} - function str2rstr_utf16be(input) { - var i, - l = input.length, - output = ''; - for (i = 0; i < l; i += 1) { - output += String.fromCharCode(input.charCodeAt(i) >>> 8 & 0xFF, input.charCodeAt(i) & 0xFF); - } - return output; - } +/** + * Mixin `Emitter` and `RequestBase`. + */ - /** - * Convert an array of big-endian words to a string - */ +Emitter(Request.prototype); +RequestBase(Request.prototype); - function binb2rstr(input) { - var i, - l = input.length * 32, - output = ''; - for (i = 0; i < l; i += 8) { - output += String.fromCharCode(input[i >> 5] >>> 24 - i % 32 & 0xFF); - } - return output; - } +/** + * Set Content-Type to `type`, mapping values from `request.types`. + * + * Examples: + * + * superagent.types.xml = 'application/xml'; + * + * request.post('/') + * .type('xml') + * .send(xmlstring) + * .end(callback); + * + * request.post('/') + * .type('application/xml') + * .send(xmlstring) + * .end(callback); + * + * @param {String} type + * @return {Request} for chaining + * @api public + */ - /** - * Convert an array of little-endian words to a string - */ +Request.prototype.type = function(type){ + this.set('Content-Type', request.types[type] || type); + return this; +}; - function binl2rstr(input) { - var i, - l = input.length * 32, - output = ''; - for (i = 0; i < l; i += 8) { - output += String.fromCharCode(input[i >> 5] >>> i % 32 & 0xFF); - } - return output; - } +/** + * Set Accept to `type`, mapping values from `request.types`. + * + * Examples: + * + * superagent.types.json = 'application/json'; + * + * request.get('/agent') + * .accept('json') + * .end(callback); + * + * request.get('/agent') + * .accept('application/json') + * .end(callback); + * + * @param {String} accept + * @return {Request} for chaining + * @api public + */ - /** - * Convert a raw string to an array of little-endian words - * Characters >255 have their high-byte silently ignored. - */ +Request.prototype.accept = function(type){ + this.set('Accept', request.types[type] || type); + return this; +}; - function rstr2binl(input) { - var i, - l = input.length * 8, - output = Array(input.length >> 2), - lo = output.length; - for (i = 0; i < lo; i += 1) { - output[i] = 0; - } - for (i = 0; i < l; i += 8) { - output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << i % 32; +/** + * Set Authorization field value with `user` and `pass`. + * + * @param {String} user + * @param {String} [pass] optional in case of using 'bearer' as type + * @param {Object} options with 'type' property 'auto', 'basic' or 'bearer' (default 'basic') + * @return {Request} for chaining + * @api public + */ + +Request.prototype.auth = function(user, pass, options){ + if (typeof pass === 'object' && pass !== null) { // pass is optional and can substitute for options + options = pass; + } + if (!options) { + options = { + type: 'function' === typeof btoa ? 'basic' : 'auto', } - return output; } - /** - * Convert a raw string to an array of big-endian words - * Characters >255 have their high-byte silently ignored. - */ + switch (options.type) { + case 'basic': + this.set('Authorization', 'Basic ' + btoa(user + ':' + pass)); + break; - function rstr2binb(input) { - var i, - l = input.length * 8, - output = Array(input.length >> 2), - lo = output.length; - for (i = 0; i < lo; i += 1) { - output[i] = 0; - } - for (i = 0; i < l; i += 8) { - output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << 24 - i % 32; - } - return output; + case 'auto': + this.username = user; + this.password = pass; + break; + + case 'bearer': // usage would be .auth(accessToken, { type: 'bearer' }) + this.set('Authorization', 'Bearer ' + user); + break; } + return this; +}; - /** - * Convert a raw string to an arbitrary string encoding - */ - - function rstr2any(input, encoding) { - var divisor = encoding.length, - remainders = Array(), - i, - q, - x, - ld, - quotient, - dividend, - output, - full_length; +/** + * Add query-string `val`. + * + * Examples: + * + * request.get('/shoes') + * .query('size=10') + * .query({ color: 'blue' }) + * + * @param {Object|String} val + * @return {Request} for chaining + * @api public + */ - /* Convert to an array of 16-bit big-endian values, forming the dividend */ - dividend = Array(Math.ceil(input.length / 2)); - ld = dividend.length; - for (i = 0; i < ld; i += 1) { - dividend[i] = input.charCodeAt(i * 2) << 8 | input.charCodeAt(i * 2 + 1); - } +Request.prototype.query = function(val){ + if ('string' != typeof val) val = serialize(val); + if (val) this._query.push(val); + return this; +}; - /** - * Repeatedly perform a long division. The binary array forms the dividend, - * the length of the encoding is the divisor. Once computed, the quotient - * forms the dividend for the next step. We stop when the dividend is zerHashes. - * All remainders are stored for later use. - */ - while (dividend.length > 0) { - quotient = Array(); - x = 0; - for (i = 0; i < dividend.length; i += 1) { - x = (x << 16) + dividend[i]; - q = Math.floor(x / divisor); - x -= q * divisor; - if (quotient.length > 0 || q > 0) { - quotient[quotient.length] = q; - } - } - remainders[remainders.length] = x; - dividend = quotient; - } +/** + * Queue the given `file` as an attachment to the specified `field`, + * with optional `options` (or filename). + * + * ``` js + * request.post('/upload') + * .attach('content', new Blob(['hey!'], { type: "text/html"})) + * .end(callback); + * ``` + * + * @param {String} field + * @param {Blob|File} file + * @param {String|Object} options + * @return {Request} for chaining + * @api public + */ - /* Convert the remainders to the output string */ - output = ''; - for (i = remainders.length - 1; i >= 0; i--) { - output += encoding.charAt(remainders[i]); +Request.prototype.attach = function(field, file, options){ + if (file) { + if (this._data) { + throw Error("superagent can't mix .send() and .attach()"); } - /* Append leading zero equivalents */ - full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2))); - for (i = output.length; i < full_length; i += 1) { - output = encoding[0] + output; - } - return output; + this._getFormData().append(field, file, options || file.name); } + return this; +}; - /** - * Convert a raw string to a base-64 string - */ - - function rstr2b64(input, b64pad) { - var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', - output = '', - len = input.length, - i, - j, - triplet; - b64pad = b64pad || '='; - for (i = 0; i < len; i += 3) { - triplet = input.charCodeAt(i) << 16 | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0); - for (j = 0; j < 4; j += 1) { - if (i * 8 + j * 6 > input.length * 8) { - output += b64pad; - } else { - output += tab.charAt(triplet >>> 6 * (3 - j) & 0x3F); - } - } - } - return output; +Request.prototype._getFormData = function(){ + if (!this._formData) { + this._formData = new root.FormData(); } + return this._formData; +}; - Hashes = { - /** - * @property {String} version - * @readonly - */ - VERSION: '1.0.5', - /** - * @member Hashes - * @class Base64 - * @constructor - */ - Base64: function Base64() { - // private properties - var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', - pad = '=', - // default pad according with the RFC standard - url = false, - // URL encoding support @todo - utf8 = true; // by default enable UTF-8 support encoding - - // public method for encoding - this.encode = function (input) { - var i, - j, - triplet, - output = '', - len = input.length; - - pad = pad || '='; - input = utf8 ? utf8Encode(input) : input; - - for (i = 0; i < len; i += 3) { - triplet = input.charCodeAt(i) << 16 | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0); - for (j = 0; j < 4; j += 1) { - if (i * 8 + j * 6 > len * 8) { - output += pad; - } else { - output += tab.charAt(triplet >>> 6 * (3 - j) & 0x3F); - } - } - } - return output; - }; +/** + * Invoke the callback with `err` and `res` + * and handle arity check. + * + * @param {Error} err + * @param {Response} res + * @api private + */ - // public method for decoding - this.decode = function (input) { - // var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; - var i, - o1, - o2, - o3, - h1, - h2, - h3, - h4, - bits, - ac, - dec = '', - arr = []; - if (!input) { - return input; - } +Request.prototype.callback = function(err, res){ + // console.log(this._retries, this._maxRetries) + if (this._maxRetries && this._retries++ < this._maxRetries && shouldRetry(err, res)) { + return this._retry(); + } - i = ac = 0; - input = input.replace(new RegExp('\\' + pad, 'gi'), ''); // use '=' - //input += ''; + var fn = this._callback; + this.clearTimeout(); - do { - // unpack four hexets into three octets using index points in b64 - h1 = tab.indexOf(input.charAt(i += 1)); - h2 = tab.indexOf(input.charAt(i += 1)); - h3 = tab.indexOf(input.charAt(i += 1)); - h4 = tab.indexOf(input.charAt(i += 1)); + if (err) { + if (this._maxRetries) err.retries = this._retries - 1; + this.emit('error', err); + } - bits = h1 << 18 | h2 << 12 | h3 << 6 | h4; + fn(err, res); +}; - o1 = bits >> 16 & 0xff; - o2 = bits >> 8 & 0xff; - o3 = bits & 0xff; - ac += 1; +/** + * Invoke callback with x-domain error. + * + * @api private + */ - if (h3 === 64) { - arr[ac] = String.fromCharCode(o1); - } else if (h4 === 64) { - arr[ac] = String.fromCharCode(o1, o2); - } else { - arr[ac] = String.fromCharCode(o1, o2, o3); - } - } while (i < input.length); +Request.prototype.crossDomainError = function(){ + var err = new Error('Request has been terminated\nPossible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.'); + err.crossDomain = true; - dec = arr.join(''); - dec = utf8 ? utf8Decode(dec) : dec; + err.status = this.status; + err.method = this.method; + err.url = this.url; - return dec; - }; + this.callback(err); +}; - // set custom pad string - this.setPad = function (str) { - pad = str || pad; - return this; - }; - // set custom tab string characters - this.setTab = function (str) { - tab = str || tab; - return this; - }; - this.setUTF8 = function (bool) { - if (typeof bool === 'boolean') { - utf8 = bool; - } - return this; - }; - }, +// This only warns, because the request is still likely to work +Request.prototype.buffer = Request.prototype.ca = Request.prototype.agent = function(){ + console.warn("This is not supported in browser version of superagent"); + return this; +}; - /** - * CRC-32 calculation - * @member Hashes - * @method CRC32 - * @static - * @param {String} str Input String - * @return {String} - */ - CRC32: function CRC32(str) { - var crc = 0, - x = 0, - y = 0, - table, - i, - iTop; - str = utf8Encode(str); +// This throws, because it can't send/receive data as expected +Request.prototype.pipe = Request.prototype.write = function(){ + throw Error("Streaming is not supported in browser version of superagent"); +}; + +/** + * Compose querystring to append to req.url + * + * @api private + */ - table = ['00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 ', '79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 ', '84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F ', '63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD ', 'A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC ', '51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 ', 'B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 ', '06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 ', 'E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 ', '12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 ', 'D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 ', '33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 ', 'CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 ', '9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E ', '7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D ', '806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 ', '60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA ', 'AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 ', '5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 ', 'B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 ', '05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 ', 'F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA ', '11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 ', 'D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F ', '30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E ', 'C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D'].join(''); +Request.prototype._appendQueryString = function(){ + var query = this._query.join('&'); + if (query) { + this.url += (this.url.indexOf('?') >= 0 ? '&' : '?') + query; + } - crc = crc ^ -1; - for (i = 0, iTop = str.length; i < iTop; i += 1) { - y = (crc ^ str.charCodeAt(i)) & 0xFF; - x = '0x' + table.substr(y * 9, 8); - crc = crc >>> 8 ^ x; + if (this._sort) { + var index = this.url.indexOf('?'); + if (index >= 0) { + var queryArr = this.url.substring(index + 1).split('&'); + if (isFunction(this._sort)) { + queryArr.sort(this._sort); + } else { + queryArr.sort(); } - // always return a positive number (that's what >>> 0 does) - return (crc ^ -1) >>> 0; - }, - /** - * @member Hashes - * @class MD5 - * @constructor - * @param {Object} [config] - * - * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message - * Digest Algorithm, as defined in RFC 1321. - * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 - * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet - * See for more infHashes. - */ - MD5: function MD5(options) { - /** - * Private config properties. You may need to tweak these to be compatible with - * the server-side, but the defaults work in most cases. - * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase} - */ - var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false, - // hexadecimal output case format. false - lowercase; true - uppercase - b64pad = options && typeof options.pad === 'string' ? options.pda : '=', - // base-64 pad character. Defaults to '=' for strict RFC compliance - utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true; // enable/disable utf8 encoding + this.url = this.url.substring(0, index) + '?' + queryArr.join('&'); + } + } +}; - // privileged (public) methods - this.hex = function (s) { - return rstr2hex(rstr(s, utf8), hexcase); - }; - this.b64 = function (s) { - return rstr2b64(rstr(s), b64pad); - }; - this.any = function (s, e) { - return rstr2any(rstr(s, utf8), e); - }; - this.raw = function (s) { - return rstr(s, utf8); - }; - this.hex_hmac = function (k, d) { - return rstr2hex(rstr_hmac(k, d), hexcase); - }; - this.b64_hmac = function (k, d) { - return rstr2b64(rstr_hmac(k, d), b64pad); - }; - this.any_hmac = function (k, d, e) { - return rstr2any(rstr_hmac(k, d), e); - }; - /** - * Perform a simple self-test to see if the VM is working - * @return {String} Hexadecimal hash sample - */ - this.vm_test = function () { - return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72'; - }; - /** - * Enable/disable uppercase hexadecimal returned string - * @param {Boolean} - * @return {Object} this - */ - this.setUpperCase = function (a) { - if (typeof a === 'boolean') { - hexcase = a; - } - return this; - }; - /** - * Defines a base64 pad string - * @param {String} Pad - * @return {Object} this - */ - this.setPad = function (a) { - b64pad = a || b64pad; - return this; - }; - /** - * Defines a base64 pad string - * @param {Boolean} - * @return {Object} [this] - */ - this.setUTF8 = function (a) { - if (typeof a === 'boolean') { - utf8 = a; - } - return this; - }; +/** + * Check if `obj` is a host object, + * we don't want to serialize these :) + * + * @param {Object} obj + * @return {Boolean} + * @api private + */ +Request.prototype._isHost = function _isHost(obj) { + // Native objects stringify to [object File], [object Blob], [object FormData], etc. + return obj && 'object' === typeof obj && !Array.isArray(obj) && Object.prototype.toString.call(obj) !== '[object Object]'; +} - // private methods +/** + * Initiate request, invoking callback `fn(res)` + * with an instanceof `Response`. + * + * @param {Function} fn + * @return {Request} for chaining + * @api public + */ - /** - * Calculate the MD5 of a raw string - */ +Request.prototype.end = function(fn){ + if (this._endCalled) { + console.warn("Warning: .end() was called twice. This is not supported in superagent"); + } + this._endCalled = true; - function rstr(s) { - s = utf8 ? utf8Encode(s) : s; - return binl2rstr(binl(rstr2binl(s), s.length * 8)); - } + // store callback + this._callback = fn || noop; - /** - * Calculate the HMAC-MD5, of a key and some data (raw strings) - */ + // querystring + this._appendQueryString(); - function rstr_hmac(key, data) { - var bkey, ipad, opad, hash, i; + return this._end(); +}; - key = utf8 ? utf8Encode(key) : key; - data = utf8 ? utf8Encode(data) : data; - bkey = rstr2binl(key); - if (bkey.length > 16) { - bkey = binl(bkey, key.length * 8); - } +Request.prototype._end = function() { + var self = this; + var xhr = this.xhr = request.getXHR(); + var data = this._formData || this._data; - ipad = Array(16), opad = Array(16); - for (i = 0; i < 16; i += 1) { - ipad[i] = bkey[i] ^ 0x36363636; - opad[i] = bkey[i] ^ 0x5C5C5C5C; - } - hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8); - return binl2rstr(binl(opad.concat(hash), 512 + 128)); + this._setTimeouts(); + + // state change + xhr.onreadystatechange = function(){ + var readyState = xhr.readyState; + if (readyState >= 2 && self._responseTimeoutTimer) { + clearTimeout(self._responseTimeoutTimer); + } + if (4 != readyState) { + return; + } + + // In IE9, reads to any property (e.g. status) off of an aborted XHR will + // result in the error "Could not complete the operation due to error c00c023f" + var status; + try { status = xhr.status } catch(e) { status = 0; } + + if (!status) { + if (self.timedout || self._aborted) return; + return self.crossDomainError(); + } + self.emit('end'); + }; + + // progress + var handleProgress = function(direction, e) { + if (e.total > 0) { + e.percent = e.loaded / e.total * 100; + } + e.direction = direction; + self.emit('progress', e); + } + if (this.hasListeners('progress')) { + try { + xhr.onprogress = handleProgress.bind(null, 'download'); + if (xhr.upload) { + xhr.upload.onprogress = handleProgress.bind(null, 'upload'); } + } catch(e) { + // Accessing xhr.upload fails in IE from a web worker, so just pretend it doesn't exist. + // Reported here: + // https://connect.microsoft.com/IE/feedback/details/837245/xmlhttprequest-upload-throws-invalid-argument-when-used-from-web-worker-context + } + } - /** - * Calculate the MD5 of an array of little-endian words, and a bit length. - */ + // initiate request + try { + if (this.username && this.password) { + xhr.open(this.method, this.url, true, this.username, this.password); + } else { + xhr.open(this.method, this.url, true); + } + } catch (err) { + // see #1149 + return this.callback(err); + } + + // CORS + if (this._withCredentials) xhr.withCredentials = true; - function binl(x, len) { - var i, - olda, - oldb, - oldc, - oldd, - a = 1732584193, - b = -271733879, - c = -1732584194, - d = 271733878; + // body + if (!this._formData && 'GET' != this.method && 'HEAD' != this.method && 'string' != typeof data && !this._isHost(data)) { + // serialize stuff + var contentType = this._header['content-type']; + var serialize = this._serializer || request.serialize[contentType ? contentType.split(';')[0] : '']; + if (!serialize && isJSON(contentType)) { + serialize = request.serialize['application/json']; + } + if (serialize) data = serialize(data); + } - /* append padding */ - x[len >> 5] |= 0x80 << len % 32; - x[(len + 64 >>> 9 << 4) + 14] = len; + // set header fields + for (var field in this.header) { + if (null == this.header[field]) continue; - for (i = 0; i < x.length; i += 16) { - olda = a; - oldb = b; - oldc = c; - oldd = d; + if (this.header.hasOwnProperty(field)) + xhr.setRequestHeader(field, this.header[field]); + } - a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936); - d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586); - c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819); - b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330); - a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897); - d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426); - c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341); - b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983); - a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416); - d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417); - c = md5_ff(c, d, a, b, x[i + 10], 17, -42063); - b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162); - a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682); - d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101); - c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290); - b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329); + if (this._responseType) { + xhr.responseType = this._responseType; + } - a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510); - d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632); - c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713); - b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302); - a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691); - d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083); - c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335); - b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848); - a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438); - d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690); - c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961); - b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501); - a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467); - d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784); - c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473); - b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734); + // send stuff + this.emit('request', this); - a = md5_hh(a, b, c, d, x[i + 5], 4, -378558); - d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463); - c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562); - b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556); - a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060); - d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353); - c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632); - b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640); - a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174); - d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222); - c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979); - b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189); - a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487); - d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835); - c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520); - b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651); + // IE11 xhr.send(undefined) sends 'undefined' string as POST payload (instead of nothing) + // We need null here if data is undefined + xhr.send(typeof data !== 'undefined' ? data : null); + return this; +}; - a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844); - d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415); - c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905); - b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055); - a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571); - d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606); - c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523); - b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799); - a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359); - d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744); - c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380); - b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649); - a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070); - d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379); - c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259); - b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551); +/** + * GET `url` with optional callback `fn(res)`. + * + * @param {String} url + * @param {Mixed|Function} [data] or fn + * @param {Function} [fn] + * @return {Request} + * @api public + */ - a = safe_add(a, olda); - b = safe_add(b, oldb); - c = safe_add(c, oldc); - d = safe_add(d, oldd); - } - return Array(a, b, c, d); - } +request.get = function(url, data, fn){ + var req = request('GET', url); + if ('function' == typeof data) fn = data, data = null; + if (data) req.query(data); + if (fn) req.end(fn); + return req; +}; - /** - * These functions implement the four basic operations the algorithm uses. - */ +/** + * HEAD `url` with optional callback `fn(res)`. + * + * @param {String} url + * @param {Mixed|Function} [data] or fn + * @param {Function} [fn] + * @return {Request} + * @api public + */ - function md5_cmn(q, a, b, x, s, t) { - return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b); - } +request.head = function(url, data, fn){ + var req = request('HEAD', url); + if ('function' == typeof data) fn = data, data = null; + if (data) req.send(data); + if (fn) req.end(fn); + return req; +}; - function md5_ff(a, b, c, d, x, s, t) { - return md5_cmn(b & c | ~b & d, a, b, x, s, t); - } +/** + * OPTIONS query to `url` with optional callback `fn(res)`. + * + * @param {String} url + * @param {Mixed|Function} [data] or fn + * @param {Function} [fn] + * @return {Request} + * @api public + */ - function md5_gg(a, b, c, d, x, s, t) { - return md5_cmn(b & d | c & ~d, a, b, x, s, t); - } +request.options = function(url, data, fn){ + var req = request('OPTIONS', url); + if ('function' == typeof data) fn = data, data = null; + if (data) req.send(data); + if (fn) req.end(fn); + return req; +}; - function md5_hh(a, b, c, d, x, s, t) { - return md5_cmn(b ^ c ^ d, a, b, x, s, t); - } +/** + * DELETE `url` with optional `data` and callback `fn(res)`. + * + * @param {String} url + * @param {Mixed} [data] + * @param {Function} [fn] + * @return {Request} + * @api public + */ - function md5_ii(a, b, c, d, x, s, t) { - return md5_cmn(c ^ (b | ~d), a, b, x, s, t); - } - }, - /** - * @member Hashes - * @class Hashes.SHA1 - * @param {Object} [config] - * @constructor - * - * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS 180-1 - * Version 2.2 Copyright Paul Johnston 2000 - 2009. - * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet - * See http://pajhome.org.uk/crypt/md5 for details. - */ - SHA1: function SHA1(options) { - /** - * Private config properties. You may need to tweak these to be compatible with - * the server-side, but the defaults work in most cases. - * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase} - */ - var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false, - // hexadecimal output case format. false - lowercase; true - uppercase - b64pad = options && typeof options.pad === 'string' ? options.pda : '=', - // base-64 pad character. Defaults to '=' for strict RFC compliance - utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true; // enable/disable utf8 encoding +function del(url, data, fn){ + var req = request('DELETE', url); + if ('function' == typeof data) fn = data, data = null; + if (data) req.send(data); + if (fn) req.end(fn); + return req; +}; - // public methods - this.hex = function (s) { - return rstr2hex(rstr(s, utf8), hexcase); - }; - this.b64 = function (s) { - return rstr2b64(rstr(s, utf8), b64pad); - }; - this.any = function (s, e) { - return rstr2any(rstr(s, utf8), e); - }; - this.raw = function (s) { - return rstr(s, utf8); - }; - this.hex_hmac = function (k, d) { - return rstr2hex(rstr_hmac(k, d)); - }; - this.b64_hmac = function (k, d) { - return rstr2b64(rstr_hmac(k, d), b64pad); - }; - this.any_hmac = function (k, d, e) { - return rstr2any(rstr_hmac(k, d), e); - }; - /** - * Perform a simple self-test to see if the VM is working - * @return {String} Hexadecimal hash sample - * @public - */ - this.vm_test = function () { - return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72'; - }; - /** - * @description Enable/disable uppercase hexadecimal returned string - * @param {boolean} - * @return {Object} this - * @public - */ - this.setUpperCase = function (a) { - if (typeof a === 'boolean') { - hexcase = a; - } - return this; - }; - /** - * @description Defines a base64 pad string - * @param {string} Pad - * @return {Object} this - * @public - */ - this.setPad = function (a) { - b64pad = a || b64pad; - return this; - }; - /** - * @description Defines a base64 pad string - * @param {boolean} - * @return {Object} this - * @public - */ - this.setUTF8 = function (a) { - if (typeof a === 'boolean') { - utf8 = a; - } - return this; - }; +request['del'] = del; +request['delete'] = del; + +/** + * PATCH `url` with optional `data` and callback `fn(res)`. + * + * @param {String} url + * @param {Mixed} [data] + * @param {Function} [fn] + * @return {Request} + * @api public + */ - // private methods +request.patch = function(url, data, fn){ + var req = request('PATCH', url); + if ('function' == typeof data) fn = data, data = null; + if (data) req.send(data); + if (fn) req.end(fn); + return req; +}; - /** - * Calculate the SHA-512 of a raw string - */ +/** + * POST `url` with optional `data` and callback `fn(res)`. + * + * @param {String} url + * @param {Mixed} [data] + * @param {Function} [fn] + * @return {Request} + * @api public + */ - function rstr(s) { - s = utf8 ? utf8Encode(s) : s; - return binb2rstr(binb(rstr2binb(s), s.length * 8)); - } +request.post = function(url, data, fn){ + var req = request('POST', url); + if ('function' == typeof data) fn = data, data = null; + if (data) req.send(data); + if (fn) req.end(fn); + return req; +}; - /** - * Calculate the HMAC-SHA1 of a key and some data (raw strings) - */ +/** + * PUT `url` with optional `data` and callback `fn(res)`. + * + * @param {String} url + * @param {Mixed|Function} [data] or fn + * @param {Function} [fn] + * @return {Request} + * @api public + */ - function rstr_hmac(key, data) { - var bkey, ipad, opad, i, hash; - key = utf8 ? utf8Encode(key) : key; - data = utf8 ? utf8Encode(data) : data; - bkey = rstr2binb(key); +request.put = function(url, data, fn){ + var req = request('PUT', url); + if ('function' == typeof data) fn = data, data = null; + if (data) req.send(data); + if (fn) req.end(fn); + return req; +}; - if (bkey.length > 16) { - bkey = binb(bkey, key.length * 8); - } - ipad = Array(16), opad = Array(16); - for (i = 0; i < 16; i += 1) { - ipad[i] = bkey[i] ^ 0x36363636; - opad[i] = bkey[i] ^ 0x5C5C5C5C; - } - hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8); - return binb2rstr(binb(opad.concat(hash), 512 + 160)); - } +},{"./is-function":4,"./is-object":5,"./request-base":6,"./response-base":7,"./should-retry":8,"component-emitter":1}],4:[function(_dereq_,module,exports){ +/** + * Check if `fn` is a function. + * + * @param {Function} fn + * @return {Boolean} + * @api private + */ +var isObject = _dereq_('./is-object'); - /** - * Calculate the SHA-1 of an array of big-endian words, and a bit length - */ +function isFunction(fn) { + var tag = isObject(fn) ? Object.prototype.toString.call(fn) : ''; + return tag === '[object Function]'; +} - function binb(x, len) { - var i, - j, - t, - olda, - oldb, - oldc, - oldd, - olde, - w = Array(80), - a = 1732584193, - b = -271733879, - c = -1732584194, - d = 271733878, - e = -1009589776; +module.exports = isFunction; - /* append padding */ - x[len >> 5] |= 0x80 << 24 - len % 32; - x[(len + 64 >> 9 << 4) + 15] = len; +},{"./is-object":5}],5:[function(_dereq_,module,exports){ +/** + * Check if `obj` is an object. + * + * @param {Object} obj + * @return {Boolean} + * @api private + */ - for (i = 0; i < x.length; i += 16) { - olda = a, oldb = b; - oldc = c; - oldd = d; - olde = e; +function isObject(obj) { + return null !== obj && 'object' === typeof obj; +} - for (j = 0; j < 80; j += 1) { - if (j < 16) { - w[j] = x[i + j]; - } else { - w[j] = bit_rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1); - } - t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)), safe_add(safe_add(e, w[j]), sha1_kt(j))); - e = d; - d = c; - c = bit_rol(b, 30); - b = a; - a = t; - } +module.exports = isObject; - a = safe_add(a, olda); - b = safe_add(b, oldb); - c = safe_add(c, oldc); - d = safe_add(d, oldd); - e = safe_add(e, olde); - } - return Array(a, b, c, d, e); - } +},{}],6:[function(_dereq_,module,exports){ +/** + * Module of mixed-in functions shared between node and client code + */ +var isObject = _dereq_('./is-object'); - /** - * Perform the appropriate triplet combination function for the current - * iteration - */ +/** + * Expose `RequestBase`. + */ - function sha1_ft(t, b, c, d) { - if (t < 20) { - return b & c | ~b & d; - } - if (t < 40) { - return b ^ c ^ d; - } - if (t < 60) { - return b & c | b & d | c & d; - } - return b ^ c ^ d; - } +module.exports = RequestBase; - /** - * Determine the appropriate additive constant for the current iteration - */ +/** + * Initialize a new `RequestBase`. + * + * @api public + */ - function sha1_kt(t) { - return t < 20 ? 1518500249 : t < 40 ? 1859775393 : t < 60 ? -1894007588 : -899497514; - } - }, - /** - * @class Hashes.SHA256 - * @param {config} - * - * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined in FIPS 180-2 - * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009. - * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet - * See http://pajhome.org.uk/crypt/md5 for details. - * Also http://anmar.eu.org/projects/jssha2/ - */ - SHA256: function SHA256(options) { - /** - * Private properties configuration variables. You may need to tweak these to be compatible with - * the server-side, but the defaults work in most cases. - * @see this.setUpperCase() method - * @see this.setPad() method - */ - var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false, - // hexadecimal output case format. false - lowercase; true - uppercase */ - b64pad = options && typeof options.pad === 'string' ? options.pda : '=', +function RequestBase(obj) { + if (obj) return mixin(obj); +} - /* base-64 pad character. Default '=' for strict RFC compliance */ - utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true, +/** + * Mixin the prototype properties. + * + * @param {Object} obj + * @return {Object} + * @api private + */ - /* enable/disable utf8 encoding */ - sha256_K; +function mixin(obj) { + for (var key in RequestBase.prototype) { + obj[key] = RequestBase.prototype[key]; + } + return obj; +} - /* privileged (public) methods */ - this.hex = function (s) { - return rstr2hex(rstr(s, utf8)); - }; - this.b64 = function (s) { - return rstr2b64(rstr(s, utf8), b64pad); - }; - this.any = function (s, e) { - return rstr2any(rstr(s, utf8), e); - }; - this.raw = function (s) { - return rstr(s, utf8); - }; - this.hex_hmac = function (k, d) { - return rstr2hex(rstr_hmac(k, d)); - }; - this.b64_hmac = function (k, d) { - return rstr2b64(rstr_hmac(k, d), b64pad); - }; - this.any_hmac = function (k, d, e) { - return rstr2any(rstr_hmac(k, d), e); - }; - /** - * Perform a simple self-test to see if the VM is working - * @return {String} Hexadecimal hash sample - * @public - */ - this.vm_test = function () { - return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72'; - }; - /** - * Enable/disable uppercase hexadecimal returned string - * @param {boolean} - * @return {Object} this - * @public - */ - this.setUpperCase = function (a) { - if (typeof a === 'boolean') { - hexcase = a; - } - return this; - }; - /** - * @description Defines a base64 pad string - * @param {string} Pad - * @return {Object} this - * @public - */ - this.setPad = function (a) { - b64pad = a || b64pad; - return this; - }; - /** - * Defines a base64 pad string - * @param {boolean} - * @return {Object} this - * @public - */ - this.setUTF8 = function (a) { - if (typeof a === 'boolean') { - utf8 = a; - } - return this; - }; +/** + * Clear previous timeout. + * + * @return {Request} for chaining + * @api public + */ - // private methods +RequestBase.prototype.clearTimeout = function _clearTimeout(){ + clearTimeout(this._timer); + clearTimeout(this._responseTimeoutTimer); + delete this._timer; + delete this._responseTimeoutTimer; + return this; +}; + +/** + * Override default response body parser + * + * This function will be called to convert incoming data into request.body + * + * @param {Function} + * @api public + */ + +RequestBase.prototype.parse = function parse(fn){ + this._parser = fn; + return this; +}; + +/** + * Set format of binary response body. + * In browser valid formats are 'blob' and 'arraybuffer', + * which return Blob and ArrayBuffer, respectively. + * + * In Node all values result in Buffer. + * + * Examples: + * + * req.get('/') + * .responseType('blob') + * .end(callback); + * + * @param {String} val + * @return {Request} for chaining + * @api public + */ - /** - * Calculate the SHA-512 of a raw string - */ +RequestBase.prototype.responseType = function(val){ + this._responseType = val; + return this; +}; - function rstr(s, utf8) { - s = utf8 ? utf8Encode(s) : s; - return binb2rstr(binb(rstr2binb(s), s.length * 8)); - } +/** + * Override default request body serializer + * + * This function will be called to convert data set via .send or .attach into payload to send + * + * @param {Function} + * @api public + */ - /** - * Calculate the HMAC-sha256 of a key and some data (raw strings) - */ +RequestBase.prototype.serialize = function serialize(fn){ + this._serializer = fn; + return this; +}; - function rstr_hmac(key, data) { - key = utf8 ? utf8Encode(key) : key; - data = utf8 ? utf8Encode(data) : data; - var hash, - i = 0, - bkey = rstr2binb(key), - ipad = Array(16), - opad = Array(16); +/** + * Set timeouts. + * + * - response timeout is time between sending request and receiving the first byte of the response. Includes DNS and connection time. + * - deadline is the time from start of the request to receiving response body in full. If the deadline is too short large files may not load at all on slow connections. + * + * Value of 0 or false means no timeout. + * + * @param {Number|Object} ms or {response, read, deadline} + * @return {Request} for chaining + * @api public + */ - if (bkey.length > 16) { - bkey = binb(bkey, key.length * 8); - } +RequestBase.prototype.timeout = function timeout(options){ + if (!options || 'object' !== typeof options) { + this._timeout = options; + this._responseTimeout = 0; + return this; + } - for (; i < 16; i += 1) { - ipad[i] = bkey[i] ^ 0x36363636; - opad[i] = bkey[i] ^ 0x5C5C5C5C; - } + for(var option in options) { + switch(option) { + case 'deadline': + this._timeout = options.deadline; + break; + case 'response': + this._responseTimeout = options.response; + break; + default: + console.warn("Unknown timeout option", option); + } + } + return this; +}; - hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8); - return binb2rstr(binb(opad.concat(hash), 512 + 256)); - } +/** + * Set number of retry attempts on error. + * + * Failed requests will be retried 'count' times if timeout or err.code >= 500. + * + * @param {Number} count + * @return {Request} for chaining + * @api public + */ - /* - * Main sha256 function, with its support functions - */ +RequestBase.prototype.retry = function retry(count){ + // Default to 1 if no count passed or true + if (arguments.length === 0 || count === true) count = 1; + if (count <= 0) count = 0; + this._maxRetries = count; + this._retries = 0; + return this; +}; - function sha256_S(X, n) { - return X >>> n | X << 32 - n; - } +/** + * Retry request + * + * @return {Request} for chaining + * @api private + */ - function sha256_R(X, n) { - return X >>> n; - } +RequestBase.prototype._retry = function() { + this.clearTimeout(); - function sha256_Ch(x, y, z) { - return x & y ^ ~x & z; - } + // node + if (this.req) { + this.req = null; + this.req = this.request(); + } - function sha256_Maj(x, y, z) { - return x & y ^ x & z ^ y & z; - } + this._aborted = false; + this.timedout = false; - function sha256_Sigma0256(x) { - return sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22); - } + return this._end(); +}; - function sha256_Sigma1256(x) { - return sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25); - } +/** + * Promise support + * + * @param {Function} resolve + * @param {Function} [reject] + * @return {Request} + */ - function sha256_Gamma0256(x) { - return sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3); - } +RequestBase.prototype.then = function then(resolve, reject) { + if (!this._fullfilledPromise) { + var self = this; + if (this._endCalled) { + console.warn("Warning: superagent request was sent twice, because both .end() and .then() were called. Never call .end() if you use promises"); + } + this._fullfilledPromise = new Promise(function(innerResolve, innerReject){ + self.end(function(err, res){ + if (err) innerReject(err); else innerResolve(res); + }); + }); + } + return this._fullfilledPromise.then(resolve, reject); +} - function sha256_Gamma1256(x) { - return sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10); - } +RequestBase.prototype.catch = function(cb) { + return this.then(undefined, cb); +}; - function sha256_Sigma0512(x) { - return sha256_S(x, 28) ^ sha256_S(x, 34) ^ sha256_S(x, 39); - } +/** + * Allow for extension + */ - function sha256_Sigma1512(x) { - return sha256_S(x, 14) ^ sha256_S(x, 18) ^ sha256_S(x, 41); - } +RequestBase.prototype.use = function use(fn) { + fn(this); + return this; +} - function sha256_Gamma0512(x) { - return sha256_S(x, 1) ^ sha256_S(x, 8) ^ sha256_R(x, 7); - } +RequestBase.prototype.ok = function(cb) { + if ('function' !== typeof cb) throw Error("Callback required"); + this._okCallback = cb; + return this; +}; - function sha256_Gamma1512(x) { - return sha256_S(x, 19) ^ sha256_S(x, 61) ^ sha256_R(x, 6); - } +RequestBase.prototype._isResponseOK = function(res) { + if (!res) { + return false; + } - sha256_K = [1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993, -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987, 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522, 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585, 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291, 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885, -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344, 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218, 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872, -1866530822, -1538233109, -1090935817, -965641998]; + if (this._okCallback) { + return this._okCallback(res); + } - function binb(m, l) { - var HASH = [1779033703, -1150833019, 1013904242, -1521486534, 1359893119, -1694144372, 528734635, 1541459225]; - var W = new Array(64); - var a, b, c, d, e, f, g, h; - var i, j, T1, T2; + return res.status >= 200 && res.status < 300; +}; - /* append padding */ - m[l >> 5] |= 0x80 << 24 - l % 32; - m[(l + 64 >> 9 << 4) + 15] = l; - for (i = 0; i < m.length; i += 16) { - a = HASH[0]; - b = HASH[1]; - c = HASH[2]; - d = HASH[3]; - e = HASH[4]; - f = HASH[5]; - g = HASH[6]; - h = HASH[7]; +/** + * Get request header `field`. + * Case-insensitive. + * + * @param {String} field + * @return {String} + * @api public + */ - for (j = 0; j < 64; j += 1) { - if (j < 16) { - W[j] = m[j + i]; - } else { - W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]), sha256_Gamma0256(W[j - 15])), W[j - 16]); - } +RequestBase.prototype.get = function(field){ + return this._header[field.toLowerCase()]; +}; - T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)), sha256_K[j]), W[j]); - T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c)); - h = g; - g = f; - f = e; - e = safe_add(d, T1); - d = c; - c = b; - b = a; - a = safe_add(T1, T2); - } +/** + * Get case-insensitive header `field` value. + * This is a deprecated internal API. Use `.get(field)` instead. + * + * (getHeader is no longer used internally by the superagent code base) + * + * @param {String} field + * @return {String} + * @api private + * @deprecated + */ - HASH[0] = safe_add(a, HASH[0]); - HASH[1] = safe_add(b, HASH[1]); - HASH[2] = safe_add(c, HASH[2]); - HASH[3] = safe_add(d, HASH[3]); - HASH[4] = safe_add(e, HASH[4]); - HASH[5] = safe_add(f, HASH[5]); - HASH[6] = safe_add(g, HASH[6]); - HASH[7] = safe_add(h, HASH[7]); - } - return HASH; - } - }, +RequestBase.prototype.getHeader = RequestBase.prototype.get; - /** - * @class Hashes.SHA512 - * @param {config} - * - * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined in FIPS 180-2 - * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009. - * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet - * See http://pajhome.org.uk/crypt/md5 for details. - */ - SHA512: function SHA512(options) { - /** - * Private properties configuration variables. You may need to tweak these to be compatible with - * the server-side, but the defaults work in most cases. - * @see this.setUpperCase() method - * @see this.setPad() method - */ - var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false, +/** + * Set header `field` to `val`, or multiple fields with one object. + * Case-insensitive. + * + * Examples: + * + * req.get('/') + * .set('Accept', 'application/json') + * .set('X-API-Key', 'foobar') + * .end(callback); + * + * req.get('/') + * .set({ Accept: 'application/json', 'X-API-Key': 'foobar' }) + * .end(callback); + * + * @param {String|Object} field + * @param {String} val + * @return {Request} for chaining + * @api public + */ - /* hexadecimal output case format. false - lowercase; true - uppercase */ - b64pad = options && typeof options.pad === 'string' ? options.pda : '=', +RequestBase.prototype.set = function(field, val){ + if (isObject(field)) { + for (var key in field) { + this.set(key, field[key]); + } + return this; + } + this._header[field.toLowerCase()] = val; + this.header[field] = val; + return this; +}; - /* base-64 pad character. Default '=' for strict RFC compliance */ - utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true, +/** + * Remove header `field`. + * Case-insensitive. + * + * Example: + * + * req.get('/') + * .unset('User-Agent') + * .end(callback); + * + * @param {String} field + */ +RequestBase.prototype.unset = function(field){ + delete this._header[field.toLowerCase()]; + delete this.header[field]; + return this; +}; - /* enable/disable utf8 encoding */ - sha512_k; +/** + * Write the field `name` and `val`, or multiple fields with one object + * for "multipart/form-data" request bodies. + * + * ``` js + * request.post('/upload') + * .field('foo', 'bar') + * .end(callback); + * + * request.post('/upload') + * .field({ foo: 'bar', baz: 'qux' }) + * .end(callback); + * ``` + * + * @param {String|Object} name + * @param {String|Blob|File|Buffer|fs.ReadStream} val + * @return {Request} for chaining + * @api public + */ +RequestBase.prototype.field = function(name, val) { - /* privileged (public) methods */ - this.hex = function (s) { - return rstr2hex(rstr(s)); - }; - this.b64 = function (s) { - return rstr2b64(rstr(s), b64pad); - }; - this.any = function (s, e) { - return rstr2any(rstr(s), e); - }; - this.raw = function (s) { - return rstr(s, utf8); - }; - this.hex_hmac = function (k, d) { - return rstr2hex(rstr_hmac(k, d)); - }; - this.b64_hmac = function (k, d) { - return rstr2b64(rstr_hmac(k, d), b64pad); - }; - this.any_hmac = function (k, d, e) { - return rstr2any(rstr_hmac(k, d), e); - }; - /** - * Perform a simple self-test to see if the VM is working - * @return {String} Hexadecimal hash sample - * @public - */ - this.vm_test = function () { - return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72'; - }; - /** - * @description Enable/disable uppercase hexadecimal returned string - * @param {boolean} - * @return {Object} this - * @public - */ - this.setUpperCase = function (a) { - if (typeof a === 'boolean') { - hexcase = a; - } - return this; - }; - /** - * @description Defines a base64 pad string - * @param {string} Pad - * @return {Object} this - * @public - */ - this.setPad = function (a) { - b64pad = a || b64pad; - return this; - }; - /** - * @description Defines a base64 pad string - * @param {boolean} - * @return {Object} this - * @public - */ - this.setUTF8 = function (a) { - if (typeof a === 'boolean') { - utf8 = a; - } - return this; - }; + // name should be either a string or an object. + if (null === name || undefined === name) { + throw new Error('.field(name, val) name can not be empty'); + } - /* private methods */ + if (this._data) { + console.error(".field() can't be used if .send() is used. Please use only .send() or only .field() & .attach()"); + } - /** - * Calculate the SHA-512 of a raw string - */ + if (isObject(name)) { + for (var key in name) { + this.field(key, name[key]); + } + return this; + } - function rstr(s) { - s = utf8 ? utf8Encode(s) : s; - return binb2rstr(binb(rstr2binb(s), s.length * 8)); - } - /* - * Calculate the HMAC-SHA-512 of a key and some data (raw strings) - */ + if (Array.isArray(val)) { + for (var i in val) { + this.field(name, val[i]); + } + return this; + } - function rstr_hmac(key, data) { - key = utf8 ? utf8Encode(key) : key; - data = utf8 ? utf8Encode(data) : data; + // val should be defined now + if (null === val || undefined === val) { + throw new Error('.field(name, val) val can not be empty'); + } + if ('boolean' === typeof val) { + val = '' + val; + } + this._getFormData().append(name, val); + return this; +}; - var hash, - i = 0, - bkey = rstr2binb(key), - ipad = Array(32), - opad = Array(32); +/** + * Abort the request, and clear potential timeout. + * + * @return {Request} + * @api public + */ +RequestBase.prototype.abort = function(){ + if (this._aborted) { + return this; + } + this._aborted = true; + this.xhr && this.xhr.abort(); // browser + this.req && this.req.abort(); // node + this.clearTimeout(); + this.emit('abort'); + return this; +}; - if (bkey.length > 32) { - bkey = binb(bkey, key.length * 8); - } +/** + * Enable transmission of cookies with x-domain requests. + * + * Note that for this to work the origin must not be + * using "Access-Control-Allow-Origin" with a wildcard, + * and also must set "Access-Control-Allow-Credentials" + * to "true". + * + * @api public + */ - for (; i < 32; i += 1) { - ipad[i] = bkey[i] ^ 0x36363636; - opad[i] = bkey[i] ^ 0x5C5C5C5C; - } +RequestBase.prototype.withCredentials = function(on){ + // This is browser-only functionality. Node side is no-op. + if(on==undefined) on = true; + this._withCredentials = on; + return this; +}; - hash = binb(ipad.concat(rstr2binb(data)), 1024 + data.length * 8); - return binb2rstr(binb(opad.concat(hash), 1024 + 512)); - } +/** + * Set the max redirects to `n`. Does noting in browser XHR implementation. + * + * @param {Number} n + * @return {Request} for chaining + * @api public + */ - /** - * Calculate the SHA-512 of an array of big-endian dwords, and a bit length - */ +RequestBase.prototype.redirects = function(n){ + this._maxRedirects = n; + return this; +}; - function binb(x, len) { - var j, - i, - l, - W = new Array(80), - hash = new Array(16), - - //Initial hash values - H = [new int64(0x6a09e667, -205731576), new int64(-1150833019, -2067093701), new int64(0x3c6ef372, -23791573), new int64(-1521486534, 0x5f1d36f1), new int64(0x510e527f, -1377402159), new int64(-1694144372, 0x2b3e6c1f), new int64(0x1f83d9ab, -79577749), new int64(0x5be0cd19, 0x137e2179)], - T1 = new int64(0, 0), - T2 = new int64(0, 0), - a = new int64(0, 0), - b = new int64(0, 0), - c = new int64(0, 0), - d = new int64(0, 0), - e = new int64(0, 0), - f = new int64(0, 0), - g = new int64(0, 0), - h = new int64(0, 0), - - //Temporary variables not specified by the document - s0 = new int64(0, 0), - s1 = new int64(0, 0), - Ch = new int64(0, 0), - Maj = new int64(0, 0), - r1 = new int64(0, 0), - r2 = new int64(0, 0), - r3 = new int64(0, 0); +/** + * Convert to a plain javascript object (not JSON string) of scalar properties. + * Note as this method is designed to return a useful non-this value, + * it cannot be chained. + * + * @return {Object} describing method, url, and data of this request + * @api public + */ - if (sha512_k === undefined) { - //SHA512 constants - sha512_k = [new int64(0x428a2f98, -685199838), new int64(0x71374491, 0x23ef65cd), new int64(-1245643825, -330482897), new int64(-373957723, -2121671748), new int64(0x3956c25b, -213338824), new int64(0x59f111f1, -1241133031), new int64(-1841331548, -1357295717), new int64(-1424204075, -630357736), new int64(-670586216, -1560083902), new int64(0x12835b01, 0x45706fbe), new int64(0x243185be, 0x4ee4b28c), new int64(0x550c7dc3, -704662302), new int64(0x72be5d74, -226784913), new int64(-2132889090, 0x3b1696b1), new int64(-1680079193, 0x25c71235), new int64(-1046744716, -815192428), new int64(-459576895, -1628353838), new int64(-272742522, 0x384f25e3), new int64(0xfc19dc6, -1953704523), new int64(0x240ca1cc, 0x77ac9c65), new int64(0x2de92c6f, 0x592b0275), new int64(0x4a7484aa, 0x6ea6e483), new int64(0x5cb0a9dc, -1119749164), new int64(0x76f988da, -2096016459), new int64(-1740746414, -295247957), new int64(-1473132947, 0x2db43210), new int64(-1341970488, -1728372417), new int64(-1084653625, -1091629340), new int64(-958395405, 0x3da88fc2), new int64(-710438585, -1828018395), new int64(0x6ca6351, -536640913), new int64(0x14292967, 0xa0e6e70), new int64(0x27b70a85, 0x46d22ffc), new int64(0x2e1b2138, 0x5c26c926), new int64(0x4d2c6dfc, 0x5ac42aed), new int64(0x53380d13, -1651133473), new int64(0x650a7354, -1951439906), new int64(0x766a0abb, 0x3c77b2a8), new int64(-2117940946, 0x47edaee6), new int64(-1838011259, 0x1482353b), new int64(-1564481375, 0x4cf10364), new int64(-1474664885, -1136513023), new int64(-1035236496, -789014639), new int64(-949202525, 0x654be30), new int64(-778901479, -688958952), new int64(-694614492, 0x5565a910), new int64(-200395387, 0x5771202a), new int64(0x106aa070, 0x32bbd1b8), new int64(0x19a4c116, -1194143544), new int64(0x1e376c08, 0x5141ab53), new int64(0x2748774c, -544281703), new int64(0x34b0bcb5, -509917016), new int64(0x391c0cb3, -976659869), new int64(0x4ed8aa4a, -482243893), new int64(0x5b9cca4f, 0x7763e373), new int64(0x682e6ff3, -692930397), new int64(0x748f82ee, 0x5defb2fc), new int64(0x78a5636f, 0x43172f60), new int64(-2067236844, -1578062990), new int64(-1933114872, 0x1a6439ec), new int64(-1866530822, 0x23631e28), new int64(-1538233109, -561857047), new int64(-1090935817, -1295615723), new int64(-965641998, -479046869), new int64(-903397682, -366583396), new int64(-779700025, 0x21c0c207), new int64(-354779690, -840897762), new int64(-176337025, -294727304), new int64(0x6f067aa, 0x72176fba), new int64(0xa637dc5, -1563912026), new int64(0x113f9804, -1090974290), new int64(0x1b710b35, 0x131c471b), new int64(0x28db77f5, 0x23047d84), new int64(0x32caab7b, 0x40c72493), new int64(0x3c9ebe0a, 0x15c9bebc), new int64(0x431d67c4, -1676669620), new int64(0x4cc5d4be, -885112138), new int64(0x597f299c, -60457430), new int64(0x5fcb6fab, 0x3ad6faec), new int64(0x6c44198c, 0x4a475817)]; - } +RequestBase.prototype.toJSON = function(){ + return { + method: this.method, + url: this.url, + data: this._data, + headers: this._header + }; +}; - for (i = 0; i < 80; i += 1) { - W[i] = new int64(0, 0); - } - // append padding to the source string. The format is described in the FIPS. - x[len >> 5] |= 0x80 << 24 - (len & 0x1f); - x[(len + 128 >> 10 << 5) + 31] = len; - l = x.length; - for (i = 0; i < l; i += 32) { - //32 dwords is the block size - int64copy(a, H[0]); - int64copy(b, H[1]); - int64copy(c, H[2]); - int64copy(d, H[3]); - int64copy(e, H[4]); - int64copy(f, H[5]); - int64copy(g, H[6]); - int64copy(h, H[7]); +/** + * Send `data` as the request body, defaulting the `.type()` to "json" when + * an object is given. + * + * Examples: + * + * // manual json + * request.post('/user') + * .type('json') + * .send('{"name":"tj"}') + * .end(callback) + * + * // auto json + * request.post('/user') + * .send({ name: 'tj' }) + * .end(callback) + * + * // manual x-www-form-urlencoded + * request.post('/user') + * .type('form') + * .send('name=tj') + * .end(callback) + * + * // auto x-www-form-urlencoded + * request.post('/user') + * .type('form') + * .send({ name: 'tj' }) + * .end(callback) + * + * // defaults to x-www-form-urlencoded + * request.post('/user') + * .send('name=tobi') + * .send('species=ferret') + * .end(callback) + * + * @param {String|Object} data + * @return {Request} for chaining + * @api public + */ - for (j = 0; j < 16; j += 1) { - W[j].h = x[i + 2 * j]; - W[j].l = x[i + 2 * j + 1]; - } +RequestBase.prototype.send = function(data){ + var isObj = isObject(data); + var type = this._header['content-type']; - for (j = 16; j < 80; j += 1) { - //sigma1 - int64rrot(r1, W[j - 2], 19); - int64revrrot(r2, W[j - 2], 29); - int64shr(r3, W[j - 2], 6); - s1.l = r1.l ^ r2.l ^ r3.l; - s1.h = r1.h ^ r2.h ^ r3.h; - //sigma0 - int64rrot(r1, W[j - 15], 1); - int64rrot(r2, W[j - 15], 8); - int64shr(r3, W[j - 15], 7); - s0.l = r1.l ^ r2.l ^ r3.l; - s0.h = r1.h ^ r2.h ^ r3.h; + if (this._formData) { + console.error(".send() can't be used if .attach() or .field() is used. Please use only .send() or only .field() & .attach()"); + } - int64add4(W[j], s1, W[j - 7], s0, W[j - 16]); - } + if (isObj && !this._data) { + if (Array.isArray(data)) { + this._data = []; + } else if (!this._isHost(data)) { + this._data = {}; + } + } else if (data && this._data && this._isHost(this._data)) { + throw Error("Can't merge these send calls"); + } - for (j = 0; j < 80; j += 1) { - //Ch - Ch.l = e.l & f.l ^ ~e.l & g.l; - Ch.h = e.h & f.h ^ ~e.h & g.h; + // merge + if (isObj && isObject(this._data)) { + for (var key in data) { + this._data[key] = data[key]; + } + } else if ('string' == typeof data) { + // default to x-www-form-urlencoded + if (!type) this.type('form'); + type = this._header['content-type']; + if ('application/x-www-form-urlencoded' == type) { + this._data = this._data + ? this._data + '&' + data + : data; + } else { + this._data = (this._data || '') + data; + } + } else { + this._data = data; + } - //Sigma1 - int64rrot(r1, e, 14); - int64rrot(r2, e, 18); - int64revrrot(r3, e, 9); - s1.l = r1.l ^ r2.l ^ r3.l; - s1.h = r1.h ^ r2.h ^ r3.h; + if (!isObj || this._isHost(data)) { + return this; + } - //Sigma0 - int64rrot(r1, a, 28); - int64revrrot(r2, a, 2); - int64revrrot(r3, a, 7); - s0.l = r1.l ^ r2.l ^ r3.l; - s0.h = r1.h ^ r2.h ^ r3.h; + // default to json + if (!type) this.type('json'); + return this; +}; - //Maj - Maj.l = a.l & b.l ^ a.l & c.l ^ b.l & c.l; - Maj.h = a.h & b.h ^ a.h & c.h ^ b.h & c.h; - int64add5(T1, h, s1, Ch, sha512_k[j], W[j]); - int64add(T2, s0, Maj); +/** + * Sort `querystring` by the sort function + * + * + * Examples: + * + * // default order + * request.get('/user') + * .query('name=Nick') + * .query('search=Manny') + * .sortQuery() + * .end(callback) + * + * // customized sort function + * request.get('/user') + * .query('name=Nick') + * .query('search=Manny') + * .sortQuery(function(a, b){ + * return a.length - b.length; + * }) + * .end(callback) + * + * + * @param {Function} sort + * @return {Request} for chaining + * @api public + */ - int64copy(h, g); - int64copy(g, f); - int64copy(f, e); - int64add(e, d, T1); - int64copy(d, c); - int64copy(c, b); - int64copy(b, a); - int64add(a, T1, T2); - } - int64add(H[0], H[0], a); - int64add(H[1], H[1], b); - int64add(H[2], H[2], c); - int64add(H[3], H[3], d); - int64add(H[4], H[4], e); - int64add(H[5], H[5], f); - int64add(H[6], H[6], g); - int64add(H[7], H[7], h); - } +RequestBase.prototype.sortQuery = function(sort) { + // _sort default to true but otherwise can be a function or boolean + this._sort = typeof sort === 'undefined' ? true : sort; + return this; +}; - //represent the hash as an array of 32-bit dwords - for (i = 0; i < 8; i += 1) { - hash[2 * i] = H[i].h; - hash[2 * i + 1] = H[i].l; - } - return hash; - } +/** + * Invoke callback with timeout error. + * + * @api private + */ - //A constructor for 64-bit numbers +RequestBase.prototype._timeoutError = function(reason, timeout, errno){ + if (this._aborted) { + return; + } + var err = new Error(reason + timeout + 'ms exceeded'); + err.timeout = timeout; + err.code = 'ECONNABORTED'; + err.errno = errno; + this.timedout = true; + this.abort(); + this.callback(err); +}; - function int64(h, l) { - this.h = h; - this.l = l; - //this.toString = int64toString; - } +RequestBase.prototype._setTimeouts = function() { + var self = this; - //Copies src into dst, assuming both are 64-bit numbers + // deadline + if (this._timeout && !this._timer) { + this._timer = setTimeout(function(){ + self._timeoutError('Timeout of ', self._timeout, 'ETIME'); + }, this._timeout); + } + // response timeout + if (this._responseTimeout && !this._responseTimeoutTimer) { + this._responseTimeoutTimer = setTimeout(function(){ + self._timeoutError('Response timeout of ', self._responseTimeout, 'ETIMEDOUT'); + }, this._responseTimeout); + } +} - function int64copy(dst, src) { - dst.h = src.h; - dst.l = src.l; - } +},{"./is-object":5}],7:[function(_dereq_,module,exports){ - //Right-rotates a 64-bit number by shift - //Won't handle cases of shift>=32 - //The function revrrot() is for that +/** + * Module dependencies. + */ - function int64rrot(dst, x, shift) { - dst.l = x.l >>> shift | x.h << 32 - shift; - dst.h = x.h >>> shift | x.l << 32 - shift; - } +var utils = _dereq_('./utils'); - //Reverses the dwords of the source and then rotates right by shift. - //This is equivalent to rotation by 32+shift +/** + * Expose `ResponseBase`. + */ - function int64revrrot(dst, x, shift) { - dst.l = x.h >>> shift | x.l << 32 - shift; - dst.h = x.l >>> shift | x.h << 32 - shift; - } +module.exports = ResponseBase; - //Bitwise-shifts right a 64-bit number by shift - //Won't handle shift>=32, but it's never needed in SHA512 +/** + * Initialize a new `ResponseBase`. + * + * @api public + */ - function int64shr(dst, x, shift) { - dst.l = x.l >>> shift | x.h << 32 - shift; - dst.h = x.h >>> shift; - } +function ResponseBase(obj) { + if (obj) return mixin(obj); +} - //Adds two 64-bit numbers - //Like the original implementation, does not rely on 32-bit operations +/** + * Mixin the prototype properties. + * + * @param {Object} obj + * @return {Object} + * @api private + */ - function int64add(dst, x, y) { - var w0 = (x.l & 0xffff) + (y.l & 0xffff); - var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16); - var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16); - var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16); - dst.l = w0 & 0xffff | w1 << 16; - dst.h = w2 & 0xffff | w3 << 16; - } +function mixin(obj) { + for (var key in ResponseBase.prototype) { + obj[key] = ResponseBase.prototype[key]; + } + return obj; +} - //Same, except with 4 addends. Works faster than adding them one by one. +/** + * Get case-insensitive `field` value. + * + * @param {String} field + * @return {String} + * @api public + */ - function int64add4(dst, a, b, c, d) { - var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff); - var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16); - var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16); - var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16); - dst.l = w0 & 0xffff | w1 << 16; - dst.h = w2 & 0xffff | w3 << 16; - } +ResponseBase.prototype.get = function(field){ + return this.header[field.toLowerCase()]; +}; - //Same, except with 5 addends +/** + * Set header related properties: + * + * - `.type` the content type without params + * + * A response of "Content-Type: text/plain; charset=utf-8" + * will provide you with a `.type` of "text/plain". + * + * @param {Object} header + * @api private + */ - function int64add5(dst, a, b, c, d, e) { - var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff), - w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16), - w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16), - w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16); - dst.l = w0 & 0xffff | w1 << 16; - dst.h = w2 & 0xffff | w3 << 16; - } - }, - /** - * @class Hashes.RMD160 - * @constructor - * @param {Object} [config] - * - * A JavaScript implementation of the RIPEMD-160 Algorithm - * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009. - * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet - * See http://pajhome.org.uk/crypt/md5 for details. - * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/ - */ - RMD160: function RMD160(options) { - /** - * Private properties configuration variables. You may need to tweak these to be compatible with - * the server-side, but the defaults work in most cases. - * @see this.setUpperCase() method - * @see this.setPad() method - */ - var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false, +ResponseBase.prototype._setHeaderProperties = function(header){ + // TODO: moar! + // TODO: make this a util - /* hexadecimal output case format. false - lowercase; true - uppercase */ - b64pad = options && typeof options.pad === 'string' ? options.pda : '=', + // content-type + var ct = header['content-type'] || ''; + this.type = utils.type(ct); - /* base-64 pad character. Default '=' for strict RFC compliance */ - utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true, + // params + var params = utils.params(ct); + for (var key in params) this[key] = params[key]; - /* enable/disable utf8 encoding */ - rmd160_r1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13], - rmd160_r2 = [5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11], - rmd160_s1 = [11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6], - rmd160_s2 = [8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11]; + this.links = {}; - /* privileged (public) methods */ - this.hex = function (s) { - return rstr2hex(rstr(s, utf8)); - }; - this.b64 = function (s) { - return rstr2b64(rstr(s, utf8), b64pad); - }; - this.any = function (s, e) { - return rstr2any(rstr(s, utf8), e); - }; - this.raw = function (s) { - return rstr(s, utf8); - }; - this.hex_hmac = function (k, d) { - return rstr2hex(rstr_hmac(k, d)); - }; - this.b64_hmac = function (k, d) { - return rstr2b64(rstr_hmac(k, d), b64pad); - }; - this.any_hmac = function (k, d, e) { - return rstr2any(rstr_hmac(k, d), e); - }; - /** - * Perform a simple self-test to see if the VM is working - * @return {String} Hexadecimal hash sample - * @public - */ - this.vm_test = function () { - return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72'; - }; - /** - * @description Enable/disable uppercase hexadecimal returned string - * @param {boolean} - * @return {Object} this - * @public - */ - this.setUpperCase = function (a) { - if (typeof a === 'boolean') { - hexcase = a; - } - return this; - }; - /** - * @description Defines a base64 pad string - * @param {string} Pad - * @return {Object} this - * @public - */ - this.setPad = function (a) { - if (typeof a !== 'undefined') { - b64pad = a; - } - return this; - }; - /** - * @description Defines a base64 pad string - * @param {boolean} - * @return {Object} this - * @public - */ - this.setUTF8 = function (a) { - if (typeof a === 'boolean') { - utf8 = a; + // links + try { + if (header.link) { + this.links = utils.parseLinks(header.link); } - return this; - }; + } catch (err) { + // ignore + } +}; + +/** + * Set flags such as `.ok` based on `status`. + * + * For example a 2xx response will give you a `.ok` of __true__ + * whereas 5xx will be __false__ and `.error` will be __true__. The + * `.clientError` and `.serverError` are also available to be more + * specific, and `.statusType` is the class of error ranging from 1..5 + * sometimes useful for mapping respond colors etc. + * + * "sugar" properties are also defined for common cases. Currently providing: + * + * - .noContent + * - .badRequest + * - .unauthorized + * - .notAcceptable + * - .notFound + * + * @param {Number} status + * @api private + */ - /* private methods */ +ResponseBase.prototype._setStatusProperties = function(status){ + var type = status / 100 | 0; + + // status / class + this.status = this.statusCode = status; + this.statusType = type; + + // basics + this.info = 1 == type; + this.ok = 2 == type; + this.redirect = 3 == type; + this.clientError = 4 == type; + this.serverError = 5 == type; + this.error = (4 == type || 5 == type) + ? this.toError() + : false; + + // sugar + this.accepted = 202 == status; + this.noContent = 204 == status; + this.badRequest = 400 == status; + this.unauthorized = 401 == status; + this.notAcceptable = 406 == status; + this.forbidden = 403 == status; + this.notFound = 404 == status; +}; - /** - * Calculate the rmd160 of a raw string - */ +},{"./utils":9}],8:[function(_dereq_,module,exports){ +var ERROR_CODES = [ + 'ECONNRESET', + 'ETIMEDOUT', + 'EADDRINFO', + 'ESOCKETTIMEDOUT' +]; - function rstr(s) { - s = utf8 ? utf8Encode(s) : s; - return binl2rstr(binl(rstr2binl(s), s.length * 8)); - } +/** + * Determine if a request should be retried. + * (Borrowed from segmentio/superagent-retry) + * + * @param {Error} err + * @param {Response} [res] + * @returns {Boolean} + */ +module.exports = function shouldRetry(err, res) { + if (err && err.code && ~ERROR_CODES.indexOf(err.code)) return true; + if (res && res.status && res.status >= 500) return true; + // Superagent timeout + if (err && 'timeout' in err && err.code == 'ECONNABORTED') return true; + if (err && 'crossDomain' in err) return true; + return false; +}; - /** - * Calculate the HMAC-rmd160 of a key and some data (raw strings) - */ +},{}],9:[function(_dereq_,module,exports){ - function rstr_hmac(key, data) { - key = utf8 ? utf8Encode(key) : key; - data = utf8 ? utf8Encode(data) : data; - var i, - hash, - bkey = rstr2binl(key), - ipad = Array(16), - opad = Array(16); +/** + * Return the mime type for the given `str`. + * + * @param {String} str + * @return {String} + * @api private + */ - if (bkey.length > 16) { - bkey = binl(bkey, key.length * 8); - } +exports.type = function(str){ + return str.split(/ *; */).shift(); +}; - for (i = 0; i < 16; i += 1) { - ipad[i] = bkey[i] ^ 0x36363636; - opad[i] = bkey[i] ^ 0x5C5C5C5C; - } - hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8); - return binl2rstr(binl(opad.concat(hash), 512 + 160)); - } +/** + * Return header field parameters. + * + * @param {String} str + * @return {Object} + * @api private + */ - /** - * Convert an array of little-endian words to a string - */ +exports.params = function(str){ + return str.split(/ *; */).reduce(function(obj, str){ + var parts = str.split(/ *= */); + var key = parts.shift(); + var val = parts.shift(); - function binl2rstr(input) { - var i, - output = '', - l = input.length * 32; - for (i = 0; i < l; i += 8) { - output += String.fromCharCode(input[i >> 5] >>> i % 32 & 0xFF); - } - return output; - } + if (key && val) obj[key] = val; + return obj; + }, {}); +}; - /** - * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length. - */ +/** + * Parse Link header fields. + * + * @param {String} str + * @return {Object} + * @api private + */ - function binl(x, len) { - var T, - j, - i, - l, - h0 = 0x67452301, - h1 = 0xefcdab89, - h2 = 0x98badcfe, - h3 = 0x10325476, - h4 = 0xc3d2e1f0, - A1, - B1, - C1, - D1, - E1, - A2, - B2, - C2, - D2, - E2; +exports.parseLinks = function(str){ + return str.split(/ *, */).reduce(function(obj, str){ + var parts = str.split(/ *; */); + var url = parts[0].slice(1, -1); + var rel = parts[1].split(/ *= */)[1].slice(1, -1); + obj[rel] = url; + return obj; + }, {}); +}; - /* append padding */ - x[len >> 5] |= 0x80 << len % 32; - x[(len + 64 >>> 9 << 4) + 14] = len; - l = x.length; +/** + * Strip content related fields from `header`. + * + * @param {Object} header + * @return {Object} header + * @api private + */ - for (i = 0; i < l; i += 16) { - A1 = A2 = h0; - B1 = B2 = h1; - C1 = C2 = h2; - D1 = D2 = h3; - E1 = E2 = h4; - for (j = 0; j <= 79; j += 1) { - T = safe_add(A1, rmd160_f(j, B1, C1, D1)); - T = safe_add(T, x[i + rmd160_r1[j]]); - T = safe_add(T, rmd160_K1(j)); - T = safe_add(bit_rol(T, rmd160_s1[j]), E1); - A1 = E1; - E1 = D1; - D1 = bit_rol(C1, 10); - C1 = B1; - B1 = T; - T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2)); - T = safe_add(T, x[i + rmd160_r2[j]]); - T = safe_add(T, rmd160_K2(j)); - T = safe_add(bit_rol(T, rmd160_s2[j]), E2); - A2 = E2; - E2 = D2; - D2 = bit_rol(C2, 10); - C2 = B2; - B2 = T; - } +exports.cleanHeader = function(header, shouldStripCookie){ + delete header['content-type']; + delete header['content-length']; + delete header['transfer-encoding']; + delete header['host']; + if (shouldStripCookie) { + delete header['cookie']; + } + return header; +}; +},{}],10:[function(_dereq_,module,exports){ +'use strict'; - T = safe_add(h1, safe_add(C1, D2)); - h1 = safe_add(h2, safe_add(D1, E2)); - h2 = safe_add(h3, safe_add(E1, A2)); - h3 = safe_add(h4, safe_add(A1, B2)); - h4 = safe_add(h0, safe_add(B1, C2)); - h0 = T; - } - return [h0, h1, h2, h3, h4]; - } +//these are used for the sentence-splitter +module.exports = ['jr', 'mr', 'mrs', 'ms', 'dr', 'prof', 'sr', 'sen', 'corp', 'calif', 'rep', 'gov', 'atty', 'supt', 'det', 'rev', 'col', 'gen', 'lt', 'cmdr', 'adm', 'capt', 'sgt', 'cpl', 'maj', 'dept', 'univ', 'assn', 'bros', 'inc', 'ltd', 'co', 'corp', 'arc', 'al', 'ave', 'blvd', 'cl', 'ct', 'cres', 'exp', 'rd', 'st', 'dist', 'mt', 'ft', 'fy', 'hwy', 'la', 'pd', 'pl', 'plz', 'tce', 'Ala', 'Ariz', 'Ark', 'Cal', 'Calif', 'Col', 'Colo', 'Conn', 'Del', 'Fed', 'Fla', 'Ga', 'Ida', 'Id', 'Ill', 'Ind', 'Ia', 'Kan', 'Kans', 'Ken', 'Ky', 'La', 'Me', 'Md', 'Mass', 'Mich', 'Minn', 'Miss', 'Mo', 'Mont', 'Neb', 'Nebr', 'Nev', 'Mex', 'Okla', 'Ok', 'Ore', 'Penna', 'Penn', 'Pa', 'Dak', 'Tenn', 'Tex', 'Ut', 'Vt', 'Va', 'Wash', 'Wis', 'Wisc', 'Wy', 'Wyo', 'USAFA', 'Alta', 'Ont', 'QuÔøΩ', 'Sask', 'Yuk', 'jan', 'feb', 'mar', 'apr', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec', 'sept', 'vs', 'etc', 'esp', 'llb', 'md', 'bl', 'phd', 'ma', 'ba', 'miss', 'misses', 'mister', 'sir', 'esq', 'mstr', 'lit', 'fl', 'ex', 'eg', 'sep', 'sept', '..']; - // specific algorithm methods +},{}],11:[function(_dereq_,module,exports){ +'use strict'; - function rmd160_f(j, x, y, z) { - return 0 <= j && j <= 15 ? x ^ y ^ z : 16 <= j && j <= 31 ? x & y | ~x & z : 32 <= j && j <= 47 ? (x | ~y) ^ z : 48 <= j && j <= 63 ? x & z | y & ~z : 64 <= j && j <= 79 ? x ^ (y | ~z) : 'rmd160_f: j out of range'; - } +// wikipedia special terms lifted and augmented from parsoid parser april 2015 +// (not even close to being complete) +var i18n = { + files: ['файл', 'fitxer', 'soubor', 'datei', 'file', 'archivo', 'پرونده', 'tiedosto', 'mynd', "su'wret", 'fichier', 'bestand', 'датотека', 'dosya', 'fil'], + images: ['image'], + templates: ['шаблён', 'plantilla', 'šablona', 'vorlage', 'template', 'الگو', 'malline', 'snið', 'shablon', 'modèle', 'sjabloon', 'шаблон', 'şablon'], + categories: ['катэгорыя', 'categoria', 'kategorie', 'category', 'categoría', 'رده', 'luokka', 'flokkur', 'kategoriya', 'catégorie', 'categorie', 'категорија', 'kategori', 'kategoria', 'تصنيف'], + redirects: ['перанакіраваньне', 'redirect', 'přesměruj', 'weiterleitung', 'redirección', 'redireccion', 'تغییر_مسیر', 'تغییرمسیر', 'ohjaus', 'uudelleenohjaus', 'tilvísun', 'aýdaw', 'айдау', 'redirection', 'doorverwijzing', 'преусмери', 'преусмјери', 'yönlendi̇rme', 'yönlendi̇r', '重定向', 'redirección', 'redireccion', '重定向', 'yönlendirm?e?', 'تغییر_مسیر', 'تغییرمسیر', 'перанакіраваньне', 'yönlendirme'], + specials: ['спэцыяльныя', 'especial', 'speciální', 'spezial', 'special', 'ویژه', 'toiminnot', 'kerfissíða', 'arnawlı', 'spécial', 'speciaal', 'посебно', 'özel'], + users: ['удзельнік', 'usuari', 'uživatel', 'benutzer', 'user', 'usuario', 'کاربر', 'käyttäjä', 'notandi', 'paydalanıwshı', 'utilisateur', 'gebruiker', 'корисник', 'kullanıcı'], + disambigs: ['disambig', //en + 'disambiguation', //en + 'dab', //en + 'disamb', //en + 'begriffsklärung', //de + 'ujednoznacznienie', //pl + 'doorverwijspagina', //nl + '消歧义', //zh + 'desambiguación', //es + 'dubbelsinnig', //af + 'disambigua', //it + 'desambiguação', //pt + 'homonymie', //fr + 'неоднозначность', //ru + 'anlam ayrımı' //tr + ], + infoboxes: ['infobox', 'ficha', 'канадский', 'inligtingskas', 'inligtingskas3', //af + 'لغة', 'bilgi kutusu', //tr + 'yerleşim bilgi kutusu', 'infoboks' //nn, no + ], + sources: [ + //blacklist these headings, as they're not plain-text + 'references', 'see also', 'external links', 'further reading', 'notes et références', 'voir aussi', 'liens externes'] +}; - function rmd160_K1(j) { - return 0 <= j && j <= 15 ? 0x00000000 : 16 <= j && j <= 31 ? 0x5a827999 : 32 <= j && j <= 47 ? 0x6ed9eba1 : 48 <= j && j <= 63 ? 0x8f1bbcdc : 64 <= j && j <= 79 ? 0xa953fd4e : 'rmd160_K1: j out of range'; - } +if (typeof module !== 'undefined' && module.exports) { + module.exports = i18n; +} - function rmd160_K2(j) { - return 0 <= j && j <= 15 ? 0x50a28be6 : 16 <= j && j <= 31 ? 0x5c4dd124 : 32 <= j && j <= 47 ? 0x6d703ef3 : 48 <= j && j <= 63 ? 0x7a6d76e9 : 64 <= j && j <= 79 ? 0x00000000 : 'rmd160_K2: j out of range'; - } - } - }; +},{}],12:[function(_dereq_,module,exports){ +'use strict'; - // exposes Hashes - (function (window, undefined) { - var freeExports = false; - if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object') { - freeExports = exports; - if (exports && (typeof global === 'undefined' ? 'undefined' : _typeof(global)) === 'object' && global && global === global.global) { - window = global; - } - } +module.exports = { + aa: { + english_title: 'Afar', + direction: 'ltr', + local_title: 'Afar' + }, + ab: { + english_title: 'Abkhazian', + direction: 'ltr', + local_title: 'Аҧсуа' + }, + af: { + english_title: 'Afrikaans', + direction: 'ltr', + local_title: 'Afrikaans' + }, + ak: { + english_title: 'Akan', + direction: 'ltr', + local_title: 'Akana' + }, + als: { + english_title: 'Alemannic', + direction: 'ltr', + local_title: 'Alemannisch' + }, + am: { + english_title: 'Amharic', + direction: 'ltr', + local_title: 'አማርኛ' + }, + an: { + english_title: 'Aragonese', + direction: 'ltr', + local_title: 'Aragonés' + }, + ang: { + english_title: 'Anglo-Saxon', + direction: 'ltr', + local_title: 'Englisc' + }, + ar: { + english_title: 'Arabic', + direction: 'rtl', + local_title: 'العربية' + }, + arc: { + english_title: 'Aramaic', + direction: 'rtl', + local_title: 'ܣܘܪܬ' + }, + as: { + english_title: 'Assamese', + direction: 'ltr', + local_title: 'অসমীয়া' + }, + ast: { + english_title: 'Asturian', + direction: 'ltr', + local_title: 'Asturianu' + }, + av: { + english_title: 'Avar', + direction: 'ltr', + local_title: 'Авар' + }, + ay: { + english_title: 'Aymara', + direction: 'ltr', + local_title: 'Aymar' + }, + az: { + english_title: 'Azerbaijani', + direction: 'ltr', + local_title: 'Azərbaycanca' + }, + ba: { + english_title: 'Bashkir', + direction: 'ltr', + local_title: 'Башҡорт' + }, + bar: { + english_title: 'Bavarian', + direction: 'ltr', + local_title: 'Boarisch' + }, + 'bat-smg': { + english_title: 'Samogitian', + direction: 'ltr', + local_title: 'Žemaitėška' + }, + bcl: { + english_title: 'Bikol', + direction: 'ltr', + local_title: 'Bikol' + }, + be: { + english_title: 'Belarusian', + direction: 'ltr', + local_title: 'Беларуская' + }, + 'be-x-old': { + english_title: 'Belarusian', + direction: '(Taraškievica)', + local_title: 'ltr' + }, + bg: { + english_title: 'Bulgarian', + direction: 'ltr', + local_title: 'Български' + }, + bh: { + english_title: 'Bihari', + direction: 'ltr', + local_title: 'भोजपुरी' + }, + bi: { + english_title: 'Bislama', + direction: 'ltr', + local_title: 'Bislama' + }, + bm: { + english_title: 'Bambara', + direction: 'ltr', + local_title: 'Bamanankan' + }, + bn: { + english_title: 'Bengali', + direction: 'ltr', + local_title: 'বাংলা' + }, + bo: { + english_title: 'Tibetan', + direction: 'ltr', + local_title: 'བོད་ཡིག' + }, + bpy: { + english_title: 'Bishnupriya', + direction: 'Manipuri', + local_title: 'ltr' + }, + br: { + english_title: 'Breton', + direction: 'ltr', + local_title: 'Brezhoneg' + }, + bs: { + english_title: 'Bosnian', + direction: 'ltr', + local_title: 'Bosanski' + }, + bug: { + english_title: 'Buginese', + direction: 'ltr', + local_title: 'ᨅᨔ' + }, + bxr: { + english_title: 'Buriat', + direction: '(Russia)', + local_title: 'ltr' + }, + ca: { + english_title: 'Catalan', + direction: 'ltr', + local_title: 'Català' + }, + cdo: { + english_title: 'Min', + direction: 'Dong', + local_title: 'Chinese' + }, + ce: { + english_title: 'Chechen', + direction: 'ltr', + local_title: 'Нохчийн' + }, + ceb: { + english_title: 'Cebuano', + direction: 'ltr', + local_title: 'Sinugboanong' + }, + ch: { + english_title: 'Chamorro', + direction: 'ltr', + local_title: 'Chamoru' + }, + cho: { + english_title: 'Choctaw', + direction: 'ltr', + local_title: 'Choctaw' + }, + chr: { + english_title: 'Cherokee', + direction: 'ltr', + local_title: 'ᏣᎳᎩ' + }, + chy: { + english_title: 'Cheyenne', + direction: 'ltr', + local_title: 'Tsetsêhestâhese' + }, + co: { + english_title: 'Corsican', + direction: 'ltr', + local_title: 'Corsu' + }, + cr: { + english_title: 'Cree', + direction: 'ltr', + local_title: 'Nehiyaw' + }, + cs: { + english_title: 'Czech', + direction: 'ltr', + local_title: 'Česky' + }, + csb: { + english_title: 'Kashubian', + direction: 'ltr', + local_title: 'Kaszëbsczi' + }, + cu: { + english_title: 'Old', + direction: 'Church', + local_title: 'Slavonic' + }, + cv: { + english_title: 'Chuvash', + direction: 'ltr', + local_title: 'Чăваш' + }, + cy: { + english_title: 'Welsh', + direction: 'ltr', + local_title: 'Cymraeg' + }, + da: { + english_title: 'Danish', + direction: 'ltr', + local_title: 'Dansk' + }, + de: { + english_title: 'German', + direction: 'ltr', + local_title: 'Deutsch' + }, + diq: { + english_title: 'Dimli', + direction: 'ltr', + local_title: 'Zazaki' + }, + dsb: { + english_title: 'Lower', + direction: 'Sorbian', + local_title: 'ltr' + }, + dv: { + english_title: 'Divehi', + direction: 'rtl', + local_title: 'ދިވެހިބަސް' + }, + dz: { + english_title: 'Dzongkha', + direction: 'ltr', + local_title: 'ཇོང་ཁ' + }, + ee: { + english_title: 'Ewe', + direction: 'ltr', + local_title: 'Ɛʋɛ' + }, + far: { + english_title: 'Farsi', + direction: 'ltr', + local_title: 'فارسی' + }, + el: { + english_title: 'Greek', + direction: 'ltr', + local_title: 'Ελληνικά' + }, + en: { + english_title: 'English', + direction: 'ltr', + local_title: 'English' + }, + eo: { + english_title: 'Esperanto', + direction: 'ltr', + local_title: 'Esperanto' + }, + es: { + english_title: 'Spanish', + direction: 'ltr', + local_title: 'Español' + }, + et: { + english_title: 'Estonian', + direction: 'ltr', + local_title: 'Eesti' + }, + eu: { + english_title: 'Basque', + direction: 'ltr', + local_title: 'Euskara' + }, + ext: { + english_title: 'Extremaduran', + direction: 'ltr', + local_title: 'Estremeñu' + }, + ff: { + english_title: 'Peul', + direction: 'ltr', + local_title: 'Fulfulde' + }, + fi: { + english_title: 'Finnish', + direction: 'ltr', + local_title: 'Suomi' + }, + 'fiu-vro': { + english_title: 'Võro', + direction: 'ltr', + local_title: 'Võro' + }, + fj: { + english_title: 'Fijian', + direction: 'ltr', + local_title: 'Na' + }, + fo: { + english_title: 'Faroese', + direction: 'ltr', + local_title: 'Føroyskt' + }, + fr: { + english_title: 'French', + direction: 'ltr', + local_title: 'Français' + }, + frp: { + english_title: 'Arpitan', + direction: 'ltr', + local_title: 'Arpitan' + }, + fur: { + english_title: 'Friulian', + direction: 'ltr', + local_title: 'Furlan' + }, + fy: { + english_title: 'West', + direction: 'Frisian', + local_title: 'ltr' + }, + ga: { + english_title: 'Irish', + direction: 'ltr', + local_title: 'Gaeilge' + }, + gan: { + english_title: 'Gan', + direction: 'Chinese', + local_title: 'ltr' + }, + gd: { + english_title: 'Scottish', + direction: 'Gaelic', + local_title: 'ltr' + }, + gil: { + english_title: 'Gilbertese', + direction: 'ltr', + local_title: 'Taetae' + }, + gl: { + english_title: 'Galician', + direction: 'ltr', + local_title: 'Galego' + }, + gn: { + english_title: 'Guarani', + direction: 'ltr', + local_title: "Avañe'ẽ" + }, + got: { + english_title: 'Gothic', + direction: 'ltr', + local_title: 'gutisk' + }, + gu: { + english_title: 'Gujarati', + direction: 'ltr', + local_title: 'ગુજરાતી' + }, + gv: { + english_title: 'Manx', + direction: 'ltr', + local_title: 'Gaelg' + }, + ha: { + english_title: 'Hausa', + direction: 'rtl', + local_title: 'هَوُسَ' + }, + hak: { + english_title: 'Hakka', + direction: 'Chinese', + local_title: 'ltr' + }, + haw: { + english_title: 'Hawaiian', + direction: 'ltr', + local_title: 'Hawai`i' + }, + he: { + english_title: 'Hebrew', + direction: 'rtl', + local_title: 'עברית' + }, + hi: { + english_title: 'Hindi', + direction: 'ltr', + local_title: 'हिन्दी' + }, + ho: { + english_title: 'Hiri', + direction: 'Motu', + local_title: 'ltr' + }, + hr: { + english_title: 'Croatian', + direction: 'ltr', + local_title: 'Hrvatski' + }, + ht: { + english_title: 'Haitian', + direction: 'ltr', + local_title: 'Krèyol' + }, + hu: { + english_title: 'Hungarian', + direction: 'ltr', + local_title: 'Magyar' + }, + hy: { + english_title: 'Armenian', + direction: 'ltr', + local_title: 'Հայերեն' + }, + hz: { + english_title: 'Herero', + direction: 'ltr', + local_title: 'Otsiherero' + }, + ia: { + english_title: 'Interlingua', + direction: 'ltr', + local_title: 'Interlingua' + }, + id: { + english_title: 'Indonesian', + direction: 'ltr', + local_title: 'Bahasa' + }, + ie: { + english_title: 'Interlingue', + direction: 'ltr', + local_title: 'Interlingue' + }, + ig: { + english_title: 'Igbo', + direction: 'ltr', + local_title: 'Igbo' + }, + ii: { + english_title: 'Sichuan', + direction: 'Yi', + local_title: 'ltr' + }, + ik: { + english_title: 'Inupiak', + direction: 'ltr', + local_title: 'Iñupiak' + }, + ilo: { + english_title: 'Ilokano', + direction: 'ltr', + local_title: 'Ilokano' + }, + io: { + english_title: 'Ido', + direction: 'ltr', + local_title: 'Ido' + }, + is: { + english_title: 'Icelandic', + direction: 'ltr', + local_title: 'Íslenska' + }, + it: { + english_title: 'Italian', + direction: 'ltr', + local_title: 'Italiano' + }, + iu: { + english_title: 'Inuktitut', + direction: 'ltr', + local_title: 'ᐃᓄᒃᑎᑐᑦ' + }, + ja: { + english_title: 'Japanese', + direction: 'ltr', + local_title: '日本語' + }, + jbo: { + english_title: 'Lojban', + direction: 'ltr', + local_title: 'Lojban' + }, + jv: { + english_title: 'Javanese', + direction: 'ltr', + local_title: 'Basa' + }, + ka: { + english_title: 'Georgian', + direction: 'ltr', + local_title: 'ქართული' + }, + kg: { + english_title: 'Kongo', + direction: 'ltr', + local_title: 'KiKongo' + }, + ki: { + english_title: 'Kikuyu', + direction: 'ltr', + local_title: 'Gĩkũyũ' + }, + kj: { + english_title: 'Kuanyama', + direction: 'ltr', + local_title: 'Kuanyama' + }, + kk: { + english_title: 'Kazakh', + direction: 'ltr', + local_title: 'Қазақша' + }, + kl: { + english_title: 'Greenlandic', + direction: 'ltr', + local_title: 'Kalaallisut' + }, + km: { + english_title: 'Cambodian', + direction: 'ltr', + local_title: 'ភាសាខ្មែរ' + }, + kn: { + english_title: 'Kannada', + direction: 'ltr', + local_title: 'ಕನ್ನಡ' + }, + khw: { + english_title: 'Khowar', + direction: 'rtl', + local_title: 'کھوار' + }, + ko: { + english_title: 'Korean', + direction: 'ltr', + local_title: '한국어' + }, + kr: { + english_title: 'Kanuri', + direction: 'ltr', + local_title: 'Kanuri' + }, + ks: { + english_title: 'Kashmiri', + direction: 'rtl', + local_title: 'कश्मीरी' + }, + ksh: { + english_title: 'Ripuarian', + direction: 'ltr', + local_title: 'Ripoarisch' + }, + ku: { + english_title: 'Kurdish', + direction: 'rtl', + local_title: 'Kurdî' + }, + kv: { + english_title: 'Komi', + direction: 'ltr', + local_title: 'Коми' + }, + kw: { + english_title: 'Cornish', + direction: 'ltr', + local_title: 'Kernewek' + }, + ky: { + english_title: 'Kirghiz', + direction: 'ltr', + local_title: 'Kırgızca' + }, + la: { + english_title: 'Latin', + direction: 'ltr', + local_title: 'Latina' + }, + lad: { + english_title: 'Ladino', + direction: 'ltr', + local_title: 'Dzhudezmo' + }, + lan: { + english_title: 'Lango', + direction: 'ltr', + local_title: 'Leb' + }, + lb: { + english_title: 'Luxembourgish', + direction: 'ltr', + local_title: 'Lëtzebuergesch' + }, + lg: { + english_title: 'Ganda', + direction: 'ltr', + local_title: 'Luganda' + }, + li: { + english_title: 'Limburgian', + direction: 'ltr', + local_title: 'Limburgs' + }, + lij: { + english_title: 'Ligurian', + direction: 'ltr', + local_title: 'Líguru' + }, + lmo: { + english_title: 'Lombard', + direction: 'ltr', + local_title: 'Lumbaart' + }, + ln: { + english_title: 'Lingala', + direction: 'ltr', + local_title: 'Lingála' + }, + lo: { + english_title: 'Laotian', + direction: 'ltr', + local_title: 'ລາວ' + }, + lt: { + english_title: 'Lithuanian', + direction: 'ltr', + local_title: 'Lietuvių' + }, + lv: { + english_title: 'Latvian', + direction: 'ltr', + local_title: 'Latviešu' + }, + 'map-bms': { + english_title: 'Banyumasan', + direction: 'ltr', + local_title: 'Basa' + }, + mg: { + english_title: 'Malagasy', + direction: 'ltr', + local_title: 'Malagasy' + }, + man: { + english_title: 'Mandarin', + direction: 'ltr', + local_title: '官話' + }, + mh: { + english_title: 'Marshallese', + direction: 'ltr', + local_title: 'Kajin' + }, + mi: { + english_title: 'Maori', + direction: 'ltr', + local_title: 'Māori' + }, + min: { + english_title: 'Minangkabau', + direction: 'ltr', + local_title: 'Minangkabau' + }, + mk: { + english_title: 'Macedonian', + direction: 'ltr', + local_title: 'Македонски' + }, + ml: { + english_title: 'Malayalam', + direction: 'ltr', + local_title: 'മലയാളം' + }, + mn: { + english_title: 'Mongolian', + direction: 'ltr', + local_title: 'Монгол' + }, + mo: { + english_title: 'Moldovan', + direction: 'ltr', + local_title: 'Moldovenească' + }, + mr: { + english_title: 'Marathi', + direction: 'ltr', + local_title: 'मराठी' + }, + ms: { + english_title: 'Malay', + direction: 'ltr', + local_title: 'Bahasa' + }, + mt: { + english_title: 'Maltese', + direction: 'ltr', + local_title: 'bil-Malti' + }, + mus: { + english_title: 'Creek', + direction: 'ltr', + local_title: 'Muskogee' + }, + my: { + english_title: 'Burmese', + direction: 'ltr', + local_title: 'Myanmasa' + }, + na: { + english_title: 'Nauruan', + direction: 'ltr', + local_title: 'Dorerin' + }, + nah: { + english_title: 'Nahuatl', + direction: 'ltr', + local_title: 'Nahuatl' + }, + nap: { + english_title: 'Neapolitan', + direction: 'ltr', + local_title: 'Nnapulitano' + }, + nd: { + english_title: 'North', + direction: 'Ndebele', + local_title: 'ltr' + }, + nds: { + english_title: 'Low German', + direction: 'ltr', + local_title: 'Plattdüütsch' + }, + 'nds-nl': { + english_title: 'Dutch', + direction: 'Low', + local_title: 'Saxon' + }, + ne: { + english_title: 'Nepali', + direction: 'ltr', + local_title: 'नेपाली' + }, + new: { + english_title: 'Newar', + direction: 'ltr', + local_title: 'नेपालभाषा' + }, + ng: { + english_title: 'Ndonga', + direction: 'ltr', + local_title: 'Oshiwambo' + }, + nl: { + english_title: 'Dutch', + direction: 'ltr', + local_title: 'Nederlands' + }, + nn: { + english_title: 'Norwegian', + direction: 'Nynorsk', + local_title: 'ltr' + }, + no: { + english_title: 'Norwegian', + direction: 'ltr', + local_title: 'Norsk' + }, + nr: { + english_title: 'South', + direction: 'Ndebele', + local_title: 'ltr' + }, + nso: { + english_title: 'Northern', + direction: 'Sotho', + local_title: 'ltr' + }, + nrm: { + english_title: 'Norman', + direction: 'ltr', + local_title: 'Nouormand' + }, + nv: { + english_title: 'Navajo', + direction: 'ltr', + local_title: 'Diné' + }, + ny: { + english_title: 'Chichewa', + direction: 'ltr', + local_title: 'Chi-Chewa' + }, + oc: { + english_title: 'Occitan', + direction: 'ltr', + local_title: 'Occitan' + }, + oj: { + english_title: 'Ojibwa', + direction: 'ltr', + local_title: 'ᐊᓂᔑᓈᐯᒧᐎᓐ' + }, + om: { + english_title: 'Oromo', + direction: 'ltr', + local_title: 'Oromoo' + }, + or: { + english_title: 'Oriya', + direction: 'ltr', + local_title: 'ଓଡ଼ିଆ' + }, + os: { + english_title: 'Ossetian', + direction: 'ltr', + local_title: 'Иронау' + }, + pa: { + english_title: 'Panjabi', + direction: 'ltr', + local_title: 'ਪੰਜਾਬੀ' + }, + pag: { + english_title: 'Pangasinan', + direction: 'ltr', + local_title: 'Pangasinan' + }, + pam: { + english_title: 'Kapampangan', + direction: 'ltr', + local_title: 'Kapampangan' + }, + pap: { + english_title: 'Papiamentu', + direction: 'ltr', + local_title: 'Papiamentu' + }, + pdc: { + english_title: 'Pennsylvania', + direction: 'German', + local_title: 'ltr' + }, + pi: { + english_title: 'Pali', + direction: 'ltr', + local_title: 'Pāli' + }, + pih: { + english_title: 'Norfolk', + direction: 'ltr', + local_title: 'Norfuk' + }, + pl: { + english_title: 'Polish', + direction: 'ltr', + local_title: 'Polski' + }, + pms: { + english_title: 'Piedmontese', + direction: 'ltr', + local_title: 'Piemontèis' + }, + ps: { + english_title: 'Pashto', + direction: 'rtl', + local_title: 'پښتو' + }, + pt: { + english_title: 'Portuguese', + direction: 'ltr', + local_title: 'Português' + }, + qu: { + english_title: 'Quechua', + direction: 'ltr', + local_title: 'Runa' + }, + rm: { + english_title: 'Raeto', + direction: 'Romance', + local_title: 'ltr' + }, + rmy: { + english_title: 'Romani', + direction: 'ltr', + local_title: 'Romani' + }, + rn: { + english_title: 'Kirundi', + direction: 'ltr', + local_title: 'Kirundi' + }, + ro: { + english_title: 'Romanian', + direction: 'ltr', + local_title: 'Română' + }, + 'roa-rup': { + english_title: 'Aromanian', + direction: 'ltr', + local_title: 'Armâneashti' + }, + ru: { + english_title: 'Russian', + direction: 'ltr', + local_title: 'Русский' + }, + rw: { + english_title: 'Rwandi', + direction: 'ltr', + local_title: 'Kinyarwandi' + }, + sa: { + english_title: 'Sanskrit', + direction: 'ltr', + local_title: 'संस्कृतम्' + }, + sc: { + english_title: 'Sardinian', + direction: 'ltr', + local_title: 'Sardu' + }, + scn: { + english_title: 'Sicilian', + direction: 'ltr', + local_title: 'Sicilianu' + }, + sco: { + english_title: 'Scots', + direction: 'ltr', + local_title: 'Scots' + }, + sd: { + english_title: 'Sindhi', + direction: 'ltr', + local_title: 'सिनधि' + }, + se: { + english_title: 'Northern', + direction: 'Sami', + local_title: 'ltr' + }, + sg: { + english_title: 'Sango', + direction: 'ltr', + local_title: 'Sängö' + }, + sh: { + english_title: 'Serbo-Croatian', + direction: 'ltr', + local_title: 'Srpskohrvatski' + }, + si: { + english_title: 'Sinhalese', + direction: 'ltr', + local_title: 'සිංහල' + }, + simple: { + english_title: 'Simple', + direction: 'English', + local_title: 'ltr' + }, + sk: { + english_title: 'Slovak', + direction: 'ltr', + local_title: 'Slovenčina' + }, + sl: { + english_title: 'Slovenian', + direction: 'ltr', + local_title: 'Slovenščina' + }, + sm: { + english_title: 'Samoan', + direction: 'ltr', + local_title: 'Gagana' + }, + sn: { + english_title: 'Shona', + direction: 'ltr', + local_title: 'chiShona' + }, + so: { + english_title: 'Somalia', + direction: 'ltr', + local_title: 'Soomaaliga' + }, + sq: { + english_title: 'Albanian', + direction: 'ltr', + local_title: 'Shqip' + }, + sr: { + english_title: 'Serbian', + direction: 'ltr', + local_title: 'Српски' + }, + ss: { + english_title: 'Swati', + direction: 'ltr', + local_title: 'SiSwati' + }, + st: { + english_title: 'Southern', + direction: 'Sotho', + local_title: 'ltr' + }, + su: { + english_title: 'Sundanese', + direction: 'ltr', + local_title: 'Basa' + }, + sv: { + english_title: 'Swedish', + direction: 'ltr', + local_title: 'Svenska' + }, + sw: { + english_title: 'Swahili', + direction: 'ltr', + local_title: 'Kiswahili' + }, + ta: { + english_title: 'Tamil', + direction: 'ltr', + local_title: 'தமிழ்' + }, + te: { + english_title: 'Telugu', + direction: 'ltr', + local_title: 'తెలుగు' + }, + tet: { + english_title: 'Tetum', + direction: 'ltr', + local_title: 'Tetun' + }, + tg: { + english_title: 'Tajik', + direction: 'ltr', + local_title: 'Тоҷикӣ' + }, + th: { + english_title: 'Thai', + direction: 'ltr', + local_title: 'ไทย' + }, + ti: { + english_title: 'Tigrinya', + direction: 'ltr', + local_title: 'ትግርኛ' + }, + tk: { + english_title: 'Turkmen', + direction: 'ltr', + local_title: 'Туркмен' + }, + tl: { + english_title: 'Tagalog', + direction: 'ltr', + local_title: 'Tagalog' + }, + tlh: { + english_title: 'Klingon', + direction: 'ltr', + local_title: 'tlhIngan-Hol' + }, + tn: { + english_title: 'Tswana', + direction: 'ltr', + local_title: 'Setswana' + }, + to: { + english_title: 'Tonga', + direction: 'ltr', + local_title: 'Lea' + }, + tpi: { + english_title: 'Tok', + direction: 'Pisin', + local_title: 'ltr' + }, + tr: { + english_title: 'Turkish', + direction: 'ltr', + local_title: 'Türkçe' + }, + ts: { + english_title: 'Tsonga', + direction: 'ltr', + local_title: 'Xitsonga' + }, + tt: { + english_title: 'Tatar', + direction: 'ltr', + local_title: 'Tatarça' + }, + tum: { + english_title: 'Tumbuka', + direction: 'ltr', + local_title: 'chiTumbuka' + }, + tw: { + english_title: 'Twi', + direction: 'ltr', + local_title: 'Twi' + }, + ty: { + english_title: 'Tahitian', + direction: 'ltr', + local_title: 'Reo' + }, + udm: { + english_title: 'Udmurt', + direction: 'ltr', + local_title: 'Удмурт' + }, + ug: { + english_title: 'Uyghur', + direction: 'ltr', + local_title: 'Uyƣurqə' + }, + uk: { + english_title: 'Ukrainian', + direction: 'ltr', + local_title: 'Українська' + }, + ur: { + english_title: 'Urdu', + direction: 'rtl', + local_title: 'اردو' + }, + uz: { + english_title: 'Uzbek', + direction: 'ltr', + local_title: 'Ўзбек' + }, + ve: { + english_title: 'Venda', + direction: 'ltr', + local_title: 'Tshivenḓa' + }, + vi: { + english_title: 'Vietnamese', + direction: 'ltr', + local_title: 'Việtnam' + }, + vec: { + english_title: 'Venetian', + direction: 'ltr', + local_title: 'Vèneto' + }, + vls: { + english_title: 'West', + direction: 'Flemish', + local_title: 'ltr' + }, + vo: { + english_title: 'Volapük', + direction: 'ltr', + local_title: 'Volapük' + }, + wa: { + english_title: 'Walloon', + direction: 'ltr', + local_title: 'Walon' + }, + war: { + english_title: 'Waray-Waray', + direction: 'ltr', + local_title: 'Winaray' + }, + wo: { + english_title: 'Wolof', + direction: 'ltr', + local_title: 'Wollof' + }, + xal: { + english_title: 'Kalmyk', + direction: 'ltr', + local_title: 'Хальмг' + }, + xh: { + english_title: 'Xhosa', + direction: 'ltr', + local_title: 'isiXhosa' + }, + yi: { + english_title: 'Yiddish', + direction: 'rtl', + local_title: 'ייִדיש' + }, + yo: { + english_title: 'Yoruba', + direction: 'ltr', + local_title: 'Yorùbá' + }, + za: { + english_title: 'Zhuang', + direction: 'ltr', + local_title: 'Cuengh' + }, + zh: { + english_title: 'Chinese', + direction: 'ltr', + local_title: '中文' + }, + 'zh-classical': { + english_title: 'Classical', + direction: 'Chinese', + local_title: 'ltr' + }, + 'zh-min-nan': { + english_title: 'Minnan', + direction: 'ltr', + local_title: 'Bân-lâm-gú' + }, + 'zh-yue': { + english_title: 'Cantonese', + direction: 'ltr', + local_title: '粵語' + }, + zu: { + english_title: 'Zulu', + direction: 'ltr', + local_title: 'isiZulu' + } +}; - if (typeof define === 'function' && _typeof(define.amd) === 'object' && define.amd) { - // define as an anonymous module, so, through path mapping, it can be aliased - define(function () { - return Hashes; - }); - } else if (freeExports) { - // in Node.js or RingoJS v0.8.0+ - if ((typeof module === 'undefined' ? 'undefined' : _typeof(module)) === 'object' && module && module.exports === freeExports) { - module.exports = Hashes; - } - // in Narwhal or RingoJS v0.7.0- - else { - freeExports.Hashes = Hashes; +},{}],13:[function(_dereq_,module,exports){ +'use strict'; + +//from https://en.wikipedia.org/w/api.php?action=sitematrix&format=json +var site_map = { + aawiki: 'https://aa.wikipedia.org', + aawiktionary: 'https://aa.wiktionary.org', + aawikibooks: 'https://aa.wikibooks.org', + abwiki: 'https://ab.wikipedia.org', + abwiktionary: 'https://ab.wiktionary.org', + acewiki: 'https://ace.wikipedia.org', + afwiki: 'https://af.wikipedia.org', + afwiktionary: 'https://af.wiktionary.org', + afwikibooks: 'https://af.wikibooks.org', + afwikiquote: 'https://af.wikiquote.org', + akwiki: 'https://ak.wikipedia.org', + akwiktionary: 'https://ak.wiktionary.org', + akwikibooks: 'https://ak.wikibooks.org', + alswiki: 'https://als.wikipedia.org', + alswiktionary: 'https://als.wiktionary.org', + alswikibooks: 'https://als.wikibooks.org', + alswikiquote: 'https://als.wikiquote.org', + amwiki: 'https://am.wikipedia.org', + amwiktionary: 'https://am.wiktionary.org', + amwikiquote: 'https://am.wikiquote.org', + anwiki: 'https://an.wikipedia.org', + anwiktionary: 'https://an.wiktionary.org', + angwiki: 'https://ang.wikipedia.org', + angwiktionary: 'https://ang.wiktionary.org', + angwikibooks: 'https://ang.wikibooks.org', + angwikiquote: 'https://ang.wikiquote.org', + angwikisource: 'https://ang.wikisource.org', + arwiki: 'https://ar.wikipedia.org', + arwiktionary: 'https://ar.wiktionary.org', + arwikibooks: 'https://ar.wikibooks.org', + arwikinews: 'https://ar.wikinews.org', + arwikiquote: 'https://ar.wikiquote.org', + arwikisource: 'https://ar.wikisource.org', + arwikiversity: 'https://ar.wikiversity.org', + arcwiki: 'https://arc.wikipedia.org', + arzwiki: 'https://arz.wikipedia.org', + aswiki: 'https://as.wikipedia.org', + aswiktionary: 'https://as.wiktionary.org', + aswikibooks: 'https://as.wikibooks.org', + aswikisource: 'https://as.wikisource.org', + astwiki: 'https://ast.wikipedia.org', + astwiktionary: 'https://ast.wiktionary.org', + astwikibooks: 'https://ast.wikibooks.org', + astwikiquote: 'https://ast.wikiquote.org', + avwiki: 'https://av.wikipedia.org', + avwiktionary: 'https://av.wiktionary.org', + aywiki: 'https://ay.wikipedia.org', + aywiktionary: 'https://ay.wiktionary.org', + aywikibooks: 'https://ay.wikibooks.org', + azwiki: 'https://az.wikipedia.org', + azwiktionary: 'https://az.wiktionary.org', + azwikibooks: 'https://az.wikibooks.org', + azwikiquote: 'https://az.wikiquote.org', + azwikisource: 'https://az.wikisource.org', + bawiki: 'https://ba.wikipedia.org', + bawikibooks: 'https://ba.wikibooks.org', + barwiki: 'https://bar.wikipedia.org', + bat_smgwiki: 'https://bat-smg.wikipedia.org', + bclwiki: 'https://bcl.wikipedia.org', + bewiki: 'https://be.wikipedia.org', + bewiktionary: 'https://be.wiktionary.org', + bewikibooks: 'https://be.wikibooks.org', + bewikiquote: 'https://be.wikiquote.org', + bewikisource: 'https://be.wikisource.org', + be_x_oldwiki: 'https://be-x-old.wikipedia.org', + bgwiki: 'https://bg.wikipedia.org', + bgwiktionary: 'https://bg.wiktionary.org', + bgwikibooks: 'https://bg.wikibooks.org', + bgwikinews: 'https://bg.wikinews.org', + bgwikiquote: 'https://bg.wikiquote.org', + bgwikisource: 'https://bg.wikisource.org', + bhwiki: 'https://bh.wikipedia.org', + bhwiktionary: 'https://bh.wiktionary.org', + biwiki: 'https://bi.wikipedia.org', + biwiktionary: 'https://bi.wiktionary.org', + biwikibooks: 'https://bi.wikibooks.org', + bjnwiki: 'https://bjn.wikipedia.org', + bmwiki: 'https://bm.wikipedia.org', + bmwiktionary: 'https://bm.wiktionary.org', + bmwikibooks: 'https://bm.wikibooks.org', + bmwikiquote: 'https://bm.wikiquote.org', + bnwiki: 'https://bn.wikipedia.org', + bnwiktionary: 'https://bn.wiktionary.org', + bnwikibooks: 'https://bn.wikibooks.org', + bnwikisource: 'https://bn.wikisource.org', + bowiki: 'https://bo.wikipedia.org', + bowiktionary: 'https://bo.wiktionary.org', + bowikibooks: 'https://bo.wikibooks.org', + bpywiki: 'https://bpy.wikipedia.org', + brwiki: 'https://br.wikipedia.org', + brwiktionary: 'https://br.wiktionary.org', + brwikiquote: 'https://br.wikiquote.org', + brwikisource: 'https://br.wikisource.org', + bswiki: 'https://bs.wikipedia.org', + bswiktionary: 'https://bs.wiktionary.org', + bswikibooks: 'https://bs.wikibooks.org', + bswikinews: 'https://bs.wikinews.org', + bswikiquote: 'https://bs.wikiquote.org', + bswikisource: 'https://bs.wikisource.org', + bugwiki: 'https://bug.wikipedia.org', + bxrwiki: 'https://bxr.wikipedia.org', + cawiki: 'https://ca.wikipedia.org', + cawiktionary: 'https://ca.wiktionary.org', + cawikibooks: 'https://ca.wikibooks.org', + cawikinews: 'https://ca.wikinews.org', + cawikiquote: 'https://ca.wikiquote.org', + cawikisource: 'https://ca.wikisource.org', + cbk_zamwiki: 'https://cbk-zam.wikipedia.org', + cdowiki: 'https://cdo.wikipedia.org', + cewiki: 'https://ce.wikipedia.org', + cebwiki: 'https://ceb.wikipedia.org', + chwiki: 'https://ch.wikipedia.org', + chwiktionary: 'https://ch.wiktionary.org', + chwikibooks: 'https://ch.wikibooks.org', + chowiki: 'https://cho.wikipedia.org', + chrwiki: 'https://chr.wikipedia.org', + chrwiktionary: 'https://chr.wiktionary.org', + chywiki: 'https://chy.wikipedia.org', + ckbwiki: 'https://ckb.wikipedia.org', + cowiki: 'https://co.wikipedia.org', + cowiktionary: 'https://co.wiktionary.org', + cowikibooks: 'https://co.wikibooks.org', + cowikiquote: 'https://co.wikiquote.org', + crwiki: 'https://cr.wikipedia.org', + crwiktionary: 'https://cr.wiktionary.org', + crwikiquote: 'https://cr.wikiquote.org', + crhwiki: 'https://crh.wikipedia.org', + cswiki: 'https://cs.wikipedia.org', + cswiktionary: 'https://cs.wiktionary.org', + cswikibooks: 'https://cs.wikibooks.org', + cswikinews: 'https://cs.wikinews.org', + cswikiquote: 'https://cs.wikiquote.org', + cswikisource: 'https://cs.wikisource.org', + cswikiversity: 'https://cs.wikiversity.org', + csbwiki: 'https://csb.wikipedia.org', + csbwiktionary: 'https://csb.wiktionary.org', + cuwiki: 'https://cu.wikipedia.org', + cvwiki: 'https://cv.wikipedia.org', + cvwikibooks: 'https://cv.wikibooks.org', + cywiki: 'https://cy.wikipedia.org', + cywiktionary: 'https://cy.wiktionary.org', + cywikibooks: 'https://cy.wikibooks.org', + cywikiquote: 'https://cy.wikiquote.org', + cywikisource: 'https://cy.wikisource.org', + dawiki: 'https://da.wikipedia.org', + dawiktionary: 'https://da.wiktionary.org', + dawikibooks: 'https://da.wikibooks.org', + dawikiquote: 'https://da.wikiquote.org', + dawikisource: 'https://da.wikisource.org', + dewiki: 'https://de.wikipedia.org', + dewiktionary: 'https://de.wiktionary.org', + dewikibooks: 'https://de.wikibooks.org', + dewikinews: 'https://de.wikinews.org', + dewikiquote: 'https://de.wikiquote.org', + dewikisource: 'https://de.wikisource.org', + dewikiversity: 'https://de.wikiversity.org', + dewikivoyage: 'https://de.wikivoyage.org', + diqwiki: 'https://diq.wikipedia.org', + dsbwiki: 'https://dsb.wikipedia.org', + dvwiki: 'https://dv.wikipedia.org', + dvwiktionary: 'https://dv.wiktionary.org', + dzwiki: 'https://dz.wikipedia.org', + dzwiktionary: 'https://dz.wiktionary.org', + eewiki: 'https://ee.wikipedia.org', + elwiki: 'https://el.wikipedia.org', + elwiktionary: 'https://el.wiktionary.org', + elwikibooks: 'https://el.wikibooks.org', + elwikinews: 'https://el.wikinews.org', + elwikiquote: 'https://el.wikiquote.org', + elwikisource: 'https://el.wikisource.org', + elwikiversity: 'https://el.wikiversity.org', + elwikivoyage: 'https://el.wikivoyage.org', + emlwiki: 'https://eml.wikipedia.org', + enwiki: 'https://en.wikipedia.org', + enwiktionary: 'https://en.wiktionary.org', + enwikibooks: 'https://en.wikibooks.org', + enwikinews: 'https://en.wikinews.org', + enwikiquote: 'https://en.wikiquote.org', + enwikisource: 'https://en.wikisource.org', + enwikiversity: 'https://en.wikiversity.org', + enwikivoyage: 'https://en.wikivoyage.org', + eowiki: 'https://eo.wikipedia.org', + eowiktionary: 'https://eo.wiktionary.org', + eowikibooks: 'https://eo.wikibooks.org', + eowikinews: 'https://eo.wikinews.org', + eowikiquote: 'https://eo.wikiquote.org', + eowikisource: 'https://eo.wikisource.org', + eswiki: 'https://es.wikipedia.org', + eswiktionary: 'https://es.wiktionary.org', + eswikibooks: 'https://es.wikibooks.org', + eswikinews: 'https://es.wikinews.org', + eswikiquote: 'https://es.wikiquote.org', + eswikisource: 'https://es.wikisource.org', + eswikiversity: 'https://es.wikiversity.org', + eswikivoyage: 'https://es.wikivoyage.org', + etwiki: 'https://et.wikipedia.org', + etwiktionary: 'https://et.wiktionary.org', + etwikibooks: 'https://et.wikibooks.org', + etwikiquote: 'https://et.wikiquote.org', + etwikisource: 'https://et.wikisource.org', + euwiki: 'https://eu.wikipedia.org', + euwiktionary: 'https://eu.wiktionary.org', + euwikibooks: 'https://eu.wikibooks.org', + euwikiquote: 'https://eu.wikiquote.org', + extwiki: 'https://ext.wikipedia.org', + fawiki: 'https://fa.wikipedia.org', + fawiktionary: 'https://fa.wiktionary.org', + fawikibooks: 'https://fa.wikibooks.org', + fawikinews: 'https://fa.wikinews.org', + fawikiquote: 'https://fa.wikiquote.org', + fawikisource: 'https://fa.wikisource.org', + fawikivoyage: 'https://fa.wikivoyage.org', + ffwiki: 'https://ff.wikipedia.org', + fiwiki: 'https://fi.wikipedia.org', + fiwiktionary: 'https://fi.wiktionary.org', + fiwikibooks: 'https://fi.wikibooks.org', + fiwikinews: 'https://fi.wikinews.org', + fiwikiquote: 'https://fi.wikiquote.org', + fiwikisource: 'https://fi.wikisource.org', + fiwikiversity: 'https://fi.wikiversity.org', + fiu_vrowiki: 'https://fiu-vro.wikipedia.org', + fjwiki: 'https://fj.wikipedia.org', + fjwiktionary: 'https://fj.wiktionary.org', + fowiki: 'https://fo.wikipedia.org', + fowiktionary: 'https://fo.wiktionary.org', + fowikisource: 'https://fo.wikisource.org', + frwiki: 'https://fr.wikipedia.org', + frwiktionary: 'https://fr.wiktionary.org', + frwikibooks: 'https://fr.wikibooks.org', + frwikinews: 'https://fr.wikinews.org', + frwikiquote: 'https://fr.wikiquote.org', + frwikisource: 'https://fr.wikisource.org', + frwikiversity: 'https://fr.wikiversity.org', + frwikivoyage: 'https://fr.wikivoyage.org', + frpwiki: 'https://frp.wikipedia.org', + frrwiki: 'https://frr.wikipedia.org', + furwiki: 'https://fur.wikipedia.org', + fywiki: 'https://fy.wikipedia.org', + fywiktionary: 'https://fy.wiktionary.org', + fywikibooks: 'https://fy.wikibooks.org', + gawiki: 'https://ga.wikipedia.org', + gawiktionary: 'https://ga.wiktionary.org', + gawikibooks: 'https://ga.wikibooks.org', + gawikiquote: 'https://ga.wikiquote.org', + gagwiki: 'https://gag.wikipedia.org', + ganwiki: 'https://gan.wikipedia.org', + gdwiki: 'https://gd.wikipedia.org', + gdwiktionary: 'https://gd.wiktionary.org', + glwiki: 'https://gl.wikipedia.org', + glwiktionary: 'https://gl.wiktionary.org', + glwikibooks: 'https://gl.wikibooks.org', + glwikiquote: 'https://gl.wikiquote.org', + glwikisource: 'https://gl.wikisource.org', + glkwiki: 'https://glk.wikipedia.org', + gnwiki: 'https://gn.wikipedia.org', + gnwiktionary: 'https://gn.wiktionary.org', + gnwikibooks: 'https://gn.wikibooks.org', + gotwiki: 'https://got.wikipedia.org', + gotwikibooks: 'https://got.wikibooks.org', + guwiki: 'https://gu.wikipedia.org', + guwiktionary: 'https://gu.wiktionary.org', + guwikibooks: 'https://gu.wikibooks.org', + guwikiquote: 'https://gu.wikiquote.org', + guwikisource: 'https://gu.wikisource.org', + gvwiki: 'https://gv.wikipedia.org', + gvwiktionary: 'https://gv.wiktionary.org', + hawiki: 'https://ha.wikipedia.org', + hawiktionary: 'https://ha.wiktionary.org', + hakwiki: 'https://hak.wikipedia.org', + hawwiki: 'https://haw.wikipedia.org', + hewiki: 'https://he.wikipedia.org', + hewiktionary: 'https://he.wiktionary.org', + hewikibooks: 'https://he.wikibooks.org', + hewikinews: 'https://he.wikinews.org', + hewikiquote: 'https://he.wikiquote.org', + hewikisource: 'https://he.wikisource.org', + hewikivoyage: 'https://he.wikivoyage.org', + hiwiki: 'https://hi.wikipedia.org', + hiwiktionary: 'https://hi.wiktionary.org', + hiwikibooks: 'https://hi.wikibooks.org', + hiwikiquote: 'https://hi.wikiquote.org', + hifwiki: 'https://hif.wikipedia.org', + howiki: 'https://ho.wikipedia.org', + hrwiki: 'https://hr.wikipedia.org', + hrwiktionary: 'https://hr.wiktionary.org', + hrwikibooks: 'https://hr.wikibooks.org', + hrwikiquote: 'https://hr.wikiquote.org', + hrwikisource: 'https://hr.wikisource.org', + hsbwiki: 'https://hsb.wikipedia.org', + hsbwiktionary: 'https://hsb.wiktionary.org', + htwiki: 'https://ht.wikipedia.org', + htwikisource: 'https://ht.wikisource.org', + huwiki: 'https://hu.wikipedia.org', + huwiktionary: 'https://hu.wiktionary.org', + huwikibooks: 'https://hu.wikibooks.org', + huwikinews: 'https://hu.wikinews.org', + huwikiquote: 'https://hu.wikiquote.org', + huwikisource: 'https://hu.wikisource.org', + hywiki: 'https://hy.wikipedia.org', + hywiktionary: 'https://hy.wiktionary.org', + hywikibooks: 'https://hy.wikibooks.org', + hywikiquote: 'https://hy.wikiquote.org', + hywikisource: 'https://hy.wikisource.org', + hzwiki: 'https://hz.wikipedia.org', + iawiki: 'https://ia.wikipedia.org', + iawiktionary: 'https://ia.wiktionary.org', + iawikibooks: 'https://ia.wikibooks.org', + idwiki: 'https://id.wikipedia.org', + idwiktionary: 'https://id.wiktionary.org', + idwikibooks: 'https://id.wikibooks.org', + idwikiquote: 'https://id.wikiquote.org', + idwikisource: 'https://id.wikisource.org', + iewiki: 'https://ie.wikipedia.org', + iewiktionary: 'https://ie.wiktionary.org', + iewikibooks: 'https://ie.wikibooks.org', + igwiki: 'https://ig.wikipedia.org', + iiwiki: 'https://ii.wikipedia.org', + ikwiki: 'https://ik.wikipedia.org', + ikwiktionary: 'https://ik.wiktionary.org', + ilowiki: 'https://ilo.wikipedia.org', + iowiki: 'https://io.wikipedia.org', + iowiktionary: 'https://io.wiktionary.org', + iswiki: 'https://is.wikipedia.org', + iswiktionary: 'https://is.wiktionary.org', + iswikibooks: 'https://is.wikibooks.org', + iswikiquote: 'https://is.wikiquote.org', + iswikisource: 'https://is.wikisource.org', + itwiki: 'https://it.wikipedia.org', + itwiktionary: 'https://it.wiktionary.org', + itwikibooks: 'https://it.wikibooks.org', + itwikinews: 'https://it.wikinews.org', + itwikiquote: 'https://it.wikiquote.org', + itwikisource: 'https://it.wikisource.org', + itwikiversity: 'https://it.wikiversity.org', + itwikivoyage: 'https://it.wikivoyage.org', + iuwiki: 'https://iu.wikipedia.org', + iuwiktionary: 'https://iu.wiktionary.org', + jawiki: 'https://ja.wikipedia.org', + jawiktionary: 'https://ja.wiktionary.org', + jawikibooks: 'https://ja.wikibooks.org', + jawikinews: 'https://ja.wikinews.org', + jawikiquote: 'https://ja.wikiquote.org', + jawikisource: 'https://ja.wikisource.org', + jawikiversity: 'https://ja.wikiversity.org', + jbowiki: 'https://jbo.wikipedia.org', + jbowiktionary: 'https://jbo.wiktionary.org', + jvwiki: 'https://jv.wikipedia.org', + jvwiktionary: 'https://jv.wiktionary.org', + kawiki: 'https://ka.wikipedia.org', + kawiktionary: 'https://ka.wiktionary.org', + kawikibooks: 'https://ka.wikibooks.org', + kawikiquote: 'https://ka.wikiquote.org', + kaawiki: 'https://kaa.wikipedia.org', + kabwiki: 'https://kab.wikipedia.org', + kbdwiki: 'https://kbd.wikipedia.org', + kgwiki: 'https://kg.wikipedia.org', + kiwiki: 'https://ki.wikipedia.org', + kjwiki: 'https://kj.wikipedia.org', + kkwiki: 'https://kk.wikipedia.org', + kkwiktionary: 'https://kk.wiktionary.org', + kkwikibooks: 'https://kk.wikibooks.org', + kkwikiquote: 'https://kk.wikiquote.org', + klwiki: 'https://kl.wikipedia.org', + klwiktionary: 'https://kl.wiktionary.org', + kmwiki: 'https://km.wikipedia.org', + kmwiktionary: 'https://km.wiktionary.org', + kmwikibooks: 'https://km.wikibooks.org', + knwiki: 'https://kn.wikipedia.org', + knwiktionary: 'https://kn.wiktionary.org', + knwikibooks: 'https://kn.wikibooks.org', + knwikiquote: 'https://kn.wikiquote.org', + knwikisource: 'https://kn.wikisource.org', + kowiki: 'https://ko.wikipedia.org', + kowiktionary: 'https://ko.wiktionary.org', + kowikibooks: 'https://ko.wikibooks.org', + kowikinews: 'https://ko.wikinews.org', + kowikiquote: 'https://ko.wikiquote.org', + kowikisource: 'https://ko.wikisource.org', + kowikiversity: 'https://ko.wikiversity.org', + koiwiki: 'https://koi.wikipedia.org', + krwiki: 'https://kr.wikipedia.org', + krwikiquote: 'https://kr.wikiquote.org', + krcwiki: 'https://krc.wikipedia.org', + kswiki: 'https://ks.wikipedia.org', + kswiktionary: 'https://ks.wiktionary.org', + kswikibooks: 'https://ks.wikibooks.org', + kswikiquote: 'https://ks.wikiquote.org', + kshwiki: 'https://ksh.wikipedia.org', + kuwiki: 'https://ku.wikipedia.org', + kuwiktionary: 'https://ku.wiktionary.org', + kuwikibooks: 'https://ku.wikibooks.org', + kuwikiquote: 'https://ku.wikiquote.org', + kvwiki: 'https://kv.wikipedia.org', + kwwiki: 'https://kw.wikipedia.org', + kwwiktionary: 'https://kw.wiktionary.org', + kwwikiquote: 'https://kw.wikiquote.org', + kywiki: 'https://ky.wikipedia.org', + kywiktionary: 'https://ky.wiktionary.org', + kywikibooks: 'https://ky.wikibooks.org', + kywikiquote: 'https://ky.wikiquote.org', + lawiki: 'https://la.wikipedia.org', + lawiktionary: 'https://la.wiktionary.org', + lawikibooks: 'https://la.wikibooks.org', + lawikiquote: 'https://la.wikiquote.org', + lawikisource: 'https://la.wikisource.org', + ladwiki: 'https://lad.wikipedia.org', + lbwiki: 'https://lb.wikipedia.org', + lbwiktionary: 'https://lb.wiktionary.org', + lbwikibooks: 'https://lb.wikibooks.org', + lbwikiquote: 'https://lb.wikiquote.org', + lbewiki: 'https://lbe.wikipedia.org', + lezwiki: 'https://lez.wikipedia.org', + lgwiki: 'https://lg.wikipedia.org', + liwiki: 'https://li.wikipedia.org', + liwiktionary: 'https://li.wiktionary.org', + liwikibooks: 'https://li.wikibooks.org', + liwikiquote: 'https://li.wikiquote.org', + liwikisource: 'https://li.wikisource.org', + lijwiki: 'https://lij.wikipedia.org', + lmowiki: 'https://lmo.wikipedia.org', + lnwiki: 'https://ln.wikipedia.org', + lnwiktionary: 'https://ln.wiktionary.org', + lnwikibooks: 'https://ln.wikibooks.org', + lowiki: 'https://lo.wikipedia.org', + lowiktionary: 'https://lo.wiktionary.org', + ltwiki: 'https://lt.wikipedia.org', + ltwiktionary: 'https://lt.wiktionary.org', + ltwikibooks: 'https://lt.wikibooks.org', + ltwikiquote: 'https://lt.wikiquote.org', + ltwikisource: 'https://lt.wikisource.org', + ltgwiki: 'https://ltg.wikipedia.org', + lvwiki: 'https://lv.wikipedia.org', + lvwiktionary: 'https://lv.wiktionary.org', + lvwikibooks: 'https://lv.wikibooks.org', + maiwiki: 'https://mai.wikipedia.org', + map_bmswiki: 'https://map-bms.wikipedia.org', + mdfwiki: 'https://mdf.wikipedia.org', + mgwiki: 'https://mg.wikipedia.org', + mgwiktionary: 'https://mg.wiktionary.org', + mgwikibooks: 'https://mg.wikibooks.org', + mhwiki: 'https://mh.wikipedia.org', + mhwiktionary: 'https://mh.wiktionary.org', + mhrwiki: 'https://mhr.wikipedia.org', + miwiki: 'https://mi.wikipedia.org', + miwiktionary: 'https://mi.wiktionary.org', + miwikibooks: 'https://mi.wikibooks.org', + minwiki: 'https://min.wikipedia.org', + mkwiki: 'https://mk.wikipedia.org', + mkwiktionary: 'https://mk.wiktionary.org', + mkwikibooks: 'https://mk.wikibooks.org', + mkwikisource: 'https://mk.wikisource.org', + mlwiki: 'https://ml.wikipedia.org', + mlwiktionary: 'https://ml.wiktionary.org', + mlwikibooks: 'https://ml.wikibooks.org', + mlwikiquote: 'https://ml.wikiquote.org', + mlwikisource: 'https://ml.wikisource.org', + mnwiki: 'https://mn.wikipedia.org', + mnwiktionary: 'https://mn.wiktionary.org', + mnwikibooks: 'https://mn.wikibooks.org', + mowiki: 'https://mo.wikipedia.org', + mowiktionary: 'https://mo.wiktionary.org', + mrwiki: 'https://mr.wikipedia.org', + mrwiktionary: 'https://mr.wiktionary.org', + mrwikibooks: 'https://mr.wikibooks.org', + mrwikiquote: 'https://mr.wikiquote.org', + mrwikisource: 'https://mr.wikisource.org', + mrjwiki: 'https://mrj.wikipedia.org', + mswiki: 'https://ms.wikipedia.org', + mswiktionary: 'https://ms.wiktionary.org', + mswikibooks: 'https://ms.wikibooks.org', + mtwiki: 'https://mt.wikipedia.org', + mtwiktionary: 'https://mt.wiktionary.org', + muswiki: 'https://mus.wikipedia.org', + mwlwiki: 'https://mwl.wikipedia.org', + mywiki: 'https://my.wikipedia.org', + mywiktionary: 'https://my.wiktionary.org', + mywikibooks: 'https://my.wikibooks.org', + myvwiki: 'https://myv.wikipedia.org', + mznwiki: 'https://mzn.wikipedia.org', + nawiki: 'https://na.wikipedia.org', + nawiktionary: 'https://na.wiktionary.org', + nawikibooks: 'https://na.wikibooks.org', + nawikiquote: 'https://na.wikiquote.org', + nahwiki: 'https://nah.wikipedia.org', + nahwiktionary: 'https://nah.wiktionary.org', + nahwikibooks: 'https://nah.wikibooks.org', + napwiki: 'https://nap.wikipedia.org', + ndswiki: 'https://nds.wikipedia.org', + ndswiktionary: 'https://nds.wiktionary.org', + ndswikibooks: 'https://nds.wikibooks.org', + ndswikiquote: 'https://nds.wikiquote.org', + nds_nlwiki: 'https://nds-nl.wikipedia.org', + newiki: 'https://ne.wikipedia.org', + newiktionary: 'https://ne.wiktionary.org', + newikibooks: 'https://ne.wikibooks.org', + newwiki: 'https://new.wikipedia.org', + ngwiki: 'https://ng.wikipedia.org', + nlwiki: 'https://nl.wikipedia.org', + nlwiktionary: 'https://nl.wiktionary.org', + nlwikibooks: 'https://nl.wikibooks.org', + nlwikinews: 'https://nl.wikinews.org', + nlwikiquote: 'https://nl.wikiquote.org', + nlwikisource: 'https://nl.wikisource.org', + nlwikivoyage: 'https://nl.wikivoyage.org', + nnwiki: 'https://nn.wikipedia.org', + nnwiktionary: 'https://nn.wiktionary.org', + nnwikiquote: 'https://nn.wikiquote.org', + nowiki: 'https://no.wikipedia.org', + nowiktionary: 'https://no.wiktionary.org', + nowikibooks: 'https://no.wikibooks.org', + nowikinews: 'https://no.wikinews.org', + nowikiquote: 'https://no.wikiquote.org', + nowikisource: 'https://no.wikisource.org', + novwiki: 'https://nov.wikipedia.org', + nrmwiki: 'https://nrm.wikipedia.org', + nsowiki: 'https://nso.wikipedia.org', + nvwiki: 'https://nv.wikipedia.org', + nywiki: 'https://ny.wikipedia.org', + ocwiki: 'https://oc.wikipedia.org', + ocwiktionary: 'https://oc.wiktionary.org', + ocwikibooks: 'https://oc.wikibooks.org', + omwiki: 'https://om.wikipedia.org', + omwiktionary: 'https://om.wiktionary.org', + orwiki: 'https://or.wikipedia.org', + orwiktionary: 'https://or.wiktionary.org', + orwikisource: 'https://or.wikisource.org', + oswiki: 'https://os.wikipedia.org', + pawiki: 'https://pa.wikipedia.org', + pawiktionary: 'https://pa.wiktionary.org', + pawikibooks: 'https://pa.wikibooks.org', + pagwiki: 'https://pag.wikipedia.org', + pamwiki: 'https://pam.wikipedia.org', + papwiki: 'https://pap.wikipedia.org', + pcdwiki: 'https://pcd.wikipedia.org', + pdcwiki: 'https://pdc.wikipedia.org', + pflwiki: 'https://pfl.wikipedia.org', + piwiki: 'https://pi.wikipedia.org', + piwiktionary: 'https://pi.wiktionary.org', + pihwiki: 'https://pih.wikipedia.org', + plwiki: 'https://pl.wikipedia.org', + plwiktionary: 'https://pl.wiktionary.org', + plwikibooks: 'https://pl.wikibooks.org', + plwikinews: 'https://pl.wikinews.org', + plwikiquote: 'https://pl.wikiquote.org', + plwikisource: 'https://pl.wikisource.org', + plwikivoyage: 'https://pl.wikivoyage.org', + pmswiki: 'https://pms.wikipedia.org', + pnbwiki: 'https://pnb.wikipedia.org', + pnbwiktionary: 'https://pnb.wiktionary.org', + pntwiki: 'https://pnt.wikipedia.org', + pswiki: 'https://ps.wikipedia.org', + pswiktionary: 'https://ps.wiktionary.org', + pswikibooks: 'https://ps.wikibooks.org', + ptwiki: 'https://pt.wikipedia.org', + ptwiktionary: 'https://pt.wiktionary.org', + ptwikibooks: 'https://pt.wikibooks.org', + ptwikinews: 'https://pt.wikinews.org', + ptwikiquote: 'https://pt.wikiquote.org', + ptwikisource: 'https://pt.wikisource.org', + ptwikiversity: 'https://pt.wikiversity.org', + ptwikivoyage: 'https://pt.wikivoyage.org', + quwiki: 'https://qu.wikipedia.org', + quwiktionary: 'https://qu.wiktionary.org', + quwikibooks: 'https://qu.wikibooks.org', + quwikiquote: 'https://qu.wikiquote.org', + rmwiki: 'https://rm.wikipedia.org', + rmwiktionary: 'https://rm.wiktionary.org', + rmwikibooks: 'https://rm.wikibooks.org', + rmywiki: 'https://rmy.wikipedia.org', + rnwiki: 'https://rn.wikipedia.org', + rnwiktionary: 'https://rn.wiktionary.org', + rowiki: 'https://ro.wikipedia.org', + rowiktionary: 'https://ro.wiktionary.org', + rowikibooks: 'https://ro.wikibooks.org', + rowikinews: 'https://ro.wikinews.org', + rowikiquote: 'https://ro.wikiquote.org', + rowikisource: 'https://ro.wikisource.org', + rowikivoyage: 'https://ro.wikivoyage.org', + roa_rupwiki: 'https://roa-rup.wikipedia.org', + roa_rupwiktionary: 'https://roa-rup.wiktionary.org', + roa_tarawiki: 'https://roa-tara.wikipedia.org', + ruwiki: 'https://ru.wikipedia.org', + ruwiktionary: 'https://ru.wiktionary.org', + ruwikibooks: 'https://ru.wikibooks.org', + ruwikinews: 'https://ru.wikinews.org', + ruwikiquote: 'https://ru.wikiquote.org', + ruwikisource: 'https://ru.wikisource.org', + ruwikiversity: 'https://ru.wikiversity.org', + ruwikivoyage: 'https://ru.wikivoyage.org', + ruewiki: 'https://rue.wikipedia.org', + rwwiki: 'https://rw.wikipedia.org', + rwwiktionary: 'https://rw.wiktionary.org', + sawiki: 'https://sa.wikipedia.org', + sawiktionary: 'https://sa.wiktionary.org', + sawikibooks: 'https://sa.wikibooks.org', + sawikiquote: 'https://sa.wikiquote.org', + sawikisource: 'https://sa.wikisource.org', + sahwiki: 'https://sah.wikipedia.org', + sahwikisource: 'https://sah.wikisource.org', + scwiki: 'https://sc.wikipedia.org', + scwiktionary: 'https://sc.wiktionary.org', + scnwiki: 'https://scn.wikipedia.org', + scnwiktionary: 'https://scn.wiktionary.org', + scowiki: 'https://sco.wikipedia.org', + sdwiki: 'https://sd.wikipedia.org', + sdwiktionary: 'https://sd.wiktionary.org', + sdwikinews: 'https://sd.wikinews.org', + sewiki: 'https://se.wikipedia.org', + sewikibooks: 'https://se.wikibooks.org', + sgwiki: 'https://sg.wikipedia.org', + sgwiktionary: 'https://sg.wiktionary.org', + shwiki: 'https://sh.wikipedia.org', + shwiktionary: 'https://sh.wiktionary.org', + siwiki: 'https://si.wikipedia.org', + siwiktionary: 'https://si.wiktionary.org', + siwikibooks: 'https://si.wikibooks.org', + simplewiki: 'https://simple.wikipedia.org', + simplewiktionary: 'https://simple.wiktionary.org', + simplewikibooks: 'https://simple.wikibooks.org', + simplewikiquote: 'https://simple.wikiquote.org', + skwiki: 'https://sk.wikipedia.org', + skwiktionary: 'https://sk.wiktionary.org', + skwikibooks: 'https://sk.wikibooks.org', + skwikiquote: 'https://sk.wikiquote.org', + skwikisource: 'https://sk.wikisource.org', + slwiki: 'https://sl.wikipedia.org', + slwiktionary: 'https://sl.wiktionary.org', + slwikibooks: 'https://sl.wikibooks.org', + slwikiquote: 'https://sl.wikiquote.org', + slwikisource: 'https://sl.wikisource.org', + slwikiversity: 'https://sl.wikiversity.org', + smwiki: 'https://sm.wikipedia.org', + smwiktionary: 'https://sm.wiktionary.org', + snwiki: 'https://sn.wikipedia.org', + snwiktionary: 'https://sn.wiktionary.org', + sowiki: 'https://so.wikipedia.org', + sowiktionary: 'https://so.wiktionary.org', + sqwiki: 'https://sq.wikipedia.org', + sqwiktionary: 'https://sq.wiktionary.org', + sqwikibooks: 'https://sq.wikibooks.org', + sqwikinews: 'https://sq.wikinews.org', + sqwikiquote: 'https://sq.wikiquote.org', + srwiki: 'https://sr.wikipedia.org', + srwiktionary: 'https://sr.wiktionary.org', + srwikibooks: 'https://sr.wikibooks.org', + srwikinews: 'https://sr.wikinews.org', + srwikiquote: 'https://sr.wikiquote.org', + srwikisource: 'https://sr.wikisource.org', + srnwiki: 'https://srn.wikipedia.org', + sswiki: 'https://ss.wikipedia.org', + sswiktionary: 'https://ss.wiktionary.org', + stwiki: 'https://st.wikipedia.org', + stwiktionary: 'https://st.wiktionary.org', + stqwiki: 'https://stq.wikipedia.org', + suwiki: 'https://su.wikipedia.org', + suwiktionary: 'https://su.wiktionary.org', + suwikibooks: 'https://su.wikibooks.org', + suwikiquote: 'https://su.wikiquote.org', + svwiki: 'https://sv.wikipedia.org', + svwiktionary: 'https://sv.wiktionary.org', + svwikibooks: 'https://sv.wikibooks.org', + svwikinews: 'https://sv.wikinews.org', + svwikiquote: 'https://sv.wikiquote.org', + svwikisource: 'https://sv.wikisource.org', + svwikiversity: 'https://sv.wikiversity.org', + svwikivoyage: 'https://sv.wikivoyage.org', + swwiki: 'https://sw.wikipedia.org', + swwiktionary: 'https://sw.wiktionary.org', + swwikibooks: 'https://sw.wikibooks.org', + szlwiki: 'https://szl.wikipedia.org', + tawiki: 'https://ta.wikipedia.org', + tawiktionary: 'https://ta.wiktionary.org', + tawikibooks: 'https://ta.wikibooks.org', + tawikinews: 'https://ta.wikinews.org', + tawikiquote: 'https://ta.wikiquote.org', + tawikisource: 'https://ta.wikisource.org', + tewiki: 'https://te.wikipedia.org', + tewiktionary: 'https://te.wiktionary.org', + tewikibooks: 'https://te.wikibooks.org', + tewikiquote: 'https://te.wikiquote.org', + tewikisource: 'https://te.wikisource.org', + tetwiki: 'https://tet.wikipedia.org', + tgwiki: 'https://tg.wikipedia.org', + tgwiktionary: 'https://tg.wiktionary.org', + tgwikibooks: 'https://tg.wikibooks.org', + thwiki: 'https://th.wikipedia.org', + thwiktionary: 'https://th.wiktionary.org', + thwikibooks: 'https://th.wikibooks.org', + thwikinews: 'https://th.wikinews.org', + thwikiquote: 'https://th.wikiquote.org', + thwikisource: 'https://th.wikisource.org', + tiwiki: 'https://ti.wikipedia.org', + tiwiktionary: 'https://ti.wiktionary.org', + tkwiki: 'https://tk.wikipedia.org', + tkwiktionary: 'https://tk.wiktionary.org', + tkwikibooks: 'https://tk.wikibooks.org', + tkwikiquote: 'https://tk.wikiquote.org', + tlwiki: 'https://tl.wikipedia.org', + tlwiktionary: 'https://tl.wiktionary.org', + tlwikibooks: 'https://tl.wikibooks.org', + tnwiki: 'https://tn.wikipedia.org', + tnwiktionary: 'https://tn.wiktionary.org', + towiki: 'https://to.wikipedia.org', + towiktionary: 'https://to.wiktionary.org', + tpiwiki: 'https://tpi.wikipedia.org', + tpiwiktionary: 'https://tpi.wiktionary.org', + trwiki: 'https://tr.wikipedia.org', + trwiktionary: 'https://tr.wiktionary.org', + trwikibooks: 'https://tr.wikibooks.org', + trwikinews: 'https://tr.wikinews.org', + trwikiquote: 'https://tr.wikiquote.org', + trwikisource: 'https://tr.wikisource.org', + tswiki: 'https://ts.wikipedia.org', + tswiktionary: 'https://ts.wiktionary.org', + ttwiki: 'https://tt.wikipedia.org', + ttwiktionary: 'https://tt.wiktionary.org', + ttwikibooks: 'https://tt.wikibooks.org', + ttwikiquote: 'https://tt.wikiquote.org', + tumwiki: 'https://tum.wikipedia.org', + twwiki: 'https://tw.wikipedia.org', + twwiktionary: 'https://tw.wiktionary.org', + tywiki: 'https://ty.wikipedia.org', + tyvwiki: 'https://tyv.wikipedia.org', + udmwiki: 'https://udm.wikipedia.org', + ugwiki: 'https://ug.wikipedia.org', + ugwiktionary: 'https://ug.wiktionary.org', + ugwikibooks: 'https://ug.wikibooks.org', + ugwikiquote: 'https://ug.wikiquote.org', + ukwiki: 'https://uk.wikipedia.org', + ukwiktionary: 'https://uk.wiktionary.org', + ukwikibooks: 'https://uk.wikibooks.org', + ukwikinews: 'https://uk.wikinews.org', + ukwikiquote: 'https://uk.wikiquote.org', + ukwikisource: 'https://uk.wikisource.org', + ukwikivoyage: 'https://uk.wikivoyage.org', + urwiki: 'https://ur.wikipedia.org', + urwiktionary: 'https://ur.wiktionary.org', + urwikibooks: 'https://ur.wikibooks.org', + urwikiquote: 'https://ur.wikiquote.org', + uzwiki: 'https://uz.wikipedia.org', + uzwiktionary: 'https://uz.wiktionary.org', + uzwikibooks: 'https://uz.wikibooks.org', + uzwikiquote: 'https://uz.wikiquote.org', + vewiki: 'https://ve.wikipedia.org', + vecwiki: 'https://vec.wikipedia.org', + vecwiktionary: 'https://vec.wiktionary.org', + vecwikisource: 'https://vec.wikisource.org', + vepwiki: 'https://vep.wikipedia.org', + viwiki: 'https://vi.wikipedia.org', + viwiktionary: 'https://vi.wiktionary.org', + viwikibooks: 'https://vi.wikibooks.org', + viwikiquote: 'https://vi.wikiquote.org', + viwikisource: 'https://vi.wikisource.org', + viwikivoyage: 'https://vi.wikivoyage.org', + vlswiki: 'https://vls.wikipedia.org', + vowiki: 'https://vo.wikipedia.org', + vowiktionary: 'https://vo.wiktionary.org', + vowikibooks: 'https://vo.wikibooks.org', + vowikiquote: 'https://vo.wikiquote.org', + wawiki: 'https://wa.wikipedia.org', + wawiktionary: 'https://wa.wiktionary.org', + wawikibooks: 'https://wa.wikibooks.org', + warwiki: 'https://war.wikipedia.org', + wowiki: 'https://wo.wikipedia.org', + wowiktionary: 'https://wo.wiktionary.org', + wowikiquote: 'https://wo.wikiquote.org', + wuuwiki: 'https://wuu.wikipedia.org', + xalwiki: 'https://xal.wikipedia.org', + xhwiki: 'https://xh.wikipedia.org', + xhwiktionary: 'https://xh.wiktionary.org', + xhwikibooks: 'https://xh.wikibooks.org', + xmfwiki: 'https://xmf.wikipedia.org', + yiwiki: 'https://yi.wikipedia.org', + yiwiktionary: 'https://yi.wiktionary.org', + yiwikisource: 'https://yi.wikisource.org', + yowiki: 'https://yo.wikipedia.org', + yowiktionary: 'https://yo.wiktionary.org', + yowikibooks: 'https://yo.wikibooks.org', + zawiki: 'https://za.wikipedia.org', + zawiktionary: 'https://za.wiktionary.org', + zawikibooks: 'https://za.wikibooks.org', + zawikiquote: 'https://za.wikiquote.org', + zeawiki: 'https://zea.wikipedia.org', + zhwiki: 'https://zh.wikipedia.org', + zhwiktionary: 'https://zh.wiktionary.org', + zhwikibooks: 'https://zh.wikibooks.org', + zhwikinews: 'https://zh.wikinews.org', + zhwikiquote: 'https://zh.wikiquote.org', + zhwikisource: 'https://zh.wikisource.org', + zhwikivoyage: 'https://zh.wikivoyage.org', + zh_classicalwiki: 'https://zh-classical.wikipedia.org', + zh_min_nanwiki: 'https://zh-min-nan.wikipedia.org', + zh_min_nanwiktionary: 'https://zh-min-nan.wiktionary.org', + zh_min_nanwikibooks: 'https://zh-min-nan.wikibooks.org', + zh_min_nanwikiquote: 'https://zh-min-nan.wikiquote.org', + zh_min_nanwikisource: 'https://zh-min-nan.wikisource.org', + zh_yuewiki: 'https://zh-yue.wikipedia.org', + zuwiki: 'https://zu.wikipedia.org', + zuwiktionary: 'https://zu.wiktionary.org', + zuwikibooks: 'https://zu.wikibooks.org' +}; +if (typeof module !== 'undefined' && module.exports) { + module.exports = site_map; +} + +},{}],14:[function(_dereq_,module,exports){ +'use strict'; + +//turns wikimedia script into json +// https://github.com/spencermountain/wtf_wikipedia +//@spencermountain +var fetch = _dereq_('./lib/fetch_text'); +var parse = _dereq_('./parse'); + +//from a page title or id, fetch the wikiscript +var from_api = function from_api(page_identifier, lang_or_wikiid, cb) { + if (typeof lang_or_wikiid === 'function') { + cb = lang_or_wikiid; + lang_or_wikiid = 'en'; + } + cb = cb || function () {}; + lang_or_wikiid = lang_or_wikiid || 'en'; + if (!fetch) { + //no http method, on the client side + return cb(null); + } + return fetch(page_identifier, lang_or_wikiid, cb); +}; + +//turn wiki-markup into a nicely-formatted text +var plaintext = function plaintext(str) { + var data = parse(str) || {}; + var arr = Object.keys(data.sections).map(function (k) { + return data.sections[k].sentences.map(function (a) { + return a.text; + }).join(' '); + }); + return arr.join('\n\n'); +}; + +module.exports = { + from_api: from_api, + parse: parse, + plaintext: plaintext +}; + +},{"./lib/fetch_text":15,"./parse":23}],15:[function(_dereq_,module,exports){ +'use strict'; +//grab the content of any article, off the api + +var request = _dereq_('superagent'); +var site_map = _dereq_('../data/site_map'); +var redirects = _dereq_('../parse/page/redirects'); + +var fetch = function fetch(page_identifier, lang_or_wikiid, cb) { + lang_or_wikiid = lang_or_wikiid || 'en'; + var identifier_type = 'titles'; + if (page_identifier.match(/^[0-9]*$/) && page_identifier.length > 3) { + identifier_type = 'curid'; + } + var url = void 0; + if (site_map[lang_or_wikiid]) { + url = site_map[lang_or_wikiid] + '/w/api.php'; + } else { + url = 'https://' + lang_or_wikiid + '.wikipedia.org/w/api.php'; + } + //we use the 'revisions' api here, instead of the Raw api, for its CORS-rules.. + url += '?action=query&prop=revisions&rvlimit=1&rvprop=content&format=json&origin=*'; + url += '&' + identifier_type + '=' + encodeURIComponent(page_identifier); + + request.get(url).end(function (err, res) { + if (err) { + console.warn(err); + cb(null); + return; + } + var pages = res.body.query.pages || {}; + var id = Object.keys(pages)[0]; + if (id) { + var page = pages[id]; + if (page && page.revisions && page.revisions[0]) { + var text = page.revisions[0]['*']; + if (redirects.is_redirect(text)) { + var result = redirects.parse_redirect(text); + fetch(result.redirect, lang_or_wikiid, cb); //recursive + return; } - } else { - // in a browser or Rhino - window.Hashes = Hashes; + cb(text); + } else { + cb(null); + } } - })(this); -})(); // IIFE + }); +}; -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],12:[function(_dereq_,module,exports){ +module.exports = fetch; + +// fetch('On_A_Friday', 'en', function(r) { // 'afwiki' +// console.log(JSON.stringify(r, null, 2)); +// }); + +},{"../data/site_map":13,"../parse/page/redirects":28,"superagent":3}],16:[function(_dereq_,module,exports){ 'use strict'; var helpers = { @@ -5727,10 +5976,10 @@ var helpers = { }; module.exports = helpers; -},{}],13:[function(_dereq_,module,exports){ +},{}],17:[function(_dereq_,module,exports){ 'use strict'; -var Hashes = _dereq_('./hashes'); +var Hashes = _dereq_('jshashes'); //the wikimedia image url is a little silly: //https://commons.wikimedia.org/wiki/Commons:FAQ#What_are_the_strangely_named_components_in_file_paths.3F @@ -5740,6 +5989,7 @@ var make_image = function make_image(file) { title = title.charAt(0).toUpperCase() + title.substring(1); //spaces to underscores title = title.replace(/ /g, '_'); + var hash = new Hashes.MD5().hex(title); var path = hash.substr(0, 1) + '/' + hash.substr(0, 2) + '/'; title = encodeURIComponent(title); @@ -5760,7 +6010,7 @@ module.exports = make_image; // make_image('File:Abingdonschool.jpg'); //1e44ecfe85c6446438da2a01a2bf9e4c -},{"./hashes":11}],14:[function(_dereq_,module,exports){ +},{"jshashes":2}],18:[function(_dereq_,module,exports){ //split text into sentences, using regex //@spencermountain MIT @@ -5769,7 +6019,10 @@ module.exports = make_image; // @spencermountain 2015 MIT 'use strict'; -var abbreviations = ['jr', 'mr', 'mrs', 'ms', 'dr', 'prof', 'sr', 'sen', 'corp', 'calif', 'rep', 'gov', 'atty', 'supt', 'det', 'rev', 'col', 'gen', 'lt', 'cmdr', 'adm', 'capt', 'sgt', 'cpl', 'maj', 'dept', 'univ', 'assn', 'bros', 'inc', 'ltd', 'co', 'corp', 'arc', 'al', 'ave', 'blvd', 'cl', 'ct', 'cres', 'exp', 'rd', 'st', 'dist', 'mt', 'ft', 'fy', 'hwy', 'la', 'pd', 'pl', 'plz', 'tce', 'Ala', 'Ariz', 'Ark', 'Cal', 'Calif', 'Col', 'Colo', 'Conn', 'Del', 'Fed', 'Fla', 'Ga', 'Ida', 'Id', 'Ill', 'Ind', 'Ia', 'Kan', 'Kans', 'Ken', 'Ky', 'La', 'Me', 'Md', 'Mass', 'Mich', 'Minn', 'Miss', 'Mo', 'Mont', 'Neb', 'Nebr', 'Nev', 'Mex', 'Okla', 'Ok', 'Ore', 'Penna', 'Penn', 'Pa', 'Dak', 'Tenn', 'Tex', 'Ut', 'Vt', 'Va', 'Wash', 'Wis', 'Wisc', 'Wy', 'Wyo', 'USAFA', 'Alta', 'Ont', 'QuÔøΩ', 'Sask', 'Yuk', 'jan', 'feb', 'mar', 'apr', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec', 'sept', 'vs', 'etc', 'esp', 'llb', 'md', 'bl', 'phd', 'ma', 'ba', 'miss', 'misses', 'mister', 'sir', 'esq', 'mstr', 'lit', 'fl', 'ex', 'eg', 'sep', 'sept', '..']; +var abbreviations = _dereq_('../data/abbreviations'); +var abbrev_reg = new RegExp('(^| )(' + abbreviations.join('|') + ')[.!?] ?$', 'i'); +var acronym_reg = new RegExp('[ |.][A-Z].? +?$', 'i'); +var elipses_reg = new RegExp('\\.\\.\\.* +?$'); //turn a nested array into one array var flatten = function flatten(arr) { @@ -5841,11 +6094,6 @@ var sentence_parser = function sentence_parser(text) { } //detection of non-sentence chunks - // const abbrev_reg = new RegExp('\\b(' + abbreviations.join('|') + ')[.!?] ?$', 'i'); - var abbrev_reg = new RegExp('(^| )(' + abbreviations.join('|') + ')[.!?] ?$', 'i'); - var acronym_reg = new RegExp('[ |\.][A-Z]\.? +?$', 'i'); - var elipses_reg = new RegExp('\\.\\.\\.* +?$'); - var isSentence = function isSentence(hmm) { if (hmm.match(abbrev_reg) || hmm.match(acronym_reg) || hmm.match(elipses_reg)) { return false; @@ -5877,41 +6125,31 @@ var sentence_parser = function sentence_parser(text) { module.exports = sentence_parser; // console.log(sentence_parser('Tony is nice. He lives in Japan.').length === 2); -},{}],15:[function(_dereq_,module,exports){ -"use strict"; - -var kill_xml = _dereq_("./kill_xml"); +},{"../data/abbreviations":10}],19:[function(_dereq_,module,exports){ +'use strict'; -function cleanup_misc(wiki) { - //the dump requires us to unescape xml - //remove comments - wiki = wiki.replace(//g, ""); - wiki = wiki.replace(/__(NOTOC|NOEDITSECTION|FORCETOC|TOC)__/ig, ""); - //signitures - wiki = wiki.replace(/~~{1,3}/, ""); - //horizontal rule - wiki = wiki.replace(/--{1,3}/, ""); - //space - wiki = wiki.replace(/ /g, " "); - //kill off interwiki links - wiki = wiki.replace(/\[\[([a-z][a-z]|simple|war|ceb|min):.{2,60}\]\]/i, ""); - //bold and italics combined - wiki = wiki.replace(/''{4}([^']{0,200})''{4}/g, "$1"); - //bold - wiki = wiki.replace(/''{2}([^']{0,200})''{2}/g, "$1"); - //italic - wiki = wiki.replace(/''([^']{0,200})''/g, "$1"); - //give it the inglorious send-off it deserves.. - wiki = kill_xml(wiki); +var i18n = _dereq_('../data/i18n'); +var cat_reg = new RegExp('\\[\\[:?(' + i18n.categories.join('|') + '):(.{2,60}?)]](w{0,10})', 'ig'); +var cat_remove_reg = new RegExp('^\\[\\[:?(' + i18n.categories.join('|') + '):', 'ig'); +var parse_categories = function parse_categories(r, wiki) { + r.categories = []; + var tmp = wiki.match(cat_reg); //regular links + if (tmp) { + tmp.forEach(function (c) { + c = c.replace(cat_remove_reg, ''); + c = c.replace(/\|?[ \*]?\]\]$/i, ''); //parse fancy onces.. + c = c.replace(/\|.*/, ''); //everything after the '|' is metadata + if (c && !c.match(/[\[\]]/)) { + r.categories.push(c); + } + }); + } return wiki; -} -module.exports = cleanup_misc; -// console.log(cleanup_misc("hi [[as:Plancton]] there")); -// console.log(cleanup_misc('hello
world')) -// console.log(cleanup_misc("hello world ")) +}; +module.exports = parse_categories; -},{"./kill_xml":16}],16:[function(_dereq_,module,exports){ +},{"../data/i18n":11}],20:[function(_dereq_,module,exports){ 'use strict'; //okay, i know you're not supposed to regex html, but... @@ -5921,7 +6159,7 @@ var kill_xml = function kill_xml(wiki) { //luckily, refs can't be recursive.. wiki = wiki.replace(/ ?[\s\S]{0,750}?<\/ref> ?/gi, ' '); // wiki = wiki.replace(/ ?]{0,200}?\/> ?/gi, ' '); // - wiki = wiki.replace(/ ?]{0,200}?>[\s\S]{0,500}?<\/ref> ?/ig, ' '); // + wiki = wiki.replace(/ ?]{0,200}?>[\s\S]{0,500}?<\/ref> ?/gi, ' '); // //other types of xml that we want to trash completely wiki = wiki.replace(/< ?(table|code|score|data|categorytree|charinsert|gallery|hiero|imagemap|inputbox|math|nowiki|poem|references|source|syntaxhighlight|timeline) ?[^>]{0,200}?>[\s\S]{0,700}< ?\/ ?(table|code|score|data|categorytree|charinsert|gallery|hiero|imagemap|inputbox|math|nowiki|poem|references|source|syntaxhighlight|timeline) ?>/gi, ' '); // hi
@@ -5947,34 +6185,294 @@ var kill_xml = function kill_xml(wiki) { // console.log(kill_xml("North America,
and one of")) module.exports = kill_xml; -},{}],17:[function(_dereq_,module,exports){ -"use strict"; +},{}],21:[function(_dereq_,module,exports){ +'use strict'; -var i18n = _dereq_("../data/i18n"); +var kill_xml = _dereq_('./kill_xml'); -function parse_categories(wiki) { - var cats = []; - var reg = new RegExp("\\[\\[:?(" + i18n.categories.join("|") + "):(.{2,60}?)\]\](\w{0,10})", "ig"); - var tmp = wiki.match(reg); //regular links - if (tmp) { - var reg2 = new RegExp("^\\[\\[:?(" + i18n.categories.join("|") + "):", "ig"); - tmp.forEach(function (c) { - c = c.replace(reg2, ""); - c = c.replace(/\|?[ \*]?\]\]$/i, ""); //parse fancy onces.. - c = c.replace(/\|.*/, ""); //everything after the '|' is metadata - if (c && !c.match(/[\[\]]/)) { - cats.push(c); - } - }); - } - return cats; +function cleanup_misc(wiki) { + //the dump requires us to unescape xml + //remove comments + wiki = wiki.replace(//g, ''); + wiki = wiki.replace(/__(NOTOC|NOEDITSECTION|FORCETOC|TOC)__/gi, ''); + //signitures + wiki = wiki.replace(/~~{1,3}/, ''); + //horizontal rule + wiki = wiki.replace(/--{1,3}/, ''); + //space + wiki = wiki.replace(/ /g, ' '); + //kill off interwiki links + wiki = wiki.replace(/\[\[([a-z][a-z]|simple|war|ceb|min):.{2,60}\]\]/i, ''); + //bold and italics combined + wiki = wiki.replace(/''{4}([^']{0,200})''{4}/g, '$1'); + //bold + wiki = wiki.replace(/''{2}([^']{0,200})''{2}/g, '$1'); + //italic + wiki = wiki.replace(/''([^']{0,200})''/g, '$1'); + //give it the inglorious send-off it deserves.. + wiki = kill_xml(wiki); + + return wiki; } -module.exports = parse_categories; +module.exports = cleanup_misc; +// console.log(cleanup_misc("hi [[as:Plancton]] there")); +// console.log(cleanup_misc('hello
world')) +// console.log(cleanup_misc("hello world ")) + +},{"./kill_xml":20}],22:[function(_dereq_,module,exports){ +'use strict'; + +var languages = _dereq_('../../data/languages'); +var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; +var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; + +// templates that need parsing and replacing for inline text +//https://en.wikipedia.org/wiki/Category:Magic_word_templates +var word_templates = function word_templates(wiki) { + //we can be sneaky with this template, as it's often found inside other templates + wiki = wiki.replace(/\{\{URL\|([^ ]{4,100}?)\}\}/gi, '$1'); + //this one needs to be handled manually + wiki = wiki.replace(/\{\{convert\|([0-9]*?)\|([^\|]*?)\}\}/gi, '$1 $2'); //TODO: support https://en.wikipedia.org/wiki/Template:Convert#Ranges_of_values + //date-time templates + var d = new Date(); + wiki = wiki.replace(/\{\{(CURRENT|LOCAL)DAY(2)?\}\}/gi, d.getDate()); + wiki = wiki.replace(/\{\{(CURRENT|LOCAL)MONTH(NAME|ABBREV)?\}\}/gi, months[d.getMonth()]); + wiki = wiki.replace(/\{\{(CURRENT|LOCAL)YEAR\}\}/gi, d.getFullYear()); + wiki = wiki.replace(/\{\{(CURRENT|LOCAL)DAYNAME\}\}/gi, days[d.getDay()]); + //formatting templates + wiki = wiki.replace(/\{\{(lc|uc|formatnum):(.*?)\}\}/gi, '$2'); + wiki = wiki.replace(/\{\{pull quote\|([\s\S]*?)(\|[\s\S]*?)?\}\}/gi, '$1'); + wiki = wiki.replace(/\{\{cquote\|([\s\S]*?)(\|[\s\S]*?)?\}\}/gi, '$1'); + + //font-size + wiki = wiki.replace(/\{\{(small|smaller|midsize|larger|big|bigger|large|huge|resize)\|([\s\S]*?)\}\}/gi, '$2'); + //{{font|size=x%|text}} + + if (wiki.match(/\{\{dts\|/)) { + var date = (wiki.match(/\{\{dts\|(.*?)[\}\|]/) || [])[1] || ''; + date = new Date(date); + if (date && date.getTime()) { + wiki = wiki.replace(/\{\{dts\|.*?\}\}/gi, date.toDateString()); + } else { + wiki = wiki.replace(/\{\{dts\|.*?\}\}/gi, ' '); + } + } + if (wiki.match(/\{\{date\|.*?\}\}/)) { + var _date = wiki.match(/\{\{date\|(.*?)\|(.*?)\|(.*?)\}\}/) || [] || []; + var dateString = _date[1] + ' ' + _date[2] + ' ' + _date[3]; + wiki = wiki.replace(/\{\{date\|.*?\}\}/gi, dateString); + } + //common templates in wiktionary + wiki = wiki.replace(/\{\{term\|(.*?)\|.*?\}\}/gi, "'$1'"); + wiki = wiki.replace(/\{\{IPA\|(.*?)\|.*?\}\}/gi, '$1'); + wiki = wiki.replace(/\{\{sense\|(.*?)\|?.*?\}\}/gi, '($1)'); + wiki = wiki.replace(/\{\{t\+?\|...?\|(.*?)(\|.*)?\}\}/gi, "'$1'"); + //replace languages in 'etyl' tags + if (wiki.match(/\{\{etyl\|/)) { + //doesn't support multiple-ones per sentence.. + var lang = wiki.match(/\{\{etyl\|(.*?)\|.*?\}\}/i)[1] || ''; + lang = lang.toLowerCase(); + if (lang && languages[lang]) { + wiki = wiki.replace(/\{\{etyl\|(.*?)\|.*?\}\}/gi, languages[lang].english_title); + } else { + wiki = wiki.replace(/\{\{etyl\|(.*?)\|.*?\}\}/gi, '($1)'); + } + } + return wiki; +}; +// console.log(word_templates("hello {{CURRENTDAY}} world")) +// console.log(word_templates("hello {{CURRENTMONTH}} world")) +// console.log(word_templates("hello {{CURRENTYEAR}} world")) +// console.log(word_templates("hello {{LOCALDAYNAME}} world")) +// console.log(word_templates("hello {{lc:88}} world")) +// console.log(word_templates("hello {{pull quote|Life is like\n|author=[[asdf]]}} world")) +// console.log(word_templates("hi {{etyl|la|-}} there")) +// console.log(word_templates("{{etyl|la|-}} cognate with {{etyl|is|-}} {{term|hugga||to comfort|lang=is}},")) + +module.exports = word_templates; + +},{"../../data/languages":12}],23:[function(_dereq_,module,exports){ +'use strict'; + +var redirects = _dereq_('./page/redirects'); +var disambig = _dereq_('./page/disambig'); +var word_templates = _dereq_('./cleanup/word_templates'); +var preprocess = _dereq_('./cleanup/misc'); +var parse_tables = _dereq_('./table'); +var parse_categories = _dereq_('./categories'); +var parse_recursion = _dereq_('./recursive'); +var parse_lines = _dereq_('./lines'); + +//convert wikiscript markup lang to json +var main = function main(wiki) { + wiki = wiki || ''; + //detect if page is just redirect, and return + if (redirects.is_redirect(wiki)) { + return redirects.parse_redirect(wiki); + } + //detect if page is just disambiguator page, and return + if (disambig.is_disambig(wiki)) { + return disambig.parse_disambig(wiki); + } + var r = { + type: 'page', + sections: {}, + categories: [], + images: [], + infobox: {}, + infobox_template: {}, + tables: [], + translations: {} + }; + //parse templates like {{currentday}} + wiki = word_templates(wiki); + //kill off (some) craziness + wiki = preprocess(wiki); + //parse the tables + wiki = parse_tables(r, wiki); + //parse+remove scary '[[ [[]] ]]' stuff + wiki = parse_recursion(r, wiki); + //ok, now that the scary recursion issues are gone, we can trust simple regex methods.. + //kill the rest of templates + wiki = wiki.replace(/\{\{.*?\}\}/g, ''); + //get list of links, categories + wiki = parse_categories(r, wiki); + //parse all the headings, and their texts/sentences + wiki = parse_lines(r, wiki); + + return r; +}; + +module.exports = main; + +},{"./categories":19,"./cleanup/misc":21,"./cleanup/word_templates":22,"./lines":24,"./page/disambig":27,"./page/redirects":28,"./recursive":31,"./table":34}],24:[function(_dereq_,module,exports){ +'use strict'; + +//interpret ==heading== lines +var fns = _dereq_('../../lib/helpers'); +var list = _dereq_('./lists'); +var parseSentences = _dereq_('./sentence'); +var heading_reg = /^(={1,5})([^=]{1,200}?)={1,5}$/; + +var parseHeading = function parseHeading(head) { + var title = head[2] || ''; + title = fns.trim_whitespace(title); + var depth = 1; + if (head[1]) { + depth = head[1].length; + } + return { + title: title, + depth: depth, + sentences: [] + }; +}; + +var parseSections = function parseSections(lines) { + var arr = [parseHeading([])]; + for (var i = 0; i < lines.length; i++) { + var line = lines[i]; + //empty lines + if (!line) { + continue; + } + //handle new ==headings== + var header = line.match(heading_reg); + if (header !== null) { + arr.push(parseHeading(header)); + continue; + } + //list or sentence? + var _section = arr[arr.length - 1]; + if (line && list.isList(line)) { + _section.list = _section.list || []; + _section.list.push(line); + } else { + var sentenceArr = parseSentences(line); + _section.sentences = _section.sentences.concat(sentenceArr); + } + } + for (var _i = 0; _i < arr.length; _i++) { + var section = arr[_i]; + if (section.list) { + section.list = list.cleanList(section.list); + } + } + return arr; +}; + +var parseText = function parseText(r, wiki) { + //next, map each line into a parsable sentence + var lines = wiki.replace(/\r/g, '').split(/\n/); + + r.sections = parseSections(lines); + + return wiki; +}; + +module.exports = parseText; + +},{"../../lib/helpers":16,"./lists":25,"./sentence":26}],25:[function(_dereq_,module,exports){ +'use strict'; + +var list_reg = /^[#\*:;\|]+/; +var bullet_reg = /^\*+[^:,\|]{4}/; +var number_reg = /^ ?\#[^:,\|]{4}/; +var parseLine = _dereq_('../text'); + +var isList = function isList(line) { + return list_reg.test(line) || bullet_reg.test(line) || number_reg.test(line); +}; + +var cleanList = function cleanList(list) { + var number = 1; + for (var i = 0; i < list.length; i++) { + var line = list[i]; + //add # numberings formatting + if (line.match(number_reg)) { + line = line.replace(/^ ?#*/, number + ') '); + line = line + '\n'; + number += 1; + } else if (line.match(list_reg)) { + number = 1; + line = line.replace(list_reg, ''); + } + list[i] = parseLine(line); + } + return list; +}; + +module.exports = { + isList: isList, + cleanList: cleanList +}; + +},{"../text":35}],26:[function(_dereq_,module,exports){ +'use strict'; + +var sentence_parser = _dereq_('../../lib/sentence_parser'); +var parseLine = _dereq_('../text'); + +var parseSentences = function parseSentences(line) { + var arr = []; + var sentences = sentence_parser(line); + sentences.forEach(function (str) { + arr.push(parseLine(str)); + }); + return arr; +}; +module.exports = parseSentences; + +},{"../../lib/sentence_parser":18,"../text":35}],27:[function(_dereq_,module,exports){ +'use strict'; -},{"../data/i18n":6}],18:[function(_dereq_,module,exports){ -"use strict"; +var i18n = _dereq_('../../data/i18n'); +var parse_links = _dereq_('../text/links'); +var template_reg = new RegExp('\\{\\{ ?(' + i18n.disambigs.join('|') + ')(\\|[a-z =]*?)? ?\\}\\}', 'i'); -var parse_links = _dereq_("./parse_links"); +var is_disambig = function is_disambig(wiki) { + return template_reg.test(wiki); +}; //return a list of probable pages for this disambig page var parse_disambig = function parse_disambig(wiki) { @@ -5990,100 +6488,251 @@ var parse_disambig = function parse_disambig(wiki) { } }); return { - type: "disambiguation", + type: 'disambiguation', pages: pages }; }; -module.exports = parse_disambig; +module.exports = { + is_disambig: is_disambig, + parse_disambig: parse_disambig +}; + +},{"../../data/i18n":11,"../text/links":36}],28:[function(_dereq_,module,exports){ +'use strict'; + +var i18n = _dereq_('../../data/i18n'); +//pulls target link out of redirect page +var REDIRECT_REGEX = new RegExp('^ ?#(' + i18n.redirects.join('|') + ') *?\\[\\[(.{2,60}?)\\]\\]', 'i'); + +var is_redirect = function is_redirect(wiki) { + return wiki.match(REDIRECT_REGEX); +}; + +var parse_redirect = function parse_redirect(wiki) { + var article = (wiki.match(REDIRECT_REGEX) || [])[2] || ''; + article = article.replace(/#.*/, ''); + return { + type: 'redirect', + redirect: article + }; +}; + +module.exports = { + is_redirect: is_redirect, + parse_redirect: parse_redirect +}; + +},{"../../data/i18n":11}],29:[function(_dereq_,module,exports){ +'use strict'; + +//find all the pairs of '[[...[[..]]...]]' in the text +//used to properly root out recursive template calls, [[.. [[...]] ]] +//basically just adds open tags, and subtracts closing tags +function find_recursive(opener, closer, text) { + var out = []; + var last = []; + var chars = text.split(''); + var open = 0; + for (var i = 0; i < chars.length; i++) { + //incriment open tag + if (chars[i] === opener) { + open += 1; + } + //decrement close tag + if (chars[i] === closer) { + open -= 1; + if (open < 0) { + open = 0; + } + } + if (open >= 0) { + last.push(chars[i]); + } + if (open === 0 && last.length > 0) { + //first, fix botched parse + var open_count = last.filter(function (s) { + return s === opener; + }); + var close_count = last.filter(function (s) { + return s === closer; + }); + //is it botched? + if (open_count.length > close_count.length) { + last.push(closer); + } + //looks good, keep it + out.push(last.join('')); + last = []; + } + } + return out; +} +module.exports = find_recursive; -},{"./parse_links":23}],19:[function(_dereq_,module,exports){ -"use strict"; +// console.log(find_recursive('{', '}', 'he is president. {{nowrap|{{small|(1995–present)}}}} he lives in texas')); +// console.log(find_recursive("{", "}", "this is fun {{nowrap{{small1995–present}}}} and it works")) + +},{}],30:[function(_dereq_,module,exports){ +'use strict'; -var i18n = _dereq_("../data/i18n"); +var i18n = _dereq_('../../data/i18n'); +var make_image = _dereq_('../../lib/make_image'); +var file_reg = new RegExp('(' + i18n.images.concat(i18n.files).join('|') + '):.*?[\\|\\]]', 'i'); //images are usually [[image:my_pic.jpg]] -function parse_image(img) { - var reg = new RegExp("(" + i18n.images.concat(i18n.files).join("|") + "):.*?[\\|\\]]", "i"); - img = img.match(reg) || [""]; - img = img[0].replace(/[\|\]]$/, ""); +var parse_image = function parse_image(img) { + img = img.match(file_reg) || ['']; + img = img[0].replace(/[\|\]]$/, ''); + //add url, etc to image + img = make_image(img); return img; -} +}; module.exports = parse_image; // console.log(parse_image("[[image:my_pic.jpg]]")); -},{"../data/i18n":6}],20:[function(_dereq_,module,exports){ -"use strict"; - -var helpers = _dereq_("../lib/helpers"); -var parse_line = _dereq_("./parse_line"); +},{"../../data/i18n":11,"../../lib/make_image":17}],31:[function(_dereq_,module,exports){ +'use strict'; -function parse_infobox(str) { - var obj = {}; +var i18n = _dereq_('../../data/i18n'); +var languages = _dereq_('../../data/languages'); +var find_recursive = _dereq_('./find'); + +var parse_infobox = _dereq_('./infobox'); +var parse_infobox_template = _dereq_('./infobox_template'); +var parse_image = _dereq_('./image'); + +var infobox_reg = new RegExp('{{(' + i18n.infoboxes.join('|') + ')[: \n]', 'ig'); +var fileRegex = new RegExp('\\[\\[(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'); +var img_regex = new RegExp('^(' + i18n.images.concat(i18n.files).join('|') + ')', 'i'); +var noWrap_reg = /^\{\{nowrap\|(.*?)\}\}$/; + +//reduce the scary recursive situations +var parse_recursive = function parse_recursive(r, wiki) { + //remove {{template {{}} }} recursions + var matches = find_recursive('{', '}', wiki); + matches.forEach(function (s) { + if (s.match(infobox_reg, 'ig') && Object.keys(r.infobox).length === 0) { + r.infobox = parse_infobox(s); + r.infobox_template = parse_infobox_template(s); + } + if (s.match(infobox_reg)) { + wiki = wiki.replace(s, ''); + } + //rest of them... + if (s.match(/^\{\{/)) { + //support nowrap + var nowrap = s.match(noWrap_reg); + if (nowrap) { + wiki = wiki.replace(s, nowrap[1]); + return; + } + //if it's not a known template, but it's recursive, remove it + //(because it will be misread later-on) + wiki = wiki.replace(s, ''); + } + }); - if (str) { - //this collapsible list stuff is just a headache - str = str.replace(/\{\{Collapsible list[^}]{10,1000}\}\}/g, ""); + //second, remove [[file:...[[]] ]] recursions + matches = find_recursive('[', ']', wiki); + matches.forEach(function (s) { + if (s.match(fileRegex)) { + r.images.push(parse_image(s)); + wiki = wiki.replace(s, ''); + } + }); - var stringBuilder = []; + //third, wiktionary-style interlanguage links + matches.forEach(function (s) { + if (s.match(/\[\[([a-z][a-z]):(.*?)\]\]/i) !== null) { + var lang = s.match(/\[\[([a-z][a-z]):/i)[1]; + if (lang && languages[lang]) { + r.translations[lang] = s.match(/\[\[([a-z][a-z]):(.*?)\]\]/i)[2]; + } + wiki = wiki.replace(s, ''); + } + }); - var lastChar = void 0; - var parDepth = -2; // first two {{ - for (var i = 0, len = str.length; i < len; i++) { + //add additional image from infobox, if applicable + if (r.infobox['image'] && r.infobox['image'].text) { + var img = r.infobox['image'].text || ''; + if (typeof img === 'string' && !img.match(img_regex)) { + img = 'File:' + img; + } + r.images.push(img); + } - if (parDepth === 0 && str[i] === '|' && lastChar !== '\n') { - stringBuilder.push('\n'); - } + return wiki; +}; - if (str[i] === '{' || str[i] === '[') { - parDepth++; - } else if (str[i] === '}' || str[i] === ']') { - parDepth--; - } +module.exports = parse_recursive; - lastChar = str[i]; - stringBuilder.push(lastChar); - } +},{"../../data/i18n":11,"../../data/languages":12,"./find":29,"./image":30,"./infobox":32,"./infobox_template":33}],32:[function(_dereq_,module,exports){ +'use strict'; - str = stringBuilder.join(''); +var helpers = _dereq_('../../lib/helpers'); +var parse_line = _dereq_('../text'); - var regex = /\n *\|([^=]*)=(.*)/g; +var line_reg = /\n *\|([^=]*)=(.*)/g; - var regexMatch; - while ((regexMatch = regex.exec(str)) !== null) { +var parse_infobox = function parse_infobox(str) { + if (!str) { + return {}; + } + var obj = {}; + var stringBuilder = []; + var lastChar = void 0; + //this collapsible list stuff is just a headache + str = str.replace(/\{\{Collapsible list[^}]{10,1000}\}\}/g, ''); + + var parDepth = -2; // first two {{ + for (var i = 0, len = str.length; i < len; i++) { + if (parDepth === 0 && str[i] === '|' && lastChar !== '\n') { + stringBuilder.push('\n'); + } + if (str[i] === '{' || str[i] === '[') { + parDepth++; + } else if (str[i] === '}' || str[i] === ']') { + parDepth--; + } + lastChar = str[i]; + stringBuilder.push(lastChar); + } - var key = helpers.trim_whitespace(regexMatch[1] || "") || ""; - var value = helpers.trim_whitespace(regexMatch[2] || "") || ""; + str = stringBuilder.join(''); - //this is necessary for mongodb, im sorry - if (key && key.match(/[\.]/)) { - key = null; - } + var regexMatch = void 0; + while ((regexMatch = line_reg.exec(str)) !== null) { + var key = helpers.trim_whitespace(regexMatch[1] || '') || ''; + var value = helpers.trim_whitespace(regexMatch[2] || '') || ''; - if (key && value) { - obj[key] = parse_line(value); - //turn number strings into integers - if (obj[key].text && obj[key].text.match(/^[0-9,]*$/)) { - obj[key].text = obj[key].text.replace(/,/, ''); - obj[key].text = parseInt(obj[key].text, 10); - } - } - } + //this is necessary for mongodb, im sorry + if (key && key.match(/[\.]/)) { + key = null; } - return obj; -} + if (key && value) { + obj[key] = parse_line(value); + //turn number strings into integers + if (obj[key].text && obj[key].text.match(/^[0-9,]*$/)) { + obj[key].text = obj[key].text.replace(/,/, ''); + obj[key].text = parseInt(obj[key].text, 10); + } + } + } + return obj; +}; module.exports = parse_infobox; -},{"../lib/helpers":12,"./parse_line":22}],21:[function(_dereq_,module,exports){ -"use strict"; +},{"../../lib/helpers":16,"../text":35}],33:[function(_dereq_,module,exports){ +'use strict'; -var i18n = _dereq_("../data/i18n"); +var i18n = _dereq_('../../data/i18n'); +var infobox_template_reg = new RegExp('{{(?:' + i18n.infoboxes.join('|') + ')\\s*(.*)', 'i'); function parse_infobox_template(str) { var template = ''; if (str) { - var infobox_template_reg = new RegExp("\{\{(?:" + i18n.infoboxes.join("|") + ")\\s*(.*)", "i"); var matches = str.match(infobox_template_reg); if (matches && matches.length > 1) { template = matches[1]; @@ -6093,139 +6742,18 @@ function parse_infobox_template(str) { } module.exports = parse_infobox_template; -},{"../data/i18n":6}],22:[function(_dereq_,module,exports){ -"use strict"; - -var helpers = _dereq_("../lib/helpers"); -var parse_links = _dereq_("./parse_links"); -var i18n = _dereq_("../data/i18n"); - -//return only rendered text of wiki links -function resolve_links(line) { - // categories, images, files - var re = new RegExp("\\[\\[:?(" + i18n.categories.join("|") + "):[^\\]\\]]{2,80}\\]\\]", "gi"); - line = line.replace(re, ""); - - // [[Common links]] - line = line.replace(/\[\[:?([^|]{2,80}?)\]\](\w{0,5})/g, "$1$2"); - // [[File:with|Size]] - line = line.replace(/\[\[File:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g, "$1"); - // [[Replaced|Links]] - line = line.replace(/\[\[:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g, "$2$3"); - // External links - line = line.replace(/\[(https?|news|ftp|mailto|gopher|irc):\/\/[^\]\| ]{4,1500}([\| ].*?)?\]/g, "$2"); - return line; -} -// console.log(resolve_links("[http://www.whistler.ca www.whistler.ca]")) - -function postprocess(line) { - - //fix links - line = resolve_links(line); - //oops, recursive image bug - if (line.match(/^(thumb|right|left)\|/i)) { - return null; - } - - line = helpers.trim_whitespace(line); - - // put new lines back in - // line=line+"\n"; - - return line; -} - -function parse_line(line) { - return { - text: postprocess(line), - links: parse_links(line) - }; -} - -// console.log(fetch_links("it is [[Tony Hawk|Tony]]s moher in [[Toronto]]s")) -module.exports = parse_line; - -},{"../data/i18n":6,"../lib/helpers":12,"./parse_links":23}],23:[function(_dereq_,module,exports){ -"use strict"; - -var helpers = _dereq_("../lib/helpers"); -//grab an array of internal links in the text -var parse_links = function parse_links(str) { - var links = []; - var tmp = str.match(/\[\[(.{2,80}?)\]\](\w{0,10})/g); //regular links - if (tmp) { - tmp.forEach(function (s) { - var link, txt; - if (s.match(/\|/)) { - //replacement link [[link|text]] - s = s.replace(/\[\[(.{2,80}?)\]\](\w{0,10})/g, "$1$2"); //remove ['s and keep suffix - link = s.replace(/(.{2,60})\|.{0,200}/, "$1"); //replaced links - txt = s.replace(/.{2,60}?\|/, ''); - //handle funky case of [[toronto|]] - if (!txt && link.match(/\|$/)) { - link = link.replace(/\|$/, ''); - txt = link; - } - } else { - // standard link [[link]] - link = s.replace(/\[\[(.{2,60}?)\]\](\w{0,10})/g, "$1"); //remove ['s - } - //kill off non-wikipedia namespaces - if (link.match(/^:?(category|catégorie|Kategorie|Categoría|Categoria|Categorie|Kategoria|تصنيف|image|file|image|fichier|datei|media|special|wp|wikipedia|help|user|mediawiki|portal|talk|template|book|draft|module|topic|wiktionary|wikisource):/i)) { - return; - } - //kill off just anchor links [[#history]] - if (link.match(/^#/i)) { - return; - } - //remove anchors from end [[toronto#history]] - link = link.replace(/#[^ ]{1,100}/, ''); - link = helpers.capitalise(link); - var obj = { - page: link, - src: txt - }; - links.push(obj); - }); - } - links = links.filter(helpers.onlyUnique); - if (links.length === 0) { - return undefined; - } - return links; -}; -module.exports = parse_links; - -},{"../lib/helpers":12}],24:[function(_dereq_,module,exports){ -"use strict"; - -var i18n = _dereq_("../data/i18n"); -//pulls target link out of redirect page -var REDIRECT_REGEX = new RegExp("^ ?#(" + i18n.redirects.join("|") + ") *?\\[\\[(.{2,60}?)\\]\\]", "i"); - -exports.is_redirect = function (wiki) { - return wiki.match(REDIRECT_REGEX); -}; - -exports.parse_redirect = function (wiki) { - var article = (wiki.match(REDIRECT_REGEX) || [])[2] || ""; - article = article.replace(/#.*/, ""); - return { - type: "redirect", - redirect: article - }; -}; - -},{"../data/i18n":6}],25:[function(_dereq_,module,exports){ +},{"../../data/i18n":11}],34:[function(_dereq_,module,exports){ 'use strict'; -var helpers = _dereq_("../lib/helpers"); +var helpers = _dereq_('../lib/helpers'); +var table_reg = /\{\|[\s\S]{1,8000}?\|\}/g; + //turn a {|...table string into an array of arrays var parse_table = function parse_table(wiki) { var table = []; var lines = wiki.replace(/\r/g, '').split(/\n/); lines.forEach(function (str) { - //die + //die here if (str.match(/^\|\}/)) { return; } @@ -6259,129 +6787,139 @@ var parse_table = function parse_table(wiki) { }); return table; }; -module.exports = parse_table; -},{"../lib/helpers":12}],26:[function(_dereq_,module,exports){ +var findTables = function findTables(r, wiki) { + r.tables = wiki.match(table_reg, '') || []; + r.tables = r.tables.map(function (str) { + return parse_table(str); + }); + //remove tables + wiki = wiki.replace(table_reg, ''); + return wiki; +}; +module.exports = findTables; + +},{"../lib/helpers":16}],35:[function(_dereq_,module,exports){ 'use strict'; -//find all the pairs of '[[...[[..]]...]]' in the text -//used to properly root out recursive template calls, [[.. [[...]] ]] -//basically just adds open tags, and subtracts closing tags -function recursive_matches(opener, closer, text) { - var out = []; - var last = []; - var chars = text.split(''); - var open = 0; - for (var i = 0; i < chars.length; i++) { - //incriment open tag - if (chars[i] === opener) { - open += 1; - } - //decrement close tag - if (chars[i] === closer) { - open -= 1; - if (open < 0) { - open = 0; - } - } - if (open >= 0) { - last.push(chars[i]); - } - if (open === 0 && last.length > 0) { - //first, fix botched parse - var open_count = last.filter(function (s) { - return s === opener; - }); - var close_count = last.filter(function (s) { - return s === closer; - }); - //is it botched? - if (open_count.length > close_count.length) { - last.push(closer); - } - //looks good, keep it - out.push(last.join('')); - last = []; - } +var helpers = _dereq_('../../lib/helpers'); +var parse_links = _dereq_('./links'); +var i18n = _dereq_('../../data/i18n'); +var cat_reg = new RegExp('\\[\\[:?(' + i18n.categories.join('|') + '):[^\\]\\]]{2,80}\\]\\]', 'gi'); + +//return only rendered text of wiki links +var resolve_links = function resolve_links(line) { + // categories, images, files + line = line.replace(cat_reg, ''); + // [[Common links]] + line = line.replace(/\[\[:?([^|]{2,80}?)\]\](\w{0,5})/g, '$1$2'); + // [[File:with|Size]] + line = line.replace(/\[\[File:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g, '$1'); + // [[Replaced|Links]] + line = line.replace(/\[\[:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g, '$2$3'); + // External links + line = line.replace(/\[(https?|news|ftp|mailto|gopher|irc):\/\/[^\]\| ]{4,1500}([\| ].*?)?\]/g, '$2'); + return line; +}; +// console.log(resolve_links("[http://www.whistler.ca www.whistler.ca]")) + +function postprocess(line) { + //fix links + line = resolve_links(line); + //oops, recursive image bug + if (line.match(/^(thumb|right|left)\|/i)) { + return null; } - return out; + line = helpers.trim_whitespace(line); + return line; +} + +function parse_line(line) { + return { + text: postprocess(line), + links: parse_links(line) + }; } -module.exports = recursive_matches; -// console.log(recursive_matches('{', '}', 'he is president. {{nowrap|{{small|(1995–present)}}}} he lives in texas')); -// console.log(recursive_matches("{", "}", "this is fun {{nowrap{{small1995–present}}}} and it works")) +module.exports = parse_line; -},{}],27:[function(_dereq_,module,exports){ +},{"../../data/i18n":11,"../../lib/helpers":16,"./links":36}],36:[function(_dereq_,module,exports){ 'use strict'; -var languages = _dereq_('./data/languages'); - -// templates that need parsing and replacing for inline text -//https://en.wikipedia.org/wiki/Category:Magic_word_templates -var word_templates = function word_templates(wiki) { - //we can be sneaky with this template, as it's often found inside other templates - wiki = wiki.replace(/\{\{URL\|([^ ]{4,100}?)\}\}/gi, '$1'); - //this one needs to be handled manually - wiki = wiki.replace(/\{\{convert\|([0-9]*?)\|([^\|]*?)\}\}/gi, '$1 $2'); //TODO: support https://en.wikipedia.org/wiki/Template:Convert#Ranges_of_values - //date-time templates - var d = new Date(); - wiki = wiki.replace(/\{\{(CURRENT|LOCAL)DAY(2)?\}\}/gi, d.getDate()); - var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; - wiki = wiki.replace(/\{\{(CURRENT|LOCAL)MONTH(NAME|ABBREV)?\}\}/gi, months[d.getMonth()]); - wiki = wiki.replace(/\{\{(CURRENT|LOCAL)YEAR\}\}/gi, d.getFullYear()); - var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; - wiki = wiki.replace(/\{\{(CURRENT|LOCAL)DAYNAME\}\}/gi, days[d.getDay()]); - //formatting templates - wiki = wiki.replace(/\{\{(lc|uc|formatnum):(.*?)\}\}/gi, '$2'); - wiki = wiki.replace(/\{\{pull quote\|([\s\S]*?)(\|[\s\S]*?)?\}\}/gi, '$1'); - wiki = wiki.replace(/\{\{cquote\|([\s\S]*?)(\|[\s\S]*?)?\}\}/gi, '$1'); +var helpers = _dereq_('../../lib/helpers'); +var link_reg = /\[\[(.{2,80}?)\]\](\w{0,10})/g; +var ignore_links = /^:?(category|catégorie|Kategorie|Categoría|Categoria|Categorie|Kategoria|تصنيف|image|file|image|fichier|datei|media|special|wp|wikipedia|help|user|mediawiki|portal|talk|template|book|draft|module|topic|wiktionary|wikisource):/i; +var external_link = /\[(https?|news|ftp|mailto|gopher|irc)(:\/\/[^\]\| ]{4,1500})([\| ].*?)?\]/g; - //font-size - wiki = wiki.replace(/\{\{(small|smaller|midsize|larger|big|bigger|large|huge|resize)\|([\s\S]*?)\}\}/gi, '$2'); - //{{font|size=x%|text}} +var external_links = function external_links(links, str) { + str.replace(external_link, function (all, protocol, link) { + var text = ''; + var m = link.match(/\[([^\| ]+)/); + if (m && m[1]) { + text = m[1]; + } + links.push({ + type: 'external', + site: protocol + link, + text: text + }); + return text; + }); + return links; +}; - if (wiki.match(/\{\{dts\|/)) { - var date = (wiki.match(/\{\{dts\|(.*?)[\}\|]/) || [])[1] || ''; - date = new Date(date); - if (date && date.getTime()) { - wiki = wiki.replace(/\{\{dts\|.*?\}\}/gi, date.toDateString()); +var internal_links = function internal_links(links, str) { + //regular links + str.replace(link_reg, function (_, s) { + var link, txt; + if (s.match(/\|/)) { + //replacement link [[link|text]] + s = s.replace(/\[\[(.{2,80}?)\]\](\w{0,10})/g, '$1$2'); //remove ['s and keep suffix + link = s.replace(/(.{2,60})\|.{0,200}/, '$1'); //replaced links + txt = s.replace(/.{2,60}?\|/, ''); + //handle funky case of [[toronto|]] + if (!txt && link.match(/\|$/)) { + link = link.replace(/\|$/, ''); + txt = link; + } } else { - wiki = wiki.replace(/\{\{dts\|.*?\}\}/gi, ' '); + // standard link [[link]] + link = s.replace(/\[\[(.{2,60}?)\]\](\w{0,10})/g, '$1'); //remove ['s } - } - if (wiki.match(/\{\{date\|.*?\}\}/)) { - var date = wiki.match(/\{\{date\|(.*?)\|(.*?)\|(.*?)\}\}/) || [] || []; - var dateString = date[1] + ' ' + date[2] + ' ' + date[3]; - wiki = wiki.replace(/\{\{date\|.*?\}\}/gi, dateString); - } - //common templates in wiktionary - wiki = wiki.replace(/\{\{term\|(.*?)\|.*?\}\}/gi, '\'$1\''); - wiki = wiki.replace(/\{\{IPA\|(.*?)\|.*?\}\}/gi, '$1'); - wiki = wiki.replace(/\{\{sense\|(.*?)\|?.*?\}\}/gi, '($1)'); - wiki = wiki.replace(/\{\{t\+?\|...?\|(.*?)(\|.*)?\}\}/gi, '\'$1\''); - //replace languages in 'etyl' tags - if (wiki.match(/\{\{etyl\|/)) { - //doesn't support multiple-ones per sentence.. - var lang = wiki.match(/\{\{etyl\|(.*?)\|.*?\}\}/i)[1] || ''; - lang = lang.toLowerCase(); - if (lang && languages[lang]) { - wiki = wiki.replace(/\{\{etyl\|(.*?)\|.*?\}\}/gi, languages[lang].english_title); - } else { - wiki = wiki.replace(/\{\{etyl\|(.*?)\|.*?\}\}/gi, '($1)'); + //kill off non-wikipedia namespaces + if (link.match(ignore_links)) { + return s; } - } - return wiki; + //kill off just anchor links [[#history]] + if (link.match(/^#/i)) { + return s; + } + //remove anchors from end [[toronto#history]] + link = link.replace(/#[^ ]{1,100}/, ''); + var obj = { + page: helpers.capitalise(link), + text: txt || link + }; + links.push(obj); + return s; + }); + return links; }; -// console.log(word_templates("hello {{CURRENTDAY}} world")) -// console.log(word_templates("hello {{CURRENTMONTH}} world")) -// console.log(word_templates("hello {{CURRENTYEAR}} world")) -// console.log(word_templates("hello {{LOCALDAYNAME}} world")) -// console.log(word_templates("hello {{lc:88}} world")) -// console.log(word_templates("hello {{pull quote|Life is like\n|author=[[asdf]]}} world")) -// console.log(word_templates("hi {{etyl|la|-}} there")) -// console.log(word_templates("{{etyl|la|-}} cognate with {{etyl|is|-}} {{term|hugga||to comfort|lang=is}},")) -module.exports = word_templates; +//grab an array of internal links in the text +var parse_links = function parse_links(str) { + var links = []; + //first, parse external links + links = external_links(links, str); + //internal links + links = internal_links(links, str); + + if (links.length === 0) { + return undefined; + } + return links; +}; +module.exports = parse_links; -},{"./data/languages":7}]},{},[9])(9) +},{"../../lib/helpers":16}]},{},[14])(14) }); \ No newline at end of file diff --git a/builds/wtf_wikipedia.min.js b/builds/wtf_wikipedia.min.js index cb5ec66b..6b6d2fa3 100644 --- a/builds/wtf_wikipedia.min.js +++ b/builds/wtf_wikipedia.min.js @@ -1,8 +1,8 @@ -/* wtf_wikipedia v0.8.7 +/* wtf_wikipedia v1.0.0 github.com/spencermountain/wtf_wikipedia MIT */ -!function(i){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=i();else if("function"==typeof define&&define.amd)define([],i);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.wtf_wikipedia=i()}}(function(){var i;return function i(t,e,o){function r(n,a){if(!e[n]){if(!t[n]){var l="function"==typeof require&&require;if(!a&&l)return l(n,!0);if(s)return s(n,!0);var k=new Error("Cannot find module '"+n+"'");throw k.code="MODULE_NOT_FOUND",k}var h=e[n]={exports:{}};t[n][0].call(h.exports,function(i){var e=t[n][1][i];return r(e?e:i)},h,h.exports,i,t,e,o)}return e[n].exports}for(var s="function"==typeof require&&require,n=0;n=300)&&(o=new Error(t.statusText||"Unsuccessful HTTP response"),o.original=i,o.response=t,o.status=t.status)}catch(i){o=i}o?e.callback(o,t):e.callback(null,t)})}function c(i,t){var e=y("DELETE",i);return t&&e.end(t),e}var g;"undefined"!=typeof window?g=window:"undefined"!=typeof self?g=self:(console.warn("Using browser-only version of superagent in non-browser environment"),g=this);var u=i("emitter"),d=i("./request-base"),f=i("./is-object"),y=t.exports=i("./request").bind(null,p);y.getXHR=function(){if(!(!g.XMLHttpRequest||g.location&&"file:"==g.location.protocol&&g.ActiveXObject))return new XMLHttpRequest;try{return new ActiveXObject("Microsoft.XMLHTTP")}catch(i){}try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(i){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(i){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(i){}throw Error("Browser-only verison of superagent could not find XHR")};var _="".trim?function(i){return i.trim()}:function(i){return i.replace(/(^\s*|\s*$)/g,"")};y.serializeObject=r,y.parseString=n,y.types={html:"text/html",json:"application/json",xml:"application/xml",urlencoded:"application/x-www-form-urlencoded",form:"application/x-www-form-urlencoded","form-data":"application/x-www-form-urlencoded"},y.serialize={"application/x-www-form-urlencoded":r,"application/json":JSON.stringify},y.parse={"application/x-www-form-urlencoded":n,"application/json":JSON.parse},w.prototype.get=function(i){return this.header[i.toLowerCase()]},w.prototype._setHeaderProperties=function(i){var t=this.header["content-type"]||"";this.type=k(t);var e=h(t);for(var o in e)this[o]=e[o]},w.prototype._parseBody=function(i){var t=y.parse[this.type];return!t&&l(this.type)&&(t=y.parse["application/json"]),t&&i&&(i.length||i instanceof Object)?t(i):null},w.prototype._setStatusProperties=function(i){1223===i&&(i=204);var t=i/100|0;this.status=this.statusCode=i,this.statusType=t,this.info=1==t,this.ok=2==t,this.clientError=4==t,this.serverError=5==t,this.error=(4==t||5==t)&&this.toError(),this.accepted=202==i,this.noContent=204==i,this.badRequest=400==i,this.unauthorized=401==i,this.notAcceptable=406==i,this.notFound=404==i,this.forbidden=403==i},w.prototype.toError=function(){var i=this.req,t=i.method,e=i.url,o="cannot "+t+" "+e+" ("+this.status+")",r=new Error(o);return r.status=this.status,r.method=t,r.url=e,r},y.Response=w,u(p.prototype);for(var b in d)p.prototype[b]=d[b];p.prototype.type=function(i){return this.set("Content-Type",y.types[i]||i),this},p.prototype.responseType=function(i){return this._responseType=i,this},p.prototype.accept=function(i){return this.set("Accept",y.types[i]||i),this},p.prototype.auth=function(i,t,e){switch(e||(e={type:"basic"}),e.type){case"basic":var o=btoa(i+":"+t);this.set("Authorization","Basic "+o);break;case"auto":this.username=i,this.password=t}return this},p.prototype.query=function(i){return"string"!=typeof i&&(i=r(i)),i&&this._query.push(i),this},p.prototype.attach=function(i,t,e){return this._getFormData().append(i,t,e||t.name),this},p.prototype._getFormData=function(){return this._formData||(this._formData=new g.FormData),this._formData},p.prototype.callback=function(i,t){var e=this._callback;this.clearTimeout(),e(i,t)},p.prototype.crossDomainError=function(){var i=new Error("Request has been terminated\nPossible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.");i.crossDomain=!0,i.status=this.status,i.method=this.method,i.url=this.url,this.callback(i)},p.prototype._timeoutError=function(){var i=this._timeout,t=new Error("timeout of "+i+"ms exceeded");t.timeout=i,this.callback(t)},p.prototype._appendQueryString=function(){var i=this._query.join("&");i&&(this.url+=~this.url.indexOf("?")?"&"+i:"?"+i)},p.prototype.end=function(i){var t=this,e=this.xhr=y.getXHR(),r=this._timeout,s=this._formData||this._data;this._callback=i||o,e.onreadystatechange=function(){if(4==e.readyState){var i;try{i=e.status}catch(t){i=0}if(0==i){if(t.timedout)return t._timeoutError();if(t._aborted)return;return t.crossDomainError()}t.emit("end")}};var n=function(i,e){e.total>0&&(e.percent=e.loaded/e.total*100),e.direction=i,t.emit("progress",e)};if(this.hasListeners("progress"))try{e.onprogress=n.bind(null,"download"),e.upload&&(e.upload.onprogress=n.bind(null,"upload"))}catch(i){}if(r&&!this._timer&&(this._timer=setTimeout(function(){t.timedout=!0,t.abort()},r)),this._appendQueryString(),this.username&&this.password?e.open(this.method,this.url,!0,this.username,this.password):e.open(this.method,this.url,!0),this._withCredentials&&(e.withCredentials=!0),"GET"!=this.method&&"HEAD"!=this.method&&"string"!=typeof s&&!this._isHost(s)){var a=this._header["content-type"],k=this._serializer||y.serialize[a?a.split(";")[0]:""];!k&&l(a)&&(k=y.serialize["application/json"]),k&&(s=k(s))}for(var h in this.header)null!=this.header[h]&&e.setRequestHeader(h,this.header[h]);return this._responseType&&(e.responseType=this._responseType),this.emit("request",this),e.send("undefined"!=typeof s?s:null),this},y.Request=p,y.get=function(i,t,e){var o=y("GET",i);return"function"==typeof t&&(e=t,t=null),t&&o.query(t),e&&o.end(e),o},y.head=function(i,t,e){var o=y("HEAD",i);return"function"==typeof t&&(e=t,t=null),t&&o.send(t),e&&o.end(e),o},y.options=function(i,t,e){var o=y("OPTIONS",i);return"function"==typeof t&&(e=t,t=null),t&&o.send(t),e&&o.end(e),o},y.del=c,y.delete=c,y.patch=function(i,t,e){var o=y("PATCH",i);return"function"==typeof t&&(e=t,t=null),t&&o.send(t),e&&o.end(e),o},y.post=function(i,t,e){var o=y("POST",i);return"function"==typeof t&&(e=t,t=null),t&&o.send(t),e&&o.end(e),o},y.put=function(i,t,e){var o=y("PUT",i);return"function"==typeof t&&(e=t,t=null),t&&o.send(t),e&&o.end(e),o}},{"./is-object":3,"./request":5,"./request-base":4,emitter:1}],3:[function(i,t,e){function o(i){return null!==i&&"object"==typeof i}t.exports=o},{}],4:[function(i,t,e){var o=i("./is-object");e.clearTimeout=function(){return this._timeout=0,clearTimeout(this._timer),this},e.parse=function(i){return this._parser=i,this},e.serialize=function(i){return this._serializer=i,this},e.timeout=function(i){return this._timeout=i,this},e.then=function(i,t){if(!this._fullfilledPromise){var e=this;this._fullfilledPromise=new Promise(function(i,t){e.end(function(e,o){e?t(e):i(o)})})}return this._fullfilledPromise.then(i,t)},e.catch=function(i){return this.then(void 0,i)},e.use=function(i){return i(this),this},e.get=function(i){return this._header[i.toLowerCase()]},e.getHeader=e.get,e.set=function(i,t){if(o(i)){for(var e in i)this.set(e,i[e]);return this}return this._header[i.toLowerCase()]=t,this.header[i]=t,this},e.unset=function(i){return delete this._header[i.toLowerCase()],delete this.header[i],this},e.field=function(i,t){if(null===i||void 0===i)throw new Error(".field(name, val) name can not be empty");if(o(i)){for(var e in i)this.field(e,i[e]);return this}if(null===t||void 0===t)throw new Error(".field(name, val) val can not be empty");return this._getFormData().append(i,t),this},e.abort=function(){return this._aborted?this:(this._aborted=!0,this.xhr&&this.xhr.abort(),this.req&&this.req.abort(),this.clearTimeout(),this.emit("abort"),this)},e.withCredentials=function(){return this._withCredentials=!0,this},e.redirects=function(i){return this._maxRedirects=i,this},e.toJSON=function(){return{method:this.method,url:this.url,data:this._data,headers:this._header}},e._isHost=function(i){var t={}.toString.call(i);switch(t){case"[object File]":case"[object Blob]":case"[object FormData]":return!0;default:return!1}},e.send=function(i){var t=o(i),e=this._header["content-type"];if(t&&o(this._data))for(var r in i)this._data[r]=i[r];else"string"==typeof i?(e||this.type("form"),e=this._header["content-type"],"application/x-www-form-urlencoded"==e?this._data=this._data?this._data+"&"+i:i:this._data=(this._data||"")+i):this._data=i;return!t||this._isHost(i)?this:(e||this.type("json"),this)}},{"./is-object":3}],5:[function(i,t,e){function o(i,t,e){return"function"==typeof e?new i("GET",t).end(e):2==arguments.length?new i("GET",t):new i(t,e)}t.exports=o},{}],6:[function(i,t,e){"use strict";var o={files:["файл","fitxer","soubor","datei","file","archivo","پرونده","tiedosto","mynd","su'wret","fichier","bestand","датотека","dosya","fil"],images:["image"],templates:["шаблён","plantilla","šablona","vorlage","template","الگو","malline","snið","shablon","modèle","sjabloon","шаблон","şablon"],categories:["катэгорыя","categoria","kategorie","category","categoría","رده","luokka","flokkur","kategoriya","catégorie","categorie","категорија","kategori","kategoria","تصنيف"],redirects:["перанакіраваньне","redirect","přesměruj","weiterleitung","redirección","redireccion","تغییر_مسیر","تغییرمسیر","ohjaus","uudelleenohjaus","tilvísun","aýdaw","айдау","redirection","doorverwijzing","преусмери","преусмјери","yönlendi̇rme","yönlendi̇r","重定向","redirección","redireccion","重定向","yönlendirm?e?","تغییر_مسیر","تغییرمسیر","перанакіраваньне","yönlendirme"],specials:["спэцыяльныя","especial","speciální","spezial","special","ویژه","toiminnot","kerfissíða","arnawlı","spécial","speciaal","посебно","özel"],users:["удзельнік","usuari","uživatel","benutzer","user","usuario","کاربر","käyttäjä","notandi","paydalanıwshı","utilisateur","gebruiker","корисник","kullanıcı"],disambigs:["disambig","disambiguation","dab","disamb","begriffsklärung","ujednoznacznienie","doorverwijspagina","消歧义","desambiguación","dubbelsinnig","disambigua","desambiguação","homonymie","неоднозначность","anlam ayrımı"],infoboxes:["infobox","ficha","канадский","inligtingskas","inligtingskas3","لغة","bilgi kutusu","yerleşim bilgi kutusu","infoboks"],sources:["references","see also","external links","further reading","notes et références","voir aussi","liens externes"]};"undefined"!=typeof t&&t.exports&&(t.exports=o)},{}],7:[function(i,t,e){"use strict";t.exports={aa:{english_title:"Afar",direction:"ltr",local_title:"Afar"},ab:{english_title:"Abkhazian",direction:"ltr",local_title:"Аҧсуа"},af:{english_title:"Afrikaans",direction:"ltr",local_title:"Afrikaans"},ak:{english_title:"Akan",direction:"ltr",local_title:"Akana"},als:{english_title:"Alemannic",direction:"ltr",local_title:"Alemannisch"},am:{english_title:"Amharic",direction:"ltr",local_title:"አማርኛ"},an:{english_title:"Aragonese",direction:"ltr",local_title:"Aragonés"},ang:{english_title:"Anglo-Saxon",direction:"ltr",local_title:"Englisc"},ar:{english_title:"Arabic",direction:"rtl",local_title:"العربية"},arc:{english_title:"Aramaic",direction:"rtl",local_title:"ܣܘܪܬ"},as:{english_title:"Assamese",direction:"ltr",local_title:"অসমীয়া"},ast:{english_title:"Asturian",direction:"ltr",local_title:"Asturianu"},av:{english_title:"Avar",direction:"ltr",local_title:"Авар"},ay:{english_title:"Aymara",direction:"ltr",local_title:"Aymar"},az:{english_title:"Azerbaijani",direction:"ltr",local_title:"Azərbaycanca"},ba:{english_title:"Bashkir",direction:"ltr",local_title:"Башҡорт"},bar:{english_title:"Bavarian",direction:"ltr",local_title:"Boarisch"},"bat-smg":{english_title:"Samogitian",direction:"ltr",local_title:"Žemaitėška"},bcl:{english_title:"Bikol",direction:"ltr",local_title:"Bikol"},be:{english_title:"Belarusian",direction:"ltr",local_title:"Беларуская"},"be-x-old":{english_title:"Belarusian",direction:"(Taraškievica)",local_title:"ltr"},bg:{english_title:"Bulgarian",direction:"ltr",local_title:"Български"},bh:{english_title:"Bihari",direction:"ltr",local_title:"भोजपुरी"},bi:{english_title:"Bislama",direction:"ltr",local_title:"Bislama"},bm:{english_title:"Bambara",direction:"ltr",local_title:"Bamanankan"},bn:{english_title:"Bengali",direction:"ltr",local_title:"বাংলা"},bo:{english_title:"Tibetan",direction:"ltr",local_title:"བོད་ཡིག"},bpy:{english_title:"Bishnupriya",direction:"Manipuri",local_title:"ltr"},br:{english_title:"Breton",direction:"ltr",local_title:"Brezhoneg"},bs:{english_title:"Bosnian",direction:"ltr",local_title:"Bosanski"},bug:{english_title:"Buginese",direction:"ltr",local_title:"ᨅᨔ"},bxr:{english_title:"Buriat",direction:"(Russia)",local_title:"ltr"},ca:{english_title:"Catalan",direction:"ltr",local_title:"Català"},cdo:{english_title:"Min",direction:"Dong",local_title:"Chinese"},ce:{english_title:"Chechen",direction:"ltr",local_title:"Нохчийн"},ceb:{english_title:"Cebuano",direction:"ltr",local_title:"Sinugboanong"},ch:{english_title:"Chamorro",direction:"ltr",local_title:"Chamoru"},cho:{english_title:"Choctaw",direction:"ltr",local_title:"Choctaw"},chr:{english_title:"Cherokee",direction:"ltr",local_title:"ᏣᎳᎩ"},chy:{english_title:"Cheyenne",direction:"ltr",local_title:"Tsetsêhestâhese"},co:{english_title:"Corsican",direction:"ltr",local_title:"Corsu"},cr:{english_title:"Cree",direction:"ltr",local_title:"Nehiyaw"},cs:{english_title:"Czech",direction:"ltr",local_title:"Česky"},csb:{english_title:"Kashubian",direction:"ltr",local_title:"Kaszëbsczi"},cu:{english_title:"Old",direction:"Church",local_title:"Slavonic"},cv:{english_title:"Chuvash",direction:"ltr",local_title:"Чăваш"},cy:{english_title:"Welsh",direction:"ltr",local_title:"Cymraeg"},da:{english_title:"Danish",direction:"ltr",local_title:"Dansk"},de:{english_title:"German",direction:"ltr",local_title:"Deutsch"},diq:{english_title:"Dimli",direction:"ltr",local_title:"Zazaki"},dsb:{english_title:"Lower",direction:"Sorbian",local_title:"ltr"},dv:{english_title:"Divehi",direction:"rtl",local_title:"ދިވެހިބަސް"},dz:{english_title:"Dzongkha",direction:"ltr",local_title:"ཇོང་ཁ"},ee:{english_title:"Ewe",direction:"ltr",local_title:"Ɛʋɛ"},far:{english_title:"Farsi",direction:"ltr",local_title:"فارسی"},el:{english_title:"Greek",direction:"ltr",local_title:"Ελληνικά"},en:{english_title:"English",direction:"ltr",local_title:"English"},eo:{english_title:"Esperanto",direction:"ltr",local_title:"Esperanto"},es:{english_title:"Spanish",direction:"ltr",local_title:"Español"},et:{english_title:"Estonian",direction:"ltr",local_title:"Eesti"},eu:{english_title:"Basque",direction:"ltr",local_title:"Euskara"},ext:{english_title:"Extremaduran",direction:"ltr",local_title:"Estremeñu"},ff:{english_title:"Peul",direction:"ltr",local_title:"Fulfulde"},fi:{english_title:"Finnish",direction:"ltr",local_title:"Suomi"},"fiu-vro":{english_title:"Võro",direction:"ltr",local_title:"Võro"},fj:{english_title:"Fijian",direction:"ltr",local_title:"Na"},fo:{english_title:"Faroese",direction:"ltr",local_title:"Føroyskt"},fr:{english_title:"French",direction:"ltr",local_title:"Français"},frp:{english_title:"Arpitan",direction:"ltr",local_title:"Arpitan"},fur:{english_title:"Friulian",direction:"ltr",local_title:"Furlan"},fy:{english_title:"West",direction:"Frisian",local_title:"ltr"},ga:{english_title:"Irish",direction:"ltr",local_title:"Gaeilge"},gan:{english_title:"Gan",direction:"Chinese",local_title:"ltr"},gd:{english_title:"Scottish",direction:"Gaelic",local_title:"ltr"},gil:{english_title:"Gilbertese",direction:"ltr",local_title:"Taetae"},gl:{english_title:"Galician",direction:"ltr",local_title:"Galego"},gn:{english_title:"Guarani",direction:"ltr",local_title:"Avañe'ẽ"},got:{english_title:"Gothic",direction:"ltr",local_title:"gutisk"},gu:{english_title:"Gujarati",direction:"ltr",local_title:"ગુજરાતી"},gv:{english_title:"Manx",direction:"ltr",local_title:"Gaelg"},ha:{english_title:"Hausa",direction:"rtl",local_title:"هَوُسَ"},hak:{english_title:"Hakka",direction:"Chinese",local_title:"ltr"},haw:{english_title:"Hawaiian",direction:"ltr",local_title:"Hawai`i"},he:{english_title:"Hebrew",direction:"rtl",local_title:"עברית"},hi:{english_title:"Hindi",direction:"ltr",local_title:"हिन्दी"},ho:{english_title:"Hiri",direction:"Motu",local_title:"ltr"},hr:{english_title:"Croatian",direction:"ltr",local_title:"Hrvatski"},ht:{english_title:"Haitian",direction:"ltr",local_title:"Krèyol"},hu:{english_title:"Hungarian",direction:"ltr",local_title:"Magyar"},hy:{english_title:"Armenian",direction:"ltr",local_title:"Հայերեն"},hz:{english_title:"Herero",direction:"ltr",local_title:"Otsiherero"},ia:{english_title:"Interlingua",direction:"ltr",local_title:"Interlingua"},id:{english_title:"Indonesian",direction:"ltr",local_title:"Bahasa"},ie:{english_title:"Interlingue",direction:"ltr",local_title:"Interlingue"},ig:{english_title:"Igbo",direction:"ltr",local_title:"Igbo"},ii:{english_title:"Sichuan",direction:"Yi",local_title:"ltr"},ik:{english_title:"Inupiak",direction:"ltr",local_title:"Iñupiak"},ilo:{english_title:"Ilokano",direction:"ltr",local_title:"Ilokano"},io:{english_title:"Ido",direction:"ltr",local_title:"Ido"},is:{english_title:"Icelandic",direction:"ltr",local_title:"Íslenska"},it:{english_title:"Italian",direction:"ltr",local_title:"Italiano"},iu:{english_title:"Inuktitut",direction:"ltr",local_title:"ᐃᓄᒃᑎᑐᑦ"},ja:{english_title:"Japanese",direction:"ltr",local_title:"日本語"},jbo:{english_title:"Lojban",direction:"ltr",local_title:"Lojban"},jv:{english_title:"Javanese",direction:"ltr",local_title:"Basa"},ka:{english_title:"Georgian",direction:"ltr",local_title:"ქართული"},kg:{english_title:"Kongo",direction:"ltr",local_title:"KiKongo"},ki:{english_title:"Kikuyu",direction:"ltr",local_title:"Gĩkũyũ"},kj:{english_title:"Kuanyama",direction:"ltr",local_title:"Kuanyama"},kk:{english_title:"Kazakh",direction:"ltr",local_title:"Қазақша"},kl:{english_title:"Greenlandic",direction:"ltr",local_title:"Kalaallisut"},km:{english_title:"Cambodian",direction:"ltr",local_title:"ភាសាខ្មែរ"},kn:{english_title:"Kannada",direction:"ltr",local_title:"ಕನ್ನಡ"},khw:{english_title:"Khowar",direction:"rtl",local_title:"کھوار"},ko:{english_title:"Korean",direction:"ltr",local_title:"한국어"},kr:{english_title:"Kanuri",direction:"ltr",local_title:"Kanuri"},ks:{english_title:"Kashmiri",direction:"rtl",local_title:"कश्मीरी"},ksh:{english_title:"Ripuarian",direction:"ltr",local_title:"Ripoarisch"},ku:{english_title:"Kurdish",direction:"rtl",local_title:"Kurdî"},kv:{english_title:"Komi",direction:"ltr",local_title:"Коми"},kw:{english_title:"Cornish",direction:"ltr",local_title:"Kernewek"},ky:{english_title:"Kirghiz",direction:"ltr",local_title:"Kırgızca"},la:{english_title:"Latin",direction:"ltr",local_title:"Latina"},lad:{english_title:"Ladino",direction:"ltr",local_title:"Dzhudezmo"},lan:{english_title:"Lango",direction:"ltr",local_title:"Leb"},lb:{english_title:"Luxembourgish",direction:"ltr",local_title:"Lëtzebuergesch"},lg:{english_title:"Ganda",direction:"ltr",local_title:"Luganda"},li:{english_title:"Limburgian",direction:"ltr",local_title:"Limburgs"},lij:{english_title:"Ligurian",direction:"ltr",local_title:"Líguru"},lmo:{english_title:"Lombard",direction:"ltr",local_title:"Lumbaart"},ln:{english_title:"Lingala",direction:"ltr",local_title:"Lingála"},lo:{english_title:"Laotian",direction:"ltr",local_title:"ລາວ"},lt:{english_title:"Lithuanian",direction:"ltr",local_title:"Lietuvių"},lv:{english_title:"Latvian",direction:"ltr",local_title:"Latviešu"},"map-bms":{english_title:"Banyumasan",direction:"ltr",local_title:"Basa"},mg:{english_title:"Malagasy",direction:"ltr",local_title:"Malagasy"},man:{english_title:"Mandarin",direction:"ltr",local_title:"官話"},mh:{english_title:"Marshallese",direction:"ltr",local_title:"Kajin"},mi:{english_title:"Maori",direction:"ltr",local_title:"Māori"},min:{english_title:"Minangkabau",direction:"ltr",local_title:"Minangkabau"},mk:{english_title:"Macedonian",direction:"ltr",local_title:"Македонски"},ml:{english_title:"Malayalam",direction:"ltr",local_title:"മലയാളം"},mn:{english_title:"Mongolian",direction:"ltr",local_title:"Монгол"},mo:{english_title:"Moldovan",direction:"ltr",local_title:"Moldovenească"},mr:{english_title:"Marathi",direction:"ltr",local_title:"मराठी"},ms:{english_title:"Malay",direction:"ltr",local_title:"Bahasa"},mt:{english_title:"Maltese",direction:"ltr",local_title:"bil-Malti"},mus:{english_title:"Creek",direction:"ltr",local_title:"Muskogee"},my:{english_title:"Burmese",direction:"ltr",local_title:"Myanmasa"},na:{english_title:"Nauruan",direction:"ltr",local_title:"Dorerin"},nah:{english_title:"Nahuatl",direction:"ltr",local_title:"Nahuatl"},nap:{english_title:"Neapolitan",direction:"ltr",local_title:"Nnapulitano"},nd:{english_title:"North",direction:"Ndebele",local_title:"ltr"},nds:{english_title:"Low German",direction:"ltr",local_title:"Plattdüütsch"},"nds-nl":{english_title:"Dutch",direction:"Low",local_title:"Saxon"},ne:{english_title:"Nepali",direction:"ltr",local_title:"नेपाली"},new:{english_title:"Newar",direction:"ltr",local_title:"नेपालभाषा"},ng:{english_title:"Ndonga",direction:"ltr",local_title:"Oshiwambo"},nl:{english_title:"Dutch",direction:"ltr",local_title:"Nederlands"},nn:{english_title:"Norwegian",direction:"Nynorsk",local_title:"ltr"},no:{english_title:"Norwegian",direction:"ltr",local_title:"Norsk"},nr:{english_title:"South",direction:"Ndebele",local_title:"ltr"},nso:{english_title:"Northern",direction:"Sotho",local_title:"ltr"},nrm:{english_title:"Norman",direction:"ltr",local_title:"Nouormand"},nv:{english_title:"Navajo",direction:"ltr",local_title:"Diné"},ny:{english_title:"Chichewa",direction:"ltr",local_title:"Chi-Chewa"},oc:{english_title:"Occitan",direction:"ltr",local_title:"Occitan"},oj:{english_title:"Ojibwa",direction:"ltr",local_title:"ᐊᓂᔑᓈᐯᒧᐎᓐ"},om:{english_title:"Oromo",direction:"ltr",local_title:"Oromoo"},or:{english_title:"Oriya",direction:"ltr",local_title:"ଓଡ଼ିଆ"},os:{english_title:"Ossetian",direction:"ltr",local_title:"Иронау"},pa:{english_title:"Panjabi",direction:"ltr",local_title:"ਪੰਜਾਬੀ"},pag:{english_title:"Pangasinan",direction:"ltr",local_title:"Pangasinan"},pam:{english_title:"Kapampangan",direction:"ltr",local_title:"Kapampangan"},pap:{english_title:"Papiamentu",direction:"ltr",local_title:"Papiamentu"},pdc:{english_title:"Pennsylvania",direction:"German",local_title:"ltr"},pi:{english_title:"Pali",direction:"ltr",local_title:"Pāli"},pih:{english_title:"Norfolk",direction:"ltr",local_title:"Norfuk"},pl:{english_title:"Polish",direction:"ltr",local_title:"Polski"},pms:{english_title:"Piedmontese",direction:"ltr",local_title:"Piemontèis"},ps:{english_title:"Pashto",direction:"rtl",local_title:"پښتو"},pt:{english_title:"Portuguese",direction:"ltr",local_title:"Português"},qu:{english_title:"Quechua",direction:"ltr",local_title:"Runa"},rm:{english_title:"Raeto",direction:"Romance",local_title:"ltr"},rmy:{english_title:"Romani",direction:"ltr",local_title:"Romani"},rn:{english_title:"Kirundi",direction:"ltr",local_title:"Kirundi"},ro:{english_title:"Romanian",direction:"ltr",local_title:"Română"},"roa-rup":{english_title:"Aromanian",direction:"ltr",local_title:"Armâneashti"},ru:{english_title:"Russian",direction:"ltr",local_title:"Русский"},rw:{english_title:"Rwandi",direction:"ltr",local_title:"Kinyarwandi"},sa:{english_title:"Sanskrit",direction:"ltr",local_title:"संस्कृतम्"},sc:{english_title:"Sardinian",direction:"ltr",local_title:"Sardu"},scn:{english_title:"Sicilian",direction:"ltr",local_title:"Sicilianu"},sco:{english_title:"Scots",direction:"ltr",local_title:"Scots"},sd:{english_title:"Sindhi",direction:"ltr",local_title:"सिनधि"},se:{english_title:"Northern",direction:"Sami",local_title:"ltr"},sg:{english_title:"Sango",direction:"ltr",local_title:"Sängö"},sh:{english_title:"Serbo-Croatian",direction:"ltr",local_title:"Srpskohrvatski"},si:{english_title:"Sinhalese",direction:"ltr",local_title:"සිංහල"},simple:{english_title:"Simple",direction:"English",local_title:"ltr"},sk:{english_title:"Slovak",direction:"ltr",local_title:"Slovenčina"},sl:{english_title:"Slovenian",direction:"ltr",local_title:"Slovenščina"},sm:{english_title:"Samoan",direction:"ltr",local_title:"Gagana"},sn:{english_title:"Shona",direction:"ltr",local_title:"chiShona"},so:{english_title:"Somalia",direction:"ltr",local_title:"Soomaaliga"},sq:{english_title:"Albanian",direction:"ltr",local_title:"Shqip"},sr:{english_title:"Serbian",direction:"ltr",local_title:"Српски"},ss:{english_title:"Swati",direction:"ltr",local_title:"SiSwati"},st:{english_title:"Southern",direction:"Sotho",local_title:"ltr"},su:{english_title:"Sundanese",direction:"ltr",local_title:"Basa"},sv:{english_title:"Swedish",direction:"ltr",local_title:"Svenska"},sw:{english_title:"Swahili",direction:"ltr",local_title:"Kiswahili"},ta:{english_title:"Tamil",direction:"ltr",local_title:"தமிழ்"},te:{english_title:"Telugu",direction:"ltr",local_title:"తెలుగు"},tet:{english_title:"Tetum",direction:"ltr",local_title:"Tetun"},tg:{english_title:"Tajik",direction:"ltr",local_title:"Тоҷикӣ"},th:{english_title:"Thai",direction:"ltr",local_title:"ไทย"},ti:{english_title:"Tigrinya",direction:"ltr",local_title:"ትግርኛ"},tk:{english_title:"Turkmen",direction:"ltr",local_title:"Туркмен"},tl:{english_title:"Tagalog",direction:"ltr",local_title:"Tagalog"},tlh:{english_title:"Klingon",direction:"ltr",local_title:"tlhIngan-Hol"},tn:{english_title:"Tswana",direction:"ltr",local_title:"Setswana"},to:{english_title:"Tonga",direction:"ltr",local_title:"Lea"},tpi:{english_title:"Tok",direction:"Pisin",local_title:"ltr"},tr:{english_title:"Turkish",direction:"ltr",local_title:"Türkçe"},ts:{english_title:"Tsonga",direction:"ltr",local_title:"Xitsonga"},tt:{english_title:"Tatar",direction:"ltr",local_title:"Tatarça"},tum:{english_title:"Tumbuka",direction:"ltr",local_title:"chiTumbuka"},tw:{english_title:"Twi",direction:"ltr",local_title:"Twi"},ty:{english_title:"Tahitian",direction:"ltr",local_title:"Reo"},udm:{english_title:"Udmurt",direction:"ltr",local_title:"Удмурт"},ug:{english_title:"Uyghur",direction:"ltr",local_title:"Uyƣurqə"},uk:{english_title:"Ukrainian",direction:"ltr",local_title:"Українська"},ur:{english_title:"Urdu",direction:"rtl",local_title:"اردو"},uz:{english_title:"Uzbek",direction:"ltr",local_title:"Ўзбек"},ve:{english_title:"Venda",direction:"ltr",local_title:"Tshivenḓa"},vi:{english_title:"Vietnamese",direction:"ltr",local_title:"Việtnam"},vec:{english_title:"Venetian",direction:"ltr",local_title:"Vèneto"},vls:{english_title:"West",direction:"Flemish",local_title:"ltr"},vo:{english_title:"Volapük",direction:"ltr",local_title:"Volapük"},wa:{english_title:"Walloon",direction:"ltr",local_title:"Walon"},war:{english_title:"Waray-Waray",direction:"ltr",local_title:"Winaray"},wo:{english_title:"Wolof",direction:"ltr",local_title:"Wollof"},xal:{english_title:"Kalmyk",direction:"ltr",local_title:"Хальмг"},xh:{english_title:"Xhosa",direction:"ltr",local_title:"isiXhosa"},yi:{english_title:"Yiddish",direction:"rtl",local_title:"ייִדיש"},yo:{english_title:"Yoruba",direction:"ltr",local_title:"Yorùbá"},za:{english_title:"Zhuang",direction:"ltr",local_title:"Cuengh"},zh:{english_title:"Chinese",direction:"ltr",local_title:"中文"},"zh-classical":{english_title:"Classical",direction:"Chinese",local_title:"ltr"},"zh-min-nan":{english_title:"Minnan",direction:"ltr",local_title:"Bân-lâm-gú"},"zh-yue":{english_title:"Cantonese",direction:"ltr",local_title:"粵語"},zu:{english_title:"Zulu",direction:"ltr",local_title:"isiZulu"}}},{}],8:[function(i,t,e){"use strict";var o={aawiki:"https://aa.wikipedia.org",aawiktionary:"https://aa.wiktionary.org",aawikibooks:"https://aa.wikibooks.org",abwiki:"https://ab.wikipedia.org",abwiktionary:"https://ab.wiktionary.org",acewiki:"https://ace.wikipedia.org",afwiki:"https://af.wikipedia.org",afwiktionary:"https://af.wiktionary.org",afwikibooks:"https://af.wikibooks.org",afwikiquote:"https://af.wikiquote.org",akwiki:"https://ak.wikipedia.org",akwiktionary:"https://ak.wiktionary.org",akwikibooks:"https://ak.wikibooks.org",alswiki:"https://als.wikipedia.org",alswiktionary:"https://als.wiktionary.org",alswikibooks:"https://als.wikibooks.org",alswikiquote:"https://als.wikiquote.org",amwiki:"https://am.wikipedia.org",amwiktionary:"https://am.wiktionary.org",amwikiquote:"https://am.wikiquote.org",anwiki:"https://an.wikipedia.org",anwiktionary:"https://an.wiktionary.org",angwiki:"https://ang.wikipedia.org",angwiktionary:"https://ang.wiktionary.org",angwikibooks:"https://ang.wikibooks.org",angwikiquote:"https://ang.wikiquote.org",angwikisource:"https://ang.wikisource.org", -arwiki:"https://ar.wikipedia.org",arwiktionary:"https://ar.wiktionary.org",arwikibooks:"https://ar.wikibooks.org",arwikinews:"https://ar.wikinews.org",arwikiquote:"https://ar.wikiquote.org",arwikisource:"https://ar.wikisource.org",arwikiversity:"https://ar.wikiversity.org",arcwiki:"https://arc.wikipedia.org",arzwiki:"https://arz.wikipedia.org",aswiki:"https://as.wikipedia.org",aswiktionary:"https://as.wiktionary.org",aswikibooks:"https://as.wikibooks.org",aswikisource:"https://as.wikisource.org",astwiki:"https://ast.wikipedia.org",astwiktionary:"https://ast.wiktionary.org",astwikibooks:"https://ast.wikibooks.org",astwikiquote:"https://ast.wikiquote.org",avwiki:"https://av.wikipedia.org",avwiktionary:"https://av.wiktionary.org",aywiki:"https://ay.wikipedia.org",aywiktionary:"https://ay.wiktionary.org",aywikibooks:"https://ay.wikibooks.org",azwiki:"https://az.wikipedia.org",azwiktionary:"https://az.wiktionary.org",azwikibooks:"https://az.wikibooks.org",azwikiquote:"https://az.wikiquote.org",azwikisource:"https://az.wikisource.org",bawiki:"https://ba.wikipedia.org",bawikibooks:"https://ba.wikibooks.org",barwiki:"https://bar.wikipedia.org",bat_smgwiki:"https://bat-smg.wikipedia.org",bclwiki:"https://bcl.wikipedia.org",bewiki:"https://be.wikipedia.org",bewiktionary:"https://be.wiktionary.org",bewikibooks:"https://be.wikibooks.org",bewikiquote:"https://be.wikiquote.org",bewikisource:"https://be.wikisource.org",be_x_oldwiki:"https://be-x-old.wikipedia.org",bgwiki:"https://bg.wikipedia.org",bgwiktionary:"https://bg.wiktionary.org",bgwikibooks:"https://bg.wikibooks.org",bgwikinews:"https://bg.wikinews.org",bgwikiquote:"https://bg.wikiquote.org",bgwikisource:"https://bg.wikisource.org",bhwiki:"https://bh.wikipedia.org",bhwiktionary:"https://bh.wiktionary.org",biwiki:"https://bi.wikipedia.org",biwiktionary:"https://bi.wiktionary.org",biwikibooks:"https://bi.wikibooks.org",bjnwiki:"https://bjn.wikipedia.org",bmwiki:"https://bm.wikipedia.org",bmwiktionary:"https://bm.wiktionary.org",bmwikibooks:"https://bm.wikibooks.org",bmwikiquote:"https://bm.wikiquote.org",bnwiki:"https://bn.wikipedia.org",bnwiktionary:"https://bn.wiktionary.org",bnwikibooks:"https://bn.wikibooks.org",bnwikisource:"https://bn.wikisource.org",bowiki:"https://bo.wikipedia.org",bowiktionary:"https://bo.wiktionary.org",bowikibooks:"https://bo.wikibooks.org",bpywiki:"https://bpy.wikipedia.org",brwiki:"https://br.wikipedia.org",brwiktionary:"https://br.wiktionary.org",brwikiquote:"https://br.wikiquote.org",brwikisource:"https://br.wikisource.org",bswiki:"https://bs.wikipedia.org",bswiktionary:"https://bs.wiktionary.org",bswikibooks:"https://bs.wikibooks.org",bswikinews:"https://bs.wikinews.org",bswikiquote:"https://bs.wikiquote.org",bswikisource:"https://bs.wikisource.org",bugwiki:"https://bug.wikipedia.org",bxrwiki:"https://bxr.wikipedia.org",cawiki:"https://ca.wikipedia.org",cawiktionary:"https://ca.wiktionary.org",cawikibooks:"https://ca.wikibooks.org",cawikinews:"https://ca.wikinews.org",cawikiquote:"https://ca.wikiquote.org",cawikisource:"https://ca.wikisource.org",cbk_zamwiki:"https://cbk-zam.wikipedia.org",cdowiki:"https://cdo.wikipedia.org",cewiki:"https://ce.wikipedia.org",cebwiki:"https://ceb.wikipedia.org",chwiki:"https://ch.wikipedia.org",chwiktionary:"https://ch.wiktionary.org",chwikibooks:"https://ch.wikibooks.org",chowiki:"https://cho.wikipedia.org",chrwiki:"https://chr.wikipedia.org",chrwiktionary:"https://chr.wiktionary.org",chywiki:"https://chy.wikipedia.org",ckbwiki:"https://ckb.wikipedia.org",cowiki:"https://co.wikipedia.org",cowiktionary:"https://co.wiktionary.org",cowikibooks:"https://co.wikibooks.org",cowikiquote:"https://co.wikiquote.org",crwiki:"https://cr.wikipedia.org",crwiktionary:"https://cr.wiktionary.org",crwikiquote:"https://cr.wikiquote.org",crhwiki:"https://crh.wikipedia.org",cswiki:"https://cs.wikipedia.org",cswiktionary:"https://cs.wiktionary.org",cswikibooks:"https://cs.wikibooks.org",cswikinews:"https://cs.wikinews.org",cswikiquote:"https://cs.wikiquote.org",cswikisource:"https://cs.wikisource.org",cswikiversity:"https://cs.wikiversity.org",csbwiki:"https://csb.wikipedia.org",csbwiktionary:"https://csb.wiktionary.org",cuwiki:"https://cu.wikipedia.org",cvwiki:"https://cv.wikipedia.org",cvwikibooks:"https://cv.wikibooks.org",cywiki:"https://cy.wikipedia.org",cywiktionary:"https://cy.wiktionary.org",cywikibooks:"https://cy.wikibooks.org",cywikiquote:"https://cy.wikiquote.org",cywikisource:"https://cy.wikisource.org",dawiki:"https://da.wikipedia.org",dawiktionary:"https://da.wiktionary.org",dawikibooks:"https://da.wikibooks.org",dawikiquote:"https://da.wikiquote.org",dawikisource:"https://da.wikisource.org",dewiki:"https://de.wikipedia.org",dewiktionary:"https://de.wiktionary.org",dewikibooks:"https://de.wikibooks.org",dewikinews:"https://de.wikinews.org",dewikiquote:"https://de.wikiquote.org",dewikisource:"https://de.wikisource.org",dewikiversity:"https://de.wikiversity.org",dewikivoyage:"https://de.wikivoyage.org",diqwiki:"https://diq.wikipedia.org",dsbwiki:"https://dsb.wikipedia.org",dvwiki:"https://dv.wikipedia.org",dvwiktionary:"https://dv.wiktionary.org",dzwiki:"https://dz.wikipedia.org",dzwiktionary:"https://dz.wiktionary.org",eewiki:"https://ee.wikipedia.org",elwiki:"https://el.wikipedia.org",elwiktionary:"https://el.wiktionary.org",elwikibooks:"https://el.wikibooks.org",elwikinews:"https://el.wikinews.org",elwikiquote:"https://el.wikiquote.org",elwikisource:"https://el.wikisource.org",elwikiversity:"https://el.wikiversity.org",elwikivoyage:"https://el.wikivoyage.org",emlwiki:"https://eml.wikipedia.org",enwiki:"https://en.wikipedia.org",enwiktionary:"https://en.wiktionary.org",enwikibooks:"https://en.wikibooks.org",enwikinews:"https://en.wikinews.org",enwikiquote:"https://en.wikiquote.org",enwikisource:"https://en.wikisource.org",enwikiversity:"https://en.wikiversity.org",enwikivoyage:"https://en.wikivoyage.org",eowiki:"https://eo.wikipedia.org",eowiktionary:"https://eo.wiktionary.org",eowikibooks:"https://eo.wikibooks.org",eowikinews:"https://eo.wikinews.org",eowikiquote:"https://eo.wikiquote.org",eowikisource:"https://eo.wikisource.org",eswiki:"https://es.wikipedia.org",eswiktionary:"https://es.wiktionary.org",eswikibooks:"https://es.wikibooks.org",eswikinews:"https://es.wikinews.org",eswikiquote:"https://es.wikiquote.org",eswikisource:"https://es.wikisource.org",eswikiversity:"https://es.wikiversity.org",eswikivoyage:"https://es.wikivoyage.org",etwiki:"https://et.wikipedia.org",etwiktionary:"https://et.wiktionary.org",etwikibooks:"https://et.wikibooks.org",etwikiquote:"https://et.wikiquote.org",etwikisource:"https://et.wikisource.org",euwiki:"https://eu.wikipedia.org",euwiktionary:"https://eu.wiktionary.org",euwikibooks:"https://eu.wikibooks.org",euwikiquote:"https://eu.wikiquote.org",extwiki:"https://ext.wikipedia.org",fawiki:"https://fa.wikipedia.org",fawiktionary:"https://fa.wiktionary.org",fawikibooks:"https://fa.wikibooks.org",fawikinews:"https://fa.wikinews.org",fawikiquote:"https://fa.wikiquote.org",fawikisource:"https://fa.wikisource.org",fawikivoyage:"https://fa.wikivoyage.org",ffwiki:"https://ff.wikipedia.org",fiwiki:"https://fi.wikipedia.org",fiwiktionary:"https://fi.wiktionary.org",fiwikibooks:"https://fi.wikibooks.org",fiwikinews:"https://fi.wikinews.org",fiwikiquote:"https://fi.wikiquote.org",fiwikisource:"https://fi.wikisource.org",fiwikiversity:"https://fi.wikiversity.org",fiu_vrowiki:"https://fiu-vro.wikipedia.org",fjwiki:"https://fj.wikipedia.org",fjwiktionary:"https://fj.wiktionary.org",fowiki:"https://fo.wikipedia.org",fowiktionary:"https://fo.wiktionary.org",fowikisource:"https://fo.wikisource.org",frwiki:"https://fr.wikipedia.org",frwiktionary:"https://fr.wiktionary.org",frwikibooks:"https://fr.wikibooks.org",frwikinews:"https://fr.wikinews.org",frwikiquote:"https://fr.wikiquote.org",frwikisource:"https://fr.wikisource.org",frwikiversity:"https://fr.wikiversity.org",frwikivoyage:"https://fr.wikivoyage.org",frpwiki:"https://frp.wikipedia.org",frrwiki:"https://frr.wikipedia.org",furwiki:"https://fur.wikipedia.org",fywiki:"https://fy.wikipedia.org",fywiktionary:"https://fy.wiktionary.org",fywikibooks:"https://fy.wikibooks.org",gawiki:"https://ga.wikipedia.org",gawiktionary:"https://ga.wiktionary.org",gawikibooks:"https://ga.wikibooks.org",gawikiquote:"https://ga.wikiquote.org",gagwiki:"https://gag.wikipedia.org",ganwiki:"https://gan.wikipedia.org",gdwiki:"https://gd.wikipedia.org",gdwiktionary:"https://gd.wiktionary.org",glwiki:"https://gl.wikipedia.org",glwiktionary:"https://gl.wiktionary.org",glwikibooks:"https://gl.wikibooks.org",glwikiquote:"https://gl.wikiquote.org",glwikisource:"https://gl.wikisource.org",glkwiki:"https://glk.wikipedia.org",gnwiki:"https://gn.wikipedia.org",gnwiktionary:"https://gn.wiktionary.org",gnwikibooks:"https://gn.wikibooks.org",gotwiki:"https://got.wikipedia.org",gotwikibooks:"https://got.wikibooks.org",guwiki:"https://gu.wikipedia.org",guwiktionary:"https://gu.wiktionary.org",guwikibooks:"https://gu.wikibooks.org",guwikiquote:"https://gu.wikiquote.org",guwikisource:"https://gu.wikisource.org",gvwiki:"https://gv.wikipedia.org",gvwiktionary:"https://gv.wiktionary.org",hawiki:"https://ha.wikipedia.org",hawiktionary:"https://ha.wiktionary.org",hakwiki:"https://hak.wikipedia.org",hawwiki:"https://haw.wikipedia.org",hewiki:"https://he.wikipedia.org",hewiktionary:"https://he.wiktionary.org",hewikibooks:"https://he.wikibooks.org",hewikinews:"https://he.wikinews.org",hewikiquote:"https://he.wikiquote.org",hewikisource:"https://he.wikisource.org",hewikivoyage:"https://he.wikivoyage.org",hiwiki:"https://hi.wikipedia.org",hiwiktionary:"https://hi.wiktionary.org",hiwikibooks:"https://hi.wikibooks.org",hiwikiquote:"https://hi.wikiquote.org",hifwiki:"https://hif.wikipedia.org",howiki:"https://ho.wikipedia.org",hrwiki:"https://hr.wikipedia.org",hrwiktionary:"https://hr.wiktionary.org",hrwikibooks:"https://hr.wikibooks.org",hrwikiquote:"https://hr.wikiquote.org",hrwikisource:"https://hr.wikisource.org",hsbwiki:"https://hsb.wikipedia.org",hsbwiktionary:"https://hsb.wiktionary.org",htwiki:"https://ht.wikipedia.org",htwikisource:"https://ht.wikisource.org",huwiki:"https://hu.wikipedia.org",huwiktionary:"https://hu.wiktionary.org",huwikibooks:"https://hu.wikibooks.org",huwikinews:"https://hu.wikinews.org",huwikiquote:"https://hu.wikiquote.org",huwikisource:"https://hu.wikisource.org",hywiki:"https://hy.wikipedia.org",hywiktionary:"https://hy.wiktionary.org",hywikibooks:"https://hy.wikibooks.org",hywikiquote:"https://hy.wikiquote.org",hywikisource:"https://hy.wikisource.org",hzwiki:"https://hz.wikipedia.org",iawiki:"https://ia.wikipedia.org",iawiktionary:"https://ia.wiktionary.org",iawikibooks:"https://ia.wikibooks.org",idwiki:"https://id.wikipedia.org",idwiktionary:"https://id.wiktionary.org",idwikibooks:"https://id.wikibooks.org",idwikiquote:"https://id.wikiquote.org",idwikisource:"https://id.wikisource.org",iewiki:"https://ie.wikipedia.org",iewiktionary:"https://ie.wiktionary.org",iewikibooks:"https://ie.wikibooks.org",igwiki:"https://ig.wikipedia.org",iiwiki:"https://ii.wikipedia.org",ikwiki:"https://ik.wikipedia.org",ikwiktionary:"https://ik.wiktionary.org",ilowiki:"https://ilo.wikipedia.org",iowiki:"https://io.wikipedia.org",iowiktionary:"https://io.wiktionary.org",iswiki:"https://is.wikipedia.org",iswiktionary:"https://is.wiktionary.org",iswikibooks:"https://is.wikibooks.org",iswikiquote:"https://is.wikiquote.org",iswikisource:"https://is.wikisource.org",itwiki:"https://it.wikipedia.org",itwiktionary:"https://it.wiktionary.org",itwikibooks:"https://it.wikibooks.org",itwikinews:"https://it.wikinews.org",itwikiquote:"https://it.wikiquote.org",itwikisource:"https://it.wikisource.org",itwikiversity:"https://it.wikiversity.org",itwikivoyage:"https://it.wikivoyage.org",iuwiki:"https://iu.wikipedia.org",iuwiktionary:"https://iu.wiktionary.org",jawiki:"https://ja.wikipedia.org",jawiktionary:"https://ja.wiktionary.org",jawikibooks:"https://ja.wikibooks.org",jawikinews:"https://ja.wikinews.org",jawikiquote:"https://ja.wikiquote.org",jawikisource:"https://ja.wikisource.org",jawikiversity:"https://ja.wikiversity.org",jbowiki:"https://jbo.wikipedia.org",jbowiktionary:"https://jbo.wiktionary.org",jvwiki:"https://jv.wikipedia.org",jvwiktionary:"https://jv.wiktionary.org",kawiki:"https://ka.wikipedia.org",kawiktionary:"https://ka.wiktionary.org",kawikibooks:"https://ka.wikibooks.org",kawikiquote:"https://ka.wikiquote.org",kaawiki:"https://kaa.wikipedia.org",kabwiki:"https://kab.wikipedia.org",kbdwiki:"https://kbd.wikipedia.org",kgwiki:"https://kg.wikipedia.org",kiwiki:"https://ki.wikipedia.org",kjwiki:"https://kj.wikipedia.org",kkwiki:"https://kk.wikipedia.org",kkwiktionary:"https://kk.wiktionary.org",kkwikibooks:"https://kk.wikibooks.org",kkwikiquote:"https://kk.wikiquote.org",klwiki:"https://kl.wikipedia.org",klwiktionary:"https://kl.wiktionary.org",kmwiki:"https://km.wikipedia.org",kmwiktionary:"https://km.wiktionary.org",kmwikibooks:"https://km.wikibooks.org",knwiki:"https://kn.wikipedia.org",knwiktionary:"https://kn.wiktionary.org",knwikibooks:"https://kn.wikibooks.org",knwikiquote:"https://kn.wikiquote.org",knwikisource:"https://kn.wikisource.org",kowiki:"https://ko.wikipedia.org",kowiktionary:"https://ko.wiktionary.org",kowikibooks:"https://ko.wikibooks.org",kowikinews:"https://ko.wikinews.org",kowikiquote:"https://ko.wikiquote.org",kowikisource:"https://ko.wikisource.org",kowikiversity:"https://ko.wikiversity.org",koiwiki:"https://koi.wikipedia.org",krwiki:"https://kr.wikipedia.org",krwikiquote:"https://kr.wikiquote.org",krcwiki:"https://krc.wikipedia.org",kswiki:"https://ks.wikipedia.org",kswiktionary:"https://ks.wiktionary.org",kswikibooks:"https://ks.wikibooks.org",kswikiquote:"https://ks.wikiquote.org",kshwiki:"https://ksh.wikipedia.org",kuwiki:"https://ku.wikipedia.org",kuwiktionary:"https://ku.wiktionary.org",kuwikibooks:"https://ku.wikibooks.org",kuwikiquote:"https://ku.wikiquote.org",kvwiki:"https://kv.wikipedia.org",kwwiki:"https://kw.wikipedia.org",kwwiktionary:"https://kw.wiktionary.org",kwwikiquote:"https://kw.wikiquote.org",kywiki:"https://ky.wikipedia.org",kywiktionary:"https://ky.wiktionary.org",kywikibooks:"https://ky.wikibooks.org",kywikiquote:"https://ky.wikiquote.org",lawiki:"https://la.wikipedia.org",lawiktionary:"https://la.wiktionary.org",lawikibooks:"https://la.wikibooks.org",lawikiquote:"https://la.wikiquote.org",lawikisource:"https://la.wikisource.org",ladwiki:"https://lad.wikipedia.org",lbwiki:"https://lb.wikipedia.org",lbwiktionary:"https://lb.wiktionary.org",lbwikibooks:"https://lb.wikibooks.org",lbwikiquote:"https://lb.wikiquote.org",lbewiki:"https://lbe.wikipedia.org",lezwiki:"https://lez.wikipedia.org",lgwiki:"https://lg.wikipedia.org",liwiki:"https://li.wikipedia.org",liwiktionary:"https://li.wiktionary.org",liwikibooks:"https://li.wikibooks.org",liwikiquote:"https://li.wikiquote.org",liwikisource:"https://li.wikisource.org",lijwiki:"https://lij.wikipedia.org",lmowiki:"https://lmo.wikipedia.org",lnwiki:"https://ln.wikipedia.org",lnwiktionary:"https://ln.wiktionary.org",lnwikibooks:"https://ln.wikibooks.org",lowiki:"https://lo.wikipedia.org",lowiktionary:"https://lo.wiktionary.org",ltwiki:"https://lt.wikipedia.org",ltwiktionary:"https://lt.wiktionary.org",ltwikibooks:"https://lt.wikibooks.org",ltwikiquote:"https://lt.wikiquote.org",ltwikisource:"https://lt.wikisource.org",ltgwiki:"https://ltg.wikipedia.org",lvwiki:"https://lv.wikipedia.org",lvwiktionary:"https://lv.wiktionary.org",lvwikibooks:"https://lv.wikibooks.org",maiwiki:"https://mai.wikipedia.org",map_bmswiki:"https://map-bms.wikipedia.org",mdfwiki:"https://mdf.wikipedia.org",mgwiki:"https://mg.wikipedia.org",mgwiktionary:"https://mg.wiktionary.org",mgwikibooks:"https://mg.wikibooks.org",mhwiki:"https://mh.wikipedia.org",mhwiktionary:"https://mh.wiktionary.org",mhrwiki:"https://mhr.wikipedia.org",miwiki:"https://mi.wikipedia.org",miwiktionary:"https://mi.wiktionary.org",miwikibooks:"https://mi.wikibooks.org",minwiki:"https://min.wikipedia.org",mkwiki:"https://mk.wikipedia.org",mkwiktionary:"https://mk.wiktionary.org",mkwikibooks:"https://mk.wikibooks.org",mkwikisource:"https://mk.wikisource.org",mlwiki:"https://ml.wikipedia.org",mlwiktionary:"https://ml.wiktionary.org",mlwikibooks:"https://ml.wikibooks.org",mlwikiquote:"https://ml.wikiquote.org",mlwikisource:"https://ml.wikisource.org",mnwiki:"https://mn.wikipedia.org",mnwiktionary:"https://mn.wiktionary.org",mnwikibooks:"https://mn.wikibooks.org",mowiki:"https://mo.wikipedia.org",mowiktionary:"https://mo.wiktionary.org",mrwiki:"https://mr.wikipedia.org",mrwiktionary:"https://mr.wiktionary.org",mrwikibooks:"https://mr.wikibooks.org",mrwikiquote:"https://mr.wikiquote.org",mrwikisource:"https://mr.wikisource.org",mrjwiki:"https://mrj.wikipedia.org",mswiki:"https://ms.wikipedia.org",mswiktionary:"https://ms.wiktionary.org",mswikibooks:"https://ms.wikibooks.org",mtwiki:"https://mt.wikipedia.org",mtwiktionary:"https://mt.wiktionary.org",muswiki:"https://mus.wikipedia.org",mwlwiki:"https://mwl.wikipedia.org",mywiki:"https://my.wikipedia.org",mywiktionary:"https://my.wiktionary.org",mywikibooks:"https://my.wikibooks.org",myvwiki:"https://myv.wikipedia.org",mznwiki:"https://mzn.wikipedia.org",nawiki:"https://na.wikipedia.org",nawiktionary:"https://na.wiktionary.org",nawikibooks:"https://na.wikibooks.org",nawikiquote:"https://na.wikiquote.org",nahwiki:"https://nah.wikipedia.org",nahwiktionary:"https://nah.wiktionary.org",nahwikibooks:"https://nah.wikibooks.org",napwiki:"https://nap.wikipedia.org",ndswiki:"https://nds.wikipedia.org",ndswiktionary:"https://nds.wiktionary.org",ndswikibooks:"https://nds.wikibooks.org",ndswikiquote:"https://nds.wikiquote.org",nds_nlwiki:"https://nds-nl.wikipedia.org",newiki:"https://ne.wikipedia.org",newiktionary:"https://ne.wiktionary.org",newikibooks:"https://ne.wikibooks.org",newwiki:"https://new.wikipedia.org",ngwiki:"https://ng.wikipedia.org",nlwiki:"https://nl.wikipedia.org",nlwiktionary:"https://nl.wiktionary.org",nlwikibooks:"https://nl.wikibooks.org",nlwikinews:"https://nl.wikinews.org",nlwikiquote:"https://nl.wikiquote.org",nlwikisource:"https://nl.wikisource.org",nlwikivoyage:"https://nl.wikivoyage.org",nnwiki:"https://nn.wikipedia.org",nnwiktionary:"https://nn.wiktionary.org",nnwikiquote:"https://nn.wikiquote.org",nowiki:"https://no.wikipedia.org",nowiktionary:"https://no.wiktionary.org",nowikibooks:"https://no.wikibooks.org",nowikinews:"https://no.wikinews.org",nowikiquote:"https://no.wikiquote.org",nowikisource:"https://no.wikisource.org",novwiki:"https://nov.wikipedia.org",nrmwiki:"https://nrm.wikipedia.org",nsowiki:"https://nso.wikipedia.org",nvwiki:"https://nv.wikipedia.org",nywiki:"https://ny.wikipedia.org",ocwiki:"https://oc.wikipedia.org",ocwiktionary:"https://oc.wiktionary.org",ocwikibooks:"https://oc.wikibooks.org",omwiki:"https://om.wikipedia.org",omwiktionary:"https://om.wiktionary.org",orwiki:"https://or.wikipedia.org",orwiktionary:"https://or.wiktionary.org",orwikisource:"https://or.wikisource.org",oswiki:"https://os.wikipedia.org",pawiki:"https://pa.wikipedia.org",pawiktionary:"https://pa.wiktionary.org",pawikibooks:"https://pa.wikibooks.org",pagwiki:"https://pag.wikipedia.org",pamwiki:"https://pam.wikipedia.org",papwiki:"https://pap.wikipedia.org",pcdwiki:"https://pcd.wikipedia.org",pdcwiki:"https://pdc.wikipedia.org",pflwiki:"https://pfl.wikipedia.org",piwiki:"https://pi.wikipedia.org",piwiktionary:"https://pi.wiktionary.org",pihwiki:"https://pih.wikipedia.org",plwiki:"https://pl.wikipedia.org",plwiktionary:"https://pl.wiktionary.org",plwikibooks:"https://pl.wikibooks.org",plwikinews:"https://pl.wikinews.org",plwikiquote:"https://pl.wikiquote.org",plwikisource:"https://pl.wikisource.org",plwikivoyage:"https://pl.wikivoyage.org",pmswiki:"https://pms.wikipedia.org",pnbwiki:"https://pnb.wikipedia.org",pnbwiktionary:"https://pnb.wiktionary.org",pntwiki:"https://pnt.wikipedia.org",pswiki:"https://ps.wikipedia.org",pswiktionary:"https://ps.wiktionary.org",pswikibooks:"https://ps.wikibooks.org",ptwiki:"https://pt.wikipedia.org",ptwiktionary:"https://pt.wiktionary.org",ptwikibooks:"https://pt.wikibooks.org",ptwikinews:"https://pt.wikinews.org",ptwikiquote:"https://pt.wikiquote.org",ptwikisource:"https://pt.wikisource.org",ptwikiversity:"https://pt.wikiversity.org",ptwikivoyage:"https://pt.wikivoyage.org",quwiki:"https://qu.wikipedia.org",quwiktionary:"https://qu.wiktionary.org",quwikibooks:"https://qu.wikibooks.org",quwikiquote:"https://qu.wikiquote.org",rmwiki:"https://rm.wikipedia.org",rmwiktionary:"https://rm.wiktionary.org",rmwikibooks:"https://rm.wikibooks.org",rmywiki:"https://rmy.wikipedia.org",rnwiki:"https://rn.wikipedia.org",rnwiktionary:"https://rn.wiktionary.org",rowiki:"https://ro.wikipedia.org",rowiktionary:"https://ro.wiktionary.org",rowikibooks:"https://ro.wikibooks.org",rowikinews:"https://ro.wikinews.org",rowikiquote:"https://ro.wikiquote.org",rowikisource:"https://ro.wikisource.org",rowikivoyage:"https://ro.wikivoyage.org",roa_rupwiki:"https://roa-rup.wikipedia.org",roa_rupwiktionary:"https://roa-rup.wiktionary.org",roa_tarawiki:"https://roa-tara.wikipedia.org",ruwiki:"https://ru.wikipedia.org",ruwiktionary:"https://ru.wiktionary.org",ruwikibooks:"https://ru.wikibooks.org",ruwikinews:"https://ru.wikinews.org",ruwikiquote:"https://ru.wikiquote.org",ruwikisource:"https://ru.wikisource.org",ruwikiversity:"https://ru.wikiversity.org",ruwikivoyage:"https://ru.wikivoyage.org",ruewiki:"https://rue.wikipedia.org",rwwiki:"https://rw.wikipedia.org",rwwiktionary:"https://rw.wiktionary.org",sawiki:"https://sa.wikipedia.org",sawiktionary:"https://sa.wiktionary.org",sawikibooks:"https://sa.wikibooks.org",sawikiquote:"https://sa.wikiquote.org",sawikisource:"https://sa.wikisource.org",sahwiki:"https://sah.wikipedia.org",sahwikisource:"https://sah.wikisource.org",scwiki:"https://sc.wikipedia.org",scwiktionary:"https://sc.wiktionary.org",scnwiki:"https://scn.wikipedia.org",scnwiktionary:"https://scn.wiktionary.org",scowiki:"https://sco.wikipedia.org",sdwiki:"https://sd.wikipedia.org",sdwiktionary:"https://sd.wiktionary.org",sdwikinews:"https://sd.wikinews.org",sewiki:"https://se.wikipedia.org",sewikibooks:"https://se.wikibooks.org",sgwiki:"https://sg.wikipedia.org",sgwiktionary:"https://sg.wiktionary.org",shwiki:"https://sh.wikipedia.org",shwiktionary:"https://sh.wiktionary.org",siwiki:"https://si.wikipedia.org",siwiktionary:"https://si.wiktionary.org",siwikibooks:"https://si.wikibooks.org",simplewiki:"https://simple.wikipedia.org",simplewiktionary:"https://simple.wiktionary.org",simplewikibooks:"https://simple.wikibooks.org",simplewikiquote:"https://simple.wikiquote.org",skwiki:"https://sk.wikipedia.org",skwiktionary:"https://sk.wiktionary.org",skwikibooks:"https://sk.wikibooks.org",skwikiquote:"https://sk.wikiquote.org",skwikisource:"https://sk.wikisource.org",slwiki:"https://sl.wikipedia.org",slwiktionary:"https://sl.wiktionary.org",slwikibooks:"https://sl.wikibooks.org",slwikiquote:"https://sl.wikiquote.org",slwikisource:"https://sl.wikisource.org",slwikiversity:"https://sl.wikiversity.org",smwiki:"https://sm.wikipedia.org",smwiktionary:"https://sm.wiktionary.org",snwiki:"https://sn.wikipedia.org",snwiktionary:"https://sn.wiktionary.org",sowiki:"https://so.wikipedia.org",sowiktionary:"https://so.wiktionary.org",sqwiki:"https://sq.wikipedia.org",sqwiktionary:"https://sq.wiktionary.org",sqwikibooks:"https://sq.wikibooks.org",sqwikinews:"https://sq.wikinews.org",sqwikiquote:"https://sq.wikiquote.org",srwiki:"https://sr.wikipedia.org",srwiktionary:"https://sr.wiktionary.org",srwikibooks:"https://sr.wikibooks.org",srwikinews:"https://sr.wikinews.org",srwikiquote:"https://sr.wikiquote.org",srwikisource:"https://sr.wikisource.org",srnwiki:"https://srn.wikipedia.org",sswiki:"https://ss.wikipedia.org",sswiktionary:"https://ss.wiktionary.org",stwiki:"https://st.wikipedia.org",stwiktionary:"https://st.wiktionary.org",stqwiki:"https://stq.wikipedia.org",suwiki:"https://su.wikipedia.org",suwiktionary:"https://su.wiktionary.org",suwikibooks:"https://su.wikibooks.org",suwikiquote:"https://su.wikiquote.org",svwiki:"https://sv.wikipedia.org",svwiktionary:"https://sv.wiktionary.org",svwikibooks:"https://sv.wikibooks.org",svwikinews:"https://sv.wikinews.org",svwikiquote:"https://sv.wikiquote.org",svwikisource:"https://sv.wikisource.org",svwikiversity:"https://sv.wikiversity.org",svwikivoyage:"https://sv.wikivoyage.org",swwiki:"https://sw.wikipedia.org",swwiktionary:"https://sw.wiktionary.org",swwikibooks:"https://sw.wikibooks.org",szlwiki:"https://szl.wikipedia.org",tawiki:"https://ta.wikipedia.org",tawiktionary:"https://ta.wiktionary.org",tawikibooks:"https://ta.wikibooks.org",tawikinews:"https://ta.wikinews.org",tawikiquote:"https://ta.wikiquote.org",tawikisource:"https://ta.wikisource.org",tewiki:"https://te.wikipedia.org",tewiktionary:"https://te.wiktionary.org",tewikibooks:"https://te.wikibooks.org",tewikiquote:"https://te.wikiquote.org",tewikisource:"https://te.wikisource.org",tetwiki:"https://tet.wikipedia.org",tgwiki:"https://tg.wikipedia.org",tgwiktionary:"https://tg.wiktionary.org",tgwikibooks:"https://tg.wikibooks.org",thwiki:"https://th.wikipedia.org",thwiktionary:"https://th.wiktionary.org",thwikibooks:"https://th.wikibooks.org",thwikinews:"https://th.wikinews.org",thwikiquote:"https://th.wikiquote.org",thwikisource:"https://th.wikisource.org",tiwiki:"https://ti.wikipedia.org",tiwiktionary:"https://ti.wiktionary.org",tkwiki:"https://tk.wikipedia.org",tkwiktionary:"https://tk.wiktionary.org",tkwikibooks:"https://tk.wikibooks.org",tkwikiquote:"https://tk.wikiquote.org",tlwiki:"https://tl.wikipedia.org",tlwiktionary:"https://tl.wiktionary.org",tlwikibooks:"https://tl.wikibooks.org",tnwiki:"https://tn.wikipedia.org",tnwiktionary:"https://tn.wiktionary.org",towiki:"https://to.wikipedia.org",towiktionary:"https://to.wiktionary.org",tpiwiki:"https://tpi.wikipedia.org",tpiwiktionary:"https://tpi.wiktionary.org",trwiki:"https://tr.wikipedia.org",trwiktionary:"https://tr.wiktionary.org",trwikibooks:"https://tr.wikibooks.org",trwikinews:"https://tr.wikinews.org",trwikiquote:"https://tr.wikiquote.org",trwikisource:"https://tr.wikisource.org",tswiki:"https://ts.wikipedia.org",tswiktionary:"https://ts.wiktionary.org",ttwiki:"https://tt.wikipedia.org",ttwiktionary:"https://tt.wiktionary.org",ttwikibooks:"https://tt.wikibooks.org",ttwikiquote:"https://tt.wikiquote.org",tumwiki:"https://tum.wikipedia.org",twwiki:"https://tw.wikipedia.org",twwiktionary:"https://tw.wiktionary.org",tywiki:"https://ty.wikipedia.org",tyvwiki:"https://tyv.wikipedia.org",udmwiki:"https://udm.wikipedia.org",ugwiki:"https://ug.wikipedia.org",ugwiktionary:"https://ug.wiktionary.org",ugwikibooks:"https://ug.wikibooks.org",ugwikiquote:"https://ug.wikiquote.org",ukwiki:"https://uk.wikipedia.org",ukwiktionary:"https://uk.wiktionary.org",ukwikibooks:"https://uk.wikibooks.org",ukwikinews:"https://uk.wikinews.org",ukwikiquote:"https://uk.wikiquote.org",ukwikisource:"https://uk.wikisource.org",ukwikivoyage:"https://uk.wikivoyage.org",urwiki:"https://ur.wikipedia.org",urwiktionary:"https://ur.wiktionary.org",urwikibooks:"https://ur.wikibooks.org",urwikiquote:"https://ur.wikiquote.org",uzwiki:"https://uz.wikipedia.org",uzwiktionary:"https://uz.wiktionary.org",uzwikibooks:"https://uz.wikibooks.org",uzwikiquote:"https://uz.wikiquote.org",vewiki:"https://ve.wikipedia.org",vecwiki:"https://vec.wikipedia.org",vecwiktionary:"https://vec.wiktionary.org",vecwikisource:"https://vec.wikisource.org",vepwiki:"https://vep.wikipedia.org",viwiki:"https://vi.wikipedia.org",viwiktionary:"https://vi.wiktionary.org",viwikibooks:"https://vi.wikibooks.org",viwikiquote:"https://vi.wikiquote.org",viwikisource:"https://vi.wikisource.org",viwikivoyage:"https://vi.wikivoyage.org",vlswiki:"https://vls.wikipedia.org",vowiki:"https://vo.wikipedia.org",vowiktionary:"https://vo.wiktionary.org",vowikibooks:"https://vo.wikibooks.org",vowikiquote:"https://vo.wikiquote.org",wawiki:"https://wa.wikipedia.org",wawiktionary:"https://wa.wiktionary.org",wawikibooks:"https://wa.wikibooks.org",warwiki:"https://war.wikipedia.org",wowiki:"https://wo.wikipedia.org",wowiktionary:"https://wo.wiktionary.org",wowikiquote:"https://wo.wikiquote.org",wuuwiki:"https://wuu.wikipedia.org",xalwiki:"https://xal.wikipedia.org",xhwiki:"https://xh.wikipedia.org",xhwiktionary:"https://xh.wiktionary.org",xhwikibooks:"https://xh.wikibooks.org",xmfwiki:"https://xmf.wikipedia.org",yiwiki:"https://yi.wikipedia.org",yiwiktionary:"https://yi.wiktionary.org",yiwikisource:"https://yi.wikisource.org",yowiki:"https://yo.wikipedia.org",yowiktionary:"https://yo.wiktionary.org",yowikibooks:"https://yo.wikibooks.org",zawiki:"https://za.wikipedia.org",zawiktionary:"https://za.wiktionary.org",zawikibooks:"https://za.wikibooks.org",zawikiquote:"https://za.wikiquote.org",zeawiki:"https://zea.wikipedia.org",zhwiki:"https://zh.wikipedia.org",zhwiktionary:"https://zh.wiktionary.org",zhwikibooks:"https://zh.wikibooks.org",zhwikinews:"https://zh.wikinews.org",zhwikiquote:"https://zh.wikiquote.org",zhwikisource:"https://zh.wikisource.org",zhwikivoyage:"https://zh.wikivoyage.org",zh_classicalwiki:"https://zh-classical.wikipedia.org",zh_min_nanwiki:"https://zh-min-nan.wikipedia.org",zh_min_nanwiktionary:"https://zh-min-nan.wiktionary.org",zh_min_nanwikibooks:"https://zh-min-nan.wikibooks.org",zh_min_nanwikiquote:"https://zh-min-nan.wikiquote.org",zh_min_nanwikisource:"https://zh-min-nan.wikisource.org",zh_yuewiki:"https://zh-yue.wikipedia.org",zuwiki:"https://zu.wikipedia.org",zuwiktionary:"https://zu.wiktionary.org",zuwikibooks:"https://zu.wikibooks.org"};"undefined"!=typeof t&&t.exports&&(t.exports=o)},{}],9:[function(i,t,e){"use strict";var o=function(){var e=i("./lib/sentence_parser"),o=i("./lib/fetch_text"),r=i("./lib/make_image"),s=i("./data/i18n"),n=i("./lib/helpers"),a=i("./data/languages"),l=i("./parse/parse_redirects"),k=i("./parse/parse_table"),h=i("./parse/parse_line"),w=i("./parse/parse_categories"),p=i("./parse/parse_disambig"),c=i("./parse/parse_infobox"),g=i("./parse/parse_infobox_template"),u=i("./parse/parse_image"),d=i("./recursive_matches"),f=i("./parse/cleanup_misc"),y=i("./word_templates"),_={ignoreLists:!0},b=function(i,t){t=Object.assign({},_,t);var o,b={},m="",v=[],C={};if(i=i||"",l.is_redirect(i))return l.parse_redirect(i);var q=new RegExp("\\{\\{ ?("+s.disambigs.join("|")+")(\\|[a-z =]*?)? ?\\}\\}","i");if(i.match(q))return p(i);i=y(i),i=f(i),o=i.match(/\{\|[\s\S]{1,8000}?\|\}/g,"")||[],o=o.map(function(i){return k(i)}),i=i.replace(/\{\|[\s\S]{1,8000}?\|\}/g,"");var A=d("{","}",i),D=new RegExp("{{("+s.infoboxes.join("|")+")[: \n]","ig");A.forEach(function(t){if(t.match(D,"ig")&&0===Object.keys(b).length&&(b=c(t),m=g(t)),t.match(D)&&(i=i.replace(t,"")),t.match(/^\{\{/)){var e=t.match(/^\{\{nowrap\|(.*?)\}\}$/);if(e)return void(i=i.replace(t,e[1]));i=i.replace(t,"")}}),A=d("[","]",i),A.forEach(function(t){t.match(new RegExp("\\[\\[("+s.images.concat(s.files).join("|")+")","i"))&&(v.push(u(t)),i=i.replace(t,""))}),A.forEach(function(t){if(null!==t.match(/\[\[([a-z][a-z]):(.*?)\]\]/i)){var e=t.match(/\[\[([a-z][a-z]):/i)[1];e&&a[e]&&(C[e]=t.match(/\[\[([a-z][a-z]):(.*?)\]\]/i)[2]),i=i.replace(t,"")}}),i=i.replace(/\{\{.*?\}\}/g,"");var B=w(i),E=new Map,x=i.replace(/\r/g,"").split(/\n/),F="Intro",z=1;if(x.forEach(function(i){if(F&&(i.match(/^ ?\#[^:,\|]{4}/i)?(i=i.replace(/^ ?#*/,z+") "),i+="\n",z+=1):z=1,i.match(/^\*+[^:,\|]{4}/)&&(i+="\n"),(!t.ignoreLists||!i.match(/^[#\*:;\|]/))&&i.match(/[a-z0-9]/i))){var o=new RegExp("^ ?("+s.sources.join("|")+") ?$","i");return i.match(/^={1,5}[^=]{1,200}={1,5}$/)?(F=i.match(/^={1,5}([^=]{1,200}?)={1,5}$/)||[],F=F[1]||"",F=F.replace(/\./g," "),F=n.trim_whitespace(F),void(F&&F.match(o)&&(F=void 0))):void e(i).forEach(function(i){i=h(i),i&&i.text&&(E.get(F)||E.set(F,[]),E.get(F).push(i))})}}),b.image&&b.image.text){var j=b.image.text||"";"string"!=typeof j||j.match(new RegExp("^("+s.images.concat(s.files).join("|")+")","i"))||(j="File:"+j), -v.push(j)}return v=v.map(r),{type:"page",text:E,categories:B,images:v,infobox:b,infobox_template:m,tables:o,translations:C}},m=function(i,t,e){return"function"==typeof t&&(e=t,t="en"),e=e||function(){},t=t||"en",o?o(i,t,e):e(null)},v=function(i){var t=b(i)||{};t.text=t.text||[];var e="";return t.text.forEach(function(i){e+=i.map(function(i){return i.text}).join(" ")+"\n"}),e},C={from_api:m,parse:b,plaintext:v};return"undefined"!=typeof t&&t.exports&&(t.exports=C),C}();t.exports=o},{"./data/i18n":6,"./data/languages":7,"./lib/fetch_text":10,"./lib/helpers":12,"./lib/make_image":13,"./lib/sentence_parser":14,"./parse/cleanup_misc":15,"./parse/parse_categories":17,"./parse/parse_disambig":18,"./parse/parse_image":19,"./parse/parse_infobox":20,"./parse/parse_infobox_template":21,"./parse/parse_line":22,"./parse/parse_redirects":24,"./parse/parse_table":25,"./recursive_matches":26,"./word_templates":27}],10:[function(i,t,e){"use strict";var o=i("superagent"),r=i("../data/site_map"),s=i("../parse/parse_redirects"),n=function i(t,e,n){e=e||"en";var a="titles";t.match(/^[0-9]*$/)&&t.length>3&&(a="curid");var l;l=r[e]?r[e]+"/w/api.php":"https://"+e+".wikipedia.org/w/api.php",l+="?action=query&prop=revisions&rvlimit=1&rvprop=content&format=json&origin=*",l+="&"+a+"="+t,o.get(l).end(function(t,o){if(t)return console.warn(t),void n(null);var r=o.body.query.pages||{},a=Object.keys(r)[0];if(a){var l=r[a];if(l&&l.revisions&&l.revisions[0]){var k=l.revisions[0]["*"];if(s.is_redirect(k)){var h=s.parse_redirect(k);return void i(h.redirect,e,n)}n(k)}}})};t.exports=n},{"../data/site_map":8,"../parse/parse_redirects":24,superagent:2}],11:[function(t,e,o){(function(t){"use strict";var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(i){return typeof i}:function(i){return i&&"function"==typeof Symbol&&i.constructor===Symbol&&i!==Symbol.prototype?"symbol":typeof i};!function(){function s(i){var t,e,o,r="",s=-1;if(i&&i.length)for(o=i.length;(s+=1)>>6&31,128|63&t):t<=65535?r+=String.fromCharCode(224|t>>>12&15,128|t>>>6&63,128|63&t):t<=2097151&&(r+=String.fromCharCode(240|t>>>18&7,128|t>>>12&63,128|t>>>6&63,128|63&t));return r}function n(i){var t,e,o,r,s,n,a=[];if(t=e=o=r=s=0,i&&i.length)for(n=i.length,i+="";t191&&o<224?(r=i.charCodeAt(t+1),a[e]=String.fromCharCode((31&o)<<6|63&r),t+=2):(r=i.charCodeAt(t+1),s=i.charCodeAt(t+2),a[e]=String.fromCharCode((15&o)<<12|(63&r)<<6|63&s),t+=3);return a.join("")}function a(i,t){var e=(65535&i)+(65535&t),o=(i>>16)+(t>>16)+(e>>16);return o<<16|65535&e}function l(i,t){return i<>>32-t}function k(i,t){for(var e,o=t?"0123456789ABCDEF":"0123456789abcdef",r="",s=0,n=i.length;s>>4&15)+o.charAt(15&e);return r}function h(i){var t,e=32*i.length,o="";for(t=0;t>5]>>>24-t%32&255);return o}function w(i){var t,e=32*i.length,o="";for(t=0;t>5]>>>t%32&255);return o}function p(i){var t,e=8*i.length,o=Array(i.length>>2),r=o.length;for(t=0;t>5]|=(255&i.charCodeAt(t/8))<>2),r=o.length;for(t=0;t>5]|=(255&i.charCodeAt(t/8))<<24-t%32;return o}function g(i,t){var e,o,r,s,n,a,l,k,h=t.length,w=Array();for(a=Array(Math.ceil(i.length/2)),s=a.length,e=0;e0;){for(n=Array(),r=0,e=0;e0||o>0)&&(n[n.length]=o);w[w.length]=r,a=n}for(l="",e=w.length-1;e>=0;e--)l+=t.charAt(w[e]);for(k=Math.ceil(8*i.length/(Math.log(t.length)/Math.log(2))),e=l.length;e8*i.length?t:s.charAt(r>>>6*(3-o)&63);return n}var d;d={VERSION:"1.0.5",Base64:function(){var i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",t="=",e=!0;this.encode=function(o){var r,n,a,l="",k=o.length;for(t=t||"=",o=e?s(o):o,r=0;r8*k?t:i.charAt(a>>>6*(3-n)&63);return l},this.decode=function(o){var r,s,a,l,k,h,w,p,c,g,u="",d=[];if(!o)return o;r=g=0,o=o.replace(new RegExp("\\"+t,"gi"),"");do k=i.indexOf(o.charAt(r+=1)),h=i.indexOf(o.charAt(r+=1)),w=i.indexOf(o.charAt(r+=1)),p=i.indexOf(o.charAt(r+=1)),c=k<<18|h<<12|w<<6|p,s=c>>16&255,a=c>>8&255,l=255&c,g+=1,64===w?d[g]=String.fromCharCode(s):64===p?d[g]=String.fromCharCode(s,a):d[g]=String.fromCharCode(s,a,l);while(r>>8^n;return(r^-1)>>>0},MD5:function(i){function t(i){return i=_?s(i):i,w(o(p(i),8*i.length))}function e(i,t){var e,r,n,a,l;for(i=_?s(i):i,t=_?s(t):t,e=p(i),e.length>16&&(e=o(e,8*i.length)),r=Array(16),n=Array(16),l=0;l<16;l+=1)r[l]=909522486^e[l],n[l]=1549556828^e[l];return a=o(r.concat(p(t)),512+8*t.length),w(o(n.concat(a),640))}function o(i,t){var e,o,r,s,l,k=1732584193,w=-271733879,p=-1732584194,g=271733878;for(i[t>>5]|=128<>>9<<4)+14]=t,e=0;e16&&(e=o(e,8*i.length)),r=Array(16),n=Array(16),a=0;a<16;a+=1)r[a]=909522486^e[a],n[a]=1549556828^e[a];return l=o(r.concat(c(t)),512+8*t.length),h(o(n.concat(l),672))}function o(i,t){var e,o,s,k,h,w,p,c,g=Array(80),u=1732584193,d=-271733879,f=-1732584194,y=271733878,_=-1009589776;for(i[t>>5]|=128<<24-t%32,i[(t+64>>9<<4)+15]=t,e=0;e16&&(r=y(r,8*i.length));o<16;o+=1)n[o]=909522486^r[o],a[o]=1549556828^r[o];return e=y(n.concat(c(t)),512+8*t.length),h(y(a.concat(e),768))}function o(i,t){return i>>>t|i<<32-t}function r(i,t){return i>>>t}function n(i,t,e){return i&t^~i&e}function l(i,t,e){return i&t^i&e^t&e}function w(i){return o(i,2)^o(i,13)^o(i,22)}function p(i){return o(i,6)^o(i,11)^o(i,25)}function d(i){return o(i,7)^o(i,18)^r(i,3)}function f(i){return o(i,17)^o(i,19)^r(i,10)}function y(i,t){var e,o,r,s,k,h,c,g,u,y,b,m,v=[1779033703,-1150833019,1013904242,-1521486534,1359893119,-1694144372,528734635,1541459225],C=new Array(64);for(i[t>>5]|=128<<24-t%32,i[(t+64>>9<<4)+15]=t,u=0;u32&&(n=o(n,8*i.length));r<32;r+=1)a[r]=909522486^n[r],l[r]=1549556828^n[r];return e=o(a.concat(c(t)),1024+8*t.length),h(o(l.concat(e),1536))}function o(i,t){var e,o,s,k=new Array(80),h=new Array(16),c=[new r(1779033703,(-205731576)),new r((-1150833019),(-2067093701)),new r(1013904242,(-23791573)),new r((-1521486534),1595750129),new r(1359893119,(-1377402159)),new r((-1694144372),725511199),new r(528734635,(-79577749)),new r(1541459225,327033209)],g=new r(0,0),u=new r(0,0),_=new r(0,0),b=new r(0,0),m=new r(0,0),v=new r(0,0),C=new r(0,0),q=new r(0,0),A=new r(0,0),D=new r(0,0),B=new r(0,0),E=new r(0,0),x=new r(0,0),F=new r(0,0),z=new r(0,0),j=new r(0,0),S=new r(0,0);for(void 0===y&&(y=[new r(1116352408,(-685199838)),new r(1899447441,602891725),new r((-1245643825),(-330482897)),new r((-373957723),(-2121671748)),new r(961987163,(-213338824)),new r(1508970993,(-1241133031)),new r((-1841331548),(-1357295717)),new r((-1424204075),(-630357736)),new r((-670586216),(-1560083902)),new r(310598401,1164996542),new r(607225278,1323610764),new r(1426881987,(-704662302)),new r(1925078388,(-226784913)),new r((-2132889090),991336113),new r((-1680079193),633803317),new r((-1046744716),(-815192428)),new r((-459576895),(-1628353838)),new r((-272742522),944711139),new r(264347078,(-1953704523)),new r(604807628,2007800933),new r(770255983,1495990901),new r(1249150122,1856431235),new r(1555081692,(-1119749164)),new r(1996064986,(-2096016459)),new r((-1740746414),(-295247957)),new r((-1473132947),766784016),new r((-1341970488),(-1728372417)),new r((-1084653625),(-1091629340)),new r((-958395405),1034457026),new r((-710438585),(-1828018395)),new r(113926993,(-536640913)),new r(338241895,168717936),new r(666307205,1188179964),new r(773529912,1546045734),new r(1294757372,1522805485),new r(1396182291,(-1651133473)),new r(1695183700,(-1951439906)),new r(1986661051,1014477480),new r((-2117940946),1206759142),new r((-1838011259),344077627),new r((-1564481375),1290863460),new r((-1474664885),(-1136513023)),new r((-1035236496),(-789014639)),new r((-949202525),106217008),new r((-778901479),(-688958952)),new r((-694614492),1432725776),new r((-200395387),1467031594),new r(275423344,851169720),new r(430227734,(-1194143544)),new r(506948616,1363258195),new r(659060556,(-544281703)),new r(883997877,(-509917016)),new r(958139571,(-976659869)),new r(1322822218,(-482243893)),new r(1537002063,2003034995),new r(1747873779,(-692930397)),new r(1955562222,1575990012),new r(2024104815,1125592928),new r((-2067236844),(-1578062990)),new r((-1933114872),442776044),new r((-1866530822),593698344),new r((-1538233109),(-561857047)),new r((-1090935817),(-1295615723)),new r((-965641998),(-479046869)),new r((-903397682),(-366583396)),new r((-779700025),566280711),new r((-354779690),(-840897762)),new r((-176337025),(-294727304)),new r(116418474,1914138554),new r(174292421,(-1563912026)),new r(289380356,(-1090974290)),new r(460393269,320620315),new r(685471733,587496836),new r(852142971,1086792851),new r(1017036298,365543100),new r(1126000580,(-1676669620)),new r(1288033470,(-885112138)),new r(1501505948,(-60457430)),new r(1607167915,987167468),new r(1816402316,1246189591)]),o=0;o<80;o+=1)k[o]=new r(0,0);for(i[t>>5]|=128<<24-(31&t),i[(t+128>>10<<5)+31]=t,s=i.length,o=0;o>>e|t.h<<32-e,i.h=t.h>>>e|t.l<<32-e}function l(i,t,e){i.l=t.h>>>e|t.l<<32-e,i.h=t.l>>>e|t.h<<32-e}function w(i,t,e){i.l=t.l>>>e|t.h<<32-e,i.h=t.h>>>e}function p(i,t,e){var o=(65535&t.l)+(65535&e.l),r=(t.l>>>16)+(e.l>>>16)+(o>>>16),s=(65535&t.h)+(65535&e.h)+(r>>>16),n=(t.h>>>16)+(e.h>>>16)+(s>>>16);i.l=65535&o|r<<16,i.h=65535&s|n<<16}function d(i,t,e,o,r){var s=(65535&t.l)+(65535&e.l)+(65535&o.l)+(65535&r.l),n=(t.l>>>16)+(e.l>>>16)+(o.l>>>16)+(r.l>>>16)+(s>>>16),a=(65535&t.h)+(65535&e.h)+(65535&o.h)+(65535&r.h)+(n>>>16),l=(t.h>>>16)+(e.h>>>16)+(o.h>>>16)+(r.h>>>16)+(a>>>16);i.l=65535&s|n<<16,i.h=65535&a|l<<16}function f(i,t,e,o,r,s){var n=(65535&t.l)+(65535&e.l)+(65535&o.l)+(65535&r.l)+(65535&s.l),a=(t.l>>>16)+(e.l>>>16)+(o.l>>>16)+(r.l>>>16)+(s.l>>>16)+(n>>>16),l=(65535&t.h)+(65535&e.h)+(65535&o.h)+(65535&r.h)+(65535&s.h)+(a>>>16),k=(t.h>>>16)+(e.h>>>16)+(o.h>>>16)+(r.h>>>16)+(s.h>>>16)+(l>>>16);i.l=65535&n|a<<16,i.h=65535&l|k<<16}var y,_=!(!i||"boolean"!=typeof i.uppercase)&&i.uppercase,b=i&&"string"==typeof i.pad?i.pda:"=",m=!i||"boolean"!=typeof i.utf8||i.utf8;this.hex=function(i){return k(t(i))},this.b64=function(i){return u(t(i),b)},this.any=function(i,e){return g(t(i),e)},this.raw=function(i){return t(i,m)},this.hex_hmac=function(i,t){return k(e(i,t))},this.b64_hmac=function(i,t){return u(e(i,t),b)},this.any_hmac=function(i,t,o){return g(e(i,t),o)},this.vm_test=function(){return"900150983cd24fb0d6963f7d28e17f72"===hex("abc").toLowerCase()},this.setUpperCase=function(i){return"boolean"==typeof i&&(_=i),this},this.setPad=function(i){return b=i||b,this},this.setUTF8=function(i){return"boolean"==typeof i&&(m=i),this}},RMD160:function(i){function t(i){return i=f?s(i):i,o(r(p(i),8*i.length))}function e(i,t){i=f?s(i):i,t=f?s(t):t;var e,n,a=p(i),l=Array(16),k=Array(16);for(a.length>16&&(a=r(a,8*i.length)),e=0;e<16;e+=1)l[e]=909522486^a[e],k[e]=1549556828^a[e];return n=r(l.concat(p(t)),512+8*t.length),o(r(k.concat(n),672))}function o(i){var t,e="",o=32*i.length;for(t=0;t>5]>>>t%32&255);return e}function r(i,t){var e,o,r,s,k,p,c,g,u,d,f,v,C,q,A=1732584193,D=4023233417,B=2562383102,E=271733878,x=3285377520;for(i[t>>5]|=128<>>9<<4)+14]=t,s=i.length,r=0;re.length)return!1;var o=i.match(/"/g);return!(o&&o.length%2!==0&&i.length<900)},a=function(i){var t=[],e=[];if(!i||"string"!=typeof i||!i.match(/\w/))return t;for(var r=s(i),a=0;a0&&(t.push(e[c]),e[c]="");return 0===t.length?[i]:t};t.exports=a},{}],15:[function(i,t,e){"use strict";function o(i){return i=i.replace(//g,""),i=i.replace(/__(NOTOC|NOEDITSECTION|FORCETOC|TOC)__/gi,""),i=i.replace(/~~{1,3}/,""),i=i.replace(/--{1,3}/,""),i=i.replace(/ /g," "),i=i.replace(/\[\[([a-z][a-z]|simple|war|ceb|min):.{2,60}\]\]/i,""),i=i.replace(/''{4}([^']{0,200})''{4}/g,"$1"),i=i.replace(/''{2}([^']{0,200})''{2}/g,"$1"),i=i.replace(/''([^']{0,200})''/g,"$1"),i=r(i)}var r=i("./kill_xml");t.exports=o},{"./kill_xml":16}],16:[function(i,t,e){"use strict";var o=function(i){return i=i.replace(/ ?[\s\S]{0,750}?<\/ref> ?/gi," "),i=i.replace(/ ?]{0,200}?\/> ?/gi," "),i=i.replace(/ ?]{0,200}?>[\s\S]{0,500}?<\/ref> ?/gi," "),i=i.replace(/< ?(table|code|score|data|categorytree|charinsert|gallery|hiero|imagemap|inputbox|math|nowiki|poem|references|source|syntaxhighlight|timeline) ?[^>]{0,200}?>[\s\S]{0,700}< ?\/ ?(table|code|score|data|categorytree|charinsert|gallery|hiero|imagemap|inputbox|math|nowiki|poem|references|source|syntaxhighlight|timeline) ?>/gi," "),i=i.replace(/ ?< ?(ref|span|div|table|data) [a-z0-9=" ]{2,20}\/ ?> ?/g," "),i=i.replace(/ ?<[ \/]?(p|sub|sup|span|nowiki|div|table|br|tr|td|th|pre|pre2|hr)[ \/]?> ?/g," "),i=i.replace(/ ?<[ \/]?(abbr|bdi|bdo|blockquote|cite|del|dfn|em|i|ins|kbd|mark|q|s)[ \/]?> ?/g," "),i=i.replace(/ ?<[ \/]?h[0-9][ \/]?> ?/g," "),i=i.replace(/ ?<[ \/]?[a-z0-9]{1,8}[ \/]?> ?/g," "),i=i.replace(/ ?< ?br ?\/> ?/g," "),i.trim()};t.exports=o},{}],17:[function(i,t,e){"use strict";function o(i){var t=[],e=new RegExp("\\[\\[:?("+r.categories.join("|")+"):(.{2,60}?)]](w{0,10})","ig"),o=i.match(e);if(o){var s=new RegExp("^\\[\\[:?("+r.categories.join("|")+"):","ig");o.forEach(function(i){i=i.replace(s,""),i=i.replace(/\|?[ \*]?\]\]$/i,""),i=i.replace(/\|.*/,""),i&&!i.match(/[\[\]]/)&&t.push(i)})}return t}var r=i("../data/i18n");t.exports=o},{"../data/i18n":6}],18:[function(i,t,e){"use strict";var o=i("./parse_links"),r=function(i){var t=[],e=i.replace(/\r/g,"").split(/\n/);return e.forEach(function(i){if(i.match(/^\*.{0,40}\[\[.*\]\]/)){var e=o(i);e&&e[0]&&e[0].page&&t.push(e[0].page)}}),{type:"disambiguation",pages:t}};t.exports=r},{"./parse_links":23}],19:[function(i,t,e){"use strict";function o(i){var t=new RegExp("("+r.images.concat(r.files).join("|")+"):.*?[\\|\\]]","i");return i=i.match(t)||[""],i=i[0].replace(/[\|\]]$/,"")}var r=i("../data/i18n");t.exports=o},{"../data/i18n":6}],20:[function(i,t,e){"use strict";function o(i){var t={};if(i){i=i.replace(/\{\{Collapsible list[^}]{10,1000}\}\}/g,"");for(var e=[],o=void 0,n=-2,a=0,l=i.length;a1&&(t=o[1])}return t}var r=i("../data/i18n");t.exports=o},{"../data/i18n":6}],22:[function(i,t,e){"use strict";function o(i){var t=new RegExp("\\[\\[:?("+l.categories.join("|")+"):[^\\]\\]]{2,80}\\]\\]","gi");return i=i.replace(t,""),i=i.replace(/\[\[:?([^|]{2,80}?)\]\](\w{0,5})/g,"$1$2"),i=i.replace(/\[\[File:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g,"$1"),i=i.replace(/\[\[:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g,"$2$3"),i=i.replace(/\[(https?|news|ftp|mailto|gopher|irc):\/\/[^\]\| ]{4,1500}([\| ].*?)?\]/g,"$2")}function r(i){return i=o(i),i.match(/^(thumb|right|left)\|/i)?null:i=n.trim_whitespace(i)}function s(i){return{text:r(i),links:a(i)}}var n=i("../lib/helpers"),a=i("./parse_links"),l=i("../data/i18n");t.exports=s},{"../data/i18n":6,"../lib/helpers":12,"./parse_links":23}],23:[function(i,t,e){"use strict";var o=i("../lib/helpers"),r=function(i){var t=[],e=i.match(/\[\[(.{2,80}?)\]\](\w{0,10})/g);if(e&&e.forEach(function(i){var e,r;if(i.match(/\|/)?(i=i.replace(/\[\[(.{2,80}?)\]\](\w{0,10})/g,"$1$2"), -e=i.replace(/(.{2,60})\|.{0,200}/,"$1"),r=i.replace(/.{2,60}?\|/,""),!r&&e.match(/\|$/)&&(e=e.replace(/\|$/,""),r=e)):e=i.replace(/\[\[(.{2,60}?)\]\](\w{0,10})/g,"$1"),!e.match(/^:?(category|catégorie|Kategorie|Categoría|Categoria|Categorie|Kategoria|تصنيف|image|file|image|fichier|datei|media|special|wp|wikipedia|help|user|mediawiki|portal|talk|template|book|draft|module|topic|wiktionary|wikisource):/i)&&!e.match(/^#/i)){e=e.replace(/#[^ ]{1,100}/,""),e=o.capitalise(e);var s={page:e,src:r};t.push(s)}}),t=t.filter(o.onlyUnique),0!==t.length)return t};t.exports=r},{"../lib/helpers":12}],24:[function(i,t,e){"use strict";var o=i("../data/i18n"),r=new RegExp("^ ?#("+o.redirects.join("|")+") *?\\[\\[(.{2,60}?)\\]\\]","i");e.is_redirect=function(i){return i.match(r)},e.parse_redirect=function(i){var t=(i.match(r)||[])[2]||"";return t=t.replace(/#.*/,""),{type:"redirect",redirect:t}}},{"../data/i18n":6}],25:[function(i,t,e){"use strict";var o=i("../lib/helpers"),r=function(i){var t=[],e=i.replace(/\r/g,"").split(/\n/);return e.forEach(function(i){if(!i.match(/^\|\}/)){if(i.match(/^\|-/))return void t.push([]);if(!i.match(/^\|\+/)&&i.match(/^[\!\|]/)){t[t.length-1]||(t[t.length-1]=[]);var e=(i.match(/\|(.*)/)||[])[1]||"";e=o.trim_whitespace(e)||"",e.match(/[!\|]{2}/)?e.split(/[!\|]{2}/g).forEach(function(i){i=o.trim_whitespace(i),t[t.length-1].push(i)}):t[t.length-1].push(e)}}}),t};t.exports=r},{"../lib/helpers":12}],26:[function(i,t,e){"use strict";function o(i,t,e){for(var o=[],r=[],s=e.split(""),n=0,a=0;a=0&&r.push(s[a]),0===n&&r.length>0){var l=r.filter(function(t){return t===i}),k=r.filter(function(i){return i===t});l.length>k.length&&r.push(t),o.push(r.join("")),r=[]}return o}t.exports=o},{}],27:[function(i,t,e){"use strict";var o=i("./data/languages"),r=function(i){i=i.replace(/\{\{URL\|([^ ]{4,100}?)\}\}/gi,"$1"),i=i.replace(/\{\{convert\|([0-9]*?)\|([^\|]*?)\}\}/gi,"$1 $2");var t=new Date;i=i.replace(/\{\{(CURRENT|LOCAL)DAY(2)?\}\}/gi,t.getDate());var e=["January","February","March","April","May","June","July","August","September","October","November","December"];i=i.replace(/\{\{(CURRENT|LOCAL)MONTH(NAME|ABBREV)?\}\}/gi,e[t.getMonth()]),i=i.replace(/\{\{(CURRENT|LOCAL)YEAR\}\}/gi,t.getFullYear());var r=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];if(i=i.replace(/\{\{(CURRENT|LOCAL)DAYNAME\}\}/gi,r[t.getDay()]),i=i.replace(/\{\{(lc|uc|formatnum):(.*?)\}\}/gi,"$2"),i=i.replace(/\{\{pull quote\|([\s\S]*?)(\|[\s\S]*?)?\}\}/gi,"$1"),i=i.replace(/\{\{cquote\|([\s\S]*?)(\|[\s\S]*?)?\}\}/gi,"$1"),i=i.replace(/\{\{(small|smaller|midsize|larger|big|bigger|large|huge|resize)\|([\s\S]*?)\}\}/gi,"$2"),i.match(/\{\{dts\|/)){var s=(i.match(/\{\{dts\|(.*?)[\}\|]/)||[])[1]||"";s=new Date(s),i=s&&s.getTime()?i.replace(/\{\{dts\|.*?\}\}/gi,s.toDateString()):i.replace(/\{\{dts\|.*?\}\}/gi," ")}if(i.match(/\{\{date\|.*?\}\}/)){var s=i.match(/\{\{date\|(.*?)\|(.*?)\|(.*?)\}\}/)||[]||[],n=s[1]+" "+s[2]+" "+s[3];i=i.replace(/\{\{date\|.*?\}\}/gi,n)}if(i=i.replace(/\{\{term\|(.*?)\|.*?\}\}/gi,"'$1'"),i=i.replace(/\{\{IPA\|(.*?)\|.*?\}\}/gi,"$1"),i=i.replace(/\{\{sense\|(.*?)\|?.*?\}\}/gi,"($1)"),i=i.replace(/\{\{t\+?\|...?\|(.*?)(\|.*)?\}\}/gi,"'$1'"),i.match(/\{\{etyl\|/)){var a=i.match(/\{\{etyl\|(.*?)\|.*?\}\}/i)[1]||"";a=a.toLowerCase(),i=a&&o[a]?i.replace(/\{\{etyl\|(.*?)\|.*?\}\}/gi,o[a].english_title):i.replace(/\{\{etyl\|(.*?)\|.*?\}\}/gi,"($1)")}return i};t.exports=r},{"./data/languages":7}]},{},[9])(9)}); +!function(i){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=i();else if("function"==typeof define&&define.amd)define([],i);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.wtf_wikipedia=i()}}(function(){var i;return function i(t,e,o){function r(n,a){if(!e[n]){if(!t[n]){var l="function"==typeof require&&require;if(!a&&l)return l(n,!0);if(s)return s(n,!0);var h=new Error("Cannot find module '"+n+"'");throw h.code="MODULE_NOT_FOUND",h}var k=e[n]={exports:{}};t[n][0].call(k.exports,function(i){var e=t[n][1][i];return r(e?e:i)},k,k.exports,i,t,e,o)}return e[n].exports}for(var s="function"==typeof require&&require,n=0;n>>6&31,128|63&t):t<=65535?r+=String.fromCharCode(224|t>>>12&15,128|t>>>6&63,128|63&t):t<=2097151&&(r+=String.fromCharCode(240|t>>>18&7,128|t>>>12&63,128|t>>>6&63,128|63&t));return r}function s(i){var t,e,o,r,s,n,a=[];if(t=e=o=r=s=0,i&&i.length)for(n=i.length,i+="";t191&&o<224?(r=i.charCodeAt(t+1),a[e]=String.fromCharCode((31&o)<<6|63&r),t+=2):(r=i.charCodeAt(t+1),s=i.charCodeAt(t+2),a[e]=String.fromCharCode((15&o)<<12|(63&r)<<6|63&s),t+=3);return a.join("")}function n(i,t){var e=(65535&i)+(65535&t),o=(i>>16)+(t>>16)+(e>>16);return o<<16|65535&e}function a(i,t){return i<>>32-t}function l(i,t){for(var e,o=t?"0123456789ABCDEF":"0123456789abcdef",r="",s=0,n=i.length;s>>4&15)+o.charAt(15&e);return r}function h(i){var t,e=32*i.length,o="";for(t=0;t>5]>>>24-t%32&255);return o}function k(i){var t,e=32*i.length,o="";for(t=0;t>5]>>>t%32&255);return o}function w(i){var t,e=8*i.length,o=Array(i.length>>2),r=o.length;for(t=0;t>5]|=(255&i.charCodeAt(t/8))<>2),r=o.length;for(t=0;t>5]|=(255&i.charCodeAt(t/8))<<24-t%32;return o}function c(i,t){var e,o,r,s,n,a,l,h,k=t.length,w=Array();for(a=Array(Math.ceil(i.length/2)),s=a.length,e=0;e0;){for(n=Array(),r=0,e=0;e0||o>0)&&(n[n.length]=o);w[w.length]=r,a=n}for(l="",e=w.length-1;e>=0;e--)l+=t.charAt(w[e]);for(h=Math.ceil(8*i.length/(Math.log(t.length)/Math.log(2))),e=l.length;e8*i.length?t:s.charAt(r>>>6*(3-o)&63);return n}var u;u={VERSION:"1.0.6",Base64:function(){var i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",t="=",e=!0;this.encode=function(o){var s,n,a,l="",h=o.length;for(t=t||"=",o=e?r(o):o,s=0;s8*h?t:i.charAt(a>>>6*(3-n)&63);return l},this.decode=function(o){var r,n,a,l,h,k,w,p,c,g,u="",d=[];if(!o)return o;r=g=0,o=o.replace(new RegExp("\\"+t,"gi"),"");do h=i.indexOf(o.charAt(r+=1)),k=i.indexOf(o.charAt(r+=1)),w=i.indexOf(o.charAt(r+=1)),p=i.indexOf(o.charAt(r+=1)),c=h<<18|k<<12|w<<6|p,n=c>>16&255,a=c>>8&255,l=255&c,g+=1,64===w?d[g]=String.fromCharCode(n):64===p?d[g]=String.fromCharCode(n,a):d[g]=String.fromCharCode(n,a,l);while(r>>8^n;return(s^-1)>>>0},MD5:function(i){function t(i){return i=_?r(i):i,k(o(w(i),8*i.length))}function e(i,t){var e,s,n,a,l;for(i=_?r(i):i,t=_?r(t):t,e=w(i),e.length>16&&(e=o(e,8*i.length)),s=Array(16),n=Array(16),l=0;l<16;l+=1)s[l]=909522486^e[l],n[l]=1549556828^e[l];return a=o(s.concat(w(t)),512+8*t.length),k(o(n.concat(a),640))}function o(i,t){var e,o,r,s,a,l=1732584193,k=-271733879,w=-1732584194,c=271733878;for(i[t>>5]|=128<>>9<<4)+14]=t,e=0;e16&&(e=o(e,8*i.length)),s=Array(16),n=Array(16),a=0;a<16;a+=1)s[a]=909522486^e[a],n[a]=1549556828^e[a];return l=o(s.concat(p(t)),512+8*t.length),h(o(n.concat(l),672))}function o(i,t){var e,o,r,l,h,w,p,c,g=Array(80),u=1732584193,d=-271733879,f=-1732584194,y=271733878,_=-1009589776;for(i[t>>5]|=128<<24-t%32,i[(t+64>>9<<4)+15]=t,e=0;e16&&(s=y(s,8*i.length));o<16;o+=1)n[o]=909522486^s[o],a[o]=1549556828^s[o];return e=y(n.concat(p(t)),512+8*t.length),h(y(a.concat(e),768))}function o(i,t){return i>>>t|i<<32-t}function s(i,t){return i>>>t}function a(i,t,e){return i&t^~i&e}function k(i,t,e){return i&t^i&e^t&e}function w(i){return o(i,2)^o(i,13)^o(i,22)}function u(i){return o(i,6)^o(i,11)^o(i,25)}function d(i){return o(i,7)^o(i,18)^s(i,3)}function f(i){return o(i,17)^o(i,19)^s(i,10)}function y(i,t){var e,o,r,s,l,h,p,c,g,y,b,m,v=[1779033703,-1150833019,1013904242,-1521486534,1359893119,-1694144372,528734635,1541459225],C=new Array(64);for(i[t>>5]|=128<<24-t%32,i[(t+64>>9<<4)+15]=t,g=0;g32&&(n=o(n,8*i.length));s<32;s+=1)a[s]=909522486^n[s],l[s]=1549556828^n[s];return e=o(a.concat(p(t)),1024+8*t.length),h(o(l.concat(e),1536))}function o(i,t){var e,o,r,l=new Array(80),h=new Array(16),p=[new s(1779033703,(-205731576)),new s((-1150833019),(-2067093701)),new s(1013904242,(-23791573)),new s((-1521486534),1595750129),new s(1359893119,(-1377402159)),new s((-1694144372),725511199),new s(528734635,(-79577749)),new s(1541459225,327033209)],c=new s(0,0),g=new s(0,0),_=new s(0,0),b=new s(0,0),m=new s(0,0),v=new s(0,0),C=new s(0,0),q=new s(0,0),A=new s(0,0),D=new s(0,0),B=new s(0,0),x=new s(0,0),E=new s(0,0),F=new s(0,0),z=new s(0,0),j=new s(0,0),T=new s(0,0);for(void 0===y&&(y=[new s(1116352408,(-685199838)),new s(1899447441,602891725),new s((-1245643825),(-330482897)),new s((-373957723),(-2121671748)),new s(961987163,(-213338824)),new s(1508970993,(-1241133031)),new s((-1841331548),(-1357295717)),new s((-1424204075),(-630357736)),new s((-670586216),(-1560083902)),new s(310598401,1164996542),new s(607225278,1323610764),new s(1426881987,(-704662302)),new s(1925078388,(-226784913)),new s((-2132889090),991336113),new s((-1680079193),633803317),new s((-1046744716),(-815192428)),new s((-459576895),(-1628353838)),new s((-272742522),944711139),new s(264347078,(-1953704523)),new s(604807628,2007800933),new s(770255983,1495990901),new s(1249150122,1856431235),new s(1555081692,(-1119749164)),new s(1996064986,(-2096016459)),new s((-1740746414),(-295247957)),new s((-1473132947),766784016),new s((-1341970488),(-1728372417)),new s((-1084653625),(-1091629340)),new s((-958395405),1034457026),new s((-710438585),(-1828018395)),new s(113926993,(-536640913)),new s(338241895,168717936),new s(666307205,1188179964),new s(773529912,1546045734),new s(1294757372,1522805485),new s(1396182291,(-1651133473)),new s(1695183700,(-1951439906)),new s(1986661051,1014477480),new s((-2117940946),1206759142),new s((-1838011259),344077627),new s((-1564481375),1290863460),new s((-1474664885),(-1136513023)),new s((-1035236496),(-789014639)),new s((-949202525),106217008),new s((-778901479),(-688958952)),new s((-694614492),1432725776),new s((-200395387),1467031594),new s(275423344,851169720),new s(430227734,(-1194143544)),new s(506948616,1363258195),new s(659060556,(-544281703)),new s(883997877,(-509917016)),new s(958139571,(-976659869)),new s(1322822218,(-482243893)),new s(1537002063,2003034995),new s(1747873779,(-692930397)),new s(1955562222,1575990012),new s(2024104815,1125592928),new s((-2067236844),(-1578062990)),new s((-1933114872),442776044),new s((-1866530822),593698344),new s((-1538233109),(-561857047)),new s((-1090935817),(-1295615723)),new s((-965641998),(-479046869)),new s((-903397682),(-366583396)),new s((-779700025),566280711),new s((-354779690),(-840897762)),new s((-176337025),(-294727304)),new s(116418474,1914138554),new s(174292421,(-1563912026)),new s(289380356,(-1090974290)),new s(460393269,320620315),new s(685471733,587496836),new s(852142971,1086792851),new s(1017036298,365543100),new s(1126000580,(-1676669620)),new s(1288033470,(-885112138)),new s(1501505948,(-60457430)),new s(1607167915,987167468),new s(1816402316,1246189591)]),o=0;o<80;o+=1)l[o]=new s(0,0);for(i[t>>5]|=128<<24-(31&t),i[(t+128>>10<<5)+31]=t,r=i.length,o=0;o>>e|t.h<<32-e,i.h=t.h>>>e|t.l<<32-e}function k(i,t,e){i.l=t.h>>>e|t.l<<32-e,i.h=t.l>>>e|t.h<<32-e}function w(i,t,e){i.l=t.l>>>e|t.h<<32-e,i.h=t.h>>>e}function u(i,t,e){var o=(65535&t.l)+(65535&e.l),r=(t.l>>>16)+(e.l>>>16)+(o>>>16),s=(65535&t.h)+(65535&e.h)+(r>>>16),n=(t.h>>>16)+(e.h>>>16)+(s>>>16);i.l=65535&o|r<<16,i.h=65535&s|n<<16}function d(i,t,e,o,r){var s=(65535&t.l)+(65535&e.l)+(65535&o.l)+(65535&r.l),n=(t.l>>>16)+(e.l>>>16)+(o.l>>>16)+(r.l>>>16)+(s>>>16),a=(65535&t.h)+(65535&e.h)+(65535&o.h)+(65535&r.h)+(n>>>16),l=(t.h>>>16)+(e.h>>>16)+(o.h>>>16)+(r.h>>>16)+(a>>>16);i.l=65535&s|n<<16,i.h=65535&a|l<<16}function f(i,t,e,o,r,s){var n=(65535&t.l)+(65535&e.l)+(65535&o.l)+(65535&r.l)+(65535&s.l),a=(t.l>>>16)+(e.l>>>16)+(o.l>>>16)+(r.l>>>16)+(s.l>>>16)+(n>>>16),l=(65535&t.h)+(65535&e.h)+(65535&o.h)+(65535&r.h)+(65535&s.h)+(a>>>16),h=(t.h>>>16)+(e.h>>>16)+(o.h>>>16)+(r.h>>>16)+(s.h>>>16)+(l>>>16);i.l=65535&n|a<<16,i.h=65535&l|h<<16}var y,_=!(!i||"boolean"!=typeof i.uppercase)&&i.uppercase,b=i&&"string"==typeof i.pad?i.pad:"=",m=!i||"boolean"!=typeof i.utf8||i.utf8;this.hex=function(i){return l(t(i))},this.b64=function(i){return g(t(i),b)},this.any=function(i,e){return c(t(i),e)},this.raw=function(i){return t(i,m)},this.hex_hmac=function(i,t){return l(e(i,t))},this.b64_hmac=function(i,t){return g(e(i,t),b)},this.any_hmac=function(i,t,o){return c(e(i,t),o)},this.vm_test=function(){return"900150983cd24fb0d6963f7d28e17f72"===hex("abc").toLowerCase()},this.setUpperCase=function(i){return"boolean"==typeof i&&(_=i),this},this.setPad=function(i){return b=i||b,this},this.setUTF8=function(i){return"boolean"==typeof i&&(m=i),this}},RMD160:function(i){function t(i){return i=f?r(i):i,o(s(w(i),8*i.length))}function e(i,t){i=f?r(i):i,t=f?r(t):t;var e,n,a=w(i),l=Array(16),h=Array(16);for(a.length>16&&(a=s(a,8*i.length)),e=0;e<16;e+=1)l[e]=909522486^a[e],h[e]=1549556828^a[e];return n=s(l.concat(w(t)),512+8*t.length),o(s(h.concat(n),672))}function o(i){var t,e="",o=32*i.length;for(t=0;t>5]>>>t%32&255);return e}function s(i,t){var e,o,r,s,l,w,c,g,u,d,f,v,C,q,A=1732584193,D=4023233417,B=2562383102,x=271733878,E=3285377520;for(i[t>>5]|=128<>>9<<4)+14]=t,s=i.length,r=0;r=0?"&":"?")+i),this._sort){var t=this.url.indexOf("?");if(t>=0){var e=this.url.substring(t+1).split("&");d(this._sort)?e.sort(this._sort):e.sort(),this.url=this.url.substring(0,t)+"?"+e.join("&")}}},k.prototype._isHost=function(i){return i&&"object"==typeof i&&!Array.isArray(i)&&"[object Object]"!==Object.prototype.toString.call(i)},k.prototype.end=function(i){return this._endCalled&&console.warn("Warning: .end() was called twice. This is not supported in superagent"),this._endCalled=!0,this._callback=i||o,this._appendQueryString(),this._end()},k.prototype._end=function(){var i=this,t=this.xhr=_.getXHR(),e=this._formData||this._data;this._setTimeouts(),t.onreadystatechange=function(){var e=t.readyState;if(e>=2&&i._responseTimeoutTimer&&clearTimeout(i._responseTimeoutTimer),4==e){var o;try{o=t.status}catch(i){o=0}if(!o){if(i.timedout||i._aborted)return;return i.crossDomainError()}i.emit("end")}};var o=function(t,e){e.total>0&&(e.percent=e.loaded/e.total*100),e.direction=t,i.emit("progress",e)};if(this.hasListeners("progress"))try{ +t.onprogress=o.bind(null,"download"),t.upload&&(t.upload.onprogress=o.bind(null,"upload"))}catch(i){}try{this.username&&this.password?t.open(this.method,this.url,!0,this.username,this.password):t.open(this.method,this.url,!0)}catch(i){return this.callback(i)}if(this._withCredentials&&(t.withCredentials=!0),!this._formData&&"GET"!=this.method&&"HEAD"!=this.method&&"string"!=typeof e&&!this._isHost(e)){var r=this._header["content-type"],s=this._serializer||_.serialize[r?r.split(";")[0]:""];!s&&l(r)&&(s=_.serialize["application/json"]),s&&(e=s(e))}for(var n in this.header)null!=this.header[n]&&this.header.hasOwnProperty(n)&&t.setRequestHeader(n,this.header[n]);return this._responseType&&(t.responseType=this._responseType),this.emit("request",this),t.send("undefined"!=typeof e?e:null),this},_.get=function(i,t,e){var o=_("GET",i);return"function"==typeof t&&(e=t,t=null),t&&o.query(t),e&&o.end(e),o},_.head=function(i,t,e){var o=_("HEAD",i);return"function"==typeof t&&(e=t,t=null),t&&o.send(t),e&&o.end(e),o},_.options=function(i,t,e){var o=_("OPTIONS",i);return"function"==typeof t&&(e=t,t=null),t&&o.send(t),e&&o.end(e),o},_.del=w,_.delete=w,_.patch=function(i,t,e){var o=_("PATCH",i);return"function"==typeof t&&(e=t,t=null),t&&o.send(t),e&&o.end(e),o},_.post=function(i,t,e){var o=_("POST",i);return"function"==typeof t&&(e=t,t=null),t&&o.send(t),e&&o.end(e),o},_.put=function(i,t,e){var o=_("PUT",i);return"function"==typeof t&&(e=t,t=null),t&&o.send(t),e&&o.end(e),o}},{"./is-function":4,"./is-object":5,"./request-base":6,"./response-base":7,"./should-retry":8,"component-emitter":1}],4:[function(i,t,e){function o(i){var t=r(i)?Object.prototype.toString.call(i):"";return"[object Function]"===t}var r=i("./is-object");t.exports=o},{"./is-object":5}],5:[function(i,t,e){function o(i){return null!==i&&"object"==typeof i}t.exports=o},{}],6:[function(i,t,e){function o(i){if(i)return r(i)}function r(i){for(var t in o.prototype)i[t]=o.prototype[t];return i}var s=i("./is-object");t.exports=o,o.prototype.clearTimeout=function(){return clearTimeout(this._timer),clearTimeout(this._responseTimeoutTimer),delete this._timer,delete this._responseTimeoutTimer,this},o.prototype.parse=function(i){return this._parser=i,this},o.prototype.responseType=function(i){return this._responseType=i,this},o.prototype.serialize=function(i){return this._serializer=i,this},o.prototype.timeout=function(i){if(!i||"object"!=typeof i)return this._timeout=i,this._responseTimeout=0,this;for(var t in i)switch(t){case"deadline":this._timeout=i.deadline;break;case"response":this._responseTimeout=i.response;break;default:console.warn("Unknown timeout option",t)}return this},o.prototype.retry=function(i){return 0!==arguments.length&&i!==!0||(i=1),i<=0&&(i=0),this._maxRetries=i,this._retries=0,this},o.prototype._retry=function(){return this.clearTimeout(),this.req&&(this.req=null,this.req=this.request()),this._aborted=!1,this.timedout=!1,this._end()},o.prototype.then=function(i,t){if(!this._fullfilledPromise){var e=this;this._endCalled&&console.warn("Warning: superagent request was sent twice, because both .end() and .then() were called. Never call .end() if you use promises"),this._fullfilledPromise=new Promise(function(i,t){e.end(function(e,o){e?t(e):i(o)})})}return this._fullfilledPromise.then(i,t)},o.prototype.catch=function(i){return this.then(void 0,i)},o.prototype.use=function(i){return i(this),this},o.prototype.ok=function(i){if("function"!=typeof i)throw Error("Callback required");return this._okCallback=i,this},o.prototype._isResponseOK=function(i){return!!i&&(this._okCallback?this._okCallback(i):i.status>=200&&i.status<300)},o.prototype.get=function(i){return this._header[i.toLowerCase()]},o.prototype.getHeader=o.prototype.get,o.prototype.set=function(i,t){if(s(i)){for(var e in i)this.set(e,i[e]);return this}return this._header[i.toLowerCase()]=t,this.header[i]=t,this},o.prototype.unset=function(i){return delete this._header[i.toLowerCase()],delete this.header[i],this},o.prototype.field=function(i,t){if(null===i||void 0===i)throw new Error(".field(name, val) name can not be empty");if(this._data&&console.error(".field() can't be used if .send() is used. Please use only .send() or only .field() & .attach()"),s(i)){for(var e in i)this.field(e,i[e]);return this}if(Array.isArray(t)){for(var o in t)this.field(i,t[o]);return this}if(null===t||void 0===t)throw new Error(".field(name, val) val can not be empty");return"boolean"==typeof t&&(t=""+t),this._getFormData().append(i,t),this},o.prototype.abort=function(){return this._aborted?this:(this._aborted=!0,this.xhr&&this.xhr.abort(),this.req&&this.req.abort(),this.clearTimeout(),this.emit("abort"),this)},o.prototype.withCredentials=function(i){return void 0==i&&(i=!0),this._withCredentials=i,this},o.prototype.redirects=function(i){return this._maxRedirects=i,this},o.prototype.toJSON=function(){return{method:this.method,url:this.url,data:this._data,headers:this._header}},o.prototype.send=function(i){var t=s(i),e=this._header["content-type"];if(this._formData&&console.error(".send() can't be used if .attach() or .field() is used. Please use only .send() or only .field() & .attach()"),t&&!this._data)Array.isArray(i)?this._data=[]:this._isHost(i)||(this._data={});else if(i&&this._data&&this._isHost(this._data))throw Error("Can't merge these send calls");if(t&&s(this._data))for(var o in i)this._data[o]=i[o];else"string"==typeof i?(e||this.type("form"),e=this._header["content-type"],"application/x-www-form-urlencoded"==e?this._data=this._data?this._data+"&"+i:i:this._data=(this._data||"")+i):this._data=i;return!t||this._isHost(i)?this:(e||this.type("json"),this)},o.prototype.sortQuery=function(i){return this._sort="undefined"==typeof i||i,this},o.prototype._timeoutError=function(i,t,e){if(!this._aborted){var o=new Error(i+t+"ms exceeded");o.timeout=t,o.code="ECONNABORTED",o.errno=e,this.timedout=!0,this.abort(),this.callback(o)}},o.prototype._setTimeouts=function(){var i=this;this._timeout&&!this._timer&&(this._timer=setTimeout(function(){i._timeoutError("Timeout of ",i._timeout,"ETIME")},this._timeout)),this._responseTimeout&&!this._responseTimeoutTimer&&(this._responseTimeoutTimer=setTimeout(function(){i._timeoutError("Response timeout of ",i._responseTimeout,"ETIMEDOUT")},this._responseTimeout))}},{"./is-object":5}],7:[function(i,t,e){function o(i){if(i)return r(i)}function r(i){for(var t in o.prototype)i[t]=o.prototype[t];return i}var s=i("./utils");t.exports=o,o.prototype.get=function(i){return this.header[i.toLowerCase()]},o.prototype._setHeaderProperties=function(i){var t=i["content-type"]||"";this.type=s.type(t);var e=s.params(t);for(var o in e)this[o]=e[o];this.links={};try{i.link&&(this.links=s.parseLinks(i.link))}catch(i){}},o.prototype._setStatusProperties=function(i){var t=i/100|0;this.status=this.statusCode=i,this.statusType=t,this.info=1==t,this.ok=2==t,this.redirect=3==t,this.clientError=4==t,this.serverError=5==t,this.error=(4==t||5==t)&&this.toError(),this.accepted=202==i,this.noContent=204==i,this.badRequest=400==i,this.unauthorized=401==i,this.notAcceptable=406==i,this.forbidden=403==i,this.notFound=404==i}},{"./utils":9}],8:[function(i,t,e){var o=["ECONNRESET","ETIMEDOUT","EADDRINFO","ESOCKETTIMEDOUT"];t.exports=function(i,t){return!!(i&&i.code&&~o.indexOf(i.code))||(!!(t&&t.status&&t.status>=500)||(!!(i&&"timeout"in i&&"ECONNABORTED"==i.code)||!!(i&&"crossDomain"in i)))}},{}],9:[function(i,t,e){e.type=function(i){return i.split(/ *; */).shift()},e.params=function(i){return i.split(/ *; */).reduce(function(i,t){var e=t.split(/ *= */),o=e.shift(),r=e.shift();return o&&r&&(i[o]=r),i},{})},e.parseLinks=function(i){return i.split(/ *, */).reduce(function(i,t){var e=t.split(/ *; */),o=e[0].slice(1,-1),r=e[1].split(/ *= */)[1].slice(1,-1);return i[r]=o,i},{})},e.cleanHeader=function(i,t){return delete i["content-type"],delete i["content-length"],delete i["transfer-encoding"],delete i.host,t&&delete i.cookie,i}},{}],10:[function(i,t,e){"use strict";t.exports=["jr","mr","mrs","ms","dr","prof","sr","sen","corp","calif","rep","gov","atty","supt","det","rev","col","gen","lt","cmdr","adm","capt","sgt","cpl","maj","dept","univ","assn","bros","inc","ltd","co","corp","arc","al","ave","blvd","cl","ct","cres","exp","rd","st","dist","mt","ft","fy","hwy","la","pd","pl","plz","tce","Ala","Ariz","Ark","Cal","Calif","Col","Colo","Conn","Del","Fed","Fla","Ga","Ida","Id","Ill","Ind","Ia","Kan","Kans","Ken","Ky","La","Me","Md","Mass","Mich","Minn","Miss","Mo","Mont","Neb","Nebr","Nev","Mex","Okla","Ok","Ore","Penna","Penn","Pa","Dak","Tenn","Tex","Ut","Vt","Va","Wash","Wis","Wisc","Wy","Wyo","USAFA","Alta","Ont","QuÔøΩ","Sask","Yuk","jan","feb","mar","apr","jun","jul","aug","sep","oct","nov","dec","sept","vs","etc","esp","llb","md","bl","phd","ma","ba","miss","misses","mister","sir","esq","mstr","lit","fl","ex","eg","sep","sept",".."]},{}],11:[function(i,t,e){"use strict";var o={files:["файл","fitxer","soubor","datei","file","archivo","پرونده","tiedosto","mynd","su'wret","fichier","bestand","датотека","dosya","fil"],images:["image"],templates:["шаблён","plantilla","šablona","vorlage","template","الگو","malline","snið","shablon","modèle","sjabloon","шаблон","şablon"],categories:["катэгорыя","categoria","kategorie","category","categoría","رده","luokka","flokkur","kategoriya","catégorie","categorie","категорија","kategori","kategoria","تصنيف"],redirects:["перанакіраваньне","redirect","přesměruj","weiterleitung","redirección","redireccion","تغییر_مسیر","تغییرمسیر","ohjaus","uudelleenohjaus","tilvísun","aýdaw","айдау","redirection","doorverwijzing","преусмери","преусмјери","yönlendi̇rme","yönlendi̇r","重定向","redirección","redireccion","重定向","yönlendirm?e?","تغییر_مسیر","تغییرمسیر","перанакіраваньне","yönlendirme"],specials:["спэцыяльныя","especial","speciální","spezial","special","ویژه","toiminnot","kerfissíða","arnawlı","spécial","speciaal","посебно","özel"],users:["удзельнік","usuari","uživatel","benutzer","user","usuario","کاربر","käyttäjä","notandi","paydalanıwshı","utilisateur","gebruiker","корисник","kullanıcı"],disambigs:["disambig","disambiguation","dab","disamb","begriffsklärung","ujednoznacznienie","doorverwijspagina","消歧义","desambiguación","dubbelsinnig","disambigua","desambiguação","homonymie","неоднозначность","anlam ayrımı"],infoboxes:["infobox","ficha","канадский","inligtingskas","inligtingskas3","لغة","bilgi kutusu","yerleşim bilgi kutusu","infoboks"],sources:["references","see also","external links","further reading","notes et références","voir aussi","liens externes"]};"undefined"!=typeof t&&t.exports&&(t.exports=o)},{}],12:[function(i,t,e){"use strict";t.exports={aa:{english_title:"Afar",direction:"ltr",local_title:"Afar"},ab:{english_title:"Abkhazian",direction:"ltr",local_title:"Аҧсуа"},af:{english_title:"Afrikaans",direction:"ltr",local_title:"Afrikaans"},ak:{english_title:"Akan",direction:"ltr",local_title:"Akana"},als:{english_title:"Alemannic",direction:"ltr",local_title:"Alemannisch"},am:{english_title:"Amharic",direction:"ltr",local_title:"አማርኛ"},an:{english_title:"Aragonese",direction:"ltr",local_title:"Aragonés"},ang:{english_title:"Anglo-Saxon",direction:"ltr",local_title:"Englisc"},ar:{english_title:"Arabic",direction:"rtl",local_title:"العربية"},arc:{english_title:"Aramaic",direction:"rtl",local_title:"ܣܘܪܬ"},as:{english_title:"Assamese",direction:"ltr",local_title:"অসমীয়া"},ast:{english_title:"Asturian",direction:"ltr",local_title:"Asturianu"},av:{english_title:"Avar",direction:"ltr",local_title:"Авар"},ay:{english_title:"Aymara",direction:"ltr",local_title:"Aymar"},az:{english_title:"Azerbaijani",direction:"ltr",local_title:"Azərbaycanca"},ba:{english_title:"Bashkir",direction:"ltr",local_title:"Башҡорт"},bar:{english_title:"Bavarian",direction:"ltr",local_title:"Boarisch"},"bat-smg":{english_title:"Samogitian",direction:"ltr",local_title:"Žemaitėška"},bcl:{english_title:"Bikol",direction:"ltr",local_title:"Bikol"},be:{english_title:"Belarusian",direction:"ltr",local_title:"Беларуская"},"be-x-old":{english_title:"Belarusian",direction:"(Taraškievica)",local_title:"ltr"},bg:{english_title:"Bulgarian",direction:"ltr",local_title:"Български"},bh:{english_title:"Bihari",direction:"ltr",local_title:"भोजपुरी"},bi:{english_title:"Bislama",direction:"ltr",local_title:"Bislama"},bm:{english_title:"Bambara",direction:"ltr",local_title:"Bamanankan"},bn:{english_title:"Bengali",direction:"ltr",local_title:"বাংলা"},bo:{english_title:"Tibetan",direction:"ltr",local_title:"བོད་ཡིག"},bpy:{english_title:"Bishnupriya",direction:"Manipuri",local_title:"ltr"},br:{english_title:"Breton",direction:"ltr",local_title:"Brezhoneg"},bs:{english_title:"Bosnian",direction:"ltr",local_title:"Bosanski"},bug:{english_title:"Buginese",direction:"ltr",local_title:"ᨅᨔ"},bxr:{english_title:"Buriat",direction:"(Russia)",local_title:"ltr"},ca:{english_title:"Catalan",direction:"ltr",local_title:"Català"},cdo:{english_title:"Min",direction:"Dong",local_title:"Chinese"},ce:{english_title:"Chechen",direction:"ltr",local_title:"Нохчийн"},ceb:{english_title:"Cebuano",direction:"ltr",local_title:"Sinugboanong"},ch:{english_title:"Chamorro",direction:"ltr",local_title:"Chamoru"},cho:{english_title:"Choctaw",direction:"ltr",local_title:"Choctaw"},chr:{english_title:"Cherokee",direction:"ltr",local_title:"ᏣᎳᎩ"},chy:{english_title:"Cheyenne",direction:"ltr",local_title:"Tsetsêhestâhese"},co:{english_title:"Corsican",direction:"ltr",local_title:"Corsu"},cr:{english_title:"Cree",direction:"ltr",local_title:"Nehiyaw"},cs:{english_title:"Czech",direction:"ltr",local_title:"Česky"},csb:{english_title:"Kashubian",direction:"ltr",local_title:"Kaszëbsczi"},cu:{english_title:"Old",direction:"Church",local_title:"Slavonic"},cv:{english_title:"Chuvash",direction:"ltr",local_title:"Чăваш"},cy:{english_title:"Welsh",direction:"ltr",local_title:"Cymraeg"},da:{english_title:"Danish",direction:"ltr",local_title:"Dansk"},de:{english_title:"German",direction:"ltr",local_title:"Deutsch"},diq:{english_title:"Dimli",direction:"ltr",local_title:"Zazaki"},dsb:{english_title:"Lower",direction:"Sorbian",local_title:"ltr"},dv:{english_title:"Divehi",direction:"rtl",local_title:"ދިވެހިބަސް"},dz:{english_title:"Dzongkha",direction:"ltr",local_title:"ཇོང་ཁ"},ee:{english_title:"Ewe",direction:"ltr",local_title:"Ɛʋɛ"},far:{english_title:"Farsi",direction:"ltr",local_title:"فارسی"},el:{english_title:"Greek",direction:"ltr",local_title:"Ελληνικά"},en:{english_title:"English",direction:"ltr",local_title:"English"},eo:{english_title:"Esperanto",direction:"ltr",local_title:"Esperanto"},es:{english_title:"Spanish",direction:"ltr",local_title:"Español"},et:{english_title:"Estonian",direction:"ltr",local_title:"Eesti"},eu:{english_title:"Basque",direction:"ltr",local_title:"Euskara"},ext:{english_title:"Extremaduran",direction:"ltr",local_title:"Estremeñu"},ff:{english_title:"Peul",direction:"ltr",local_title:"Fulfulde"},fi:{english_title:"Finnish",direction:"ltr",local_title:"Suomi"},"fiu-vro":{english_title:"Võro",direction:"ltr",local_title:"Võro"},fj:{english_title:"Fijian",direction:"ltr",local_title:"Na"},fo:{english_title:"Faroese",direction:"ltr",local_title:"Føroyskt"},fr:{english_title:"French",direction:"ltr",local_title:"Français"},frp:{english_title:"Arpitan",direction:"ltr",local_title:"Arpitan"},fur:{english_title:"Friulian",direction:"ltr",local_title:"Furlan"},fy:{english_title:"West",direction:"Frisian",local_title:"ltr"},ga:{english_title:"Irish",direction:"ltr",local_title:"Gaeilge"},gan:{english_title:"Gan",direction:"Chinese",local_title:"ltr"},gd:{english_title:"Scottish",direction:"Gaelic",local_title:"ltr"},gil:{english_title:"Gilbertese",direction:"ltr",local_title:"Taetae"},gl:{english_title:"Galician",direction:"ltr",local_title:"Galego"},gn:{english_title:"Guarani",direction:"ltr",local_title:"Avañe'ẽ"},got:{english_title:"Gothic",direction:"ltr",local_title:"gutisk"},gu:{english_title:"Gujarati",direction:"ltr",local_title:"ગુજરાતી"},gv:{english_title:"Manx",direction:"ltr",local_title:"Gaelg"},ha:{english_title:"Hausa",direction:"rtl",local_title:"هَوُسَ"},hak:{english_title:"Hakka",direction:"Chinese",local_title:"ltr"},haw:{english_title:"Hawaiian",direction:"ltr",local_title:"Hawai`i"},he:{english_title:"Hebrew",direction:"rtl",local_title:"עברית"},hi:{english_title:"Hindi",direction:"ltr",local_title:"हिन्दी"},ho:{english_title:"Hiri",direction:"Motu",local_title:"ltr"},hr:{english_title:"Croatian",direction:"ltr",local_title:"Hrvatski"},ht:{english_title:"Haitian",direction:"ltr",local_title:"Krèyol"},hu:{english_title:"Hungarian",direction:"ltr",local_title:"Magyar"},hy:{english_title:"Armenian",direction:"ltr",local_title:"Հայերեն"},hz:{english_title:"Herero",direction:"ltr",local_title:"Otsiherero"},ia:{english_title:"Interlingua",direction:"ltr",local_title:"Interlingua"},id:{english_title:"Indonesian",direction:"ltr",local_title:"Bahasa"},ie:{english_title:"Interlingue",direction:"ltr",local_title:"Interlingue"},ig:{english_title:"Igbo",direction:"ltr",local_title:"Igbo"},ii:{english_title:"Sichuan",direction:"Yi",local_title:"ltr"},ik:{english_title:"Inupiak",direction:"ltr",local_title:"Iñupiak"},ilo:{english_title:"Ilokano",direction:"ltr",local_title:"Ilokano"},io:{english_title:"Ido",direction:"ltr",local_title:"Ido"},is:{english_title:"Icelandic",direction:"ltr",local_title:"Íslenska"},it:{english_title:"Italian",direction:"ltr",local_title:"Italiano"},iu:{english_title:"Inuktitut",direction:"ltr",local_title:"ᐃᓄᒃᑎᑐᑦ"},ja:{english_title:"Japanese",direction:"ltr",local_title:"日本語"},jbo:{english_title:"Lojban",direction:"ltr",local_title:"Lojban"},jv:{english_title:"Javanese",direction:"ltr",local_title:"Basa"},ka:{english_title:"Georgian",direction:"ltr",local_title:"ქართული"},kg:{english_title:"Kongo",direction:"ltr",local_title:"KiKongo"},ki:{english_title:"Kikuyu",direction:"ltr",local_title:"Gĩkũyũ"},kj:{english_title:"Kuanyama",direction:"ltr",local_title:"Kuanyama"},kk:{english_title:"Kazakh",direction:"ltr",local_title:"Қазақша"},kl:{english_title:"Greenlandic",direction:"ltr",local_title:"Kalaallisut"},km:{english_title:"Cambodian",direction:"ltr",local_title:"ភាសាខ្មែរ"},kn:{english_title:"Kannada",direction:"ltr",local_title:"ಕನ್ನಡ"},khw:{english_title:"Khowar",direction:"rtl",local_title:"کھوار"},ko:{english_title:"Korean",direction:"ltr",local_title:"한국어"},kr:{english_title:"Kanuri",direction:"ltr",local_title:"Kanuri"},ks:{english_title:"Kashmiri",direction:"rtl",local_title:"कश्मीरी"},ksh:{english_title:"Ripuarian",direction:"ltr",local_title:"Ripoarisch"},ku:{english_title:"Kurdish",direction:"rtl",local_title:"Kurdî"},kv:{english_title:"Komi",direction:"ltr",local_title:"Коми"},kw:{english_title:"Cornish",direction:"ltr",local_title:"Kernewek"},ky:{english_title:"Kirghiz",direction:"ltr",local_title:"Kırgızca"},la:{english_title:"Latin",direction:"ltr",local_title:"Latina"},lad:{english_title:"Ladino",direction:"ltr",local_title:"Dzhudezmo"},lan:{english_title:"Lango",direction:"ltr",local_title:"Leb"},lb:{english_title:"Luxembourgish",direction:"ltr",local_title:"Lëtzebuergesch"},lg:{english_title:"Ganda",direction:"ltr",local_title:"Luganda"},li:{english_title:"Limburgian",direction:"ltr",local_title:"Limburgs"},lij:{english_title:"Ligurian",direction:"ltr",local_title:"Líguru"},lmo:{english_title:"Lombard",direction:"ltr",local_title:"Lumbaart"},ln:{english_title:"Lingala",direction:"ltr",local_title:"Lingála"},lo:{english_title:"Laotian",direction:"ltr",local_title:"ລາວ"},lt:{english_title:"Lithuanian",direction:"ltr",local_title:"Lietuvių"},lv:{english_title:"Latvian",direction:"ltr",local_title:"Latviešu"},"map-bms":{english_title:"Banyumasan",direction:"ltr",local_title:"Basa"},mg:{english_title:"Malagasy",direction:"ltr",local_title:"Malagasy"},man:{english_title:"Mandarin",direction:"ltr",local_title:"官話"},mh:{english_title:"Marshallese",direction:"ltr",local_title:"Kajin"},mi:{english_title:"Maori",direction:"ltr",local_title:"Māori"},min:{english_title:"Minangkabau",direction:"ltr",local_title:"Minangkabau"},mk:{english_title:"Macedonian",direction:"ltr",local_title:"Македонски"},ml:{english_title:"Malayalam",direction:"ltr",local_title:"മലയാളം"},mn:{english_title:"Mongolian",direction:"ltr",local_title:"Монгол"},mo:{english_title:"Moldovan",direction:"ltr",local_title:"Moldovenească"},mr:{english_title:"Marathi",direction:"ltr",local_title:"मराठी"},ms:{english_title:"Malay",direction:"ltr",local_title:"Bahasa"},mt:{english_title:"Maltese",direction:"ltr",local_title:"bil-Malti"},mus:{english_title:"Creek",direction:"ltr",local_title:"Muskogee"},my:{english_title:"Burmese",direction:"ltr",local_title:"Myanmasa"},na:{english_title:"Nauruan",direction:"ltr",local_title:"Dorerin"},nah:{english_title:"Nahuatl",direction:"ltr",local_title:"Nahuatl"},nap:{english_title:"Neapolitan",direction:"ltr",local_title:"Nnapulitano"},nd:{english_title:"North",direction:"Ndebele",local_title:"ltr"},nds:{english_title:"Low German",direction:"ltr",local_title:"Plattdüütsch"},"nds-nl":{english_title:"Dutch",direction:"Low",local_title:"Saxon"},ne:{english_title:"Nepali",direction:"ltr",local_title:"नेपाली"},new:{english_title:"Newar",direction:"ltr",local_title:"नेपालभाषा"},ng:{english_title:"Ndonga",direction:"ltr",local_title:"Oshiwambo"},nl:{english_title:"Dutch",direction:"ltr",local_title:"Nederlands"},nn:{english_title:"Norwegian",direction:"Nynorsk",local_title:"ltr"},no:{english_title:"Norwegian",direction:"ltr",local_title:"Norsk"},nr:{english_title:"South",direction:"Ndebele",local_title:"ltr"},nso:{english_title:"Northern",direction:"Sotho",local_title:"ltr"},nrm:{english_title:"Norman",direction:"ltr",local_title:"Nouormand"},nv:{english_title:"Navajo",direction:"ltr",local_title:"Diné"},ny:{english_title:"Chichewa",direction:"ltr",local_title:"Chi-Chewa"},oc:{english_title:"Occitan",direction:"ltr",local_title:"Occitan"},oj:{english_title:"Ojibwa",direction:"ltr",local_title:"ᐊᓂᔑᓈᐯᒧᐎᓐ"},om:{english_title:"Oromo",direction:"ltr",local_title:"Oromoo"},or:{english_title:"Oriya",direction:"ltr",local_title:"ଓଡ଼ିଆ"},os:{english_title:"Ossetian",direction:"ltr",local_title:"Иронау"},pa:{english_title:"Panjabi",direction:"ltr",local_title:"ਪੰਜਾਬੀ"},pag:{english_title:"Pangasinan",direction:"ltr",local_title:"Pangasinan"},pam:{english_title:"Kapampangan",direction:"ltr",local_title:"Kapampangan"},pap:{english_title:"Papiamentu",direction:"ltr",local_title:"Papiamentu"},pdc:{english_title:"Pennsylvania",direction:"German",local_title:"ltr"},pi:{english_title:"Pali",direction:"ltr",local_title:"Pāli"},pih:{english_title:"Norfolk",direction:"ltr",local_title:"Norfuk"},pl:{english_title:"Polish",direction:"ltr",local_title:"Polski"},pms:{english_title:"Piedmontese",direction:"ltr",local_title:"Piemontèis"},ps:{english_title:"Pashto",direction:"rtl",local_title:"پښتو"},pt:{english_title:"Portuguese",direction:"ltr",local_title:"Português"},qu:{english_title:"Quechua",direction:"ltr",local_title:"Runa"},rm:{english_title:"Raeto",direction:"Romance",local_title:"ltr"},rmy:{english_title:"Romani",direction:"ltr",local_title:"Romani"},rn:{english_title:"Kirundi",direction:"ltr",local_title:"Kirundi"},ro:{english_title:"Romanian",direction:"ltr",local_title:"Română"},"roa-rup":{english_title:"Aromanian",direction:"ltr",local_title:"Armâneashti"},ru:{english_title:"Russian",direction:"ltr",local_title:"Русский"},rw:{english_title:"Rwandi",direction:"ltr",local_title:"Kinyarwandi"},sa:{english_title:"Sanskrit",direction:"ltr",local_title:"संस्कृतम्"},sc:{english_title:"Sardinian",direction:"ltr",local_title:"Sardu"},scn:{english_title:"Sicilian",direction:"ltr",local_title:"Sicilianu"},sco:{english_title:"Scots",direction:"ltr",local_title:"Scots"},sd:{english_title:"Sindhi",direction:"ltr",local_title:"सिनधि"},se:{english_title:"Northern",direction:"Sami",local_title:"ltr"},sg:{english_title:"Sango",direction:"ltr",local_title:"Sängö"},sh:{english_title:"Serbo-Croatian",direction:"ltr",local_title:"Srpskohrvatski"},si:{english_title:"Sinhalese",direction:"ltr",local_title:"සිංහල"},simple:{english_title:"Simple",direction:"English",local_title:"ltr"},sk:{english_title:"Slovak",direction:"ltr",local_title:"Slovenčina"},sl:{english_title:"Slovenian",direction:"ltr",local_title:"Slovenščina"},sm:{english_title:"Samoan",direction:"ltr",local_title:"Gagana"},sn:{english_title:"Shona",direction:"ltr",local_title:"chiShona"},so:{english_title:"Somalia",direction:"ltr",local_title:"Soomaaliga"},sq:{english_title:"Albanian",direction:"ltr",local_title:"Shqip"},sr:{english_title:"Serbian",direction:"ltr",local_title:"Српски"},ss:{english_title:"Swati",direction:"ltr",local_title:"SiSwati"},st:{english_title:"Southern",direction:"Sotho",local_title:"ltr"},su:{english_title:"Sundanese",direction:"ltr",local_title:"Basa"},sv:{english_title:"Swedish",direction:"ltr",local_title:"Svenska"},sw:{english_title:"Swahili",direction:"ltr",local_title:"Kiswahili"},ta:{english_title:"Tamil",direction:"ltr",local_title:"தமிழ்"},te:{english_title:"Telugu",direction:"ltr",local_title:"తెలుగు"},tet:{english_title:"Tetum",direction:"ltr",local_title:"Tetun"},tg:{english_title:"Tajik",direction:"ltr",local_title:"Тоҷикӣ"},th:{english_title:"Thai",direction:"ltr",local_title:"ไทย"},ti:{english_title:"Tigrinya",direction:"ltr",local_title:"ትግርኛ"},tk:{english_title:"Turkmen",direction:"ltr",local_title:"Туркмен"},tl:{english_title:"Tagalog",direction:"ltr",local_title:"Tagalog"},tlh:{english_title:"Klingon",direction:"ltr",local_title:"tlhIngan-Hol"},tn:{english_title:"Tswana",direction:"ltr",local_title:"Setswana"},to:{english_title:"Tonga",direction:"ltr",local_title:"Lea"},tpi:{english_title:"Tok",direction:"Pisin",local_title:"ltr"},tr:{english_title:"Turkish",direction:"ltr",local_title:"Türkçe"},ts:{english_title:"Tsonga",direction:"ltr",local_title:"Xitsonga"},tt:{english_title:"Tatar",direction:"ltr",local_title:"Tatarça"},tum:{english_title:"Tumbuka",direction:"ltr",local_title:"chiTumbuka"},tw:{english_title:"Twi",direction:"ltr",local_title:"Twi"},ty:{english_title:"Tahitian",direction:"ltr",local_title:"Reo"},udm:{english_title:"Udmurt",direction:"ltr",local_title:"Удмурт"},ug:{english_title:"Uyghur",direction:"ltr",local_title:"Uyƣurqə"},uk:{english_title:"Ukrainian",direction:"ltr",local_title:"Українська"},ur:{english_title:"Urdu",direction:"rtl",local_title:"اردو"},uz:{english_title:"Uzbek",direction:"ltr",local_title:"Ўзбек"},ve:{english_title:"Venda",direction:"ltr",local_title:"Tshivenḓa"},vi:{english_title:"Vietnamese",direction:"ltr",local_title:"Việtnam"},vec:{english_title:"Venetian",direction:"ltr",local_title:"Vèneto"},vls:{english_title:"West",direction:"Flemish",local_title:"ltr"},vo:{english_title:"Volapük",direction:"ltr",local_title:"Volapük"},wa:{english_title:"Walloon",direction:"ltr",local_title:"Walon"},war:{english_title:"Waray-Waray",direction:"ltr",local_title:"Winaray"},wo:{english_title:"Wolof",direction:"ltr",local_title:"Wollof"},xal:{english_title:"Kalmyk",direction:"ltr",local_title:"Хальмг"},xh:{english_title:"Xhosa",direction:"ltr",local_title:"isiXhosa"},yi:{english_title:"Yiddish",direction:"rtl",local_title:"ייִדיש"},yo:{english_title:"Yoruba",direction:"ltr",local_title:"Yorùbá"},za:{english_title:"Zhuang",direction:"ltr",local_title:"Cuengh"},zh:{english_title:"Chinese",direction:"ltr",local_title:"中文"},"zh-classical":{english_title:"Classical",direction:"Chinese",local_title:"ltr"},"zh-min-nan":{english_title:"Minnan",direction:"ltr",local_title:"Bân-lâm-gú"},"zh-yue":{english_title:"Cantonese",direction:"ltr",local_title:"粵語"},zu:{english_title:"Zulu",direction:"ltr",local_title:"isiZulu"}}},{}],13:[function(i,t,e){"use strict";var o={aawiki:"https://aa.wikipedia.org",aawiktionary:"https://aa.wiktionary.org",aawikibooks:"https://aa.wikibooks.org",abwiki:"https://ab.wikipedia.org",abwiktionary:"https://ab.wiktionary.org",acewiki:"https://ace.wikipedia.org",afwiki:"https://af.wikipedia.org",afwiktionary:"https://af.wiktionary.org",afwikibooks:"https://af.wikibooks.org",afwikiquote:"https://af.wikiquote.org",akwiki:"https://ak.wikipedia.org",akwiktionary:"https://ak.wiktionary.org",akwikibooks:"https://ak.wikibooks.org",alswiki:"https://als.wikipedia.org",alswiktionary:"https://als.wiktionary.org",alswikibooks:"https://als.wikibooks.org",alswikiquote:"https://als.wikiquote.org",amwiki:"https://am.wikipedia.org",amwiktionary:"https://am.wiktionary.org",amwikiquote:"https://am.wikiquote.org",anwiki:"https://an.wikipedia.org",anwiktionary:"https://an.wiktionary.org",angwiki:"https://ang.wikipedia.org",angwiktionary:"https://ang.wiktionary.org",angwikibooks:"https://ang.wikibooks.org",angwikiquote:"https://ang.wikiquote.org",angwikisource:"https://ang.wikisource.org",arwiki:"https://ar.wikipedia.org",arwiktionary:"https://ar.wiktionary.org",arwikibooks:"https://ar.wikibooks.org",arwikinews:"https://ar.wikinews.org",arwikiquote:"https://ar.wikiquote.org",arwikisource:"https://ar.wikisource.org",arwikiversity:"https://ar.wikiversity.org",arcwiki:"https://arc.wikipedia.org",arzwiki:"https://arz.wikipedia.org",aswiki:"https://as.wikipedia.org",aswiktionary:"https://as.wiktionary.org",aswikibooks:"https://as.wikibooks.org",aswikisource:"https://as.wikisource.org",astwiki:"https://ast.wikipedia.org",astwiktionary:"https://ast.wiktionary.org",astwikibooks:"https://ast.wikibooks.org",astwikiquote:"https://ast.wikiquote.org",avwiki:"https://av.wikipedia.org",avwiktionary:"https://av.wiktionary.org",aywiki:"https://ay.wikipedia.org",aywiktionary:"https://ay.wiktionary.org",aywikibooks:"https://ay.wikibooks.org",azwiki:"https://az.wikipedia.org",azwiktionary:"https://az.wiktionary.org",azwikibooks:"https://az.wikibooks.org",azwikiquote:"https://az.wikiquote.org",azwikisource:"https://az.wikisource.org",bawiki:"https://ba.wikipedia.org",bawikibooks:"https://ba.wikibooks.org",barwiki:"https://bar.wikipedia.org",bat_smgwiki:"https://bat-smg.wikipedia.org",bclwiki:"https://bcl.wikipedia.org",bewiki:"https://be.wikipedia.org",bewiktionary:"https://be.wiktionary.org",bewikibooks:"https://be.wikibooks.org",bewikiquote:"https://be.wikiquote.org",bewikisource:"https://be.wikisource.org",be_x_oldwiki:"https://be-x-old.wikipedia.org",bgwiki:"https://bg.wikipedia.org",bgwiktionary:"https://bg.wiktionary.org",bgwikibooks:"https://bg.wikibooks.org",bgwikinews:"https://bg.wikinews.org",bgwikiquote:"https://bg.wikiquote.org",bgwikisource:"https://bg.wikisource.org",bhwiki:"https://bh.wikipedia.org",bhwiktionary:"https://bh.wiktionary.org",biwiki:"https://bi.wikipedia.org",biwiktionary:"https://bi.wiktionary.org",biwikibooks:"https://bi.wikibooks.org",bjnwiki:"https://bjn.wikipedia.org",bmwiki:"https://bm.wikipedia.org",bmwiktionary:"https://bm.wiktionary.org",bmwikibooks:"https://bm.wikibooks.org",bmwikiquote:"https://bm.wikiquote.org",bnwiki:"https://bn.wikipedia.org",bnwiktionary:"https://bn.wiktionary.org",bnwikibooks:"https://bn.wikibooks.org",bnwikisource:"https://bn.wikisource.org",bowiki:"https://bo.wikipedia.org",bowiktionary:"https://bo.wiktionary.org",bowikibooks:"https://bo.wikibooks.org",bpywiki:"https://bpy.wikipedia.org",brwiki:"https://br.wikipedia.org",brwiktionary:"https://br.wiktionary.org",brwikiquote:"https://br.wikiquote.org",brwikisource:"https://br.wikisource.org",bswiki:"https://bs.wikipedia.org",bswiktionary:"https://bs.wiktionary.org",bswikibooks:"https://bs.wikibooks.org",bswikinews:"https://bs.wikinews.org",bswikiquote:"https://bs.wikiquote.org",bswikisource:"https://bs.wikisource.org",bugwiki:"https://bug.wikipedia.org",bxrwiki:"https://bxr.wikipedia.org",cawiki:"https://ca.wikipedia.org",cawiktionary:"https://ca.wiktionary.org",cawikibooks:"https://ca.wikibooks.org",cawikinews:"https://ca.wikinews.org",cawikiquote:"https://ca.wikiquote.org",cawikisource:"https://ca.wikisource.org",cbk_zamwiki:"https://cbk-zam.wikipedia.org",cdowiki:"https://cdo.wikipedia.org",cewiki:"https://ce.wikipedia.org", +cebwiki:"https://ceb.wikipedia.org",chwiki:"https://ch.wikipedia.org",chwiktionary:"https://ch.wiktionary.org",chwikibooks:"https://ch.wikibooks.org",chowiki:"https://cho.wikipedia.org",chrwiki:"https://chr.wikipedia.org",chrwiktionary:"https://chr.wiktionary.org",chywiki:"https://chy.wikipedia.org",ckbwiki:"https://ckb.wikipedia.org",cowiki:"https://co.wikipedia.org",cowiktionary:"https://co.wiktionary.org",cowikibooks:"https://co.wikibooks.org",cowikiquote:"https://co.wikiquote.org",crwiki:"https://cr.wikipedia.org",crwiktionary:"https://cr.wiktionary.org",crwikiquote:"https://cr.wikiquote.org",crhwiki:"https://crh.wikipedia.org",cswiki:"https://cs.wikipedia.org",cswiktionary:"https://cs.wiktionary.org",cswikibooks:"https://cs.wikibooks.org",cswikinews:"https://cs.wikinews.org",cswikiquote:"https://cs.wikiquote.org",cswikisource:"https://cs.wikisource.org",cswikiversity:"https://cs.wikiversity.org",csbwiki:"https://csb.wikipedia.org",csbwiktionary:"https://csb.wiktionary.org",cuwiki:"https://cu.wikipedia.org",cvwiki:"https://cv.wikipedia.org",cvwikibooks:"https://cv.wikibooks.org",cywiki:"https://cy.wikipedia.org",cywiktionary:"https://cy.wiktionary.org",cywikibooks:"https://cy.wikibooks.org",cywikiquote:"https://cy.wikiquote.org",cywikisource:"https://cy.wikisource.org",dawiki:"https://da.wikipedia.org",dawiktionary:"https://da.wiktionary.org",dawikibooks:"https://da.wikibooks.org",dawikiquote:"https://da.wikiquote.org",dawikisource:"https://da.wikisource.org",dewiki:"https://de.wikipedia.org",dewiktionary:"https://de.wiktionary.org",dewikibooks:"https://de.wikibooks.org",dewikinews:"https://de.wikinews.org",dewikiquote:"https://de.wikiquote.org",dewikisource:"https://de.wikisource.org",dewikiversity:"https://de.wikiversity.org",dewikivoyage:"https://de.wikivoyage.org",diqwiki:"https://diq.wikipedia.org",dsbwiki:"https://dsb.wikipedia.org",dvwiki:"https://dv.wikipedia.org",dvwiktionary:"https://dv.wiktionary.org",dzwiki:"https://dz.wikipedia.org",dzwiktionary:"https://dz.wiktionary.org",eewiki:"https://ee.wikipedia.org",elwiki:"https://el.wikipedia.org",elwiktionary:"https://el.wiktionary.org",elwikibooks:"https://el.wikibooks.org",elwikinews:"https://el.wikinews.org",elwikiquote:"https://el.wikiquote.org",elwikisource:"https://el.wikisource.org",elwikiversity:"https://el.wikiversity.org",elwikivoyage:"https://el.wikivoyage.org",emlwiki:"https://eml.wikipedia.org",enwiki:"https://en.wikipedia.org",enwiktionary:"https://en.wiktionary.org",enwikibooks:"https://en.wikibooks.org",enwikinews:"https://en.wikinews.org",enwikiquote:"https://en.wikiquote.org",enwikisource:"https://en.wikisource.org",enwikiversity:"https://en.wikiversity.org",enwikivoyage:"https://en.wikivoyage.org",eowiki:"https://eo.wikipedia.org",eowiktionary:"https://eo.wiktionary.org",eowikibooks:"https://eo.wikibooks.org",eowikinews:"https://eo.wikinews.org",eowikiquote:"https://eo.wikiquote.org",eowikisource:"https://eo.wikisource.org",eswiki:"https://es.wikipedia.org",eswiktionary:"https://es.wiktionary.org",eswikibooks:"https://es.wikibooks.org",eswikinews:"https://es.wikinews.org",eswikiquote:"https://es.wikiquote.org",eswikisource:"https://es.wikisource.org",eswikiversity:"https://es.wikiversity.org",eswikivoyage:"https://es.wikivoyage.org",etwiki:"https://et.wikipedia.org",etwiktionary:"https://et.wiktionary.org",etwikibooks:"https://et.wikibooks.org",etwikiquote:"https://et.wikiquote.org",etwikisource:"https://et.wikisource.org",euwiki:"https://eu.wikipedia.org",euwiktionary:"https://eu.wiktionary.org",euwikibooks:"https://eu.wikibooks.org",euwikiquote:"https://eu.wikiquote.org",extwiki:"https://ext.wikipedia.org",fawiki:"https://fa.wikipedia.org",fawiktionary:"https://fa.wiktionary.org",fawikibooks:"https://fa.wikibooks.org",fawikinews:"https://fa.wikinews.org",fawikiquote:"https://fa.wikiquote.org",fawikisource:"https://fa.wikisource.org",fawikivoyage:"https://fa.wikivoyage.org",ffwiki:"https://ff.wikipedia.org",fiwiki:"https://fi.wikipedia.org",fiwiktionary:"https://fi.wiktionary.org",fiwikibooks:"https://fi.wikibooks.org",fiwikinews:"https://fi.wikinews.org",fiwikiquote:"https://fi.wikiquote.org",fiwikisource:"https://fi.wikisource.org",fiwikiversity:"https://fi.wikiversity.org",fiu_vrowiki:"https://fiu-vro.wikipedia.org",fjwiki:"https://fj.wikipedia.org",fjwiktionary:"https://fj.wiktionary.org",fowiki:"https://fo.wikipedia.org",fowiktionary:"https://fo.wiktionary.org",fowikisource:"https://fo.wikisource.org",frwiki:"https://fr.wikipedia.org",frwiktionary:"https://fr.wiktionary.org",frwikibooks:"https://fr.wikibooks.org",frwikinews:"https://fr.wikinews.org",frwikiquote:"https://fr.wikiquote.org",frwikisource:"https://fr.wikisource.org",frwikiversity:"https://fr.wikiversity.org",frwikivoyage:"https://fr.wikivoyage.org",frpwiki:"https://frp.wikipedia.org",frrwiki:"https://frr.wikipedia.org",furwiki:"https://fur.wikipedia.org",fywiki:"https://fy.wikipedia.org",fywiktionary:"https://fy.wiktionary.org",fywikibooks:"https://fy.wikibooks.org",gawiki:"https://ga.wikipedia.org",gawiktionary:"https://ga.wiktionary.org",gawikibooks:"https://ga.wikibooks.org",gawikiquote:"https://ga.wikiquote.org",gagwiki:"https://gag.wikipedia.org",ganwiki:"https://gan.wikipedia.org",gdwiki:"https://gd.wikipedia.org",gdwiktionary:"https://gd.wiktionary.org",glwiki:"https://gl.wikipedia.org",glwiktionary:"https://gl.wiktionary.org",glwikibooks:"https://gl.wikibooks.org",glwikiquote:"https://gl.wikiquote.org",glwikisource:"https://gl.wikisource.org",glkwiki:"https://glk.wikipedia.org",gnwiki:"https://gn.wikipedia.org",gnwiktionary:"https://gn.wiktionary.org",gnwikibooks:"https://gn.wikibooks.org",gotwiki:"https://got.wikipedia.org",gotwikibooks:"https://got.wikibooks.org",guwiki:"https://gu.wikipedia.org",guwiktionary:"https://gu.wiktionary.org",guwikibooks:"https://gu.wikibooks.org",guwikiquote:"https://gu.wikiquote.org",guwikisource:"https://gu.wikisource.org",gvwiki:"https://gv.wikipedia.org",gvwiktionary:"https://gv.wiktionary.org",hawiki:"https://ha.wikipedia.org",hawiktionary:"https://ha.wiktionary.org",hakwiki:"https://hak.wikipedia.org",hawwiki:"https://haw.wikipedia.org",hewiki:"https://he.wikipedia.org",hewiktionary:"https://he.wiktionary.org",hewikibooks:"https://he.wikibooks.org",hewikinews:"https://he.wikinews.org",hewikiquote:"https://he.wikiquote.org",hewikisource:"https://he.wikisource.org",hewikivoyage:"https://he.wikivoyage.org",hiwiki:"https://hi.wikipedia.org",hiwiktionary:"https://hi.wiktionary.org",hiwikibooks:"https://hi.wikibooks.org",hiwikiquote:"https://hi.wikiquote.org",hifwiki:"https://hif.wikipedia.org",howiki:"https://ho.wikipedia.org",hrwiki:"https://hr.wikipedia.org",hrwiktionary:"https://hr.wiktionary.org",hrwikibooks:"https://hr.wikibooks.org",hrwikiquote:"https://hr.wikiquote.org",hrwikisource:"https://hr.wikisource.org",hsbwiki:"https://hsb.wikipedia.org",hsbwiktionary:"https://hsb.wiktionary.org",htwiki:"https://ht.wikipedia.org",htwikisource:"https://ht.wikisource.org",huwiki:"https://hu.wikipedia.org",huwiktionary:"https://hu.wiktionary.org",huwikibooks:"https://hu.wikibooks.org",huwikinews:"https://hu.wikinews.org",huwikiquote:"https://hu.wikiquote.org",huwikisource:"https://hu.wikisource.org",hywiki:"https://hy.wikipedia.org",hywiktionary:"https://hy.wiktionary.org",hywikibooks:"https://hy.wikibooks.org",hywikiquote:"https://hy.wikiquote.org",hywikisource:"https://hy.wikisource.org",hzwiki:"https://hz.wikipedia.org",iawiki:"https://ia.wikipedia.org",iawiktionary:"https://ia.wiktionary.org",iawikibooks:"https://ia.wikibooks.org",idwiki:"https://id.wikipedia.org",idwiktionary:"https://id.wiktionary.org",idwikibooks:"https://id.wikibooks.org",idwikiquote:"https://id.wikiquote.org",idwikisource:"https://id.wikisource.org",iewiki:"https://ie.wikipedia.org",iewiktionary:"https://ie.wiktionary.org",iewikibooks:"https://ie.wikibooks.org",igwiki:"https://ig.wikipedia.org",iiwiki:"https://ii.wikipedia.org",ikwiki:"https://ik.wikipedia.org",ikwiktionary:"https://ik.wiktionary.org",ilowiki:"https://ilo.wikipedia.org",iowiki:"https://io.wikipedia.org",iowiktionary:"https://io.wiktionary.org",iswiki:"https://is.wikipedia.org",iswiktionary:"https://is.wiktionary.org",iswikibooks:"https://is.wikibooks.org",iswikiquote:"https://is.wikiquote.org",iswikisource:"https://is.wikisource.org",itwiki:"https://it.wikipedia.org",itwiktionary:"https://it.wiktionary.org",itwikibooks:"https://it.wikibooks.org",itwikinews:"https://it.wikinews.org",itwikiquote:"https://it.wikiquote.org",itwikisource:"https://it.wikisource.org",itwikiversity:"https://it.wikiversity.org",itwikivoyage:"https://it.wikivoyage.org",iuwiki:"https://iu.wikipedia.org",iuwiktionary:"https://iu.wiktionary.org",jawiki:"https://ja.wikipedia.org",jawiktionary:"https://ja.wiktionary.org",jawikibooks:"https://ja.wikibooks.org",jawikinews:"https://ja.wikinews.org",jawikiquote:"https://ja.wikiquote.org",jawikisource:"https://ja.wikisource.org",jawikiversity:"https://ja.wikiversity.org",jbowiki:"https://jbo.wikipedia.org",jbowiktionary:"https://jbo.wiktionary.org",jvwiki:"https://jv.wikipedia.org",jvwiktionary:"https://jv.wiktionary.org",kawiki:"https://ka.wikipedia.org",kawiktionary:"https://ka.wiktionary.org",kawikibooks:"https://ka.wikibooks.org",kawikiquote:"https://ka.wikiquote.org",kaawiki:"https://kaa.wikipedia.org",kabwiki:"https://kab.wikipedia.org",kbdwiki:"https://kbd.wikipedia.org",kgwiki:"https://kg.wikipedia.org",kiwiki:"https://ki.wikipedia.org",kjwiki:"https://kj.wikipedia.org",kkwiki:"https://kk.wikipedia.org",kkwiktionary:"https://kk.wiktionary.org",kkwikibooks:"https://kk.wikibooks.org",kkwikiquote:"https://kk.wikiquote.org",klwiki:"https://kl.wikipedia.org",klwiktionary:"https://kl.wiktionary.org",kmwiki:"https://km.wikipedia.org",kmwiktionary:"https://km.wiktionary.org",kmwikibooks:"https://km.wikibooks.org",knwiki:"https://kn.wikipedia.org",knwiktionary:"https://kn.wiktionary.org",knwikibooks:"https://kn.wikibooks.org",knwikiquote:"https://kn.wikiquote.org",knwikisource:"https://kn.wikisource.org",kowiki:"https://ko.wikipedia.org",kowiktionary:"https://ko.wiktionary.org",kowikibooks:"https://ko.wikibooks.org",kowikinews:"https://ko.wikinews.org",kowikiquote:"https://ko.wikiquote.org",kowikisource:"https://ko.wikisource.org",kowikiversity:"https://ko.wikiversity.org",koiwiki:"https://koi.wikipedia.org",krwiki:"https://kr.wikipedia.org",krwikiquote:"https://kr.wikiquote.org",krcwiki:"https://krc.wikipedia.org",kswiki:"https://ks.wikipedia.org",kswiktionary:"https://ks.wiktionary.org",kswikibooks:"https://ks.wikibooks.org",kswikiquote:"https://ks.wikiquote.org",kshwiki:"https://ksh.wikipedia.org",kuwiki:"https://ku.wikipedia.org",kuwiktionary:"https://ku.wiktionary.org",kuwikibooks:"https://ku.wikibooks.org",kuwikiquote:"https://ku.wikiquote.org",kvwiki:"https://kv.wikipedia.org",kwwiki:"https://kw.wikipedia.org",kwwiktionary:"https://kw.wiktionary.org",kwwikiquote:"https://kw.wikiquote.org",kywiki:"https://ky.wikipedia.org",kywiktionary:"https://ky.wiktionary.org",kywikibooks:"https://ky.wikibooks.org",kywikiquote:"https://ky.wikiquote.org",lawiki:"https://la.wikipedia.org",lawiktionary:"https://la.wiktionary.org",lawikibooks:"https://la.wikibooks.org",lawikiquote:"https://la.wikiquote.org",lawikisource:"https://la.wikisource.org",ladwiki:"https://lad.wikipedia.org",lbwiki:"https://lb.wikipedia.org",lbwiktionary:"https://lb.wiktionary.org",lbwikibooks:"https://lb.wikibooks.org",lbwikiquote:"https://lb.wikiquote.org",lbewiki:"https://lbe.wikipedia.org",lezwiki:"https://lez.wikipedia.org",lgwiki:"https://lg.wikipedia.org",liwiki:"https://li.wikipedia.org",liwiktionary:"https://li.wiktionary.org",liwikibooks:"https://li.wikibooks.org",liwikiquote:"https://li.wikiquote.org",liwikisource:"https://li.wikisource.org",lijwiki:"https://lij.wikipedia.org",lmowiki:"https://lmo.wikipedia.org",lnwiki:"https://ln.wikipedia.org",lnwiktionary:"https://ln.wiktionary.org",lnwikibooks:"https://ln.wikibooks.org",lowiki:"https://lo.wikipedia.org",lowiktionary:"https://lo.wiktionary.org",ltwiki:"https://lt.wikipedia.org",ltwiktionary:"https://lt.wiktionary.org",ltwikibooks:"https://lt.wikibooks.org",ltwikiquote:"https://lt.wikiquote.org",ltwikisource:"https://lt.wikisource.org",ltgwiki:"https://ltg.wikipedia.org",lvwiki:"https://lv.wikipedia.org",lvwiktionary:"https://lv.wiktionary.org",lvwikibooks:"https://lv.wikibooks.org",maiwiki:"https://mai.wikipedia.org",map_bmswiki:"https://map-bms.wikipedia.org",mdfwiki:"https://mdf.wikipedia.org",mgwiki:"https://mg.wikipedia.org",mgwiktionary:"https://mg.wiktionary.org",mgwikibooks:"https://mg.wikibooks.org",mhwiki:"https://mh.wikipedia.org",mhwiktionary:"https://mh.wiktionary.org",mhrwiki:"https://mhr.wikipedia.org",miwiki:"https://mi.wikipedia.org",miwiktionary:"https://mi.wiktionary.org",miwikibooks:"https://mi.wikibooks.org",minwiki:"https://min.wikipedia.org",mkwiki:"https://mk.wikipedia.org",mkwiktionary:"https://mk.wiktionary.org",mkwikibooks:"https://mk.wikibooks.org",mkwikisource:"https://mk.wikisource.org",mlwiki:"https://ml.wikipedia.org",mlwiktionary:"https://ml.wiktionary.org",mlwikibooks:"https://ml.wikibooks.org",mlwikiquote:"https://ml.wikiquote.org",mlwikisource:"https://ml.wikisource.org",mnwiki:"https://mn.wikipedia.org",mnwiktionary:"https://mn.wiktionary.org",mnwikibooks:"https://mn.wikibooks.org",mowiki:"https://mo.wikipedia.org",mowiktionary:"https://mo.wiktionary.org",mrwiki:"https://mr.wikipedia.org",mrwiktionary:"https://mr.wiktionary.org",mrwikibooks:"https://mr.wikibooks.org",mrwikiquote:"https://mr.wikiquote.org",mrwikisource:"https://mr.wikisource.org",mrjwiki:"https://mrj.wikipedia.org",mswiki:"https://ms.wikipedia.org",mswiktionary:"https://ms.wiktionary.org",mswikibooks:"https://ms.wikibooks.org",mtwiki:"https://mt.wikipedia.org",mtwiktionary:"https://mt.wiktionary.org",muswiki:"https://mus.wikipedia.org",mwlwiki:"https://mwl.wikipedia.org",mywiki:"https://my.wikipedia.org",mywiktionary:"https://my.wiktionary.org",mywikibooks:"https://my.wikibooks.org",myvwiki:"https://myv.wikipedia.org",mznwiki:"https://mzn.wikipedia.org",nawiki:"https://na.wikipedia.org",nawiktionary:"https://na.wiktionary.org",nawikibooks:"https://na.wikibooks.org",nawikiquote:"https://na.wikiquote.org",nahwiki:"https://nah.wikipedia.org",nahwiktionary:"https://nah.wiktionary.org",nahwikibooks:"https://nah.wikibooks.org",napwiki:"https://nap.wikipedia.org",ndswiki:"https://nds.wikipedia.org",ndswiktionary:"https://nds.wiktionary.org",ndswikibooks:"https://nds.wikibooks.org",ndswikiquote:"https://nds.wikiquote.org",nds_nlwiki:"https://nds-nl.wikipedia.org",newiki:"https://ne.wikipedia.org",newiktionary:"https://ne.wiktionary.org",newikibooks:"https://ne.wikibooks.org",newwiki:"https://new.wikipedia.org",ngwiki:"https://ng.wikipedia.org",nlwiki:"https://nl.wikipedia.org",nlwiktionary:"https://nl.wiktionary.org",nlwikibooks:"https://nl.wikibooks.org",nlwikinews:"https://nl.wikinews.org",nlwikiquote:"https://nl.wikiquote.org",nlwikisource:"https://nl.wikisource.org",nlwikivoyage:"https://nl.wikivoyage.org",nnwiki:"https://nn.wikipedia.org",nnwiktionary:"https://nn.wiktionary.org",nnwikiquote:"https://nn.wikiquote.org",nowiki:"https://no.wikipedia.org",nowiktionary:"https://no.wiktionary.org",nowikibooks:"https://no.wikibooks.org",nowikinews:"https://no.wikinews.org",nowikiquote:"https://no.wikiquote.org",nowikisource:"https://no.wikisource.org",novwiki:"https://nov.wikipedia.org",nrmwiki:"https://nrm.wikipedia.org",nsowiki:"https://nso.wikipedia.org",nvwiki:"https://nv.wikipedia.org",nywiki:"https://ny.wikipedia.org",ocwiki:"https://oc.wikipedia.org",ocwiktionary:"https://oc.wiktionary.org",ocwikibooks:"https://oc.wikibooks.org",omwiki:"https://om.wikipedia.org",omwiktionary:"https://om.wiktionary.org",orwiki:"https://or.wikipedia.org",orwiktionary:"https://or.wiktionary.org",orwikisource:"https://or.wikisource.org",oswiki:"https://os.wikipedia.org",pawiki:"https://pa.wikipedia.org",pawiktionary:"https://pa.wiktionary.org",pawikibooks:"https://pa.wikibooks.org",pagwiki:"https://pag.wikipedia.org",pamwiki:"https://pam.wikipedia.org",papwiki:"https://pap.wikipedia.org",pcdwiki:"https://pcd.wikipedia.org",pdcwiki:"https://pdc.wikipedia.org",pflwiki:"https://pfl.wikipedia.org",piwiki:"https://pi.wikipedia.org",piwiktionary:"https://pi.wiktionary.org",pihwiki:"https://pih.wikipedia.org",plwiki:"https://pl.wikipedia.org",plwiktionary:"https://pl.wiktionary.org",plwikibooks:"https://pl.wikibooks.org",plwikinews:"https://pl.wikinews.org",plwikiquote:"https://pl.wikiquote.org",plwikisource:"https://pl.wikisource.org",plwikivoyage:"https://pl.wikivoyage.org",pmswiki:"https://pms.wikipedia.org",pnbwiki:"https://pnb.wikipedia.org",pnbwiktionary:"https://pnb.wiktionary.org",pntwiki:"https://pnt.wikipedia.org",pswiki:"https://ps.wikipedia.org",pswiktionary:"https://ps.wiktionary.org",pswikibooks:"https://ps.wikibooks.org",ptwiki:"https://pt.wikipedia.org",ptwiktionary:"https://pt.wiktionary.org",ptwikibooks:"https://pt.wikibooks.org",ptwikinews:"https://pt.wikinews.org",ptwikiquote:"https://pt.wikiquote.org",ptwikisource:"https://pt.wikisource.org",ptwikiversity:"https://pt.wikiversity.org",ptwikivoyage:"https://pt.wikivoyage.org",quwiki:"https://qu.wikipedia.org",quwiktionary:"https://qu.wiktionary.org",quwikibooks:"https://qu.wikibooks.org",quwikiquote:"https://qu.wikiquote.org",rmwiki:"https://rm.wikipedia.org",rmwiktionary:"https://rm.wiktionary.org",rmwikibooks:"https://rm.wikibooks.org",rmywiki:"https://rmy.wikipedia.org",rnwiki:"https://rn.wikipedia.org",rnwiktionary:"https://rn.wiktionary.org",rowiki:"https://ro.wikipedia.org",rowiktionary:"https://ro.wiktionary.org",rowikibooks:"https://ro.wikibooks.org",rowikinews:"https://ro.wikinews.org",rowikiquote:"https://ro.wikiquote.org",rowikisource:"https://ro.wikisource.org",rowikivoyage:"https://ro.wikivoyage.org",roa_rupwiki:"https://roa-rup.wikipedia.org",roa_rupwiktionary:"https://roa-rup.wiktionary.org",roa_tarawiki:"https://roa-tara.wikipedia.org",ruwiki:"https://ru.wikipedia.org",ruwiktionary:"https://ru.wiktionary.org",ruwikibooks:"https://ru.wikibooks.org",ruwikinews:"https://ru.wikinews.org",ruwikiquote:"https://ru.wikiquote.org",ruwikisource:"https://ru.wikisource.org",ruwikiversity:"https://ru.wikiversity.org",ruwikivoyage:"https://ru.wikivoyage.org",ruewiki:"https://rue.wikipedia.org",rwwiki:"https://rw.wikipedia.org",rwwiktionary:"https://rw.wiktionary.org",sawiki:"https://sa.wikipedia.org",sawiktionary:"https://sa.wiktionary.org",sawikibooks:"https://sa.wikibooks.org",sawikiquote:"https://sa.wikiquote.org",sawikisource:"https://sa.wikisource.org",sahwiki:"https://sah.wikipedia.org",sahwikisource:"https://sah.wikisource.org",scwiki:"https://sc.wikipedia.org",scwiktionary:"https://sc.wiktionary.org",scnwiki:"https://scn.wikipedia.org",scnwiktionary:"https://scn.wiktionary.org",scowiki:"https://sco.wikipedia.org",sdwiki:"https://sd.wikipedia.org",sdwiktionary:"https://sd.wiktionary.org",sdwikinews:"https://sd.wikinews.org",sewiki:"https://se.wikipedia.org",sewikibooks:"https://se.wikibooks.org",sgwiki:"https://sg.wikipedia.org",sgwiktionary:"https://sg.wiktionary.org",shwiki:"https://sh.wikipedia.org",shwiktionary:"https://sh.wiktionary.org",siwiki:"https://si.wikipedia.org",siwiktionary:"https://si.wiktionary.org",siwikibooks:"https://si.wikibooks.org",simplewiki:"https://simple.wikipedia.org",simplewiktionary:"https://simple.wiktionary.org",simplewikibooks:"https://simple.wikibooks.org",simplewikiquote:"https://simple.wikiquote.org",skwiki:"https://sk.wikipedia.org",skwiktionary:"https://sk.wiktionary.org",skwikibooks:"https://sk.wikibooks.org",skwikiquote:"https://sk.wikiquote.org",skwikisource:"https://sk.wikisource.org",slwiki:"https://sl.wikipedia.org",slwiktionary:"https://sl.wiktionary.org",slwikibooks:"https://sl.wikibooks.org",slwikiquote:"https://sl.wikiquote.org",slwikisource:"https://sl.wikisource.org",slwikiversity:"https://sl.wikiversity.org",smwiki:"https://sm.wikipedia.org",smwiktionary:"https://sm.wiktionary.org",snwiki:"https://sn.wikipedia.org",snwiktionary:"https://sn.wiktionary.org",sowiki:"https://so.wikipedia.org",sowiktionary:"https://so.wiktionary.org",sqwiki:"https://sq.wikipedia.org",sqwiktionary:"https://sq.wiktionary.org",sqwikibooks:"https://sq.wikibooks.org",sqwikinews:"https://sq.wikinews.org",sqwikiquote:"https://sq.wikiquote.org",srwiki:"https://sr.wikipedia.org",srwiktionary:"https://sr.wiktionary.org",srwikibooks:"https://sr.wikibooks.org",srwikinews:"https://sr.wikinews.org",srwikiquote:"https://sr.wikiquote.org",srwikisource:"https://sr.wikisource.org",srnwiki:"https://srn.wikipedia.org",sswiki:"https://ss.wikipedia.org",sswiktionary:"https://ss.wiktionary.org",stwiki:"https://st.wikipedia.org",stwiktionary:"https://st.wiktionary.org",stqwiki:"https://stq.wikipedia.org",suwiki:"https://su.wikipedia.org",suwiktionary:"https://su.wiktionary.org",suwikibooks:"https://su.wikibooks.org",suwikiquote:"https://su.wikiquote.org",svwiki:"https://sv.wikipedia.org",svwiktionary:"https://sv.wiktionary.org",svwikibooks:"https://sv.wikibooks.org",svwikinews:"https://sv.wikinews.org",svwikiquote:"https://sv.wikiquote.org",svwikisource:"https://sv.wikisource.org",svwikiversity:"https://sv.wikiversity.org",svwikivoyage:"https://sv.wikivoyage.org",swwiki:"https://sw.wikipedia.org",swwiktionary:"https://sw.wiktionary.org",swwikibooks:"https://sw.wikibooks.org",szlwiki:"https://szl.wikipedia.org",tawiki:"https://ta.wikipedia.org",tawiktionary:"https://ta.wiktionary.org",tawikibooks:"https://ta.wikibooks.org",tawikinews:"https://ta.wikinews.org",tawikiquote:"https://ta.wikiquote.org",tawikisource:"https://ta.wikisource.org",tewiki:"https://te.wikipedia.org",tewiktionary:"https://te.wiktionary.org",tewikibooks:"https://te.wikibooks.org",tewikiquote:"https://te.wikiquote.org",tewikisource:"https://te.wikisource.org",tetwiki:"https://tet.wikipedia.org",tgwiki:"https://tg.wikipedia.org",tgwiktionary:"https://tg.wiktionary.org",tgwikibooks:"https://tg.wikibooks.org",thwiki:"https://th.wikipedia.org",thwiktionary:"https://th.wiktionary.org",thwikibooks:"https://th.wikibooks.org",thwikinews:"https://th.wikinews.org",thwikiquote:"https://th.wikiquote.org",thwikisource:"https://th.wikisource.org",tiwiki:"https://ti.wikipedia.org",tiwiktionary:"https://ti.wiktionary.org",tkwiki:"https://tk.wikipedia.org",tkwiktionary:"https://tk.wiktionary.org",tkwikibooks:"https://tk.wikibooks.org",tkwikiquote:"https://tk.wikiquote.org",tlwiki:"https://tl.wikipedia.org",tlwiktionary:"https://tl.wiktionary.org",tlwikibooks:"https://tl.wikibooks.org",tnwiki:"https://tn.wikipedia.org",tnwiktionary:"https://tn.wiktionary.org",towiki:"https://to.wikipedia.org",towiktionary:"https://to.wiktionary.org",tpiwiki:"https://tpi.wikipedia.org",tpiwiktionary:"https://tpi.wiktionary.org",trwiki:"https://tr.wikipedia.org",trwiktionary:"https://tr.wiktionary.org",trwikibooks:"https://tr.wikibooks.org",trwikinews:"https://tr.wikinews.org",trwikiquote:"https://tr.wikiquote.org",trwikisource:"https://tr.wikisource.org",tswiki:"https://ts.wikipedia.org",tswiktionary:"https://ts.wiktionary.org",ttwiki:"https://tt.wikipedia.org",ttwiktionary:"https://tt.wiktionary.org",ttwikibooks:"https://tt.wikibooks.org",ttwikiquote:"https://tt.wikiquote.org",tumwiki:"https://tum.wikipedia.org",twwiki:"https://tw.wikipedia.org",twwiktionary:"https://tw.wiktionary.org",tywiki:"https://ty.wikipedia.org",tyvwiki:"https://tyv.wikipedia.org",udmwiki:"https://udm.wikipedia.org",ugwiki:"https://ug.wikipedia.org",ugwiktionary:"https://ug.wiktionary.org",ugwikibooks:"https://ug.wikibooks.org",ugwikiquote:"https://ug.wikiquote.org",ukwiki:"https://uk.wikipedia.org",ukwiktionary:"https://uk.wiktionary.org",ukwikibooks:"https://uk.wikibooks.org",ukwikinews:"https://uk.wikinews.org",ukwikiquote:"https://uk.wikiquote.org",ukwikisource:"https://uk.wikisource.org",ukwikivoyage:"https://uk.wikivoyage.org",urwiki:"https://ur.wikipedia.org",urwiktionary:"https://ur.wiktionary.org",urwikibooks:"https://ur.wikibooks.org",urwikiquote:"https://ur.wikiquote.org",uzwiki:"https://uz.wikipedia.org",uzwiktionary:"https://uz.wiktionary.org",uzwikibooks:"https://uz.wikibooks.org",uzwikiquote:"https://uz.wikiquote.org",vewiki:"https://ve.wikipedia.org",vecwiki:"https://vec.wikipedia.org",vecwiktionary:"https://vec.wiktionary.org",vecwikisource:"https://vec.wikisource.org",vepwiki:"https://vep.wikipedia.org",viwiki:"https://vi.wikipedia.org",viwiktionary:"https://vi.wiktionary.org",viwikibooks:"https://vi.wikibooks.org",viwikiquote:"https://vi.wikiquote.org",viwikisource:"https://vi.wikisource.org",viwikivoyage:"https://vi.wikivoyage.org",vlswiki:"https://vls.wikipedia.org",vowiki:"https://vo.wikipedia.org",vowiktionary:"https://vo.wiktionary.org",vowikibooks:"https://vo.wikibooks.org",vowikiquote:"https://vo.wikiquote.org",wawiki:"https://wa.wikipedia.org",wawiktionary:"https://wa.wiktionary.org",wawikibooks:"https://wa.wikibooks.org",warwiki:"https://war.wikipedia.org",wowiki:"https://wo.wikipedia.org",wowiktionary:"https://wo.wiktionary.org",wowikiquote:"https://wo.wikiquote.org",wuuwiki:"https://wuu.wikipedia.org",xalwiki:"https://xal.wikipedia.org",xhwiki:"https://xh.wikipedia.org",xhwiktionary:"https://xh.wiktionary.org",xhwikibooks:"https://xh.wikibooks.org",xmfwiki:"https://xmf.wikipedia.org",yiwiki:"https://yi.wikipedia.org",yiwiktionary:"https://yi.wiktionary.org",yiwikisource:"https://yi.wikisource.org",yowiki:"https://yo.wikipedia.org",yowiktionary:"https://yo.wiktionary.org",yowikibooks:"https://yo.wikibooks.org",zawiki:"https://za.wikipedia.org",zawiktionary:"https://za.wiktionary.org",zawikibooks:"https://za.wikibooks.org",zawikiquote:"https://za.wikiquote.org",zeawiki:"https://zea.wikipedia.org",zhwiki:"https://zh.wikipedia.org",zhwiktionary:"https://zh.wiktionary.org",zhwikibooks:"https://zh.wikibooks.org",zhwikinews:"https://zh.wikinews.org",zhwikiquote:"https://zh.wikiquote.org",zhwikisource:"https://zh.wikisource.org",zhwikivoyage:"https://zh.wikivoyage.org",zh_classicalwiki:"https://zh-classical.wikipedia.org",zh_min_nanwiki:"https://zh-min-nan.wikipedia.org",zh_min_nanwiktionary:"https://zh-min-nan.wiktionary.org",zh_min_nanwikibooks:"https://zh-min-nan.wikibooks.org",zh_min_nanwikiquote:"https://zh-min-nan.wikiquote.org",zh_min_nanwikisource:"https://zh-min-nan.wikisource.org",zh_yuewiki:"https://zh-yue.wikipedia.org",zuwiki:"https://zu.wikipedia.org",zuwiktionary:"https://zu.wiktionary.org",zuwikibooks:"https://zu.wikibooks.org"};"undefined"!=typeof t&&t.exports&&(t.exports=o)},{}],14:[function(i,t,e){"use strict";var o=i("./lib/fetch_text"),r=i("./parse"),s=function(i,t,e){return"function"==typeof t&&(e=t,t="en"),e=e||function(){},t=t||"en",o?o(i,t,e):e(null)},n=function(i){var t=r(i)||{},e=Object.keys(t.sections).map(function(i){return t.sections[i].sentences.map(function(i){return i.text}).join(" ")});return e.join("\n\n")};t.exports={from_api:s,parse:r,plaintext:n}},{"./lib/fetch_text":15,"./parse":23}],15:[function(i,t,e){"use strict";var o=i("superagent"),r=i("../data/site_map"),s=i("../parse/page/redirects"),n=function i(t,e,n){e=e||"en";var a="titles";t.match(/^[0-9]*$/)&&t.length>3&&(a="curid");var l=void 0;l=r[e]?r[e]+"/w/api.php":"https://"+e+".wikipedia.org/w/api.php",l+="?action=query&prop=revisions&rvlimit=1&rvprop=content&format=json&origin=*",l+="&"+a+"="+encodeURIComponent(t),o.get(l).end(function(t,o){if(t)return console.warn(t),void n(null);var r=o.body.query.pages||{},a=Object.keys(r)[0];if(a){var l=r[a];if(l&&l.revisions&&l.revisions[0]){var h=l.revisions[0]["*"];if(s.is_redirect(h)){var k=s.parse_redirect(h);return void i(k.redirect,e,n)}n(h)}else n(null)}})};t.exports=n},{"../data/site_map":13,"../parse/page/redirects":28,superagent:3}],16:[function(i,t,e){"use strict";var o={capitalise:function(i){return i&&"string"==typeof i?i.charAt(0).toUpperCase()+i.slice(1):""},onlyUnique:function(i,t,e){return e.indexOf(i)===t},trim_whitespace:function(i){return i&&"string"==typeof i?(i=i.replace(/^\s\s*/,""),i=i.replace(/\s\s*$/,""),i=i.replace(/ {2}/," "),i=i.replace(/\s, /,", ")):""}};t.exports=o},{}],17:[function(i,t,e){"use strict";var o=i("jshashes"),r=function(i){var t=i.replace(/^(image|file?)\:/i,"");t=t.charAt(0).toUpperCase()+t.substring(1),t=t.replace(/ /g,"_");var e=(new o.MD5).hex(t),r=e.substr(0,1)+"/"+e.substr(0,2)+"/";t=encodeURIComponent(t),r+=t;var s="https://upload.wikimedia.org/wikipedia/commons/",n="/300px-"+t;return{url:s+r,file:i,thumb:s+"thumb/"+r+n}};t.exports=r},{jshashes:2}],18:[function(i,t,e){"use strict";var o=i("../data/abbreviations"),r=new RegExp("(^| )("+o.join("|")+")[.!?] ?$","i"),s=new RegExp("[ |.][A-Z].? +?$","i"),n=new RegExp("\\.\\.\\.* +?$"),a=function(i){var t=[];return i.forEach(function(i){t=t.concat(i)}),t},l=function(i){var t=i.split(/(\n+)/);return t=t.map(function(i){return i.split(/(\S.+?[.!?])(?=\s+|$)/g)}),a(t)},h=function(i){i=i||"";var t=i.split(/\[\[/)||[],e=i.split(/\]\]/)||[];if(t.length>e.length)return!1;var o=i.match(/"/g);return!(o&&o.length%2!==0&&i.length<900)},k=function(i){var t=[],e=[];if(!i||"string"!=typeof i||!i.match(/\w/))return t;for(var o=l(i),a=0;a0&&(t.push(e[p]),e[p]="");return 0===t.length?[i]:t};t.exports=k},{"../data/abbreviations":10}],19:[function(i,t,e){"use strict";var o=i("../data/i18n"),r=new RegExp("\\[\\[:?("+o.categories.join("|")+"):(.{2,60}?)]](w{0,10})","ig"),s=new RegExp("^\\[\\[:?("+o.categories.join("|")+"):","ig"),n=function(i,t){i.categories=[];var e=t.match(r);return e&&e.forEach(function(t){t=t.replace(s,""),t=t.replace(/\|?[ \*]?\]\]$/i,""),t=t.replace(/\|.*/,""),t&&!t.match(/[\[\]]/)&&i.categories.push(t)}),t};t.exports=n},{"../data/i18n":11}],20:[function(i,t,e){"use strict";var o=function(i){return i=i.replace(/ ?[\s\S]{0,750}?<\/ref> ?/gi," "),i=i.replace(/ ?]{0,200}?\/> ?/gi," "),i=i.replace(/ ?]{0,200}?>[\s\S]{0,500}?<\/ref> ?/gi," "),i=i.replace(/< ?(table|code|score|data|categorytree|charinsert|gallery|hiero|imagemap|inputbox|math|nowiki|poem|references|source|syntaxhighlight|timeline) ?[^>]{0,200}?>[\s\S]{0,700}< ?\/ ?(table|code|score|data|categorytree|charinsert|gallery|hiero|imagemap|inputbox|math|nowiki|poem|references|source|syntaxhighlight|timeline) ?>/gi," "),i=i.replace(/ ?< ?(ref|span|div|table|data) [a-z0-9=" ]{2,20}\/ ?> ?/g," "),i=i.replace(/ ?<[ \/]?(p|sub|sup|span|nowiki|div|table|br|tr|td|th|pre|pre2|hr)[ \/]?> ?/g," "),i=i.replace(/ ?<[ \/]?(abbr|bdi|bdo|blockquote|cite|del|dfn|em|i|ins|kbd|mark|q|s)[ \/]?> ?/g," "),i=i.replace(/ ?<[ \/]?h[0-9][ \/]?> ?/g," "),i=i.replace(/ ?<[ \/]?[a-z0-9]{1,8}[ \/]?> ?/g," "),i=i.replace(/ ?< ?br ?\/> ?/g," "),i.trim()};t.exports=o},{}],21:[function(i,t,e){"use strict";function o(i){return i=i.replace(//g,""),i=i.replace(/__(NOTOC|NOEDITSECTION|FORCETOC|TOC)__/gi,""),i=i.replace(/~~{1,3}/,""),i=i.replace(/--{1,3}/,""),i=i.replace(/ /g," "),i=i.replace(/\[\[([a-z][a-z]|simple|war|ceb|min):.{2,60}\]\]/i,""),i=i.replace(/''{4}([^']{0,200})''{4}/g,"$1"),i=i.replace(/''{2}([^']{0,200})''{2}/g,"$1"),i=i.replace(/''([^']{0,200})''/g,"$1"),i=r(i)}var r=i("./kill_xml");t.exports=o},{"./kill_xml":20}],22:[function(i,t,e){"use strict";var o=i("../../data/languages"),r=["January","February","March","April","May","June","July","August","September","October","November","December"],s=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],n=function(i){i=i.replace(/\{\{URL\|([^ ]{4,100}?)\}\}/gi,"$1"),i=i.replace(/\{\{convert\|([0-9]*?)\|([^\|]*?)\}\}/gi,"$1 $2");var t=new Date;if(i=i.replace(/\{\{(CURRENT|LOCAL)DAY(2)?\}\}/gi,t.getDate()),i=i.replace(/\{\{(CURRENT|LOCAL)MONTH(NAME|ABBREV)?\}\}/gi,r[t.getMonth()]), +i=i.replace(/\{\{(CURRENT|LOCAL)YEAR\}\}/gi,t.getFullYear()),i=i.replace(/\{\{(CURRENT|LOCAL)DAYNAME\}\}/gi,s[t.getDay()]),i=i.replace(/\{\{(lc|uc|formatnum):(.*?)\}\}/gi,"$2"),i=i.replace(/\{\{pull quote\|([\s\S]*?)(\|[\s\S]*?)?\}\}/gi,"$1"),i=i.replace(/\{\{cquote\|([\s\S]*?)(\|[\s\S]*?)?\}\}/gi,"$1"),i=i.replace(/\{\{(small|smaller|midsize|larger|big|bigger|large|huge|resize)\|([\s\S]*?)\}\}/gi,"$2"),i.match(/\{\{dts\|/)){var e=(i.match(/\{\{dts\|(.*?)[\}\|]/)||[])[1]||"";e=new Date(e),i=e&&e.getTime()?i.replace(/\{\{dts\|.*?\}\}/gi,e.toDateString()):i.replace(/\{\{dts\|.*?\}\}/gi," ")}if(i.match(/\{\{date\|.*?\}\}/)){var n=i.match(/\{\{date\|(.*?)\|(.*?)\|(.*?)\}\}/)||[]||[],a=n[1]+" "+n[2]+" "+n[3];i=i.replace(/\{\{date\|.*?\}\}/gi,a)}if(i=i.replace(/\{\{term\|(.*?)\|.*?\}\}/gi,"'$1'"),i=i.replace(/\{\{IPA\|(.*?)\|.*?\}\}/gi,"$1"),i=i.replace(/\{\{sense\|(.*?)\|?.*?\}\}/gi,"($1)"),i=i.replace(/\{\{t\+?\|...?\|(.*?)(\|.*)?\}\}/gi,"'$1'"),i.match(/\{\{etyl\|/)){var l=i.match(/\{\{etyl\|(.*?)\|.*?\}\}/i)[1]||"";l=l.toLowerCase(),i=l&&o[l]?i.replace(/\{\{etyl\|(.*?)\|.*?\}\}/gi,o[l].english_title):i.replace(/\{\{etyl\|(.*?)\|.*?\}\}/gi,"($1)")}return i};t.exports=n},{"../../data/languages":12}],23:[function(i,t,e){"use strict";var o=i("./page/redirects"),r=i("./page/disambig"),s=i("./cleanup/word_templates"),n=i("./cleanup/misc"),a=i("./table"),l=i("./categories"),h=i("./recursive"),k=i("./lines"),w=function(i){if(i=i||"",o.is_redirect(i))return o.parse_redirect(i);if(r.is_disambig(i))return r.parse_disambig(i);var t={type:"page",sections:{},categories:[],images:[],infobox:{},infobox_template:{},tables:[],translations:{}};return i=s(i),i=n(i),i=a(t,i),i=h(t,i),i=i.replace(/\{\{.*?\}\}/g,""),i=l(t,i),i=k(t,i),t};t.exports=w},{"./categories":19,"./cleanup/misc":21,"./cleanup/word_templates":22,"./lines":24,"./page/disambig":27,"./page/redirects":28,"./recursive":31,"./table":34}],24:[function(i,t,e){"use strict";var o=i("../../lib/helpers"),r=i("./lists"),s=i("./sentence"),n=/^(={1,5})([^=]{1,200}?)={1,5}$/,a=function(i){var t=i[2]||"";t=o.trim_whitespace(t);var e=1;return i[1]&&(e=i[1].length),{title:t,depth:e,sentences:[]}},l=function(i){for(var t=[a([])],e=0;e=0&&r.push(s[a]),0===n&&r.length>0){var l=r.filter(function(t){return t===i}),h=r.filter(function(i){return i===t});l.length>h.length&&r.push(t),o.push(r.join("")),r=[]}return o}t.exports=o},{}],30:[function(i,t,e){"use strict";var o=i("../../data/i18n"),r=i("../../lib/make_image"),s=new RegExp("("+o.images.concat(o.files).join("|")+"):.*?[\\|\\]]","i"),n=function(i){return i=i.match(s)||[""],i=i[0].replace(/[\|\]]$/,""),i=r(i)};t.exports=n},{"../../data/i18n":11,"../../lib/make_image":17}],31:[function(i,t,e){"use strict";var o=i("../../data/i18n"),r=i("../../data/languages"),s=i("./find"),n=i("./infobox"),a=i("./infobox_template"),l=i("./image"),h=new RegExp("{{("+o.infoboxes.join("|")+")[: \n]","ig"),k=new RegExp("\\[\\[("+o.images.concat(o.files).join("|")+")","i"),w=new RegExp("^("+o.images.concat(o.files).join("|")+")","i"),p=/^\{\{nowrap\|(.*?)\}\}$/,c=function(i,t){var e=s("{","}",t);if(e.forEach(function(e){if(e.match(h,"ig")&&0===Object.keys(i.infobox).length&&(i.infobox=n(e),i.infobox_template=a(e)),e.match(h)&&(t=t.replace(e,"")),e.match(/^\{\{/)){var o=e.match(p);if(o)return void(t=t.replace(e,o[1]));t=t.replace(e,"")}}),e=s("[","]",t),e.forEach(function(e){e.match(k)&&(i.images.push(l(e)),t=t.replace(e,""))}),e.forEach(function(e){if(null!==e.match(/\[\[([a-z][a-z]):(.*?)\]\]/i)){var o=e.match(/\[\[([a-z][a-z]):/i)[1];o&&r[o]&&(i.translations[o]=e.match(/\[\[([a-z][a-z]):(.*?)\]\]/i)[2]),t=t.replace(e,"")}}),i.infobox.image&&i.infobox.image.text){var o=i.infobox.image.text||"";"string"!=typeof o||o.match(w)||(o="File:"+o),i.images.push(o)}return t};t.exports=c},{"../../data/i18n":11,"../../data/languages":12,"./find":29,"./image":30,"./infobox":32,"./infobox_template":33}],32:[function(i,t,e){"use strict";var o=i("../../lib/helpers"),r=i("../text"),s=/\n *\|([^=]*)=(.*)/g,n=function(i){if(!i)return{};var t={},e=[],n=void 0;i=i.replace(/\{\{Collapsible list[^}]{10,1000}\}\}/g,"");for(var a=-2,l=0,h=i.length;l1&&(t=e[1])}return t}var r=i("../../data/i18n"),s=new RegExp("{{(?:"+r.infoboxes.join("|")+")\\s*(.*)","i");t.exports=o},{"../../data/i18n":11}],34:[function(i,t,e){"use strict";var o=i("../lib/helpers"),r=/\{\|[\s\S]{1,8000}?\|\}/g,s=function(i){var t=[],e=i.replace(/\r/g,"").split(/\n/);return e.forEach(function(i){if(!i.match(/^\|\}/)){if(i.match(/^\|-/))return void t.push([]);if(!i.match(/^\|\+/)&&i.match(/^[\!\|]/)){t[t.length-1]||(t[t.length-1]=[]);var e=(i.match(/\|(.*)/)||[])[1]||"";e=o.trim_whitespace(e)||"",e.match(/[!\|]{2}/)?e.split(/[!\|]{2}/g).forEach(function(i){i=o.trim_whitespace(i),t[t.length-1].push(i)}):t[t.length-1].push(e)}}}),t},n=function(i,t){return i.tables=t.match(r,"")||[],i.tables=i.tables.map(function(i){return s(i)}),t=t.replace(r,"")};t.exports=n},{"../lib/helpers":16}],35:[function(i,t,e){"use strict";function o(i){return i=h(i),i.match(/^(thumb|right|left)\|/i)?null:i=s.trim_whitespace(i)}function r(i){return{text:o(i),links:n(i)}}var s=i("../../lib/helpers"),n=i("./links"),a=i("../../data/i18n"),l=new RegExp("\\[\\[:?("+a.categories.join("|")+"):[^\\]\\]]{2,80}\\]\\]","gi"),h=function(i){return i=i.replace(l,""),i=i.replace(/\[\[:?([^|]{2,80}?)\]\](\w{0,5})/g,"$1$2"),i=i.replace(/\[\[File:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g,"$1"),i=i.replace(/\[\[:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g,"$2$3"),i=i.replace(/\[(https?|news|ftp|mailto|gopher|irc):\/\/[^\]\| ]{4,1500}([\| ].*?)?\]/g,"$2")};t.exports=r},{"../../data/i18n":11,"../../lib/helpers":16,"./links":36}],36:[function(i,t,e){"use strict";var o=i("../../lib/helpers"),r=/\[\[(.{2,80}?)\]\](\w{0,10})/g,s=/^:?(category|catégorie|Kategorie|Categoría|Categoria|Categorie|Kategoria|تصنيف|image|file|image|fichier|datei|media|special|wp|wikipedia|help|user|mediawiki|portal|talk|template|book|draft|module|topic|wiktionary|wikisource):/i,n=/\[(https?|news|ftp|mailto|gopher|irc)(:\/\/[^\]\| ]{4,1500})([\| ].*?)?\]/g,a=function(i,t){return t.replace(n,function(t,e,o){var r="",s=o.match(/\[([^\| ]+)/);return s&&s[1]&&(r=s[1]),i.push({type:"external",site:e+o,text:r}),r}),i},l=function(i,t){return t.replace(r,function(t,e){var r,n;if(e.match(/\|/)?(e=e.replace(/\[\[(.{2,80}?)\]\](\w{0,10})/g,"$1$2"),r=e.replace(/(.{2,60})\|.{0,200}/,"$1"),n=e.replace(/.{2,60}?\|/,""),!n&&r.match(/\|$/)&&(r=r.replace(/\|$/,""),n=r)):r=e.replace(/\[\[(.{2,60}?)\]\](\w{0,10})/g,"$1"),r.match(s))return e;if(r.match(/^#/i))return e;r=r.replace(/#[^ ]{1,100}/,"");var a={page:o.capitalise(r),text:n||r};return i.push(a),e}),i},h=function(i){var t=[];if(t=a(t,i),t=l(t,i),0!==t.length)return t};t.exports=h},{"../../lib/helpers":16}]},{},[14])(14)}); diff --git a/package.json b/package.json index 4c843f48..f0f62bd0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "wtf_wikipedia", "description": "parse wikiscript into json", - "version": "0.8.7", + "version": "1.0.0", "author": "Spencer Kelly (http://spencermounta.in)", "repository": { "type": "git", @@ -50,4 +50,4 @@ "shelljs": "^0.7.2" }, "license": "MIT" -} +} \ No newline at end of file From cfd3c2aeb2c81411fa1dd3cc09211096b399867e Mon Sep 17 00:00:00 2001 From: spencermountain Date: Wed, 14 Jun 2017 19:08:48 -0400 Subject: [PATCH 24/26] yolo --- README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ffff5bee..2ff0d5f7 100644 --- a/README.md +++ b/README.md @@ -55,15 +55,11 @@ m ok, lets write our own parser what culd go rong its a combination of [instaview](https://en.wikipedia.org/wiki/User:Pilaf/InstaView), [txtwiki](https://github.com/joaomsa/txtwiki.js), and uses the inter-language data from [Parsoid javascript parser](https://www.mediawiki.org/wiki/Parsoid). # Methods -## **.parse(markup, options)** +## **.parse(markup)** turns wikipedia markup into a nice json object -options is optional. The options supported are -* 'ignoreLists' which defaults to true. -* 'appendSectionLabelsWithParent' which defaults to false. When turned on, the parse function will not just use the header of a section as the key in the map, but if there is a parent header that has no text of itself, the key will be amended to reflect Parent Header Name : Section Name" - ```javascript -wtf_wikipedia.parse(someWikiScript, { ignoreLists: false, appendSectionLabelsWithParent: true }) +wtf_wikipedia.parse(someWikiScript) // {text:[...], infobox:{}, categories:[...], images:[] } ``` From 98e624997331e7eda3c20e2c093474faa4bced6a Mon Sep 17 00:00:00 2001 From: spencermountain Date: Thu, 22 Jun 2017 17:19:25 -0400 Subject: [PATCH 25/26] parse tables into objects for #56 --- scratch.js | 24 +- src/parse/table.js | 59 ++++- src/parse/text/index.js | 28 ++- tests/cache/bluejays.txt | 46 ++++ tests/cache/earthquakes.txt | 466 ++++++++++++++++++++++++++++++++++++ tests/table.test.js | 21 ++ tests/template.test.js | 65 ++--- 7 files changed, 654 insertions(+), 55 deletions(-) create mode 100644 tests/cache/bluejays.txt create mode 100644 tests/cache/earthquakes.txt create mode 100644 tests/table.test.js diff --git a/scratch.js b/scratch.js index 40e20e5e..039e67b9 100644 --- a/scratch.js +++ b/scratch.js @@ -1,5 +1,5 @@ -'use strict'; -const wtf = require('./src/index'); +"use strict"; +const wtf = require("./src/index"); // const wtf = require('./builds/wtf_wikipedia'); // const wtf = require('./build'); // let parse = wtf.parse; @@ -14,14 +14,16 @@ const wtf = require('./src/index'); // }); function from_file(page) { - let str = require('fs').readFileSync('./tests/cache/' + page.toLowerCase() + '.txt', 'utf-8'); + let str = require("fs").readFileSync("./tests/cache/" + page.toLowerCase() + ".txt", "utf-8"); // console.log(wtf.plaintext(str)); let r = wtf.parse(str, {}); - console.log(r.sections); + // console.log(r.tables); // console.log(JSON.stringify(r.sections, null, 2)); } // from_file("list") +// from_file("earthquakes"); +// from_file("bluejays"); // from_file("Toronto") // from_file('Toronto_Star'); // from_file('royal_cinema'); @@ -35,6 +37,16 @@ function from_file(page) { // console.log(obj); // }); -let str = `tony hawk [http://www.whistler.ca]`; +// let str = `tony hawk [http://www.whistler.ca]`; +let str = ` +{| border="1" cellpadding="2" cellspacing="0" class="wikitable" +|- +! bgcolor="#DDDDFF" width="4%" | # +|- align="center" bgcolor="ffbbbb" +| 1 || April 6 || @ [[Minnesota Twins|Twins]] || 6 - 1 || [[Brad Radke|Radke]] (1-0) || '''[[Pat Hentgen|Hentgen]]''' (0-1) || || 45,601 || 0-1 +|- align="center" bgcolor="bbffbb" +| 2 || April 7 || @ [[Minnesota Twins|Twins]] || 9 - 3 || '''[[David Wells|Wells]]''' (1-0) || [[Mike Lincoln|Lincoln]] (0-1) || '''[[Roy Halladay|Halladay]]''' (1) || 9,220 || 1-1 +|} +`; let doc = wtf.parse(str); -console.log(JSON.stringify(doc.sections, null, 2)); +console.log(JSON.stringify(doc.tables, null, 2)); diff --git a/src/parse/table.js b/src/parse/table.js index 6ae524b1..52c6acad 100644 --- a/src/parse/table.js +++ b/src/parse/table.js @@ -1,10 +1,38 @@ -const helpers = require('../lib/helpers'); +const helpers = require("../lib/helpers"); +const parse_line = require("./text"); + const table_reg = /\{\|[\s\S]{1,8000}?\|\}/g; +const parseHeading = function(str) { + str = str.replace(/^\! +/, ""); + if (str.match(/\|/)) { + str = str.replace(/.+\| ?/, ""); //class="unsortable"|title + } + str = parse_line(str).text; + return str; +}; + //turn a {|...table string into an array of arrays const parse_table = function(wiki) { let table = []; - const lines = wiki.replace(/\r/g, '').split(/\n/); + let headings = []; + const lines = wiki.replace(/\r/g, "").split(/\n/); + + //find headings first + for (let i = 0; i < lines.length; i++) { + let str = lines[i]; + //header + if (str.match(/^\!/)) { + str = parseHeading(str); + if (!str) { + str = "col-" + headings.length; + } + headings.push(str); + } else if (str.match(/^\| /)) { + break; + } + } + lines.forEach(function(str) { //die here if (str.match(/^\|\}/)) { @@ -19,14 +47,18 @@ const parse_table = function(wiki) { if (str.match(/^\|\+/)) { return; } + //header + if (str.match(/^\!/)) { + return; + } //juicy line - if (str.match(/^[\!\|]/)) { + if (str.match(/^\|/)) { //make a new row if (!table[table.length - 1]) { table[table.length - 1] = []; } - let want = (str.match(/\|(.*)/) || [])[1] || ''; - want = helpers.trim_whitespace(want) || ''; + let want = (str.match(/\|(.*)/) || [])[1] || ""; + want = helpers.trim_whitespace(want) || ""; //handle the || shorthand.. if (want.match(/[!\|]{2}/)) { want.split(/[!\|]{2}/g).forEach(function(s) { @@ -38,16 +70,29 @@ const parse_table = function(wiki) { } } }); + //remove top one, if it's empty + if (table[0] && Object.keys(table[0]).length === 0) { + table.shift(); + } + //index them by their header + table = table.map(arr => { + let obj = {}; + arr.forEach((a, i) => { + let head = headings[i] || "col-" + i; + obj[head] = parse_line(a); + }); + return obj; + }); return table; }; const findTables = function(r, wiki) { - r.tables = wiki.match(table_reg, '') || []; + r.tables = wiki.match(table_reg, "") || []; r.tables = r.tables.map(function(str) { return parse_table(str); }); //remove tables - wiki = wiki.replace(table_reg, ''); + wiki = wiki.replace(table_reg, ""); return wiki; }; module.exports = findTables; diff --git a/src/parse/text/index.js b/src/parse/text/index.js index a4be6052..ac694040 100644 --- a/src/parse/text/index.js +++ b/src/parse/text/index.js @@ -1,20 +1,20 @@ -const helpers = require('../../lib/helpers'); -const parse_links = require('./links'); -const i18n = require('../../data/i18n'); -const cat_reg = new RegExp('\\[\\[:?(' + i18n.categories.join('|') + '):[^\\]\\]]{2,80}\\]\\]', 'gi'); +const helpers = require("../../lib/helpers"); +const parse_links = require("./links"); +const i18n = require("../../data/i18n"); +const cat_reg = new RegExp("\\[\\[:?(" + i18n.categories.join("|") + "):[^\\]\\]]{2,80}\\]\\]", "gi"); //return only rendered text of wiki links const resolve_links = function(line) { // categories, images, files - line = line.replace(cat_reg, ''); + line = line.replace(cat_reg, ""); // [[Common links]] - line = line.replace(/\[\[:?([^|]{2,80}?)\]\](\w{0,5})/g, '$1$2'); + line = line.replace(/\[\[:?([^|]{2,80}?)\]\](\w{0,5})/g, "$1$2"); // [[File:with|Size]] - line = line.replace(/\[\[File:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g, '$1'); + line = line.replace(/\[\[File:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g, "$1"); // [[Replaced|Links]] - line = line.replace(/\[\[:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g, '$2$3'); + line = line.replace(/\[\[:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g, "$2$3"); // External links - line = line.replace(/\[(https?|news|ftp|mailto|gopher|irc):\/\/[^\]\| ]{4,1500}([\| ].*?)?\]/g, '$2'); + line = line.replace(/\[(https?|news|ftp|mailto|gopher|irc):\/\/[^\]\| ]{4,1500}([\| ].*?)?\]/g, "$2"); return line; }; // console.log(resolve_links("[http://www.whistler.ca www.whistler.ca]")) @@ -31,10 +31,14 @@ function postprocess(line) { } function parse_line(line) { - return { - text: postprocess(line), - links: parse_links(line) + let obj = { + text: postprocess(line) }; + let links = parse_links(line); + if (links) { + obj.links = links; + } + return obj; } module.exports = parse_line; diff --git a/tests/cache/bluejays.txt b/tests/cache/bluejays.txt new file mode 100644 index 00000000..08c3a566 --- /dev/null +++ b/tests/cache/bluejays.txt @@ -0,0 +1,46 @@ +{| class="wikitable" +|- +! style="text-align:center; {{Baseball primary style|Toronto Blue Jays|border=2}};"|Level +! style="text-align:center; {{Baseball primary style|Toronto Blue Jays|border=2}};"|Team +! style="text-align:center; {{Baseball primary style|Toronto Blue Jays|border=2}};"|League +! style="text-align:center; {{Baseball primary style|Toronto Blue Jays|border=2}};"|Location +|- +| ''AAA'' +| [[Buffalo Bisons]] +| [[International League]] +| [[Buffalo, New York|Buffalo]], New York{{cite web|url=http://buffalonews.com/apps/pbcs.dll/article?AID=/20120917/SPORTS/120919102/1003|title=Herd signs with Blue Jays for two years|last=Harrington|first=Mike|date=17 September 2012|work=[[The Buffalo News]]|accessdate=18 September 2012}} +|- +| ''AA'' +| [[New Hampshire Fisher Cats]] +| [[Eastern League (baseball)|Eastern League]] +| [[Manchester, New Hampshire|Manchester]], New Hampshire +|- +| ''Advanced A'' +| [[Dunedin Blue Jays]] +| [[Florida State League]] +| [[Dunedin, Florida|Dunedin]], Florida +|- +| ''A'' +| [[Lansing Lugnuts]] +| [[Midwest League]] +| [[Lansing, Michigan|Lansing]], Michigan +|- +|''Short Season A'' +| [[Vancouver Canadians]] +| [[Northwest League]] +| [[Vancouver]], British Columbia +|- +|''Rookie-Advanced'' +| [[Bluefield Blue Jays]] +| [[Appalachian League]] +| [[Bluefield micropolitan area|Bluefield]], Virginia/West Virginia +|- +|rowspan=2|''Rookie'' +| [[Gulf Coast League Blue Jays|GCL Blue Jays]] +| [[Gulf Coast League]] +| Dunedin, Florida +|- +| [[Dominican Summer League Blue Jays|DSL Blue Jays]] +| [[Dominican Summer League]] +| [[San Pedro de Macorís]], [[Dominican Republic]] +|} diff --git a/tests/cache/earthquakes.txt b/tests/cache/earthquakes.txt new file mode 100644 index 00000000..2f80b27f --- /dev/null +++ b/tests/cache/earthquakes.txt @@ -0,0 +1,466 @@ +This is a list of '''earthquakes in Canada''': + +== List == +{{Expand list|date=March 2016}} +{| class="wikitable sortable" style="text-align: center;" +|- bgcolor="#ececec" +! Date +! Time‡ +! Place +! [[Latitude|Lat]] +! [[Longitude|Lon]] +! Deaths +! [[Moment magnitude scale|''M'']] +! +! ''I'' +! class="unsortable"|Comments +! class="unsortable"| +|- +| [[1663 Charlevoix earthquake|1663-02-05]] +| 17:30 (local time) +| [[Charlevoix]]–[[Kamouraska, Quebec|Kamouraska]] Region, [[Quebec|QC]] +| 47.60 +| -70.10 +| +| 7.0 +| [[moment magnitude scale|Mw]] +| [[Mercalli intensity scale|X]] +| +| {{cite web|url=http://earthquakescanada.nrcan.gc.ca/historic-historique/map-carte-eng.php|title=Important Canadian Earthquakes|last=Natural Resources Canada|work=Earthquakes Canada|accessdate=2 December 2011}} +|- +| [[1700 Cascadia earthquake|1700-01-26]] +| 21:00 (local time) +| [[Pacific Northwest]] +| 48.50 +| -125.00 +| +| 8.7–9.2 +| Mw +| +| This earthquake was linked to the "orphan tsunami" in Japan +| +|- +| [[1732 Montreal earthquake|1732-09-16]] +| 11:00 (local time) +| [[Montreal]], QC +| 45.50 +| -73.60 +| +| 5.8 +| Mw +| +| +| +|- +| 1791-12-06 +| 20:00 (local time) +| Charlevoix +| 47.4 +| -70.5 +| +| 6.0 +| +| +| +| +|- +| 1860-10-17 +| 06:15 (local time) +| Charlevoix, QC +| 47.5 +| -70.1 +| +| 6.0 +| +| +| +| +|- +| 1870-10-20 +| 11:30 (local time) +| Charlevoix, QC +| 47.4 +| -70.5 +| +| 6.5 +| +| +| +| +|- +| [[1872 North Cascades earthquake|1872-12-15]] +| 05:37 +| Washington State +| 47.76 +| -119.90 +| +| 6.5–7.0 +| Mw +| [[Mercalli intensity scale|VIII]] +| +| +|- +| 1899-09-04 +| 00:22 +| Yukon–Alaska border +| 60.00 +| -140.00 +| +| 8.2 +| Ms +| +| +| +|- +| [[1918 Vancouver Island earthquake|1918-12-06]] +| 08:41:08 +| [[Vancouver Island]], BC +| 49.44 +| -126.22 +| +| 7.2 +| Mw +| [[Mercalli intensity scale|VIII]] +| +| +|- +| [[1925 Charlevoix–Kamouraska earthquake|1925-03-01]] +| 02:19:20 +| Charlevoix–Kamouraska, QC +| 47.8 +| -69.8 +| +| 6.2 +| Mw +| [[Mercalli intensity scale|VIII]] +| +| +|- +| 1929-05-26 +| 22:39:54 +| South of [[Haida Gwaii|Queen Charlotte Islands]], BC +| 51.51 +| -130.74 +| +| 7.0 +| Mw +| +| +| +|- +| [[1929 Grand Banks earthquake|1929-11-18]] +| 20:32 +| [[Grand Banks of Newfoundland]] +| 44.5 +| -56.30 +| 28 +| 7.2 +| Mw +| [[Rossi–Forel scale|VI]] +| Triggered a major underwater slump that caused a large tsunami, which devastated some coastal communities on Newfoundland +| +|- +| [[1933 Baffin Bay earthquake|1933-11-20]] +| 23:21:32 +| [[Baffin Bay]] +| 73.0 +| -70.75 +| +| 7.3–7.4 +| Mw +| +| Largest known earthquake north of the [[Arctic Circle]] +| +|- +| [[1935 Timiskaming earthquake|1935-11-01]] +| 06:03:40 +| Timiskaming +| 46.78 +| 79.07 +| +| 6.1 +| Mw +| [[Mercalli intensity scale|VII]] +| +| +|- +| [[1944 Cornwall–Massena earthquake|1944-09-05]] +| 04:38:45 +| [[Cornwall, Ontario|Cornwall]], ON/[[Massena, New York|Massena]], NY +| 44.97 +| -74.90 +| +| 5.8 +| Mw +| [[Mercalli intensity scale|VII]] +| +| +|- +| [[1946 Vancouver Island earthquake|1946-06-23]] +| 17:13:26 +| Vancouver Island, BC +| 49.76 +| -125.34 +| 2 +| 7.3 +| Ms +| [[Mercalli intensity scale|VIII]] +| +| +|- +| [[1949 Queen Charlotte Islands earthquake|1949-08-22]] +| 04:01:12 +| Queen Charlotte Islands, BC +| 53.62 +| -133.27 +| +| 8.1 +| Mw +| [[Mercalli intensity scale|VIII]] +| +| +|- +| [[1958 Lituya Bay megatsunami|1958-07-09]] +| 06:15 +| Lituya Bay, Alaska +| 58.6 +| -137.10 +| 5 +| 8.3 +| Mw +| [[Mercalli intensity scale|XI]] +| Triggered a rockfall that caused a tsunami with a runup of {{convert|524|m}} +| +|- +| 1970-06-24 +| 13:09:08 +| Queen Charlotte Islands, BC +| 51.77 +| -130.76 +| +| 7.4 +| Mw +| +| +| +|- +| 1979-02-28 +| 13:27 (local time) +| Southern Yukon–Alaska Border +| 60.59 +| -141.47 +| +| 7.2 +| Mw +| +| +| +|- +| 1982-01-09 +| 08:53 +| [[Miramichi, New Brunswick|Miramichi]], NB +| 47.00 +| -66.60 +| +| 5.7 +| +| +| A pair of earthquakes, two days apart +| +|- +| [[1985 Nahanni earthquakes|1985-12-23]] +| 23:16 (local time) +| The Nahanni region +| 62.19 +| -124.24 +| +| 6.9 +| Mw +| +| The strongest of a sequence of major earthquakes +| +|- +| [[1988 Saguenay earthquake|1988-11-25]] +| 23:46:04 +| Saguenay +| 48.12 +| -71.18 +| +| 5.9 +| Mw +| [[Mercalli intensity scale|VII]] +| +| +|- +| [[1989 Ungava earthquake|1989-12-25]] +| 14:24 +| Ungava Region +| 60.12 +| -73.60 +| +| 6.3 +| Ms +| +| This was the first earthquake in eastern North America confirmed to have produced surface faulting +| +|- +| [[1997 Cap-Rouge earthquake|1997-11-05]] +| 02:34:33 +| Quebec City, QC
+| 46.80 +| -71.42 +| 1 +| 5.1 +| Mn +| +| +| +|- +| [[2000 Kipawa earthquake|2000-01-01]] +| 11:22:58 +| Temiscamingue Region +| 46.84 +| -78.93 +| +| 5.2 +| Mn +| [[Mercalli intensity scale|VI]] +| +| +|- +| [[2001 Nisqually earthquake|2001-02-28]] +| 18:54:32 +| [[Puget Sound]] +| 47.15 +| -122.71 +| 1 (USA) +| 6.8 +| Mw +| +| +| {{cite web|url=http://www.earthquakescanada.nrcan.gc.ca/stndon/NEDB-BNDS/bull-en.php?time_start=1990%2F01%2F01+00%3A00%3A00&time_end=2011%2F12%2F31+24%3A00%3A00&depth_min=0&depth_max=100&mag_min=3.4&mag_max=10.0&shape_type=region&radius_center_lat=50&radius_center_lon=-95&radius_radius=1000®ion_north=90®ion_south=41®ion_east=-40®ion_west=-150&eq_type_L=1&display_list=1&list_sort=date&list_order=a&tpl_output=html&submited=1|title=Search results for earthquakes M>3.4, 1990-2011|last=Natural Resources Canada|work=Search the Earthquake Database|accessdate=8 November 2016}} +|- +| 2004-11-02 +| 10:02:11 +| Vancouver Island, BC +| 49.15 +| -129.00 +| +| 6.6 +| Mw +| +| +| +|- +| [[2007–2008 Nazko earthquakes|2007-10-09]] +| +| The [[Nazko]] region +| 52.88 +| -124.8 +| +| 4.0 (or less) +| +| [[Mercalli intensity scale|I]] +| The first of a [[earthquake swarm|swarm of earthquakes]] that went on until 12 June 2008 +| +|- +| 2008-01-05 +| 11:01:01 +| Queen Charlotte Islands, BC +| 51.07 +| -131.06 +| +| 6.5 +| Mw +| +| Followed by a magnitude 6.4 earthquake just over 40 minutes later +| +|- +| 2009-11-17 +| 15:30:41 +| Queen Charlotte Islands, BC +| 51.82 +| -131.78 +| +| 6.5 +| Mw +| +| +| +|- +| [[2010 Central Canada earthquake|2010-06-23]] +| 13:41:41 EDT +| Central Canada +| 45.9 +| -75.5 +| +| 5.0 +| Mw +| [[Mercalli intensity scale|VI]] +| +| +|- +| 2011-09-09 +| 19:31:34 +| [[Vancouver Island]] +| 49.49 +| -126.97 +| +| 6.4 +| Mw +| +| This earthquake, which lasted 20–30 seconds, was the strongest to hit the region in nearly 7 years. It occurred on a [[Earthquake#Earthquake fault types|secondary strike-slip]] structure and not on the plate boundary itself +| {{cite news|last=Mann|first=Ted|title=Vancouver Looks to New Zealand to Prepare for Quakes|url=http://www.theatlanticwire.com/global/2011/09/vancouver-looks-new-zealand-prepare-quakes/42324/|accessdate=18 September 2011|newspaper=The Atlantic Wire|date=10 September 2011}} +|- +|2012-08-19 +| +|279 km WSW of [[Tofino]], BC (offshore) +| +| +| +| 5.2 +| +| +| +| +|- +| [[2012 Haida Gwaii earthquake|2012-10-27]] +|20:04 (local time) +| [[Haida Gwaii]] +| +| +| +|7.7 +| +| [[Mercalli intensity scale|V]] +| +| +|- +|} + +Abbreviations used: + +* Mw [[Moment magnitude scale]] +* ML [[Richter magnitude scale]] +* Ms [[Surface wave magnitude]] scale +* Mn Nuttli magnitude scale—a version of the Richter scale specifically for use in eastern North America{{cite web|url=http://earthquakescanada.nrcan.gc.ca/info-gen/faq-eng.php#ml_and_mn|title=Frequently Asked Questions about Earthquakes (FAQ)|last=Natural Resources Canada|date=12 August 2011|accessdate=3 December 2011}} + +==See also== +*[[Hydraulic fracturing in Canada]] + +==References== +{{Reflist| +http://www.earthquakescanada.nrcan.gc.ca/recent/index-eng.php/ +http://www.earthquakescanada.nrcan.gc.ca/index-eng.php +}} + +==External links== +*Natural Resources Canada [http://www.earthquakescanada.nrcan.gc.ca/index-eng.php Earthquakes Canada] +*Earthquakes Canada [http://www.earthquakescanada.nrcan.gc.ca/recent/index-eng.php/ Recent earthquakes] + +{{DEFAULTSORT:List Of Earthquakes In Canada}} +[[Category:Earthquakes in Canada| ]] +[[Category:Canada geography-related lists|Earthquakes]] +[[Category:Lists of earthquakes by country|Canada]] +[[Category:Canada history-related lists|disasters]] +[[Category:Lists of disasters in Canada]] diff --git a/tests/table.test.js b/tests/table.test.js new file mode 100644 index 00000000..aa3f4351 --- /dev/null +++ b/tests/table.test.js @@ -0,0 +1,21 @@ +"use strict"; +var test = require("tape"); +var path = require("path"); +var fs = require("fs"); +const wtf = require("../src/index"); + +//read cached file +var fetch = function(file) { + return fs.readFileSync(path.join(__dirname, "cache", file + ".txt"), "utf-8"); +}; + +test("big table", t => { + var bluejays = fetch("bluejays"); + let arr = wtf.parse(bluejays).tables[0]; + t.equal(arr.length, 8); + t.equal(arr[0]["Level"].text, "AAA", "level-col"); + t.equal(arr[0]["Team"].text, "Buffalo Bisons", "team-col"); + t.equal(arr[0]["League"].text, "International League", "league-col"); + t.equal(arr[1]["Location"].text, "Manchester, New Hampshire", "location-col"); + t.end(); +}); diff --git a/tests/template.test.js b/tests/template.test.js index 8c276fb7..a802d4af 100644 --- a/tests/template.test.js +++ b/tests/template.test.js @@ -1,6 +1,6 @@ -'use strict'; -var wtf = require('../src/'); -var test = require('tape'); +"use strict"; +var wtf = require("../src/"); +var test = require("tape"); let boloZenden = `{{Infobox football biography | name = Boudewijn Zenden @@ -29,16 +29,16 @@ let boloZenden = `{{Infobox football biography | manageryears2 = 2013– |managerclubs2 = [[Jong PSV]] (assistant manager) }}`; -test('boloZenden infobox', function(t) { +test("boloZenden infobox", function(t) { let o = wtf.parse(boloZenden).infobox; - t.equal(o.years1.text, '1993–1998'); - t.equal(o.clubs1.text, 'PSV'); - t.equal(o.youthyears1.text, '1985–1987'); - t.equal(o.youthclubs1.text, 'MVV'); - t.equal(o.nationalyears1.text, '1997–2004'); - t.equal(o.nationalteam1.text, 'Netherlands'); - t.equal(o.nationalteam1.links[0].page, 'Netherlands national football team'); - t.equal(o.nationalteam1.links[0].text, 'Netherlands'); + t.equal(o.years1.text, "1993–1998"); + t.equal(o.clubs1.text, "PSV"); + t.equal(o.youthyears1.text, "1985–1987"); + t.equal(o.youthclubs1.text, "MVV"); + t.equal(o.nationalyears1.text, "1997–2004"); + t.equal(o.nationalteam1.text, "Netherlands"); + t.equal(o.nationalteam1.links[0].page, "Netherlands national football team"); + t.equal(o.nationalteam1.links[0].text, "Netherlands"); t.equal(o.nationalcaps1.text, 54); t.equal(o.nationalgoals1.text, 7); t.end(); @@ -61,12 +61,12 @@ let hurricane = `{{Infobox Hurricane | Areas=[[Florida]] | Hurricane season=[[2002 Atlantic hurricane season]] }}`; -test('hurricane infobox', function(t) { +test("hurricane infobox", function(t) { let o = wtf.parse(hurricane).infobox; - t.equal(o.Name.text, 'Tropical Storm Edouard'); - t.equal(o.Dissipated.text, 'September 6, 2002'); - t.equal(o['Hurricane season'].text, '2002 Atlantic hurricane season'); - t.equal(o.Areas.links[0].page, 'Florida'); + t.equal(o.Name.text, "Tropical Storm Edouard"); + t.equal(o.Dissipated.text, "September 6, 2002"); + t.equal(o["Hurricane season"].text, "2002 Atlantic hurricane season"); + t.equal(o.Areas.links[0].page, "Florida"); t.end(); }); @@ -85,30 +85,35 @@ let park_place = ` * [[Park Place Mall]], Lethbridge, Alberta {{disambiguation}} `; -test('parkplace disambig', function(t) { +test("parkplace disambig", function(t) { let o = wtf.parse(park_place); - t.equal(o.type, 'disambiguation'); + t.equal(o.type, "disambiguation"); t.equal(o.pages.length, 4); - t.equal(o.pages[0], 'Park Place (TV series)'); + t.equal(o.pages[0], "Park Place (TV series)"); t.end(); }); let bluejays = ` {| border="1" cellpadding="2" cellspacing="0" class="wikitable" |- -! bgcolor="#DDDDFF" width="4%" | # +! bgcolor="#DDDDFF" width="4%" | Number +! bgcolor="#D12DFF" width="4%" | Date +! bgcolor="#D12DFF" width="4%" | Team |- align="center" bgcolor="ffbbbb" | 1 || April 6 || @ [[Minnesota Twins|Twins]] || 6 - 1 || [[Brad Radke|Radke]] (1-0) || '''[[Pat Hentgen|Hentgen]]''' (0-1) || || 45,601 || 0-1 |- align="center" bgcolor="bbffbb" | 2 || April 7 || @ [[Minnesota Twins|Twins]] || 9 - 3 || '''[[David Wells|Wells]]''' (1-0) || [[Mike Lincoln|Lincoln]] (0-1) || '''[[Roy Halladay|Halladay]]''' (1) || 9,220 || 1-1 |} `; -test('bluejays table', function(t) { +test("bluejays table", function(t) { let arr = wtf.parse(bluejays).tables[0]; - t.equal(arr.length, 3); - t.equal(arr[0][0], '#'); - t.equal(arr[1][0], '1'); - t.equal(arr[1][1], 'April 6'); + t.equal(arr.length, 2); + t.equal(arr[0]["Number"].text, "1"); + t.equal(arr[0]["Date"].text, "April 6"); + t.equal(arr[0]["Team"].text, "@ Twins"); + t.equal(arr[1]["Number"].text, "2"); + t.equal(arr[1]["Date"].text, "April 7"); + t.equal(arr[1]["col-3"].text, "9 - 3"); t.end(); }); @@ -141,11 +146,11 @@ let alabama = ` | logo = [[File:University of Alabama (logo).png|250px]] }} `; -test('Alabama infobox', function(t) { +test("Alabama infobox", function(t) { let infobox = wtf.parse(alabama).infobox; - t.equal(infobox.athletics.text, 'NCAA Division I – SEC', 'athletics =' + infobox.athletics.text); - t.equal(infobox.country.text, 'U.S.', 'country =' + infobox.country.text); - t.equal(infobox.president.text, 'Stuart R. Bell', 'president =' + infobox.president.text); + t.equal(infobox.athletics.text, "NCAA Division I – SEC", "athletics =" + infobox.athletics.text); + t.equal(infobox.country.text, "U.S.", "country =" + infobox.country.text); + t.equal(infobox.president.text, "Stuart R. Bell", "president =" + infobox.president.text); // t.equal(infobox.campus.text, 'Urban (small city); 1970 acre', 'campus = ' + infobox.campus.text); t.end(); }); From c5d1593f2259c738ce57d2e106916afd59cbb64e Mon Sep 17 00:00:00 2001 From: spencermountain Date: Thu, 22 Jun 2017 17:20:16 -0400 Subject: [PATCH 26/26] v1.0.0 --- builds/wtf_wikipedia.js | 93 ++++++++++++++++++++++++++++--------- builds/wtf_wikipedia.min.js | 4 +- 2 files changed, 73 insertions(+), 24 deletions(-) diff --git a/builds/wtf_wikipedia.js b/builds/wtf_wikipedia.js index 60af84df..6212f844 100644 --- a/builds/wtf_wikipedia.js +++ b/builds/wtf_wikipedia.js @@ -6743,15 +6743,43 @@ function parse_infobox_template(str) { module.exports = parse_infobox_template; },{"../../data/i18n":11}],34:[function(_dereq_,module,exports){ -'use strict'; +"use strict"; + +var helpers = _dereq_("../lib/helpers"); +var parse_line = _dereq_("./text"); -var helpers = _dereq_('../lib/helpers'); var table_reg = /\{\|[\s\S]{1,8000}?\|\}/g; +var parseHeading = function parseHeading(str) { + str = str.replace(/^\! +/, ""); + if (str.match(/\|/)) { + str = str.replace(/.+\| ?/, ""); //class="unsortable"|title + } + str = parse_line(str).text; + return str; +}; + //turn a {|...table string into an array of arrays var parse_table = function parse_table(wiki) { var table = []; - var lines = wiki.replace(/\r/g, '').split(/\n/); + var headings = []; + var lines = wiki.replace(/\r/g, "").split(/\n/); + + //find headings first + for (var i = 0; i < lines.length; i++) { + var str = lines[i]; + //header + if (str.match(/^\!/)) { + str = parseHeading(str); + if (!str) { + str = "col-" + headings.length; + } + headings.push(str); + } else if (str.match(/^\| /)) { + break; + } + } + lines.forEach(function (str) { //die here if (str.match(/^\|\}/)) { @@ -6766,14 +6794,18 @@ var parse_table = function parse_table(wiki) { if (str.match(/^\|\+/)) { return; } + //header + if (str.match(/^\!/)) { + return; + } //juicy line - if (str.match(/^[\!\|]/)) { + if (str.match(/^\|/)) { //make a new row if (!table[table.length - 1]) { table[table.length - 1] = []; } - var want = (str.match(/\|(.*)/) || [])[1] || ''; - want = helpers.trim_whitespace(want) || ''; + var want = (str.match(/\|(.*)/) || [])[1] || ""; + want = helpers.trim_whitespace(want) || ""; //handle the || shorthand.. if (want.match(/[!\|]{2}/)) { want.split(/[!\|]{2}/g).forEach(function (s) { @@ -6785,40 +6817,53 @@ var parse_table = function parse_table(wiki) { } } }); + //remove top one, if it's empty + if (table[0] && Object.keys(table[0]).length === 0) { + table.shift(); + } + //index them by their header + table = table.map(function (arr) { + var obj = {}; + arr.forEach(function (a, i) { + var head = headings[i] || "col-" + i; + obj[head] = parse_line(a); + }); + return obj; + }); return table; }; var findTables = function findTables(r, wiki) { - r.tables = wiki.match(table_reg, '') || []; + r.tables = wiki.match(table_reg, "") || []; r.tables = r.tables.map(function (str) { return parse_table(str); }); //remove tables - wiki = wiki.replace(table_reg, ''); + wiki = wiki.replace(table_reg, ""); return wiki; }; module.exports = findTables; -},{"../lib/helpers":16}],35:[function(_dereq_,module,exports){ -'use strict'; +},{"../lib/helpers":16,"./text":35}],35:[function(_dereq_,module,exports){ +"use strict"; -var helpers = _dereq_('../../lib/helpers'); -var parse_links = _dereq_('./links'); -var i18n = _dereq_('../../data/i18n'); -var cat_reg = new RegExp('\\[\\[:?(' + i18n.categories.join('|') + '):[^\\]\\]]{2,80}\\]\\]', 'gi'); +var helpers = _dereq_("../../lib/helpers"); +var parse_links = _dereq_("./links"); +var i18n = _dereq_("../../data/i18n"); +var cat_reg = new RegExp("\\[\\[:?(" + i18n.categories.join("|") + "):[^\\]\\]]{2,80}\\]\\]", "gi"); //return only rendered text of wiki links var resolve_links = function resolve_links(line) { // categories, images, files - line = line.replace(cat_reg, ''); + line = line.replace(cat_reg, ""); // [[Common links]] - line = line.replace(/\[\[:?([^|]{2,80}?)\]\](\w{0,5})/g, '$1$2'); + line = line.replace(/\[\[:?([^|]{2,80}?)\]\](\w{0,5})/g, "$1$2"); // [[File:with|Size]] - line = line.replace(/\[\[File:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g, '$1'); + line = line.replace(/\[\[File:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g, "$1"); // [[Replaced|Links]] - line = line.replace(/\[\[:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g, '$2$3'); + line = line.replace(/\[\[:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g, "$2$3"); // External links - line = line.replace(/\[(https?|news|ftp|mailto|gopher|irc):\/\/[^\]\| ]{4,1500}([\| ].*?)?\]/g, '$2'); + line = line.replace(/\[(https?|news|ftp|mailto|gopher|irc):\/\/[^\]\| ]{4,1500}([\| ].*?)?\]/g, "$2"); return line; }; // console.log(resolve_links("[http://www.whistler.ca www.whistler.ca]")) @@ -6835,10 +6880,14 @@ function postprocess(line) { } function parse_line(line) { - return { - text: postprocess(line), - links: parse_links(line) + var obj = { + text: postprocess(line) }; + var links = parse_links(line); + if (links) { + obj.links = links; + } + return obj; } module.exports = parse_line; diff --git a/builds/wtf_wikipedia.min.js b/builds/wtf_wikipedia.min.js index 6b6d2fa3..44f1bd4f 100644 --- a/builds/wtf_wikipedia.min.js +++ b/builds/wtf_wikipedia.min.js @@ -2,7 +2,7 @@ github.com/spencermountain/wtf_wikipedia MIT */ -!function(i){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=i();else if("function"==typeof define&&define.amd)define([],i);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.wtf_wikipedia=i()}}(function(){var i;return function i(t,e,o){function r(n,a){if(!e[n]){if(!t[n]){var l="function"==typeof require&&require;if(!a&&l)return l(n,!0);if(s)return s(n,!0);var h=new Error("Cannot find module '"+n+"'");throw h.code="MODULE_NOT_FOUND",h}var k=e[n]={exports:{}};t[n][0].call(k.exports,function(i){var e=t[n][1][i];return r(e?e:i)},k,k.exports,i,t,e,o)}return e[n].exports}for(var s="function"==typeof require&&require,n=0;n>>6&31,128|63&t):t<=65535?r+=String.fromCharCode(224|t>>>12&15,128|t>>>6&63,128|63&t):t<=2097151&&(r+=String.fromCharCode(240|t>>>18&7,128|t>>>12&63,128|t>>>6&63,128|63&t));return r}function s(i){var t,e,o,r,s,n,a=[];if(t=e=o=r=s=0,i&&i.length)for(n=i.length,i+="";t191&&o<224?(r=i.charCodeAt(t+1),a[e]=String.fromCharCode((31&o)<<6|63&r),t+=2):(r=i.charCodeAt(t+1),s=i.charCodeAt(t+2),a[e]=String.fromCharCode((15&o)<<12|(63&r)<<6|63&s),t+=3);return a.join("")}function n(i,t){var e=(65535&i)+(65535&t),o=(i>>16)+(t>>16)+(e>>16);return o<<16|65535&e}function a(i,t){return i<>>32-t}function l(i,t){for(var e,o=t?"0123456789ABCDEF":"0123456789abcdef",r="",s=0,n=i.length;s>>4&15)+o.charAt(15&e);return r}function h(i){var t,e=32*i.length,o="";for(t=0;t>5]>>>24-t%32&255);return o}function k(i){var t,e=32*i.length,o="";for(t=0;t>5]>>>t%32&255);return o}function w(i){var t,e=8*i.length,o=Array(i.length>>2),r=o.length;for(t=0;t>5]|=(255&i.charCodeAt(t/8))<>2),r=o.length;for(t=0;t>5]|=(255&i.charCodeAt(t/8))<<24-t%32;return o}function c(i,t){var e,o,r,s,n,a,l,h,k=t.length,w=Array();for(a=Array(Math.ceil(i.length/2)),s=a.length,e=0;e0;){for(n=Array(),r=0,e=0;e0||o>0)&&(n[n.length]=o);w[w.length]=r,a=n}for(l="",e=w.length-1;e>=0;e--)l+=t.charAt(w[e]);for(h=Math.ceil(8*i.length/(Math.log(t.length)/Math.log(2))),e=l.length;e8*i.length?t:s.charAt(r>>>6*(3-o)&63);return n}var u;u={VERSION:"1.0.6",Base64:function(){var i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",t="=",e=!0;this.encode=function(o){var s,n,a,l="",h=o.length;for(t=t||"=",o=e?r(o):o,s=0;s8*h?t:i.charAt(a>>>6*(3-n)&63);return l},this.decode=function(o){var r,n,a,l,h,k,w,p,c,g,u="",d=[];if(!o)return o;r=g=0,o=o.replace(new RegExp("\\"+t,"gi"),"");do h=i.indexOf(o.charAt(r+=1)),k=i.indexOf(o.charAt(r+=1)),w=i.indexOf(o.charAt(r+=1)),p=i.indexOf(o.charAt(r+=1)),c=h<<18|k<<12|w<<6|p,n=c>>16&255,a=c>>8&255,l=255&c,g+=1,64===w?d[g]=String.fromCharCode(n):64===p?d[g]=String.fromCharCode(n,a):d[g]=String.fromCharCode(n,a,l);while(r>>8^n;return(s^-1)>>>0},MD5:function(i){function t(i){return i=_?r(i):i,k(o(w(i),8*i.length))}function e(i,t){var e,s,n,a,l;for(i=_?r(i):i,t=_?r(t):t,e=w(i),e.length>16&&(e=o(e,8*i.length)),s=Array(16),n=Array(16),l=0;l<16;l+=1)s[l]=909522486^e[l],n[l]=1549556828^e[l];return a=o(s.concat(w(t)),512+8*t.length),k(o(n.concat(a),640))}function o(i,t){var e,o,r,s,a,l=1732584193,k=-271733879,w=-1732584194,c=271733878;for(i[t>>5]|=128<>>9<<4)+14]=t,e=0;e16&&(e=o(e,8*i.length)),s=Array(16),n=Array(16),a=0;a<16;a+=1)s[a]=909522486^e[a],n[a]=1549556828^e[a];return l=o(s.concat(p(t)),512+8*t.length),h(o(n.concat(l),672))}function o(i,t){var e,o,r,l,h,w,p,c,g=Array(80),u=1732584193,d=-271733879,f=-1732584194,y=271733878,_=-1009589776;for(i[t>>5]|=128<<24-t%32,i[(t+64>>9<<4)+15]=t,e=0;e16&&(s=y(s,8*i.length));o<16;o+=1)n[o]=909522486^s[o],a[o]=1549556828^s[o];return e=y(n.concat(p(t)),512+8*t.length),h(y(a.concat(e),768))}function o(i,t){return i>>>t|i<<32-t}function s(i,t){return i>>>t}function a(i,t,e){return i&t^~i&e}function k(i,t,e){return i&t^i&e^t&e}function w(i){return o(i,2)^o(i,13)^o(i,22)}function u(i){return o(i,6)^o(i,11)^o(i,25)}function d(i){return o(i,7)^o(i,18)^s(i,3)}function f(i){return o(i,17)^o(i,19)^s(i,10)}function y(i,t){var e,o,r,s,l,h,p,c,g,y,b,m,v=[1779033703,-1150833019,1013904242,-1521486534,1359893119,-1694144372,528734635,1541459225],C=new Array(64);for(i[t>>5]|=128<<24-t%32,i[(t+64>>9<<4)+15]=t,g=0;g32&&(n=o(n,8*i.length));s<32;s+=1)a[s]=909522486^n[s],l[s]=1549556828^n[s];return e=o(a.concat(p(t)),1024+8*t.length),h(o(l.concat(e),1536))}function o(i,t){var e,o,r,l=new Array(80),h=new Array(16),p=[new s(1779033703,(-205731576)),new s((-1150833019),(-2067093701)),new s(1013904242,(-23791573)),new s((-1521486534),1595750129),new s(1359893119,(-1377402159)),new s((-1694144372),725511199),new s(528734635,(-79577749)),new s(1541459225,327033209)],c=new s(0,0),g=new s(0,0),_=new s(0,0),b=new s(0,0),m=new s(0,0),v=new s(0,0),C=new s(0,0),q=new s(0,0),A=new s(0,0),D=new s(0,0),B=new s(0,0),x=new s(0,0),E=new s(0,0),F=new s(0,0),z=new s(0,0),j=new s(0,0),T=new s(0,0);for(void 0===y&&(y=[new s(1116352408,(-685199838)),new s(1899447441,602891725),new s((-1245643825),(-330482897)),new s((-373957723),(-2121671748)),new s(961987163,(-213338824)),new s(1508970993,(-1241133031)),new s((-1841331548),(-1357295717)),new s((-1424204075),(-630357736)),new s((-670586216),(-1560083902)),new s(310598401,1164996542),new s(607225278,1323610764),new s(1426881987,(-704662302)),new s(1925078388,(-226784913)),new s((-2132889090),991336113),new s((-1680079193),633803317),new s((-1046744716),(-815192428)),new s((-459576895),(-1628353838)),new s((-272742522),944711139),new s(264347078,(-1953704523)),new s(604807628,2007800933),new s(770255983,1495990901),new s(1249150122,1856431235),new s(1555081692,(-1119749164)),new s(1996064986,(-2096016459)),new s((-1740746414),(-295247957)),new s((-1473132947),766784016),new s((-1341970488),(-1728372417)),new s((-1084653625),(-1091629340)),new s((-958395405),1034457026),new s((-710438585),(-1828018395)),new s(113926993,(-536640913)),new s(338241895,168717936),new s(666307205,1188179964),new s(773529912,1546045734),new s(1294757372,1522805485),new s(1396182291,(-1651133473)),new s(1695183700,(-1951439906)),new s(1986661051,1014477480),new s((-2117940946),1206759142),new s((-1838011259),344077627),new s((-1564481375),1290863460),new s((-1474664885),(-1136513023)),new s((-1035236496),(-789014639)),new s((-949202525),106217008),new s((-778901479),(-688958952)),new s((-694614492),1432725776),new s((-200395387),1467031594),new s(275423344,851169720),new s(430227734,(-1194143544)),new s(506948616,1363258195),new s(659060556,(-544281703)),new s(883997877,(-509917016)),new s(958139571,(-976659869)),new s(1322822218,(-482243893)),new s(1537002063,2003034995),new s(1747873779,(-692930397)),new s(1955562222,1575990012),new s(2024104815,1125592928),new s((-2067236844),(-1578062990)),new s((-1933114872),442776044),new s((-1866530822),593698344),new s((-1538233109),(-561857047)),new s((-1090935817),(-1295615723)),new s((-965641998),(-479046869)),new s((-903397682),(-366583396)),new s((-779700025),566280711),new s((-354779690),(-840897762)),new s((-176337025),(-294727304)),new s(116418474,1914138554),new s(174292421,(-1563912026)),new s(289380356,(-1090974290)),new s(460393269,320620315),new s(685471733,587496836),new s(852142971,1086792851),new s(1017036298,365543100),new s(1126000580,(-1676669620)),new s(1288033470,(-885112138)),new s(1501505948,(-60457430)),new s(1607167915,987167468),new s(1816402316,1246189591)]),o=0;o<80;o+=1)l[o]=new s(0,0);for(i[t>>5]|=128<<24-(31&t),i[(t+128>>10<<5)+31]=t,r=i.length,o=0;o>>e|t.h<<32-e,i.h=t.h>>>e|t.l<<32-e}function k(i,t,e){i.l=t.h>>>e|t.l<<32-e,i.h=t.l>>>e|t.h<<32-e}function w(i,t,e){i.l=t.l>>>e|t.h<<32-e,i.h=t.h>>>e}function u(i,t,e){var o=(65535&t.l)+(65535&e.l),r=(t.l>>>16)+(e.l>>>16)+(o>>>16),s=(65535&t.h)+(65535&e.h)+(r>>>16),n=(t.h>>>16)+(e.h>>>16)+(s>>>16);i.l=65535&o|r<<16,i.h=65535&s|n<<16}function d(i,t,e,o,r){var s=(65535&t.l)+(65535&e.l)+(65535&o.l)+(65535&r.l),n=(t.l>>>16)+(e.l>>>16)+(o.l>>>16)+(r.l>>>16)+(s>>>16),a=(65535&t.h)+(65535&e.h)+(65535&o.h)+(65535&r.h)+(n>>>16),l=(t.h>>>16)+(e.h>>>16)+(o.h>>>16)+(r.h>>>16)+(a>>>16);i.l=65535&s|n<<16,i.h=65535&a|l<<16}function f(i,t,e,o,r,s){var n=(65535&t.l)+(65535&e.l)+(65535&o.l)+(65535&r.l)+(65535&s.l),a=(t.l>>>16)+(e.l>>>16)+(o.l>>>16)+(r.l>>>16)+(s.l>>>16)+(n>>>16),l=(65535&t.h)+(65535&e.h)+(65535&o.h)+(65535&r.h)+(65535&s.h)+(a>>>16),h=(t.h>>>16)+(e.h>>>16)+(o.h>>>16)+(r.h>>>16)+(s.h>>>16)+(l>>>16);i.l=65535&n|a<<16,i.h=65535&l|h<<16}var y,_=!(!i||"boolean"!=typeof i.uppercase)&&i.uppercase,b=i&&"string"==typeof i.pad?i.pad:"=",m=!i||"boolean"!=typeof i.utf8||i.utf8;this.hex=function(i){return l(t(i))},this.b64=function(i){return g(t(i),b)},this.any=function(i,e){return c(t(i),e)},this.raw=function(i){return t(i,m)},this.hex_hmac=function(i,t){return l(e(i,t))},this.b64_hmac=function(i,t){return g(e(i,t),b)},this.any_hmac=function(i,t,o){return c(e(i,t),o)},this.vm_test=function(){return"900150983cd24fb0d6963f7d28e17f72"===hex("abc").toLowerCase()},this.setUpperCase=function(i){return"boolean"==typeof i&&(_=i),this},this.setPad=function(i){return b=i||b,this},this.setUTF8=function(i){return"boolean"==typeof i&&(m=i),this}},RMD160:function(i){function t(i){return i=f?r(i):i,o(s(w(i),8*i.length))}function e(i,t){i=f?r(i):i,t=f?r(t):t;var e,n,a=w(i),l=Array(16),h=Array(16);for(a.length>16&&(a=s(a,8*i.length)),e=0;e<16;e+=1)l[e]=909522486^a[e],h[e]=1549556828^a[e];return n=s(l.concat(w(t)),512+8*t.length),o(s(h.concat(n),672))}function o(i){var t,e="",o=32*i.length;for(t=0;t>5]>>>t%32&255);return e}function s(i,t){var e,o,r,s,l,w,c,g,u,d,f,v,C,q,A=1732584193,D=4023233417,B=2562383102,x=271733878,E=3285377520;for(i[t>>5]|=128<>>9<<4)+14]=t,s=i.length,r=0;r=0?"&":"?")+i),this._sort){var t=this.url.indexOf("?");if(t>=0){var e=this.url.substring(t+1).split("&");d(this._sort)?e.sort(this._sort):e.sort(),this.url=this.url.substring(0,t)+"?"+e.join("&")}}},k.prototype._isHost=function(i){return i&&"object"==typeof i&&!Array.isArray(i)&&"[object Object]"!==Object.prototype.toString.call(i)},k.prototype.end=function(i){return this._endCalled&&console.warn("Warning: .end() was called twice. This is not supported in superagent"),this._endCalled=!0,this._callback=i||o,this._appendQueryString(),this._end()},k.prototype._end=function(){var i=this,t=this.xhr=_.getXHR(),e=this._formData||this._data;this._setTimeouts(),t.onreadystatechange=function(){var e=t.readyState;if(e>=2&&i._responseTimeoutTimer&&clearTimeout(i._responseTimeoutTimer),4==e){var o;try{o=t.status}catch(i){o=0}if(!o){if(i.timedout||i._aborted)return;return i.crossDomainError()}i.emit("end")}};var o=function(t,e){e.total>0&&(e.percent=e.loaded/e.total*100),e.direction=t,i.emit("progress",e)};if(this.hasListeners("progress"))try{ +!function(i){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=i();else if("function"==typeof define&&define.amd)define([],i);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.wtf_wikipedia=i()}}(function(){var i;return function i(t,e,o){function r(n,a){if(!e[n]){if(!t[n]){var l="function"==typeof require&&require;if(!a&&l)return l(n,!0);if(s)return s(n,!0);var h=new Error("Cannot find module '"+n+"'");throw h.code="MODULE_NOT_FOUND",h}var k=e[n]={exports:{}};t[n][0].call(k.exports,function(i){var e=t[n][1][i];return r(e?e:i)},k,k.exports,i,t,e,o)}return e[n].exports}for(var s="function"==typeof require&&require,n=0;n>>6&31,128|63&t):t<=65535?r+=String.fromCharCode(224|t>>>12&15,128|t>>>6&63,128|63&t):t<=2097151&&(r+=String.fromCharCode(240|t>>>18&7,128|t>>>12&63,128|t>>>6&63,128|63&t));return r}function s(i){var t,e,o,r,s,n,a=[];if(t=e=o=r=s=0,i&&i.length)for(n=i.length,i+="";t191&&o<224?(r=i.charCodeAt(t+1),a[e]=String.fromCharCode((31&o)<<6|63&r),t+=2):(r=i.charCodeAt(t+1),s=i.charCodeAt(t+2),a[e]=String.fromCharCode((15&o)<<12|(63&r)<<6|63&s),t+=3);return a.join("")}function n(i,t){var e=(65535&i)+(65535&t),o=(i>>16)+(t>>16)+(e>>16);return o<<16|65535&e}function a(i,t){return i<>>32-t}function l(i,t){for(var e,o=t?"0123456789ABCDEF":"0123456789abcdef",r="",s=0,n=i.length;s>>4&15)+o.charAt(15&e);return r}function h(i){var t,e=32*i.length,o="";for(t=0;t>5]>>>24-t%32&255);return o}function k(i){var t,e=32*i.length,o="";for(t=0;t>5]>>>t%32&255);return o}function w(i){var t,e=8*i.length,o=Array(i.length>>2),r=o.length;for(t=0;t>5]|=(255&i.charCodeAt(t/8))<>2),r=o.length;for(t=0;t>5]|=(255&i.charCodeAt(t/8))<<24-t%32;return o}function c(i,t){var e,o,r,s,n,a,l,h,k=t.length,w=Array();for(a=Array(Math.ceil(i.length/2)),s=a.length,e=0;e0;){for(n=Array(),r=0,e=0;e0||o>0)&&(n[n.length]=o);w[w.length]=r,a=n}for(l="",e=w.length-1;e>=0;e--)l+=t.charAt(w[e]);for(h=Math.ceil(8*i.length/(Math.log(t.length)/Math.log(2))),e=l.length;e8*i.length?t:s.charAt(r>>>6*(3-o)&63);return n}var u;u={VERSION:"1.0.6",Base64:function(){var i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",t="=",e=!0;this.encode=function(o){var s,n,a,l="",h=o.length;for(t=t||"=",o=e?r(o):o,s=0;s8*h?t:i.charAt(a>>>6*(3-n)&63);return l},this.decode=function(o){var r,n,a,l,h,k,w,p,c,g,u="",d=[];if(!o)return o;r=g=0,o=o.replace(new RegExp("\\"+t,"gi"),"");do h=i.indexOf(o.charAt(r+=1)),k=i.indexOf(o.charAt(r+=1)),w=i.indexOf(o.charAt(r+=1)),p=i.indexOf(o.charAt(r+=1)),c=h<<18|k<<12|w<<6|p,n=c>>16&255,a=c>>8&255,l=255&c,g+=1,64===w?d[g]=String.fromCharCode(n):64===p?d[g]=String.fromCharCode(n,a):d[g]=String.fromCharCode(n,a,l);while(r>>8^n;return(s^-1)>>>0},MD5:function(i){function t(i){return i=_?r(i):i,k(o(w(i),8*i.length))}function e(i,t){var e,s,n,a,l;for(i=_?r(i):i,t=_?r(t):t,e=w(i),e.length>16&&(e=o(e,8*i.length)),s=Array(16),n=Array(16),l=0;l<16;l+=1)s[l]=909522486^e[l],n[l]=1549556828^e[l];return a=o(s.concat(w(t)),512+8*t.length),k(o(n.concat(a),640))}function o(i,t){var e,o,r,s,a,l=1732584193,k=-271733879,w=-1732584194,c=271733878;for(i[t>>5]|=128<>>9<<4)+14]=t,e=0;e16&&(e=o(e,8*i.length)),s=Array(16),n=Array(16),a=0;a<16;a+=1)s[a]=909522486^e[a],n[a]=1549556828^e[a];return l=o(s.concat(p(t)),512+8*t.length),h(o(n.concat(l),672))}function o(i,t){var e,o,r,l,h,w,p,c,g=Array(80),u=1732584193,d=-271733879,f=-1732584194,y=271733878,_=-1009589776;for(i[t>>5]|=128<<24-t%32,i[(t+64>>9<<4)+15]=t,e=0;e16&&(s=y(s,8*i.length));o<16;o+=1)n[o]=909522486^s[o],a[o]=1549556828^s[o];return e=y(n.concat(p(t)),512+8*t.length),h(y(a.concat(e),768))}function o(i,t){return i>>>t|i<<32-t}function s(i,t){return i>>>t}function a(i,t,e){return i&t^~i&e}function k(i,t,e){return i&t^i&e^t&e}function w(i){return o(i,2)^o(i,13)^o(i,22)}function u(i){return o(i,6)^o(i,11)^o(i,25)}function d(i){return o(i,7)^o(i,18)^s(i,3)}function f(i){return o(i,17)^o(i,19)^s(i,10)}function y(i,t){var e,o,r,s,l,h,p,c,g,y,b,m,v=[1779033703,-1150833019,1013904242,-1521486534,1359893119,-1694144372,528734635,1541459225],C=new Array(64);for(i[t>>5]|=128<<24-t%32,i[(t+64>>9<<4)+15]=t,g=0;g32&&(n=o(n,8*i.length));s<32;s+=1)a[s]=909522486^n[s],l[s]=1549556828^n[s];return e=o(a.concat(p(t)),1024+8*t.length),h(o(l.concat(e),1536))}function o(i,t){var e,o,r,l=new Array(80),h=new Array(16),p=[new s(1779033703,(-205731576)),new s((-1150833019),(-2067093701)),new s(1013904242,(-23791573)),new s((-1521486534),1595750129),new s(1359893119,(-1377402159)),new s((-1694144372),725511199),new s(528734635,(-79577749)),new s(1541459225,327033209)],c=new s(0,0),g=new s(0,0),_=new s(0,0),b=new s(0,0),m=new s(0,0),v=new s(0,0),C=new s(0,0),q=new s(0,0),A=new s(0,0),D=new s(0,0),x=new s(0,0),B=new s(0,0),E=new s(0,0),F=new s(0,0),z=new s(0,0),j=new s(0,0),T=new s(0,0);for(void 0===y&&(y=[new s(1116352408,(-685199838)),new s(1899447441,602891725),new s((-1245643825),(-330482897)),new s((-373957723),(-2121671748)),new s(961987163,(-213338824)),new s(1508970993,(-1241133031)),new s((-1841331548),(-1357295717)),new s((-1424204075),(-630357736)),new s((-670586216),(-1560083902)),new s(310598401,1164996542),new s(607225278,1323610764),new s(1426881987,(-704662302)),new s(1925078388,(-226784913)),new s((-2132889090),991336113),new s((-1680079193),633803317),new s((-1046744716),(-815192428)),new s((-459576895),(-1628353838)),new s((-272742522),944711139),new s(264347078,(-1953704523)),new s(604807628,2007800933),new s(770255983,1495990901),new s(1249150122,1856431235),new s(1555081692,(-1119749164)),new s(1996064986,(-2096016459)),new s((-1740746414),(-295247957)),new s((-1473132947),766784016),new s((-1341970488),(-1728372417)),new s((-1084653625),(-1091629340)),new s((-958395405),1034457026),new s((-710438585),(-1828018395)),new s(113926993,(-536640913)),new s(338241895,168717936),new s(666307205,1188179964),new s(773529912,1546045734),new s(1294757372,1522805485),new s(1396182291,(-1651133473)),new s(1695183700,(-1951439906)),new s(1986661051,1014477480),new s((-2117940946),1206759142),new s((-1838011259),344077627),new s((-1564481375),1290863460),new s((-1474664885),(-1136513023)),new s((-1035236496),(-789014639)),new s((-949202525),106217008),new s((-778901479),(-688958952)),new s((-694614492),1432725776),new s((-200395387),1467031594),new s(275423344,851169720),new s(430227734,(-1194143544)),new s(506948616,1363258195),new s(659060556,(-544281703)),new s(883997877,(-509917016)),new s(958139571,(-976659869)),new s(1322822218,(-482243893)),new s(1537002063,2003034995),new s(1747873779,(-692930397)),new s(1955562222,1575990012),new s(2024104815,1125592928),new s((-2067236844),(-1578062990)),new s((-1933114872),442776044),new s((-1866530822),593698344),new s((-1538233109),(-561857047)),new s((-1090935817),(-1295615723)),new s((-965641998),(-479046869)),new s((-903397682),(-366583396)),new s((-779700025),566280711),new s((-354779690),(-840897762)),new s((-176337025),(-294727304)),new s(116418474,1914138554),new s(174292421,(-1563912026)),new s(289380356,(-1090974290)),new s(460393269,320620315),new s(685471733,587496836),new s(852142971,1086792851),new s(1017036298,365543100),new s(1126000580,(-1676669620)),new s(1288033470,(-885112138)),new s(1501505948,(-60457430)),new s(1607167915,987167468),new s(1816402316,1246189591)]),o=0;o<80;o+=1)l[o]=new s(0,0);for(i[t>>5]|=128<<24-(31&t),i[(t+128>>10<<5)+31]=t,r=i.length,o=0;o>>e|t.h<<32-e,i.h=t.h>>>e|t.l<<32-e}function k(i,t,e){i.l=t.h>>>e|t.l<<32-e,i.h=t.l>>>e|t.h<<32-e}function w(i,t,e){i.l=t.l>>>e|t.h<<32-e,i.h=t.h>>>e}function u(i,t,e){var o=(65535&t.l)+(65535&e.l),r=(t.l>>>16)+(e.l>>>16)+(o>>>16),s=(65535&t.h)+(65535&e.h)+(r>>>16),n=(t.h>>>16)+(e.h>>>16)+(s>>>16);i.l=65535&o|r<<16,i.h=65535&s|n<<16}function d(i,t,e,o,r){var s=(65535&t.l)+(65535&e.l)+(65535&o.l)+(65535&r.l),n=(t.l>>>16)+(e.l>>>16)+(o.l>>>16)+(r.l>>>16)+(s>>>16),a=(65535&t.h)+(65535&e.h)+(65535&o.h)+(65535&r.h)+(n>>>16),l=(t.h>>>16)+(e.h>>>16)+(o.h>>>16)+(r.h>>>16)+(a>>>16);i.l=65535&s|n<<16,i.h=65535&a|l<<16}function f(i,t,e,o,r,s){var n=(65535&t.l)+(65535&e.l)+(65535&o.l)+(65535&r.l)+(65535&s.l),a=(t.l>>>16)+(e.l>>>16)+(o.l>>>16)+(r.l>>>16)+(s.l>>>16)+(n>>>16),l=(65535&t.h)+(65535&e.h)+(65535&o.h)+(65535&r.h)+(65535&s.h)+(a>>>16),h=(t.h>>>16)+(e.h>>>16)+(o.h>>>16)+(r.h>>>16)+(s.h>>>16)+(l>>>16);i.l=65535&n|a<<16,i.h=65535&l|h<<16}var y,_=!(!i||"boolean"!=typeof i.uppercase)&&i.uppercase,b=i&&"string"==typeof i.pad?i.pad:"=",m=!i||"boolean"!=typeof i.utf8||i.utf8;this.hex=function(i){return l(t(i))},this.b64=function(i){return g(t(i),b)},this.any=function(i,e){return c(t(i),e)},this.raw=function(i){return t(i,m)},this.hex_hmac=function(i,t){return l(e(i,t))},this.b64_hmac=function(i,t){return g(e(i,t),b)},this.any_hmac=function(i,t,o){return c(e(i,t),o)},this.vm_test=function(){return"900150983cd24fb0d6963f7d28e17f72"===hex("abc").toLowerCase()},this.setUpperCase=function(i){return"boolean"==typeof i&&(_=i),this},this.setPad=function(i){return b=i||b,this},this.setUTF8=function(i){return"boolean"==typeof i&&(m=i),this}},RMD160:function(i){function t(i){return i=f?r(i):i,o(s(w(i),8*i.length))}function e(i,t){i=f?r(i):i,t=f?r(t):t;var e,n,a=w(i),l=Array(16),h=Array(16);for(a.length>16&&(a=s(a,8*i.length)),e=0;e<16;e+=1)l[e]=909522486^a[e],h[e]=1549556828^a[e];return n=s(l.concat(w(t)),512+8*t.length),o(s(h.concat(n),672))}function o(i){var t,e="",o=32*i.length;for(t=0;t>5]>>>t%32&255);return e}function s(i,t){var e,o,r,s,l,w,c,g,u,d,f,v,C,q,A=1732584193,D=4023233417,x=2562383102,B=271733878,E=3285377520;for(i[t>>5]|=128<>>9<<4)+14]=t,s=i.length,r=0;r=0?"&":"?")+i),this._sort){var t=this.url.indexOf("?");if(t>=0){var e=this.url.substring(t+1).split("&");d(this._sort)?e.sort(this._sort):e.sort(),this.url=this.url.substring(0,t)+"?"+e.join("&")}}},k.prototype._isHost=function(i){return i&&"object"==typeof i&&!Array.isArray(i)&&"[object Object]"!==Object.prototype.toString.call(i)},k.prototype.end=function(i){return this._endCalled&&console.warn("Warning: .end() was called twice. This is not supported in superagent"),this._endCalled=!0,this._callback=i||o,this._appendQueryString(),this._end()},k.prototype._end=function(){var i=this,t=this.xhr=_.getXHR(),e=this._formData||this._data;this._setTimeouts(),t.onreadystatechange=function(){var e=t.readyState;if(e>=2&&i._responseTimeoutTimer&&clearTimeout(i._responseTimeoutTimer),4==e){var o;try{o=t.status}catch(i){o=0}if(!o){if(i.timedout||i._aborted)return;return i.crossDomainError()}i.emit("end")}};var o=function(t,e){e.total>0&&(e.percent=e.loaded/e.total*100),e.direction=t,i.emit("progress",e)};if(this.hasListeners("progress"))try{ t.onprogress=o.bind(null,"download"),t.upload&&(t.upload.onprogress=o.bind(null,"upload"))}catch(i){}try{this.username&&this.password?t.open(this.method,this.url,!0,this.username,this.password):t.open(this.method,this.url,!0)}catch(i){return this.callback(i)}if(this._withCredentials&&(t.withCredentials=!0),!this._formData&&"GET"!=this.method&&"HEAD"!=this.method&&"string"!=typeof e&&!this._isHost(e)){var r=this._header["content-type"],s=this._serializer||_.serialize[r?r.split(";")[0]:""];!s&&l(r)&&(s=_.serialize["application/json"]),s&&(e=s(e))}for(var n in this.header)null!=this.header[n]&&this.header.hasOwnProperty(n)&&t.setRequestHeader(n,this.header[n]);return this._responseType&&(t.responseType=this._responseType),this.emit("request",this),t.send("undefined"!=typeof e?e:null),this},_.get=function(i,t,e){var o=_("GET",i);return"function"==typeof t&&(e=t,t=null),t&&o.query(t),e&&o.end(e),o},_.head=function(i,t,e){var o=_("HEAD",i);return"function"==typeof t&&(e=t,t=null),t&&o.send(t),e&&o.end(e),o},_.options=function(i,t,e){var o=_("OPTIONS",i);return"function"==typeof t&&(e=t,t=null),t&&o.send(t),e&&o.end(e),o},_.del=w,_.delete=w,_.patch=function(i,t,e){var o=_("PATCH",i);return"function"==typeof t&&(e=t,t=null),t&&o.send(t),e&&o.end(e),o},_.post=function(i,t,e){var o=_("POST",i);return"function"==typeof t&&(e=t,t=null),t&&o.send(t),e&&o.end(e),o},_.put=function(i,t,e){var o=_("PUT",i);return"function"==typeof t&&(e=t,t=null),t&&o.send(t),e&&o.end(e),o}},{"./is-function":4,"./is-object":5,"./request-base":6,"./response-base":7,"./should-retry":8,"component-emitter":1}],4:[function(i,t,e){function o(i){var t=r(i)?Object.prototype.toString.call(i):"";return"[object Function]"===t}var r=i("./is-object");t.exports=o},{"./is-object":5}],5:[function(i,t,e){function o(i){return null!==i&&"object"==typeof i}t.exports=o},{}],6:[function(i,t,e){function o(i){if(i)return r(i)}function r(i){for(var t in o.prototype)i[t]=o.prototype[t];return i}var s=i("./is-object");t.exports=o,o.prototype.clearTimeout=function(){return clearTimeout(this._timer),clearTimeout(this._responseTimeoutTimer),delete this._timer,delete this._responseTimeoutTimer,this},o.prototype.parse=function(i){return this._parser=i,this},o.prototype.responseType=function(i){return this._responseType=i,this},o.prototype.serialize=function(i){return this._serializer=i,this},o.prototype.timeout=function(i){if(!i||"object"!=typeof i)return this._timeout=i,this._responseTimeout=0,this;for(var t in i)switch(t){case"deadline":this._timeout=i.deadline;break;case"response":this._responseTimeout=i.response;break;default:console.warn("Unknown timeout option",t)}return this},o.prototype.retry=function(i){return 0!==arguments.length&&i!==!0||(i=1),i<=0&&(i=0),this._maxRetries=i,this._retries=0,this},o.prototype._retry=function(){return this.clearTimeout(),this.req&&(this.req=null,this.req=this.request()),this._aborted=!1,this.timedout=!1,this._end()},o.prototype.then=function(i,t){if(!this._fullfilledPromise){var e=this;this._endCalled&&console.warn("Warning: superagent request was sent twice, because both .end() and .then() were called. Never call .end() if you use promises"),this._fullfilledPromise=new Promise(function(i,t){e.end(function(e,o){e?t(e):i(o)})})}return this._fullfilledPromise.then(i,t)},o.prototype.catch=function(i){return this.then(void 0,i)},o.prototype.use=function(i){return i(this),this},o.prototype.ok=function(i){if("function"!=typeof i)throw Error("Callback required");return this._okCallback=i,this},o.prototype._isResponseOK=function(i){return!!i&&(this._okCallback?this._okCallback(i):i.status>=200&&i.status<300)},o.prototype.get=function(i){return this._header[i.toLowerCase()]},o.prototype.getHeader=o.prototype.get,o.prototype.set=function(i,t){if(s(i)){for(var e in i)this.set(e,i[e]);return this}return this._header[i.toLowerCase()]=t,this.header[i]=t,this},o.prototype.unset=function(i){return delete this._header[i.toLowerCase()],delete this.header[i],this},o.prototype.field=function(i,t){if(null===i||void 0===i)throw new Error(".field(name, val) name can not be empty");if(this._data&&console.error(".field() can't be used if .send() is used. Please use only .send() or only .field() & .attach()"),s(i)){for(var e in i)this.field(e,i[e]);return this}if(Array.isArray(t)){for(var o in t)this.field(i,t[o]);return this}if(null===t||void 0===t)throw new Error(".field(name, val) val can not be empty");return"boolean"==typeof t&&(t=""+t),this._getFormData().append(i,t),this},o.prototype.abort=function(){return this._aborted?this:(this._aborted=!0,this.xhr&&this.xhr.abort(),this.req&&this.req.abort(),this.clearTimeout(),this.emit("abort"),this)},o.prototype.withCredentials=function(i){return void 0==i&&(i=!0),this._withCredentials=i,this},o.prototype.redirects=function(i){return this._maxRedirects=i,this},o.prototype.toJSON=function(){return{method:this.method,url:this.url,data:this._data,headers:this._header}},o.prototype.send=function(i){var t=s(i),e=this._header["content-type"];if(this._formData&&console.error(".send() can't be used if .attach() or .field() is used. Please use only .send() or only .field() & .attach()"),t&&!this._data)Array.isArray(i)?this._data=[]:this._isHost(i)||(this._data={});else if(i&&this._data&&this._isHost(this._data))throw Error("Can't merge these send calls");if(t&&s(this._data))for(var o in i)this._data[o]=i[o];else"string"==typeof i?(e||this.type("form"),e=this._header["content-type"],"application/x-www-form-urlencoded"==e?this._data=this._data?this._data+"&"+i:i:this._data=(this._data||"")+i):this._data=i;return!t||this._isHost(i)?this:(e||this.type("json"),this)},o.prototype.sortQuery=function(i){return this._sort="undefined"==typeof i||i,this},o.prototype._timeoutError=function(i,t,e){if(!this._aborted){var o=new Error(i+t+"ms exceeded");o.timeout=t,o.code="ECONNABORTED",o.errno=e,this.timedout=!0,this.abort(),this.callback(o)}},o.prototype._setTimeouts=function(){var i=this;this._timeout&&!this._timer&&(this._timer=setTimeout(function(){i._timeoutError("Timeout of ",i._timeout,"ETIME")},this._timeout)),this._responseTimeout&&!this._responseTimeoutTimer&&(this._responseTimeoutTimer=setTimeout(function(){i._timeoutError("Response timeout of ",i._responseTimeout,"ETIMEDOUT")},this._responseTimeout))}},{"./is-object":5}],7:[function(i,t,e){function o(i){if(i)return r(i)}function r(i){for(var t in o.prototype)i[t]=o.prototype[t];return i}var s=i("./utils");t.exports=o,o.prototype.get=function(i){return this.header[i.toLowerCase()]},o.prototype._setHeaderProperties=function(i){var t=i["content-type"]||"";this.type=s.type(t);var e=s.params(t);for(var o in e)this[o]=e[o];this.links={};try{i.link&&(this.links=s.parseLinks(i.link))}catch(i){}},o.prototype._setStatusProperties=function(i){var t=i/100|0;this.status=this.statusCode=i,this.statusType=t,this.info=1==t,this.ok=2==t,this.redirect=3==t,this.clientError=4==t,this.serverError=5==t,this.error=(4==t||5==t)&&this.toError(),this.accepted=202==i,this.noContent=204==i,this.badRequest=400==i,this.unauthorized=401==i,this.notAcceptable=406==i,this.forbidden=403==i,this.notFound=404==i}},{"./utils":9}],8:[function(i,t,e){var o=["ECONNRESET","ETIMEDOUT","EADDRINFO","ESOCKETTIMEDOUT"];t.exports=function(i,t){return!!(i&&i.code&&~o.indexOf(i.code))||(!!(t&&t.status&&t.status>=500)||(!!(i&&"timeout"in i&&"ECONNABORTED"==i.code)||!!(i&&"crossDomain"in i)))}},{}],9:[function(i,t,e){e.type=function(i){return i.split(/ *; */).shift()},e.params=function(i){return i.split(/ *; */).reduce(function(i,t){var e=t.split(/ *= */),o=e.shift(),r=e.shift();return o&&r&&(i[o]=r),i},{})},e.parseLinks=function(i){return i.split(/ *, */).reduce(function(i,t){var e=t.split(/ *; */),o=e[0].slice(1,-1),r=e[1].split(/ *= */)[1].slice(1,-1);return i[r]=o,i},{})},e.cleanHeader=function(i,t){return delete i["content-type"],delete i["content-length"],delete i["transfer-encoding"],delete i.host,t&&delete i.cookie,i}},{}],10:[function(i,t,e){"use strict";t.exports=["jr","mr","mrs","ms","dr","prof","sr","sen","corp","calif","rep","gov","atty","supt","det","rev","col","gen","lt","cmdr","adm","capt","sgt","cpl","maj","dept","univ","assn","bros","inc","ltd","co","corp","arc","al","ave","blvd","cl","ct","cres","exp","rd","st","dist","mt","ft","fy","hwy","la","pd","pl","plz","tce","Ala","Ariz","Ark","Cal","Calif","Col","Colo","Conn","Del","Fed","Fla","Ga","Ida","Id","Ill","Ind","Ia","Kan","Kans","Ken","Ky","La","Me","Md","Mass","Mich","Minn","Miss","Mo","Mont","Neb","Nebr","Nev","Mex","Okla","Ok","Ore","Penna","Penn","Pa","Dak","Tenn","Tex","Ut","Vt","Va","Wash","Wis","Wisc","Wy","Wyo","USAFA","Alta","Ont","QuÔøΩ","Sask","Yuk","jan","feb","mar","apr","jun","jul","aug","sep","oct","nov","dec","sept","vs","etc","esp","llb","md","bl","phd","ma","ba","miss","misses","mister","sir","esq","mstr","lit","fl","ex","eg","sep","sept",".."]},{}],11:[function(i,t,e){"use strict";var o={files:["файл","fitxer","soubor","datei","file","archivo","پرونده","tiedosto","mynd","su'wret","fichier","bestand","датотека","dosya","fil"],images:["image"],templates:["шаблён","plantilla","šablona","vorlage","template","الگو","malline","snið","shablon","modèle","sjabloon","шаблон","şablon"],categories:["катэгорыя","categoria","kategorie","category","categoría","رده","luokka","flokkur","kategoriya","catégorie","categorie","категорија","kategori","kategoria","تصنيف"],redirects:["перанакіраваньне","redirect","přesměruj","weiterleitung","redirección","redireccion","تغییر_مسیر","تغییرمسیر","ohjaus","uudelleenohjaus","tilvísun","aýdaw","айдау","redirection","doorverwijzing","преусмери","преусмјери","yönlendi̇rme","yönlendi̇r","重定向","redirección","redireccion","重定向","yönlendirm?e?","تغییر_مسیر","تغییرمسیر","перанакіраваньне","yönlendirme"],specials:["спэцыяльныя","especial","speciální","spezial","special","ویژه","toiminnot","kerfissíða","arnawlı","spécial","speciaal","посебно","özel"],users:["удзельнік","usuari","uživatel","benutzer","user","usuario","کاربر","käyttäjä","notandi","paydalanıwshı","utilisateur","gebruiker","корисник","kullanıcı"],disambigs:["disambig","disambiguation","dab","disamb","begriffsklärung","ujednoznacznienie","doorverwijspagina","消歧义","desambiguación","dubbelsinnig","disambigua","desambiguação","homonymie","неоднозначность","anlam ayrımı"],infoboxes:["infobox","ficha","канадский","inligtingskas","inligtingskas3","لغة","bilgi kutusu","yerleşim bilgi kutusu","infoboks"],sources:["references","see also","external links","further reading","notes et références","voir aussi","liens externes"]};"undefined"!=typeof t&&t.exports&&(t.exports=o)},{}],12:[function(i,t,e){"use strict";t.exports={aa:{english_title:"Afar",direction:"ltr",local_title:"Afar"},ab:{english_title:"Abkhazian",direction:"ltr",local_title:"Аҧсуа"},af:{english_title:"Afrikaans",direction:"ltr",local_title:"Afrikaans"},ak:{english_title:"Akan",direction:"ltr",local_title:"Akana"},als:{english_title:"Alemannic",direction:"ltr",local_title:"Alemannisch"},am:{english_title:"Amharic",direction:"ltr",local_title:"አማርኛ"},an:{english_title:"Aragonese",direction:"ltr",local_title:"Aragonés"},ang:{english_title:"Anglo-Saxon",direction:"ltr",local_title:"Englisc"},ar:{english_title:"Arabic",direction:"rtl",local_title:"العربية"},arc:{english_title:"Aramaic",direction:"rtl",local_title:"ܣܘܪܬ"},as:{english_title:"Assamese",direction:"ltr",local_title:"অসমীয়া"},ast:{english_title:"Asturian",direction:"ltr",local_title:"Asturianu"},av:{english_title:"Avar",direction:"ltr",local_title:"Авар"},ay:{english_title:"Aymara",direction:"ltr",local_title:"Aymar"},az:{english_title:"Azerbaijani",direction:"ltr",local_title:"Azərbaycanca"},ba:{english_title:"Bashkir",direction:"ltr",local_title:"Башҡорт"},bar:{english_title:"Bavarian",direction:"ltr",local_title:"Boarisch"},"bat-smg":{english_title:"Samogitian",direction:"ltr",local_title:"Žemaitėška"},bcl:{english_title:"Bikol",direction:"ltr",local_title:"Bikol"},be:{english_title:"Belarusian",direction:"ltr",local_title:"Беларуская"},"be-x-old":{english_title:"Belarusian",direction:"(Taraškievica)",local_title:"ltr"},bg:{english_title:"Bulgarian",direction:"ltr",local_title:"Български"},bh:{english_title:"Bihari",direction:"ltr",local_title:"भोजपुरी"},bi:{english_title:"Bislama",direction:"ltr",local_title:"Bislama"},bm:{english_title:"Bambara",direction:"ltr",local_title:"Bamanankan"},bn:{english_title:"Bengali",direction:"ltr",local_title:"বাংলা"},bo:{english_title:"Tibetan",direction:"ltr",local_title:"བོད་ཡིག"},bpy:{english_title:"Bishnupriya",direction:"Manipuri",local_title:"ltr"},br:{english_title:"Breton",direction:"ltr",local_title:"Brezhoneg"},bs:{english_title:"Bosnian",direction:"ltr",local_title:"Bosanski"},bug:{english_title:"Buginese",direction:"ltr",local_title:"ᨅᨔ"},bxr:{english_title:"Buriat",direction:"(Russia)",local_title:"ltr"},ca:{english_title:"Catalan",direction:"ltr",local_title:"Català"},cdo:{english_title:"Min",direction:"Dong",local_title:"Chinese"},ce:{english_title:"Chechen",direction:"ltr",local_title:"Нохчийн"},ceb:{english_title:"Cebuano",direction:"ltr",local_title:"Sinugboanong"},ch:{english_title:"Chamorro",direction:"ltr",local_title:"Chamoru"},cho:{english_title:"Choctaw",direction:"ltr",local_title:"Choctaw"},chr:{english_title:"Cherokee",direction:"ltr",local_title:"ᏣᎳᎩ"},chy:{english_title:"Cheyenne",direction:"ltr",local_title:"Tsetsêhestâhese"},co:{english_title:"Corsican",direction:"ltr",local_title:"Corsu"},cr:{english_title:"Cree",direction:"ltr",local_title:"Nehiyaw"},cs:{english_title:"Czech",direction:"ltr",local_title:"Česky"},csb:{english_title:"Kashubian",direction:"ltr",local_title:"Kaszëbsczi"},cu:{english_title:"Old",direction:"Church",local_title:"Slavonic"},cv:{english_title:"Chuvash",direction:"ltr",local_title:"Чăваш"},cy:{english_title:"Welsh",direction:"ltr",local_title:"Cymraeg"},da:{english_title:"Danish",direction:"ltr",local_title:"Dansk"},de:{english_title:"German",direction:"ltr",local_title:"Deutsch"},diq:{english_title:"Dimli",direction:"ltr",local_title:"Zazaki"},dsb:{english_title:"Lower",direction:"Sorbian",local_title:"ltr"},dv:{english_title:"Divehi",direction:"rtl",local_title:"ދިވެހިބަސް"},dz:{english_title:"Dzongkha",direction:"ltr",local_title:"ཇོང་ཁ"},ee:{english_title:"Ewe",direction:"ltr",local_title:"Ɛʋɛ"},far:{english_title:"Farsi",direction:"ltr",local_title:"فارسی"},el:{english_title:"Greek",direction:"ltr",local_title:"Ελληνικά"},en:{english_title:"English",direction:"ltr",local_title:"English"},eo:{english_title:"Esperanto",direction:"ltr",local_title:"Esperanto"},es:{english_title:"Spanish",direction:"ltr",local_title:"Español"},et:{english_title:"Estonian",direction:"ltr",local_title:"Eesti"},eu:{english_title:"Basque",direction:"ltr",local_title:"Euskara"},ext:{english_title:"Extremaduran",direction:"ltr",local_title:"Estremeñu"},ff:{english_title:"Peul",direction:"ltr",local_title:"Fulfulde"},fi:{english_title:"Finnish",direction:"ltr",local_title:"Suomi"},"fiu-vro":{english_title:"Võro",direction:"ltr",local_title:"Võro"},fj:{english_title:"Fijian",direction:"ltr",local_title:"Na"},fo:{english_title:"Faroese",direction:"ltr",local_title:"Føroyskt"},fr:{english_title:"French",direction:"ltr",local_title:"Français"},frp:{english_title:"Arpitan",direction:"ltr",local_title:"Arpitan"},fur:{english_title:"Friulian",direction:"ltr",local_title:"Furlan"},fy:{english_title:"West",direction:"Frisian",local_title:"ltr"},ga:{english_title:"Irish",direction:"ltr",local_title:"Gaeilge"},gan:{english_title:"Gan",direction:"Chinese",local_title:"ltr"},gd:{english_title:"Scottish",direction:"Gaelic",local_title:"ltr"},gil:{english_title:"Gilbertese",direction:"ltr",local_title:"Taetae"},gl:{english_title:"Galician",direction:"ltr",local_title:"Galego"},gn:{english_title:"Guarani",direction:"ltr",local_title:"Avañe'ẽ"},got:{english_title:"Gothic",direction:"ltr",local_title:"gutisk"},gu:{english_title:"Gujarati",direction:"ltr",local_title:"ગુજરાતી"},gv:{english_title:"Manx",direction:"ltr",local_title:"Gaelg"},ha:{english_title:"Hausa",direction:"rtl",local_title:"هَوُسَ"},hak:{english_title:"Hakka",direction:"Chinese",local_title:"ltr"},haw:{english_title:"Hawaiian",direction:"ltr",local_title:"Hawai`i"},he:{english_title:"Hebrew",direction:"rtl",local_title:"עברית"},hi:{english_title:"Hindi",direction:"ltr",local_title:"हिन्दी"},ho:{english_title:"Hiri",direction:"Motu",local_title:"ltr"},hr:{english_title:"Croatian",direction:"ltr",local_title:"Hrvatski"},ht:{english_title:"Haitian",direction:"ltr",local_title:"Krèyol"},hu:{english_title:"Hungarian",direction:"ltr",local_title:"Magyar"},hy:{english_title:"Armenian",direction:"ltr",local_title:"Հայերեն"},hz:{english_title:"Herero",direction:"ltr",local_title:"Otsiherero"},ia:{english_title:"Interlingua",direction:"ltr",local_title:"Interlingua"},id:{english_title:"Indonesian",direction:"ltr",local_title:"Bahasa"},ie:{english_title:"Interlingue",direction:"ltr",local_title:"Interlingue"},ig:{english_title:"Igbo",direction:"ltr",local_title:"Igbo"},ii:{english_title:"Sichuan",direction:"Yi",local_title:"ltr"},ik:{english_title:"Inupiak",direction:"ltr",local_title:"Iñupiak"},ilo:{english_title:"Ilokano",direction:"ltr",local_title:"Ilokano"},io:{english_title:"Ido",direction:"ltr",local_title:"Ido"},is:{english_title:"Icelandic",direction:"ltr",local_title:"Íslenska"},it:{english_title:"Italian",direction:"ltr",local_title:"Italiano"},iu:{english_title:"Inuktitut",direction:"ltr",local_title:"ᐃᓄᒃᑎᑐᑦ"},ja:{english_title:"Japanese",direction:"ltr",local_title:"日本語"},jbo:{english_title:"Lojban",direction:"ltr",local_title:"Lojban"},jv:{english_title:"Javanese",direction:"ltr",local_title:"Basa"},ka:{english_title:"Georgian",direction:"ltr",local_title:"ქართული"},kg:{english_title:"Kongo",direction:"ltr",local_title:"KiKongo"},ki:{english_title:"Kikuyu",direction:"ltr",local_title:"Gĩkũyũ"},kj:{english_title:"Kuanyama",direction:"ltr",local_title:"Kuanyama"},kk:{english_title:"Kazakh",direction:"ltr",local_title:"Қазақша"},kl:{english_title:"Greenlandic",direction:"ltr",local_title:"Kalaallisut"},km:{english_title:"Cambodian",direction:"ltr",local_title:"ភាសាខ្មែរ"},kn:{english_title:"Kannada",direction:"ltr",local_title:"ಕನ್ನಡ"},khw:{english_title:"Khowar",direction:"rtl",local_title:"کھوار"},ko:{english_title:"Korean",direction:"ltr",local_title:"한국어"},kr:{english_title:"Kanuri",direction:"ltr",local_title:"Kanuri"},ks:{english_title:"Kashmiri",direction:"rtl",local_title:"कश्मीरी"},ksh:{english_title:"Ripuarian",direction:"ltr",local_title:"Ripoarisch"},ku:{english_title:"Kurdish",direction:"rtl",local_title:"Kurdî"},kv:{english_title:"Komi",direction:"ltr",local_title:"Коми"},kw:{english_title:"Cornish",direction:"ltr",local_title:"Kernewek"},ky:{english_title:"Kirghiz",direction:"ltr",local_title:"Kırgızca"},la:{english_title:"Latin",direction:"ltr",local_title:"Latina"},lad:{english_title:"Ladino",direction:"ltr",local_title:"Dzhudezmo"},lan:{english_title:"Lango",direction:"ltr",local_title:"Leb"},lb:{english_title:"Luxembourgish",direction:"ltr",local_title:"Lëtzebuergesch"},lg:{english_title:"Ganda",direction:"ltr",local_title:"Luganda"},li:{english_title:"Limburgian",direction:"ltr",local_title:"Limburgs"},lij:{english_title:"Ligurian",direction:"ltr",local_title:"Líguru"},lmo:{english_title:"Lombard",direction:"ltr",local_title:"Lumbaart"},ln:{english_title:"Lingala",direction:"ltr",local_title:"Lingála"},lo:{english_title:"Laotian",direction:"ltr",local_title:"ລາວ"},lt:{english_title:"Lithuanian",direction:"ltr",local_title:"Lietuvių"},lv:{english_title:"Latvian",direction:"ltr",local_title:"Latviešu"},"map-bms":{english_title:"Banyumasan",direction:"ltr",local_title:"Basa"},mg:{english_title:"Malagasy",direction:"ltr",local_title:"Malagasy"},man:{english_title:"Mandarin",direction:"ltr",local_title:"官話"},mh:{english_title:"Marshallese",direction:"ltr",local_title:"Kajin"},mi:{english_title:"Maori",direction:"ltr",local_title:"Māori"},min:{english_title:"Minangkabau",direction:"ltr",local_title:"Minangkabau"},mk:{english_title:"Macedonian",direction:"ltr",local_title:"Македонски"},ml:{english_title:"Malayalam",direction:"ltr",local_title:"മലയാളം"},mn:{english_title:"Mongolian",direction:"ltr",local_title:"Монгол"},mo:{english_title:"Moldovan",direction:"ltr",local_title:"Moldovenească"},mr:{english_title:"Marathi",direction:"ltr",local_title:"मराठी"},ms:{english_title:"Malay",direction:"ltr",local_title:"Bahasa"},mt:{english_title:"Maltese",direction:"ltr",local_title:"bil-Malti"},mus:{english_title:"Creek",direction:"ltr",local_title:"Muskogee"},my:{english_title:"Burmese",direction:"ltr",local_title:"Myanmasa"},na:{english_title:"Nauruan",direction:"ltr",local_title:"Dorerin"},nah:{english_title:"Nahuatl",direction:"ltr",local_title:"Nahuatl"},nap:{english_title:"Neapolitan",direction:"ltr",local_title:"Nnapulitano"},nd:{english_title:"North",direction:"Ndebele",local_title:"ltr"},nds:{english_title:"Low German",direction:"ltr",local_title:"Plattdüütsch"},"nds-nl":{english_title:"Dutch",direction:"Low",local_title:"Saxon"},ne:{english_title:"Nepali",direction:"ltr",local_title:"नेपाली"},new:{english_title:"Newar",direction:"ltr",local_title:"नेपालभाषा"},ng:{english_title:"Ndonga",direction:"ltr",local_title:"Oshiwambo"},nl:{english_title:"Dutch",direction:"ltr",local_title:"Nederlands"},nn:{english_title:"Norwegian",direction:"Nynorsk",local_title:"ltr"},no:{english_title:"Norwegian",direction:"ltr",local_title:"Norsk"},nr:{english_title:"South",direction:"Ndebele",local_title:"ltr"},nso:{english_title:"Northern",direction:"Sotho",local_title:"ltr"},nrm:{english_title:"Norman",direction:"ltr",local_title:"Nouormand"},nv:{english_title:"Navajo",direction:"ltr",local_title:"Diné"},ny:{english_title:"Chichewa",direction:"ltr",local_title:"Chi-Chewa"},oc:{english_title:"Occitan",direction:"ltr",local_title:"Occitan"},oj:{english_title:"Ojibwa",direction:"ltr",local_title:"ᐊᓂᔑᓈᐯᒧᐎᓐ"},om:{english_title:"Oromo",direction:"ltr",local_title:"Oromoo"},or:{english_title:"Oriya",direction:"ltr",local_title:"ଓଡ଼ିଆ"},os:{english_title:"Ossetian",direction:"ltr",local_title:"Иронау"},pa:{english_title:"Panjabi",direction:"ltr",local_title:"ਪੰਜਾਬੀ"},pag:{english_title:"Pangasinan",direction:"ltr",local_title:"Pangasinan"},pam:{english_title:"Kapampangan",direction:"ltr",local_title:"Kapampangan"},pap:{english_title:"Papiamentu",direction:"ltr",local_title:"Papiamentu"},pdc:{english_title:"Pennsylvania",direction:"German",local_title:"ltr"},pi:{english_title:"Pali",direction:"ltr",local_title:"Pāli"},pih:{english_title:"Norfolk",direction:"ltr",local_title:"Norfuk"},pl:{english_title:"Polish",direction:"ltr",local_title:"Polski"},pms:{english_title:"Piedmontese",direction:"ltr",local_title:"Piemontèis"},ps:{english_title:"Pashto",direction:"rtl",local_title:"پښتو"},pt:{english_title:"Portuguese",direction:"ltr",local_title:"Português"},qu:{english_title:"Quechua",direction:"ltr",local_title:"Runa"},rm:{english_title:"Raeto",direction:"Romance",local_title:"ltr"},rmy:{english_title:"Romani",direction:"ltr",local_title:"Romani"},rn:{english_title:"Kirundi",direction:"ltr",local_title:"Kirundi"},ro:{english_title:"Romanian",direction:"ltr",local_title:"Română"},"roa-rup":{english_title:"Aromanian",direction:"ltr",local_title:"Armâneashti"},ru:{english_title:"Russian",direction:"ltr",local_title:"Русский"},rw:{english_title:"Rwandi",direction:"ltr",local_title:"Kinyarwandi"},sa:{english_title:"Sanskrit",direction:"ltr",local_title:"संस्कृतम्"},sc:{english_title:"Sardinian",direction:"ltr",local_title:"Sardu"},scn:{english_title:"Sicilian",direction:"ltr",local_title:"Sicilianu"},sco:{english_title:"Scots",direction:"ltr",local_title:"Scots"},sd:{english_title:"Sindhi",direction:"ltr",local_title:"सिनधि"},se:{english_title:"Northern",direction:"Sami",local_title:"ltr"},sg:{english_title:"Sango",direction:"ltr",local_title:"Sängö"},sh:{english_title:"Serbo-Croatian",direction:"ltr",local_title:"Srpskohrvatski"},si:{english_title:"Sinhalese",direction:"ltr",local_title:"සිංහල"},simple:{english_title:"Simple",direction:"English",local_title:"ltr"},sk:{english_title:"Slovak",direction:"ltr",local_title:"Slovenčina"},sl:{english_title:"Slovenian",direction:"ltr",local_title:"Slovenščina"},sm:{english_title:"Samoan",direction:"ltr",local_title:"Gagana"},sn:{english_title:"Shona",direction:"ltr",local_title:"chiShona"},so:{english_title:"Somalia",direction:"ltr",local_title:"Soomaaliga"},sq:{english_title:"Albanian",direction:"ltr",local_title:"Shqip"},sr:{english_title:"Serbian",direction:"ltr",local_title:"Српски"},ss:{english_title:"Swati",direction:"ltr",local_title:"SiSwati"},st:{english_title:"Southern",direction:"Sotho",local_title:"ltr"},su:{english_title:"Sundanese",direction:"ltr",local_title:"Basa"},sv:{english_title:"Swedish",direction:"ltr",local_title:"Svenska"},sw:{english_title:"Swahili",direction:"ltr",local_title:"Kiswahili"},ta:{english_title:"Tamil",direction:"ltr",local_title:"தமிழ்"},te:{english_title:"Telugu",direction:"ltr",local_title:"తెలుగు"},tet:{english_title:"Tetum",direction:"ltr",local_title:"Tetun"},tg:{english_title:"Tajik",direction:"ltr",local_title:"Тоҷикӣ"},th:{english_title:"Thai",direction:"ltr",local_title:"ไทย"},ti:{english_title:"Tigrinya",direction:"ltr",local_title:"ትግርኛ"},tk:{english_title:"Turkmen",direction:"ltr",local_title:"Туркмен"},tl:{english_title:"Tagalog",direction:"ltr",local_title:"Tagalog"},tlh:{english_title:"Klingon",direction:"ltr",local_title:"tlhIngan-Hol"},tn:{english_title:"Tswana",direction:"ltr",local_title:"Setswana"},to:{english_title:"Tonga",direction:"ltr",local_title:"Lea"},tpi:{english_title:"Tok",direction:"Pisin",local_title:"ltr"},tr:{english_title:"Turkish",direction:"ltr",local_title:"Türkçe"},ts:{english_title:"Tsonga",direction:"ltr",local_title:"Xitsonga"},tt:{english_title:"Tatar",direction:"ltr",local_title:"Tatarça"},tum:{english_title:"Tumbuka",direction:"ltr",local_title:"chiTumbuka"},tw:{english_title:"Twi",direction:"ltr",local_title:"Twi"},ty:{english_title:"Tahitian",direction:"ltr",local_title:"Reo"},udm:{english_title:"Udmurt",direction:"ltr",local_title:"Удмурт"},ug:{english_title:"Uyghur",direction:"ltr",local_title:"Uyƣurqə"},uk:{english_title:"Ukrainian",direction:"ltr",local_title:"Українська"},ur:{english_title:"Urdu",direction:"rtl",local_title:"اردو"},uz:{english_title:"Uzbek",direction:"ltr",local_title:"Ўзбек"},ve:{english_title:"Venda",direction:"ltr",local_title:"Tshivenḓa"},vi:{english_title:"Vietnamese",direction:"ltr",local_title:"Việtnam"},vec:{english_title:"Venetian",direction:"ltr",local_title:"Vèneto"},vls:{english_title:"West",direction:"Flemish",local_title:"ltr"},vo:{english_title:"Volapük",direction:"ltr",local_title:"Volapük"},wa:{english_title:"Walloon",direction:"ltr",local_title:"Walon"},war:{english_title:"Waray-Waray",direction:"ltr",local_title:"Winaray"},wo:{english_title:"Wolof",direction:"ltr",local_title:"Wollof"},xal:{english_title:"Kalmyk",direction:"ltr",local_title:"Хальмг"},xh:{english_title:"Xhosa",direction:"ltr",local_title:"isiXhosa"},yi:{english_title:"Yiddish",direction:"rtl",local_title:"ייִדיש"},yo:{english_title:"Yoruba",direction:"ltr",local_title:"Yorùbá"},za:{english_title:"Zhuang",direction:"ltr",local_title:"Cuengh"},zh:{english_title:"Chinese",direction:"ltr",local_title:"中文"},"zh-classical":{english_title:"Classical",direction:"Chinese",local_title:"ltr"},"zh-min-nan":{english_title:"Minnan",direction:"ltr",local_title:"Bân-lâm-gú"},"zh-yue":{english_title:"Cantonese",direction:"ltr",local_title:"粵語"},zu:{english_title:"Zulu",direction:"ltr",local_title:"isiZulu"}}},{}],13:[function(i,t,e){"use strict";var o={aawiki:"https://aa.wikipedia.org",aawiktionary:"https://aa.wiktionary.org",aawikibooks:"https://aa.wikibooks.org",abwiki:"https://ab.wikipedia.org",abwiktionary:"https://ab.wiktionary.org",acewiki:"https://ace.wikipedia.org",afwiki:"https://af.wikipedia.org",afwiktionary:"https://af.wiktionary.org",afwikibooks:"https://af.wikibooks.org",afwikiquote:"https://af.wikiquote.org",akwiki:"https://ak.wikipedia.org",akwiktionary:"https://ak.wiktionary.org",akwikibooks:"https://ak.wikibooks.org",alswiki:"https://als.wikipedia.org",alswiktionary:"https://als.wiktionary.org",alswikibooks:"https://als.wikibooks.org",alswikiquote:"https://als.wikiquote.org",amwiki:"https://am.wikipedia.org",amwiktionary:"https://am.wiktionary.org",amwikiquote:"https://am.wikiquote.org",anwiki:"https://an.wikipedia.org",anwiktionary:"https://an.wiktionary.org",angwiki:"https://ang.wikipedia.org",angwiktionary:"https://ang.wiktionary.org",angwikibooks:"https://ang.wikibooks.org",angwikiquote:"https://ang.wikiquote.org",angwikisource:"https://ang.wikisource.org",arwiki:"https://ar.wikipedia.org",arwiktionary:"https://ar.wiktionary.org",arwikibooks:"https://ar.wikibooks.org",arwikinews:"https://ar.wikinews.org",arwikiquote:"https://ar.wikiquote.org",arwikisource:"https://ar.wikisource.org",arwikiversity:"https://ar.wikiversity.org",arcwiki:"https://arc.wikipedia.org",arzwiki:"https://arz.wikipedia.org",aswiki:"https://as.wikipedia.org",aswiktionary:"https://as.wiktionary.org",aswikibooks:"https://as.wikibooks.org",aswikisource:"https://as.wikisource.org",astwiki:"https://ast.wikipedia.org",astwiktionary:"https://ast.wiktionary.org",astwikibooks:"https://ast.wikibooks.org",astwikiquote:"https://ast.wikiquote.org",avwiki:"https://av.wikipedia.org",avwiktionary:"https://av.wiktionary.org",aywiki:"https://ay.wikipedia.org",aywiktionary:"https://ay.wiktionary.org",aywikibooks:"https://ay.wikibooks.org",azwiki:"https://az.wikipedia.org",azwiktionary:"https://az.wiktionary.org",azwikibooks:"https://az.wikibooks.org",azwikiquote:"https://az.wikiquote.org",azwikisource:"https://az.wikisource.org",bawiki:"https://ba.wikipedia.org",bawikibooks:"https://ba.wikibooks.org",barwiki:"https://bar.wikipedia.org",bat_smgwiki:"https://bat-smg.wikipedia.org",bclwiki:"https://bcl.wikipedia.org",bewiki:"https://be.wikipedia.org",bewiktionary:"https://be.wiktionary.org",bewikibooks:"https://be.wikibooks.org",bewikiquote:"https://be.wikiquote.org",bewikisource:"https://be.wikisource.org",be_x_oldwiki:"https://be-x-old.wikipedia.org",bgwiki:"https://bg.wikipedia.org",bgwiktionary:"https://bg.wiktionary.org",bgwikibooks:"https://bg.wikibooks.org",bgwikinews:"https://bg.wikinews.org",bgwikiquote:"https://bg.wikiquote.org",bgwikisource:"https://bg.wikisource.org",bhwiki:"https://bh.wikipedia.org",bhwiktionary:"https://bh.wiktionary.org",biwiki:"https://bi.wikipedia.org",biwiktionary:"https://bi.wiktionary.org",biwikibooks:"https://bi.wikibooks.org",bjnwiki:"https://bjn.wikipedia.org",bmwiki:"https://bm.wikipedia.org",bmwiktionary:"https://bm.wiktionary.org",bmwikibooks:"https://bm.wikibooks.org",bmwikiquote:"https://bm.wikiquote.org",bnwiki:"https://bn.wikipedia.org",bnwiktionary:"https://bn.wiktionary.org",bnwikibooks:"https://bn.wikibooks.org",bnwikisource:"https://bn.wikisource.org",bowiki:"https://bo.wikipedia.org",bowiktionary:"https://bo.wiktionary.org",bowikibooks:"https://bo.wikibooks.org",bpywiki:"https://bpy.wikipedia.org",brwiki:"https://br.wikipedia.org",brwiktionary:"https://br.wiktionary.org",brwikiquote:"https://br.wikiquote.org",brwikisource:"https://br.wikisource.org",bswiki:"https://bs.wikipedia.org",bswiktionary:"https://bs.wiktionary.org",bswikibooks:"https://bs.wikibooks.org",bswikinews:"https://bs.wikinews.org",bswikiquote:"https://bs.wikiquote.org",bswikisource:"https://bs.wikisource.org",bugwiki:"https://bug.wikipedia.org",bxrwiki:"https://bxr.wikipedia.org",cawiki:"https://ca.wikipedia.org",cawiktionary:"https://ca.wiktionary.org",cawikibooks:"https://ca.wikibooks.org",cawikinews:"https://ca.wikinews.org",cawikiquote:"https://ca.wikiquote.org",cawikisource:"https://ca.wikisource.org",cbk_zamwiki:"https://cbk-zam.wikipedia.org",cdowiki:"https://cdo.wikipedia.org",cewiki:"https://ce.wikipedia.org", cebwiki:"https://ceb.wikipedia.org",chwiki:"https://ch.wikipedia.org",chwiktionary:"https://ch.wiktionary.org",chwikibooks:"https://ch.wikibooks.org",chowiki:"https://cho.wikipedia.org",chrwiki:"https://chr.wikipedia.org",chrwiktionary:"https://chr.wiktionary.org",chywiki:"https://chy.wikipedia.org",ckbwiki:"https://ckb.wikipedia.org",cowiki:"https://co.wikipedia.org",cowiktionary:"https://co.wiktionary.org",cowikibooks:"https://co.wikibooks.org",cowikiquote:"https://co.wikiquote.org",crwiki:"https://cr.wikipedia.org",crwiktionary:"https://cr.wiktionary.org",crwikiquote:"https://cr.wikiquote.org",crhwiki:"https://crh.wikipedia.org",cswiki:"https://cs.wikipedia.org",cswiktionary:"https://cs.wiktionary.org",cswikibooks:"https://cs.wikibooks.org",cswikinews:"https://cs.wikinews.org",cswikiquote:"https://cs.wikiquote.org",cswikisource:"https://cs.wikisource.org",cswikiversity:"https://cs.wikiversity.org",csbwiki:"https://csb.wikipedia.org",csbwiktionary:"https://csb.wiktionary.org",cuwiki:"https://cu.wikipedia.org",cvwiki:"https://cv.wikipedia.org",cvwikibooks:"https://cv.wikibooks.org",cywiki:"https://cy.wikipedia.org",cywiktionary:"https://cy.wiktionary.org",cywikibooks:"https://cy.wikibooks.org",cywikiquote:"https://cy.wikiquote.org",cywikisource:"https://cy.wikisource.org",dawiki:"https://da.wikipedia.org",dawiktionary:"https://da.wiktionary.org",dawikibooks:"https://da.wikibooks.org",dawikiquote:"https://da.wikiquote.org",dawikisource:"https://da.wikisource.org",dewiki:"https://de.wikipedia.org",dewiktionary:"https://de.wiktionary.org",dewikibooks:"https://de.wikibooks.org",dewikinews:"https://de.wikinews.org",dewikiquote:"https://de.wikiquote.org",dewikisource:"https://de.wikisource.org",dewikiversity:"https://de.wikiversity.org",dewikivoyage:"https://de.wikivoyage.org",diqwiki:"https://diq.wikipedia.org",dsbwiki:"https://dsb.wikipedia.org",dvwiki:"https://dv.wikipedia.org",dvwiktionary:"https://dv.wiktionary.org",dzwiki:"https://dz.wikipedia.org",dzwiktionary:"https://dz.wiktionary.org",eewiki:"https://ee.wikipedia.org",elwiki:"https://el.wikipedia.org",elwiktionary:"https://el.wiktionary.org",elwikibooks:"https://el.wikibooks.org",elwikinews:"https://el.wikinews.org",elwikiquote:"https://el.wikiquote.org",elwikisource:"https://el.wikisource.org",elwikiversity:"https://el.wikiversity.org",elwikivoyage:"https://el.wikivoyage.org",emlwiki:"https://eml.wikipedia.org",enwiki:"https://en.wikipedia.org",enwiktionary:"https://en.wiktionary.org",enwikibooks:"https://en.wikibooks.org",enwikinews:"https://en.wikinews.org",enwikiquote:"https://en.wikiquote.org",enwikisource:"https://en.wikisource.org",enwikiversity:"https://en.wikiversity.org",enwikivoyage:"https://en.wikivoyage.org",eowiki:"https://eo.wikipedia.org",eowiktionary:"https://eo.wiktionary.org",eowikibooks:"https://eo.wikibooks.org",eowikinews:"https://eo.wikinews.org",eowikiquote:"https://eo.wikiquote.org",eowikisource:"https://eo.wikisource.org",eswiki:"https://es.wikipedia.org",eswiktionary:"https://es.wiktionary.org",eswikibooks:"https://es.wikibooks.org",eswikinews:"https://es.wikinews.org",eswikiquote:"https://es.wikiquote.org",eswikisource:"https://es.wikisource.org",eswikiversity:"https://es.wikiversity.org",eswikivoyage:"https://es.wikivoyage.org",etwiki:"https://et.wikipedia.org",etwiktionary:"https://et.wiktionary.org",etwikibooks:"https://et.wikibooks.org",etwikiquote:"https://et.wikiquote.org",etwikisource:"https://et.wikisource.org",euwiki:"https://eu.wikipedia.org",euwiktionary:"https://eu.wiktionary.org",euwikibooks:"https://eu.wikibooks.org",euwikiquote:"https://eu.wikiquote.org",extwiki:"https://ext.wikipedia.org",fawiki:"https://fa.wikipedia.org",fawiktionary:"https://fa.wiktionary.org",fawikibooks:"https://fa.wikibooks.org",fawikinews:"https://fa.wikinews.org",fawikiquote:"https://fa.wikiquote.org",fawikisource:"https://fa.wikisource.org",fawikivoyage:"https://fa.wikivoyage.org",ffwiki:"https://ff.wikipedia.org",fiwiki:"https://fi.wikipedia.org",fiwiktionary:"https://fi.wiktionary.org",fiwikibooks:"https://fi.wikibooks.org",fiwikinews:"https://fi.wikinews.org",fiwikiquote:"https://fi.wikiquote.org",fiwikisource:"https://fi.wikisource.org",fiwikiversity:"https://fi.wikiversity.org",fiu_vrowiki:"https://fiu-vro.wikipedia.org",fjwiki:"https://fj.wikipedia.org",fjwiktionary:"https://fj.wiktionary.org",fowiki:"https://fo.wikipedia.org",fowiktionary:"https://fo.wiktionary.org",fowikisource:"https://fo.wikisource.org",frwiki:"https://fr.wikipedia.org",frwiktionary:"https://fr.wiktionary.org",frwikibooks:"https://fr.wikibooks.org",frwikinews:"https://fr.wikinews.org",frwikiquote:"https://fr.wikiquote.org",frwikisource:"https://fr.wikisource.org",frwikiversity:"https://fr.wikiversity.org",frwikivoyage:"https://fr.wikivoyage.org",frpwiki:"https://frp.wikipedia.org",frrwiki:"https://frr.wikipedia.org",furwiki:"https://fur.wikipedia.org",fywiki:"https://fy.wikipedia.org",fywiktionary:"https://fy.wiktionary.org",fywikibooks:"https://fy.wikibooks.org",gawiki:"https://ga.wikipedia.org",gawiktionary:"https://ga.wiktionary.org",gawikibooks:"https://ga.wikibooks.org",gawikiquote:"https://ga.wikiquote.org",gagwiki:"https://gag.wikipedia.org",ganwiki:"https://gan.wikipedia.org",gdwiki:"https://gd.wikipedia.org",gdwiktionary:"https://gd.wiktionary.org",glwiki:"https://gl.wikipedia.org",glwiktionary:"https://gl.wiktionary.org",glwikibooks:"https://gl.wikibooks.org",glwikiquote:"https://gl.wikiquote.org",glwikisource:"https://gl.wikisource.org",glkwiki:"https://glk.wikipedia.org",gnwiki:"https://gn.wikipedia.org",gnwiktionary:"https://gn.wiktionary.org",gnwikibooks:"https://gn.wikibooks.org",gotwiki:"https://got.wikipedia.org",gotwikibooks:"https://got.wikibooks.org",guwiki:"https://gu.wikipedia.org",guwiktionary:"https://gu.wiktionary.org",guwikibooks:"https://gu.wikibooks.org",guwikiquote:"https://gu.wikiquote.org",guwikisource:"https://gu.wikisource.org",gvwiki:"https://gv.wikipedia.org",gvwiktionary:"https://gv.wiktionary.org",hawiki:"https://ha.wikipedia.org",hawiktionary:"https://ha.wiktionary.org",hakwiki:"https://hak.wikipedia.org",hawwiki:"https://haw.wikipedia.org",hewiki:"https://he.wikipedia.org",hewiktionary:"https://he.wiktionary.org",hewikibooks:"https://he.wikibooks.org",hewikinews:"https://he.wikinews.org",hewikiquote:"https://he.wikiquote.org",hewikisource:"https://he.wikisource.org",hewikivoyage:"https://he.wikivoyage.org",hiwiki:"https://hi.wikipedia.org",hiwiktionary:"https://hi.wiktionary.org",hiwikibooks:"https://hi.wikibooks.org",hiwikiquote:"https://hi.wikiquote.org",hifwiki:"https://hif.wikipedia.org",howiki:"https://ho.wikipedia.org",hrwiki:"https://hr.wikipedia.org",hrwiktionary:"https://hr.wiktionary.org",hrwikibooks:"https://hr.wikibooks.org",hrwikiquote:"https://hr.wikiquote.org",hrwikisource:"https://hr.wikisource.org",hsbwiki:"https://hsb.wikipedia.org",hsbwiktionary:"https://hsb.wiktionary.org",htwiki:"https://ht.wikipedia.org",htwikisource:"https://ht.wikisource.org",huwiki:"https://hu.wikipedia.org",huwiktionary:"https://hu.wiktionary.org",huwikibooks:"https://hu.wikibooks.org",huwikinews:"https://hu.wikinews.org",huwikiquote:"https://hu.wikiquote.org",huwikisource:"https://hu.wikisource.org",hywiki:"https://hy.wikipedia.org",hywiktionary:"https://hy.wiktionary.org",hywikibooks:"https://hy.wikibooks.org",hywikiquote:"https://hy.wikiquote.org",hywikisource:"https://hy.wikisource.org",hzwiki:"https://hz.wikipedia.org",iawiki:"https://ia.wikipedia.org",iawiktionary:"https://ia.wiktionary.org",iawikibooks:"https://ia.wikibooks.org",idwiki:"https://id.wikipedia.org",idwiktionary:"https://id.wiktionary.org",idwikibooks:"https://id.wikibooks.org",idwikiquote:"https://id.wikiquote.org",idwikisource:"https://id.wikisource.org",iewiki:"https://ie.wikipedia.org",iewiktionary:"https://ie.wiktionary.org",iewikibooks:"https://ie.wikibooks.org",igwiki:"https://ig.wikipedia.org",iiwiki:"https://ii.wikipedia.org",ikwiki:"https://ik.wikipedia.org",ikwiktionary:"https://ik.wiktionary.org",ilowiki:"https://ilo.wikipedia.org",iowiki:"https://io.wikipedia.org",iowiktionary:"https://io.wiktionary.org",iswiki:"https://is.wikipedia.org",iswiktionary:"https://is.wiktionary.org",iswikibooks:"https://is.wikibooks.org",iswikiquote:"https://is.wikiquote.org",iswikisource:"https://is.wikisource.org",itwiki:"https://it.wikipedia.org",itwiktionary:"https://it.wiktionary.org",itwikibooks:"https://it.wikibooks.org",itwikinews:"https://it.wikinews.org",itwikiquote:"https://it.wikiquote.org",itwikisource:"https://it.wikisource.org",itwikiversity:"https://it.wikiversity.org",itwikivoyage:"https://it.wikivoyage.org",iuwiki:"https://iu.wikipedia.org",iuwiktionary:"https://iu.wiktionary.org",jawiki:"https://ja.wikipedia.org",jawiktionary:"https://ja.wiktionary.org",jawikibooks:"https://ja.wikibooks.org",jawikinews:"https://ja.wikinews.org",jawikiquote:"https://ja.wikiquote.org",jawikisource:"https://ja.wikisource.org",jawikiversity:"https://ja.wikiversity.org",jbowiki:"https://jbo.wikipedia.org",jbowiktionary:"https://jbo.wiktionary.org",jvwiki:"https://jv.wikipedia.org",jvwiktionary:"https://jv.wiktionary.org",kawiki:"https://ka.wikipedia.org",kawiktionary:"https://ka.wiktionary.org",kawikibooks:"https://ka.wikibooks.org",kawikiquote:"https://ka.wikiquote.org",kaawiki:"https://kaa.wikipedia.org",kabwiki:"https://kab.wikipedia.org",kbdwiki:"https://kbd.wikipedia.org",kgwiki:"https://kg.wikipedia.org",kiwiki:"https://ki.wikipedia.org",kjwiki:"https://kj.wikipedia.org",kkwiki:"https://kk.wikipedia.org",kkwiktionary:"https://kk.wiktionary.org",kkwikibooks:"https://kk.wikibooks.org",kkwikiquote:"https://kk.wikiquote.org",klwiki:"https://kl.wikipedia.org",klwiktionary:"https://kl.wiktionary.org",kmwiki:"https://km.wikipedia.org",kmwiktionary:"https://km.wiktionary.org",kmwikibooks:"https://km.wikibooks.org",knwiki:"https://kn.wikipedia.org",knwiktionary:"https://kn.wiktionary.org",knwikibooks:"https://kn.wikibooks.org",knwikiquote:"https://kn.wikiquote.org",knwikisource:"https://kn.wikisource.org",kowiki:"https://ko.wikipedia.org",kowiktionary:"https://ko.wiktionary.org",kowikibooks:"https://ko.wikibooks.org",kowikinews:"https://ko.wikinews.org",kowikiquote:"https://ko.wikiquote.org",kowikisource:"https://ko.wikisource.org",kowikiversity:"https://ko.wikiversity.org",koiwiki:"https://koi.wikipedia.org",krwiki:"https://kr.wikipedia.org",krwikiquote:"https://kr.wikiquote.org",krcwiki:"https://krc.wikipedia.org",kswiki:"https://ks.wikipedia.org",kswiktionary:"https://ks.wiktionary.org",kswikibooks:"https://ks.wikibooks.org",kswikiquote:"https://ks.wikiquote.org",kshwiki:"https://ksh.wikipedia.org",kuwiki:"https://ku.wikipedia.org",kuwiktionary:"https://ku.wiktionary.org",kuwikibooks:"https://ku.wikibooks.org",kuwikiquote:"https://ku.wikiquote.org",kvwiki:"https://kv.wikipedia.org",kwwiki:"https://kw.wikipedia.org",kwwiktionary:"https://kw.wiktionary.org",kwwikiquote:"https://kw.wikiquote.org",kywiki:"https://ky.wikipedia.org",kywiktionary:"https://ky.wiktionary.org",kywikibooks:"https://ky.wikibooks.org",kywikiquote:"https://ky.wikiquote.org",lawiki:"https://la.wikipedia.org",lawiktionary:"https://la.wiktionary.org",lawikibooks:"https://la.wikibooks.org",lawikiquote:"https://la.wikiquote.org",lawikisource:"https://la.wikisource.org",ladwiki:"https://lad.wikipedia.org",lbwiki:"https://lb.wikipedia.org",lbwiktionary:"https://lb.wiktionary.org",lbwikibooks:"https://lb.wikibooks.org",lbwikiquote:"https://lb.wikiquote.org",lbewiki:"https://lbe.wikipedia.org",lezwiki:"https://lez.wikipedia.org",lgwiki:"https://lg.wikipedia.org",liwiki:"https://li.wikipedia.org",liwiktionary:"https://li.wiktionary.org",liwikibooks:"https://li.wikibooks.org",liwikiquote:"https://li.wikiquote.org",liwikisource:"https://li.wikisource.org",lijwiki:"https://lij.wikipedia.org",lmowiki:"https://lmo.wikipedia.org",lnwiki:"https://ln.wikipedia.org",lnwiktionary:"https://ln.wiktionary.org",lnwikibooks:"https://ln.wikibooks.org",lowiki:"https://lo.wikipedia.org",lowiktionary:"https://lo.wiktionary.org",ltwiki:"https://lt.wikipedia.org",ltwiktionary:"https://lt.wiktionary.org",ltwikibooks:"https://lt.wikibooks.org",ltwikiquote:"https://lt.wikiquote.org",ltwikisource:"https://lt.wikisource.org",ltgwiki:"https://ltg.wikipedia.org",lvwiki:"https://lv.wikipedia.org",lvwiktionary:"https://lv.wiktionary.org",lvwikibooks:"https://lv.wikibooks.org",maiwiki:"https://mai.wikipedia.org",map_bmswiki:"https://map-bms.wikipedia.org",mdfwiki:"https://mdf.wikipedia.org",mgwiki:"https://mg.wikipedia.org",mgwiktionary:"https://mg.wiktionary.org",mgwikibooks:"https://mg.wikibooks.org",mhwiki:"https://mh.wikipedia.org",mhwiktionary:"https://mh.wiktionary.org",mhrwiki:"https://mhr.wikipedia.org",miwiki:"https://mi.wikipedia.org",miwiktionary:"https://mi.wiktionary.org",miwikibooks:"https://mi.wikibooks.org",minwiki:"https://min.wikipedia.org",mkwiki:"https://mk.wikipedia.org",mkwiktionary:"https://mk.wiktionary.org",mkwikibooks:"https://mk.wikibooks.org",mkwikisource:"https://mk.wikisource.org",mlwiki:"https://ml.wikipedia.org",mlwiktionary:"https://ml.wiktionary.org",mlwikibooks:"https://ml.wikibooks.org",mlwikiquote:"https://ml.wikiquote.org",mlwikisource:"https://ml.wikisource.org",mnwiki:"https://mn.wikipedia.org",mnwiktionary:"https://mn.wiktionary.org",mnwikibooks:"https://mn.wikibooks.org",mowiki:"https://mo.wikipedia.org",mowiktionary:"https://mo.wiktionary.org",mrwiki:"https://mr.wikipedia.org",mrwiktionary:"https://mr.wiktionary.org",mrwikibooks:"https://mr.wikibooks.org",mrwikiquote:"https://mr.wikiquote.org",mrwikisource:"https://mr.wikisource.org",mrjwiki:"https://mrj.wikipedia.org",mswiki:"https://ms.wikipedia.org",mswiktionary:"https://ms.wiktionary.org",mswikibooks:"https://ms.wikibooks.org",mtwiki:"https://mt.wikipedia.org",mtwiktionary:"https://mt.wiktionary.org",muswiki:"https://mus.wikipedia.org",mwlwiki:"https://mwl.wikipedia.org",mywiki:"https://my.wikipedia.org",mywiktionary:"https://my.wiktionary.org",mywikibooks:"https://my.wikibooks.org",myvwiki:"https://myv.wikipedia.org",mznwiki:"https://mzn.wikipedia.org",nawiki:"https://na.wikipedia.org",nawiktionary:"https://na.wiktionary.org",nawikibooks:"https://na.wikibooks.org",nawikiquote:"https://na.wikiquote.org",nahwiki:"https://nah.wikipedia.org",nahwiktionary:"https://nah.wiktionary.org",nahwikibooks:"https://nah.wikibooks.org",napwiki:"https://nap.wikipedia.org",ndswiki:"https://nds.wikipedia.org",ndswiktionary:"https://nds.wiktionary.org",ndswikibooks:"https://nds.wikibooks.org",ndswikiquote:"https://nds.wikiquote.org",nds_nlwiki:"https://nds-nl.wikipedia.org",newiki:"https://ne.wikipedia.org",newiktionary:"https://ne.wiktionary.org",newikibooks:"https://ne.wikibooks.org",newwiki:"https://new.wikipedia.org",ngwiki:"https://ng.wikipedia.org",nlwiki:"https://nl.wikipedia.org",nlwiktionary:"https://nl.wiktionary.org",nlwikibooks:"https://nl.wikibooks.org",nlwikinews:"https://nl.wikinews.org",nlwikiquote:"https://nl.wikiquote.org",nlwikisource:"https://nl.wikisource.org",nlwikivoyage:"https://nl.wikivoyage.org",nnwiki:"https://nn.wikipedia.org",nnwiktionary:"https://nn.wiktionary.org",nnwikiquote:"https://nn.wikiquote.org",nowiki:"https://no.wikipedia.org",nowiktionary:"https://no.wiktionary.org",nowikibooks:"https://no.wikibooks.org",nowikinews:"https://no.wikinews.org",nowikiquote:"https://no.wikiquote.org",nowikisource:"https://no.wikisource.org",novwiki:"https://nov.wikipedia.org",nrmwiki:"https://nrm.wikipedia.org",nsowiki:"https://nso.wikipedia.org",nvwiki:"https://nv.wikipedia.org",nywiki:"https://ny.wikipedia.org",ocwiki:"https://oc.wikipedia.org",ocwiktionary:"https://oc.wiktionary.org",ocwikibooks:"https://oc.wikibooks.org",omwiki:"https://om.wikipedia.org",omwiktionary:"https://om.wiktionary.org",orwiki:"https://or.wikipedia.org",orwiktionary:"https://or.wiktionary.org",orwikisource:"https://or.wikisource.org",oswiki:"https://os.wikipedia.org",pawiki:"https://pa.wikipedia.org",pawiktionary:"https://pa.wiktionary.org",pawikibooks:"https://pa.wikibooks.org",pagwiki:"https://pag.wikipedia.org",pamwiki:"https://pam.wikipedia.org",papwiki:"https://pap.wikipedia.org",pcdwiki:"https://pcd.wikipedia.org",pdcwiki:"https://pdc.wikipedia.org",pflwiki:"https://pfl.wikipedia.org",piwiki:"https://pi.wikipedia.org",piwiktionary:"https://pi.wiktionary.org",pihwiki:"https://pih.wikipedia.org",plwiki:"https://pl.wikipedia.org",plwiktionary:"https://pl.wiktionary.org",plwikibooks:"https://pl.wikibooks.org",plwikinews:"https://pl.wikinews.org",plwikiquote:"https://pl.wikiquote.org",plwikisource:"https://pl.wikisource.org",plwikivoyage:"https://pl.wikivoyage.org",pmswiki:"https://pms.wikipedia.org",pnbwiki:"https://pnb.wikipedia.org",pnbwiktionary:"https://pnb.wiktionary.org",pntwiki:"https://pnt.wikipedia.org",pswiki:"https://ps.wikipedia.org",pswiktionary:"https://ps.wiktionary.org",pswikibooks:"https://ps.wikibooks.org",ptwiki:"https://pt.wikipedia.org",ptwiktionary:"https://pt.wiktionary.org",ptwikibooks:"https://pt.wikibooks.org",ptwikinews:"https://pt.wikinews.org",ptwikiquote:"https://pt.wikiquote.org",ptwikisource:"https://pt.wikisource.org",ptwikiversity:"https://pt.wikiversity.org",ptwikivoyage:"https://pt.wikivoyage.org",quwiki:"https://qu.wikipedia.org",quwiktionary:"https://qu.wiktionary.org",quwikibooks:"https://qu.wikibooks.org",quwikiquote:"https://qu.wikiquote.org",rmwiki:"https://rm.wikipedia.org",rmwiktionary:"https://rm.wiktionary.org",rmwikibooks:"https://rm.wikibooks.org",rmywiki:"https://rmy.wikipedia.org",rnwiki:"https://rn.wikipedia.org",rnwiktionary:"https://rn.wiktionary.org",rowiki:"https://ro.wikipedia.org",rowiktionary:"https://ro.wiktionary.org",rowikibooks:"https://ro.wikibooks.org",rowikinews:"https://ro.wikinews.org",rowikiquote:"https://ro.wikiquote.org",rowikisource:"https://ro.wikisource.org",rowikivoyage:"https://ro.wikivoyage.org",roa_rupwiki:"https://roa-rup.wikipedia.org",roa_rupwiktionary:"https://roa-rup.wiktionary.org",roa_tarawiki:"https://roa-tara.wikipedia.org",ruwiki:"https://ru.wikipedia.org",ruwiktionary:"https://ru.wiktionary.org",ruwikibooks:"https://ru.wikibooks.org",ruwikinews:"https://ru.wikinews.org",ruwikiquote:"https://ru.wikiquote.org",ruwikisource:"https://ru.wikisource.org",ruwikiversity:"https://ru.wikiversity.org",ruwikivoyage:"https://ru.wikivoyage.org",ruewiki:"https://rue.wikipedia.org",rwwiki:"https://rw.wikipedia.org",rwwiktionary:"https://rw.wiktionary.org",sawiki:"https://sa.wikipedia.org",sawiktionary:"https://sa.wiktionary.org",sawikibooks:"https://sa.wikibooks.org",sawikiquote:"https://sa.wikiquote.org",sawikisource:"https://sa.wikisource.org",sahwiki:"https://sah.wikipedia.org",sahwikisource:"https://sah.wikisource.org",scwiki:"https://sc.wikipedia.org",scwiktionary:"https://sc.wiktionary.org",scnwiki:"https://scn.wikipedia.org",scnwiktionary:"https://scn.wiktionary.org",scowiki:"https://sco.wikipedia.org",sdwiki:"https://sd.wikipedia.org",sdwiktionary:"https://sd.wiktionary.org",sdwikinews:"https://sd.wikinews.org",sewiki:"https://se.wikipedia.org",sewikibooks:"https://se.wikibooks.org",sgwiki:"https://sg.wikipedia.org",sgwiktionary:"https://sg.wiktionary.org",shwiki:"https://sh.wikipedia.org",shwiktionary:"https://sh.wiktionary.org",siwiki:"https://si.wikipedia.org",siwiktionary:"https://si.wiktionary.org",siwikibooks:"https://si.wikibooks.org",simplewiki:"https://simple.wikipedia.org",simplewiktionary:"https://simple.wiktionary.org",simplewikibooks:"https://simple.wikibooks.org",simplewikiquote:"https://simple.wikiquote.org",skwiki:"https://sk.wikipedia.org",skwiktionary:"https://sk.wiktionary.org",skwikibooks:"https://sk.wikibooks.org",skwikiquote:"https://sk.wikiquote.org",skwikisource:"https://sk.wikisource.org",slwiki:"https://sl.wikipedia.org",slwiktionary:"https://sl.wiktionary.org",slwikibooks:"https://sl.wikibooks.org",slwikiquote:"https://sl.wikiquote.org",slwikisource:"https://sl.wikisource.org",slwikiversity:"https://sl.wikiversity.org",smwiki:"https://sm.wikipedia.org",smwiktionary:"https://sm.wiktionary.org",snwiki:"https://sn.wikipedia.org",snwiktionary:"https://sn.wiktionary.org",sowiki:"https://so.wikipedia.org",sowiktionary:"https://so.wiktionary.org",sqwiki:"https://sq.wikipedia.org",sqwiktionary:"https://sq.wiktionary.org",sqwikibooks:"https://sq.wikibooks.org",sqwikinews:"https://sq.wikinews.org",sqwikiquote:"https://sq.wikiquote.org",srwiki:"https://sr.wikipedia.org",srwiktionary:"https://sr.wiktionary.org",srwikibooks:"https://sr.wikibooks.org",srwikinews:"https://sr.wikinews.org",srwikiquote:"https://sr.wikiquote.org",srwikisource:"https://sr.wikisource.org",srnwiki:"https://srn.wikipedia.org",sswiki:"https://ss.wikipedia.org",sswiktionary:"https://ss.wiktionary.org",stwiki:"https://st.wikipedia.org",stwiktionary:"https://st.wiktionary.org",stqwiki:"https://stq.wikipedia.org",suwiki:"https://su.wikipedia.org",suwiktionary:"https://su.wiktionary.org",suwikibooks:"https://su.wikibooks.org",suwikiquote:"https://su.wikiquote.org",svwiki:"https://sv.wikipedia.org",svwiktionary:"https://sv.wiktionary.org",svwikibooks:"https://sv.wikibooks.org",svwikinews:"https://sv.wikinews.org",svwikiquote:"https://sv.wikiquote.org",svwikisource:"https://sv.wikisource.org",svwikiversity:"https://sv.wikiversity.org",svwikivoyage:"https://sv.wikivoyage.org",swwiki:"https://sw.wikipedia.org",swwiktionary:"https://sw.wiktionary.org",swwikibooks:"https://sw.wikibooks.org",szlwiki:"https://szl.wikipedia.org",tawiki:"https://ta.wikipedia.org",tawiktionary:"https://ta.wiktionary.org",tawikibooks:"https://ta.wikibooks.org",tawikinews:"https://ta.wikinews.org",tawikiquote:"https://ta.wikiquote.org",tawikisource:"https://ta.wikisource.org",tewiki:"https://te.wikipedia.org",tewiktionary:"https://te.wiktionary.org",tewikibooks:"https://te.wikibooks.org",tewikiquote:"https://te.wikiquote.org",tewikisource:"https://te.wikisource.org",tetwiki:"https://tet.wikipedia.org",tgwiki:"https://tg.wikipedia.org",tgwiktionary:"https://tg.wiktionary.org",tgwikibooks:"https://tg.wikibooks.org",thwiki:"https://th.wikipedia.org",thwiktionary:"https://th.wiktionary.org",thwikibooks:"https://th.wikibooks.org",thwikinews:"https://th.wikinews.org",thwikiquote:"https://th.wikiquote.org",thwikisource:"https://th.wikisource.org",tiwiki:"https://ti.wikipedia.org",tiwiktionary:"https://ti.wiktionary.org",tkwiki:"https://tk.wikipedia.org",tkwiktionary:"https://tk.wiktionary.org",tkwikibooks:"https://tk.wikibooks.org",tkwikiquote:"https://tk.wikiquote.org",tlwiki:"https://tl.wikipedia.org",tlwiktionary:"https://tl.wiktionary.org",tlwikibooks:"https://tl.wikibooks.org",tnwiki:"https://tn.wikipedia.org",tnwiktionary:"https://tn.wiktionary.org",towiki:"https://to.wikipedia.org",towiktionary:"https://to.wiktionary.org",tpiwiki:"https://tpi.wikipedia.org",tpiwiktionary:"https://tpi.wiktionary.org",trwiki:"https://tr.wikipedia.org",trwiktionary:"https://tr.wiktionary.org",trwikibooks:"https://tr.wikibooks.org",trwikinews:"https://tr.wikinews.org",trwikiquote:"https://tr.wikiquote.org",trwikisource:"https://tr.wikisource.org",tswiki:"https://ts.wikipedia.org",tswiktionary:"https://ts.wiktionary.org",ttwiki:"https://tt.wikipedia.org",ttwiktionary:"https://tt.wiktionary.org",ttwikibooks:"https://tt.wikibooks.org",ttwikiquote:"https://tt.wikiquote.org",tumwiki:"https://tum.wikipedia.org",twwiki:"https://tw.wikipedia.org",twwiktionary:"https://tw.wiktionary.org",tywiki:"https://ty.wikipedia.org",tyvwiki:"https://tyv.wikipedia.org",udmwiki:"https://udm.wikipedia.org",ugwiki:"https://ug.wikipedia.org",ugwiktionary:"https://ug.wiktionary.org",ugwikibooks:"https://ug.wikibooks.org",ugwikiquote:"https://ug.wikiquote.org",ukwiki:"https://uk.wikipedia.org",ukwiktionary:"https://uk.wiktionary.org",ukwikibooks:"https://uk.wikibooks.org",ukwikinews:"https://uk.wikinews.org",ukwikiquote:"https://uk.wikiquote.org",ukwikisource:"https://uk.wikisource.org",ukwikivoyage:"https://uk.wikivoyage.org",urwiki:"https://ur.wikipedia.org",urwiktionary:"https://ur.wiktionary.org",urwikibooks:"https://ur.wikibooks.org",urwikiquote:"https://ur.wikiquote.org",uzwiki:"https://uz.wikipedia.org",uzwiktionary:"https://uz.wiktionary.org",uzwikibooks:"https://uz.wikibooks.org",uzwikiquote:"https://uz.wikiquote.org",vewiki:"https://ve.wikipedia.org",vecwiki:"https://vec.wikipedia.org",vecwiktionary:"https://vec.wiktionary.org",vecwikisource:"https://vec.wikisource.org",vepwiki:"https://vep.wikipedia.org",viwiki:"https://vi.wikipedia.org",viwiktionary:"https://vi.wiktionary.org",viwikibooks:"https://vi.wikibooks.org",viwikiquote:"https://vi.wikiquote.org",viwikisource:"https://vi.wikisource.org",viwikivoyage:"https://vi.wikivoyage.org",vlswiki:"https://vls.wikipedia.org",vowiki:"https://vo.wikipedia.org",vowiktionary:"https://vo.wiktionary.org",vowikibooks:"https://vo.wikibooks.org",vowikiquote:"https://vo.wikiquote.org",wawiki:"https://wa.wikipedia.org",wawiktionary:"https://wa.wiktionary.org",wawikibooks:"https://wa.wikibooks.org",warwiki:"https://war.wikipedia.org",wowiki:"https://wo.wikipedia.org",wowiktionary:"https://wo.wiktionary.org",wowikiquote:"https://wo.wikiquote.org",wuuwiki:"https://wuu.wikipedia.org",xalwiki:"https://xal.wikipedia.org",xhwiki:"https://xh.wikipedia.org",xhwiktionary:"https://xh.wiktionary.org",xhwikibooks:"https://xh.wikibooks.org",xmfwiki:"https://xmf.wikipedia.org",yiwiki:"https://yi.wikipedia.org",yiwiktionary:"https://yi.wiktionary.org",yiwikisource:"https://yi.wikisource.org",yowiki:"https://yo.wikipedia.org",yowiktionary:"https://yo.wiktionary.org",yowikibooks:"https://yo.wikibooks.org",zawiki:"https://za.wikipedia.org",zawiktionary:"https://za.wiktionary.org",zawikibooks:"https://za.wikibooks.org",zawikiquote:"https://za.wikiquote.org",zeawiki:"https://zea.wikipedia.org",zhwiki:"https://zh.wikipedia.org",zhwiktionary:"https://zh.wiktionary.org",zhwikibooks:"https://zh.wikibooks.org",zhwikinews:"https://zh.wikinews.org",zhwikiquote:"https://zh.wikiquote.org",zhwikisource:"https://zh.wikisource.org",zhwikivoyage:"https://zh.wikivoyage.org",zh_classicalwiki:"https://zh-classical.wikipedia.org",zh_min_nanwiki:"https://zh-min-nan.wikipedia.org",zh_min_nanwiktionary:"https://zh-min-nan.wiktionary.org",zh_min_nanwikibooks:"https://zh-min-nan.wikibooks.org",zh_min_nanwikiquote:"https://zh-min-nan.wikiquote.org",zh_min_nanwikisource:"https://zh-min-nan.wikisource.org",zh_yuewiki:"https://zh-yue.wikipedia.org",zuwiki:"https://zu.wikipedia.org",zuwiktionary:"https://zu.wiktionary.org",zuwikibooks:"https://zu.wikibooks.org"};"undefined"!=typeof t&&t.exports&&(t.exports=o)},{}],14:[function(i,t,e){"use strict";var o=i("./lib/fetch_text"),r=i("./parse"),s=function(i,t,e){return"function"==typeof t&&(e=t,t="en"),e=e||function(){},t=t||"en",o?o(i,t,e):e(null)},n=function(i){var t=r(i)||{},e=Object.keys(t.sections).map(function(i){return t.sections[i].sentences.map(function(i){return i.text}).join(" ")});return e.join("\n\n")};t.exports={from_api:s,parse:r,plaintext:n}},{"./lib/fetch_text":15,"./parse":23}],15:[function(i,t,e){"use strict";var o=i("superagent"),r=i("../data/site_map"),s=i("../parse/page/redirects"),n=function i(t,e,n){e=e||"en";var a="titles";t.match(/^[0-9]*$/)&&t.length>3&&(a="curid");var l=void 0;l=r[e]?r[e]+"/w/api.php":"https://"+e+".wikipedia.org/w/api.php",l+="?action=query&prop=revisions&rvlimit=1&rvprop=content&format=json&origin=*",l+="&"+a+"="+encodeURIComponent(t),o.get(l).end(function(t,o){if(t)return console.warn(t),void n(null);var r=o.body.query.pages||{},a=Object.keys(r)[0];if(a){var l=r[a];if(l&&l.revisions&&l.revisions[0]){var h=l.revisions[0]["*"];if(s.is_redirect(h)){var k=s.parse_redirect(h);return void i(k.redirect,e,n)}n(h)}else n(null)}})};t.exports=n},{"../data/site_map":13,"../parse/page/redirects":28,superagent:3}],16:[function(i,t,e){"use strict";var o={capitalise:function(i){return i&&"string"==typeof i?i.charAt(0).toUpperCase()+i.slice(1):""},onlyUnique:function(i,t,e){return e.indexOf(i)===t},trim_whitespace:function(i){return i&&"string"==typeof i?(i=i.replace(/^\s\s*/,""),i=i.replace(/\s\s*$/,""),i=i.replace(/ {2}/," "),i=i.replace(/\s, /,", ")):""}};t.exports=o},{}],17:[function(i,t,e){"use strict";var o=i("jshashes"),r=function(i){var t=i.replace(/^(image|file?)\:/i,"");t=t.charAt(0).toUpperCase()+t.substring(1),t=t.replace(/ /g,"_");var e=(new o.MD5).hex(t),r=e.substr(0,1)+"/"+e.substr(0,2)+"/";t=encodeURIComponent(t),r+=t;var s="https://upload.wikimedia.org/wikipedia/commons/",n="/300px-"+t;return{url:s+r,file:i,thumb:s+"thumb/"+r+n}};t.exports=r},{jshashes:2}],18:[function(i,t,e){"use strict";var o=i("../data/abbreviations"),r=new RegExp("(^| )("+o.join("|")+")[.!?] ?$","i"),s=new RegExp("[ |.][A-Z].? +?$","i"),n=new RegExp("\\.\\.\\.* +?$"),a=function(i){var t=[];return i.forEach(function(i){t=t.concat(i)}),t},l=function(i){var t=i.split(/(\n+)/);return t=t.map(function(i){return i.split(/(\S.+?[.!?])(?=\s+|$)/g)}),a(t)},h=function(i){i=i||"";var t=i.split(/\[\[/)||[],e=i.split(/\]\]/)||[];if(t.length>e.length)return!1;var o=i.match(/"/g);return!(o&&o.length%2!==0&&i.length<900)},k=function(i){var t=[],e=[];if(!i||"string"!=typeof i||!i.match(/\w/))return t;for(var o=l(i),a=0;a0&&(t.push(e[p]),e[p]="");return 0===t.length?[i]:t};t.exports=k},{"../data/abbreviations":10}],19:[function(i,t,e){"use strict";var o=i("../data/i18n"),r=new RegExp("\\[\\[:?("+o.categories.join("|")+"):(.{2,60}?)]](w{0,10})","ig"),s=new RegExp("^\\[\\[:?("+o.categories.join("|")+"):","ig"),n=function(i,t){i.categories=[];var e=t.match(r);return e&&e.forEach(function(t){t=t.replace(s,""),t=t.replace(/\|?[ \*]?\]\]$/i,""),t=t.replace(/\|.*/,""),t&&!t.match(/[\[\]]/)&&i.categories.push(t)}),t};t.exports=n},{"../data/i18n":11}],20:[function(i,t,e){"use strict";var o=function(i){return i=i.replace(/ ?[\s\S]{0,750}?<\/ref> ?/gi," "),i=i.replace(/ ?]{0,200}?\/> ?/gi," "),i=i.replace(/ ?]{0,200}?>[\s\S]{0,500}?<\/ref> ?/gi," "),i=i.replace(/< ?(table|code|score|data|categorytree|charinsert|gallery|hiero|imagemap|inputbox|math|nowiki|poem|references|source|syntaxhighlight|timeline) ?[^>]{0,200}?>[\s\S]{0,700}< ?\/ ?(table|code|score|data|categorytree|charinsert|gallery|hiero|imagemap|inputbox|math|nowiki|poem|references|source|syntaxhighlight|timeline) ?>/gi," "),i=i.replace(/ ?< ?(ref|span|div|table|data) [a-z0-9=" ]{2,20}\/ ?> ?/g," "),i=i.replace(/ ?<[ \/]?(p|sub|sup|span|nowiki|div|table|br|tr|td|th|pre|pre2|hr)[ \/]?> ?/g," "),i=i.replace(/ ?<[ \/]?(abbr|bdi|bdo|blockquote|cite|del|dfn|em|i|ins|kbd|mark|q|s)[ \/]?> ?/g," "),i=i.replace(/ ?<[ \/]?h[0-9][ \/]?> ?/g," "),i=i.replace(/ ?<[ \/]?[a-z0-9]{1,8}[ \/]?> ?/g," "),i=i.replace(/ ?< ?br ?\/> ?/g," "),i.trim()};t.exports=o},{}],21:[function(i,t,e){"use strict";function o(i){return i=i.replace(//g,""),i=i.replace(/__(NOTOC|NOEDITSECTION|FORCETOC|TOC)__/gi,""),i=i.replace(/~~{1,3}/,""),i=i.replace(/--{1,3}/,""),i=i.replace(/ /g," "),i=i.replace(/\[\[([a-z][a-z]|simple|war|ceb|min):.{2,60}\]\]/i,""),i=i.replace(/''{4}([^']{0,200})''{4}/g,"$1"),i=i.replace(/''{2}([^']{0,200})''{2}/g,"$1"),i=i.replace(/''([^']{0,200})''/g,"$1"),i=r(i)}var r=i("./kill_xml");t.exports=o},{"./kill_xml":20}],22:[function(i,t,e){"use strict";var o=i("../../data/languages"),r=["January","February","March","April","May","June","July","August","September","October","November","December"],s=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],n=function(i){i=i.replace(/\{\{URL\|([^ ]{4,100}?)\}\}/gi,"$1"),i=i.replace(/\{\{convert\|([0-9]*?)\|([^\|]*?)\}\}/gi,"$1 $2");var t=new Date;if(i=i.replace(/\{\{(CURRENT|LOCAL)DAY(2)?\}\}/gi,t.getDate()),i=i.replace(/\{\{(CURRENT|LOCAL)MONTH(NAME|ABBREV)?\}\}/gi,r[t.getMonth()]), -i=i.replace(/\{\{(CURRENT|LOCAL)YEAR\}\}/gi,t.getFullYear()),i=i.replace(/\{\{(CURRENT|LOCAL)DAYNAME\}\}/gi,s[t.getDay()]),i=i.replace(/\{\{(lc|uc|formatnum):(.*?)\}\}/gi,"$2"),i=i.replace(/\{\{pull quote\|([\s\S]*?)(\|[\s\S]*?)?\}\}/gi,"$1"),i=i.replace(/\{\{cquote\|([\s\S]*?)(\|[\s\S]*?)?\}\}/gi,"$1"),i=i.replace(/\{\{(small|smaller|midsize|larger|big|bigger|large|huge|resize)\|([\s\S]*?)\}\}/gi,"$2"),i.match(/\{\{dts\|/)){var e=(i.match(/\{\{dts\|(.*?)[\}\|]/)||[])[1]||"";e=new Date(e),i=e&&e.getTime()?i.replace(/\{\{dts\|.*?\}\}/gi,e.toDateString()):i.replace(/\{\{dts\|.*?\}\}/gi," ")}if(i.match(/\{\{date\|.*?\}\}/)){var n=i.match(/\{\{date\|(.*?)\|(.*?)\|(.*?)\}\}/)||[]||[],a=n[1]+" "+n[2]+" "+n[3];i=i.replace(/\{\{date\|.*?\}\}/gi,a)}if(i=i.replace(/\{\{term\|(.*?)\|.*?\}\}/gi,"'$1'"),i=i.replace(/\{\{IPA\|(.*?)\|.*?\}\}/gi,"$1"),i=i.replace(/\{\{sense\|(.*?)\|?.*?\}\}/gi,"($1)"),i=i.replace(/\{\{t\+?\|...?\|(.*?)(\|.*)?\}\}/gi,"'$1'"),i.match(/\{\{etyl\|/)){var l=i.match(/\{\{etyl\|(.*?)\|.*?\}\}/i)[1]||"";l=l.toLowerCase(),i=l&&o[l]?i.replace(/\{\{etyl\|(.*?)\|.*?\}\}/gi,o[l].english_title):i.replace(/\{\{etyl\|(.*?)\|.*?\}\}/gi,"($1)")}return i};t.exports=n},{"../../data/languages":12}],23:[function(i,t,e){"use strict";var o=i("./page/redirects"),r=i("./page/disambig"),s=i("./cleanup/word_templates"),n=i("./cleanup/misc"),a=i("./table"),l=i("./categories"),h=i("./recursive"),k=i("./lines"),w=function(i){if(i=i||"",o.is_redirect(i))return o.parse_redirect(i);if(r.is_disambig(i))return r.parse_disambig(i);var t={type:"page",sections:{},categories:[],images:[],infobox:{},infobox_template:{},tables:[],translations:{}};return i=s(i),i=n(i),i=a(t,i),i=h(t,i),i=i.replace(/\{\{.*?\}\}/g,""),i=l(t,i),i=k(t,i),t};t.exports=w},{"./categories":19,"./cleanup/misc":21,"./cleanup/word_templates":22,"./lines":24,"./page/disambig":27,"./page/redirects":28,"./recursive":31,"./table":34}],24:[function(i,t,e){"use strict";var o=i("../../lib/helpers"),r=i("./lists"),s=i("./sentence"),n=/^(={1,5})([^=]{1,200}?)={1,5}$/,a=function(i){var t=i[2]||"";t=o.trim_whitespace(t);var e=1;return i[1]&&(e=i[1].length),{title:t,depth:e,sentences:[]}},l=function(i){for(var t=[a([])],e=0;e=0&&r.push(s[a]),0===n&&r.length>0){var l=r.filter(function(t){return t===i}),h=r.filter(function(i){return i===t});l.length>h.length&&r.push(t),o.push(r.join("")),r=[]}return o}t.exports=o},{}],30:[function(i,t,e){"use strict";var o=i("../../data/i18n"),r=i("../../lib/make_image"),s=new RegExp("("+o.images.concat(o.files).join("|")+"):.*?[\\|\\]]","i"),n=function(i){return i=i.match(s)||[""],i=i[0].replace(/[\|\]]$/,""),i=r(i)};t.exports=n},{"../../data/i18n":11,"../../lib/make_image":17}],31:[function(i,t,e){"use strict";var o=i("../../data/i18n"),r=i("../../data/languages"),s=i("./find"),n=i("./infobox"),a=i("./infobox_template"),l=i("./image"),h=new RegExp("{{("+o.infoboxes.join("|")+")[: \n]","ig"),k=new RegExp("\\[\\[("+o.images.concat(o.files).join("|")+")","i"),w=new RegExp("^("+o.images.concat(o.files).join("|")+")","i"),p=/^\{\{nowrap\|(.*?)\}\}$/,c=function(i,t){var e=s("{","}",t);if(e.forEach(function(e){if(e.match(h,"ig")&&0===Object.keys(i.infobox).length&&(i.infobox=n(e),i.infobox_template=a(e)),e.match(h)&&(t=t.replace(e,"")),e.match(/^\{\{/)){var o=e.match(p);if(o)return void(t=t.replace(e,o[1]));t=t.replace(e,"")}}),e=s("[","]",t),e.forEach(function(e){e.match(k)&&(i.images.push(l(e)),t=t.replace(e,""))}),e.forEach(function(e){if(null!==e.match(/\[\[([a-z][a-z]):(.*?)\]\]/i)){var o=e.match(/\[\[([a-z][a-z]):/i)[1];o&&r[o]&&(i.translations[o]=e.match(/\[\[([a-z][a-z]):(.*?)\]\]/i)[2]),t=t.replace(e,"")}}),i.infobox.image&&i.infobox.image.text){var o=i.infobox.image.text||"";"string"!=typeof o||o.match(w)||(o="File:"+o),i.images.push(o)}return t};t.exports=c},{"../../data/i18n":11,"../../data/languages":12,"./find":29,"./image":30,"./infobox":32,"./infobox_template":33}],32:[function(i,t,e){"use strict";var o=i("../../lib/helpers"),r=i("../text"),s=/\n *\|([^=]*)=(.*)/g,n=function(i){if(!i)return{};var t={},e=[],n=void 0;i=i.replace(/\{\{Collapsible list[^}]{10,1000}\}\}/g,"");for(var a=-2,l=0,h=i.length;l1&&(t=e[1])}return t}var r=i("../../data/i18n"),s=new RegExp("{{(?:"+r.infoboxes.join("|")+")\\s*(.*)","i");t.exports=o},{"../../data/i18n":11}],34:[function(i,t,e){"use strict";var o=i("../lib/helpers"),r=/\{\|[\s\S]{1,8000}?\|\}/g,s=function(i){var t=[],e=i.replace(/\r/g,"").split(/\n/);return e.forEach(function(i){if(!i.match(/^\|\}/)){if(i.match(/^\|-/))return void t.push([]);if(!i.match(/^\|\+/)&&i.match(/^[\!\|]/)){t[t.length-1]||(t[t.length-1]=[]);var e=(i.match(/\|(.*)/)||[])[1]||"";e=o.trim_whitespace(e)||"",e.match(/[!\|]{2}/)?e.split(/[!\|]{2}/g).forEach(function(i){i=o.trim_whitespace(i),t[t.length-1].push(i)}):t[t.length-1].push(e)}}}),t},n=function(i,t){return i.tables=t.match(r,"")||[],i.tables=i.tables.map(function(i){return s(i)}),t=t.replace(r,"")};t.exports=n},{"../lib/helpers":16}],35:[function(i,t,e){"use strict";function o(i){return i=h(i),i.match(/^(thumb|right|left)\|/i)?null:i=s.trim_whitespace(i)}function r(i){return{text:o(i),links:n(i)}}var s=i("../../lib/helpers"),n=i("./links"),a=i("../../data/i18n"),l=new RegExp("\\[\\[:?("+a.categories.join("|")+"):[^\\]\\]]{2,80}\\]\\]","gi"),h=function(i){return i=i.replace(l,""),i=i.replace(/\[\[:?([^|]{2,80}?)\]\](\w{0,5})/g,"$1$2"),i=i.replace(/\[\[File:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g,"$1"),i=i.replace(/\[\[:?(.{2,80}?)\|([^\]]+?)\]\](\w{0,5})/g,"$2$3"),i=i.replace(/\[(https?|news|ftp|mailto|gopher|irc):\/\/[^\]\| ]{4,1500}([\| ].*?)?\]/g,"$2")};t.exports=r},{"../../data/i18n":11,"../../lib/helpers":16,"./links":36}],36:[function(i,t,e){"use strict";var o=i("../../lib/helpers"),r=/\[\[(.{2,80}?)\]\](\w{0,10})/g,s=/^:?(category|catégorie|Kategorie|Categoría|Categoria|Categorie|Kategoria|تصنيف|image|file|image|fichier|datei|media|special|wp|wikipedia|help|user|mediawiki|portal|talk|template|book|draft|module|topic|wiktionary|wikisource):/i,n=/\[(https?|news|ftp|mailto|gopher|irc)(:\/\/[^\]\| ]{4,1500})([\| ].*?)?\]/g,a=function(i,t){return t.replace(n,function(t,e,o){var r="",s=o.match(/\[([^\| ]+)/);return s&&s[1]&&(r=s[1]),i.push({type:"external",site:e+o,text:r}),r}),i},l=function(i,t){return t.replace(r,function(t,e){var r,n;if(e.match(/\|/)?(e=e.replace(/\[\[(.{2,80}?)\]\](\w{0,10})/g,"$1$2"),r=e.replace(/(.{2,60})\|.{0,200}/,"$1"),n=e.replace(/.{2,60}?\|/,""),!n&&r.match(/\|$/)&&(r=r.replace(/\|$/,""),n=r)):r=e.replace(/\[\[(.{2,60}?)\]\](\w{0,10})/g,"$1"),r.match(s))return e;if(r.match(/^#/i))return e;r=r.replace(/#[^ ]{1,100}/,"");var a={page:o.capitalise(r),text:n||r};return i.push(a),e}),i},h=function(i){var t=[];if(t=a(t,i),t=l(t,i),0!==t.length)return t};t.exports=h},{"../../lib/helpers":16}]},{},[14])(14)}); +i=i.replace(/\{\{(CURRENT|LOCAL)YEAR\}\}/gi,t.getFullYear()),i=i.replace(/\{\{(CURRENT|LOCAL)DAYNAME\}\}/gi,s[t.getDay()]),i=i.replace(/\{\{(lc|uc|formatnum):(.*?)\}\}/gi,"$2"),i=i.replace(/\{\{pull quote\|([\s\S]*?)(\|[\s\S]*?)?\}\}/gi,"$1"),i=i.replace(/\{\{cquote\|([\s\S]*?)(\|[\s\S]*?)?\}\}/gi,"$1"),i=i.replace(/\{\{(small|smaller|midsize|larger|big|bigger|large|huge|resize)\|([\s\S]*?)\}\}/gi,"$2"),i.match(/\{\{dts\|/)){var e=(i.match(/\{\{dts\|(.*?)[\}\|]/)||[])[1]||"";e=new Date(e),i=e&&e.getTime()?i.replace(/\{\{dts\|.*?\}\}/gi,e.toDateString()):i.replace(/\{\{dts\|.*?\}\}/gi," ")}if(i.match(/\{\{date\|.*?\}\}/)){var n=i.match(/\{\{date\|(.*?)\|(.*?)\|(.*?)\}\}/)||[]||[],a=n[1]+" "+n[2]+" "+n[3];i=i.replace(/\{\{date\|.*?\}\}/gi,a)}if(i=i.replace(/\{\{term\|(.*?)\|.*?\}\}/gi,"'$1'"),i=i.replace(/\{\{IPA\|(.*?)\|.*?\}\}/gi,"$1"),i=i.replace(/\{\{sense\|(.*?)\|?.*?\}\}/gi,"($1)"),i=i.replace(/\{\{t\+?\|...?\|(.*?)(\|.*)?\}\}/gi,"'$1'"),i.match(/\{\{etyl\|/)){var l=i.match(/\{\{etyl\|(.*?)\|.*?\}\}/i)[1]||"";l=l.toLowerCase(),i=l&&o[l]?i.replace(/\{\{etyl\|(.*?)\|.*?\}\}/gi,o[l].english_title):i.replace(/\{\{etyl\|(.*?)\|.*?\}\}/gi,"($1)")}return i};t.exports=n},{"../../data/languages":12}],23:[function(i,t,e){"use strict";var o=i("./page/redirects"),r=i("./page/disambig"),s=i("./cleanup/word_templates"),n=i("./cleanup/misc"),a=i("./table"),l=i("./categories"),h=i("./recursive"),k=i("./lines"),w=function(i){if(i=i||"",o.is_redirect(i))return o.parse_redirect(i);if(r.is_disambig(i))return r.parse_disambig(i);var t={type:"page",sections:{},categories:[],images:[],infobox:{},infobox_template:{},tables:[],translations:{}};return i=s(i),i=n(i),i=a(t,i),i=h(t,i),i=i.replace(/\{\{.*?\}\}/g,""),i=l(t,i),i=k(t,i),t};t.exports=w},{"./categories":19,"./cleanup/misc":21,"./cleanup/word_templates":22,"./lines":24,"./page/disambig":27,"./page/redirects":28,"./recursive":31,"./table":34}],24:[function(i,t,e){"use strict";var o=i("../../lib/helpers"),r=i("./lists"),s=i("./sentence"),n=/^(={1,5})([^=]{1,200}?)={1,5}$/,a=function(i){var t=i[2]||"";t=o.trim_whitespace(t);var e=1;return i[1]&&(e=i[1].length),{title:t,depth:e,sentences:[]}},l=function(i){for(var t=[a([])],e=0;e=0&&r.push(s[a]),0===n&&r.length>0){var l=r.filter(function(t){return t===i}),h=r.filter(function(i){return i===t});l.length>h.length&&r.push(t),o.push(r.join("")),r=[]}return o}t.exports=o},{}],30:[function(i,t,e){"use strict";var o=i("../../data/i18n"),r=i("../../lib/make_image"),s=new RegExp("("+o.images.concat(o.files).join("|")+"):.*?[\\|\\]]","i"),n=function(i){return i=i.match(s)||[""],i=i[0].replace(/[\|\]]$/,""),i=r(i)};t.exports=n},{"../../data/i18n":11,"../../lib/make_image":17}],31:[function(i,t,e){"use strict";var o=i("../../data/i18n"),r=i("../../data/languages"),s=i("./find"),n=i("./infobox"),a=i("./infobox_template"),l=i("./image"),h=new RegExp("{{("+o.infoboxes.join("|")+")[: \n]","ig"),k=new RegExp("\\[\\[("+o.images.concat(o.files).join("|")+")","i"),w=new RegExp("^("+o.images.concat(o.files).join("|")+")","i"),p=/^\{\{nowrap\|(.*?)\}\}$/,c=function(i,t){var e=s("{","}",t);if(e.forEach(function(e){if(e.match(h,"ig")&&0===Object.keys(i.infobox).length&&(i.infobox=n(e),i.infobox_template=a(e)),e.match(h)&&(t=t.replace(e,"")),e.match(/^\{\{/)){var o=e.match(p);if(o)return void(t=t.replace(e,o[1]));t=t.replace(e,"")}}),e=s("[","]",t),e.forEach(function(e){e.match(k)&&(i.images.push(l(e)),t=t.replace(e,""))}),e.forEach(function(e){if(null!==e.match(/\[\[([a-z][a-z]):(.*?)\]\]/i)){var o=e.match(/\[\[([a-z][a-z]):/i)[1];o&&r[o]&&(i.translations[o]=e.match(/\[\[([a-z][a-z]):(.*?)\]\]/i)[2]),t=t.replace(e,"")}}),i.infobox.image&&i.infobox.image.text){var o=i.infobox.image.text||"";"string"!=typeof o||o.match(w)||(o="File:"+o),i.images.push(o)}return t};t.exports=c},{"../../data/i18n":11,"../../data/languages":12,"./find":29,"./image":30,"./infobox":32,"./infobox_template":33}],32:[function(i,t,e){"use strict";var o=i("../../lib/helpers"),r=i("../text"),s=/\n *\|([^=]*)=(.*)/g,n=function(i){if(!i)return{};var t={},e=[],n=void 0;i=i.replace(/\{\{Collapsible list[^}]{10,1000}\}\}/g,"");for(var a=-2,l=0,h=i.length;l1&&(t=e[1])}return t}var r=i("../../data/i18n"),s=new RegExp("{{(?:"+r.infoboxes.join("|")+")\\s*(.*)","i");t.exports=o},{"../../data/i18n":11}],34:[function(i,t,e){"use strict";var o=i("../lib/helpers"),r=i("./text"),s=/\{\|[\s\S]{1,8000}?\|\}/g,n=function(i){return i=i.replace(/^\! +/,""),i.match(/\|/)&&(i=i.replace(/.+\| ?/,"")),i=r(i).text},a=function(i){for(var t=[],e=[],s=i.replace(/\r/g,"").split(/\n/),a=0;a