From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.

	// ***************************************************************** //

	//                          DYKcheck tool                            //

	//                           Version 1.1                             //

	// For quick installation, add                                       //

	// importScript('User:Shubinator/DYKcheck.js');                      //

	// to your vector.js                                                 //

	// See [[User:Shubinator/DYKcheck]] for more info, including         //

	// configurable options and how to use the tool without installation //

	// or logging in.                                                    //

	// First version written by Shubinator in February 2009              //

	// ***************************************************************** //



mw.loader.using(['mediawiki.api', 'mediawiki.util'], function () {

"use strict";



var onTTDYK, nextSection, urlJump, sections, currentTitle, partsProcessing,

	articleTitles, dates, nom5x;



// Configurable options

var

	dateFormat = window.dateFormat,

	unlock = window.unlock,

	hookLengthYellow = window.hookLengthYellow || 200,

	hookLengthRed = window.hookLengthRed || 220,

	check5xNoms = window.check5xNoms || "ifnom5x",

	fixedSidebar = window.fixedSidebar || "onttydk";



var mwConfig = mw.config.get([

	"wgAction",

	"wgTitle",

	"wgPageName",

	"wgUserName",

	"wgNamespaceNumber",

	"skin"

]);



var api = new mw.Api();



// Polyfill String.prototype.includes so that we don't have to write "!== -1" all over

// the codebase.

if (!String.prototype.includes) {

  String.prototype.includes = function() {

    return String.prototype.indexOf.apply(this, arguments) !== -1;

  };

}



function escapeHtml(s) {

	// Use the browser's built-in ability to escape HTML.

	var div = document.createElement('div');

	div.appendChild(document.createTextNode(s));

	return div.innerHTML;

}



function scanArticle(title, output, html) {

	// the meat of the DYKcheck tool

	// calculates prose size of the given html

	// checks for inline citations and stub templates in the given html

	// passes info to checkTalk(), getFirstRevision(), checkMove(), and checkExpansion()

	

	if (!onTTDYK || (check5xNoms === "always") || (check5xNoms === "ifnom5x" && nom5x)) {

		partsProcessing = new Array(4);

	} else {

		partsProcessing = new Array(3);

	}

	dates = new Array(4);



	var proseDisp = document.createElement("li");

	proseDisp.id = "dyk-prose";

	output.appendChild(proseDisp);



	// calculate prose size

	var prose = calculateProse(html, true);

	var pList = html.getElementsByTagName("p");

	var word_count = 0;

	for (var iPara = 0;iPara < pList.length; iPara++) {

		var para = pListiPara];

		if (para.parentNode.parentNode === html || para.parentNode.parentNode.parentNode.id === getBodyId()) {

			word_count += para.innerHTML.replace(/(<([^>]+)>)/ig,"").split(' ').length;

		}

	}

	proseDisp.innerHTML='<b>Prose size (text only): </b>' + escapeHtml(prose) + '&nbsp;characters (' +

			escapeHtml(word_count) + ' words) "readable prose size"';

	if (prose < 1500) {

		proseDisp.style.cssText = "background-color:pink";

	}

	

	// check for inline citations

	if (!html.innerHTML.includes('id="cite_ref-') && !html.innerHTML.includes('id=cite_ref-')) {

		var noref = document.createElement("li");

		noref.id = "no-ref";

		output.appendChild(noref);

		noref.innerHTML = 'No inline citations';

		noref.style.cssText = "background-color:pink";

	}

	

	// check if article is stub or if it has appeared in DYK or ITN

	if (html.innerHTML.includes('id="stub"') || html.innerHTML.includes('id=stub') || 

			html.innerHTML.includes('metadata plainlinks stub')) {

		var stubAlert = document.createElement("li");

		stubAlert.id = "stub-alert";

		output.appendChild(stubAlert);

		stubAlert.innerHTML = 'Article is classified as a stub';

		stubAlert.style.cssText = "background-color:yellow";

	}

	checkTalk(title, output); //check talk page

	

	// check for various tags

	var alertColor = "yellow";

	var imageList = new Array("Text_document_with_red_question_mark.svg", 

			"Question book-new.svg", "Ambox content.png", "Ambox style.png", 

			"Imbox style.png", "Copyright-problem.svg", "Copyright-problem paste.svg", 

			"Ambox globe content.svg", "Unbalanced scales.svg", "Ambox scales.svg", 

			"Ambox_contradict.svg", "Ambox warning orange.svg", "Acap.svg");

	var tagList = new Array("unverified content", "insufficient citations", "dispute", "cleanup", "cleanup",

			"copyright violations", "copyright violations", "globalization", "neutrality", 

			"neutrality", "contradiction", "dispute", "copyedit");

	var tagsFound = false;

	var tagAlert = document.createElement("li");

	if (html.innerHTML.includes("This article is being considered for deletion in accordance with Wikipedia's")) {

		tagsFound = true;

		var afdIndex = html.innerHTML.indexOf('title="Wikipedia:Articles for deletion/') + 7;

		var afdLink = html.innerHTML.substring(afdIndex, html.innerHTML.indexOf('"', afdIndex));

		var afdBoldTag = document.createElement("b");

		var afdLinkTag = document.createElement("a");

		afdLinkTag.setAttribute("href", "//en.wikipedia.org/wiki/" + afdLink);

		afdLinkTag.appendChild(document.createTextNode("nominated for deletion"));

		afdBoldTag.appendChild(afdLinkTag);

		tagAlert.appendChild(document.createTextNode("Article has been "));

		tagAlert.appendChild(afdBoldTag);

		tagAlert.appendChild(document.createTextNode(". "));

		alertColor = "pink";			

	} else if ((html.innerHTML.toLowerCase().includes('<table class="plainlinks ombox ombox-speedy"')) || 

			(html.innerHTML.toLowerCase().includes('<table class="plainlinks ambox ambox-speedy"')) || 

			(html.innerHTML.toLowerCase().includes('<table class="metadata plainlinks ombox ombox-speedy"')) ||

			(html.innerHTML.toLowerCase().includes('<table class="metadata plainlinks ambox ambox-speedy"'))) {

		tagsFound = true;

		tagAlert.appendChild("Article has been <b>tagged for speedy deletion</b>. ");

		alertColor = "pink";

	}

	for (var iImage = 0; iImage < imageList.length; iImage++) {

		if (html.innerHTML.includes(imageListiImage])) {

			tagsFound = true;

			tagAlert.appendChild(document.createTextNode("Article has a "));

			tagAlert.appendChild(document.createTextNode(tagListiImage]));

			tagAlert.appendChild(document.createTextNode(" tag. "));

		}

	}

	if (tagsFound) {

		tagAlert.id = "tag-alert";

		tagAlert.style"background-color" = alertColor;

		output.appendChild(tagAlert);

	}

		

	// find creator of article and date

	getFirstRevision(title, output);

	

	// check if the article has been moved from userspace within last 100 edits

	if (mwConfig.wgNamespaceNumber !== 2) {

		checkMove(title, output);

	} else {

		partsProcessing2 = true;

	}

	

	// check for expansion start date, assuming now expanded to 5x (last 500 edits)

	if (!onTTDYK || (check5xNoms === "always") || (check5xNoms === "ifnom5x" && nom5x)) {

		checkExpansion(title, output, prose);

	}

}



function checkDocument() {

	// prepares for scan and passes info to scanArticle()

	onTTDYK = false;

	if (document.getElementById("dyk-stats-0")) {

		clearStats();

	} else {

		var output = document.createElement("ul");

		output.id = "dyk-stats-0";

		

		var body = getBody();

		var dummy = body.getElementsByTagName("div")[0];

		if (dummy.nextSibling && dummy.nextSibling.id === 'siteNotice') { // if siteNotice is below siteSub

			dummy = dummy.nextSibling;

		} else if (dummy.nextSibling.nextSibling && dummy.nextSibling.nextSibling.id === 'siteNotice') {

			dummy = dummy.nextSibling.nextSibling;

		}

		dummy.parentNode.insertBefore(output, dummy.nextSibling);

		createHeaderAndProcessing(output);

		currentTitle = 0;

		var title = mwConfig.wgTitle;

		if (mwConfig.wgNamespaceNumber === 2) {

			title = "User:" + title;

		}

		scanArticle(title, output, body);

	}

}



function checkTTDYK() {

	// finds the current nomination

	// can jump to a section if it shows up in the URL

	// (i.e. http://en.wikipedia.org/wiki/T:TDYK#Older_nominations)

	// prepares for scan and passes info to checkHooks() and scanArticle() (through pit stop)



	onTTDYK = true;

	if (!sections) {

		sections = document.getElementsByTagName("h4");

		nextSection = getFirstNom();

	}

	// Jumping code

	if (window.location.hash) {

		var sectionAt = window.location.hash;

		if (sectionAt !== urlJump) {

			var jump = document.getElementById(sectionAt.substring(1, sectionAt.length));

			var next = jump.parentNode;

			while (next.nodeName.toLowerCase() !== "h4") {

				next = next.nextSibling;

			}

			for (var iSection = 0; iSection < sections.length; iSection++) {

				if (sectionsiSection === next) {

					nextSection = iSection;

					urlJump = sectionAt;

					break;

				}

			}

		}

	}

	

	if (nextSection === sections.length) {

		alert("Reached end of nominations; looping to beginning");

		nextSection = getFirstNom();

	}

	if (document.getElementById("dyk-stats-0")) {

		clearStats();

	}

	var firstOutput = document.createElement("ul");

	firstOutput.id = "dyk-stats-0";

	sectionsnextSection].parentNode.insertBefore(firstOutput, sectionsnextSection]);

	var hook = checkHooks(firstOutput);

	if (!hook) {

		var hookErrorDisp = document.createElement("div");

		hookErrorDisp.id = "error-disp";

		hookErrorDisp.style.cssText = 'color:red; font-weight:bold;';

		hookErrorDisp.innerHTML = 'Error: Hook is not formatted correctly';

		firstOutput.parentNode.insertBefore(hookErrorDisp, firstOutput);

		nextSection++;

		return;

	}

	createHeaderAndProcessing(document.getElementById("dyk-stats-0"));

	var tempHolder = document.createElement("div");

	tempHolder.id = "temp-holder";

	tempHolder.innerHTML = hook;

	var bolded = tempHolder.getElementsByTagName("b");

	var articleTitlesTemp = new Array(bolded.length);

	var titlesCounter = 0;

	for (var iBolded = 0; iBolded < bolded.length; iBolded++) {

		var links = boldediBolded].getElementsByTagName("a");

		if (links.length > 0) {

			for (var iLink = 0; iLink < links.length; iLink++) {

				var linkTitle = linksiLink].getAttribute("title");

				if (!linkTitle) linkTitle = linksiLink].innerHTML; // links that aren't piped

				articleTitlesTemptitlesCounter = linkTitle;

				titlesCounter++;

			}

		} else {

			var pointer = boldediBolded];

			while (pointer !== tempHolder) {

				if (pointer.nodeName.toLowerCase() === "a") {

					var pointerTitle = pointer.getAttribute("title");

					if (!pointerTitle) pointerTitle = pointer.innerHTML; // links that aren't piped

					articleTitlesTemptitlesCounter = pointerTitle;

					titlesCounter++;

				}

				pointer = pointer.parentNode;

			}

		}

	}

	currentTitle = 0;

	articleTitles = new Array(titlesCounter);

	var hookOutput = document.getElementById("hook-container");

	for (var i = 0; i < titlesCounter; i++) {

		var output;

		if (i === 0) {

			output = firstOutput;

		} else {

			output = document.createElement("ul");

			output.id = "dyk-stats-" + i;

			hookOutput.parentNode.insertBefore(output, hookOutput);

		}

		var articleDisp = document.createElement("li");

		articleDisp.id = "article-title" + i;

		output.appendChild(articleDisp);

		articleDisp.innerHTML = '<b>Article ' + escapeHtml(i+1) + ':</b> ' + escapeHtml(articleTitlesTempi]);

		articleTitlesi = articleTitlesTempi];

	}

	if (titlesCounter === 1) {

		document.getElementById("article-title0").innerHTML = '<b>Article:</b> ' + escapeHtml(articleTitles0]);

	} else if (titlesCounter === 0) {

		if (document.getElementById("dyk-processing")) {

			var processing = document.getElementById("dyk-processing");

			processing.parentNode.removeChild(processing);

		}

		var boldErrorDisp = document.createElement("div");

		boldErrorDisp.id = "error-disp";

		boldErrorDisp.style.cssText = 'color:red; font-weight:bold;';

		boldErrorDisp.innerHTML = document.createTextNode('Error: The nominated article must appear in bold');

		sectionsnextSection].parentNode.insertBefore(boldErrorDisp, firstOutput);

		nextSection++;

		return;

	}

	nextSection++;

	checkTitle(articleTitles0], firstOutput, 0);

}



function checkHooks(output) {

	// gets the nomination section (complete with comments, etc) and passes this to helper function

	// returns the last suggested hook so the parent method can find article titles

	var hookOutput = document.createElement("ul");

	hookOutput.id = "hook-container";

	output.parentNode.insertBefore(hookOutput, output.nextSibling);

	var bodyHTML = getBody().innerHTML;

	var thisSection;

	if (nextSection !== sections.length - 1) {

		thisSection = bodyHTML.substring(bodyHTML.indexOf(sectionsnextSection].innerHTML) + sectionsnextSection].innerHTML.length, 

				bodyHTML.indexOf(sectionsnextSection+1].innerHTML));

	} else {

		thisSection = bodyHTML.substring(bodyHTML.indexOf(sectionsnextSection].innerHTML) + sectionsnextSection].innerHTML.length, 

				bodyHTML.indexOf('NewPP limit report'));

	}

	thisSection = thisSection.replace('that,', 'that ').replace('...that ', '... that ');

	if (thisSection.includes("5x expan")) {

		nom5x = true;

	} else {

		nom5x = false;

	}

	return checkHooksHelper(hookOutput, thisSection, 0);

}



function checkHooksHelper(hookOutput, whatsLeft, num) {

	// recursively finds proposed hooks for a nom

	// identifies hooks starting with " ... that " and ending with "?"

	// does not count "... " or "(pictured)" in hook character count

	var hook;

	var questionIndex = whatsLeft.indexOf("?");

	var whatsLeftLowerCase = whatsLeft.toLowerCase();

	while ((whatsLeftLowerCase.indexOf("<a ", questionIndex) > 

			whatsLeftLowerCase.indexOf("</a>", questionIndex)) || 

			((!whatsLeftLowerCase.includes("<a ", questionIndex)) && 

			(whatsLeftLowerCase.includes("</a>", questionIndex))) ||

			(whatsLeftLowerCase.indexOf("<i>", questionIndex) > 

			whatsLeftLowerCase.indexOf("</i>", questionIndex)) || 

			((!whatsLeftLowerCase.includes("<i>", questionIndex)) && 

			(whatsLeftLowerCase.includes("</i>", questionIndex)))) {

		questionIndex = whatsLeft.indexOf("?", questionIndex + 1);

	}

	if (whatsLeft.includes("... that ") && questionIndex !== -1) {

		if (whatsLeft.indexOf("... that ") < questionIndex) {

			hook = whatsLeft.substring(whatsLeft.indexOf("... that ") + 4, 

					questionIndex + 1);

			var hookTemp = document.createElement("div");

			hookTemp.id = "hook-temp";

			hookTemp.innerHTML = "<p>" + hook + "</p>";

			var hookLength = calculateProse(hookTemp, false);

			if (hookTemp.innerHTML.includes("pictured)") || 

					hookTemp.innerHTML.includes("(pictured")) {

				hookLength = hookLength - 10;

			}

			var hookDisp = document.createElement("li");

			hookDisp.id = "hooks-" + num;

			if (num === 0) {

				hookDisp.innerHTML = '<b>Original Hook:</b> ' + escapeHtml(hookLength) + ' characters';

			} else {

				hookDisp.innerHTML = '<b>Alternate Hook ' + escapeHtml(num) +'</b>: ' +

					escapeHtml(hookLength) + ' characters';

			}

			if (hookLength > hookLengthRed) {

				hookDisp.style.cssText = 'background-color:pink';

			} else if (hookLength > hookLengthYellow) {

				hookDisp.style.cssText = 'background-color:yellow';

			}

			hookOutput.appendChild(hookDisp);

			num = num + 1;

		}

		var parsed = whatsLeft.substring(questionIndex + 1, whatsLeft.length - 1);

		var lastHook = checkHooksHelper(hookOutput, parsed, num);

		if (!lastHook && hook) {

			lastHook = hook;

		}

		return lastHook;

	}

	return;

}



function checkTitle(title, output, i) {

	// gets the given title from Wikipedia's server and passes it to scanArticle(),

	// resolving any redirects.

	var promise = api.get({

		format: 'json',

		action: 'parse',

		page: title,

		redirects: true,

		prop: 'text'

	});

	promise.done(function (obj) {

		var ttdykTemp = document.createElement("div");

		ttdykTemp.id = "ttdyk-temp" + i;

		ttdykTemp.innerHTML = obj.parse.text"*"];

		title = obj.parse.title; // Get the new title if we were redirected

		scanArticle(title, output, ttdykTemp);

	});

	promise.fail(function () {

		alert("API error");

	});

}



function clearStats() {

	// if scan results already exist, turn them off and remove highlighting

	if (!onTTDYK) {

		var oldStyle = document.getElementById("dyk-stats-0").className;

		var mainContent = getBody();

		var pList = mainContent.getElementsByTagName("p");

		for (var iPara = 0; iPara < pList.length; iPara++) {

			if (pListiPara].parentNode === mainContent || pListiPara].parentNode.parentNode === mainContent) {

				pListiPara].style.cssText = oldStyle;

			}

		}

	}

	if (document.getElementById("error-disp")) {

		var errorDisp = document.getElementById("error-disp");

		errorDisp.parentNode.removeChild(errorDisp);

	}

	var iStat = 0;

	while (document.getElementById("dyk-stats-" + iStat)) {

		var output = document.getElementById("dyk-stats-" + iStat);

		output.parentNode.removeChild(output);

		iStat++;

	}

	if (document.getElementById("hook-container")) {

		var hookOutput = document.getElementById("hook-container");

		hookOutput.parentNode.removeChild(hookOutput);

	}

	if (document.getElementById("dyk-header")) {

		var header = document.getElementById("dyk-header");

		header.parentNode.removeChild(header);

	}

	if (document.getElementById("dyk-processing")) {

		var processing = document.getElementById("dyk-processing");

		processing.parentNode.removeChild(processing);

	}

}



function calculateProse(doc, visible) {

	// calculates the prose of a given document

	// this function and its helper below are modified versions of

	// the prosesize tool (http://en.wikipedia.org/wiki/User:Dr_pda/prosesize.js)

	var pList = doc.getElementsByTagName("p");

	var prose_size = 0;

	

	var i = 0;

	if (mwConfig.wgAction === 'submit' && visible) i = 1; // Avoid the "Remember that this is only a preview" text

	for (; i < pList.length; i++) {

		if (pListi].parentNode.parentNode === doc || pListi].parentNode.parentNode.parentNode.id === getBodyId()) {

			prose_size += getReadable(pListi], visible);

			if (!onTTDYK && visible) {

				pListi].style.cssText = 'background-color:yellow';

			}

		}

	}

	return prose_size;

}



function getReadable(id, visible) {

	// helper method for calculateProse()

	var textReadable = 0;

	for (var i = 0; i < id.childNodes.length; i++) {

		if (id.childNodesi].nodeName === '#text') {

			textReadable += id.childNodesi].nodeValue.length;

		} else if (id.childNodesi].className !== 'reference' && 

				!(id.childNodesi].className && id.childNodesi].className.includes('emplate')) &&

				id.childNodesi].id !== 'coordinates') {

			textReadable += getReadable(id.childNodesi], visible);

		} else if (visible) { // if it's an inline maintenance tag (like [citation needed]) or geocoordinates

			if (document.getElementById("dyk-stats-0").className) {

				id.childNodesi].style.cssText = document.getElementById("dyk-stats-0").className;

			} else {

				id.childNodesi].style.cssText = 'background-color:white';

			}	

		}

	}

	return textReadable;

}



function checkExpansion(title, output, current) {  

	// finds the start of expansion date (last 500 edits)

	// gets the last 500 unique revision ids for past revisions of the article and passes to helper function

	var promise = getRevisions({

		titles: title,

		rvlimit: 500,

		rvprop: 'ids', 'timestamp', 'sha1'],

		rvdir: 'older'

	});

	promise.done(function (revisionsWithDeletedRevs) {

		var revisions = revisionsWithDeletedRevs.filter(revision => 'sha1' in revision);

		var expandTemp = document.createElement("div");

		expandTemp.id = "expand-temp";

		checkExpansionHelper(title, current, output, expandTemp, revisions, 0, revisions.length-1, -1);

	});

}



function checkExpansionHelper(title, current, output, expandTemp, revisions, min, max, expandIndex) {

	// helper for expansion check, used recursively

	// searches for start of expansion date using a binary search algorithm

	// assumes the article has been more or less increasing in size all the time

	// if the article length has yoyo-ed, this function won't give accurate results

	var mid = Math.ceil((max + min)/2);

	if ((((max - min) < 2) && (max !== revisions.length - 1 || expandIndex !== -1)) || expandIndex === -2) {

		var expandResult = document.createElement("li");

		expandResult.id = "expand-result";

		output.appendChild(expandResult);

		if (expandIndex < 0) {

			if (revisions.length === 500) {

				expandResult.innerHTML = escapeHtml('Article has not been expanded 5x in the last 500 edits');

			} else {

				expandResult.innerHTML = escapeHtml('Article has not been expanded 5x since it was created');

			}

		} else {

			var date = revisionsexpandIndex-1].timestamp;

			expandResult.innerHTML = 'Assuming article is at 5x now, expansion began ' + 

					escapeHtml(expandIndex) + ' edits ago on ' + escapeHtml(toNormalDate(date.substring(0,10)));

			dates2 = toDateObject(date);

		}

		partsProcessing3 = true;

		doneProcessing();

		return;

	} else if ((max - min) < 2 && max === revisions.length - 1) {

		expandIndex = -2;

	}

	var promise = api.get({

		format: 'json',

		action: 'parse',

		oldid: revisionsmid].revid,

		prop: 'text'

	});

	promise.done(function (obj) {

		expandTemp.innerHTML = obj.parse.text'*'];

		var prose = calculateProse(expandTemp, false);

		// alert("Prose: " + prose + " 1x: " + current/5 + " Mid: " + mid + " Expand index: " + expandIndex); 

		// use above line to debug the expansion check

		if (prose < (current/5.0)) {

			if ((expandIndex > mid) || (expandIndex < 0)) {

				expandIndex = mid;

			}

			checkExpansionHelper(title, current, output, expandTemp, revisions, min, mid, expandIndex);

		} else {

			checkExpansionHelper(title, current, output, expandTemp, revisions, mid, max, expandIndex);

		}

	});

	promise.fail(function () {

		alert("API error");

		partsProcessing3 = true;

		doneProcessing();

	});

}



function checkTalk(title, output) { 

	// checks the talk page of the article for DYK, ITN, or stub templates

	if (mwConfig.wgNamespaceNumber !== 2) {

		title = "Talk:" + title;

	} else {

		title = title.replace("User:", "User talk:");

	}

	var promise = getRevisions({

		titles: title,

		rvprop: 'content'

	});

	promise.done(function (revisions) {

		if (revisions && revisions0]) {

			var talkPage = revisions0]['*'];

			var result = '';

			var color = '';

			if (talkPage.match(/class\s*=\s*[sS]tub/) && 

					(document.getElementById("stub-alert") === null)) {

				result += 'Article is classified as a stub ';

				color = 'yellow';

			}

			var dyktalkRegexMatches = talkPage.match(/{{\s*[dD](yk|YK\s?)talk[^}]*}}/g);

			if (dyktalkRegexMatches) {

				// if there's a DYK tag, try to find the date of previous appearance

				result += 'Article has appeared on Did You Know before ';

				var dyktalkTag = dyktalkRegexMatches.pop();

				var firstPipeIndex = dyktalkTag.indexOf('|');

				var secondPipeIndex = dyktalkTag.indexOf('|', firstPipeIndex + 1);

				var thirdPipeIndex = dyktalkTag.indexOf('|', secondPipeIndex + 1);

				if (firstPipeIndex !== -1 && secondPipeIndex !== -1) {

					if (thirdPipeIndex === -1) {

						thirdPipeIndex = dyktalkTag.length - 2; // -2 to get rid of the }}

					}

					var monthDate = dyktalkTag.substring(firstPipeIndex + 1, secondPipeIndex);

					var year = dyktalkTag.substring(secondPipeIndex + 1, thirdPipeIndex);

					var featuredDate = new Date(monthDate + " " + year);

					if (featuredDate.toString() !== 'Invalid Date') {

						var month = featuredDate.getMonth() + 1;

						if (month < 10) {

							month = '0' + month;

						}

						var date = featuredDate.getDate();

						if (date < 10) {

							date = '0' + date;

						}

						var dateString = toNormalDate(featuredDate.getFullYear() + '-' + month + '-' + date);

						result = result.substring(0, result.length - 1) + ', on ' + escapeHtml(dateString);

					}

				}

				color = 'pink';

			} else if (talkPage.match(/rticle[ ]?[hH]istory[\s\S]*dykdate\s*=.*?\S/)) {

				result += 'Article has appeared on Did You Know before ';

				color = 'pink';

			}

			if (talkPage.match(/{{\s*[iI]TN(\st|t|T)alk/)) { // {{ITNtalk}}, {{ITN talk}}, {{ITNTalk}}

				result += 'Article has appeared on In The News before ';

				color = 'pink';

			}

			if (result) {

				var talkResult = document.createElement("li");

				talkResult.id = "talk-result";

				output.appendChild(talkResult);

				talkResult.innerHTML = result;

				if (color) {

					talkResult.style"background-color" = color;

				}

			}

			checkTalkForGoodArticleStatus(talkPage, output);

		}

		partsProcessing0 = true;

		doneProcessing();

	});

	promise.fail(function () {

		partsProcessing0 = true;

		doneProcessing();

	});

}



function checkTalkForGoodArticleStatus(talkPage, output) {

	// Test cases:

	// Cathedral of the Immaculate Conception (Moscow) - ArticleHistory, two GANs (last successful), currently a featured article

	// LoveGame - ArticleHistory, one successful GAN, no GARs

	// Paparazzi (Lady Gaga song) - ArticleHistory, one successful GAN, unlisted after a GAR, another successful GAN, no-op GAR

	// Curtis (50 Cent album) - ArticleHistory, one successful GAN, unlisted after a GAR

	// G.U.Y. - ArticleHistory with unconventional formatting

	// Arthur Adams (comics) - ArticleHistory with unconventional formatting

	// Blackburn Firebrand - {{GA}}

	// Tony Hawk's Underground - {{GA}} with confounding {{Game}} tag

	var gaDate = '';

	var gaRegexMatches = talkPage.match(/{{\s*[gG][aA]\s*[|][^}]*}}/g);

	if (gaRegexMatches) {

		// if there's a GA tag, try to find the date of promotion to Good Article

		var gaTag = gaRegexMatches.pop();

		var firstPipeIndex = gaTag.indexOf('|');

		var secondPipeIndex = gaTag.indexOf('|', firstPipeIndex + 1);

		if (firstPipeIndex !== -1) {

			if (secondPipeIndex === -1) {

				secondPipeIndex = gaTag.length - 2; // -2 to get rid of the }}

			}

			gaDate = gaTag.substring(firstPipeIndex + 1, secondPipeIndex);

		}

	} else if (talkPage.match(/rticle[ ]?[hH]istory/)) {

		// check ArticleHistory tag for Good Article status

		

		// grab last GAN action

		// figure out action number

		// given action number, was action result "listed"?

		// if no, stop here - article is not a Good Article

		// if yes, grab the Good Article promotion date from actionXdate

		var ganMatches = talkPage.match(/action[0123456789]+\s*=\s*(gan|GAN)/g);

		if (ganMatches) {

			var lastGanAction = ganMatches.pop();

			var lastGanActionNumber = lastGanAction.substring(6, lastGanAction.indexOf('=')); // remove 'action' and everything at and after the equals sign

			lastGanActionNumber = lastGanActionNumber.trim();

			var ganResultIndex = talkPage.indexOf('action' + lastGanActionNumber +  'result');

			var ganResult = talkPage.substring(talkPage.indexOf('=', ganResultIndex) + 1, talkPage.indexOf('|', ganResultIndex)).trim();

			if (ganResult === 'listed' || ganResult === 'Listed' || ganResult === 'passed' || ganResult === 'Passed') {

				var ganDateIndex = talkPage.indexOf('action' + lastGanActionNumber +  'date');

				gaDate = talkPage.substring(talkPage.indexOf('=', ganDateIndex) + 1, talkPage.indexOf('|', ganDateIndex)).trim();

			}

			

			// then grab last GAR action

			// figure out action number

			// is GAR action number after GAN action number? if yes, carry on

			// given action number, was action result "not listed"?

			// if yes, article is not a Good Article

			var garMatches = talkPage.match(/action[0123456789]+\s*=\s*(gar|GAR)/g);

			if (garMatches) {

				var lastGarAction = garMatches.pop();

				var lastGarActionNumber = lastGarAction.substring(6, lastGarAction.indexOf('=')); // remove 'action' and everything at and after the equals sign

				lastGarActionNumber = lastGarActionNumber.trim();

				if (parseInt(lastGarActionNumber) > parseInt(lastGanActionNumber)) {

					var garResultIndex = talkPage.indexOf('action' + lastGarActionNumber +  'result');

					var garResult = talkPage.substring(talkPage.indexOf('=', garResultIndex) + 1, talkPage.indexOf('|', garResultIndex)).trim();

					if (garResult === 'delisted' || garResult === 'Delisted') {

						gaDate = ''; // Not a Good Article, GAR came after GAN and demoted the article

					}

				}

			}

		}

	}

	

	if (gaDate) {

		if (gaDate.length > 6 && gaDate.indexOf(' (UTC)') === gaDate.length - 6) {

			gaDate = gaDate.substring(0, gaDate.length - 6); // The Boat Race 1997 is not parsing correctly if (UTC) is left in

		}

		if (gaDate.length > 5 && gaDate2 === ':' && gaDate5 === ',') {

			gaDate = gaDate.substring(6, gaDate.length).trim(); // Chrome not parsing as expected for strings like "17:21, 26 June 2014"

		}

		

		var gaPromotion = document.createElement("li");

		gaPromotion.id = "ga-promotion";

		output.appendChild(gaPromotion);

		var gaPromotedDate = new Date(gaDate);

		

		// ensure the Date object is in the right time zone

		gaPromotedDate = new Date(Date.UTC(gaPromotedDate.getFullYear(), gaPromotedDate.getMonth(), gaPromotedDate.getDate(), gaPromotedDate.getHours(), gaPromotedDate.getMinutes(), gaPromotedDate.getSeconds()));

		

		dates3 = gaPromotedDate;

		gaPromotion.innerHTML = 'Article was promoted to Good Article status on ' +

			escapeHtml(toNormalDate(gaPromotedDate.toISOString()));

	}

}



function getRevisions(options) {

	// Returns a jQuery promise with an array of a title's revisions.

	// The first parameter is an options object accepting the following API fields:

	// - titles

	// - rvlimit

	// - rvprop

	// - rvdir

	options = options || {};

	return api.get({

		format: 'json',

		action: 'query',

		prop: 'revisions',

		titles: options.titles,

		rvlimit: options.rvlimit,

		rvprop: options.rvprop,

		rvdir: options.rvdir,

		indexpageids: true

	}).then(

		// On success

		function (obj) {

			var pageId = obj.query.pageids0];

			return obj.query.pagespageId].revisions;

		},

		// On failure

		function (err) {

			alert("API error");

			return err;

		}

	);

}



function getFirstRevision(title, output) {

	// finds the creator of the article, and the date created

	// also checks if the article was created as a redirect, finds non-redirect date if so



	var created = document.createElement("li");

	created.id = "creation-info";

	output.appendChild(created);

		

	var promise = getRevisions({

		titles: title,

		rvlimit: 4,

		rvprop: 'timestamp', 'user', 'content'],

		rvdir: 'newer'

	});

	promise.done(function (revisions) {

		var user = revisions0].user;

		var timestamp = revisions0].timestamp;

		created.innerHTML='<b>Article created </b> by ' + escapeHtml(user) + 

				' on ' + escapeHtml(toNormalDate(timestamp.substring(0,10)));

		dates0 = toDateObject(timestamp);

		for (var i = 0; i < revisions.length; i++) {

			var content = revisionsi]['*'];

			var isRedirect = content.replace(' ', '').replace(':', '').toUpperCase().includes('#REDIRECT[[');

			if (isRedirect && i === 0) {

				created.innerHTML = created.innerHTML + ' as a redirect';

			} else if (!isRedirect) {

				if (i !== 0) {

					var unRedirect = document.createElement("li");

					unRedirect.id = "expanded-from-redirect";

					output.appendChild(unRedirect);

					var urUser = revisionsi].user;

					var urTimestamp = revisionsi].timestamp;

					unRedirect.innerHTML = 'Article became a non-redirect on ' + 

							escapeHtml(toNormalDate(urTimestamp.substring(0,10))) +

							' by ' + escapeHtml(urUser);

					dates0 = toDateObject(urTimestamp);

				}

				break;

			}

		}

		partsProcessing1 = true;

		doneProcessing();

	});

	promise.fail(function () {

		partsProcessing1 = true;

		doneProcessing();

	});

}



function checkMove(title, output) { 

	//checks the last 100 edits of an article for a move from userspace or AfC to current location

	var promise = getRevisions({

		titles: title,

		rvlimit: 100,

		rvprop: 'flags', 'user', 'timestamp', 'comment'],

		rvdir: 'older',

	});

	promise.done(function (revisions) {

		for (var i = 0; i < revisions.length; i++) {

			var comment = revisionsi].comment;

			var userName = revisionsi].user;

			if ((revisionsi].minor === "") && 

					comment.match(/moved (page )?((\[\[User:)|(\[\[Draft:)|(\[\[Wikipedia talk:Articles for creation\/))[\s\S]*to \[\[/)) {

				var movedFrom = comment.substring(comment.indexOf("[[") + 2, comment.indexOf("to [[") - 3);

				var date = revisionsi].timestamp;

				var moved = document.createElement("li");

				moved.id = "moved-userspace";

				output.appendChild(moved);

				moved.innerHTML = '<b>Article moved</b> from ' + escapeHtml(movedFrom) + 

						' on ' + escapeHtml(toNormalDate(date.substring(0,10)));

				dates1 = toDateObject(date);

				break;

			}

		}

		partsProcessing2 = true;

		doneProcessing();

	});

	promise.fail(function () {

		partsProcessing2 = true;

		doneProcessing();

	});

}



function doneProcessing() {

	// checks if all parts are done processing

	// if they are, the dates of creation and expansion are checked for within 10 days (rounded down, in nominator's favor)

	// then the next title (for multiple article noms) is processed (required to combat asynchronous threads)

	// if there are no more titles left (or not on T:TDYK), the processing message is removed

	var titleComplete = true;

	for (var i = 0; i < partsProcessing.length; i++) {

		if (!partsProcessingi]) {

			titleComplete = false;

			break;

		}

	}

	if (document.getElementById("dyk-processing") && titleComplete) {

		var curDate = new Date();

		var winner = new Date();

		if (dates1]) {

			winner = dates1]; 

		} else {

			winner = dates0];

		}

		if (dates2 > winner) {

			winner = dates2];

		}

		if (dates3 > winner) {

			winner = dates3];

		}

		var dateDifference = Math.floor((curDate.getTime() - winner.getTime())/(1000*60*60*24));

		if (dateDifference > 10) {

			var output = document.getElementById("dyk-stats-" + currentTitle);

			var notRecent = document.createElement("li");

			notRecent.id = "not-recent";

			output.appendChild(notRecent);

			if (!onTTDYK || (check5xNoms === "always") || (check5xNoms === "ifnom5x" && nom5x)) {

				notRecent.innerHTML = "Article has not been created or expanded 5x or promoted to Good Article within the past 10 days (" + 

						escapeHtml(dateDifference) + " days)" + " <small>DYKcheck does not account for previous versions with " +

						'<a href="//en.wikipedia.org/wiki/Wikipedia:Split">splits</a> or ' +

						'<a href="//en.wikipedia.org/wiki/Wikipedia:Copyright_violations">copyright violations</a>.</small>';

			} else {

				notRecent.innerHTML = "Article was not created within the past 10 days (" + escapeHtml(dateDifference) + " days)";

			}

			notRecent.style.cssText = 'background-color:pink';

		}

		if (onTTDYK && currentTitle < (articleTitles.length - 1)) {

			currentTitle++;

			checkTitle(articleTitlescurrentTitle], 

					document.getElementById("dyk-stats-" + (currentTitle)), currentTitle);

		} else {

			var processing = document.getElementById("dyk-processing");

			processing.parentNode.removeChild(processing);

		}

	}

}



// taken from the prosesize tool (http://en.wikipedia.org/wiki/User:Dr_pda/prosesize.js)

function getBodyId() {

	var contentName;

	if (mwConfig.skin === 'monobook' || mwConfig.skin === 'chick' || mwConfig.skin === 'mymwConfig.skin' || mwConfig.skin === 'simple') {

		contentName = 'bodyContent';

	} else if (mwConfig.skin === 'modern') {

		contentName = 'mw_contentholder';

	} else if (mwConfig.skin === 'standard' || mwConfig.skin === 'cologneblue' || mwConfig.skin === 'nostalgia') {

		contentName = 'article';

	} else {

		// fallback case; the above covers all currently existing skins

		contentName = 'bodyContent';

	}

	// Same for all skins if previewing page

	if (mwConfig.wgAction === 'submit') contentName = 'wikiPreview';

	return contentName;

}



function getBody() { 

	// gets the HTML body of the page

	// taken from the prosesize tool (http://en.wikipedia.org/wiki/User:Dr_pda/prosesize.js)

	return document.getElementById(getBodyId());

}



function getFirstNom() {

	var firstNom = 0;

	

	// Find the first "Articles created/expanded on ..." h3 section

	var elementIterator = sectionsfirstNom].previousSibling;

	while (elementIterator.nodeName.toLowerCase() !== "h3") {

		elementIterator = elementIterator.previousSibling;

	}

	while (!(elementIterator.nodeName.toLowerCase() === "h3" && 

			elementIterator.innerHTML.includes("Articles created/expanded on"))) {

		if (elementIterator.nodeName.toLowerCase() === "h4") {

			firstNom++;

		}

		elementIterator = elementIterator.nextSibling;

	}

	return firstNom;

}



function createHeaderAndProcessing(output) { 

	// makes the header above the scan results

	var header = document.createElement("span");

	header.id = "dyk-header";

	header.innerHTML = '<br /><b>DYK eligibility scan results: <small><i>(See <a href="//en.wikipedia.org/wiki/' + 

			'User:Shubinator/DYKcheck">here</a> for details.)</i></small></b>';

	output.parentNode.insertBefore(header,output);

	var processing = document.createElement("span");

	processing.id = "dyk-processing";

	processing.innerHTML = '<br /><b><font color="crimson"> Processing... </font></b>';

	output.parentNode.insertBefore(processing, header);

}



function toNormalDate(utc) { 

	// converts the date part of a Wikipedia timestamp to a readable date

	var months = new Array("blank","January","February", "March", "April", "May", "June", 

			"July", "August", "September", "October", "November", "December");

	if (dateFormat === "british") {

		return (utc.substring(8,10) * 1) + ' ' + monthsutc.substring(5,7) * 1 + ' ' + utc.substring(0,4);

	} else {

		return monthsutc.substring(5,7) * 1 + ' ' + (utc.substring(8,10) * 1) + ', ' + utc.substring(0,4);

	}

}



function toDateObject(timestamp) { 

	// converts a Wikipedia timestamp to a Javascript Date object

	var date = new Date();

	date.setUTCFullYear(timestamp.substring(0,4), timestamp.substring(5,7) - 1, timestamp.substring(8,10));

	date.setUTCHours(timestamp.substring(11,13), timestamp.substring(14,16), timestamp.substring(17,19));

	return date;

}



function fixSidebar() { // part of the code to fix the sidebar; the rest is below the addToolbarPortletLink function

	// this function is only necessary for the monobook skin

	var content = document.getElementById("column-content");    // Find the main content column



	var footer = document.getElementById("footer");  // Find the footer

	footer.parentNode.removeChild(footer);    // Remove the footer from the global wrapper

	content.appendChild(footer);    // Place footer at the end of the content column;



	var tabs = document.getElementById("p-cactions");   // Find the top tab list

	tabs.parentNode.removeChild(tabs);    // Remove the tab list from the side column

	content.insertBefore(tabs, content.lastChild);    // Place tab list in the content column



	var personal = document.getElementById("p-personal");   // Find the personal links list

	personal.parentNode.removeChild(personal);    // Remove the personal links list from the side column

	content.insertBefore(personal, content.lastChild);    // Place personal links list in the content column

}



window.dykCheck = function () { 

	// this function for casual use and anons

	if (((mwConfig.wgAction === 'view' || mwConfig.wgAction === 'submit' || mwConfig.wgAction === 'purge') && 

			(mwConfig.wgNamespaceNumber === 0 || mwConfig.wgNamespaceNumber === 2)) || unlock) {

		checkDocument();

	} else if (mwConfig.wgPageName === 'Template_talk:Did_you_know') {

		checkTTDYK();

	}

};



function addToolbarPortletLink(func, tooltip) {

	var link = mw.util.addPortletLink(

		'p-tb',

		'#',

		'DYK check',

		't-dyk-check',

		tooltip

	);

	$( link ).click( function (e) {

		e.preventDefault();

		func();

	});

}



// Add toolbar portlet links

if (unlock || (

		(mwConfig.wgAction === 'view' || mwConfig.wgAction === 'submit' || mwConfig.wgAction === 'purge') && 

		(mwConfig.wgNamespaceNumber === 0 || mwConfig.wgNamespaceNumber === 2)

)) {

	addToolbarPortletLink(checkDocument, 'Check if this article qualifies for DYK');

} else if (mwConfig.wgPageName === 'Template_talk:Did_you_know') {

	addToolbarPortletLink(checkTTDYK, 'Check DYK nominations for eligibility');

}



// Fix the sidebar

if (mwConfig.wgUserName && mwConfig.skin === 'monobook' && (

		fixedSidebar === "always" ||

		fixedSidebar === "onttydk" && mwConfig.wgPageName === 'Template_talk:Did_you_know'

)) {

	fixSidebar();

}



// The code below for the fixed sidebar is a blend of two sources:

//		http://meta.wikimedia.org/wiki/Help:User_style/floating_quickbar 

// 		http://en.wikipedia.org/wiki/User:Omegatron/monobook.js/floatingSidebar.js

// Very little of the code below was written by me (Shubinator)



// This CSS should be hidden from older versions of IE using javascript instead of the attribute selector?



// Include style sheet inline so that script is self-contained:

if (mwConfig.wgUserName && (

		fixedSidebar === "always" ||

		fixedSidebar === "onttydk" && mwConfig.wgPageName === 'Template_talk:Did_you_know'

)) {

	var head = document.getElementsByTagName("head")[0];

	var style = document.createElement('style');

	style.type = 'text/css';

	var sidebarDivHidden;

	var sidebarDiv;

	var langBody;

	if (mwConfig.skin === 'vector') { // default skin  (as of May 2010)

		sidebarDivHidden = 'div#mw-panel';

		sidebarDiv = 'div#mw-panel';

		langBody = '#p-lang .body';

	} else { // monobook, modern, and simple skins

		if (mwConfig.skin === 'modern') {

			sidebarDivHidden = 'div[id=mw_portlets]';

		} else if (mwConfig.skin === 'simple') {

			sidebarDivHidden = '#column-one';

		} else { // monobook skin

			sidebarDivHidden = 'div[id=column-one]'; /* Using the attribute selector hides this from IE */

		}

		sidebarDiv = '#column-one';

		langBody = '#p-lang .pBody';

	}

	var cssText = "   /* Fix the sidebar's position while you scroll */             "+

	    sidebarDivHidden + ' {                                                      '+

	'       position: fixed;                                                        ';

	if (mwConfig.skin === 'vector') { // force the sidebar to the upper left; only necessary in some skins

	    cssText += 'left: 0px;                                                      '+

	    '   top: 0px;                                                               ';

	} else if (mwConfig.skin === 'monobook') {

	    cssText += 'left: 0px;                                                      '+

	    '   top: -160px;                                                            ';

	}

	cssText += 'height: 100%;   /* If you shrink the browser too small, the     */  '+

	'       overflow: auto;     /* side column will become scrollable, so stuff */  '+

	'       z-index: 2;         /* is always accessible, albeit ugly            */  '+

	'   }                                                                           '+

	'                                                                               '+

	'   #p-logo {               /* Make logo inline with other divs             */  '+

	'       position:static;                                                        '+

	'   }                                                                           '+

	'                                                                               '+

	    sidebarDiv       + ' {  /* Sidebar column start at the top screen edge  */  '+

	'       padding-top: 0;                                                         '+

	'   }                                                                           '+

	'                                                                               '+

	    langBody + 	  ' ul{      /* Sets the language box to a fixed height and  */ '+

	'       height: 6em;        /* scrollable if too long to fit on screen      */  '+

	'       overflow: auto;                                                         '+

	'   }                                                                           '+

	'                                                                               '+

	'   /* Fix the background image, too, so it looks nice as you scroll */         '+

	'   body {                                                                      '+

	'       background-attachment: fixed;                                           '+

	'   }                                                                           '+

	'                                                                               '+

	"   /* Fix the footer so it looks nice and doesn't overlap the sidebar */       "+

	'   #footer {                                                                   '+

	'       margin-left: 13.6em;                                                    '+

	'       border-left: solid 1px rgb(250, 189, 35);                               '+

	'       -moz-border-radius-topleft: 1em;                                        '+

	'       -moz-border-radius-bottomleft: 1em;                                     '+

	'   }                                                                           ';

	if (mwConfig.skin === 'monobook') {

	    cssText += 	'   /* Keep personal links at the top right */                  '+

	'   #p-personal {                                                               '+

	'       width:100%;                                                             '+

	'       white-space:nowrap;                                                     '+

	'       padding:0 0 0 0;                                                        '+

	'       margin:0;                                                               '+

	'       position:absolute;                                                      '+

	'       left:0px;                                                               '+

	'       top:0px;                                                                '+

	'       z-index: 0;                                                             '+

	'       border: none;                                                           '+

	'       background: none;                                                       '+

	'       overflow: visible;                                                      '+

	'       line-height: 1.2em;                                                     '+

	'   }                                                                           '+

	'                                                                               '+

	'   #p-personal h5 {                                                            '+

	'       display:none;                                                           '+

	'   }                                                                           '+

	'   #p-personal .portlet,                                                       '+

	'   #p-personal .pBody {                                                        '+

	'       padding:0;                                                              '+

	'       margin:0;                                                               '+

	'       border: none;                                                           '+

	'       z-index:0;                                                              '+

	'       overflow: visible;                                                      '+

	'       background: none;                                                       '+

	'   }                                                                           '+

	'   /* this is the ul contained in the portlet */                               '+

	'   #p-personal ul {                                                            '+

	'       border: none;                                                           '+

	'       line-height: 1.4em;                                                     '+

	'       color: #2f6fab;                                                         '+

	'       padding: 0em 2em 0 3em;                                                 '+

	'       margin: 0;                                                              '+

	'       text-align: right;                                                      '+

	'       text-transform: lowercase;                                              '+

	'       list-style: none;                                                       '+

	'       z-index:0;                                                              '+

	'       background: none;                                                       '+

	'   }                                                                           '+

	'   #p-personal li {                                                            '+

	'       z-index:0;                                                              '+

	'       border:none;                                                            '+

	'       padding:0;                                                              '+

	'       display: inline;                                                        '+

	'       color: #2f6fab;                                                         '+

	'       margin-left: 1em;                                                       '+

	'       line-height: 1.2em;                                                     '+

	'       background: none;                                                       '+

	'   }                                                                           '+

	'   #p-personal li a {                                                          '+

	'       text-decoration: none;                                                  '+

	'       color: #005896;                                                         '+

	'       padding-bottom: 0.2em;                                                  '+

	'       background: none;                                                       '+

	'   }                                                                           '+

	'   #p-personal li a:hover {                                                    '+

	'       background-color: White;                                                '+

	'       padding-bottom: 0.2em;                                                  '+

	'       text-decoration: none;                                                  '+

	'   }                                                                           '+

	'   /* Keep the small user figure left of your user name */                     '+

	'   li#pt-userpage,                                                             '+

	'   li#pt-anonuserpage,                                                         '+

	'   li#pt-login {                                                               '+

	'       background: url(/skins-1.5/monobook/user.gif) top left no-repeat;       '+

	'       padding-left: 20px;                                                     '+

	'       text-transform: none;                                                   '+

	'   }                                                                           '+

	'                                                                               ';

	}

	var rules = document.createTextNode(cssText);

	if (style.styleSheet) {

		style.styleSheet.cssText = rules.nodeValue;

	} else {

		style.appendChild(rules);

	}

	head.appendChild(style);

}



});
From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.

	// ***************************************************************** //

	//                          DYKcheck tool                            //

	//                           Version 1.1                             //

	// For quick installation, add                                       //

	// importScript('User:Shubinator/DYKcheck.js');                      //

	// to your vector.js                                                 //

	// See [[User:Shubinator/DYKcheck]] for more info, including         //

	// configurable options and how to use the tool without installation //

	// or logging in.                                                    //

	// First version written by Shubinator in February 2009              //

	// ***************************************************************** //



mw.loader.using(['mediawiki.api', 'mediawiki.util'], function () {

"use strict";



var onTTDYK, nextSection, urlJump, sections, currentTitle, partsProcessing,

	articleTitles, dates, nom5x;



// Configurable options

var

	dateFormat = window.dateFormat,

	unlock = window.unlock,

	hookLengthYellow = window.hookLengthYellow || 200,

	hookLengthRed = window.hookLengthRed || 220,

	check5xNoms = window.check5xNoms || "ifnom5x",

	fixedSidebar = window.fixedSidebar || "onttydk";



var mwConfig = mw.config.get([

	"wgAction",

	"wgTitle",

	"wgPageName",

	"wgUserName",

	"wgNamespaceNumber",

	"skin"

]);



var api = new mw.Api();



// Polyfill String.prototype.includes so that we don't have to write "!== -1" all over

// the codebase.

if (!String.prototype.includes) {

  String.prototype.includes = function() {

    return String.prototype.indexOf.apply(this, arguments) !== -1;

  };

}



function escapeHtml(s) {

	// Use the browser's built-in ability to escape HTML.

	var div = document.createElement('div');

	div.appendChild(document.createTextNode(s));

	return div.innerHTML;

}



function scanArticle(title, output, html) {

	// the meat of the DYKcheck tool

	// calculates prose size of the given html

	// checks for inline citations and stub templates in the given html

	// passes info to checkTalk(), getFirstRevision(), checkMove(), and checkExpansion()

	

	if (!onTTDYK || (check5xNoms === "always") || (check5xNoms === "ifnom5x" && nom5x)) {

		partsProcessing = new Array(4);

	} else {

		partsProcessing = new Array(3);

	}

	dates = new Array(4);



	var proseDisp = document.createElement("li");

	proseDisp.id = "dyk-prose";

	output.appendChild(proseDisp);



	// calculate prose size

	var prose = calculateProse(html, true);

	var pList = html.getElementsByTagName("p");

	var word_count = 0;

	for (var iPara = 0;iPara < pList.length; iPara++) {

		var para = pListiPara];

		if (para.parentNode.parentNode === html || para.parentNode.parentNode.parentNode.id === getBodyId()) {

			word_count += para.innerHTML.replace(/(<([^>]+)>)/ig,"").split(' ').length;

		}

	}

	proseDisp.innerHTML='<b>Prose size (text only): </b>' + escapeHtml(prose) + '&nbsp;characters (' +

			escapeHtml(word_count) + ' words) "readable prose size"';

	if (prose < 1500) {

		proseDisp.style.cssText = "background-color:pink";

	}

	

	// check for inline citations

	if (!html.innerHTML.includes('id="cite_ref-') && !html.innerHTML.includes('id=cite_ref-')) {

		var noref = document.createElement("li");

		noref.id = "no-ref";

		output.appendChild(noref);

		noref.innerHTML = 'No inline citations';

		noref.style.cssText = "background-color:pink";

	}

	

	// check if article is stub or if it has appeared in DYK or ITN

	if (html.innerHTML.includes('id="stub"') || html.innerHTML.includes('id=stub') || 

			html.innerHTML.includes('metadata plainlinks stub')) {

		var stubAlert = document.createElement("li");

		stubAlert.id = "stub-alert";

		output.appendChild(stubAlert);

		stubAlert.innerHTML = 'Article is classified as a stub';

		stubAlert.style.cssText = "background-color:yellow";

	}

	checkTalk(title, output); //check talk page

	

	// check for various tags

	var alertColor = "yellow";

	var imageList = new Array("Text_document_with_red_question_mark.svg", 

			"Question book-new.svg", "Ambox content.png", "Ambox style.png", 

			"Imbox style.png", "Copyright-problem.svg", "Copyright-problem paste.svg", 

			"Ambox globe content.svg", "Unbalanced scales.svg", "Ambox scales.svg", 

			"Ambox_contradict.svg", "Ambox warning orange.svg", "Acap.svg");

	var tagList = new Array("unverified content", "insufficient citations", "dispute", "cleanup", "cleanup",

			"copyright violations", "copyright violations", "globalization", "neutrality", 

			"neutrality", "contradiction", "dispute", "copyedit");

	var tagsFound = false;

	var tagAlert = document.createElement("li");

	if (html.innerHTML.includes("This article is being considered for deletion in accordance with Wikipedia's")) {

		tagsFound = true;

		var afdIndex = html.innerHTML.indexOf('title="Wikipedia:Articles for deletion/') + 7;

		var afdLink = html.innerHTML.substring(afdIndex, html.innerHTML.indexOf('"', afdIndex));

		var afdBoldTag = document.createElement("b");

		var afdLinkTag = document.createElement("a");

		afdLinkTag.setAttribute("href", "//en.wikipedia.org/wiki/" + afdLink);

		afdLinkTag.appendChild(document.createTextNode("nominated for deletion"));

		afdBoldTag.appendChild(afdLinkTag);

		tagAlert.appendChild(document.createTextNode("Article has been "));

		tagAlert.appendChild(afdBoldTag);

		tagAlert.appendChild(document.createTextNode(". "));

		alertColor = "pink";			

	} else if ((html.innerHTML.toLowerCase().includes('<table class="plainlinks ombox ombox-speedy"')) || 

			(html.innerHTML.toLowerCase().includes('<table class="plainlinks ambox ambox-speedy"')) || 

			(html.innerHTML.toLowerCase().includes('<table class="metadata plainlinks ombox ombox-speedy"')) ||

			(html.innerHTML.toLowerCase().includes('<table class="metadata plainlinks ambox ambox-speedy"'))) {

		tagsFound = true;

		tagAlert.appendChild("Article has been <b>tagged for speedy deletion</b>. ");

		alertColor = "pink";

	}

	for (var iImage = 0; iImage < imageList.length; iImage++) {

		if (html.innerHTML.includes(imageListiImage])) {

			tagsFound = true;

			tagAlert.appendChild(document.createTextNode("Article has a "));

			tagAlert.appendChild(document.createTextNode(tagListiImage]));

			tagAlert.appendChild(document.createTextNode(" tag. "));

		}

	}

	if (tagsFound) {

		tagAlert.id = "tag-alert";

		tagAlert.style"background-color" = alertColor;

		output.appendChild(tagAlert);

	}

		

	// find creator of article and date

	getFirstRevision(title, output);

	

	// check if the article has been moved from userspace within last 100 edits

	if (mwConfig.wgNamespaceNumber !== 2) {

		checkMove(title, output);

	} else {

		partsProcessing2 = true;

	}

	

	// check for expansion start date, assuming now expanded to 5x (last 500 edits)

	if (!onTTDYK || (check5xNoms === "always") || (check5xNoms === "ifnom5x" && nom5x)) {

		checkExpansion(title, output, prose);

	}

}



function checkDocument() {

	// prepares for scan and passes info to scanArticle()

	onTTDYK = false;

	if (document.getElementById("dyk-stats-0")) {

		clearStats();

	} else {

		var output = document.createElement("ul");

		output.id = "dyk-stats-0";

		

		var body = getBody();

		var dummy = body.getElementsByTagName("div")[0];

		if (dummy.nextSibling && dummy.nextSibling.id === 'siteNotice') { // if siteNotice is below siteSub

			dummy = dummy.nextSibling;

		} else if (dummy.nextSibling.nextSibling && dummy.nextSibling.nextSibling.id === 'siteNotice') {

			dummy = dummy.nextSibling.nextSibling;

		}

		dummy.parentNode.insertBefore(output, dummy.nextSibling);

		createHeaderAndProcessing(output);

		currentTitle = 0;

		var title = mwConfig.wgTitle;

		if (mwConfig.wgNamespaceNumber === 2) {

			title = "User:" + title;

		}

		scanArticle(title, output, body);

	}

}



function checkTTDYK() {

	// finds the current nomination

	// can jump to a section if it shows up in the URL

	// (i.e. http://en.wikipedia.org/wiki/T:TDYK#Older_nominations)

	// prepares for scan and passes info to checkHooks() and scanArticle() (through pit stop)



	onTTDYK = true;

	if (!sections) {

		sections = document.getElementsByTagName("h4");

		nextSection = getFirstNom();

	}

	// Jumping code

	if (window.location.hash) {

		var sectionAt = window.location.hash;

		if (sectionAt !== urlJump) {

			var jump = document.getElementById(sectionAt.substring(1, sectionAt.length));

			var next = jump.parentNode;

			while (next.nodeName.toLowerCase() !== "h4") {

				next = next.nextSibling;

			}

			for (var iSection = 0; iSection < sections.length; iSection++) {

				if (sectionsiSection === next) {

					nextSection = iSection;

					urlJump = sectionAt;

					break;

				}

			}

		}

	}

	

	if (nextSection === sections.length) {

		alert("Reached end of nominations; looping to beginning");

		nextSection = getFirstNom();

	}

	if (document.getElementById("dyk-stats-0")) {

		clearStats();

	}

	var firstOutput = document.createElement("ul");

	firstOutput.id = "dyk-stats-0";

	sectionsnextSection].parentNode.insertBefore(firstOutput, sectionsnextSection]);

	var hook = checkHooks(firstOutput);

	if (!hook) {

		var hookErrorDisp = document.createElement("div");

		hookErrorDisp.id = "error-disp";

		hookErrorDisp.style.cssText = 'color:red; font-weight:bold;';

		hookErrorDisp.innerHTML = 'Error: Hook is not formatted correctly';

		firstOutput.parentNode.insertBefore(hookErrorDisp, firstOutput);

		nextSection++;

		return;

	}

	createHeaderAndProcessing(document.getElementById("dyk-stats-0"));

	var tempHolder = document.createElement("div");

	tempHolder.id = "temp-holder";

	tempHolder.innerHTML = hook;

	var bolded = tempHolder.getElementsByTagName("b");

	var articleTitlesTemp = new Array(bolded.length);

	var titlesCounter = 0;

	for (var iBolded = 0; iBolded < bolded.length; iBolded++) {

		var links = boldediBolded].getElementsByTagName("a");

		if (links.length > 0) {

			for (var iLink = 0; iLink < links.length; iLink++) {

				var linkTitle = linksiLink].getAttribute("title");

				if (!linkTitle) linkTitle = linksiLink].innerHTML; // links that aren't piped

				articleTitlesTemptitlesCounter = linkTitle;

				titlesCounter++;

			}

		} else {

			var pointer = boldediBolded];

			while (pointer !== tempHolder) {

				if (pointer.nodeName.toLowerCase() === "a") {

					var pointerTitle = pointer.getAttribute("title");

					if (!pointerTitle) pointerTitle = pointer.innerHTML; // links that aren't piped

					articleTitlesTemptitlesCounter = pointerTitle;

					titlesCounter++;

				}

				pointer = pointer.parentNode;

			}

		}

	}

	currentTitle = 0;

	articleTitles = new Array(titlesCounter);

	var hookOutput = document.getElementById("hook-container");

	for (var i = 0; i < titlesCounter; i++) {

		var output;

		if (i === 0) {

			output = firstOutput;

		} else {

			output = document.createElement("ul");

			output.id = "dyk-stats-" + i;

			hookOutput.parentNode.insertBefore(output, hookOutput);

		}

		var articleDisp = document.createElement("li");

		articleDisp.id = "article-title" + i;

		output.appendChild(articleDisp);

		articleDisp.innerHTML = '<b>Article ' + escapeHtml(i+1) + ':</b> ' + escapeHtml(articleTitlesTempi]);

		articleTitlesi = articleTitlesTempi];

	}

	if (titlesCounter === 1) {

		document.getElementById("article-title0").innerHTML = '<b>Article:</b> ' + escapeHtml(articleTitles0]);

	} else if (titlesCounter === 0) {

		if (document.getElementById("dyk-processing")) {

			var processing = document.getElementById("dyk-processing");

			processing.parentNode.removeChild(processing);

		}

		var boldErrorDisp = document.createElement("div");

		boldErrorDisp.id = "error-disp";

		boldErrorDisp.style.cssText = 'color:red; font-weight:bold;';

		boldErrorDisp.innerHTML = document.createTextNode('Error: The nominated article must appear in bold');

		sectionsnextSection].parentNode.insertBefore(boldErrorDisp, firstOutput);

		nextSection++;

		return;

	}

	nextSection++;

	checkTitle(articleTitles0], firstOutput, 0);

}



function checkHooks(output) {

	// gets the nomination section (complete with comments, etc) and passes this to helper function

	// returns the last suggested hook so the parent method can find article titles

	var hookOutput = document.createElement("ul");

	hookOutput.id = "hook-container";

	output.parentNode.insertBefore(hookOutput, output.nextSibling);

	var bodyHTML = getBody().innerHTML;

	var thisSection;

	if (nextSection !== sections.length - 1) {

		thisSection = bodyHTML.substring(bodyHTML.indexOf(sectionsnextSection].innerHTML) + sectionsnextSection].innerHTML.length, 

				bodyHTML.indexOf(sectionsnextSection+1].innerHTML));

	} else {

		thisSection = bodyHTML.substring(bodyHTML.indexOf(sectionsnextSection].innerHTML) + sectionsnextSection].innerHTML.length, 

				bodyHTML.indexOf('NewPP limit report'));

	}

	thisSection = thisSection.replace('that,', 'that ').replace('...that ', '... that ');

	if (thisSection.includes("5x expan")) {

		nom5x = true;

	} else {

		nom5x = false;

	}

	return checkHooksHelper(hookOutput, thisSection, 0);

}



function checkHooksHelper(hookOutput, whatsLeft, num) {

	// recursively finds proposed hooks for a nom

	// identifies hooks starting with " ... that " and ending with "?"

	// does not count "... " or "(pictured)" in hook character count

	var hook;

	var questionIndex = whatsLeft.indexOf("?");

	var whatsLeftLowerCase = whatsLeft.toLowerCase();

	while ((whatsLeftLowerCase.indexOf("<a ", questionIndex) > 

			whatsLeftLowerCase.indexOf("</a>", questionIndex)) || 

			((!whatsLeftLowerCase.includes("<a ", questionIndex)) && 

			(whatsLeftLowerCase.includes("</a>", questionIndex))) ||

			(whatsLeftLowerCase.indexOf("<i>", questionIndex) > 

			whatsLeftLowerCase.indexOf("</i>", questionIndex)) || 

			((!whatsLeftLowerCase.includes("<i>", questionIndex)) && 

			(whatsLeftLowerCase.includes("</i>", questionIndex)))) {

		questionIndex = whatsLeft.indexOf("?", questionIndex + 1);

	}

	if (whatsLeft.includes("... that ") && questionIndex !== -1) {

		if (whatsLeft.indexOf("... that ") < questionIndex) {

			hook = whatsLeft.substring(whatsLeft.indexOf("... that ") + 4, 

					questionIndex + 1);

			var hookTemp = document.createElement("div");

			hookTemp.id = "hook-temp";

			hookTemp.innerHTML = "<p>" + hook + "</p>";

			var hookLength = calculateProse(hookTemp, false);

			if (hookTemp.innerHTML.includes("pictured)") || 

					hookTemp.innerHTML.includes("(pictured")) {

				hookLength = hookLength - 10;

			}

			var hookDisp = document.createElement("li");

			hookDisp.id = "hooks-" + num;

			if (num === 0) {

				hookDisp.innerHTML = '<b>Original Hook:</b> ' + escapeHtml(hookLength) + ' characters';

			} else {

				hookDisp.innerHTML = '<b>Alternate Hook ' + escapeHtml(num) +'</b>: ' +

					escapeHtml(hookLength) + ' characters';

			}

			if (hookLength > hookLengthRed) {

				hookDisp.style.cssText = 'background-color:pink';

			} else if (hookLength > hookLengthYellow) {

				hookDisp.style.cssText = 'background-color:yellow';

			}

			hookOutput.appendChild(hookDisp);

			num = num + 1;

		}

		var parsed = whatsLeft.substring(questionIndex + 1, whatsLeft.length - 1);

		var lastHook = checkHooksHelper(hookOutput, parsed, num);

		if (!lastHook && hook) {

			lastHook = hook;

		}

		return lastHook;

	}

	return;

}



function checkTitle(title, output, i) {

	// gets the given title from Wikipedia's server and passes it to scanArticle(),

	// resolving any redirects.

	var promise = api.get({

		format: 'json',

		action: 'parse',

		page: title,

		redirects: true,

		prop: 'text'

	});

	promise.done(function (obj) {

		var ttdykTemp = document.createElement("div");

		ttdykTemp.id = "ttdyk-temp" + i;

		ttdykTemp.innerHTML = obj.parse.text"*"];

		title = obj.parse.title; // Get the new title if we were redirected

		scanArticle(title, output, ttdykTemp);

	});

	promise.fail(function () {

		alert("API error");

	});

}



function clearStats() {

	// if scan results already exist, turn them off and remove highlighting

	if (!onTTDYK) {

		var oldStyle = document.getElementById("dyk-stats-0").className;

		var mainContent = getBody();

		var pList = mainContent.getElementsByTagName("p");

		for (var iPara = 0; iPara < pList.length; iPara++) {

			if (pListiPara].parentNode === mainContent || pListiPara].parentNode.parentNode === mainContent) {

				pListiPara].style.cssText = oldStyle;

			}

		}

	}

	if (document.getElementById("error-disp")) {

		var errorDisp = document.getElementById("error-disp");

		errorDisp.parentNode.removeChild(errorDisp);

	}

	var iStat = 0;

	while (document.getElementById("dyk-stats-" + iStat)) {

		var output = document.getElementById("dyk-stats-" + iStat);

		output.parentNode.removeChild(output);

		iStat++;

	}

	if (document.getElementById("hook-container")) {

		var hookOutput = document.getElementById("hook-container");

		hookOutput.parentNode.removeChild(hookOutput);

	}

	if (document.getElementById("dyk-header")) {

		var header = document.getElementById("dyk-header");

		header.parentNode.removeChild(header);

	}

	if (document.getElementById("dyk-processing")) {

		var processing = document.getElementById("dyk-processing");

		processing.parentNode.removeChild(processing);

	}

}



function calculateProse(doc, visible) {

	// calculates the prose of a given document

	// this function and its helper below are modified versions of

	// the prosesize tool (http://en.wikipedia.org/wiki/User:Dr_pda/prosesize.js)

	var pList = doc.getElementsByTagName("p");

	var prose_size = 0;

	

	var i = 0;

	if (mwConfig.wgAction === 'submit' && visible) i = 1; // Avoid the "Remember that this is only a preview" text

	for (; i < pList.length; i++) {

		if (pListi].parentNode.parentNode === doc || pListi].parentNode.parentNode.parentNode.id === getBodyId()) {

			prose_size += getReadable(pListi], visible);

			if (!onTTDYK && visible) {

				pListi].style.cssText = 'background-color:yellow';

			}

		}

	}

	return prose_size;

}



function getReadable(id, visible) {

	// helper method for calculateProse()

	var textReadable = 0;

	for (var i = 0; i < id.childNodes.length; i++) {

		if (id.childNodesi].nodeName === '#text') {

			textReadable += id.childNodesi].nodeValue.length;

		} else if (id.childNodesi].className !== 'reference' && 

				!(id.childNodesi].className && id.childNodesi].className.includes('emplate')) &&

				id.childNodesi].id !== 'coordinates') {

			textReadable += getReadable(id.childNodesi], visible);

		} else if (visible) { // if it's an inline maintenance tag (like [citation needed]) or geocoordinates

			if (document.getElementById("dyk-stats-0").className) {

				id.childNodesi].style.cssText = document.getElementById("dyk-stats-0").className;

			} else {

				id.childNodesi].style.cssText = 'background-color:white';

			}	

		}

	}

	return textReadable;

}



function checkExpansion(title, output, current) {  

	// finds the start of expansion date (last 500 edits)

	// gets the last 500 unique revision ids for past revisions of the article and passes to helper function

	var promise = getRevisions({

		titles: title,

		rvlimit: 500,

		rvprop: 'ids', 'timestamp', 'sha1'],

		rvdir: 'older'

	});

	promise.done(function (revisionsWithDeletedRevs) {

		var revisions = revisionsWithDeletedRevs.filter(revision => 'sha1' in revision);

		var expandTemp = document.createElement("div");

		expandTemp.id = "expand-temp";

		checkExpansionHelper(title, current, output, expandTemp, revisions, 0, revisions.length-1, -1);

	});

}



function checkExpansionHelper(title, current, output, expandTemp, revisions, min, max, expandIndex) {

	// helper for expansion check, used recursively

	// searches for start of expansion date using a binary search algorithm

	// assumes the article has been more or less increasing in size all the time

	// if the article length has yoyo-ed, this function won't give accurate results

	var mid = Math.ceil((max + min)/2);

	if ((((max - min) < 2) && (max !== revisions.length - 1 || expandIndex !== -1)) || expandIndex === -2) {

		var expandResult = document.createElement("li");

		expandResult.id = "expand-result";

		output.appendChild(expandResult);

		if (expandIndex < 0) {

			if (revisions.length === 500) {

				expandResult.innerHTML = escapeHtml('Article has not been expanded 5x in the last 500 edits');

			} else {

				expandResult.innerHTML = escapeHtml('Article has not been expanded 5x since it was created');

			}

		} else {

			var date = revisionsexpandIndex-1].timestamp;

			expandResult.innerHTML = 'Assuming article is at 5x now, expansion began ' + 

					escapeHtml(expandIndex) + ' edits ago on ' + escapeHtml(toNormalDate(date.substring(0,10)));

			dates2 = toDateObject(date);

		}

		partsProcessing3 = true;

		doneProcessing();

		return;

	} else if ((max - min) < 2 && max === revisions.length - 1) {

		expandIndex = -2;

	}

	var promise = api.get({

		format: 'json',

		action: 'parse',

		oldid: revisionsmid].revid,

		prop: 'text'

	});

	promise.done(function (obj) {

		expandTemp.innerHTML = obj.parse.text'*'];

		var prose = calculateProse(expandTemp, false);

		// alert("Prose: " + prose + " 1x: " + current/5 + " Mid: " + mid + " Expand index: " + expandIndex); 

		// use above line to debug the expansion check

		if (prose < (current/5.0)) {

			if ((expandIndex > mid) || (expandIndex < 0)) {

				expandIndex = mid;

			}

			checkExpansionHelper(title, current, output, expandTemp, revisions, min, mid, expandIndex);

		} else {

			checkExpansionHelper(title, current, output, expandTemp, revisions, mid, max, expandIndex);

		}

	});

	promise.fail(function () {

		alert("API error");

		partsProcessing3 = true;

		doneProcessing();

	});

}



function checkTalk(title, output) { 

	// checks the talk page of the article for DYK, ITN, or stub templates

	if (mwConfig.wgNamespaceNumber !== 2) {

		title = "Talk:" + title;

	} else {

		title = title.replace("User:", "User talk:");

	}

	var promise = getRevisions({

		titles: title,

		rvprop: 'content'

	});

	promise.done(function (revisions) {

		if (revisions && revisions0]) {

			var talkPage = revisions0]['*'];

			var result = '';

			var color = '';

			if (talkPage.match(/class\s*=\s*[sS]tub/) && 

					(document.getElementById("stub-alert") === null)) {

				result += 'Article is classified as a stub ';

				color = 'yellow';

			}

			var dyktalkRegexMatches = talkPage.match(/{{\s*[dD](yk|YK\s?)talk[^}]*}}/g);

			if (dyktalkRegexMatches) {

				// if there's a DYK tag, try to find the date of previous appearance

				result += 'Article has appeared on Did You Know before ';

				var dyktalkTag = dyktalkRegexMatches.pop();

				var firstPipeIndex = dyktalkTag.indexOf('|');

				var secondPipeIndex = dyktalkTag.indexOf('|', firstPipeIndex + 1);

				var thirdPipeIndex = dyktalkTag.indexOf('|', secondPipeIndex + 1);

				if (firstPipeIndex !== -1 && secondPipeIndex !== -1) {

					if (thirdPipeIndex === -1) {

						thirdPipeIndex = dyktalkTag.length - 2; // -2 to get rid of the }}

					}

					var monthDate = dyktalkTag.substring(firstPipeIndex + 1, secondPipeIndex);

					var year = dyktalkTag.substring(secondPipeIndex + 1, thirdPipeIndex);

					var featuredDate = new Date(monthDate + " " + year);

					if (featuredDate.toString() !== 'Invalid Date') {

						var month = featuredDate.getMonth() + 1;

						if (month < 10) {

							month = '0' + month;

						}

						var date = featuredDate.getDate();

						if (date < 10) {

							date = '0' + date;

						}

						var dateString = toNormalDate(featuredDate.getFullYear() + '-' + month + '-' + date);

						result = result.substring(0, result.length - 1) + ', on ' + escapeHtml(dateString);

					}

				}

				color = 'pink';

			} else if (talkPage.match(/rticle[ ]?[hH]istory[\s\S]*dykdate\s*=.*?\S/)) {

				result += 'Article has appeared on Did You Know before ';

				color = 'pink';

			}

			if (talkPage.match(/{{\s*[iI]TN(\st|t|T)alk/)) { // {{ITNtalk}}, {{ITN talk}}, {{ITNTalk}}

				result += 'Article has appeared on In The News before ';

				color = 'pink';

			}

			if (result) {

				var talkResult = document.createElement("li");

				talkResult.id = "talk-result";

				output.appendChild(talkResult);

				talkResult.innerHTML = result;

				if (color) {

					talkResult.style"background-color" = color;

				}

			}

			checkTalkForGoodArticleStatus(talkPage, output);

		}

		partsProcessing0 = true;

		doneProcessing();

	});

	promise.fail(function () {

		partsProcessing0 = true;

		doneProcessing();

	});

}



function checkTalkForGoodArticleStatus(talkPage, output) {

	// Test cases:

	// Cathedral of the Immaculate Conception (Moscow) - ArticleHistory, two GANs (last successful), currently a featured article

	// LoveGame - ArticleHistory, one successful GAN, no GARs

	// Paparazzi (Lady Gaga song) - ArticleHistory, one successful GAN, unlisted after a GAR, another successful GAN, no-op GAR

	// Curtis (50 Cent album) - ArticleHistory, one successful GAN, unlisted after a GAR

	// G.U.Y. - ArticleHistory with unconventional formatting

	// Arthur Adams (comics) - ArticleHistory with unconventional formatting

	// Blackburn Firebrand - {{GA}}

	// Tony Hawk's Underground - {{GA}} with confounding {{Game}} tag

	var gaDate = '';

	var gaRegexMatches = talkPage.match(/{{\s*[gG][aA]\s*[|][^}]*}}/g);

	if (gaRegexMatches) {

		// if there's a GA tag, try to find the date of promotion to Good Article

		var gaTag = gaRegexMatches.pop();

		var firstPipeIndex = gaTag.indexOf('|');

		var secondPipeIndex = gaTag.indexOf('|', firstPipeIndex + 1);

		if (firstPipeIndex !== -1) {

			if (secondPipeIndex === -1) {

				secondPipeIndex = gaTag.length - 2; // -2 to get rid of the }}

			}

			gaDate = gaTag.substring(firstPipeIndex + 1, secondPipeIndex);

		}

	} else if (talkPage.match(/rticle[ ]?[hH]istory/)) {

		// check ArticleHistory tag for Good Article status

		

		// grab last GAN action

		// figure out action number

		// given action number, was action result "listed"?

		// if no, stop here - article is not a Good Article

		// if yes, grab the Good Article promotion date from actionXdate

		var ganMatches = talkPage.match(/action[0123456789]+\s*=\s*(gan|GAN)/g);

		if (ganMatches) {

			var lastGanAction = ganMatches.pop();

			var lastGanActionNumber = lastGanAction.substring(6, lastGanAction.indexOf('=')); // remove 'action' and everything at and after the equals sign

			lastGanActionNumber = lastGanActionNumber.trim();

			var ganResultIndex = talkPage.indexOf('action' + lastGanActionNumber +  'result');

			var ganResult = talkPage.substring(talkPage.indexOf('=', ganResultIndex) + 1, talkPage.indexOf('|', ganResultIndex)).trim();

			if (ganResult === 'listed' || ganResult === 'Listed' || ganResult === 'passed' || ganResult === 'Passed') {

				var ganDateIndex = talkPage.indexOf('action' + lastGanActionNumber +  'date');

				gaDate = talkPage.substring(talkPage.indexOf('=', ganDateIndex) + 1, talkPage.indexOf('|', ganDateIndex)).trim();

			}

			

			// then grab last GAR action

			// figure out action number

			// is GAR action number after GAN action number? if yes, carry on

			// given action number, was action result "not listed"?

			// if yes, article is not a Good Article

			var garMatches = talkPage.match(/action[0123456789]+\s*=\s*(gar|GAR)/g);

			if (garMatches) {

				var lastGarAction = garMatches.pop();

				var lastGarActionNumber = lastGarAction.substring(6, lastGarAction.indexOf('=')); // remove 'action' and everything at and after the equals sign

				lastGarActionNumber = lastGarActionNumber.trim();

				if (parseInt(lastGarActionNumber) > parseInt(lastGanActionNumber)) {

					var garResultIndex = talkPage.indexOf('action' + lastGarActionNumber +  'result');

					var garResult = talkPage.substring(talkPage.indexOf('=', garResultIndex) + 1, talkPage.indexOf('|', garResultIndex)).trim();

					if (garResult === 'delisted' || garResult === 'Delisted') {

						gaDate = ''; // Not a Good Article, GAR came after GAN and demoted the article

					}

				}

			}

		}

	}

	

	if (gaDate) {

		if (gaDate.length > 6 && gaDate.indexOf(' (UTC)') === gaDate.length - 6) {

			gaDate = gaDate.substring(0, gaDate.length - 6); // The Boat Race 1997 is not parsing correctly if (UTC) is left in

		}

		if (gaDate.length > 5 && gaDate2 === ':' && gaDate5 === ',') {

			gaDate = gaDate.substring(6, gaDate.length).trim(); // Chrome not parsing as expected for strings like "17:21, 26 June 2014"

		}

		

		var gaPromotion = document.createElement("li");

		gaPromotion.id = "ga-promotion";

		output.appendChild(gaPromotion);

		var gaPromotedDate = new Date(gaDate);

		

		// ensure the Date object is in the right time zone

		gaPromotedDate = new Date(Date.UTC(gaPromotedDate.getFullYear(), gaPromotedDate.getMonth(), gaPromotedDate.getDate(), gaPromotedDate.getHours(), gaPromotedDate.getMinutes(), gaPromotedDate.getSeconds()));

		

		dates3 = gaPromotedDate;

		gaPromotion.innerHTML = 'Article was promoted to Good Article status on ' +

			escapeHtml(toNormalDate(gaPromotedDate.toISOString()));

	}

}



function getRevisions(options) {

	// Returns a jQuery promise with an array of a title's revisions.

	// The first parameter is an options object accepting the following API fields:

	// - titles

	// - rvlimit

	// - rvprop

	// - rvdir

	options = options || {};

	return api.get({

		format: 'json',

		action: 'query',

		prop: 'revisions',

		titles: options.titles,

		rvlimit: options.rvlimit,

		rvprop: options.rvprop,

		rvdir: options.rvdir,

		indexpageids: true

	}).then(

		// On success

		function (obj) {

			var pageId = obj.query.pageids0];

			return obj.query.pagespageId].revisions;

		},

		// On failure

		function (err) {

			alert("API error");

			return err;

		}

	);

}



function getFirstRevision(title, output) {

	// finds the creator of the article, and the date created

	// also checks if the article was created as a redirect, finds non-redirect date if so



	var created = document.createElement("li");

	created.id = "creation-info";

	output.appendChild(created);

		

	var promise = getRevisions({

		titles: title,

		rvlimit: 4,

		rvprop: 'timestamp', 'user', 'content'],

		rvdir: 'newer'

	});

	promise.done(function (revisions) {

		var user = revisions0].user;

		var timestamp = revisions0].timestamp;

		created.innerHTML='<b>Article created </b> by ' + escapeHtml(user) + 

				' on ' + escapeHtml(toNormalDate(timestamp.substring(0,10)));

		dates0 = toDateObject(timestamp);

		for (var i = 0; i < revisions.length; i++) {

			var content = revisionsi]['*'];

			var isRedirect = content.replace(' ', '').replace(':', '').toUpperCase().includes('#REDIRECT[[');

			if (isRedirect && i === 0) {

				created.innerHTML = created.innerHTML + ' as a redirect';

			} else if (!isRedirect) {

				if (i !== 0) {

					var unRedirect = document.createElement("li");

					unRedirect.id = "expanded-from-redirect";

					output.appendChild(unRedirect);

					var urUser = revisionsi].user;

					var urTimestamp = revisionsi].timestamp;

					unRedirect.innerHTML = 'Article became a non-redirect on ' + 

							escapeHtml(toNormalDate(urTimestamp.substring(0,10))) +

							' by ' + escapeHtml(urUser);

					dates0 = toDateObject(urTimestamp);

				}

				break;

			}

		}

		partsProcessing1 = true;

		doneProcessing();

	});

	promise.fail(function () {

		partsProcessing1 = true;

		doneProcessing();

	});

}



function checkMove(title, output) { 

	//checks the last 100 edits of an article for a move from userspace or AfC to current location

	var promise = getRevisions({

		titles: title,

		rvlimit: 100,

		rvprop: 'flags', 'user', 'timestamp', 'comment'],

		rvdir: 'older',

	});

	promise.done(function (revisions) {

		for (var i = 0; i < revisions.length; i++) {

			var comment = revisionsi].comment;

			var userName = revisionsi].user;

			if ((revisionsi].minor === "") && 

					comment.match(/moved (page )?((\[\[User:)|(\[\[Draft:)|(\[\[Wikipedia talk:Articles for creation\/))[\s\S]*to \[\[/)) {

				var movedFrom = comment.substring(comment.indexOf("[[") + 2, comment.indexOf("to [[") - 3);

				var date = revisionsi].timestamp;

				var moved = document.createElement("li");

				moved.id = "moved-userspace";

				output.appendChild(moved);

				moved.innerHTML = '<b>Article moved</b> from ' + escapeHtml(movedFrom) + 

						' on ' + escapeHtml(toNormalDate(date.substring(0,10)));

				dates1 = toDateObject(date);

				break;

			}

		}

		partsProcessing2 = true;

		doneProcessing();

	});

	promise.fail(function () {

		partsProcessing2 = true;

		doneProcessing();

	});

}



function doneProcessing() {

	// checks if all parts are done processing

	// if they are, the dates of creation and expansion are checked for within 10 days (rounded down, in nominator's favor)

	// then the next title (for multiple article noms) is processed (required to combat asynchronous threads)

	// if there are no more titles left (or not on T:TDYK), the processing message is removed

	var titleComplete = true;

	for (var i = 0; i < partsProcessing.length; i++) {

		if (!partsProcessingi]) {

			titleComplete = false;

			break;

		}

	}

	if (document.getElementById("dyk-processing") && titleComplete) {

		var curDate = new Date();

		var winner = new Date();

		if (dates1]) {

			winner = dates1]; 

		} else {

			winner = dates0];

		}

		if (dates2 > winner) {

			winner = dates2];

		}

		if (dates3 > winner) {

			winner = dates3];

		}

		var dateDifference = Math.floor((curDate.getTime() - winner.getTime())/(1000*60*60*24));

		if (dateDifference > 10) {

			var output = document.getElementById("dyk-stats-" + currentTitle);

			var notRecent = document.createElement("li");

			notRecent.id = "not-recent";

			output.appendChild(notRecent);

			if (!onTTDYK || (check5xNoms === "always") || (check5xNoms === "ifnom5x" && nom5x)) {

				notRecent.innerHTML = "Article has not been created or expanded 5x or promoted to Good Article within the past 10 days (" + 

						escapeHtml(dateDifference) + " days)" + " <small>DYKcheck does not account for previous versions with " +

						'<a href="//en.wikipedia.org/wiki/Wikipedia:Split">splits</a> or ' +

						'<a href="//en.wikipedia.org/wiki/Wikipedia:Copyright_violations">copyright violations</a>.</small>';

			} else {

				notRecent.innerHTML = "Article was not created within the past 10 days (" + escapeHtml(dateDifference) + " days)";

			}

			notRecent.style.cssText = 'background-color:pink';

		}

		if (onTTDYK && currentTitle < (articleTitles.length - 1)) {

			currentTitle++;

			checkTitle(articleTitlescurrentTitle], 

					document.getElementById("dyk-stats-" + (currentTitle)), currentTitle);

		} else {

			var processing = document.getElementById("dyk-processing");

			processing.parentNode.removeChild(processing);

		}

	}

}



// taken from the prosesize tool (http://en.wikipedia.org/wiki/User:Dr_pda/prosesize.js)

function getBodyId() {

	var contentName;

	if (mwConfig.skin === 'monobook' || mwConfig.skin === 'chick' || mwConfig.skin === 'mymwConfig.skin' || mwConfig.skin === 'simple') {

		contentName = 'bodyContent';

	} else if (mwConfig.skin === 'modern') {

		contentName = 'mw_contentholder';

	} else if (mwConfig.skin === 'standard' || mwConfig.skin === 'cologneblue' || mwConfig.skin === 'nostalgia') {

		contentName = 'article';

	} else {

		// fallback case; the above covers all currently existing skins

		contentName = 'bodyContent';

	}

	// Same for all skins if previewing page

	if (mwConfig.wgAction === 'submit') contentName = 'wikiPreview';

	return contentName;

}



function getBody() { 

	// gets the HTML body of the page

	// taken from the prosesize tool (http://en.wikipedia.org/wiki/User:Dr_pda/prosesize.js)

	return document.getElementById(getBodyId());

}



function getFirstNom() {

	var firstNom = 0;

	

	// Find the first "Articles created/expanded on ..." h3 section

	var elementIterator = sectionsfirstNom].previousSibling;

	while (elementIterator.nodeName.toLowerCase() !== "h3") {

		elementIterator = elementIterator.previousSibling;

	}

	while (!(elementIterator.nodeName.toLowerCase() === "h3" && 

			elementIterator.innerHTML.includes("Articles created/expanded on"))) {

		if (elementIterator.nodeName.toLowerCase() === "h4") {

			firstNom++;

		}

		elementIterator = elementIterator.nextSibling;

	}

	return firstNom;

}



function createHeaderAndProcessing(output) { 

	// makes the header above the scan results

	var header = document.createElement("span");

	header.id = "dyk-header";

	header.innerHTML = '<br /><b>DYK eligibility scan results: <small><i>(See <a href="//en.wikipedia.org/wiki/' + 

			'User:Shubinator/DYKcheck">here</a> for details.)</i></small></b>';

	output.parentNode.insertBefore(header,output);

	var processing = document.createElement("span");

	processing.id = "dyk-processing";

	processing.innerHTML = '<br /><b><font color="crimson"> Processing... </font></b>';

	output.parentNode.insertBefore(processing, header);

}



function toNormalDate(utc) { 

	// converts the date part of a Wikipedia timestamp to a readable date

	var months = new Array("blank","January","February", "March", "April", "May", "June", 

			"July", "August", "September", "October", "November", "December");

	if (dateFormat === "british") {

		return (utc.substring(8,10) * 1) + ' ' + monthsutc.substring(5,7) * 1 + ' ' + utc.substring(0,4);

	} else {

		return monthsutc.substring(5,7) * 1 + ' ' + (utc.substring(8,10) * 1) + ', ' + utc.substring(0,4);

	}

}



function toDateObject(timestamp) { 

	// converts a Wikipedia timestamp to a Javascript Date object

	var date = new Date();

	date.setUTCFullYear(timestamp.substring(0,4), timestamp.substring(5,7) - 1, timestamp.substring(8,10));

	date.setUTCHours(timestamp.substring(11,13), timestamp.substring(14,16), timestamp.substring(17,19));

	return date;

}



function fixSidebar() { // part of the code to fix the sidebar; the rest is below the addToolbarPortletLink function

	// this function is only necessary for the monobook skin

	var content = document.getElementById("column-content");    // Find the main content column



	var footer = document.getElementById("footer");  // Find the footer

	footer.parentNode.removeChild(footer);    // Remove the footer from the global wrapper

	content.appendChild(footer);    // Place footer at the end of the content column;



	var tabs = document.getElementById("p-cactions");   // Find the top tab list

	tabs.parentNode.removeChild(tabs);    // Remove the tab list from the side column

	content.insertBefore(tabs, content.lastChild);    // Place tab list in the content column



	var personal = document.getElementById("p-personal");   // Find the personal links list

	personal.parentNode.removeChild(personal);    // Remove the personal links list from the side column

	content.insertBefore(personal, content.lastChild);    // Place personal links list in the content column

}



window.dykCheck = function () { 

	// this function for casual use and anons

	if (((mwConfig.wgAction === 'view' || mwConfig.wgAction === 'submit' || mwConfig.wgAction === 'purge') && 

			(mwConfig.wgNamespaceNumber === 0 || mwConfig.wgNamespaceNumber === 2)) || unlock) {

		checkDocument();

	} else if (mwConfig.wgPageName === 'Template_talk:Did_you_know') {

		checkTTDYK();

	}

};



function addToolbarPortletLink(func, tooltip) {

	var link = mw.util.addPortletLink(

		'p-tb',

		'#',

		'DYK check',

		't-dyk-check',

		tooltip

	);

	$( link ).click( function (e) {

		e.preventDefault();

		func();

	});

}



// Add toolbar portlet links

if (unlock || (

		(mwConfig.wgAction === 'view' || mwConfig.wgAction === 'submit' || mwConfig.wgAction === 'purge') && 

		(mwConfig.wgNamespaceNumber === 0 || mwConfig.wgNamespaceNumber === 2)

)) {

	addToolbarPortletLink(checkDocument, 'Check if this article qualifies for DYK');

} else if (mwConfig.wgPageName === 'Template_talk:Did_you_know') {

	addToolbarPortletLink(checkTTDYK, 'Check DYK nominations for eligibility');

}



// Fix the sidebar

if (mwConfig.wgUserName && mwConfig.skin === 'monobook' && (

		fixedSidebar === "always" ||

		fixedSidebar === "onttydk" && mwConfig.wgPageName === 'Template_talk:Did_you_know'

)) {

	fixSidebar();

}



// The code below for the fixed sidebar is a blend of two sources:

//		http://meta.wikimedia.org/wiki/Help:User_style/floating_quickbar 

// 		http://en.wikipedia.org/wiki/User:Omegatron/monobook.js/floatingSidebar.js

// Very little of the code below was written by me (Shubinator)



// This CSS should be hidden from older versions of IE using javascript instead of the attribute selector?



// Include style sheet inline so that script is self-contained:

if (mwConfig.wgUserName && (

		fixedSidebar === "always" ||

		fixedSidebar === "onttydk" && mwConfig.wgPageName === 'Template_talk:Did_you_know'

)) {

	var head = document.getElementsByTagName("head")[0];

	var style = document.createElement('style');

	style.type = 'text/css';

	var sidebarDivHidden;

	var sidebarDiv;

	var langBody;

	if (mwConfig.skin === 'vector') { // default skin  (as of May 2010)

		sidebarDivHidden = 'div#mw-panel';

		sidebarDiv = 'div#mw-panel';

		langBody = '#p-lang .body';

	} else { // monobook, modern, and simple skins

		if (mwConfig.skin === 'modern') {

			sidebarDivHidden = 'div[id=mw_portlets]';

		} else if (mwConfig.skin === 'simple') {

			sidebarDivHidden = '#column-one';

		} else { // monobook skin

			sidebarDivHidden = 'div[id=column-one]'; /* Using the attribute selector hides this from IE */

		}

		sidebarDiv = '#column-one';

		langBody = '#p-lang .pBody';

	}

	var cssText = "   /* Fix the sidebar's position while you scroll */             "+

	    sidebarDivHidden + ' {                                                      '+

	'       position: fixed;                                                        ';

	if (mwConfig.skin === 'vector') { // force the sidebar to the upper left; only necessary in some skins

	    cssText += 'left: 0px;                                                      '+

	    '   top: 0px;                                                               ';

	} else if (mwConfig.skin === 'monobook') {

	    cssText += 'left: 0px;                                                      '+

	    '   top: -160px;                                                            ';

	}

	cssText += 'height: 100%;   /* If you shrink the browser too small, the     */  '+

	'       overflow: auto;     /* side column will become scrollable, so stuff */  '+

	'       z-index: 2;         /* is always accessible, albeit ugly            */  '+

	'   }                                                                           '+

	'                                                                               '+

	'   #p-logo {               /* Make logo inline with other divs             */  '+

	'       position:static;                                                        '+

	'   }                                                                           '+

	'                                                                               '+

	    sidebarDiv       + ' {  /* Sidebar column start at the top screen edge  */  '+

	'       padding-top: 0;                                                         '+

	'   }                                                                           '+

	'                                                                               '+

	    langBody + 	  ' ul{      /* Sets the language box to a fixed height and  */ '+

	'       height: 6em;        /* scrollable if too long to fit on screen      */  '+

	'       overflow: auto;                                                         '+

	'   }                                                                           '+

	'                                                                               '+

	'   /* Fix the background image, too, so it looks nice as you scroll */         '+

	'   body {                                                                      '+

	'       background-attachment: fixed;                                           '+

	'   }                                                                           '+

	'                                                                               '+

	"   /* Fix the footer so it looks nice and doesn't overlap the sidebar */       "+

	'   #footer {                                                                   '+

	'       margin-left: 13.6em;                                                    '+

	'       border-left: solid 1px rgb(250, 189, 35);                               '+

	'       -moz-border-radius-topleft: 1em;                                        '+

	'       -moz-border-radius-bottomleft: 1em;                                     '+

	'   }                                                                           ';

	if (mwConfig.skin === 'monobook') {

	    cssText += 	'   /* Keep personal links at the top right */                  '+

	'   #p-personal {                                                               '+

	'       width:100%;                                                             '+

	'       white-space:nowrap;                                                     '+

	'       padding:0 0 0 0;                                                        '+

	'       margin:0;                                                               '+

	'       position:absolute;                                                      '+

	'       left:0px;                                                               '+

	'       top:0px;                                                                '+

	'       z-index: 0;                                                             '+

	'       border: none;                                                           '+

	'       background: none;                                                       '+

	'       overflow: visible;                                                      '+

	'       line-height: 1.2em;                                                     '+

	'   }                                                                           '+

	'                                                                               '+

	'   #p-personal h5 {                                                            '+

	'       display:none;                                                           '+

	'   }                                                                           '+

	'   #p-personal .portlet,                                                       '+

	'   #p-personal .pBody {                                                        '+

	'       padding:0;                                                              '+

	'       margin:0;                                                               '+

	'       border: none;                                                           '+

	'       z-index:0;                                                              '+

	'       overflow: visible;                                                      '+

	'       background: none;                                                       '+

	'   }                                                                           '+

	'   /* this is the ul contained in the portlet */                               '+

	'   #p-personal ul {                                                            '+

	'       border: none;                                                           '+

	'       line-height: 1.4em;                                                     '+

	'       color: #2f6fab;                                                         '+

	'       padding: 0em 2em 0 3em;                                                 '+

	'       margin: 0;                                                              '+

	'       text-align: right;                                                      '+

	'       text-transform: lowercase;                                              '+

	'       list-style: none;                                                       '+

	'       z-index:0;                                                              '+

	'       background: none;                                                       '+

	'   }                                                                           '+

	'   #p-personal li {                                                            '+

	'       z-index:0;                                                              '+

	'       border:none;                                                            '+

	'       padding:0;                                                              '+

	'       display: inline;                                                        '+

	'       color: #2f6fab;                                                         '+

	'       margin-left: 1em;                                                       '+

	'       line-height: 1.2em;                                                     '+

	'       background: none;                                                       '+

	'   }                                                                           '+

	'   #p-personal li a {                                                          '+

	'       text-decoration: none;                                                  '+

	'       color: #005896;                                                         '+

	'       padding-bottom: 0.2em;                                                  '+

	'       background: none;                                                       '+

	'   }                                                                           '+

	'   #p-personal li a:hover {                                                    '+

	'       background-color: White;                                                '+

	'       padding-bottom: 0.2em;                                                  '+

	'       text-decoration: none;                                                  '+

	'   }                                                                           '+

	'   /* Keep the small user figure left of your user name */                     '+

	'   li#pt-userpage,                                                             '+

	'   li#pt-anonuserpage,                                                         '+

	'   li#pt-login {                                                               '+

	'       background: url(/skins-1.5/monobook/user.gif) top left no-repeat;       '+

	'       padding-left: 20px;                                                     '+

	'       text-transform: none;                                                   '+

	'   }                                                                           '+

	'                                                                               ';

	}

	var rules = document.createTextNode(cssText);

	if (style.styleSheet) {

		style.styleSheet.cssText = rules.nodeValue;

	} else {

		style.appendChild(rules);

	}

	head.appendChild(style);

}



});

Videos

Youtube | Vimeo | Bing

Websites

Google | Yahoo | Bing

Encyclopedia

Google | Yahoo | Bing

Facebook