Замечание: Возможно, после публикации вам придётся очистить кэш своего браузера, чтобы увидеть изменения.

  • Firefox / Safari: Удерживая клавишу Shift, нажмите на панели инструментов Обновить либо нажмите Ctrl+F5 или Ctrl+R (⌘+R на Mac)
  • Google Chrome: Нажмите Ctrl+Shift+R (⌘+Shift+R на Mac)
  • Edge: Удерживая Ctrl, нажмите Обновить либо нажмите Ctrl+F5
  • Opera: Нажмите Ctrl+F5.
mw.loader.using(['mediawiki.api'], function() {  var commonMessages = {     addTitle: 'Добавить объект',     editTitle: 'Редактировать объект',     submitApiError: 'Во время сохранения листинга на сервере произошла ошибка, пожайлуста, попробуйте сохранить ещё раз',     submitBlacklistError: 'Ошибка: текст содержит ссылку из чёрного списка, пожайлуста, удалите её и попробуйте сохранить снова',     submitUnknownError: 'Ошибка: при попытке сохранить листинг произошла неизвестная ошибка, пожайлуста, попробуйте сохранить ещё раз',     submitHttpError: 'Ошибка: сервер сообщил о HTTP ошибке, возникшей во время сохранения листинга, пожайлуста, попробуйте сохранить ещё раз',     submitEmptyError: 'Ошибка: сервер вернул пустой ответ при попытке сохранить листинг, пожайлуста, попробуйте сохранить ещё раз',     enterCaptcha: 'Введите CAPTCHA',     changesSummaryAdded: 'Добавлен объект',     changesSummaryUpdated: 'Обновлён объект',     captchaSubmit: 'Продолжить',     captchaCancel: 'Отмена' };   var StringUtils = {     contains: function contains(string, substring) {         return string.indexOf(substring) >= 0;     },     trim: function trim(string) {         // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim         return string.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');     } };   var ArrayUtils = {     hasElement: function hasElement(array, element) {         return array.indexOf(element) >= 0;     },     inArray: function inArray(element, array) {         return this.hasElement(array, element);     } };   var AsyncUtils = {     runSequence: function runSequence(functions, onSuccess, results) {         if (!results) {             results = [];         }          if (functions.length > 0) {             var firstFunction = functions[0];             firstFunction(function (result) {                 results.push(result);                 setTimeout( // hack to break recursion chain                 function () {                     AsyncUtils.runSequence(functions.slice(1), onSuccess, results);                 }, 0);             });         } else {             onSuccess(results);         }     },     runChunks: function runChunks(runSingleChunkFunction, maxChunkSize, data, onSuccess) {         var chunkRunFunctions = [];          var _loop = function _loop(dataNumStart) {             var dataChunk = data.slice(dataNumStart, dataNumStart + maxChunkSize);             chunkRunFunctions.push(function (onSuccess) {                 return runSingleChunkFunction(dataChunk, onSuccess);             });         };          for (var dataNumStart = 0; dataNumStart < data.length; dataNumStart += maxChunkSize) {             _loop(dataNumStart);         }         this.runSequence(chunkRunFunctions, function (chunkResults) {             var result = chunkResults.reduce(function (current, total) {                 return total.concat(current);             }, []);             onSuccess(result);         });     } };   var ObjectUtils = {     merge: function merge(obj1, obj2) {         var result = {};         for (var prop in obj1) {             if (obj1.hasOwnProperty(prop)) {                 result[prop] = obj1[prop];             }         }         for (var _prop in obj2) {             if (obj2.hasOwnProperty(_prop)) {                 result[_prop] = obj2[_prop];             }         }         return result;     } };   var ValidationUtils = {     normalizeUrl: function normalizeUrl(url) {         var webRegex = new RegExp('^https?://', 'i');         if (!webRegex.test(url) && url !== '') {             return 'http://' + url;         } else {             return url;         }     } };   var MediaWikiPage = {     getPageName: function getPageName() {         return mw.config.get('wgPageName');     },     isDiffMode: function isDiffMode() {         return $('table.diff').length > 0;     },     isLastRevision: function isLastRevision() {         return mw.config.get('wgCurRevisionId') === mw.config.get('wgRevisionId');     },     isViewAction: function isViewAction() {         return mw.config.get('wgAction') === 'view';     },     isViewSourceMode: function isViewSourceMode() {         return $('#ca-viewsource').length > 0;     },     isViewSpecificRevisionMode: function isViewSpecificRevisionMode() {         return $('#mw-revision-info').length > 0;     },     isRegularNamespace: function isRegularNamespace() {         var namespace = mw.config.get('wgNamespaceNumber');         return namespace === 0 || namespace === 2 || namespace === 4;     } };   var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }  var CaptchaDialog = function () {     function CaptchaDialog(captchaImgSrc, onCaptchaSubmit) {         var _this = this;          _classCallCheck(this, CaptchaDialog);          this._captcha = $('<div id="captcha-dialog">');         $('<img class="fancycaptcha-image">').attr('src', captchaImgSrc).appendTo(this._captcha);         $('<input id="input-captcha" type="text">').appendTo(this._captcha);          this._captcha.dialog({             modal: true,             title: commonMessages.enterCaptcha,             buttons: [{                 text: commonMessages.captchaSubmit,                 click: function click() {                     onCaptchaSubmit($('#input-captcha').val());                     _this.destroy();                 }             }, {                 text: commonMessages.captchaCancel,                 click: function click() {                     return _this.destroy();                 }             }]         });     }      _createClass(CaptchaDialog, [{         key: 'destroy',         value: function destroy() {             this._captcha.dialog('destroy').remove();         }     }]);      return CaptchaDialog; }();   var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }  var ListingSection = function () {     function ListingSection(headerElement, sectionIndex) {         _classCallCheck(this, ListingSection);          this._headerElement = headerElement;         this._sectionIndex = sectionIndex;     }      _createClass(ListingSection, [{         key: 'getHeaderElement',         value: function getHeaderElement() {             return this._headerElement;         }     }, {         key: 'getSectionIndex',         value: function getSectionIndex() {             return this._sectionIndex;         }     }]);      return ListingSection; }();  var ListingTable = function () {     function ListingTable(tableElement, sectionIndex, listingIndex) {         _classCallCheck(this, ListingTable);          this._tableElement = tableElement;         this._sectionIndex = sectionIndex;         this._listingIndex = listingIndex;     }      _createClass(ListingTable, [{         key: 'getTableElement',         value: function getTableElement() {             return this._tableElement;         }     }, {         key: 'getSectionIndex',         value: function getSectionIndex() {             return this._sectionIndex;         }     }, {         key: 'getListingIndex',         value: function getListingIndex() {             return this._listingIndex;         }     }]);      return ListingTable; }();  var ListingPageElements = function () {     function ListingPageElements(sections, listingTables) {         _classCallCheck(this, ListingPageElements);          this._sections = sections;         this._listingTables = listingTables;     }      /**      * @returns {ListingSection[]}      */       _createClass(ListingPageElements, [{         key: 'getSections',         value: function getSections() {             return this._sections;         }     }, {         key: 'getListingTables',         value: function getListingTables() {             return this._listingTables;         }     }]);      return ListingPageElements; }();  var ListingEditorUtils = {     isEditablePage: function isEditablePage() {         return MediaWikiPage.isRegularNamespace() && MediaWikiPage.isViewAction() && MediaWikiPage.isLastRevision() && !MediaWikiPage.isDiffMode() && !MediaWikiPage.isViewSpecificRevisionMode() && !MediaWikiPage.isViewSourceMode();     },       /**      * @returns {ListingPageElements}      */     getListingPageElements: function getListingPageElements() {         var pageBodyContentElement = $('.mw-parser-output');          var currentSectionIndex = 0;         var currentListingIndex = 0;          var sections = [];         var listingTables = [];          function isTableOfContentsHeader(headerElement) {             return headerElement.parents('.toc').length > 0;         }          // Here we add buttons to:         // - add new listing - for each section header         // - edit existing listing - for each existing listing         //         // - section index, to which we are going to add new listing         // - section index and listing index (within a section) for listing which we are going to edit         // To calculate section index and listing index, we iterate over all section header and listing         // table elements sequentially (in the same order as we have them in HTML).         // When we meet header - we consider that new section is started and increase current section index,         // and reset current listing index (listings are enumerated within section). All listings belong         // to that section until we meet the next header.         // When we meet listing table - we increase current listing index.         pageBodyContentElement.find('h1, h2, h3, h4, h5, h6, table.monument').each(function () {             if (ArrayUtils.inArray(this.tagName, ['H1', 'H2', 'H3', 'H4', 'H5', 'H6'])) {                 var headerElement = $(this);                  if (!isTableOfContentsHeader(headerElement)) {                     currentSectionIndex++;                     currentListingIndex = 0;                     sections.push(new ListingSection(headerElement, currentSectionIndex));                 }             } else if (this.tagName === 'TABLE') {                 var listingTable = $(this);                 listingTables.push(new ListingTable(listingTable, currentSectionIndex, currentListingIndex));                 currentListingIndex++;             }         });          return new ListingPageElements(sections, listingTables);     } };   var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }  var ListingEditorButtonEdit = function () {     function ListingEditorButtonEdit(button, listingTable) {         _classCallCheck(this, ListingEditorButtonEdit);          this._button = button;         this._listingTable = listingTable;     }      _createClass(ListingEditorButtonEdit, [{         key: 'click',         value: function click(handler) {             var _this = this;              this._button.click(function () {                 return handler(_this._listingTable);             });         }     }]);      return ListingEditorButtonEdit; }();  var ListingEditorButtonAdd = function () {     function ListingEditorButtonAdd(button, section) {         _classCallCheck(this, ListingEditorButtonAdd);          this._button = button;         this._section = section;     }      _createClass(ListingEditorButtonAdd, [{         key: 'click',         value: function click(handler) {             var _this2 = this;              this._button.click(function () {                 return handler(_this2._section);             });         }     }]);      return ListingEditorButtonAdd; }();  var ListingEditorButtons = {     /**      *      * @param listingTable ListingTable      */     createListingEditButton: function createListingEditButton(listingTable) {         var editListingButton = $('<span class="vcard-edit-button noprint" style="padding-left: 5px;">');         editListingButton.html('<a href="javascript:" class="icon-pencil" title="Редактировать">Редактировать</a>');          var nameElement = listingTable.getTableElement().find('span.monument-name').first();         if (nameElement) {             nameElement.append(editListingButton);         }          return new ListingEditorButtonEdit(editListingButton, listingTable);     },     createListingAddButton: function createListingAddButton(section) {         var sectionAddButton = $('<a href="javascript:">добавить</a>');         var bracketStart = $('<span class="mw-editsection-bracket">[</span>');         var bracketEnd = $('<span class="mw-editsection-bracket">]</span>');         section.getHeaderElement().append($('<span class="mw-editsection"/>').append(bracketStart).append(sectionAddButton).append(bracketEnd));          return new ListingEditorButtonAdd(sectionAddButton, section);     } };   var MAX_DIALOG_WIDTH = 1200; var LICENSE_TEXT = 'Нажимая кнопку «Сохранить», вы соглашаетесь с <a class="external" target="_blank" href="https://wikimediafoundation.org/wiki/Terms_of_Use/ru">условиями использования</a>, а также соглашаетесь на неотзывную публикацию по лицензии <a class="external" target="_blank" href="https://en.wikipedia.org/wiki/ru:Википедия:Текст_Лицензии_Creative_Commons_Attribution-ShareAlike_3.0_Unported">CC-BY-SA 3.0</a>.';  var ListingEditorDialog = {     showDialog: function showDialog(formElement, dialogTitle, onSubmit, onCancel, onHelp) {         var windowWidth = $(window).width();         var dialogWidth = windowWidth > MAX_DIALOG_WIDTH ? MAX_DIALOG_WIDTH : 'auto';          mw.loader.using(['jquery.ui'], function () {             formElement.dialog({                 modal: true,                 height: 'auto',                 width: dialogWidth,                 title: dialogTitle,                 dialogClass: 'listing-editor-dialog',                 buttons: [{                     text: '?',                     id: 'listing-help',                     click: function click() {                         onHelp();                     }                 }, {                     text: "Сохранить",                     click: function click() {                         onSubmit();                     }                 }, {                     text: "Отмена",                     click: function click() {                         onCancel();                     }                 }],                 create: function create() {                     $('.ui-dialog-buttonpane').append('<div class="listing-license">' + LICENSE_TEXT + '</div>');                 }             });         });     } };   var ListingEditorFormComposer = {     createInputFormRow: function createInputFormRow(inputElementId, labelText) {         var rowElement = $('<tr>');         var label = $('<label>', {             'for': inputElementId,             'html': labelText         });         var labelColumn = $('<td>', {             'class': "editor-label-col",             'style': "width: 200px"         }).append(label);         var inputColumnElement = $('<td>');         rowElement.append(labelColumn).append(inputColumnElement);         return {             'rowElement': rowElement,             'inputColumnElement': inputColumnElement         };     },     createInputFormRowCheckbox: function createInputFormRowCheckbox(inputElementId, labelText) {         var row = this.createInputFormRow(inputElementId, labelText);         var inputElement = $('<input>', {             'type': 'checkbox',             'id': inputElementId         });         row.inputColumnElement.append(inputElement);         return {             'rowElement': row.rowElement,             'inputElement': inputElement         };     },     createInputFormRowSelect: function createInputFormRowSelect(inputElementId, labelText, options) {         var row = this.createInputFormRow(inputElementId, labelText);         var inputElement = $('<select>', {             'id': inputElementId         });         options.forEach(function (option) {             var optionElement = $('<option>', {                 'value': option.value,                 'html': option.title             });             inputElement.append(optionElement);         });         row.inputColumnElement.append(inputElement);         return {             'rowElement': row.rowElement,             'inputElement': inputElement         };     },     createInputFormRowText: function createInputFormRowText(inputElementId, labelText, placeholderText, partialWidth, insertSymbols) {         if (!placeholderText) {             placeholderText = '';         }         var row = this.createInputFormRow(inputElementId, labelText);         var inputElement = $('<input>', {             'type': 'text',             'class': partialWidth ? 'editor-partialwidth' : 'editor-fullwidth',             'style': insertSymbols ? 'width: 90%' : '',             'placeholder': placeholderText,             'id': inputElementId         });         row.inputColumnElement.append(inputElement);          if (insertSymbols) {             var buttonInsertQuotes = $('<a>', {                 'class': 'name-quotes-template',                 href: 'javascript:;',                 html: '«»'             });             var buttonInsertDash = $('<a>', {                 'class': 'name-dash-template',                 href: 'javascript:;',                 html: '—'             });             InputInsertSymbols.addDashInsertHandler(buttonInsertDash, inputElement);             InputInsertSymbols.addQuotesInsertHandler(buttonInsertQuotes, inputElement);              row.inputColumnElement.append('&nbsp;');             row.inputColumnElement.append(buttonInsertQuotes);             row.inputColumnElement.append('&nbsp;');             row.inputColumnElement.append(buttonInsertDash);         }          return {             'rowElement': row.rowElement,             'inputElement': inputElement         };     },     createRowDivider: function createRowDivider() {         return $('<tr>').append($('<td>', { 'colspan': "2" }).append($('<div>', {             'class': "listing-divider",             'style': "margin: 3px 0"         })));     },     createRowLink: function createRowLink(linkText) {         var linkElement = $("<a>", {             'href': 'javascript:;',             'html': linkText         });         var rowElement = $('<tr>').append($('<td>')).append($('<td>').append(linkElement));         return {             'rowElement': rowElement,             'linkElement': linkElement         };     },     createChangesDescriptionRow: function createChangesDescriptionRow() {         var inputChangesSummary = $('<input>', {             'type': "text",             'class': "editor-partialwidth",             'placeholder': "что именно было изменено",             'id': "input-summary"         });         var inputIsMinorChanges = $('<input>', {             'type': "checkbox",             'id': "input-minor"         });         var labelChangesSummary = $('<label>', {             'for': "input-summary",             'html': 'Описание изменений'         });         var labelIsMinorChanges = $('<label>', {             'for': "input-minor",             'class': "listing-tooltip",             'title': "Установите галочку, если изменение незначительное, например, исправление опечатки",             'html': 'незначительное изменение?'         });         var spanIsMinorChanges = $('<span>', { id: "span-minor" });         spanIsMinorChanges.append(inputIsMinorChanges).append(labelIsMinorChanges);         var row = $('<tr>');         row.append($('<td>', { 'class': "editor-label-col", style: "width: 200px" }).append(labelChangesSummary));         row.append($('<td>').append(inputChangesSummary).append(spanIsMinorChanges));         return {             'row': row,             'inputChangesSummary': inputChangesSummary,             'inputIsMinorChanges': inputIsMinorChanges         };     },     createObjectDescriptionRow: function createObjectDescriptionRow() {         var inputDescription = $('<textarea>', {             'rows': "4",             'class': "editor-fullwidth",             'placeholder': "описание объекта",             'id': "input-description"         });         var labelDescription = $('<label>', {             'for': "input-description",             'html': "Описание"         });         var row = $('<tr>');         row.append($('<td>', { 'class': "editor-label-col", 'style': "width: 200px" }).append(labelDescription));         row.append($('<td>').append(inputDescription));         return {             'row': row,             'inputDescription': inputDescription         };     },     createTableFullWidth: function createTableFullWidth() {         var tableElement = $('<table>', {             'class': 'editor-fullwidth'         });         var wrapperElement = $('<div>');         wrapperElement.append(tableElement);         return {             'wrapperElement': wrapperElement,             'tableElement': tableElement         };     },     createTableTwoColumns: function createTableTwoColumns() {         var leftTableElement = $('<table>', {             'class': "editor-fullwidth"         });         var rightTableElement = $('<table>', {             'class': "editor-fullwidth"         });         var wrapperElement = $('<div>');         wrapperElement.append($('<div>', {             'class': 'listing-col listing-span_1_of_2'         }).append(leftTableElement));         wrapperElement.append($('<div>', {             'class': 'listing-col listing-span_1_of_2'         }).append(rightTableElement));         return {             'wrapperElement': wrapperElement,             'leftTableElement': leftTableElement,             'rightTableElement': rightTableElement         };     },     createForm: function createForm() {         var formElement = $('<form id="listing-editor">');         formElement.append($('<br>'));         return {             'formElement': formElement         };     } };   var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }  var Region = function () {     function Region(id, title) {         _classCallCheck(this, Region);          this._id = id;         this._title = title;     }      _createClass(Region, [{         key: "getId",         value: function getId() {             return this._id;         }     }, {         key: "getTitle",         value: function getTitle() {             return this._title;         }     }]);      return Region; }();  var regions = [new Region("", "не задан"), new Region("ru-ad", "Адыгея"), new Region("ru-ba", "Башкортостан"), new Region("ru-bu", "Бурятия"), new Region("ru-al", "Алтай"), new Region("ru-da", "Дагестан"), new Region("ru-in", "Ингушетия"), new Region("ru-kb", "Кабардино-Балкария"), new Region("ru-kl", "Калмыкия"), new Region("ru-kc", "Карачаево-Черкесия"), new Region("ru-krl", "Карелия"), new Region("ru-ko", "республика Коми"), new Region("ru-me", "Марий Эл"), new Region("ru-mo", "Мордовия"), new Region("ru-sa", "Якутия (Саха)"), new Region("ru-se", "Северная Осетия"), new Region("ru-ta", "Татарстан"), new Region("ru-ty", "Тува"), new Region("ru-ud", "Удмуртия"), new Region("ru-kk", "Хакасия"), new Region("ru-ce", "Чеченская республика"), new Region("ru-chv", "Чувашия"), new Region("ru-alt", "Алтайский край"), new Region("ru-kda", "Краснодарский край"), new Region("ru-kya", "Красноярский край"), new Region("ru-pri", "Приморский край"), new Region("ru-sta", "Ставропольский край"), new Region("ru-kha", "Хабаровский край"), new Region("ru-amu", "Амурская область"), new Region("ru-ark", "Архангельская область"), new Region("ru-ast", "Астраханская область"), new Region("ru-bel", "Белгородская область"), new Region("ru-bry", "Брянская область"), new Region("ru-vla", "Владимирская область"), new Region("ru-vgg", "Волгоградская область"), new Region("ru-vol", "Вологодская область"), new Region("ru-vor", "Воронежская область"), new Region("ru-iva", "Ивановская область"), new Region("ru-irk", "Иркутская область"), new Region("ru-kal", "Калининградская область"), new Region("ru-klu", "Калужская область"), new Region("ru-kam", "Камчатский край"), new Region("ru-kem", "Кемеровская область"), new Region("ru-kir", "Кировская область"), new Region("ru-kos", "Костромская область"), new Region("ru-kgn", "Курганская область"), new Region("ru-krs", "Курская область"), new Region("ru-len", "Ленинградская область"), new Region("ru-lip", "Липецкая область"), new Region("ru-mag", "Магаданская область"), new Region("ru-mos", "Московская область"), new Region("ru-mur", "Мурманская область"), new Region("ru-niz", "Нижегородская область"), new Region("ru-ngr", "Новгородская область"), new Region("ru-nvs", "Новосибирская область"), new Region("ru-oms", "Омская область"), new Region("ru-ore", "Оренбургская область"), new Region("ru-orl", "Орловская область"), new Region("ru-pnz", "Пензенская область"), new Region("ru-per", "Пермский край"), new Region("ru-psk", "Псковская область"), new Region("ru-ros", "Ростовская область"), new Region("ru-rya", "Рязанская область"), new Region("ru-sam", "Самарская область"), new Region("ru-sar", "Саратовская область"), new Region("ru-sak", "Сахалинская область"), new Region("ru-sve", "Свердловская область"), new Region("ru-smo", "Смоленская область"), new Region("ru-tam", "Тамбовская область"), new Region("ru-tve", "Тверская область"), new Region("ru-tom", "Томская область"), new Region("ru-tul", "Тульская область"), new Region("ru-tyu", "Тюменская область"), new Region("ru-uly", "Ульяновская область"), new Region("ru-che", "Челябинская область"), new Region("ru-zab", "Забайкальский край"), new Region("ru-yar", "Ярославская область"), new Region("ru-mow", "Москва"), new Region("ru-spb", "Санкт-Петербург"), new Region("ru-jew", "Еврейская автономная область"), new Region("ru-km", "Крым"), new Region("ru-nen", "Ненецкий автономный округ"), new Region("ru-khm", "Ханты-Мансийский автономный округ"), new Region("ru-chu", "Чукотский автономный округ"), new Region("ru-yam", "Ямало-Ненецкий автономный округ"), new Region("ru-sev", "Севастополь")];   var api = new mw.Api();  var MediaWikiPageWikitext = {     loadSectionWikitext: function loadSectionWikitext(sectionIndex, onSuccess) {         $.ajax({             url: mw.util.wikiScript(''),             data: {                 title: mw.config.get('wgPageName'),                 action: 'raw',                 section: sectionIndex             },             cache: false         }).done(function (data) {             onSuccess(data);         }).fail(function (jqXHR, textStatus, errorThrown) {             alert('Ошибка при получении исходного вики-текста статьи: ' + textStatus + ' ' + errorThrown);         });     },     saveSectionWikitext: function saveSectionWikitext(sectionIndex, sectionWikitext, changesSummary, changesIsMinor, captchaId, captchaAnswer, onSuccess, onFailure, onCaptcha) {         var editPayload = {             action: "edit",             title: mw.config.get("wgPageName"),             section: sectionIndex,             text: sectionWikitext,             summary: changesSummary,             captchaid: captchaId,             captchaword: captchaAnswer         };         if (changesIsMinor) {             $.extend(editPayload, { minor: 'true' });         }          api.postWithToken("csrf", editPayload).done(function (data) {             if (data && data.edit && data.edit.result === 'Success') {                 onSuccess();             } else if (data && data.error) {                 onFailure(commonMessages.submitApiError + ' "' + data.error.code + '": ' + data.error.info);             } else if (data && data.edit.spamblacklist) {                 onFailure(commonMessages.submitBlacklistError + ': ' + data.edit.spamblacklist);             } else if (data && data.edit.captcha) {                 onCaptcha(data.edit.captcha.url, data.edit.captcha.id);             } else {                 onFailure(commonMessages.submitUnknownError);             }         }).fail(function (code, result) {             if (code === "http") {                 onFailure(commonMessages.submitHttpError + ': ' + result.textStatus);             } else if (code === "ok-but-empty") {                 onFailure(commonMessages.submitEmptyError);             } else {                 onFailure(commonMessages.submitUnknownError + ': ' + code);             }         });     },     getSectionName: function getSectionName(sectionWikitext) {         var HEADING_REGEX = /^=+\s*([^=]+)\s*=+\s*\n/;         var result = HEADING_REGEX.exec(sectionWikitext);         return result !== null ? result[1].trim() : "";     } };   var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }  var Region = function () {     function Region(id, title) {         _classCallCheck(this, Region);          this._id = id;         this._title = title;     }      _createClass(Region, [{         key: "getId",         value: function getId() {             return this._id;         }     }, {         key: "getTitle",         value: function getTitle() {             return this._title;         }     }]);      return Region; }();  var regions = [new Region("", "не задан"), new Region("ru-ad", "Адыгея"), new Region("ru-ba", "Башкортостан"), new Region("ru-bu", "Бурятия"), new Region("ru-al", "Алтай"), new Region("ru-da", "Дагестан"), new Region("ru-in", "Ингушетия"), new Region("ru-kb", "Кабардино-Балкария"), new Region("ru-kl", "Калмыкия"), new Region("ru-kc", "Карачаево-Черкесия"), new Region("ru-krl", "Карелия"), new Region("ru-ko", "республика Коми"), new Region("ru-me", "Марий Эл"), new Region("ru-mo", "Мордовия"), new Region("ru-sa", "Якутия (Саха)"), new Region("ru-se", "Северная Осетия"), new Region("ru-ta", "Татарстан"), new Region("ru-ty", "Тува"), new Region("ru-ud", "Удмуртия"), new Region("ru-kk", "Хакасия"), new Region("ru-ce", "Чеченская республика"), new Region("ru-chv", "Чувашия"), new Region("ru-alt", "Алтайский край"), new Region("ru-kda", "Краснодарский край"), new Region("ru-kya", "Красноярский край"), new Region("ru-pri", "Приморский край"), new Region("ru-sta", "Ставропольский край"), new Region("ru-kha", "Хабаровский край"), new Region("ru-amu", "Амурская область"), new Region("ru-ark", "Архангельская область"), new Region("ru-ast", "Астраханская область"), new Region("ru-bel", "Белгородская область"), new Region("ru-bry", "Брянская область"), new Region("ru-vla", "Владимирская область"), new Region("ru-vgg", "Волгоградская область"), new Region("ru-vol", "Вологодская область"), new Region("ru-vor", "Воронежская область"), new Region("ru-iva", "Ивановская область"), new Region("ru-irk", "Иркутская область"), new Region("ru-kal", "Калининградская область"), new Region("ru-klu", "Калужская область"), new Region("ru-kam", "Камчатский край"), new Region("ru-kem", "Кемеровская область"), new Region("ru-kir", "Кировская область"), new Region("ru-kos", "Костромская область"), new Region("ru-kgn", "Курганская область"), new Region("ru-krs", "Курская область"), new Region("ru-len", "Ленинградская область"), new Region("ru-lip", "Липецкая область"), new Region("ru-mag", "Магаданская область"), new Region("ru-mos", "Московская область"), new Region("ru-mur", "Мурманская область"), new Region("ru-niz", "Нижегородская область"), new Region("ru-ngr", "Новгородская область"), new Region("ru-nvs", "Новосибирская область"), new Region("ru-oms", "Омская область"), new Region("ru-ore", "Оренбургская область"), new Region("ru-orl", "Орловская область"), new Region("ru-pnz", "Пензенская область"), new Region("ru-per", "Пермский край"), new Region("ru-psk", "Псковская область"), new Region("ru-ros", "Ростовская область"), new Region("ru-rya", "Рязанская область"), new Region("ru-sam", "Самарская область"), new Region("ru-sar", "Саратовская область"), new Region("ru-sak", "Сахалинская область"), new Region("ru-sve", "Свердловская область"), new Region("ru-smo", "Смоленская область"), new Region("ru-tam", "Тамбовская область"), new Region("ru-tve", "Тверская область"), new Region("ru-tom", "Томская область"), new Region("ru-tul", "Тульская область"), new Region("ru-tyu", "Тюменская область"), new Region("ru-uly", "Ульяновская область"), new Region("ru-che", "Челябинская область"), new Region("ru-zab", "Забайкальский край"), new Region("ru-yar", "Ярославская область"), new Region("ru-mow", "Москва"), new Region("ru-spb", "Санкт-Петербург"), new Region("ru-jew", "Еврейская автономная область"), new Region("ru-km", "Крым"), new Region("ru-nen", "Ненецкий автономный округ"), new Region("ru-khm", "Ханты-Мансийский автономный округ"), new Region("ru-chu", "Чукотский автономный округ"), new Region("ru-yam", "Ямало-Ненецкий автономный округ"), new Region("ru-sev", "Севастополь")];   var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }  var NaturalMonumentCategory = function () {     function NaturalMonumentCategory(id, title) {         _classCallCheck(this, NaturalMonumentCategory);          this._id = id;         this._title = title;     }      _createClass(NaturalMonumentCategory, [{         key: 'getId',         value: function getId() {             return this._id;         }     }, {         key: 'getTitle',         value: function getTitle() {             return this._title;         }     }]);      return NaturalMonumentCategory; }();  var naturalMonumentCategories = [new NaturalMonumentCategory('', 'не задано'), new NaturalMonumentCategory('federal', 'федерального значения'), new NaturalMonumentCategory('regional', 'регионального значения'), new NaturalMonumentCategory('municipal', 'местного значения'), new NaturalMonumentCategory('new', 'выявленный памятник')];   var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }  var NaturalMonumentStatus = function () {     function NaturalMonumentStatus(id, title) {         _classCallCheck(this, NaturalMonumentStatus);          this._id = id;         this._title = title;     }      _createClass(NaturalMonumentStatus, [{         key: 'getId',         value: function getId() {             return this._id;         }     }, {         key: 'getTitle',         value: function getTitle() {             return this._title;         }     }]);      return NaturalMonumentStatus; }();  var naturalMonumentStatuses = [new NaturalMonumentStatus('', 'действующий'), new NaturalMonumentStatus('destroyed', 'утрачен'), new NaturalMonumentStatus('dismissed', 'упразднён'), new NaturalMonumentStatus('rejected', 'предложенный, не созданный'), new NaturalMonumentStatus('reorganized', 'реорганизованный'), new NaturalMonumentStatus('planned', 'перспективный')];   var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }  var NaturalMonumentType = function () {     function NaturalMonumentType(id, title) {         _classCallCheck(this, NaturalMonumentType);          this._id = id;         this._title = title;     }      _createClass(NaturalMonumentType, [{         key: 'getId',         value: function getId() {             return this._id;         }     }, {         key: 'getTitle',         value: function getTitle() {             return this._title;         }     }]);      return NaturalMonumentType; }();  var naturalMonumentTypes = [new NaturalMonumentType('', 'не задано'), new NaturalMonumentType('reserve', 'заповедник'), new NaturalMonumentType('sanctuary', 'заказник'), new NaturalMonumentType('resource reserve', 'ресурсный резерват'), new NaturalMonumentType('arboretum', 'ботанический сад / дендрарий'), new NaturalMonumentType('national park', 'национальный парк'), new NaturalMonumentType('nature park', 'природный парк'), new NaturalMonumentType('city park', 'городской парк'), new NaturalMonumentType('garden', 'памятник садово-паркового искусства'), new NaturalMonumentType('traditional', 'территории традиционного природопользования'), new NaturalMonumentType('resort', 'рекреационная местность / курорт'), new NaturalMonumentType('nature', 'памятник природы'), new NaturalMonumentType('general', 'другое')];   var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }  var NaturalHeritageEditorForm = function () {     function NaturalHeritageEditorForm() {         var _this = this;          _classCallCheck(this, NaturalHeritageEditorForm);          this._form = ListingEditorFormComposer.createForm();          this._inputObjectName = ListingEditorFormComposer.createInputFormRowText('input-name', 'Название', 'название объекта', false, true);          this._inputStatus = ListingEditorFormComposer.createInputFormRowSelect('input-status', 'Статус', naturalMonumentStatuses.map(function (status) {             return { title: status.getTitle(), value: status.getId() };         }));         this._inputType = ListingEditorFormComposer.createInputFormRowSelect('input-type', 'Тип', naturalMonumentTypes.map(function (type) {             return { title: type.getTitle(), value: type.getId() };         }));         this._inputCategory = ListingEditorFormComposer.createInputFormRowSelect('input-category', 'Категория', naturalMonumentCategories.map(function (category) {             return { title: category.getTitle(), value: category.getId() };         }));          this._inputRegion = ListingEditorFormComposer.createInputFormRowSelect('input-region', 'Регион', regions.map(function (region) {             return { title: region.getTitle(), value: region.getId() };         }));         this._inputDistrict = ListingEditorFormComposer.createInputFormRowText('input-district', 'Район');         this._inputMunicipality = ListingEditorFormComposer.createInputFormRowText('input-municipality', 'Населённый пункт');         this._inputAddress = ListingEditorFormComposer.createInputFormRowText('input-address', 'Адрес', 'улица название, номер дома');          this._inputLat = ListingEditorFormComposer.createInputFormRowText('input-lat', 'Широта', '11.11111', true);         this._inputLong = ListingEditorFormComposer.createInputFormRowText('input-long', 'Долгота', '111.11111', true);         this._inputPrecise = ListingEditorFormComposer.createInputFormRowCheckbox('input-precise', 'Точные координаты');          this._inputArea = ListingEditorFormComposer.createInputFormRowText('input-area', 'Площадь');          this._inputKnid = ListingEditorFormComposer.createInputFormRowText('input-knid', '№ объекта', 'dddddddddd', true);         this._inputComplex = ListingEditorFormComposer.createInputFormRowText('input-complex', '№ комплекса', 'dddddddddd', true);         this._inputUid = ListingEditorFormComposer.createInputFormRowText('input-uid', '№ объекта (UA)', 'dddddddddd', true);          this._inputImage = ListingEditorFormComposer.createInputFormRowText('input-image', 'Изображение', 'изображение на Викискладе');         this._inputWiki = ListingEditorFormComposer.createInputFormRowText('input-wiki', 'Википедия', 'статья в русской Википедии');         this._inputWdid = ListingEditorFormComposer.createInputFormRowText('input-wdid', 'Викиданные', 'идентификатор Викиданных', true);         this._inputCommonscat = ListingEditorFormComposer.createInputFormRowText('input-commonscat', 'Викисклад', 'категория Викисклада');         this._inputMunid = ListingEditorFormComposer.createInputFormRowText('input-munid', 'Викиданные нас. пункта', 'идентификатор Викиданных', true);          this._inputLink = ListingEditorFormComposer.createInputFormRowText('input-link', 'Ссылка №1', 'внешняя ссылка с дополнительной информацией об объекте');         this._inputLinkExtra = ListingEditorFormComposer.createInputFormRowText('input-linkextra', 'Ссылка №2', 'внешняя ссылка с дополнительной информацией об объекте');         this._inputOopt = ListingEditorFormComposer.createInputFormRowText('input-oopt', 'На сайте ООПТ России');         this._inputDocument = ListingEditorFormComposer.createInputFormRowText('input-document', 'Документ', '', true);          var selectImageLinkRow = ListingEditorFormComposer.createRowLink('выбрать изображение из галереи');         selectImageLinkRow.linkElement.click(function () {             CommonsImagesSelectDialog.showDialog(             /*knidWLM=*/null, _this._inputKnid.inputElement.val(), _this._inputCommonscat.inputElement.val(), function (selectedImage) {                 _this._inputImage.inputElement.val(selectedImage);             });         });          var tableObjectName = ListingEditorFormComposer.createTableFullWidth();         tableObjectName.tableElement.append(this._inputObjectName.rowElement);         tableObjectName.tableElement.append(ListingEditorFormComposer.createRowDivider());         this._form.formElement.append(tableObjectName.wrapperElement);          var tableObjectProperties = ListingEditorFormComposer.createTableTwoColumns();          tableObjectProperties.leftTableElement.append(this._inputType.rowElement);         tableObjectProperties.leftTableElement.append(this._inputStatus.rowElement);         tableObjectProperties.leftTableElement.append(this._inputCategory.rowElement);         tableObjectProperties.leftTableElement.append(ListingEditorFormComposer.createRowDivider());         tableObjectProperties.leftTableElement.append(this._inputRegion.rowElement);         tableObjectProperties.leftTableElement.append(this._inputDistrict.rowElement);         tableObjectProperties.leftTableElement.append(this._inputMunicipality.rowElement);         tableObjectProperties.leftTableElement.append(this._inputAddress.rowElement);         tableObjectProperties.leftTableElement.append(ListingEditorFormComposer.createRowDivider());         tableObjectProperties.leftTableElement.append(this._inputLat.rowElement);         tableObjectProperties.leftTableElement.append(this._inputLong.rowElement);         tableObjectProperties.leftTableElement.append(this._inputPrecise.rowElement);         tableObjectProperties.leftTableElement.append(ListingEditorFormComposer.createRowDivider());         tableObjectProperties.leftTableElement.append(this._inputArea.rowElement);          tableObjectProperties.rightTableElement.append(this._inputKnid.rowElement);         tableObjectProperties.rightTableElement.append(this._inputComplex.rowElement);         tableObjectProperties.rightTableElement.append(this._inputUid.rowElement);         tableObjectProperties.rightTableElement.append(ListingEditorFormComposer.createRowDivider());         tableObjectProperties.rightTableElement.append(this._inputImage.rowElement);         tableObjectProperties.rightTableElement.append(selectImageLinkRow.rowElement);         tableObjectProperties.rightTableElement.append(this._inputWiki.rowElement);         tableObjectProperties.rightTableElement.append(this._inputWdid.rowElement);         tableObjectProperties.rightTableElement.append(this._inputCommonscat.rowElement);         tableObjectProperties.rightTableElement.append(this._inputMunid.rowElement);         tableObjectProperties.rightTableElement.append(ListingEditorFormComposer.createRowDivider());         tableObjectProperties.rightTableElement.append(this._inputLink.rowElement);         tableObjectProperties.rightTableElement.append(this._inputLinkExtra.rowElement);         tableObjectProperties.rightTableElement.append(this._inputOopt.rowElement);         tableObjectProperties.rightTableElement.append(this._inputDocument.rowElement);          this._form.formElement.append(tableObjectProperties.wrapperElement);          var tableObjectDescription = ListingEditorFormComposer.createTableFullWidth();         var objectDescriptionRow = ListingEditorFormComposer.createObjectDescriptionRow();         this._inputDescription = objectDescriptionRow.inputDescription;         tableObjectDescription.tableElement.append(objectDescriptionRow.row);         tableObjectDescription.tableElement.append(ListingEditorFormComposer.createRowDivider());         this._form.formElement.append(tableObjectDescription.wrapperElement);          var tableChanges = ListingEditorFormComposer.createTableFullWidth();         var changesDescriptionRow = ListingEditorFormComposer.createChangesDescriptionRow();         this._inputChangesSummary = changesDescriptionRow.inputChangesSummary;         this._inputIsMinorChanges = changesDescriptionRow.inputIsMinorChanges;         tableChanges.tableElement.append(ListingEditorFormComposer.createRowDivider());         tableChanges.tableElement.append(changesDescriptionRow.row);         this._form.formElement.append(tableChanges.wrapperElement);          this._directMappingInputs = {             name: this._inputObjectName.inputElement,             status: this._inputStatus.inputElement,             type: this._inputType.inputElement,             category: this._inputCategory.inputElement,             region: this._inputRegion.inputElement,             district: this._inputDistrict.inputElement,             municipality: this._inputMunicipality.inputElement,             address: this._inputAddress.inputElement,             lat: this._inputLat.inputElement,             long: this._inputLong.inputElement,             description: this._inputDescription,             area: this._inputArea.inputElement,             knid: this._inputKnid.inputElement,             complex: this._inputComplex.inputElement,             uid: this._inputUid.inputElement,             image: this._inputImage.inputElement,             wiki: this._inputWiki.inputElement,             wdid: this._inputWdid.inputElement,             commonscat: this._inputCommonscat.inputElement,             munid: this._inputMunid.inputElement,             link: this._inputLink.inputElement,             linkextra: this._inputLinkExtra.inputElement,             document: this._inputDocument.inputElement,             oopt: this._inputOopt.inputElement         };     }      _createClass(NaturalHeritageEditorForm, [{         key: 'getForm',         value: function getForm() {             return this._form;         }     }, {         key: 'setData',         value: function setData(listingData) {             var _this2 = this;              Object.keys(this._directMappingInputs).forEach(function (key) {                 if (listingData[key]) {                     _this2._directMappingInputs[key].val(listingData[key]);                 }             });             this._inputPrecise.inputElement.attr('checked', listingData['precise'] === 'yes');         }     }, {         key: 'getData',         value: function getData() {             var _this3 = this;              var data = {};             Object.keys(this._directMappingInputs).forEach(function (key) {                 data[key] = _this3._directMappingInputs[key].val();             });             if (this._inputPrecise.inputElement.is(':checked')) {                 data['precise'] = 'yes';             } else {                 data['precise'] = 'no';             }             data['link'] = ValidationUtils.normalizeUrl(data['link']);             data['linkextra'] = ValidationUtils.normalizeUrl(data['linkextra']);             return data;         }     }, {         key: 'getObjectName',         value: function getObjectName() {             return this._inputObjectName.inputElement.val();         }     }, {         key: 'getChangesSummary',         value: function getChangesSummary() {             return this._inputChangesSummary.val();         }     }, {         key: 'getChangesIsMinor',         value: function getChangesIsMinor() {             return this._inputIsMinorChanges.is(':checked');         }     }]);      return NaturalHeritageEditorForm; }();   var WikitextParser = {     /**      * Given a listing index, return the full wikitext for that listing      * ("{{listing|key=value|...}}"). An index of 0 returns the first listing      * template invocation, 1 returns the second, etc.      */     getListingWikitextBraces: function getListingWikitextBraces(wikitext, listingName, listingIndex) {         // find the listing wikitext that matches the same index as the listing index         var listingRegex = new RegExp('{{\\s*(' + listingName + ')(\\s|\\|)', 'ig');         // look through all matches for "{{listing|see|do...}}" within the section         // wikitext, returning the nth match, where 'n' is equal to the index of the         // edit link that was clicked         var listingSyntax = void 0,             regexResult = void 0,             listingMatchIndex = void 0;         for (var i = 0; i <= listingIndex; i++) {             regexResult = listingRegex.exec(wikitext);             listingMatchIndex = regexResult.index;             listingSyntax = regexResult[0];         }         // listings may contain nested templates, so step through all section         // text after the matched text to find MATCHING closing braces         // the first two braces are matched by the listing regex and already         // captured in the listingSyntax variable         var curlyBraceCount = 2;         var endPos = wikitext.length;         var startPos = listingMatchIndex + listingSyntax.length;         var matchFound = false;         for (var j = startPos; j < endPos; j++) {             if (wikitext[j] === '{') {                 ++curlyBraceCount;             } else if (wikitext[j] === '}') {                 --curlyBraceCount;             }             if (curlyBraceCount === 0 && j + 1 < endPos) {                 listingSyntax = wikitext.substring(listingMatchIndex, j + 1);                 matchFound = true;                 break;             }         }         if (!matchFound) {             listingSyntax = wikitext.substring(listingMatchIndex);         }         return StringUtils.trim(listingSyntax);     },       /**      * Convert raw wiki listing syntax into a mapping of key-value pairs      * corresponding to the listing template parameters.      */     wikiTextToListing: function wikiTextToListing(wikitext) {         // remove the trailing braces if there are some         for (var i = 0; i < 2; i++) {             if (wikitext[wikitext.length - 1] === '}') {                 wikitext = wikitext.slice(0, -1);             }         }          var listingData = {};         var lastKey = void 0;         var listParams = WikitextParser.listingTemplateToParamsArray(wikitext);         for (var _i = 1; _i < listParams.length; _i++) {             var param = listParams[_i];             var index = param.indexOf('=');             if (index > 0) {                 // param is of the form key=value                 var key = StringUtils.trim(param.substr(0, index));                 listingData[key] = StringUtils.trim(param.substr(index + 1));                 lastKey = key;             } else if (listingData[lastKey].length) {                 // there was a pipe character within a param value, such as                 // "key=value1|value2", so just append to the previous param                 listingData[lastKey] += '|' + param;             }         }          return listingData;     },       /**      * Split the raw template wikitext into an array of params. The pipe      * symbol delimits template params, but this method will also inspect the      * description to deal with nested templates or wikilinks that might contain      * pipe characters that should not be used as delimiters.      */     listingTemplateToParamsArray: function listingTemplateToParamsArray(wikitext) {         var results = [];         var paramValue = '';         var pos = 0;         while (pos < wikitext.length) {             var remainingString = wikitext.substr(pos);             // check for a nested template or wikilink             var patternMatch = WikitextParser.findPatternMatch(remainingString, "{{", "}}");             if (patternMatch.length === 0) {                 patternMatch = WikitextParser.findPatternMatch(remainingString, "[[", "]]");             }             if (patternMatch.length > 0) {                 paramValue += patternMatch;                 pos += patternMatch.length;             } else if (wikitext.charAt(pos) === '|') {                 // delimiter - push the previous param and move on to the next                 results.push(paramValue);                 paramValue = '';                 pos++;             } else {                 // append the character to the param value being built                 paramValue += wikitext.charAt(pos);                 pos++;             }         }         if (paramValue.length > 0) {             // append the last param value             results.push(paramValue);         }         return results;     },       /**      * Utility method for finding a matching end pattern for a specified start      * pattern, including nesting.  The specified value must start with the      * start value, otherwise an empty string will be returned.      */     findPatternMatch: function findPatternMatch(value, startPattern, endPattern) {         var matchString = '';         var startRegex = new RegExp('^' + WikitextParser.replaceSpecial(startPattern), 'i');         if (startRegex.test(value)) {             var endRegex = new RegExp('^' + WikitextParser.replaceSpecial(endPattern), 'i');             var matchCount = 1;             for (var i = startPattern.length; i < value.length; i++) {                 var remainingValue = value.substr(i);                 if (startRegex.test(remainingValue)) {                     matchCount++;                 } else if (endRegex.test(remainingValue)) {                     matchCount--;                 }                 if (matchCount === 0) {                     matchString = value.substr(0, i);                     break;                 }             }         }         return matchString;     },     replaceSpecial: function replaceSpecial(str) {         return str.replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&");     } };   var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }  var WikitextSectionEditor = function () {     function WikitextSectionEditor(sectionText, listingName) {         _classCallCheck(this, WikitextSectionEditor);          this._sectionText = sectionText;         this._listingName = listingName;         this._commentReplacements = {};         this._stripComments();     }      _createClass(WikitextSectionEditor, [{         key: 'getListingData',         value: function getListingData(listingIndex) {             var listingText = WikitextParser.getListingWikitextBraces(this._sectionText, this._listingName, listingIndex);             var listingData = WikitextParser.wikiTextToListing(listingText);             for (var key in listingData) {                 if (!listingData.hasOwnProperty(key)) {                     continue;                 }                 listingData[key] = this._restoreComments(listingData[key]);             }             return listingData;         }     }, {         key: 'getSectionTextWithReplacedListing',         value: function getSectionTextWithReplacedListing(listingIndex, newListingText) {             var oldListingText = WikitextParser.getListingWikitextBraces(this._sectionText, this._listingName, listingIndex);             var result = this._sectionText;             result = result.replace(oldListingText, newListingText);             result = this._restoreComments(result);             return result;         }     }, {         key: 'getSectionTextWithAddedListing',         value: function getSectionTextWithAddedListing(newListingText) {             var result = this._sectionText;              var index = result.indexOf('{{footer');              if (index > 0) {                 result = result.substr(0, index) + '\n' + newListingText + '\n' + result.substr(index);             } else {                 result += '\n' + newListingText;             }              result = this._restoreComments(result);              return result;         }          /**          * Commented-out listings can result in the wrong listing being edited, so          * strip out any comments and replace them with placeholders that can be          * restored prior to saving changes.          */      }, {         key: '_stripComments',         value: function _stripComments() {             var comments = this._sectionText.match(/<!--[\s\S]*?-->/mig);             if (comments !== null) {                 for (var i = 0; i < comments.length; i++) {                     var comment = comments[i];                     var rep = '<<<COMMENT' + i + '>>>';                     this._sectionText = this._sectionText.replace(comment, rep);                     this._commentReplacements[rep] = comment;                 }             }         }          /**          * Search the text provided, and if it contains any text that was          * previously stripped out for replacement purposes, restore it.          */      }, {         key: '_restoreComments',         value: function _restoreComments(sectionText) {             for (var key in this._commentReplacements) {                 var val = this._commentReplacements[key];                 sectionText = sectionText.replace(key, val);             }             return sectionText;         }     }]);      return WikitextSectionEditor; }();   var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }  var ListingSerializer = function () {     function ListingSerializer(listingType, listingData) {         _classCallCheck(this, ListingSerializer);          this._listingType = listingType;         this._listingData = listingData;         this._serializedListing = '';         this._serializedParameters = [];     }      _createClass(ListingSerializer, [{         key: 'writeListingStart',         value: function writeListingStart(addNewline) {             this._serializedListing += '{{' + this._listingType;             if (addNewline) {                 this._serializedListing += "\n";             } else {                 this._serializedListing += ' ';             }         }     }, {         key: 'writeParameterLine',         value: function writeParameterLine(parameterName, optional) {             var parameterValue = this._listingData[parameterName];             if (optional && (parameterValue === '' || parameterValue === undefined)) {                 return;             }             if (parameterValue === undefined) {                 parameterValue = '';             }             this._serializedListing += '|' + parameterName + "=" + parameterValue + "\n";             this._serializedParameters.push(parameterName);         }     }, {         key: 'writeParametersLine',         value: function writeParametersLine(parameterNames) {             for (var i = 0; i < parameterNames.length; i++) {                 var parameterName = parameterNames[i];                 var parameterValue = this._listingData[parameterName];                 if (parameterValue === undefined) {                     parameterValue = '';                 }                 if (i > 0) {                     this._serializedListing += " ";                 }                 this._serializedListing += "|" + parameterName + "=" + parameterValue;                 this._serializedParameters.push(parameterName);             }             this._serializedListing += "\n";         }     }, {         key: 'writeOtherNonEmptyParameters',         value: function writeOtherNonEmptyParameters() {             for (var parameterName in this._listingData) {                 if (!this._listingData.hasOwnProperty(parameterName)) {                     continue;                 }                  if (!ArrayUtils.hasElement(this._serializedParameters, parameterName)) {                     var parameterValue = this._listingData[parameterName];                     if (parameterValue !== '' && parameterValue !== undefined) {                         this._serializedListing += '|' + parameterName + "=" + parameterValue + "\n";                     }                 }             }         }     }, {         key: 'writeListingEnd',         value: function writeListingEnd() {             this._serializedListing += '}}';         }     }, {         key: 'getSerializedListing',         value: function getSerializedListing() {             return this._serializedListing;         }     }]);      return ListingSerializer; }();   var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }  var NaturalEditorListingSerializer = function () {     function NaturalEditorListingSerializer() {         _classCallCheck(this, NaturalEditorListingSerializer);     }      _createClass(NaturalEditorListingSerializer, [{         key: "serializeListingData",         value: function serializeListingData(listingData) {             var listingSerializer = new ListingSerializer('natural monument', listingData);             listingSerializer.writeListingStart();             listingSerializer.writeParametersLine(["type", "status"]);             listingSerializer.writeParametersLine(["lat", "long", "precise"]);             listingSerializer.writeParameterLine("name");             listingSerializer.writeParameterLine("category", true);             listingSerializer.writeParameterLine("knid");             listingSerializer.writeParameterLine("complex", true);             listingSerializer.writeParameterLine("uid", true);             listingSerializer.writeParametersLine(["region", "district"]);             listingSerializer.writeParametersLine(["municipality", "munid"]);             listingSerializer.writeParameterLine("address");             listingSerializer.writeParameterLine("area", true);             listingSerializer.writeParameterLine("description");             listingSerializer.writeParameterLine("image");             listingSerializer.writeParameterLine("wdid");             listingSerializer.writeParameterLine("wiki");             listingSerializer.writeParameterLine("commonscat");             listingSerializer.writeParameterLine("link", true);             listingSerializer.writeParameterLine("linkextra", true);             listingSerializer.writeParameterLine("document", true);             listingSerializer.writeParameterLine("oopt", true);             listingSerializer.writeOtherNonEmptyParameters();             listingSerializer.writeListingEnd();             return listingSerializer.getSerializedListing();         }     }]);      return NaturalEditorListingSerializer; }();   var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }  var SavingForm = function () {     function SavingForm() {         _classCallCheck(this, SavingForm);          this._progress = $('<div id="progress-dialog">' + 'Сохранение...' + '</div>');         this._progress.dialog({             modal: true,             height: 100,             width: 300,             title: ''         });         $(".ui-dialog-titlebar").hide();     }      _createClass(SavingForm, [{         key: 'destroy',         value: function destroy() {             this._progress.dialog('destroy').remove();         }     }]);      return SavingForm; }();   InputInsertSymbols = {     addQuotesInsertHandler: function addQuotesInsertHandler(insertButton, insertToInput) {         insertButton.click(function () {             var selectionStart = insertToInput[0].selectionStart;             var selectionEnd = insertToInput[0].selectionEnd;             var oldValue