User:Perhelion/simpleSVGcheck.js

From Wikimedia Commons, the free media repository
Jump to navigation Jump to search
Note: After saving, you have to bypass your browser's cache to see the changes. Internet Explorer: press Ctrl-F5, Mozilla: hold down Shift while clicking Reload (or press Ctrl-Shift-R), Opera/Konqueror: press F5, Safari: hold down Shift + Alt while clicking Reload, Chrome: hold down Shift while clicking Reload.
/**
* @Remarks
* Since Perhelion had quitted Wikipedia, this script is still much used; and maintenance is necessary.				//ed_
* Because nobody else did it, I tried some reparations and enhancements; the problem is: I have no JS knowledge.	//ed_
* It can be seen that I made a lot of helpless tries, marked all with  //ed_										//ed_
* It can well be seen that I fight heavily with JS and made things much more complicated							//ed_
* than an expert would have done it. Some things that I made function - more or less. Others don't.					//ed_
* 
* 
* @Description:
* Adds several SVG-valid-check-links on file-pages. Get the real byte-size for SVG-images. Put the template Igen prefilled in the file-description page.
* 14.07.2016 added tool-name recognition from SVG-code
* For usage show [[c:Template:Image generation]]
* @Revision: 12:00, 08 September 2020 (UTC) by Perhelion
* @Last Revision: 18:00, 09 July 2021  ๐Ÿ’ƒ๐Ÿ’ƒ๐Ÿ’ƒ๐Ÿ’ƒ๐Ÿ’ƒ๐Ÿ’ƒ๐Ÿ’ƒ๐Ÿ’ƒ๐Ÿ’ƒ๐Ÿ’ƒ๐Ÿ’ƒ๐Ÿ’ƒ๐Ÿ’ƒ๐Ÿ’ƒ๐Ÿ’ƒ๐Ÿ’ƒ Sarang
* @Author: [[User:Perhelion]], together featured with [[User:Sarang]]
* @License: CC BY-SA 3.0
* @Required modules: jquery.badge, mediawiki.api, mediawiki.util, jquery.spinner
* @TODO:
**/
// [[Category:User scripts|simpleSVGcheck]] <nowiki>
/* eslint-env es6*/
/* global mediaWiki, OO, importScript */
(function ($, mw) {
'use strict';
let gbs = [],
c = mw.config.get([
			'wgAction',
			'wgPageName',
			'wgTitle',
			'wgUserLanguage',
			'wgUserName' // For simplSVG
		]),
isEdit = /^(edit|submit)$/.test(c.wgAction),
err,
// size, // For simplSVG
toolName,
$textarea,
expeUser = /^Sarang|Sarangbot|JoKalliauer|Perhelion$/.test(c.wgUserName),
summary = '[[User:Perhelion/simpleSVGcheck.js|Script]]+[[Template:Image generation|Template]]',

cSVG = {
	// When maintaining this script always bump this number!
	version: '0.5.7',
	name: 'simpleSVGcheck',
	failStr: 'FAIL automatic insert', // Igen, please insert manually
	curSize: 0,
	textPath: 0,
	badSVG: 0,
	PGF: 0,
	switchTrans: 0,
	init: function () {
		// W3C-Validator check-link for every SVG (by [[User:Perhelion]] fixed also now for admins)
		let $g = $('<a>', {
				title: 'Get exact byte-size'
			}).badge('B?', 'inline', 1),
		$igen,
		/* = $('<a>', {
		title: 'Insert Template:Image_generation with W3-Validity',
		href: '#',
		text: 'โ†’SVG-Igen',
		click: mw.libs.simpleSVGcheck.getW3Data
		Uri <- Also
		})*/
		$SVGc = $('<a>', {
				title: 'Commons-libRSVG-Validator',
				href: '/wiki/Commons:Commons_SVG_Checker?withJS=MediaWiki:CommonsSvgChecker.js&checkSVG=' + encodeURIComponent(c.wgPageName),
				text: 'โ†’SVG Checker',
				target: '_blank'
			}),
		$rows = $('#mw-imagepage-section-filehistory').find('tr').slice(1),
		$t1 = $rows.first();

		$igen = $(mw.libs.commons.ui.addEditLink('', 'โ†’SVG Igen', 'e-igen', 'Insert Template:Image_generation with W3C-validity')).find('a')
			.on('click', mw.libs.simpleSVGcheck.getW3Data);

		$t1.children('td').slice(-3, -2).append(['<br>', $igen.clone(true)]);
		$t1.find('td[style]').append(['<br>', $SVGc]);
		$rows.each(function (i) {
			let $t = $(this);
			$t.find('td[style]>a:first').after(function () {
				let linkTxt = 'โ†’Valid SVG',
				file = $(this).attr('href'),
				// var href = "http://validator.w3.org/check?uri=" + $(this).attr("href") + "&group=1"; // there is an discrepance in automatic check

				href = 'https://validator.nu/?doc=' + file + '&group=1&schema=http%3A%2F%2Fs.validator.nu%2Fsvg-xhtml5-rdf-mathml.rnc+http%3A%2F%2Fs.validator.nu%2Fhtml5%2Fassertions.sch+http%3A%2F%2Fc.validator.nu%2Fall%2F&parser=xml',

				a = $('<a>', {
						title: 'W3C-Nu-Validator',
						href: href,
						target: '_blank'
					});
				return ['<br>', a.text(linkTxt),
					a.clone().attr('href', href + '&showsource=1#result').text(' (+src)?')
					// ,"<br>",a.clone().attr("href", "http://validator.w3.org/check?uri=" + file + "&group=1&ss=1").text( "(โ†’old W3-check)" )
				];
			});
			$t.children('td').slice(-3, -2).children('span').after(function () {
				if (!/Byte/.test(this.textContent)) {
					let $gb = $g.clone();
					gbs.push($gb.attr('name', i).click(cSVG.getImgData));
					return $gb;
				}
				gbs.push('');
			});
		});
	},

	getImgData: function () {
		mw.loader.using(['mediawiki.api'], function () {
			new mw.Api().get({
				prop: 'imageinfo',
				iiprop: 'user|size', // |archivename
				iilimit: 9, // max requested images
				titles: c.wgPageName,
				formatversion: 2
			}).done(function (json) {
				if (!json || !json.query || !json.query.pages || !json.query.pages[0])
					return;
				let p = json.query.pages[0];
				let data = [];
				for (let i = 0; i < p.imageinfo.length; i++)
					data.push(p.imageinfo[i].size);
				c.wgUserName = p.imageinfo[0].user; // global var
				cSVG.setImgSize(data);
			});
		});
	},

	warnMsg: function (w) {
		mw.loader.using([], function () {
			if (typeof w === 'number') {
				return mw.notify('SVG file is with ' + w + ' error' + ((w === 1) ? '' : 's') + ' not valid! ', {
					title: 'W3-Validity-check',
					type: 'warn'
				});
			}

			if (w instanceof Object)
				return mw.notify(cSVG.failStr + '!', w);
			mw.notify(w + ' Please check manually again with the web-service.', {
				title: 'W3-Validity-check warning!',
				type: 'error',
				autoHideSeconds: 7
			});
		});
	},

	getW3Data: function (e) {
		if (e && e.preventDefault)
			e.preventDefault();
		// FIXME: maybe use also Rillke Bot
		if (isEdit) {
			$('#editform').prepend($.createSpinner({
					id: 'w3nu',
					size: 'large',
					type: 'block'
				}));
			if (cSVG.err)
				return cSVG.addToFileDesc($textarea, cSVG.err, '', cSVG.toolName);
		}
		let file = '';
		if (!(isEdit && e instanceof Object)) {
			file = $('#file > a:first'); // fullImageLink
			if (!file.length)
				$(this).parent().prev().find('a'); // thumb preview, may superfluous
			if (file.length)
				file = file.attr('href');
		}
		if (!file || !/SVG$/i.test(file))
			file = 'https:' + mw.config.get('wgServer') + '/wiki/Special:Filepath/' + c.wgTitle.replace(' ', '_');
		// console.log(typeof e, e.nodeName , file );

		/* https://validator.w3.org/docs/api.html */
		// only once
		if (cSVG.xhr)
			return cSVG.addToFileDesc($textarea, -1);

		cSVG.xhr = $.getJSON('https://validator.w3.org/nu/', {
				'out': 'json',
				'showsource': 1, // for check tool-name
				// "charset" : "UTF-8",
				'doctype': 'SVG 1.1 + URL + XHTML + MathML 3.0', // SVG+1.1+%2B+URL+%2B+XHTML+%2B+MathML+3.0
				'parser': 'xml',
				'user-agent': 'W3C_Validator/1.3 http://validator.w3.org/services', // W3C_Validator%2F1.3+http%3A%2F%2Fvalidator.w3.org%2Fservices
				'schema': 'http://s.validator.nu/svg-xhtml5-rdf-mathml.rnc http://s.validator.nu/html5/assertions.sch http://c.validator.nu/all/',
				'doc': file
			}
				// https://validator.w3.org/docs/users.html#Options
				// $.getJSON("https://validator.w3.org/check?uri=" + file + "&ss=1&output=json" // CORS-Kopfzeile 'Access-Control-Allow-Origin' fehlt
			).done(
				function (json) {
				let data = json.messages;
				if (!data || !json.source || !json.source.code)
					return cSVG.warnMsg('Fail to read file ' + json);
				let code = json.source.code,
				doctype = /<!DOCTYPE svg/i.test(code),
				err = [],
				warn = [],
				warnRDF = 'This validator does not validate RDF.', // FIXME only discrepance if <!DOCTYPE present
				para = {}; // Parameter 5
				para.curSize = code.length;
				para.badSVG = /[<:]image[\s>]/.test(code);
				para.PGF = /<i:pgf[ \n]|[^#]adobe_illustrator_pgf/.test(code);
	//			para.PGF = /<i:pgf[ \n]|[^#]adobe_illustrator_pgf|\!\[CDATA/.test(code);	// pgf cdata 
				let toolName = cSVG.toolName = cSVG.getToolName(code, para.PGF);
				if (!(para.badSVG && para.PGF)) {
					para.switchTrans = / systemLanguage/.test(code); // /[<:]switch[\s>]/;
					para.textTrans = /[^>]\s?(<\/tspan>)?\s?<\/text>/.test(code);
					if (para.switchTrans)
						para.switchTrans = para.textTrans;
					else
						para.switchTrans = 0;
					if (para.switchTrans && !expeUser)
						para.textTrans = 0;
				}
				if (para.badSVG && !/[<:](path|text)[\s>]/.test(code))
					para.badSVG = 2; // Fake SVG
				if ((toolName === 'inkscape' || toolName === 'IA') && code.indexOf('aria-label=') > 20)
					para.textPath = 1; // textPath

				for (let i in data) {
					// console.log(i, data[i], doctype); // data.messages is an array
					json = data[i].type;
					if (!json)
						continue;
					if (json === 'error')
						err.push(data[i].message);
					else if (json === 'info' && data[i].subType === 'warning')
						warn.push(data[i].message);
				}
				err = err.length;
				let w = warn.length;

				if (w && doctype) {
					while (w--) {
						if (!warn[w].indexOf(warnRDF)) {
							warn = warnRDF;
							warnRDF = '';
							break;
						}
					}
				}
				// console.log("Successfully checked for SVG errors ", err, w, warn.length, warnRDF); // error messages
				if (isEdit) {
					if (!(err || warnRDF))
						cSVG.warnMsg(warn);
					$.extend(cSVG, para);
					return cSVG.addToFileDesc($textarea, err, warn, toolName);
				} else if (!(err || warnRDF)) {
					cSVG.warnMsg(warn);
					setTimeout(function () {
						cSVG.addIgenURL(err, '', toolName, para);
					}, 4000);
				} else {
					cSVG.addIgenURL(err, '', toolName, para);
				}
			}).fail(function (e) {
				mw.log.warn('Ajax error to ', e);
				if (isEdit)
					return cSVG.addToFileDesc($textarea, -1);
			});
		return false;
	},

	/**
	 * Gets the tool name from SVG code.
	 *
	 * @param      {string}		code
	 * @param      {boolean}	toolName
	 * @return     {string}		tool name
	 */
	getToolName: function (code, toolName) {
		// TODO can be extended
		let toolList = [
			'geogebra',
			'sodipodi',
			'Sketch',
			'ShareMap',
			'openoffice',
			'libreoffice',
			'inkscape',
			' potrace', // + whitespace
			' graphviz', // + whitespace
			' dot version 2.2.1', // ??
			'QGIS',
			'MetaPost',
			'MATLAB',
			'Illustrator',
			'Gnuplot',  'GNUPLOT',
			'fig2svg',
			'EazyDraw',		// Peter coxhead
			'CorelDRAW',
			'ElCompLib',	// ed_wdh
			'Method Draw',	// Cookieman1.1.1
			'Chemtool',
			'ChemSketch',	// ChristianBausW	
			'bkchem',
			'Batik',
			'ArcMap',
			'Adobe',
	//		'parliament diagram creator'],
			'Generated with Qt',			// <desc>Generated with Qt</desc>
			'baseProfile="full"',			// when nothing else can be used - only hint for GeoGebra
			'parliament'],
		i = toolList.length;

		toolName = toolName ? 'Adobe' : '';
		while (i-- && !toolName) {
			if (code.indexOf(toolList[i]) + 1) {
				toolName = toolList[i];
				break;
			}
		}
		if (!toolName) { // Guess tool, boilerplate in every Illustrator SVG export
			i = /<svg [^>]+>/i.exec(code); // Root
			if (i) {
				if (i[0].indexOf('enable-background') + 1)
					toolName = 'Adobe';
				if (i[0].indexOf('id="svg2"') + 1)
					toolName = toolName ? 'IA' : 'I';
			}
		} else if (toolName === 'inkscape' &&
			/(inkscape:grid|sodipodi:(guide|cx))/.test(code)) {
			toolName = 'Im';
		} // IMPORTANT=yes
		// Mixtures
		if ((/^[Aa]dobe|Illustrator/.test(toolName) && /[Ii]nkscape/.test(code)) || (/^[Ii]nkscape/.test(toolName) && /[Aa]dobe|Illustrator/.test(code)))
			toolName = 'IA';

		return toolName;
	},

	setImgSize: function (data) { // get & set file size
		$.each(gbs, function (i) {
			$(this).prev().remove();
			// no link for first
			if (this && this[0].name !== '0') {
				return $(this).text('โ†’' + data[i])
				.attr('title', 'Insert Template:Igen with actual simple size: ' + data[0])
				.off('click')
				.click(function (/* e*/) {
					cSVG.addIgenURL('0', [data[i], data[0]]);
				});
			}
			// first badge link only for display
			return $(this).replaceWith(data[0] + ' Byte');
		});
	},

	/* registerModules: function() { // Register custom modules
	if ( !mw.loader.getState('mediawiki.commons.MwJSBot') ) mw.loader.implement('mediawiki.commons.MwJSBot', ["//commons.wikimedia.org/w/index.php?action=raw&ctype=text/javascript&title=User:Rillke/MwJSBot.js"], {
	}, {
	});
	},
	run: function() { // Create GUI
	cSVG.registerModules();
	mw.loader.using(['mediawiki.commons.MwJSBot'], function() {
	});
	}, */

	setIgen: function (pre, post) {
		$textarea.textSelection('encapsulateSelection', {
			pre: pre,
			// peri: '',
			post: post
		});
	},

	replaceTag: function (txt, err, toolname) {
		if (!txt)
			return;
		let size = this.size,
		txT = txt, // for test
		imRE = /^\s*\| *[Oo]ther[_ ]fields *=\s*\{\{[Ii]mgen\|(\w+)\}\} *$/m,
		coa = /\{\{COAInformation\s*\|\s*/.test(txT), // coat of arms template boolean
		imgenRE = /\|\s*[Ii](?:m?gen|mage generation) *=\s*[^\s]+ *\n/,
		imgen = ((coa && imgenRE.test(txT)) || imRE.test(txT)),
		toolName = '', // default nothing, most possible is Inkscape
		// sourcecode, // possible from which are generated for "Created with code"
		g = '', // specify the Graphic lab
		T = '', // additional trailing text for templates (extension)
		p5 = '', // Parameter 5
		r = '', // retouched
		s = '', // suffix for subcat
		s1 = '', // leading whitespaces as indent?
		s2 = '', // whitespace on parameter?
		ls = '', // last substring index
		topp = '', // template igen on topposition
		replaced = false,
		LeyoChem = false,
		ofRE = /( )*\|\s*[Oo]ther[_ ]fields( )*=\s*([^\n]*\n)/g,
		inRE = [
			/\{\{(COA)?[Ii]nformation\s*\|\s*/,
			/( )*\|\s*[Pp]ermission( )*=\s*[^\n]*\n/,
			/( )*\|\s*[Oo]ther[_ ]versions( )*=(\n?[^\n]*\n)/
		],
		IgenName = '{{Igen|',
		IgenNameLong = '{{Image generation|',
		tempPre = '}}\n',
		user = '', // for u=
		// Normalized toolnames different to code
		toolNames = {
			'Fig2svg': 'Fig2SVG',
			'Illustrator': 'Adobe',	'Adobe Illustrator': 'Adobe',
			'bkchem': 'BKchem', 	'Bkchem': 'BKchem', 
			'Libreoffice': 'LibreOffice',
			'geogebra': 'GeoGebra',	'BaseProfile="full"': 'GeoGebra',
			'Openoffice': 'OpenOffice.org',
			'Generated with Qt': 'Qt',
			' potrace': 'Potrace',
			' graphviz': 'Graphviz',
			' dot version 2.2.1': 'Graphviz'
		},
		
		// Toolname abbreviations (experienced users only)
		toolAbbr = {
			'Adobe': 'A',
			'Adobe-hand': 'AH',
			'Inkscape': 'I',
			'Inkscape-hand': 'H',
			'BKchem': 'B',			// ed_sf
			'ChemDraw': 'C',		// ed_sf
			'CorelDraw': 'D',
			'CorelDRAW': 'D',
			'Fig2SVG': 'F',
			'Gnuplot': 'G', 'GNUPLOT': 'G',
			'LibreOffice': 'L',
			'OpenOffice.org': 'OOo',
			'Parliament': 'Wpdc'
		},
		// Full replace - use templates:W		Expand this table when there are more (W)ikilink templates 
		Langtab = {
			"en" :	"W" ,
			"ar" :	"WA" ,
			"bn" :	"Wb" ,
			"ca" :	"WC" ,
			"cs" :	"Wc" ,
		//	"da" :	"Wda" ,
			"de" :	"Wd" ,
		//	"el" :	"Wel" ,
		//	"eo" :	"Weo" ,
			"es" :	"We" ,
			"fa" :	"Wfa" ,
		//	"fi" :	"Wfi" ,
			"fr" :	"Wf" ,
			"gl" :	"Wg" ,
			"hu" :	"Wh" ,
			"he" :	"Whe" ,
		//	"id" :	"Wid" ,
			"it" :	"Wi" ,
			"ja" :	"Wๆ—ฅ" ,
			"kn" :   "เฒตเฒฟ" ,
			"ko" :	"W๋ง" ,
		//	"lt" :	"Wlt" ,
		//	"lv" :	"Wlv" ,
			"mk" :	"Wm" ,
			"ml" :   "เดตเดฟ" ,
			"nl" :	"Wn" ,
		//	"nn" :	"Wnn" ,
		//	"no" :	"Wno" ,
			"pl" :	"WP" ,
			"pt" :	"Wp" ,
			"ru" :	"Wr" ,
			"si" :   "เท€เท’" ,
			"sl" :	"Wsl" ,
			"su" :	"Wsu" ,
			"sv" :	"Wsv" ,
			"th" :	"Wth" ,
			"tr" :	"Wtr" ,
			"uk" :	"Wu" ,
			"zh" :	"Wz"
		};

		/*
		 * t instanceof RegExp
		 * return the end-index "topp" of info template before brackets
		 * ============================================================
		 */

		 
		function encodeAlsoComponent(str) {
		   return encodeURIComponent(str).
		       replace(/[%'()]/g, escape); // i.e., %25 %27 %28 %29
		 }

		function _findPosition(t) {
			let p = 0; // end of info template
			let arr;
			let li = 0;
			let str;
			let RE = /[\s\S]+?\n\}\}\n/g;
			// sometimes index = 0
			t = t.lastIndex ? t.lastIndex - RegExp.lastMatch.length : txt.search(t);
			str = txt.substr(t);
			s1 = RegExp.$1 || s1;
			s2 = RegExp.$2 || s2;
			// Try to go at template end (fallback risky if another template ends in same way)    ed_wd 
			// often wrong position when 
			while ((arr = RE.exec(str)) !== null) {
				let m = arr[0];
				li = arr.index;
				p = m.lastIndexOf("{{");
				if (m && (p === -1 || (p = m.indexOf("}}", p)) !== -1 && p < m.length - 3)) {
					p = li + m.length - 3;
					str = "";
					break;
				} else
					p = 0;
			}
			if (!p) {
				p = str.search(/\n?\}\}$\n/m); // \s is trimmed before
				if (RegExp.lastMatch.length === 3) {
					txt = txt.substr(0, t + p) + '\n' + txt.substr(t + p);
					p++;
				}
			}

			t = (p >= 0) ? t + p : 0;
			return t;
		}
	//	 * ============================================================
		function _ucfirst(s) { // Uppercase
			return s.slice(0, 1).toUpperCase() + s.slice(1);
		}
	//	 * ============================================================

		function generalCleanup(text) {
			// TODO: namespace User could be extended with any language
			// lowercase parameter name default, trim leading whitespace
			if (inRE[0].test(text)) {
				text = text.replace(/^( *)\|\s*([A-Z][^=\n{}|?!.]+ *=)/gm,
						function (m, p1, p2) {
						return p1 + '|' + p2.toLowerCase();
					});
			}
			// For AutVec and Own based
			let fileTruncate = function (m, p1) {
				// Shorten parameter if names are the same (currently only 3 letter ext are supported)
				let fExt = p1.slice(-4),
				fName = p1.slice(0, -4);
				fName = (fExt[0] === '.' && fName === c.wgTitle.slice(0, -4)) ? fExt : p1;
				fName = fName === '.png' ? '.' : fName;
				return m.replace(p1, fName);
			};
	/*	---------------- blocks
			// For AutVec, Own based, F, File, Filelist, Other versions, Derived from, Derivative versions; Retouched
			let fileTruncate = function (m, p1) {
				// Shorten parameter if names are the same - currently only 3 (or 4) letter ext is supported
				p1    = p1.trim(); 
				let fExt = p1.slice(-4),
				fEx4  = p1.slice(-5),
				fName = p1.slice(0, -4);
				fName = fName.substring(0, 5) === 'File:'  ? fName.substring(5 ) : fName;		//ed_wdh -
				fName = fName.substring(0, 5) === 'file:'  ? fName.substring(5 ) : fName;		//ed_wdh -
				fName = fName.substring(0, 6) === 'Image:' ? fName.substring(6 ) : fName;		//ed_wdh -
				fName = fName.substring(0, 6) === 'image:' ? fName.substring(6 ) : fName;		//ed_wdh -
				fwebp = (fEx4[0] === '.' && fName === c.wgTitle.slice(0, -5)) ? fExt : p1;		//ed_wdh -
				fName = (fExt[0] === '.' && fName === c.wgTitle.slice(0, -4)) ? fExt : p1;
				fName = fName === '.png' ? '.' : fName;
				fName = fName === '.gif' ? '.g' : fName;		// ed_wdh: 
				fName = fName === '.jpg' ? '.j' : fName;		// ed_wdh: 
				fName = fName === '.svg' ? '.s' : fName;		// ed_wdh: 
				fName = fName === '.tif' ? '.t' : fName;		// ed_wdh: 
				fName = fName === '.xcf' ? '.x' : fName;		// ed_wdh: 
				fName = fwebp === '.webp' ? '.w' : fName;		// ed_wdh: 
				return m.replace(p1, fName);
				};
	*/
			return text
			.replace(inRE[2], '$1|other versions$2=$3') // standardize

		.replace (/( *\| *[Dd]ate *= *\d{4}-\d{2}-\d{2}) \d{2}:\d{2}(?::\d{2})?(?: \(UTC\))?/g, '$1') // ed_wdh: clock does not belong to date
// restore falsified parameter names:
			.replace(/(\|\s*)svg(?= tool\s*=)/g, '$1 SVG')				// ed_wdh: undo
				.replace(/(\|\s*)tool(?=\s?name\s*=)/g, '$1 Tool')		// ed_wdh: undo
				.replace(/(\|\s*)other(?=\s?tool\s*=)/g, '$1 Other')	// ed_wdh: undo
			.replace(/(\|\s*)w3c(?= error count\s*=)/g, '$1 W3C')		// ed_wdh: undo
			.replace(/(\|\s*)topic(?=\s*=)/g, '$1 Topic')				// ed_wdh: undo
			.replace(/(\|\s*)text(?= embedded\s*=)/g, '$1 Text')		// ed_wdh: undo
			.replace(/(\|\s*)text(?= as path\s*=)/g, '$1 Text')			// ed_wdh: undo
			.replace(/(\|\s*)text(?=edit only\s*=)/g, '$1 Text')		// ed_wdh: undo
			.replace(/(\|\s*)draw(?= by hand\s*=)/g, '$1 Draw')			// ed_wdh: undo
			.replace(/(\|\s?)user(?=link\s*=)/g, '$1 User')				// ed_wdh: undo
// shorten indentions:
			.replace(/\|tincture       = ?/, '|tincture    =')   // ed_wdh (ls)
			.replace(/\|blazon of      = ?/, '|blazon of   =')   // ed_wdh (ls)
			.replace(/\|blazon         = ?/, '|blazon      =')   // ed_wdh (ls)
			.replace(/\|references     = ?/, '|references  =')   // ed_wdh (ls)
			.replace(/\|description    = ?/, '|description =')   // ed_wdh (ls)
			.replace(/\|date           = ?/, '|date        =')   // ed_wdh (ls)
			.replace(/\|source         = ?/, '|source      =')   // ed_wdh (ls)
			.replace(/\|author         = ?/, '|author      =')   // ed_wdh (ls)
			.replace(/\|artist         = ?/, '|artist      =')   // ed_wdh (ls)
			.replace(/\|permission     = ?/, '|permission  =')   // ed_wdh (ls)
			.replace(/\|other fields *= ?/, '|other fields=')   // ed_wdh (ls)

//		remove the "1=" when text is without "="
	//	1) plain text without equal sign		โœ“
	//	2) plain text with equal sign			โœ“
	//	3) text with templates -  ignore "=" in template 	-no-
	//	4) any series of text and templates - ignore "=" in template but not in text	-no-

//		.replace(/(\{\{\w\w\w? ?\|) ?1 ?=([^=\}]+\})/g, '$1$2')		// remove when no '='

	
	/*	//	 clean text switch part of files treated with toolforge translator
		//	 =================================================================
	.replace(/<\/text><text>/g, '</text>\n<text>')   // ed_wdh (insert newline)
//	.replace(/<text id="trsvg[^"]+"><tspan id="trsvg[^"]+">([^<]+)<\/tspan><\/text>/g, '<text>$1</text>')   // ed_wdh
	.replace(/ id="trsvg[^"]+"><tspan id="trsvg[^"]+">([^<]+)<\/tspan><\/text>/g, '>$1</text>')   // ed_wdh
	.replace(/<\/tspan><tspan x="(\d+)" y="(\d+)" id="trsvg[^"]+">([^<]+)<\/tspan><\/text>/g, '</tspan><tspan x="$1" y="$2">$3</tspan></text>')   // ed_wdh 
	.replace(/<text(?: id="trsvg[^"]+")? systemLanguage="(\w+)"(?: id="trsvg[^"]+")?><tspan id="trsvg[^"]+">([^<]+)<\/tspan><\/text>/g, '<text systemLanguage="$1">$2</text>')   // ed_wdh
	.replace(/<text(?: id="trsvg[^"]+")? systemLanguage="(\w+)"(?: id="trsvg[^"]+")?><tspan id="trsvg[^"]+">([^<]+)<\/tspan><tspan([^<]+)<\/tspan><\/text>/g, '<text systemLanguage="$1">$2</tspan><tspan>$3</tspan></text>')   // ed_wdh 
	*/

		// now simplify [[namespace: ...]] to the template transclusion {{N| ...}}
		// =======================================================================
		// namespaces: ns 0 = :W, ns 2 = U, ns 6 = :F, ns 10 = T, ns 14 = :C, ns 828 = M
/* replace: [[ns:link]]         -> {{N|link}}           one param
 *			[ns:link|name]]		-> {{N|link|name}}      two params
 *         
 *          [[ns:lx:link]]      -> {{N|link||lx}}       one param  plus language (two pipes)
 *          [[ns:lx:link|name]] -> {{N|link|name|lx}}   two params plus language

 *			[[ns:Link|Link]]    -> {{N|Link}}           two params, but 2nd is same
 *			[[ns:link|linkxyz]] -> {{N|link}}xyz        two params, but 2nd is 1st with suffix
                                    analog with language code
 *			[[ns:Link|link]]    -> {{N|link}}           two params, but 2nd is lcfirst
 *    		[[ns:link|Link]]    -> {{N|Link}}           two params, but 2nd is ucfirst
                                    analog with language code
 *			[[ns:lx:Link|linkxyz]]                      combination: same name lowercase,   
 *                              -> {{N|link||lx}}xyz           plus language, plus suffix 
 */

// first all other namespaces - then (as the last one) the namespace 0 
// ===================================================================

		.replace(/\[\[:?(?:[Ww](?:ikipedia)?):([Uu]ser|[Ff]ile|[Tt]emplate|[Cc]ategory|[Mm]odule):/g, '[[:en:$1:')	// ed_wdh: W namespace 
		.replace(/\[\[:?(?:[Ww](?:ikipedia)?):([a-z]{2,3}):/g, '[[:$1:') 		// double interlink - remove useless :w


	//	2  {{U		Wikipedia user links:
		.replace(/\|artist *= *\*?unknown\n\n\* *vectorized by \[\[(Chris die Seele)\]\]/m, '|artist = {{AutVec||$1}}')	// ed_wdh:
 			.replace(/Thom.lanaud/g, 'Thom.Lanaud')		//ed_wdh user writing
 			.replace(/User:Domdomegg/g, 'user:domdomegg')		//ed_wdh user writing
 			
	.replace(/([Uu]ser|[Bb]enutzer|[Ff]ile|[Ii]mage|[Tt]emplate|[Cc]ategory|[Mm]odule): ?(_ucfirst([^\]\|]+?))(\|\2)([^\]]+?)?\]\]/g,  '$1:$3|$3]]$4๐Ÿ’–')	
	.replace(/\[\[(:?[Uu]ser|[Bb]enutzer|[Ff]ile|[Ii]mage|[Tt]emplate|[Cc]ategory|[Mm]odule): ?([^\]\|]+?)\|(_ucfirst(\2))([^\]]+?)?\]\]/g,  '[[$1:$3|$3]]$4๐Ÿ’—')	
 			
				  .replace(/\[\[:?(?:[Uu]ser|Benutzer): ?([^\]\|]+?)(?:\|\1)?\]\]/g, '{{U|$1}}')		// ed_wdh: U [single or same]
				  .replace(/\[\[:?(?:[Uu]ser|Benutzer): ?([^\]\|]+?)\|(.+?)\]\]/g, '{{U|$1|$2}}')		// ed_wdh: U [link & disp]
	.replace(/\[\[:([a-z]{2,3}):(?:[Uu]ser|Benutzer): ?([^\]\|]+?)(?:\|\2)?\]\]/g, '{{U|$2||$1}}')		// ed_wdh: U [single or same]:lg
	.replace(/\[\[:([a-z]{2,3}):(?:[Uu]ser|Benutzer): ?([^\]\|]+?)\|(.+?)\]\]/g, '{{U|$2|$3|$1}}')		// ed_wdh: U [link & disp]:lg

	//	6  {{F			l= for external	
				  .replace(/\[\[:(?:[Ff]ile|[Ii]mage): ?([^\]\|]+?)(?:\|\1)?\]\]/g, '{{F|$1}}')			// ed_wdh: F [single or same]
				  .replace(/\[\[:(?:[Ff]ile|[Ii]mage): ?([^\]\|]+?)\|(.+?)\]\]/g, '{{F|$1|$2}}')		// ed_wdh: F [link & disp]
	.replace(/\[\[:([a-z]{2,3}):(?:[Ff]ile|[Ii]mage): ?([^\]\|]+?)(?:\|\2)?\]\]/g, '{{F|$2||l=$1}}')	// ed_wdh: F [single or same]:lg
	.replace(/\[\[:([a-z]{2,3}):(?:[Ff]ile|[Ii]mage): ?([^\]\|]+?)\|(.+?)\]\]/g, '{{F|$2|$3|l=$1}}')	// ed_wdh: F [link & disp]:lg
// test "by=":
				.replace(/\{\{F\|([^\}]+?)\}\} *by *\{\{U\|([^\}]+?)\}\}/g, '{{F|$1|by={{U|$2}}}}')		// ed_wdh: simplify by=U later
				.replace(/\{\{U\|([^\|]+)\|(?:([^\|]*)?)?\|de\}\}/g, '{{Ud|$1|$2}}')					// ed_wdh: Ud

	// 10  {{T
			.replace(/\[\[(?::?[Tt]emplate): ?([^\]\|]+?)(?:\|\1)?\]\]/g, '{{T|$1}}')					// ed_wdh: T [single or same]
			.replace(/\[\[(?::?[Tt]emplate): ?([^\]\|]+?)\|([^\]\|]+?)\]\]/g, '{{T|$1|$2}}')			// ed_wdh: T
 					.replace(/\{\{[Tt]emplate:/g, '{{')			//ed_wdh written by some users
		.replace(/\[\[:([a-z]{2,3}):(?:[Tt]emplate): ?([^\]\|]+?)(\|[^\]]+?)?\]\]/g, '{{T|$2$3|$1}}')	// ed_wdh: T [link & disp]:lg

	// 14  {{C
		.replace(/\[\[(?::[Cc]ategory): ?([^\]\|]+?)(?:\|\1)?\]\]/g, '{{C|$1}}')			// ed_wdh: C [single or same]
		.replace(/\[\[(?::[Cc]ategory): ?([^\]\|]+?)\|([^\]\|]+?)\]\]/g, '{{C|$1|$2}}')		// ed_wdh: C

	//828  {{M
		.replace(/\[\[(?::?[Mm]odule): ?([^\]\|]+?)(?:\|\1)?\]\]/g, '{{M|$1}}')				// ed_wdh: M [single or same]
		.replace(/\[\[(?::?[Mm]odule): ?([^\]\|]+?)\|([^\]\|]+?)\]\]/g, '{{M|$1|$2}}')		// ed_wdh: M

	//	0  {{W    	 Wikipedia interwikilinks: ๐Ÿฎ (๐Ÿ”…๐Ÿ”†)
	.replace(/\[\[:?(?:[Ww](?:ikipedia)?:)(?:([a-z]{2,3}):) ?([^\]\|]+?)(?:\|\2)?\]\]/g, '{{W|$2||$1}}')	// ed_wdh: W [single/same]
	.replace(/\[\[:?(?:[Ww](?:ikipedia)?:)(?:([a-z]{2,3}):) ?([^\]\|]+?)\|(.+?)\]\]/g, '{{W|$2|$3|$1}}')	// ed_wdh: W [link & disp] 
	.replace(/\[\[:?(?:[Ww](?:ikipedia)?:) ?([^\]\|]+?)(?:\|\1)?\]\]/g, '{{W|$1||en}}')		// ed_wdh: W:en [single/same]
	.replace(/\[\[:?(?:[Ww](?:ikipedia)?:) ?([^\]\|]+?)\|(.+?)\]\]/g, '{{W|$1|$2|en}}')		// ed_wdh: W:en [link & disp] 
 
	.replace(/\[\[:(?:([a-z]{2,3}):)?(?:[Ww](?:ikipedia)?:)? ?([^\]\|]+?)(?:\|\2)?\]\]/g, '{{W|$2||$1}}')	// ed_wdh: W [single/same]
	.replace(/\[\[:(?:([a-z]{2,3}):)?(?:[Ww](?:ikipedia)?:)? ?([^\]\|]+?)\|(.+?)\]\]/g, '{{W|$2|$3|$1}}')	// ed_wdh: W [link & disp]  

 	.replace(/\{\{(W|U|Ud|[FTCM])\|([^\|\}]*)\|([^\}\|]+)?\|?([a-z]{2,3})?\}\}/g, function (m, ns, link, disp, lang)//  = '') 
		{	if (!disp || disp === '')		disp =  link;		// same for default (later stripped)
		 	if (!lang)	 lang =  '';
 			if (lang !== '')				lang = "|" + lang;	// pipe only when present

 			let ssts = "";									// sub-string suffix
			if (link.length <= disp.length) {
 	 			for (let i = 1; i < link.length; i++)
  				{	if ( link.substring(i, i+1) === "_")  
  						link = link.substring(0, i) + " " + link.substring(i + 1);	// replace 
  					if ( disp.substring(i, i+1) === "_")  
  						disp = disp.substring(0, i) + " " + disp.substring(i + 1);	// replace, except {{U}}
  				}
	
 				ssts += disp.substring(0, link.length);	// part of possible sameness
 				if (ssts ===  link
				 || ssts ===  link.substring(0,1).toUpperCase() + link.substring(1)
				 || ssts ===  link.substring(0,1).toLowerCase() + link.substring(1)  )
 				{	link = ssts;					// case_correct from disp
 					ssts = "" + disp.substring(link.length, disp.length);	// suffix
 					disp = "";						// strip 
 				} 
 				else ssts = "";						// without suffix
 			}
		 	if (disp !== "" || lang !== "")		disp = "|" + disp; 
			return "{{" + ns + "|" + link  + disp + lang + "}}" + ssts;
		})

		// Full replace (was not intentional by oalb) using Langtab
	.replace(/\{\{[Ww]\|([^\|\}]*?)(?:\|\||(\|[^\|]*?)\|)([a-z]{2,3})\}\}/g, function (m, link, disp, lang)// = "")
		{	if (!disp)	 disp =  "";
		 	if (!lang)	 lang =  "";
			let diss = "" + disp;
			if (diss === "")		diss =  "|";
			let ns = lang;
			ns = Langtab[lang] ? Langtab[lang] : lang;
			if (ns !== lang) 
				return "{{" + ns + "|" + link  + disp + "}}";		// language replaced๐Ÿ”บ
			else
				return "{{W|" + link  + diss + "|" + lang + "}}";	// language not found 
		})

			.replace(/\|by=\{\{U\|([^\|\}]+?)\}\}/g, '|by=$1')		// ed_wdh: simplify by=U
			.replace(/(XY \(siehe Dateiname\)|[Xx][Yy] ? \(see filename\))/g, '{{F|F}}')	// ed_wdh: 'XY' TUBS
			.replace(/von  \{\{F\|F\}\}/g, 'von {{F|F}}')			// ed_wdh: TUBS doublespace
			.replace(/(XY \(ะดะธะฒ. ะฝะฐะทะฒัƒ ั„ะฐะนะปัƒ\))/g, '{{F|F}}')						// ed_wdh: 'XY' TUBS
			.replace (/\{\{AutVec\|o\=\{\{Creator/, '{{AutVec|{{Creator') 			// ed_wdh
			.replace(/\(?\[\[[Uu]ser[ _]talk: ?([^\]|[]+)\|?[^\][]*\]\]\)?/g, '')	// ed_wdh: User talk - only when not stand-alone 
			.replace(/\[\[Category:Location not applicable ?(\|[^\n\]]+)?\]\]\n*/, '')
			.replace (/\{\{([Ll]ocation) (?:dms|dec)/g, '{{$1') 			// ed_wdh
			.replace (/\{\{([Kk]oordynaty)/g, '{{Location') 				// ed_wdh
		.replace(/\[\[Category:Created with ShareMap ?(\|[^\n\]]+)?\]\]\n*/, '')	// ed_wdh
		.replace(/Created with \[\[ShareMap:\|ShareMap\.org\]\]\n*/, '')  			// ed_wdh 
		.replace(/Created with \[http:\/\/sharemap\.org ShareMap\.org\]\n*/, '')	// ed_wdh 
		.replace(/\[\[\Category:Created with Inkscape\]\]\s?/, '')					// ed_wdh  remove / uncat
		.replace(/(?:<center>)?\{\{(?:[Cc]reated with |[Mm]ade with )?Inkscape(?:\|err=\d*)?\}\}(?:<\/center>)?\s?\n*/, '')	// ed_wdh  Orem remove
		.replace(/<center>\s?\n*<\/center>\s?\n*/, '')	// ed_wdh  Orem remove
		.replace(/\{\{Created with Inkscape\}\}\s?\n*/, '')							// ed_wdh  remove / uncat
		.replace(/\[\[\Category:Inkscape\]\]\s?/, '')								// ed_wdh  remove even worse
			.replace(/\[\[Category:SVG files ?(\|[^\n\]]+)?\]\]\n*/, '')			// MetaCat
		.replace(/ ?(?:[Vv]ector(?:ized|ization)|r?e?drawn|[Vv]ektorisiert) ?(?:by|von)? ?(\{\{U\|(?:[^}]+)\}\})/g, ' {{author|Vectorization|$1}}')

		.replace(/\*\{\{F\|([^\]|[]+)\|\+\}\} licensed/g, '*{{F|$1|-}} licensed')	// ed_wdh: Original upload log
		.replace(/\[\[:[Cc]ategory: ?([^\]|[\n]+)(?:\| ?\1 ?)\]\]/g, '{{C|$1}}')
		.replace(/=\s*\{?\{?(own)?\}?\}? ?(work|made|after|nach|from)?,? (?:based|basierend|from)? (after|nach|on|off):?/gi, '={{Own based}}')
		.replace(/=\s*\{\{[Oo]wn\}\} ?from /g, '={{Own based}} ')		// ed_wdh (previous did not work); include the file:
		.replace(/=\s*\{\{[Oo]wn based\}\};*\s*(?:\[\[:(?:[Ff]ile|[Ii]mage):|\{\{[Ff]\|) ?([^\]|[\n]+)(?:\]\]\.?|\}\})/g, '={{Own based|$1}}')

		.replace(/\| *[Oo]rig(?:off)? *=([^\]|[\n]+)(?:\}\}|\|)/g, fileTruncate)		// ed_wdh
		.replace(/\{\{ *[Oo]wn based *\|([^\]|[\n]+)(?:\}\}|\|)/g, fileTruncate)		// ed_wdh
		.replace(/\{\{ *[Vv][Vv][Aa] *=([^\]|[\n]+)(?:\}\}|\|)/g, fileTruncate)			// ed_wdh + aliases
		.replace(/\{\{ *[Dd]erived(?: +from)? *\|([^\]|[\n]+)(?:\}\}|\|)/g, fileTruncate)	// ed_wdh
		.replace(/\{\{ *[Ff]ile(?:list)? ?\|([^\]|[\n]+)(?:\}\}|\|)/g, fileTruncate)	// ed_wdh
			
		.replace(/=\s*(?:(?:[Nn]achgezeichnet )?nach|[Bb]ased on|(?:[Rr]edrawn )?after)? (?:Vorlage)?:?\s*\*?\[?(?:\{\{[Nn]gw2\|(?:1|url ?=)?)? ?(?:(?:heraldrywiki\/index\.php\?title=)([\w_ ()]*)|(?:(?:http:\/\/)?www\.ngw\.nl\/?(?:heraldrywiki\/index\.php\?title=([\w_ ()]*)|int\/dld\/\w+\/(?:images\/)?([\w_ ()]*)\.\w{3})?))\}?\}?(?: [\w .]+)?\]?/g, function (m, p1, p2, p3) {
			m = '';
			let l = [p1, p2, p3],
			p = 3,
			r = /\d$/,
			w = '<!--PLEASE CHECK-->';
			while (p--) {
				m += (l[p] || '');
				if (r.test(m)) {
					m = m.replace(r, w);
					w = '';
				}
			}
			if (w && (m.length === 8 || c.wgTitle.toLowerCase().indexOf(m) === -1))
				m += w;
			// never use ngw2 on SVG
			return '={{Ngw3|' + _ucfirst(m) + '}}';
		})
//
//	*** Iterative replacings for:    Attrib;  Legend;  Gallery; 
			.replace(/\{\{\s?[Aa]ttrib(?:SVG)? ?\|(?: ?1 ?= ?)?(?:[Ff]ile:|[Ii]mage:)?/g, '{{Attrib|')		// ed_wdh
		// when there are more "Attrib"s, change to "Attribs":			[[[without backreference ! ]]]
					.replace(/(\s*\{\{Attrib\|(?:.*?)\}\})\{\{Attrib\|/gm, '$1@\n{{Attrib|')		//ed_wdh
			.replace(/(\s*\{\{Attrib\|(?:.*?)\}\})[\s ]*\{\{Attrib\|/gm, '$1@\n{{Attrib|')		//ed_wdh
			.replace(/(\s*\{\{Attrib\|(?:.*?)\}\})[\s ]*\{\{Attrib\|/gm, '$1@\n{{Attrib|')		//ed_wdh
 			.replace(/(?:\}\}@[\s ]*\{\{Attrib\|)/gm, '\n |')		//ed_wdh
 			.replace(/(\s*\{\{Attrib)/g, '$1s|t=\n ')				//ed_wdh (all, also singles! - better: only first of queue)
//	*** Assume "coat of arms" (c) - but be aware that it can be as well "map" (m/lm/wm) or another topic			
			.replace(/\{\{Attribs?\|t=\n \|Blason_Vide_3D\.svg\}\}/m, '{{Attrib|t=c|Blason Vide 3D.svg}}')	//ed_wdh aroche
			.replace(/\{\{Attribs?\|t=\n \|(.*?) map([^\|]*?)/g, '{{Attribs|t=m\n |$1 map$2')				// it's a  map
 			.replace(/\{\{Attribs?\|t=m\n \|(.*?)world([^\|]*?)/g, '{{Attribs|t=wm\n |$1 location $2')		// wm/ggg map
 			.replace(/\{\{Attribs?\|t=m\n \|(.*?) location ([^\|]*?)/g, '{{Attribs|t=lm\n |$1 location $2')	// locator map
 			.replace(/\{\{Attribs\|t=(c|lm|wm|m)?\n \|([^\n\}]*?)\}\} *\n/m, '{{Attrib|t=$1|$2}}\n')	//ed_wdh re_singularize	 
 		.replace(/\{\{Attrib(s)?\|t= *([\n\|])/m,  function (m, tm, lf) {
			let topic = '';
			if (!tm)	tm = '';		// undefined ?
			if (coa || /PD-Coa|coats? of arms|[Ee]scu|:CoA/i.test(txT))
				topic = 'c';
			else 
			if (/[Mm]aps/.test(txT) && /green and grey/i.test(txT))
				topic = 'ggg';
			else 
			if (/[Mm]aps/.test(txT) && /[Ww]orld/.test(txT))
				topic = 'wm';
			else 
			if (/[Mm]aps/.test(txT) && /[Ff]lag/.test(txT))
				topic = 'fm';
			else 
			if (/[: -_]icon/i.test(txT) && /[Ff]lag/.test(txT))
				topic = 'fi';
			else 
			if (/[Mm]aps/.test(txT))
				topic = 'm';
	//		else 
	//		if (/[Ff]ootball/.test(txT) && /line-up/.test(txT))
	//			topic = 'm';
			else 
			if (/PD-Flag-|flag/.test(txT))
				topic = 'f';
			return '{{Attrib' + tm + '|t=' + topic + lf; 		//ed_wdh: topic 
		}) 		
				
 
//  ***  template:Legend 
 		.replace(/\{\{ *[Ll]egend(-small|-line| inline|2)? *\| *([^\|]*) *\| *([^\}]*)/g, function (m, typ, col, txt)
		{	if (!typ)	 typ =  "";
		 	if (!col)	 col =  "";			// otherwise (when col="") flagged
		 	if (!txt)	 txt =  "";
			if (col.substring(0,2) === "1=")	col = col.substring(2);
			if (txt.substring(0,2) === "2=")	
			{	txt = txt.substring(2);
				for (let i = 0; i < txt.length; i++)
				{	if ( txt.substring(i, i+1) === "=")  
  						txt = txt.substring(0, i) + "&#61;" + txt.substring(i+1);	// replace equal sign
  					if ( txt.substring(i, i+2) === ">=")  
  						txt = txt.substring(0, i) + "โ‰ฅ" + txt.substring(i+2);	// replace  
  	 				if ( txt.substring(i, i+2) === "<=")  
  	 					txt = txt.substring(0, i) + "โ‰ค" + txt.substring(i+2);	// replace 
  				}
			}
			return "{{Legend" + typ + "|" + col + "|" + txt;					// txt without "="
		})
 
		.replace(/\s*\{\{[Ll]egend\|\|line=/g, '{{Legend-linew|')	//ed_wdh	
//	dw	.replace(/(\s*\{\{[Ll]egend(?:[^\|]*?)\|(?:[^\|]*?)\| *2 *= *[^=]*)=((?:.*?)\}\}(?:[\s ]*)\{\{[Ll]egend)/g, '$1๐Ÿฎ&#61;๐Ÿฎ$2')	//ed_wdh 
//		.replace(/(\s*\{\{[Ll]egend(?:[^\|]*?)\|)(?: *1 *= *)?([^\|]*\|?)(?: *2 *= *)?/g, '$1$2')	//ed_wdh rem. pos. (??=both)

		.replace(/(\s*\{\{[Ll]egend *\|(?:.*?)\}\}(?:[\s ]*))\{\{[Ll]egend([\s ]*)\|/gm, '$1โœ‹{{Legend|$2')	//ed_wdh
		.replace(/(\s*\{\{[Ll]egend *\|(?:.*?)\}\}(?:[\s ]*))\{\{[Ll]egend([\s ]*)\|/gm, '$1โœ‹{{Legend|$2')	//ed_wdh
		.replace(/(?:\}\}([\s ]*)โœ‹\{\{[Ll]egend)/gm, '$1')							//ed_wdh: remove all but 1st
		.replace(/(\s*\{\{[Ll])(?:egend)( *\|)/g, '$1egtab$2')						//ed_wdh (+ singles)
 		.replace(/(\s*\{\{[Ll])(?:egtab)\|([^\n\}]*?)\}\} *\n/m, '$1egend|$2}}\n')	//ed_wdh re_singularize	 


	.replace(/(\s*\{\{[Ll]egend-small *\|(?:.*?)\}\})([\s ]*)\{\{[Ll]egend-small([\s ]*)\|/g, '$1โ˜•$2{{Legend-small|$3') //ed_test
	.replace(/(\s*\{\{[Ll]egend-small *\|(?:.*?)\}\})([\s ]*)\{\{[Ll]egend-small([\s ]*)\|/g, '$1โ˜•$2{{Legend-small|$3') //ed_ repeat
	.replace(/(?:\}\}โ˜•([\s ]*)\{\{Legend-small\|)/gm, '$1|')						//ed_wdh
	.replace(/(\s*\{\{[Ll])(?:egend-small *\|)/g, '$1egtab||M|')					//ed_wdh (+ singles)	

	.replace(/(\s*\{\{[Ll]egend-line *\|(?:.*?)\}\})([\s ]*)\{\{[Ll]egend-line([\s ]*)\|/g, '$1โ™“$2{{Legend-line|$3') //ed_test
	.replace(/(\s*\{\{[Ll]egend-line *\|(?:.*?)\}\})([\s ]*)\{\{[Ll]egend-line([\s ]*)\|/g, '$1โ™“$2{{Legend-line|$3') //ed_ repeat
	.replace(/(?:\}\}โ™“([\s ]*)\{\{Legend-line\|)/gm, '$1|')						//ed_wdh
	.replace(/(\s*\{\{[Ll])(?:egend-line *\|)/g, '$1eglin|')					//ed_wdh (+ singles)	

	.replace(/(\s*\{\{[Ll]egend-linew *\|(?:.*?)\}\})([\s ]*)\{\{[Ll]egend-linew([\s ]*)\|/g, '$1โ™“$2{{Legend-linew|$3') //ed_test
	.replace(/(\s*\{\{[Ll]egend-linew *\|(?:.*?)\}\})([\s ]*)\{\{[Ll]egend-linew([\s ]*)\|/g, '$1โ™“$2{{Legend-linew|$3') //ed_ repeat
	.replace(/(?:\}\}โ™“([\s ]*)\{\{Legend-linew\|)/gm, '$1|')					//ed_wdh
	.replace(/(\s*\{\{[Ll])(?:egend-linew *\|)/g, '$1eglin|w=33px|')			//ed_wdh (+ singles)	

	.replace(/(\s*\{\{[Ll]egend inline *\|(?:.*?)\}\})([\s ]*)\{\{[Ll]egend inline([\s ]*)\|/g, '$1โŒ›$2{{Legend inline|$3') //ed_test
	.replace(/(\s*\{\{[Ll]egend inline *\|(?:.*?)\}\})([\s ]*)\{\{[Ll]egend inline([\s ]*)\|/g, '$1โŒ›$2{{Legend inline|$3') //ed_test
	.replace(/(?:\}\}โŒ›([\s ]*)\{\{Legend inline\|)/gm, '$1|')						//ed_wdh
	.replace(/(\s*\{\{[Ll])(?:egend inline *\|)/g, '$1eglin|t=Legend inline|')		//ed_wdh (+ singles)	

	.replace(/(\s*\{\{[Ll]egend2 *\|(?:.*?)\}\})([\s ]*)\{\{[Ll]egend2([\s ]*)\|/g, '$1โ›บ$2{{Legend2|$3') //ed_test
	.replace(/(\s*\{\{[Ll]egend2 *\|(?:.*?)\}\})([\s ]*)\{\{[Ll]egend2([\s ]*)\|/g, '$1โ›บ$2{{Legend2|$3') //ed_test
	.replace(/(?:\}\}โ›บ([\s ]*)\{\{Legend2\|)/gm, '$1|')						//ed_wdh
	.replace(/(\s*\{\{[Ll])(?:egend2 *\|)/g, '$1eglin|t=Legend2|')			//ed_wdh (+ singles)	

//	*** Set 6-byte-Colorcode to uppercase; when possible, shorten 'rrggbb' to 'rgb'
		.replace(/(#[\dA-Fa-f]{6})/g, function (m, c)
		{	let rgb = c.toUpperCase();			//		if (expeUser &&
			if (rgb.substring(1,2) === rgb.substring(2,3)	// rr
			&&  rgb.substring(3,4) === rgb.substring(4,5)	// gg
			&&  rgb.substring(5,6) === rgb.substring(6,7) )	// bb
				return rgb.substring(0,2) + rgb.substring(3,4) + rgb.substring(5,6);
			else
				return rgb;		// uppercase only
		})

			.replace(/([^{])[Dd]erivative[ _]versions?[ _]?(?!of):?([^s}])/, '$1{{Derivative versions}}$2') // TODO: parameter as filenames
			.replace(/([^{])[Dd]erivative[ _]work(?![ _]of)(:?)([^s}])/, '$1{{Derivative}}$2$3') // TEST
			.replace(/[Ss]ource( +)?=( +)?\{\{\w\w\|(?:1=)?([^|\]]+)([| ])(?:Vorlage|Template)(\]\]?)?\s*\}\}/, 'source$1=$2$3$4{{Template-ns}}$5')
//	*** gallery treating
		 		.replace (/(?:\n?)<[Gg]allery>([\w\s]+?)<\/[Gg]allery>/gm, '{{G|$1}}โ˜•') 		// ed_wdh
		// 		.replace (/<[Gg]allery>([\n\s\w]+?)<\/[Gg]allery>/gm, '{{H|$1}}') 			// ed_wdh   dmy template
		//		.replace (/<[Gg]allery>(?:[^\n]+?)(\n.+)<\/[Gg]allery>/gm, '{{J|$1}}') 		// ed_wdh
		//	.replace (/<[Gg]allery>(.*?)<\/[Gg]allery>/gm, '{{X|$1}}') 				// ed_wdh
		// 	.replace (/<[Gg]allery>([\n.]+?)<\/[Gg]allery>/gm, '{{Y|$1}}โŒ›')			// ed_wdh
		.replace(/(?:\n?)<[Gg]allery>\s*(?:[Ff]ile\:|[Ii]mage\:)?([^\n|]+)(\|?[^\n]+)?\s*<\/[Gg]allery>(?:\n?)/g, '{{G|\n$1$2}}\n') // ed_wdh test	
			.replace(/\{\{G\|\n([^\n\}]+?)\}\}/gm, '{{G|$1}}') 						// ed_wdh: single item gallery only one line

			.replace (/<[Gg]allery>([^<]*?)\n?<\/[Gg]allery>/gm, '{{G|$1}}') 			// ed_wdh: multiple lines


//	*** General very specific cleanup (old usernames) */
			.replace( /[Mm]axxl2/g, 'MaxxL' )
		//	.replace   ( /\[\[[Uu]ser:(.*?)(\|[^\]|[]+)?\]\]/g, '{{U|$1}}')		// ed_wdh test ????
//	*** Try to sort the parameters: date - source - author
	//				dsaโœ“	das		sda		sad		ads		asd	
	//	as			 		dsaโœ“	 		  		 		sad	
	//	ad			 		 		 		sda		das		sda	
	//	as			 		 		 		 		dsaโœ“	 	
	//	sd			 		 		dsaโœ“	dsaโœ“			dsaโœ“	
		.replace (/( *\| *[Aa]uthor(?:.*))\n( *\| *[Ss]ource(?:.*))\n/, '$2\n$1\n' ) // ed_wdh sort: as 
		.replace (/( *\| *[Aa]uthor(?:.*))\n( *\| *[Dd]ate(?:.*))\n/,   '$2\n$1\n' ) // ed_wdh sort: ad  
		.replace (/( *\| *[Ss]ource(?:.*))\n( *\| *[Dd]ate(?:.*))\n/,   '$2\n$1\n' ) // ed_wdh sort: sd 		
			
			.replace (/\{\{self-photographed\}\}/, '{{Own}}')				// Aliman
			.replace (/\(\[\[Switzerland\]\]\)/, '({{W|Switzerland}})')		// Aliman
			.replace(/\|s\=-COAInformation/, '|s=c')		              	// ed_wdh ???
		.replace(/https:\/\/armorialdefrance\.fr\/page_blason\.php\?ville=(\d+)/, '{{Page blason|$1}}')			// ed_wdh
		.replace(/https?:\/\/www\.newgaso\.fr\/lecture[ _]fiche[ _]commune\.php3\?page=(f\d+)/, '{{Fiche commune|$1}}')	// ed_wdh		

		.replace(/^ *\|\s*[Pp]ermission\s*= *(?:\[\])? *\n( *[\|\}])/m, '$1')			// ed_wdh remove empty permission param up
		.replace(/^ *\|\s*[Pp]ermission\s*= *[Pp]ublic domain *\n( *[\|\}])/m, '$1')	// ed_wdh remove obsolete permission
		.replace(/^ *\|\s*[Pp]ermission\s*= *(?:[Oo]wn work,?)? *(?:all rights released)? *(?:\(?Public domain\)?)? *\n( *[\|\}])/, '$1')	// ed_wdh rem

//	*** AutVec([[Switzerland]])
			
			.replace(/Original:? ([^\n|<]+)(?:<br ?\/?>)?\s*(?:SVG:? )(\[\[[\w:]*User:[^\n|[\]]+(?:\|[^\n|[\]]+)?\]\])/i, '{{AutVec|o=$1|v=$2}}')
			.replace(/=\s*{{AutVec ?\|\s*(?:o=)?(?:(?:{{Uc?\|[^}]+)(?:\}\})|[^}|]*)?\|(?:v=)?(?:(?:{{Uc?\|[^}]+)(?:\}\})|[^}|]*)?\|([^\]|[\n]+)(?:\}\}|\|)/g, fileTruncate);
		}
		// COAInformation has special parameter ยฟimgen/image? so warn if present
		if (/=\s*\{\{[Ii](m?gen|mage[ _]generation)/.test(txT) || imgen) {
			cSVG.warnMsg({
				title: 'Already present, ' + (err ? 'There are ' + err + ' error' : 'but file is valid') + '!',
				type: 'warn'
			});
 				if (/s\=sf|s\=eq/.test(txT)) {
 					LeyoChem = 1;	// use FGD  773
 				} 
		}

		/* SVG Template and cosmetic replace (continued line 950 ff) */
		txt = txt /* Other SVG related templates (for T), currently only working for sure if they are on a single line */
			.replace(/\s?(\{\{\s?(\w+werkstatt[^\|\n\}]*|[Gg]raphic[ _][Ll]ab[^\|\n\}]*|[Ww]PGW[ _]vector[ _]im[^\|\n\}]+|[Tt]HV[^\|\n\}]*|[Aa]telier[ _]graphique[^\|\n\}]*|[Ll]aboratorio[ _]grafico\|?[^\|\n\}]*|[Pp]rojet[ _]Blasons)\}\})\s?/g, function (m, p) {
				T += p;
				return '';
			})
			.replace(/(\{\{(TracedSVG|Autotraced|Bad[ _]trace|PoorSVG)\}\})\s?/i, function (m, p) {
				p5 = '|ยง';
				return '';
			}) // PoorSVG
			.replace(/\{\{\s?Bad[ _]?SVG\s?\}\}\s?/i, function (/* m, p*/) {
				p5 = '|!';
				return '';
			}) // BadSVG
			.replace(/\{\{\s?[Ee]asy[ _-]border(?:\s?\|\s?([^\n]+))?\s?\}\}\s?/, function (m, p) {
				p5 += '|ยฐ';
				s = p || s;
				return '';
			}) // Easy-border
			.replace(/(\{\{([Tt]ranslat(?:e|able|ion possible)|[Ee]asy translation)[^\\n}]*}})\s?/, function () {
				p5 += '|%';
				return '';
			})
			.replace(/\{\{\s?([Ss]uper[cs]eded(?:-Image)|(?:[Rr]aster|PNG|Bitmap)(?:[ _]version)?(?:[ _]available)|[Oo]bsolete)(?:\s?\|\s?([^\n]+))?\s?\}\}\s?/, function (m, p, p2) {
				p5 += '|\\' + (p2 ? '=' + p2 : '');
				return '';
			}) // Superseded
	//		.replace(/\{\{\s?([Ss]uper[cs]edes)(?:\s?\|\s?([^\n]+))?\s?\}\}\s?/, function (m, p, p2) {
			.replace(/\{\{\s?([Ss]uper[cs]edes)(?:\s?\|\s?(?:1=)?([^\n]+))?\s?\}\}\s?/, function (m, p, p2) {
				p5 += '|\\+=' + p2;
				return '';
			}) // Supersedes
			.replace(/\{\{\s?([Cc]ommonist)(?: no icon)?(?:\s?\|\s?([^\n]+))?\s?\}\}\s?/, function () {
				p5 += '|$';
				return '';
			}) // Commonist (works not properly}
			
			.replace(/(?:\{\{(?:[Rr]etouched[ _]?(?:[Pp]icture|[Ii]mage)?|[Rr]estored|[Mm]odified)([^}\n]+\}\}))/, function (m, p) {
				T += '{{retouched' + p;		// 1st create "T= ", later make it with "|r="; variable 'p' contains all the parameters
				return '';
			})
			.replace(/\{\{\s?(in)?valid[ _]?(SVG)?[^}]*\}\}\s?/ig, '') // remove SVG validity templates
			.replace(/\[\[\Category:ChemSketch\]\]\s?/ig, '')               		// ed_wdh  
			.replace(/\[\[\Category:Created with Inkscape\]\]\s?/ig, '')			// ed_wdh 2nd

			.replace(/^ *\|\s*[Pp]ermission\s*= *\n( *[\|\}])/m, '$1')			// ed_wdh remove empty permission param
			.replace(/^ *\|\s*[Oo]ther[ _]versions\s*= *\n*( *[\|\}])/m, '$1')	// ed_wdh remove empty other_versions param
			.replace(/^\s*\}\}\s*$/gm, '}}\n'); 		// trim on every separate temp end

		/* Search SVG templates for tool-name and remove them */
		if (size) {
			txt = txt.replace(/\{\{\s?[Ss]implSVG\|([^{}|]+)\|[^}]+\}\}\s*/ig, function (m, p) {
					toolName = p;
					return '\n';
				});
		}
		txt = txt.replace(/\{\{(Inkscape(-hand)?|Adobe([ _]Illustrator|-hand)?|Illustrator|Gnuplot|CorelDraw)\|?[^{}]*\}\}\s?/i,
				function (m, p, p2) {
				if (p2)
					toolName = /[Aa]dobe-hand$/m.test(p2) ? 'AH' : 'H';
				else
					toolName = p;
				replaced = 1;
				if (/code ?=/.test(m))
					T += m;
				else if (p === 'Inkscape' && /IMPORTANT=yes/.test(m))
					toolName = 'Im';
				return '\n';
			} // replace success
			);
		if (!replaced) { // search Created with ... templates
			txt = txt.replace(/\{\{[Cc]reated with ([^{}|]+)\|?([^{}]*)\}\}\s?/, function (m, p, p2) {
					toolName = p;
					replaced = 1;
					if (/code/.test(p2))
						T += m;
					return '\n';
				} // replace success
				);
			if (!replaced) { // TODO: search redirects to Created with ... templates
				txt = txt.replace(/\{\{(QGIS|[Ll]ibreOffice|[Oo]penOffice(?:\.org)?|MATLAB|[Gg]numeric|[Mm]athematica)\|?[^{}]*\}\}\s*/,
						function (m, p) {
						toolName = p || toolName;
						replaced = 1;
						return '\n';
					});
				if (!replaced) { // replace previous igen
 					if (/s\=sf|s\=eq/.test(txT)) {
 						LeyoChem = 1;	// use FGD
 					} 
					// FIXME: don't replace fully
					
					txt = txt.replace(/(\s)?\{\{[Ii](gen|mage[ _]generation)\|([\w ]*)?\|?[^{}]*\}\}\1?/,
							function (m, s, i, p) {
							if (i.length > 4)
								IgenName = IgenNameLong;
							toolName = p || toolName;
							replaced = 1;
							return /code ?=/.test(m) ? m : '\n';
						} // replace success
						);
					if (!replaced) { // replace completely previous FGD  (834)  ed_wdh
						if (/structural formula|chemical equation/.test(txT)) {
							LeyoChem = 1;	// use FGD
						} 
						txt = txt.replace(/\{\{File generation description((?:[^\}]{2})+\}\}\n)/m, '');
					}
				}
			}
		}
		toolName = toolname || toolName;	// "toolname" from SVG code  has priority over "toolName" from file desc
											// (this inhibits tool specification if is later e.g. inkscaped)
		/* Exclude nowiki text with split */
		let nowiki = txt.split('<nowiki>'), // TODO: Works only on non nested (may be sufficient)
		wikiTxt = [nowiki.shift()];
		if (nowiki.length) {
			for (let n = 0; n < nowiki.length; n++) {
				let nClose = nowiki[n].split('<\/nowiki>');
				if (nClose.length > 1) {
					nowiki[n] = '<nowiki>' + nClose.shift() + '<\/nowiki>';
					wikiTxt.push(nClose.join());
				} else {
					wikiTxt[n - 1] += nowiki.splice(n, 1);
				}
				// console.log(n, nowiki[n])
			}
		}
		txt = ''; // clear

		for (let wt in wikiTxt)
			txt += generalCleanup(wikiTxt[wt]) + (nowiki[wt] || '');

		txT += c.wgTitle;
		/* Search for sub suffix parameter */
		if (/text[: -_]?logo/i.test(txT)) {
			this.textTrans = 0; // Logos don't get translated
			s = 'tl'; // :textlogo
		} else if (/Logos? of |:Logos?/i.test(txT)) {
			s = 'l'; // :Logos
		} else if (/[Mm]aps/.test(txT) && /green and grey/i.test(txT)) {			
			s = 'ggg'; // :green and gray world maps
		} else if (/[Mm]aps/.test(txT) && /[Ww]orld/.test(txT)) {			
			s = 'wm'; // :World maps
		} else if (/[Mm]aps/.test(txT) && /[Ff]lag/.test(txT)) {
			s = 'fm'; // :flag maps
		} else if (/[Mm]aps/.test(txT)) {			
			s = 'm'; // :Maps
		} else if (/[: -_]icon/i.test(txT) && /[Ff]lag/.test(txT)) {
			s = 'fi'; // :flag icons
		} else if (/[: -_]icon/i.test(txT)) {
			s = 'i'; // :Icons
		} else if (coa) {
			s = 'c'; // :CoA
		} else if (/PD-Coa|coats? of arms|escu|:CoA|heraldic/i.test(txT)) {
			s = 'c'; // :CoA / ecclesiastical heraldry
		} else if (/[Ii]nsignia|[Ii]dentification badge|[Ee]mblem/.test(txT)) {
			s = 'em'; // :Emblems
		} else if (/[Pp][Dd]-chem|ChemDraw|BKchem|Chemtool|ChemSketch|GChemPaint|N2S|[Cc]hemical structure/.test(txT)) {
			LeyoChem = 1;					// use FGD
			s = 'sf'; // :Structural formulas
		//			IgenName = IgenNameLong;						// for Leyo
		} else if (/[Rr]ibbon bar|Order /.test(txT)) {
			s = 'o'; // :Orders
		} else if (/ signs\]/.test(txT)) {
			s = 'v'; // :Signs {when category}
		} else if (/PD-Unicode|[Uu]nicode|alphabet|letter/.test(txT)) {
			s = 'u'; // :Unicode
		} else if (/[Ss]ymbol/.test(txT)) {
			s = 'y'; // :Symbols
		} else if (/[Ss]eal/.test(txT)) {
			s = 's'; // :seal
		} else if (/[Mm]athematic|[Aa]lgoritmo|[Tt]rigonometry|[Gg]eometry|[Ii]sometric/.test(txT)) {
			s = 't'; // :Trigonometry
		} else if (/Diagram/i.test(txT) && toolName !== 'Wpdc') {     // ed_wdh 
			s = 'd'; // :Diagrams
		} else if (/PD-Flag-|flag/.test(txT)) {
			s = 'f'; // :Flags
		} else if (/[Ff]ootball/.test(txT) && /line-up/.test(txT)) {
			s = 'm|sd=/line-up'; // :line ups
		} else if (/[Ff]ootball/.test(txT)) {
			s = 'fk'; // :Football kits
		} else if (LeyoChem) {
 			s = 'sf'; // :Structural formulas
		} else if (/[Aa]utograph/.test(txT)) {
			s = 'sig'; // :Signatures
		} else if (/[Ss]ignature/.test(txT) && !/[Ss]ignature-talk/.test(txT)) {
			s = 'sig'; // :Signatures                          // 'sig' comes too often
		}

		// topic with UserID (only special users)    // ed_wdh if
		if (s === 'm' && /globe/.test(txT) && /Hagar66/.test(txT) && toolName === 'Adobe')	
			s = 'wm|U=Hagar66';							// Hagars world maps (precedence over TUBS)
		if (s === 'm' && /globe/.test(txT) && /NordNordWest/.test(txT))
			s = 'wm|u=NordNordWest';					// NordNordWest world maps (precedence over TUBS, but not over Hagar)
		if (s === 'm' && /globe/.test(txT) && /TUBS/.test(txT))	  
			s = 'wm|u=TUBS';							// TUBS world maps
	//	if  (s === 'm' && /globe/.test(txT))
	//		s = 'wm';									// world maps
		if (/Hagar66/.test(txT) && /[Ll]ocator|[Ll]ocation /.test(txT) && s === 'm' && toolName === 'Adobe')	
			s = 'lm|U=Hagar66';							// Hagars location maps (precedence over TUBS)
		if  (/NordNordWest/.test(txT) && /[Ll]ocator|[Ll]ocation /.test(txT) && s === 'm')
			s = 'lm|u=NordNordWest';					// NordNordWest location maps (precedence over TUBS, but not over Hagar)
		if  (/TUBS/.test(txT) && /[Ll]ocator|[Ll]ocation /.test(txT) && s === 'm')	  
			s = 'lm|u=TUBS';							// TUBS location maps
		if (/Hagar66/.test(txT) && s === 'm' && toolName === 'Adobe')	
			s = 'm|U=Hagar66';						// Hagars maps (precedence over TUBS)
		if  (/NordNordWest/.test(txT) && s === 'm')	// (/NordNordWest/.test(txT) && s === 'm')  
			s = 'm|u=NordNordWest';					// NordNordWest maps (precedence over TUBS)
		if  (/TUBS/.test(txT) && s === 'm')			// (/TUBS/.test(txT) && s === 'm' && toolName === 'Adobe')  
			s = 'm|u=TUBS';							// TUBS maps
	//	if (/Hagar66/.test(txT) && (s === 'm' || s === 'm|u=TUBS'))	
	//		s = 'm|U=Hagar66';						// Hagars maps (replacing TUBS)
		if  (/Locator|Location maps/i.test(txT) && s === 'm')
			s = 'lm';								// location maps
		if (/Petrus3743/.test(txT)  && s === 't')	// && toolName === 'GeoGebra'
			s = 't|u=Petrus3743|<v';				// Petrus_trigonometry	โœ”
		if (/\[\[User\:Cdang\|Cdang\]\]/i.test(txT) || /\{\{U\|Cdang\}\}/i.test(txT))	// Cdang ?
			s += '|u=cdang';						// cdang โœ”

		// default: "Unknown tool" (but can also be Text Editor)
		toolName = _ucfirst(toolName) || ((this.curSize && this.curSize > 50 && this.curSize < 2000) ? 'T' : 'U');
		toolName = toolNames[toolName] ? toolNames[toolName] : toolName;
		if (expeUser)
			toolName = toolAbbr[toolName] ? toolAbbr[toolName] : toolName;

		// Graphic Lab replace: Map Lab	๐Ÿž๐Ÿž๐Ÿž๐Ÿž๐Ÿž๐Ÿž this buggy procedure is disabled ๐Ÿž๐Ÿž๐Ÿž๐Ÿž๐Ÿž๐Ÿž
		if (T) {
			T = T.replace(/\{\{Grafikwerkstatt๐Ÿœ\}\}/, function (/* m*/) {
	//	ed_			g = 'de';
					gd;
					return '';
				});

			if (T && !g) {
				T = T.replace(/\{\{[Aa]telier๐Ÿœ[ _]graphique([ _]carte)?\}\}/, function (m, p) {
	//	ed_				g = 'fr';
						gf;
						s = (p && !s) ? 'm' : s;
						return '';
					});
			}
			if (T && !g) {
				T = T.replace(/\{\{[Ll]aboratorio๐Ÿœ[ _]grafico([ _]mappa)?\}\}/, function (m, p) {
	//	ed_				g = 'it';
						gi;
						s = (p && !s) ? 'm' : s;
						return '';
					});
			}
			if (T && !g) {
				T = T.replace(/\{\{\s*[Gg]raphic[ _][Ll]ab\s*\|\s*([\w-]+)\|?(map|[^{}]*)?\}\}/, function (m, p1, p) {
	//	ed_				g = p1;
						gP;
						s = (p && !s) ? 'm' : s;
						return '';
					});
			}
			if (T && !g) {
				T = T.replace(/\{\{WPGW๐Ÿœ vector image\}\}/, function (m, p1, p) {
						gP;
						s = (p && !s) ? 'm' : s;
						return '';
					});
			}
			g = g ? '|g=' + g : '';

	//		put $1 (modifications) into '|r', $2 contains all the other parameters		
			if (/\{\{retouched\|([^|}\n]*)\|?([^}\n]+)\}\}/.test(T)) { // TODO: filename can't contain "}"
				r = '|r=' + (RegExp.$1 || '-') + '|' + (RegExp.$2 || '');
				T = T.replace(RegExp.lastMatch, ''); // FIXME: non standard
			}
			T = (T.length > 4) ? '|T=' + T : '';
		}

		// Cleanup remnants
		txt = txt.replace(/\{\{\s?[Ii]n(formation[ _]field|Fi)\|[^{}\n|]+\|\s?value\s?=(\s*\}\})?\s*/g, ''); // empty field
		if (s === 'm')
			txt = txt.replace('<!--PLEASE CHECK, not generally for all SVG maps-->', '');

		/** *
		 * Get lastIndex, from now, NO text manipulation anymore, or var topp must be fixed
		 ***/
		if (!ofRE.test(txt)) {
			let i = inRE.length;
			while (i--) { // iter over possible positions
				if ((topp = new RegExp(inRE[i], 'g')).test(txt)) {
					topp = _findPosition(topp);
		//	console.log(" topp '%i', i '%i'", topp, i);		//---test 
					i = 0;
					break;
				} else
					topp = 0;
			}
		} else {
			topp = ofRE.lastIndex;
			txt = txt.replace(ofRE, '');
			topp -= RegExp.lastMatch.length;
			ls = RegExp.$3;
		}
		s1 = s1 || RegExp.$1;
		s2 = s2 || RegExp.$2;

		if (!coa && /[Ii]mgen\|/.test(ls)) { // CoA but without COAInformation
			IgenName = '|image' + s2 + '=' + s2;
			tempPre = '';
		} else if (!topp && /\}\}/g.test(txt)) {
			topp = txt.lastIndexOf(tempPre) + 3; // put on last postion of a template
		} else {
			IgenName = '|other fields' + s2 + '=' + s2 + IgenName;
		}

	//	 console.log(" ofRE s1 '%s', s2 '%s', ls '%s'", s1, s2, ls, topp);		//---test

		if (typeof err === 'number') {
			if (!topp) {
				this.setIgen(IgenName += (toolName || 'ร—?ร—') + (err ? '|' + err.toString() : '') + '|+|s=' + s, tempPre);
				return '';
			}
		} else if (typeof err === 'undefined') {
			return txt; // don't insert igen
		}

		// Parameter 5
		if (this.badSVG) {
			if (!/^\|!/.test(p5))
				p5 += '|!';
			if (this.badSVG > 1)
				p5 += '=f'; // Fake SVG
			else if (!expeUser && s !== 'm')
				p5 += '<!--PLEASE CHECK, not generally for all graphic types-->'; // Maybe
		}
		if (this.curSize > 3407872)			// 3407872 = 3.4M; 4194304 = 4M
			p5 += '|>'; // Large SVG 4 MB? 3.4 MB?
		if (this.textPath)
			p5 += '|<'; // "less" sign to insert the {Path text SVG} tag.
		if (this.PGF)
			p5 += '|~'; // "squiggle" sign for PGF CDATA
		else if (this.switchTrans)
			p5 = p5.replace(/\|%/, '') + '|%s';
		else if (this.textTrans && !/\|%/.test(p5) && toolName !== 'Wpdc')      // ed_wdh
			p5 += '|%';

		T = p5 + r + T;

		if (topp) {
			err = Number(err);
			if (size) {
				IgenName += toolName + '|' + size + '|9=+|10=S|user=' + c.wgUserName + ((s === '-COAInformation') ? '|sub=' : '|4=') + s + T;
			} else {
				if (s === '-COAInformation' && $.inArray(toolName, ['I', 'Inkscape', '']) !== -1) {
					let coaUsers;
					// ls = ls.replace( /\{\{[Ii]mgen\|([\w\d ]+)\}\} *\n/, function(m, p){ user = p; return "";} );
					if (!user) {
						coaUsers = [// [[Template: Igen/coa]]
							['{{Projet Blasons}}', 'f'], // must be first  // ed_wdh
							['Aroche', 'Ar'], 		 // ed_wdh
							['Chatsam', 'Ch'], 		 // ed_wdh
							['Chris die Seele', 'CS'],		['Gliwi', 'Gl'],
							['Dan Koehl', 'DK'], 	 // ed_wdh
							['Erlenmeyer', 'Er'], 	 // ed_wdh
							['Doc Taxon', 'DTx'], 	 // ed_wdh
							['Ipankonin', 'Ip'],  	 // ed_wdh
							['Jimmy44', 'JN'],
							['Jpgibert', 'JPG'],  	 // ed_wdh
							['Jรผrgen Krause', 'JK'],
				//			['Kaboldy', 'Ka']		 // ed_wdh
							['Lanaud', 'Tl'],		 // ed_wdh
				//			['Macucal', 'Ma']		 // ed_wdh
							['Madboy74', 'Mb'],
							['MaxxL', 'ML'],
							['Milenioscuro', 'Mi'],	 // ed_wdh
							['Odejea', 'Od'],		 // ed_wdh
							['Ruthven', 'Ru'],		 // ed_wdh
							['SajoR', 'Sa'],		 // ed_wdh  (Alejandro Rojas)
							['Simon.eller', 'SE'],	 // ed_wdh
							['Spax89', 'S0'],
							['Spedona', 'Sp'],		// ed_wdh
							['SteveK', 'SK'], 
							['Syriatsu', 'Sy'],		// ed_wdh
							['Thom.Lanaud', 'TL'],	// ed_wdh
							['The Eloquent Peasant', 'PE'],	//ed_wdh
							['Zardoz91', 'Za']  	 // ed_wdh
				
						];
						let l = coaUsers.length;
						while (l--) {
							if (txt.indexOf(coaUsers[l][0]) !== -1) {
								user = coaUsers[l][1];
								coaUsers = coaUsers[l][0];
								break;
							}
						}
					}
					if (user) {
						if (err) {
							IgenName += 'I|' + err + '|s=:CoA by ' + coaUsers + T;
						} else {
							IgenName = '|image' + s2 + '=' + s2 + user;		// ed_wdh
							tempPre = '\n';
						}
						if (user !== 'f') {								// ed_wdh
							// Remove redundant cats (when Igen/coa writes them)
							coaUsers = {
								Ch: 'Blason chatsam',					// ed_wdh
								DK: 'Coats of arms by Dan Koehl',		// ed_wdh
								Er: 'Contribuciones de Erlenmeyer',		// ed_wdh
								Ip: 'Images by Ipankonin',				// ed_wdh
								Gl: 'Files by User:Gliwi',
								JN: 'Files by User:Jimmy from fr.wikipedia',
								Mi: 'Coats of arms by User:Milenioscuro',	// ed_wdh
								ML: 'COAs by User:MaxxL',
								Mb: 'Pictures by Madboy74 - 0',
								Za: 'SVG coats of arms of France',		// ed_wdh
								Od: 'Files by Odejea/SVG coat of arms',	// ed_wdh
						//		Ka: 'Files by User:Kaboldy',
								Sy: 'Blason par Syryatsu',				// ed_wdh
								S0: '{{Projet Blasons}}'	 // "Blason spax89" don't want
						//		"SK": "COA by SteveK"  don't want
							}
							[user];

							if (coaUsers && ['S0', 'SK'].indexOf(user) === -1) { // Spax, Steve do not want
								coaUsers = '[[Category:' + coaUsers + ']]\n';
							}
						}
						if (coaUsers) {
							if (txt.lastIndexOf(coaUsers) < topp)
								topp -= coaUsers.length;
							txt = txt.replace(coaUsers, '');
						}
						// replace only TODO: may skip this complete or check the replacing para
						if (imgen) {
							// topp -= txt.length;
							// TODO: exclude unsure users (with multiple shorthands)
							if (['ML', 'JN', 'S0', 'SK'].indexOf(user) === -1)
								txt = txt.replace(imgenRE, template + '\n');
							// topp += txt.length;
							IgenName = '';
							tempPre = '';
							s1 = '';
						}
						// ls = ""; // delete other fields?
					} else if (!imgen) { // Default
						IgenName = '|image' + s2 + '=' + s2 + err;   // ed_wdh
						tempPre = '\n';
					}
				} else {
					IgenName += toolName + (err ? '|' + err : '') + '|+' + g + T + '|s=' + s;
				}
			}

			txt = txt.substr(0, topp) + s1 + IgenName + tempPre + ls + txt.substr(topp);
			return txt;
		}
		mw.log.warn('Igen not inserted ');
		return {
			type: 'warn'
		};
	},

	addToFileDesc: function ($textarea, e, warn, toolName) {
		// WikiEditor
		$textarea = $textarea.$textarea || $textarea;
		return mw.loader.using('oojs-ui-core', function () {
			let txt = $textarea.val();
			if (typeof e === 'string') {
				e = Number(e);
				if (e)
					cSVG.warnMsg(e);
				if (warn)
					cSVG.warnMsg(warn);
			}
			$.removeSpinner('w3nu');
			txt = cSVG.replaceTag(txt, e, toolName);
			if (txt) {
				if (txt instanceof Object)
					return cSVG.warnMsg(txt);
				else
					$textarea.val(txt);
			}
			// mw.notify("Igen inserted ", { title: "Done!" });

			$('#wpSummary').val(function (i, v) {
				return (v.replace(summary, '') + ' ' + summary).trim();
			});
			$('#wpMinoredit').prop('checked', 1);
			// if (typeof e === 'string')
			mw.hook('gadget.cleanup.done').add(function () {
				mw.loader.using(['mediawiki.action.edit.preview', 'mediawiki.diff.styles']).always(
					function () {
					$('#wpDiff').trigger('click');
				});
			});
			// TODO: may only manual or cleanup same time?
			mw.hook('gadget.cleanup.run').fire({ text: 0 });
			return false;
		});
	},

	addIgenURL: function (err, size, toolName, para) {
		let param = '';
		if (typeof err === 'number')
			console.log('Successfully checked for SVG errors: ', err);
		// else err = 0;
		size = ($.isArray(size)) ? '&SVGsize=' + size[0] + '|' + size[1] + '&username=' + encodeURIComponent(c.wgUserName) : '';
		toolName = toolName ? '&toolname=' + encodeURI(toolName) : '';
		if (para instanceof Object) {
			$.each(para, function (i, o) {
				param += '&' + i + '=' + Number(o);
			});
		}
		location.href = mw.config.get('wgScript') + '?title=' + encodeURIComponent(c.wgPageName) + '&action=edit&' + cSVG.name + '=' + err + size + toolName + param;
	},

	/**
	 * Get the text of a template
	 * @param {string} fullStr
	 * @param {number} start
	 * @return {string} endPart
	 */
	getTempBlock: function (fullStr, start) {
		start = start || 0;
		let pos = 0,
		endPos = 0,
		RE = /\}\}/g,
		endPart = fullStr.slice(start + 2);
		while (RE.test(endPart)) {
			endPos = RE.lastIndex;
			// console.log(endPos, endPart.slice(pos, endPos - 2));
			if (!/\{\{/.test(endPart.slice(pos, endPos - 2)))
				break;
			pos = endPos;
		}
		endPart = endPos ? fullStr.slice(start, start + endPos) : '';
		return endPart;
	},

	insertIgenSub: function () {
		let txt = $textarea.val(),
		$this = $(this),
		sub = $this.data('key'),
		igenRE = /\s*\{\{[Ii](m?gen|mage[ _]generation)/g, // =?
		t1 = 0, // first
		t2 = 0; // last
		if (igenRE.test(txt)) {
			t1 = igenRE.lastIndex;
		} else {
			cSVG.warnMsg({
				title: 'Igen not found!',
				type: 'warn'
			});
			return;
		}
		igenRE = /\|\s*[Ss](ub|[c: -m])?= ?([^\n|}]*)/g;
		t2 = txt.substr(t1);
		if (igenRE.test(t2)) {
			t2 = t1 += igenRE.lastIndex;
			t1 -= RegExp.lastMatch.length;
		} else {
			t2 = cSVG.getTempBlock(t2);
			//	console.log('getTempBlock', t2);
			igenRE = /([^\n|}]+)/g;
			if (igenRE.test(t2)) {
				let lastIndex = igenRE.lastIndex;
				igenRE.lastIndex = 0;
				while (igenRE.test(t2))
					lastIndex = igenRE.lastIndex;
				// console.log('para', RegExp.lastMatch);
				t2 = t1 += lastIndex;
			} else {
				t1 = 0;
			}
		}
		cSVG.XHR.abort(); // current ajax
		$this.off('mouseover');
		if (t1) {
			txt = txt.substr(0, t1) + '|s=' + sub + txt.substr(t2);
			$textarea.val(txt);
		} else { // Should never happen?
			cSVG.warnMsg({
				title: 'Igen not valid!?',
				type: 'error'
			});
		}
	},
	// Template:AutVec
	insertAutVec: function ($textarea) {
		let autRE = /^( *\|\s*[Aa](?:uthor|rtist)\s*=\s*)\*? ?(?:{{[Uu]nknown\|?(?:artist|author)?}}\s*)?(?:\*? ?vectorized by \s*)?({{[Uu]\|([^|\n]+)}}|[^\n]+) *$/m,
		txt,
		lm,
		pr,
		p1,
		p2,
		pre = '{{AutVec|',
		post = '}}';
		$textarea = $textarea.$textarea;
		txt = $textarea.val();

		if (autRE.test(txt)) {
			lm = RegExp.lastMatch;
			pr = RegExp.$1;
			p1 = RegExp.$2;
			p2 = RegExp.$3;
			if (!p2 && /(?:\[\[(?:[Uu]ser:)?)([^|\n]+)(\|\1)?(?:\]\])/.test(p1))
				p2 = RegExp.$1;
			p2 = p2 ? '|' + p2 : 'o=|2=' + p1;
			txt = txt.replace(lm, pr + pre + p2 + post);
			$textarea.val(txt);
		} else {
			$textarea.textSelection('encapsulateSelection', {
				pre: pre + 'o=|2=',
				post: post
			});
		}
	},

	addButtons: function ($textarea) {
		cSVG.done = 1;
		$textarea.on('wikiEditor-toolbar-buildSection-IgenSub', function (/* event, section*/) {
			$.removeCookie('wikiEditor-0-toolbar-section', {
				path: '/'
			});
			// $('.wikiEditor-ui-toolbar .sections').hide(); not working
			$('#wikiEditor-section-IgenSub')
			.attr('aria-expanded', 'false')
			.removeClass('section-visible')
			.addClass('section-hidden')
			.parent().hide();
		});

		$textarea.wikiEditor('addToToolbar', {
			section: 'main',
			groups: {
				SVG: {
					tools: {
						Igen: {
							label: 'SVG Image Generation (+W3Ccheck)',
							type: 'button',
							icon: 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/6c/SVG_Simple_Icon.svg/24px-SVG_Simple_Icon.svg.png',
							action: {
								type: 'callback',
								execute: mw.libs.simpleSVGcheck.getW3Data
							}
						},
						AutVec: {
							label: 'Author-Vector',
							type: 'button',
							icon: 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Gnome-vector-author.svg/24px-Gnome-vector-author.svg.png',
							action: {
								type: 'callback',
								execute: mw.libs.simpleSVGcheck.insertAutVec
							}
						},
						descCleanup: {
							label: 'Description cleanup (without Igen)',
							type: 'button',
							icon: 'https://upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Gnome-vector-cleanup.svg/24px-Gnome-vector-cleanup.svg.png',
							action: {
								type: 'callback',
								execute: mw.libs.simpleSVGcheck.addToFileDesc
								// execute: function (el) { cSVG.addToFileDesc(el.$textarea); }
							}
						}
					}
				}
			},
			sections: {
				IgenSub: {
					type: 'booklet',
					// label: 'SubCats',
					pages: {
						subtree: {
							// label: 'SubCats1',
							layout: 'characters'
						}
					}
				}
			}
		});
		this.$button = $('#wikiEditor-section-main .group.group-insert a[rel="Igen"]').css('float', 'left');
		// Made section button (HACK)
		$('#wikiEditor-ui-toolbar .tabs .tab-IgenSub')
		.before(this.$button)
		.find('a').css('padding', '0 8px').append($('<img>', {
				'src': 'https://upload.wikimedia.org/wikipedia/commons/thumb/3/32/SVG_category_subtree.svg/24px-SVG_category_subtree.svg.png',
				'width': 22,
				'height': 22,
				'title': 'Igen subtree parameter',
				'rel': 'IgenSub',
				'role': 'button',
				'class': 'tool tool-button'
			})).one('click', cSVG.addToolbar);

		// Add another toollink to the edit-dropdown
		mw.loader.using('ext.gadget.editDropdown', function () {
			mw.libs.commons.ui.addEditLink('', 'SVG Igen +', 'e-igen', 'Insert Template:Image_generation with W3-validity')
			.addEventListener('click', mw.libs.simpleSVGcheck.getW3Data);
		});
	},
	getIgenTop: function () {
		let $this = $(this),
		toolTip,
		// mouseOut = function(){ if ($this.tipsy) $this.tipsy('hide'); },
		mouseOut = function (tooltip) {
			if (tooltip && tooltip.visible)
				tooltip.toggle(false);
		},
		json = cSVG.jsonIgenTop,
		r,
		lang = c.wgUserLanguage,
		sub = $this.data('key');
		if (!sub)
			return false;
		// $this.tipsy(); // install tooltip
		// Auto-close
		setTimeout(function () {
			if (!toolTip || !toolTip.visible)
				return;
			setTimeout(function () {
				mouseOut(toolTip);
			}, 2000);
		}, 1000);

		function addTooltip(r) {
			// $this.attr('title', r).tipsy('show');
			let tooltip = new OO.ui.PopupWidget({
					padded: true,
					width: 'auto',
					align: 'forwards',
					// label: $this.attr('title'),
					// classes: [ 'mw-revslider-tooltip', 'mw-revslider-revision-tooltip' ],
					$content: r
				});
			$this.append(tooltip.$element)
			// .removeAttr('title')
			.on('mouseout', function () {
				mouseOut(tooltip);
			})
			.on('mouseover', function () {
				tooltip.toggle(true);
			});
			// setTimeout(function () { if (tooltip) tooltip.toggle(false); }, 2000);
			tooltip.toggle(true);
			toolTip = tooltip;
		}

		function getParse(text) {
			// console.log('getParse', text);
			// $.getJSON('/w/api.php?action=expandtemplates&format=json&text=%7B%7BIgen%2Ftop%7C' + sub + '%7D%7D&prop=wikitext',
			cSVG.XHR = $.getJSON('/w/api.php?action=parse&format=json&text=' + text + '&prop=text&pst=1&disablelimitreport=1&disableeditsection=1&disabletidy=1&contentmodel=wikitext&noimages=1', function (r) {
					// if (!(r = r.expandtemplates) || !(r = r.wikitext))
					if (!(r = r.parse) || !(r = r.text) || !(r = r['*']))
						r = $('<p>').text(sub);
					else
						r = $(r).unwrap(); // div
					if (!(text = r.html()))
						return;
					addTooltip(r);
					// Save parsed to json for possible later usage
					cSVG.jsonIgenTop[sub][lang] = text;
				});
		}
		// TODO: could be outsourced as lib
		// r = json[sub]
		function langSwitch(r) {
			let i;
			if (!(lang in r)) {
				lang = 'en';
				// Allow input in format: {{LangSwitch|de=Grรผn|es/it/pt=Verde|fr=Vert|en=Green |lang=en}}
				// with multiple languages mapping to a single value
				for (let name in r) {
					var val,
					args;
					if (typeof name === 'string' && (val = r[name])) {
						args = name.split('/');
						if (args.length === 2)
							for (i = 1; i >= 0; i--)
								r[args[i]] = val.replace('{{{lang|{{int:lang|}}}}}', args[i]);

						// TODO: {{#switch:{{{1}}} pre parse?
					}
				}
				cSVG.jsonIgenTop[sub] = r; // put back
				// get the list of accepetable language (lang + those in lang's fallback chain) and check their content
				for (i = cSVG.langChain.length - 1; i >= 0; i--)
					if (cSVG.langChain[i]in r)
						lang = cSVG.langChain[i]; // no break as lower i is better

			}
			r = r[lang];
			// if (r)?
			if (/{/.test(r))
				getParse(encodeURIComponent(r));
			else
				addTooltip($('<p>').html(r));
		}

		// JSON source!
		if (json instanceof Object && (r = json[sub])) {
			if (r instanceof Object) {
				langSwitch(r);
			} else if (typeof(sub = r) === 'string' && (r = json[r]) && r instanceof Object) {
				// link
				langSwitch(r);
			} else {
				r = 0;
			}
		}
		if (!r) { // Fallback API parse!?
			getParse('%7B%7BIgen%2Ftop%7C' + sub + '%7D%7D');
		}
	},

	addToolbar: function () {
		$.getJSON('/w/index.php?title=Template:Igen/sub.json&action=raw', function (r) { // &ctype=text/javascript
			// mw.util.addCSS( '#wikiEditor-section-IgenSub .index{display:none}\n#wikiEditor-section-IgenSub .page div span {line-height:.8em;font-size:.8em;}' );
			if (c.wgUserLanguage === 'en') {
				cSVG.getIgenTop = null;
			} else {
				$.getJSON('/w/index.php?title=Template:Igen/top.json&action=raw', function (json) {
					cSVG.langChain = mw.language.getFallbackLanguages();
					cSVG.jsonIgenTop = json;
				});
			}
			mw.loader.load('oojs-ui'); // 'jquery.tipsy'
			let section = [],
			itemChk = {},
			$section = $('#wikiEditor-section-IgenSub');
			$section.find('.index').remove();
			// TODO: could be improved
			$.each(r, function (key, value) {
				let title = key,
				mouseover = cSVG.getIgenTop;
				if (!value) {
					value = '-';
					title = 'inhibit subcategorizing';
					mouseover = null;
				} else {
					value = value.replace('&#58;', '');
				}
				// Exclude double values
				if (itemChk[value]) {
					// console.log(value, 'is double', key, itemChk[value]);
					return;
				}
				itemChk[value] = key;
				section.push($('<span>', {
						title: title,
						data: {
							key: key
						},
						text: value,
						style: 'font-size:.8em',
						click: cSVG.insertIgenSub
					})
					// .tipsy({title: mouseover, fallback: title })
					.one('mouseover', mouseover));
			});
			$section.find('.page div').append(section);
			$section.parent().animate({
				opacity: 1
			}, 200);
			// });
		});
	}
};

mw.libs.simpleSVGcheck = cSVG; // Expose globally

if (mw.config.get('wgNamespaceNumber') === 6 && /SVG$/i.test(c.wgTitle)) {
	if (isEdit) {

		// Allways collapsed
		if ($.fn.cookie && $.cookie('wikiEditor-0-toolbar-section') === 'IgenSub')
			$.removeCookie('wikiEditor-0-toolbar-section', {
				path: '/'
			}); // 0 is original $( this ).data( 'context' ).instance

		// Late try?
		// (window.RLQ = window.RLQ || []).push(function () {
		window.addEventListener('load', function () {
			if ($.fn.wikiEditor && mw.loader.getState('ext.wikiEditor') === 'ready') {
				if (!cSVG.done)
					cSVG.addButtons($textarea);
			} else if (expeUser) {
				mw.log.error('WikiEditor not ready!?', mw.loader.getState('ext.wikiEditor'), $textarea, $.fn.wikiEditor);
			}
		});
		$textarea = $('#wpTextbox1');
		// Early try, direct load (as we don't know if the ready load event triggered)
		if ($textarea[0]) {
			$textarea.on('wikiEditor-toolbar-doneInitialSections', function () {
				if (!cSVG.done)
					cSVG.addButtons($textarea);
			});
		} else if (expeUser) {
			throw Error('$textarea is not ready!?!');
		}
		/* if (mw.loader.getState('ext.wikiEditor') === 'registered') {
		mw.loader.using('user.options', function () {
		if (!mw.user.options.get('usebetatoolbar')) mw.log.warn('You must enable the Wikieditor to use the SVG-Igen buttons.');
		});
		}*/
		// Force Wikieditor on!?
		$.when(mw.loader.using(['mediawiki.util', 'mediawiki.user', 'jquery.spinner', 'ext.wikiEditor']), $.ready).always(function () {
			// if (mw.config.get('wgPageContentModel') === 'wikitext' && /^(edit|submit)$/.test(c.wgAction)) {
			// deprecated [[phab:T30856]]
	/*		mw.loader.using( 'mediawiki.toolbar', function () {
			mw.toolbar.addButtons( {
			speedTip: 'SVG Igen',
			imageFile: 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/6c/SVG_Simple_Icon.svg/24px-SVG_Simple_Icon.svg.png',
			onClick: mw.libs.simpleSVGcheck.getW3Data
			} );
			});
 	*/		// $textarea = $( '#wpTextbox1' );
			if (!cSVG.done)
				cSVG.addButtons($textarea);
			// cleanup?
			if (!mw.libs.fastCleanup)
				importScript('User:Sarang/cleanup.js');    // ed_wdh
			// Get parameter
			let URL = window.location.search,
			param = {},
			nameReg = new RegExp(cSVG.name + '=(\\d+)', 'g');
			err = nameReg.test(URL);
			if (c.wgAction === 'edit' && err) {
				cSVG.err = err = mw.util.getParamValue(cSVG.name);	// TODO only one err needed
				cSVG.size = mw.util.getParamValue('SVGsize');
				c.wgUserName = mw.util.getParamValue('username');
				toolName = mw.util.getParamValue('toolname');
				let URn = URL.substr(nameReg.lastIndex + 1);		// RL is readonly ?
				for (let aItKey, nKeyId = 0, aCouples = URn.split('&'); nKeyId < aCouples.length; nKeyId++) {
					aItKey = aCouples[nKeyId].split('=');
					param[aItKey[0]] = aItKey.length > 1 ? Number(aItKey[1]) : 0;
				}
				$.extend(cSVG, param);
				cSVG.addToFileDesc($textarea, err, '', toolName);
			}
		});
	} else {
		mw.loader.using(['ext.gadget.jquery.badge', 'ext.gadget.editDropdown'], cSVG.init);
	}
	// mw.libs.simpleSVGcheck.addButtons($('#wpTextbox1')); // DEBUG
}
}
(jQuery, mediaWiki));
// EOF </nowiki>