( function () {     // An mw.Api object     var api;      // Keep "common" at beginning     var SKINS = [ "common", "monobook", "minerva", "vector", "vector-2022", "timeless" ];      // How many scripts do we need before we show the quick filter?     var NUM_SCRIPTS_FOR_SEARCH = 5;      // The master import list, keyed by target. (A "target" is a user JS subpage     // where the script is imported, like "common" or "vector".) Set in buildImportList     var imports = {};      // Local scripts, keyed on name; value will be the target. Set in buildImportList.     var localScriptsByName = {};      // How many scripts are installed?     var scriptCount = 0;      // Goes on the end of edit summaries     var ADVERT = " (স্ক্রিপ্ট ইনস্টলার)";     var link = $("<a>")         .attr("href", mw.util.getUrl("উইকিপিডিয়া:ব্যবহারকারী স্ক্রিপ্ট/তালিকা"))         .text("(আরও স্ক্রিপ্ট)");      /**      * Strings, for translation      */     var STRINGS = {         installSummary: "$1 ইনস্টল করা হয়েছে",         installLinkText: "ইনস্টল করুন",         installProgressMsg: "ইনস্টল করা হচ্ছে...",         uninstallSummary: "$1 আনইনস্টল করা হয়েছে",         uninstallLinkText: "আনইনস্টল করুন",         uninstallProgressMsg: "আনইনস্টল করা হচ্ছে...",         disableSummary: "$1 নিষ্ক্রিয় করা হয়েছে",         disableLinkText: "নিষ্ক্রিয় করুন",         disableProgressMsg: "নিষ্ক্রিয় করা হচ্ছে...",         enableSummary: "$1 সক্রিয় করা হয়েছে",         enableLinkText: "সক্রিয় করুন",         enableProgressMsg: "সক্রিয় করা হচ্ছে...",         moveLinkText: "স্থানান্তর করুন",         moveProgressMsg: "স্থানান্তর করা হচ্ছে...",         movePrompt: "গন্তব্য? নিচের যেকোনও একটি প্রবেশ করান:", // followed by the names of skins         normalizeSummary: "স্ক্রিপ্ট ইনস্টল স্বাভাবিকীকরণ",         remoteUrlDesc: "$1, $2 হতে লোড করা হয়েছে",         panelHeader: "আপনার বর্তমানে নিম্নের স্ক্রিপ্টগুলো ইনস্টল করা রয়েছে। ",         cannotInstall: "ইনস্টল করা যাবেনা",         cannotInstallSkin: "এই পাতাটি আপনার ব্যবহারকারী কাস্টমাইজকরণ পাতাগুলোর একটি। আর হয়তঃ (যদি common.js হয়, তাহলে নিশ্চিতভাবে) প্রতি পাতা লোড হওয়ার সময় ইতোমধ্যে স্বয়ংক্রিয়ভাবে চালিত হয়।",         cannotInstallContentModel: "এই পাতাটির বিষয়বস্তুর রূপ হচ্ছে $1, 'javascript' নয়।",         insecure: "(অনিরাপদ)", // used at the end of some messages         notJavaScript: "জাভাস্ক্রিপ্ট নয়",         installViaPreferences: "পছন্দসমূহের মাধ্যমে ইনস্টল",         showNormalizeLinks: ' "স্বাভাবিকীকরণ" সংযোগ দেখান?',         showMoveLinks: ' "স্থানান্তর করুন" সংযোগ দেখান?',         quickFilter: "তড়িৎ ছাঁকনি:",         tempWarning: "ব্যবহারকারী ও মিডিয়াউইকি নামস্থান ব্যতীত অন্যান্য নামস্থানের সুরক্ষিত পাতাগুলোর ইনস্টলকরণ অস্থায়ী এবং ভবিষ্যতে খুব সম্ভবত সরিয়ে ফেলা হবে।",         badPageError: "পাতাটি ব্যবহারকারী: বা মিডিয়াউইকি: নামস্থানের নয় এবং অরক্ষিত",         manageUserScripts: "স্ক্রিপ্ট পরিচালনা",         bigSecurityWarning: "সতর্কতা!$1\n\nসমস্ত ব্যবহারকারীর স্ক্রিপ্টে ক্ষতিকারক সামগ্রী থাকতে পারে যা আপনার অ্যাকাউন্ট বেহাত করতে সক্ষম। একটি স্ক্রিপ্ট ইনস্টল করার অর্থ এটি অন্যদের দ্বারা পরিবর্তন হতে পারে; নিশ্চিত করুন যে আপনি এর লেখককে বিশ্বাস করেন। আপনি যদি নিশ্চিত না হন যে এই স্ক্রিপ্ট নিরাপদ কিনা, তাহলে তা নিয়ে আলোচনাসভায় আলোচনা করুন। এই স্ক্রিপ্টটি ইনস্টল করবেন?",         securityWarningSection: " আপনি $1 ইনস্টল করতে যাচ্ছেন।"     };      var USER_NAMESPACE_NAME = mw.config.get( "wgFormattedNamespaces" )[2];      /**      * Constructs an Import. An Import is a line in a JS file that imports a      * user script. Properties:      *      *  - "page" is a page name, such as "User:Foo/Bar.js".      *  - "wiki" is a wiki from which the script is loaded, such as      *    "en.wikipedia". If null, the script is local, on the user's      *    wiki.      *  - "url" is a URL that can be passed into mw.loader.load.      *  - "target" is the title of the user subpage where the script is,      *    without the .js ending: for example, "common".      *  - "disabled" is whether this import is commented out.      *  - "type" is 0 if local, 1 if remotely loaded, and 2 if URL.      *      * EXACTLY one of "page" or "url" are null for every Import. This      * constructor should not be used directly; use the factory      * functions (Import.ofLocal, Import.ofUrl, Import.fromJs) instead.      */     function Import( page, wiki, url, target, disabled ) {         this.page = page;         this.wiki = wiki;         this.url = url;         this.target = target;         this.disabled = disabled;         this.type = this.url ? 2 : ( this.wiki ? 1 : 0 );     }      Import.ofLocal = function ( page, target, disabled ) {         if( disabled === undefined ) disabled = false;         return new Import( page, null, null, target, disabled );     }      /** URL to Import. Assumes wgScriptPath is "/w" */     Import.ofUrl = function ( url, target, disabled ) {         if( disabled === undefined ) disabled = false;         var URL_RGX = /^(?:https?:)?\/\/(.+?)\.org\/w\/index\.php\?.*?title=(.+?(?:&|$))/;         var match;         if( match = URL_RGX.exec( url ) ) {             var title = decodeURIComponent( match[2].replace( /&$/, "" ) ),                 wiki = decodeURIComponent( match[1] );             return new Import( title, wiki, null, target, disabled );         }         return new Import( null, null, url, target, disabled );     }      Import.fromJs = function ( line, target ) {         var IMPORT_RGX = /^\s*(\/\/)?\s*importScript\s*\(\s*(?:"|')(.+?)(?:"|')\s*\)/;         var match;         if( match = IMPORT_RGX.exec( line ) ) {             return Import.ofLocal( unescapeForJsString( match[2] ), target, !!match[1] );         }          var LOADER_RGX = /^\s*(\/\/)?\s*mw\.loader\.load\s*\(\s*(?:"|')(.+?)(?:"|')\s*\)/;         if( match = LOADER_RGX.exec( line ) ) {             return Import.ofUrl( unescapeForJsString( match[2] ), target, !!match[1] );         }     }      Import.prototype.getDescription = function ( useWikitext ) {         switch( this.type ) {             case 0: return useWikitext ? ( "" + this.page + "" ) : this.page;             case 1: return STRINGS.remoteUrlDesc.replace( "$1", this.page ).replace( "$2", this.wiki );             case 2: return this.url;         }     }      /**      * Human-readable (NOT necessarily suitable for ResourceLoader) URL.      */     Import.prototype.getHumanUrl = function () {         switch( this.type ) {             case 0: return "/wiki/" + encodeURI( this.page );             case 1: return "//" + this.wiki + ".org/wiki/" + encodeURI( this.page );             case 2: return this.url;         }     }      Import.prototype.toJs = function () {         var dis = this.disabled ? "//" : "",             url = this.url;         switch( this.type ) {             case 0: return dis + "importScript('" + escapeForJsString( this.page ) + "'); // পিছন সংযোগ: " + escapeForJsComment( this.page ) + "";             case 1: url = "//" + encodeURIComponent( this.wiki ) + ".org/w/index.php?title=" +                             encodeURIComponent( this.page ) + "&action=raw&ctype=text/javascript";                      /* FALL THROUGH */             case 2: return dis + "mw.loader.load('" + escapeForJsString( url ) + "');";         }     }      /**      * Installs the import.      */     Import.prototype.install = function () {         return api.postWithEditToken( {             action: "edit",             title: getFullTarget( this.target ),             summary: STRINGS.installSummary.replace( "$1", this.getDescription( /* useWikitext */ true ) ) + ADVERT,             appendtext: "\n" + this.toJs()         } );     }      /**      * Get all line numbers from the target page that mention      * the specified script.      */     Import.prototype.getLineNums = function ( targetWikitext ) {         function quoted( s ) {             return new RegExp( "(['\"])" + escapeForRegex( s ) + "\\1" );         }         var toFind;         switch( this.type ) {             case 0: toFind = quoted( escapeForJsString( this.page ) ); break;             case 1: toFind = new RegExp( escapeForRegex( encodeURIComponent( this.wiki ) ) + ".*?" +                             escapeForRegex( encodeURIComponent( this.page ) ) ); break;             case 2: toFind = quoted( escapeForJsString( this.url ) ); break;         }         var lineNums = [], lines = targetWikitext.split( "\n" );         for( var i = 0; i < lines.length; i++ ) {             if( toFind.test( lines[i] ) ) {                 lineNums.push( i );             }         }         return lineNums;     }      /**      * Uninstalls the given import. That is, delete all lines from the      * target page that import the specified script.      */     Import.prototype.uninstall = function () {         var that = this;         return getWikitext( getFullTarget( this.target ) ).then( function ( wikitext ) {             var lineNums = that.getLineNums( wikitext ),                 newWikitext = wikitext.split( "\n" ).filter( function ( _, idx ) {                     return lineNums.indexOf( idx ) < 0;                 } ).join( "\n" );             return api.postWithEditToken( {                 action: "edit",                 title: getFullTarget( that.target ),                 summary: STRINGS.uninstallSummary.replace( "$1", that.getDescription( /* useWikitext */ true ) ) + ADVERT,                 text: newWikitext             } );         } );     }      /**      * Sets whether the given import is disabled, based on the provided      * boolean value.      */     Import.prototype.setDisabled = function ( disabled ) {         var that = this;         this.disabled = disabled;         return getWikitext( getFullTarget( this.target ) ).then( function ( wikitext ) {             var lineNums = that.getLineNums( wikitext ),                 newWikitextLines = wikitext.split( "\n" );              if( disabled ) {                 lineNums.forEach( function ( lineNum ) {                     if( newWikitextLines[lineNum].trim().indexOf( "//" ) != 0 ) {                         newWikitextLines[lineNum] = "//" + newWikitextLines[lineNum].trim();                     }                 } );             } else {                 lineNums.forEach( function ( lineNum ) {                     if( newWikitextLines[lineNum].trim().indexOf( "//" ) == 0 ) {                         newWikitextLines[lineNum] = newWikitextLines[lineNum].replace( /^\s*\/\/\s*/, "" );                     }                 } );             }              var summary = ( disabled ? STRINGS.disableSummary : STRINGS.enableSummary )                     .replace( "$1", that.getDescription( /* useWikitext */ true ) ) + ADVERT;             return api.postWithEditToken( {                 action: "edit",                 title: getFullTarget( that.target ),                 summary: summary,                 text: newWikitextLines.join( "\n" )             } );         } );     }      Import.prototype.toggleDisabled = function () {         this.disabled = !this.disabled;         return this.setDisabled( this.disabled );     }      /**      * Move this import to another file.      */     Import.prototype.move = function ( newTarget ) {         if( this.target === newTarget ) return;         var old = new Import( this.page, this.wiki, this.url, this.target, this.disabled );         this.target = newTarget;         return $.when( old.uninstall(), this.install() );     }      function getAllTargetWikitexts() {         return $.getJSON(             mw.util.wikiScript( "api" ),             {                 format: "json",                 action: "query",                 prop: "revisions",                 rvprop: "content",                 rvslots: "main",                 titles: SKINS.map( getFullTarget ).join( "|" )             }         ).then( function ( data ) {             if( data && data.query && data.query.pages ) {                 var result = {};                     prefixLength = mw.config.get( "wgUserName" ).length + 6;                 Object.values( data.query.pages ).forEach( function ( moreData ) {                     var nameWithoutExtension = new mw.Title( moreData.title ).getNameText();                     var targetName = nameWithoutExtension.substring( nameWithoutExtension.indexOf( "/" ) + 1 );                     result[targetName] = moreData.revisions ? moreData.revisions[0].slots.main["*"] : null;                 } );                 return result;             }         } );     }      function buildImportList() {         return getAllTargetWikitexts().then( function ( wikitexts ) {             Object.keys( wikitexts ).forEach( function ( targetName ) {                 var targetImports = [];                 if( wikitexts[ targetName ] ) {                     var lines = wikitexts[ targetName ].split( "\n" );                     var currImport;                     for( var i = 0; i < lines.length; i++ ) {                         if( currImport = Import.fromJs( lines[i], targetName ) ) {                             targetImports.push( currImport );                             scriptCount++;                             if( currImport.type === 0 ) {                                 if( !localScriptsByName[ currImport.page ] )                                     localScriptsByName[ currImport.page ] = [];                                 localScriptsByName[ currImport.page ].push( currImport.target );                             }                         }                     }                 }                 imports[ targetName ] = targetImports;             } );         } );     }      /*      * "Normalizes" (standardizes the format of) lines in the given      * config page.      */     function normalize( target ) {         return getWikitext( getFullTarget( target ) ).then( function ( wikitext ) {             var lines = wikitext.split( "\n" ),                 newLines = Array( lines.length ),                 currImport;             for( var i = 0; i < lines.length; i++ ) {                 if( currImport = Import.fromJs( lines[i], target ) ) {                     newLines[i] = currImport.toJs();                 } else {                     newLines[i] = lines[i];                 }             }             return api.postWithEditToken( {                 action: "edit",                 title: getFullTarget( target ),                 summary: STRINGS.normalizeSummary,                 text: newLines.join( "\n" )             } );         } );     }      function conditionalReload( openPanel ) {         if( window.scriptInstallerAutoReload ) {             if( openPanel ) document.cookie = "open_script_installer=yes";             window.location.reload( true );         }     }      /********************************************      *      * UI code      *      ********************************************/     function makePanel() {         var list = $( "<div>" ).attr( "id", "script-installer-panel" )             .append( $( "<header>" ).text( STRINGS.panelHeader ) );           list.find("header").append(link);              var container = $( "<div>" ).addClass( "container" ).appendTo( list );                  // Container for checkboxes         container.append( $( "<div>" )             .attr( "class", "checkbox-container" )             .append(                 $( "<input>" )                     .attr( { "id": "siNormalize", "type": "checkbox" } )                     .click( function () {                         $( ".normalize-wrapper" ).toggle( 0 )                     } ),                 $( "<label>" )                     .attr( "for", "siNormalize" )                     .text( STRINGS.showNormalizeLinks ),                 $( "<input>" )                     .attr( { "id": "siMove", "type": "checkbox" } )                     .click( function () {                         $( ".move-wrapper" ).toggle( 0 )                     } ),                 $( "<label>" )                     .attr( "for", "siMove" )                     .text( STRINGS.showMoveLinks ) ) );         if( scriptCount > NUM_SCRIPTS_FOR_SEARCH ) {             container.append( $( "<div>" )                 .attr( "class", "filter-container" )                 .append(                     $( "<label>" )                         .attr( "for", "siQuickFilter" )                         .text( STRINGS.quickFilter ),                     $( "<input>" )                         .attr( { "id": "siQuickFilter", "type": "text" } )                         .on( "input", function () {                             var filterString = $( this ).val();                             if( filterString ) {                                 var sel = "#script-installer-panel li[name*='" +                                         $.escapeSelector( $( this ).val() ) + "']";                                 $( "#script-installer-panel li.script" ).toggle( false );                                 $( sel ).toggle( true );                             } else {                                 $( "#script-installer-panel li.script" ).toggle( true );                             }                         } )                 ) );              // Now, get the checkboxes out of the way             container.find( ".checkbox-container" )                 .css( "float", "right" );         }         $.each( imports, function ( targetName, targetImports ) {             var fmtTargetName = ( targetName === "common"                 ? "সার্বজনীন (সকল স্কিনে প্রয়োগ হয়)"                 : targetName );                 if( targetImports.length ) {                 container.append(                     $( "<h2>" ).append(                         fmtTargetName,                         $( "<span>" )                         .addClass( "normalize-wrapper" )                         .append(                              " (",                             $( "<a>" )                                 .text( "স্বাভাবিকীকরণ" )                                 .click( function () {                                     normalize( targetName ).done( function () {                                         conditionalReload( true );                                     } );                                  } ),                             ")" )                             .hide() ),                         $( "<ul>" ).append(                             targetImports.map( function ( anImport ) {                                 return $( "<li>" )                                     .addClass( "script" )                                     .attr( "name", anImport.getDescription() )                                     .append(                                         $( "<a>" )                                             .text( anImport.getDescription() )                                             .addClass( "script" )                                             .attr( "href", anImport.getHumanUrl() ),                                         " (",                                         $( "<a>" )                                             .text( STRINGS.uninstallLinkText )                                             .click( function () {                                                 $( this ).text( STRINGS.uninstallProgressMsg );                                                 anImport.uninstall().done( function () {                                                     conditionalReload( true );                                                 } );                                             } ),                                         " | ",                                         $( "<a>" )                                             .text( anImport.disabled ? STRINGS.enableLinkText : STRINGS.disableLinkText )                                             .click( function () {                                                 $( this ).text( anImport.disabled ? STRINGS.enableProgressMsg : STRINGS.disableProgressMsg );                                                 anImport.toggleDisabled().done( function () {                                                     $( this ).toggleClass( "disabled" );                                                     conditionalReload( true );                                                 } );                                             } ),                                         $( "<span>" )                                             .addClass( "move-wrapper" )                                             .append(                                             " | ",                                             $( "<a>" )                                                 .text( STRINGS.moveLinkText )                                                 .click( function () {                                                     var dest = null;                                                     var PROMPT = STRINGS.movePrompt + " " + SKINS.join( ", " );                                                     do {                                                         dest = ( window.prompt( PROMPT ) || "" ).toLowerCase();                                                     } while( dest && SKINS.indexOf( dest ) < 0 )                                                     if( !dest ) return;                                                     $( this ).text( STRINGS.moveProgressMsg );                                                     anImport.move( dest ).done( function () {                                                         conditionalReload( true );                                                     } );                                                 } )                                             )                                             .hide(),                                         ")" )                                 .toggleClass( "disabled", anImport.disabled );                                 } ) ) );                 }         } );         return list;     }      function buildCurrentPageInstallElement() {         var addingInstallLink = false; // will we be adding a legitimate install link?         var installElement = $( "<span>" ); // only used if addingInstallLink is set to true          var namespaceNumber = mw.config.get( "wgNamespaceNumber" );         var pageName = mw.config.get( "wgPageName" );          // Namespace 2 is User         if( namespaceNumber === 2 &&                 pageName.indexOf( "/" ) > 0 ) {             var contentModel = mw.config.get( "wgPageContentModel" );             if( contentModel === "javascript" ) {                 var prefixLength = mw.config.get( "wgUserName" ).length + 6;                 if( pageName.indexOf( USER_NAMESPACE_NAME + ":" + mw.config.get( "wgUserName" ) ) === 0 ) {                     var skinIndex = SKINS.indexOf( pageName.substring( prefixLength ).slice( 0, -3 ) );                     if( skinIndex >= 0 ) {                         return $( "<abbr>" ).text( STRINGS.cannotInstall )                                 .attr( "title", STRINGS.cannotInstallSkin );                     }                 }                 addingInstallLink = true;             } else {                 return $( "<abbr>" ).text( STRINGS.cannotInstall + " (" + STRINGS.notJavaScript + ")" )                         .attr( "title", STRINGS.cannotInstallContentModel.replace( "$1", contentModel ) );             }         }          // Namespace 8 is MediaWiki         if( namespaceNumber === 8 ) {             return $( "<a>" ).text( STRINGS.installViaPreferences )                     .attr( "href", mw.util.getUrl( "Special:Preferences" ) + "#mw-prefsection-gadgets" );         }          var editRestriction = mw.config.get( "wgRestrictionEdit" ) || [];         if( ( namespaceNumber !== 2 && namespaceNumber !== 8 ) &&             ( editRestriction.indexOf( "sysop" ) >= 0 ||                 editRestriction.indexOf( "editprotected" ) >= 0 ) ) {             installElement.append( " ",                 $( "<abbr>" ).append(                     $( "" ).attr( "src", "https://upload.wikimedia.org/wikipedia/commons/thumb/3/35/Achtung-yellow.svg/20px-Achtung-yellow.svg.png" ).addClass( "warning" ),                     STRINGS.insecure )                 .attr( "title", STRINGS.tempWarning ) );             addingInstallLink = true;         }          if( addingInstallLink ) {             var fixedPageName = mw.config.get( "wgPageName" ).replace( /_/g, " " );             installElement.prepend( $( "<a>" )                     .attr( "id", "script-installer-main-install" )                     .text( localScriptsByName[ fixedPageName ] ? STRINGS.uninstallLinkText : STRINGS.installLinkText )                     .click( makeLocalInstallClickHandler( fixedPageName ) ) );              // If the script is installed but disabled, allow the user to enable it             var allScriptsInTarget = imports[ localScriptsByName[ fixedPageName ] ];             var importObj = allScriptsInTarget && allScriptsInTarget.find( function ( anImport ) { return anImport.page === fixedPageName; } );             if( importObj && importObj.disabled ) {                 installElement.append( " | ",                     $( "<a>" )                         .attr( "id", "script-installer-main-enable" )                         .text( STRINGS.enableLinkText )                         .click( function () {                             $( this ).text( STRINGS.enableProgressMsg );                             importObj.setDisabled( false ).done( function () {                                 conditionalReload( false );                             } );                         } ) );             }             return installElement;         }          return $( "<abbr>" ).text( STRINGS.cannotInstall + " " + STRINGS.insecure )                 .attr( "title", STRINGS.badPageError );     }      function showUi() {         var fixedPageName = mw.config.get( "wgPageName" ).replace( /_/g, " " );         $( "#firstHeading" ).append( $( "<span>" )             .attr( "id", "script-installer-top-container" )             .append(                 buildCurrentPageInstallElement(),                 " | ",                 $( "<a>" )                     .text( STRINGS.manageUserScripts ).click( function () {                         if( !document.getElementById( "script-installer-panel" ) ) {                             $( "#mw-content-text" ).before( makePanel() );                         } else {                             $( "#script-installer-panel" ).remove();                         }                      } ) ) );     }      function attachInstallLinks() {         // At the end of each  transclusion, there is         //          $( "span.scriptInstallerLink" ).each( function () {             var scriptName = this.id;             $( this ).append( " | ", $( "<a>" )                     .text( localScriptsByName[ scriptName ] ? STRINGS.uninstallLinkText : STRINGS.installLinkText )                     .click( makeLocalInstallClickHandler( scriptName ) ) );         } );          $( "table.infobox-user-script" ).each( function () {             var scriptName = $( this ).find( "th:contains('উৎস')" ).next().text() ||                     mw.config.get( "wgPageName" );             scriptName = /ব্যবহারকারী:.+?\/.+?.js/i.exec( scriptName )[0];             $( this ).children( "tbody" ).append( $( "" ).append( $( "" )                     .attr( "colspan", "2" )                     .addClass( "script-installer-ibx" )                     .append( $( "<button>" )                         .addClass( "mw-ui-button mw-ui-progressive mw-ui-big" )                         .text( localScriptsByName[ scriptName ] ? STRINGS.uninstallLinkText : STRINGS.installLinkText )                         .click( makeLocalInstallClickHandler( scriptName ) ) ) ) );         } );     }      function makeLocalInstallClickHandler( scriptName ) {         return function () {             var $this = $( this );             if( $this.text() === STRINGS.installLinkText ) {                 var okay = window.confirm(                     STRINGS.bigSecurityWarning.replace( '$1',                         STRINGS.securityWarningSection.replace( '$1', scriptName ) ) );                 if( okay ) {                     $( this ).text( STRINGS.installProgressMsg )                     Import.ofLocal( scriptName, window.scriptInstallerInstallTarget ).install().done( function () {                         $( this ).text( STRINGS.uninstallLinkText );                         conditionalReload( false );                     }.bind( this ) );                 }             } else {                 $( this ).text( STRINGS.uninstallProgressMsg )                 var uninstalls = uniques( localScriptsByName[ scriptName ] )                         .map( function ( target ) { return Import.ofLocal( scriptName, target ).uninstall(); } )                 $.when.apply( $, uninstalls ).then( function () {                     $( this ).text( STRINGS.installLinkText );                     conditionalReload( false );                 }.bind( this ) );             }          };     }      function addCss() {         mw.util.addCSS(             "#script-installer-panel li.disabled a.script { "+               "text-decoration: line-through; font-style: italic; }"+             "#script-installer-panel { width:100%; border:solid black 1.5px; border-radius:3px; "+               "padding:0; margin-left: auto; "+               "margin-right: auto; margin-bottom: 15px; overflow: auto; "+               "box-shadow: 5px 5px 5px #999; background-color: #fff; z-index:50; }"+             "#script-installer-panel header { background-color:#CAE1FF; display:block;"+               "padding:5px; font-size:1.1em; font-weight:bold; text-align:left; }"+             "#script-installer-panel .checkbox-container input { margin-left: 1.5em; }"+             "#script-installer-panel .filter-container { margin-bottom: -0.75em; }"+             "#script-installer-panel .filter-container label { margin-right: 0.35em; }"+             "#script-installer-panel .container { padding: 0.75em; }"+             "#script-installer-panel .container h2 { margin-top: 0.75em; }"+             "#script-installer-panel a { cursor: pointer; }"+             "#script-installer-main-install { font-weight: bold ; }"+             "#script-installer-top-container { bottom: 5px; font-size: 70%; margin-left: 1em }"+             "body.skin-modern #script-installer-top-container a { color: inherit; cursor: pointer }"+             "body.skin-timeless #script-installer-top-container a,body.skin-cologneblue #script-installer-top-container a { cursor: pointer }"+             "#script-installer-top-container img.warning { position: relative; top: -2px; margin-right: 3px }"+             "td.script-installer-ibx { text-align: center }"         );     }      /********************************************      *      * Utility functions      *      ********************************************/      /**      * Gets the wikitext of a page with the given title (namespace required).      */     function getWikitext( title ) {         return $.getJSON(             mw.util.wikiScript( "api" ),             {                 format: "json",                 action: "query",                 prop: "revisions",                 rvprop: "content",                 rvslots: "main",                 rvlimit: 1,                 titles: title             }         ).then( function ( data ) {             var pageId = Object.keys( data.query.pages )[0];             if( data.query.pages[pageId].revisions ) {                 return data.query.pages[pageId].revisions[0].slots.main["*"];             }             return "";         } );     }      function escapeForRegex( s ) {         return s.replace( /[-\/\\^$*+?.()|[\]{}]/g, '\\$&' );     }      /**     * Escape a string for use in a JavaScript string literal.     * This function is adapted from     * https://github.com/joliss/js-string-escape/blob/6887a69003555edf5c6caaa75f2592228558c595/index.js     * (released under the MIT licence).     */     function escapeForJsString( s ) {         return s.replace( /["'\\\n\r\u2028\u2029]/g, function ( character ) {             // Escape all characters not included in SingleStringCharacters and             // DoubleStringCharacters on             // http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4             switch ( character ) {                 case '"':                 case "'":                 case '\\':                     return '\\' + character;                 // Four possible LineTerminator characters need to be escaped:                 case '\n':                     return '\\n';                 case '\r':                     return '\\r';                 case '\u2028':                     return '\\u2028';                 case '\u2029':                     return '\\u2029';             }         } );     }      /**     * Escape a string for use in an inline JavaScript comment (comments that     * start with two slashes "//").     * This function is adapted from     * https://github.com/joliss/js-string-escape/blob/6887a69003555edf5c6caaa75f2592228558c595/index.js     * (released under the MIT licence).     */     function escapeForJsComment( s ) {         return s.replace( /[\n\r\u2028\u2029]/g, function ( character ) {             switch ( character ) {                 // Escape possible LineTerminator characters                 case '\n':                     return '\\n';                 case '\r':                     return '\\r';                 case '\u2028':                     return '\\u2028';                 case '\u2029':                     return '\\u2029';             }         } );     }      /**     * Unescape a JavaScript string literal.     *     * This is the inverse of escapeForJsString.     */     function unescapeForJsString( s ) {         return s.replace( /\\"|\\'|\\\\|\\n|\\r|\\u2028|\\u2029/g, function ( substring ) {             switch ( substring ) {                 case '\\"':                     return '"';                 case "\\'":                     return "'";                 case "\\\\":                     return "\\";                 case "\\r":                     return "\r";                 case "\\n":                     return "\n";                 case "\\u2028":                     return "\u2028";                 case "\\u2029":                     return "\u2029";             }         } );     }      function getFullTarget ( target ) {         return USER_NAMESPACE_NAME + ":" + mw.config.get( "wgUserName" ) + "/" +                  target + ".js";     }      // From https://stackoverflow.com/a/10192255     function uniques( array ){         return array.filter( function( el, index, arr ) {             return index === arr.indexOf( el );         });     }      if( window.scriptInstallerAutoReload === undefined ) {         window.scriptInstallerAutoReload = true;     }      if( window.scriptInstallerInstallTarget === undefined ) {         window.scriptInstallerInstallTarget = "common"; // by default, install things to the user's common.js     }      var jsPage = mw.config.get( "wgPageName" ).slice( -3 ) === ".js" ||         mw.config.get( "wgPageContentModel" ) === "javascript";     $.when(         $.ready,         mw.loader.using( [ "mediawiki.api", "mediawiki.util" ] )     ).then( function () {         api = new mw.Api();         addCss();         buildImportList().then( function () {             attachInstallLinks();             if( jsPage ) showUi();              // Auto-open the panel if we set the cookie to do so (see `conditionalReload()`)             if( document.cookie.indexOf( "open_script_installer=yes" ) >= 0 ) {                 document.cookie = "open_script_installer=; expires=Thu, 01 Jan 1970 00:00:01 GMT";                 $( "#script-installer-top-container a:contains('Manage')" ).trigger( "click" );             }         } );     } ); } )();