(Translated by https://www.hiragana.jp/)
User:Anderjef/common.js: Difference between revisions - Wikipedia Jump to content

User:Anderjef/common.js: Difference between revisions

From Wikipedia, the free encyclopedia
Content deleted Content added
Bugfix circa-formatting regex
Filter current events containing "In tennis, "
 
(37 intermediate revisions by the same user not shown)
Line 1: Line 1:
// <nowiki>
// <nowiki>
/* jshint esversion: 5, leanswitch: true, nonbsp: true, nonew: true, singleGroups: true, strict: true, undef: true, unused: true */
/* jshint leanswitch: true, nonbsp: true, nonew: true, singleGroups: true, strict: true, undef: true, unused: true */
/* globals $, console, document, Event, mw, pathoschild, performance, window */
/* globals $, console, document, Event, mw, pathoschild, performance, window */
$(function() {
$(function() {
"use strict";
"use strict";
try {
try {
var forbiddenPages = [];
var dayOfWeek = (new Date()).getDay();
var dayOfWeek = (new Date()).getDay();
if (1 <= dayOfWeek) {
if (1 <= dayOfWeek) {
var forbiddenPages = ['Main_Page', 'Special:Search', 'Special:Homepage', 'Special:Watchlist'];
forbiddenPages = ['Main_Page', 'Special:Search', 'Special:Homepage', 'Special:Watchlist', 'User:Uhai/Pages_without_short_descriptions_by_view_count'];
}
for (var i = 0; i < forbiddenPages.length; i++) {
else {
if (window.location.pathname.includes(forbiddenPages[i]) || window.location.search.includes(forbiddenPages[i]) || window.location.pathname === '/wiki/User:Anderjef') {
var hour = (new Date()).getHours();
window.location.assign("https://www.wikipedia.org");
if (hour < 7 || 19 <= hour) {
break;
forbiddenPages = ['User:Uhai/Pages_without_short_descriptions_by_view_count'];
}
}
}
}
}
for (var i = 0; i < forbiddenPages.length; i++) {
if (window.location.pathname.includes(forbiddenPages[i]) || window.location.search.includes(forbiddenPages[i])) {
window.location.assign("https://www.wikipedia.org");
break;
}
}
}
catch (e) { //continue even if an error occurred
console.error(e.message);
}
}
catch (e) {} //continue even if an error occurred
function reportCompletion(description, duration, notificationType, storageName, storageAdditionalSum, textSize) { //duration is assumed to be in milliseconds; notificationType being 'info', 'warn', 'error', or 'success'; notification becomes description + " in " + duration + "ms"
function reportCompletion(description, duration, notificationType, storageName, storageAdditionalSum, textSize) { //duration is assumed to be in milliseconds; notificationType being 'info', 'warn', 'error', or 'success'; notification becomes description + " in " + duration + "ms"
var notificationString = description + " in " + duration + "ms";
var notificationString = description + " in " + duration + "ms";
Line 39: Line 48:
if (existingItem !== null) {
if (existingItem !== null) {
var existingStorageAdditionalSum = parseInt(existingItem.substring(existingItem.indexOf(attributeName + ': ') + (attributeName + ': ').length));
var existingStorageAdditionalSum = parseInt(existingItem.substring(existingItem.indexOf(attributeName + ': ') + (attributeName + ': ').length));
var existingTextSize = (existingItem.indexOf('bytes: ') < 0 ? 'NaN' : parseInt(existingItem.substring(existingItem.indexOf('bytes: ') + 'bytes: '.length)));
var existingTextSize = existingItem.indexOf('bytes: ') < 0 ? 'NaN' : parseInt(existingItem.substring(existingItem.indexOf('bytes: ') + 'bytes: '.length));
window.localStorage.setItem(storageName + ' ' + notificationType, 'milliseconds: ' + (parseInt(existingItem.substring(existingItem.indexOf('milliseconds: ') + 'milliseconds: '.length)) + duration) + ', ' + attributeName + ': ' + (isNaN(existingStorageAdditionalSum) ? (!isNaN(storageAdditionalSum) ? storageAdditionalSum : 'NaN') : existingStorageAdditionalSum + storageAdditionalSum) + ', tally: ' + (parseInt(existingItem.substring(existingItem.indexOf('tally: ') + 'tally: '.length)) + 1) + (isNaN(existingTextSize) ? (!isNaN(textSize) ? ', bytes: ' + textSize : '') : ', bytes: ' + (existingTextSize + textSize)));
window.localStorage.setItem(storageName + ' ' + notificationType, 'milliseconds: ' + (parseInt(existingItem.substring(existingItem.indexOf('milliseconds: ') + 'milliseconds: '.length)) + duration) + ', ' + attributeName + ': ' + (isNaN(existingStorageAdditionalSum) ? (!isNaN(storageAdditionalSum) ? storageAdditionalSum : 'NaN') : existingStorageAdditionalSum + storageAdditionalSum) + ', tally: ' + (parseInt(existingItem.substring(existingItem.indexOf('tally: ') + 'tally: '.length)) + 1) + (isNaN(existingTextSize) ? (!isNaN(textSize) ? ', bytes: ' + textSize : '') : ', bytes: ' + (existingTextSize + textSize)));
}
}
Line 52: Line 61:
function filterCurrentEvents(numTries, startTime) {
function filterCurrentEvents(numTries, startTime) {
if ($('.p-current-events-headlines ul').length && $('.itn-img').length) {
if ($('.p-current-events-headlines ul').length && $('.itn-img').length) {
var currentEventsFilter = ["cricket", "filmmaker", "football", "golf", "hockey", "In television, ", "rugby"];
var currentEventsFilter = ["basketball", "cricket", "Cricket World Cup", "Eurovision Song Contest", "filmmaker", "Film Awards", "Film Festival", "football", "golf", "hockey", "In television, ", "In tennis, ", "Japan Series", "NASCAR Cup Series", "PDC World Championship", "rugby", "World Baseball Classic"];
for (var i = 0; i < currentEventsFilter.length; i++) {
for (var i = 0; i < currentEventsFilter.length; i++) {
for (var j = 0; j < $('.p-current-events-headlines ul li:contains(' + currentEventsFilter[i] + ')').length; j++) {
for (var j = 0; j < $('.p-current-events-headlines ul li:contains(' + currentEventsFilter[i] + ')').length; j++) {
Line 76: Line 85:
var watchlistExpiryIsSet = false; //basically a mutex for the watchlist expiry
var watchlistExpiryIsSet = false; //basically a mutex for the watchlist expiry
function setWatchlistExpiry(numTries, startTime, expiryValue) {
function setWatchlistExpiry(numTries, startTime, expiryValue) {
if ((expiryValue === undefined ? $('#wpWatchthis').length : $('#wpWatchlistExpiry').length)) {
if (expiryValue === undefined ? $('#wpWatchthis').length : $('#wpWatchlistExpiry').length) {
if (expiryValue === undefined) {
if (expiryValue === undefined) {
if ($('#wpWatchthis')[0].checked) {
if ($('#wpWatchthis')[0].checked) {
Line 90: Line 99:
else if (++numTries < 1000) { window.setTimeout(setWatchlistExpiry, 5, numTries, startTime, expiryValue); } //try for 1000*5 milliseconds (that is 5 seconds)
else if (++numTries < 1000) { window.setTimeout(setWatchlistExpiry, 5, numTries, startTime, expiryValue); } //try for 1000*5 milliseconds (that is 5 seconds)
else { reportCompletion("Failed to set watchlist expiry", (performance.now() - startTime).round(3), 'error', 'watchlist-expiry-setting', numTries, 'NaN'); }
else { reportCompletion("Failed to set watchlist expiry", (performance.now() - startTime).round(3), 'error', 'watchlist-expiry-setting', numTries, 'NaN'); }
}
function increaseEditorSpecialCharactersBarHeight(numTries, startTime) {
if ($('#editpage-specialchars').length) {
$('#editpage-specialchars').css('padding-top', $(document.body).height() / 16);
window.dispatchEvent(new Event('resize'));
reportCompletion(numTries + " tries before wikitext editor's special characters bar was heightened", (performance.now() - startTime).round(3), 'success', 'special-characters-bar-heightening', numTries, 'NaN');
}
else if (++numTries < 5000) { window.setTimeout(increaseEditorSpecialCharactersBarHeight, 10, numTries, startTime); } //try for 5000*10 milliseconds (that is 50 seconds)
else { reportCompletion("Failed to increase height of wikitext editor's special characters bar", (performance.now() - startTime).round(3), 'error', 'special-characters-bar-heightening', numTries, 'NaN'); }
}
}
function filterWatchlistExpiryOptions(numTries, startTime) {
function filterWatchlistExpiryOptions(numTries, startTime) {
Line 122: Line 122:
else if (++numTries < 5000) { window.setTimeout(filterWatchlistExpiryOptions, 5, numTries, startTime); } //try for 5000*5 milliseconds (that is 25 seconds)
else if (++numTries < 5000) { window.setTimeout(filterWatchlistExpiryOptions, 5, numTries, startTime); } //try for 5000*5 milliseconds (that is 25 seconds)
else { reportCompletion("Failed to filter watchlist expiry options", (performance.now() - startTime).round(3), 'error', 'watchlist-expiry-filtering', numTries, 'NaN'); }
else { reportCompletion("Failed to filter watchlist expiry options", (performance.now() - startTime).round(3), 'error', 'watchlist-expiry-filtering', numTries, 'NaN'); }
}
function increaseEditorSpecialCharactersBarHeight(numTries, startTime) {
if ($('#editpage-specialchars').length) {
$('#editpage-specialchars').css('padding-top', '6.25vh');
window.dispatchEvent(new Event('resize'));
reportCompletion(numTries + " tries before wikitext editor's special characters bar was heightened", (performance.now() - startTime).round(3), 'success', 'special-characters-bar-heightening', numTries, 'NaN');
}
else if (++numTries < 5000) { window.setTimeout(increaseEditorSpecialCharactersBarHeight, 10, numTries, startTime); } //try for 5000*10 milliseconds (that is 50 seconds)
else { reportCompletion("Failed to increase height of wikitext editor's special characters bar", (performance.now() - startTime).round(3), 'error', 'special-characters-bar-heightening', numTries, 'NaN'); }
}
}
function increaseWikitextEditorHeight(numTries, startTime) {
function increaseWikitextEditorHeight(numTries, startTime) {
if ($('.ui-resizable').length) {
if ($('.wikiEditor-ui-view-wikitext').length) {
$('.wikiEditor-ui-view-wikitext').height(3 * $(document.body).height() / 4);
$('.wikiEditor-ui-view-wikitext').height('75vh');
$('.wikiEditor-ui-left').height('100%');
$('.wikiEditor-ui-bottom').height('100%');
$('.wikiEditor-ui-text').height('100%');
$('.ui-resizable').height('100%');
window.dispatchEvent(new Event('resize'));
window.dispatchEvent(new Event('resize'));
reportCompletion(numTries + " tries before wikitext editor was heightened", (performance.now() - startTime).round(3), 'success', 'wikitext-editor-heightening', numTries, 'NaN');
reportCompletion(numTries + " tries before wikitext editor was heightened", (performance.now() - startTime).round(3), 'success', 'wikitext-editor-heightening', numTries, 'NaN');
Line 136: Line 141:
else if (++numTries < 5000) { window.setTimeout(increaseWikitextEditorHeight, 10, numTries, startTime); } //try for 5000*10 milliseconds (that is 50 seconds)
else if (++numTries < 5000) { window.setTimeout(increaseWikitextEditorHeight, 10, numTries, startTime); } //try for 5000*10 milliseconds (that is 50 seconds)
else { reportCompletion("Failed to increase height of wikitext editor", (performance.now() - startTime).round(3), 'error', 'wikitext-editor-heightening', numTries, 'NaN'); }
else { reportCompletion("Failed to increase height of wikitext editor", (performance.now() - startTime).round(3), 'error', 'wikitext-editor-heightening', numTries, 'NaN'); }
}
function increaseCodeEditorHeight(numTries, startTime) {
if ($('.ui-resizable').length) {
$('.wikiEditor-ui').height(3 * $(document.body).height() / 4);
$('.wikiEditor-ui-view-wikitext').height('100%');
$('.wikiEditor-ui-left').height('100%');
$('.wikiEditor-ui-bottom').height('100%');
$('.wikiEditor-ui-text').height('100%');
$('.ui-resizable').height('100%');
window.dispatchEvent(new Event('resize'));
reportCompletion(numTries + " tries before code editor was heightened", (performance.now() - startTime).round(3), 'success', 'code-editor-heightening', numTries, 'NaN');
}
else if (++numTries < 5000) { window.setTimeout(increaseCodeEditorHeight, 10, numTries, startTime); } //try for 5000*10 milliseconds (that is 50 seconds)
else { reportCompletion("Failed to increase code editor's height", (performance.now() - startTime).round(3), 'error', 'code-editor-heightening', numTries, 'NaN'); }
}
}
var allowLaterModificationOfWatchlistExpiry;
var allowLaterModificationOfWatchlistExpiry;
Line 165: Line 156:
if (mw.config.get('wgPageContentModel') === 'wikitext') { //if editing wikitext
if (mw.config.get('wgPageContentModel') === 'wikitext') { //if editing wikitext
increaseWikitextEditorHeight(0, performance.now());
increaseWikitextEditorHeight(0, performance.now());
}
else if (['javascript', 'css', 'Scribunto'].includes(mw.config.get('wgPageContentModel'))) { //if editing code
increaseCodeEditorHeight(0, performance.now());
}
}
}
}
Line 192: Line 180:
}
}
}
}
catch (e) {} //continue even if an error occurred
catch (e) { //continue even if an error occurred
console.error(e.message);
}


/**
/**
Line 206: Line 196:
reportCompletion(numTries + " tries before watchlist indicator was detected", (performance.now() - startTime).round(3), 'success', 'watchlist-indicator-detection', numTries, 'NaN');
reportCompletion(numTries + " tries before watchlist indicator was detected", (performance.now() - startTime).round(3), 'success', 'watchlist-indicator-detection', numTries, 'NaN');
if ($('#ca-watch').length) { //presence of the #ca-watch element indicates the ability to watch the page because it is not already on the watchlist
if ($('#ca-watch').length) { //presence of the #ca-watch element indicates the ability to watch the page because it is not already on the watchlist
var expiryValue = undefined;
var expiryValue;
switch (watchlistExpiryMode) {
switch (watchlistExpiryMode) {
case 0:
case 0:
Line 259: Line 249:
}
}
function pluralize(num) {
function pluralize(num) {
return (num === 1 ? "" : "s");
return num === 1 ? "" : "s";
}
}
pathoschild.TemplateScript.add(
pathoschild.TemplateScript.add(
Line 267: Line 257:
script: function(editor) {
script: function(editor) {
summaryAppendix = "";
summaryAppendix = "";
conductRegexReplacement([[/((?:.|\r|\n)+)(\{\{\s*short\s+description\s*\|[^\}]+\}\})(?:\r\n)?/i, function(match, p1, p2) { count++; return p2 + "\r\n" + p1; }]], editor, "MOS:ORDER", 'reorder-short-description', 1);
conductRegexReplacement([[/(?<=\n)(=+)([^=\r\n\[\]\|\{\}]*)\[\[([^=\r\n\[\]\|\{\}]*)\]\]([^=\r\n\[\]\|\{\}]*)\1(?=\n)/g, function(match, p1, p2, p3, p4) { count++; return p1 + p2 + p3 + p4 + p1; }]], editor, "MOS:HEAD", 'remove-heading-wiki-links', 1); //should happen before any escaping of wiki links as well as geographical wiki links combination and wiki-link shortening
conductRegexReplacement([[/(?<=\n)(=+)([^=\r\n\[\]\|\{\}]*)\[\[([^=\r\n\[\]\|\{\}]*)\]\]([^=\r\n\[\]\|\{\}]*)\1(?=\n)/g, function(match, p1, p2, p3, p4) { count++; return p1 + p2 + p3 + p4 + p1; }]], editor, "MOS:HEAD", 'remove-heading-wiki-links', 1); //should happen before any escaping of wiki links as well as geographical wiki links combination and wiki-link shortening


Line 285: Line 276:


conductRegexReplacement([
conductRegexReplacement([
[RegExp('(?<=\\d)\\s+(?=' + compoundNumbersRegex + '|(?:[km]g|[aApP][mM])(?![a-zA-Z]))', 'g'), function(match) { count++; return "&nbsp;"; }],
[RegExp('(?<=\\d)\\s+(?=' + compoundNumbersRegex + '|(?:[km]g|[aApP][mM])(?![a-zA-Z]))', 'g'), function() { count++; return "&nbsp;"; }],
[/(?<=[ \r\n]) | (?=[ \r\n])/g, function(match) { count++; return ""; }],
[/(?<=[ \r\n])\u00A0|\u00A0(?=[ \r\n])/g, function() { count++; return ""; }],
[/ /g, function(match) { count++; return "&nbsp;"; }]
[/\u00A0/g, function() { count++; return "&nbsp;"; }]
], editor, "MOS:NBSP", 'insert-nbsps', 1); //should happen before any regex relying on "\s" is used
], editor, "MOS:NBSP", 'insert-nbsps', 1); //should happen before any regex relying on "\s" is used


editor
editor
Line 302: Line 293:
var escaped4 = editor.escape(headingEscapeRegex);
var escaped4 = editor.escape(headingEscapeRegex);


conductRegexReplacement([[/ (?:\{\{[nN]dash\}\}|&ndash;)(?: |\{\{[nN]dash\}\}|&ndash;)/g, function(match) { count++; return "{{snd}}"; }]], editor, "MOS:ENDASH", 'fix-ndashes', 1); //should happen after literal non-breaking space removal and replacement
conductRegexReplacement([[/ (?:\{\{\s*[nN]dash\s*\}\}|&ndash;)(?: |\{\{\s*[nN]dash\s*\}\}|&ndash;)/g, function() { count++; return "{{snd}}"; }]], editor, "MOS:ENDASH", 'fix-ndashes', 1); //should happen after literal non-breaking space removal and replacement


editor
editor
Line 321: Line 312:
// [/(?<![‘\'])‘(?![‘\'])/g, function(match) { count++; return "'"; }], //future consideration: add nowiki tags if preceding or proceeding text is a non-curly single quotation mark
// [/(?<![‘\'])‘(?![‘\'])/g, function(match) { count++; return "'"; }], //future consideration: add nowiki tags if preceding or proceeding text is a non-curly single quotation mark
// [/(?<![’\'])’(?![’\'])/g, function(match) { count++; return "'"; }] //future consideration: add nowiki tags if preceding or proceeding text is a non-curly single quotation mark
// [/(?<![’\'])’(?![’\'])/g, function(match) { count++; return "'"; }] //future consideration: add nowiki tags if preceding or proceeding text is a non-curly single quotation mark
// ], editor, "MOS:CURLY", 'replace-curlies', 0);
// ], editor, "MOS:CURLY", 'replace-curlies', 0);


// editor
// editor
Line 331: Line 322:
var nowikiEscapeRegex = RegExp('(?:<nowiki\s*>(?:(?!<\/' + 'nowiki\s*>)(?:.|\r|\n))*<\/' + 'nowiki\s*>|\{\{\s*#tag:\s*nowiki\s*\}\})', 'gi'); //string is broken at closing nowiki tags to avoid throwing off Wikipedia wherever this document is loaded
var nowikiEscapeRegex = RegExp('(?:<nowiki\s*>(?:(?!<\/' + 'nowiki\s*>)(?:.|\r|\n))*<\/' + 'nowiki\s*>|\{\{\s*#tag:\s*nowiki\s*\}\})', 'gi'); //string is broken at closing nowiki tags to avoid throwing off Wikipedia wherever this document is loaded
var escaped8 = editor.escape(nowikiEscapeRegex);
var escaped8 = editor.escape(nowikiEscapeRegex);
var escaped9 = editor.escape(/(?:<!--(?:(?!-->)(?:.|\r|\n))*-->|\{\{\s*#tag:\s*!--\s*\}\})/g);


var startTime = performance.now();
var startTime = performance.now();
var textLength = editor.get().length;
var textLength = editor.get().length;
count = 0;
count = 0;
var emptyCitationBlacklistRegex = 'Gaia\\s+DR2';
var emptyCitationBlacklistRegex = 'Gaia +DR2';
var emptyCitationNegativeLookbehindRegex = '(?<!<!--- See http:\\/\\/en.wikipedia.org\\/wiki\\/Wikipedia:Footnotes on how to create references using |<!--- See https:\\/\\/en.wikipedia.org\\/wiki\\/Wikipedia:Footnotes on how to create references using )';
var emptyCitationNegativeLookaheadRegex = '(?! tags which will then appear here automatically -->)';
editor
editor
.replace(RegExp(emptyCitationNegativeLookbehindRegex + '<[rR][eE][fF][^>\\/]*>\\s*(?:\\{\\{[cC]ite\\s+(?!' + emptyCitationBlacklistRegex + ')\\w+\\s*(?:\\|(?:\\s*[\\w-]+\\s*=)?\\s*)*\\}\\}\\s*)?<\\/[rR][eE][fF]\\s*>' + emptyCitationNegativeLookaheadRegex, 'g'), function(match) { count++; return ""; })
.replace(RegExp('<[rR][eE][fF][^>\\/]*>\\s*(?:\\{\\{\\s*[cC]ite +(?!' + emptyCitationBlacklistRegex + ')\\w+\\s*(?:\\|(?:\\s*[\\w-]+\\s*=)?\\s*)*\\}\\}\\s*)?<\\/[rR][eE][fF]\\s*>', 'g'), function() { count++; return ""; })
.replace(RegExp('\\{\\{[cC]ite\\s+(?!' + emptyCitationBlacklistRegex + ')\\w+\\s*(?:\\|(?:\\s*[\\w-]+\\s*=)?\\s*)*\\}\\}\\s*', 'g'), function(match) { count++; return ""; });
.replace(RegExp('\\{\\{\\s*[cC]ite +(?!' + emptyCitationBlacklistRegex + ')\\w+\\s*(?:\\|(?:\\s*[\\w-]+\\s*=)?\\s*)*\\}\\}\\s*', 'g'), function() { count++; return ""; });
if (count) {
if (count) {
summaryAppendix += "rm " + (count !== 1 ? count + " " : "") + "[[Category:CS1 errors: empty citation|empty CS1 citation]]" + pluralize(count) + ", ";
summaryAppendix += "rm " + (count !== 1 ? count + " " : "") + "[[Category:CS1 errors: empty citation|empty CS1 citation]]" + pluralize(count) + ", ";
Line 346: Line 336:
}
}
reportCompletion(count + " empty CS1 citation" + pluralize(count), (performance.now() - startTime).round(3), 'info', 'remove-empty-citations', count, textLength);
reportCompletion(count + " empty CS1 citation" + pluralize(count), (performance.now() - startTime).round(3), 'info', 'remove-empty-citations', count, textLength);
var openingCitationTemplateRegex = '\\{\\{\\s*[cC]ite\\s+\\w+\\s*';
var openingRefHTMLRegex = '<[rR][eE][fF][^>]*>';
var closingCitationTemplateRegex = '\\}\\}';
var closingRefHTMLRegex = '<\\/[rR][eE][fF]\\s*>';
var openingRefParserRegex = '\\{\\{\\s*#tag:\\s*ref\\s*\\|';
var openingCitationHTMLRegex = '<[rR][eE][fF][^>]*>\\s*' + openingCitationTemplateRegex;
var closingCitationHTMLRegex = closingCitationTemplateRegex + '\\s*<\\/[rR][eE][fF]\\s*>';
var closingRefParserRegex = '\\}\\}';
var openingCitationParserRegex = '\\{\\{\\s*#tag:\\s*ref\\s*\\|\\s*' + openingCitationTemplateRegex;
var closingCitationParserRegex = '(?:\\|[^\\|\\}])*' + closingCitationTemplateRegex + '\\s*\\}\\}';
var problematicIntermediaryRegex = '<nowiki\\s*>|<\\/' + 'nowiki\\s*>|<nowiki\\s*\\/>|\\{\\{\\s*#tag:\\s*(?:nowiki|!--)\\s*\\}\\}'; //string is broken at closing nowiki tag to avoid throwing off Wikipedia wherever this document is loaded
var problematicIntermediaryRegex = '<nowiki\\s*>|<\\/' + 'nowiki\\s*>|<nowiki\\s*\\/>|\\{\\{\\s*#tag:\\s*(?:nowiki|!--)\\s*\\}\\}'; //string is broken at closing nowiki tag to avoid throwing off Wikipedia wherever this document is loaded
conductRegexReplacement([
startTime = performance.now();
[RegExp('\\s+(' + openingRefHTMLRegex + '(?:(?!\\|' + problematicIntermediaryRegex + '|' + closingRefHTMLRegex + ')(?:.|\r|\n))*' + closingRefHTMLRegex + ')', 'g'), function(match, p1) { count++; return p1; }],
textLength = editor.get().length;
[RegExp('\\s+(' + openingRefParserRegex + '(?:(?!\\|' + problematicIntermediaryRegex + '|' + closingRefParserRegex + ')(?:.|\r|\n))*' + closingRefParserRegex + ')', 'g'), function(match, p1) { count++; return p1; }]
count = 0;
], editor, "MOS:REFSPACE", 'add-spaces-before-refs', 1);
var editionArg = '\\s*edition\\s*=';

// // The following was removed for being broken (the conducted replacement of duplicate references is nonsensical) for unknown reasons.
// startTime = performance.now();
// textLength = editor.get().length;
// count = 0;
// var referencesArray = Array.from(editor.get().matchAll(RegExp('<ref(\s*(?:[^<>]+(?<!\/))?)>(?:(?!<\/ref\s*>)(?:.|\r|\n))*<\/ref\s*>', 'gi')));
// for (var i = 0; referencesArray.length; i++) {
// var firstReplacement = true;
// editor.replace(RegExp(referencesArray[0][0].replaceAll(/([\^\$\*\(\)\+\{\}\[\]\\\.\?\/\-])/g, function(match, p1) { return '\\' + p1; }), 'g'), function(match, p1) {
// if (firstReplacement) {
// firstReplacement = false;
// return match;
// }
// count++;
// return "<ref" + (p1 === undefined ? " name=\":" + (i + 10) + "\"" : p1) + " />";
// });
// var captureGroup1 = referencesArray[0][1];
// var referenceMatch = (captureGroup1 ? referencesArray[0][0].replace(captureGroup1, '') : referencesArray[0][0]);
// referencesArray = referencesArray.filter(function(value) { return (captureGroup1 && value[0].indexOf(captureGroup1) === 4 ? value[0].replace(captureGroup1, '') : value[0]) !== referenceMatch; });
// }
// reportCompletion(count + " duplicate reference" + pluralize(count), (performance.now() - startTime).round(3), 'info', 'merge-duplicate-references', count, textLength);

editor
editor
.unescape(escaped8)
.replace(RegExp('(' + openingCitationHTMLRegex + '(?:(?!\\|' + editionArg + '|' + problematicIntermediaryRegex + '|' + closingCitationHTMLRegex + ')(?:.|\r|\n))*\\|' + editionArg + '\\s*\\w+)\\s+(?:ed(?:ition|n)?)\\s*((?:\\|(?:(?!' + editionArg + '|' + problematicIntermediaryRegex + '|\\s*' + closingCitationHTMLRegex + ')[^\\|])*)*' + closingCitationHTMLRegex + ')', 'g'), function(match, p1, p2) { count++; return p1 + p2; })
.unescape(escaped9);
.replace(RegExp('(' + openingCitationParserRegex + '(?:(?!\\|' + editionArg + '|' + problematicIntermediaryRegex + '|' + closingCitationParserRegex + ')(?:.|\r|\n))*\\|' + editionArg + '\\s*\\w+)\\s+(?:ed(?:ition|n)?)\\s*((?:\\|(?:(?!' + editionArg + '|' + problematicIntermediaryRegex + '|\\s*' + closingCitationParserRegex + ')[^\\|])*)*' + closingCitationParserRegex + ')', 'g'), function(match, p1, p2) { count++; return p1 + p2; });

if (count) {

summaryAppendix += "rm " + (count !== 1 ? count + " " : "") + "[[Category:CS1 errors: extra text: edition|extra CS1 edition text]]" + pluralize(count) + ", ";
escaped8 = editor.escape(nowikiEscapeRegex);
watchlistExpiryMode = 2;

}
var openingCitationTemplateRegex = '\\{\\{\\s*[cC]ite +\\w+\\s*';
reportCompletion(count + " extra CS1 edition text" + pluralize(count), (performance.now() - startTime).round(3), 'info', 'fix-extra-edition-text', count, textLength);
var closingCitationTemplateRegex = '\\}\\}';
var openingCitationHTMLRegex = openingRefHTMLRegex + '\\s*' + openingCitationTemplateRegex;
var closingCitationHTMLRegex = closingCitationTemplateRegex + '\\s*' + closingRefHTMLRegex;
var openingCitationParserRegex = openingRefParserRegex + '\\s*' + openingCitationTemplateRegex;
var closingCitationParserRegex = '(?:\\|[^\\|\\}])*' + closingCitationTemplateRegex + '\\s*' + closingRefParserRegex;
startTime = performance.now();
startTime = performance.now();
textLength = editor.get().length;
textLength = editor.get().length;
Line 418: Line 433:
countArray.push(0);
countArray.push(0);
editor
editor
.replace(/(?<=\n)([\*#]*)(:+|;[^\n]*\n|)([^\n]*)\n(?=[:\*#])/g, function(match, p1, p2, p3) {
if (p2.length && p2[0] === ":") {
countArray[1]++;
return p1 + new Array(p2.length + 1).join('*') + p3 + "\n";
}
else {
return p1 + p2 + p3 + "\n";
}
})
.replace(/(?<=\n)([\*#]*)(:+|;[^\n]*\n|)([^\n]*)\n(?=\s*\n)/g, function(match, p1, p2, p3) {
.replace(/(?<=\n)([\*#]*)(:+|;[^\n]*\n|)([^\n]*)\n(?=\s*\n)/g, function(match, p1, p2, p3) {
if (p2.length && p2[0] === ":") {
if (p2.length && p2[0] === ":") {
Line 449: Line 455:
watchlistExpiryMode = 2;
watchlistExpiryMode = 2;
}
}
reportCompletion(countArray[1] + " colon indentation" + pluralize(count), (performance.now() - startTime).round(3), 'info', 'fix-colon-indent', countArray[1], textLength);
reportCompletion(countArray[1] + " colon indentation" + pluralize(countArray[1]), (performance.now() - startTime).round(3), 'info', 'fix-colon-indent', countArray[1], textLength);
conductRegexReplacement([[/\[\[\s*([^\]\|\{\}<>]+(?<!\s))\s*\|\s*([^\]\|\{\}<>]+)\s*\]\]/g, function(match, p1, p2) {
conductRegexReplacement([[/\[\[\s*([^\]\|\{\}<>]+(?<!\s))\s*\|\s*([^\]\|\{\}<>]+)\s*\]\]/g, function(match, p1, p2) {
var p2Temp = p2.charAt(0).toLowerCase() + p2.substring(1).replaceAll(/[‘’]/g, '\'').replaceAll(/[“”]/g, '\"');
var p2Temp = p2.charAt(0).toLowerCase() + p2.substring(1).replaceAll(/[‘’]/g, '\'').replaceAll(/[“”]/g, '\"');
Line 468: Line 474:
tableEscapeString += '\\|\\})*';
tableEscapeString += '\\|\\})*';
}
}
var escaped9 = editor.escape(RegExp(tableEscapeString, 'g'));
var escaped10 = editor.escape(RegExp(tableEscapeString, 'g'));


conductRegexReplacement([[/\[\[\s*(?:[Ff][Ii][Ll][Ee]|[Ii][Mm][Aa][Gg][Ee])\s*:\s*([^\|\[\]]+)\s*\|((?:(?:(?!\d+\s*px|upright)[^\|\[\]])*\|)*)(\d+)\s*px((?:\s*\|(?:(?!\d+\s*px|upright)[^\|\[\]])*)*)\]\]/g, function(match, p1, p2, pixelValue, p4) { count++; return "[[File:" + p1 + "|" + p2 + "upright=" + (Number(pixelValue) / 220).round(3) + p4 + "]]"; }]], editor, "MOS:IMGSIZE", 'convert-image-pixel-sizes', 1); //convert pixels to upright (rounded to nearest thousandth due to the three significant digits of 220)
conductRegexReplacement([[/\[\[\s*(?:[Ff][Ii][Ll][Ee]|[Ii][Mm][Aa][Gg][Ee])\s*:\s*([^\|\[\]]+)\s*\|((?:(?:(?!\d+\s*px|upright)[^\|\[\]])*\|)*)(\d+)\s*px((?:\s*\|(?:(?!\d+\s*px|upright)[^\|\[\]])*)*)\]\]/g, function(match, p1, p2, pixelValue, p4) { count++; return "[[File:" + p1 + "|" + p2 + "upright=" + (Number(pixelValue) / 220).round(3) + p4 + "]]"; }]], editor, "MOS:IMGSIZE", 'convert-image-pixel-sizes', 1); //convert pixels to upright (rounded to nearest thousandth due to the three significant digits of 220)
Line 474: Line 480:
editor
editor
.unescape(escaped8)
.unescape(escaped8)
.unescape(escaped9);
.unescape(escaped10);




Line 480: Line 486:
// escaped2 = editor.escape(HTMLEscapeRegex);
// escaped2 = editor.escape(HTMLEscapeRegex);
// escaped3 = editor.escape(RegExp('\\{\\{' + templateEscapeString + '\\}\\}', 'g')); //note that this assumes that no single-paired nested braces will be used to surpass the expansion-depth limit
// escaped3 = editor.escape(RegExp('\\{\\{' + templateEscapeString + '\\}\\}', 'g')); //note that this assumes that no single-paired nested braces will be used to surpass the expansion-depth limit
// var escaped10 = editor.escape(/\"[^\"]*\"/g); //requires curly quotation marks to have been converted, though is of highly varying accuracy anyway
// var escaped11 = editor.escape(/\"[^\"]*\"/g); //requires curly quotation marks to have been converted, though is of highly varying accuracy anyway


var monthOfYearRegex = 'January|February|March|April|May|June|July|August|September|October|November|December|(?:Jan|Feb|Mar|Apr|Jun|Jul|Aug|Sep|Oct|Nov|Dec)';
// var monthOfYearRegex = 'January|February|March|April|May|June|July|August|September|October|November|December|(?:Jan|Feb|Mar|Apr|Jun|Jul|Aug|Sep|Oct|Nov|Dec)';
var compoundNumbersRegex = '(?:m|b|tr|quadr)illion';
var compoundNumbersRegex = '(?:m|b|tr|quadr)illion';
// conductRegexReplacement([
// conductRegexReplacement([
Line 512: Line 518:
// }
// }
// }]
// }]
// ], editor, "MOS:SPELL09", 'spell-digits', 1);
// ], editor, "MOS:SPELL09", 'spell-digits', 1);


// editor
// editor
Line 518: Line 524:
// .unescape(escaped2)
// .unescape(escaped2)
// .unescape(escaped3)
// .unescape(escaped3)
// .unescape(escaped10);
// .unescape(escaped11);




Line 526: Line 532:
var escaped6 = editor.escape(imageParameterRegex);
var escaped6 = editor.escape(imageParameterRegex);
escaped8 = editor.escape(nowikiEscapeRegex);
escaped8 = editor.escape(nowikiEscapeRegex);
var escaped11 = editor.escape('\\{\\{[cC]ite\\s+\\w+\\s*' + templateEscapeString + '\\}\\}');
var escaped12 = editor.escape('\\{\\{\\s*[cC]ite +\\w+\\s*' + templateEscapeString + '\\}\\}');


var discouragedCircaRegex = '(?:circa|ca?(?:\\.|\\s)|C\\.|around|approx(?:imately|\\.))';
var discouragedCircaRegex = '(?:circa|ca?(?:\\.|\\s)|C\\.|around|approx(?:imately|\\.))';
var eraAbbreviationRegex = 'BCE?|AD|CE|B\\.\\s?C\\.\\s?(?:E\\.)?|A\\.\\s?D\\.|C\\.\\s?E\\.';
var eraAbbreviationRegex = 'BCE?|AD|CE|B\\.\\s?C\\.\\s?(?:E\\.)?|A\\.\\s?D\\.|C\\.\\s?E\\.';
var nbspRegex = '\\{\\{[nN]bsp\\}\\}|&nbsp;';
var nbspRegex = '\\{\\{\\s*[nN]bsp\\s*\\}\\}|&nbsp;';
var ndashRegex = '\\{\\{[eE]n [dD]ash\\}\\}|&ndash;|–';
var ndashRegex = '\\{\\{\\s*[eE]n +[dD]ash\\s*\\}\\}|&ndash;|–';
var mdashRegex = '\\{\\{[mM]dash\\}\\}|&mdash;|—';
var mdashRegex = '\\{\\{\\s*[mM]dash\\s*\\}\\}|&mdash;|—';
conductRegexReplacement([[RegExp('(?<=[^\\w])' + discouragedCircaRegex + '\\s*(\\d+)(?:\\s+(' + eraAbbreviationRegex + ')(?!(?:' + nbspRegex + ')|(?:\\s{0,}(?:-|' + ndashRegex + '))|\\s{0,}(?:' + mdashRegex + ')|\s+to\s)|(?!\\d*(?:(?:(?:' + nbspRegex + ')|(?:\\s{0,}(?:-|' + ndashRegex + '))|\\s{0,}(?:' + mdashRegex + '))|[a-zA-Z%°\/]|[,\\.:]\\d+|\\s+(?:%|per\\s?cent|kilo|milli|' + compoundNumbersRegex + '|to\\s|' + eraAbbreviationRegex + '))))', 'g'), function(match, p1, p2) { count++; return "{{circa|" + p1 + (p2 === undefined ? "" : "&nbsp;" + p2.replaceAll(' ', '').replaceAll('.', '')) + "}}"; }]], editor, "MOS:CIRCA", 'fix-circa-formatting', 1); //note that to minimize false positives, spelling single-digit numbers and non-breaking space insertion should be handled before this circa formatting
conductRegexReplacement([[RegExp('(?<=[^\\w])' + discouragedCircaRegex + '\\s*(\\d+)(?:\\s+(' + eraAbbreviationRegex + ')(?!(?:(?:' + nbspRegex + ')|(?:\\s{0,}(?:-|' + ndashRegex + '))|\\s{0,}(?:' + mdashRegex + ')|\\s+to\\s)|E\\.?(?:(?:' + nbspRegex + ')|(?:\\s{0,}(?:-|' + ndashRegex + '))|\\s{0,}(?:' + mdashRegex + ')|\\s+to\\s))|(?!\\d*(?:(?:(?:' + nbspRegex + ')|(?:\\s{0,}(?:-|' + ndashRegex + '))|\\s{0,}(?:' + mdashRegex + '))|[a-zA-Z%°\/]|[,\\.:]\\d+|\\s+(?:%|per\\s?cent|kilo|milli|' + compoundNumbersRegex + '|to\\s|' + eraAbbreviationRegex + '))))', 'g'), function(match, p1, p2) { count++; return "{{circa|" + p1 + (p2 === undefined ? "" : "&nbsp;" + p2.replaceAll(' ', '').replaceAll('.', '')) + "}}"; }]], editor, "MOS:CIRCA", 'fix-circa-formatting', 1); //note that to minimize false positives, spelling single-digit numbers and non-breaking space insertion should be handled before this circa formatting


editor
editor
Line 541: Line 547:
.unescape(escaped6)
.unescape(escaped6)
.unescape(escaped8)
.unescape(escaped8)
.unescape(escaped11);
.unescape(escaped12);




// var escaped12 = editor.escape(/(?:<!--(?:(?!-->)(?:.|\r|\n))*-->|\{\{\s*#tag:\s*!--\s*\}\})/g);
// var escaped13 = editor.escape(/(?:<!--(?:(?!-->)(?:.|\r|\n))*-->|\{\{\s*#tag:\s*!--\s*\}\})/g);
// var escaped13 = editor.escape(RegExp('(?:<ref\s*(?:[^<>]+)?(?<!\/)>(?:(?!<\/ref\s*>)(?:.|\r|\n))*<\/ref\s*>|\{\{\s*#tag:\s*ref\s*\}\})', 'gi'));
// var escaped14 = editor.escape(RegExp('(?:<ref\s*(?:[^<>]+(?<!\/))?>(?:(?!<\/ref\s*>)(?:.|\r|\n))*<\/ref\s*>|\{\{\s*#tag:\s*ref\s*\}\})', 'gi'));
// var escaped14 = editor.escape(RegExp('(?:<gallery\s*(?:[^<>]+)>(?:(?!<\/gallery\s*>)(?:.|\r|\n))*<\/gallery\s*>|\{\{\s*#tag:\s*gallery\s*\}\})', 'gi'));
// var escaped15 = editor.escape(RegExp('(?:<gallery\s*(?:[^<>]+)>(?:(?!<\/gallery\s*>)(?:.|\r|\n))*<\/gallery\s*>|\{\{\s*#tag:\s*gallery\s*\}\})', 'gi'));


editor
// editor
// .unescape(escaped12)
// .unescape(escaped13)
// .unescape(escaped13)
// .unescape(escaped14)
// .unescape(escaped14);
// .unescape(escaped15);




Line 621: Line 627:
if (capitalize) {
if (capitalize) {
summaryAppendix = summaryAppendix.charAt(0).toUpperCase() + summaryAppendix.slice(1);
summaryAppendix = summaryAppendix.charAt(0).toUpperCase() + summaryAppendix.slice(1);
if (summaryAppendix.split(",").length === 2 - existingSummaryLength) { summaryAppendix = (!existingSummaryLength ? summaryAppendix.replace(",", " and") : "and " + summaryAppendix); }
if (summaryAppendix.split(",").length === 2 - existingSummaryLength) { summaryAppendix = !existingSummaryLength ? summaryAppendix.replace(",", " and") : "and " + summaryAppendix; }
else if (summaryAppendix.split(",").length > 2 - existingSummaryLength) { summaryAppendix = summaryAppendix.slice(0, summaryAppendix.lastIndexOf(",") + 1) + " and" + summaryAppendix.slice(summaryAppendix.lastIndexOf(",") + 1); }
else if (summaryAppendix.split(",").length > 2 - existingSummaryLength) { summaryAppendix = summaryAppendix.slice(0, summaryAppendix.lastIndexOf(",") + 1) + " and" + summaryAppendix.slice(summaryAppendix.lastIndexOf(",") + 1); }
if (!$('#wpMinoredit').checked) {
if (!$('#wpMinoredit').checked) {
Line 639: Line 645:
script: function(editor) {
script: function(editor) {
summaryAppendix = "";
summaryAppendix = "";
var textLength = editor.get().length;
// var textLength = editor.get().length;


var templateEscapeString = '';
var templateEscapeString = '';
Line 658: Line 664:


var monthOfYearRegex = 'January|February|March|April|May|June|July|August|September|October|November|December|(?:Jan|Feb|Mar|Apr|Jun|Jul|Aug|Sep|Oct|Nov|Dec)';
var monthOfYearRegex = 'January|February|March|April|May|June|July|August|September|October|November|December|(?:Jan|Feb|Mar|Apr|Jun|Jul|Aug|Sep|Oct|Nov|Dec)';
conductRegexReplacement([[RegExp('(?<=' + monthOfYearRegex + ')\\s+(?=\\d{3,})', 'g'), function(match) { count++; return "&nbsp;"; }]], editor, "MOS:NBSP", 'insert-date-nbsps', 2);
conductRegexReplacement([[RegExp('(?<=' + monthOfYearRegex + ')\\s+(?=\\d{3,})', 'g'), function() { count++; return "&nbsp;"; }]], editor, "MOS:NBSP", 'insert-date-nbsps', 2);


editor
editor
Line 675: Line 681:
if (capitalize) {
if (capitalize) {
summaryAppendix = summaryAppendix.charAt(0).toUpperCase() + summaryAppendix.slice(1);
summaryAppendix = summaryAppendix.charAt(0).toUpperCase() + summaryAppendix.slice(1);
if (summaryAppendix.split(",").length === 2 - existingSummaryLength) { summaryAppendix = (!existingSummaryLength ? summaryAppendix.replace(",", " and") : "and " + summaryAppendix); }
if (summaryAppendix.split(",").length === 2 - existingSummaryLength) { summaryAppendix = !existingSummaryLength ? summaryAppendix.replace(",", " and") : "and " + summaryAppendix; }
else if (summaryAppendix.split(",").length > 2 - existingSummaryLength) { summaryAppendix = summaryAppendix.slice(0, summaryAppendix.lastIndexOf(",") + 1) + " and" + summaryAppendix.slice(summaryAppendix.lastIndexOf(",") + 1); }
else if (summaryAppendix.split(",").length > 2 - existingSummaryLength) { summaryAppendix = summaryAppendix.slice(0, summaryAppendix.lastIndexOf(",") + 1) + " and" + summaryAppendix.slice(summaryAppendix.lastIndexOf(",") + 1); }
if (!$('#wpMinoredit').checked) {
if (!$('#wpMinoredit').checked) {
Line 717: Line 723:
});
});
// </nowiki>
// </nowiki>
importScript('User:SuperHamster/CiteUnseen.js'); // Backlink: [[User:SuperHamster/CiteUnseen.js]]
importScript('User:Novem_Linguae/Scripts/CiteHighlighter.js'); // Backlink: [[User:Novem_Linguae/Scripts/CiteHighlighter.js]]
importScript('User:Headbomb/unreliable.js'); // Backlink: [[User:Headbomb/unreliable.js]]

Latest revision as of 14:15, 16 June 2024

// <nowiki>
/* jshint leanswitch: true, nonbsp: true, nonew: true, singleGroups: true, strict: true, undef: true, unused: true */
/* globals $, console, document, Event, mw, pathoschild, performance, window */
$(function() {
	"use strict";
	try {
		var forbiddenPages = [];
		var dayOfWeek = (new Date()).getDay();
		if (1 <= dayOfWeek) {
			forbiddenPages = ['Main_Page', 'Special:Search', 'Special:Homepage', 'Special:Watchlist', 'User:Uhai/Pages_without_short_descriptions_by_view_count'];
		}
		else {
			var hour = (new Date()).getHours();
			if (hour < 7 || 19 <= hour) {
				forbiddenPages = ['User:Uhai/Pages_without_short_descriptions_by_view_count'];
			}
		}
		for (var i = 0; i < forbiddenPages.length; i++) {
			if (window.location.pathname.includes(forbiddenPages[i]) || window.location.search.includes(forbiddenPages[i])) {
				window.location.assign("https://www.wikipedia.org");
				break;
			}
		}
	}
	catch (e) { //continue even if an error occurred
		 console.error(e.message);
	}
	function reportCompletion(description, duration, notificationType, storageName, storageAdditionalSum, textSize) { //duration is assumed to be in milliseconds; notificationType being 'info', 'warn', 'error', or 'success'; notification becomes description + " in " + duration + "ms"
		var notificationString = description + " in " + duration + "ms";
		if (notificationType !== 'info') {
			mw.notify(notificationString, { type: notificationType });
		}
		switch (notificationType) {
			case 'error':
				console.error(notificationString);
				break;
			case 'info':
			case 'success':
				console.info(notificationString);
				break;
			case 'warn':
				console.warn(notificationString);
				break;
		}
		if (storageName !== undefined) {
			var attributeName = notificationType === 'info' ? 'count' : 'tries';
			var existingItem = window.localStorage.getItem(storageName + ' ' + notificationType);
			if (existingItem !== null) {
				var existingStorageAdditionalSum = parseInt(existingItem.substring(existingItem.indexOf(attributeName + ': ') + (attributeName + ': ').length));
				var existingTextSize = existingItem.indexOf('bytes: ') < 0 ? 'NaN' : parseInt(existingItem.substring(existingItem.indexOf('bytes: ') + 'bytes: '.length));
				window.localStorage.setItem(storageName + ' ' + notificationType, 'milliseconds: ' + (parseInt(existingItem.substring(existingItem.indexOf('milliseconds: ') + 'milliseconds: '.length)) + duration) + ', ' + attributeName + ': ' + (isNaN(existingStorageAdditionalSum) ? (!isNaN(storageAdditionalSum) ? storageAdditionalSum : 'NaN') : existingStorageAdditionalSum + storageAdditionalSum) + ', tally: ' + (parseInt(existingItem.substring(existingItem.indexOf('tally: ') + 'tally: '.length)) + 1) + (isNaN(existingTextSize) ? (!isNaN(textSize) ? ', bytes: ' + textSize : '') : ', bytes: ' + (existingTextSize + textSize)));
			}
			else {
				window.localStorage.setItem(storageName + ' ' + notificationType, 'milliseconds: ' + duration + ', ' + attributeName + ': ' + storageAdditionalSum + ', tally: 1' + (!isNaN(textSize) ? ', bytes: ' + textSize : ''));
			}
		}
	}
	Number.prototype.round = function(numPlaces) {
		return +(Math.round(this + "e+" + numPlaces) + "e-" + numPlaces); //+ casts string back to number to strip excess zeroes
	};
	function filterCurrentEvents(numTries, startTime) {
		if ($('.p-current-events-headlines ul').length && $('.itn-img').length) {
			var currentEventsFilter = ["basketball", "cricket", "Cricket World Cup", "Eurovision Song Contest", "filmmaker", "Film Awards", "Film Festival", "football", "golf", "hockey", "In television, ", "In tennis, ", "Japan Series", "NASCAR Cup Series", "PDC World Championship", "rugby", "World Baseball Classic"];
			for (var i = 0; i < currentEventsFilter.length; i++) {
				for (var j = 0; j < $('.p-current-events-headlines ul li:contains(' + currentEventsFilter[i] + ')').length; j++) {
					if ($('.p-current-events-headlines ul li:contains(' + currentEventsFilter[i] + ')')[j].innerText.match(/\([^\(\)]*[pP]ictured[^\(\)]*\)/)) {
						$('.itn-img')[0].remove();
					}
				}
				$('.p-current-events-headlines ul li:contains(' + currentEventsFilter[i] + ')').hide();
			}
			reportCompletion(numTries + " tries before current events were filtered", (performance.now() - startTime).round(3), 'success', 'current-events-filtering', numTries, 'NaN');
		}
		else if (++numTries < 10000) { window.setTimeout(filterCurrentEvents, 5, numTries, startTime); } //try for 10000*5 milliseconds (that is 50 seconds)
		else { reportCompletion("Failed to filter current events", (performance.now() - startTime).round(3), 'error', 'current-events-filtering', numTries, 'NaN'); }
	}
	function scrollToEditWindow(numTries, startTime) {
		if ($('#wikiEditor-ui-toolbar').length) {
			$('#wikiEditor-ui-toolbar')[0].scrollIntoView();
			reportCompletion(numTries + " tries before editor window was scrolled to", (performance.now() - startTime).round(3), 'success', 'editor-window-focusing', numTries, 'NaN');
		}
		else if (++numTries < 5000) { window.setTimeout(scrollToEditWindow, 5, numTries, startTime); } //try for 5000*5 milliseconds (that is 25 seconds)
		else { reportCompletion("Failed to scroll to editor window", (performance.now() - startTime).round(3), 'error', 'editor-window-focusing', numTries, 'NaN'); }
	}
	var watchlistExpiryIsSet = false; //basically a mutex for the watchlist expiry
	function setWatchlistExpiry(numTries, startTime, expiryValue) {
		if (expiryValue === undefined ? $('#wpWatchthis').length : $('#wpWatchlistExpiry').length) {
			if (expiryValue === undefined) {
				if ($('#wpWatchthis')[0].checked) {
					$('#wpWatchthis').first().click(); //unset watching
				}
			}
			else {
				$('#wpWatchlistExpiry').val(expiryValue).trigger('change');
			}
			reportCompletion(numTries + " tries before watchlist expiry was set", (performance.now() - startTime).round(3), 'success', 'watchlist-expiry-setting', numTries, 'NaN');
			watchlistExpiryIsSet = true;
		}
		else if (++numTries < 1000) { window.setTimeout(setWatchlistExpiry, 5, numTries, startTime, expiryValue); } //try for 1000*5 milliseconds (that is 5 seconds)
		else { reportCompletion("Failed to set watchlist expiry", (performance.now() - startTime).round(3), 'error', 'watchlist-expiry-setting', numTries, 'NaN'); }
	}
	function filterWatchlistExpiryOptions(numTries, startTime) {
		var watchlistExpiryElements = document.getElementsByClassName('oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget');
		if ($('#wpWatchlistExpiry').length && watchlistExpiryElements.length) {
			var filteredWatchlistExpiryOptions = ["6 months", "1 year"];
			for (var i = 0; i < $('#wpWatchlistExpiry')[0].children.length; i++) {
				for (var j = 0; j < filteredWatchlistExpiryOptions.length; j++) {
					if ($('#wpWatchlistExpiry')[0].children[i].innerText === filteredWatchlistExpiryOptions[j]) {
						$('#wpWatchlistExpiry')[0].children[i].remove();
					}
				}
			}
			for (var k = 0; k < watchlistExpiryElements.length; k++) {
				for (var l = 0; l < filteredWatchlistExpiryOptions.length; l++) {
					if (watchlistExpiryElements[k].innerText === filteredWatchlistExpiryOptions[l]) {
						watchlistExpiryElements[k].remove();
					}
				}
			}
			reportCompletion(numTries + " tries before watchlist expiry options were filtered", (performance.now() - startTime).round(3), 'success', 'watchlist-expiry-filtering', numTries, 'NaN');
		}
		else if (++numTries < 5000) { window.setTimeout(filterWatchlistExpiryOptions, 5, numTries, startTime); } //try for 5000*5 milliseconds (that is 25 seconds)
		else { reportCompletion("Failed to filter watchlist expiry options", (performance.now() - startTime).round(3), 'error', 'watchlist-expiry-filtering', numTries, 'NaN'); }
	}
	function increaseEditorSpecialCharactersBarHeight(numTries, startTime) {
		if ($('#editpage-specialchars').length) {
            $('#editpage-specialchars').css('padding-top', '6.25vh');
			window.dispatchEvent(new Event('resize'));
			reportCompletion(numTries + " tries before wikitext editor's special characters bar was heightened", (performance.now() - startTime).round(3), 'success', 'special-characters-bar-heightening', numTries, 'NaN');
		}
		else if (++numTries < 5000) { window.setTimeout(increaseEditorSpecialCharactersBarHeight, 10, numTries, startTime); } //try for 5000*10 milliseconds (that is 50 seconds)
		else { reportCompletion("Failed to increase height of wikitext editor's special characters bar", (performance.now() - startTime).round(3), 'error', 'special-characters-bar-heightening', numTries, 'NaN'); }
	}
	function increaseWikitextEditorHeight(numTries, startTime) {
		if ($('.wikiEditor-ui-view-wikitext').length) {
			$('.wikiEditor-ui-view-wikitext').height('75vh');
			window.dispatchEvent(new Event('resize'));
			reportCompletion(numTries + " tries before wikitext editor was heightened", (performance.now() - startTime).round(3), 'success', 'wikitext-editor-heightening', numTries, 'NaN');
			increaseEditorSpecialCharactersBarHeight(0, performance.now());
		}
		else if (++numTries < 5000) { window.setTimeout(increaseWikitextEditorHeight, 10, numTries, startTime); } //try for 5000*10 milliseconds (that is 50 seconds)
		else { reportCompletion("Failed to increase height of wikitext editor", (performance.now() - startTime).round(3), 'error', 'wikitext-editor-heightening', numTries, 'NaN'); }
	}
	var allowLaterModificationOfWatchlistExpiry;
	try {
		if (['edit', 'submit'].includes(mw.config.get('wgAction'))) {
			allowLaterModificationOfWatchlistExpiry = !['User', 'User_talk'].includes(mw.config.get('wgCanonicalNamespace'));
			scrollToEditWindow(0, performance.now());
			if (!allowLaterModificationOfWatchlistExpiry) {
				if (mw.config.get('wgUserName') === mw.config.get('wgTitle').substring(0, mw.config.get('wgUserName').length)) { setWatchlistExpiry(0, performance.now(), 'infinite'); }
				else { setWatchlistExpiry(0, performance.now(), "1 week"); }
			}
			else { setWatchlistExpiry(0, performance.now(), "3 months"); }
			$('.editButtons').insertBefore('#editpage-copywarn');
			filterWatchlistExpiryOptions(0, performance.now());
			if (mw.config.get('wgPageContentModel') === 'wikitext') { //if editing wikitext
				increaseWikitextEditorHeight(0, performance.now());
			}
		}
		else {
			allowLaterModificationOfWatchlistExpiry = false;
			if (mw.config.get('wgCanonicalSpecialPageName') === 'Homepage') { //hide suggested edits
				$('.growthexperiments-homepage-module-header')[0].remove();
				$('.growthexperiments-homepage-module-body')[1].style.display = 'none';
				$('.growthexperiments-homepage-module-mobile-summary activated')[0].remove();
			}
			else if (mw.config.get('wgCanonicalSpecialPageName') === 'Watchlist') { //add current events headlines
				var element = document.createElement('div');
				element.setAttribute('class', 'my-class');
				document.getElementById('mw-content-text').insertBefore(element, document.getElementsByClassName('mw-rcfilters-head')[0]);
				$('.my-class').load('https://en.wikipedia.org/wiki/Portal:Current_events .p-current-events-headlines');
				filterCurrentEvents(0, performance.now());
			}
			else if (mw.config.get('wgPageName') === 'User:' + mw.config.get('wgUserName')) { //add (primitive-looking) impact view counts
				var element = document.createElement('div');
				element.setAttribute('class', 'my-class');
				document.getElementById('bodyContent').insertBefore(element, document.getElementById('catlinks')[0]);
				$('.my-class').load('https://en.wikipedia.org/wiki/Special:Homepage .growthexperiments-homepage-group-sidebar-subgroup-primary');
			}
		}
	}
	catch (e) { //continue even if an error occurred
		 console.error(e.message);
	}

	/**
	 * TemplateScript adds configurable templates and scripts to the sidebar, and adds an example regex editor.
	 * @see https://meta.wikimedia.org/wiki/TemplateScript
	 * @update-token [[File:Pathoschild/templatescript.js]]
	 */
	mw.config.set('userjs-templatescript', { regexEditor: false }); //disable TemplateScript's regex editor
	$.ajax('//tools-static.wmflabs.org/meta/scripts/pathoschild.templatescript.js', { dataType:'script', cache:true }).then(function() {
		var watchlistExpiryMode = 0; //0 for don't watch, 1 for regular, 2 for extended
		function waitForWatchlistIndicatorForAutomaticCleanup(numTries, startTime) {
			if ($('#ca-watch').length || $('#ca-unwatch').length) {
				reportCompletion(numTries + " tries before watchlist indicator was detected", (performance.now() - startTime).round(3), 'success', 'watchlist-indicator-detection', numTries, 'NaN');
				if ($('#ca-watch').length) { //presence of the #ca-watch element indicates the ability to watch the page because it is not already on the watchlist
					var expiryValue;
					switch (watchlistExpiryMode) {
						case 0:
							//leave expiryValue undefined
							break;
						case 1:
							expiryValue = '1 week';
							break;
						case 2:
							expiryValue = '1 month';
							break;
					}
					setWatchlistExpiry(0, performance.now(), expiryValue);
				}
			}
			else if (++numTries < 1000) { window.setTimeout(waitForWatchlistIndicatorForAutomaticCleanup, 5, numTries, startTime); } //try for 1000*5 milliseconds (that is 5 seconds)
			else { reportCompletion("Failed to detect watchlist indicator", (performance.now() - startTime).round(3), 'error', 'watchlist-indicator-detection', numTries, 'NaN'); }
		}
		function setWatchlistExpiryForCleanupHelper(numTries, startTime) {
			if (watchlistExpiryIsSet) {
				watchlistExpiryIsSet = false;
				reportCompletion(numTries + " tries before setting watchlist expiry on cleanup", (performance.now() - startTime).round(3), 'success', 'cleanup-watchlist-expiry-setting', numTries, 'NaN');
				waitForWatchlistIndicatorForAutomaticCleanup(0, performance.now());
			}
			else if (++numTries < 1000) { window.setTimeout(setWatchlistExpiryForCleanupHelper, 5, numTries, startTime); } //try for 1000*5 milliseconds (that is 5 seconds)
			else { reportCompletion("Failed to set watchlist expiry on cleanup", (performance.now() - startTime).round(3), 'error', 'cleanup-watchlist-expiry-setting', numTries, 'NaN'); }
		}
		function setWatchlistExpiryForCleanup(numTries, startTime) {
			if (allowLaterModificationOfWatchlistExpiry !== undefined) {
				reportCompletion(numTries + " tries before permission to set watchlist expiry on cleanup was detected", (performance.now() - startTime).round(3), 'success', 'cleanup-watchlist-expiry-permission-detection', numTries, 'NaN');
				if (allowLaterModificationOfWatchlistExpiry) {
					setWatchlistExpiryForCleanupHelper(0, performance.now());
				}
			}
			else if (++numTries < 1000) { window.setTimeout(setWatchlistExpiryForCleanup, 5, numTries, startTime); } //try for 1000*5 milliseconds (that is 5 seconds)
			else { reportCompletion("Failed to detect permission to set watchlist expiry on cleanup", (performance.now() - startTime).round(3), 'error', 'cleanup-watchlist-expiry-permission-detection', numTries, 'NaN'); }
		}
		var summaryAppendix; //globalized due to use in conductRegexReplacement() which is used in both cleanup and HTML cleanup
		var count; //globalized as callback functions require variable to exist where callback functions are scoped rather than inside calling function
		function conductRegexReplacement(arrayOfMatchPatternsAndReplacementFunctions, editor, description, storageName, newWatchlistExpiryMode) { //arrayOfMatchPatternsAndReplacementFunctions is an array of arrays where each subarray has exactly two elements, the first being the regex pattern to match and the second being the regex replacement callback function; summaryAppendix relies on description being an explanatory wiki link; notification becomes count + description + " in " + duration + "ms"
			var startTime = performance.now();
			var textLength = editor.get().length;
			count = 0;
			for (var i = 0; i < arrayOfMatchPatternsAndReplacementFunctions.length; i++) {
				editor.replace(arrayOfMatchPatternsAndReplacementFunctions[i][0], arrayOfMatchPatternsAndReplacementFunctions[i][1]);
			}
			if (count) {
				summaryAppendix += "[[" + description + "]] (" + count + "), ";
				watchlistExpiryMode = Math.max(watchlistExpiryMode, newWatchlistExpiryMode);
			}
			reportCompletion(count + " " + description, (performance.now() - startTime).round(3), 'info', storageName, count, textLength);
		}
		function pluralize(num) {
			return num === 1 ? "" : "s";
		}
		pathoschild.TemplateScript.add(
			[
				{
					name: 'Cleanup',
					script: function(editor) {
						summaryAppendix = "";
						conductRegexReplacement([[/((?:.|\r|\n)+)(\{\{\s*short\s+description\s*\|[^\}]+\}\})(?:\r\n)?/i, function(match, p1, p2) { count++; return p2 + "\r\n" + p1; }]], editor, "MOS:ORDER", 'reorder-short-description', 1);
						conductRegexReplacement([[/(?<=\n)(=+)([^=\r\n\[\]\|\{\}]*)\[\[([^=\r\n\[\]\|\{\}]*)\]\]([^=\r\n\[\]\|\{\}]*)\1(?=\n)/g, function(match, p1, p2, p3, p4) { count++; return p1 + p2 + p3 + p4 + p1; }]], editor, "MOS:HEAD", 'remove-heading-wiki-links', 1); //should happen before any escaping of wiki links as well as geographical wiki links combination and wiki-link shortening


						var templateEscapeString = '';
						for (var i = 0; i < expansionDepthLimit * 2 - 1; i++) { //the expansion-depth limit is multiplied by two for each level requiring two nested curly braces and minus one for the outermost two pairs being supplied later; note the assumption that no single-paired nested braces will be used to surpass the limit of eighty nested pairs of curly braces
							templateEscapeString += '(?:[^\\{\\}]|\\{';
						}
						templateEscapeString += '[^\\{\\}]*';
						for (var i = 0; i < expansionDepthLimit * 2 - 1; i++) { //the expansion-depth limit is multiplied by two for each level requiring two nested curly braces and minus one for the outermost two pairs being supplied later; note the assumption that no single-paired nested braces will be used to surpass the limit of eighty nested pairs of curly braces
							templateEscapeString += '\\})*';
						}
						var wikiLinkEscapeRegex = RegExp('\[\[[^\|\]]*(?:\|(?=[^\|\]]*\]\])|\]\])', 'g');
						var HTMLEscapeRegex = RegExp(/<(?!(?:br|references)\s*\/?>)([a-zA-Z]+)[^<>]*>(?:(?!<\/\1\s*>)(?:.|\r|\n))*<\/\1\s*>/gi);
						var escaped1 = editor.escape(wikiLinkEscapeRegex);
						var escaped2 = editor.escape(HTMLEscapeRegex);
						var escaped3 = editor.escape(RegExp('\\{\\{' + templateEscapeString + '\\}\\}', 'g')); //note that this assumes that no single-paired nested braces will be used to surpass the expansion-depth limit

						conductRegexReplacement([
							[RegExp('(?<=\\d)\\s+(?=' + compoundNumbersRegex + '|(?:[km]g|[aApP][mM])(?![a-zA-Z]))', 'g'), function() { count++; return "&nbsp;"; }],
							[/(?<=[ \r\n])\u00A0|\u00A0(?=[ \r\n])/g, function() { count++; return ""; }],
							[/\u00A0/g, function() { count++; return "&nbsp;"; }]
						], editor, "MOS:NBSP", 'insert-nbsps', 1); //should happen before any regex relying on "\s" is used

						editor
							.unescape(escaped1)
							.unescape(escaped2)
							.unescape(escaped3);


						var headingEscapeRegex = /(?<=\n)(=+)[^=\r\n]*\1(?=\n)/g;
						escaped1 = editor.escape(wikiLinkEscapeRegex);
						escaped2 = editor.escape(HTMLEscapeRegex);
						escaped3 = editor.escape(RegExp('\\{\\{' + templateEscapeString + '\\}\\}', 'g')); //note that this assumes that no single-paired nested braces will be used to surpass the expansion-depth limit
						var escaped4 = editor.escape(headingEscapeRegex);

						conductRegexReplacement([[/ (?:\{\{\s*[nN]dash\s*\}\}|&ndash;)(?: |\{\{\s*[nN]dash\s*\}\}|&ndash;)/g, function() { count++; return "{{snd}}"; }]], editor, "MOS:ENDASH", 'fix-ndashes', 1); //should happen after literal non-breaking space removal and replacement

						editor
							.unescape(escaped1)
							.unescape(escaped2)
							.unescape(escaped3)
							.unescape(escaped4);


						var fileRegex = /(?:File|Image):[^\|\]\r\n]+\|/g;
						var imageParameterRegex = /\|\s*image\s*=(?:(?!\||\}\})[^\|])*/g;
						// var escaped5 = editor.escape(fileRegex);
						// var escaped6 = editor.escape(imageParameterRegex);
						// var escaped7 = editor.escape(/„[^“]*“/);

						// conductRegexReplacement([
						// 	[/[“”]/g, function(match) { count++; return '"'; }],
						// 	[/(?<![‘\'])‘(?![‘\'])/g, function(match) { count++; return "'"; }], //future consideration: add nowiki tags if preceding or proceeding text is a non-curly single quotation mark
						// 	[/(?<![’\'])’(?![’\'])/g, function(match) { count++; return "'"; }]  //future consideration: add nowiki tags if preceding or proceeding text is a non-curly single quotation mark
						// ], editor, "MOS:CURLY", 'replace-curlies', 0);

						// editor
						// 	.unescape(escaped5)
						// 	.unescape(escaped6)
						// 	.unescape(escaped7);


						var nowikiEscapeRegex = RegExp('(?:<nowiki\s*>(?:(?!<\/' + 'nowiki\s*>)(?:.|\r|\n))*<\/' + 'nowiki\s*>|\{\{\s*#tag:\s*nowiki\s*\}\})', 'gi'); //string is broken at closing nowiki tags to avoid throwing off Wikipedia wherever this document is loaded
						var escaped8 = editor.escape(nowikiEscapeRegex);
						var escaped9 = editor.escape(/(?:<!--(?:(?!-->)(?:.|\r|\n))*-->|\{\{\s*#tag:\s*!--\s*\}\})/g);

						var startTime = performance.now();
						var textLength = editor.get().length;
						count = 0;
						var emptyCitationBlacklistRegex = 'Gaia +DR2';
						editor
							.replace(RegExp('<[rR][eE][fF][^>\\/]*>\\s*(?:\\{\\{\\s*[cC]ite +(?!' + emptyCitationBlacklistRegex + ')\\w+\\s*(?:\\|(?:\\s*[\\w-]+\\s*=)?\\s*)*\\}\\}\\s*)?<\\/[rR][eE][fF]\\s*>', 'g'), function() { count++; return ""; })
							.replace(RegExp('\\{\\{\\s*[cC]ite +(?!' + emptyCitationBlacklistRegex + ')\\w+\\s*(?:\\|(?:\\s*[\\w-]+\\s*=)?\\s*)*\\}\\}\\s*', 'g'), function() { count++; return ""; });
						if (count) {
							summaryAppendix += "rm " + (count !== 1 ? count + " " : "") + "[[Category:CS1 errors: empty citation|empty CS1 citation]]" + pluralize(count) + ", ";
							watchlistExpiryMode = 2;
						}
						reportCompletion(count + " empty CS1 citation" + pluralize(count), (performance.now() - startTime).round(3), 'info', 'remove-empty-citations', count, textLength);
						var openingRefHTMLRegex = '<[rR][eE][fF][^>]*>';
						var closingRefHTMLRegex = '<\\/[rR][eE][fF]\\s*>';
						var openingRefParserRegex = '\\{\\{\\s*#tag:\\s*ref\\s*\\|';
						var closingRefParserRegex = '\\}\\}';
						var problematicIntermediaryRegex = '<nowiki\\s*>|<\\/' + 'nowiki\\s*>|<nowiki\\s*\\/>|\\{\\{\\s*#tag:\\s*(?:nowiki|!--)\\s*\\}\\}'; //string is broken at closing nowiki tag to avoid throwing off Wikipedia wherever this document is loaded
						conductRegexReplacement([
							[RegExp('\\s+(' + openingRefHTMLRegex + '(?:(?!\\|' + problematicIntermediaryRegex + '|' + closingRefHTMLRegex + ')(?:.|\r|\n))*' + closingRefHTMLRegex + ')', 'g'), function(match, p1) { count++; return p1; }],
							[RegExp('\\s+(' + openingRefParserRegex + '(?:(?!\\|' + problematicIntermediaryRegex + '|' + closingRefParserRegex + ')(?:.|\r|\n))*' + closingRefParserRegex + ')', 'g'), function(match, p1) { count++; return p1; }]
						], editor, "MOS:REFSPACE", 'add-spaces-before-refs', 1);

						// // The following was removed for being broken (the conducted replacement of duplicate references is nonsensical) for unknown reasons.
						// startTime = performance.now();
						// textLength = editor.get().length;
						// count = 0;
						// var referencesArray = Array.from(editor.get().matchAll(RegExp('<ref(\s*(?:[^<>]+(?<!\/))?)>(?:(?!<\/ref\s*>)(?:.|\r|\n))*<\/ref\s*>', 'gi')));
						// for (var i = 0; referencesArray.length; i++) {
						// 	var firstReplacement = true;
						// 	editor.replace(RegExp(referencesArray[0][0].replaceAll(/([\^\$\*\(\)\+\{\}\[\]\\\.\?\/\-])/g, function(match, p1) { return '\\' + p1; }), 'g'), function(match, p1) {
						// 		if (firstReplacement) {
						// 			firstReplacement = false;
						// 			return match;
						// 		}
						// 		count++;
						// 		return "<ref" + (p1 === undefined ? " name=\":" + (i + 10) + "\"" : p1) + " />";
						// 	});
						// 	var captureGroup1 = referencesArray[0][1];
						// 	var referenceMatch = (captureGroup1 ? referencesArray[0][0].replace(captureGroup1, '') : referencesArray[0][0]);
						// 	referencesArray = referencesArray.filter(function(value) { return (captureGroup1 && value[0].indexOf(captureGroup1) === 4 ? value[0].replace(captureGroup1, '') : value[0]) !== referenceMatch; });
						// }
						// reportCompletion(count + " duplicate reference" + pluralize(count), (performance.now() - startTime).round(3), 'info', 'merge-duplicate-references', count, textLength);

						editor
							.unescape(escaped8)
							.unescape(escaped9);


						escaped8 = editor.escape(nowikiEscapeRegex);

						var openingCitationTemplateRegex = '\\{\\{\\s*[cC]ite +\\w+\\s*';
						var closingCitationTemplateRegex = '\\}\\}';
						var openingCitationHTMLRegex = openingRefHTMLRegex + '\\s*' + openingCitationTemplateRegex;
						var closingCitationHTMLRegex = closingCitationTemplateRegex + '\\s*' + closingRefHTMLRegex;
						var openingCitationParserRegex = openingRefParserRegex + '\\s*' + openingCitationTemplateRegex;
						var closingCitationParserRegex = '(?:\\|[^\\|\\}])*' + closingCitationTemplateRegex + '\\s*' + closingRefParserRegex;
						startTime = performance.now();
						textLength = editor.get().length;
						count = 0;
						var postscriptArg = '\\s*postscript\\s*=';
						editor
							.replace(RegExp('(' + openingCitationHTMLRegex + '(?:(?!\\|' + postscriptArg + '|' + problematicIntermediaryRegex + '|' + closingCitationHTMLRegex + ')(?:.|\r|\n))*)\\|' + postscriptArg + '\\s*\\.\\s*((?:\\|(?:(?!' + postscriptArg + '|' + problematicIntermediaryRegex + '|\\s*' + closingCitationHTMLRegex + ')[^\\|])*)*' + closingCitationHTMLRegex + ')', 'g'), function(match, p1, p2) { count++; return p1 + p2; })
							.replace(RegExp('(' + openingCitationParserRegex + '(?:(?!\\|' + postscriptArg + '|' + problematicIntermediaryRegex + '|' + closingCitationParserRegex + ')(?:.|\r|\n))*)\\|' + postscriptArg + '\\s*\\.\\s*((?:\\|(?:(?!' + postscriptArg + '|' + problematicIntermediaryRegex + '|\\s*' + closingCitationParserRegex + ')[^\\|])*)*' + closingCitationParserRegex + ')', 'g'), function(match, p1, p2) { count++; return p1 + p2; });
						if (count) {
							summaryAppendix += "rm " + (count !== 1 ? count + " " : "") + "[[Category:CS1 maint: postscript|redundant CS1 postscript]]" + pluralize(count) + ", ";
							watchlistExpiryMode = 2;
						}
						reportCompletion(count + " redundant CS1 postscript" + pluralize(count), (performance.now() - startTime).round(3), 'info', 'fix-postscript-period', count, textLength);
						startTime = performance.now();
						textLength = editor.get().length;
						count = 0;
						var urlStatusArg = '\\s*url-status\\s*=';
						var archiveArgs = '\\s*archive-(?:url|date)\\s*=\\s*\\w+';
						editor
							.replace(RegExp('(' + openingCitationTemplateRegex + '(?:(?!\\|' + urlStatusArg + '|\\|' + archiveArgs + '|' + problematicIntermediaryRegex + '|' + closingCitationTemplateRegex + ')(?:.|\r|\n))*)\\|' + urlStatusArg + '\\s*live\\s*((?:\\|(?:(?!' + urlStatusArg + '|' + archiveArgs + '|' + problematicIntermediaryRegex + '|\\s*' + closingCitationTemplateRegex + ')[^\\|])*)*\\s*' + closingCitationTemplateRegex + ')', 'g'), function(match, p1, p2) { count++; return p1 + p2; });
						if (count) {
							summaryAppendix += "rm " + (count !== 1 ? count + " " : "") + "[[Category:CS1 maint: url-status|live CS1 url status]]" + (count === 1 ? "" : "es") + ", ";
						}
						reportCompletion(count + " live CS1 url status" + (count === 1 ? "" : "es"), (performance.now() - startTime).round(3), 'info', 'remove-live-url-status', count, textLength);
						conductRegexReplacement([[/\[\[\s*([\w-]+(?:\s+[\w-]+)?),\s*([\w-]+(?:\s+[\w-]+)?)\s*\|\s*((?:[\w-]+(?:\s+[\w-]+)?)?)\s*\]\],\s*\[\[\s*([\w-]+(?:\s+[\w-]+)?)((?:,(?:\s+[\w-]+)*|\s+\([\w-]+(?:\s+[\w-]+)*\))?\s*(?:\|\s*[\w-]+(?:\s+[\w-]+)?\s*)?)\]\]/g, function(match, p1, p2, p3, p4, p5) {
							var p2Temp = p2.replaceAll(/[‘’]/g, '\'').replaceAll(/[“”]/g, '\"');
							if (p1.replaceAll(/[‘’]/g, '\'').replaceAll(/[“”]/g, '\"') === p3.replaceAll(/[‘’]/g, '\'').replaceAll(/[“”]/g, '\"') && p2Temp === p4.replaceAll(/[‘’]/g, '\'').replaceAll(/[“”]/g, '\"') && (!p5.length || (p5.indexOf('|') >= 0 && (p5.indexOf('|') === p5.length - 1 || p5.substring(p5.indexOf('|') + 1).trim().replaceAll(/[‘’]/g, '\'').replaceAll(/[“”]/g, '\"') === p2Temp)))) {
								count++;
								return "[[" + p1 + ", " + p2 + "]]";
							}
							return "[[" + p1 + ", " + p2 + "|" + p3 + "]], [[" + p4 + p5 + "]]";
						}]], editor, "MOS:GEOLINK", 'combine-geographical-wiki-links', 0);
						conductRegexReplacement([[/<u\s*>((?:(?!<\/?u\s*>)(?:.|\r|\n))*.?)<\/u\s*>/gi, function(match, p1) { count++; return "{{em|" + p1 + "}}"; }]], editor, "MOS:EMPHASIS", 'fix-HTML-underlining', 2);
						startTime = performance.now();
						textLength = editor.get().length;
						var countArray = [0]; //an array style for two replacement segments sharing a summary excerpt
						editor
							.replace(/(?<!\n;[^\n]*)\n:\s*<math(?:\s*(\s[^<>]*))?>((?:(?!<\/math\s*>)(?:.|\r|\n))*.?)<\/math\s*>\s*\n/gi, function(match, p1, p2) { countArray[0]++; return "\n<math " + (p1 !== undefined || /\sdisplay\s*=\s*([\"\'])\s*block\s*\1/gi.test(p1) ? "" : "display=\"block\"") + (p1 === undefined ? "" : p1) + ">" + p2 + "</math>\n"; });
						//note: appending message to summary is handled by the replacement segment after next
						reportCompletion(countArray[0] + " HTML math tag" + pluralize(countArray[0]) + " display as block", (performance.now() - startTime).round(3), 'info', 'fix-colon-indent-math', countArray[0], textLength);
						conductRegexReplacement([[/(?<=\n)([\*#]*)(:+|;[^\n]*\n|)([^\n]*)\n(?=[:\*#])/g,
							function(match, p1, p2, p3) {
								if (p2.length && p2[0] === ":") {
									count++;
									return p1 + new Array(p2.length + 1).join('*') + p3 + "\n";
								}
								else {
									return p1 + p2 + p3 + "\n";
								}
							}]], editor, "MOS:DLIST", 'fix-dlist', 1);
						startTime = performance.now();
						textLength = editor.get().length;
						countArray.push(0);
						editor
							.replace(/(?<=\n)([\*#]*)(:+|;[^\n]*\n|)([^\n]*)\n(?=\s*\n)/g, function(match, p1, p2, p3) {
								if (p2.length && p2[0] === ":") {
									countArray[1]++;
									return p1 + "{{block indent" + (p2.length === 2 ? "" : "|left=" + (1.5 * p2.length)) + "|1=" + p3 + "}}\n";
								}
								else {
									return p1 + p2 + p3 + "\n";
								}
							})
							.replace(/(?<=\n)([\*#]*)(:+|;[^\n]*\n|)([^\n]*)\n/g, function(match, p1, p2, p3) {
								if (p2.length && p2[0] === ":") {
									countArray[1]++;
									return p1 + "{{block indent" + (p2.length === 2 ? "" : "|left=" + (1.5 * p2.length)) + "|1=" + p3 + (p3.length >= "<br>".length && p3.match(/<br\s*\/?>/g) !== null && p3.lastIndexOf(p3.match(/<br\s*\/?>/g).slice(-1)[0]) === p3.length - p3.match(/<br\s*\/?>/g).slice(-1)[0].length ? "" : "<br>") + "}}\n";
								}
								else {
									return p1 + p2 + p3 + "\n";
								}
							});
						if (countArray[0] || countArray[1]) {
							summaryAppendix += "[[MOS:INDENTGAP]] (" + (countArray[0] ? countArray[0] : "") + (countArray[0] && countArray[1] ? "+" : "") + (countArray[1] ? countArray[1] : "") + "), ";
							watchlistExpiryMode = 2;
						}
						reportCompletion(countArray[1] + " colon indentation" + pluralize(countArray[1]), (performance.now() - startTime).round(3), 'info', 'fix-colon-indent', countArray[1], textLength);
						conductRegexReplacement([[/\[\[\s*([^\]\|\{\}<>]+(?<!\s))\s*\|\s*([^\]\|\{\}<>]+)\s*\]\]/g, function(match, p1, p2) {
							var p2Temp = p2.charAt(0).toLowerCase() + p2.substring(1).replaceAll(/[‘’]/g, '\'').replaceAll(/[“”]/g, '\"');
							if (p2Temp.indexOf((p1.charAt(0).toLowerCase() + p1.substring(1)).replaceAll(/[‘’]/g, '\'').replaceAll(/[“”]/g, '\"')) === 0 && (p2Temp.length === p1.length || (p2Temp.substring(p1.length).match(/[^\s`~!@#$%^&*\(\)\-–—_=+\[\]\{\}\\\|;:\'\"‘’“”,\.<>\/?A-Z\d][^\s`~!@#$%^&*\(\)\-–—_=+\[\]\{\}\\\|;:\'\"‘’“”,\.<>\/?\d]*/g) !== null && p2Temp.substring(p1.length).match(/[^\s`~!@#$%^&*\(\)\-–—_=+\[\]\{\}\\\|;:\'\"‘’“”,\.<>\/?A-Z\d][^\s`~!@#$%^&*\(\)\-–—_=+\[\]\{\}\\\|;:\'\"‘’“”,\.<>\/?\d]*/g)[0].length === p2Temp.length - p1.length))) {
								count++;
								return "[[" + p2.charAt(0) + p2Temp.substring(1, p1.length) + "]]" + p2Temp.substring(p1.length);
							}
							return "[[" + p1 + "|" + p2 + "]]";
						}]], editor, "MOS:PIPESTYLE", 'shorten-wiki-links', 0);

						var tableEscapeString = '';
						var expansionDepthLimit = 40; //40 is the expansion-depth limit (and is assumed to apply to table nesting)
						for (var i = 0; i < expansionDepthLimit; i++) {
							tableEscapeString += '(?:(?:(?!\\{\\||\\|\\})(?:.|\\r|\\n))*.?|\\{\\|';
						}
						tableEscapeString += '(?:(?!\\{\\||\\|\\})(?:.|\\r|\\n))*.?';
						for (var i = 0; i < expansionDepthLimit; i++) {
							tableEscapeString += '\\|\\})*';
						}
						var escaped10 = editor.escape(RegExp(tableEscapeString, 'g'));

						conductRegexReplacement([[/\[\[\s*(?:[Ff][Ii][Ll][Ee]|[Ii][Mm][Aa][Gg][Ee])\s*:\s*([^\|\[\]]+)\s*\|((?:(?:(?!\d+\s*px|upright)[^\|\[\]])*\|)*)(\d+)\s*px((?:\s*\|(?:(?!\d+\s*px|upright)[^\|\[\]])*)*)\]\]/g, function(match, p1, p2, pixelValue, p4) { count++; return "[[File:" + p1 + "|" + p2 + "upright=" + (Number(pixelValue) / 220).round(3) + p4 + "]]"; }]], editor, "MOS:IMGSIZE", 'convert-image-pixel-sizes', 1); //convert pixels to upright (rounded to nearest thousandth due to the three significant digits of 220)

						editor
							.unescape(escaped8)
							.unescape(escaped10);


						// escaped1 = editor.escape(wikiLinkEscapeRegex);
						// escaped2 = editor.escape(HTMLEscapeRegex);
						// escaped3 = editor.escape(RegExp('\\{\\{' + templateEscapeString + '\\}\\}', 'g')); //note that this assumes that no single-paired nested braces will be used to surpass the expansion-depth limit
						// var escaped11 = editor.escape(/\"[^\"]*\"/g); //requires curly quotation marks to have been converted, though is of highly varying accuracy anyway

						// var monthOfYearRegex = 'January|February|March|April|May|June|July|August|September|October|November|December|(?:Jan|Feb|Mar|Apr|Jun|Jul|Aug|Sep|Oct|Nov|Dec)';
						var compoundNumbersRegex = '(?:m|b|tr|quadr)illion';
						// conductRegexReplacement([
						// 	[RegExp('(?<=[a-z](?<!' + monthOfYearRegex + '|version))\\s+(\\d)(?=\\s+(?!' + monthOfYearRegex + '|' + compoundNumbersRegex + ')[a-z])', 'gi'), function(match, p1) {
						// 		count++;
						// 		switch (p1) {
						// 			case '0':
						// 				return " zero";
						// 			case '1':
						// 				return " one";
						// 			case '2':
						// 				return " two";
						// 			case '3':
						// 				return " three";
						// 			case '4':
						// 				return " four";
						// 			case '5':
						// 				return " five";
						// 			case '6':
						// 				return " six";
						// 			case '7':
						// 				return " seven";
						// 			case '8':
						// 				return " eight";
						// 			case '9':
						// 				return " nine";
						// 			default: //should never occur, but replace with original if it does
						// 				return " " + p1;
						// 		}
						// 	}]
						// ], editor, "MOS:SPELL09", 'spell-digits', 1);

						// editor
						// 	.unescape(escaped1)
						// 	.unescape(escaped2)
						// 	.unescape(escaped3)
						// 	.unescape(escaped11);


						escaped1 = editor.escape(wikiLinkEscapeRegex);
						escaped4 = editor.escape(headingEscapeRegex);
						var escaped5 = editor.escape(fileRegex);
						var escaped6 = editor.escape(imageParameterRegex);
						escaped8 = editor.escape(nowikiEscapeRegex);
						var escaped12 = editor.escape('\\{\\{\\s*[cC]ite +\\w+\\s*' + templateEscapeString + '\\}\\}');

						var discouragedCircaRegex = '(?:circa|ca?(?:\\.|\\s)|C\\.|around|approx(?:imately|\\.))';
						var eraAbbreviationRegex = 'BCE?|AD|CE|B\\.\\s?C\\.\\s?(?:E\\.)?|A\\.\\s?D\\.|C\\.\\s?E\\.';
						var nbspRegex = '\\{\\{\\s*[nN]bsp\\s*\\}\\}|&nbsp;';
						var ndashRegex = '\\{\\{\\s*[eE]n +[dD]ash\\s*\\}\\}|&ndash;|–';
						var mdashRegex = '\\{\\{\\s*[mM]dash\\s*\\}\\}|&mdash;|—';
						conductRegexReplacement([[RegExp('(?<=[^\\w])' + discouragedCircaRegex + '\\s*(\\d+)(?:\\s+(' + eraAbbreviationRegex + ')(?!(?:(?:' + nbspRegex + ')|(?:\\s{0,}(?:-|' + ndashRegex + '))|\\s{0,}(?:' + mdashRegex + ')|\\s+to\\s)|E\\.?(?:(?:' + nbspRegex + ')|(?:\\s{0,}(?:-|' + ndashRegex + '))|\\s{0,}(?:' + mdashRegex + ')|\\s+to\\s))|(?!\\d*(?:(?:(?:' + nbspRegex + ')|(?:\\s{0,}(?:-|' + ndashRegex + '))|\\s{0,}(?:' + mdashRegex + '))|[a-zA-Z%°\/]|[,\\.:]\\d+|\\s+(?:%|per\\s?cent|kilo|milli|' + compoundNumbersRegex + '|to\\s|' + eraAbbreviationRegex + '))))', 'g'), function(match, p1, p2) { count++; return "{{circa|" + p1 + (p2 === undefined ? "" : "&nbsp;" + p2.replaceAll(' ', '').replaceAll('.', '')) + "}}"; }]], editor, "MOS:CIRCA", 'fix-circa-formatting', 1); //note that to minimize false positives, spelling single-digit numbers and non-breaking space insertion should be handled before this circa formatting

						editor
							.unescape(escaped1)
							.unescape(escaped4)
							.unescape(escaped5)
							.unescape(escaped6)
							.unescape(escaped8)
							.unescape(escaped12);


						// var escaped13 = editor.escape(/(?:<!--(?:(?!-->)(?:.|\r|\n))*-->|\{\{\s*#tag:\s*!--\s*\}\})/g);
						// var escaped14 = editor.escape(RegExp('(?:<ref\s*(?:[^<>]+(?<!\/))?>(?:(?!<\/ref\s*>)(?:.|\r|\n))*<\/ref\s*>|\{\{\s*#tag:\s*ref\s*\}\})', 'gi'));
						// var escaped15 = editor.escape(RegExp('(?:<gallery\s*(?:[^<>]+)>(?:(?!<\/gallery\s*>)(?:.|\r|\n))*<\/gallery\s*>|\{\{\s*#tag:\s*gallery\s*\}\})', 'gi'));

						// editor
						// 	.unescape(escaped13)
						// 	.unescape(escaped14)
						// 	.unescape(escaped15);


						startTime = performance.now();
						textLength = editor.get().length;
						countArray = [0, 0, 0, 0]; //ol then li in ol then ul then li in ul
						editor
							.replace(/<ol\s*>((?:(?!<\/?[ou]l\s*>)(?:.|\r|\n))*.?)<\/ol\s*>/gi, function(match, p1) { countArray[0]++; return p1.replace(/\n?<li\s*>((?:(?!<\/?li\s*>)(?:.|\r|\n))*.?)<\/li\s*>/gi, function(match, p1) { countArray[1]++; return "\n# " + p1; }); })
							.replace(/<ul\s*>((?:(?!<\/?[ou]l\s*>)(?:.|\r|\n))*.?)<\/ul\s*>/gi, function(match, p1) { countArray[2]++; return p1.replace(/\n?<li\s*>((?:(?!<\/?li\s*>)(?:.|\r|\n))*.?)<\/li\s*>/gi, function(match, p1) { countArray[3]++; return "\n* " + p1; }); });
						if (countArray[0] || countArray[2]) {
							summaryAppendix += "converted " + (countArray[0] ? countArray[0] + " HTML ol tag" + pluralize(countArray[0]) + " containing " + countArray[1] + " list item" + pluralize(countArray[1]) : "") + (countArray[0] && countArray[2] ? " and " : "") + (countArray[2] ? countArray[2] + " HTML ul tag" + pluralize(countArray[2]) + " containing " + countArray[3] + " list item" + pluralize(countArray[3]) : "") + " to wikitext, ";
							watchlistExpiryMode = 2;
						}
						reportCompletion((countArray[0] || !countArray[2] ? countArray[0] + " HTML ol tag" + pluralize(countArray[0]) + " containing " + countArray[1] + " HTML li tag" + pluralize(countArray[1]) : "") + (countArray[0] === countArray[2] ? " and " : "") + (!countArray[0] || countArray[2] ? countArray[2] + " HTML ul tag" + pluralize(countArray[2]) + " containing " + countArray[3] + " HTML li tag" + pluralize(countArray[3]) : "") + " converted", (performance.now() - startTime).round(3), 'info', 'fix-HTML-lists', countArray[0] + " containing " + countArray[1] + " and " + countArray[2] + " containing " + countArray[3], textLength);

						startTime = performance.now();
						textLength = editor.get().length;
						count = 0;
						editor
							.replace(/(?:\n\s*)?<tr(?:\s+([^<>]*))?>(?=\s*<th(?:\s+[^<>]*)?>)\s*((?:(?!\s*<\/?t(?:r|able)\s*>)(?:.|\r|\n))*.?)\s*<\/tr\s*>\s*/gi, function(match, p1, p2) { count++; return "\n|-" + (p1 !== undefined ? " " + p1 : "") + "\n!" + p2; })
							.replace(/(?:\n\s*)?<tr(?:\s+([^<>]*))?>\s*((?:(?!\s*<\/?t(?:r|able)\s*>)(?:.|\r|\n))*.?)\s*<\/tr\s*>\s*/gi, function(match, p1, p2) { count++; return "\n|-" + (p1 !== undefined ? " " + p1 : "") + "\n|" + p2; });
						if (count) {
							summaryAppendix += "converted " + count + " HTML tr tag" + pluralize(count) + " to wikitext, ";
							watchlistExpiryMode = 2;
						}
						reportCompletion(count + " HTML tr conversion" + pluralize(count), (performance.now() - startTime).round(3), 'info', 'fix-HTML-tr', count, textLength);
						startTime = performance.now();
						textLength = editor.get().length;
						count = 0;
						editor
							.replace(/<td(?:\s+([^<>]*))?>\s*((?:(?!\s*<\/?t(?:[dhr]|able)\s*>)(?:.|\r|\n))*.?)\s*<\/td\s*>\s*(?=\s*<td(?:\s+[^<>]*)?>)/gi, function(match, p1, p2) { count++; return (p1 !== undefined ? " " + p1 + " |" : "") + " " + p2 + " ||"; })
							.replace(/<td(?:\s+([^<>]*))?>\s*((?:(?!\s*<\/?t(?:[dhr]|able)\s*>)(?:.|\r|\n))*.?)\s*<\/td\s*>\s*/gi, function(match, p1, p2) { count++; return (p1 !== undefined ? " " + p1 + " |" : "") + " " + p2 + "\n"; });
						if (count) {
							summaryAppendix += "converted " + count + " HTML td tag" + pluralize(count) + " to wikitext, ";
							watchlistExpiryMode = 2;
						}
						reportCompletion(count + " HTML td conversion" + pluralize(count), (performance.now() - startTime).round(3), 'info', 'fix-HTML-td', count, textLength);
						startTime = performance.now();
						textLength = editor.get().length;
						count = 0;
						editor
							.replace(/<th(?:\s+([^<>]*))?>\s*((?:(?!\s*<\/?t(?:[dhr]|able)\s*>)(?:.|\r|\n))*.?)\s*<\/th\s*>\s*(?=<th(?:\s+[^<>]*)?>)/gi, function(match, p1, p2) { count++; return (p1 !== undefined ? " " + p1 + " |" : "") + " " + p2 + " !!"; })
							.replace(/<th(?:\s+([^<>]*))?>\s*((?:(?!\s*<\/?t(?:[dhr]|able)\s*>)(?:.|\r|\n))*.?)\s*<\/th\s*>\s*/gi, function(match, p1, p2) { count++; return (p1 !== undefined ? " " + p1 + " |" : "") + " " + p2 + "\n"; });
						if (count) {
							summaryAppendix += "converted " + count + " HTML th tag" + pluralize(count) + " to wikitext, ";
							watchlistExpiryMode = 2;
						}
						reportCompletion(count + " HTML th conversion" + pluralize(count), (performance.now() - startTime).round(3), 'info', 'fix-HTML-th', count, textLength);
						startTime = performance.now();
						textLength = editor.get().length;
						count = 0;
						editor
							.replace(/<table\s*>\s*((?:(?!\s*<\/?t(?:[dhr]|able)\s*>)(?:.|\r|\n))*.?)\s*<\/table\s*>/gi, function(match, p1) { count++; return "{| \n|+ \n" + p1 + "\n|}"; })
							.replace(/<table(?:\s+([^<>]*))>\s*((?:(?!\s*<\/?t(?:[dhr]|able)\s*>)(?:.|\r|\n))*.?)\s*<\/table\s*>/gi, function(match, p1, p2) { count++; return "{| " + p1 + "\n|+ \n" + p2 + "\n|}"; });
						if (count) {
							summaryAppendix += "converted " + count + " HTML table tag" + pluralize(count) + " to wikitext, ";
							watchlistExpiryMode = 2;
						}
						reportCompletion(count + " HTML table conversion" + pluralize(count), (performance.now() - startTime).round(3), 'info', 'fix-HTML-table', count, textLength);


						startTime = performance.now();
						if (summaryAppendix.substr(summaryAppendix.length - 2) === ", ") {
							summaryAppendix = summaryAppendix.substr(0, summaryAppendix.length - 2);
						}
						if (summaryAppendix.length) {
							var existingSummaryLength = $('#wpSummary').val().length;
							var capitalize = !existingSummaryLength || /^(?:\s*\/\*(?:(?!\*\/)(?:.|\r|\n))*\*\/\s*)+$/.test($('#wpSummary').val());
							if (capitalize) {
								summaryAppendix = summaryAppendix.charAt(0).toUpperCase() + summaryAppendix.slice(1);
								if (summaryAppendix.split(",").length === 2 - existingSummaryLength) { summaryAppendix = !existingSummaryLength ? summaryAppendix.replace(",", " and") : "and " + summaryAppendix; }
								else if (summaryAppendix.split(",").length > 2 - existingSummaryLength) { summaryAppendix = summaryAppendix.slice(0, summaryAppendix.lastIndexOf(",") + 1) + " and" + summaryAppendix.slice(summaryAppendix.lastIndexOf(",") + 1); }
								if (!$('#wpMinoredit').checked) {
									$('#wpMinoredit').prop( 'checked', true );
								}
							}
							editor.appendEditSummary(summaryAppendix);
							setWatchlistExpiryForCleanup(0, performance.now());
							summaryAppendix = "";
						}
						editor.clickDiff();
						reportCompletion("completed cleanup operation", (performance.now() - startTime).round(3), 'info', 'complete-cleanup', 'NaN');
	  				}
	  			},
				{
					name: 'NBSP cleanup',
					script: function(editor) {
						summaryAppendix = "";
						// var textLength = editor.get().length;

						var templateEscapeString = '';
						var expansionDepthLimit = 40; //40 is the expansion-depth limit (and is assumed to apply to table nesting)
						for (var i = 0; i < expansionDepthLimit * 2 - 1; i++) { //the expansion-depth limit is multiplied by two for each level requiring two nested curly braces and minus one for the outermost two pairs being supplied later; note the assumption that no single-paired nested braces will be used to surpass the limit of eighty nested pairs of curly braces
							templateEscapeString += '(?:[^\\{\\}]|\\{';
						}
						templateEscapeString += '[^\\{\\}]*';
						for (var i = 0; i < expansionDepthLimit * 2 - 1; i++) { //the expansion-depth limit is multiplied by two for each level requiring two nested curly braces and minus one for the outermost two pairs being supplied later; note the assumption that no single-paired nested braces will be used to surpass the limit of eighty nested pairs of curly braces
							templateEscapeString += '\\})*';
						}
						templateEscapeString = '\\{\\{' + templateEscapeString + '\\}\\}';
						var wikiLinkEscapeRegex = RegExp('\[\[[^\|\]]*(?:\|(?=[^\|\]]*\]\])|\]\])', 'g');
						var HTMLEscapeRegex = RegExp(/<(?!(?:br|references)\s*\/?>)([a-zA-Z]+)[^<>]*>(?:(?!<\/\1\s*>)(?:.|\r|\n))*<\/\1\s*>/gi);
						var escaped1 = editor.escape(wikiLinkEscapeRegex);
						var escaped2 = editor.escape(HTMLEscapeRegex);
						var escaped3 = editor.escape(RegExp(templateEscapeString, 'g')); //note that this assumes that no single-paired nested braces will be used to surpass the expansion-depth limit

						var monthOfYearRegex = 'January|February|March|April|May|June|July|August|September|October|November|December|(?:Jan|Feb|Mar|Apr|Jun|Jul|Aug|Sep|Oct|Nov|Dec)';
						conductRegexReplacement([[RegExp('(?<=' + monthOfYearRegex + ')\\s+(?=\\d{3,})', 'g'), function() { count++; return "&nbsp;"; }]], editor, "MOS:NBSP", 'insert-date-nbsps', 2);

						editor
							.unescape(escaped1)
							.unescape(escaped2)
							.unescape(escaped3);


						var startTime = performance.now();
						if (summaryAppendix.substr(summaryAppendix.length - 2) === ", ") {
							summaryAppendix = summaryAppendix.substr(0, summaryAppendix.length - 2);
						}
						if (summaryAppendix.length) {
							var existingSummaryLength = $('#wpSummary').val().length;
							var capitalize = !existingSummaryLength || /^(?:\s*\/\*(?:(?!\*\/)(?:.|\r|\n))*\*\/\s*)+$/.test($('#wpSummary').val());
							if (capitalize) {
								summaryAppendix = summaryAppendix.charAt(0).toUpperCase() + summaryAppendix.slice(1);
								if (summaryAppendix.split(",").length === 2 - existingSummaryLength) { summaryAppendix = !existingSummaryLength ? summaryAppendix.replace(",", " and") : "and " + summaryAppendix; }
								else if (summaryAppendix.split(",").length > 2 - existingSummaryLength) { summaryAppendix = summaryAppendix.slice(0, summaryAppendix.lastIndexOf(",") + 1) + " and" + summaryAppendix.slice(summaryAppendix.lastIndexOf(",") + 1); }
								if (!$('#wpMinoredit').checked) {
									$('#wpMinoredit').prop( 'checked', true );
								}
							}
							editor.appendEditSummary(summaryAppendix);
							setWatchlistExpiryForCleanup(0, performance.now());
							summaryAppendix = "";
						}
						editor.clickDiff();
						reportCompletion("completed NBSP cleanup operation", (performance.now() - startTime).round(3), 'info', 'complete-nbsp-cleanup', 'NaN');
					}
				},
				{
					name: 'Insert MiszaBot config',
					template: '{{User:MiszaBot/config\n| algo                = old(30d)\n| archive             = {{SUBST:FULLPAGENAME}}/Archive %(counter)d\n| counter             = 1\n| maxarchivesize      = 150K\n| archiveheader       = {{Automatic archive navigator}}\n| minthreadstoarchive = 1\n| minthreadsleft      = 4\n}}', //[[User:MiszaBot/config]]
					position: 'cursor',
					editSummary: 'WARNING: The magic word FULLPAGENAME does not work when the article title contains special characters (\"&\').',
					editSummaryPosition: 'after',
					script: function() {
						if (!($('#wpSummary').val().length || /^(?:\s*\/\*(?:(?!\*\/)(?:.|\r|\n))*\*\/\s*)+$/.test($('#wpSummary').val())) && $('#wpMinoredit').checked) {
							$('#wpMinoredit').prop( 'checked', false );
						}
					}
				},
				{
					name: 'Insert parser function–wrappable {{Test case|_format=tablerows}} replacement',
					template: '<!-- Test # -->\n{{indent|2}}<code><nowiki>{{#expr:{{formatnum:{{{{SUBST:BASEPAGENAME}}}}|R}}/1e6 round 0}} million</' + 'nowiki></code>\n\n{| style="text-align: left;"\n|-\n! scope="row" | \'\'\'{{tl|Anderjef}}\'\'\'\n| style="padding:0 1em" | {{Right-arrow}}\n| {{#expr:{{formatnum:{{Template:Anderjef}}|R}}/1e6 round 0}} million\n|-\n! scope="row" | \'\'\'{{tl|Anderjef/sandbox}}\'\'\'\n| style="padding:0 1em" | {{Right-arrow}}\n| {{#expr:{{formatnum:{{Template:Anderjef/sandbox}}|R}}/1e6 round 0}} million\n|}</syntaxhighlight>', //string is broken at closing nowiki tag to avoid throwing off Wikipedia wherever this document is loaded
					position: 'cursor',
					script: function() {
						if (!($('#wpSummary').val().length || /^(?:\s*\/\*(?:(?!\*\/)(?:.|\r|\n))*\*\/\s*)+$/.test($('#wpSummary').val())) && $('#wpMinoredit').checked) {
							$('#wpMinoredit').prop( 'checked', false );
						}
					}
				}
			],
			{ forActions: 'edit' }
		);
	});
});
// </nowiki>
importScript('User:SuperHamster/CiteUnseen.js'); // Backlink: [[User:SuperHamster/CiteUnseen.js]]
importScript('User:Novem_Linguae/Scripts/CiteHighlighter.js'); // Backlink: [[User:Novem_Linguae/Scripts/CiteHighlighter.js]]
importScript('User:Headbomb/unreliable.js'); // Backlink: [[User:Headbomb/unreliable.js]]