<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="pl">
	<id>https://minewiki.pl/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Majr</id>
	<title>Minecraft Wiki Polska - Wkład użytkownika [pl]</title>
	<link rel="self" type="application/atom+xml" href="https://minewiki.pl/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Majr"/>
	<link rel="alternate" type="text/html" href="https://minewiki.pl/Specjalna:Wk%C5%82ad/Majr"/>
	<updated>2026-05-06T12:19:13Z</updated>
	<subtitle>Wkład użytkownika</subtitle>
	<generator>MediaWiki 1.42.7</generator>
	<entry>
		<id>https://minewiki.pl/index.php?title=MediaWiki:Gadget-spriteEditLoader.js&amp;diff=96835</id>
		<title>MediaWiki:Gadget-spriteEditLoader.js</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=MediaWiki:Gadget-spriteEditLoader.js&amp;diff=96835"/>
		<updated>2018-11-16T02:03:26Z</updated>

		<summary type="html">&lt;p&gt;Majr: Don&amp;#039;t remember this being an issue before&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;$( function() {&lt;br /&gt;
&#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Add an edit button which loads the sprite editor&lt;br /&gt;
 *&lt;br /&gt;
 * If spriteaction=edit is in the URL, the editor will be loaded&lt;br /&gt;
 * immediately, otherwise it will wait for the button to be clicked.&lt;br /&gt;
 */&lt;br /&gt;
var editPage = $( &#039;#sprite-editor-message&#039; ).data( &#039;page&#039; ) || null;&lt;br /&gt;
if ( !$( &#039;#spritedoc&#039; ).length &amp;amp;&amp;amp; !editPage ) {&lt;br /&gt;
	return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $editTab = $( &#039;#ca-edit&#039; );&lt;br /&gt;
if ( !$editTab.length ) {&lt;br /&gt;
	$editTab = $( &#039;#ca-viewsource&#039; );&lt;br /&gt;
}&lt;br /&gt;
var $spriteEditLink = $( &#039;&amp;lt;a&amp;gt;&#039; ).text( &#039;Edit sprite&#039; ).attr( &#039;href&#039;,&lt;br /&gt;
	mw.util.getUrl( editPage, { spriteaction: &#039;edit&#039; } )&lt;br /&gt;
);&lt;br /&gt;
var $spriteEditTab = $( &#039;&amp;lt;li&amp;gt;&#039; ).attr( &#039;id&#039;, &#039;ca-spriteedit&#039; ).append(&lt;br /&gt;
	$( &#039;&amp;lt;span&amp;gt;&#039; ).append( $spriteEditLink )&lt;br /&gt;
);&lt;br /&gt;
$spriteEditTab.insertAfter( $editTab );&lt;br /&gt;
&lt;br /&gt;
// Page to sprite edit is not here, so no need to bind events&lt;br /&gt;
if ( editPage ) {&lt;br /&gt;
	return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var loadSpriteEditor = function() {&lt;br /&gt;
	$spriteEditTab.add( &#039;#ca-view&#039; ).toggleClass( &#039;selected&#039; );&lt;br /&gt;
	&lt;br /&gt;
	return mw.loader.using( &#039;ext.gadget.spriteEdit&#039; );&lt;br /&gt;
};&lt;br /&gt;
if ( location.search.match( &#039;[?&amp;amp;]spriteaction=edit&#039; ) ) {&lt;br /&gt;
	loadSpriteEditor();&lt;br /&gt;
	return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $win = $( window );&lt;br /&gt;
$spriteEditLink.one( &#039;click.spriteEditLoader&#039;, function( e ) {&lt;br /&gt;
	// Initially add the history so it is not delayed waiting&lt;br /&gt;
	// for the editor to load. The editor will handle it from now.&lt;br /&gt;
	history.pushState( {}, &#039;&#039;, this.href );&lt;br /&gt;
	&lt;br /&gt;
	loadSpriteEditor().then( function() {&lt;br /&gt;
		$win.off( &#039;.spriteEditLoader&#039; );&lt;br /&gt;
	} );&lt;br /&gt;
	&lt;br /&gt;
	e.preventDefault();&lt;br /&gt;
} );&lt;br /&gt;
&lt;br /&gt;
// If the page is reloaded while the editor isn&#039;t loaded, navigating&lt;br /&gt;
// back to the editor won&#039;t work, so an initial navigation check is&lt;br /&gt;
// necessary to load the editor, where it will then monitor navigation&lt;br /&gt;
$win.on( &#039;popstate.spriteEditLoader&#039;, function() {&lt;br /&gt;
	if (&lt;br /&gt;
		location.search.match( &#039;[?&amp;amp;]spriteaction=edit&#039; ) &amp;amp;&amp;amp;&lt;br /&gt;
		!$( &#039;html&#039; ).hasClass( &#039;spriteedit-loaded&#039; )&lt;br /&gt;
	) {&lt;br /&gt;
		loadSpriteEditor().then( function() {&lt;br /&gt;
			$win.off( &#039;.spriteEditLoader&#039; );&lt;br /&gt;
		} );&lt;br /&gt;
	}&lt;br /&gt;
} );&lt;br /&gt;
&lt;br /&gt;
} );&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=MediaWiki:Gadget-spriteEdit.js&amp;diff=96825</id>
		<title>MediaWiki:Gadget-spriteEdit.js</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=MediaWiki:Gadget-spriteEdit.js&amp;diff=96825"/>
		<updated>2018-11-16T01:52:19Z</updated>

		<summary type="html">&lt;p&gt;Majr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;( function() {&lt;br /&gt;
&#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
/** &amp;quot;Global&amp;quot; vars (preserved between editing sessions) **/&lt;br /&gt;
var i18n = {&lt;br /&gt;
	blockedNotice: &#039;You cannot edit this sprite as you are blocked.&#039;,&lt;br /&gt;
	blockedReason: &#039;Reason: $1&#039;,&lt;br /&gt;
	browserActionNotSupported: &#039;Not supported by your browser.&#039;,&lt;br /&gt;
	changesSavedNotice: &#039;Your changes were saved.&#039;,&lt;br /&gt;
	controlNewName: &#039;New name&#039;,&lt;br /&gt;
	ctxDeleteImage: &#039;Delete&#039;,&lt;br /&gt;
	ctxDownloadImage: &#039;Download&#039;,&lt;br /&gt;
	ctxReplaceImage: &#039;Replace&#039;,&lt;br /&gt;
	diffError: &#039;Failed to retrieve diff&#039;,&lt;br /&gt;
	diffErrorMissingPage: &#039;Failed to retrieve page&#039;,&lt;br /&gt;
	dupeName: &#039;This name already exists.&#039;,&lt;br /&gt;
	dupeNamesNotice: &#039;There are duplicate names which must be resolved prior to saving.&#039;,&lt;br /&gt;
	errorApi: &#039;API error&#039;,&lt;br /&gt;
	errorConnection: &#039;Connection error&#039;,&lt;br /&gt;
	errorConnectionText: &#039;Check your internet connection&#039;,&lt;br /&gt;
	errorGeneric: &#039;Error&#039;,&lt;br /&gt;
	errorHttp: &#039;HTTP error&#039;,&lt;br /&gt;
	genericError: &#039;Something went wrong&#039;,&lt;br /&gt;
	luaKeyDeprecated: &#039;deprecated&#039;,&lt;br /&gt;
	luaKeyId: &#039;id&#039;,&lt;br /&gt;
	luaKeyIds: &#039;ids&#039;,&lt;br /&gt;
	luaKeyName: &#039;name&#039;,&lt;br /&gt;
	luaKeyPos: &#039;pos&#039;,&lt;br /&gt;
	luaKeySection: &#039;section&#039;,&lt;br /&gt;
	luaKeySections: &#039;sections&#039;,&lt;br /&gt;
	luaKeySettings: &#039;settings&#039;,&lt;br /&gt;
	luaKeySettingsHeight: &#039;height&#039;,&lt;br /&gt;
	luaKeySettingsPos: &#039;pos&#039;,&lt;br /&gt;
	luaKeySettingsSize: &#039;size&#039;,&lt;br /&gt;
	luaKeySettingsSpacing: &#039;spacing&#039;,&lt;br /&gt;
	luaKeySettingsUrl: &#039;url&#039;,&lt;br /&gt;
	luaKeySettingsWidth: &#039;width&#039;,&lt;br /&gt;
	namePlaceholder: &#039;Type a name&#039;,&lt;br /&gt;
	noPermissionNotice: &#039;You do not have permission to edit this sprite.&#039;,&lt;br /&gt;
	panelChangesIdTitle: &#039;Data changes&#039;,&lt;br /&gt;
	panelChangesNoDiffFromCur: &#039;No changes from current revision.&#039;,&lt;br /&gt;
	panelChangesSheetTitle: &#039;Spritesheet changes&#039;,&lt;br /&gt;
	panelChangesTitle: &#039;Review your changes&#039;,&lt;br /&gt;
	panelCloseTip: &#039;Close&#039;,&lt;br /&gt;
	panelConflictCurText: &#039;Current text&#039;,&lt;br /&gt;
	panelConflictReview: &#039;Review changes&#039;,&lt;br /&gt;
	panelConflictSave: &#039;Save&#039;,&lt;br /&gt;
	panelConflictText: &#039;An edit conflict has occurred, and was not able to be resolved automatically.&#039;,&lt;br /&gt;
	panelConflictTitle: &#039;Edit conflict&#039;,&lt;br /&gt;
	panelConflictYourText: &#039;Your text&#039;,&lt;br /&gt;
	panelDiscardContinue: &#039;Keep editing&#039;,&lt;br /&gt;
	panelDiscardDiscard: &#039;Discard changes&#039;,&lt;br /&gt;
	panelDiscardText: &#039;Are you sure you wish to discard your changes?&#039;,&lt;br /&gt;
	panelDiscardTitle: &#039;Unsaved changes&#039;,&lt;br /&gt;
	panelEcchangesReturn: &#039;Return to edit conflict form&#039;,&lt;br /&gt;
	panelEcchangesTitle: &#039;Review your manual changes&#039;,&lt;br /&gt;
	sectionPlaceholder: &#039;Type a section name&#039;,&lt;br /&gt;
	sectionUncategorized: &#039;Uncategorized&#039;,&lt;br /&gt;
	titleEditing: &#039;Sprite editing $1&#039;,&lt;br /&gt;
	toolbarHelp: &#039;Help&#039;,&lt;br /&gt;
	toolbarHelpPage: &#039;Help:Sprite editor&#039;,&lt;br /&gt;
	toolbarNewImage: &#039;New image&#039;,&lt;br /&gt;
	toolbarNewSection: &#039;New section&#039;,&lt;br /&gt;
	toolbarRedo: &#039;Redo&#039;,&lt;br /&gt;
	toolbarReviewChanges: &#039;Review changes&#039;,&lt;br /&gt;
	toolbarSave: &#039;Save&#039;,&lt;br /&gt;
	toolbarSummaryLabelTip: &#039;The number of bytes remaining&#039;,&lt;br /&gt;
	toolbarSummaryPlaceholder: &#039;Summarize the changes you made&#039;,&lt;br /&gt;
	toolbarToolDeprecate: &#039;Deprecate&#039;,&lt;br /&gt;
	toolbarToolDeprecateTip: &#039;Toggle names as deprecated&#039;,&lt;br /&gt;
	toolbarTools: &#039;Tools&#039;,&lt;br /&gt;
	toolbarUndo: &#039;Undo&#039;,&lt;br /&gt;
};&lt;br /&gt;
var $root = $( document.documentElement );&lt;br /&gt;
var $win = $( window );&lt;br /&gt;
var $body = $( document.body );&lt;br /&gt;
var URL = window.URL || window.webkitURL;&lt;br /&gt;
var imageEditingSupported = !!( window.FileList &amp;amp;&amp;amp;&lt;br /&gt;
	window.ArrayBuffer &amp;amp;&amp;amp;&lt;br /&gt;
	window.Blob &amp;amp;&amp;amp;&lt;br /&gt;
	window.FormData &amp;amp;&amp;amp;&lt;br /&gt;
	window.ProgressEvent &amp;amp;&amp;amp;&lt;br /&gt;
	URL &amp;amp;&amp;amp; URL.revokeObjectURL &amp;amp;&amp;amp; URL.createObjectURL &amp;amp;&amp;amp;&lt;br /&gt;
	document.createElement( &#039;canvas&#039; ).getContext );&lt;br /&gt;
// HTML pointer-events is dumb and can&#039;t be tested for&lt;br /&gt;
// Just check that we&#039;re not IE &amp;lt; 11, old Opera has too little usage to bother checking for&lt;br /&gt;
var pointerEventsSupported = $.client.profile().name !== &#039;msie&#039; || $.client.profile().versionBase &amp;gt; 10;&lt;br /&gt;
var originalTitle = document.title;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Start loading OOUI&#039;s icons in the background&lt;br /&gt;
mw.loader.load( [&lt;br /&gt;
	&#039;oojs-ui.styles.icons-editing-core&#039;,&lt;br /&gt;
	&#039;oojs-ui.styles.icons-editing-styling&#039;,&lt;br /&gt;
	&#039;oojs-ui.styles.icons-media&#039;,&lt;br /&gt;
	&#039;oojs-ui.styles.icons-moderation&#039;,&lt;br /&gt;
	&#039;oojs-ui.styles.icons-interactions&#039;,&lt;br /&gt;
	&#039;oojs-ui.styles.icons-movement&#039;,&lt;br /&gt;
	&#039;oojs-ui.styles.icons-content&#039;,&lt;br /&gt;
] );&lt;br /&gt;
&lt;br /&gt;
// Handle recreating the editor&lt;br /&gt;
$( &#039;#ca-spriteedit&#039; ).find( &#039;a&#039; ).click( function( e ) {&lt;br /&gt;
	// Editor is already loaded, reload the page&lt;br /&gt;
	if ( $root.hasClass( &#039;spriteedit-loaded&#039; ) ) {&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
	create();&lt;br /&gt;
	e.preventDefault();&lt;br /&gt;
} );&lt;br /&gt;
$win.on( &#039;popstate&#039;, function() {&lt;br /&gt;
	if (&lt;br /&gt;
		location.search.match( &#039;[?&amp;amp;]spriteaction=edit&#039; ) &amp;amp;&amp;amp;&lt;br /&gt;
		!$root.hasClass( &#039;spriteedit-loaded&#039; )&lt;br /&gt;
	) {&lt;br /&gt;
		create( &#039;history&#039; );&lt;br /&gt;
	}&lt;br /&gt;
} );&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/** Functions **/&lt;br /&gt;
/**&lt;br /&gt;
 * Entry point for the editor&lt;br /&gt;
 *&lt;br /&gt;
 * Updates the page if it has been edited since being viewed&lt;br /&gt;
 * and creates the editor once ready&lt;br /&gt;
 * Is called right at the end of the script, once all other functions&lt;br /&gt;
 * are defined.&lt;br /&gt;
 *&lt;br /&gt;
 * &amp;quot;state&amp;quot; is what triggered the creation (e.g. from history navigation)&lt;br /&gt;
 */&lt;br /&gt;
var create = function( state ) {&lt;br /&gt;
	var $doc = $( &#039;#spritedoc&#039; );&lt;br /&gt;
	var preventClose;&lt;br /&gt;
	var settings = {};&lt;br /&gt;
	var mouse = {&lt;br /&gt;
		moved: false,&lt;br /&gt;
		x: 0, y: 0&lt;br /&gt;
	};&lt;br /&gt;
	var sorting = false;&lt;br /&gt;
	var oldHtml;&lt;br /&gt;
	var spritesheet;&lt;br /&gt;
	var spriteSettings = JSON.parse( $doc.attr( &#039;data-settings&#039; ) );&lt;br /&gt;
	var dataPage = $doc.data( &#039;datapage&#039; );&lt;br /&gt;
	var changes = [];&lt;br /&gt;
	var undoneChanges = [];&lt;br /&gt;
	var usedNames = {};&lt;br /&gt;
	var loadingImages = [];&lt;br /&gt;
	var panels = {};&lt;br /&gt;
	var canTag = null;&lt;br /&gt;
	&lt;br /&gt;
	// Update the title to say we&#039;re editing&lt;br /&gt;
	document.title = i18n.titleEditing.replace( /\$1/g, originalTitle );&lt;br /&gt;
	&lt;br /&gt;
	var revisionsApi = new mw.Api( { parameters: {&lt;br /&gt;
		action: &#039;query&#039;,&lt;br /&gt;
		prop: &#039;revisions&#039;,&lt;br /&gt;
		rvprop: &#039;content&#039;,&lt;br /&gt;
		formatversion: 2,&lt;br /&gt;
	} } );&lt;br /&gt;
	var parseApi = new mw.Api( { parameters: {&lt;br /&gt;
		action: &#039;parse&#039;,&lt;br /&gt;
		prop: &#039;text&#039;,&lt;br /&gt;
		disabletoc: true,&lt;br /&gt;
		disablelimitreport: true,&lt;br /&gt;
		formatversion: 2,&lt;br /&gt;
	} } );&lt;br /&gt;
	var $headingTemplate = $( &#039;&amp;lt;h3&amp;gt;&#039; ).html(&lt;br /&gt;
		$( &#039;&amp;lt;span&amp;gt;&#039; )&lt;br /&gt;
			.addClass( &#039;mw-headline spriteedit-new&#039; )&lt;br /&gt;
			.attr( &#039;data-placeholder&#039;, i18n.sectionPlaceholder )&lt;br /&gt;
	);&lt;br /&gt;
	var $boxTemplate = $( &#039;&amp;lt;li&amp;gt;&#039; ).addClass( &#039;spritedoc-box spriteedit-new&#039; ).append(&lt;br /&gt;
		$( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;spritedoc-image&#039; ),&lt;br /&gt;
		$( &#039;&amp;lt;ul&amp;gt;&#039; ).addClass( &#039;spritedoc-names&#039; ).append(&lt;br /&gt;
			$( &#039;&amp;lt;li&amp;gt;&#039; ).addClass( &#039;spritedoc-name&#039; ).html( &#039;&amp;lt;code&amp;gt;&#039; )&lt;br /&gt;
		)&lt;br /&gt;
	);&lt;br /&gt;
	addControls( $headingTemplate, &#039;heading&#039; );&lt;br /&gt;
	addControls( $boxTemplate, &#039;box&#039; );&lt;br /&gt;
	&lt;br /&gt;
	// Pre-load modules which will be needed later&lt;br /&gt;
	var saveModules = mw.loader.using( [&lt;br /&gt;
		&#039;mediawiki.widgets.visibleLengthLimit&#039;,&lt;br /&gt;
		&#039;mediawiki.diff.styles&#039;,&lt;br /&gt;
	] ).fail( console.warn );&lt;br /&gt;
	&lt;br /&gt;
	$root.addClass( &#039;spriteedit-loaded&#039; );&lt;br /&gt;
	&lt;br /&gt;
	if ( !state ) {&lt;br /&gt;
		history.pushState( {}, &#039;&#039;, mw.util.getUrl( null, { spriteaction: &#039;edit&#039; } ) );&lt;br /&gt;
	}&lt;br /&gt;
	if ( state !== &#039;initial&#039; ) {&lt;br /&gt;
		$( &#039;#ca-view&#039; ).add( &#039;#ca-spriteedit&#039; ).toggleClass( &#039;selected&#039; );&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	// Get some info about this wiki, the user&#039;s rights and&lt;br /&gt;
	// block status, and the last edit timestamp for the ids page&lt;br /&gt;
	var infoRequest = retryableRequest( function() {&lt;br /&gt;
		return revisionsApi.get( {&lt;br /&gt;
			rvprop: &#039;timestamp&#039;,&lt;br /&gt;
			titles: dataPage,&lt;br /&gt;
			meta: &#039;siteinfo|userinfo&#039;,&lt;br /&gt;
			uiprop: &#039;rights|blockinfo&#039;,&lt;br /&gt;
		} );&lt;br /&gt;
	} ).done( function( data ) {&lt;br /&gt;
		fixTimestamp.offset = data.query.general.timeoffset;&lt;br /&gt;
	} );&lt;br /&gt;
	&lt;br /&gt;
	// Check if the ids page has been edited since opening the&lt;br /&gt;
	// documentation page, and re-download it if necessary&lt;br /&gt;
	var contentRequest = infoRequest.then( function( data ) {&lt;br /&gt;
		var currentTimestamp = fixTimestamp( data.query.pages[0].revisions[0].timestamp );&lt;br /&gt;
		if ( currentTimestamp &amp;gt; $doc.data( &#039;datatimestamp&#039; ) ) {&lt;br /&gt;
			var newContent = retryableRequest( function() {&lt;br /&gt;
				return parseApi.get( {&lt;br /&gt;
					title: mw.config.get( &#039;wgPageName&#039; ),&lt;br /&gt;
					text: $( &#039;&amp;lt;i&amp;gt;&#039; ).html(&lt;br /&gt;
						$.parseHTML( $doc.attr( &#039;data-refreshtext&#039; ) )&lt;br /&gt;
					).html()&lt;br /&gt;
				} );&lt;br /&gt;
			} ).done( function( parseData ) {&lt;br /&gt;
				oldHtml = parseData.parse.text;&lt;br /&gt;
				$doc.replaceWith( oldHtml );&lt;br /&gt;
				$doc = $( &#039;#spritedoc&#039; );&lt;br /&gt;
				spriteSettings = JSON.parse( $doc.attr( &#039;data-settings&#039; ) );&lt;br /&gt;
				dataPage = $doc.data( &#039;datapage&#039; );&lt;br /&gt;
			} );&lt;br /&gt;
			&lt;br /&gt;
			return newContent;&lt;br /&gt;
		} else {&lt;br /&gt;
			oldHtml = $doc[0].outerHTML;&lt;br /&gt;
		}&lt;br /&gt;
	} );&lt;br /&gt;
	&lt;br /&gt;
	// Check if we have permission to edit the IDs page, spritesheet&lt;br /&gt;
	// file, and use tags, and that the user isn&#039;t blocked&lt;br /&gt;
	var permissionsRequest = $.when( infoRequest, contentRequest ).then( function( data ) {&lt;br /&gt;
		var info = data[0].query.userinfo;&lt;br /&gt;
		&lt;br /&gt;
		var canEdit = true;&lt;br /&gt;
		if ( info.blockid ) {&lt;br /&gt;
			canEdit = false;&lt;br /&gt;
			var $blockNotice = $( &#039;&amp;lt;p&amp;gt;&#039; ).text( i18n.blockedNotice );&lt;br /&gt;
			var blockText;&lt;br /&gt;
			if ( info.blockreason ) {&lt;br /&gt;
				blockText = retryableRequest( function() {&lt;br /&gt;
					return parseApi.get( { summary: info.blockreason } );&lt;br /&gt;
				} ).done( function( parseData ) {&lt;br /&gt;
					$blockNotice.append( &#039;&amp;lt;br&amp;gt;&#039;, i18n.blockedReason.replace( /\$1/g,&lt;br /&gt;
						$( &#039;&amp;lt;span&amp;gt;&#039; ).addClass( &#039;comment&#039; ).html( parseData.parse.parsedsummary ).html()&lt;br /&gt;
					) );&lt;br /&gt;
				} );&lt;br /&gt;
			}&lt;br /&gt;
			$.when( blockText ).always( function() {&lt;br /&gt;
				mw.notify( $blockNotice, { type: &#039;error&#039;, autoHide: false } );&lt;br /&gt;
			} );&lt;br /&gt;
		} else {&lt;br /&gt;
			var rights = info.rights;&lt;br /&gt;
			$.each( [ &#039;data&#039;, &#039;sprite&#039; ], function() {&lt;br /&gt;
				var requiredRights = $doc.data( this + &#039;protection&#039; ).split( &#039;,&#039; );&lt;br /&gt;
				$.each( requiredRights, function() {&lt;br /&gt;
					if ( rights.indexOf( this ) === -1 ) {&lt;br /&gt;
						canEdit = false;&lt;br /&gt;
						return false;&lt;br /&gt;
					}&lt;br /&gt;
				} );&lt;br /&gt;
				&lt;br /&gt;
				return canEdit;&lt;br /&gt;
			} );&lt;br /&gt;
			&lt;br /&gt;
			if ( !canEdit ) {&lt;br /&gt;
				mw.notify( i18n.noPermissionNotice, { type: &#039;error&#039;, autoHide: false } );&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			/* User doesn&#039;t have the right to apply change tags */&lt;br /&gt;
			if ( rights.indexOf( &#039;applychangetags&#039; ) === -1 ) {&lt;br /&gt;
				canTag = false;&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		if ( !canEdit ) {&lt;br /&gt;
			sheetRequest &amp;amp;&amp;amp; sheetRequest.abort();&lt;br /&gt;
			contentRequest.abort &amp;amp;&amp;amp; contentRequest.abort();&lt;br /&gt;
			&lt;br /&gt;
			destroy( true );&lt;br /&gt;
		}&lt;br /&gt;
	} );&lt;br /&gt;
	&lt;br /&gt;
	// Replace the spritesheet with a fresh uncached one to ensure&lt;br /&gt;
	// we don&#039;t save over it with an old version.&lt;br /&gt;
	var sheetRequest;&lt;br /&gt;
	if ( imageEditingSupported ) {&lt;br /&gt;
		sheetRequest = contentRequest.then( function() {&lt;br /&gt;
			var $sprite = $doc.find( &#039;.sprite&#039; ).first();&lt;br /&gt;
			settings.imageWidth = spriteSettings[i18n.luaKeySettingsWidth] || spriteSettings[i18n.luaKeySettingsSize] || 16;&lt;br /&gt;
			settings.imageHeight = spriteSettings[i18n.luaKeySettingsHeight] || settings.imageWidth || 16;&lt;br /&gt;
			settings.spacing = spriteSettings[i18n.luaKeySettingsSpacing] || 0;&lt;br /&gt;
			settings.sheet = $doc.data( &#039;original-url&#039; );&lt;br /&gt;
			if ( !settings.sheet ) {&lt;br /&gt;
				// Get a capture of the whole URL, and of the URL minus the query string&lt;br /&gt;
				var urlParts = $sprite.css( &#039;background-image&#039; )&lt;br /&gt;
					.match( /^url\([&amp;quot;&#039;]?(([^?&amp;quot;]+)(?:\?[^&amp;quot;]+)?)[&amp;quot;&#039;]?\)$/ );&lt;br /&gt;
				$doc.data( &#039;original-url&#039;, urlParts[1] );&lt;br /&gt;
				settings.sheet = urlParts[2] + &#039;?version=&#039; + Date.now();&lt;br /&gt;
				$doc.data( &#039;url&#039;, settings.sheet );&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			// XHR is used instead of a CORS Image so a blob URL can&lt;br /&gt;
			// be used for the background image, rather than the real URL.&lt;br /&gt;
			// This works around the image being downloaded twice, probably&lt;br /&gt;
			// caused by the background image not reusing the CORS request.&lt;br /&gt;
			return retryableRequest( function() {&lt;br /&gt;
				var deferred = $.Deferred();&lt;br /&gt;
				var requestTimeout;&lt;br /&gt;
				var xhr = new XMLHttpRequest();&lt;br /&gt;
				xhr.open( &#039;GET&#039;, settings.sheet, true );&lt;br /&gt;
				xhr.responseType = &#039;blob&#039;;&lt;br /&gt;
				xhr.onload = function() {&lt;br /&gt;
					clearTimeout( requestTimeout );&lt;br /&gt;
					if ( this.status !== 200 ) {&lt;br /&gt;
						deferred.reject( &#039;http&#039;, {&lt;br /&gt;
							textStatus: this.statusText ? this.status + &#039; &#039; + this.statusText : &#039;error&#039;&lt;br /&gt;
						} );&lt;br /&gt;
						return;&lt;br /&gt;
					}&lt;br /&gt;
					&lt;br /&gt;
					spritesheet = new Image();&lt;br /&gt;
					spritesheet.onload = function() {&lt;br /&gt;
						settings.sheetWidth = this.width;&lt;br /&gt;
						settings.sheetHeight = this.height;&lt;br /&gt;
						&lt;br /&gt;
						overwriteSpritesheet( this.src );&lt;br /&gt;
						&lt;br /&gt;
						deferred.resolve();&lt;br /&gt;
					};&lt;br /&gt;
					spritesheet.src = URL.createObjectURL( this.response );&lt;br /&gt;
				};&lt;br /&gt;
				requestTimeout = setTimeout( function() {&lt;br /&gt;
					xhr.abort();&lt;br /&gt;
					deferred.reject( &#039;http&#039;, { textStatus: &#039;timeout&#039; } );&lt;br /&gt;
				}, 30 * 1000 );&lt;br /&gt;
				&lt;br /&gt;
				xhr.onabort = xhr.onerror = function() {&lt;br /&gt;
					if ( deferred.state() === &#039;pending&#039; ) {&lt;br /&gt;
						deferred.reject( &#039;http&#039;, { textStatus: &#039;error&#039; } );&lt;br /&gt;
					}&lt;br /&gt;
				};&lt;br /&gt;
				xhr.send();&lt;br /&gt;
				&lt;br /&gt;
				return deferred.promise( { abort: function() {&lt;br /&gt;
					deferred.reject( &#039;http&#039;, { textStatus: &#039;abort&#039; } );&lt;br /&gt;
					xhr.abort();&lt;br /&gt;
				} } );&lt;br /&gt;
			} ).fail( handleError );&lt;br /&gt;
		} );&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	$.when( contentRequest, permissionsRequest ).then( function() {&lt;br /&gt;
		// Make sure the editor wasn&#039;t destroyed while we were waiting&lt;br /&gt;
		if ( $root.hasClass( &#039;spriteedit-loaded&#039; ) ) {&lt;br /&gt;
			enable();&lt;br /&gt;
		}&lt;br /&gt;
	}, function( code, error ) {&lt;br /&gt;
		// Fatal error, bail&lt;br /&gt;
		sheetRequest &amp;amp;&amp;amp; sheetRequest.abort();&lt;br /&gt;
		infoRequest.abort();&lt;br /&gt;
		contentRequest.abort &amp;amp;&amp;amp; contentRequest.abort();&lt;br /&gt;
		&lt;br /&gt;
		handleError( code, error );&lt;br /&gt;
		destroy( true );&lt;br /&gt;
	} );&lt;br /&gt;
	&lt;br /&gt;
	// Handle closing the editor on navigation&lt;br /&gt;
	$win.on( &#039;popstate.spriteEdit&#039;, function() {&lt;br /&gt;
		if (&lt;br /&gt;
			!location.search.match( &#039;[?&amp;amp;]spriteaction=edit&#039; ) &amp;amp;&amp;amp;&lt;br /&gt;
			$root.hasClass( &#039;spriteedit-loaded&#039; )&lt;br /&gt;
		) {&lt;br /&gt;
			close( &#039;history&#039; );&lt;br /&gt;
		}&lt;br /&gt;
	} );&lt;br /&gt;
	&lt;br /&gt;
	&lt;br /&gt;
	/**&lt;br /&gt;
	 * Create the editor interface&lt;br /&gt;
	 *&lt;br /&gt;
	 * Makes the necessary HTML changes to the documentation,&lt;br /&gt;
	 * creates the extra interface elements, and binds the events.&lt;br /&gt;
	 */&lt;br /&gt;
	var enable = function() {&lt;br /&gt;
		var $content = $doc.closest( &#039;.documentation&#039; );&lt;br /&gt;
		var $toolbar;&lt;br /&gt;
		&lt;br /&gt;
		if ( !$content.length ) {&lt;br /&gt;
			$content = $( &#039;#content&#039; );&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		$root.addClass( &#039;spriteedit-enabled&#039; );&lt;br /&gt;
		if ( imageEditingSupported ) {&lt;br /&gt;
			$root.addClass( &#039;spriteedit-imageeditingenabled&#039; );&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		$( &#039;.mw-editsection&#039; ).add( &#039;.mw-editsection-like&#039; ).css( &#039;display&#039;, &#039;none&#039; );&lt;br /&gt;
		&lt;br /&gt;
		// Store previous element and parent to re-attach to once done&lt;br /&gt;
		// and the current scroll position&lt;br /&gt;
		var $docPrev = $doc.prev();&lt;br /&gt;
		var $docParent = $doc.parent();&lt;br /&gt;
		var initialScroll = $win.scrollTop();&lt;br /&gt;
		$doc.detach();&lt;br /&gt;
		&lt;br /&gt;
		$doc.find( &#039;#toc&#039; ).remove();&lt;br /&gt;
		&lt;br /&gt;
		$doc.append(&lt;br /&gt;
			$( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;spriteedit-autoscroll spriteedit-autoscroll-up&#039; ),&lt;br /&gt;
			$( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;spriteedit-autoscroll spriteedit-autoscroll-down&#039; )&lt;br /&gt;
		);&lt;br /&gt;
		var autoScroll = function( now ) {&lt;br /&gt;
			autoScroll.delta = ( now - autoScroll.timeLast ) / ( 1000 / 60 );&lt;br /&gt;
			autoScroll.timeLast = now;&lt;br /&gt;
			&lt;br /&gt;
			if ( mouse.y !== autoScroll.lastMouseY ) {&lt;br /&gt;
				var areaRect = autoScroll.area.getBoundingClientRect();&lt;br /&gt;
				if ( autoScroll.dir === -1 ) {&lt;br /&gt;
					autoScroll.speed = areaRect.bottom - mouse.y;&lt;br /&gt;
				} else {&lt;br /&gt;
					autoScroll.speed = mouse.y - areaRect.top + 1;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				autoScroll.lastMouseY = mouse.y;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			// Prevent overscroll&lt;br /&gt;
			var scrollTop = $win.scrollTop();&lt;br /&gt;
			if (&lt;br /&gt;
				autoScroll.dir === -1 &amp;amp;&amp;amp; scrollTop &amp;gt; autoScroll.topLimit ||&lt;br /&gt;
				autoScroll.dir === 1 &amp;amp;&amp;amp; scrollTop + $win.height() &amp;lt; autoScroll.bottomLimit&lt;br /&gt;
			) {&lt;br /&gt;
				scrollBy( 0, autoScroll.dir * Math.round( autoScroll.speed / 2 ) * Math.round( autoScroll.delta ) );&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			autoScroll.id = requestAnimationFrame( autoScroll );&lt;br /&gt;
		};&lt;br /&gt;
		autoScroll.start = function( area ) {&lt;br /&gt;
			if ( autoScroll.id ) {&lt;br /&gt;
				autoScroll.stop();&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			var scrollTop = $win.scrollTop();&lt;br /&gt;
			autoScroll.area = area;&lt;br /&gt;
			autoScroll.dir = $( area ).hasClass( &#039;spriteedit-autoscroll-up&#039; ) ? -1 : 1;&lt;br /&gt;
			autoScroll.speed = 1;&lt;br /&gt;
			autoScroll.timeLast = window.performance ? performance.now() : Date.now();&lt;br /&gt;
			autoScroll.topLimit = scrollTop + $doc[0].getBoundingClientRect().top;&lt;br /&gt;
			autoScroll.bottomLimit = scrollTop + $doc.find( &#039;.spritedoc-section&#039; ).last()[0].getBoundingClientRect().bottom + 50;&lt;br /&gt;
			autoScroll.id = requestAnimationFrame( autoScroll );&lt;br /&gt;
		};&lt;br /&gt;
		autoScroll.stop = function() {&lt;br /&gt;
			cancelAnimationFrame( autoScroll.id );&lt;br /&gt;
			autoScroll.id = 0;&lt;br /&gt;
		};&lt;br /&gt;
		&lt;br /&gt;
		$doc.find( &#039;.spriteedit-autoscroll&#039; )&lt;br /&gt;
			.on( &#039;mouseenter.spriteEdit dragenter.spriteEdit&#039;, function() {&lt;br /&gt;
				autoScroll.start( this );&lt;br /&gt;
			} )&lt;br /&gt;
			.on( &#039;mouseleave.spriteEdit dragleave.spriteEdit&#039;, autoScroll.stop );&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
		addControls( $doc.find( &#039;h3&#039; ), &#039;heading&#039; );&lt;br /&gt;
		&lt;br /&gt;
		var $boxes = $doc.find( &#039;.spritedoc-box&#039; );&lt;br /&gt;
		$boxes.each( function() {&lt;br /&gt;
			var $this = $( this );&lt;br /&gt;
			&lt;br /&gt;
			var $names = $this.find( &#039;.spritedoc-name&#039; );&lt;br /&gt;
			$this.attr( &#039;data-sort-key&#039;, $names.first().text() );&lt;br /&gt;
			&lt;br /&gt;
			$names.find( &#039;code&#039; ).each( function() {&lt;br /&gt;
				var $code = $( this );&lt;br /&gt;
				usedNames[$code.text()] = [ $code ];&lt;br /&gt;
			} );&lt;br /&gt;
		} );&lt;br /&gt;
		addControls( $boxes, &#039;box&#039; );&lt;br /&gt;
		&lt;br /&gt;
		// Collapses and expands boxes in each section when sorting&lt;br /&gt;
		// sections or boxes, so it&#039;s easier to get to the right section&lt;br /&gt;
		var collapseBoxes = function( placeholder ) {&lt;br /&gt;
			var $this = $( this );&lt;br /&gt;
			var isBox = $this.hasClass( &#039;spritedoc-box&#039; );&lt;br /&gt;
			var section = isBox ? $this.closest( &#039;.spritedoc-section&#039; )[0] : placeholder;&lt;br /&gt;
			var origPos = this.getBoundingClientRect();&lt;br /&gt;
			var origSectionPos = section.getBoundingClientRect();&lt;br /&gt;
			var heights = [];&lt;br /&gt;
			&lt;br /&gt;
			$doc.find( &#039;.spritedoc-boxes&#039; ).each( function() {&lt;br /&gt;
				var child = this.firstElementChild;&lt;br /&gt;
				if ( child ) {&lt;br /&gt;
					if ( $( child ).hasClass( &#039;spriteedit-ghost&#039; ) ) {&lt;br /&gt;
						child = child.nextElementSibling || child;&lt;br /&gt;
					}&lt;br /&gt;
					heights.push( child.getBoundingClientRect().height );&lt;br /&gt;
				} else {&lt;br /&gt;
					heights.push( 0 );&lt;br /&gt;
				}&lt;br /&gt;
			} ).each( function( i ) {&lt;br /&gt;
				// Set styling after get loop to avoid layout thrashing&lt;br /&gt;
				var height = heights[i];&lt;br /&gt;
				if ( !height ) {&lt;br /&gt;
					return;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				$( this ).css( {&lt;br /&gt;
					height: height,&lt;br /&gt;
					overflow: &#039;hidden&#039;,&lt;br /&gt;
				} );&lt;br /&gt;
			} );&lt;br /&gt;
			&lt;br /&gt;
			// First make sure the section is in the same place relative to the window&lt;br /&gt;
			scroll( 0, $win.scrollTop() + section.getBoundingClientRect().top - origSectionPos.top );&lt;br /&gt;
			&lt;br /&gt;
			// Now if we&#039;re sorting boxes, make sure the box remains inside the section&lt;br /&gt;
			if ( isBox ) {&lt;br /&gt;
				var sectionPos = section.getBoundingClientRect();&lt;br /&gt;
				if ( origPos.bottom &amp;gt; sectionPos.bottom ) {&lt;br /&gt;
					scroll( 0, $win.scrollTop() + sectionPos.bottom - origPos.bottom );&lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
		};&lt;br /&gt;
		var expandBoxes = function() {&lt;br /&gt;
			var origPos = this.getBoundingClientRect();&lt;br /&gt;
			&lt;br /&gt;
			$doc.find( &#039;.spritedoc-boxes&#039; ).css( {&lt;br /&gt;
				height: &#039;auto&#039;,&lt;br /&gt;
				overflow: &#039;visible&#039;,&lt;br /&gt;
			} );&lt;br /&gt;
			&lt;br /&gt;
			// If we&#039;re sorting boxes, scroll so the box is near the cursor&lt;br /&gt;
			var $this = $( this );&lt;br /&gt;
			if ( $this.hasClass( &#039;spritedoc-box&#039; ) ) {&lt;br /&gt;
				var boxPos = this.getBoundingClientRect();&lt;br /&gt;
				scroll( 0, $win.scrollTop() + boxPos.top + boxPos.height / 2 - mouse.y );&lt;br /&gt;
				&lt;br /&gt;
				// Flash the box so it is obvious where it was sorted to&lt;br /&gt;
				$this.css( &#039;background-color&#039;, &#039;yellow&#039; );&lt;br /&gt;
				setTimeout( function() {&lt;br /&gt;
					$this.css( &#039;background-color&#039;, &#039;&#039; );&lt;br /&gt;
				}, 1000 );&lt;br /&gt;
			} else {&lt;br /&gt;
				// Otherwise make sure the section is in the same place relative to the window&lt;br /&gt;
				scroll( 0, $win.scrollTop() + this.getBoundingClientRect().top - origPos.top );&lt;br /&gt;
			}&lt;br /&gt;
		};&lt;br /&gt;
		makeSortable( {&lt;br /&gt;
			selectors: &#039;.spritedoc-section&#039;,&lt;br /&gt;
			handle: &#039;h3&#039;,&lt;br /&gt;
			vertical: true,&lt;br /&gt;
			sortStart: collapseBoxes,&lt;br /&gt;
			sortEnd: expandBoxes,&lt;br /&gt;
		} );&lt;br /&gt;
		makeSortable( {&lt;br /&gt;
			selectors: {&lt;br /&gt;
				container: &#039;.spritedoc-section&#039;,&lt;br /&gt;
				parent: &#039;.spritedoc-boxes&#039;,&lt;br /&gt;
				elem: &#039;.spritedoc-box&#039;,&lt;br /&gt;
			},&lt;br /&gt;
			autoSort: true,&lt;br /&gt;
			sortStart: collapseBoxes,&lt;br /&gt;
			sortEnd: expandBoxes,&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		// Create toolbar&lt;br /&gt;
		var contentPadding = {&lt;br /&gt;
			left: $content.css( &#039;padding-left&#039; ),&lt;br /&gt;
			right: $content.css( &#039;padding-right&#039; ),&lt;br /&gt;
		};&lt;br /&gt;
		$toolbar = $( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;spriteedit-toolbar&#039; ).css( {&lt;br /&gt;
			paddingLeft: contentPadding.left,&lt;br /&gt;
			paddingRight: contentPadding.right,&lt;br /&gt;
			marginLeft: &#039;-&#039; + contentPadding.left,&lt;br /&gt;
			marginRight: &#039;-&#039; + contentPadding.right,&lt;br /&gt;
		} );&lt;br /&gt;
		var undoButton = new OO.ui.ButtonInputWidget( {&lt;br /&gt;
			id: &#039;spriteedit-undo&#039;,&lt;br /&gt;
			icon: &#039;undo&#039;,&lt;br /&gt;
			label: i18n.toolbarUndo,&lt;br /&gt;
			disabled: true,&lt;br /&gt;
		} );&lt;br /&gt;
		undoButton.$element.data( &#039;ooui-object&#039;, undoButton );&lt;br /&gt;
		&lt;br /&gt;
		var redoButton = new OO.ui.ButtonInputWidget( {&lt;br /&gt;
			id: &#039;spriteedit-redo&#039;,&lt;br /&gt;
			icon: &#039;redo&#039;,&lt;br /&gt;
			label: i18n.toolbarRedo,&lt;br /&gt;
			disabled: true,&lt;br /&gt;
		} );&lt;br /&gt;
		redoButton.$element.data( &#039;ooui-object&#039;, redoButton );&lt;br /&gt;
		&lt;br /&gt;
		var newSectionButton = new OO.ui.ButtonInputWidget( {&lt;br /&gt;
			id: &#039;spriteedit-add-section&#039;,&lt;br /&gt;
			icon: &#039;textStyle&#039;,&lt;br /&gt;
			label: i18n.toolbarNewSection,&lt;br /&gt;
		} );&lt;br /&gt;
		newSectionButton.$element.data( &#039;ooui-object&#039;, newSectionButton );&lt;br /&gt;
		&lt;br /&gt;
		var newImageButton = new OO.ui.ButtonInputWidget( {&lt;br /&gt;
			id: &#039;spriteedit-add-image&#039;,&lt;br /&gt;
			icon: &#039;imageAdd&#039;,&lt;br /&gt;
			label: i18n.toolbarNewImage,&lt;br /&gt;
		} );&lt;br /&gt;
		newImageButton.$element.data( &#039;ooui-object&#039;, newImageButton );&lt;br /&gt;
		if ( !imageEditingSupported ) {&lt;br /&gt;
			newImageButton.setDisabled( true ).$element&lt;br /&gt;
				.prop( &#039;title&#039;, i18n.browserActionNotSupported )&lt;br /&gt;
				.css( &#039;cursor&#039;, &#039;help&#039; );&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		var saveButton = new OO.ui.ButtonInputWidget( {&lt;br /&gt;
			id: &#039;spriteedit-save&#039;,&lt;br /&gt;
			flags: [ &#039;progressive&#039;, &#039;primary&#039; ],&lt;br /&gt;
			icon: &#039;expand&#039;,&lt;br /&gt;
			label: i18n.toolbarSave,&lt;br /&gt;
			disabled: true,&lt;br /&gt;
		} );&lt;br /&gt;
		saveButton.$element.data( &#039;ooui-object&#039;, saveButton ).css( &#039;right&#039;, contentPadding.right );&lt;br /&gt;
		&lt;br /&gt;
		var toolboxSelect = new OO.ui.DropdownWidget( {&lt;br /&gt;
			id: &#039;spriteedit-toolbox&#039;,&lt;br /&gt;
			label: i18n.toolbarTools,&lt;br /&gt;
			$overlay: $doc,&lt;br /&gt;
		} );&lt;br /&gt;
		toolboxSelect.$element.data( &#039;ooui-object&#039;, toolboxSelect );&lt;br /&gt;
		&lt;br /&gt;
		var helpButton = new OO.ui.ButtonWidget( {&lt;br /&gt;
			id: &#039;spriteedit-help&#039;,&lt;br /&gt;
			framed: false,&lt;br /&gt;
			icon: &#039;help&#039;,&lt;br /&gt;
			title: i18n.toolbarHelp,&lt;br /&gt;
			href: mw.util.getUrl( i18n.toolbarHelpPage ),&lt;br /&gt;
			target: &#039;_blank&#039;,&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		$toolbar.append(&lt;br /&gt;
			new OO.ui.ButtonGroupWidget( {&lt;br /&gt;
				items: [ undoButton, redoButton ],&lt;br /&gt;
			} ).$element,&lt;br /&gt;
			new OO.ui.ButtonGroupWidget( {&lt;br /&gt;
				items: [ newSectionButton, newImageButton ],&lt;br /&gt;
			} ).$element,&lt;br /&gt;
			toolboxSelect.$element,&lt;br /&gt;
			saveButton.$element,&lt;br /&gt;
			helpButton.$element&lt;br /&gt;
		);&lt;br /&gt;
		&lt;br /&gt;
		// Create tools&lt;br /&gt;
		var $toolbox = $toolbar.find( &#039;#spriteedit-toolbox&#039; );&lt;br /&gt;
		var deprecateOption = new OO.ui.MenuOptionWidget( {&lt;br /&gt;
			data: &#039;deprecate&#039;,&lt;br /&gt;
			label: i18n.toolbarToolDeprecate,&lt;br /&gt;
			icon: &#039;flag&#039;,&lt;br /&gt;
		} );&lt;br /&gt;
		deprecateOption.$element.prop( &#039;title&#039;, i18n.toolbarToolDeprecateTip );&lt;br /&gt;
		toolboxSelect.getMenu().addItems( [ deprecateOption ] );&lt;br /&gt;
		&lt;br /&gt;
		var $barContainer = $( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;spriteedit-toolbar-container&#039; )&lt;br /&gt;
			.append( $toolbar ).prependTo( $doc );&lt;br /&gt;
		&lt;br /&gt;
		// Re-attach content and reset scroll position&lt;br /&gt;
		if ( $docPrev.length ) {&lt;br /&gt;
			$doc.insertAfter( $docPrev );&lt;br /&gt;
		} else {&lt;br /&gt;
			$doc.prependTo( $docParent );&lt;br /&gt;
		}&lt;br /&gt;
		if ( $win.scrollTop() !== initialScroll ) {&lt;br /&gt;
			scroll( 0, initialScroll );&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		// Set height now that everything is re-attached&lt;br /&gt;
		var toolbarHeight = $toolbar[0].getBoundingClientRect().height;&lt;br /&gt;
		$barContainer.height( toolbarHeight );&lt;br /&gt;
		&lt;br /&gt;
		// Wait until everything else is done so the animation is smooth&lt;br /&gt;
		requestAnimationFrame( function() {&lt;br /&gt;
			var barTop = $barContainer[0].getBoundingClientRect().top;&lt;br /&gt;
			if ( barTop &amp;gt; 0 ) {&lt;br /&gt;
				$root.addClass( &#039;spriteedit-smoothscroll&#039; );&lt;br /&gt;
				scroll( 0, barTop + $win.scrollTop() + 1 );&lt;br /&gt;
			}&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		// Check the editor&#039;s change tag exists&lt;br /&gt;
		// Since the tag isn&#039;t important, we don&#039;t wait for the request to finish&lt;br /&gt;
		// If it isn&#039;t done by the time we try to save, we assume we can&#039;t tag&lt;br /&gt;
		if ( canTag !== false ) {&lt;br /&gt;
			findChangeTag( &#039;spriteeditor&#039; ).then( function( result ) {&lt;br /&gt;
				canTag = result;&lt;br /&gt;
			} );&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
		/** Bind events **/&lt;br /&gt;
		/* Outside interface events */&lt;br /&gt;
		// Prevent accidentally closing window if changes have been made&lt;br /&gt;
		preventClose = mw.confirmCloseWindow( {&lt;br /&gt;
			namespace: &#039;spriteEdit&#039;,&lt;br /&gt;
			test: function() {&lt;br /&gt;
				return !saveButton.isDisabled();&lt;br /&gt;
			},&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		$( &#039;#ca-view&#039; ).find( &#039;a&#039; ).on( &#039;click.spriteEdit&#039;, function( e ) {&lt;br /&gt;
			close();&lt;br /&gt;
			e.preventDefault();&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
		/* Toolbar events */&lt;br /&gt;
		// Manually make the toolbar sticky if position:sticky isn&#039;t supported&lt;br /&gt;
		if ( !supports( &#039;position&#039;, &#039;sticky&#039; ) &amp;amp;&amp;amp; !supports( &#039;position&#039;, &#039;-webkit-sticky&#039; ) ) {&lt;br /&gt;
			var fixedClass = &#039;spriteedit-toolbar-fixed&#039;;&lt;br /&gt;
			var contentOffset = $content.offset().left + 1;&lt;br /&gt;
			$win.on( &#039;scroll.spriteEdit&#039;, $.throttle( 32, function() {&lt;br /&gt;
				var fixed = $toolbar.hasClass( fixedClass ),&lt;br /&gt;
					scrollTop = $win.scrollTop(),&lt;br /&gt;
					offset = $barContainer.offset().top;&lt;br /&gt;
				if ( !fixed &amp;amp;&amp;amp; scrollTop &amp;gt;= offset ) {&lt;br /&gt;
					$toolbar.addClass( fixedClass ).css( &#039;left&#039;, contentOffset );&lt;br /&gt;
				} else if ( fixed &amp;amp;&amp;amp; scrollTop &amp;lt; offset ) {&lt;br /&gt;
					$toolbar.removeClass( fixedClass ).css( &#039;left&#039;, &#039;&#039; );&lt;br /&gt;
				}&lt;br /&gt;
			} ) );&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		$( &#039;#spriteedit-undo&#039; ).find( &#039;button&#039; ).on( &#039;click.spriteEdit&#039;, function() {&lt;br /&gt;
			$( this ).focus().blur();&lt;br /&gt;
			&lt;br /&gt;
			// We&#039;re not meant to be editing&lt;br /&gt;
			if ( $root.hasClass( &#039;spriteedit-hidecontrols&#039; ) ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			var hist = changes.pop();&lt;br /&gt;
			revert( hist );&lt;br /&gt;
			undoneChanges.push( hist );&lt;br /&gt;
			redoButton.setDisabled( false );&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		$( &#039;#spriteedit-redo&#039; ).find( &#039;button&#039; ).on( &#039;click.spriteEdit&#039;, function() {&lt;br /&gt;
			$( this ).focus().blur();&lt;br /&gt;
			&lt;br /&gt;
			// We&#039;re not meant to be editing&lt;br /&gt;
			if ( $root.hasClass( &#039;spriteedit-hidecontrols&#039; ) ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			var hist = undoneChanges.pop();&lt;br /&gt;
			$.each( hist, function() {&lt;br /&gt;
				change( this.action, this.content, false, true );&lt;br /&gt;
			} );&lt;br /&gt;
			changes.push( hist );&lt;br /&gt;
			&lt;br /&gt;
			if ( !undoneChanges.length ) {&lt;br /&gt;
				redoButton.setDisabled( true );&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			$.each( [&lt;br /&gt;
				&#039;#spriteedit-undo&#039;,&lt;br /&gt;
				&#039;#spriteedit-save&#039;,&lt;br /&gt;
				&#039;#spriteedit-summary&#039;,&lt;br /&gt;
				&#039;#spriteedit-review-button&#039;,&lt;br /&gt;
			], function() {&lt;br /&gt;
				if ( $( this ).length ) {&lt;br /&gt;
					$( this ).data( &#039;ooui-object&#039; ).setDisabled( false );&lt;br /&gt;
				}&lt;br /&gt;
			} );&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		$( &#039;#spriteedit-add-section&#039; ).find( &#039;button&#039; ).on( &#039;click.spriteEdit&#039;, function() {&lt;br /&gt;
			$( this ).focus().blur();&lt;br /&gt;
			&lt;br /&gt;
			// We&#039;re not meant to be editing&lt;br /&gt;
			if ( $root.hasClass( &#039;spriteedit-hidecontrols&#039; ) ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			var $newHeading = $headingTemplate.clone();&lt;br /&gt;
			change( &#039;insert&#039;, {&lt;br /&gt;
				$elem: $( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;spritedoc-section&#039; ).prepend(&lt;br /&gt;
					$newHeading,&lt;br /&gt;
					$( &#039;&amp;lt;ul&amp;gt;&#039; ).addClass( &#039;spritedoc-boxes&#039; )&lt;br /&gt;
				),&lt;br /&gt;
				index: $( nearestSection() ).index() - 1,&lt;br /&gt;
				$parent: $doc,&lt;br /&gt;
			}, true );&lt;br /&gt;
			&lt;br /&gt;
			$newHeading.find( &#039;.mw-headline&#039; ).focus();&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		$( &#039;#spriteedit-add-image&#039; ).find( &#039;button&#039; ).on( &#039;click.spriteEdit&#039;, function() {&lt;br /&gt;
			$( this ).focus().blur();&lt;br /&gt;
			&lt;br /&gt;
			// We&#039;re not meant to be editing&lt;br /&gt;
			if ( $root.hasClass( &#039;spriteedit-hidecontrols&#039; ) ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			$( &#039;&amp;lt;input type=&amp;quot;file&amp;quot;&amp;gt;&#039; )&lt;br /&gt;
				.attr( {&lt;br /&gt;
					accept: &#039;image/*&#039;,&lt;br /&gt;
					multiple: true,&lt;br /&gt;
				} )&lt;br /&gt;
				.one( &#039;change.spriteEdit&#039;, function() {&lt;br /&gt;
					insertSprites( this.files );&lt;br /&gt;
				} ).click();&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		// Toolbox functions&lt;br /&gt;
		// Modify click event to not open menu when we&#039;re not meant to be editing,&lt;br /&gt;
		// or a tool is already selected&lt;br /&gt;
		toolboxSelect.origOnClick = toolboxSelect.onClick;&lt;br /&gt;
		toolboxSelect.onClick = function( e ) {&lt;br /&gt;
			if ( $root.hasClass( &#039;spriteedit-hidecontrols&#039; ) ) {&lt;br /&gt;
				this.$handle.blur();&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			toolboxSelect.origOnClick.call( toolboxSelect, e );&lt;br /&gt;
		};&lt;br /&gt;
		toolboxSelect.$handle.off( &#039;click&#039; ).on( &#039;click&#039;, toolboxSelect.onClick.bind( toolboxSelect ) );&lt;br /&gt;
		&lt;br /&gt;
		toolboxSelect.on( &#039;labelChange&#039;, function() {&lt;br /&gt;
			if ( !toolboxSelect.getLabel() ) {&lt;br /&gt;
				toolboxSelect.setLabel( i18n.toolbarTools );&lt;br /&gt;
			}&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		var toolNamespace = &#039;.spriteEdit.spriteEditTool.spriteEditTool&#039;;&lt;br /&gt;
		var tool;&lt;br /&gt;
		// Bind events for each tool&#039;s function&lt;br /&gt;
		toolboxSelect.getMenu().on( &#039;choose&#039;, function( item ) {&lt;br /&gt;
			tool = item.getData();&lt;br /&gt;
			$root.addClass( &#039;spriteedit-hidecontrols spriteedit-tool spriteedit-tool-&#039; + tool );&lt;br /&gt;
			&lt;br /&gt;
			switch ( tool ) {&lt;br /&gt;
				case &#039;deprecate&#039;:&lt;br /&gt;
					$doc.on( &#039;click&#039; + toolNamespace + &#039;Deprecate&#039;, &#039;.spritedoc-name &amp;gt; code&#039;, function() {&lt;br /&gt;
						change( &#039;toggle deprecation&#039;, { $elem: $( this ) } );&lt;br /&gt;
					} );&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
		} );&lt;br /&gt;
		// Clear tool when clicking a toolbar button, the toolbox itself, or pressing escape&lt;br /&gt;
		var clearTool = function( e ) {&lt;br /&gt;
			if ( !$root.hasClass( &#039;spriteedit-tool&#039; ) ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			toolboxSelect.getMenu().selectItem();&lt;br /&gt;
			$doc.off( &#039;.spriteEditTool&#039; );&lt;br /&gt;
			$root.removeClass( &#039;spriteedit-hidecontrols spriteedit-tool spriteedit-tool-&#039; + tool );&lt;br /&gt;
			tool = null;&lt;br /&gt;
		};&lt;br /&gt;
		$toolbar.on( &#039;mouseup.spriteEdit&#039;, &#039;button&#039;, function() {&lt;br /&gt;
			clearTool();&lt;br /&gt;
		} );&lt;br /&gt;
		$toolbox.on( &#039;click.spriteEdit&#039;, function() {&lt;br /&gt;
			clearTool();&lt;br /&gt;
		} );&lt;br /&gt;
		$( document ).on( &#039;keydown.spriteEdit&#039;, function( e ) {&lt;br /&gt;
			// Esc&lt;br /&gt;
			if ( e.keyCode === 27 ) {&lt;br /&gt;
				clearTool();&lt;br /&gt;
			}&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		// Drag and drop functionality&lt;br /&gt;
		if ( imageEditingSupported ) {&lt;br /&gt;
			var dragTimeout, dragEnded;&lt;br /&gt;
			var endDrag = function() {&lt;br /&gt;
				$root.removeClass( &#039;spriteedit-dragging&#039; );&lt;br /&gt;
				&lt;br /&gt;
				clearTimeout( dragTimeout );&lt;br /&gt;
				clearTimeout( dropTimeout );&lt;br /&gt;
				dragEnded = false;&lt;br /&gt;
				dropEnded = false;&lt;br /&gt;
			};&lt;br /&gt;
			var isFile = function( e ) {&lt;br /&gt;
				var types = e.originalEvent.dataTransfer.types;&lt;br /&gt;
				return types.indexOf ?&lt;br /&gt;
					types.indexOf( &#039;Files&#039; ) &amp;gt; -1 || types.indexOf( &#039;application/x-moz-file&#039; ) &amp;gt; -1 :&lt;br /&gt;
					types.contains( &#039;Files&#039; );&lt;br /&gt;
			};&lt;br /&gt;
			$win.on( &#039;dragenter.spriteEdit&#039;, function( e ) {&lt;br /&gt;
				if ( !isFile( e ) ) {&lt;br /&gt;
					return;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				$root.addClass( &#039;spriteedit-dragging&#039; );&lt;br /&gt;
			} ).on( &#039;dragover.spriteEdit&#039;, function() {&lt;br /&gt;
				clearTimeout( dragTimeout );&lt;br /&gt;
				dragEnded = false;&lt;br /&gt;
			} ).on( &#039;dragleave.spriteEdit&#039;, function( e ) {&lt;br /&gt;
				if ( !isFile( e ) ) {&lt;br /&gt;
					return;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				clearTimeout( dragTimeout );&lt;br /&gt;
				dragEnded = true;&lt;br /&gt;
				dragTimeout = setTimeout( function() {&lt;br /&gt;
					if ( dragEnded ) {&lt;br /&gt;
						endDrag();&lt;br /&gt;
					}&lt;br /&gt;
				}, 100 );&lt;br /&gt;
			} );&lt;br /&gt;
			&lt;br /&gt;
			var dropTimeout, dropEnded;&lt;br /&gt;
			$doc.on( &#039;dragenter.spriteEdit&#039;, &#039;.spritedoc-section&#039;, function( e ) {&lt;br /&gt;
				if ( !isFile( e ) ) {&lt;br /&gt;
					return;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				$doc.find( &#039;.spriteedit-droptarget&#039; ).not( this ).removeClass( &#039;spriteedit-droptarget&#039; );&lt;br /&gt;
				$( this ).addClass( &#039;spriteedit-droptarget&#039; );&lt;br /&gt;
			} ).on( &#039;dragover.spriteEdit&#039;, &#039;.spritedoc-section&#039;, function( e ) {&lt;br /&gt;
				clearTimeout( dropTimeout );&lt;br /&gt;
				dropEnded = false;&lt;br /&gt;
				&lt;br /&gt;
				e.originalEvent.dataTransfer.dropEffect = &#039;copy&#039;;&lt;br /&gt;
				&lt;br /&gt;
				e.preventDefault();&lt;br /&gt;
			} ).on( &#039;dragleave.spriteEdit&#039;, &#039;.spritedoc-section&#039;, function( e ) {&lt;br /&gt;
				if ( !isFile( e ) ) {&lt;br /&gt;
					return;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				clearTimeout( dropTimeout );&lt;br /&gt;
				dropEnded = true;&lt;br /&gt;
				dropTimeout = setTimeout( function() {&lt;br /&gt;
					if ( dropEnded ) {&lt;br /&gt;
						$doc.find( &#039;.spriteedit-droptarget&#039; ).removeClass( &#039;spriteedit-droptarget&#039; );&lt;br /&gt;
						dropEnded = false;&lt;br /&gt;
					}&lt;br /&gt;
				}, 100 );&lt;br /&gt;
			} ).on( &#039;drop.spriteEdit&#039;, &#039;.spritedoc-section&#039;, function( e ) {&lt;br /&gt;
				if ( !isFile( e ) ) {&lt;br /&gt;
					return;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				$doc.find( &#039;.spriteedit-droptarget&#039; ).removeClass( &#039;spriteedit-droptarget&#039; );&lt;br /&gt;
				&lt;br /&gt;
				insertSprites( e.originalEvent.dataTransfer.files, this );&lt;br /&gt;
				endDrag();&lt;br /&gt;
				e.preventDefault();&lt;br /&gt;
			} );&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		$( &#039;#spriteedit-save&#039; ).find( &#039;button&#039; ).on( &#039;click.spriteEdit&#039;, function() {&lt;br /&gt;
			var $button = $( this );&lt;br /&gt;
			$button.focus().blur();&lt;br /&gt;
			&lt;br /&gt;
			// Prevent saving and notify if there are duplicate names, but only&lt;br /&gt;
			// if there&#039;s more than one. If there&#039;s only one, it&#039;s clearly been&lt;br /&gt;
			// incorrectly marked as a duplicate&lt;br /&gt;
			if ( $doc.find( &#039;.spriteedit-dupe&#039; ).length &amp;gt; 1 ) {&lt;br /&gt;
				mw.notify( i18n.dupeNamesNotice, { type: &#039;warn&#039;, autoHide: false } );&lt;br /&gt;
				&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			// Prevent saving if button already pressed and still processing&lt;br /&gt;
			if ( $button.hasClass( &#039;spriteedit-processing&#039; ) ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			$button.addClass( &#039;spriteedit-processing&#039; );&lt;br /&gt;
			&lt;br /&gt;
			if ( $toolbar.hasClass( &#039;spriteedit-saveform-open&#039; ) ) {&lt;br /&gt;
				// If we know changes weren&#039;t made (by performing a diff),&lt;br /&gt;
				// quit out, otherwise it&#039;s likely faster to just save and&lt;br /&gt;
				// assume changes were made, than wait for the diff to be ready.&lt;br /&gt;
				// It will just be a null edit if nothing was changed.&lt;br /&gt;
				if ( !names.modified &amp;amp;&amp;amp; !sheet.modified ) {&lt;br /&gt;
					destroy( true );&lt;br /&gt;
					&lt;br /&gt;
					return;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				saveChanges( $( &#039;#spriteedit-summary&#039; ).data( &#039;ooui-object&#039; ).getValue() );&lt;br /&gt;
				&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			saveModules.done( function() {&lt;br /&gt;
				$toolbar.addClass( &#039;spriteedit-saveform-open&#039; );&lt;br /&gt;
				$button&lt;br /&gt;
					.removeClass( &#039;spriteedit-processing&#039; )&lt;br /&gt;
					// Prevent accidental double-click saving&lt;br /&gt;
					.css( &#039;pointer-events&#039;, &#039;none&#039; );&lt;br /&gt;
				&lt;br /&gt;
				$button.parent().data( &#039;ooui-object&#039; ).setIcon( &#039;check&#039; );&lt;br /&gt;
				&lt;br /&gt;
				if ( !$toolbar.find( &#039;#spriteedit-saveform&#039; ).length ) {&lt;br /&gt;
					var summaryInput = new OO.ui.TextInputWidget( {&lt;br /&gt;
						id: &#039;spriteedit-summary&#039;,&lt;br /&gt;
						name: &#039;wpSummary&#039;,&lt;br /&gt;
						spellcheck: true,&lt;br /&gt;
						placeholder: i18n.toolbarSummaryPlaceholder,&lt;br /&gt;
					} );&lt;br /&gt;
					summaryInput.$element.data( &#039;ooui-object&#039;, summaryInput );&lt;br /&gt;
					mw.widgets.visibleByteLimit( summaryInput, mw.config.get( &#039;wgCommentByteLimit&#039; ) );&lt;br /&gt;
					$( &#039;&amp;lt;div&amp;gt;&#039; )&lt;br /&gt;
						.attr( &#039;id&#039;, &#039;spriteedit-saveform&#039; )&lt;br /&gt;
						.css( &#039;margin-right&#039;, $( &#039;#spriteedit-save&#039; )[0].getBoundingClientRect().width )&lt;br /&gt;
						.append(&lt;br /&gt;
							summaryInput.$element,&lt;br /&gt;
							makeButton( i18n.toolbarReviewChanges, { id: &#039;spriteedit-review-button&#039; } )&lt;br /&gt;
					).appendTo( $toolbar );&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				var openedToolbarHeight = $toolbar[0].getBoundingClientRect().height;&lt;br /&gt;
				$toolbar&lt;br /&gt;
					.outerHeight( toolbarHeight )&lt;br /&gt;
					.redraw()&lt;br /&gt;
					.outerHeight( openedToolbarHeight )&lt;br /&gt;
					.transitionEnd( function() {&lt;br /&gt;
						$button.css( &#039;pointer-events&#039;, &#039;&#039; );&lt;br /&gt;
						$barContainer.height( openedToolbarHeight );&lt;br /&gt;
						$( &#039;#spriteedit-summary&#039; ).data( &#039;ooui-object&#039; ).focus();&lt;br /&gt;
						&lt;br /&gt;
						// Do this after the transition so there is no stutter&lt;br /&gt;
						names.getDiff();&lt;br /&gt;
						sheet.stash();&lt;br /&gt;
					} );&lt;br /&gt;
			} );&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		$doc.on( &#039;keydown.spriteEdit&#039;, &#039;#spriteedit-summary&#039;, function( e ) {&lt;br /&gt;
			// Anything but Enter&lt;br /&gt;
			if ( e.which !== 13 ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			$( this ).blur();&lt;br /&gt;
			$( &#039;#spriteedit-save&#039; ).find( &#039;button&#039; ).click();&lt;br /&gt;
			e.preventDefault();&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		$doc.on( &#039;click.spriteEdit&#039;, &#039;#spriteedit-review-button &amp;gt; button&#039;, function() {&lt;br /&gt;
			var $button = $( this );&lt;br /&gt;
			if ( $button.hasClass( &#039;spriteedit-processing&#039; ) ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			$button.focus().blur().addClass( &#039;spriteedit-processing&#039; );&lt;br /&gt;
			&lt;br /&gt;
			var sheetUrl;&lt;br /&gt;
			var changesPanel = panels.changes || panel( &#039;changes&#039;, {&lt;br /&gt;
				title: i18n.panelChangesTitle,&lt;br /&gt;
				content: [&lt;br /&gt;
					$( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;spriteedit-sheet-changes&#039; ),&lt;br /&gt;
					$( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;spriteedit-id-changes&#039; ),&lt;br /&gt;
				],&lt;br /&gt;
				onClose: function() {&lt;br /&gt;
					URL.revokeObjectURL( sheetUrl );&lt;br /&gt;
				},&lt;br /&gt;
			} );&lt;br /&gt;
			var $changesText = changesPanel.$text;&lt;br /&gt;
			&lt;br /&gt;
			$.when( names.getDiff(), sheet.getData() ).then( function( diff, sheetBlob ) {&lt;br /&gt;
				var sheetChanges;&lt;br /&gt;
				if ( !diff &amp;amp;&amp;amp; !sheetBlob ) {&lt;br /&gt;
					$changesText.text( i18n.panelChangesNoDiffFromCur );&lt;br /&gt;
				} else {&lt;br /&gt;
					if ( sheetBlob ) {&lt;br /&gt;
						sheetChanges = $.Deferred();&lt;br /&gt;
						var newSpritesheet = new Image();&lt;br /&gt;
						newSpritesheet.onload = function() {&lt;br /&gt;
							newSpritesheet.onload = null;&lt;br /&gt;
							$changesText.find( &#039;.spriteedit-sheet-changes&#039; ).append(&lt;br /&gt;
								$( &#039;&amp;lt;div&amp;gt;&#039; ).text( i18n.panelChangesSheetTitle ),&lt;br /&gt;
								$( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;spriteedit-sheet-diff&#039; ).append(&lt;br /&gt;
									$( &#039;&amp;lt;span&amp;gt;&#039; ).addClass( &#039;spriteedit-old-sheet&#039; ).append( spritesheet ),&lt;br /&gt;
									$( &#039;&amp;lt;span&amp;gt;&#039; ).addClass( &#039;spriteedit-new-sheet&#039; ).append( newSpritesheet )&lt;br /&gt;
								)&lt;br /&gt;
							);&lt;br /&gt;
							&lt;br /&gt;
							sheetChanges.resolve();&lt;br /&gt;
						};&lt;br /&gt;
						sheetUrl = URL.createObjectURL( sheetBlob );&lt;br /&gt;
						newSpritesheet.src = sheetUrl;&lt;br /&gt;
					}&lt;br /&gt;
					if ( diff ) {&lt;br /&gt;
						$changesText.find( &#039;.spriteedit-id-changes&#039; ).append(&lt;br /&gt;
							$( &#039;&amp;lt;div&amp;gt;&#039; ).text( i18n.panelChangesIdTitle ),&lt;br /&gt;
							$( &#039;&amp;lt;div&amp;gt;&#039; ).append( diff )&lt;br /&gt;
						);&lt;br /&gt;
					}&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				$.when( sheetChanges ).done( function() {&lt;br /&gt;
					$button.removeClass( &#039;spriteedit-processing&#039; );&lt;br /&gt;
					changesPanel.show();&lt;br /&gt;
				} );&lt;br /&gt;
			}, function( code, data ) {&lt;br /&gt;
				$button.removeClass( &#039;spriteedit-processing&#039; );&lt;br /&gt;
				handleError( code, data );&lt;br /&gt;
			} );&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
		/* Edit control events */&lt;br /&gt;
		$doc.on( &#039;click.spriteEdit&#039;, &#039;.spriteedit-add-name &amp;gt; button&#039;, function() {&lt;br /&gt;
			var $names = $( this ).closest( &#039;.spritedoc-box&#039; ).find( &#039;.spritedoc-name&#039; );&lt;br /&gt;
			var $item = $( &#039;&amp;lt;li&amp;gt;&#039; ).addClass( &#039;spritedoc-name&#039; );&lt;br /&gt;
			var $name = $( &#039;&amp;lt;code&amp;gt;&#039; ).addClass( &#039;spriteedit-new&#039; )&lt;br /&gt;
				.attr( &#039;data-placeholder&#039;, i18n.namePlaceholder );&lt;br /&gt;
			addControls( $item.append( $name ), &#039;name&#039; );&lt;br /&gt;
			&lt;br /&gt;
			change( &#039;insert&#039;, {&lt;br /&gt;
				$elem: $item,&lt;br /&gt;
				index: $names.length - 1,&lt;br /&gt;
				$parent: $names.first().parent(),&lt;br /&gt;
			}, true );&lt;br /&gt;
			&lt;br /&gt;
			$name.focus();&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		$doc.on( &#039;focus.spriteEdit&#039;, &#039;[contenteditable]&#039;, function() {&lt;br /&gt;
			var $this = $( this );&lt;br /&gt;
			if ( $root.hasClass( &#039;spriteedit-hidecontrols&#039; ) ) {&lt;br /&gt;
				$this.blur();&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			var text = $this.text();&lt;br /&gt;
			$this.attr( &#039;data-original-text&#039;, text );&lt;br /&gt;
			&lt;br /&gt;
			if ( !changes.length ) {&lt;br /&gt;
				$this.one( &#039;keypress.spriteEdit&#039;, function() {&lt;br /&gt;
					$.each( [&lt;br /&gt;
						&#039;#spriteedit-save&#039;,&lt;br /&gt;
						&#039;#spriteedit-summary&#039;,&lt;br /&gt;
						&#039;#spriteedit-review-button&#039;,&lt;br /&gt;
					], function() {&lt;br /&gt;
						if ( $( this ).length ) {&lt;br /&gt;
							$( this ).data( &#039;ooui-object&#039; ).setDisabled( false );&lt;br /&gt;
						}&lt;br /&gt;
					} );&lt;br /&gt;
				} );&lt;br /&gt;
			}&lt;br /&gt;
		} );&lt;br /&gt;
		$doc.on( &#039;blur.spriteEdit&#039;, &#039;[contenteditable]&#039;, function() {&lt;br /&gt;
			if ( $root.hasClass( &#039;spriteedit-hidecontrols&#039; ) ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			var $this = $( this );&lt;br /&gt;
			var text = $this.text();&lt;br /&gt;
			var trimmedText = text.trim().replace( /  +/g, &#039; &#039; );&lt;br /&gt;
			var origText = $this.attr( &#039;data-original-text&#039; );&lt;br /&gt;
			$this.removeAttr( &#039;data-original-text&#039; ).off( &#039;keypress.spriteEdit&#039; );&lt;br /&gt;
			&lt;br /&gt;
			// Can&#039;t make a change if we don&#039;t know what the original text was&lt;br /&gt;
			// This can happen when Edge calls the blur event on elements that&lt;br /&gt;
			// that aren&#039;t focused, which it does when moving the highlight&lt;br /&gt;
			// when using the find in browser feature&lt;br /&gt;
			if ( origText === undefined ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			if ( text !== trimmedText ) {&lt;br /&gt;
				text = trimmedText;&lt;br /&gt;
				$this.text( text );&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			if ( text === &#039;&#039; ) {&lt;br /&gt;
				var $remove, $parent;&lt;br /&gt;
				if ( $this.hasClass( &#039;mw-headline&#039; ) ) {&lt;br /&gt;
					if ( $doc.find( &#039;.spritedoc-section&#039; ).length === 1 ) {&lt;br /&gt;
						text = i18n.sectionUncategorized;&lt;br /&gt;
						$this.text( text );&lt;br /&gt;
					} else {&lt;br /&gt;
						$remove = $this.closest( &#039;.spritedoc-section&#039; );&lt;br /&gt;
						$parent = $doc;&lt;br /&gt;
					}&lt;br /&gt;
				} else {&lt;br /&gt;
					var $names = $this.closest( &#039;.spritedoc-names&#039; );&lt;br /&gt;
					if ( $names.find( &#039;.spritedoc-name&#039; ).length &amp;gt; 1 ) {&lt;br /&gt;
						$remove = $this.parent();&lt;br /&gt;
						$parent = $names;&lt;br /&gt;
					} else {&lt;br /&gt;
						$remove = $names.parent();&lt;br /&gt;
						$parent = $remove.parent();&lt;br /&gt;
					}&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				if ( $remove ) {&lt;br /&gt;
					if ( $this.hasClass( &#039;spriteedit-new&#039; ) ) {&lt;br /&gt;
						// Just pretend it never happened&lt;br /&gt;
						$remove.remove();&lt;br /&gt;
						change.discard();&lt;br /&gt;
						return;&lt;br /&gt;
					}&lt;br /&gt;
					&lt;br /&gt;
					// Restore original text before deleting so undo works&lt;br /&gt;
					$this.text( origText );&lt;br /&gt;
					&lt;br /&gt;
					change( &#039;delete&#039;, {&lt;br /&gt;
						$elem: $remove,&lt;br /&gt;
						index: $remove.index() - 1,&lt;br /&gt;
						$parent: $parent,&lt;br /&gt;
					} );&lt;br /&gt;
					return;&lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			if ( text === origText ) {&lt;br /&gt;
				if ( !changes.length ) {&lt;br /&gt;
					$.each( [&lt;br /&gt;
						&#039;#spriteedit-save&#039;,&lt;br /&gt;
						&#039;#spriteedit-summary&#039;,&lt;br /&gt;
						&#039;#spriteedit-review-button&#039;,&lt;br /&gt;
					], function() {&lt;br /&gt;
						if ( $( this ).length ) {&lt;br /&gt;
							$( this ).data( &#039;ooui-object&#039; ).setDisabled( true );&lt;br /&gt;
						}&lt;br /&gt;
					} );&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			if ( usedNames[text] ) {&lt;br /&gt;
				// Wait until after edit change, as it may move the element&lt;br /&gt;
				// which the tooltip should be anchored to&lt;br /&gt;
				requestAnimationFrame( function() {&lt;br /&gt;
					tooltip( $this, i18n.dupeName );&lt;br /&gt;
				} );&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			change( &#039;edit&#039;, {&lt;br /&gt;
				$elem: $this,&lt;br /&gt;
				oldText: origText,&lt;br /&gt;
				text: text,&lt;br /&gt;
			} );&lt;br /&gt;
			&lt;br /&gt;
			if ( $this.hasClass( &#039;spriteedit-new&#039; ) ) {&lt;br /&gt;
				$this.removeClass( &#039;spriteedit-new&#039; ).removeAttr( &#039;data-placeholder&#039; );&lt;br /&gt;
			}&lt;br /&gt;
		} );&lt;br /&gt;
		$doc.on( &#039;keypress.spriteEdit&#039;, &#039;[contenteditable]&#039;, function( e ) {&lt;br /&gt;
			// Enter key&lt;br /&gt;
			if ( e.which === 13 ) {&lt;br /&gt;
				$( this ).blur();&lt;br /&gt;
				e.preventDefault();&lt;br /&gt;
			}&lt;br /&gt;
		} );&lt;br /&gt;
		// Make pastes plain text&lt;br /&gt;
		$doc.on( &#039;paste.spriteEdit&#039;, &#039;[contenteditable]&#039;, function( e ) {&lt;br /&gt;
			var text = ( e.originalEvent.clipboardData || window.clipboardData ).getData( &#039;Text&#039; );&lt;br /&gt;
			text = text.replace( /\n/g, &#039; &#039; ).trim();&lt;br /&gt;
			window.document.execCommand( &#039;insertText&#039;, false, text );&lt;br /&gt;
			&lt;br /&gt;
			e.preventDefault();&lt;br /&gt;
		} );&lt;br /&gt;
		var isText = function( e ) {&lt;br /&gt;
			var types = e.originalEvent.dataTransfer.types;&lt;br /&gt;
			return types.indexOf ? types.indexOf( &#039;text/plain&#039; ) &amp;gt; -1 : types.contains( &#039;text/plain&#039; );&lt;br /&gt;
		};&lt;br /&gt;
		$doc.on( &#039;dragenter.spriteEdit dragover.spriteEdit&#039;, &#039;[contenteditable]&#039;, function( e ) {&lt;br /&gt;
			if ( !isText( e ) ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			e.preventDefault();&lt;br /&gt;
		} );&lt;br /&gt;
		$doc.on( &#039;drop.spriteEdit&#039;, function( e ) {&lt;br /&gt;
			// Prevent default drop on anything but contenteditable&lt;br /&gt;
			// This prevents browsers dropping content into a nearby contenteditable, which doesn&#039;t&lt;br /&gt;
			// trigger any kind of drop event on the contenteditable (because you didn&#039;t actually&lt;br /&gt;
			// drop anything directly on it), thus making it impossible to handle it properly.&lt;br /&gt;
			if ( !$( e.target ).is( &#039;[contenteditable]&#039; ) ) {&lt;br /&gt;
				e.preventDefault();&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			if ( !isText( e ) ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			var $this = $( e.target );&lt;br /&gt;
			$this.focus();&lt;br /&gt;
			setTimeout( function() {&lt;br /&gt;
				var text = $this.text().replace( /\n/g, &#039; &#039; );&lt;br /&gt;
				if ( $this.html() !== $( &#039;&amp;lt;i&amp;gt;&#039; ).text( text ).html() ) {&lt;br /&gt;
					$this.text( text );&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				$this.blur();&lt;br /&gt;
			}, 0 );&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		if ( imageEditingSupported ) {&lt;br /&gt;
			$doc.on( &#039;click.spriteEdit&#039;, &#039;.spritedoc-image&#039;, function() {&lt;br /&gt;
				var $parent = $( this );&lt;br /&gt;
				&lt;br /&gt;
				tooltip( $parent, [&lt;br /&gt;
					makeButton( i18n.ctxReplaceImage, {&lt;br /&gt;
						type: [ &#039;progressive&#039;, &#039;primary&#039; ],&lt;br /&gt;
						icon: &#039;imageGallery&#039;,&lt;br /&gt;
						action: function() {&lt;br /&gt;
							$( &#039;&amp;lt;input type=&amp;quot;file&amp;quot;&amp;gt;&#039; )&lt;br /&gt;
								.attr( &#039;accept&#039;, &#039;image/*&#039; )&lt;br /&gt;
								.one( &#039;change&#039;, function() {&lt;br /&gt;
									tooltip.hide();&lt;br /&gt;
									&lt;br /&gt;
									scaleImage( this.files[0] ).done( function( $img ) {&lt;br /&gt;
										$img.addClass( &#039;spriteedit-replacing-image&#039; );&lt;br /&gt;
										change( &#039;replace image&#039;, {&lt;br /&gt;
											$elem: $img,&lt;br /&gt;
											$parent: $parent,&lt;br /&gt;
											$oldImg: $parent.find( &#039;img&#039; ),&lt;br /&gt;
										} );&lt;br /&gt;
									} );&lt;br /&gt;
								} ).click();&lt;br /&gt;
						},&lt;br /&gt;
					} ),&lt;br /&gt;
					makeButton( i18n.ctxDownloadImage, {&lt;br /&gt;
						icon: &#039;download&#039;,&lt;br /&gt;
						action: function() {&lt;br /&gt;
							var $button = $( this );&lt;br /&gt;
							var data;&lt;br /&gt;
							var $box = $parent.parent();&lt;br /&gt;
							// Already an image, just pass on the object URL&lt;br /&gt;
							if ( $box.hasClass( &#039;spriteedit-new&#039; ) ) {&lt;br /&gt;
								data = $parent.find( &#039;&amp;gt; img&#039; ).attr( &#039;src&#039; );&lt;br /&gt;
							} else {&lt;br /&gt;
								$button.addClass( &#039;spriteedit-processing&#039; );&lt;br /&gt;
								data = sheetRequest.then( function() {&lt;br /&gt;
									// Individual sprite needs to be extracted from the spritesheet&lt;br /&gt;
									var width = settings.imageWidth;&lt;br /&gt;
									var height = settings.imageHeight;&lt;br /&gt;
									var posPx = posToPx( $box.data( &#039;pos&#039; ) );&lt;br /&gt;
									var imgCanv = getCanvas( &#039;image&#039; );&lt;br /&gt;
									&lt;br /&gt;
									imgCanv.clear();&lt;br /&gt;
									imgCanv.ctx.drawImage( spritesheet,&lt;br /&gt;
										posPx.left, posPx.top, width, height,&lt;br /&gt;
										0, 0, width, height&lt;br /&gt;
									);&lt;br /&gt;
									&lt;br /&gt;
									var d = $.Deferred();&lt;br /&gt;
									imgCanv.canvas.toBlob( d.resolve );&lt;br /&gt;
									&lt;br /&gt;
									return d.promise();&lt;br /&gt;
								} );&lt;br /&gt;
							}&lt;br /&gt;
							&lt;br /&gt;
							$.when( data ).then( function( blob ) {&lt;br /&gt;
								$button.removeClass( &#039;spriteedit-processing&#039; );&lt;br /&gt;
								var name = $box.data( &#039;sort-key&#039; ) + &#039;.png&#039;;&lt;br /&gt;
								// IE10+: (has Blob, but not a[download])&lt;br /&gt;
								if ( navigator.msSaveBlob ) {&lt;br /&gt;
									return navigator.msSaveBlob( blob, name );&lt;br /&gt;
								}&lt;br /&gt;
								&lt;br /&gt;
								var dlLink = $( &#039;&amp;lt;a&amp;gt;&#039; ).attr( {&lt;br /&gt;
									href: URL.createObjectURL( blob ),&lt;br /&gt;
									download: name,&lt;br /&gt;
								} ).appendTo( &#039;body&#039; );&lt;br /&gt;
								dlLink[0].click();&lt;br /&gt;
								dlLink.remove();&lt;br /&gt;
							} );&lt;br /&gt;
						},&lt;br /&gt;
					} ),&lt;br /&gt;
					makeButton( i18n.ctxDeleteImage, {&lt;br /&gt;
						type: [ &#039;destructive&#039;, &#039;primary&#039; ],&lt;br /&gt;
						icon: &#039;trash&#039;,&lt;br /&gt;
						action: function() {&lt;br /&gt;
							tooltip.hide( function() {&lt;br /&gt;
								var $box = $parent.parent();&lt;br /&gt;
								change( &#039;delete&#039;, {&lt;br /&gt;
									$elem: $box,&lt;br /&gt;
									$parent: $box.parent(),&lt;br /&gt;
									index: $box.index() - 1,&lt;br /&gt;
								} );&lt;br /&gt;
							} );&lt;br /&gt;
						},&lt;br /&gt;
					} ),&lt;br /&gt;
				], { horizontal: true, class: &#039;spriteedit-tooltip-controls&#039; } );&lt;br /&gt;
			} );&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
		/* Window events */&lt;br /&gt;
		$win.on( &#039;resize.spriteEdit&#039;, $.throttle( 32, function() {&lt;br /&gt;
			var $conflict = $( &#039;#spriteedit-dialog-conflict&#039; );&lt;br /&gt;
			if ( $conflict.length &amp;amp;&amp;amp; $conflict.is( &#039;:visible&#039; ) ) {&lt;br /&gt;
				var $textarea = $conflict.find( &#039;textarea&#039; );&lt;br /&gt;
				$textarea.css( &#039;max-height&#039;, (&lt;br /&gt;
					$conflict.find( &#039;.spriteedit-dialog-text&#039; ).height() - $textarea.parent()[0].offsetTop&lt;br /&gt;
				) + &#039;px&#039; );&lt;br /&gt;
			}&lt;br /&gt;
		} ) );&lt;br /&gt;
		&lt;br /&gt;
		var updateMouse = function( e ) {&lt;br /&gt;
			mouse.moved = true;&lt;br /&gt;
			mouse.x = e.clientX;&lt;br /&gt;
			mouse.y = e.clientY;&lt;br /&gt;
		};&lt;br /&gt;
		// Only update mouse while sorting, dragging, or while over a handle&lt;br /&gt;
		$doc.on( &#039;mouseenter.spriteEdit mousemove.spriteEdit&#039;, &#039;.spriteedit-handle&#039;, function( e ) {&lt;br /&gt;
			if ( !sorting ) {&lt;br /&gt;
				updateMouse( e );&lt;br /&gt;
			}&lt;br /&gt;
		} );&lt;br /&gt;
		$( document ).on( &#039;mousemove.spriteEdit&#039;, function( e ) {&lt;br /&gt;
			if ( sorting ) {&lt;br /&gt;
				updateMouse( e );&lt;br /&gt;
			}&lt;br /&gt;
		} ).on( &#039;dragover.spriteEdit&#039;, function( e ) {&lt;br /&gt;
			updateMouse( e.originalEvent );&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		// Disable smooth scrolling once scrolling ends so it does not interfere with user scrolling.&lt;br /&gt;
		$win.on( &#039;scroll.spriteEdit&#039;, $.debounce( 250, function() {&lt;br /&gt;
			$root.removeClass( &#039;spriteedit-smoothscroll&#039; );&lt;br /&gt;
		} ) );&lt;br /&gt;
	};&lt;br /&gt;
	&lt;br /&gt;
	&lt;br /&gt;
	/** Editor functions **/&lt;br /&gt;
	/**&lt;br /&gt;
	 * Closes the editor&lt;br /&gt;
	 *&lt;br /&gt;
	 * If there are no changes, destroys the editor immediately.&lt;br /&gt;
	 * If there are changes, opens a panel asking for confirmation first.&lt;br /&gt;
	 *&lt;br /&gt;
	 * &amp;quot;state&amp;quot; is what triggered the editor to close (e.g. from history navigation)&lt;br /&gt;
	 */&lt;br /&gt;
	var close = function( state ) {&lt;br /&gt;
		if ( !$root.hasClass( &#039;spriteedit-enabled&#039; ) || $( &#039;#spriteedit-save&#039; ).data( &#039;ooui-object&#039; ).isDisabled() ) {&lt;br /&gt;
			destroy( true, state === &#039;history&#039; );&lt;br /&gt;
		} else {&lt;br /&gt;
			var discardPanel = panels.discard || panel( &#039;discard&#039;, {&lt;br /&gt;
				title: i18n.panelDiscardTitle,&lt;br /&gt;
				content: $( &#039;&amp;lt;p&amp;gt;&#039; ).text( i18n.panelDiscardText ),&lt;br /&gt;
				actions: { right: [&lt;br /&gt;
					{ text: i18n.panelDiscardContinue, config: {&lt;br /&gt;
						action: function() {&lt;br /&gt;
							discardPanel.hide();&lt;br /&gt;
						}&lt;br /&gt;
					} },&lt;br /&gt;
					{ text: i18n.panelDiscardDiscard, config: {&lt;br /&gt;
						type: [ &#039;destructive&#039;, &#039;primary&#039; ],&lt;br /&gt;
						icon: &#039;trash&#039;,&lt;br /&gt;
						action: function() {&lt;br /&gt;
							discardPanel.hide( function() {&lt;br /&gt;
								destroy( true, state === &#039;history&#039; );&lt;br /&gt;
							} );&lt;br /&gt;
						}&lt;br /&gt;
					} },&lt;br /&gt;
				] },&lt;br /&gt;
			} );&lt;br /&gt;
			discardPanel.show();&lt;br /&gt;
		}&lt;br /&gt;
	};&lt;br /&gt;
	&lt;br /&gt;
	/**&lt;br /&gt;
	 * Construct a wiki diff from an API request&lt;br /&gt;
	 *&lt;br /&gt;
	 * &amp;quot;data&amp;quot; is the API response.&lt;br /&gt;
	 * Returns a jQuery object containing the diff table, an error message&lt;br /&gt;
	 * if something went wrong, or nothing if the diff is empty.&lt;br /&gt;
	 */&lt;br /&gt;
	var makeDiff = function( data ) {&lt;br /&gt;
		if ( !data || !data.query || !data.query.pages ) {&lt;br /&gt;
			return i18n.genericError;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		var page = data.query.pages[0];&lt;br /&gt;
		if ( !page ) {&lt;br /&gt;
			return i18n.diffErrorMissingPage;&lt;br /&gt;
		}&lt;br /&gt;
		var diff = page.revisions[0].diff.body;&lt;br /&gt;
		if ( diff === undefined ) {&lt;br /&gt;
			return i18n.diffError;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		if ( !diff.length ) {&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		return $( &#039;&amp;lt;table&amp;gt;&#039; ).addClass( &#039;diff&#039; ).append(&lt;br /&gt;
			$( &#039;&amp;lt;col&amp;gt;&#039; ).addClass( &#039;diff-marker&#039; ),&lt;br /&gt;
			$( &#039;&amp;lt;col&amp;gt;&#039; ).addClass( &#039;diff-content&#039; ),&lt;br /&gt;
			$( &#039;&amp;lt;col&amp;gt;&#039; ).addClass( &#039;diff-marker&#039; ),&lt;br /&gt;
			$( &#039;&amp;lt;col&amp;gt;&#039; ).addClass( &#039;diff-content&#039; ),&lt;br /&gt;
			$( &#039;&amp;lt;tbody&amp;gt;&#039; ).html( diff )&lt;br /&gt;
		);&lt;br /&gt;
	};&lt;br /&gt;
	&lt;br /&gt;
	var names = ( function() {&lt;br /&gt;
		var promises = {};&lt;br /&gt;
		/**&lt;br /&gt;
		 * Create a deferred object for the request type&lt;br /&gt;
		 *&lt;br /&gt;
		 * If a deferred of this type already exists, or names is not&lt;br /&gt;
		 * modified, returns false.&lt;br /&gt;
		 *&lt;br /&gt;
		 * Otherwise, adds the deferred&#039;s promise to the list, and returns&lt;br /&gt;
		 * the deferred.&lt;br /&gt;
		 */&lt;br /&gt;
		var makeDeferred = function( type ) {&lt;br /&gt;
			if ( promises[type] ) {&lt;br /&gt;
				return false;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			var deferred = $.Deferred();&lt;br /&gt;
			promises[type] = deferred.promise();&lt;br /&gt;
			if ( !names.modified ) {&lt;br /&gt;
				deferred.resolve();&lt;br /&gt;
				return false;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			return deferred;&lt;br /&gt;
		};&lt;br /&gt;
		&lt;br /&gt;
		return {&lt;br /&gt;
			/**&lt;br /&gt;
			 * Invalidates all promises and sets the modified state, if specified&lt;br /&gt;
			 */&lt;br /&gt;
			invalidate: function( modified ) {&lt;br /&gt;
				promises = {};&lt;br /&gt;
				if ( modified !== undefined ) {&lt;br /&gt;
					names.modified = modified;&lt;br /&gt;
				}&lt;br /&gt;
			},&lt;br /&gt;
			/**&lt;br /&gt;
			 * Returns the names object&lt;br /&gt;
			 */&lt;br /&gt;
			getObject: function() {&lt;br /&gt;
				var deferred = makeDeferred( &#039;object&#039; );&lt;br /&gt;
				if ( !deferred ) {&lt;br /&gt;
					return promises.object;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				sheet.updatePositions().done( function() {&lt;br /&gt;
					var $sections = $doc.find( &#039;.spritedoc-section&#039; );&lt;br /&gt;
					var sectionIds = [];&lt;br /&gt;
					var getSectionId = ( function() {&lt;br /&gt;
						var id = 0;&lt;br /&gt;
						return function() {&lt;br /&gt;
							if ( id &amp;lt; sectionIds.length ) {&lt;br /&gt;
								sectionIds.sort( function( a, b ) {&lt;br /&gt;
									return a - b;&lt;br /&gt;
								} );&lt;br /&gt;
								&lt;br /&gt;
								$.each( sectionIds, function( _, v ) {&lt;br /&gt;
									if ( v - id &amp;gt; 1 ) {&lt;br /&gt;
										return false;&lt;br /&gt;
									}&lt;br /&gt;
									id = v;&lt;br /&gt;
								} );&lt;br /&gt;
							}&lt;br /&gt;
							&lt;br /&gt;
							id++;&lt;br /&gt;
							&lt;br /&gt;
							sectionIds.push( id );&lt;br /&gt;
							return id;&lt;br /&gt;
						};&lt;br /&gt;
					}() );&lt;br /&gt;
					&lt;br /&gt;
					$sections.each( function() {&lt;br /&gt;
						var id = $( this ).data( &#039;section-id&#039; );&lt;br /&gt;
						if ( id !== undefined ) {&lt;br /&gt;
							sectionIds.push( id );&lt;br /&gt;
						}&lt;br /&gt;
					} );&lt;br /&gt;
					&lt;br /&gt;
					var headingRows = [];&lt;br /&gt;
					var ids = [];&lt;br /&gt;
					$sections.each( function() {&lt;br /&gt;
						var $section = $( this );&lt;br /&gt;
						var sectionId = $section.data( &#039;section-id&#039; ) || getSectionId();&lt;br /&gt;
						var sectionName = $section.find( &#039;.mw-headline&#039; ).text().replace( /\s+/g, &#039; &#039; );&lt;br /&gt;
						var row = {};&lt;br /&gt;
						row[i18n.luaKeyName] = sectionName;&lt;br /&gt;
						row[i18n.luaKeyId] = sectionId;&lt;br /&gt;
						headingRows.push( row );&lt;br /&gt;
						&lt;br /&gt;
						$section.find( &#039;.spritedoc-box&#039; ).each( function() {&lt;br /&gt;
							var $box = $( this );&lt;br /&gt;
							var pos = $box.data( &#039;pos&#039; );&lt;br /&gt;
							if ( pos === undefined ) {&lt;br /&gt;
								pos = $box.data( &#039;new-pos&#039; );&lt;br /&gt;
							}&lt;br /&gt;
							$box.find( &#039;.spritedoc-name&#039; ).find( &#039;code&#039; ).each( function() {&lt;br /&gt;
								var $this = $( this );&lt;br /&gt;
								var id = $this.text().replace( /\s+/g, &#039; &#039; );&lt;br /&gt;
								ids.push( {&lt;br /&gt;
									sortKey: id.toLowerCase(),&lt;br /&gt;
									id: id,&lt;br /&gt;
									pos: pos,&lt;br /&gt;
									section: sectionId,&lt;br /&gt;
									deprecated: $this.hasClass( &#039;spritedoc-deprecated&#039; ),&lt;br /&gt;
								} );&lt;br /&gt;
							} );&lt;br /&gt;
						} );&lt;br /&gt;
					} );&lt;br /&gt;
					ids.sort( function( a, b ) {&lt;br /&gt;
						return a.sortKey &amp;gt; b.sortKey ? 1 : -1;&lt;br /&gt;
					} );&lt;br /&gt;
					&lt;br /&gt;
					var idsRows = {};&lt;br /&gt;
					$.each( ids, function() {&lt;br /&gt;
						var idData = {};&lt;br /&gt;
						idData[i18n.luaKeyPos] = this.pos;&lt;br /&gt;
						idData[i18n.luaKeySection] = this.section;&lt;br /&gt;
						if ( this.deprecated ) {&lt;br /&gt;
							idData[i18n.luaKeyDeprecated] = this.deprecated;&lt;br /&gt;
						}&lt;br /&gt;
						idsRows[this.id] = idData;&lt;br /&gt;
					} );&lt;br /&gt;
					&lt;br /&gt;
					// Sort the settings object so it doesn&#039;t change order&lt;br /&gt;
					// everytime due to lua not supporting ordered tables&lt;br /&gt;
					var sortedSettings = {};&lt;br /&gt;
					Object.keys( spriteSettings ).sort().forEach( function( key ) {&lt;br /&gt;
						sortedSettings[key] = spriteSettings[key];&lt;br /&gt;
					} );&lt;br /&gt;
					&lt;br /&gt;
					var table = {};&lt;br /&gt;
					table[i18n.luaKeySettings] = sortedSettings;&lt;br /&gt;
					table[i18n.luaKeySections] = headingRows;&lt;br /&gt;
					table[i18n.luaKeyIds] = idsRows;&lt;br /&gt;
					&lt;br /&gt;
					deferred.resolve( table );&lt;br /&gt;
				} );&lt;br /&gt;
				&lt;br /&gt;
				return promises.object;&lt;br /&gt;
			},&lt;br /&gt;
			/**&lt;br /&gt;
			 * Returns the names Lua table&lt;br /&gt;
			 * &lt;br /&gt;
			 * Updates the URL timestamp if URLs are being used and the sheet&lt;br /&gt;
			 * has been modified. As such, this always generates a new table if&lt;br /&gt;
			 * there isn&#039;t one already pending.&lt;br /&gt;
			 */&lt;br /&gt;
			getTable: function() {&lt;br /&gt;
				if ( promises.table &amp;amp;&amp;amp; promises.table.state() === &#039;resolved&#039; ) {&lt;br /&gt;
					promises.table = null;&lt;br /&gt;
				}&lt;br /&gt;
				var deferred = makeDeferred( &#039;table&#039; );&lt;br /&gt;
				if ( !deferred ) {&lt;br /&gt;
					return promises.table;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				names.getObject().then( function( obj ) {&lt;br /&gt;
					if ( spriteSettings[i18n.luaKeySettingsUrl] ) {&lt;br /&gt;
						var url = $doc.data( &#039;original-url&#039; ).split( &#039;?&#039; );&lt;br /&gt;
						// Update the version parameter if the sheet was modified&lt;br /&gt;
						// or if there&#039;s no version parameter&lt;br /&gt;
						if ( sheet.modified || !url[1] ) {&lt;br /&gt;
							url[1] = &#039;version=&#039; + Date.now();&lt;br /&gt;
							$doc.data( &#039;url&#039;, url.join( &#039;?&#039; ) );&lt;br /&gt;
						}&lt;br /&gt;
						&lt;br /&gt;
						obj[i18n.luaKeySettings][i18n.luaKeySettingsUrl] =&lt;br /&gt;
							luaTable.func( $doc.data( &#039;urlfunc&#039; ).replace( /\$1/, url[1] ) );&lt;br /&gt;
					}&lt;br /&gt;
					deferred.resolve( &#039;return &#039; + luaTable.create( obj ) );&lt;br /&gt;
				} );&lt;br /&gt;
				&lt;br /&gt;
				return promises.table;&lt;br /&gt;
			},&lt;br /&gt;
			/**&lt;br /&gt;
			 * Sets the names Lua table to the specified content&lt;br /&gt;
			 */&lt;br /&gt;
			setTable: function( table ) {&lt;br /&gt;
				names.invalidate( true );&lt;br /&gt;
				promises.table = $.Deferred().resolve( table ).promise();&lt;br /&gt;
			},&lt;br /&gt;
			/**&lt;br /&gt;
			 * Requests a diff of the names Lua table against&lt;br /&gt;
			 * the current revisions content&lt;br /&gt;
			 */&lt;br /&gt;
			getDiff: function() {&lt;br /&gt;
				var deferred = makeDeferred( &#039;diff&#039; );&lt;br /&gt;
				if ( !deferred ) {&lt;br /&gt;
					return promises.diff;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				names.getTable().then( function( table ) {&lt;br /&gt;
					return retryableRequest( function() {&lt;br /&gt;
						return new mw.Api( {&lt;br /&gt;
							ajax: { contentType: &#039;multipart/form-data&#039; },&lt;br /&gt;
						} ).post( {&lt;br /&gt;
							action: &#039;query&#039;,&lt;br /&gt;
							prop: &#039;revisions&#039;,&lt;br /&gt;
							titles: dataPage,&lt;br /&gt;
							rvprop: &#039;&#039;,&lt;br /&gt;
							rvdifftotext: table,&lt;br /&gt;
							rvlimit: 1,&lt;br /&gt;
							formatversion: 2,&lt;br /&gt;
						} );&lt;br /&gt;
					} );&lt;br /&gt;
				} ).then( function( data ) {&lt;br /&gt;
					var diff = makeDiff( data );&lt;br /&gt;
					names.modified = !!diff;&lt;br /&gt;
					deferred.resolve( diff );&lt;br /&gt;
				}, function( code, data ) {&lt;br /&gt;
					deferred.reject( code, data );&lt;br /&gt;
					promises.diff = null;&lt;br /&gt;
				} );&lt;br /&gt;
				&lt;br /&gt;
				return promises.diff;&lt;br /&gt;
			},&lt;br /&gt;
			/**&lt;br /&gt;
			 * Saves the names table&lt;br /&gt;
			 *&lt;br /&gt;
			 * &amp;quot;summary&amp;quot; is the edit summary for the edit.&lt;br /&gt;
			 */&lt;br /&gt;
			save: function( summary, conflict ) {&lt;br /&gt;
				var deferred = makeDeferred( &#039;save&#039; );&lt;br /&gt;
				if ( !deferred ) {&lt;br /&gt;
					return promises.save;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				names.getTable().then( function( table ) {&lt;br /&gt;
					// TODO: Check if edit actually succeeded on failure or null edit&lt;br /&gt;
					return retryableRequest( function() {&lt;br /&gt;
						return new mw.Api( {&lt;br /&gt;
							ajax: { contentType: &#039;multipart/form-data&#039; },&lt;br /&gt;
						} ).postWithToken( &#039;csrf&#039;, {&lt;br /&gt;
							action: &#039;edit&#039;,&lt;br /&gt;
							nocreate: true,&lt;br /&gt;
							title: dataPage,&lt;br /&gt;
							text: table,&lt;br /&gt;
							// If there&#039;s already been an edit conflict, just allow the edit&lt;br /&gt;
							// through conflict-free, as it&#039;s already annoying enough to&lt;br /&gt;
							// deal with one conflict.&lt;br /&gt;
							basetimestamp: !conflict ? $doc.data( &#039;datatimestamp&#039; ) : undefined,&lt;br /&gt;
							summary: summary,&lt;br /&gt;
							tags: canTag ? &#039;spriteeditor&#039; : undefined,&lt;br /&gt;
							formatversion: 2,&lt;br /&gt;
						} );&lt;br /&gt;
					} );&lt;br /&gt;
				} ).then( deferred.resolve, function( code, data ) {&lt;br /&gt;
					deferred.reject( code, data );&lt;br /&gt;
					promises.save = null;&lt;br /&gt;
				} );&lt;br /&gt;
				&lt;br /&gt;
				return promises.save;&lt;br /&gt;
			},&lt;br /&gt;
		};&lt;br /&gt;
	}() );&lt;br /&gt;
	&lt;br /&gt;
	var sheet = ( function() {&lt;br /&gt;
		var promises = {};&lt;br /&gt;
		/**&lt;br /&gt;
		 * Create a deferred object for the request type&lt;br /&gt;
		 *&lt;br /&gt;
		 * If a deferred of this type already exists, or the sheet is not&lt;br /&gt;
		 * modified, returns false.&lt;br /&gt;
		 *&lt;br /&gt;
		 * Otherwise, adds the deferred&#039;s promise to the list, and returns&lt;br /&gt;
		 * the deferred.&lt;br /&gt;
		 */&lt;br /&gt;
		var makeDeferred = function( type ) {&lt;br /&gt;
			if ( promises[type] ) {&lt;br /&gt;
				return false;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			var deferred = $.Deferred();&lt;br /&gt;
			promises[type] = deferred.promise();&lt;br /&gt;
			if ( !sheet.modified ) {&lt;br /&gt;
				deferred.resolve();&lt;br /&gt;
				return false;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			return deferred;&lt;br /&gt;
		};&lt;br /&gt;
		&lt;br /&gt;
		return {&lt;br /&gt;
			/**&lt;br /&gt;
			 * Invalidates all promises and sets the modified state, if specified&lt;br /&gt;
			 */&lt;br /&gt;
			invalidate: function( modified ) {&lt;br /&gt;
				promises = {};&lt;br /&gt;
				if ( modified !== undefined ) {&lt;br /&gt;
					sheet.modified = modified;&lt;br /&gt;
				}&lt;br /&gt;
				if ( spriteSettings[i18n.luaKeySettingsUrl] ) {&lt;br /&gt;
					names.invalidate( true );&lt;br /&gt;
				}&lt;br /&gt;
			},&lt;br /&gt;
			/**&lt;br /&gt;
			 * Invalidates just the stash&#039;s promise&lt;br /&gt;
			 */&lt;br /&gt;
			invalidateStash: function() {&lt;br /&gt;
				promises.stash = null;&lt;br /&gt;
			},&lt;br /&gt;
			/**&lt;br /&gt;
			 * Updates the potential position information&lt;br /&gt;
			 * for any new images, and resizes the canvas&lt;br /&gt;
			 */&lt;br /&gt;
			updatePositions: function() {&lt;br /&gt;
				var deferred = makeDeferred( &#039;pos&#039; );&lt;br /&gt;
				if ( !deferred ) {&lt;br /&gt;
					return promises.pos;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				sheetRequest.then( function() {&lt;br /&gt;
					var lastPos = spriteSettings[i18n.luaKeySettingsPos] || 1;&lt;br /&gt;
					var usedPos = {};&lt;br /&gt;
					usedPos[lastPos] = true;&lt;br /&gt;
					&lt;br /&gt;
					var newImgs = [];&lt;br /&gt;
					$doc.find( &#039;.spritedoc-box&#039; ).each( function() {&lt;br /&gt;
						var $box = $( this );&lt;br /&gt;
						var pos = $box.data( &#039;pos&#039; );&lt;br /&gt;
						if ( pos === undefined ) {&lt;br /&gt;
							newImgs.push( $box );&lt;br /&gt;
						} else {&lt;br /&gt;
							usedPos[pos] = true;&lt;br /&gt;
							if ( pos &amp;gt; lastPos ) {&lt;br /&gt;
								lastPos = pos;&lt;br /&gt;
							}&lt;br /&gt;
						}&lt;br /&gt;
					} );&lt;br /&gt;
					&lt;br /&gt;
					if ( newImgs.length ) {&lt;br /&gt;
						var unusedPos = [];&lt;br /&gt;
						for ( var i = 1; i &amp;lt;= lastPos; i++ ) {&lt;br /&gt;
							if ( !usedPos[i] ) {&lt;br /&gt;
								unusedPos.push( i );&lt;br /&gt;
							}&lt;br /&gt;
						}&lt;br /&gt;
						&lt;br /&gt;
						newImgs.forEach( function( $box ) {&lt;br /&gt;
							$box.data( &#039;new-pos&#039;, unusedPos.length ? unusedPos.shift() : ++lastPos );&lt;br /&gt;
						} );&lt;br /&gt;
						&lt;br /&gt;
						if ( !unusedPos.length ) {&lt;br /&gt;
							var imagesPerRow = ( settings.sheetWidth + settings.spacing ) / ( settings.imageWidth + settings.spacing );&lt;br /&gt;
							settings.sheetHeight = Math.ceil( lastPos / imagesPerRow ) * ( settings.imageHeight + settings.spacing ) - settings.spacing;&lt;br /&gt;
							getCanvas( &#039;sheet&#039; ).resize();&lt;br /&gt;
						}&lt;br /&gt;
					}&lt;br /&gt;
					&lt;br /&gt;
					deferred.resolve();&lt;br /&gt;
				} );&lt;br /&gt;
				&lt;br /&gt;
				return promises.pos;&lt;br /&gt;
			},&lt;br /&gt;
			/**&lt;br /&gt;
			 * Draws the new sheet and returns it as a data URL&lt;br /&gt;
			 */&lt;br /&gt;
			getData: function() {&lt;br /&gt;
				var deferred = makeDeferred( &#039;sheet&#039; );&lt;br /&gt;
				if ( !deferred ) {&lt;br /&gt;
					return promises.sheet;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				$.when( sheet.updatePositions(), $.when.apply( null, loadingImages ) ).then( function() {&lt;br /&gt;
					var sheetCanvas = getCanvas( &#039;sheet&#039; );&lt;br /&gt;
					sheetCanvas.clear();&lt;br /&gt;
					sheetCanvas.ctx.drawImage( spritesheet, 0, 0 );&lt;br /&gt;
					&lt;br /&gt;
					// TODO: Clear deleted images so when new images fill their place&lt;br /&gt;
					// the original images don&#039;t show up while the old sheet is cached&lt;br /&gt;
					&lt;br /&gt;
					// Insert new images into sheet&lt;br /&gt;
					$doc.find( &#039;.spriteedit-new&#039; ).each( function() {&lt;br /&gt;
						var $box = $( this );&lt;br /&gt;
						var img = $box.find( &#039;img&#039; )[0];&lt;br /&gt;
						var pos = $box.data( &#039;pos&#039; );&lt;br /&gt;
						if ( pos === undefined ) {&lt;br /&gt;
							pos = $box.data( &#039;new-pos&#039; );&lt;br /&gt;
						}&lt;br /&gt;
						&lt;br /&gt;
						var posPx = posToPx( pos );&lt;br /&gt;
						// Clear previous image including spacing, just in-case&lt;br /&gt;
						// someone manually uploaded an image overlapping the spacing&lt;br /&gt;
						sheetCanvas.ctx.clearRect(&lt;br /&gt;
							posPx.left - settings.spacing,&lt;br /&gt;
							posPx.top - settings.spacing,&lt;br /&gt;
							settings.imageWidth + settings.spacing * 2,&lt;br /&gt;
							settings.imageHeight + settings.spacing * 2&lt;br /&gt;
						);&lt;br /&gt;
						&lt;br /&gt;
						sheetCanvas.ctx.drawImage( img, posPx.left, posPx.top );&lt;br /&gt;
					} );&lt;br /&gt;
					sheetCanvas.canvas.toBlob( deferred.resolve );&lt;br /&gt;
					&lt;br /&gt;
					loadingImages = [];&lt;br /&gt;
				}, function() {&lt;br /&gt;
					deferred.reject();&lt;br /&gt;
					promises.sheet = null;&lt;br /&gt;
				} );&lt;br /&gt;
				&lt;br /&gt;
				return promises.sheet;&lt;br /&gt;
			},&lt;br /&gt;
			/**&lt;br /&gt;
			 * Stashes the sheet to the server&lt;br /&gt;
			 */&lt;br /&gt;
			stash: function() {&lt;br /&gt;
				var deferred = makeDeferred( &#039;stash&#039; );&lt;br /&gt;
				if ( !deferred ) {&lt;br /&gt;
					return promises.stash;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				sheet.getData().then( function( blob ) {&lt;br /&gt;
					return retryableRequest( function() {&lt;br /&gt;
						return new mw.Api( {&lt;br /&gt;
							ajax: { contentType: &#039;multipart/form-data&#039; },&lt;br /&gt;
						} ).postWithToken( &#039;csrf&#039;, {&lt;br /&gt;
							action: &#039;upload&#039;,&lt;br /&gt;
							stash: true,&lt;br /&gt;
							ignorewarnings: true,&lt;br /&gt;
							filename: $doc.data( &#039;spritesheet&#039; ),&lt;br /&gt;
							file: blob,&lt;br /&gt;
							formatversion: 2,&lt;br /&gt;
						} );&lt;br /&gt;
					} );&lt;br /&gt;
				} ).then( function( data ) {&lt;br /&gt;
					deferred.resolve( data.upload.filekey );&lt;br /&gt;
				}, function( code, data ) {&lt;br /&gt;
					deferred.reject( code, data );&lt;br /&gt;
					promises.stash = null;&lt;br /&gt;
				} );&lt;br /&gt;
				&lt;br /&gt;
				return promises.stash;&lt;br /&gt;
			},&lt;br /&gt;
			/**&lt;br /&gt;
			 * Commits the stash to the server&lt;br /&gt;
			 *&lt;br /&gt;
			 * If the request fails, will re-stash the image and commit it, once.&lt;br /&gt;
			 * &lt;br /&gt;
			 * &amp;quot;summary&amp;quot; is the edit summary for the upload.&lt;br /&gt;
			 * &amp;quot;retried&amp;quot; is a boolean stating whether the upload has&lt;br /&gt;
			 * already been retried.&lt;br /&gt;
			 */&lt;br /&gt;
			save: function( summary, retried ) {&lt;br /&gt;
				var deferred = makeDeferred( &#039;save&#039; );&lt;br /&gt;
				if ( !deferred ) {&lt;br /&gt;
					return promises.save;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				sheet.stash().then( function( key ) {&lt;br /&gt;
					// TODO: Check if upload actually succeeded on failure&lt;br /&gt;
					return retryableRequest( function() {&lt;br /&gt;
						return new mw.Api().postWithToken( &#039;csrf&#039;, {&lt;br /&gt;
							action: &#039;upload&#039;,&lt;br /&gt;
							ignorewarnings: true,&lt;br /&gt;
							comment: summary,&lt;br /&gt;
							filename: $doc.data( &#039;spritesheet&#039; ),&lt;br /&gt;
							filekey: key,&lt;br /&gt;
							tags: canTag ? &#039;spriteeditor&#039; : undefined,&lt;br /&gt;
							formatversion: 2,&lt;br /&gt;
						} );&lt;br /&gt;
					} );&lt;br /&gt;
				} ).then( deferred.resolve, function( code, data ) {&lt;br /&gt;
					promises.save = null;&lt;br /&gt;
					if ( retried ) {&lt;br /&gt;
						if ( code === &#039;stashedfilenotfound&#039; ) {&lt;br /&gt;
							sheet.invalidateStash();&lt;br /&gt;
						}&lt;br /&gt;
						deferred.reject( code, data );&lt;br /&gt;
					} else {&lt;br /&gt;
						sheet.invalidateStash();&lt;br /&gt;
						sheet.save( summary, true );&lt;br /&gt;
					}&lt;br /&gt;
				} );&lt;br /&gt;
				&lt;br /&gt;
				return promises.save;&lt;br /&gt;
			},&lt;br /&gt;
		};&lt;br /&gt;
	}() );&lt;br /&gt;
	&lt;br /&gt;
	/**&lt;br /&gt;
	 * Performs a save of the ID changes and/or spritesheet changes&lt;br /&gt;
	 *&lt;br /&gt;
	 * If there are changes and everything works out, the editor closes, the current&lt;br /&gt;
	 * page is purged, the timestamp is updated (for another edit in this session),&lt;br /&gt;
	 * and a success message is displayed.&lt;br /&gt;
	 * If there aren&#039;t changes, the editor will silently close, as if a null edit was performed&lt;br /&gt;
	 * (which if the diff wasn&#039;t ready in time, there will have been).&lt;br /&gt;
	 * In the event of an edit conflict, a manual resolution panel will be displayed.&lt;br /&gt;
	 * Otherwise, whatever error occurred will be displayed.&lt;br /&gt;
	 *&lt;br /&gt;
	 * &amp;quot;summary&amp;quot; is the text from the summary field.&lt;br /&gt;
	 * &amp;quot;refresh&amp;quot; is a boolean, which when true will cause the sprite documentation&lt;br /&gt;
	 * to be reparsed after saving (e.g. in the event of an edit conflict).&lt;br /&gt;
	 * &amp;quot;conflict&amp;quot; is a boolean which specifies if this is saving an edit conflict or not&lt;br /&gt;
	 */&lt;br /&gt;
	var saveChanges = function( summary, refresh, conflict ) {&lt;br /&gt;
		// No more editing&lt;br /&gt;
		$root.addClass( &#039;spriteedit-hidecontrols&#039; );&lt;br /&gt;
		&lt;br /&gt;
		// Have to refresh if a new image is added to get the sprite HTML&lt;br /&gt;
		if ( refresh !== false ) {&lt;br /&gt;
			refresh = !!$( &#039;.spriteedit-new-image&#039; ).length;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		sheet.save( summary ).then( function() {&lt;br /&gt;
			return names.save( summary, conflict );&lt;br /&gt;
		} ).then( function( data ) {&lt;br /&gt;
			if ( sheet.modified ) {&lt;br /&gt;
				if ( spriteSettings[i18n.luaKeySettingsUrl] ) {&lt;br /&gt;
					var url = $doc.data( &#039;url&#039; );&lt;br /&gt;
					overwriteSpritesheet( url );&lt;br /&gt;
					$doc.data( &#039;original-url&#039;, url );&lt;br /&gt;
				} else {&lt;br /&gt;
					sheet.getData().then( function( blob ) {&lt;br /&gt;
						overwriteSpritesheet( URL.createObjectURL( blob ) );&lt;br /&gt;
					} );&lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
			// Prevent disabling, otherwise we&#039;d end up with the old&lt;br /&gt;
			// spritesheet if the editor was restarted and closed&lt;br /&gt;
			overwriteSpritesheet.style = null;&lt;br /&gt;
			&lt;br /&gt;
			// Null edit, nothing to do here&lt;br /&gt;
			if ( !data || data.edit.nochange ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			$doc.data( &#039;datatimestamp&#039;, fixTimestamp( data.edit.newtimestamp ) );&lt;br /&gt;
			&lt;br /&gt;
			// Purge this page so the changes show up immediately&lt;br /&gt;
			retryableRequest( function() {&lt;br /&gt;
				return new mw.Api().post( {&lt;br /&gt;
					action: &#039;purge&#039;,&lt;br /&gt;
					pageids: mw.config.get( &#039;wgArticleId&#039; ),&lt;br /&gt;
				} );&lt;br /&gt;
			} );&lt;br /&gt;
		} ).then( function() {&lt;br /&gt;
			var newContent;&lt;br /&gt;
			if ( refresh ) {&lt;br /&gt;
				newContent = retryableRequest( function() {&lt;br /&gt;
					return parseApi.get( {&lt;br /&gt;
						title: mw.config.get( &#039;wgPageName&#039; ),&lt;br /&gt;
						text: $( &#039;&amp;lt;i&amp;gt;&#039; ).html(&lt;br /&gt;
							$.parseHTML( $doc.attr( &#039;data-refreshtext&#039; ) )&lt;br /&gt;
						).html(),&lt;br /&gt;
					} );&lt;br /&gt;
				} );&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			$.when( newContent ).done( function( data ) {&lt;br /&gt;
				if ( refresh ) {&lt;br /&gt;
					$doc.replaceWith( data.parse.text );&lt;br /&gt;
				}&lt;br /&gt;
			} ).always( function() {&lt;br /&gt;
				destroy();&lt;br /&gt;
				&lt;br /&gt;
				mw.hook( &#039;postEdit&#039; ).fire( { message: i18n.changesSavedNotice } );&lt;br /&gt;
			} );&lt;br /&gt;
		}, handleSaveError );&lt;br /&gt;
	};&lt;br /&gt;
	&lt;br /&gt;
	/**&lt;br /&gt;
	 * Handles special case errors that occur when saving (AKA, handleError with edit conflicts)&lt;br /&gt;
	 *&lt;br /&gt;
	 * If there&#039;s an edit conflict, this will be display a barely human-usable edit conflict&lt;br /&gt;
	 * panel, where the user may manually merge the raw lua table changes. Sprite edit conflict&lt;br /&gt;
	 * merging is not supported (because image uploading doesn&#039;t implement edit conflicts, for one).&lt;br /&gt;
	 * Otherwise, passes it on to handleError.&lt;br /&gt;
	 *&lt;br /&gt;
	 * &amp;quot;code&amp;quot; and &amp;quot;data&amp;quot; are the standard variables returned by a mw.Api promise rejection.&lt;br /&gt;
	 */&lt;br /&gt;
	var handleSaveError = function( code, data ) {&lt;br /&gt;
		// Allow editing again&lt;br /&gt;
		$root.removeClass( &#039;spriteedit-hidecontrols&#039; );&lt;br /&gt;
		$( &#039;#spriteedit-save&#039; ).find( &#039;button&#039; ).removeClass( &#039;spriteedit-processing&#039; );&lt;br /&gt;
		&lt;br /&gt;
		if ( code !== &#039;editconflict&#039; ) {&lt;br /&gt;
			handleError( code, data );&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		var conflictPanel = panels.conflict || panel( &#039;conflict&#039;, {&lt;br /&gt;
			title: i18n.panelConflictTitle,&lt;br /&gt;
			content: $( &#039;&amp;lt;p&amp;gt;&#039; ).text( i18n.panelConflictText ),&lt;br /&gt;
			actions: {&lt;br /&gt;
				left: { text: i18n.panelConflictReview, config: {&lt;br /&gt;
					id: &#039;review-conflict-changes&#039;,&lt;br /&gt;
					action: function() {&lt;br /&gt;
						var $button = $( this );&lt;br /&gt;
						if ( $button.hasClass( &#039;spriteedit-processing&#039; ) ) {&lt;br /&gt;
							return;&lt;br /&gt;
						}&lt;br /&gt;
						$button.blur().addClass( &#039;spriteedit-processing&#039; );&lt;br /&gt;
						&lt;br /&gt;
						var changesPanel = panels.ecchanges || panel( &#039;ecchanges&#039;, {&lt;br /&gt;
							title: i18n.panelEcchangesTitle,&lt;br /&gt;
							content: $( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;spriteedit-id-changes&#039; ),&lt;br /&gt;
							actions: { right: { text: i18n.panelEcchangesReturn, config: {&lt;br /&gt;
								id: &#039;spriteedit-return-edit&#039;,&lt;br /&gt;
								type: [ &#039;progressive&#039;, &#039;primary&#039; ],&lt;br /&gt;
								action: function() {&lt;br /&gt;
									conflictPanel.show();&lt;br /&gt;
								},&lt;br /&gt;
							} } },&lt;br /&gt;
							onClose: function() {&lt;br /&gt;
								names.invalidate( true );&lt;br /&gt;
							},&lt;br /&gt;
						} );&lt;br /&gt;
						&lt;br /&gt;
						names.setTable( $( &#039;#spriteedit-ec-curText&#039; ).data( &#039;ooui-object&#039; ).getValue() );&lt;br /&gt;
						names.getDiff().then( function( diff ) {&lt;br /&gt;
							changesPanel.clean();&lt;br /&gt;
							&lt;br /&gt;
							if ( !diff ) {&lt;br /&gt;
								diff = i18n.panelChangesNoDiffFromCur;&lt;br /&gt;
							}&lt;br /&gt;
							changesPanel.$text.find( &#039;.spriteedit-id-changes&#039; ).append( diff );&lt;br /&gt;
							changesPanel.show();&lt;br /&gt;
						}, function( code, data ) {&lt;br /&gt;
							$button.removeClass( &#039;spriteedit-processing&#039; );&lt;br /&gt;
							handleError( code, data );&lt;br /&gt;
						} );&lt;br /&gt;
					}&lt;br /&gt;
				} },&lt;br /&gt;
				right: { text: i18n.panelConflictSave, config: {&lt;br /&gt;
					id: &#039;save-conflict&#039;,&lt;br /&gt;
					type: [ &#039;progressive&#039;, &#039;primary&#039; ],&lt;br /&gt;
					action: function() {&lt;br /&gt;
						var $button = $( this );&lt;br /&gt;
						if ( $button.hasClass( &#039;spriteedit-processing&#039; ) ) {&lt;br /&gt;
							return;&lt;br /&gt;
						}&lt;br /&gt;
						$button.blur().addClass( &#039;spriteedit-processing&#039; );&lt;br /&gt;
						&lt;br /&gt;
						names.setTable( $( &#039;#spriteedit-ec-curText&#039; ).data( &#039;ooui-object&#039; ).getValue() );&lt;br /&gt;
						saveChanges( $( &#039;#spriteedit-summary&#039; ).data( &#039;ooui-object&#039; ).getValue(), true, true );&lt;br /&gt;
					},&lt;br /&gt;
				} },&lt;br /&gt;
			},&lt;br /&gt;
			onShow: function() {&lt;br /&gt;
				this.$actions.find( &#039;button&#039; ).removeClass( &#039;spriteedit-processing&#039; );&lt;br /&gt;
				&lt;br /&gt;
				var $textarea = this.$text.find( &#039;textarea&#039; );&lt;br /&gt;
				$textarea.css( &#039;max-height&#039;, ( this.$text.height() - $textarea.parent()[0].offsetTop ) + &#039;px&#039; );&lt;br /&gt;
			},&lt;br /&gt;
			onClose: function() {&lt;br /&gt;
				names.invalidate( true );&lt;br /&gt;
			},&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		$.when(&lt;br /&gt;
			names.getTable(),&lt;br /&gt;
			names.getDiff(),&lt;br /&gt;
			retryableRequest( function() {&lt;br /&gt;
				return revisionsApi.get( { titles: dataPage } );&lt;br /&gt;
			} )&lt;br /&gt;
		).then( function( table, diff, curTextData ) {&lt;br /&gt;
			// TODO: Change to MultilineTextInputWidget on MW 1.30&lt;br /&gt;
			var curEditbox = new OO.ui.TextInputWidget( {&lt;br /&gt;
				id: &#039;spriteedit-ec-curText&#039;,&lt;br /&gt;
				multiline: true,&lt;br /&gt;
				value: curTextData[0].query.pages[0].revisions[0].content,&lt;br /&gt;
			} );&lt;br /&gt;
			curEditbox.$element.data( &#039;ooui-object&#039;, curEditbox );&lt;br /&gt;
			var oldEditbox = new OO.ui.TextInputWidget( {&lt;br /&gt;
				id: &#039;spriteedit-ec-oldText&#039;,&lt;br /&gt;
				multiline: true,&lt;br /&gt;
				readOnly: true,&lt;br /&gt;
				value: table,&lt;br /&gt;
			} );&lt;br /&gt;
			oldEditbox.$element.data( &#039;ooui-object&#039;, oldEditbox );&lt;br /&gt;
			&lt;br /&gt;
			var $curText = $( &#039;&amp;lt;div&amp;gt;&#039; ).append(&lt;br /&gt;
				$( &#039;&amp;lt;p&amp;gt;&#039; ).text( i18n.panelConflictCurText ),&lt;br /&gt;
				curEditbox.$element&lt;br /&gt;
			);&lt;br /&gt;
			var $oldText = $( &#039;&amp;lt;div&amp;gt;&#039; ).append(&lt;br /&gt;
				$( &#039;&amp;lt;p&amp;gt;&#039; ).text( i18n.panelConflictYourText ),&lt;br /&gt;
				oldEditbox.$element&lt;br /&gt;
			);&lt;br /&gt;
			&lt;br /&gt;
			conflictPanel.$text.append(&lt;br /&gt;
				$( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;spriteedit-ec-editboxes&#039; ).append(&lt;br /&gt;
					$curText,&lt;br /&gt;
					$oldText&lt;br /&gt;
				),&lt;br /&gt;
				diff&lt;br /&gt;
			);&lt;br /&gt;
			&lt;br /&gt;
			conflictPanel.show();&lt;br /&gt;
		}, function( code, data ) {&lt;br /&gt;
			$( &#039;#spriteedit-save&#039; ).find( &#039;button&#039; ).removeClass( &#039;spriteedit-processing&#039; );&lt;br /&gt;
			handleError( code, data );&lt;br /&gt;
		} );&lt;br /&gt;
	};&lt;br /&gt;
	&lt;br /&gt;
	/**&lt;br /&gt;
	 * Converts a position to pixel co-ordinates on the sheet&lt;br /&gt;
	 */&lt;br /&gt;
	var posToPx = function( pos ) {&lt;br /&gt;
		settings.imagesPerRow = settings.imagesPerRow ||&lt;br /&gt;
			( settings.sheetWidth + settings.spacing ) / ( settings.imageWidth + settings.spacing );&lt;br /&gt;
		pos -= 1;&lt;br /&gt;
		return {&lt;br /&gt;
			left: pos % settings.imagesPerRow * ( settings.imageWidth + settings.spacing ),&lt;br /&gt;
			top: Math.floor( pos / settings.imagesPerRow ) * ( settings.imageHeight + settings.spacing ),&lt;br /&gt;
		};&lt;br /&gt;
	};&lt;br /&gt;
	&lt;br /&gt;
	/**&lt;br /&gt;
	 * Inserts new images into the editor&lt;br /&gt;
	 *&lt;br /&gt;
	 * A box is created for the new image, with the name set to the file&#039;s name (minus extension).&lt;br /&gt;
	 * The box is inserted into the nearest section and then sorted to the correct location.&lt;br /&gt;
	 * Any file that doesn&#039;t match the image/* mime type is ignored.&lt;br /&gt;
	 *&lt;br /&gt;
	 * &amp;quot;files&amp;quot; is a &amp;quot;FileList&amp;quot; (or an array of &amp;quot;File&amp;quot; objects) from a file input or drop.&lt;br /&gt;
	 * &amp;quot;section&amp;quot; is an Element which is the section to place the sprites in. Defaults to&lt;br /&gt;
	 * the nearestSection()&lt;br /&gt;
	 */&lt;br /&gt;
	var insertSprites = function( files, section ) {&lt;br /&gt;
		var $parent = $( section || nearestSection() ).find( &#039;.spritedoc-boxes&#039; );&lt;br /&gt;
		$.each( files, function() {&lt;br /&gt;
			if ( !this.type.match( /^image\// ) ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			var $newBox = $boxTemplate.clone();&lt;br /&gt;
			$newBox.find( &#039;code&#039; ).text( this.name.trim().replace( /\.[^\.]+$/, &#039;&#039; ).replace( /_/g, &#039; &#039; ) );&lt;br /&gt;
			scaleImage( this ).done( function( $img ) {&lt;br /&gt;
				$img.addClass( &#039;spriteedit-new-image&#039; );&lt;br /&gt;
				$newBox.find( &#039;.spritedoc-image&#039; ).html( $img );&lt;br /&gt;
			} );&lt;br /&gt;
			&lt;br /&gt;
			var name = $newBox.find( &#039;.spritedoc-name&#039; ).text();&lt;br /&gt;
			$newBox.attr( &#039;data-sort-key&#039;, name );&lt;br /&gt;
			&lt;br /&gt;
			var index = getAlphaIndex( name, undefined, $parent );&lt;br /&gt;
			change( &#039;insert&#039;, {&lt;br /&gt;
				$elem: $newBox,&lt;br /&gt;
				index: index - 1,&lt;br /&gt;
				$parent: $parent,&lt;br /&gt;
			} );&lt;br /&gt;
		} );&lt;br /&gt;
	};&lt;br /&gt;
	&lt;br /&gt;
	/**&lt;br /&gt;
	 * Constructs (or retrieves) a canvas for a particular purpose&lt;br /&gt;
	 *&lt;br /&gt;
	 * Either for image scaling, or spritesheet creation.&lt;br /&gt;
	 *&lt;br /&gt;
	 * Returns an object containing the canvas, its context,&lt;br /&gt;
	 * and some convenience functions for clearing the canvas&lt;br /&gt;
	 * and for updating its dimensions.&lt;br /&gt;
	 *&lt;br /&gt;
	 * &amp;quot;type&amp;quot; is the canvas type (&amp;quot;image&amp;quot; or &amp;quot;sheet&amp;quot;).&lt;br /&gt;
	 */&lt;br /&gt;
	var getCanvas = ( function() {&lt;br /&gt;
		var canvases = {};&lt;br /&gt;
		return function( type ) {&lt;br /&gt;
			if ( canvases[type] ) {&lt;br /&gt;
				return canvases[type];&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			var $canvas = $( &#039;&amp;lt;canvas&amp;gt;&#039; ).attr( {&lt;br /&gt;
				width: settings[type + &#039;Width&#039;],&lt;br /&gt;
				height: settings[type + &#039;Height&#039;],&lt;br /&gt;
			} ).appendTo( $doc );&lt;br /&gt;
			var canvas = $canvas[0];&lt;br /&gt;
			var ctx = canvas.getContext( &#039;2d&#039; );&lt;br /&gt;
			&lt;br /&gt;
			var funcs = {&lt;br /&gt;
				canvas: canvas,&lt;br /&gt;
				ctx: ctx,&lt;br /&gt;
				resize: function() {&lt;br /&gt;
					$canvas.attr( {&lt;br /&gt;
						width: settings[type + &#039;Width&#039;],&lt;br /&gt;
						height: settings[type + &#039;Height&#039;],&lt;br /&gt;
					} );&lt;br /&gt;
				},&lt;br /&gt;
				clear: function() {&lt;br /&gt;
					ctx.clearRect( 0, 0, canvas.width, canvas.height );&lt;br /&gt;
				},&lt;br /&gt;
			};&lt;br /&gt;
			canvases[type] = funcs;&lt;br /&gt;
			return funcs;&lt;br /&gt;
		};&lt;br /&gt;
	}() );&lt;br /&gt;
	&lt;br /&gt;
	/**&lt;br /&gt;
	 * Scales an image down to the correct size (if necessary)&lt;br /&gt;
	 *&lt;br /&gt;
	 * Performs only a basic low quality scaling, ignoring the original image&#039;s&lt;br /&gt;
	 * aspect ratio.&lt;br /&gt;
	 * Also performs a &amp;quot;scale&amp;quot; if the image isn&#039;t a png, in essence converting it to one.&lt;br /&gt;
	 *&lt;br /&gt;
	 * Returns a promise which will contain a jQuery object containing a new image element&lt;br /&gt;
	 * the url of which is either a object URL or data URL of the scaled image.&lt;br /&gt;
	 */&lt;br /&gt;
	var scaleImage = ( function() {&lt;br /&gt;
		var scaler;&lt;br /&gt;
		return function( file ) {&lt;br /&gt;
			var deferred = $.Deferred();&lt;br /&gt;
			var img = new Image();&lt;br /&gt;
			img.onload = function() {&lt;br /&gt;
				if (&lt;br /&gt;
					file.type === &#039;image/png&#039; &amp;amp;&amp;amp;&lt;br /&gt;
					img.width === settings.imageWidth &amp;amp;&amp;amp; img.height === settings.imageHeight&lt;br /&gt;
				) {&lt;br /&gt;
					// No scaling necessary&lt;br /&gt;
					deferred.resolve( $( img ) );&lt;br /&gt;
					return;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				if ( !scaler ) {&lt;br /&gt;
					scaler = getCanvas( &#039;image&#039; );&lt;br /&gt;
				}&lt;br /&gt;
				scaler.clear();&lt;br /&gt;
				scaler.ctx.drawImage( img, 0, 0, settings.imageWidth, settings.imageHeight );&lt;br /&gt;
				&lt;br /&gt;
				URL.revokeObjectURL( img.src );&lt;br /&gt;
				&lt;br /&gt;
				var scaledImg = new Image();&lt;br /&gt;
				scaledImg.onload = function() {&lt;br /&gt;
					deferred.resolve( $( scaledImg ) );&lt;br /&gt;
				};&lt;br /&gt;
				scaler.canvas.toBlob( function( blob ) {&lt;br /&gt;
					scaledImg.src = URL.createObjectURL( blob );&lt;br /&gt;
				} );&lt;br /&gt;
			};&lt;br /&gt;
			img.src = URL.createObjectURL( file );&lt;br /&gt;
			&lt;br /&gt;
			loadingImages.push( deferred.promise() );&lt;br /&gt;
			return deferred.promise();&lt;br /&gt;
		};&lt;br /&gt;
	}() );&lt;br /&gt;
	&lt;br /&gt;
	/**&lt;br /&gt;
	 * Creates panels to display in a dialog window&lt;br /&gt;
	 *&lt;br /&gt;
	 * If this is the first panel, the dialog window is created.&lt;br /&gt;
	 * Panels are stored in the &amp;quot;panels&amp;quot; object, which should be checked for&lt;br /&gt;
	 * panel id prior to calling this function to create a new panel,&lt;br /&gt;
	 * so duplicates are not made.&lt;br /&gt;
	 * E.g: `var myPanel = panels.myPanel || panel( &#039;myPanel&#039;, ... );`&lt;br /&gt;
	 *&lt;br /&gt;
	 * &amp;quot;id&amp;quot; is the unique ID that identifies this panel&lt;br /&gt;
	 * &amp;quot;config&amp;quot; is an object of config options for this panel&lt;br /&gt;
	 *  &amp;quot;title&amp;quot; is the string to use for the panel&#039;s title&lt;br /&gt;
	 *  &amp;quot;content&amp;quot; is HTML to use for the panel&#039;s text area,&lt;br /&gt;
	 *   it can be in any format $().append takes (jQuery, nodes, HTML strings, array)&lt;br /&gt;
	 *   The panel will reset to this HTML whenever the dialog box is closed&lt;br /&gt;
	 *   (if &amp;quot;cached&amp;quot; isn&#039;t specified)&lt;br /&gt;
	 *  &amp;quot;actions&amp;quot; is an object to specify which buttons to place.&lt;br /&gt;
	 *   It has a &amp;quot;left&amp;quot; and &amp;quot;right&amp;quot; key to specify which side of the&lt;br /&gt;
	 *   dialog to place the buttons which accept an array of objects&lt;br /&gt;
	 *   which are passed to `makeButton`&lt;br /&gt;
	 *  &amp;quot;onShow&amp;quot; is a callback which is called whenever the dialog is&lt;br /&gt;
	 *   opened, or this panel is shown&lt;br /&gt;
	 *  &amp;quot;onHide&amp;quot; is a callback which is called whenever the dialog is&lt;br /&gt;
	 *   closed, or this panel is hidden&lt;br /&gt;
	 *  &amp;quot;onClose&amp;quot; is a callback which is called whenever the dialog is&lt;br /&gt;
	 *   closed, regardless of which panel is currently shown&lt;br /&gt;
	 *  &amp;quot;cached&amp;quot; is a boolean specifying if the panel&#039;s HTML should be&lt;br /&gt;
	 *   retained after the dialog is closed, or should be reset to the&lt;br /&gt;
	 *   value of &amp;quot;config.content&amp;quot;&lt;br /&gt;
	 *&lt;br /&gt;
	 * Returns the panel object for the new panel (or the currently displayed&lt;br /&gt;
	 * panel if called with no arguments).&lt;br /&gt;
	 * The panel object contains jQuery objects of the panel&#039;s parts, some of&lt;br /&gt;
	 * the config options, and methods for controlling the panel/dialog window.&lt;br /&gt;
	 * &lt;br /&gt;
	 * panel.show shows the panel, opening the dialog if it isn&#039;t already&lt;br /&gt;
	 *  It accepts a callback function which is called once the dialog/panel&lt;br /&gt;
	 *  opening animation is finished&lt;br /&gt;
	 * panel.hide closes the dialog&lt;br /&gt;
	 *  It accepts a callback function which is called once the dialog closing&lt;br /&gt;
	 *  animation is finished&lt;br /&gt;
	 * panel.clean deletes the panel&#039;s text and resets it to the initial&lt;br /&gt;
	 *  value specified in &amp;quot;config.content&amp;quot;&lt;br /&gt;
	 */&lt;br /&gt;
	var panel = function( id, config ) {&lt;br /&gt;
		var $overlay;&lt;br /&gt;
		var $dialog = $( &#039;.spriteedit-dialog&#039; );&lt;br /&gt;
		if ( !id ) {&lt;br /&gt;
			return panels[$dialog.data( &#039;active-panel&#039; )];&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		var thisPanel = panels[id];&lt;br /&gt;
		if ( thisPanel ) {&lt;br /&gt;
			return thisPanel;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		if ( !$dialog.length ) {&lt;br /&gt;
			$overlay = $( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;spriteedit-dialog-overlay&#039; ).css( &#039;display&#039;, &#039;none&#039; );&lt;br /&gt;
			$dialog = $( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;spriteedit-dialog&#039; ).append(&lt;br /&gt;
				makeButton( &#039;&#039;, {&lt;br /&gt;
					id: &#039;spriteedit-dialog-close&#039;,&lt;br /&gt;
					icon: &#039;close&#039;,&lt;br /&gt;
					title: i18n.panelCloseTip,&lt;br /&gt;
					action: function() {&lt;br /&gt;
						var closingPanel = panel();&lt;br /&gt;
						closingPanel.hide();&lt;br /&gt;
						if ( closingPanel.onClose ) {&lt;br /&gt;
							closingPanel.onClose.call( closingPanel );&lt;br /&gt;
						}&lt;br /&gt;
					},&lt;br /&gt;
				} )&lt;br /&gt;
			).appendTo( $overlay );&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		if ( config.content &amp;amp;&amp;amp; !Array.isArray( config.content ) ) {&lt;br /&gt;
			config.content = [ config.content ];&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		var $panel = $( &#039;&amp;lt;div&amp;gt;&#039; )&lt;br /&gt;
			.prop( &#039;id&#039;, &#039;spriteedit-dialog-&#039; + id )&lt;br /&gt;
			.addClass( &#039;spriteedit-dialog-panel&#039; );&lt;br /&gt;
		&lt;br /&gt;
		var $title = $( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;spriteedit-dialog-title&#039; ).text( config.title ).appendTo( $panel );&lt;br /&gt;
		&lt;br /&gt;
		var $text = $( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;spriteedit-dialog-text&#039; ).appendTo( $panel );&lt;br /&gt;
		&lt;br /&gt;
		if ( config.content ) {&lt;br /&gt;
			$text.append( config.content );&lt;br /&gt;
			&lt;br /&gt;
			// Keep content as the initial HTML for resetting&lt;br /&gt;
			config.content = $text.html();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		var $actions;&lt;br /&gt;
		if ( config.actions ) {&lt;br /&gt;
			$actions = $( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;spriteedit-dialog-actions&#039; ).appendTo( $panel );&lt;br /&gt;
			var $leftActions = $( &#039;&amp;lt;span&amp;gt;&#039; ).appendTo( $actions );&lt;br /&gt;
			var $rightActions = $( &#039;&amp;lt;span&amp;gt;&#039; ).css( &#039;float&#039;, &#039;right&#039; ).appendTo( $actions );&lt;br /&gt;
			var addButtons = function( buttons, right ) {&lt;br /&gt;
				if ( !buttons ) {&lt;br /&gt;
					return;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				var $area = right ? $rightActions : $leftActions;&lt;br /&gt;
				if ( !Array.isArray( buttons ) ) {&lt;br /&gt;
					buttons = [ buttons ];&lt;br /&gt;
				}&lt;br /&gt;
				$.each( buttons, function() {&lt;br /&gt;
					$area.append( makeButton( this.text, this.config ) );&lt;br /&gt;
				} );&lt;br /&gt;
			};&lt;br /&gt;
			&lt;br /&gt;
			addButtons( config.actions.left );&lt;br /&gt;
			addButtons( config.actions.right, true );&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		$dialog.append( $panel );&lt;br /&gt;
		&lt;br /&gt;
		if ( $overlay ) {&lt;br /&gt;
			$body.append( $overlay );&lt;br /&gt;
		} else {&lt;br /&gt;
			$overlay = $dialog.parent();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		$overlay.show();&lt;br /&gt;
		&lt;br /&gt;
		if ( $overlay.css( &#039;opacity&#039; ) === &#039;0&#039; ) {&lt;br /&gt;
			$overlay.hide();&lt;br /&gt;
		}&lt;br /&gt;
		$panel.hide();&lt;br /&gt;
		&lt;br /&gt;
		thisPanel = panels[id] = {&lt;br /&gt;
			$panel: $panel,&lt;br /&gt;
			$title: $title,&lt;br /&gt;
			$text: $text,&lt;br /&gt;
			$actions: $actions,&lt;br /&gt;
			show: function( callback ) {&lt;br /&gt;
				$dialog.css( { transform: &#039;none&#039;, transition: &#039;none&#039; } );&lt;br /&gt;
				&lt;br /&gt;
				var prevPanel;&lt;br /&gt;
				if ( $overlay.css( &#039;opacity&#039; ) === &#039;1&#039; ) {&lt;br /&gt;
					prevPanel = panel();&lt;br /&gt;
					// Remember to cleanup previous panel when the dialog is closed&lt;br /&gt;
					if ( prevPanel &amp;amp;&amp;amp; !prevPanel.cached ) {&lt;br /&gt;
						prevPanel.cleanup = true;&lt;br /&gt;
					}&lt;br /&gt;
					if ( prevPanel.onHide ) {&lt;br /&gt;
						prevPanel.onHide.call( prevPanel );&lt;br /&gt;
					}&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				var oldRect;&lt;br /&gt;
				if ( prevPanel ) {&lt;br /&gt;
					oldRect = $dialog[0].getBoundingClientRect();&lt;br /&gt;
					prevPanel.$panel.hide();&lt;br /&gt;
				}&lt;br /&gt;
				$overlay.css( &#039;display&#039;, &#039;&#039; );&lt;br /&gt;
				$panel.css( &#039;display&#039;, &#039;&#039; );&lt;br /&gt;
				if ( prevPanel ) {&lt;br /&gt;
					var newRect = $dialog[0].getBoundingClientRect();&lt;br /&gt;
					$dialog.css( &#039;transform&#039;, &#039;scale(1)&#039; ).redraw().css( &#039;transition&#039;, &#039;&#039; );&lt;br /&gt;
					if ( oldRect.width === newRect.width &amp;amp;&amp;amp; oldRect.height === newRect.height ) {&lt;br /&gt;
						// No transition to be made&lt;br /&gt;
						$dialog.trigger( &#039;transitionend&#039; );&lt;br /&gt;
					} else {&lt;br /&gt;
						$panel.css( &#039;display&#039;, &#039;none&#039; );&lt;br /&gt;
						$dialog.css( {&lt;br /&gt;
							width: oldRect.width,&lt;br /&gt;
							height: oldRect.height,&lt;br /&gt;
						} ).redraw().css( {&lt;br /&gt;
							width: newRect.width,&lt;br /&gt;
							height: newRect.height,&lt;br /&gt;
						} ).transitionEnd( function() {&lt;br /&gt;
							panelShown = true;&lt;br /&gt;
							$dialog.css( { width: &#039;&#039;, height: &#039;&#039; } );&lt;br /&gt;
							$panel.css( &#039;display&#039;, &#039;&#039; );&lt;br /&gt;
						} );&lt;br /&gt;
						&lt;br /&gt;
						// Make sure the panel gets displayed&lt;br /&gt;
						var panelShown;&lt;br /&gt;
						setTimeout( function() {&lt;br /&gt;
							if ( panelShown ) {&lt;br /&gt;
								return;&lt;br /&gt;
							}&lt;br /&gt;
							&lt;br /&gt;
							$dialog.trigger( &#039;transitionend&#039; );&lt;br /&gt;
						}, 1000 );&lt;br /&gt;
					}&lt;br /&gt;
				} else {&lt;br /&gt;
					$dialog.css( &#039;transform&#039;, &#039;&#039; ).redraw().css( &#039;transition&#039;, &#039;&#039; );&lt;br /&gt;
					$overlay.css( &#039;opacity&#039;, 1 );&lt;br /&gt;
					$dialog&lt;br /&gt;
						.addClass( &#039;spriteedit-elastic&#039; )&lt;br /&gt;
						.css( &#039;transform&#039;, &#039;scale(1)&#039; )&lt;br /&gt;
						.transitionEnd( function() {&lt;br /&gt;
							$dialog.removeClass( &#039;spriteedit-elastic&#039; );&lt;br /&gt;
						} );&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				$dialog.data( &#039;active-panel&#039;, id );&lt;br /&gt;
				&lt;br /&gt;
				if ( config.onShow ) {&lt;br /&gt;
					config.onShow.call( thisPanel );&lt;br /&gt;
				}&lt;br /&gt;
				if ( callback ) {&lt;br /&gt;
					callback.call( thisPanel );&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				return this;&lt;br /&gt;
			},&lt;br /&gt;
			hide: function( callback ) {&lt;br /&gt;
				if ( !$overlay.is( &#039;:visible&#039; ) ) {&lt;br /&gt;
					return this;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				if ( config.onHide ) {&lt;br /&gt;
					config.onHide.call( thisPanel );&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				$dialog.css( &#039;transform&#039;, &#039;scale(0)&#039; );&lt;br /&gt;
				$overlay.css( &#039;opacity&#039;, 0 ).transitionEnd( function() {&lt;br /&gt;
					// Reset scrollbar BEFORE hiding&lt;br /&gt;
					$text.scrollLeft( 0 );&lt;br /&gt;
					$text.scrollTop( 0 );&lt;br /&gt;
					&lt;br /&gt;
					$overlay.css( &#039;display&#039;, &#039;none&#039; );&lt;br /&gt;
					thisPanel.$panel.css( &#039;display&#039;, &#039;none&#039; );&lt;br /&gt;
					&lt;br /&gt;
					if ( !config.cached ) {&lt;br /&gt;
						thisPanel.cleanup = true;&lt;br /&gt;
					}&lt;br /&gt;
					$.each( panels, function() {&lt;br /&gt;
						if ( this.cleanup ) {&lt;br /&gt;
							this.clean();&lt;br /&gt;
						}&lt;br /&gt;
					} );&lt;br /&gt;
					&lt;br /&gt;
					if ( callback ) {&lt;br /&gt;
						callback.call( thisPanel );&lt;br /&gt;
					}&lt;br /&gt;
				} );&lt;br /&gt;
				&lt;br /&gt;
				return this;&lt;br /&gt;
			},&lt;br /&gt;
			clean: function() {&lt;br /&gt;
				$text.empty();&lt;br /&gt;
				&lt;br /&gt;
				if ( config.content ) {&lt;br /&gt;
					$text.append( config.content );&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				thisPanel.cleanup = false;&lt;br /&gt;
			},&lt;br /&gt;
			onShow: config.onShow,&lt;br /&gt;
			onHide: config.onHide,&lt;br /&gt;
			onClose: config.onClose,&lt;br /&gt;
			cached: config.cached,&lt;br /&gt;
		};&lt;br /&gt;
		return thisPanel;&lt;br /&gt;
	};&lt;br /&gt;
	&lt;br /&gt;
	/**&lt;br /&gt;
	 * Creates a simple tooltip&lt;br /&gt;
	 *&lt;br /&gt;
	 * Used to create a small tooltip anchored to an element.&lt;br /&gt;
	 * Only a single tooltip can exist at a time (opening a new one will close the old)&lt;br /&gt;
	 * and clicking anywhere but the tooltip itself will close it.&lt;br /&gt;
	 *&lt;br /&gt;
	 * In the main function:&lt;br /&gt;
	 * &amp;quot;$elem&amp;quot; is a jQuery object which the tooltip should be anchored to.&lt;br /&gt;
	 * &amp;quot;content&amp;quot; is the content to go in the tooltip, and can be in whatever format can&lt;br /&gt;
	 * go into jQuery().append (jQuery objects, elements, HTML strings, etc.).&lt;br /&gt;
	 * &amp;quot;config&amp;quot; contains key-value pairs of the following configuration options:&lt;br /&gt;
	 *   &amp;quot;horizontal&amp;quot; is a boolean determining if the tooltip should open horizontally or vertically&lt;br /&gt;
	 *   relative to its anchor.&lt;br /&gt;
	 *   &amp;quot;callback&amp;quot; is a function called once the tooltip finishes its opening animation.&lt;br /&gt;
	 *   &amp;quot;class&amp;quot; is a classname to add to the tooltip&lt;br /&gt;
	 *&lt;br /&gt;
	 * In the tooltip.hide function:&lt;br /&gt;
	 * &amp;quot;callback&amp;quot; is a function called once the tooltip finishes its closing animation.&lt;br /&gt;
	 */&lt;br /&gt;
	var tooltip = ( function() {&lt;br /&gt;
		var $tooltip = $(), $anchor = $();&lt;br /&gt;
		&lt;br /&gt;
		$win.click( function( e ) {&lt;br /&gt;
			if (&lt;br /&gt;
				e.which === 1 &amp;amp;&amp;amp;&lt;br /&gt;
				$tooltip.length &amp;amp;&amp;amp; !$tooltip.has( e.target ).length &amp;amp;&amp;amp;&lt;br /&gt;
				$tooltip.css( &#039;opacity&#039; ) === &#039;1&#039;&lt;br /&gt;
			) {&lt;br /&gt;
				func.hide();&lt;br /&gt;
			}&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		var func = function( $elem, content, config ) {&lt;br /&gt;
			config = config || {};&lt;br /&gt;
			if ( $tooltip.length ) {&lt;br /&gt;
				if ( $elem.is( $anchor ) ) {&lt;br /&gt;
					func.hide();&lt;br /&gt;
					return;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				func.hide();&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			$anchor = $elem;&lt;br /&gt;
			$tooltip = $( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;spriteedit-tooltip&#039; ).append(&lt;br /&gt;
				$( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;spriteedit-tooltip-text&#039; ).append( content ),&lt;br /&gt;
				$( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;spriteedit-tooltip-arrow&#039; )&lt;br /&gt;
			).appendTo( document.body );&lt;br /&gt;
			&lt;br /&gt;
			if ( config.class ) {&lt;br /&gt;
				$tooltip.addClass( config.class );&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			var anchorPos = $anchor.offset();&lt;br /&gt;
			var bodyPos = $body.offset();&lt;br /&gt;
			if ( config.horizontal ) {&lt;br /&gt;
				$tooltip.addClass( &#039;spriteedit-tooltip-horizontal&#039; ).css( {&lt;br /&gt;
					top: anchorPos.top - bodyPos.top + $anchor.outerHeight() / 2,&lt;br /&gt;
					left: anchorPos.left - bodyPos.left - $tooltip.outerWidth(),&lt;br /&gt;
				} );&lt;br /&gt;
			} else {&lt;br /&gt;
				$tooltip.css( {&lt;br /&gt;
					top: anchorPos.top - bodyPos.top - $tooltip.outerHeight(),&lt;br /&gt;
					left: anchorPos.left - bodyPos.left + $anchor.outerWidth() / 2,&lt;br /&gt;
				} );&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			$tooltip.addClass( &#039;spriteedit-elastic&#039; ).css( {&lt;br /&gt;
				opacity: 1,&lt;br /&gt;
				transform: &#039;scale(1)&#039;,&lt;br /&gt;
			} ).transitionEnd( function() {&lt;br /&gt;
				$( this ).removeClass( &#039;spriteedit-elastic&#039; );&lt;br /&gt;
				&lt;br /&gt;
				if ( config.callback ) {&lt;br /&gt;
					config.callback.call( this );&lt;br /&gt;
				}&lt;br /&gt;
			} );&lt;br /&gt;
		};&lt;br /&gt;
		func.hide = function( callback ) {&lt;br /&gt;
			if ( !$tooltip.length ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			$tooltip.off( &#039;transitionend.spriteEdit&#039; ).css( {&lt;br /&gt;
				opacity: 0,&lt;br /&gt;
				transform: &#039;scale(0)&#039;,&lt;br /&gt;
			} ).transitionEnd( function() {&lt;br /&gt;
				$( this ).remove();&lt;br /&gt;
				&lt;br /&gt;
				if ( callback ) {&lt;br /&gt;
					callback.call( this );&lt;br /&gt;
				}&lt;br /&gt;
			} );&lt;br /&gt;
			&lt;br /&gt;
			$tooltip = $anchor = $();&lt;br /&gt;
		};&lt;br /&gt;
		&lt;br /&gt;
		return func;&lt;br /&gt;
	}() );&lt;br /&gt;
	&lt;br /&gt;
	/**&lt;br /&gt;
	 * Makes a set of elements sortable by dragging them&lt;br /&gt;
	 *&lt;br /&gt;
	 * The elements can either be dragged around to be sorted within or between&lt;br /&gt;
	 * each set manually or can be sorted in each set automatically, with dragging&lt;br /&gt;
	 * only being used to move them between sets.&lt;br /&gt;
	 *&lt;br /&gt;
	 * The &amp;quot;options&amp;quot; object contains:&lt;br /&gt;
	 * &amp;quot;selectors&amp;quot; is a string containing the selector of the set of elements to enable sorting,&lt;br /&gt;
	 * or an object containing containing additional selections to define the sortable element&#039;s parent&lt;br /&gt;
	 * and the sortable elements container (which elements can be sorted between).&lt;br /&gt;
	 * &amp;quot;handle&amp;quot; is a string containing the selector to find the element which the handle is a child of,&lt;br /&gt;
	 * in relation to the sortable element. Set if the handle is not a direct child of the sortable&lt;br /&gt;
	 * element.&lt;br /&gt;
	 * &amp;quot;vertical&amp;quot; is a boolean determining if the elements should only be able to be moved vertically.&lt;br /&gt;
	 * &amp;quot;autoSort&amp;quot; is a boolean determining if the elements should be sorted within their container&lt;br /&gt;
	 * automatically, only allowing elements to be manually moved between containers.&lt;br /&gt;
	 * &amp;quot;sortStart&amp;quot; is a callback function called after the placeholder and ghost elements are created,&lt;br /&gt;
	 * but prior to sorting actually beginning. &amp;quot;this&amp;quot; is set to the ghost element, and the first&lt;br /&gt;
	 * argument is set to the placeholder element if there is one.&lt;br /&gt;
	 * &amp;quot;sortEnd&amp;quot; is a callback function called after the element has been sorted, but prior to the&lt;br /&gt;
	 * placeholder and ghost elements being destroyed. Variables are set the same as &amp;quot;sortStart&amp;quot;.&lt;br /&gt;
	 */&lt;br /&gt;
	var makeSortable = function( options ) {&lt;br /&gt;
		var selectors = options.selectors;&lt;br /&gt;
		var handle = options.handle || &#039;&#039;;&lt;br /&gt;
		var vertical = options.vertical;&lt;br /&gt;
		var autoSort = options.autoSort;&lt;br /&gt;
		var selector = selectors;&lt;br /&gt;
		var $ghost = $(), $placeholder = $(), $hover = $(), $hoverParent = $();&lt;br /&gt;
		if ( typeof selectors !== &#039;string&#039; ) {&lt;br /&gt;
			selector = selectors.parent + &#039; &amp;gt; &#039; + selectors.elem;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		if ( pointerEventsSupported ) {&lt;br /&gt;
			if ( autoSort ) {&lt;br /&gt;
				$doc.on( &#039;mouseenter.spriteEdit&#039;, selectors.container, function() {&lt;br /&gt;
					if ( $ghost.length ) {&lt;br /&gt;
						$hoverParent = $( this ).css( &#039;outline&#039;, &#039;1px dashed #000&#039; );&lt;br /&gt;
					}&lt;br /&gt;
				} ).on( &#039;mouseleave.spriteEdit&#039;, selectors.container, function() {&lt;br /&gt;
					if ( $ghost.length ) {&lt;br /&gt;
						$hoverParent.css( &#039;outline&#039;, &#039;&#039; );&lt;br /&gt;
						$hoverParent = $();&lt;br /&gt;
					}&lt;br /&gt;
				} );&lt;br /&gt;
			} else {&lt;br /&gt;
				$doc.on( &#039;mouseenter.spriteEdit&#039;, selector, function() {&lt;br /&gt;
					if ( $ghost.length &amp;amp;&amp;amp; !$( this ).is( $placeholder ) ) {&lt;br /&gt;
						$hover = $( this );&lt;br /&gt;
					}&lt;br /&gt;
				} ).on( &#039;mouseleave.spriteEdit&#039;, selector, function() {&lt;br /&gt;
					if ( $ghost.length ) {&lt;br /&gt;
						$hover = $();&lt;br /&gt;
					}&lt;br /&gt;
				} );&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		$doc.on( &#039;mousedown.spriteEdit&#039;, selector + &#039; &#039; + handle + &#039; &amp;gt; .spriteedit-handle&#039;, function( e ) {&lt;br /&gt;
			if ( e.which !== 1 ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			if ( handle ) {&lt;br /&gt;
				$ghost = $( this ).closest( selector );&lt;br /&gt;
			} else {&lt;br /&gt;
				$ghost = $( this ).parent();&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			if ( $ghost.find( &#039;.spriteedit-new&#039; ).length &amp;amp;&amp;amp; $ghost.text().trim() === &#039;&#039; ) {&lt;br /&gt;
				$ghost = $();&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			tooltip.hide();&lt;br /&gt;
			&lt;br /&gt;
			// Keep the documentation from getting smaller to allow for overscroll&lt;br /&gt;
			$doc.css( &#039;min-height&#039;, $doc[0].getBoundingClientRect().height );&lt;br /&gt;
			&lt;br /&gt;
			var ghostElem = $ghost[0];&lt;br /&gt;
			&lt;br /&gt;
			if ( !autoSort ) {&lt;br /&gt;
				// We don&#039;t want to clone all the content, just the parent element&lt;br /&gt;
				$placeholder = $( &#039;&amp;lt;&#039; + ghostElem.nodeName + &#039;&amp;gt;&#039; )&lt;br /&gt;
					.addClass( ghostElem.className + &#039; spriteedit-placeholder&#039; )&lt;br /&gt;
					.insertAfter( $ghost );&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			// Calculate cursor offset percentage to apply&lt;br /&gt;
			// after the ghost is resized to its correct size&lt;br /&gt;
			var ghostRect = ghostElem.getBoundingClientRect();&lt;br /&gt;
			var cursorOffset = {&lt;br /&gt;
				top: ( ghostRect.top - e.clientY ) / ghostRect.height,&lt;br /&gt;
				left: ( ghostRect.left - e.clientX ) / ghostRect.width,&lt;br /&gt;
			};&lt;br /&gt;
			&lt;br /&gt;
			$ghost.addClass( &#039;spriteedit-ghost&#039; ).css( {&lt;br /&gt;
				top: e.clientY,&lt;br /&gt;
				left: e.clientX,&lt;br /&gt;
			} );&lt;br /&gt;
			&lt;br /&gt;
			// Apply offsets&lt;br /&gt;
			var newGhostRect = ghostElem.getBoundingClientRect();&lt;br /&gt;
			$ghost.css( {&lt;br /&gt;
				marginTop: newGhostRect.height * cursorOffset.top,&lt;br /&gt;
				marginLeft: newGhostRect.width * cursorOffset.left,&lt;br /&gt;
			} );&lt;br /&gt;
			&lt;br /&gt;
			if ( options.sortStart ) {&lt;br /&gt;
				options.sortStart.call( ghostElem, $placeholder[0] );&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			// Must be set after callback for collapsing.&lt;br /&gt;
			if ( !autoSort ) {&lt;br /&gt;
				$placeholder.css( &#039;min-height&#039;, ghostElem.getBoundingClientRect().height );&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			$ghost.parent().mouseenter();&lt;br /&gt;
			&lt;br /&gt;
			sorting = true;&lt;br /&gt;
			$root.addClass( &#039;spriteedit-sorting spriteedit-hidecontrols&#039; );&lt;br /&gt;
			&lt;br /&gt;
			requestAnimationFrame( mouseMove );&lt;br /&gt;
			&lt;br /&gt;
			e.preventDefault();&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		var mouseMove = function() {&lt;br /&gt;
			if ( !$ghost.length ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			requestAnimationFrame( mouseMove );&lt;br /&gt;
			&lt;br /&gt;
			if ( !mouse.moved ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			mouse.moved = false;&lt;br /&gt;
			&lt;br /&gt;
			var pos = { top: mouse.y };&lt;br /&gt;
			if ( !vertical ) {&lt;br /&gt;
				pos.left = mouse.x;&lt;br /&gt;
			}&lt;br /&gt;
			$ghost.css( pos );&lt;br /&gt;
			&lt;br /&gt;
			if ( !pointerEventsSupported ) {&lt;br /&gt;
				// Emulate pointer-events:none&lt;br /&gt;
				$ghost.css( &#039;visibility&#039;, &#039;hidden&#039; );&lt;br /&gt;
				var $nearest = $( document.elementFromPoint( mouse.x, mouse.y ) );&lt;br /&gt;
				if ( autoSort ) {&lt;br /&gt;
					$hoverParent.css( &#039;outline&#039;, &#039;&#039; );&lt;br /&gt;
					$hoverParent = $nearest.closest( selectors.container );&lt;br /&gt;
					$hoverParent.css( &#039;outline&#039;, &#039;1px dashed #000&#039; );&lt;br /&gt;
				} else {&lt;br /&gt;
					$hover = $nearest.closest( selector );&lt;br /&gt;
				}&lt;br /&gt;
				$ghost.css( &#039;visibility&#039;, &#039;&#039; );&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			if ( $hover.length ) {&lt;br /&gt;
				var side = &#039;Before&#039;;&lt;br /&gt;
				if ( $hover.index() &amp;gt; $placeholder.index() ) {&lt;br /&gt;
					side = &#039;After&#039;;&lt;br /&gt;
				}&lt;br /&gt;
				$placeholder[&#039;insert&#039; + side]( $hover );&lt;br /&gt;
				$hover = $();&lt;br /&gt;
			}&lt;br /&gt;
		};&lt;br /&gt;
		&lt;br /&gt;
		$( document ).on( &#039;mouseup.spriteEdit&#039;, function( e ) {&lt;br /&gt;
			if ( e.which !== 1 || !$ghost.length ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			var index = -1;&lt;br /&gt;
			if ( autoSort ) {&lt;br /&gt;
				if ( $hoverParent.length &amp;amp;&amp;amp; !$ghost.closest( selectors.container ).is( $hoverParent ) ) {&lt;br /&gt;
					var text = $ghost.attr( &#039;data-sort-key&#039; ) || $ghost.text();&lt;br /&gt;
					index = getAlphaIndex( text, undefined, $hoverParent.find( selectors.parent ) );&lt;br /&gt;
				}&lt;br /&gt;
			} else {&lt;br /&gt;
				index = $placeholder.index();&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			if (&lt;br /&gt;
				index &amp;gt; -1 &amp;amp;&amp;amp; (&lt;br /&gt;
					index - 1 !== $ghost.index() ||&lt;br /&gt;
					autoSort &amp;amp;&amp;amp; $hoverParent.length &amp;amp;&amp;amp;&lt;br /&gt;
					!$ghost.closest( selectors.container ).is( $hoverParent )&lt;br /&gt;
				)&lt;br /&gt;
			) {&lt;br /&gt;
				// If the last name is moved, delete its box&lt;br /&gt;
				if ( $ghost.hasClass( &#039;spritedoc-name&#039; ) &amp;amp;&amp;amp; !$ghost.siblings().length ) {&lt;br /&gt;
					var $box = $ghost.closest( selectors.container );&lt;br /&gt;
					change( &#039;delete&#039;, {&lt;br /&gt;
						$elem: $box,&lt;br /&gt;
						index: $box.index() - 1,&lt;br /&gt;
						$parent: $box.parent(),&lt;br /&gt;
					}, true );&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				change( &#039;insert&#039;, {&lt;br /&gt;
					$elem: $ghost,&lt;br /&gt;
					oldIndex: $ghost.index() - 1,&lt;br /&gt;
					$oldParent: $ghost.parent(),&lt;br /&gt;
					index: index - 1,&lt;br /&gt;
					$parent: $hoverParent.length &amp;amp;&amp;amp; $hoverParent.find( selectors.parent ) ||&lt;br /&gt;
						$placeholder.parent(),&lt;br /&gt;
				} );&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			$ghost.removeAttr( &#039;style&#039; ).removeClass( &#039;spriteedit-ghost&#039; );&lt;br /&gt;
			$hoverParent.css( &#039;outline&#039;, &#039;&#039; );&lt;br /&gt;
			$doc.css( &#039;min-height&#039;, &#039;&#039; );&lt;br /&gt;
			&lt;br /&gt;
			if ( options.sortEnd ) {&lt;br /&gt;
				options.sortEnd.call( $ghost[0], $placeholder[0] );&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			$placeholder.remove();&lt;br /&gt;
			$ghost = $placeholder = $hover = $hoverParent = $();&lt;br /&gt;
			&lt;br /&gt;
			sorting = false;&lt;br /&gt;
			$root.removeClass( &#039;spriteedit-sorting spriteedit-hidecontrols&#039; );&lt;br /&gt;
		} );&lt;br /&gt;
	};&lt;br /&gt;
	&lt;br /&gt;
	/**&lt;br /&gt;
	 * Allows repeatable changes to be performed, which can be undone and redone&lt;br /&gt;
	 *&lt;br /&gt;
	 * The main function performs a change of a particular type.&lt;br /&gt;
	 * &amp;quot;action&amp;quot; is the type of change this is:&lt;br /&gt;
	 * * &amp;quot;edit&amp;quot; is changes to text (anything contentEditable)&lt;br /&gt;
	 * * &amp;quot;insert&amp;quot; is any element being inserted, either fresh from the aether or taken&lt;br /&gt;
	 *   from somewhere else in the document.&lt;br /&gt;
	 * * &amp;quot;delete&amp;quot; is any element being removed from the document.&lt;br /&gt;
	 * * &amp;quot;replace image&amp;quot; is when an image is replaced with a new image.&lt;br /&gt;
	 * * &amp;quot;reset image&amp;quot; is when an image is reset to the original image in the sprite sheet.&lt;br /&gt;
	 * &amp;quot;content&amp;quot; is an object containing anything necessary to describe the change, including&lt;br /&gt;
	 * details to revert the change.&lt;br /&gt;
	 * &amp;quot;queueChange&amp;quot; is a boolean determining if the change should be queued rather than committed&lt;br /&gt;
	 * to history immediately. This allows multiple changes to be grouped as one history event. Note&lt;br /&gt;
	 * that making a change which isn&#039;t queued will commit any currently queued changes to history&lt;br /&gt;
	 * along with itself.&lt;br /&gt;
	 * &amp;quot;oldChange&amp;quot; is a boolean determining if this change shouldn&#039;t be queued. Intended mainly for&lt;br /&gt;
	 * undoing/redoing.&lt;br /&gt;
	 *&lt;br /&gt;
	 * The change.commit function allows queued changes to be committed to history.&lt;br /&gt;
	 * The change.discard function allows queued changes to be discarded, although the changes&lt;br /&gt;
	 * are not reverted.&lt;br /&gt;
	 */&lt;br /&gt;
	var change = ( function() {&lt;br /&gt;
		var queue = [];&lt;br /&gt;
		var func = function( action, content, queueChange, oldChange ) {&lt;br /&gt;
			var isBox;&lt;br /&gt;
			var $box;&lt;br /&gt;
			var $code;&lt;br /&gt;
			switch ( action ) {&lt;br /&gt;
				case &#039;edit&#039;:&lt;br /&gt;
					if ( oldChange ) {&lt;br /&gt;
						content.$elem.text( content.text );&lt;br /&gt;
					}&lt;br /&gt;
					&lt;br /&gt;
					if ( content.$elem.parent().hasClass( &#039;spritedoc-name&#039; ) ) {&lt;br /&gt;
						updateName( content.oldText, content.text, content.$elem );&lt;br /&gt;
					}&lt;br /&gt;
					&lt;br /&gt;
					names.invalidate( true );&lt;br /&gt;
				break;&lt;br /&gt;
				&lt;br /&gt;
				case &#039;insert&#039;:&lt;br /&gt;
					var moved = content.$elem.parent().length;&lt;br /&gt;
					isBox = content.$elem.hasClass( &#039;spritedoc-box&#039; );&lt;br /&gt;
					var $oldBox = !isBox &amp;amp;&amp;amp; content.$elem.closest( &#039;.spritedoc-box&#039; );&lt;br /&gt;
					&lt;br /&gt;
					if ( content.index === -1 ) {&lt;br /&gt;
						content.$parent.prepend( content.$elem );&lt;br /&gt;
					} else {&lt;br /&gt;
						content.$parent.children().eq( content.index ).after( content.$elem );&lt;br /&gt;
					}&lt;br /&gt;
					&lt;br /&gt;
					if ( !moved &amp;amp;&amp;amp; ( isBox || content.$elem.hasClass( &#039;spritedoc-section&#039; ) ) ) {&lt;br /&gt;
						content.$elem.find( &#039;.spritedoc-name&#039; ).find( &#039;code&#039; ).each( function() {&lt;br /&gt;
							updateName( undefined, $( this ).text(), $( this ) );&lt;br /&gt;
						} );&lt;br /&gt;
						if ( $doc.find( &#039;.spriteedit-new&#039; ).length ) {&lt;br /&gt;
							sheet.invalidate( true );&lt;br /&gt;
						}&lt;br /&gt;
					} else if ( content.$elem.hasClass( &#039;spritedoc-name&#039; ) ) {&lt;br /&gt;
						if ( moved ) {&lt;br /&gt;
							$box = content.$elem.closest( &#039;.spritedoc-box&#039; );&lt;br /&gt;
							if ( !$box.is( $oldBox ) ) {&lt;br /&gt;
								updateBoxSorting( $oldBox );&lt;br /&gt;
							}&lt;br /&gt;
							updateBoxSorting( $box );&lt;br /&gt;
						} else {&lt;br /&gt;
							$code = content.$elem.find( &#039;code&#039; );&lt;br /&gt;
							updateName( undefined, $code.text(), $code );&lt;br /&gt;
						}&lt;br /&gt;
					}&lt;br /&gt;
					&lt;br /&gt;
					requestAnimationFrame( function() {&lt;br /&gt;
						scrollIntoView( content.$elem );&lt;br /&gt;
					} );&lt;br /&gt;
					&lt;br /&gt;
					names.invalidate( true );&lt;br /&gt;
				break;&lt;br /&gt;
				&lt;br /&gt;
				case &#039;delete&#039;:&lt;br /&gt;
					isBox = content.$elem.hasClass( &#039;spritedoc-box&#039; );&lt;br /&gt;
					$box = !isBox &amp;amp;&amp;amp; content.$elem.closest( &#039;.spritedoc-box&#039; );&lt;br /&gt;
					&lt;br /&gt;
					content.$elem.detach();&lt;br /&gt;
					&lt;br /&gt;
					if ( isBox || content.$elem.hasClass( &#039;spritedoc-section&#039; ) ) {&lt;br /&gt;
						content.$elem.find( &#039;.spritedoc-name&#039; ).find( &#039;code&#039; ).each( function() {&lt;br /&gt;
							updateName( $( this ).text(), undefined, $( this ) );&lt;br /&gt;
						} );&lt;br /&gt;
						sheet.invalidate( !!$doc.find( &#039;.spriteedit-new&#039; ).length );&lt;br /&gt;
					} else if ( content.$elem.hasClass( &#039;spritedoc-name&#039; ) ) {&lt;br /&gt;
						$code = content.$elem.find( &#039;code&#039; );&lt;br /&gt;
						updateName( $code.text(), undefined, $code );&lt;br /&gt;
						updateBoxSorting( $box );&lt;br /&gt;
					}&lt;br /&gt;
					&lt;br /&gt;
					names.invalidate( true );&lt;br /&gt;
				break;&lt;br /&gt;
				&lt;br /&gt;
				case &#039;replace image&#039;:&lt;br /&gt;
					$box = content.$parent.parent();&lt;br /&gt;
					if ( content.$oldImg &amp;amp;&amp;amp; content.$oldImg.length ) {&lt;br /&gt;
						content.$oldImg.detach();&lt;br /&gt;
					} else {&lt;br /&gt;
						$box.addClass( &#039;spriteedit-new&#039; );&lt;br /&gt;
						content.$parent.find( &#039;.sprite&#039; ).addClass( &#039;spriteedit-replaced-image&#039; );&lt;br /&gt;
					}&lt;br /&gt;
					content.$parent.append( content.$elem );&lt;br /&gt;
					sheet.invalidate( true );&lt;br /&gt;
				break;&lt;br /&gt;
				&lt;br /&gt;
				case &#039;reset image&#039;:&lt;br /&gt;
					content.$elem.detach();&lt;br /&gt;
					content.$parent.find( &#039;.sprite&#039; ).removeClass( &#039;spriteedit-replaced-image&#039; );&lt;br /&gt;
					content.$parent.parent().removeClass( &#039;spriteedit-new&#039; );&lt;br /&gt;
					&lt;br /&gt;
					if ( !$doc.find( &#039;.spriteedit-new&#039; ).length ) {&lt;br /&gt;
						sheet.invalidate( false );&lt;br /&gt;
					}&lt;br /&gt;
				break;&lt;br /&gt;
				&lt;br /&gt;
				case &#039;toggle deprecation&#039;:&lt;br /&gt;
					content.$elem.toggleClass( &#039;spritedoc-deprecated&#039; );&lt;br /&gt;
					&lt;br /&gt;
					names.invalidate( true );&lt;br /&gt;
				break;&lt;br /&gt;
				&lt;br /&gt;
				default:&lt;br /&gt;
					console.error( &#039;Invalid action: `%s`&#039;, action );&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			var hist = { action: action, content: content };&lt;br /&gt;
			if ( !oldChange ) {&lt;br /&gt;
				queue.push( hist );&lt;br /&gt;
				if ( !queueChange ) {&lt;br /&gt;
					func.commit();&lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
		};&lt;br /&gt;
		func.commit = function() {&lt;br /&gt;
			addHistory( queue );&lt;br /&gt;
			&lt;br /&gt;
			queue = [];&lt;br /&gt;
		};&lt;br /&gt;
		func.discard = function() {&lt;br /&gt;
			queue = [];&lt;br /&gt;
			&lt;br /&gt;
			if ( !$doc.find( &#039;.spriteedit-new&#039; ).length ) {&lt;br /&gt;
				sheet.invalidate( false );&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			if ( !changes.length ) {&lt;br /&gt;
				names.invalidate( false );&lt;br /&gt;
				&lt;br /&gt;
				$.each( [&lt;br /&gt;
					&#039;#spriteedit-save&#039;,&lt;br /&gt;
					&#039;#spriteedit-summary&#039;,&lt;br /&gt;
					&#039;#spriteedit-review-button&#039;,&lt;br /&gt;
				], function() {&lt;br /&gt;
					if ( $( this ).length ) {&lt;br /&gt;
						$( this ).data( &#039;ooui-object&#039; ).setDisabled( true );&lt;br /&gt;
					}&lt;br /&gt;
				} );&lt;br /&gt;
			}&lt;br /&gt;
		};&lt;br /&gt;
		&lt;br /&gt;
		return func;&lt;br /&gt;
	}() );&lt;br /&gt;
	&lt;br /&gt;
	/**&lt;br /&gt;
	 * Adds a change to history&lt;br /&gt;
	 *&lt;br /&gt;
	 * Handles enabling the save and undo button, disabling the redo button,&lt;br /&gt;
	 * releasing undone object URLs, and deleting the undone changes.&lt;br /&gt;
	 */&lt;br /&gt;
	var addHistory = function( actions ) {&lt;br /&gt;
		changes.push( actions );&lt;br /&gt;
		&lt;br /&gt;
		if ( undoneChanges.length ) {&lt;br /&gt;
			// Release now unusable image URLs&lt;br /&gt;
			$.each( undoneChanges, function() {&lt;br /&gt;
				if ( this.action === &#039;replace image&#039; ) {&lt;br /&gt;
					URL.revokeObjectURL( this.content.$elem.attr( &#039;src&#039; ) );&lt;br /&gt;
				}&lt;br /&gt;
			} );&lt;br /&gt;
			&lt;br /&gt;
			undoneChanges = [];&lt;br /&gt;
			&lt;br /&gt;
			$( &#039;#spriteedit-redo&#039; ).data( &#039;ooui-object&#039; ).setDisabled( true );&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		$.each( [&lt;br /&gt;
			&#039;#spriteedit-undo&#039;,&lt;br /&gt;
			&#039;#spriteedit-save&#039;,&lt;br /&gt;
			&#039;#spriteedit-summary&#039;,&lt;br /&gt;
			&#039;#spriteedit-review-button&#039;,&lt;br /&gt;
		], function() {&lt;br /&gt;
			if ( $( this ).length ) {&lt;br /&gt;
				$( this ).data( &#039;ooui-object&#039; ).setDisabled( false );&lt;br /&gt;
			}&lt;br /&gt;
		} );&lt;br /&gt;
	};&lt;br /&gt;
	&lt;br /&gt;
	/**&lt;br /&gt;
	 * Reverts a change&lt;br /&gt;
	 *&lt;br /&gt;
	 * Takes a previously stored history entry and performs the necessary change&lt;br /&gt;
	 * to revert it.&lt;br /&gt;
	 */&lt;br /&gt;
	var revert = function( hist ) {&lt;br /&gt;
		// Invert the history entry&#039;s changes to revert it&lt;br /&gt;
		var i = hist.length, histChange, content;&lt;br /&gt;
		while ( i-- ) {&lt;br /&gt;
			histChange = hist[i];&lt;br /&gt;
			content = histChange.content;&lt;br /&gt;
			switch( histChange.action ) {&lt;br /&gt;
				case &#039;edit&#039;:&lt;br /&gt;
					change( &#039;edit&#039;, {&lt;br /&gt;
						$elem: content.$elem,&lt;br /&gt;
						text: content.oldText,&lt;br /&gt;
						oldText: content.text,&lt;br /&gt;
					}, false, true );&lt;br /&gt;
				break;&lt;br /&gt;
				&lt;br /&gt;
				case &#039;insert&#039;:&lt;br /&gt;
					if ( content.$oldParent ) {&lt;br /&gt;
						change( &#039;insert&#039;, {&lt;br /&gt;
							$elem: content.$elem,&lt;br /&gt;
							index: content.oldIndex,&lt;br /&gt;
							$parent: content.$oldParent,&lt;br /&gt;
						}, false, true );&lt;br /&gt;
					} else {&lt;br /&gt;
						change( &#039;delete&#039;, {&lt;br /&gt;
							$elem: content.$elem,&lt;br /&gt;
							$parent: content.$parent,&lt;br /&gt;
						}, false, true );&lt;br /&gt;
					}&lt;br /&gt;
				break;&lt;br /&gt;
				&lt;br /&gt;
				case &#039;delete&#039;:&lt;br /&gt;
					change( &#039;insert&#039;, {&lt;br /&gt;
						$elem: content.$elem,&lt;br /&gt;
						index: content.index,&lt;br /&gt;
						$parent: content.$parent,&lt;br /&gt;
					}, false, true );&lt;br /&gt;
				break;&lt;br /&gt;
				&lt;br /&gt;
				case &#039;replace image&#039;:&lt;br /&gt;
					if ( content.$oldImg.length ) {&lt;br /&gt;
						change( &#039;replace image&#039;, {&lt;br /&gt;
							$elem: content.$oldImg,&lt;br /&gt;
							$parent: content.$parent,&lt;br /&gt;
							$oldImg: content.$elem,&lt;br /&gt;
						}, false, true );&lt;br /&gt;
					} else {&lt;br /&gt;
						change( &#039;reset image&#039;, content, false, true );&lt;br /&gt;
					}&lt;br /&gt;
				break;&lt;br /&gt;
				&lt;br /&gt;
				case &#039;reset image&#039;:&lt;br /&gt;
					change( &#039;replace image&#039;, content, false, true );&lt;br /&gt;
				break;&lt;br /&gt;
				&lt;br /&gt;
				case &#039;toggle deprecation&#039;:&lt;br /&gt;
					change( &#039;toggle deprecation&#039;, content, false, true );&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		if ( !$doc.find( &#039;.spriteedit-new&#039; ).length ) {&lt;br /&gt;
			sheet.invalidate( false );&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		if ( !changes.length ) {&lt;br /&gt;
			names.invalidate( false );&lt;br /&gt;
			&lt;br /&gt;
			$.each( [&lt;br /&gt;
				&#039;#spriteedit-undo&#039;,&lt;br /&gt;
				&#039;#spriteedit-save&#039;,&lt;br /&gt;
				&#039;#spriteedit-summary&#039;,&lt;br /&gt;
				&#039;#spriteedit-review-button&#039;,&lt;br /&gt;
			], function() {&lt;br /&gt;
				if ( $( this ).length ) {&lt;br /&gt;
					$( this ).data( &#039;ooui-object&#039; ).setDisabled( true );&lt;br /&gt;
				}&lt;br /&gt;
			} );&lt;br /&gt;
		}&lt;br /&gt;
	};&lt;br /&gt;
	&lt;br /&gt;
	/**&lt;br /&gt;
	 * Updates the list of names for duplicate detection&lt;br /&gt;
	 *&lt;br /&gt;
	 * Also sorts the names and box if necessary.&lt;br /&gt;
	 */&lt;br /&gt;
	var updateName = function( oldText, newText, $elem ) {&lt;br /&gt;
		if ( oldText ) {&lt;br /&gt;
			var oldNames = usedNames[oldText];&lt;br /&gt;
			if ( oldNames.length === 1 ) {&lt;br /&gt;
				delete usedNames[oldText];&lt;br /&gt;
			} else {&lt;br /&gt;
				$.each( oldNames, function( i ) {&lt;br /&gt;
					if ( $elem.is( this ) ) {&lt;br /&gt;
						oldNames.splice( i, 1 );&lt;br /&gt;
						return false;&lt;br /&gt;
					}&lt;br /&gt;
				} );&lt;br /&gt;
				if ( oldNames.length === 1 ) {&lt;br /&gt;
					oldNames[0].removeClass( &#039;spriteedit-dupe&#039; );&lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		var $item = $elem.parent();&lt;br /&gt;
		var oldIndex = $item.index();&lt;br /&gt;
		if ( newText ) {&lt;br /&gt;
			var newNames = usedNames[newText];&lt;br /&gt;
			if ( !newNames ) {&lt;br /&gt;
				newNames = usedNames[newText] = [];&lt;br /&gt;
				$elem.removeClass( &#039;spriteedit-dupe&#039; );&lt;br /&gt;
			} else {&lt;br /&gt;
				if ( newNames.length === 1 ) {&lt;br /&gt;
					newNames[0].addClass( &#039;spriteedit-dupe&#039; );&lt;br /&gt;
				}&lt;br /&gt;
				$elem.addClass( &#039;spriteedit-dupe&#039; );&lt;br /&gt;
			}&lt;br /&gt;
			newNames.push( $elem );&lt;br /&gt;
			&lt;br /&gt;
			var $parent = $item.parent();&lt;br /&gt;
			var index = getAlphaIndex( newText, $item );&lt;br /&gt;
			if ( index !== oldIndex ) {&lt;br /&gt;
				change( &#039;insert&#039;, {&lt;br /&gt;
					$elem: $item,&lt;br /&gt;
					oldIndex: oldIndex - 1,&lt;br /&gt;
					$oldParent: $parent,&lt;br /&gt;
					index: index - 1,&lt;br /&gt;
					$parent: $parent,&lt;br /&gt;
				}, false, true );&lt;br /&gt;
			} else if ( index === 0 ) {&lt;br /&gt;
				updateBoxSorting( $item.closest( &#039;.spritedoc-box&#039; ) );&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	};&lt;br /&gt;
	&lt;br /&gt;
	/**&lt;br /&gt;
	 * Updates the box&#039;s sort key and sorts it.&lt;br /&gt;
	 */&lt;br /&gt;
	var updateBoxSorting = function( $box ) {&lt;br /&gt;
		var name = $box.find( &#039;.spritedoc-name&#039; ).first().text();&lt;br /&gt;
		var oldName = $box.attr( &#039;data-sort-key&#039; );&lt;br /&gt;
		if ( name === oldName ) {&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		$box.attr( &#039;data-sort-key&#039;, name );&lt;br /&gt;
		&lt;br /&gt;
		var $parent = $box.parent();&lt;br /&gt;
		var oldIndex = $box.index();&lt;br /&gt;
		var index = getAlphaIndex( name, $box );&lt;br /&gt;
		if ( index !== oldIndex ) {&lt;br /&gt;
			change( &#039;insert&#039;, {&lt;br /&gt;
				$elem: $box,&lt;br /&gt;
				oldIndex: oldIndex - 1,&lt;br /&gt;
				$oldParent: $parent,&lt;br /&gt;
				index: index - 1,&lt;br /&gt;
				$parent: $parent,&lt;br /&gt;
			}, false, true );&lt;br /&gt;
		}&lt;br /&gt;
	};&lt;br /&gt;
	&lt;br /&gt;
	/**&lt;br /&gt;
	 * Picks the section which is probably the section the user wants to put things&lt;br /&gt;
	 *&lt;br /&gt;
	 * Mainly based on the section closest to the top of the screen,&lt;br /&gt;
	 * but prefers elements which are not at all going off the screen&lt;br /&gt;
	 * (accounting for the space taken up by the toolbar).&lt;br /&gt;
	 *&lt;br /&gt;
	 * Returns the section element&lt;br /&gt;
	 */&lt;br /&gt;
	var nearestSection = function() {&lt;br /&gt;
		var offscreen, prox, elem;&lt;br /&gt;
		$doc.find( &#039;.spritedoc-section&#039; ).each( function() {&lt;br /&gt;
			var curPos = this.getBoundingClientRect().top - 35;&lt;br /&gt;
			var curProx = Math.abs( curPos );&lt;br /&gt;
			if ( prox &amp;amp;&amp;amp; curProx &amp;gt; prox ) {&lt;br /&gt;
				// Prefer on-screen section, even if it is further from the top&lt;br /&gt;
				if ( offscreen ) {&lt;br /&gt;
					elem = this;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				return false;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			offscreen = curPos &amp;lt; 0;&lt;br /&gt;
			prox = curProx;&lt;br /&gt;
			elem = this;&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		return elem;&lt;br /&gt;
	};&lt;br /&gt;
	&lt;br /&gt;
	/**&lt;br /&gt;
	 * Destroys the editor&lt;br /&gt;
	 *&lt;br /&gt;
	 * Removes any controls, and unbinds all events in the spriteEdit namespace, and releases&lt;br /&gt;
	 * object URLs.&lt;br /&gt;
	 *&lt;br /&gt;
	 * &amp;quot;restore&amp;quot; is a boolean determining if the documentation should be restored to how it was&lt;br /&gt;
	 * prior to opening the editor.&lt;br /&gt;
	 * &amp;quot;leaveUrl&amp;quot; is a boolean determining if a the page URL shouldn&#039;t be updated to remove the&lt;br /&gt;
	 * spriteedit action. Used for when the editor is destroyed due to history navigation.&lt;br /&gt;
	 */&lt;br /&gt;
	var destroy = function( restore, leaveUrl ) {&lt;br /&gt;
		document.title = originalTitle;&lt;br /&gt;
		&lt;br /&gt;
		// Disable close confirm dialog&lt;br /&gt;
		preventClose &amp;amp;&amp;amp; preventClose.release();&lt;br /&gt;
		&lt;br /&gt;
		$win.add( document ).off( &#039;.spriteEdit&#039; );&lt;br /&gt;
		&lt;br /&gt;
		if ( !leaveUrl ) {&lt;br /&gt;
			history.pushState( {}, &#039;&#039;, mw.util.getUrl() );&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		var enabled = $root.hasClass( &#039;spriteedit-enabled&#039; );&lt;br /&gt;
		&lt;br /&gt;
		$root.removeClass( &#039;spriteedit-loaded spriteedit-enabled spriteedit-imageeditingenabled spriteedit-hidecontrols&#039; );&lt;br /&gt;
		&lt;br /&gt;
		var $viewTab = $( &#039;#ca-view&#039; );&lt;br /&gt;
		$viewTab.add( &#039;#ca-spriteedit&#039; ).toggleClass( &#039;selected&#039; );&lt;br /&gt;
		&lt;br /&gt;
		$doc.add( $viewTab.find( &#039;a&#039; ) ).off( &#039;.spriteEdit&#039; );&lt;br /&gt;
		&lt;br /&gt;
		if ( restore ) {&lt;br /&gt;
			overwriteSpritesheet.disable();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		// No further cleanup necessary&lt;br /&gt;
		if ( !enabled ) {&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		$( &#039;.mw-editsection&#039; ).add( &#039;.mw-editsection-like&#039; ).css( &#039;display&#039;, &#039;&#039; );&lt;br /&gt;
		&lt;br /&gt;
		// Release old image URL references&lt;br /&gt;
		if ( sheet.modified ) {&lt;br /&gt;
			$.each( changes, function() {&lt;br /&gt;
				if ( this.action === &#039;replace image&#039; ) {&lt;br /&gt;
					URL.revokeObjectURL( this.content.$oldImg.attr( &#039;src&#039; ) );&lt;br /&gt;
				}&lt;br /&gt;
			} );&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		if ( restore ) {&lt;br /&gt;
			// Release current image URL references&lt;br /&gt;
			if ( sheet.modified ) {&lt;br /&gt;
				$doc.find( &#039;.spritedoc-image&#039; ).find( &#039;img&#039; ).each( function() {&lt;br /&gt;
					URL.revokeObjectURL( this.src );&lt;br /&gt;
				} );&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			$doc.replaceWith( oldHtml );&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		$doc.find( &#039;.mw-headline&#039; ).add( $doc.find( &#039;.spritedoc-name&#039; ).find( &#039;code&#039; ) )&lt;br /&gt;
			.removeAttr( &#039;contenteditable&#039; );&lt;br /&gt;
		&lt;br /&gt;
		$.each( [&lt;br /&gt;
			&#039;.spriteedit-toolbar-container&#039;,&lt;br /&gt;
			&#039;.spriteedit-handle&#039;,&lt;br /&gt;
			&#039;.spriteedit-add-name&#039;,&lt;br /&gt;
			&#039;.spriteedit-tooltip&#039;,&lt;br /&gt;
			&#039;.spriteedit-dialog-overlay&#039;,&lt;br /&gt;
		], function() {&lt;br /&gt;
			$( this ).remove();&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		$( &#039;.spriteedit-new&#039; ).removeClass( &#039;spriteedit-new&#039; ).each( function() {&lt;br /&gt;
			var newPos = $( this ).data( &#039;new-pos&#039; );&lt;br /&gt;
			if ( newPos !== undefined ) {&lt;br /&gt;
				$( this ).data( &#039;pos&#039;, newPos ).removeData( &#039;new-pos&#039; );&lt;br /&gt;
			}&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		$doc.find( &#039;.spriteedit-replaced-image&#039; ).removeClass( &#039;spriteedit-replaced-image&#039; );&lt;br /&gt;
		$doc.find( &#039;.spriteedit-replacing-image&#039; ).remove();&lt;br /&gt;
	};&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/** Utility functions **/&lt;br /&gt;
/**&lt;br /&gt;
 * Allows calling a function when a main transition ends&lt;br /&gt;
 *&lt;br /&gt;
 * This only listens to transitions that happen on the element this is&lt;br /&gt;
 * called on, ignoring transitions bubbling from its children.&lt;br /&gt;
 * Additionally, if the browser doesn&#039;t support transitions, the callback&lt;br /&gt;
 * will be called immediately.&lt;br /&gt;
 *&lt;br /&gt;
 * The callback is passed along the &amp;quot;this&amp;quot; and &amp;quot;event&amp;quot; object from the event.&lt;br /&gt;
 */&lt;br /&gt;
$.fn.transitionEnd = function( callback ) {&lt;br /&gt;
	if ( supports( &#039;transition&#039; ) ) {&lt;br /&gt;
		this.on( &#039;transitionend.spriteEdit&#039;, function( e ) {&lt;br /&gt;
			var $elem = $( this );&lt;br /&gt;
			if ( !$elem.is( e.target ) ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			callback.call( this, e );&lt;br /&gt;
			&lt;br /&gt;
			$elem.off( &#039;transitionend.spriteEdit&#039; );&lt;br /&gt;
		} );&lt;br /&gt;
	} else {&lt;br /&gt;
		this.each( function() {&lt;br /&gt;
			callback.call( this );&lt;br /&gt;
		} );&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	return this;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Forces the browser to redraw an element&lt;br /&gt;
 */&lt;br /&gt;
$.fn.redraw = function() {&lt;br /&gt;
	this.each( function() {&lt;br /&gt;
		this.offsetWidth;&lt;br /&gt;
	} );&lt;br /&gt;
	&lt;br /&gt;
	return this;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Returns the index to move an element to to sort it alphabetically, ignoring case&lt;br /&gt;
 *&lt;br /&gt;
 * &amp;quot;text&amp;quot; is the string to sort by.&lt;br /&gt;
 * &amp;quot;$elem&amp;quot; is the jQuery object which is to be sorted&lt;br /&gt;
 * &amp;quot;$parent&amp;quot; is the jQuery object which is the parent of the elements which &amp;quot;text&amp;quot; will be sorted by.&lt;br /&gt;
 *&lt;br /&gt;
 * Use &amp;quot;$elem&amp;quot; when sorting an element by its siblings.&lt;br /&gt;
 * Use &amp;quot;$parent&amp;quot; when sorting an element in a different container.&lt;br /&gt;
 */&lt;br /&gt;
var getAlphaIndex = function( text, $elem, $parent ) {&lt;br /&gt;
	var index;&lt;br /&gt;
	var $items = $parent ? $parent.children() : $elem.siblings();&lt;br /&gt;
	$items.each( function() {&lt;br /&gt;
		var $this = $( this );&lt;br /&gt;
		var compare = $this.attr( &#039;data-sort-key&#039; ) || $this.text();&lt;br /&gt;
		if ( text.toLowerCase() &amp;lt; compare.toLowerCase() ) {&lt;br /&gt;
			index = $this.index();&lt;br /&gt;
			return false;&lt;br /&gt;
		}&lt;br /&gt;
	} );&lt;br /&gt;
	if ( index === undefined ) {&lt;br /&gt;
		if ( $items.length ) {&lt;br /&gt;
			index = $items.length;&lt;br /&gt;
			if ( !$parent ) {&lt;br /&gt;
				index++;&lt;br /&gt;
			}&lt;br /&gt;
		} else {&lt;br /&gt;
			index = 0;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	// Account for trying to sort the element after itself&lt;br /&gt;
	if ( !$parent &amp;amp;&amp;amp; index - 1 === $elem.index() ) {&lt;br /&gt;
		index--;&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	return index;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Attempts to scroll an element into view&lt;br /&gt;
 *&lt;br /&gt;
 * Takes into account the portion of window obscured by the toolbar.&lt;br /&gt;
 * Flashes the element&#039;s background yellow for a moment to bring it to attention.&lt;br /&gt;
 *&lt;br /&gt;
 * &amp;quot;$elem&amp;quot; is the jQuery object to scroll to.&lt;br /&gt;
 * &amp;quot;instant&amp;quot; is a boolean determining if the scrolling should be instant, instead of smooth&lt;br /&gt;
 * (if the browser supports smooth scrolling in the first place, that is).&lt;br /&gt;
 */&lt;br /&gt;
var scrollIntoView = function( $elem, instant ) {&lt;br /&gt;
	var elemRect = $elem[0].getBoundingClientRect();&lt;br /&gt;
	var toolbarHeight = $( &#039;.spriteedit-toolbar&#039; )[0].getBoundingClientRect().height;&lt;br /&gt;
	var scrollPos;&lt;br /&gt;
	if ( elemRect.top - toolbarHeight &amp;lt; 10 ) {&lt;br /&gt;
		scrollPos = elemRect.top + $win.scrollTop() - toolbarHeight - 10;&lt;br /&gt;
	} else {&lt;br /&gt;
		var winHeight = $win.height() - 40;&lt;br /&gt;
		if ( elemRect.height &amp;gt; winHeight || elemRect.bottom &amp;lt; winHeight ) {&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
		scrollPos = elemRect.bottom + $win.scrollTop() - winHeight;&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	if ( !instant ) {&lt;br /&gt;
		$root.addClass( &#039;spriteedit-smoothscroll&#039; );&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	scroll( 0, scrollPos );&lt;br /&gt;
	$elem.css( &#039;background-color&#039;, &#039;yellow&#039; );&lt;br /&gt;
	setTimeout( function() {&lt;br /&gt;
		$elem.css( &#039;background-color&#039;, &#039;&#039; );&lt;br /&gt;
	}, 1000 );&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Converts the extended ISO UTC timestamp returned by the API&lt;br /&gt;
 * into the MediaWiki format in the wiki&#039;s timezone&lt;br /&gt;
 *&lt;br /&gt;
 * YYYY-MM-DDTHH:MM:SSZ -&amp;gt; YYYYMMDDHHMMSS&lt;br /&gt;
 */&lt;br /&gt;
var fixTimestamp = function( timestamp ) {&lt;br /&gt;
	// Make UTC date&lt;br /&gt;
	var date = new Date( timestamp );&lt;br /&gt;
	// Convert to wiki&#039;s timezone&lt;br /&gt;
	date.setTime( date.getTime() + fixTimestamp.offset * 60 * 1000 );&lt;br /&gt;
	// Return MW timestamp format&lt;br /&gt;
	return date.toISOString().replace( /[\-T:]|\.\d+Z/g, &#039;&#039; );&lt;br /&gt;
};&lt;br /&gt;
// This will be set when the editor is created and a siteinfo request is made&lt;br /&gt;
fixTimestamp.offset = 0;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Add various types of in-page controls to a set of elements&lt;br /&gt;
 *&lt;br /&gt;
 * &amp;quot;$elems&amp;quot; is a jQuery object containing the elements to add controls to.&lt;br /&gt;
 * &amp;quot;type&amp;quot; is the type of controls to add.&lt;br /&gt;
 */&lt;br /&gt;
var addControls = function( $elems, type ) {&lt;br /&gt;
	switch ( type ) {&lt;br /&gt;
		case &#039;heading&#039;:&lt;br /&gt;
			$elems.prepend( $( &#039;&amp;lt;span&amp;gt;&#039; ).addClass( &#039;spriteedit-handle&#039; ) )&lt;br /&gt;
				.find( &#039;.mw-headline&#039; ).attr( &#039;contenteditable&#039;, true );&lt;br /&gt;
		break;&lt;br /&gt;
		case &#039;box&#039;:&lt;br /&gt;
			$elems.each( function(){&lt;br /&gt;
				var addNameButton = new OO.ui.ButtonInputWidget( {&lt;br /&gt;
					classes: [ &#039;spriteedit-add-name&#039; ],&lt;br /&gt;
					framed: false,&lt;br /&gt;
					icon: &#039;add&#039;,&lt;br /&gt;
					title: i18n.controlNewName,&lt;br /&gt;
				} );&lt;br /&gt;
				addNameButton.$element.data( &#039;ooui-object&#039;, addNameButton );&lt;br /&gt;
				$( this ).prepend(&lt;br /&gt;
					$( &#039;&amp;lt;span&amp;gt;&#039; ).addClass( &#039;spriteedit-handle&#039; ),&lt;br /&gt;
					addNameButton.$element&lt;br /&gt;
				);&lt;br /&gt;
			} );&lt;br /&gt;
			addControls( $elems.find( &#039;.spritedoc-name&#039; ), &#039;name&#039; );&lt;br /&gt;
		break;&lt;br /&gt;
		case &#039;name&#039;:&lt;br /&gt;
			$elems.find( &#039;code&#039; ).attr( &#039;contenteditable&#039;, true );&lt;br /&gt;
		break;&lt;br /&gt;
	}&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Create an OOUI button widget&lt;br /&gt;
 *&lt;br /&gt;
 * &amp;quot;text&amp;quot; is the string displayed on the button.&lt;br /&gt;
 * &amp;quot;config&amp;quot; is an object defining various properties of the button:&lt;br /&gt;
 * * &amp;quot;type&amp;quot; is a string or array of strings defining the OOUI flags&lt;br /&gt;
 *   this button should use (e.g.: progressive, destructive, primary).&lt;br /&gt;
 * * &amp;quot;id&amp;quot; is the id attribute applied to the button.&lt;br /&gt;
 * * &amp;quot;icon&amp;quot; is the OOUI icon to use&lt;br /&gt;
 * * &amp;quot;action&amp;quot; is a function called when the button is clicked.&lt;br /&gt;
 */&lt;br /&gt;
var makeButton = function( text, config ) {&lt;br /&gt;
	var button = new OO.ui.ButtonInputWidget( {&lt;br /&gt;
		flags: config.type,&lt;br /&gt;
		id: config.id,&lt;br /&gt;
		label: text,&lt;br /&gt;
		icon: config.icon,&lt;br /&gt;
		title: config.title,&lt;br /&gt;
	} );&lt;br /&gt;
	&lt;br /&gt;
	if ( config.action ) {&lt;br /&gt;
		button.$button.on( &#039;click.spriteEdit&#039;, function( e ) {&lt;br /&gt;
			$( this ).focus().blur();&lt;br /&gt;
			config.action.call( this, e );&lt;br /&gt;
		} );&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	button.$element.data( &#039;ooui-object&#039;, button );&lt;br /&gt;
	&lt;br /&gt;
	return button.$element;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Check if a CSS property or value is supported by the browser&lt;br /&gt;
 */&lt;br /&gt;
var supports = function( prop, val ) {&lt;br /&gt;
	if ( !val ) {&lt;br /&gt;
		return prop in $root[0].style;&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	if ( window.CSS &amp;amp;&amp;amp; CSS.supports ) {&lt;br /&gt;
		return CSS.supports( prop, val );&lt;br /&gt;
	}&lt;br /&gt;
	if ( window.supportsCSS ) {&lt;br /&gt;
		return supportsCSS( prop, val );&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	var camelProp = prop.replace( /-([a-z]|[0-9])/ig, function( _, chr ) {&lt;br /&gt;
		return chr.toUpperCase();&lt;br /&gt;
	} );&lt;br /&gt;
	var elStyle = document.createElement( &#039;i&#039; ).style;&lt;br /&gt;
	elStyle.cssText = prop + &#039;:&#039; + val;&lt;br /&gt;
	return elStyle[camelProp] !== &#039;&#039;;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Retries a request once if it fails&lt;br /&gt;
 *&lt;br /&gt;
 * Always returns an abortable promise, even if the request itself isn&#039;t abortable.&lt;br /&gt;
 *&lt;br /&gt;
 * &amp;quot;request&amp;quot; is a function which will run the request,&lt;br /&gt;
 * and should return the request&#039;s promise.&lt;br /&gt;
 * &amp;quot;delay&amp;quot; is the amount of milliseconds to wait before retrying.&lt;br /&gt;
 * &amp;quot;retries&amp;quot; is the amount of times to retry&lt;br /&gt;
 */&lt;br /&gt;
var retryableRequest = function( request, delay, retries ) {&lt;br /&gt;
	var deferred = $.Deferred();&lt;br /&gt;
	var curRequest;&lt;br /&gt;
	var timeout;&lt;br /&gt;
	retries = retries || 1;&lt;br /&gt;
	var attemptRequest = function( attempt ) {&lt;br /&gt;
		( curRequest = request() ).then( deferred.resolve, function( code, data ) {&lt;br /&gt;
			if ( attempt &amp;lt;= retries ) {&lt;br /&gt;
				timeout = setTimeout( function() {&lt;br /&gt;
					attemptRequest( ++attempt );&lt;br /&gt;
				}, delay || 1000 );&lt;br /&gt;
			} else {&lt;br /&gt;
				deferred.reject( code, data );&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
		} );&lt;br /&gt;
	};&lt;br /&gt;
	attemptRequest( 1 );&lt;br /&gt;
	&lt;br /&gt;
	return deferred.promise( { abort: function() {&lt;br /&gt;
		if ( curRequest.abort ) {&lt;br /&gt;
			curRequest.abort();&lt;br /&gt;
		}&lt;br /&gt;
		clearTimeout( timeout );&lt;br /&gt;
	} } );&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Handles generic API errors&lt;br /&gt;
 *&lt;br /&gt;
 * Just uselessly displays whatever error the API returns.&lt;br /&gt;
 * Hopefully the user can retry whatever they were doing.&lt;br /&gt;
 *&lt;br /&gt;
 * &amp;quot;code&amp;quot; and &amp;quot;data&amp;quot; are the standard variables returned by a mw.Api promise rejection.&lt;br /&gt;
 */&lt;br /&gt;
var handleError = function( code, data ) {&lt;br /&gt;
	var errorTitle = i18n.errorGeneric;&lt;br /&gt;
	var errorText;&lt;br /&gt;
	if ( code === &#039;http&#039; ) {&lt;br /&gt;
		// Not an error&lt;br /&gt;
		if ( data.textStatus === &#039;abort&#039; ) {&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		if ( data.textStatus === &#039;error&#039; || data.textStatus === &#039;timeout&#039; ) {&lt;br /&gt;
			errorTitle = i18n.errorConnection;&lt;br /&gt;
			errorText = i18n.errorConnectionText;&lt;br /&gt;
		} else {&lt;br /&gt;
			errorTitle = i18n.errorHttp;&lt;br /&gt;
			errorText = data.textStatus;&lt;br /&gt;
		}&lt;br /&gt;
	} else {&lt;br /&gt;
		errorTitle = i18n.errorApi;&lt;br /&gt;
		errorText = data.error.info;&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	mw.notify( errorText, { title: errorTitle, type: &#039;error&#039;, autoHide: false } );&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Looks for the specified change tag&lt;br /&gt;
 * &lt;br /&gt;
 * Returns a promise which resolves to a boolean stating if the tag is active or not,&lt;br /&gt;
 * or null if the tag doesn&#039;t exist.&lt;br /&gt;
 * &lt;br /&gt;
 * &amp;quot;tag&amp;quot; is the tag to search for.&lt;br /&gt;
 * &amp;quot;options&amp;quot; is an object of additional values to add to the request.&lt;br /&gt;
 */&lt;br /&gt;
var findChangeTag = function( tag, options ) {&lt;br /&gt;
	return retryableRequest( function() {&lt;br /&gt;
		return new mw.Api().get( $.extend( {&lt;br /&gt;
			action: &#039;query&#039;,&lt;br /&gt;
			list: &#039;tags&#039;,&lt;br /&gt;
			tgprop: &#039;active&#039;,&lt;br /&gt;
			tglimit: &#039;max&#039;,&lt;br /&gt;
			formatversion: 2,&lt;br /&gt;
		}, options || {} ) );&lt;br /&gt;
	} ).then( function( data ) {&lt;br /&gt;
		var foundActive = null;&lt;br /&gt;
		$.each( data.query.tags, function() {&lt;br /&gt;
			if ( this.name === tag ) {&lt;br /&gt;
				foundActive = this.active;&lt;br /&gt;
				return false;&lt;br /&gt;
			}&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		// XXX: MW JS requires ES5 support, but JavascriptMinifier doesn&#039;t&lt;br /&gt;
		// support ES5, so these have to remain strings. See T96901&lt;br /&gt;
		if ( foundActive === null &amp;amp;&amp;amp; data[&#039;continue&#039;] ) {&lt;br /&gt;
			return findChangeTag( tag, data[&#039;continue&#039;] );&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		return foundActive;&lt;br /&gt;
	} );&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Replaces the spritesheet with the provided URL&lt;br /&gt;
 * &lt;br /&gt;
 * It&#039;s assumed the URL will be an object URL, which it handles revoking&lt;br /&gt;
 * if the spritesheet is replaced again or disabled.&lt;br /&gt;
 * &lt;br /&gt;
 * The current style element can be accessed from `overwriteSpritesheet.style`.&lt;br /&gt;
 */&lt;br /&gt;
var overwriteSpritesheet = function( url ) {&lt;br /&gt;
	overwriteSpritesheet.disable();&lt;br /&gt;
	overwriteSpritesheet.style = mw.util.addCSS(&lt;br /&gt;
		&#039;#spritedoc .sprite { background-image: url(&#039; + url + &#039;) !important }&#039;&lt;br /&gt;
	);&lt;br /&gt;
	overwriteSpritesheet.style.url = url;&lt;br /&gt;
};&lt;br /&gt;
/**&lt;br /&gt;
 * Disables the current style so its styles don&#039;t apply&lt;br /&gt;
 * and revokes the object URL.&lt;br /&gt;
 */&lt;br /&gt;
overwriteSpritesheet.disable = function() {&lt;br /&gt;
	var inlineStyle = overwriteSpritesheet.style;&lt;br /&gt;
	if ( inlineStyle ) {&lt;br /&gt;
		inlineStyle.disabled = true;&lt;br /&gt;
		URL.revokeObjectURL( inlineStyle.url );&lt;br /&gt;
	}&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var luaTable = {};&lt;br /&gt;
/** Recursively creates a pretty printed lua table from an object&lt;br /&gt;
 * &lt;br /&gt;
 * Supports only the value which `luaTable.createValue` supports, and&lt;br /&gt;
 * only numbers and strings as keys.&lt;br /&gt;
 * &lt;br /&gt;
 * Objects with less than 4 keys and with no sub-objects will be&lt;br /&gt;
 * on a single line, otherwise will be one line per value.&lt;br /&gt;
 */&lt;br /&gt;
luaTable.create = function( obj, indent ) {&lt;br /&gt;
	indent = indent || 1;&lt;br /&gt;
	var out = [ &#039;{&#039; ];&lt;br /&gt;
	var isArray = Array.isArray( obj );&lt;br /&gt;
	var size = isArray ? obj.length : Object.keys( obj ).length;&lt;br /&gt;
	var containsObject;&lt;br /&gt;
	$.each( obj, function( k, v ) {&lt;br /&gt;
		if ( typeof v === &#039;object&#039; ) {&lt;br /&gt;
			containsObject = true;&lt;br /&gt;
			return false;&lt;br /&gt;
		}&lt;br /&gt;
	} );&lt;br /&gt;
	var multiline = containsObject || size &amp;gt; 3;&lt;br /&gt;
	&lt;br /&gt;
	$.each( obj, function( k, v ) {&lt;br /&gt;
		if ( v === null || v === undefined ) {&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
		var key = isArray ? &#039;&#039; : luaTable.createKey( k ) + &#039; = &#039;;&lt;br /&gt;
		out.push( &#039;\t&#039;.repeat( multiline * indent ) + key + luaTable.createValue( v, indent + 1 ) + &#039;,&#039; );&lt;br /&gt;
	} );&lt;br /&gt;
	// No trailing commas for single line objects&lt;br /&gt;
	if ( !multiline ) {&lt;br /&gt;
		out.push( out.pop().slice( 0, -1 ) );&lt;br /&gt;
	}&lt;br /&gt;
	out.push( &#039;\t&#039;.repeat( multiline * --indent ) + &#039;}&#039; );&lt;br /&gt;
	&lt;br /&gt;
	return out.join( multiline ? &#039;\n&#039; : &#039; &#039; );&lt;br /&gt;
};&lt;br /&gt;
/** Allows creating a string that should be considered a lua function&lt;br /&gt;
 * &lt;br /&gt;
 * &amp;quot;funcStr&amp;quot; should be the exact value to be output as&lt;br /&gt;
 * in the table.&lt;br /&gt;
 * &lt;br /&gt;
 * Returns a function that will be converted back in to&lt;br /&gt;
 * the specified string when building the table.&lt;br /&gt;
 */&lt;br /&gt;
luaTable.func = function( funcStr ) {&lt;br /&gt;
	var f = function() {&lt;br /&gt;
		return funcStr;&lt;br /&gt;
	};&lt;br /&gt;
	f.luaFunc = true;&lt;br /&gt;
	return f;&lt;br /&gt;
};&lt;br /&gt;
/**&lt;br /&gt;
 * List of reserved keywords in lua&lt;br /&gt;
 */&lt;br /&gt;
luaTable.keywords = [&lt;br /&gt;
	&#039;and&#039;, &#039;break&#039;, &#039;do&#039;, &#039;else&#039;, &#039;elseif&#039;, &#039;end&#039;, &#039;false&#039;, &#039;for&#039;, &#039;function&#039;,&lt;br /&gt;
	&#039;if&#039;, &#039;in&#039;, &#039;local&#039;, &#039;nil&#039;, &#039;not&#039;, &#039;or&#039;, &#039;repeat&#039;, &#039;return&#039;, &#039;then&#039;,&lt;br /&gt;
	&#039;true&#039;, &#039;until&#039;, &#039;while&#039;,&lt;br /&gt;
];&lt;br /&gt;
/**&lt;br /&gt;
 * Returns a lua key with quotes and brackets if necessary&lt;br /&gt;
 * &lt;br /&gt;
 * Only supports numbers and strings.&lt;br /&gt;
 */&lt;br /&gt;
luaTable.createKey = function( key ) {&lt;br /&gt;
	if ( key.match( /^-?\d+(\.\d+)?$/ ) ) {&lt;br /&gt;
		return &#039;[&#039; + Number( key ) + &#039;]&#039;;&lt;br /&gt;
	}&lt;br /&gt;
	if ( luaTable.keywords.indexOf( key ) &amp;lt; 0 &amp;amp;&amp;amp; !key.match( /^[^a-z_]|\W/i ) ) {&lt;br /&gt;
		return key;&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	return &#039;[&#039; + luaTable.createString( key ) + &#039;]&#039;;&lt;br /&gt;
};&lt;br /&gt;
/**&lt;br /&gt;
 * Create a lua table value&lt;br /&gt;
 * &lt;br /&gt;
 * Only supports the types in the switch, and only functions created with&lt;br /&gt;
 * `luaTable.func` are supported.&lt;br /&gt;
 * Will recursively resolve object values.&lt;br /&gt;
 */&lt;br /&gt;
luaTable.createValue = function( val, indent ) {&lt;br /&gt;
	switch ( typeof val ) {&lt;br /&gt;
		case &#039;number&#039;:&lt;br /&gt;
		case &#039;boolean&#039;:&lt;br /&gt;
			return val;&lt;br /&gt;
		case &#039;string&#039;:&lt;br /&gt;
			return luaTable.createString( val );&lt;br /&gt;
		case &#039;object&#039;:&lt;br /&gt;
			return luaTable.create( val, indent );&lt;br /&gt;
		case &#039;function&#039;:&lt;br /&gt;
			// If the function is supposed to be a lua function,&lt;br /&gt;
			// execute it to get the lua function string and&lt;br /&gt;
			// return it directly, otherwise invalid type&lt;br /&gt;
			if ( val.luaFunc ) {&lt;br /&gt;
				return val();&lt;br /&gt;
			}&lt;br /&gt;
		default:&lt;br /&gt;
			throw new TypeError( &#039;Lua table: Invalid value type: &#039; + typeof val );&lt;br /&gt;
	}&lt;br /&gt;
};&lt;br /&gt;
/**&lt;br /&gt;
 * Quote a string for lua table&lt;br /&gt;
 *&lt;br /&gt;
 * Uses either &#039; or &amp;quot; as the delimiter (depending on which is least used in the string),&lt;br /&gt;
 * then escapes \ and the chosen delimiter within the string.&lt;br /&gt;
 */&lt;br /&gt;
luaTable.createString = function( str ) {&lt;br /&gt;
	if ( !str ) {&lt;br /&gt;
		return &amp;quot;&#039;&#039;&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
	var delim, delimRegex;&lt;br /&gt;
	var quotes = ( str.match( /&amp;quot;/g ) || &#039;&#039; ).length;&lt;br /&gt;
	var apostrophies = ( str.match( /&#039;/g ) || &#039;&#039; ).length;&lt;br /&gt;
	if ( apostrophies &amp;gt; quotes ) {&lt;br /&gt;
		delim = &#039;&amp;quot;&#039;;&lt;br /&gt;
		delimRegex = /&amp;quot;/g;&lt;br /&gt;
	} else {&lt;br /&gt;
		delim = &amp;quot;&#039;&amp;quot;;&lt;br /&gt;
		delimRegex = /&#039;/g;&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	return delim + str.replace( /\\/g, &#039;\\\\&#039; ).replace( delimRegex, &#039;\\&#039; + delim ) + delim;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/** Polyfills **/&lt;br /&gt;
if ( !HTMLCanvasElement.prototype.toBlob ) {&lt;br /&gt;
	Object.defineProperty( HTMLCanvasElement.prototype, &#039;toBlob&#039;, {&lt;br /&gt;
		value: function( callback, type, quality ) {&lt;br /&gt;
			var canvas = this;&lt;br /&gt;
			setTimeout( function() {&lt;br /&gt;
				var binStr = atob( canvas.toDataURL( type, quality ).split( &#039;,&#039; )[1] );&lt;br /&gt;
				var len = binStr.length;&lt;br /&gt;
				var arr = new Uint8Array( len );&lt;br /&gt;
				&lt;br /&gt;
				for ( var i = 0; i &amp;lt; len; i++ ) {&lt;br /&gt;
					arr[i] = binStr.charCodeAt( i );&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				callback( new Blob( [arr], { type: type || &#039;image/png&#039; } ) );&lt;br /&gt;
			} );&lt;br /&gt;
		},&lt;br /&gt;
	} );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Finally start the editor&lt;br /&gt;
create( &#039;initial&#039; );&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}() );&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=MediaWiki:Gadget-sound.js&amp;diff=96818</id>
		<title>MediaWiki:Gadget-sound.js</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=MediaWiki:Gadget-sound.js&amp;diff=96818"/>
		<updated>2018-05-11T08:30:40Z</updated>

		<summary type="html">&lt;p&gt;Majr: Add jshint definitions&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;// jshint jquery:true, esversion:5&lt;br /&gt;
/* globals require, module, mediaWiki, mw, OO */&lt;br /&gt;
&#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
mw.hook( &#039;wikipage.content&#039; ).add( function( $content ) {&lt;br /&gt;
	var i18n = {&lt;br /&gt;
		playTitle: &#039;Click to play&#039;,&lt;br /&gt;
		stopTitle: &#039;Click to stop&#039;,&lt;br /&gt;
	};&lt;br /&gt;
	$content.find(&#039;.sound&#039; ).prop( &#039;title&#039;, i18n.playTitle ).on( &#039;click&#039;, function( e ) {&lt;br /&gt;
		// Ignore links&lt;br /&gt;
		if ( e.target.tagName === &#039;A&#039; ) {&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		var audio = $( this ).find( &#039;.sound-audio&#039; )[0];&lt;br /&gt;
		if ( audio ) {&lt;br /&gt;
			audio.paused ? audio.play() : audio.pause();&lt;br /&gt;
		}&lt;br /&gt;
	} ).find( &#039;.sound-audio&#039; ).on( &#039;play&#039;, function() {&lt;br /&gt;
		// Stop any already playing sounds&lt;br /&gt;
		var playing = $( &#039;.sound-playing .sound-audio&#039; )[0];&lt;br /&gt;
		playing &amp;amp;&amp;amp; playing.pause();&lt;br /&gt;
		&lt;br /&gt;
		$( this ).closest( &#039;.sound&#039; )&lt;br /&gt;
			.addClass( &#039;sound-playing&#039; ).prop( &#039;title&#039;, i18n.stopTitle );&lt;br /&gt;
	} ).on( &#039;pause&#039;, function() {&lt;br /&gt;
		// Reset back to the start&lt;br /&gt;
		this.currentTime = 0;&lt;br /&gt;
		&lt;br /&gt;
		$( this ).closest( &#039;.sound&#039; )&lt;br /&gt;
			.removeClass( &#039;sound-playing&#039; ).prop( &#039;title&#039;, i18n.playTitle );&lt;br /&gt;
	} );&lt;br /&gt;
&lt;br /&gt;
} );&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=MediaWiki:Gadget-sound&amp;diff=96813</id>
		<title>MediaWiki:Gadget-sound</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=MediaWiki:Gadget-sound&amp;diff=96813"/>
		<updated>2018-05-05T10:21:27Z</updated>

		<summary type="html">&lt;p&gt;Majr: Created page with &amp;quot;Show the inline sound playing button for Template:Sound.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Show the inline sound playing button for [[Template:Sound]].&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=MediaWiki:Gadget-spriteEditMCW.css&amp;diff=96840</id>
		<title>MediaWiki:Gadget-spriteEditMCW.css</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=MediaWiki:Gadget-spriteEditMCW.css&amp;diff=96840"/>
		<updated>2018-04-08T15:59:50Z</updated>

		<summary type="html">&lt;p&gt;Majr: Rather than have the MCW colours as part of the generic module&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;.spriteedit-toolbar {&lt;br /&gt;
	background-color: #80b640;&lt;br /&gt;
	border-bottom-color: #3c6a02;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=MediaWiki:Gadget-spriteEditLoader.js&amp;diff=96834</id>
		<title>MediaWiki:Gadget-spriteEditLoader.js</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=MediaWiki:Gadget-spriteEditLoader.js&amp;diff=96834"/>
		<updated>2018-04-08T15:55:05Z</updated>

		<summary type="html">&lt;p&gt;Majr: https://github.com/Majr-/SpriteEdit/compare/111b3b2...3e70656&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;( function() {&lt;br /&gt;
&#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Add an edit button which loads the sprite editor&lt;br /&gt;
 *&lt;br /&gt;
 * If spriteaction=edit is in the URL, the editor will be loaded&lt;br /&gt;
 * immediately, otherwise it will wait for the button to be clicked.&lt;br /&gt;
 */&lt;br /&gt;
var editPage = $( &#039;#sprite-editor-message&#039; ).data( &#039;page&#039; ) || null;&lt;br /&gt;
if ( !$( &#039;#spritedoc&#039; ).length &amp;amp;&amp;amp; !editPage ) {&lt;br /&gt;
	return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $editTab = $( &#039;#ca-edit&#039; );&lt;br /&gt;
if ( !$editTab.length ) {&lt;br /&gt;
	$editTab = $( &#039;#ca-viewsource&#039; );&lt;br /&gt;
}&lt;br /&gt;
var $spriteEditLink = $( &#039;&amp;lt;a&amp;gt;&#039; ).text( &#039;Edit sprite&#039; ).attr( &#039;href&#039;,&lt;br /&gt;
	mw.util.getUrl( editPage, { spriteaction: &#039;edit&#039; } )&lt;br /&gt;
);&lt;br /&gt;
var $spriteEditTab = $( &#039;&amp;lt;li&amp;gt;&#039; ).attr( &#039;id&#039;, &#039;ca-spriteedit&#039; ).append(&lt;br /&gt;
	$( &#039;&amp;lt;span&amp;gt;&#039; ).append( $spriteEditLink )&lt;br /&gt;
);&lt;br /&gt;
$spriteEditTab.insertAfter( $editTab );&lt;br /&gt;
&lt;br /&gt;
// Page to sprite edit is not here, so no need to bind events&lt;br /&gt;
if ( editPage ) {&lt;br /&gt;
	return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var loadSpriteEditor = function() {&lt;br /&gt;
	$spriteEditTab.add( &#039;#ca-view&#039; ).toggleClass( &#039;selected&#039; );&lt;br /&gt;
	&lt;br /&gt;
	return mw.loader.using( &#039;ext.gadget.spriteEdit&#039; );&lt;br /&gt;
};&lt;br /&gt;
if ( location.search.match( &#039;[?&amp;amp;]spriteaction=edit&#039; ) ) {&lt;br /&gt;
	loadSpriteEditor();&lt;br /&gt;
	return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $win = $( window );&lt;br /&gt;
$spriteEditLink.one( &#039;click.spriteEditLoader&#039;, function( e ) {&lt;br /&gt;
	// Initially add the history so it is not delayed waiting&lt;br /&gt;
	// for the editor to load. The editor will handle it from now.&lt;br /&gt;
	history.pushState( {}, &#039;&#039;, this.href );&lt;br /&gt;
	&lt;br /&gt;
	loadSpriteEditor().then( function() {&lt;br /&gt;
		$win.off( &#039;.spriteEditLoader&#039; );&lt;br /&gt;
	} );&lt;br /&gt;
	&lt;br /&gt;
	e.preventDefault();&lt;br /&gt;
} );&lt;br /&gt;
&lt;br /&gt;
// If the page is reloaded while the editor isn&#039;t loaded, navigating&lt;br /&gt;
// back to the editor won&#039;t work, so an initial navigation check is&lt;br /&gt;
// necessary to load the editor, where it will then monitor navigation&lt;br /&gt;
$win.on( &#039;popstate.spriteEditLoader&#039;, function() {&lt;br /&gt;
	if (&lt;br /&gt;
		location.search.match( &#039;[?&amp;amp;]spriteaction=edit&#039; ) &amp;amp;&amp;amp;&lt;br /&gt;
		!$( &#039;html&#039; ).hasClass( &#039;spriteedit-loaded&#039; )&lt;br /&gt;
	) {&lt;br /&gt;
		loadSpriteEditor().then( function() {&lt;br /&gt;
			$win.off( &#039;.spriteEditLoader&#039; );&lt;br /&gt;
		} );&lt;br /&gt;
	}&lt;br /&gt;
} );&lt;br /&gt;
&lt;br /&gt;
}() );&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=MediaWiki:Gadget-spriteEdit.css&amp;diff=96823</id>
		<title>MediaWiki:Gadget-spriteEdit.css</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=MediaWiki:Gadget-spriteEdit.css&amp;diff=96823"/>
		<updated>2018-04-08T15:53:15Z</updated>

		<summary type="html">&lt;p&gt;Majr: https://github.com/Majr-/SpriteEdit/compare/111b3b2...3e70656&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#spritedoc {&lt;br /&gt;
	position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#spritedoc canvas {&lt;br /&gt;
	display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.spriteedit-enabled {&lt;br /&gt;
	overflow-y: scroll;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.spriteedit-smoothscroll {&lt;br /&gt;
	scroll-behavior: smooth;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.spriteedit-sorting * {&lt;br /&gt;
	cursor: move !important;&lt;br /&gt;
	cursor: -webkit-grabbing !important;&lt;br /&gt;
	cursor: grabbing !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.spriteedit-elastic {&lt;br /&gt;
	-webkit-transition-timing-function: cubic-bezier(0.46, 0, 0.19, 1.44) !important;&lt;br /&gt;
	        transition-timing-function: cubic-bezier(0.46, 0, 0.19, 1.44) !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.spriteedit-droptarget {&lt;br /&gt;
	outline: 1px dashed #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.spriteedit-autoscroll {&lt;br /&gt;
	visibility: hidden;&lt;br /&gt;
	position: fixed;&lt;br /&gt;
	left: 0;&lt;br /&gt;
	right: 0;&lt;br /&gt;
	height: 50px;&lt;br /&gt;
	z-index: 999;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-autoscroll-up {&lt;br /&gt;
	top: 0;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-autoscroll-down {&lt;br /&gt;
	bottom: 0;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-sorting .spriteedit-autoscroll,&lt;br /&gt;
.spriteedit-dragging .spriteedit-autoscroll {&lt;br /&gt;
	visibility: visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.spriteedit-toolbar-container {&lt;br /&gt;
	position: -webkit-sticky;&lt;br /&gt;
	position: sticky;&lt;br /&gt;
	top: 0;&lt;br /&gt;
	z-index: 91;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-toolbar {&lt;br /&gt;
	position: relative;&lt;br /&gt;
	background-color: #FFF;&lt;br /&gt;
	border-bottom: 4px solid #c8ccd1;&lt;br /&gt;
	padding: 0.5em 0;&lt;br /&gt;
	overflow: hidden;&lt;br /&gt;
	-webkit-transition: height 200ms;&lt;br /&gt;
	        transition: height 200ms;&lt;br /&gt;
	z-index: 91;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-toolbar-fixed {&lt;br /&gt;
	position: fixed;&lt;br /&gt;
	top: 0;&lt;br /&gt;
	right: 0;&lt;br /&gt;
	margin: 0 !important;&lt;br /&gt;
}&lt;br /&gt;
#spriteedit-toolbox {&lt;br /&gt;
	font-weight: bold;&lt;br /&gt;
	vertical-align: middle;&lt;br /&gt;
	width: 10em;&lt;br /&gt;
}&lt;br /&gt;
#spritedoc .oo-ui-menuSelectWidget {&lt;br /&gt;
	z-index: 92;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-tool-deprecate .spritedoc-name &amp;gt; code {&lt;br /&gt;
	-webkit-user-select: none;&lt;br /&gt;
	   -moz-user-select: none;&lt;br /&gt;
	    -ms-user-select: none;&lt;br /&gt;
	user-select: none;&lt;br /&gt;
	cursor: pointer;&lt;br /&gt;
}&lt;br /&gt;
#spriteedit-save {&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	right: 0;&lt;br /&gt;
	bottom: 0.5em;&lt;br /&gt;
	margin-right: 0;&lt;br /&gt;
}&lt;br /&gt;
#spriteedit-saveform {&lt;br /&gt;
	display: -ms-flexbox;&lt;br /&gt;
	display: -webkit-box;&lt;br /&gt;
	display: flex;&lt;br /&gt;
	margin-top: 0.5em;&lt;br /&gt;
}&lt;br /&gt;
#spriteedit-summary {&lt;br /&gt;
	margin-right: 0.5em;&lt;br /&gt;
	-webkit-box-flex: 1;&lt;br /&gt;
	-ms-flex: auto;&lt;br /&gt;
	    flex: auto;&lt;br /&gt;
	max-width: none;&lt;br /&gt;
}&lt;br /&gt;
/* XXX: Missing padding, probably fixed in a new version */&lt;br /&gt;
#spriteedit-summary .oo-ui-labelElement-label {&lt;br /&gt;
	padding-right: 0.9375em;&lt;br /&gt;
}&lt;br /&gt;
#spriteedit-review-button {&lt;br /&gt;
	margin-right: 0.5em;&lt;br /&gt;
	-webkit-box-flex: 0;&lt;br /&gt;
	-ms-flex: none;&lt;br /&gt;
	    flex: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#spritedoc .mw-headline {&lt;br /&gt;
	display: inline-block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.spriteedit-handle {&lt;br /&gt;
	-webkit-box-flex: 0;&lt;br /&gt;
	-ms-flex: none;&lt;br /&gt;
	    flex: none;&lt;br /&gt;
	background: #AAA;&lt;br /&gt;
	background: -webkit-linear-gradient(#AAA, #AAA 50%, #FFF 50%, #FFF) 0 0, -webkit-linear-gradient(#AAA, #AAA 50%, #FFF 50%, #FFF) 2px 2px;&lt;br /&gt;
	background: linear-gradient(#AAA, #AAA 50%, #FFF 50%, #FFF) 0 0, linear-gradient(#AAA, #AAA 50%, #FFF 50%, #FFF) 2px 2px;&lt;br /&gt;
	background-repeat: repeat-y;&lt;br /&gt;
	background-size: 2px 4px;&lt;br /&gt;
	padding-right: 4px;&lt;br /&gt;
	margin-right: 0.3em;&lt;br /&gt;
	cursor: move;&lt;br /&gt;
	cursor: -webkit-grab;&lt;br /&gt;
	cursor: grab;&lt;br /&gt;
	visibility: hidden;&lt;br /&gt;
	opacity: 0;&lt;br /&gt;
	-webkit-transition: opacity 200ms 300ms, visibility 0s linear 500ms;&lt;br /&gt;
	        transition: opacity 200ms 300ms, visibility 0s linear 500ms;&lt;br /&gt;
}&lt;br /&gt;
.spritedoc-box &amp;gt; .spriteedit-handle {&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	top: 0;&lt;br /&gt;
	left: 0;&lt;br /&gt;
	bottom: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.spriteedit-imageeditingenabled .spritedoc-image {&lt;br /&gt;
	cursor: pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sprite.spriteedit-replaced-image {&lt;br /&gt;
	display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.spriteedit-add-name {&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	right: -3px;&lt;br /&gt;
	bottom: -3px;&lt;br /&gt;
	margin-right: 0;&lt;br /&gt;
	visibility: hidden;&lt;br /&gt;
	opacity: 0;&lt;br /&gt;
	-webkit-transition: opacity 200ms 300ms, visibility 0s linear 500ms;&lt;br /&gt;
	        transition: opacity 200ms 300ms, visibility 0s linear 500ms;&lt;br /&gt;
	z-index: 9;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.spriteedit-hidecontrols .spriteedit-handle,&lt;br /&gt;
.spriteedit-hidecontrols .spriteedit-add-name {&lt;br /&gt;
	visibility: hidden !important;&lt;br /&gt;
	opacity: 0 !important;&lt;br /&gt;
	-webkit-transition: visibility, opacity !important;&lt;br /&gt;
	        transition: visibility, opacity !important;&lt;br /&gt;
}&lt;br /&gt;
#spritedoc h3:hover &amp;gt; .spriteedit-handle,&lt;br /&gt;
.spritedoc-box:hover .spriteedit-handle,&lt;br /&gt;
.spritedoc-box:hover &amp;gt; .spriteedit-add-name {&lt;br /&gt;
	visibility: visible;&lt;br /&gt;
	opacity: 1;&lt;br /&gt;
	-webkit-transition-delay: 200ms;&lt;br /&gt;
	        transition-delay: 200ms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#spritedoc [contentEditable]:empty:after {&lt;br /&gt;
	content: &amp;quot;\A0&amp;quot;; /* Non-breaking space */&lt;br /&gt;
}&lt;br /&gt;
#spritedoc [contentEditable][data-placeholder]:empty:after {&lt;br /&gt;
	content: attr(data-placeholder);&lt;br /&gt;
	opacity: 0.54;&lt;br /&gt;
	font-style: italic;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.spriteedit-dupe {&lt;br /&gt;
	background-color: #FFC7CE !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.spriteedit-ghost {&lt;br /&gt;
	position: fixed !important;&lt;br /&gt;
	z-index: 999;&lt;br /&gt;
	opacity: 0.8;&lt;br /&gt;
	pointer-events: none;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-placeholder {&lt;br /&gt;
	opacity: 0.5;&lt;br /&gt;
	outline: 1px dashed #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.spriteedit-processing {&lt;br /&gt;
	background-size: 1em 1em;&lt;br /&gt;
	background-image: -webkit-linear-gradient(&lt;br /&gt;
		45deg,&lt;br /&gt;
		rgba(204, 204, 204, 0.4) 25%,&lt;br /&gt;
		transparent 25%,&lt;br /&gt;
		transparent 50%,&lt;br /&gt;
		rgba(204, 204, 204, 0.4) 50%,&lt;br /&gt;
		rgba(204, 204, 204, 0.4) 75%,&lt;br /&gt;
		transparent 75%,&lt;br /&gt;
		transparent&lt;br /&gt;
	);&lt;br /&gt;
	background-image: linear-gradient(&lt;br /&gt;
		45deg,&lt;br /&gt;
		rgba(204, 204, 204, 0.4) 25%,&lt;br /&gt;
		transparent 25%,&lt;br /&gt;
		transparent 50%,&lt;br /&gt;
		rgba(204, 204, 204, 0.4) 50%,&lt;br /&gt;
		rgba(204, 204, 204, 0.4) 75%,&lt;br /&gt;
		transparent 75%,&lt;br /&gt;
		transparent&lt;br /&gt;
	);&lt;br /&gt;
	-webkit-animation: spriteedit-processing 1s infinite linear;&lt;br /&gt;
	        animation: spriteedit-processing 1s infinite linear;&lt;br /&gt;
}&lt;br /&gt;
@-webkit-keyframes spriteedit-processing {&lt;br /&gt;
	0% { background-position: 0 0; }&lt;br /&gt;
	100% { background-position: 1em 0; }&lt;br /&gt;
}&lt;br /&gt;
@keyframes spriteedit-processing {&lt;br /&gt;
	0% { background-position: 0 0; }&lt;br /&gt;
	100% { background-position: 1em 0; }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.spriteedit-tooltip {&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	margin-left: -19px;&lt;br /&gt;
	padding: 9px;&lt;br /&gt;
	opacity: 0;&lt;br /&gt;
	-webkit-transform: scale(0);&lt;br /&gt;
	        transform: scale(0);&lt;br /&gt;
	-webkit-transform-origin: 19px bottom;&lt;br /&gt;
	        transform-origin: 19px bottom;&lt;br /&gt;
	-webkit-transition: opacity 350ms, -webkit-transform 350ms;&lt;br /&gt;
	        transition: opacity 350ms, -webkit-transform 350ms;&lt;br /&gt;
	        transition: transform 350ms, opacity 350ms;&lt;br /&gt;
	z-index: 121;&lt;br /&gt;
	white-space: nowrap;&lt;br /&gt;
	line-height: 1.6;&lt;br /&gt;
	font-size: 0.875em;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-tooltip-horizontal {&lt;br /&gt;
	margin-left: 0;&lt;br /&gt;
	margin-top: -19px;&lt;br /&gt;
	-webkit-transform-origin: right 19px;&lt;br /&gt;
	        transform-origin: right 19px;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-tooltip-text,&lt;br /&gt;
.spriteedit-tooltip-arrow:before {&lt;br /&gt;
	border: 1px solid #CCC;&lt;br /&gt;
	background-color: #FFF;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-tooltip-arrow {&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	bottom: 1px;&lt;br /&gt;
	left: 9px;&lt;br /&gt;
	height: 9px;&lt;br /&gt;
	width: 20px;&lt;br /&gt;
	overflow: hidden;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-tooltip-horizontal .spriteedit-tooltip-arrow {&lt;br /&gt;
	top: 14px;&lt;br /&gt;
	right: -4px;&lt;br /&gt;
	bottom: auto;&lt;br /&gt;
	left: auto;&lt;br /&gt;
	-webkit-transform: rotate(-90deg);&lt;br /&gt;
	        transform: rotate(-90deg);&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-tooltip-arrow:before {&lt;br /&gt;
	content: &amp;quot;&amp;quot;;&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	-webkit-transform: rotate(45deg);&lt;br /&gt;
	        transform: rotate(45deg);&lt;br /&gt;
	height: 10px;&lt;br /&gt;
	width: 10px;&lt;br /&gt;
	left: 4px;&lt;br /&gt;
	top: -6px;&lt;br /&gt;
	padding: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.spriteedit-tooltip-controls .oo-ui-buttonInputWidget,&lt;br /&gt;
.spriteedit-tooltip-controls .oo-ui-buttonInputWidget .oo-ui-buttonElement-button {&lt;br /&gt;
	display: block;&lt;br /&gt;
	width: 100%;&lt;br /&gt;
	text-align: left;&lt;br /&gt;
	margin-right: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.spriteedit-dialog-overlay {&lt;br /&gt;
	display: -ms-flex;&lt;br /&gt;
	display: -webkit-box;&lt;br /&gt;
	display: -ms-flexbox;&lt;br /&gt;
	display: flex;&lt;br /&gt;
	position: fixed;&lt;br /&gt;
	left: 0;&lt;br /&gt;
	top: 0;&lt;br /&gt;
	right: 0;&lt;br /&gt;
	bottom: 0;&lt;br /&gt;
	background-color: rgba(0,0,0,0.2);&lt;br /&gt;
	opacity: 0;&lt;br /&gt;
	-webkit-transition: opacity 300ms;&lt;br /&gt;
	        transition: opacity 300ms;&lt;br /&gt;
	z-index: 9000&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-dialog {&lt;br /&gt;
	display: -webkit-box;&lt;br /&gt;
	display: -ms-flexbox;&lt;br /&gt;
	display: flex;&lt;br /&gt;
	position: relative;&lt;br /&gt;
	background-color: #FFF;&lt;br /&gt;
	max-width: 90%;&lt;br /&gt;
	max-height: 90%;&lt;br /&gt;
	-webkit-transform: scale(0);&lt;br /&gt;
	        transform: scale(0);&lt;br /&gt;
	-webkit-transition-property: width, height, -webkit-transform;&lt;br /&gt;
	        transition-property: width, height, -webkit-transform;&lt;br /&gt;
	        transition-property: transform, width, height;&lt;br /&gt;
	-webkit-transition-duration: 400ms, 350ms, 350ms;&lt;br /&gt;
	        transition-duration: 400ms, 350ms, 350ms;&lt;br /&gt;
	margin: auto;&lt;br /&gt;
	border-radius: 3px;&lt;br /&gt;
	overflow: hidden;&lt;br /&gt;
	line-height: 1.6;&lt;br /&gt;
	font-size: 0.875em;&lt;br /&gt;
}&lt;br /&gt;
#spriteedit-dialog-close {&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	top: 0;&lt;br /&gt;
	right: 0;&lt;br /&gt;
	margin-right: 0;&lt;br /&gt;
}&lt;br /&gt;
#spriteedit-dialog-close .oo-ui-buttonElement-button {&lt;br /&gt;
	border: 0;&lt;br /&gt;
	border-radius: 0;&lt;br /&gt;
	border-left: 1px solid #CCC;&lt;br /&gt;
	width: 42px;&lt;br /&gt;
	height: 42px;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-dialog-panel {&lt;br /&gt;
	display: -webkit-box;&lt;br /&gt;
	display: -ms-flexbox;&lt;br /&gt;
	display: flex;&lt;br /&gt;
	-webkit-box-orient: vertical;&lt;br /&gt;
	-webkit-box-direction: normal;&lt;br /&gt;
	   -ms-flex-direction: column;&lt;br /&gt;
	       flex-direction: column;&lt;br /&gt;
	width: 100%;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-dialog-title {&lt;br /&gt;
	text-align: center;&lt;br /&gt;
	font-size: 120%;&lt;br /&gt;
	white-space: nowrap;&lt;br /&gt;
	padding: 0.45em 42px;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-dialog-text {&lt;br /&gt;
	-webkit-box-flex: 1;&lt;br /&gt;
	-ms-flex: 1;&lt;br /&gt;
	    flex: 1;&lt;br /&gt;
	border: solid #CCC;&lt;br /&gt;
	border-width: 1px 0;&lt;br /&gt;
	padding: 0.5em;&lt;br /&gt;
	overflow: auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.spriteedit-dialog-actions {&lt;br /&gt;
	padding: 0.5em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.spriteedit-sheet-diff {&lt;br /&gt;
	display: -webkit-box;&lt;br /&gt;
	display: -ms-flexbox;&lt;br /&gt;
	display: flex;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-sheet-diff img {&lt;br /&gt;
	width: 100%;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-old-sheet,&lt;br /&gt;
.spriteedit-new-sheet {&lt;br /&gt;
	display: inline-block;&lt;br /&gt;
	padding: 1em;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-new-sheet {&lt;br /&gt;
	background-color: #D8ECFF;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-old-sheet {&lt;br /&gt;
	background-color: #FEEEC8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.spriteedit-ec-editboxes {&lt;br /&gt;
	display: flex;&lt;br /&gt;
	flex-wrap: wrap;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-ec-editboxes &amp;gt; div {&lt;br /&gt;
	flex-grow: 1;&lt;br /&gt;
	margin: 0 1em;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-ec-editboxes .oo-ui-textInputWidget {&lt;br /&gt;
	min-width: 30em;&lt;br /&gt;
	max-width: none;&lt;br /&gt;
}&lt;br /&gt;
.spriteedit-ec-editboxes .oo-ui-textInputWidget &amp;gt; .oo-ui-inputWidget-input {&lt;br /&gt;
	min-height: 20em;&lt;br /&gt;
	height: 200em;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=MediaWiki:Gadget-spriteEditLoader.js&amp;diff=96833</id>
		<title>MediaWiki:Gadget-spriteEditLoader.js</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=MediaWiki:Gadget-spriteEditLoader.js&amp;diff=96833"/>
		<updated>2017-08-10T08:09:37Z</updated>

		<summary type="html">&lt;p&gt;Majr: Make sure this doesn&amp;#039;t get loaded too soon.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;$( function() {&lt;br /&gt;
&#039;use strict&#039;;&lt;br /&gt;
/**&lt;br /&gt;
 * Add an edit button which loads the sprite editor&lt;br /&gt;
 *&lt;br /&gt;
 * If spriteaction=edit is in the URL, the editor will be loaded&lt;br /&gt;
 * immediately, otherwise it will wait for the button to be clicked.&lt;br /&gt;
 * Uses the History API where supported to update the URL, otherwise&lt;br /&gt;
 * the URL isn&#039;t updated.&lt;br /&gt;
 */&lt;br /&gt;
if ( !$( &#039;#spritedoc&#039; ).length ) {&lt;br /&gt;
	return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $editTab = $( &#039;#ca-edit&#039; );&lt;br /&gt;
if ( !$editTab.length ) {&lt;br /&gt;
	$editTab = $( &#039;#ca-viewsource&#039; );&lt;br /&gt;
}&lt;br /&gt;
var $spriteEditLink = $( &#039;&amp;lt;a&amp;gt;&#039; ).text( &#039;Edit sprite&#039; ).attr( &#039;href&#039;,&lt;br /&gt;
	mw.util.getUrl( null, { spriteaction: &#039;edit&#039; } )&lt;br /&gt;
);&lt;br /&gt;
var $spriteEditTab = $( &#039;&amp;lt;li&amp;gt;&#039; ).attr( &#039;id&#039;, &#039;ca-spriteedit&#039; ).append(&lt;br /&gt;
	$( &#039;&amp;lt;span&amp;gt;&#039; ).append( $spriteEditLink )&lt;br /&gt;
);&lt;br /&gt;
$spriteEditTab.insertAfter( $editTab );&lt;br /&gt;
&lt;br /&gt;
var loadSpriteEditor = function() {&lt;br /&gt;
	$spriteEditTab.add( &#039;#ca-view&#039; ).toggleClass( &#039;selected&#039; );&lt;br /&gt;
	&lt;br /&gt;
	mw.loader.load( &#039;ext.gadget.spriteEdit&#039; );&lt;br /&gt;
};&lt;br /&gt;
if ( location.search.match( &#039;spriteaction=edit&#039; ) ) {&lt;br /&gt;
	loadSpriteEditor();&lt;br /&gt;
} else {&lt;br /&gt;
	var $win = $( window );&lt;br /&gt;
	$spriteEditLink.one( &#039;click&#039;, function( e ) {&lt;br /&gt;
		if ( window.history &amp;amp;&amp;amp; history.pushState ) {&lt;br /&gt;
			// Initially add the history so it is not delayed waiting&lt;br /&gt;
			// for the editor to load. The editor will handle it from now.&lt;br /&gt;
			history.pushState( {}, &#039;&#039;, this.href );&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		loadSpriteEditor();&lt;br /&gt;
		$win.off( &#039;.spriteEditLoader&#039; );&lt;br /&gt;
		&lt;br /&gt;
		e.preventDefault();&lt;br /&gt;
	} );&lt;br /&gt;
	&lt;br /&gt;
	if ( window.history &amp;amp;&amp;amp; history.pushState ) {&lt;br /&gt;
		// If the page is reloaded while the editor isn&#039;t loaded, navigating&lt;br /&gt;
		// back to the editor won&#039;t work, so an initial navigation check is&lt;br /&gt;
		// necessary to load the editor, where it will then monitor navigation&lt;br /&gt;
		$win.on( &#039;popstate.spriteEditLoader&#039;, function() {&lt;br /&gt;
			if (&lt;br /&gt;
				location.search.match( &#039;spriteaction=edit&#039; ) &amp;amp;&amp;amp;&lt;br /&gt;
				!$( &#039;html&#039; ).hasClass( &#039;spriteedit-loaded&#039; )&lt;br /&gt;
			) {&lt;br /&gt;
				loadSpriteEditor();&lt;br /&gt;
				$win.off( &#039;.spriteEditLoader&#039; );&lt;br /&gt;
			}&lt;br /&gt;
		} );&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
} );&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=U%C5%BCytkownik:Majr/hydra.css&amp;diff=71346</id>
		<title>Użytkownik:Majr/hydra.css</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=U%C5%BCytkownik:Majr/hydra.css&amp;diff=71346"/>
		<updated>2016-09-08T01:31:38Z</updated>

		<summary type="html">&lt;p&gt;Majr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;@import &amp;quot;//minecraft.gamepedia.com/index.php?title=User:Majr/hydra.css&amp;amp;action=raw&amp;amp;ctype=text/css&amp;quot;;&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=U%C5%BCytkownik:Majr/hydra.js&amp;diff=71348</id>
		<title>Użytkownik:Majr/hydra.js</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=U%C5%BCytkownik:Majr/hydra.js&amp;diff=71348"/>
		<updated>2016-09-08T01:29:38Z</updated>

		<summary type="html">&lt;p&gt;Majr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load( &#039;//minecraft.gamepedia.com/index.php?title=User:Majr/hydra.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039; );&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=Szablon:YouTube&amp;diff=103122</id>
		<title>Szablon:YouTube</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=Szablon:YouTube&amp;diff=103122"/>
		<updated>2016-09-03T02:39:58Z</updated>

		<summary type="html">&lt;p&gt;Majr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;{{#ev:youtube|{{{1}}}|{{#if: {{{2|}}} | {{{2}}} | 425 }}|{{{align|}}}}}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{documentation}}&lt;br /&gt;
&amp;lt;!-- Put categories/interwiki on the documentation page --&amp;gt;&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=MediaWiki:Common.css&amp;diff=96254</id>
		<title>MediaWiki:Common.css</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=MediaWiki:Common.css&amp;diff=96254"/>
		<updated>2016-07-29T08:59:28Z</updated>

		<summary type="html">&lt;p&gt;Majr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/*** Temp fixing any images missing from CDN ***/&lt;br /&gt;
/* Redirect arrow */&lt;br /&gt;
.redirectMsg {&lt;br /&gt;
	padding-left: 40px;&lt;br /&gt;
	background: url(&amp;quot;http://hydra-media.cursecdn.com/minecraft-pl.gamepedia.com/b/b5/Redirectltr.png&amp;quot;) no-repeat left center;&lt;br /&gt;
}&lt;br /&gt;
.redirectMsg img {&lt;br /&gt;
	display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/** Template stylings **/&lt;br /&gt;
/* [[Template:Grid]] */&lt;br /&gt;
.grid {&lt;br /&gt;
	display: inline-block;&lt;br /&gt;
	position: relative;&lt;br /&gt;
	text-align: left !important;&lt;br /&gt;
	background-color: #8B8B8B;&lt;br /&gt;
	height: 32px;&lt;br /&gt;
	width: 32px;&lt;br /&gt;
	padding: 2px;&lt;br /&gt;
	vertical-align: bottom;&lt;br /&gt;
}&lt;br /&gt;
.grid.output {&lt;br /&gt;
	height: 48px;&lt;br /&gt;
	width: 48px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.grid img,&lt;br /&gt;
.pixel-image img {&lt;br /&gt;
	image-rendering: -moz-crisp-edges;&lt;br /&gt;
	image-rendering: -o-crisp-edges;&lt;br /&gt;
	image-rendering: -webkit-optimize-contrast;&lt;br /&gt;
	-ms-interpolation-mode: nearest-neighbor;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
.grid .border {&lt;br /&gt;
	display: block;&lt;br /&gt;
	margin: -2px 0 0 -2px;&lt;br /&gt;
	border-style: solid none none solid;&lt;br /&gt;
	border-width: 2px;&lt;br /&gt;
	border-color: #373737;&lt;br /&gt;
	height: 100%;&lt;br /&gt;
}&lt;br /&gt;
.grid .border &amp;gt; span {&lt;br /&gt;
	display: block;&lt;br /&gt;
	margin-right: -2px;&lt;br /&gt;
	border-style: none solid solid none;&lt;br /&gt;
	border-width: 2px;&lt;br /&gt;
	border-color: #FFFFFF;&lt;br /&gt;
	height: 100%;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
.grid .image,&lt;br /&gt;
.grid .default-image {&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	line-height: 16px;&lt;br /&gt;
	top: 2px;&lt;br /&gt;
	width: 32px;&lt;br /&gt;
	height: 32px;&lt;br /&gt;
}&lt;br /&gt;
.grid.output .image {&lt;br /&gt;
	top: 10px;&lt;br /&gt;
	left: 10px;&lt;br /&gt;
}&lt;br /&gt;
.grid .image &amp;gt; a.new {&lt;br /&gt;
	background-image: url(&amp;quot;http://hydra-media.cursecdn.com/minecraft-pl.gamepedia.com/3/35/Grid_Unknown.png&amp;quot;);&lt;br /&gt;
	display: block;&lt;br /&gt;
	width: 32px;&lt;br /&gt;
	height: 32px;&lt;br /&gt;
	outline: none;&lt;br /&gt;
	text-indent: -99999px;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
.grid .number {&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	right: -2px;&lt;br /&gt;
	bottom: -2px;&lt;br /&gt;
	text-align: right;&lt;br /&gt;
	font-family: Minecraft;&lt;br /&gt;
	font-size: 16px;&lt;br /&gt;
	color: #FFF;&lt;br /&gt;
	pointer-events: none;&lt;br /&gt;
	z-index: 6;&lt;br /&gt;
	text-shadow: 2px 2px 0px #3F3F3F;&lt;br /&gt;
	filter: dropshadow(color=#3F3F3F, offx=2, offy=2);&lt;br /&gt;
}&lt;br /&gt;
.grid .number a {&lt;br /&gt;
	color: #FFF;&lt;br /&gt;
	text-decoration: none;&lt;br /&gt;
}&lt;br /&gt;
.grid .number .selflink {&lt;br /&gt;
	font-weight: normal;&lt;br /&gt;
}&lt;br /&gt;
.grid .image a.new + .number {&lt;br /&gt;
	display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.grid-Crafting_Table,&lt;br /&gt;
.grid-Furnace,&lt;br /&gt;
.grid-Brewing_Stand table,&lt;br /&gt;
.grid-generic {&lt;br /&gt;
	background: #C6C6C6;&lt;br /&gt;
	border: outset 2px #999;&lt;br /&gt;
	padding: 6px;&lt;br /&gt;
	text-align: left !important;&lt;br /&gt;
}&lt;br /&gt;
.grid-Crafting_Table td,&lt;br /&gt;
.grid-Furnace td,&lt;br /&gt;
.grid-Brewing_Stand td,&lt;br /&gt;
.grid-generic td {&lt;br /&gt;
	border: none;&lt;br /&gt;
	padding: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* [[Template:Grid/Crafting Table]] */&lt;br /&gt;
.grid-Crafting_Table .arrow,&lt;br /&gt;
.grid-Crafting_Table .shapeless {&lt;br /&gt;
	text-align: center;&lt;br /&gt;
	vertical-align: bottom;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.grid-Crafting_Table .arrow {&lt;br /&gt;
	width: 40px;&lt;br /&gt;
	padding-bottom: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.grid-Crafting_Table .shapeless span {&lt;br /&gt;
	cursor: help;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* [[Template:Grid/Furnace]] */&lt;br /&gt;
.grid-Furnace {&lt;br /&gt;
	padding-left: 24px;&lt;br /&gt;
	padding-right: 24px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.grid-Furnace .arrow,&lt;br /&gt;
.grid-Furnace .output {&lt;br /&gt;
	text-align: center;&lt;br /&gt;
	vertical-align: middle;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.grid-Furnace .arrow {&lt;br /&gt;
	padding-right: 18px !important;&lt;br /&gt;
	padding-left: 14px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* [[Template:Grid/Brewing Stand]] */&lt;br /&gt;
.grid-Brewing_Stand {&lt;br /&gt;
	position: relative;&lt;br /&gt;
	width: 144px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.grid-Brewing_Stand .bubbles {&lt;br /&gt;
	text-align: right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.grid-Brewing_Stand .input {&lt;br /&gt;
	padding: 3px 0 !important;&lt;br /&gt;
	vertical-align: top;&lt;br /&gt;
}&lt;br /&gt;
.grid-Brewing_Stand .output1 {&lt;br /&gt;
	padding: 4px 10px 14px 0 !important;&lt;br /&gt;
}&lt;br /&gt;
.grid-Brewing_Stand .output2 {&lt;br /&gt;
	padding-top: 18px !important;&lt;br /&gt;
}&lt;br /&gt;
.grid-Brewing_Stand .output3 {&lt;br /&gt;
	padding: 4px 0 14px 10px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.grid-Brewing_Stand .paths {&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	bottom: 42px;&lt;br /&gt;
	left: 42px;&lt;br /&gt;
	z-index: 5;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* [[Template:Grid/Hotbar]] */&lt;br /&gt;
.grid-Hotbar {&lt;br /&gt;
	display: inline-block;&lt;br /&gt;
	position: relative;&lt;br /&gt;
}&lt;br /&gt;
.grid-Hotbar &amp;gt; .selector {&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	top: -2px;&lt;br /&gt;
	margin-left: -2px;&lt;br /&gt;
}&lt;br /&gt;
.grid-Hotbar &amp;gt; .slots {&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	top: 0;&lt;br /&gt;
	left: 0;&lt;br /&gt;
	margin: 2px;&lt;br /&gt;
}&lt;br /&gt;
.grid-Hotbar .grid {&lt;br /&gt;
	margin: 2px;&lt;br /&gt;
	background-color: transparent;&lt;br /&gt;
}&lt;br /&gt;
.grid-Hotbar .grid &amp;gt; .border,&lt;br /&gt;
.grid-Hotbar .grid &amp;gt; .border &amp;gt; span {&lt;br /&gt;
	border: 0;&lt;br /&gt;
	margin: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* [[Template:Infobox common]] */&lt;br /&gt;
.infobox {&lt;br /&gt;
	clear: right;&lt;br /&gt;
	margin: 3px 0px 3px 3px;&lt;br /&gt;
	width: 300px;&lt;br /&gt;
	font-size: 90%;&lt;br /&gt;
	background: #FFFFFF;&lt;br /&gt;
	float: right;&lt;br /&gt;
	border: 1px solid #CCCCCC;&lt;br /&gt;
	padding: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.infobox-title {&lt;br /&gt;
	font-weight: bold;&lt;br /&gt;
	text-align: center;&lt;br /&gt;
	font-size: 120%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.infobox-imagearea {&lt;br /&gt;
	text-align: center;&lt;br /&gt;
	padding: 4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.infobox table {&lt;br /&gt;
	width: 100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.infobox p {&lt;br /&gt;
	margin: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.infobox audio {&lt;br /&gt;
	width: 184px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.infobox dl:last-child {&lt;br /&gt;
	margin-bottom: 0.2em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.infobox-footer {&lt;br /&gt;
	text-align: center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Merge adjacent dls in the infobox (since they&#039;re usually supposed to be one, but the wiki screws up sometimes) */&lt;br /&gt;
.infobox dl + dl {&lt;br /&gt;
	margin-top: -0.4em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* What is this? */&lt;br /&gt;
.infobox.atfmrec {&lt;br /&gt;
	border: none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* [[Template:Infobox row]] */&lt;br /&gt;
.infobox-row {&lt;br /&gt;
	white-space: nowrap;&lt;br /&gt;
	font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* [[Template:Navbox]] */&lt;br /&gt;
.navbox {&lt;br /&gt;
	background: #FFF;&lt;br /&gt;
	border: 1px solid #CCC;&lt;br /&gt;
	margin: 1em auto 0;&lt;br /&gt;
	clear: both;&lt;br /&gt;
	width: 100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.navbox table {&lt;br /&gt;
	background: #FFF;&lt;br /&gt;
	margin-left: -4px;&lt;br /&gt;
	margin-right: -2px;&lt;br /&gt;
}&lt;br /&gt;
.navbox table:first-child {&lt;br /&gt;
	margin-top: -2px;&lt;br /&gt;
}&lt;br /&gt;
.navbox table:last-child {&lt;br /&gt;
	margin-bottom: -2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.navbox-top {&lt;br /&gt;
	white-space: nowrap;&lt;br /&gt;
	background-color: #CCC;&lt;br /&gt;
	padding: 0 3px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.navbox-navbar,&lt;br /&gt;
.navbox-navbar-mini {&lt;br /&gt;
	float: left;&lt;br /&gt;
	font-size: 80%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.navbox-title {&lt;br /&gt;
	padding: 0 10px;&lt;br /&gt;
	font-size: 110%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.navbox-group {&lt;br /&gt;
	background-color: #EEE;&lt;br /&gt;
	padding: 0 10px;&lt;br /&gt;
	white-space: nowrap;&lt;br /&gt;
	text-align: right;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.navbox-list {&lt;br /&gt;
	width: 100%;&lt;br /&gt;
	padding: 0 0 0 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* [[Template:LoadBox]] with navbox */&lt;br /&gt;
.loadbox-navbox {&lt;br /&gt;
	padding: 2px !important;&lt;br /&gt;
	margin: 1em 0 0 !important;&lt;br /&gt;
	clear: both;&lt;br /&gt;
}&lt;br /&gt;
.loadbox-navbox &amp;gt; p {&lt;br /&gt;
	background-color: #CCC;&lt;br /&gt;
	text-align: center;&lt;br /&gt;
	margin: 0;&lt;br /&gt;
	padding: 0 3px;&lt;br /&gt;
}&lt;br /&gt;
.loadbox-navbox &amp;gt; p &amp;gt; b {&lt;br /&gt;
	font-size: 110%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.loadbox-navbox .navbox {&lt;br /&gt;
	margin: 0 -2px -2px;&lt;br /&gt;
	border: 0;&lt;br /&gt;
}&lt;br /&gt;
.loadbox-navbox .navbox &amp;gt; tbody &amp;gt; tr:first-child {&lt;br /&gt;
	display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* [[Template:History2]] */&lt;br /&gt;
.history2 td &amp;gt; pre,&lt;br /&gt;
.history2 td &amp;gt; ol {&lt;br /&gt;
	display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.history2 ul {&lt;br /&gt;
	margin-top: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.history2 .toggleHistDetails {&lt;br /&gt;
	float: right;&lt;br /&gt;
	text-align: right;&lt;br /&gt;
	width: 150px;&lt;br /&gt;
}&lt;br /&gt;
.history2 &amp;gt; tbody &amp;gt; tr:first-child &amp;gt; th {&lt;br /&gt;
    padding-left: 152px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* [[Template:Sprite]] */&lt;br /&gt;
.sprite {&lt;br /&gt;
	display: inline-block;&lt;br /&gt;
	position: relative;&lt;br /&gt;
	overflow: hidden;&lt;br /&gt;
	vertical-align: middle;&lt;br /&gt;
	height: 16px;&lt;br /&gt;
	width: 16px;&lt;br /&gt;
}&lt;br /&gt;
.sprite &amp;gt; span {&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	height: 256px;&lt;br /&gt;
	width: 256px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* [[Template:Sprite/Preview]] */&lt;br /&gt;
.sprite-preview:hover div {&lt;br /&gt;
	opacity: 0.7 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* [[Template:Schematic]] */&lt;br /&gt;
.schematic img {&lt;br /&gt;
  image-rendering: crisp-edges;&lt;br /&gt;
  image-rendering: -moz-crisp-edges;&lt;br /&gt;
  image-rendering: -o-crisp-edges;&lt;br /&gt;
  image-rendering: -webkit-optimize-contrast;&lt;br /&gt;
  -ms-interpolation-mode: nearest-neighbor;&lt;br /&gt;
}&lt;br /&gt;
table.schematic {&lt;br /&gt;
  background-color: white;&lt;br /&gt;
  border-collapse: collapse;&lt;br /&gt;
  line-height: 0;&lt;br /&gt;
}&lt;br /&gt;
table.schematic td,&lt;br /&gt;
span.schematic {&lt;br /&gt;
  border: 1px solid #AAAAAA !important;&lt;br /&gt;
  padding: 0;&lt;br /&gt;
}&lt;br /&gt;
table.schematic span,&lt;br /&gt;
span.schematic {&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
table.schematic span span,&lt;br /&gt;
span.schematic span {&lt;br /&gt;
  color: black;&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
  left: 0;&lt;br /&gt;
  line-height: 1.5em;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  text-align: center;&lt;br /&gt;
  text-shadow: 0 0 2px #FFF;&lt;br /&gt;
  top: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/** Misc stuff **/&lt;br /&gt;
/* Prevent page jump from the toolbar loading, doesn&#039;t affect people with the toolbar disabled */&lt;br /&gt;
#toolbar {&lt;br /&gt;
	height: 22px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Remove the header from the main page */&lt;br /&gt;
body.page-Minecraft_Wiki.action-view h1.firstHeading {&lt;br /&gt;
	display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Collapsible Tables ([[MediaWiki:Common.js]]) */&lt;br /&gt;
table.collapsed tr.collapsible {&lt;br /&gt;
	display: none;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
.collapsible-button {&lt;br /&gt;
	float: right;&lt;br /&gt;
	font-weight: normal;&lt;br /&gt;
	text-align: right;&lt;br /&gt;
&lt;br /&gt;
	/* Other languages: Change this to a bit wider (~4px) than your collapse/expand button text */&lt;br /&gt;
	width: 3.5em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.collapsible.collapse-button-left &amp;gt; tr &amp;gt; th .collapsible-button,&lt;br /&gt;
.collapsible.collapse-button-left &amp;gt; * &amp;gt; tr &amp;gt; th .collapsible-button {&lt;br /&gt;
	float: left;&lt;br /&gt;
	text-align: left;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.collapsible.collapse-button-none &amp;gt; tr &amp;gt; th .collapsible-button,&lt;br /&gt;
.collapsible.collapse-button-none &amp;gt; * &amp;gt; tr &amp;gt; th .collapsible-button {&lt;br /&gt;
	float: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Alternating cell background, primarily used with [[Template:Infobox row]] */&lt;br /&gt;
.alternatecells:nth-child(odd) {&lt;br /&gt;
	background-color: #F9F9F9;&lt;br /&gt;
}&lt;br /&gt;
/* Alternating table rows */&lt;br /&gt;
.alternaterows tr:nth-child(even) {&lt;br /&gt;
	background-color: #F9F9F9;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* The blue header used throughout the wiki */&lt;br /&gt;
.mcwiki-header,&lt;br /&gt;
#curse-panel .block_header {&lt;br /&gt;
	background: #729FCF;&lt;br /&gt;
	border: 1px solid #ccc;&lt;br /&gt;
	border-bottom: 4px groove #999999;&lt;br /&gt;
	border-right: 4px groove #999999;&lt;br /&gt;
	padding: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Make transparency visible on image pages */&lt;br /&gt;
.filehistory a img,&lt;br /&gt;
#file img:hover {&lt;br /&gt;
	background: url(&amp;quot;http://hydra-media.cursecdn.com/minecraft=pl.gamepedia.com/5/5d/Checker-16x16.png&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
#file button img {&lt;br /&gt;
	background: none !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Scale file page image to the width of the page */&lt;br /&gt;
#file img {&lt;br /&gt;
	max-width: 100%;&lt;br /&gt;
	height: auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Remove margin from file page table */&lt;br /&gt;
#mw-imagepage-section-filehistory .filehistory {&lt;br /&gt;
	margin-right: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Highlight clicked reference in blue to help navigation */&lt;br /&gt;
ol.references li:target,&lt;br /&gt;
sup.reference:target,&lt;br /&gt;
span.citation:target { &lt;br /&gt;
	background-color: #C1DAF2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Style the sitenotice and fix up its awful spacing (why is it even a table!?) */&lt;br /&gt;
#siteNotice #localNotice,&lt;br /&gt;
.page-MediaWiki_Sitenotice .mw-content-ltr &amp;gt; div&lt;br /&gt;
 {&lt;br /&gt;
	background-color: #FFFFFF;&lt;br /&gt;
/*	border: 1px solid #D3D3D3;*/&lt;br /&gt;
	margin-bottom: 12px;&lt;br /&gt;
	text-align: center;&lt;br /&gt;
}&lt;br /&gt;
#siteNotice #mw-dismissable-notice #localNotice {&lt;br /&gt;
	/* Note to other languages: Change this to the same width as the &amp;quot;dismiss&amp;quot; button in your language, this makes the sitenotice centred better */&lt;br /&gt;
	margin-left: 55px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#siteNotice td:first-child {&lt;br /&gt;
	width: 100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#localNotice div p {&lt;br /&gt;
	padding: 0.4em 0 0.5em;&lt;br /&gt;
	margin: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Minecraft font */&lt;br /&gt;
@font-face {&lt;br /&gt;
	font-family: Minecraft;&lt;br /&gt;
	src: url(&amp;quot;http://hydra-media.cursecdn.com/minecraft.gamepedia.com/fonts/minecraft.eot?#iefix&amp;quot;),&lt;br /&gt;
		 url(&amp;quot;http://hydra-media.cursecdn.com/minecraft.gamepedia.com/fonts/minecraft.woff&amp;quot;) format(&#039;woff&#039;),&lt;br /&gt;
		 url(&amp;quot;http://hydra-media.cursecdn.com/minecraft.gamepedia.com/fonts/minecraft.ttf&amp;quot;)  format(&#039;truetype&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Allow parts of toc to be hidden */&lt;br /&gt;
/* Section levels */&lt;br /&gt;
.toc-hidelevel2 .toclevel-1 ul,&lt;br /&gt;
.toc-hidelevel3 .toclevel-2 ul,&lt;br /&gt;
.toc-hidelevel4 .toclevel-2 ul,&lt;br /&gt;
/* Numbers */&lt;br /&gt;
.toc-nonumbers .tocnumber {&lt;br /&gt;
	display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Pre-collapse collapsed tables, so there is no page jump when JS kicks in */&lt;br /&gt;
.collapsible.collapsed &amp;gt; tr,&lt;br /&gt;
.collapsible.collapsed &amp;gt; tbody &amp;gt; tr {&lt;br /&gt;
	display: none;&lt;br /&gt;
}&lt;br /&gt;
.collapsible.collapsed &amp;gt; tr:first-child,&lt;br /&gt;
.collapsible.collapsed &amp;gt; tbody &amp;gt; tr:first-child {&lt;br /&gt;
	display: table-row;&lt;br /&gt;
}&lt;br /&gt;
.collapsible.collapsed &amp;gt; thead + tbody &amp;gt; tr:first-child {&lt;br /&gt;
	display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Turn a list into a tree view style (See [[.minecraft]]) */&lt;br /&gt;
.treeview {&lt;br /&gt;
	margin-top: 0.3em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.treeview ul,&lt;br /&gt;
.treeview li {&lt;br /&gt;
	margin: 0;&lt;br /&gt;
	padding: 0;&lt;br /&gt;
	list-style-type: none;&lt;br /&gt;
	list-style-image: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.treeview li {&lt;br /&gt;
	display: table;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.treeview li li {&lt;br /&gt;
	position: relative;&lt;br /&gt;
	padding-left: 13px;&lt;br /&gt;
	margin-left: 7px;&lt;br /&gt;
	border-left: 1px solid #636363;&lt;br /&gt;
}&lt;br /&gt;
.treeview li li:before {&lt;br /&gt;
	content: &amp;quot;&amp;quot;;&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	top: 0;&lt;br /&gt;
	left: 0;&lt;br /&gt;
	width: 11px;&lt;br /&gt;
	height: 11px;&lt;br /&gt;
	border-bottom: 1px solid #636363;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.treeview li li.first:before {&lt;br /&gt;
	border-color: #636363;&lt;br /&gt;
	border-style: solid;&lt;br /&gt;
	border-width: 1px 0 0 1px;&lt;br /&gt;
	height: 100%;&lt;br /&gt;
	margin-top: 11px;&lt;br /&gt;
	width: 10px;&lt;br /&gt;
}&lt;br /&gt;
.treeview li li.first,&lt;br /&gt;
.treeview li li:last-child {&lt;br /&gt;
	border: 0;&lt;br /&gt;
	padding-left: 14px;&lt;br /&gt;
}&lt;br /&gt;
.treeview li li:last-child:before {&lt;br /&gt;
	border-left: 1px solid #636363;&lt;br /&gt;
	width: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Move suggestions back into place (netbar moved them) */&lt;br /&gt;
.suggestions {&lt;br /&gt;
	margin-top: -29px !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Simulate link styling for JS only links */&lt;br /&gt;
.jslink {&lt;br /&gt;
	color: #0645AD;&lt;br /&gt;
	-webkit-user-select: none;&lt;br /&gt;
	   -moz-user-select: none;&lt;br /&gt;
		-ms-user-select: none;&lt;br /&gt;
}&lt;br /&gt;
.jslink:hover {&lt;br /&gt;
	text-decoration: underline;&lt;br /&gt;
	cursor: pointer;&lt;br /&gt;
}&lt;br /&gt;
.jslink:active {&lt;br /&gt;
	color: #FAA700;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Improve styling of sub-categories */&lt;br /&gt;
#mw-subcategories ul {&lt;br /&gt;
	list-style-type: none;&lt;br /&gt;
	margin-left: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Use text arrows for enhanced rc instead of outdated (and broken) images */&lt;br /&gt;
td.mw-enhanced-rc {&lt;br /&gt;
	padding-left: 13px !important;&lt;br /&gt;
}&lt;br /&gt;
td + td.mw-enhanced-rc {&lt;br /&gt;
	padding-left: 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.mw-enhanced-rc img {&lt;br /&gt;
	display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.mw-rc-openarrow:after {&lt;br /&gt;
	content: &amp;quot;►&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
.mw-rc-closearrow:after {&lt;br /&gt;
	content: &amp;quot;▼&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.mw-enhanced-rc .mw-collapsible-toggle {&lt;br /&gt;
	cursor: pointer;&lt;br /&gt;
	color: #0645AD;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Horizontal list */&lt;br /&gt;
.hlist ul {&lt;br /&gt;
	display: inline;&lt;br /&gt;
	margin: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.hlist li {&lt;br /&gt;
	display: inline-block;&lt;br /&gt;
	white-space: nowrap;&lt;br /&gt;
	margin: 0;&lt;br /&gt;
}&lt;br /&gt;
.hlist li:after {&lt;br /&gt;
	content: &amp;quot; •&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
.hlist li:last-child:after,&lt;br /&gt;
.hlist li.last-child:after {&lt;br /&gt;
	content: &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.hlist li &amp;gt; ul li:first-child:before {&lt;br /&gt;
	content: &amp;quot;(&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
.hlist li &amp;gt; ul li:last-child:after,&lt;br /&gt;
.hlist li &amp;gt; ul li.last-child:after {&lt;br /&gt;
	content: &amp;quot;)&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.hlist li li li {&lt;br /&gt;
	font-size: x-small;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Generic styling for animation class */&lt;br /&gt;
.animated &amp;gt; *:not(.active):not(.skip),&lt;br /&gt;
.paused &amp;gt; *:not(.active):not(.skip) {&lt;br /&gt;
	display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.nowrap {&lt;br /&gt;
	white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Hide noscript only elements */&lt;br /&gt;
.noscript {&lt;br /&gt;
	display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Cite text needs to be a block element, but should display inline */&lt;br /&gt;
.references &amp;gt; li {&lt;br /&gt;
	white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
div.cite-reference-text {&lt;br /&gt;
	display: inline-block;&lt;br /&gt;
	vertical-align: top;&lt;br /&gt;
	white-space: normal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Add icon to known MC dev userlinks */&lt;br /&gt;
.mw-userlink[title=&amp;quot;User:Jeb&amp;quot;],&lt;br /&gt;
.mw-userlink[title=&amp;quot;User:Dinnerbone&amp;quot;],&lt;br /&gt;
.mw-userlink[title=&amp;quot;User:EvilSeph&amp;quot;],&lt;br /&gt;
.mw-userlink[title=&amp;quot;User:MarcWatson&amp;quot;],&lt;br /&gt;
.mw-userlink[title=&amp;quot;User:Tahg&amp;quot;] {&lt;br /&gt;
	padding-left: 17px;&lt;br /&gt;
	background: url(&amp;quot;http://hydra-media.cursecdn.com/minecraft.gamepedia.com/thumb/a/ad/Mojang_logo.svg/14px-Mojang_logo.svg.png&amp;quot;) no-repeat left center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Mark internal links as plain */&lt;br /&gt;
#content a.external[href^=&amp;quot;http://minecraft.gamepedia.com&amp;quot;] {&lt;br /&gt;
	background: none;&lt;br /&gt;
	padding-right: 0;&lt;br /&gt;
}&lt;br /&gt;
#content a.external[href^=&amp;quot;http://minecraft-pl.gamepedia.com&amp;quot;] {&lt;br /&gt;
	background: none;&lt;br /&gt;
	padding-right: 0;&lt;br /&gt;
}&lt;br /&gt;
/* Make tabs the correct size */&lt;br /&gt;
* {&lt;br /&gt;
	-moz-tab-size: 4;&lt;br /&gt;
	  -o-tab-size: 4;&lt;br /&gt;
	     tab-size: 4;&lt;br /&gt;
}&lt;br /&gt;
.new-navbox tr td li { &lt;br /&gt;
display: inline-block;&lt;br /&gt;
padding-right: 5px;&lt;br /&gt;
}&lt;br /&gt;
.new-navbox tr td li:last-child { &lt;br /&gt;
padding-right: 0px;&lt;br /&gt;
}&lt;br /&gt;
.new-navbox tr td li:last-child::after { &lt;br /&gt;
content: &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
.new-navbox tr td ul { &lt;br /&gt;
display: inline-block;&lt;br /&gt;
margin: 0px;&lt;br /&gt;
}&lt;br /&gt;
.new-navbox tr td li ul { &lt;br /&gt;
font-size: 90%;&lt;br /&gt;
}&lt;br /&gt;
.new-navbox tr td li ul::before { &lt;br /&gt;
content: &amp;quot; (&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
.new-navbox tr td li ul::after { &lt;br /&gt;
content: &amp;quot;) &amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
.new-navbox tr td li::after { &lt;br /&gt;
content: &amp;quot; •  &amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/*  START NOTIFICATIONS */&lt;br /&gt;
div.alert-message {&lt;br /&gt;
	display: block;&lt;br /&gt;
	padding: 13px 12px 12px;&lt;br /&gt;
	font-weight: bold !important;&lt;br /&gt;
	font-size: 14px;&lt;br /&gt;
	color: white;&lt;br /&gt;
	background-color: #2ba6cb;&lt;br /&gt;
	border: 1px solid rgba(0, 0, 0, 0.1);&lt;br /&gt;
	margin-bottom: 12px;&lt;br /&gt;
	-webkit-border-radius: 3px;&lt;br /&gt;
	-moz-border-radius: 3px;&lt;br /&gt;
	-ms-border-radius: 3px;&lt;br /&gt;
	-o-border-radius: 3px;&lt;br /&gt;
	border-radius: 3px;&lt;br /&gt;
	text-shadow: 0 -1px rgba(0, 0, 0, 0.3);&lt;br /&gt;
	position: relative;&lt;br /&gt;
}&lt;br /&gt;
div.alert-message a {&lt;br /&gt;
	color: white !important;&lt;br /&gt;
	text-decoration: underline !important;&lt;br /&gt;
}&lt;br /&gt;
div.alert-message .box-icon {&lt;br /&gt;
	display: block;&lt;br /&gt;
	float: left;&lt;br /&gt;
	background-image: url(&#039;/images/a/a6/NoticeIcon.png&#039;);&lt;br /&gt;
	width: 30px;&lt;br /&gt;
	height: 25px;&lt;br /&gt;
	margin-top: -2px;&lt;br /&gt;
	background-position: -8px -8px;&lt;br /&gt;
}&lt;br /&gt;
div.alert-message p {&lt;br /&gt;
	margin: 0px !important;&lt;br /&gt;
}&lt;br /&gt;
div.alert-message.success {&lt;br /&gt;
	background-color: #5da423;&lt;br /&gt;
	color: #fff;&lt;br /&gt;
	text-shadow: 0 -1px rgba(0, 0, 0, 0.3);&lt;br /&gt;
}&lt;br /&gt;
div.alert-message.success .box-icon {&lt;br /&gt;
	background-position: -48px -8px;&lt;br /&gt;
}&lt;br /&gt;
div.alert-message.warning {&lt;br /&gt;
	background-color: #e3b000;&lt;br /&gt;
	color: #fff;&lt;br /&gt;
	text-shadow: 0px 1px 5px rgba(0, 0, 0, 0.61);&lt;br /&gt;
}&lt;br /&gt;
div.alert-message.warning .box-icon {&lt;br /&gt;
	background-position: -88px -8px;&lt;br /&gt;
}&lt;br /&gt;
div.alert-message.error {&lt;br /&gt;
	background-color: #c60f13;&lt;br /&gt;
	color: #fff;&lt;br /&gt;
	text-shadow: 0 -1px rgba(0, 0, 0, 0.3);&lt;br /&gt;
}&lt;br /&gt;
div.alert-message.error .box-icon {&lt;br /&gt;
	background-position: -128px -8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* linki zewnętrzne do wewnątrz jako plaintext */&lt;br /&gt;
#content a.external[href^=&amp;quot;http://prisonwiki.pl&amp;quot;] {&lt;br /&gt;
	background: none;&lt;br /&gt;
	padding-right: 0;&lt;br /&gt;
}&lt;br /&gt;
#content a.external[href^=&amp;quot;http://devwiki.introversion.co.uk&amp;quot;] {&lt;br /&gt;
	background: none;&lt;br /&gt;
	padding-right: 0;&lt;br /&gt;
}&lt;br /&gt;
.plainlink a {&lt;br /&gt;
	background: none !important;&lt;br /&gt;
	padding-right: 0 !important;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* tooltips*/&lt;br /&gt;
/* Add this attribute to the element that needs a tooltip */&lt;br /&gt;
[data-tooltip] {&lt;br /&gt;
	position: relative;&lt;br /&gt;
	z-index: 2;&lt;br /&gt;
	cursor: pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Hide the tooltip content by default */&lt;br /&gt;
[data-tooltip]:before,&lt;br /&gt;
[data-tooltip]:after {&lt;br /&gt;
  visibility: hidden;&lt;br /&gt;
	-ms-filter: &amp;quot;progid:DXImageTransform.Microsoft.Alpha(Opacity=0)&amp;quot;;&lt;br /&gt;
	filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0);&lt;br /&gt;
	opacity: 0;&lt;br /&gt;
	pointer-events: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Position tooltip above the element */&lt;br /&gt;
[data-tooltip]:before {&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	bottom: 150%;&lt;br /&gt;
	left: 50%;&lt;br /&gt;
	margin-bottom: 5px;&lt;br /&gt;
	margin-left: -80px;&lt;br /&gt;
	padding: 7px;&lt;br /&gt;
	min-width: 160px;&lt;br /&gt;
	max-width: 300px;&lt;br /&gt;
	-webkit-border-radius: 3px;&lt;br /&gt;
	-moz-border-radius:    3px;&lt;br /&gt;
	border-radius:         3px;&lt;br /&gt;
	background-color: #000;&lt;br /&gt;
	background-color: hsla(0, 0%, 20%, 0.9);&lt;br /&gt;
	color: #fff;&lt;br /&gt;
	content: attr(data-tooltip);&lt;br /&gt;
	text-align: center;&lt;br /&gt;
	font-size: 14px;&lt;br /&gt;
	line-height: 1.2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Triangle hack to make tooltip look like a speech bubble */&lt;br /&gt;
[data-tooltip]:after {&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	bottom: 150%;&lt;br /&gt;
	left: 50%;&lt;br /&gt;
	margin-left: -5px;&lt;br /&gt;
	width: 0;&lt;br /&gt;
	border-top: 5px solid #000;&lt;br /&gt;
	border-top: 5px solid hsla(0, 0%, 20%, 0.9);&lt;br /&gt;
	border-right: 5px solid transparent;&lt;br /&gt;
	border-left: 5px solid transparent;&lt;br /&gt;
	content: &amp;quot; &amp;quot;;&lt;br /&gt;
	font-size: 0;&lt;br /&gt;
	line-height: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Show tooltip content on hover */&lt;br /&gt;
[data-tooltip]:hover:before,&lt;br /&gt;
[data-tooltip]:hover:after {&lt;br /&gt;
	visibility: visible;&lt;br /&gt;
	-ms-filter: &amp;quot;progid:DXImageTransform.Microsoft.Alpha(Opacity=100)&amp;quot;;&lt;br /&gt;
	filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);&lt;br /&gt;
	opacity: 1;&lt;br /&gt;
}&lt;br /&gt;
/* END NOTIFICATIONS */&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=MediaWiki:Gadget-spriteEditLoader.js&amp;diff=96832</id>
		<title>MediaWiki:Gadget-spriteEditLoader.js</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=MediaWiki:Gadget-spriteEditLoader.js&amp;diff=96832"/>
		<updated>2016-07-12T12:22:42Z</updated>

		<summary type="html">&lt;p&gt;Majr: Created page with &amp;quot;( function() { &amp;#039;use strict&amp;#039;; /**  * Add an edit button which loads the sprite editor  *  * If spriteaction=edit is in the URL, the editor will be loaded  * immediately, otherw...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;( function() {&lt;br /&gt;
&#039;use strict&#039;;&lt;br /&gt;
/**&lt;br /&gt;
 * Add an edit button which loads the sprite editor&lt;br /&gt;
 *&lt;br /&gt;
 * If spriteaction=edit is in the URL, the editor will be loaded&lt;br /&gt;
 * immediately, otherwise it will wait for the button to be clicked.&lt;br /&gt;
 * Uses the History API where supported to update the URL, otherwise&lt;br /&gt;
 * the URL isn&#039;t updated.&lt;br /&gt;
 */&lt;br /&gt;
if ( !$( &#039;#spritedoc&#039; ).length ) {&lt;br /&gt;
	return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var $editTab = $( &#039;#ca-edit&#039; );&lt;br /&gt;
if ( !$editTab.length ) {&lt;br /&gt;
	$editTab = $( &#039;#ca-viewsource&#039; );&lt;br /&gt;
}&lt;br /&gt;
var $spriteEditLink = $( &#039;&amp;lt;a&amp;gt;&#039; ).text( &#039;Edit sprite&#039; ).attr( &#039;href&#039;,&lt;br /&gt;
	mw.util.getUrl( null, { spriteaction: &#039;edit&#039; } )&lt;br /&gt;
);&lt;br /&gt;
var $spriteEditTab = $( &#039;&amp;lt;li&amp;gt;&#039; ).attr( &#039;id&#039;, &#039;ca-spriteedit&#039; ).append(&lt;br /&gt;
	$( &#039;&amp;lt;span&amp;gt;&#039; ).append( $spriteEditLink )&lt;br /&gt;
);&lt;br /&gt;
$spriteEditTab.insertAfter( $editTab );&lt;br /&gt;
&lt;br /&gt;
var loadSpriteEditor = function() {&lt;br /&gt;
	$spriteEditTab.add( &#039;#ca-view&#039; ).toggleClass( &#039;selected&#039; );&lt;br /&gt;
	&lt;br /&gt;
	mw.loader.load( &#039;ext.gadget.spriteEdit&#039; );&lt;br /&gt;
};&lt;br /&gt;
if ( location.search.match( &#039;spriteaction=edit&#039; ) ) {&lt;br /&gt;
	loadSpriteEditor();&lt;br /&gt;
} else {&lt;br /&gt;
	var $win = $( window );&lt;br /&gt;
	$spriteEditLink.one( &#039;click&#039;, function( e ) {&lt;br /&gt;
		if ( window.history &amp;amp;&amp;amp; history.pushState ) {&lt;br /&gt;
			// Initially add the history so it is not delayed waiting&lt;br /&gt;
			// for the editor to load. The editor will handle it from now.&lt;br /&gt;
			history.pushState( {}, &#039;&#039;, this.href );&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		loadSpriteEditor();&lt;br /&gt;
		$win.off( &#039;.spriteEditLoader&#039; );&lt;br /&gt;
		&lt;br /&gt;
		e.preventDefault();&lt;br /&gt;
	} );&lt;br /&gt;
	&lt;br /&gt;
	if ( window.history &amp;amp;&amp;amp; history.pushState ) {&lt;br /&gt;
		// If the page is reloaded while the editor isn&#039;t loaded, navigating&lt;br /&gt;
		// back to the editor won&#039;t work, so an initial navigation check is&lt;br /&gt;
		// necessary to load the editor, where it will then monitor navigation&lt;br /&gt;
		$win.on( &#039;popstate.spriteEditLoader&#039;, function() {&lt;br /&gt;
			if (&lt;br /&gt;
				location.search.match( &#039;spriteaction=edit&#039; ) &amp;amp;&amp;amp;&lt;br /&gt;
				!$( &#039;html&#039; ).hasClass( &#039;spriteedit-loaded&#039; )&lt;br /&gt;
			) {&lt;br /&gt;
				loadSpriteEditor();&lt;br /&gt;
				$win.off( &#039;.spriteEditLoader&#039; );&lt;br /&gt;
			}&lt;br /&gt;
		} );&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
}() );&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=MediaWiki:Gadget-refTooltip.js&amp;diff=96779</id>
		<title>MediaWiki:Gadget-refTooltip.js</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=MediaWiki:Gadget-refTooltip.js&amp;diff=96779"/>
		<updated>2016-06-07T08:21:08Z</updated>

		<summary type="html">&lt;p&gt;Majr: Allow specifying references section name so options button works on other languages&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;$( function() {&lt;br /&gt;
	&#039;use strict&#039;;&lt;br /&gt;
	&lt;br /&gt;
	var i18n = {&lt;br /&gt;
		cancelButton: &#039;Cancel&#039;,&lt;br /&gt;
		doneButton: &#039;Done&#039;,&lt;br /&gt;
		enableLabel: &#039;Enable reference tooltips&#039;,&lt;br /&gt;
		optionsButtonTitle: &#039;Change reference tooltip options&#039;,&lt;br /&gt;
		referencesSectionName: &#039;References&#039;,&lt;br /&gt;
		saveFailedStorageFull: &amp;quot;Is your browser&#039;s localStorage full?&amp;quot;,&lt;br /&gt;
		saveFailedTitle: &#039;Saving options failed&#039;&lt;br /&gt;
	};&lt;br /&gt;
	&lt;br /&gt;
	var $win = $( window );&lt;br /&gt;
	var $body = $( &#039;.mw-body&#039; );&lt;br /&gt;
	var $content = $( &#039;#mw-content-text&#039; );&lt;br /&gt;
	var $tooltip = $();&lt;br /&gt;
	var $tooltipText = $();&lt;br /&gt;
	var tooltipRect, tooltipInnerWidth, tooltipOffset, $anchor, anchorRect;&lt;br /&gt;
	var showTimer, hideTimer;&lt;br /&gt;
	var loggedIn = !!mw.config.get( &#039;wgUserId&#039; );&lt;br /&gt;
	var options = {&lt;br /&gt;
		enabled: true&lt;br /&gt;
	};&lt;br /&gt;
	if ( !loggedIn ) {&lt;br /&gt;
		try {&lt;br /&gt;
			options = JSON.parse( localStorage.refTooltip );&lt;br /&gt;
		} catch ( e ) {}&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	var createTooltip = function( $anchor, content, showOptions ) {&lt;br /&gt;
		// Get rid of any existing tooltip&lt;br /&gt;
		$tooltip.remove();&lt;br /&gt;
		&lt;br /&gt;
		// Create the tooltip&lt;br /&gt;
		$tooltip = $( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;ref-tooltip&#039; ).data( {&lt;br /&gt;
			anchor: $anchor,&lt;br /&gt;
			fresh: true,&lt;br /&gt;
		} ).hover( function() {&lt;br /&gt;
		// Callback to the ref&#039;s hover functions when the tooltip is hovered over&lt;br /&gt;
			$anchor.mouseenter();&lt;br /&gt;
		}, function() {&lt;br /&gt;
			$anchor.mouseleave();&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		$tooltipText = $( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;ref-tooltip-text&#039; )&lt;br /&gt;
			.append( content ).appendTo( $tooltip );&lt;br /&gt;
		if ( showOptions ) {&lt;br /&gt;
			$tooltipText.prepend(&lt;br /&gt;
				$( &#039;&amp;lt;button&amp;gt;&#039; ).addClass( &#039;pixel-image ref-tooltip-options-button&#039; )&lt;br /&gt;
					.attr( &#039;title&#039;, i18n.optionsButtonTitle )&lt;br /&gt;
			);&lt;br /&gt;
		}&lt;br /&gt;
		$( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;ref-tooltip-arrow&#039; ).appendTo( $tooltip );&lt;br /&gt;
		$tooltip.appendTo( &#039;body&#039; );&lt;br /&gt;
		// Set width to content size&lt;br /&gt;
		$tooltipText.width( $tooltipText.width() + 1 );&lt;br /&gt;
		&lt;br /&gt;
		setPos( true );&lt;br /&gt;
		&lt;br /&gt;
		// Data prevents tooltips being immediately closed if opened via a click&lt;br /&gt;
		setTimeout( function() {&lt;br /&gt;
			$tooltip.removeData( &#039;fresh&#039; );&lt;br /&gt;
		}, 0 );&lt;br /&gt;
	};&lt;br /&gt;
	var removeTooltip = function() {&lt;br /&gt;
		$tooltip.trigger( &#039;refTooltip-close&#039; );&lt;br /&gt;
		&lt;br /&gt;
		$tooltip.remove();&lt;br /&gt;
		$tooltip = $();&lt;br /&gt;
	};&lt;br /&gt;
	var getRefText = function( $ref ) {&lt;br /&gt;
		var refId = $ref.find( &#039;a&#039; ).attr( &#039;href&#039; ).split( &#039;#&#039; )[1];&lt;br /&gt;
		var $refText = $( document.getElementById( refId ) ).clone();&lt;br /&gt;
		$refText.find( &#039;.mw-cite-backlink&#039; ).remove();&lt;br /&gt;
		&lt;br /&gt;
		return $refText.html();&lt;br /&gt;
	};&lt;br /&gt;
	var setPos = function( initial ) {&lt;br /&gt;
		if ( !$tooltip.length ) {&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		if ( initial ) {&lt;br /&gt;
			tooltipRect = $tooltipText[0].getBoundingClientRect();&lt;br /&gt;
			tooltipInnerWidth = $tooltipText.width();&lt;br /&gt;
			tooltipOffset = {&lt;br /&gt;
				top: parseFloat( $tooltipText.css( &#039;margin-top&#039; ) ),&lt;br /&gt;
				left: parseFloat( $tooltipText.css( &#039;margin-left&#039; ) )&lt;br /&gt;
			};&lt;br /&gt;
			$anchor = $tooltip.data( &#039;anchor&#039; );&lt;br /&gt;
			anchorRect = $anchor[0].getBoundingClientRect();&lt;br /&gt;
		} else {&lt;br /&gt;
			$tooltip.removeClass( &#039;ref-tooltip-flipped&#039; );&lt;br /&gt;
			$tooltipText.css( &#039;margin-left&#039;, &#039;&#039; );&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		// Position the tooltip&lt;br /&gt;
		var tooltipPos = {&lt;br /&gt;
			top: $win.scrollTop(),&lt;br /&gt;
			left: $win.scrollLeft()&lt;br /&gt;
		};&lt;br /&gt;
		if ( anchorRect.top + tooltipOffset.top &amp;lt; tooltipRect.height ) {&lt;br /&gt;
			$tooltip.addClass( &#039;ref-tooltip-flipped&#039; );&lt;br /&gt;
			tooltipPos.top += anchorRect.bottom;&lt;br /&gt;
		} else {&lt;br /&gt;
			tooltipPos.top += anchorRect.top - tooltipRect.height;&lt;br /&gt;
		}&lt;br /&gt;
		tooltipPos.left += anchorRect.left + anchorRect.width / 2;&lt;br /&gt;
		&lt;br /&gt;
		// Stop it going off the side of the page&lt;br /&gt;
		var contentPadding = parseFloat( $body.css( &#039;padding-right&#039; ) );&lt;br /&gt;
		var contentBoundary = $body[0].getBoundingClientRect().right - contentPadding / 2;&lt;br /&gt;
		var overlap = anchorRect.left + tooltipOffset.left + tooltipRect.width - contentBoundary;&lt;br /&gt;
		if ( overlap &amp;gt; 0 ) {&lt;br /&gt;
			$tooltipText.css(&lt;br /&gt;
				&#039;margin-left&#039;,&lt;br /&gt;
				Math.max( tooltipOffset.left - overlap, -tooltipInnerWidth )&lt;br /&gt;
			);&lt;br /&gt;
		}&lt;br /&gt;
		$tooltip.css( tooltipPos );&lt;br /&gt;
	};&lt;br /&gt;
	var bindRefHandlers = function() {&lt;br /&gt;
		$content.on( {&lt;br /&gt;
			&#039;mouseenter.refTooltip&#039;: function() {&lt;br /&gt;
				var $this = $( this );&lt;br /&gt;
				&lt;br /&gt;
				clearTimeout( hideTimer );&lt;br /&gt;
				&lt;br /&gt;
				// Current tooltip, do nothing&lt;br /&gt;
				if ( $tooltip.length &amp;amp;&amp;amp; (&lt;br /&gt;
					$this.is( $tooltip.data( &#039;anchor&#039; ) ) || $.contains( $tooltip[0], this )&lt;br /&gt;
				) ) {&lt;br /&gt;
					return;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				// Create the tooltip if timeout succeeds&lt;br /&gt;
				showTimer = setTimeout( function() {&lt;br /&gt;
					createTooltip( $this, getRefText( $this ), true );&lt;br /&gt;
				}, 200 );&lt;br /&gt;
			},&lt;br /&gt;
			&#039;mouseleave.refTooltip&#039;: function() {&lt;br /&gt;
				clearTimeout( showTimer );&lt;br /&gt;
				&lt;br /&gt;
				// Remove the tooltip if timeout succeeds&lt;br /&gt;
				hideTimer = setTimeout( function() {&lt;br /&gt;
					removeTooltip();&lt;br /&gt;
				}, 300 );&lt;br /&gt;
			}&lt;br /&gt;
		}, &#039;.reference&#039; );&lt;br /&gt;
	};&lt;br /&gt;
	&lt;br /&gt;
	// When anywhere but the tooltip or anchor is clicked, remove it immediately&lt;br /&gt;
	$( window ).on( &#039;click.refTooltip&#039;, function( e ) {&lt;br /&gt;
		if ( $tooltip.length &amp;amp;&amp;amp; !$tooltip.data( &#039;fresh&#039; ) &amp;amp;&amp;amp; !$.contains( $tooltip[0], e.target ) ) {&lt;br /&gt;
			clearTimeout( showTimer );&lt;br /&gt;
			removeTooltip();&lt;br /&gt;
		}&lt;br /&gt;
	} );&lt;br /&gt;
	&lt;br /&gt;
	// TODO: Replace with mw.util.escapeId on MW 1.27&lt;br /&gt;
	var escapeId = function( id ) {&lt;br /&gt;
		return mw.util.rawurlencode( String( id ).replace( / /g, &#039;_&#039; ) )&lt;br /&gt;
	        .replace( /%3A/g, &#039;:&#039; )&lt;br /&gt;
	        .replace( /%/g, &#039;.&#039; );&lt;br /&gt;
	};&lt;br /&gt;
	$( document.getElementById( escapeId( i18n.referencesSectionName ) ) ).before(&lt;br /&gt;
		$( &#039;&amp;lt;button&amp;gt;&#039; ).addClass( &#039;pixel-image ref-tooltip-options-button&#039; )&lt;br /&gt;
			.attr( &#039;title&#039;, i18n.optionsButtonTitle )&lt;br /&gt;
	);&lt;br /&gt;
	$( &#039;body&#039; ).on( &#039;click.refTooltip&#039;, &#039;.ref-tooltip-options-button&#039;, function( e ) {&lt;br /&gt;
		// Just close the tooltip if it is already open&lt;br /&gt;
		if ( $tooltip.length &amp;amp;&amp;amp; $tooltip.data( &#039;anchor&#039; ).is( e.target ) ) {&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		// Disable ref handlers while options are open&lt;br /&gt;
		$content.off( &#039;mouseenter.refTooltip mouseleave.refTooltip&#039; );&lt;br /&gt;
		$tooltip.on( &#039;refTooltip-close&#039;, function() {&lt;br /&gt;
			if ( options.enabled ) {&lt;br /&gt;
				bindRefHandlers();&lt;br /&gt;
			}&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
		var $anchor = $( this );&lt;br /&gt;
		&lt;br /&gt;
		$anchor.addClass( &#039;ref-tooltip-loading&#039; );&lt;br /&gt;
		&lt;br /&gt;
		// Replace current tooltip if clicking the options button within a tooltip&lt;br /&gt;
		if ( $tooltip.length &amp;amp;&amp;amp; $.contains( $tooltip[0], $anchor[0] ) ) {&lt;br /&gt;
			$anchor = $tooltip.data( &#039;anchor&#039; );&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		mw.loader.using( [ &#039;mediawiki.api&#039;, &#039;mediawiki.ui.button&#039;, &#039;mediawiki.ui.checkbox&#039; ], function() {&lt;br /&gt;
			$anchor.removeClass( &#039;ref-tooltip-loading&#039; );&lt;br /&gt;
			&lt;br /&gt;
			var $optionsText = $( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;ref-tooltip-options&#039; ).append(&lt;br /&gt;
				$( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;mw-ui-checkbox&#039; ).append(&lt;br /&gt;
					$( &#039;&amp;lt;input&amp;gt;&#039; ).attr( {&lt;br /&gt;
						type: &#039;checkbox&#039;,&lt;br /&gt;
						id: &#039;ref-tooltip-options-enabled&#039;,&lt;br /&gt;
						checked: options.enabled&lt;br /&gt;
					} ),&lt;br /&gt;
					$( &#039;&amp;lt;label&amp;gt;&#039; ).attr( &#039;for&#039;, &#039;ref-tooltip-options-enabled&#039; ).text( i18n.enableLabel )&lt;br /&gt;
				),&lt;br /&gt;
				$( &#039;&amp;lt;div&amp;gt;&#039; ).addClass( &#039;ref-tooltip-actions&#039; ).append(&lt;br /&gt;
					$( &#039;&amp;lt;button&amp;gt;&#039; ).addClass( &#039;mw-ui-button mw-ui-quiet&#039; ).text( i18n.cancelButton )&lt;br /&gt;
						.on( &#039;click.refTooltip&#039;, function() {&lt;br /&gt;
							removeTooltip();&lt;br /&gt;
						} ),&lt;br /&gt;
					$( &#039;&amp;lt;button&amp;gt;&#039; ).addClass( &#039;mw-ui-button mw-ui-progressive&#039; ).text( i18n.doneButton )&lt;br /&gt;
						.on( &#039;click.refTooltip&#039;, function() {&lt;br /&gt;
							options.enabled = $( &#039;#ref-tooltip-options-enabled&#039; ).prop( &#039;checked&#039; );&lt;br /&gt;
							var saveOptions = $.Deferred();&lt;br /&gt;
							if ( loggedIn ) {&lt;br /&gt;
								saveOptions = new mw.Api().postWithToken( &#039;edit&#039;, {&lt;br /&gt;
									action: &#039;options&#039;,&lt;br /&gt;
									optionname: &#039;gadget-refTooltip&#039;,&lt;br /&gt;
									optionvalue: options.enabled ? undefined : 0&lt;br /&gt;
								} );&lt;br /&gt;
							} else {&lt;br /&gt;
								try {&lt;br /&gt;
									localStorage.refTooltip = JSON.stringify( options );&lt;br /&gt;
									saveOptions.resolve();&lt;br /&gt;
								} catch ( e ) {&lt;br /&gt;
									saveOptions.reject( &#039;storage&#039; );&lt;br /&gt;
								}&lt;br /&gt;
							}&lt;br /&gt;
							&lt;br /&gt;
							saveOptions.then( function() {&lt;br /&gt;
								removeTooltip();&lt;br /&gt;
							}, function( code, error ) {&lt;br /&gt;
								mw.notify(&lt;br /&gt;
									code === &#039;storage&#039; ? i18n.saveFailedStorageFull : error,&lt;br /&gt;
									{ title: i18n.saveFailedTitle }&lt;br /&gt;
								);&lt;br /&gt;
							} );&lt;br /&gt;
						} )&lt;br /&gt;
				)&lt;br /&gt;
			);&lt;br /&gt;
			&lt;br /&gt;
			createTooltip( $anchor, $optionsText, false );&lt;br /&gt;
			$tooltip.on( &#039;refTooltip-close&#039;, function() {&lt;br /&gt;
				if ( options.enabled ) {&lt;br /&gt;
					bindRefHandlers();&lt;br /&gt;
				}&lt;br /&gt;
			} );&lt;br /&gt;
		} );&lt;br /&gt;
	} );&lt;br /&gt;
	&lt;br /&gt;
	// Finally, enable tooltips&lt;br /&gt;
	if ( options.enabled ) {&lt;br /&gt;
		bindRefHandlers();&lt;br /&gt;
	}&lt;br /&gt;
} );&lt;br /&gt;
&lt;br /&gt;
// Add width and height to Element.getBoundingClientRect() in IE8&lt;br /&gt;
// TODO: Remove on 1.27&lt;br /&gt;
if ( window.TextRectangle &amp;amp;&amp;amp; !TextRectangle.prototype.width ) {&lt;br /&gt;
	Object.defineProperty( TextRectangle.prototype, &#039;width&#039;, {&lt;br /&gt;
		get: function() { return this.right - this.left; }&lt;br /&gt;
	} );&lt;br /&gt;
	Object.defineProperty( TextRectangle.prototype, &#039;height&#039;, {&lt;br /&gt;
		get: function() { return this.bottom - this.top; }&lt;br /&gt;
	} );&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=MediaWiki:Gadget-refTooltip.css&amp;diff=96776</id>
		<title>MediaWiki:Gadget-refTooltip.css</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=MediaWiki:Gadget-refTooltip.css&amp;diff=96776"/>
		<updated>2016-05-12T12:58:14Z</updated>

		<summary type="html">&lt;p&gt;Majr: Use protocol relative URL&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;.ref-tooltip {&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	margin-top: -29px;&lt;br /&gt;
	font-size: 0.875em;&lt;br /&gt;
	z-index: 99;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.ref-tooltip-text {&lt;br /&gt;
	border: 1px solid #AAA;&lt;br /&gt;
	border-radius: 2px;&lt;br /&gt;
	background-color: #FFF;&lt;br /&gt;
	box-shadow: 0 2px 0 rgba(0, 0, 0, 0.15);&lt;br /&gt;
	margin-top: -14px;&lt;br /&gt;
	margin-left: -21px;&lt;br /&gt;
	padding: 0.5em 0.8em;&lt;br /&gt;
	font-size: smaller;&lt;br /&gt;
	min-width: 20px;&lt;br /&gt;
	max-width: 300px;&lt;br /&gt;
	word-wrap: break-word;&lt;br /&gt;
}&lt;br /&gt;
.ref-tooltip-flipped &amp;gt; .ref-tooltip-text {&lt;br /&gt;
	margin-top: 13px;&lt;br /&gt;
}&lt;br /&gt;
.ref-tooltip-text &amp;gt; p:first-child {&lt;br /&gt;
	margin-top: 0;&lt;br /&gt;
}&lt;br /&gt;
.ref-tooltip-text &amp;gt; p:last-child {&lt;br /&gt;
	margin-bottom: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.ref-tooltip-arrow,&lt;br /&gt;
.ref-tooltip-arrow:before,&lt;br /&gt;
.ref-tooltip-arrow:after {&lt;br /&gt;
	content: &amp;quot;&amp;quot;;&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	bottom: -9px;&lt;br /&gt;
	left: -9px;&lt;br /&gt;
	border: 10px solid;&lt;br /&gt;
	border-color: #888 transparent;&lt;br /&gt;
	border-bottom-style: none;&lt;br /&gt;
	width: 0;&lt;br /&gt;
	height: 0;&lt;br /&gt;
}&lt;br /&gt;
.ref-tooltip-arrow:before {&lt;br /&gt;
	bottom: -3px;&lt;br /&gt;
	left: -10px;&lt;br /&gt;
	border-color: rgba(0, 0, 0, 0.15) transparent;&lt;br /&gt;
}&lt;br /&gt;
.ref-tooltip-arrow:after {&lt;br /&gt;
	bottom: 1px;&lt;br /&gt;
	left: -9px;&lt;br /&gt;
	border-color: #FFF transparent;&lt;br /&gt;
	border-width: 9px;&lt;br /&gt;
}&lt;br /&gt;
.ref-tooltip-flipped &amp;gt; .ref-tooltip-arrow,&lt;br /&gt;
.ref-tooltip-flipped &amp;gt; .ref-tooltip-arrow:after {&lt;br /&gt;
	bottom: auto;&lt;br /&gt;
	border-top-style: none;&lt;br /&gt;
	border-bottom-style: solid;&lt;br /&gt;
}&lt;br /&gt;
.ref-tooltip-flipped &amp;gt; .ref-tooltip-arrow {&lt;br /&gt;
	top: 4px;&lt;br /&gt;
}&lt;br /&gt;
.ref-tooltip-flipped &amp;gt; .ref-tooltip-arrow:before {&lt;br /&gt;
	content: none;&lt;br /&gt;
}&lt;br /&gt;
.ref-tooltip-flipped &amp;gt; .ref-tooltip-arrow:after {&lt;br /&gt;
	top: 1px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.ref-tooltip-options-button {&lt;br /&gt;
	display: inline-block;&lt;br /&gt;
	font: inherit;&lt;br /&gt;
	float: right;&lt;br /&gt;
	-webkit-appearance: none;&lt;br /&gt;
	border: none;&lt;br /&gt;
	outline: none;&lt;br /&gt;
	background: url(//hydra-media.cursecdn.com/minecraft.gamepedia.com/e/e0/Reference_options.png) no-repeat;&lt;br /&gt;
	margin: 0.3em 0 0 0.5em;&lt;br /&gt;
	width: 16px;&lt;br /&gt;
	height: 16px;&lt;br /&gt;
	cursor: pointer;&lt;br /&gt;
}&lt;br /&gt;
.ref-tooltip-options-button::-moz-focus-inner {&lt;br /&gt;
   border: none;&lt;br /&gt;
}&lt;br /&gt;
.ref-tooltip-options-button.ref-tooltip-loading {&lt;br /&gt;
	animation: 1s linear infinite rotate;&lt;br /&gt;
}&lt;br /&gt;
.ref-tooltip-text .ref-tooltip-options-button {&lt;br /&gt;
	margin-top: -0.1em;&lt;br /&gt;
	margin-right: -0.3em;&lt;br /&gt;
}&lt;br /&gt;
.ref-tooltip-options {&lt;br /&gt;
	padding: 0.3em 0;&lt;br /&gt;
}&lt;br /&gt;
.ref-tooltip-actions {&lt;br /&gt;
	margin-top: 0.8em;&lt;br /&gt;
	text-align: right;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=MediaWiki:Gadget-editableRollback.css&amp;diff=96589</id>
		<title>MediaWiki:Gadget-editableRollback.css</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=MediaWiki:Gadget-editableRollback.css&amp;diff=96589"/>
		<updated>2016-05-12T12:57:57Z</updated>

		<summary type="html">&lt;p&gt;Majr: Use protocol relative URL&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;.edit-rollback {&lt;br /&gt;
	display: inline-block;&lt;br /&gt;
	width: 10px;&lt;br /&gt;
	height: 10px;&lt;br /&gt;
	margin-left: 2px;&lt;br /&gt;
	background: url(//hydra-media.cursecdn.com/minecraft.gamepedia.com/6/6c/Edit_pencil.png) no-repeat;&lt;br /&gt;
	cursor: pointer;&lt;br /&gt;
}&lt;br /&gt;
#rollback-summary {&lt;br /&gt;
	display: flex;&lt;br /&gt;
	align-items: center;&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	left: 1em;&lt;br /&gt;
	right: 1em;&lt;br /&gt;
	padding: 0.8em;&lt;br /&gt;
	border: 1px solid #CCC;&lt;br /&gt;
	background-color: #F9F9F9;&lt;br /&gt;
	z-index: 99;&lt;br /&gt;
	box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.2);&lt;br /&gt;
}&lt;br /&gt;
#rollback-summary &amp;gt; *:first-child {&lt;br /&gt;
	flex: auto;&lt;br /&gt;
	margin-right: 1em;&lt;br /&gt;
}&lt;br /&gt;
#rollback-summary &amp;gt; .rollback-submit-button {&lt;br /&gt;
	flex: none;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=MediaWiki:Gadget-editableRollback&amp;diff=96586</id>
		<title>MediaWiki:Gadget-editableRollback</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=MediaWiki:Gadget-editableRollback&amp;diff=96586"/>
		<updated>2016-05-09T06:31:21Z</updated>

		<summary type="html">&lt;p&gt;Majr: Created page with &amp;quot;Allow editing rollback summary&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Allow editing rollback summary&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=MediaWiki:Gadget-editableRollback.js&amp;diff=96594</id>
		<title>MediaWiki:Gadget-editableRollback.js</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=MediaWiki:Gadget-editableRollback.js&amp;diff=96594"/>
		<updated>2016-05-09T06:30:16Z</updated>

		<summary type="html">&lt;p&gt;Majr: Majr moved page User:Majr/editableRollback.js to MediaWiki:Gadget-editableRollback.js&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;$( function() {&lt;br /&gt;
&#039;use strict&#039;;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
$( &#039;.mw-rollback-link &amp;gt; a&#039; ).after( $( &#039;&amp;lt;span&amp;gt;&#039; ).addClass( &#039;edit-rollback&#039; ).prop( &#039;title&#039;, &#039;Edit rollback summary&#039; ) );&lt;br /&gt;
$( &#039;#mw-content-text&#039; ).on( &#039;click&#039;, &#039;.edit-rollback&#039;, function() {&lt;br /&gt;
	var $rollback = $( &#039;#rollback-summary&#039; );&lt;br /&gt;
	&lt;br /&gt;
	if ( $( this ).parent().is( $rollback.parent() ) ) {&lt;br /&gt;
		$rollback.toggle();&lt;br /&gt;
	} else {&lt;br /&gt;
		$rollback.remove();&lt;br /&gt;
		&lt;br /&gt;
		var name = decodeURIComponent( $( this ).prev().prop( &#039;href&#039; ).match( /&amp;amp;from=(.+)&amp;amp;token/ )[1].replace( /\+/g, &#039; &#039; ) );&lt;br /&gt;
		$rollback = $( &#039;&amp;lt;div id=&amp;quot;rollback-summary&amp;quot;&amp;gt;&#039; ).append(&lt;br /&gt;
			$( &#039;&amp;lt;input type=&amp;quot;text&amp;quot;&amp;gt;&#039; ).addClass( &#039;mw-ui-input rollback-text&#039; ).prop( { maxlength: 250, spellcheck: true } ).val(&lt;br /&gt;
				&#039;Revert consecutive edits by [[Special:Contribs/&#039; + name + &#039;|&#039; + name + &#039;]] ([[User talk:&#039; + name + &#039;|talk]])&#039;&lt;br /&gt;
			),&lt;br /&gt;
			$( &#039;&amp;lt;input type=&amp;quot;button&amp;quot;&amp;gt;&#039; ).addClass( &#039;mw-ui-button mw-ui-constructive rollback-submit-button&#039; ).val( &#039;Rollback&#039; )&lt;br /&gt;
		).insertAfter( this );&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	// This puts the cursor at the end of the text&lt;br /&gt;
	var $text = $rollback.find( &#039;.rollback-text&#039; );&lt;br /&gt;
	var summary = $text.val();&lt;br /&gt;
	$text.focus().val( &#039;&#039; ).val( summary );&lt;br /&gt;
} );&lt;br /&gt;
&lt;br /&gt;
$( &#039;#mw-content-text&#039; ).on( &#039;click&#039;, &#039;.rollback-submit-button&#039;, function() {&lt;br /&gt;
	var $link = $( this ).closest( &#039;.mw-rollback-link&#039; );&lt;br /&gt;
	window.location = $link.find( &#039;a&#039; ).prop( &#039;href&#039; ) + &#039;&amp;amp;summary=&#039; + encodeURIComponent( $link.find( &#039;.rollback-text&#039; ).val() );&lt;br /&gt;
} );&lt;br /&gt;
&lt;br /&gt;
// Allow rollback to be submitted by pressing enter while focused on the input field&lt;br /&gt;
$( &#039;#mw-content-text&#039; ).on( &#039;keypress&#039;, &#039;.rollback-text&#039;, function( e ) {&lt;br /&gt;
	if ( e.which !== 13 ) {&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
	e.preventDefault();&lt;br /&gt;
	$( &#039;.rollback-submit-button&#039; ).click();&lt;br /&gt;
} );&lt;br /&gt;
&lt;br /&gt;
// Close rollback if clicked anywhere else&lt;br /&gt;
$( window ).click( function( e ) {&lt;br /&gt;
	if ( !$( e.target ).is( &#039;#rollback-summary, .edit-rollback&#039; ) &amp;amp;&amp;amp; !$( &#039;#rollback-summary&#039; ).has( e.target ).length ) {&lt;br /&gt;
		$( &#039;#rollback-summary&#039; ).hide();&lt;br /&gt;
	}&lt;br /&gt;
} );&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
} );&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=MediaWiki:Gadget-refTooltip&amp;diff=96773</id>
		<title>MediaWiki:Gadget-refTooltip</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=MediaWiki:Gadget-refTooltip&amp;diff=96773"/>
		<updated>2016-05-08T04:50:49Z</updated>

		<summary type="html">&lt;p&gt;Majr: Created page with &amp;quot;Show reference content in a tooltip when hovered over&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Show reference content in a tooltip when hovered over&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=U%C5%BCytkownik:Majr&amp;diff=71344</id>
		<title>Użytkownik:Majr</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=U%C5%BCytkownik:Majr&amp;diff=71344"/>
		<updated>2015-05-08T11:43:16Z</updated>

		<summary type="html">&lt;p&gt;Majr: Utworzono nową stronę &amp;quot;&amp;lt;div class=&amp;quot;redirectMsg&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;font-size:200%;font-weight:bold;margin-right:.5em&amp;quot;&amp;gt;↳&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;redirectText&amp;quot;&amp;gt;:en:User:Majr&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;redirectMsg&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;font-size:200%;font-weight:bold;margin-right:.5em&amp;quot;&amp;gt;↳&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;redirectText&amp;quot;&amp;gt;[[:en:User:Majr]]&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=Szablon:Za%C5%82aduj&amp;diff=103158</id>
		<title>Szablon:Załaduj</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=Szablon:Za%C5%82aduj&amp;diff=103158"/>
		<updated>2014-10-06T01:55:23Z</updated>

		<summary type="html">&lt;p&gt;Majr: Update formatting&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;&amp;lt;div class=&amp;quot;load-page&amp;quot; data-page=&amp;quot;{{{1}}}&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;{{{3|h2}}}&amp;gt;{{#if: {{{2|}}} | {{{2}}} | {{{1}}} }}&amp;lt;/{{{3|h2}}}&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;load-page-content noscript&amp;quot;&amp;gt;{{main|{{{1}}}}}&amp;lt;span class=&amp;quot;mw-editsection&amp;quot; title=&amp;quot;Редактировать: {{{1}}}&amp;quot;&amp;gt;[&amp;lt;nowiki/&amp;gt;[{{fullurl: {{{1}}} | action=edit }} {{int:editlink}}]&amp;lt;nowiki/&amp;gt;]&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;{{Док}}[[Category:Шаблоны]]&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=Plik:Wiki.png&amp;diff=94162</id>
		<title>Plik:Wiki.png</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=Plik:Wiki.png&amp;diff=94162"/>
		<updated>2014-10-01T05:39:51Z</updated>

		<summary type="html">&lt;p&gt;Majr: Majr przesłano nową wersję pliku „Plik:Wiki.png“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;MsUpload&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=Plik:Achievement_background.png&amp;diff=79090</id>
		<title>Plik:Achievement background.png</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=Plik:Achievement_background.png&amp;diff=79090"/>
		<updated>2014-10-01T05:15:59Z</updated>

		<summary type="html">&lt;p&gt;Majr: Zabezpieczył(a) „Plik:Achievement background.png”: Style image ([edytowanie=Dozwolone tylko dla administratorów] (na zawsze) [przenoszenie=Dozwolone tylko dla administratorów] (na zawsze) [przesyłanie=Dozwolone tylko dla administratorów] (na &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Licencja ==&lt;br /&gt;
{{License Mojang}}&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=Plik:Achievement_background.png&amp;diff=79089</id>
		<title>Plik:Achievement background.png</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=Plik:Achievement_background.png&amp;diff=79089"/>
		<updated>2014-10-01T05:14:56Z</updated>

		<summary type="html">&lt;p&gt;Majr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Licencja ==&lt;br /&gt;
{{License Mojang}}&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=U%C5%BCytkownik:Majr/hydra.css&amp;diff=71345</id>
		<title>Użytkownik:Majr/hydra.css</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=U%C5%BCytkownik:Majr/hydra.css&amp;diff=71345"/>
		<updated>2014-09-29T13:18:08Z</updated>

		<summary type="html">&lt;p&gt;Majr: Utworzono nową stronę &amp;quot;@import &amp;quot;http://minecraft.gamepedia.com/index.php?title=User:Majr/hydra.css&amp;amp;action=raw&amp;amp;ctype=text/css&amp;quot;;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;@import &amp;quot;http://minecraft.gamepedia.com/index.php?title=User:Majr/hydra.css&amp;amp;action=raw&amp;amp;ctype=text/css&amp;quot;;&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=U%C5%BCytkownik:Majr/hydra.js&amp;diff=71347</id>
		<title>Użytkownik:Majr/hydra.js</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=U%C5%BCytkownik:Majr/hydra.js&amp;diff=71347"/>
		<updated>2014-09-29T13:12:37Z</updated>

		<summary type="html">&lt;p&gt;Majr: Utworzono nową stronę &amp;quot;importScriptURI( &amp;#039;http://minecraft.gamepedia.com/index.php?title=User:Majr/hydra.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&amp;#039; );&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;importScriptURI( &#039;http://minecraft.gamepedia.com/index.php?title=User:Majr/hydra.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&#039; );&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=Szablon:YouTube&amp;diff=103121</id>
		<title>Szablon:YouTube</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=Szablon:YouTube&amp;diff=103121"/>
		<updated>2014-09-11T04:54:39Z</updated>

		<summary type="html">&lt;p&gt;Majr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;{{#ev:youtube|{{{1}}}|{{#if: {{{2|}}} | {{{2}}} | 425 }}}}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{documentation}}&lt;br /&gt;
&amp;lt;!-- Put categories/interwiki on the documentation page --&amp;gt;&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=Szablon:YouTube&amp;diff=103119</id>
		<title>Szablon:YouTube</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=Szablon:YouTube&amp;diff=103119"/>
		<updated>2014-01-31T08:39:54Z</updated>

		<summary type="html">&lt;p&gt;Majr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;{{#if: {{{sd|}}}&lt;br /&gt;
| {{#ev:youtube|{{{1}}}|{{#if: {{{2|}}} | {{{2}}} | 425 }}}}&lt;br /&gt;
| {{#ev:youtubehd|{{{1}}}|{{#if: {{{2|}}} | {{{2}}} | 425 }}}}&lt;br /&gt;
}}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{documentation}}&lt;br /&gt;
&amp;lt;!-- Put categories/interwiki on the documentation page --&amp;gt;&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=Szablon:Zwini%C4%99ty_film&amp;diff=103189</id>
		<title>Szablon:Zwinięty film</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=Szablon:Zwini%C4%99ty_film&amp;diff=103189"/>
		<updated>2013-03-14T09:23:58Z</updated>

		<summary type="html">&lt;p&gt;Majr: Use collapsible tables instead of links.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;{| class=&amp;quot;collapsible collapsed collapse-button-none&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;text-align:left&amp;quot; | {{#if: {{{2|}}} | {{{2}}} | YouTube }} Video ([http://www.youtube.com/watch?v={{{1}}} view on YouTube])&lt;br /&gt;
|-&lt;br /&gt;
| {{YouTube|{{{1}}}}}&amp;amp;nbsp;&lt;br /&gt;
|}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{/doc}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Formatting templates]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=Szablon:Zwini%C4%99ty_film&amp;diff=103188</id>
		<title>Szablon:Zwinięty film</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=Szablon:Zwini%C4%99ty_film&amp;diff=103188"/>
		<updated>2013-03-14T09:18:18Z</updated>

		<summary type="html">&lt;p&gt;Majr: moved Template:Yt to Template:CollapsedVideo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;{{#if: {{{2|}}} |[}}http://www.youtube.com/watch?v={{{1}}} {{#if: {{{2|}}} |{{{2}}}]}}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{/doc}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Formatting templates]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=Szablon:YouTube&amp;diff=103116</id>
		<title>Szablon:YouTube</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=Szablon:YouTube&amp;diff=103116"/>
		<updated>2013-03-14T09:07:29Z</updated>

		<summary type="html">&lt;p&gt;Majr: Created page with &amp;quot;&amp;lt;includeonly&amp;gt;{{#if: {{{sd|}}} | {{#ev:youtube|{{{1}}}|{{#if: {{{2|}}} | {{{2}}} | 425 }}}} | {{#ev:youtubehd|{{{1}}}|{{#if: {{{2|}}} | {{{2}}} | 425 }}}} }}&amp;lt;/includeonly&amp;gt;&amp;lt;noin...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;{{#if: {{{sd|}}}&lt;br /&gt;
| {{#ev:youtube|{{{1}}}|{{#if: {{{2|}}} | {{{2}}} | 425 }}}}&lt;br /&gt;
| {{#ev:youtubehd|{{{1}}}|{{#if: {{{2|}}} | {{{2}}} | 425 }}}}&lt;br /&gt;
}}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{doc}}&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=Szablon:Fraction&amp;diff=99453</id>
		<title>Szablon:Fraction</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=Szablon:Fraction&amp;diff=99453"/>
		<updated>2011-04-05T07:26:22Z</updated>

		<summary type="html">&lt;p&gt;Majr: moved Template:Frac to Template:Fraction&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{#if:{{{3|}}} | {{{1}}}&amp;amp;nbsp;&amp;lt;sup&amp;gt;{{{2}}}&amp;lt;/sup&amp;gt;&amp;amp;frasl;&amp;lt;sub&amp;gt;{{{3}}} | &amp;lt;sup&amp;gt;{{{1}}}&amp;lt;/sup&amp;gt;&amp;amp;frasl;&amp;lt;sub&amp;gt;{{{2}}} }}&amp;lt;/sub&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{/doc}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Templates]]&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=Szablon:Frac&amp;diff=99448</id>
		<title>Szablon:Frac</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=Szablon:Frac&amp;diff=99448"/>
		<updated>2011-04-05T07:26:22Z</updated>

		<summary type="html">&lt;p&gt;Majr: moved Template:Frac to Template:Fraction&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Template:Fraction]]&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=Szablon:Fraction&amp;diff=99452</id>
		<title>Szablon:Fraction</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=Szablon:Fraction&amp;diff=99452"/>
		<updated>2011-04-05T07:18:17Z</updated>

		<summary type="html">&lt;p&gt;Majr: Oops&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{#if:{{{3|}}} | {{{1}}}&amp;amp;nbsp;&amp;lt;sup&amp;gt;{{{2}}}&amp;lt;/sup&amp;gt;&amp;amp;frasl;&amp;lt;sub&amp;gt;{{{3}}} | &amp;lt;sup&amp;gt;{{{1}}}&amp;lt;/sup&amp;gt;&amp;amp;frasl;&amp;lt;sub&amp;gt;{{{2}}} }}&amp;lt;/sub&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{/doc}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Templates]]&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
	<entry>
		<id>https://minewiki.pl/index.php?title=Szablon:Fraction&amp;diff=99451</id>
		<title>Szablon:Fraction</title>
		<link rel="alternate" type="text/html" href="https://minewiki.pl/index.php?title=Szablon:Fraction&amp;diff=99451"/>
		<updated>2011-04-05T07:16:36Z</updated>

		<summary type="html">&lt;p&gt;Majr: This template smells like a wikipedia carbon copy&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{#if:{{{2|}}} | {{{1}}}&amp;amp;nbsp;&amp;lt;sup&amp;gt;{{{2}}}&amp;lt;/sup&amp;gt;&amp;amp;frasl;&amp;lt;sub&amp;gt;{{{3}}} | &amp;lt;sup&amp;gt;{{{1}}}&amp;lt;/sup&amp;gt;&amp;amp;frasl;&amp;lt;sub&amp;gt;{{{2}}} }}&amp;lt;/sub&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{/doc}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Templates]]&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Majr</name></author>
	</entry>
</feed>