User:Chealer/simpleSVGcheck.js

/**
* @description Adds several SVG-valid-check-links on file-pages.
* Adds a "B?" button offering to display the exact size (in bytes) in the File history section's Dimensions column for SVG files.
* Also adds a "→SVG Igen" link in the same column to put the Igen template prefilled in the file-description page.
* For usage show [[c:Template:Image generation]]
* 
* History:
* 2016-07-14 added tool-name recognition from SVG-code
* 
* This script was created by Perhelion. After he quit Wikimedia in 2019, this script was adopted by Sarang, who tried some fixes and enhancements despite his lack of JS knowledge because nobody else did it.
* It can be seen that Sarang made a lot of helpless tries while heavily fighting with JS, which he marked using "ed_" comments like the one on this line,		//ed_
* so that it can easily be seen which things he made much more complicated than an expert would have. Some things that he made work―more or less. Others don't.
* In October 2024, after Sarang's 2023 death, Chealer merged the 2 versions into this new user page which will hopefully replace both [[User:Sarang/simpleSVGcheck.js]] and [[User:Perhelion/simpleSVGcheck.js]].
* 
* Last revision: 2024-10-21 05:00 by Chealer
* 
* @author [[User:Perhelion]] and [[User:Sarang]]
* @License: CC BY-SA 3.0
* @requires modules: jquery.badge, mediawiki.api, mediawiki.util, jquery.spinner
* @TODO: Move out of User:Chealer/
**/
// [[Category:User scripts|simpleSVGcheck]] <nowiki>
/* eslint-env es6*/
let tstex = 0;	// global counter
let lcode = '';	// global langtst
(function ($, mw) {
'use strict';
let gbs = [],
c = mw.config.get([
			'wgAction',
	//		'wgScriptPath', 'wgScript',
			'wgPageName', 	'wgTitle',
			'wgUserLanguage',
			'wgUserName'	// For simplSVG
		]),
isEdit = /^(edit|submit)$/.test(c.wgAction),
err,
// size, // For simplSVG
toolName,
$textarea,
expeUser = /^Sarang|Sarangbot|JoKalliauer|Perhelion|Minorax$/.test(c.wgUserName),
myName   = c.wgUserName,
// Author= /^Hagar66|NordNordWest|TUBS$/.test(txT), // author with PGF ** invalide JS **
summary  =  '[[User:Sarang/simpleSVGcheck.js|script]]+SVG-[[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
//	lcode: '',		// langtst	
	curSize: 0,
	flowRoot: 0,
	textPath: 0,
	timestamp: 0,
	badSVG: 0,											// 1=bad; 2=fake; 3=fake
//	author: 0,
//	PGFauthor: /^Hagar66|NordNordWest|TUBS$/.test(txT), // author with PGF  ** invalide JS **
	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('');
			});
		});
	},				// init 

	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);
			});
		});
	},				// image 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
			});
		});
	},				// warn msg

	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,
//				lcode = code.slice(0, 14),		// langtst 
				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);							// 1=bad
				para.PGF = /strator_pgf">\s*(<!\[CDATA\[\s*)?[a-zA-Z]+/.test(code);	// pgf very different
				let toolName = cSVG.toolName = cSVG.getToolName(code, para.PGF);
				para.flowRoot = /[<:]flowRoot/.test(code);
				para.timestamp = /Martin Weinelt<\/tspan/.test(code); 			// 
				if (!para.timestamp)
					para.timestamp = /Christian Duscha<\/tspan/.test(code);
				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|polyline|polygon)[\s>]/.test(code))
					para.badSVG = 2; // Fake SVG
				if (para.badSVG && !/[<:]path[\s>]/.test(code) && /[<:]text[\s>]/.test(code))
					para.badSVG = 3; // Fake SVG with text
				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;
	},				// getW3Data

	/**
	 * 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',
			'DrawShield',
			'ElCompLib',	// ed_wdh
			'Method Draw',	// Cookieman1.1.1
			'Microsoft Visio',
			'Chemtool',
			'ChemSketch',	// ChristianBausW	
			'bkchem',
			'dvisvgm',
			'Batik',
			'ArcMap',
			'Adobe',
	//		'parliament diagram creator'],
			'Generated with Qt',			// <desc>Generated with Qt</desc>
			'Ratio="xMidYMid meet',			// can be DrawShield ?
			'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;
	},				// getToolName

	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');
		});
	},				// setImgSize

/*	 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"], {
	}, {
	});
	},				// registerModules
	
	run: function() { // Create GUI
	cSVG.registerModules();
	mw.loader.using(['mediawiki.commons.MwJSBot'], function() {
	});
	},				// run
*/

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

	replaceTag: function (txt, err, toolname) 
	{	if (!txt)
			return;
		let size = this.size,
		txT = txt,	//.replace(/( *\| *[Ii]m)(?:gen|ag)?( *= *)/, '$1age$2'),		//	pre_normalize [im, imag, imgen]
/*		Info/var	imRe: not-empty parameter
	Information		|other fields		{{file generation description
	COAInformation	|imgen, image		{{igen
	Infor[m]		|im, imag[e]		{{image generation
*/		imRE = /^\s*\| *(?:[Oo]ther[_ ]fields|[Ii]mage) *=\s*\{\{(?:[Ii]genc?|[Ii]mage generation|[Ff]ile generation description) *\|(\w+)\}\} *$/m,
//		ivar = /\{\{ *[Ii]nform?\s*\|\s*/.test(txT),								// Info/var
		imag = '|image',															// parm
		coai = /\{\{ *COAInformation\s*\|\s*/.test(txT),								// coat of arms template boolean
		imageRE = /\|\s*[Ii]mage\s*=\s*[^\s]+ *\n/,									// COA short parm (^imgen)
		imgenRE = /\|\s*[Ii]ma?gen?\s*=\s*[^\s]+ *\n/,								// COA short parm (=imgen)
		imPar = ((coai && imageRE.test(txT)) || imRE.test(txT)),						// coai & image, O_f
		toolName = '',			// default nothing, most possible is Inkscape
	//	IgenVar  = (coai) ? '|fields' : '|other fields',								// decide which param name
		IgenParm = (coai) ? '|image       ' : '|other fields',		// from here it comes  decide which param name
 		// sourcecode, // possible from which are generated for "Created with code"
		g = '',  // specify the Graphic lab
		r = '',  // retouched
		s = '',  // suffix for subcat = "topic"							💵💵💵💵💵💵💵💵💵💵💵
		T = '',  // additional trailing text for templates (extension)	💵💵💵💵💵💵💵💵💵💵💵
		p5 = '', // Parameter 5
		s1 = '', // leading whitespaces as indent?
		s2 = '', // whitespace on parameter?
		ls = '', // last substring index
		stxt = '|s=',	// or |s:=	
		topp = '', // template igen on topposition
		replaced = false,
		LeyoChem = false,
	 	Otagtab =					//  Other Tags Table:
		{	"bf"  : false,			//	broken file
			"bl"  : false,			//	colorblind
			"ci"  : false,			//	current int.
			"ff"  : false,			//	fictitious flag
			"fi"  : false,			//	fake sports logo
			"fw"  : false,			//	fotowerkstatt		??fw??
			"lh"  : false,			//	logo hist
			"ni"  : false,			//	no inkscape ()
			"nu"  : false,			//	noUpdate
			"oq"  : true,			//	opaque
			"ov"  : false,			//	overlay
			"re"  : false,			//	recent
			"rs"  : false,			//	restoration
			"tr"  : false,			//	translate
			"tw"  : false,			//	taken with 
			"up"  : false,			//	update/outdate
			"zf"  : false			//	zoofary
		},
		Fwrktab =					//  Fotowerkstatt
		{	"fwc"  : false,			//	change
			"fwe"  : false,			//	editor
			"fwo"  : false,			//	orig
			"fwl"  : false,			//	orig-lang
			"fwt"  : false,			//	topic
			"fws"  : false,			//	style
		},
	//		ofRC = /( )*\|\s*[Oo]ther[_ ]fields( )*=\s*([^\n]*\n)/g,			// $1, $2, $3
		ofRE = /( )*\|\s*(?:[Oo]ther[_ ]fields|image)( )*=\s*([^\n]*\n)/g,	//  Info/var $1, $2, $3
		inRE = 
		[	/\{\{(COA)?[Ii]nform?(ation)?\s*\|\s*/,							//  var
			/( )*\|\s*[Pp]ermission( )*=\s*[^\n]*\n/,
			/( )*\|\s*[Oo]ther[_ ]versions( )*=(\n?[^\n]*\n)/
		],
		IgenName = '{{Igen|',
		IgenNameLong = '{{Image generation|',
		tempPre = '}}\n',
		fnam = c.wgTitle.slice(0, -4),	// without .extension 		
		fext = c.wgTitle.slice(-4),		// = .svg
	//	fbmp = '',			// fname of raster 
	//	fbmx = '',			// exten of raster 
		user = '',			// for u=
		
		// Normalized toolnames different to code
		toolNames = 
		{	'Fig2svg': 'Fig2SVG',
			'Illustrator': 'Adobe',	'Adobe Illustrator': 'Adobe',
			'bkchem': 'BKchem', 	'Bkchem': 'BKchem', 
			'Libreoffice': 'LibreOffice',
			'Microsoft Visio': 'Visio',
			'DrawShield': 'DrawShield', 
			'geogebra': 'GeoGebra',	
			'Openoffice': 'OpenOffice.org',
			'Generated with Qt': 'Qt',
			' potrace': 'Potrace',
			' Perl': 'perl',
			' graphviz': 'Graphviz',  ' dot version 2.2.1': 'Graphviz',
			'Dvisvgm': 'dvisvgm',								// sombody made it uppercase;
			' vector-effect="none" ': 'Natural Earth',			// maybe more ident is needed
			'path vector-effect': 'Natural Earth',				// maybe more ident is needed
			'Ratio="xMidYMid meet': 'DrawShield',
			'BaseProfile="full"': 'GeoGebra'
		},
		
		// 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',
			'Text Editor': 'T',
			'Parliament': 'Wpdc'
		},
		// Full replace - use templates:W		Expand this table when there are more (W)ikilink templates 
		Langtab = 
		{	"en" :	"W" ,
			"ar" :	"WA" ,				// arab     199K
			"bn" :	"Wb" ,				// bengali  131K
			"ca" :	"WC" ,				// catalan
			"cs" :	"Wc" ,				// czech/český
			"da" :	"Wda" ,				// danish   136K
			"de" :	"Wd" ,
		//	"el" :	"Wel" ,				// hellenian 126K
		//	"eo" :	"Weo" ,				// esperanto 139K
			"es" :	"We" ,
			"et" :	"Wet" ,				// estonian  112K
			"fa" :	"Wfa" ,				// persian   199K   
			"fi" :	"Wfi" ,				// finnish   257K
			"fr" :	"Wf" ,
			"gl" :	"Wg" ,
			"he" :	"Whe" ,				// ivrit     432K
		//	"hr" :	"Whr" ,				// croatian  102K
			"hu" :	"Wh" ,
		//	"id" :	"Wid" ,				// indonesian 95K
			"it" :	"Wi" ,
			"ja" :	"W日" ,				// japanese 1.116M
			"kn" :   "ವಿ" ,				// Kannada    4K –— very seldom
			"ko" :	"W말" ,				// korean
			"lt" :	"Wlt" ,				// lithunian   77K
			"lv" :	"Wlv" ,				// latvian     68K
			"mk" :	"Wm" ,				// makedonian 143K
			"ml" :   "വി" ,				// malayalam  29K –— seldom
			"nl" :	"Wn" ,
		//	"no" :	"Wno" ,				// norsk (nb=Norsk Bokmål, 242K)   (nn=Norsk Nynorsk,  15K)
			"pl" :	"WP" ,
			"pt" :	"Wp" ,
			"ru" :	"Wr" ,
		//	"sa" :	"Wsa" ,				// sanskrit   2K –— very seldom
		//	"sc" :	"Wsc" ,				// sardinian  1K –— very seldom
		//	"sd" :	"Wsd" ,				// sindhi     1K –— very seldom
			"si" :   "වි" ,				// sinhala     2K –— very seldom
			"sk" :	"Wsk" ,				// slovak (Slovenčina)  155K
			"sl" :	"Wsl" ,				// sloven (Slovenščina) 127K
		//	"sq" :	"Wsq" ,				// albanian   51K
			"sr" :	"Wsr" ,				// serbian   189K
			"su" :	"Wsu" , 			// sundanese  ~2K –— very seldom
			"sv" :	"Wsv" ,
			"th" :	"Wth" ,
			"tr" :	"Wtr" ,
			"uk" :	"Wu" ,
			"zh" :	"Wz"
		},
		// Dynamic table of users	(expanded by function when existence is checked)
		Usertab = 
		{	"Perhelion" :	"U" ,	// may be U, Ut, Uw, Uwt, Un, Uc, Uf
	//		"Sarangbot" :	"U" ,
			 myName     :   "U" ,	// dyn. (test)
			"CdnMCG"	:	"U" ,	// temp.
			"Cburnett"  :	"U" ,	// temp.
	//		"Delta-9"	:	"U" ,	// temp. (Steve Perucchi, Geneva)
			"D Wells"	:	"U" ,	// temp.
			"Etxeko"    :   "U" ,	// temp
			"Erlenmeyer":   "U" ,
			"GabrielStella":"Ut" ,	// temp.
			"Gigillo83" :	"Ut" ,	// temp.
			"Jimmy44"   :	"U" ,	// temp.
			"Manassas"  :	"Uwt" ,	// temp.
			"Miyagawa":"U", "Pixelsquid":"U",
			"Miguillen"	:	"U" ,	// temp.
			"NEUROtiker":	"U" ,	// temp.
			"Smokefoot" :	"U" ,	// temp.
			"Rodelar"	:	"U" ,	// temp.
			"Urhixidur" :	"U" ,	// temp.
			"NordNordWest": "U", "TUBS":"U", "Hagar66":"U",	// temp.
			"JoKalliauer":	"U"
		};

		/*
		 * t instanceof RegExp - "top position"
		 * 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
		}				// enc

		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;
		}				// _findPosition
		
	//	 * ============================================================ langtst
	function syslang ()  {return '/' + lcode;}
//	function syslang ()  {return lcode.slice(0, 44) + '/' + this.curSize;}
	//	 * ============================================================
	function _ucfirst(s)		// Uppercase
		{	return s.slice(0, 1).toUpperCase() + s.slice(1);
		}
	//	 * ============================================================
	function isHexval (val)		// test whether hexad
    	{ let retval = new RegExp('[0-9a-fA-F]');
    		return retval.test(val);
    	}
	//	 * ============================================================

	function pageExists(pagename, callback)
	{	$.ajax(mw.util.getUrl(pagename), 
		{	method: 'HEAD',
			success: function() { callback(true); },
			error: function(xhr) { callback(xhr.status === 404 ? false : null); }
		});
	}				// 

	function userExists(pagename, namespac) 
	{	++tstex;							// add 1 for each one of the expensive accesses
		pageExists(pagename, function(userexists) {
			var result = userexists ? namespac : 'Un';
			callback(result);
		});
	}				// 

	//	 * ============================================================
	function pageexist( pagename, callback )
	{	mw.loader.using( 'mediawiki.api', function () 
		{	( new mw.Api() ).get(
				{	action: 'query',
					prop: 'info',
					titles: pagename,
					formatversion: 2
				}, 
				{	success: function ( response ) 
					{	var page = response.query.pages[ 0 ];
						if ( page.invalid )
							{ callback( null );}
						else 
						if ( page.missing ) 
							{ callback( false );}
						else
							{ callback( true );}
					},
					error: function () { callback( null ); }
			}
		);
		} );
	}				// pageexist 
 	//	 * ============================================================
		function userexist( username, namespace ) 
		{	let retval = 'Un'; 
				++tstex;							// add 1 for each one of the expensive accesses
				pageexist ( username, (boolres) => 
			{	//	await;
				if (boolres)	retval = namespace;	// ns when 'true'
	//			else 
	//			if (boolres == null)	// CommonsMaintenanceBot issue
	//							retval = 'Uf';		// when 'null' 
	 			else retval = 'Un';					// when 'false'
			}); //setTimeout ( function() {return;} , 250);
				alert('r='+retval+'/'+username);	// does not work without
			return retval;
		}				// 
	//	 * ============================================================
	//	function get_param(ctxt) {
	//		return ctxt.replace(/\{\{(?:[^\|]*)\|([^\}]*)/, '$1');		// analize transcusion, and get params
	//	}																// not working test

		function generalCleanup(text) 
		{	// TODO: namespace User could be extended with any language
			// lowercase parameter name default, trim leading whitespace
		Otagtab.bf = (/\{\{\s*[Bb]roken file\s*[\|\}]/.test(txT)); 		// other tags
		Otagtab.bl = (/\{\{\s*[Cc]olou?r ?blind\s*[\|\}]/.test(txT));
		Otagtab.ci = (/\{\{ *[Cc]urrent *[\|\}]/.test(txT));
		Otagtab.ff = ( (/\{\{ *[Ff]ictitious flag *[\|\}]/.test(txT)) || (/\{\{ *[Ff]ictional flag *[\|\}]/.test(txT)) );
		Otagtab.fw = ( (/\{\{ *[Ff]otowerkstatt *[\|\}]/.test(txT)) || (/\{\{ *[Bb]ilderwerkstatt *[\|\}]/.test(txT)) );  //  ??fw??
		Otagtab.fi = ( (/\{\{ *[Ff]ake sports logo *[\|\}]/.test(txT)) || (/\{\{ *[Bb]andeira falsa *[\|\}]/.test(txT)) );
		Otagtab.lh = (/\{\{ *[Ll]ogo history *[\|\}]/.test(txT));
		Otagtab.ni = (/\{\{ *[Nn]o[Ii]nkscape *[\|\}]/.test(txT));
		Otagtab.nu =  /\{\{ *[Nn]oUpdate\s*\}\}/.test(txT);		// no parm
		Otagtab.oq =  /\{\{\s*[Oo]paque\s*\}\}/.test(txT);		// no parm
		Otagtab.ov = (/\{\{\s*[Oo]verlay\s*\}\}/.test(txT));	// no parm
		Otagtab.re = (/\{\{\s*[Rr]ecent\s*[\|\}]/.test(txT));
		Otagtab.rs = (/\{\{\s*[Rr]estoration\s*[\|\}]/.test(txT));
		Otagtab.tr = (/\{\{\s*[Tt]ranslate\s*\}\}/.test(txT));
		Otagtab.tw = (/\{\{\s*[Tt]aken with\s*\}\}/.test(txT));
		Otagtab.up = ( (/\{\{\s*[Uu]pdate\s*\}\}/.test(txT)) || (/\{\{\s*[oO]utdated\s*\}\}/.test(txT)) );
		Otagtab.zf = (/\{\{\s*User:ZooFari\/Template:SVG\s*\}\}/i.test(txT));		// no parm
	//  ??fw?? 
	
	//	ge = (/\{\{\s*[Tt]aller de Cartografía\s*\}\}/i.test(text));
	
			if (inRE[0].test(text)) 				// ??? .test(txT) ???
			{	text = text.replace(/^( *)\|\s*([A-Z][^=\n{}|?!.]+ *=)/gm,
						function (m, p1, p2) {
						return p1 + '|' + p2.toLowerCase();
					});
			}
			// 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),			//	3-letter ext
				fEx4  = p1.slice(-5),				//	6-letter ext
				fName = p1.slice(0, -4);			//	file name w/o ext
				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 -
				// replace understrokes 
				for (let i = 1; i < fName.length; i++)
  				{	if ( fName.substring(i, i+1) === "_")  
  						fName = fName.substring(0, i) + " " + fName.substring(0, i);	// change understroke 
				}									
				fName = (fEx4[0] === '.' && fName === c.wgTitle.slice(0, -5)) ? fEx4 : 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 = fName === '.webp' ? '.w' : fName;		// ed_wdh: 
				Name = fName + "👻";							//test
				return m.replace ( fName );
			};

			return text					// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
		.replace(inRE[2], '$1|other versions$2=$3') // standardize
		.replace(/( *\| *[Ii]m)(?:gen|ag)?( *= *)/, '$1age$2')		//	pre_normalize [im, imag, imgen]
		.replace(/\ *\| *(?:[Oo]ther[ _])?versions *= */, function (m)
			{ if (coai)
				return '|versions=';	// COAInformation only !!!
			  else
				return m;
			})
		.replace(/\ *\| *(?:[Oo]ther[ _])?fields *= */, function (m)	// should be in advance
			{ if (coai)
				return '|fields=';	// COAInformation only !!!
			  else
				return m;
			})
//		.replace(/\ *\| *[Aa]uthor *= */, function (m)	
//			{ if (coai)
//				return '|artist=';	// COAInformation only !!!
//			  else
//				return m;
//			})

 //		standardize	different layout formats of date	to	yyyy-mm-dd	
	.replace (/( *\| *[Dd]ate *= *\d{4}-\d{1,2}-\d{1,2}) *(?:\d{2}:\d{2}(?::\d{2})?)?(?: *\(?(?:UTC *[\+-]?\d?d?)?\)?)?/, '$1')	// ed_wdh: clock does NOT belong to date
	.replace (/( *\| *[Dd]ate *= *)\d{2}:\d{2}, (\d{1,2}) ([^\s]+) (\d{4})(?: \(UTC\))?/, '$1$4-$3-$2')		// ed_wdh: replace ~~~~~ h:m, dd Mmmmm yyyy
	.replace (/( *\| *[Dd]ate *= *)\d{2}:\d{2}, (\d{4}) ([^\s]+) (\d{1,2})(?: \(UTC\))?/, '$1$2-$3-$4')		// ed_wdh: replace ~~~~~ h:m, yyyy Mmmmm dd
	.replace (/( *\| *[Dd]ate *= *)\d{2}:\d{2}, ([^\s]+) (\d{1,2}), (\d{4})(?: \(UTC\))?/, '$1$4-$2-$3')	// ed_wdh: replace ~~~~~ h:m Mmmmm dd, yyyy
	.replace (/( *\| *[Dd]ate *= *)(\d{4})-(\d{1,2})-(\d{1,2})(?:T\d\d:\d\d:?\d?\d?\d?)?/, '$1$2-$3-$4')	// ed_wdh: replace ~~~~~ yyyy-mm-dd...
	.replace (/( *\| *[Dd]ate *= *)(\d{1,2})\/(\d{1,2})\/(\d{2})(?:T\d\d:\d\d:?\d?\d?\d?)?/, '$120$4-$3-$2')// ed_wdh: replace ~~~~~ dd/mm/yy...
	.replace (/( *\| *[Dd]ate *= *)(\d{1,2})\/(\d{1,2})\/(\d{4})(?:T\d\d:\d\d:?\d?\d?\d?)?/, '$1$4-$3-$2')	// ed_wdh: replace ~~~~~ dd/mm/yyyy...

		.replace (/( *\| *[Dd]ate *= *)(\d{4})-(\d)-(\d{1,2}\s)/, '$1$2-0$3-$4')		// ed_wdh: normalize inserting zero
		.replace (/( *\| *[Dd]ate *= *)(\d{4})-(\d{2})-(\d\s)/, '$1$2-$3-0$4')			// ed_wdh: normalize inserting zero
	.replace (/( *\| *[Dd]ate *= *\d{4}-\d{2}-\d{2})(?:T\d\d:\d\d:?\d?\d?\d?)?/, '$1')	// ed_wdh: remove time

// 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 (if !coai):
			.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)		
		//	.replace(/\|other versions *= ?/,'|other versions=')   // ed_wdh (ls)		
			.replace(/\|fields *= ?/,        '|fields      =')   // ed_wdh (ls)		fields ?
			.replace(/\|versions *= ?/,      '|versions    =')   // ed_wdh (ls)	
			.replace(/\|element *= ?/,       '|element     =')   // ed_wdh (ls)
			.replace(/\|tincture *= ?/,      '|tincture    =')   // ed_wdh (ls)
			.replace(/\|im[gen|age] *= ?/,   '|image       =')   // ed_wdh (ls)
			.replace(/\[\[:de:Benutzer:\[\[User:Summer ... hier!\|[^\)]+\)*\]*/, '{{U|Summer ... hier!}}')
	.replace(/\|[Ss]ource *=\s*\n?\{\{de\|Eigene Arbeit, basiert auf:\}\}\s*\n\{\{en\|Own work, based on:\}\}\s*\n\*\[\[:File:([^\]]+)\]\], \[\[User:([^\|]+)\|\2\]\]/im, '|source={{Based|$1|by=$2}}')

		.replace(/== *[Gg]nuplot script to generate this plot *== *\n/, '')
		.replace(/<syntaxhighlight lang="gnuplot"> *\n/, '')
		.replace(/<source lang="gnuplot"> *\n/, '')
//<		.replace(/<\/syntaxhighlight> *\n/, '}}\n}}')
//<		.replace(/<\/source>/, '}}\n}}')
		.replace(/hist\.csv \] \|\|/g, 'hist.csv ] {{!!}}')
//		.replace(/([^\[]+)\[([^\]]+)\] *\n/g, '[$2] <$1>\n')		// OLY temp.


/*		//	 clean text switch part of files treated with toolforge translator
		//	 =================================================================
		// id="text1900-el" systemLanguage="el"><tspan id="tspan1893-el"
//	.replace(/ *\n*id="(text|trsvg|tspan|switc)[^"]+"/gm, '')									//  ed_wdh (useless id's)
		.replace(/ *\n*id="text[^"]+"/g, '')									//  ed_wdh (useless id's)
		.replace(/ *\n*id="trsvg[^"]+"/g, '')									//  ed_wdh (useless id's)
		.replace(/ *\n*id="tspan[^"]+"/g, '')									//  ed_wdh (useless id's)
		.replace(/ *\n*id="switc[^"]+"/g, '')									//  ed_wdh (useless id's)
	.replace(/<text id="trsvg[^"]+"><tspan id="trsvg[^"]+">([^<]+)<\/tspan>/g, '<text>$1')		// ed_wdh (first tspan)
	.replace(/ id="trsvg[^"]+"><tspan id="trsvg[^"]+">([^<]+)<\/tspan><\/text>/g, '>$1</text>')	// ed_wdh (last  tspan)
	.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 
		// <text systemLanguage="it"><tspan>Sistemici;</tspan>
	.replace(/systemLanguage="([^"]+)">\n?<tspan>([^<]+)<\/tspan>/g, 'systemLanguage="$1">$2')	// ed_wdh (first tspan)
		// <text><tspan>Systemic:</tspan>
	.replace(/<text><tspan>([^<]+)<\/tspan>/g, '<text>$1')										// ed_wdh (empty tspan)
	.replace(/<\/tspan>\n<\/text>/g, '</tspan></text>')  										// ed_wdh (remove newline)
	.replace(/<\/text><text/g, '</text>\n<text')  												// ed_wdh (insert newline)
	.replace(/<\/text><\/switch/g, '</text>\n</switch')  										// ed_wdh (insert newline)

	.replace(/stemLanguage="([^"]+)"><tspan x="0" y="([^"]+)">([^<]+)<\/tspan>/g, 'stemLanguage="$1" y="$2">$3')	// Mrmw x=0
	.replace(/<text><tspan x="0" y="([^"]+)">([^<]+)<\/tspan>/g, '<text y="$1">$2')									// Mrmw

	.replace(/<text systemLanguage="(\w+)"><tspan>([^<]+)<\/tspan>/g, '<text systemLanguage="$1">$2')   // ed_wdh first
*/
//	.replace(/<text(?: id="trsvg[^"]+")? systemLanguage="(\w+)"(?: id="trsvg[^"]+")?><tspan(?: id="trsvg[^"]+")?>([^<]+)<\/tspan>/g, '<text systemLanguage="$1">$2')   // ed_wdh 1 ts[an]


		// 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(/\|[Aa](rtist|uthor) *= *\*? *\{?\{?unknown\}?\}? *\n\n?\* *vectorized by (?:\[\[(?:[Uu]ser:)?|\{\{U\|)([^\]\}\|]+)(?:\|\2)?(?:\]\]|\}\})/m, '|a$1 = {{AutVec||$2}}')	// ed_wdh:
 		.replace(/Thom.lanaud/g, 'Thom.Lanaud')				//ed_wdh user writing
 		.replace(/User:Domdomegg/g, 'user:domdomegg')		//ed_wdh user writing
		.replace(/\{\{F\|([^\}]+?)\}\} +by +\[\[User\:([^\]]+?)\]\]/ig, '{{F|$1|by={{U|$2}}}}')	// L_P
		.replace(/\{\{F\|([^\}]+?)\}\} +by +\{\{U\|([^\}]+?)\}\}/ig, '{{F|$1|by={{U|$2}}}}')		// L_P
		.replace(/\{\{F\|([^\}]+?)\}\} +by +\{\{([^\}]+?)\}\}/ig, '{{F|$1|by={{$2}}}}')			// e.g. Wikidata
		.replace(/source=\{\{own\}\}\n\* \{\{Based/ig, 'source={{Based')
		.replace(/source=self-made \(based on/ig, 'source={{Based}}')		//bracket not closed 
		
//	.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(/\[\[:?(?:User|Benutzer): ?([^\]\|]+?)(?:\|\1)?\]\]/ig, '{{U|$1}}')			// ed_wdh: U [single or same]
				  .replace(/\[\[:?(?:User|Benutzer): ?([^\]\|]+?)(\| ?[^\]]+?)?\]\]/ig, '{{U|$1$2}}')	// ed_wdh: U [link & disp]
 	.replace(/\[\[:([a-z]{2,3}) ?:(?:User|Benutzer): ?([^\]\|]+?)(?:\|\2)?\]\]/ig, '{{U|$2||$1}}')		// ed_wdh: U [single or same]:lg
	.replace(/\[\[:([a-z]{2,3}):(?:User|Benutzer): ?([^\]\|]+?)\| ?([^\]]+?)\]\]/ig, '{{U|$2|$3|$1}}')	// ed_wdh: U [link & disp]:lg
 				  .replace(/\[\[:?(?:User talk): ?([^\]\|]+?)(?:\|\1)?\]\]/ig, '{{Ut|$1}}')				// ed_wdh: Ut[single or same]
				  .replace(/\[\[:?(?:User talk): ?([^\]\|]+?)(\| ?[^\]]+?)?\]\]/ig, '{{Ut|$1$2}}')		// ed_wdh: Ut[link & disp]
 	.replace(/\[\[:([a-z]{2,3}):(?:User talk): ?([^\]\|]+?)(?:\|\2)?\]\]/ig, '{{Ut|$2||$1}}')				// ed_wdh: Ut[single or same]:lg
	.replace(/\[\[:([a-z]{2,3}):(?:User talk): ?([^\]\|]+?)\| ?([^\]]+?)\]\]/ig, '{{Ut|$2|$3|$1}}')		// ed_wdh: Ut[link & disp]:lg

	//	6  {{F			l= for external	
			  .replace(/\[\[:(?:[Ff]ile|[Ii]mage): ?([^\]\|]+?)(?:\|(?:File:)\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(/\[\[:?(?:W(?:ikipedia)?:) ?(?:File|Image) ?: ?([^\]\|]+?)(\|[^\]]+?)?\]\]/ig, '{{F|$1$2|l=en}}')		// ed_wdh:
	.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
				.replace(/\{\{(U|Ud|Ut)\|([^\|\}]+?)\|\}\}/g, '{{$1|$2}}')								// ed_wdh: remove pipe 
	
//(cleanup)	.replace(/\[\[(?:[Ff]ile:|[Ii]mage: *)([^\|]+?)\|(\d+)px\]\] */gm, '{{F|$1|Z|$2}}')			// ed_wdh: display image
//			.replace(/\{\{F\|([^\|]+?)\|Z\|(\d+)\}\} ?\{\{F\|([^\|]+?)\|Z\|(\2)\}\}/gm, '{{F1|$1|Z|$2}}{{F2|$3|Z|$2}}')
//			.replace(/\{\{F2\|([^\|]+?)\|Z\|(\d+)\}\} ?\{\{F[12]?\|([^\|]+?)\|Z\|(\2)\}\}/gm, '{{F2|$1|Z|$2}}{{F2|$3|Z|$2}}')
//			.replace(/\{\{F2\|([^\|]+?)\|Z\|\d+\}\}/gm, '{{F2|$1}}')		// rem. |Z|dd
//			.replace(/\}\}\{\{F2\|([^\|\}]+?)(\|?\}*)/gm, '|$1$2')			// rem. }}{{F2		  
//			.replace(/\{\{F1(\|[^\|]+?)\|Z\|(\d+)\|/g, '{{Fl|d=$2|o=Z$1|')	// change to {{Fl
				
	// 10  {{T
		.replace(/\[\[(?::?[Tt]emplate): ?([^\]\|]+?) ?(\| ?[^\]]+?)?\]\]/g, '{{T|$1$2}}')			// ed_wdh: T [link & disp]
 					.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]at(?:egory)?): ?([^\]\|]+?) ?(\| ?[^\]]+)?\]\]/g, '{{C|$1$2}}')	// ed_wdh: C [link & disp]

	//828  {{M
		.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}))?:([Bb}ooks|{Dd}ata|[Mm]eta|[Nn]ews|[Qq]ote|[Ss]ource|[Ss]pecies|[Vv]ersity|[Vv}oyage|[Ww](?:ikipedia)):([^\]\|]+?)\|(.+?)\]\]/g, '{{W|$3|$4|$1:$2}}')	// ed_wdh: W [link & disp]  
	.replace(/\[\[:[Cc]:/g, '[[c:')
	.replace(/\[\[:?(\w):(?:([a-z]{2,3}):)?(?:[Ww](?:ikipedia)?:)? ?([^\]\|]+?)(?:\|\3)?\]\]/g, '{{W|$3||$1:$2}}')	// ed_wdh:+W [single/same]
	.replace(/\[\[:(?:([a-z]{2,3}):)?(?:[Ww](?:ikipedia)?:)? ?([^\]\|]+?)(?:\|\2)?\]\]/g, '{{W|$2||$1}}')	// ed_wdh: W [single/same] 
	.replace(/\[\[:?([\W\w][\w]{0,7}):(?:([a-z]{2,3}):)(?:[Ww](?:ikipedia)?:)? ?([^\]\|]+?)\|(.+?)\]\]/g, '{{W|$3|$4|$1:$2}}')	// ed_wdh:+W [l&d] lg
	.replace(/\[\[:(?:([a-z]{2,3}):)?(?:[Ww](?:ikipedia)?:)? ?([^\]\|]+?)\|(.+?)\]\]/g, '{{W|$2|$3|$1}}')	// ed_wdh: W [link & disp]  

	.replace(/\[\[:?(?:[Ww](?:ikt(?:ionary)?)): ?([^\]\|]+?)(\| ?[^\]]+)?\]\]/g, '{{Wt|$1$2}}')		// ed_wdh: Wikt:en [link & disp]
	.replace(/\{\{W\|User:([^\}]+)\}\}/g, '{{U|$1||en}}')	// en User (without link)
 //	.replace(/\{\{([UFTCMW]|Ut|Ud|Uc|Wt|[HX])\|(?: *1 *= *)?([^\|\}]*?)(?:\|([^\}\|]+?))?(?:\|([a-z]{2,3}))?\}\}/g, function (m, ns, link, disp='', lang='') 
 	.replace(/\{\{ *([UFTCMW]|Ut|Ud|Uc|Wt) *\|(?:1 *= *)?([^\|\}]*?)(?:\|([^\}\|]*?))?(?:\|([a-z]{2,3})?)?\}\}/g, function (m, ns, link, disp='', 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; 
// ===================================================================
 			if ( lang === '' && ( ns === 'U' || ns === 'Uc' ) )	// user existence check
 			{	let linx = link.slice(0, 1).toUpperCase() + link.slice(1); // standardize user id
 	//			if (!Usertab[myName]) 
	//				Usertab[myName] = 'U';			// assume that own user page exists: insert when not element
  				ns = Usertab[linx] ? ''+Usertab[linx] : 'Un';	// test: with prefix when from Usertab
				if (myName !== 'Sarang')			// perform tests only for Sarang(not _bot)
					ns = 'U';						// otherwise assume that user page exists
				if (ns === 'Un')					// when not in table
 					ns = userexist("User:" + linx, 'U');				
 				if (ns === 'Un')
 					ns = userexist("User talk:" + linx, 'Ut');	
 				if (ns === 'Un')
 					ns = userexist("User:" + linx + '~commonswiki', 'Uw');
 				if (ns === 'Un')
					ns = userexist("User talk:" + linx + '~commonswiki', 'Uwt');
				Usertab[linx] = ns;				// new element into Usertab
 			}	
// ===================================================================
			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(/1=Siehe Dateiname und Grafikinhalt/, '{{F|F}}')				// summer hier
			.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*/, '')	// Perhelion 2016-09-08 (disliked by Koavf)
			.replace (/\{\{([Ll]ocation) (?:dms|dec)/g, '{{$1') 					// ed_wdh deprecated
			.replace (/\{\{([Kk]oordynaty)/g, '{{Location') 						// ed_wdh deprecated
		.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(/\{\{\s*[Bb]roken file\s*\}\}\s*\n?/, '')						// ed_wdh  remove (bf)
		.replace(/\{\{\s*[Cc]olou?r ?blind\s*\}\}\s*\n?/, '')					// ed_wdh  remove (bl)
		.replace(/\{\{\s*[Cc]urrent\s*\}\}\s*\n?/, '')							// ed_wdh  remove (ci)
		.replace(/\{\{\s*[Ff]ictitious flag\s*\}\}\s*\n?/, '')					// ed_wdh  remove (ff)
		.replace(/\{\{\s*[Ff]ictional flag\s*\}\}\s*\n?/, '')					// ed_wdh  remove (ff)
		.replace(/\{\{\s*[Ff]ake sports logo\s*\}\}\s*\n?/, '')					// ed_wdh  remove (fi)
		.replace(/\{\{\s*[Ff]otowerkstatt\s*\}\}\s*\n?/, '')					// ed_wdh  remove (fw)		-- ??fw??
		.replace(/\{\{\s*[Bb]ilderwerkstatt\s*\}\}\s*\n?/, '')					// ed_wdh  remove (fi)		-- ??fw??
		.replace(/\{\{\s*[Bb]andeira falsa\s*\}\}\s*\n?/, '')					// ed_wdh  remove (fi)
		.replace(/\{\{\s*[Ll]ogo history\s*\}\}\s*\n?/, '')						// ed_wdh  remove (lh)
		.replace(/\{\{\s*[Nn]o[Ii]nkscape\s*\}\}\s*\n?/, '')					// ed_wdh  remove {ni}
		.replace(/\{\{\s*[Nn]oUpdate\s*\}\}\s*\n?/, '')							// ed_wdh  remove (nu)
		.replace(/\{\{\s*[Oo]paque\s*\}\}\s*\n?/, '')							// ed_wdh  remove (oq)
		.replace(/\{\{\s*[Oo]verlay\s*\}\}\s*\n?/, '')							// ed_wdh  remove (ov) 
		.replace(/\{\{\s*[Rr]ecent\s*\}\}\s*\n?/, '')							// ed_wdh  remove (re)
		.replace(/\{\{\s*[Rr]estoration\s*\}\}\s*\n?/, '')						// ed_wdh  remove (rs)
		.replace(/\{\{\s*[Tt]ranslate\s*\}\}\s*\n?/, '')						// ed_wdh  remove (tr)
	//	.replace(/\{\{\s*[Tt]aken with\s*\}\}\s*\n?/, '')						// ed_wdh  remove (tw)
		.replace(/\{\{\s*[Nn]oUpdate\s*\}\}\s*\n?/, '')							// ed_wdh  remove (up)
		.replace(/\{\{\s*User:ZooFari\/Template:SVG\s*\}\}\n?/, '')				// ed_wdh  remove {zf}
	//	.replace(/\{\{ *[Vv]ector text versions *\| *\.*\}\}\s*\n?/, '')		// ed_wdh  remove Zoofari's

		.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(/( *\|source *= *)\* *\{\{F\|([^\}]+?)\}/g, '$1{{Based|$2|by=}')	// ed_wdh: replace F with Based
		.replace(/\[?https:\/\/www\.hdbg\.eu\/gemeinden\/web\/index\.php\/detail\?rschl=([\d]{3,9})\]?/, '{{hdbg|$1}}')

// ========================================  filetruncate
		.replace(/(?:[Dd]erived ?(?:[Ff]rom)?|(?:[Oo]wn)? ?[Bb]ased(?: on)?)\|([^\|\}]+)/, function (m, fn)	
		{
			let fbmp = fn.slice(0, -4);			// fname of raster
			let fbmx = fn.slice(-4);			// exten of raster 
//			if (fbmx.toLowerCase() === ".svg")
//	minorax		return m;						// don't generate Abbr 


			let abbr = "";						// for raster file:
			switch  (fn.slice(-4))				// analize raster extension	
			{	case ".png":	abbr = ".";		break;
				case ".jpg":	abbr = ".j";	break;
				case ".gif":	abbr = ".g";	break;
				case ".tif":	abbr = ".t";	break; 
				case ".xcf":	abbr = ".x";	break;
				case "webp":	abbr = ".w";	break;
				default: 		abbr = fn.slice(-4);	// other extension
			}
			if (fbmp !== fnam)					// compare file names
			{  	for (let i = 1; i < fbmp.length; i++)
  				{	if ( fbmp.substring(i, i+1) === "_")  
  						fbmp = fbmp.substring(0, i) + " " + fbmp.substring(i+1);	// change raster understrokes 
				}
			}
			if (fbmp !== fnam)				// compare again 
				abbr = fbmp + fbmx;			// other file name: not shortened 

			return  "Based|" + abbr;
		}	)

// ========================================  filetruncate

	.replace(/(\n)?\* *derivative work:/, '$1{{Derivative}}:')
// 	.replace(/ *\|author *= *(?:[^\n]+)(?:[^\n]+)/m, function (m) { alert (m);  return m; })
	.replace(/( *\|author *= *)\* *\{\{F\|([^\}]+?)\}\}\:? *(\{\{Un?w?t?\|(?:[^\}]+?)\}\}) *\n? *\*?\/? *\{\{Derivative\}\}\:? *(\{\{Un?w?t?\|(?:[^\}]+?)\}\})/gm, function (m, p1, fn, u1, u2)	// 
		{
			let fbmp = fn.slice(0, -4);			// fname of raster
			let fbmx = fn.slice(-4);			// exten of raster 
			let pix  = '';						// testvarable
			if (fbmx.toLowerCase() === ".svg")
				return m;						// don't generate AutVec 

			let abbr = "";						// for raster file:
			switch  (fn.slice(-4))				// analize raster extension	
			{	case ".png":	abbr = ".";		break;
				case ".jpg":	abbr = ".j";	break;
				case ".gif":	abbr = ".g";	break;
				case ".tif":	abbr = ".t";	break; 
				case ".xcf":	abbr = ".x";	break;
				case "webp":	abbr = ".w";	break;
				default: 		abbr = fn.slice(-4);	// other extension
			}
			if (fbmp !== fnam)					// compare file names
			{  	for (let i = 1; i < fbmp.length; i++)
  				{	if ( fbmp.substring(i, i+1) === "_")  
  						fbmp = fbmp.substring(0, i) + " " + fbmp.substring(0, i);	// change raster understrokes 
				}
			}
				if (fbmp !== fnam)				// compare again 
					abbr = fbmp + fbmx;			// other file name: not shortened 
		
	//	analize user names u1 and u2; remove "U" transclusion (but not e.g. "Ut" ! )
			u1 = u1.trim();
			if (u1.slice(0, 4) === "{{U|")
			{	u1 = u1.slice(0, -2);
				u1 = u1.slice(4);
			}
			if (u1.slice(0, 5) === "{{Un|")
			{	u1 = u1.slice(0, -2);
				u1 = "<>" + u1.slice(5);
			}
	 		u2 = u2.trim();
			if (u2.slice(0, 4) === "{{U|")
			{	u2 = u2.slice(0, -2);
				u2 = u2.slice(4);
			}
			if (u2 === 'Pixelsquid' )
				pix = '🎱';						// //AutVec test maint 
	
			return p1 + "{{AutVec|" + u1 + "|" + u2 + "|" + abbr + "}}" + pix + "\n";
		}	)
// ========================================  
	
			.replace(/\[\[:[Cc]ategory: ?([^\]|[\n]+)(?:\| ?\1 ?)\]\]/g, '{{C|$1}}')
			.replace(/[Aa]uthor=moi même/, 'author=')						// fr:own
			.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\}\} ?from /g, '={{Own based}} ')		// ed_wdh (previous did not work); include the file:
			.replace(/\{\{[Oo]wn\}\}\.? ?[Bb]ased ?(?:on)? ?/g, '{{Own based}} ')	// ed_wdh 
	
			.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; 
//  *** but when it is the template {{Attribution}} restore it !
			.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 (/Bandera/.test(txT) && /Escut/.test(txT))
				topic = 'f|f=c';		// flag from coa *?*
			else 
			if (coai || /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 (/Bandera|PD-Flag-|flag/.test(txT))
				topic = 'f';		// |f=c
			return '{{Attrib' + tm + '|t=' + topic + lf; 		//ed_wdh: topic 
		}) 	
		.replace (/\{\{Attribs\|t=\n ution([\|\}])/, '{{Attribution$1') 		// restore erroneously changed name

	
 		.replace(/\{\{ *PD-shape\}\}/g, function (m, txt)
		{	if (/Parliament diagram tool/.test(txT) || /Wpdc/.test(txT))
				return '{{PD-wpdc}}'; 		//ed_wdh: wpdc
			else
				return m;					// PD-shape
		}) 			
 		.replace(/(?:\{\{Using\}\} *)?\[?https:\/\/parliamentdiagram\.toolforge\.org\/parliamentinputform\.html Parliament diagram tool\]?/, '{{Wpdcx}}')
 		.replace(/(?:\{\{(?:[Oo]wn )?[Uu]sing\}\} *)?\[?https:\/\/tools\.wmflabs\.org\/parliamentdiagram\/parliamentinputform\.html Parliament diagram (tool|creator)\]?/, '{{Wpdcx}}')

//		replace(/\{\{self\|cc-zero\}\}/g, function (m, txt)
//		{	if (/Parliament diagram tool/.test(txT) || /Wpdc/.test(txT))
//				return '{{PD-wpdc}}'; 		//ed_wdh: wpdc 
//			else
//				return m;					// self|cc-zero
//		}) 			
 
//  ***  template:Legend (here it is necessary to remove the "1=" independently of the "LAW OF 9/22")
 		.replace(/\{\{ *([Ll])egend(-small|-line| inline|2)? *\| *([^\|]*) *\| *([^\}]*)/g, function (m, cas, typ="", col="", 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 "{{"+cas+"egend" + typ + "|" + col + "|" + txt;				// txt without "="
		})
 
		.replace(/\{[Cc]olorString\|/g, '{Legend|')				//ed_wdh reset
		.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)
	// border/line: does not work when $2 contains a pipe
		.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(/\|border=transparent\}/gm, '|border=thin solid transparent}')			// complete	  ed_wdh 
		.replace(/\{\{[Ll]egend\|\|([^\|]*)\|line=([^\|\}]+)/gm, '{{legend|$2|$1')					//ed_wdh
		.replace(/\{\{[Ll]egend\|([^\|]*)\|([^\|]*)\|char=([^\|\}]+)/gm, '{{legend|$1 $3|$2')		//ed_wdh
		.replace(/\{\{[Ll]egend\|([^\|]*)\|([^\|]*)\|file=([^\|\}]+)/gm, '{{legend|$1 $3|$2')		//ed_wdh (no space in filename)
		.replace(/\{\{[Ll]egend\|([^\|]*)\|([^\|]*)\|border=([^\|\}]+)/gm, '{{legend|$1 $3|$2')		//ed_wdh
		.replace(/\{\{[Ll]egend\|([^\|]*)\|([^\|]*)\|line=([^\|\}]+)/gm, '{{legend|$1  $3|$2')		//ed_wdh  two spaces !
		.replace(/\{\{[Ll]egend\|([^\|]*)\|([^\|]*)\|striped=([^\|\}]+)/gm, '{{legend|$3)$1|$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*(?:[^\|]+)\|(?:[^\{\}\|]+)\}\})/gm, '$1egend$2')	//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)	

	//	.replace(/\{\{en\|1=(\{\{[Ll]eg)/, '$1')							//ed_wdh remove "en|1=" without )) pair
		.replace(/\{\{en\|1=(\{\{leg[^\}]+)\}\}(\}\}\n\|date=)/, '$1$2')	//ed_wdh remove "en|1=" (TapticInfo)

//	*** Set 6-byte-Colorcode to uppercase; when possible, shorten 'rrggbb' to 'rgb'
		.replace(/(#[\dA-Fa-f]{6})(..)/g, function (m, c, o)
		{	let rgb = c.toUpperCase();			//		if (expeUser &&
	//		let o3   = o.toUpperCase();
	//		let o2 = isHexval (o.substring(0,1)) + '.' + isHexval (o.substring(1,2));
			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
			&& !(isHexval(o.substring(0,1)) && isHexval(o.substring(1,2))) // not both hex
			)
				return rgb.substring(0,2) + rgb.substring(3,4) + rgb.substring(5,6) + o;
			else
				return rgb + o;		// uppercase only
		})	// 8-byte-Colorcode to uppercase:

			.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
//  *** single item 
		.replace(/(?:\n?)<Gallery>\s*(?:File\:|Image\:)?([^\n|]+)(\|?[^\n]+)?\s*<\/Gallery>(?:\n?)/ig, '{{G|\n$1$2}}\n') // ed_wdh test	
		.replace(/\{\{G\|\n([^\n\}]+?)\}\}/gm, '{{G|$1}}') 						// ed_wdh: single item gallery only one line
//		.replace(/(?:\n?)<[Gg]allery>\s*(?:[Ff]ile\:|[Ii]mage\:)?([^\n|]+)(\|?[^\n]+)?\s*<\/[Gg]allery>(?:\n?)/g, '{{G|\n$1$2}}⓵\n') // ed_wdh test	

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


	//?	.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\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([^\]]*)\]/, 'http://www.newgaso.fr/lecture$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);
		}	// ========================================= end	function generalCleanup	

		// COAInformation has special parameter ¿imgen/image? so warn if present
		if ( (coai && imgenRE.test(txT)) || /\{\{[Ii]genc/.test(txT)) {
			cSVG.warnMsg({
				title: 'Coa already present, ' + (err ? 'there ' + ((err === 1) ? 'is 1 error' : 'are ' + err + ' errors') : 'file is valid') + '!',
				type: 'warn'		//					
			});
 				if (/[st]\=sf|[st]\=eq/.test(txT)) {
 					LeyoChem = 1;	// use FGD  773
 				} 
		}
	/* more test:
		if ( imageRE.test(txT)) {
			cSVG.warnMsg({
				title: 'Image= presenT !',
				type: 'warn'
			});
		}
		if ( imgenRE.test(txt)) {
			cSVG.warnMsg({
				title: 'Imgen= present !',
				type: 'warn'
			});
		}
		if ( imgenRE.test(txT)) {
			cSVG.warnMsg({
				title: 'Imgen= presenT !',
				type: 'warn'
			});
			txt = txt.replace(/( *\| *[Ii]m)(?:gen|ag)?( *= *)/, '$1age$2');		//	pre_normalize [im, imag, imgen]
		}
		if ( imgenRE.test(txt)) {
			cSVG.warnMsg({
				title: 'Imgen= present !',
				type: 'warn'
			});
		}
	*/
 	// SVG Template and cosmetic replace:  all graphic labs, replace later in cleanup.js
		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|[Gg]raphic[ _][Ll]ab|[Ww]PGW[ _]vector[ _]im|[Tt]HV|[Aa]telier[ _]graphique|[Ll]aboratorio[ _]grafico|[Tt][\s_\w]+Cartografía|[Pp]rojet[ _]Blasons)[^\|\n\}]*\}\})\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
	//	tr	.replace(/(\{\{([Tt]ranslat(?:e|able|ion possible)|[Ee]asy translation)[^\\n}]*}})\s?/, function () {
			.replace(/(\{\{([Tt]ranslat(?: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)?\|[^\.]+\. Vector(?:ed|ized)[^\n]+/, '')		// remove => AutVec
			.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(/\{\{[Hh]andSVG\}\}\s?\n/ig, '') 		// remove (creted with ...)
			
			.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.slice(0,6)))	// " code "	?
						p5 += '|' + p2;				// T += m;			T T T T T
					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 (/[st]\=sf|[st]\=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   ed_wdh
						if (/structural formula|chemical equation/i.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 (/openclipart/.test(txT)) {
			s = 'oc';	// :openclipart
		} else if (/text[: -_]?logo/i.test(txT)) {
			this.textTrans = 0; // Logos don't get translated
			s = 'tl';	// :textlogo
		} else if (/blazon|våben/i.test(txT) || /COAInf/.test(txT)) {
			s = 'c'; // :CoA 
		} else if (/seal/i.test(txT)) {
			s = 's';	// :seal
		} else if (/logos? of |:logos?/i.test(txT)) {
			s = 'l';	// :Logos
		} else if (/maps/i.test(txT) && /green and grey/i.test(txT)) {			
			s = 'ggg';	// :green and gray world maps
		} else if (/maps/i.test(txT) && /World war/i.test(txT)) {			
			s = 'm';	//  :maps (not wm})
		} else if (/Natural Earth/.test(txT)) {
			s = 'm|w=Natural Earth map|>';	// :Natural Earth map		// multi_error SVG 
		} else if (/maps/i.test(txT) && /globe|earth|world|monde|mondial/i.test(txT)) {			
			s = 'wm';	// :World maps
		} else if (/maps/i.test(txT) && /Localisation|Locator|location /i.test(txT)) {
			s = 'lm';	// :locator maps
		} else if (/DescrMapComuneItaly/.test(txT)) {
			s = 'lm';	// :italian locator maps
		} else if (/maps/i.test(txT) && /flag/i.test(txT)) {
			s = 'fm';	// :flag maps
		} else if (/maps/i.test(txT)) {			
			s = 'm';	// :Maps
		} else if (/Military map symbol/.test(txT) && /CdnMCG/.test(txT)) {			
			s = '|s:=Military map symbol|U=CdnMCG';	// :mmy 
		} else if (/Military map symbol/.test(txT)) {			
			s = '|s:=Military map symbol';			// :mmy ( |s=|s:= )
		} else if (/pictogram/i.test(txT)) {			
			s = 'p';	// :SVG sports pictograms
		} else if (/[: -_]icon/i.test(txT) && /[Ff]lag/.test(txT)) {
			s = 'fi';	// :flag icons
//		} else if (/Chess/i.test(txT)) {
//			s = 'chesspiece'; // :user:Churnett/Chess				*** temporar ***
		} else if (/[: -_]icon/i.test(txT) && /Noun Project/.test(txT)) {
			s = 'npi';	// :flag icons
		} else if (/OOUI icons/.test(txT)) {
			s = 'OOUI'; // :icons
		} else if (/BSicon/.test(txT) || /Icons for riverfloat/.test(txT)) {
			s = 'bi';	// :BSicons
		} else if (/[: -_]icon/i.test(txT) && /coats of arms/i.test(txT)) {
			s = 'c';	// :Coa
		} else if (/[: -_]icon/i.test(txT)) {
			s = 'i';	// :Icons
		} else if ( /Bandièra/.test(txT) || /Category:Flags/.test(txT)) {
			s = 'f';	// :Flags
		} else if (/japanese crest/i.test(txT)) {
			s = 'jc';	// :jap.crest
		} else if (coai) {
			s = 'c';	// :CoA
		} else if (/PD-Coa|coats? of arms|escu|:CoA|heraldic/i.test(txT)) {
			s = 'c';	// :CoA / ecclesiastical heraldry
		} else if (/fin flash/i.test(txT) && (this.curSize < 2000)) {
			s = 'fin flash'; // :f flash, 
			stxt = '|s:=';
//		} else if (/fin flash/i.test(txT) && (toolName === 'Text Editor')) {
//			s = 'fin flash';	// :f flash, 
//			stxt = '|s:=';
		} else if (/Insignia|Identification badge|Emblem|uniforms/i.test(txT)) {
			s = 'em';	// :Emblems
		} else if (/PD-chem|BKchem|ChemDraw|Chemtool|ChemSketch|GChemPaint|N2S|dvisvgm|Chemical structure|Drug synthes|reactio/i.test(txT)) {
			LeyoChem = 1;					// use FGD (unsure whether "reactio" should trigger) |stru[ck]tur|
			s = 'sf';						// :Structural formulas
		} else if (/Igen\|[B|C]|Image generation\|[B|C]/i.test(txT)) {
			LeyoChem = 1;					// use FGD when old version abbreviation B=BKchem or C=ChemDraw (or User:#11)
			s = 'sf';	// :Structural formulas
		//			IgenName = IgenNameLong;						// for Leyo
		} else if (/Ribbon bar|Order /i.test(txT)) {
			s = 'o';	// :Orders
		} else if (/ signs|[Rr]oad [Ss]ign\]/.test(txT)) {
			s = 'v';	// :Signs {when category}
		} else if (/\[Category\:Signature/.test(txT)) {
			s = 'sig';	// :Signatures (even when 'letter')
		} else if (/Unicode|alphabet|letter/i.test(txT)) {
			s = 'u';	// :Unicode
		} else if (/Symbol/i.test(txT) && !/flags/i.test(txT)) {
			s = 'y';	// :Symbols
		} else if (/Mathematic|Algorit|Trigonometry|Geometry|Isometric/i.test(txT)) {
			s = 't';	// :Trigonometry 
		} else if (/ route marker/.test(txT)) {
			s = 'v';	// :Signs
		} else if (/Diagram/i.test(txT) && toolName !== 'Wpdc') {     // ed_wdh 
			s = 'd';	// :Diagrams
		} else if (/PD-Flag-|flag|Флаг/i.test(txT)) {
			s = 'f';	// :Flags
		} else if (/Football/i.test(txT) && /line-up/.test(txT)) {
			s = 'm|sd=/line-up'; // :line ups
		} else if (/Football/i.test(txT)) {
			s = 'fk';	// :Football kits
		} else if (LeyoChem) {
 			s = 'sf';	// :Structural formulas
		} else if (/ex[ae]mpe?l/i.test(txT)) {
			s = 'ex';	// :Example (exempel)
		} else if (/highway/i.test(txT)) {			
			s = 'm';	// :Maps
		} else if (/Autogra/i.test(txT)) {
			s = 'sig';	// :Signatures
		} else if (/Signatur/i.test(txT) && !/signature-talk/i.test(txT)) {
			s = 'sig';	// :Signatures                          // 'sig' comes too often
		} else if (/Monogram/i.test(txT)) {
			s = 'rm';	// :Royal monogram
		}

// change PD-chem for all chemical equations
		if (LeyoChem) 
		{	txt = txt.replace(/\{\{self\|[Cc]c-by-sa-4\.0\}\}/, '{{PD-chem}}');	//t=sf~eq
			txt = txt.replace(/\{\{self\|[Cc]c-zero\}\}/, '{{PD-chem|t=sf}}');	//
			txt = txt.replace(/\{\{PD-self\}\}/, '{{PD-chem}}');
		}
		if (/Topic = chemical equation|\|[st]=eq[\|\}]/.test(txT))		//s* C{{int:license-header}} ==\n{{PD-self}}
		{	txt = txt.replace(/\{\{PD-chem(?:\|s=eq)?\}\}(?:\|[st]=eq[\|\}])?/, "{{PD-chem|t=eq}}"); // -helper "|s=eq}"
			s = 'eq';			// repair afterwards to "chemical equation"  
		}
		if (/\{\{PD-chem(?:\|[st]=eq)?\}\}/.test(txT))
			txt = txt.replace(/\n?== *\{\{int:license-header\}\} *==\n\{\{PD-self\}\}/, '');	// remove

	//	if  (s === 'm' && /globe|earth|world|monde|mondial/i.test(txT))
	//		s = 'wm';									// world maps
	//	if  (s === 'm' && /Locator|location /i.test(txT))
	//		s = 'lm';									// locat maps
	//	// topic with UserID (only special users)   	// ed_wdh if
		if (s === 'wm' && /Hagar66/.test(txT) && toolName === 'Adobe')	
			s = 'wm|U=Hagar66';							// Hagar world maps (precedence over TUBS!)
		if (s === 'wm' && /NordNordWest/.test(txT))
			s = 'wm|u=NordNordWest';					// NordNordWest world maps (precedence over TUBS, but not over Hagar)
		if (s === 'wm' && /TUBS/.test(txT))	  
			s = 'wm|u=TUBS';							// TUBS world maps

		if (/Hagar66/.test(txT) && s === 'lm' && toolName === 'Adobe')	
			s = 'lm|U=Hagar66';							// Hagar location maps (precedence over TUBS)
		if  (/NordNordWest/.test(txT) && s === 'lm')
			s = 'lm|u=NordNordWest';					// NordNordWest location maps (precedence over TUBS, but not over Hagar)
		if  (/TUBS/.test(txT) && s === 'lm')	  
			s = 'lm|u=TUBS';							// TUBS location maps
	if  (/TUBS/.test(txT) && s === 'lm|u=TUBS' && /Latvia/.test(txT))	  
			s += '|sd=-Latvia';							// TUBS location maps **temp** for all regional subcats
	if  (s === 'lm|u=NordNordWest' && /Lettland 2/.test(txT))	  
			s += '|sd=-Latvia';							// TUBS location maps **temp** for all regional subcats

		if (/Hagar66/.test(txT) && s === 'm' && toolName === 'Adobe')		// PGFauthor	
			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 ✔
//		if  (s === 's' && /SVG - Seals of the United States/.test(txT) )
//			s += '|sd=(US)';						// **temp**
			
		// default: "Unknown tool" (but can also be Text Editor)	SVG - Seals of the United States
		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(/\{\{[Tt]aller🐜[ _]de[ _]Cartografía\}\}/, function (m, p) {
	//	ed_				g = 'es';
						ge;
						s = (p && !s) ? 'm' : s;
						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 || '');		// 🎨 for removing useless "r=-"
				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)) 										// no orevious igen
		{	let i = inRE.length;
			while (i--) { // iter over possible positions
				if ((topp = new RegExp(inRE[i], 'g')).test(txt)) 
				{	topp = _findPosition(topp);
					i = 0;
					break;
				} else
					topp = 0;
			}
		} else 
		{	topp = ofRE.lastIndex;
			if (!(coai && imageRE.test(txt)))  
			{	txt = txt.replace(ofRE, '');		// $1 $2 $3 (but not when "image")
				topp -= RegExp.lastMatch.length;
				ls = RegExp.$3;						// or
			}
		}
		s1 = s1 || RegExp.$1;
		s2 = s2 || RegExp.$2;
//		s1 = s1.slice(0, 1);			// elminate strange error ?

		if (coai && /[Ii]mage\|/.test(ls)) 		// CoA but without COAInformation
			{	IgenName = s1 + '|imag-' + s2 + '=' + s2 + ' °°°';	// test
				tempPre = '';
			} 
		else if (/\{\{ *[Ii]nform?\s*\|\s*/.test(txT)) 			//  Info/var
			{	imag = '|image';
				if (/[Ii]nform?\s*\|\s*desc\s*=/.test(txT))
					imag = '|imag';										// param length as "description"
				if (/[Ii]nform?\s*\|\s*de\s*=/.test(txT))
					imag = '|im';
				IgenName = s1 + imag + s2 + '=' + s2 + IgenName;		// + ls (later)	
			}
		 else if (!topp && /\}\}/g.test(txt)) 
			{	topp = txt.lastIndexOf(tempPre) + 3;	// put on last postion of a template
			} 
		else 
			{
	//			IgenName = s1 + '|other fields' + s2 + '=' + s2 + IgenName;	//  Info/var
				IgenName = s1 + IgenParm + '=' + IgenName;			// without the spaces
			}

		if (this.switchTrans && (myName === 'Sarang'))		// langtst
	//		if (/( )*\|\s*[Oo]ther[_ ]versions( )*= *[^\n]*\n/.test(txT))
	//			txt = txt.replace(/( )*\|\s*[Oo]ther[_ ]versions( )*= *[^\n]*\n/, '$1|other versions$2={{' + syslang(code) + '')}}\n');
	//		else
				tempPre = tempPre + syslang ();			//  Test
		//		tempPre = tempPre + '%%';				//  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 === 2)
				p5 += '=f'; // Fake SVG
			if (this.badSVG === 3)
				p5 += '=x'; // Fake SVG with text
	//		if (this.badSVG > 1 && /Smokefoot/.test(txT))
	//			p5 += '|u=Smokefoot'; // Fake SVG **temp**
			if (expeUser && s === 'm' && this.badSVG < 2) 
				p5 += '=t'; // may be TOPO 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) || /with non-modifiable/.test(txT))			// Zoofari's
			p5 += '|<'; // "less" sign to insert the {Path text SVG} tag.
		if (this.flowRoot)
			p5 += '|?x'; // "q_mark" sign for flowRoot
		else if (this.switchTrans) 
			p5 = p5.replace(/\|%/, '') + '|%s';
		if (this.PGF) {							// table processing would be better
			if (/Hagar66/.test(txT))
				p5 += '|~U=' + 'Hagar66';		//
			else
			if (/NordNordWest/.test(txT))
				p5 += '|~u=' + 'NordNordWest';	//
			else
			if (/TUBS/.test(txT))
				p5 += '|~u=' + 'TUBS';			//
			else
				p5 += '|~'; // "squiggle" sign for PGF CDATA
		}

 	 	else if (this.timestamp)
	  		p5 += '|%w';					// or '|%|%w'
		else if (this.textTrans && !/\|%/.test(p5) && toolName !== 'Wpdc')			//ed_wdh (after code)
	// 		p5 += '|%';		
			p5 += '|%r';					// reduced display		
		else if (/Impru20/.test(txT) && toolName === 'Wpdc')			//ed_wdh Impru
			p5 += '|sub=/Impru';			//		
								// other tags
	 	if	(Otagtab.bf)		p5 += '|bf';	// Broken file
		if	(Otagtab.bl)		p5 += '|bl';
		if	(Otagtab.ci)		p5 += '|ci';
		if	(Otagtab.ff)		p5 += '|ff';
		if	(Otagtab.fi)		p5 += '|fi';
	//	if	(Otagtab.fw)		p5 += '|fw';	// Fotowerkstatt		??fw??
		if	(Otagtab.lh)		p5 += '|lh';
		if	(Otagtab.ni)		p5 += '|ni';	//	|←
		if	(Otagtab.nu)		p5 += '|nu';
		if	(Otagtab.oq)		p5 += '|oq';
		if	(Otagtab.ov)		p5 += '|ov';
		if	(Otagtab.re)		p5 += '|re';
		if	(Otagtab.rs)		p5 += '|rs';
		if	(Otagtab.tr)		p5 += '|tr';
		if	(Otagtab.tw)		p5 += '|tw';	// Taken with ...
		if	(Otagtab.up)		p5 += '|up';
		if	(Otagtab.zf)		p5 += '|zf';

		if	(Fwrktab.fwc || Fwrktab.fwe || Fwrktab.fwo || Fwrktab.fwl || Fwrktab.fwt)
			{	if	(Fwrktab.fwc)	p5 += '|fwc='+Fwrktab.fwc;	
				if	(Fwrktab.fwe)	p5 += '|fwe='+Fwrktab.fwe;			
				if	(Fwrktab.fwo)	p5 += '|fwo='+Fwrktab.fwo;			
				if	(Fwrktab.fwl)	p5 += '|fwl='+Fwrktab.fwl;			
				if	(Fwrktab.fwt)	p5 += '|fwt='+Fwrktab.fwt;			
				if	(Fwrktab.fws)	p5 += '|fws='+Fwrktab.fws;			
			}
		else	if	(Otagtab.fw)	p5 += '|fw';	// Fotowerkstatt		??fw??

//		p5 += Otagtab.zf ? '~zf~' : '';  test
//		p5 += Otagtab.ov ? '~ov~' : '';
	
		T = p5 + r + T;

		if (topp) 
		{	err = Number(err);
			if (size) 
				IgenName += toolName + '|' + size + '|9=+|10=S|user=' + c.wgUserName + '|4=' + s + T;
			else
			 	IgenName += toolName + (err ? '|' + err : '') + '|+' + g + T + stxt + s;

			s1 = s1.slice(0, 1);			// elminate strange error ?
			txt = txt.substr(0, topp) + s1 + IgenName + tempPre + ls + txt.substr(topp);
			return txt;
		}		// if topp			🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺

		mw.log.warn('Igen not inserted ');
		return { 	type: 'warn'	};
	},			// 	replaceTag: function (txt, err, toolname) 

	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!" });
			if (expeUser && tstex > 1)
				mw.notify("expensive: "+tstex.toString() );		// display number of (expensive) existence checks

			$('#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;
		});
	},				// addToFileDesc	

	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;
	},				// addIgenURL

	/**
	 * 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;
	},				// getTempBlock

	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'
			});
		}
	},				// insertIgenSub
	
	// 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
			});
		}
	},				// insertAutVec

	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);
		});
	},				// addButtons
	
	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;
		} 				// addTooltip

		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;
				});
		}				// getParse
		
		// 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);
			// });
		});
	}
};				// langSwitch


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 (sandbox ?)
			// 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>
Category:User scripts