"use strict";

if (typeof window.tasks !== "function") {
	// Not initialized

	// Initialize of the class in global namespace
	window.tasks = class tasks {
		/**
		 * Заблокировать функцию закрытия всплывающего окна?
		 */
		static freeze = false;

		/**
		 * Тело всплывающего окна (массив)
		 */
		static body = {};

		/**
		 * Инициализирован класс?
		 */
		static initialized = false;

		/**
		 * Создать заявку
		 *
		 * @param {HTMLElement} cashiers Колонка с кассирами <div>
		 * @param {HTMLElement} displayers Колонка с выкладчиками <div>
		 * @param {HTMLElement} gastronomes Колонка с гастрономов <div>
		 * @param {HTMLElement} brigadiers Колонка с бригадирами <div>
		 * @param {HTMLElement} loaders Колонка с грузчиками <input>
		 * @param {HTMLElement} loaders_mobile Колонка с мобильными грузчиками <div>
		 * @param {HTMLElement} universals_mobile Колонка с мобильными универсалами <div>
		 * @param {HTMLElement} button Кнопка создания <button>
		 *
		 * @return {void}
		 */
		static _create(
			cashiers,
			displayers,
			gastronomes,
			brigadiers,
			loaders,
			loaders_mobile,
			universals_mobile,
			button
		) {
			if (cashiers instanceof HTMLElement) {
				// Кассиры получены

				// Блокировка полей ввода
				for (let i = 1; i < cashiers.childElementCount; i += 2) {
					if (
						cashiers.children[i].children[0].children instanceof HTMLCollection
					) {
						for (const element of cashiers.children[i].children[0].children) {
							element.setAttribute("disabled", true);
						}
					}
				}
				for (let i = 2; i < cashiers.childElementCount; i += 2) {
					if (cashiers.children[i].children[0] instanceof HTMLElement) {
						cashiers.children[i].children[0].setAttribute("disabled", true);
					}
				}
			}

			if (displayers instanceof HTMLElement) {
				// Выкладчики получены

				// Блокировка полей ввода
				for (let i = 1; i < displayers.childElementCount; i += 2) {
					if (
						displayers.children[i].children[0].children instanceof
						HTMLCollection
					) {
						for (const element of displayers.children[i].children[0].children) {
							element.setAttribute("disabled", true);
						}
					}
				}
				for (let i = 2; i < displayers.childElementCount; i += 2) {
					if (displayers.children[i].children[0] instanceof HTMLElement) {
						displayers.children[i].children[0].setAttribute("disabled", true);
					}
				}
			}

			if (gastronomes instanceof HTMLElement) {
				// Гастрономы получены

				// Блокировка полей ввода
				for (let i = 1; i < gastronomes.childElementCount; i += 2) {
					if (
						gastronomes.children[i].children[0].children instanceof
						HTMLCollection
					) {
						for (const element of gastronomes.children[i].children[0]
							.children) {
							element.setAttribute("disabled", true);
						}
					}
				}
				for (let i = 2; i < gastronomes.childElementCount; i += 2) {
					if (gastronomes.children[i].children[0] instanceof HTMLElement) {
						gastronomes.children[i].children[0].setAttribute("disabled", true);
					}
				}
			}

			if (brigadiers instanceof HTMLElement) {
				// Бригадиры получены

				// Блокировка полей ввода
				for (let i = 1; i < brigadiers.childElementCount; i += 2) {
					if (
						brigadiers.children[i].children[0].children instanceof
						HTMLCollection
					) {
						for (const element of brigadiers.children[i].children[0].children) {
							element.setAttribute("disabled", true);
						}
					}
				}
				for (let i = 2; i < brigadiers.childElementCount; i += 2) {
					if (brigadiers.children[i].children[0] instanceof HTMLElement) {
						brigadiers.children[i].children[0].setAttribute("disabled", true);
					}
				}
			}

			if (loaders instanceof HTMLElement) {
				// Грузчики получены

				// Блокировка полей ввода
				for (let i = 1; i < loaders.childElementCount; i += 2) {
					if (
						loaders.children[i].children[0].children instanceof HTMLCollection
					) {
						for (const element of loaders.children[i].children[0].children) {
							element.setAttribute("disabled", true);
						}
					}
				}
				for (let i = 2; i < loaders.childElementCount; i += 2) {
					if (loaders.children[i].children[0] instanceof HTMLElement) {
						loaders.children[i].children[0].setAttribute("disabled", true);
					}
				}
			}

			if (loaders_mobile instanceof HTMLElement) {
				// Мобильные грузчики получены

				// Блокировка полей ввода
				for (let i = 1; i < loaders_mobile.childElementCount; i += 2) {
					if (
						loaders_mobile.children[i].children[0].children instanceof
						HTMLCollection
					) {
						for (const element of loaders_mobile.children[i].children[0]
							.children) {
							element.setAttribute("disabled", true);
						}
					}
				}
				for (let i = 2; i < loaders_mobile.childElementCount; i += 2) {
					if (loaders_mobile.children[i].children[0] instanceof HTMLElement) {
						loaders_mobile.children[i].children[0].setAttribute(
							"disabled",
							true
						);
					}
				}
			}

			if (universals_mobile instanceof HTMLElement) {
				// Мобильные универсалы получены

				// Блокировка полей ввода
				for (let i = 1; i < universals_mobile.childElementCount; i += 2) {
					if (
						universals_mobile.children[i].children[0].children instanceof
						HTMLCollection
					) {
						for (const element of universals_mobile.children[i].children[0]
							.children) {
							element.setAttribute("disabled", true);
						}
					}
				}
				for (let i = 2; i < universals_mobile.childElementCount; i += 2) {
					if (
						universals_mobile.children[i].children[0] instanceof HTMLElement
					) {
						universals_mobile.children[i].children[0].setAttribute(
							"disabled",
							true
						);
					}
				}
			}

			// Блокировка кнопки
			button.setAttribute("disabled", true);

			// Запуск выполнения
			this.__create(
				cashiers,
				displayers,
				gastronomes,
				brigadiers,
				loaders,
				loaders_mobile,
				universals_mobile,
				button
			);
		}

		/**
		 * Создать заявку
		 *
		 * @param {HTMLElement} cashiers Колонка с кассирами <div>
		 * @param {HTMLElement} displayers Колонка с выкладчиками <div>
		 * @param {HTMLElement} gastronomes Колонка с гастрономов <div>
		 * @param {HTMLElement} brigadiers Колонка с бригадирами <div>
		 * @param {HTMLElement} loaders Колонка с грузчиками <input>
		 * @param {HTMLElement} loaders_mobile Колонка с мобильными грузчиками <div>
		 * @param {HTMLElement} universals_mobile Колонка с мобильными универсалами <div>
		 * @param {HTMLElement} button Кнопка создания <button>
		 *
		 * @return {void}
		 */
		static __create = damper(
			async (
				cashiers,
				displayers,
				gastronomes,
				brigadiers,
				loaders,
				loaders_mobile,
				universals_mobile,
				button
			) => {
				// Инициализация функции разблокировки
				function unblock() {
					if (cashiers instanceof HTMLElement) {
						// Кассиры получены

						// Разблокировка полей ввода
						for (let i = 1; i < cashiers.childElementCount; i += 2) {
							if (
								cashiers.children[i].children[0].children instanceof
								HTMLCollection
							) {
								for (const element of cashiers.children[i].children[0]
									.children) {
									element.removeAttribute("disabled");
								}
							}
						}
						for (let i = 2; i < cashiers.childElementCount; i += 2) {
							if (cashiers.children[i].children[0] instanceof HTMLElement) {
								cashiers.children[i].children[0].removeAttribute("disabled");
							}
						}
					}

					if (displayers instanceof HTMLElement) {
						// Выкладчики получены

						// Разблокировка полей ввода
						for (let i = 1; i < displayers.childElementCount; i += 2) {
							if (
								displayers.children[i].children[0].children instanceof
								HTMLCollection
							) {
								for (const element of displayers.children[i].children[0]
									.children) {
									element.removeAttribute("disabled");
								}
							}
						}
						for (let i = 2; i < displayers.childElementCount; i += 2) {
							if (displayers.children[i].children[0] instanceof HTMLElement) {
								displayers.children[i].children[0].removeAttribute("disabled");
							}
						}
					}

					if (gastronomes instanceof HTMLElement) {
						// Гастрономы получены

						// Разблокировка полей ввода
						for (let i = 1; i < gastronomes.childElementCount; i += 2) {
							if (
								gastronomes.children[i].children[0].children instanceof
								HTMLCollection
							) {
								for (const element of gastronomes.children[i].children[0]
									.children) {
									element.removeAttribute("disabled");
								}
							}
						}
						for (let i = 2; i < gastronomes.childElementCount; i += 2) {
							if (gastronomes.children[i].children[0] instanceof HTMLElement) {
								gastronomes.children[i].children[0].removeAttribute("disabled");
							}
						}
					}

					if (brigadiers instanceof HTMLElement) {
						// Бригадиры получены

						// Разблокировка полей ввода
						for (let i = 1; i < brigadiers.childElementCount; i += 2) {
							if (
								brigadiers.children[i].children[0].children instanceof
								HTMLCollection
							) {
								for (const element of brigadiers.children[i].children[0]
									.children) {
									element.removeAttribute("disabled");
								}
							}
						}
						for (let i = 2; i < brigadiers.childElementCount; i += 2) {
							if (brigadiers.children[i].children[0] instanceof HTMLElement) {
								brigadiers.children[i].children[0].removeAttribute("disabled");
							}
						}
					}

					if (loaders instanceof HTMLElement) {
						// Грузчики получены

						// Разблокировка полей ввода
						for (let i = 1; i < loaders.childElementCount; i += 2) {
							if (
								loaders.children[i].children[0].children instanceof
								HTMLCollection
							) {
								for (const element of loaders.children[i].children[0]
									.children) {
									element.removeAttribute("disabled");
								}
							}
						}
						for (let i = 2; i < loaders.childElementCount; i += 2) {
							if (loaders.children[i].children[0] instanceof HTMLElement) {
								loaders.children[i].children[0].removeAttribute("disabled");
							}
						}
					}

					if (loaders_mobile instanceof HTMLElement) {
						// Мобильные грузчики получены

						// Разблокировка полей ввода
						for (let i = 1; i < loaders_mobile.childElementCount; i += 2) {
							if (
								loaders_mobile.children[i].children[0].children instanceof
								HTMLCollection
							) {
								for (const element of loaders_mobile.children[i].children[0]
									.children) {
									element.removeAttribute("disabled");
								}
							}
						}
						for (let i = 2; i < loaders_mobile.childElementCount; i += 2) {
							if (
								loaders_mobile.children[i].children[0] instanceof HTMLElement
							) {
								loaders_mobile.children[i].children[0].removeAttribute(
									"disabled"
								);
							}
						}
					}

					if (universals_mobile instanceof HTMLElement) {
						// Мобильные универсалы получены

						// Разблокировка полей ввода
						for (let i = 1; i < universals_mobile.childElementCount; i += 2) {
							if (
								universals_mobile.children[i].children[0].children instanceof
								HTMLCollection
							) {
								for (const element of universals_mobile.children[i].children[0]
									.children) {
									element.removeAttribute("disabled");
								}
							}
						}
						for (let i = 2; i < universals_mobile.childElementCount; i += 2) {
							if (
								universals_mobile.children[i].children[0] instanceof HTMLElement
							) {
								universals_mobile.children[i].children[0].removeAttribute(
									"disabled"
								);
							}
						}
					}

					// Разблокировка кнопки
					button.removeAttribute("disabled");
				}

				// Запуск отсрочки разблокировки на случай, если сервер не отвечает
				const timeout = setTimeout(() => {
					this.errors(["Сервер не отвечает"]);
					unblock();
				}, 5000);

				// Инициадизация буфера JSON для отправки
				const body = {};

				if (cashiers instanceof HTMLElement) {
					// Кассиры получены

					// Инициализация реестра
					body.cashiers = [];

					// Запись в буфер JSON для отправки
					for (let i = 1; i < cashiers.childElementCount; i += 2) {
						if (
							cashiers.children[i].children[0].children instanceof
							HTMLCollection
						) {
							body.cashiers.push({
								start:
									cashiers.children[i].children[0].children[0].value ?? null,
								end: cashiers.children[i].children[0].children[1].value ?? null,
								date:
									cashiers.children[i].children[0].children[2].valueAsDate /
										1000 ?? null,
								commentary: cashiers.children[i + 1].children[0].value ?? null,
							});
						}
					}
				}

				if (displayers instanceof HTMLElement) {
					// Выкладчики получены

					// Инициализация реестра
					body.displayers = [];

					// Запись в буфер JSON для отправки
					for (let i = 1; i < displayers.childElementCount; i += 2) {
						if (
							displayers.children[i].children[0].children instanceof
							HTMLCollection
						) {
							body.displayers.push({
								start:
									displayers.children[i].children[0].children[0].value ?? null,
								end:
									displayers.children[i].children[0].children[1].value ?? null,
								date:
									displayers.children[i].children[0].children[2].valueAsDate /
										1000 ?? null,
								commentary:
									displayers.children[i + 1].children[0].value ?? null,
							});
						}
					}
				}

				if (gastronomes instanceof HTMLElement) {
					// Гастрономы получены

					// Инициализация реестра
					body.gastronomes = [];

					// Запись в буфер JSON для отправки
					for (let i = 1; i < gastronomes.childElementCount; i += 2) {
						if (
							gastronomes.children[i].children[0].children instanceof
							HTMLCollection
						) {
							body.gastronomes.push({
								start:
									gastronomes.children[i].children[0].children[0].value ?? null,
								end:
									gastronomes.children[i].children[0].children[1].value ?? null,
								date:
									gastronomes.children[i].children[0].children[2].valueAsDate /
										1000 ?? null,
								commentary:
									gastronomes.children[i + 1].children[0].value ?? null,
							});
						}
					}
				}

				if (brigadiers instanceof HTMLElement) {
					// Бригадиры получены

					// Инициализация реестра
					body.brigadiers = [];

					// Запись в буфер JSON для отправки
					for (let i = 1; i < brigadiers.childElementCount; i += 2) {
						if (
							brigadiers.children[i].children[0].children instanceof
							HTMLCollection
						) {
							body.brigadiers.push({
								start:
									brigadiers.children[i].children[0].children[0].value ?? null,
								end:
									brigadiers.children[i].children[0].children[1].value ?? null,
								date:
									brigadiers.children[i].children[0].children[2].valueAsDate /
										1000 ?? null,
								commentary:
									brigadiers.children[i + 1].children[0].value ?? null,
							});
						}
					}
				}

				if (loaders instanceof HTMLElement) {
					// Грузчики получены

					// Инициализация реестра
					body.loaders = [];

					// Запись в буфер JSON для отправки
					for (let i = 1; i < loaders.childElementCount; i += 2) {
						if (
							loaders.children[i].children[0].children instanceof HTMLCollection
						) {
							body.loaders.push({
								start:
									loaders.children[i].children[0].children[0].value ?? null,
								end: loaders.children[i].children[0].children[1].value ?? null,
								date: loaders.children[i].children[0].children[2].value ?? null,
								commentary: loaders.children[i + 1].children[0].value ?? null,
							});
						}
					}
				}

				if (loaders_mobile instanceof HTMLElement) {
					// Мобильные грузчики получены

					// Инициализация реестра
					body.loaders_mobile = [];

					// Запись в буфер JSON для отправки
					for (let i = 1; i < loaders_mobile.childElementCount; i += 2) {
						if (
							loaders_mobile.children[i].children[0].children instanceof
							HTMLCollection
						) {
							body.loaders_mobile.push({
								start:
									loaders_mobile.children[i].children[0].children[0].value ??
									null,
								end:
									loaders_mobile.children[i].children[0].children[1].value ??
									null,
								date:
									loaders_mobile.children[i].children[0].children[2]
										.valueAsDate / 1000 ?? null,
								commentary:
									loaders_mobile.children[i + 1].children[0].value ?? null,
							});
						}
					}
				}

				if (universals_mobile instanceof HTMLElement) {
					// Мобильные универсалы получены

					// Инициализация реестра
					body.universals_mobile = [];

					// Запись в буфер JSON для отправки
					for (let i = 1; i < universals_mobile.childElementCount; i += 2) {
						if (
							universals_mobile.children[i].children[0].children instanceof
							HTMLCollection
						) {
							body.universals_mobile.push({
								start:
									universals_mobile.children[i].children[0].children[0].value ??
									null,
								end:
									universals_mobile.children[i].children[0].children[1].value ??
									null,
								date:
									universals_mobile.children[i].children[0].children[2]
										.valueAsDate / 1000 ?? null,
								commentary:
									universals_mobile.children[i + 1].children[0].value ?? null,
							});
						}
					}
				}

				// Запрос к серверу
				return await fetch("/tasks/create", {
					method: "POST",
					headers: {
						Accept: "application/json",
						"Content-Type": "application/json",
					},
					body: JSON.stringify(body),
				})
					.then((response) => response.json())
					.then((data) => {
						// Удаление отсрочки разблокировки
						clearTimeout(timeout);

						if (this.errors(data.errors)) {
							// Сгенерированы ошибки

							// Разблокировка полей ввода и кнопок
							unblock();
						} else {
							// Не сгенерированы ошибки (подразумевается их отсутствие)

							if (this.body.wrap instanceof HTMLElement) {
								// Найдено активное окно

								// Деинициализация быстрых действий по кнопкам
								document.removeEventListener("keydown", this.buttons);

								// Сброс блокировки
								this.freeze = false;

								// Деинициализация активного окна
								this.body.wrap.remove();
							}

							// Реинициализация строк
							this.reinit();
						}
					});
			},
			300
		);

		/**
		 * Сгенерировать окно создания заявок
		 *
		 * @return {void}
		 */
		static create = damper(() => {
			// Инициализация оболочки всплывающего окна
			this.body.wrap = document.createElement("div");
			this.body.wrap.setAttribute("id", "popup");

			// Инициализация всплывающего окна
			const popup = document.createElement("section");
			popup.classList.add("list", "small");

			// Инициализация заголовка всплывающего окна
			const title = document.createElement("h3");
			title.classList.add("unselectable");
			title.innerText = "Создание заявки";

			// Инициализация оболочки с основной информацией
			const main = document.createElement("section");
			main.classList.add("main");

			// Инициализация колонки с задачами
			const tasks = document.createElement("div");
			tasks.classList.add("column");
			tasks.setAttribute("data-column", "tasks");

			// Инициализация строки
			const row_1 = document.createElement("div");
			row_1.classList.add("row", "merged");

			// Инициализация оболочки для строки с кассирами
			const cashier = document.createElement("label");
			cashier.setAttribute("id", "cashier");

			// Инициализация заголовка для поля ввода кассиров
			const cashier_title = document.createElement("b");
			cashier_title.classList.add("separated", "right", "unselectable");
			cashier_title.innerText = "Кассиры:";

			// Инициализация поля ввода кассиров
			const cashier_input = document.createElement("input");
			cashier_input.classList.add("small", "center", "cloud");
			cashier_input.setAttribute("type", "number");
			cashier_input.setAttribute("min", "0");
			cashier_input.setAttribute("max", "10");
			cashier_input.setAttribute("title", "Количество кассиров");
			cashier_input.value = 0;

			// Инициализация строки
			const row_2 = document.createElement("div");
			row_2.classList.add("row", "merged");

			// Инициализация оболочки для строки с выкладчиками
			const displayer = document.createElement("label");
			displayer.setAttribute("id", "displayer");

			// Инициализация заголовка для поля ввода выкладчиков
			const displayer_title = document.createElement("b");
			displayer_title.classList.add("separated", "right", "unselectable");
			displayer_title.innerText = "Выкладчики:";

			// Инициализация поля ввода выкладчиков
			const displayer_input = document.createElement("input");
			displayer_input.classList.add("small", "center", "cloud");
			displayer_input.setAttribute("type", "number");
			displayer_input.setAttribute("min", "0");
			displayer_input.setAttribute("max", "10");
			displayer_input.setAttribute("title", "Количество выкладчиков");
			displayer_input.value = 0;

			// Инициализация строки
			const row_3 = document.createElement("div");
			row_3.classList.add("row", "merged");

			// Инициализация оболочки для строки с гастрономами
			const gastronome = document.createElement("label");
			gastronome.setAttribute("id", "gastronome");

			// Инициализация заголовка для поля ввода гастрономов
			const gastronome_title = document.createElement("b");
			gastronome_title.classList.add("separated", "right", "unselectable");
			gastronome_title.innerText = "Гастрономы:";

			// Инициализация поля ввода гастрономов
			const gastronome_input = document.createElement("input");
			gastronome_input.classList.add("small", "center", "cloud");
			gastronome_input.setAttribute("type", "number");
			gastronome_input.setAttribute("min", "0");
			gastronome_input.setAttribute("max", "10");
			gastronome_input.setAttribute("title", "Количество гастрономов");
			gastronome_input.value = 0;

			// Инициализация строки
			const row_4 = document.createElement("div");
			row_4.classList.add("row", "merged");

			// Инициализация оболочки для строки с бригадирами
			const brigadier = document.createElement("label");
			brigadier.setAttribute("id", "brigadier");

			// Инициализация заголовка для поля ввода бригадиров
			const brigadier_title = document.createElement("b");
			brigadier_title.classList.add("separated", "right", "unselectable");
			brigadier_title.innerText = "Бригадиры:";

			// Инициализация поля ввода бригадиров
			const brigadier_input = document.createElement("input");
			brigadier_input.classList.add("small", "center", "cloud");
			brigadier_input.setAttribute("type", "number");
			brigadier_input.setAttribute("min", "0");
			brigadier_input.setAttribute("max", "10");
			brigadier_input.setAttribute("title", "Количество бригадиров");
			brigadier_input.value = 0;

			// Инициализация строки
			const row_5 = document.createElement("div");
			row_5.classList.add("row", "merged");

			// Инициализация оболочки для строки с грузчиками
			const loader = document.createElement("label");
			loader.setAttribute("id", "loader");

			// Инициализация заголовка для поля ввода грузчиков
			const loader_title = document.createElement("b");
			loader_title.classList.add("separated", "right", "unselectable");
			loader_title.innerText = "Грузчики:";

			// Инициализация поля ввода грузчиков
			const loader_input = document.createElement("input");
			loader_input.classList.add("small", "center", "cloud");
			loader_input.setAttribute("type", "number");
			loader_input.setAttribute("min", "0");
			loader_input.setAttribute("max", "10");
			loader_input.setAttribute("title", "Количество грузчиков");
			loader_input.value = 0;

			// Инициализация строки
			const row_6 = document.createElement("div");
			row_6.classList.add("row", "merged");

			// Инициализация оболочки для строки с мобильными грузчиками
			const loader_mobile = document.createElement("label");
			loader_mobile.setAttribute("id", "loader_mobile");

			// Инициализация заголовка для поля ввода мобильных грузчиков
			const loader_mobile_title = document.createElement("b");
			loader_mobile_title.classList.add("separated", "right", "unselectable");
			loader_mobile_title.innerText = "Мобильные грузчики:";

			// Инициализация поля ввода мобильных грузчиков
			const loader_mobile_input = document.createElement("input");
			loader_mobile_input.classList.add("small", "center", "cloud");
			loader_mobile_input.setAttribute("type", "number");
			loader_mobile_input.setAttribute("min", "0");
			loader_mobile_input.setAttribute("max", "10");
			loader_mobile_input.setAttribute(
				"title",
				"Количество мобильных грузчиков"
			);
			loader_mobile_input.value = 0;

			// Инициализация строки
			const row_7 = document.createElement("div");
			row_7.classList.add("row", "merged");

			// Инициализация оболочки для строки с мобильными универсалами
			const universal_mobile = document.createElement("label");
			universal_mobile.setAttribute("id", "universal_mobile");

			// Инициализация заголовка для поля ввода мобильных универсалов
			const universal_mobile_title = document.createElement("b");
			universal_mobile_title.classList.add(
				"separated",
				"right",
				"unselectable"
			);
			universal_mobile_title.innerText = "Мобильные универсалы:";

			// Инициализация поля ввода мобильных универсалов
			const universal_mobile_input = document.createElement("input");
			universal_mobile_input.classList.add("small", "center", "cloud");
			universal_mobile_input.setAttribute("type", "number");
			universal_mobile_input.setAttribute("min", "0");
			universal_mobile_input.setAttribute("max", "10");
			universal_mobile_input.setAttribute(
				"title",
				"Количество мобильных универсалов"
			);
			universal_mobile_input.value = 0;

			// Инициализация строки
			const row_8 = document.createElement("div");
			row_8.classList.add("row", "buttons");

			// Инициализация оболочки для кнопок
			const buttons = document.createElement("label");

			// Инициализация кнопки настройки создаваемых заявок
			const next = document.createElement("button");
			next.classList.add("grass");
			next.innerText = "Продолжить";
			next.setAttribute(
				"onclick",
				`tasks.create_detailed(
					this.parentElement.parentElement.parentElement.children[0].children[0].children[1], 
					this.parentElement.parentElement.parentElement.children[1].children[0].children[1], 
					this.parentElement.parentElement.parentElement.children[2].children[0].children[1], 
					this.parentElement.parentElement.parentElement.children[3].children[0].children[1], 
					this.parentElement.parentElement.parentElement.children[4].children[0].children[1], 
					this.parentElement.parentElement.parentElement.children[5].children[0].children[1], 
					this.parentElement.parentElement.parentElement.children[6].children[0].children[1], 
				)`
			);

			// Инициализация окна с ошибками
			this.body.errors = document.createElement("section");
			this.body.errors.classList.add(
				"errors",
				"window",
				"list",
				"calculated",
				"hidden"
			);
			this.body.errors.setAttribute("data-errors", true);

			// Инициализация элемента-тела (оболочки) окна с ошибками
			const errors = document.createElement("section");
			errors.classList.add("body");

			// Инициализация элемента-списка ошибок
			const dl = document.createElement("dl");

			// Инициализация активного всплывающего окна
			const old = document.getElementById("popup");

			if (old instanceof HTMLElement) {
				// Найдено активное окно

				// Деинициализация быстрых действий по кнопкам
				document.removeEventListener("keydown", this.buttons);

				// Сброс блокировки
				this.freeze = false;

				// Удаление активного окна
				old.remove();
			}

			// Запись в документ
			popup.appendChild(title);

			cashier.appendChild(cashier_title);
			cashier.appendChild(cashier_input);
			row_1.appendChild(cashier);
			tasks.appendChild(row_1);

			displayer.appendChild(displayer_title);
			displayer.appendChild(displayer_input);
			row_2.appendChild(displayer);
			tasks.appendChild(row_2);

			gastronome.appendChild(gastronome_title);
			gastronome.appendChild(gastronome_input);
			row_3.appendChild(gastronome);
			tasks.appendChild(row_3);

			brigadier.appendChild(brigadier_title);
			brigadier.appendChild(brigadier_input);
			row_4.appendChild(brigadier);
			tasks.appendChild(row_4);

			loader.appendChild(loader_title);
			loader.appendChild(loader_input);
			row_5.appendChild(loader);
			tasks.appendChild(row_5);

			loader_mobile.appendChild(loader_mobile_title);
			loader_mobile.appendChild(loader_mobile_input);
			row_6.appendChild(loader_mobile);
			tasks.appendChild(row_6);

			universal_mobile.appendChild(universal_mobile_title);
			universal_mobile.appendChild(universal_mobile_input);
			row_7.appendChild(universal_mobile);
			tasks.appendChild(row_7);

			buttons.appendChild(next);
			row_8.appendChild(buttons);
			tasks.appendChild(row_8);

			main.appendChild(tasks);
			popup.appendChild(main);

			this.body.wrap.appendChild(popup);
			document.body.appendChild(this.body.wrap);

			errors.appendChild(dl);
			this.body.errors.appendChild(errors);
			this.body.wrap.appendChild(this.body.errors);

			// Инициализация ширины окна с ошибками
			this.body.errors.style.setProperty(
				"--calculated-width",
				popup.offsetWidth + "px"
			);

			// Инициализация переменных для окна с ошибками (12 - это значение gap из div#popup)
			function top(errors) {
				errors.style.setProperty("transition", "0s");
				errors.style.setProperty(
					"--top",
					popup.offsetTop + popup.offsetHeight + 12 + "px"
				);
				setTimeout(() => errors.style.removeProperty("transition"), 100);
			}
			top(this.body.errors);
			const resize = new ResizeObserver(() => top(this.body.errors));
			resize.observe(this.body.wrap);

			// Инициализация функции блокировки кнопки
			const block = () => {
				if (
					cashier_input.value > 0 ||
					displayer_input.value > 0 ||
					gastronome_input.value > 0 ||
					brigadier_input.value > 0 ||
					loader_input.value > 0 ||
					loader_mobile_input.value > 0 ||
					universal_mobile_input.value > 0
				) {
					next.removeAttribute("disabled");
				} else next.setAttribute("disabled", "true");
			};

			// Добавление функции блокировки кнопки по событиям
			cashier_input.addEventListener("keyup", block);
			displayer_input.addEventListener("keyup", block);
			gastronome_input.addEventListener("keyup", block);
			brigadier_input.addEventListener("keyup", block);
			loader_input.addEventListener("keyup", block);
			loader_mobile_input.addEventListener("keyup", block);
			universal_mobile_input.addEventListener("keyup", block);

			// Добавление функции блокировки кнопки по событиям
			cashier_input.addEventListener("change", block);
			displayer_input.addEventListener("change", block);
			gastronome_input.addEventListener("change", block);
			brigadier_input.addEventListener("change", block);
			loader_input.addEventListener("change", block);
			loader_mobile_input.addEventListener("change", block);
			universal_mobile_input.addEventListener("change", block);

			// Первичная активация функции блокировки кнопки
			block();

			// Инициализация функции закрытия всплывающего окна
			const click = () => {
				// Блокировка
				if (this.freeze) return;

				// Удаление всплывающего окна
				this.body.wrap.remove();

				// Удаление статуса активной строки
				row.removeAttribute("data-selected");

				// Деинициализация быстрых действий по кнопкам
				document.removeEventListener("keydown", this.buttons);

				// Сброс блокировки
				this.freeze = false;
			};

			// Инициализация функции добавления функции закрытия всплывающего окна
			const enable = () => this.body.wrap.addEventListener("click", click);

			// Инициализация функции удаления функции закрытия всплывающего окна
			const disable = () => this.body.wrap.removeEventListener("click", click);

			// Первичная активация функции удаления всплывающего окна
			enable();

			// Инициализация блокировки удаления окна при взаимодействии с select-элементом
			for (const select of popup.getElementsByTagName("select")) {
				// Перебор всех select-элементов

				// Инициализация функции блокировки удаления окна по событию
				select.addEventListener("click", () => {
					// Блокировка удаления окна
					this.freeze = true;

					// Разблокировка удаления окна
					setTimeout(() => (this.freeze = false), 100);
				});

				for (const option of select.getElementsByTagName("option")) {
					// Перебор всех option-элементов

					// Инициализация функции блокировки удаления окна по событию
					option.addEventListener("click", () => {
						// Блокировка удаления окна
						this.freeze = true;

						// Разблокировка удаления окна
						setTimeout(() => (this.freeze = false), 100);
					});
				}
			}

			// Инициализация блокировки удаления окна при взаимодействии с textarea-элементом
			for (const textarea of popup.getElementsByTagName("textarea")) {
				// Перебор всех textarea-элементов

				// Обновлять позицию окна с ошибками при изменении размера textarea (там position: absolute)
				new MutationObserver(() => top(this.body.errors)).observe(textarea, {
					attributes: true,
					attributeFilter: ["style"],
				});

				// Инициализация функции игнорирования блокировки для выбранных кнопок
				textarea.addEventListener("keydown", (e) => {
					if (e.keyCode === 27) {
						// Нажата кнопка: "escape"

						// Вызов глобальной функции управления кнопками
						this.buttons(e, true);
					} else if (e.ctrlKey && e.keyCode === 13) {
						// Нажаты кнопки: "control", "enter"

						// Вызов глобальной функции управления кнопками
						this.buttons(e, true);
					}
				});

				// Добавление функции блокировки удаления окна и клавиш по событиям
				textarea.addEventListener("focus", () => (this.freeze = true));
				textarea.addEventListener("focusout", () => (this.freeze = false));
			}

			// Инициализация функции управления кнопками
			this.buttons = (e, force = false) => {
				// Блокировка
				if (!force && this.freeze) return;

				if (e.keyCode === 27) {
					// Нажата кнопка: "escape"

					// Удаление окна
					click();
				} else if (event.keyCode === 13) {
					// Нажата кнопка: "enter"

					// Инициализация буфера с текущим статусом блокировки закрытия окна
					const freeze = this.freeze;

					// Блокировка закрытия окна (чтобы не вызвался click() через событие onclick)
					this.freeze = true;

					// Активация виртуальной кнопки "создать"
					create.click();

					// Возвращение статуса блокировки закрытия окна
					this.freeze = freeze;
				}
			};

			// Инициализация быстрых действий по кнопкам
			document.addEventListener("keydown", this.buttons);

			// Добавление функции удаления всплывающего окна по событиям
			popup.addEventListener("mouseenter", disable);
			popup.addEventListener("mouseleave", enable);

			// Фокусировка
			cashier_input.focus();
		}, 300);

		/**
		 * Сгенерировать окно продолжения создания заявок (настройки)
		 *
		 * @param {HTMLElement} cashiers Количество кассиров <input>
		 * @param {HTMLElement} displayers Количество выкладчиков <input>
		 * @param {HTMLElement} gastronomes Количество гастрономов <input>
		 * @param {HTMLElement} brigadiers Количество бригадиров <input>
		 * @param {HTMLElement} loaders Количество грузчиков <input>
		 * @param {HTMLElement} loaders_mobile Количество мобильных грузчиков <input>
		 * @param {HTMLElement} universals_mobile Количество мобильных универсалов <input>
		 *
		 * @return {void}
		 */
		static create_detailed = damper(
			(
				cashiers,
				displayers,
				gastronomes,
				brigadiers,
				loaders,
				loaders_mobile,
				universals_mobile
			) => {
				// Инициализация всплывающего окна
				const popup = this.body.wrap.children[0];

				// Инициализация оболочки с основной информацией
				const main = popup.children[1];
				main.classList.add("flow");

				// Увеличение отступов между колонками
				main.style.setProperty("--gap", "30px");

				// Деинициализация колонки с задачами
				main.children[0].remove();

				// Деактиация стандартизированного размера всплывающего окна
				popup.classList.remove("small");

				if (cashiers.value > 0) {
					// Кассиры запрошены

					// Инициализация колонки
					const column = document.createElement("div");
					column.classList.add("column");
					column.setAttribute("data-column", "cashiers");

					// Инициализация строки
					const row = document.createElement("div");
					row.classList.add("row", "merged");

					// Инициализация оболочки
					const label = document.createElement("label");

					// Инициализация заголовка
					const title = document.createElement("b");
					title.classList.add("separated", "right", "unselectable");
					title.innerText = "Кассиры:";

					// Запись в документ
					label.appendChild(title);
					row.appendChild(label);
					column.appendChild(row);
					main.appendChild(column);

					for (let i = 0; i < cashiers.value; ++i) {
						// Перебор кассиров

						// Инициализация строки
						const row = document.createElement("div");
						row.classList.add("row", "merged");
						if (i !== 0) row.classList.add("divided");

						// Инициализация оболочки
						const label = document.createElement("label");
						label.setAttribute("id", `cashier_${i}`);

						// Инициализация поля ввода времени начала
						const start = document.createElement("input");
						start.classList.add("cloud");
						start.setAttribute("type", "time");
						start.setAttribute("title", "Время начала работы по заявке");
						start.value = "09:00";

						// Инициализация поля ввода времени окончания
						const end = document.createElement("input");
						end.classList.add("cloud");
						end.setAttribute("type", "time");
						end.setAttribute("title", "Время конца работы по заявке");
						end.value = "18:00";

						// Инициализация поля ввода даты (дня)
						const day = document.createElement("input");
						day.classList.add("cloud");
						day.setAttribute("type", "date");
						day.setAttribute("title", "Дата заявки");
						const tomorrow = new Date();
						tomorrow.setDate(tomorrow.getDate() + 1);
						day.valueAsDate = tomorrow;

						// Инициализация строки
						const row_commentary = document.createElement("div");
						row_commentary.classList.add("row", "merged", "stretchable");

						// Инициализация поля ввода
						const commentary = document.createElement("textarea");
						commentary.classList.add("snow");
						commentary.setAttribute("maxlength", "800");
						commentary.setAttribute(
							"title",
							"Дополнительная информация для администраторов и операторов"
						);
						commentary.setAttribute("placeholder", "Дополнительная информация");

						// Запись в документ
						label.appendChild(start);
						label.appendChild(end);
						label.appendChild(day);
						row.appendChild(label);
						column.appendChild(row);

						row_commentary.appendChild(commentary);
						column.appendChild(row_commentary);
					}
				}

				if (displayers.value > 0) {
					// Выкладчикы запрошены

					// Инициализация колонки
					const column = document.createElement("div");
					column.classList.add("column");
					column.setAttribute("data-column", "displayers");

					// Инициализация строки
					const row = document.createElement("div");
					row.classList.add("row", "merged");

					// Инициализация оболочки
					const label = document.createElement("label");

					// Инициализация заголовка
					const title = document.createElement("b");
					title.classList.add("separated", "right", "unselectable");
					title.innerText = "Выкладчики:";

					// Запись в документ
					label.appendChild(title);
					row.appendChild(label);
					column.appendChild(row);
					main.appendChild(column);

					for (let i = 0; i < displayers.value; ++i) {
						// Перебор выкладчиков

						// Инициализация строки
						const row = document.createElement("div");
						row.classList.add("row", "merged");
						if (i !== 0) row.classList.add("divided");

						// Инициализация оболочки
						const label = document.createElement("label");
						label.setAttribute("id", `displayer_${i}`);

						// Инициализация поля ввода времени начала
						const start = document.createElement("input");
						start.classList.add("cloud");
						start.setAttribute("type", "time");
						start.setAttribute("title", "Время начала работы по заявке");
						start.value = "09:00";

						// Инициализация поля ввода времени окончания
						const end = document.createElement("input");
						end.classList.add("cloud");
						end.setAttribute("type", "time");
						end.setAttribute("title", "Время конца работы по заявке");
						end.value = "18:00";

						// Инициализация поля ввода даты (дня)
						const day = document.createElement("input");
						day.classList.add("cloud");
						day.setAttribute("type", "date");
						day.setAttribute("title", "Дата заявки");
						const tomorrow = new Date();
						tomorrow.setDate(tomorrow.getDate() + 1);
						day.valueAsDate = tomorrow;

						// Инициализация строки
						const row_commentary = document.createElement("div");
						row_commentary.classList.add("row", "merged", "stretchable");

						// Инициализация поля ввода
						const commentary = document.createElement("textarea");
						commentary.classList.add("snow");
						commentary.setAttribute("maxlength", "800");
						commentary.setAttribute(
							"title",
							"Дополнительная информация для администраторов и операторов"
						);
						commentary.setAttribute("placeholder", "Дополнительная информация");

						// Запись в документ
						label.appendChild(start);
						label.appendChild(end);
						label.appendChild(day);
						row.appendChild(label);
						column.appendChild(row);

						row_commentary.appendChild(commentary);
						column.appendChild(row_commentary);
					}
				}

				if (gastronomes.value > 0) {
					// Гастрономы запрошены

					// Инициализация колонки
					const column = document.createElement("div");
					column.classList.add("column");
					column.setAttribute("data-column", "gastronomes");

					// Инициализация строки
					const row = document.createElement("div");
					row.classList.add("row", "merged");

					// Инициализация оболочки
					const label = document.createElement("label");

					// Инициализация заголовка
					const title = document.createElement("b");
					title.classList.add("separated", "right", "unselectable");
					title.innerText = "Гастрономы:";

					// Запись в документ
					label.appendChild(title);
					row.appendChild(label);
					column.appendChild(row);
					main.appendChild(column);

					for (let i = 0; i < gastronomes.value; ++i) {
						// Перебор гастрономов

						// Инициализация строки
						const row = document.createElement("div");
						row.classList.add("row", "merged");
						if (i !== 0) row.classList.add("divided");

						// Инициализация оболочки
						const label = document.createElement("label");
						label.setAttribute("id", `gastronome_${i}`);

						// Инициализация поля ввода времени начала
						const start = document.createElement("input");
						start.classList.add("cloud");
						start.setAttribute("type", "time");
						start.setAttribute("title", "Время начала работы по заявке");
						start.value = "09:00";

						// Инициализация поля ввода времени окончания
						const end = document.createElement("input");
						end.classList.add("cloud");
						end.setAttribute("type", "time");
						end.setAttribute("title", "Время конца работы по заявке");
						end.value = "18:00";

						// Инициализация поля ввода даты (дня)
						const day = document.createElement("input");
						day.classList.add("cloud");
						day.setAttribute("type", "date");
						day.setAttribute("title", "Дата заявки");
						const tomorrow = new Date();
						tomorrow.setDate(tomorrow.getDate() + 1);
						day.valueAsDate = tomorrow;

						// Инициализация строки
						const row_commentary = document.createElement("div");
						row_commentary.classList.add("row", "merged", "stretchable");

						// Инициализация поля ввода
						const commentary = document.createElement("textarea");
						commentary.classList.add("snow");
						commentary.setAttribute("maxlength", "800");
						commentary.setAttribute(
							"title",
							"Дополнительная информация для администраторов и операторов"
						);
						commentary.setAttribute("placeholder", "Дополнительная информация");

						// Запись в документ
						label.appendChild(start);
						label.appendChild(end);
						label.appendChild(day);
						row.appendChild(label);
						column.appendChild(row);

						row_commentary.appendChild(commentary);
						column.appendChild(row_commentary);
					}
				}

				if (brigadiers.value > 0) {
					// Бригадиры запрошены

					// Инициализация колонки
					const column = document.createElement("div");
					column.classList.add("column");
					column.setAttribute("data-column", "brigadiers");

					// Инициализация строки
					const row = document.createElement("div");
					row.classList.add("row", "merged");

					// Инициализация оболочки
					const label = document.createElement("label");

					// Инициализация заголовка
					const title = document.createElement("b");
					title.classList.add("separated", "right", "unselectable");
					title.innerText = "Бригадиры:";

					// Запись в документ
					label.appendChild(title);
					row.appendChild(label);
					column.appendChild(row);
					main.appendChild(column);

					for (let i = 0; i < brigadiers.value; ++i) {
						// Перебор бригадиров

						// Инициализация строки
						const row = document.createElement("div");
						row.classList.add("row", "merged");
						if (i !== 0) row.classList.add("divided");

						// Инициализация оболочки
						const label = document.createElement("label");
						label.setAttribute("id", `brigadier_${i}`);

						// Инициализация поля ввода времени начала
						const start = document.createElement("input");
						start.classList.add("cloud");
						start.setAttribute("type", "time");
						start.setAttribute("title", "Время начала работы по заявке");
						start.value = "09:00";

						// Инициализация поля ввода времени окончания
						const end = document.createElement("input");
						end.classList.add("cloud");
						end.setAttribute("type", "time");
						end.setAttribute("title", "Время конца работы по заявке");
						end.value = "18:00";

						// Инициализация поля ввода даты (дня)
						const day = document.createElement("input");
						day.classList.add("cloud");
						day.setAttribute("type", "date");
						day.setAttribute("title", "Дата заявки");
						const tomorrow = new Date();
						tomorrow.setDate(tomorrow.getDate() + 1);
						day.valueAsDate = tomorrow;

						// Инициализация строки
						const row_commentary = document.createElement("div");
						row_commentary.classList.add("row", "merged", "stretchable");

						// Инициализация поля ввода
						const commentary = document.createElement("textarea");
						commentary.classList.add("snow");
						commentary.setAttribute("maxlength", "800");
						commentary.setAttribute(
							"title",
							"Дополнительная информация для администраторов и операторов"
						);
						commentary.setAttribute("placeholder", "Дополнительная информация");

						// Запись в документ
						label.appendChild(start);
						label.appendChild(end);
						label.appendChild(day);
						row.appendChild(label);
						column.appendChild(row);

						row_commentary.appendChild(commentary);
						column.appendChild(row_commentary);
					}
				}

				if (loaders.value > 0) {
					// Грузчики запрошены

					// Инициализация колонки
					const column = document.createElement("div");
					column.classList.add("column");
					column.setAttribute("data-column", "loaders");

					// Инициализация строки
					const row = document.createElement("div");
					row.classList.add("row", "merged");

					// Инициализация оболочки
					const label = document.createElement("label");

					// Инициализация заголовка
					const title = document.createElement("b");
					title.classList.add("separated", "right", "unselectable");
					title.innerText = "Грузчики:";

					// Запись в документ
					label.appendChild(title);
					row.appendChild(label);
					column.appendChild(row);
					main.appendChild(column);

					for (let i = 0; i < loaders.value; ++i) {
						// Перебор грузчиков

						// Инициализация строки
						const row = document.createElement("div");
						row.classList.add("row", "merged");
						if (i !== 0) row.classList.add("divided");

						// Инициализация оболочки
						const label = document.createElement("label");
						label.setAttribute("id", `loader_${i}`);

						// Инициализация поля ввода времени начала
						const start = document.createElement("input");
						start.classList.add("cloud");
						start.setAttribute("type", "time");
						start.setAttribute("title", "Время начала работы по заявке");
						start.value = "09:00";

						// Инициализация поля ввода времени окончания
						const end = document.createElement("input");
						end.classList.add("cloud");
						end.setAttribute("type", "time");
						end.setAttribute("title", "Время конца работы по заявке");
						end.value = "18:00";

						// Инициализация поля ввода даты (дня)
						const day = document.createElement("input");
						day.classList.add("cloud");
						day.setAttribute("type", "date");
						day.setAttribute("title", "Дата заявки");
						const tomorrow = new Date();
						tomorrow.setDate(tomorrow.getDate() + 1);
						day.valueAsDate = tomorrow;

						// Инициализация строки
						const row_commentary = document.createElement("div");
						row_commentary.classList.add("row", "merged", "stretchable");

						// Инициализация поля ввода
						const commentary = document.createElement("textarea");
						commentary.classList.add("snow");
						commentary.setAttribute("maxlength", "800");
						commentary.setAttribute(
							"title",
							"Дополнительная информация для администраторов и операторов"
						);
						commentary.setAttribute("placeholder", "Дополнительная информация");

						// Запись в документ
						label.appendChild(start);
						label.appendChild(end);
						label.appendChild(day);
						row.appendChild(label);
						column.appendChild(row);

						row_commentary.appendChild(commentary);
						column.appendChild(row_commentary);
					}
				}

				if (loaders_mobile.value > 0) {
					// Мобильные грузчики запрошены

					// Инициализация колонки
					const column = document.createElement("div");
					column.classList.add("column");
					column.setAttribute("data-column", "loaders_mobile");

					// Инициализация строки
					const row = document.createElement("div");
					row.classList.add("row", "merged");

					// Инициализация оболочки
					const label = document.createElement("label");

					// Инициализация заголовка
					const title = document.createElement("b");
					title.classList.add("separated", "right", "unselectable");
					title.innerText = "Мобильные грузчики:";

					// Запись в документ
					label.appendChild(title);
					row.appendChild(label);
					column.appendChild(row);
					main.appendChild(column);

					for (let i = 0; i < loaders_mobile.value; ++i) {
						// Перебор мобильных грузчиков

						// Инициализация строки
						const row = document.createElement("div");
						row.classList.add("row", "merged");
						if (i !== 0) row.classList.add("divided");

						// Инициализация оболочки
						const label = document.createElement("label");
						label.setAttribute("id", `loader_mobile_${i}`);

						// Инициализация поля ввода времени начала
						const start = document.createElement("input");
						start.classList.add("cloud");
						start.setAttribute("type", "time");
						start.setAttribute("title", "Время начала работы по заявке");
						start.value = "09:00";

						// Инициализация поля ввода времени окончания
						const end = document.createElement("input");
						end.classList.add("cloud");
						end.setAttribute("type", "time");
						end.setAttribute("title", "Время конца работы по заявке");
						end.value = "18:00";

						// Инициализация поля ввода даты (дня)
						const day = document.createElement("input");
						day.classList.add("cloud");
						day.setAttribute("type", "date");
						day.setAttribute("title", "Дата заявки");
						const tomorrow = new Date();
						tomorrow.setDate(tomorrow.getDate() + 1);
						day.valueAsDate = tomorrow;

						// Инициализация строки
						const row_commentary = document.createElement("div");
						row_commentary.classList.add("row", "merged", "stretchable");

						// Инициализация поля ввода
						const commentary = document.createElement("textarea");
						commentary.classList.add("snow");
						commentary.setAttribute("maxlength", "800");
						commentary.setAttribute(
							"title",
							"Дополнительная информация для администраторов и операторов"
						);
						commentary.setAttribute("placeholder", "Дополнительная информация");

						// Запись в документ
						label.appendChild(start);
						label.appendChild(end);
						label.appendChild(day);
						row.appendChild(label);
						column.appendChild(row);

						row_commentary.appendChild(commentary);
						column.appendChild(row_commentary);
					}
				}

				if (universals_mobile.value > 0) {
					// Мобильные универсалы запрошены

					// Инициализация колонки
					const column = document.createElement("div");
					column.classList.add("column");
					column.setAttribute("data-column", "universals_mobile");

					// Инициализация строки
					const row = document.createElement("div");
					row.classList.add("row", "merged");

					// Инициализация оболочки
					const label = document.createElement("label");

					// Инициализация заголовка
					const title = document.createElement("b");
					title.classList.add("separated", "right", "unselectable");
					title.innerText = "Мобильные универсалы:";

					// Запись в документ
					label.appendChild(title);
					row.appendChild(label);
					column.appendChild(row);
					main.appendChild(column);

					for (let i = 0; i < universals_mobile.value; ++i) {
						// Перебор мобильных универсалов

						// Инициализация строки
						const row = document.createElement("div");
						row.classList.add("row", "merged");
						if (i !== 0) row.classList.add("divided");

						// Инициализация оболочки
						const label = document.createElement("label");
						label.setAttribute("id", `universal_mobile_${i}`);

						// Инициализация поля ввода времени начала
						const start = document.createElement("input");
						start.classList.add("cloud");
						start.setAttribute("type", "time");
						start.setAttribute("title", "Время начала работы по заявке");
						start.value = "09:00";

						// Инициализация поля ввода времени окончания
						const end = document.createElement("input");
						end.classList.add("cloud");
						end.setAttribute("type", "time");
						end.setAttribute("title", "Время конца работы по заявке");
						end.value = "18:00";

						// Инициализация поля ввода даты (дня)
						const day = document.createElement("input");
						day.classList.add("cloud");
						day.setAttribute("type", "date");
						day.setAttribute("title", "Дата заявки");
						const tomorrow = new Date();
						tomorrow.setDate(tomorrow.getDate() + 1);
						day.valueAsDate = tomorrow;

						// Инициализация строки
						const row_commentary = document.createElement("div");
						row_commentary.classList.add("row", "merged", "stretchable");

						// Инициализация поля ввода
						const commentary = document.createElement("textarea");
						commentary.classList.add("snow");
						commentary.setAttribute("maxlength", "800");
						commentary.setAttribute(
							"title",
							"Дополнительная информация для администраторов и операторов"
						);
						commentary.setAttribute("placeholder", "Дополнительная информация");

						// Запись в документ
						label.appendChild(start);
						label.appendChild(end);
						label.appendChild(day);
						row.appendChild(label);
						column.appendChild(row);

						row_commentary.appendChild(commentary);
						column.appendChild(row_commentary);
					}
				}

				// Инициализация колонки
				const column = document.createElement("div");
				column.classList.add("column");
				column.setAttribute("data-column", "buttons");

				// Инициализация строки
				const row = document.createElement("div");
				row.classList.add("row", "merged");

				// Инициализация оболочки
				const label = document.createElement("label");
				label.setAttribute("id", `create`);

				// Инициализация кнопки создания заявок
				const create = document.createElement("button");
				create.classList.add("grass");
				create.innerText = "Создать";
				create.setAttribute(
					"onclick",
					`tasks._create(
					this.parentElement.parentElement.parentElement.parentElement.querySelector('div[data-column="cashiers"]'),
					this.parentElement.parentElement.parentElement.parentElement.querySelector('div[data-column="displayers"]'),
					this.parentElement.parentElement.parentElement.parentElement.querySelector('div[data-column="gastronomes"]'),
					this.parentElement.parentElement.parentElement.parentElement.querySelector('div[data-column="brigadiers"]'),
					this.parentElement.parentElement.parentElement.parentElement.querySelector('div[data-column="loaders"]'),
					this.parentElement.parentElement.parentElement.parentElement.querySelector('div[data-column="loaders_mobile"]'),
					this.parentElement.parentElement.parentElement.parentElement.querySelector('div[data-column="universals_mobile"]'),
					this
				)`
				);

				// Запись в документ
				label.appendChild(create);
				row.appendChild(label);
				column.appendChild(row);
				main.appendChild(column);

				// Инициализация ширины окна с ошибками
				this.body.errors.style.setProperty(
					"--calculated-width",
					popup.offsetWidth + "px"
				);

				// Инициализация переменных для окна с ошибками (12 - это значение gap из div#popup)
				function top(errors) {
					errors.style.setProperty("transition", "0s");
					errors.style.setProperty(
						"--top",
						popup.offsetTop + popup.offsetHeight + 12 + "px"
					);
					setTimeout(() => errors.style.removeProperty("transition"), 100);
				}
				top(this.body.errors);
			},
			300
		);

		/**
		 * Записать или переключить фильтр (0, 1, 2)
		 *
		 * @param {string} name Название
		 * @param {string|number|null} value Значение
		 * @param {HTMLElement|null} button Кнопка
		 * @param {bool} force Принудительное выполнение (используется в damper())
		 *
		 * @return {void}
		 */
		static filter = damper(
			async (name, value, button, force = false) => {
				return new Promise(async (resolve, reject) => {
					if (typeof name === "string") {
						// Получено название

						// Инициализация сериализованного пути к директории
						const path = `tasks_filter_${name}`;

						if (typeof value === "string" || typeof value === "number") {
							// Получено значение

							// Запись нового значения
							await buffer.write(path, value);

							resolve();
						} else {
							// Не получено значение

							// Чтение текущего значения
							value = +(await buffer.read(path));

							// Инициализация значения по умолчанию
							if (isNaN(value)) value = 0;

							// Запись нового значения (инвертирование)
							await buffer.write(path, ++value < 3 ? value : 0);

							resolve();

							if (button instanceof HTMLElement) {
								// Получена кнопка

								// Деинициализация классов статуса фильтра
								button.classList.remove("earth", "sand", "river");

								// Инициализация классов статуса фильтра
								if (value === 1) button.classList.add("sand");
								else if (value === 2) button.classList.add("river");
								else button.classList.add("earth");
							}
						}
					}

					reject();
				});
			},
			300,
			3
		);

		/**
		 * Записать фильтр поиска
		 *
		 * @param {HTMLElement} input Строка поиска
		 * @param {HTMLElement} button Кнопка отправки
		 *
		 * @return {void}
		 */
		static search = (input, button) => {
			input.setAttribute("readonly", true);
			button.setAttribute("disabled", true);

			this._search(input, button);
		};

		/**
		 * Записать фильтр поиска (системное)
		 *
		 * Используется как оболочка для большей временной задержки
		 *
		 * @param {HTMLElement} input Строка поиска
		 * @param {HTMLElement} button Кнопка отправки
		 *
		 * @return {void}
		 */
		static _search = damper((input, button) => {
			this.filter("search", input.value);
			this.reinit(() => {
				input.removeAttribute("readonly");
				button.removeAttribute("disabled");
			});
		}, 1000);

		/**
		 * Инициализация страниц
		 *
		 * @param {number} amount Количество страниц для генерации
		 * @param {number} iteration Номер итерации (системное)
		 *
		 * @return {void}
		 */
		static init(amount = 3, iteration = 0) {
			if (
				typeof amount === "number" &&
				typeof iteration === "number" &&
				this.initialized === false
			) {
				// Получены количество страниц и номер итерации

				// Инициализация страницы
				tasks.read(++iteration);

				function generate() {
					// Завершено выполнение итерации

					// Деинициализация слушателя завершения текущей итерации
					document.removeEventListener("tasks.read." + iteration, generate);

					// Проверка условий и запуск следующей итерации
					if (iteration < amount) tasks.init(amount, iteration);
					else this.initialized = true;
				}

				// Инициализация слушателя завершения текущей итерации
				document.addEventListener("tasks.read." + iteration, generate);
			}
		}

		/**
		 * Реинициализация страниц
		 *
		 * @param {function} postprocessing Функция которая будет исполнена после реинициализации
		 * @param {number} amount Количество страниц для генерации при инициализации
		 *
		 * @return {void}
		 */
		static reinit = damper((postprocessing, amount = 3) => {
			if (typeof amount === "number") {
				// Получены количество страниц

				// Деинициализация cookie с номером страницы
				Cookies.remove("tasks_page", { path: "/" });

				// Инициализация оболочки
				const tasks = document.getElementById("tasks");

				if (tasks instanceof HTMLElement) {
					// Найдена оболочка

					// Инициализация буфера активного элемента
					const active = document.activeElement;

					// Инициализация буфера элементов
					const buffer = document.createElement("div");

					// Перенос элементов в буфер
					buffer.replaceChildren(...tasks.children);

					// Удаление комментариев с индексами страниц
					tasks.innerHTML = tasks.innerHTML.replace(
						/<!--(?!>)[\S\s]*?-->/g,
						""
					);

					// Перенос элементов из буфера
					tasks.replaceChildren(...buffer.children);

					// Деинициализация страниц
					for (const row of tasks.querySelectorAll(
						':scope > div[data-row="task"]'
					)) {
						row.remove();
					}

					// Сброс статуса инициализированности
					this.initialized = false;

					// Инициализация страниц
					this.init(amount);

					// Возвращение фокуса на активный элемент
					active.focus();

					// Постобработка
					if (typeof postprocessing === "function") postprocessing();
				}
			}
		}, 2000);

		/**
		 * Прочитать
		 *
		 * Читает список задач и модифицирует документ (записывает в общий список)
		 *
		 * @param {number} page Страница
		 *
		 * @return {void}
		 */
		static read = damper(async (page) => {
			if (typeof page !== "number") {
				// Не получена страница

				// Инициализация страницы (если не получена, то брать из cookie и прибавлять 1)
				page = Cookies.get(`tasks_page`) ?? 0;

				// Запись идентификатора следующей страницы
				++page;
			}

			// Запрос к серверу
			await fetch("/tasks/read", {
				method: "POST",
				headers: {
					"Content-Type": "application/x-www-form-urlencoded",
				},
				body: `page=${page}`,
			})
				.then((response) => response.json())
				.then((data) => {
					if (this.errors(data.errors)) {
						// Сгенерированы ошибки
					} else {
						// Не сгенерированы ошибки (подразумевается их отсутствие)

						// Инициализация буфера для записи в документ
						const element = document.createElement("div");

						// Запись пустого элемента из буфера в документ
						document.getElementById("tasks").appendChild(element);

						// Запись в документ HTML-данных через буфер
						element.outerHTML = data.rows;

						// Запуск реинициализатора строк
						this.reinitializer.start();

						// Вызов события: "итерация чтения завершена"
						document.dispatchEvent(new CustomEvent("tasks.read." + page));
					}
				});
		}, 50);

		/**
		 * Сгенерировать всплывающее окно c данными задачи
		 *
		 * @param {HTMLElement} row Строка
		 *
		 * @return {void}
		 */
		static popup = damper(async (row) => {
			if (row instanceof HTMLElement) {
				// Получена строка

				// Инициализация идентификатора сотрудника
				const task = row.getAttribute("id");

				// Запрос к серверу
				return await fetch(`/task/${task}/read`, {
					method: "POST",
					headers: {
						"Content-Type": "application/x-www-form-urlencoded",
					},
				})
					.then((response) => response.json())
					.then((data) => {
						if (this.errors(data.errors)) {
							// Сгенерированы ошибки
						} else {
							// Не сгенерированы ошибки

							if (((Date.now() / 1000) | 0) - data.start > 0) {
								// Началась заявка (возможно уже закончилась)

								// Инициализация буфера выбранных строк
								const buffer = [
									...document.querySelectorAll('div[data-selected="true"]'),
								];

								// Удаление статуса активной строки у остальных строк
								for (const element of buffer) {
									element.removeAttribute("data-selected");
								}

								// Инициализация статуса активной строки (обрабатываемой в данный момент)
								row.setAttribute("data-selected", "true");

								// Инициализация оболочки всплывающего окна
								this.body.wrap = document.createElement("div");
								this.body.wrap.setAttribute("id", "popup");

								// Инициализация всплывающего окна
								const popup = document.createElement("section");
								popup.classList.add("list", "small");

								// Инициализация заголовка всплывающего окна
								const title = document.createElement("h3");
								title.classList.add("unselectable");
								title.innerText = task;

								// Инициализация оболочки с основной информацией
								const main = document.createElement("section");
								main.classList.add("main");

								// Инициализация колонки
								const column = document.createElement("div");
								column.classList.add("column");

								// Инициализация буфера для записи во всплывающее окно
								const list = document.createElement("div");

								// Инициализация строки рейтинга
								const rating_row = document.createElement("div");
								rating_row.classList.add(
									"row",
									"divided",
									"range",
									"small",
									"stretched"
								);

								// Инициализация ползунка выбора рейтинга
								const rating_input = document.createElement("input");
								rating_input.classList.add("cloud");
								rating_input.setAttribute("type", "range");
								rating_input.setAttribute("title", "Оценка");
								rating_input.setAttribute("min", "1");
								rating_input.setAttribute("max", "5");
								rating_input.setAttribute("step", "1");
								rating_input.setAttribute(
									"oninput",
									`this.nextElementSibling.innerText = this.value; setTimeout(() => {this.nextElementSibling.style.opacity = 1; setTimeout(() => this.nextElementSibling.style.transition = "0s", 100)}, 100); this.nextElementSibling.style.setProperty('--left', (((this.value - 1) / 4) * (this.offsetWidth - 24) + 12) + 'px');`
								);

								// Инициализация значения в курсоре ползунка выбора рейтинга
								const rating_value = document.createElement("i");
								rating_value.classList.add("value", "unselectable");
								rating_value.style.opacity = 0;
								rating_value.style.transition = "0.1s ease-in";
								rating_value.setAttribute("title", "Оценка");
								rating_value.value = 5;

								// Инициализация поля ввода отзыва
								const review = document.createElement("textarea");
								review.classList.add("snow");
								review.setAttribute("autofocus", "true");
								review.setAttribute("maxlength", "300");
								review.setAttribute("title", "Отзыв");
								review.setAttribute("placeholder", "Отзыв о сотруднике");

								// Запись актуальных значений
								this.value(row, "completed").then((completed) => {
									// Рейтинг
									this.value(row, "rating").then((text) => {
										if (completed) {
											// Завершена заявка

											// Блокировка
											rating_input.setAttribute("disabled", "true");
										}

										// Запись актуального рейтинга
										rating_input.value = text ?? 5;
									});

									// Отзыв
									this.value(row, "review").then((text) => {
										if (completed) {
											// Завершена заявка

											// Блокировка
											review.setAttribute("readonly", "true");
										}

										// Запись актуального отзыва
										review.value = text ?? "";
									});
								});

								// Инициализация оболочки для кнопок
								const buttons_worker = document.createElement("div");
								buttons_worker.classList.add("row", "buttons", "divided", "merged");

								// Инициализация кнопки подтверждения
								const ban = document.createElement("button");
								if (true) {
									// Забанен сотрудник

									ban.classList.add("earth", "stretched");
									ban.innerText = "Разблокировать";
									ban.setAttribute('title', 'Сотрудник снова сможет записываться на ваши заявки');
									ban.setAttribute(
										"onclick",
										`tasks.unban(this, this.parentElement.previousElementSibling.previousElementSibling.children[0], this.parentElement.previousElementSibling, document.getElementById('${task}'))`
									);
								} else {
									// Не забанен сотрудник

									ban.classList.add("clay", "stretched");
									ban.innerText = "Заблокировать";
									ban.setAttribute('title', 'Сотрудник не сможет записываться на ваши заявки');
									ban.setAttribute(
										"onclick",
										`tasks.ban(this, this.parentElement.previousElementSibling.previousElementSibling.children[0], this.parentElement.previousElementSibling, document.getElementById('${task}'))`
									);
								}
								
								// Инициализация оболочки для кнопок
								const buttons = document.createElement("div");
								buttons.classList.add("row", "buttons", "merged");

								// Инициализация кнопки заявления о проблеме
								const problem = document.createElement("button");
								problem.classList.add("clay", "stretched");
								if (row.classList.contains("problematic")) {
									// Проблемная заявка

									problem.classList.add("grass");
									problem.innerText = "Проблема решена";

									problem.setAttribute(
										"onclick",
										`chat.send(this, null, document.getElementById('${task}'), 'market', 'solution', true, 'Проблема решена'); document.removeEventListener("keydown", tasks.buttons);`
									);
								} else {
									// Не проблемная заявка

									problem.classList.add("clay");
									problem.innerText = "Проблема";

									problem.setAttribute(
										"onclick",
										`tasks.problem(document.getElementById('${task}'))`
									);
								}

								// Инициализация кнопки подтверждения
								const complete = document.createElement("button");
								complete.classList.add("grass", "stretched");
								complete.innerText = "Завершить";
								complete.setAttribute(
									"onclick",
									`tasks.complete(this, this.parentElement.previousElementSibling.previousElementSibling.previousElementSibling.children[0], this.parentElement.previousElementSibling.previousElementSibling, document.getElementById('${task}'))`
								);

								// Инициализация окна с ошибками
								this.body.errors = document.createElement("section");
								this.body.errors.classList.add(
									"errors",
									"window",
									"list",
									"small",
									"hidden"
								);
								this.body.errors.setAttribute("data-errors", true);

								// Инициализация элемента-тела (оболочки) окна с ошибками
								const errors = document.createElement("section");
								errors.classList.add("body");

								// Инициализация элемента-списка ошибок
								const dl = document.createElement("dl");

								// Инициализация активного всплывающего окна
								const old = document.getElementById("popup");

								if (old instanceof HTMLElement) {
									// Найдено активное окно

									// Деинициализация быстрых действий по кнопкам
									document.removeEventListener("keydown", this.buttons);

									// Сброс блокировки
									this.freeze = false;

									// Удаление активного окна
									old.remove();
								}

								// Удаление блокировки выполнения закрытия всплывающего окна
								this.freeze = false;

								// Запись в документ
								popup.appendChild(title);

								column.appendChild(list);
								rating_row.appendChild(rating_input);
								rating_row.appendChild(rating_value);
								column.appendChild(rating_row);
								column.appendChild(review);

								if (data.completed !== true) {
									// Зявка не завершена

									buttons_worker.appendChild(ban);
									column.appendChild(buttons_worker);

									buttons.appendChild(problem);
									buttons.appendChild(complete);
									column.appendChild(buttons);
								}

								main.appendChild(column);
								popup.appendChild(main);
								this.body.wrap.appendChild(popup);

								errors.appendChild(dl);
								this.body.errors.appendChild(errors);
								this.body.wrap.appendChild(this.body.errors);

								document.body.appendChild(this.body.wrap);

								// Запись в документ HTML-данных через буфер
								list.outerHTML = data.task;

								// Первичная инициализация (для генерации местоположения элемента со значением)
								setTimeout(() => rating_input.oninput(), 300);

								// Инициализация ошибок
								this.errors(data.errors);

								// Инициализация переменных для окна с ошибками (12 - это значение gap из div#popup)
								function top(errors) {
									errors.style.setProperty("transition", "0s");
									errors.style.setProperty(
										"--top",
										popup.offsetTop + popup.offsetHeight + 12 + "px"
									);
									setTimeout(
										() => errors.style.removeProperty("transition"),
										100
									);
								}
								top(this.body.errors);
								const resize = new ResizeObserver(() => top(this.body.errors));
								resize.observe(this.body.wrap);

								// Инициализация функции закрытия всплывающего окна
								const click = () => {
									// Блокировка
									if (this.freeze) return;

									// Удаление всплывающего окна
									this.body.wrap.remove();

									// Инициализация буфера выбранных строк
									const buffer = [
										...document.querySelectorAll('div[data-selected="true"]'),
									];

									// Удаление статуса активной строки у остальных строк
									for (const element of buffer) {
										element.removeAttribute("data-selected");
									}

									// Деинициализация быстрых действий по кнопкам
									document.removeEventListener("keydown", this.buttons);

									// Сброс блокировки
									this.freeze = false;
								};

								// Инициализация функции добавления функции закрытия всплывающего окна
								const enable = () =>
									this.body.wrap.addEventListener("click", click);

								// Инициализация функции удаления функции закрытия всплывающего окна
								const disable = () =>
									this.body.wrap.removeEventListener("click", click);

								// Первичная активация функции удаления всплывающего окна
								enable();

								// Инициализация блокировки удаления окна при взаимодействии с select-элементом
								for (const select of popup.getElementsByTagName("select")) {
									// Перебор всех select-элементов

									// Инициализация функции блокировки удаления окна по событию
									select.addEventListener("click", () => {
										// Блокировка удаления окна
										this.freeze = true;

										// Разблокировка удаления окна
										setTimeout(() => (this.freeze = false), 100);
									});

									for (const option of select.getElementsByTagName("option")) {
										// Перебор всех option-элементов

										// Инициализация функции блокировки удаления окна по событию
										option.addEventListener("click", () => {
											// Блокировка удаления окна
											this.freeze = true;

											// Разблокировка удаления окна
											setTimeout(() => (this.freeze = false), 100);
										});
									}
								}

								// Инициализация блокировки удаления окна при взаимодействии с textarea-элементом
								for (const textarea of popup.getElementsByTagName("textarea")) {
									// Перебор всех textarea-элементов

									// Обновлять позицию окна с ошибками при изменении размера textarea (там position: absolute)
									new MutationObserver(() => top(this.body.errors)).observe(
										textarea,
										{
											attributes: true,
											attributeFilter: ["style"],
										}
									);

									// Инициализация функции игнорирования блокировки для выбранных кнопок
									textarea.addEventListener("keydown", (e) => {
										if (e.keyCode === 27) {
											// Нажата кнопка: "escape"

											// Вызов глобальной функции управления кнопками
											this.buttons(e, true);
										} else if (e.ctrlKey && e.keyCode === 13) {
											// Нажаты кнопки: "control", "enter"

											// Вызов глобальной функции управления кнопками
											this.buttons(e, true);
										}
									});

									// Добавление функции блокировки удаления окна и клавиш по событиям
									textarea.addEventListener(
										"focus",
										() => (this.freeze = true)
									);
									textarea.addEventListener(
										"focusout",
										() => (this.freeze = false)
									);
								}

								// Инициализация функции управления кнопками
								this.buttons = (e, force = false) => {
									// Блокировка
									if (!force && this.freeze) return;

									if (e.keyCode === 27) {
										// Нажата кнопка: "escape"

										// Удаление окна
										click();
									} else if (event.keyCode === 13) {
										// Нажата кнопка: "enter"

										// Инициализация буфера с текущим статусом блокировки закрытия окна
										const freeze = this.freeze;

										// Блокировка закрытия окна (чтобы не вызвался click() через событие onclick)
										this.freeze = true;

										// Активация виртуальной кнопки "завершить"
										complete.click();

										// Возвращение статуса блокировки закрытия окна
										this.freeze = freeze;
									}
								};

								// Инициализация быстрых действий по кнопкам
								document.addEventListener("keydown", this.buttons);

								// Добавление функции удаления всплывающего окна по событиям
								popup.addEventListener("mouseenter", disable);
								popup.addEventListener("mouseleave", enable);

								// Фокусировка
								review.focus();
							} else {
								// Не началась заявка

								// Инициализация буфера выбранных строк
								const buffer = [
									...document.querySelectorAll('div[data-selected="true"]'),
								];

								// Удаление статуса активной строки у остальных строк
								for (const element of buffer) {
									element.removeAttribute("data-selected");
								}

								// Инициализация статуса активной строки (обрабатываемой в данный момент)
								row.setAttribute("data-selected", "true");

								// Инициализация оболочки всплывающего окна
								this.body.wrap = document.createElement("div");
								this.body.wrap.setAttribute("id", "popup");

								// Инициализация всплывающего окна
								const popup = document.createElement("section");
								popup.classList.add("list", "small");

								// Инициализация заголовка всплывающего окна
								const title = document.createElement("h3");
								title.classList.add("unselectable");
								title.innerText = task;

								// Инициализация оболочки с основной информацией
								const main = document.createElement("section");
								main.classList.add("main");

								// Инициализация колонки
								const column = document.createElement("div");
								column.classList.add("column");

								// Инициализация буфера для записи во всплывающее окно
								const list = document.createElement("div");

								// Инициализация оболочки для строки с полем ввода даты и времени, и кнопкой
								const _row = document.createElement("div");
								_row.classList.add("row", "divided");

								// Инициализация оболочки для строки с полем ввода даты
								const label = document.createElement("label");

								// Инициализация поля ввода даты
								const date = document.createElement("input");
								date.classList.add("cloud");
								date.setAttribute("type", "date");
								date.setAttribute("title", "Дата заявки");
								this.value(row, "date").then(
									(text) => (date.valueAsDate = new Date(text * 1000))
								);

								// Инициализация поля ввода времени начала
								const start = document.createElement("input");
								start.classList.add("cloud");
								start.setAttribute("type", "time");
								start.setAttribute("title", "Время начала работы");
								this.value(row, "start").then(
									(text) =>
										(start.value =
											typeof text === "string"
												? text.length === 7
													? 0 + text.replace(/(?<=:00):00/, "")
													: text.replace(/(?<=:00):00/, "")
												: "00:00")
								);

								// Инициализация поля ввода времени окончания
								const end = document.createElement("input");
								end.classList.add("cloud");
								end.setAttribute("type", "time");
								end.setAttribute("title", "Время конца работы");
								this.value(row, "end").then(
									(text) =>
										(end.value =
											typeof text === "string"
												? text.length === 7
													? 0 + text.replace(/(?<=:00):00/, "")
													: text.replace(/(?<=:00):00/, "")
												: "00:00")
								);

								// Инициализация кнопки подтверждения даты
								const replace = document.createElement("button");
								replace.classList.add("sea");
								replace.innerText = "Записать";
								replace.setAttribute(
									"onclick",
									`tasks.date(document.getElementById('${task}'), this.previousElementSibling.previousElementSibling.previousElementSibling, this.previousElementSibling.previousElementSibling, this.previousElementSibling, this)`
								);

								// Инициализация списка выбора типа работы
								const work = document.createElement("select");
								work.classList.add("row", "connected", "stretched");
								this.works(task).then((html) => (work.innerHTML = html));
								work.setAttribute("title", "Тип работы");

								// Инициализация поля ввода описания
								const description = document.createElement("textarea");
								description.classList.add("snow");
								this.value(row, "description").then(
									(text) => (description.value = text)
								);
								description.setAttribute("autofocus", "true");
								description.setAttribute("maxlength", "300");
								description.setAttribute(
									"onkeyup",
									`tasks.description(document.getElementById('${task}'), this)`
								);
								description.setAttribute("title", "Дополнительная информация");
								description.setAttribute(
									"placeholder",
									"Дополнительная информация о требуемой работе"
								);

								// Инициализация оболочки для кнопок
								const buttons_1 = document.createElement("div");
								buttons_1.classList.add("row", "merged", "divided", "buttons");

								// Инициализация кнопки подтверждения
								const problem = document.createElement("button");
								problem.classList.add("wide");
								if (row.classList.contains("problematic")) {
									// Проблемная заявка

									problem.classList.add("grass");
									problem.innerText = "Проблема решена";

									problem.setAttribute(
										"onclick",
										`chat.send(this, null, document.getElementById('${task}'), 'market', 'solution', true, 'Проблема решена'); document.removeEventListener("keydown", tasks.buttons);`
									);
								} else {
									// Не проблемная заявка

									problem.classList.add("clay");
									problem.innerText = "Проблема";

									problem.setAttribute(
										"onclick",
										`tasks.problem(document.getElementById('${task}'))`
									);
								}

								// Инициализация оболочки для кнопок
								const buttons_2 = document.createElement("div");
								buttons_2.classList.add("row", "merged", "buttons");

								// Инициализация кнопки подтверждения
								const confirm = document.createElement("button");
								confirm.classList.add("wide");
								if (row.classList.contains("confirmed")) {
									// Подтверждена заявка

									confirm.classList.add("clay");
									confirm.innerText = "Отклонить";
								} else {
									// Не подтверждена заявка

									confirm.classList.add("grass");
									confirm.innerText = "Подтвердить";
								}
								confirm.setAttribute(
									"onclick",
									`tasks.confirm(this, document.getElementById('${task}'))`
								);

								// Инициализация кнопки скрытия
								const hide = document.createElement("button");
								if (row.classList.contains("hided")) {
									// Скрыта заявка

									hide.classList.add("grass");
									hide.innerText = "Показать";
								} else {
									// Не подтверждена заявка

									hide.classList.add("sea");
									hide.innerText = "Скрыть";
								}
								hide.setAttribute(
									"onclick",
									`tasks.hide(this, document.getElementById('${task}'))`
								);

								// Инициализация кнопки удаления
								const remove = document.createElement("button");
								remove.classList.add("clay");
								remove.innerText = "Удалить";
								remove.setAttribute(
									"onclick",
									`tasks.remove(this, document.getElementById('${task}'))`
								);

								if (
									typeof core === "function" &&
									(core.interface === "market" || core.interface === "worker")
								) {
									// Расширить кнопку для магазина и сотрудника

									remove.classList.add("stretched");
								}

								// Инициализация окна с ошибками
								this.body.errors = document.createElement("section");
								this.body.errors.classList.add(
									"errors",
									"window",
									"list",
									"small",
									"hidden"
								);
								this.body.errors.setAttribute("data-errors", true);

								// Инициализация элемента-тела (оболочки) окна с ошибками
								const errors = document.createElement("section");
								errors.classList.add("body");

								// Инициализация элемента-списка ошибок
								const dl = document.createElement("dl");

								// Инициализация активного всплывающего окна
								const old = document.getElementById("popup");

								if (old instanceof HTMLElement) {
									// Найдено активное окно

									// Деинициализация быстрых действий по кнопкам
									document.removeEventListener("keydown", this.buttons);

									// Сброс блокировки
									this.freeze = false;

									// Удаление активного окна
									old.remove();
								}

								// Удаление блокировки выполнения закрытия всплывающего окна
								this.freeze = false;

								// Запись в документ
								popup.appendChild(title);

								column.appendChild(list);
								label.appendChild(date);
								label.appendChild(start);
								label.appendChild(end);
								label.appendChild(replace);
								_row.appendChild(label);
								column.appendChild(_row);
								column.appendChild(work);
								column.appendChild(description);

								if (
									typeof core === "function" &&
									core.interface !== "market" &&
									core.interface !== "worker"
								) {
									// Скрытие для магазина и сотрудника

									buttons_1.appendChild(problem);
									column.appendChild(buttons_1);

									buttons_2.appendChild(confirm);
									buttons_2.appendChild(hide);
								} else {
									// Отображение для магазина и сотрудника

									problem.classList.add("stretched");
									buttons_2.appendChild(problem);
								}

								buttons_2.appendChild(remove);
								column.appendChild(buttons_2);

								main.appendChild(column);
								popup.appendChild(main);
								this.body.wrap.appendChild(popup);

								errors.appendChild(dl);
								this.body.errors.appendChild(errors);
								this.body.wrap.appendChild(this.body.errors);

								document.body.appendChild(this.body.wrap);

								// Запись в документ HTML-данных через буфер
								list.outerHTML = data.task;

								// Инициализация ошибок
								this.errors(data.errors);

								// Инициализация переменных для окна с ошибками (12 - это значение gap из div#popup)
								function top(errors) {
									errors.style.setProperty("transition", "0s");
									errors.style.setProperty(
										"--top",
										popup.offsetTop + popup.offsetHeight + 12 + "px"
									);
									setTimeout(
										() => errors.style.removeProperty("transition"),
										100
									);
								}
								top(this.body.errors);
								const resize = new ResizeObserver(() => top(this.body.errors));
								resize.observe(this.body.wrap);

								// Инициализация функции закрытия всплывающего окна
								const click = () => {
									// Блокировка
									if (this.freeze) return;

									// Удаление всплывающего окна
									this.body.wrap.remove();

									// Инициализация буфера выбранных строк
									const buffer = [
										...document.querySelectorAll('div[data-selected="true"]'),
									];

									// Удаление статуса активной строки у остальных строк
									for (const element of buffer) {
										element.removeAttribute("data-selected");
									}

									// Деинициализация быстрых действий по кнопкам
									document.removeEventListener("keydown", this.buttons);

									// Сброс блокировки
									this.freeze = false;
								};

								// Инициализация функции добавления функции закрытия всплывающего окна
								const enable = () =>
									this.body.wrap.addEventListener("click", click);

								// Инициализация функции удаления функции закрытия всплывающего окна
								const disable = () =>
									this.body.wrap.removeEventListener("click", click);

								// Первичная активация функции удаления всплывающего окна
								enable();

								// Инициализация блокировки удаления окна при взаимодействии с select-элементом
								for (const select of popup.getElementsByTagName("select")) {
									// Перебор всех select-элементов

									// Инициализация функции блокировки удаления окна по событию
									select.addEventListener("click", () => {
										// Блокировка удаления окна
										this.freeze = true;

										// Разблокировка удаления окна
										setTimeout(() => (this.freeze = false), 100);
									});

									for (const option of select.getElementsByTagName("option")) {
										// Перебор всех option-элементов

										// Инициализация функции блокировки удаления окна по событию
										option.addEventListener("click", () => {
											// Блокировка удаления окна
											this.freeze = true;

											// Разблокировка удаления окна
											setTimeout(() => (this.freeze = false), 100);
										});
									}
								}

								// Инициализация блокировки удаления окна при взаимодействии с textarea-элементом
								for (const textarea of popup.getElementsByTagName("textarea")) {
									// Перебор всех textarea-элементов

									// Обновлять позицию окна с ошибками при изменении размера textarea (там position: absolute)
									new MutationObserver(() => top(this.body.errors)).observe(
										textarea,
										{
											attributes: true,
											attributeFilter: ["style"],
										}
									);

									// Инициализация функции игнорирования блокировки для выбранных кнопок
									textarea.addEventListener("keydown", (e) => {
										if (e.keyCode === 27) {
											// Нажата кнопка: "escape"

											// Вызов глобальной функции управления кнопками
											this.buttons(e, true);
										} else if (e.ctrlKey && e.keyCode === 13) {
											// Нажаты кнопки: "control", "enter"

											// Вызов глобальной функции управления кнопками
											this.buttons(e, true);
										}
									});

									// Добавление функции блокировки удаления окна и клавиш по событиям
									textarea.addEventListener(
										"focus",
										() => (this.freeze = true)
									);
									textarea.addEventListener(
										"focusout",
										() => (this.freeze = false)
									);
								}

								// Инициализация функции управления кнопками
								this.buttons = (e, force = false) => {
									// Блокировка
									if (!force && this.freeze) return;

									if (e.keyCode === 27) {
										// Нажата кнопка: "escape"

										// Удаление окна
										click();
									} else if (event.keyCode === 13) {
										// Нажата кнопка: "enter"

										// Инициализация буфера с текущим статусом блокировки закрытия окна
										const freeze = this.freeze;

										// Блокировка закрытия окна (чтобы не вызвался click() через событие onclick)
										this.freeze = true;

										// Активация виртуальной кнопки "подтвердить"
										confirm.click();

										// Возвращение статуса блокировки закрытия окна
										this.freeze = freeze;
									}
								};

								// Инициализация быстрых действий по кнопкам
								document.addEventListener("keydown", this.buttons);

								// Добавление функции удаления всплывающего окна по событиям
								popup.addEventListener("mouseenter", disable);
								popup.addEventListener("mouseleave", enable);

								// Фокусировка
								description.focus();
							}
						}
					});
			}
		}, 300);

		/**
		 * Подтвердить
		 *
		 * @param {HTMLElement} button Кнопка
		 * @param {HTMLElement} row Строка
		 *
		 * @return {void}
		 */
		static confirm = damper(async (button, row) => {
			if (row instanceof HTMLElement && button instanceof HTMLElement) {
				// Получена кнопка и строка

				// Инициализация идентификатора строки
				const id = row.getAttribute("id");

				if (typeof id === "string") {
					// Инициализирован идентификатор

					// Запрос к серверу
					return await fetch(`/task/${id}/confirm`, {
						method: "POST",
						headers: {
							"Content-Type": "application/x-www-form-urlencoded",
						},
					})
						.then((response) => response.json())
						.then((data) => {
							if (this.errors(data.errors)) {
								// Сгенерированы ошибки
							} else {
								// Не сгенерированы ошибки (подразумевается их отсутствие)

								// Инициализация буфера списка классов
								// const buffer = [...row.classList];

								// Инициализация статуса активной строки
								const selected = row.getAttribute("data-selected");

								// Реинициализация строки
								row.outerHTML = data.row;

								// Реинициализация строки (выражение странное, но правильное)
								row = document.getElementById(row.getAttribute("id"));

								// Копирование классов из буфера классов удалённой строки
								// row.classList.add(...buffer);

								// Копирование статуса активной строки
								if (
									typeof selected === "string" &&
									selected === "true" &&
									document.body.contains(document.getElementById("popup")) &&
									!document.body.contains(
										document.querySelector('[data-selected="true"]')
									)
								) {
									row.setAttribute("data-selected", "true");
								}

								if (data.confirmed) {
									// Подтверждена заявка

									// Реинициализация текста
									button.innerText = "Отклонить";

									// Реинициализация стиля
									button.classList.remove("grass");
									button.classList.add("clay");

									// УЛОВКА: браузер ещё не успевает перерисовать документ во время исполнения this.task(row)
									row.classList.add("confirmed");
								} else {
									// Не подтверждена заявка

									// Реинициализация текста
									button.innerText = "Подтвердить";

									// Реинициализация стиля
									button.classList.remove("clay");
									button.classList.add("grass");

									// УЛОВКА: браузер ещё не успевает перерисовать документ во время исполнения this.task(row)
									row.classList.remove("confirmed");
								}

								if (this.body.wrap instanceof HTMLElement) {
									// Найдено активное окно

									// Деинициализация быстрых действий по кнопкам
									document.removeEventListener("keydown", this.buttons);

									// Сброс блокировки
									this.freeze = false;

									// Реинициализация активного окна
									tasks.popup(row);
								}
							}
						});
				}
			}
		}, 300);

		/**
		 * Сгенерировать всплывающее окно c заявлением о проблеме
		 *
		 * @param {HTMLElement} row Строка
		 *
		 * @return {void}
		 */
		static problem = damper((row) => {
			if (row instanceof HTMLElement) {
				// Получена строка

				if (row.classList.contains("problematic")) {
					// Проблемная заявка

					// Снятие статуса проблемной заявки
					this.__problem(null, null, row);
				} else {
					// Не проблемная заявка

					// Инициализация идентификатора сотрудника
					const task = row.getAttribute("id");

					// Инициализация буфера выбранных строк
					const buffer = [
						...document.querySelectorAll('div[data-selected="true"]'),
					];

					// Удаление статуса активной строки у остальных строк
					for (const element of buffer) {
						element.removeAttribute("data-selected");
					}

					// Инициализация статуса активной строки (обрабатываемой в данный момент)
					row.setAttribute("data-selected", "true");

					// Инициализация оболочки всплывающего окна
					this.body.wrap = document.createElement("div");
					this.body.wrap.setAttribute("id", "popup");

					// Инициализация всплывающего окна
					const popup = document.createElement("section");
					popup.classList.add("list", "small");

					// Инициализация заголовка всплывающего окна
					const title = document.createElement("h3");
					title.classList.add("unselectable");
					title.innerText = "Заявление о проблеме";

					// Инициализация оболочки с основной информацией
					const main = document.createElement("section");
					main.classList.add("main");

					// Инициализация колонки
					const column = document.createElement("div");
					column.classList.add("column");

					// Инициализация поля ввода отзыва
					const problem = document.createElement("textarea");
					problem.classList.add("snow");
					problem.setAttribute("autofocus", "true");
					problem.setAttribute("maxlength", "300");
					problem.setAttribute("title", "Проблема");
					problem.setAttribute("placeholder", "Описание проблемы");

					// Инициализация оболочки для кнопок
					const buttons = document.createElement("div");
					buttons.classList.add("row", "buttons");

					// Инициализация кнопки подтверждения
					const send = document.createElement("button");
					send.classList.add("grass", "stretched");
					send.innerText = "Отправить";
					send.setAttribute(
						"onclick",
						`chat.send(this, this.parentElement.previousElementSibling, document.getElementById('${task}'), 'market', 'problem', true); document.removeEventListener("keydown", tasks.buttons);`
					);

					// Инициализация окна с ошибками
					this.body.errors = document.createElement("section");
					this.body.errors.classList.add(
						"errors",
						"window",
						"list",
						"small",
						"hidden"
					);
					this.body.errors.setAttribute("data-errors", true);

					// Инициализация элемента-тела (оболочки) окна с ошибками
					const errors = document.createElement("section");
					errors.classList.add("body");

					// Инициализация элемента-списка ошибок
					const dl = document.createElement("dl");

					// Инициализация активного всплывающего окна
					const old = document.getElementById("popup");

					if (old instanceof HTMLElement) {
						// Найдено активное окно

						// Деинициализация быстрых действий по кнопкам
						document.removeEventListener("keydown", this.buttons);

						// Сброс блокировки
						this.freeze = false;

						// Удаление активного окна
						old.remove();
					}

					// Удаление блокировки выполнения закрытия всплывающего окна
					this.freeze = false;

					// Запись в документ
					popup.appendChild(title);

					column.appendChild(problem);
					buttons.appendChild(send);
					column.appendChild(buttons);

					main.appendChild(column);
					popup.appendChild(main);
					this.body.wrap.appendChild(popup);

					errors.appendChild(dl);
					this.body.errors.appendChild(errors);
					this.body.wrap.appendChild(this.body.errors);

					document.body.appendChild(this.body.wrap);

					// Инициализация переменных для окна с ошибками (12 - это значение gap из div#popup)
					function top(errors) {
						errors.style.setProperty("transition", "0s");
						errors.style.setProperty(
							"--top",
							popup.offsetTop + popup.offsetHeight + 12 + "px"
						);
						setTimeout(() => errors.style.removeProperty("transition"), 100);
					}
					top(this.body.errors);
					const resize = new ResizeObserver(() => top(this.body.errors));
					resize.observe(this.body.wrap);

					// Инициализация функции закрытия всплывающего окна
					const click = () => {
						// Блокировка
						if (this.freeze) return;

						// Удаление всплывающего окна
						this.body.wrap.remove();

						// Инициализация буфера выбранных строк
						const buffer = [
							...document.querySelectorAll('div[data-selected="true"]'),
						];

						// Удаление статуса активной строки у остальных строк
						for (const element of buffer) {
							element.removeAttribute("data-selected");
						}

						// Деинициализация быстрых действий по кнопкам
						document.removeEventListener("keydown", this.buttons);

						// Сброс блокировки
						this.freeze = false;
					};

					// Инициализация функции добавления функции закрытия всплывающего окна
					const enable = () => this.body.wrap.addEventListener("click", click);

					// Инициализация функции удаления функции закрытия всплывающего окна
					const disable = () =>
						this.body.wrap.removeEventListener("click", click);

					// Первичная активация функции удаления всплывающего окна
					enable();

					// Инициализация блокировки удаления окна при взаимодействии с select-элементом
					for (const select of popup.getElementsByTagName("select")) {
						// Перебор всех select-элементов

						// Инициализация функции блокировки удаления окна по событию
						select.addEventListener("click", () => {
							// Блокировка удаления окна
							this.freeze = true;

							// Разблокировка удаления окна
							setTimeout(() => (this.freeze = false), 100);
						});

						for (const option of select.getElementsByTagName("option")) {
							// Перебор всех option-элементов

							// Инициализация функции блокировки удаления окна по событию
							option.addEventListener("click", () => {
								// Блокировка удаления окна
								this.freeze = true;

								// Разблокировка удаления окна
								setTimeout(() => (this.freeze = false), 100);
							});
						}
					}

					// Инициализация блокировки удаления окна при взаимодействии с textarea-элементом
					for (const textarea of popup.getElementsByTagName("textarea")) {
						// Перебор всех textarea-элементов

						// Обновлять позицию окна с ошибками при изменении размера textarea (там position: absolute)
						new MutationObserver(() => top(this.body.errors)).observe(
							textarea,
							{
								attributes: true,
								attributeFilter: ["style"],
							}
						);

						// Инициализация функции игнорирования блокировки для выбранных кнопок
						textarea.addEventListener("keydown", (e) => {
							if (e.keyCode === 27) {
								// Нажата кнопка: "escape"

								// Вызов глобальной функции управления кнопками
								this.buttons(e, true);
							} else if (e.ctrlKey && e.keyCode === 13) {
								// Нажаты кнопки: "control", "enter"

								// Вызов глобальной функции управления кнопками
								this.buttons(e, true);
							}
						});

						// Добавление функции блокировки удаления окна и клавиш по событиям
						textarea.addEventListener("focus", () => (this.freeze = true));
						textarea.addEventListener("focusout", () => (this.freeze = false));
					}

					// Инициализация функции управления кнопками
					this.buttons = (e, force = false) => {
						// Блокировка
						if (!force && this.freeze) return;

						if (e.keyCode === 27) {
							// Нажата кнопка: "escape"

							// Удаление окна
							click();
						} else if (event.keyCode === 13) {
							// Нажата кнопка: "enter"

							// Инициализация буфера с текущим статусом блокировки закрытия окна
							const freeze = this.freeze;

							// Блокировка закрытия окна (чтобы не вызвался click() через событие onclick)
							this.freeze = true;

							// Активация виртуальной кнопки "отправить"
							send.click();

							// Возвращение статуса блокировки закрытия окна
							this.freeze = freeze;
						}
					};

					// Инициализация быстрых действий по кнопкам
					document.addEventListener("keydown", this.buttons);

					// Добавление функции удаления всплывающего окна по событиям
					popup.addEventListener("mouseenter", disable);
					popup.addEventListener("mouseleave", enable);

					// Фокусировка
					problem.focus();
				}
			}
		}, 300);

		/**
		 * Проблемная заявка (вызов демпфера)
		 *
		 * Изменить статус заявки на проблемную и не проблемную
		 * Если изменяется статус на проблемную, то необходимо передать текст сообщения
		 *
		 * @param {HTMLElement} button Кнопка
		 * @param {HTMLElement} textarea Поле для ввода описания проблемы <textarea>
		 * @param {HTMLElement} row Строка
		 *
		 * @return {void}
		 */
		static _problem(button, textarea, row) {
			// Блокировка полей ввода
			textarea.setAttribute("readonly", true);

			// Блокировка кнопки
			button.setAttribute("disabled", true);

			// Деинициализация индикатора и анимации об ошибке
			textarea.classList.remove("error");

			// Сброс анимации
			this.body.errors.classList.add("hidden");

			// Запуск выполнения
			this.__problem(button, textarea, row);
		}

		/**
		 * Проблемная заявка (демпфер)
		 *
		 * Изменить статус заявки на проблемную и не проблемную
		 * Если изменяется статус на проблемную, то необходимо передать текст сообщения
		 *
		 * @param {HTMLElement} button Кнопка
		 * @param {HTMLElement} textarea Поле для ввода описания проблемы <textarea>
		 * @param {HTMLElement} row Строка
		 *
		 * @return {void}
		 */
		static __problem = damper(async (button, textarea, row) => {
			if (row instanceof HTMLElement) {
				// Получена строка

				// Инициализация идентификатора строки
				const id = row.getAttribute("id");

				if (typeof id === "string") {
					// Инициализирован идентификатор

					// Инициализация функции разблокировки
					function unblock() {
						// Разблокировка поля ввода
						textarea.removeAttribute("readonly");

						// Разблокировка кнопки
						button.removeAttribute("disabled");
					}

					// Запуск отсрочки разблокировки на случай, если сервер не отвечает
					const timeout = setTimeout(() => {
						this.errors(["Сервер не отвечает"]);
						unblock();
					}, 5000);

					// Запрос к серверу
					return await fetch(`/task/${id}/problem`, {
						method: "POST",
						headers: {
							"Content-Type": "application/x-www-form-urlencoded",
						},
						body:
							textarea instanceof HTMLElement && textarea.value.length > 0
								? `text=${textarea.value}`
								: "",
					})
						.then((response) => response.json())
						.then((data) => {
							// Удаление отсрочки разблокировки
							clearTimeout(timeout);

							if (this.errors(data.errors)) {
								// Сгенерированы ошибки

								// Инициализация отображения ошибки
								textarea.classList.add("error");

								// Фокусировка на поле ввода
								textarea.focus();

								// Разблокировка полей ввода и кнопок
								unblock();
							} else {
								// Не сгенерированы ошибки (подразумевается их отсутствие)

								// Инициализация буфера списка классов
								// const buffer = [...row.classList];

								// Инициализация статуса активной строки
								const selected = row.getAttribute("data-selected");

								// Реинициализация строки
								row.outerHTML = data.row;

								// Реинициализация строки (выражение странное, но правильное)
								row = document.getElementById(row.getAttribute("id"));

								// Копирование классов из буфера классов удалённой строки
								// row.classList.add(...buffer);

								// Копирование статуса активной строки
								if (
									typeof selected === "string" &&
									selected === "true" &&
									document.body.contains(document.getElementById("popup")) &&
									!document.body.contains(
										document.querySelector('[data-selected="true"]')
									)
								) {
									row.setAttribute("data-selected", "true");
								}

								if (data.problematic) {
									// Проблемная заявка

									// УЛОВКА: браузер ещё не успевает перерисовать документ во время исполнения this.task(row)
									row.classList.add("problematic");
								} else {
									// Не проблемная заявка

									// УЛОВКА: браузер ещё не успевает перерисовать документ во время исполнения this.task(row)
									row.classList.remove("problematic");
								}

								if (this.body.wrap instanceof HTMLElement) {
									// Найдено активное окно

									// Деинициализация быстрых действий по кнопкам
									document.removeEventListener("keydown", this.buttons);

									// Сброс блокировки
									this.freeze = false;

									// Деинициализация активного окна
									this.body.wrap.remove();

									// Удаление статуса активной строки
									row.removeAttribute("data-selected");
								}
							}
						});
				}
			}
		}, 300);

		/**
		 * Подтверждение заявки (вызов демпфера)
		 *
		 * @param {HTMLElement} button Кнопка <button>
		 * @param {HTMLElement} rating Рейтинг <input>
		 * @param {HTMLElement} review Отзыв <input>
		 * @param {HTMLElement} row Строка
		 *
		 * @return {void}
		 */
		static complete(button, rating, review, row) {
			// Блокировка ползунка
			rating.setAttribute("disabled", true);

			// Блокировка полей ввода
			review.setAttribute("readonly", true);

			// Деинициализация индикатора и анимации об ошибке
			rating.classList.remove("error");
			review.classList.remove("error");

			// Блокировка кнопки
			button.setAttribute("disabled", true);

			// Сброс анимации
			this.body.errors.classList.add("hidden");

			// Запуск выполнения
			this._complete(button, rating, review, row);
		}

		/**
		 * Подтверждение заявки (демпфер)
		 *
		 * @param {HTMLElement} button Кнопка <button>
		 * @param {HTMLElement} rating Рейтинг <input>
		 * @param {HTMLElement} review Отзыв <input>
		 * @param {HTMLElement} row Строка
		 *
		 * @return {void}
		 */
		static _complete = damper(async (button, rating, review, row) => {
			if (
				button instanceof HTMLElement &&
				rating instanceof HTMLElement &&
				review instanceof HTMLElement &&
				row instanceof HTMLElement
			) {
				// Получена кнопка, рейтинг, отзыв и строка

				// Инициализация идентификатора строки
				const id = row.getAttribute("id");

				if (typeof id === "string") {
					// Инициализирован идентификатор

					// Инициализация функции разблокировки
					function unblock() {
						// Разблокировка ползунка
						rating.removeAttribute("disabled");

						// Разблокировка поля ввода
						review.removeAttribute("readonly");

						// Разблокировка кнопки
						button.removeAttribute("disabled");
					}

					// Запуск отсрочки разблокировки на случай, если сервер не отвечает
					const timeout = setTimeout(() => {
						this.errors(["Сервер не отвечает"]);
						unblock();
					}, 5000);

					// Запрос к серверу
					return await fetch(`/task/${id}/complete`, {
						method: "POST",
						headers: {
							"Content-Type": "application/x-www-form-urlencoded",
						},
						body: `rating=${rating.value}&review=${review.value}`,
					})
						.then((response) => response.json())
						.then((data) => {
							// Удаление отсрочки разблокировки
							clearTimeout(timeout);

							if (this.errors(data.errors)) {
								// Сгенерированы ошибки

								// Инициализация отображения ошибки
								rating.classList.add("error");
								review.classList.add("error");

								// Фокусировка на поле ввода
								review.focus();

								if (!data.completed) {
									// Не завершена заявка

									// Разблокировка полей ввода и кнопок
									unblock();
								}
							} else {
								// Не сгенерированы ошибки (подразумевается их отсутствие)

								// Инициализация буфера списка классов
								// const buffer = [...row.classList];

								// Инициализация статуса активной строки
								const selected = row.getAttribute("data-selected");

								// Реинициализация строки
								row.outerHTML = data.row;

								// Реинициализация строки (выражение странное, но правильное)
								row = document.getElementById(row.getAttribute("id"));

								// Копирование классов из буфера классов удалённой строки
								// row.classList.add(...buffer);

								// Копирование статуса активной строки
								if (
									typeof selected === "string" &&
									selected === "true" &&
									document.body.contains(document.getElementById("popup")) &&
									!document.body.contains(
										document.querySelector('[data-selected="true"]')
									)
								) {
									row.setAttribute("data-selected", "true");
								}

								if (data.completed) {
									// Завершена заявка

									// УЛОВКА: браузер ещё не успевает перерисовать документ во время исполнения this.task(row)
									row.classList.add("completed");
								} else {
									// Не завершена заявка

									// УЛОВКА: браузер ещё не успевает перерисовать документ во время исполнения this.task(row)
									row.classList.remove("completed");
								}

								if (this.body.wrap instanceof HTMLElement) {
									// Найдено активное окно

									// Деинициализация быстрых действий по кнопкам
									document.removeEventListener("keydown", this.buttons);

									// Сброс блокировки
									this.freeze = false;

									// Деинициализация активного окна
									this.body.wrap.remove();

									// Удаление статуса активной строки
									row.removeAttribute("data-selected");
								}
							}
						});
				}
			}
		}, 300);

		/**
		 * Скрыть
		 *
		 * @param {HTMLElement} button Кнопка
		 * @param {HTMLElement} row Строка
		 *
		 * @return {void}
		 */
		static hide = damper(async (button, row) => {
			if (row instanceof HTMLElement && button instanceof HTMLElement) {
				// Получена кнопка и строка

				// Инициализация идентификатора строки
				const id = row.getAttribute("id");

				if (typeof id === "string") {
					// Инициализирован идентификатор

					// Запрос к серверу
					return await fetch(`/task/${id}/hide`, {
						method: "POST",
						headers: {
							"Content-Type": "application/x-www-form-urlencoded",
						},
					})
						.then((response) => response.json())
						.then((data) => {
							if (this.errors(data.errors)) {
								// Сгенерированы ошибки
							} else {
								// Не сгенерированы ошибки (подразумевается их отсутствие)

								// Инициализация буфера списка классов
								// const buffer = [...row.classList];

								// Инициализация статуса активной строки
								const selected = row.getAttribute("data-selected");

								// Реинициализация строки
								row.outerHTML = data.row;

								// Реинициализация строки (выражение странное, но правильное)
								row = document.getElementById(row.getAttribute("id"));

								// Копирование классов из буфера классов удалённой строки
								// row.classList.add(...buffer);

								// Копирование статуса активной строки
								if (
									typeof selected === "string" &&
									selected === "true" &&
									document.body.contains(document.getElementById("popup")) &&
									!document.body.contains(
										document.querySelector('[data-selected="true"]')
									)
								) {
									row.setAttribute("data-selected", "true");
								}

								if (data.hided) {
									// Скрыта заявка

									// Реинициализация текста
									button.innerText = "Показать";

									// Реинициализация стиля
									button.classList.remove("sea");
									button.classList.add("grass");

									// УЛОВКА: браузер ещё не успевает перерисовать документ во время исполнения this.task(row)
									row.classList.add("hided");
								} else {
									// Не скрыта заявка

									// Реинициализация текста
									button.innerText = "Скрыть";

									// Реинициализация стиля
									button.classList.remove("grass");
									button.classList.add("sea");

									// УЛОВКА: браузер ещё не успевает перерисовать документ во время исполнения this.task(row)
									row.classList.remove("hided");
								}

								if (this.body.wrap instanceof HTMLElement) {
									// Найдено активное окно

									// Деинициализация быстрых действий по кнопкам
									document.removeEventListener("keydown", this.buttons);

									// Сброс блокировки
									this.freeze = false;

									// Реинициализация активного окна
									tasks.popup(row);
								}
							}
						});
				}
			}
		}, 300);

		/**
		 * Удалить
		 *
		 * @param {HTMLElement} button Кнопка
		 * @param {HTMLElement} row Строка
		 *
		 * @return {void}
		 */
		static remove = damper(async (button, row) => {
			if (row instanceof HTMLElement && button instanceof HTMLElement) {
				// Получена кнопка и строка

				// Инициализация идентификатора строки
				const id = row.getAttribute("id");

				alert(228);

				if (typeof id === "string") {
					// Инициализирован идентификатор

					// Запрос к серверу
					return await fetch(`/task/${id}/remove`, {
						method: "POST",
						headers: {
							"Content-Type": "application/x-www-form-urlencoded",
						},
					})
						.then((response) => response.json())
						.then((data) => {
							if (this.errors(data.errors)) {
								// Сгенерированы ошибки
							} else {
								// Не сгенерированы ошибки (подразумевается их отсутствие)

								if (data.deleted) {
									// Удалена заявка

									if (this.body.wrap instanceof HTMLElement) {
										// Найдено активное окно

										// Деинициализация быстрых действий по кнопкам
										document.removeEventListener("keydown", this.buttons);

										// Сброс блокировки
										this.freeze = false;

										// Деинициализация активного окна
										this.body.wrap.remove();

										// Удаление статуса активной строки
										row.removeAttribute("data-selected");
									}

									// Удаление строки
									row.remove();
								}
							}
						});
				}
			}
		}, 300);

		/**
		 * Прочитать значение из базы данных
		 *
		 * @param {HTMLElement} row Строка
		 * @param {string} name Название
		 *
		 * @return {string} Значение
		 */
		static async value(row, name) {
			if (row instanceof HTMLElement && typeof name === "string") {
				// Получена строка и название

				// Инициализация идентификатора строки
				const id = row.getAttribute("id");

				if (typeof id === "string") {
					// Инициализирован идентификатор

					// Запрос к серверу
					return await fetch(`/task/${id}/value`, {
						method: "POST",
						headers: {
							"Content-Type": "application/x-www-form-urlencoded",
						},
						body: `name=${name}`,
					})
						.then((response) => response.json())
						.then((data) => {
							if (this.errors(data.errors)) {
								// Сгенерированы ошибки
							} else {
								// Не сгенерированы ошибки (подразумевается их отсутствие)

								return data.value;
							}
						});
				}
			}
		}

		/**
		 * Список работ
		 *
		 * Сгенерировать список работ и выбрать в нём ту, что записана в базе данных у заявки, если передана
		 *
		 * @param {number|null} id Идентификатор заявки
		 *
		 * @return {array|null} Массив HTML-элементов <option>
		 */
		static async works(id) {
			// Запрос к серверу
			return await fetch(`/tasks/works`, {
				method: "POST",
				headers: {
					"Content-Type": "application/x-www-form-urlencoded",
				},
				body: `task=${id}`,
			})
				.then((response) => response.json())
				.then((data) => {
					if (this.errors(data.errors)) {
						// Сгенерированы ошибки
					} else {
						// Не сгенерированы ошибки (подразумевается их отсутствие)

						return data.works;
					}
				});
		}

		/**
		 * Записать тип работы
		 *
		 * @param {HTMLElement} row Строка
		 * @param {HTMLElement} select HTML-элемент <select>
		 *
		 * @return {void}
		 */
		static work = damper(async (row, select) => {
			if (row instanceof HTMLElement && select instanceof HTMLElement) {
				// Получена строка и select-элемент

				// Инициализация идентификатора строки
				const id = row.getAttribute("id");

				if (typeof id === "string") {
					// Инициализирован идентификатор

					// Запрос к серверу
					return await fetch(`/task/${id}/work`, {
						method: "POST",
						headers: {
							"Content-Type": "application/x-www-form-urlencoded",
						},
						body: `work=${select.value}`,
					})
						.then((response) => response.json())
						.then((data) => {
							if (this.errors(data.errors)) {
								// Сгенерированы ошибки
							} else {
								// Не сгенерированы ошибки (подразумевается их отсутствие)

								if (data.writed) {
									// Записано новое значение в базу данных

									// Инициализация буфера списка классов
									// const buffer = [...row.classList];

									// Инициализация статуса активной строки
									const selected = row.getAttribute("data-selected");

									// Реинициализация строки в документе
									row.outerHTML = data.row;

									// Реинициализация строки (выражение странное, но правильное)
									row = document.getElementById(row.getAttribute("id"));

									// Копирование классов из буфера классов удалённой строки
									// row.classList.add(...buffer);

									// Копирование статуса активной строки
									if (
										typeof selected === "string" &&
										selected === "true" &&
										document.body.contains(document.getElementById("popup")) &&
										!document.body.contains(
											document.querySelector('[data-selected="true"]')
										)
									) {
										row.setAttribute("data-selected", "true");
									}
								}

								if (this.body.wrap instanceof HTMLElement) {
									// Найдено активное окно

									// Деинициализация быстрых действий по кнопкам
									document.removeEventListener("keydown", this.buttons);

									// Сброс блокировки
									this.freeze = false;

									// Реинициализация активного окна
									tasks.popup(row);
								}
							}
						});
				}
			}
		}, 300);

		/**
		 * Записать дату
		 *
		 * @param {HTMLElement} row Строка
		 * @param {HTMLElement} date Дата
		 * @param {HTMLElement} start Время начала
		 * @param {HTMLElement} end Время окончания
		 * @param {HTMLElement} button Кнопка отправки
		 *
		 * @return {void}
		 */
		static date(row, date, start, end, button) {
			// Блокировка полей ввода
			date.setAttribute("readonly", true);
			start.setAttribute("readonly", true);
			end.setAttribute("readonly", true);
			button.setAttribute("disabled", true);

			// Запуск выполнения
			this._date(row, date, start, end, button);
		}

		/**
		 * Записать дату
		 *
		 * @param {HTMLElement} row Строка
		 * @param {HTMLElement} date Дата
		 * @param {HTMLElement} start Время начала
		 * @param {HTMLElement} end Время окончания
		 * @param {HTMLElement} button Кнопка отправки
		 *
		 * @return {void}
		 */
		static _date = damper(async (row, date, start, end, button) => {
			if (
				row instanceof HTMLElement &&
				date instanceof HTMLElement &&
				start instanceof HTMLElement &&
				end instanceof HTMLElement &&
				button instanceof HTMLElement
			) {
				// Получены строка, поле даты, поле начала заявки, поле окончания заяки и кнопка

				// Инициализация идентификатора строки
				const id = row.getAttribute("id");

				if (typeof id === "string") {
					// Инициализирован идентификатор

					// Запрос к серверу
					return await fetch(`/task/${id}/date`, {
						method: "POST",
						headers: {
							"Content-Type": "application/x-www-form-urlencoded",
						},
						body: `date=${date.valueAsDate / 1000}&start=${start.value}&end=${
							end.value
						}`,
					})
						.then((response) => response.json())
						.then((data) => {
							if (this.errors(data.errors)) {
								// Сгенерированы ошибки

								// Разблокировка ввода
								date.removeAttribute("readonly");
								start.removeAttribute("readonly");
								end.removeAttribute("readonly");
								button.removeAttribute("disabled");
							} else {
								// Не сгенерированы ошибки (подразумевается их отсутствие)

								if (data.writed) {
									// Записано новое значение в базу данных

									// Инициализация буфера списка классов
									// const buffer = [...row.classList];

									// Инициализация статуса активной строки
									const selected = row.getAttribute("data-selected");

									// Реинициализация строки в документе
									row.outerHTML = data.row;

									// Реинициализация строки (выражение странное, но правильное)
									row = document.getElementById(row.getAttribute("id"));

									// Копирование классов из буфера классов удалённой строки
									// row.classList.add(...buffer);

									// Копирование статуса активной строки
									if (
										typeof selected === "string" &&
										selected === "true" &&
										document.body.contains(document.getElementById("popup")) &&
										!document.body.contains(
											document.querySelector('[data-selected="true"]')
										)
									) {
										row.setAttribute("data-selected", "true");
									}

									if (this.body.wrap instanceof HTMLElement) {
										// Найдено активное окно

										// Деинициализация быстрых действий по кнопкам
										document.removeEventListener("keydown", this.buttons);

										// Сброс блокировки
										this.freeze = false;

										// Реинициализация активного окна
										tasks.popup(row);
									}
								} else {
									// Не записано новое значение в базу данных

									// Разблокировка ввода
									date.removeAttribute("readonly");
									start.removeAttribute("readonly");
									end.removeAttribute("readonly");
									button.removeAttribute("disabled");
								}
							}
						});
				}
			}
		}, 300);

		/**
		 * Записать описание
		 *
		 * @param {HTMLElement} row Строка
		 * @param {HTMLElement} textarea HTML-элемент <textarea>
		 *
		 * @return {void}
		 */
		static description(row, textarea) {
			// Сброс анимации ошибки
			textarea.classList.remove("error");

			// Запуск выполнения
			this._description(row, textarea);
		}

		/**
		 * Записать описание (системное)
		 *
		 * @param {HTMLElement} row Строка
		 * @param {HTMLElement} textarea HTML-элемент <textarea>
		 *
		 * @return {void}
		 */
		static _description = damper(async (row, textarea) => {
			if (row instanceof HTMLElement && textarea instanceof HTMLElement) {
				// Получена строка и select-элемент

				// Инициализация идентификатора строки
				const id = row.getAttribute("id");

				if (typeof id === "string") {
					// Инициализирован идентификатор

					// Запрос к серверу
					return await fetch(`/task/${id}/description`, {
						method: "POST",
						headers: {
							"Content-Type": "application/x-www-form-urlencoded",
						},
						body: `description=${textarea.value}`,
					})
						.then((response) => response.json())
						.then((data) => {
							if (this.errors(data.errors)) {
								// Сгенерированы ошибки

								// Запись анимации ошибки
								textarea.classList.add("error");
							} else {
								// Не сгенерированы ошибки (подразумевается их отсутствие)

								if (data.writed) {
									// Записано новое значение в базу данных

									// Удаление анимации ошибки
									textarea.classList.remove("error");
								} else {
									// Не записано новое значение в базу данных

									// Запись анимации ошибки
									textarea.classList.add("error");
								}
							}
						});
				}
			}
		}, 300);

		/**
		 * Сгенерировать HTML-элемент со списком ошибок
		 *
		 * @param {object} registry Реестр ошибок
		 * @param {bool} render Отобразить в окне с ошибками?
		 * @param {bool} clean Очистить окно с ошибками перед добавлением?
		 *
		 * @return {bool} Сгенерированы ошибки?
		 */
		static errors(registry, render = true, clean = true) {
			// Инициализация ссылки на HTML-элемент с ошибками
			const wrap = document.body.contains(this.body.errors)
				? this.body.errors
				: document.querySelector('[data-errors="true"]');

			if (wrap instanceof HTMLElement && document.body.contains(wrap)) {
				// Найден HTML-элемент с ошибками

				// Перерасчёт высоты элемента
				function height() {
					wrap.classList.remove("hidden");
					wrap.classList.remove("animation");
					// Реинициализация переменной с данными о высоте HTML-элемента (16 - это padding-top + padding-bottom у div#popup > section.errors)
					wrap.style.setProperty("--height", wrap.offsetHeight - 16 + "px");
					wrap.classList.add("animation");
					wrap.classList.add("hidden");
				}

				// Инициализация элемента-списка ошибок
				const list = wrap.getElementsByTagName("dl")[0];

				// Удаление ошибок из прошлой генерации
				if (clean) list.innerHTML = null;

				for (const error in registry) {
					// Генерация HTML-элементов с текстами ошибок

					// Инициализация HTML-элемента текста ошибки
					const samp = document.createElement("samp");

					if (typeof registry[error] === "object") {
						// Категория ошибок

						// Проверка наличия ошибок
						if (registry[error].length === 0) continue;

						// Инициализация HTML-элемента-оболочки
						const wrap = document.createElement("dt");

						// Запись текста категории
						samp.innerText = error;

						// Запись HTML-элементов в список
						wrap.appendChild(samp);
						list.appendChild(wrap);

						// Реинициализация высоты
						height();

						// Обработка вложенных ошибок (вход в рекурсию)
						this.errors(registry[error], false);
					} else {
						// Текст ошибки (подразумевается)

						// Инициализация HTML-элемента
						const wrap = document.createElement("dd");

						// Запись текста ошибки
						samp.innerText = registry[error];

						// Запись HTML-элемента в список
						wrap.appendChild(samp);
						list.appendChild(wrap);

						// Реинициализация высоты
						height();
					}
				}

				if (render) {
					// Запрошена отрисовка

					if (list.childElementCount !== 0) {
						// Найдены ошибки

						// Сброс анимации
						// УЛОВКА: таким образом не запускается анимация до взаимодействия с элементом (исправлял это в CSS, но не помню как)
						wrap.classList.add("animation");

						// Отображение
						wrap.classList.remove("hidden");
					} else {
						// Не найдены ошибки

						// Скрытие
						wrap.classList.add("hidden");
					}
				}

				return list.childElementCount === 0 ? false : true;
			}

			return false;
		}

		/**
		 * Сотрудник
		 */
		static worker = class {
			/**
			 * Ссылка на ядро (родительский класс)
			 */
			static core;

			/**
			 * Сгенерировать всплывающее окно c данными сотрудника
			 *
			 * @param {HTMLElement} row Строка
			 *
			 * @return {void}
			 */
			static async popup(row) {
				if (
					row instanceof HTMLElement &&
					typeof core === "function" &&
					core.interface !== "worker"
				) {
					// Получена строка и аккаунт не является сотрудником

					// Инициализация идентификатора сотрудника
					const worker = row.querySelector(
						'span[data-column="worker"]'
					).innerText;

					if (worker.length > 0) {
						// Инициализирован идентификатор сотрудника

						// Инициализация идентификатора строки
						const task = row.getAttribute("id");

						if (task.length > 0) {
							// Инициализирован идентификатор строки

							// Запрос к серверу
							return await fetch(`/worker/${worker}/read`, {
								method: "POST",
								headers: {
									"Content-Type": "application/x-www-form-urlencoded",
								},
							})
								.then((response) => response.json())
								.then((data) => {
									if (this.core.errors(data.errors)) {
										// Сгенерированы ошибки
									} else {
										// Не сгенерированы ошибки (подразумевается их отсутствие)

										if (data.worker.length > 0) {
											// Получены данные (подразумевается, что сотрудник найден)

											// Инициализация буфера выбранных строк
											const buffer = [
												...document.querySelectorAll(
													'div[data-selected="true"]'
												),
											];

											// Удаление статуса активной строки у остальных строк
											for (const element of buffer) {
												element.removeAttribute("data-selected");
											}

											// Инициализация статуса активной строки (обрабатываемой в данный момент)
											row.setAttribute("data-selected", "true");

											// Инициализация оболочки всплывающего окна
											this.core.body.wrap = document.createElement("div");
											this.core.body.wrap.setAttribute("id", "popup");

											// Инициализация всплывающего окна
											const popup = document.createElement("section");
											popup.classList.add("window", "list", "small");

											// Инициализация заголовка всплывающего окна
											const title = document.createElement("h3");
											title.innerText = worker;

											// Инициализация оболочки с основной информацией
											const main = document.createElement("section");
											main.classList.add("main");

											// Инициализация колонки
											const column = document.createElement("div");
											column.classList.add("column");

											// Инициализация буфера для записи во всплывающее окно
											const list = document.createElement("div");

											// Инициализация оболочки для кнопок
											const buttons = document.createElement("div");
											buttons.classList.add("row", "divided", "buttons");

											// Инициализация оболочки для строки с полем ввода
											const label = document.createElement("label");

											// Инициализация иконки для поля ввода замены
											const icon = document.createElement("i");
											icon.classList.add("icon", "user");

											// Инициализация поля ввода замены
											const input = document.createElement("input");
											input.classList.add("cloud");
											input.setAttribute("placeholder", "Сотрудник");
											input.setAttribute("autocomplete", "username");
											input.setAttribute("autofocus", "true");
											input.setAttribute("title", "Идентификатор сотрудника");
											input.setAttribute("list", "popup_worker_datalist");

											// Инициализация кнопки смены
											const replace = document.createElement("button");
											replace.classList.add("sea");
											replace.innerText = "Заменить";
											replace.setAttribute(
												"onclick",
												`tasks.worker.update(document.getElementById('${task}'), this.previousElementSibling, this)`
											);

											// Инициализация списка сотружников
											const datalist = document.createElement("datalist");
											datalist.setAttribute("id", "popup_worker_datalist");
											workers
												.list()
												.then((html) => (datalist.innerHTML = html));

											// Инициализация кнопки удаления
											const remove = document.createElement("button");
											remove.classList.add("clay");
											remove.innerText = "Удалить";
											remove.setAttribute(
												"onclick",
												`tasks.worker.remove(document.getElementById('${task}'), this)`
											);

											// Инициализация окна с ошибками
											this.core.body.errors = document.createElement("section");
											this.core.body.errors.classList.add(
												"errors",
												"window",
												"list",
												"small",
												"hidden"
											);
											this.core.body.errors.setAttribute("data-errors", true);

											// Инициализация элемента-тела (оболочки) окна с ошибками
											const errors = document.createElement("section");
											errors.classList.add("body");

											// Инициализация элемента-списка ошибок
											const dl = document.createElement("dl");

											// Инициализация активного всплывающего окна
											const old = document.getElementById("popup");

											if (old instanceof HTMLElement) {
												// Найдено активное окно

												// Деинициализация быстрых действий по кнопкам
												document.removeEventListener(
													"keydown",
													this.core.buttons
												);

												// Сброс блокировки
												this.core.freeze = false;

												// Удаление активного окна
												old.remove();
											}

											// Запись в документ
											popup.appendChild(title);

											label.appendChild(icon);
											label.appendChild(input);
											label.appendChild(replace);
											label.appendChild(remove);
											label.appendChild(datalist);
											buttons.appendChild(label);
											column.appendChild(list);
											column.appendChild(buttons);

											main.appendChild(column);
											popup.appendChild(main);
											this.core.body.wrap.appendChild(popup);

											errors.appendChild(dl);
											this.core.body.errors.appendChild(errors);
											this.core.body.wrap.appendChild(this.core.body.errors);

											document.body.appendChild(this.core.body.wrap);

											// Запись в документ HTML-данных через буфер
											list.outerHTML = data.worker;

											// Инициализация элемента с номером в списке данных сотрудника
											const number = document
												.getElementById(`${worker}_number`)
												.getElementsByTagName("a")[0];

											// Инициализация маски номера
											const mask = IMask.createMask({
												mask: "+{7} (000) 000-00-00",
											});

											// Применение маски номера
											mask.resolve(number.innerText);

											// Запись нового значения
											number.innerText = mask.value;

											// Инициализация переменных для окна с ошибками (12 - это значение gap из div#popup)
											function top(errors) {
												errors.style.setProperty("transition", "0s");
												errors.style.setProperty(
													"--top",
													popup.offsetTop + popup.offsetHeight + 12 + "px"
												);
												setTimeout(
													() => errors.style.removeProperty("transition"),
													100
												);
											}
											top(this.core.body.errors);
											const resize = new ResizeObserver(() =>
												top(this.core.body.errors)
											);
											resize.observe(this.core.body.wrap);

											// Инициалиация маски идентификатора сотрудника в поле ввода идентификатора сотрудника
											IMask(input, { mask: "000000000" });

											// Инициализация функции закрытия всплывающего окна
											const click = () => {
												// Блокировка
												if (this.core.freeze) return;

												// Удаление всплывающего окна
												this.core.body.wrap.remove();

												// Инициализация буфера выбранных строк
												const buffer = [
													...document.querySelectorAll(
														'div[data-selected="true"]'
													),
												];

												// Удаление статуса активной строки у остальных строк
												for (const element of buffer) {
													element.removeAttribute("data-selected");
												}

												// Деинициализация быстрых действий по кнопкам
												document.removeEventListener(
													"keydown",
													this.core.buttons
												);

												// Сброс блокировки
												this.core.freeze = false;
											};

											// Инициализация функции добавления функции закрытия всплывающего окна
											const enable = () =>
												this.core.body.wrap.addEventListener("click", click);

											// Инициализация функции удаления функции закрытия всплывающего окна
											const disable = () =>
												this.core.body.wrap.removeEventListener("click", click);

											// Первичная активация функции удаления всплывающего окна
											enable();

											// Инициализация блокировки удаления окна при взаимодействии с select-элементом
											for (const select of popup.getElementsByTagName(
												"select"
											)) {
												// Перебор всех select-элементов

												// Инициализация функции блокировки удаления окна по событию
												select.addEventListener("click", () => {
													// Блокировка удаления окна
													this.core.freeze = true;

													// Разблокировка удаления окна
													setTimeout(() => (this.core.freeze = false), 100);
												});

												for (const option of select.getElementsByTagName(
													"option"
												)) {
													// Перебор всех option-элементов

													// Инициализация функции блокировки удаления окна по событию
													option.addEventListener("click", () => {
														// Блокировка удаления окна
														this.core.freeze = true;

														// Разблокировка удаления окна
														setTimeout(() => (this.core.freeze = false), 100);
													});
												}
											}

											// Инициализация блокировки удаления окна при взаимодействии с textarea-элементом
											for (const textarea of popup.getElementsByTagName(
												"textarea"
											)) {
												// Перебор всех textarea-элементов

												// Обновлять позицию окна с ошибками при изменении размера textarea (там position: absolute)
												new MutationObserver(() =>
													top(this.core.body.errors)
												).observe(textarea, {
													attributes: true,
													attributeFilter: ["style"],
												});

												// Инициализация функции игнорирования блокировки для выбранных кнопок
												textarea.addEventListener("keydown", (e) => {
													if (e.keyCode === 27) {
														// Нажата кнопка: "escape"

														// Вызов глобальной функции управления кнопками
														this.core.buttons(e, true);
													} else if (e.ctrlKey && e.keyCode === 13) {
														// Нажаты кнопки: "control", "enter"

														// Вызов глобальной функции управления кнопками
														this.core.buttons(e, true);
													}
												});

												// Добавление функции блокировки удаления окна и клавиш по событиям
												textarea.addEventListener(
													"focus",
													() => (this.core.freeze = true)
												);
												textarea.addEventListener(
													"focusout",
													() => (this.core.freeze = false)
												);
											}

											// Инициализация функции управления кнопками
											this.core.buttons = (e, force = false) => {
												// Блокировка
												if (!force && this.core.freeze) return;

												if (e.keyCode === 27) {
													// Нажата кнопка: "escape"

													// Удаление окна
													click();
												} else if (event.keyCode === 13) {
													// Нажата кнопка: "enter"

													// Инициализация буфера с текущим статусом блокировки закрытия окна
													const freeze = this.core.freeze;

													// Блокировка закрытия окна (чтобы не вызвался click() через событие onclick)
													this.core.freeze = true;

													// Активация виртуальной кнопки "заменить"
													replace.click();

													// Возвращение статуса блокировки закрытия окна
													this.core.freeze = freeze;
												}
											};

											// Инициализация быстрых действий по кнопкам
											document.addEventListener("keydown", this.core.buttons);

											// Добавление функции удаления всплывающего окна по событиям
											popup.addEventListener("mouseenter", disable);
											popup.addEventListener("mouseleave", enable);

											// Фокусировка
											input.focus();
										} else {
											// Не получены данные (подразумевается, что сотрудник не найден)

											// Открытие окна инициализации сотрудника
											this.init(row);
										}
									}
								});
						}
					} else {
						// Не инициализирован идентификатор сотрудника

						// Открытие окна инициализации сотрудника
						this.init(row);
					}
				}
			}

			static init(row) {
				// Инициализация идентификатора строки
				const task = row.getAttribute("id");

				if (task.length > 0) {
					// Инициализирован идентификатор строки

					// Инициализация статуса: "опубликовано"
					const published = row.classList.contains("published");

					// Инициализация статуса: "подтверждено"
					const confirmed = row.classList.contains("confirmed");

					// Инициализация статуса: "завершено"
					const completed = row.classList.contains("completed");

					// Инициализация буфера выбранных строк
					const buffer = [
						...document.querySelectorAll('div[data-selected="true"]'),
					];

					// Удаление статуса активной строки у остальных строк
					for (const element of buffer) {
						element.removeAttribute("data-selected");
					}

					// Инициализация статуса активной строки (обрабатываемой в данный момент)
					row.setAttribute("data-selected", "true");

					// Инициализация оболочки всплывающего окна
					this.core.body.wrap = document.createElement("div");
					this.core.body.wrap.setAttribute("id", "popup");

					// Инициализация оболочки с основной информацией
					const main = document.createElement("section");
					main.classList.add("main");

					// Инициализация колонки
					const column = document.createElement("div");
					column.classList.add("column");

					// Инициализация всплывающего окна
					const popup = document.createElement("section");
					popup.classList.add("window", "list", "small");

					// Инициализация оболочки для кнопок
					const buttons = document.createElement("div");
					buttons.classList.add("row", "buttons");

					// Инициализация оболочки для строки с полем ввода
					const label = document.createElement("label");

					// Инициализация иконки для поля ввода замены
					const icon = document.createElement("i");
					icon.classList.add("icon", "user");

					// Инициализация поля ввода замены
					const input = document.createElement("input");
					input.classList.add("cloud");
					input.setAttribute("placeholder", "Сотрудник");
					input.setAttribute("autocomplete", "username");
					input.setAttribute("autofocus", "true");
					input.setAttribute("title", "Идентификатор сотрудника");
					input.setAttribute("list", "popup_worker_datalist");
					if (published || confirmed || completed) {
						input.setAttribute("readonly", "true");
					}

					// Инициализация кнопки замены
					const connect = document.createElement("button");
					connect.classList.add("grass");
					connect.innerText = "Назначить";
					connect.setAttribute(
						"onclick",
						`tasks.worker.update(document.getElementById('${task}'), this.previousElementSibling, this)`
					);
					if (published || confirmed || completed) {
						connect.setAttribute("disabled", "true");
					}

					// Инициализация списка сотрудников
					const datalist = document.createElement("datalist");
					datalist.setAttribute("id", "popup_worker_datalist");
					workers.list().then((html) => (datalist.innerHTML = html));

					// Инициализация оболочки для кнопок
					const buttons_2 = document.createElement("div");
					buttons_2.classList.add("row", "buttons");

					// Инициализация оболочки для строки с полем ввода
					const label_2 = document.createElement("label");

					// Инициализация кнопки замены
					const publish = document.createElement("button");
					publish.classList.add(published ? "clay" : "sea");
					publish.innerText = published ? "Снять с публикации" : "Опубликовать";
					publish.setAttribute(
						"onclick",
						published
							? `tasks.worker.unpublish(document.getElementById('${task}'), this)`
							: `tasks.worker.publish(document.getElementById('${task}'), this)`
					);

					// Инициализация окна с ошибками
					this.core.body.errors = document.createElement("section");
					this.core.body.errors.classList.add(
						"errors",
						"window",
						"list",
						"small",
						"hidden"
					);
					this.core.body.errors.setAttribute("data-errors", true);

					// Инициализация элемента-тела (оболочки) окна с ошибками
					const body = document.createElement("section");
					body.classList.add("body");

					// Инициализация элемента-списка ошибок
					const dl = document.createElement("dl");

					// Инициализация активного всплывающего окна
					const old = document.getElementById("popup");

					if (old instanceof HTMLElement) {
						// Найдено активное окно

						// Деинициализация быстрых действий по кнопкам
						document.removeEventListener("keydown", this.core.buttons);

						// Сброс блокировки
						this.core.freeze = false;

						// Удаление активного окна
						old.remove();
					}

					// Запись в документ
					label.appendChild(icon);
					label.appendChild(input);
					label.appendChild(connect);
					label.appendChild(datalist);
					buttons.appendChild(label);
					column.appendChild(buttons);

					if (
						typeof core === "function" &&
						core.interface !== "market" &&
						core.interface !== "worker"
					) {
						// Скрытие для магазина и сотрудника

						label_2.appendChild(publish);
						buttons_2.appendChild(label_2);
						column.appendChild(buttons_2);
					}

					main.appendChild(column);
					popup.appendChild(main);
					this.core.body.wrap.appendChild(popup);

					body.appendChild(dl);
					this.core.body.errors.appendChild(body);
					this.core.body.wrap.appendChild(this.core.body.errors);

					document.body.appendChild(this.core.body.wrap);

					// Инициализация переменных для окна с ошибками (12 - это значение gap из div#popup)
					function top(errors) {
						errors.style.setProperty("transition", "0s");
						errors.style.setProperty(
							"--top",
							popup.offsetTop + popup.offsetHeight + 12 + "px"
						);
						setTimeout(() => errors.style.removeProperty("transition"), 100);
					}
					top(this.core.body.errors);
					const resize = new ResizeObserver(() => top(this.core.body.errors));
					resize.observe(this.core.body.wrap);

					// Инициалиация маски идентификатора сотрудника
					IMask(input, { mask: "000000000" });

					// Инициализация функции закрытия всплывающего окна
					const click = () => {
						// Блокировка
						if (this.core.freeze) return;

						// Удаление всплывающего окна
						this.core.body.wrap.remove();

						// Инициализация буфера выбранных строк
						const buffer = [
							...document.querySelectorAll('div[data-selected="true"]'),
						];

						// Удаление статуса активной строки у остальных строк
						for (const element of buffer) {
							element.removeAttribute("data-selected");
						}

						// Деинициализация быстрых действий по кнопкам
						document.removeEventListener("keydown", this.core.buttons);

						// Сброс блокировки
						this.core.freeze = false;
					};

					// Инициализация функции добавления функции закрытия всплывающего окна
					const enable = () =>
						this.core.body.wrap.addEventListener("click", click);

					// Инициализация функции удаления функции закрытия всплывающего окна
					const disable = () =>
						this.core.body.wrap.removeEventListener("click", click);

					// Первичная активация функции удаления всплывающего окна
					enable();

					// Инициализация блокировки удаления окна при взаимодействии с select-элементом
					for (const select of popup.getElementsByTagName("select")) {
						// Перебор всех select-элементов

						// Инициализация функции блокировки удаления окна по событию
						select.addEventListener("click", () => {
							// Блокировка удаления окна
							this.core.freeze = true;

							// Разблокировка удаления окна
							setTimeout(() => (this.core.freeze = false), 100);
						});

						for (const option of select.getElementsByTagName("option")) {
							// Перебор всех option-элементов

							// Инициализация функции блокировки удаления окна по событию
							option.addEventListener("click", () => {
								// Блокировка удаления окна
								this.core.freeze = true;

								// Разблокировка удаления окна
								setTimeout(() => (this.core.freeze = false), 100);
							});
						}
					}

					// Инициализация блокировки удаления окна при взаимодействии с textarea-элементом
					for (const textarea of popup.getElementsByTagName("textarea")) {
						// Перебор всех textarea-элементов

						// Обновлять позицию окна с ошибками при изменении размера textarea (там position: absolute)
						new MutationObserver(() => top(this.core.body.errors)).observe(
							textarea,
							{
								attributes: true,
								attributeFilter: ["style"],
							}
						);

						// Инициализация функции игнорирования блокировки для выбранных кнопок
						textarea.addEventListener("keydown", (e) => {
							if (e.keyCode === 27) {
								// Нажата кнопка: "escape"

								// Вызов глобальной функции управления кнопками
								this.core.buttons(e, true);
							} else if (e.ctrlKey && e.keyCode === 13) {
								// Нажаты кнопки: "control", "enter"

								// Вызов глобальной функции управления кнопками
								this.core.buttons(e, true);
							}
						});

						// Добавление функции блокировки удаления окна и клавиш по событиям
						textarea.addEventListener("focus", () => (this.core.freeze = true));
						textarea.addEventListener(
							"focusout",
							() => (this.core.freeze = false)
						);
					}

					// Инициализация функции управления кнопками
					this.core.buttons = (e, force = false) => {
						// Блокировка
						if (!force && this.core.freeze) return;

						if (e.keyCode === 27) {
							// Нажата кнопка: "escape"

							// Удаление окна
							click();
						} else if (event.keyCode === 13) {
							// Нажата кнопка: "enter"

							// Инициализация буфера с текущим статусом блокировки закрытия окна
							const freeze = this.core.freeze;

							// Блокировка закрытия окна (чтобы не вызвался click() через событие onclick)
							this.core.freeze = true;

							// Активация виртуальной кнопки "назначить"
							connect.click();

							// Возвращение статуса блокировки закрытия окна
							this.core.freeze = freeze;
						}
					};

					// Инициализация быстрых действий по кнопкам
					document.addEventListener("keydown", this.core.buttons);

					// Добавление функции удаления всплывающего окна по событиям
					popup.addEventListener("mouseenter", disable);
					popup.addEventListener("mouseleave", enable);

					// Фокусировка
					input.focus();
				}
			}

			/**
			 * Обновить
			 *
			 * @param {HTMLElement} row Строка
			 * @param {HTMLElement} input Поле для ввода идентификатора сотрудника
			 * @param {HTMLElement} button Кнопка
			 *
			 * @return {void}
			 */
			static update(row, input, button) {
				// Блокировка поля ввода
				input.setAttribute("readonly", true);
				button.setAttribute("disabled", true);

				// Деинициализация индикатора и анимации об ошибке
				input.classList.remove("error");
				input.previousElementSibling.classList.remove("error");

				// Сброс анимации
				this.core.body.errors.classList.add("hidden");

				// Запуск выполнения
				this._update(row, input, button);
			}

			/**
			 * Обновить (системное)
			 *
			 * @param {HTMLElement} row Строка
			 * @param {HTMLElement} input Поле для ввода идентификатора сотрудника
			 * @param {HTMLElement} button Кнопка
			 *
			 * @return {void}
			 */
			static _update = damper(async (row, input, button) => {
				if (
					row instanceof HTMLElement &&
					input instanceof HTMLElement &&
					button instanceof HTMLElement
				) {
					// Получена строка, поле для ввода и кнопка

					// Инициализация идентификатора строки
					const id = row.getAttribute("id");

					if (typeof id === "string") {
						// Инициализирован идентификатор

						// Инициализация функции разблокировки
						function unblock() {
							// Разблокировка поля ввода
							input.removeAttribute("readonly");
							button.removeAttribute("disabled");
						}

						// Запуск отсрочки разблокировки на случай, если сервер не отвечает
						const timeout = setTimeout(() => {
							this.core.errors(["Сервер не отвечает"]);
							unblock();
						}, 5000);

						// Запрос к серверу
						return await fetch(`/task/${id}/worker/update`, {
							method: "POST",
							headers: {
								"Content-Type": "application/x-www-form-urlencoded",
							},
							body: `worker=${input.value}`,
						})
							.then((response) => response.json())
							.then((data) => {
								// Удаление отсрочки разблокировки
								clearTimeout(timeout);

								if (this.core.errors(data.errors)) {
									// Сгенерированы ошибки

									// Инициализация отображения ошибки
									input.classList.add("error");
									input.previousElementSibling.classList.add("error");

									// Фокусировка на поле ввода
									input.focus();

									// Разблокировка полей ввода и кнопок
									unblock();
								} else {
									// Не сгенерированы ошибки (подразумевается их отсутствие)

									if (data.updated) {
										// Записано обновление

										// Инициализация буфера списка классов
										// const buffer = [...row.classList];

										// Инициализация статуса активной строки
										const selected = row.getAttribute("data-selected");

										// Реинициализация строки
										row.outerHTML = data.row;

										// Реинициализация строки (выражение странное, но правильное)
										row = document.getElementById(row.getAttribute("id"));

										// Копирование классов из буфера классов удалённой строки
										// row.classList.add(...buffer);

										// Копирование статуса активной строки
										if (
											typeof selected === "string" &&
											selected === "true" &&
											document.body.contains(
												document.getElementById("popup")
											) &&
											!document.body.contains(
												document.querySelector('[data-selected="true"]')
											)
										) {
											row.setAttribute("data-selected", "true");
										}
									}

									if (this.core.body.wrap instanceof HTMLElement) {
										// Найдено активное окно

										// Деинициализация быстрых действий по кнопкам
										document.removeEventListener("keydown", this.core.buttons);

										// Сброс блокировки
										this.core.freeze = false;

										// Реинициализация активного окна
										tasks.worker.popup(row);
									}
								}
							});
					}
				}
			}, 300);

			/**
			 * Удалить
			 *
			 * @param {HTMLElement} row Строка
			 * @param {HTMLElement} button Кнопка
			 *
			 * @return {void}
			 */
			static remove(row, button) {
				// Запуск выполнения
				this._remove(row, button);
			}

			/**
			 * Удалить (системное)
			 *
			 * @param {HTMLElement} row Строка
			 * @param {HTMLElement} button Кнопка
			 *
			 * @return {void}
			 */
			static _remove = damper(async (row, button) => {
				if (row instanceof HTMLElement && button instanceof HTMLElement) {
					// Получена строка и кнопка

					// Инициализация идентификатора строки
					const id = row.getAttribute("id");

					if (typeof id === "string") {
						// Инициализирован идентификатор

						// Запуск отсрочки разблокировки на случай, если сервер не отвечает
						const timeout = setTimeout(() => {
							this.core.errors(["Сервер не отвечает"]);
							unblock();
						}, 5000);

						// Запрос к серверу
						return await fetch(`/task/${id}/worker/update`, {
							method: "POST",
							headers: {
								"Content-Type": "application/x-www-form-urlencoded",
							},
							body: `worker=delete`,
						})
							.then((response) => response.json())
							.then((data) => {
								// Удаление отсрочки разблокировки
								clearTimeout(timeout);

								if (this.core.errors(data.errors)) {
									// Сгенерированы ошибки
								} else {
									// Не сгенерированы ошибки (подразумевается их отсутствие)

									if (data.updated) {
										// Записано обновление

										// Инициализация буфера списка классов
										// const buffer = [...row.classList];

										// Инициализация статуса активной строки
										const selected = row.getAttribute("data-selected");

										// Реинициализация строки
										row.outerHTML = data.row;

										// Реинициализация строки (выражение странное, но правильное)
										row = document.getElementById(row.getAttribute("id"));

										// Копирование классов из буфера классов удалённой строки
										// row.classList.add(...buffer);

										// Копирование статуса активной строки
										if (
											typeof selected === "string" &&
											selected === "true" &&
											document.body.contains(
												document.getElementById("popup")
											) &&
											!document.body.contains(
												document.querySelector('[data-selected="true"]')
											)
										) {
											row.setAttribute("data-selected", "true");
										}
									}

									if (this.core.body.wrap instanceof HTMLElement) {
										// Найдено активное окно

										// Деинициализация быстрых действий по кнопкам
										document.removeEventListener("keydown", this.core.buttons);

										// Сброс блокировки
										this.core.freeze = false;

										// Реинициализация активного окна
										tasks.worker.popup(row);
									}
								}
							});
					}
				}
			}, 300);

			/**
			 * Опубликовать
			 *
			 * @param {HTMLElement} row Строка
			 * @param {HTMLElement} button Кнопка
			 *
			 * @return {void}
			 */
			static publish(row, button) {
				// Запуск выполнения
				this._publish(row, button);
			}

			/**
			 * Опубликовать (системное)
			 *
			 * @param {HTMLElement} row Строка
			 * @param {HTMLElement} button Кнопка
			 *
			 * @return {void}
			 */
			static _publish = damper(async (row, button) => {
				if (row instanceof HTMLElement && button instanceof HTMLElement) {
					// Получена строка и кнопка

					// Инициализация идентификатора строки
					const id = row.getAttribute("id");

					if (typeof id === "string") {
						// Инициализирован идентификатор

						// Запуск отсрочки разблокировки на случай, если сервер не отвечает
						const timeout = setTimeout(() => {
							this.core.errors(["Сервер не отвечает"]);
							unblock();
						}, 5000);

						// Запрос к серверу
						return await fetch(`/task/${id}/publish`, {
							method: "POST",
							headers: {
								"Content-Type": "application/x-www-form-urlencoded",
							},
						})
							.then((response) => response.json())
							.then((data) => {
								// Удаление отсрочки разблокировки
								clearTimeout(timeout);

								if (this.core.errors(data.errors)) {
									// Сгенерированы ошибки
								} else {
									// Не сгенерированы ошибки (подразумевается их отсутствие)

									if (data.published) {
										// Опубликована заявка

										// Инициализация буфера списка классов
										// const buffer = [...row.classList];

										// Инициализация статуса активной строки
										const selected = row.getAttribute("data-selected");

										// Инициализация идентификатора строки
										const id = row.getAttribute("id");

										// Реинициализация строки
										row.outerHTML = data.row;

										// Реинициализация строки (выражение странное, но правильное)
										row = document.getElementById(id);

										// Копирование классов из буфера классов удалённой строки и добавление соответствующего
										// row.classList.add(...buffer, "published");
										row.classList.add("published");

										// Копирование статуса активной строки
										if (
											typeof selected === "string" &&
											selected === "true" &&
											document.body.contains(
												document.getElementById("popup")
											) &&
											!document.body.contains(
												document.querySelector('[data-selected="true"]')
											)
										) {
											row.setAttribute("data-selected", "true");
										}

										// Запись текста состояния кнопки
										button.innerText = "Снять с публикации";

										// Реинициализация стиля кнопки
										button.classList.remove("sea");
										button.classList.add("clay");

										// Инициализация вызова функции: "снять с публикации"
										button.setAttribute(
											"onclick",
											`tasks.worker.unpublish(document.getElementById('${id}'), this)`
										);

										// Инициализация оболочки элементов для блокировки
										const wrap =
											button.parentElement.parentElement.previousElementSibling
												.children[0];

										// Блокировка поля для ввода сотрудника
										wrap
											.getElementsByTagName("input")[0]
											.setAttribute("readonly", "true");

										// Блокировка кнопки назначения сотрудника
										wrap
											.getElementsByTagName("button")[0]
											.setAttribute("disabled", "true");
									}
								}
							});
					}
				}
			}, 300);

			/**
			 * Снять с публикации
			 *
			 * @param {HTMLElement} row Строка
			 * @param {HTMLElement} button Кнопка
			 *
			 * @return {void}
			 */
			static unpublish(row, button) {
				// Запуск выполнения
				this._unpublish(row, button);
			}

			/**
			 * Снять с публикации (системное)
			 *
			 * @param {HTMLElement} row Строка
			 * @param {HTMLElement} button Кнопка
			 *
			 * @return {void}
			 */
			static _unpublish = damper(async (row, button) => {
				if (row instanceof HTMLElement && button instanceof HTMLElement) {
					// Получена строка и кнопка

					// Инициализация идентификатора строки
					const id = row.getAttribute("id");

					if (typeof id === "string") {
						// Инициализирован идентификатор

						// Запуск отсрочки разблокировки на случай, если сервер не отвечает
						const timeout = setTimeout(() => {
							this.core.errors(["Сервер не отвечает"]);
							unblock();
						}, 5000);

						// Запрос к серверу
						return await fetch(`/task/${id}/unpublish`, {
							method: "POST",
							headers: {
								"Content-Type": "application/x-www-form-urlencoded",
							},
						})
							.then((response) => response.json())
							.then((data) => {
								// Удаление отсрочки разблокировки
								clearTimeout(timeout);

								if (this.core.errors(data.errors)) {
									// Сгенерированы ошибки
								} else {
									// Не сгенерированы ошибки (подразумевается их отсутствие)

									if (data.unpublished) {
										// Снята с публикации заявка

										// Инициализация буфера списка классов
										// const buffer = [...row.classList];

										// Инициализация статуса активной строки
										const selected = row.getAttribute("data-selected");

										// Реинициализация строки
										row.outerHTML = data.row;

										// Реинициализация строки (выражение странное, но правильное)
										row = document.getElementById(row.getAttribute("id"));

										// Копирование классов из буфера классов удалённой строки и добавление соответствующего
										// row.classList.add(...buffer, "published");
										// row.classList.add("published");

										// Удаление класса неактуального состояния
										// row.classList.remove("published");

										// Копирование статуса активной строки
										if (
											typeof selected === "string" &&
											selected === "true" &&
											document.body.contains(
												document.getElementById("popup")
											) &&
											!document.body.contains(
												document.querySelector('[data-selected="true"]')
											)
										) {
											row.setAttribute("data-selected", "true");
										}

										// Запись текста состояния кнопки
										button.innerText = "Опубликовать";

										// Реинициализация стиля кнопки
										button.classList.remove("clay");
										button.classList.add("sea");

										// Инициализация вызова функции: "опубликовать"
										button.setAttribute(
											"onclick",
											`tasks.worker.publish(document.getElementById('${id}'), this)`
										);

										// Инициализация оболочки элементов для разблокировки
										const wrap =
											button.parentElement.parentElement.previousElementSibling
												.children[0];

										// Разблокировка поля для ввода сотрудника
										wrap
											.getElementsByTagName("input")[0]
											.removeAttribute("readonly");

										// Разблокировка кнопки назначения сотрудника
										wrap
											.getElementsByTagName("button")[0]
											.removeAttribute("disabled");
									}
								}
							});
					}
				}
			}, 300);
		};

		/**
		 * Магазин
		 */
		static market = class {
			/**
			 * Ссылка на ядро (родительский класс)
			 */
			static core;

			/**
			 * Сгенерировать всплывающее окно c данными магазина
			 *
			 * @param {HTMLElement} row Строка
			 *
			 * @return {void}
			 */
			static async popup(row) {
				if (
					row instanceof HTMLElement &&
					typeof core === "function" &&
					core.interface !== "market" &&
					core.interface !== "worker"
				) {
					// Получена строка и аккаунт не является магазином или сотрудником

					// Инициализация идентификатора магазина
					const market = row.querySelector(
						'span[data-column="market"]'
					).innerText;

					if (market.length > 0) {
						// Инициализирован идентификатор магазина

						// Инициализация идентификатора строки
						const task = row.getAttribute("id");

						if (task.length > 0) {
							// Инициализирован идентификатор строки

							// Запрос к серверу
							return await fetch(`/market/${market}/read`, {
								method: "POST",
								headers: {
									"Content-Type": "application/x-www-form-urlencoded",
								},
							})
								.then((response) => response.json())
								.then((data) => {
									if (this.core.errors(data.errors)) {
										// Сгенерированы ошибки
									} else {
										// Не сгенерированы ошибки (подразумевается их отсутствие)

										if (data.market.length > 0) {
											// Получены данные (подразумевается, что сотрудник найден)

											// Инициализация буфера выбранных строк
											const buffer = [
												...document.querySelectorAll(
													'div[data-selected="true"]'
												),
											];

											// Удаление статуса активной строки у остальных строк
											for (const element of buffer) {
												element.removeAttribute("data-selected");
											}

											// Инициализация статуса активной строки (обрабатываемой в данный момент)
											row.setAttribute("data-selected", "true");

											// Инициализация оболочки всплывающего окна
											this.core.body.wrap = document.createElement("div");
											this.core.body.wrap.setAttribute("id", "popup");

											// Инициализация всплывающего окна
											const popup = document.createElement("section");
											popup.classList.add("window", "list", "small");

											// Инициализация заголовка всплывающего окна
											const title = document.createElement("h3");
											title.classList.add("unselectable");
											title.innerText = market;

											// Инициализация оболочки с основной информацией
											const main = document.createElement("section");
											main.classList.add("main");

											// Инициализация колонки
											const column = document.createElement("div");
											column.classList.add("column");

											// Инициализация буфера для записи во всплывающее окно
											const list = document.createElement("div");

											// Инициализация оболочки для кнопок
											const buttons = document.createElement("div");
											buttons.classList.add("row", "buttons");

											// Инициализация оболочки для строки с полем ввода
											const label = document.createElement("label");

											// Инициализация иконки для поля ввода замены
											const icon = document.createElement("i");
											icon.classList.add("icon", "shopping", "cart");

											// Инициализация поля ввода замены
											const input = document.createElement("input");
											input.classList.add("cloud");
											input.setAttribute("placeholder", "Магазин");
											input.setAttribute("autocomplete", "username");
											input.setAttribute("autofocus", "true");
											input.setAttribute("title", "Идентификатор магазина");
											input.setAttribute("list", "popup_market_datalist");

											// Инициализация кнопки смены
											const replace = document.createElement("button");
											replace.classList.add("sea");
											replace.innerText = "Заменить";
											replace.setAttribute(
												"onclick",
												`tasks.market.update(document.getElementById('${task}'), this.previousElementSibling, this)`
											);

											// Инициализация списка сотружников
											const datalist = document.createElement("datalist");
											datalist.setAttribute("id", "popup_market_datalist");
											markets
												.list()
												.then((html) => (datalist.innerHTML = html));

											// Инициализация кнопки удаления
											const remove = document.createElement("button");
											remove.classList.add("clay");
											remove.innerText = "Удалить";
											remove.setAttribute(
												"onclick",
												`tasks.market.remove(document.getElementById('${task}'), this)`
											);

											// Инициализация окна с ошибками
											this.core.body.errors = document.createElement("section");
											this.core.body.errors.classList.add(
												"errors",
												"window",
												"list",
												"small",
												"hidden"
											);
											this.core.body.errors.setAttribute("data-errors", true);

											// Инициализация элемента-тела (оболочки) окна с ошибками
											const body = document.createElement("section");
											body.classList.add("body");

											// Инициализация элемента-списка ошибок
											const dl = document.createElement("dl");

											// Инициализация активного всплывающего окна
											const old = document.getElementById("popup");

											if (old instanceof HTMLElement) {
												// Найдено активное окно

												// Деинициализация быстрых действий по кнопкам
												document.removeEventListener(
													"keydown",
													this.core.buttons
												);

												// Сброс блокировки
												this.core.freeze = false;

												// Удаление активного окна
												old.remove();
											}

											// Запись в документ
											popup.appendChild(title);

											label.appendChild(icon);
											label.appendChild(input);
											label.appendChild(replace);
											label.appendChild(remove);
											label.appendChild(datalist);
											buttons.appendChild(label);
											column.appendChild(list);
											column.appendChild(buttons);

											main.appendChild(column);
											popup.appendChild(main);
											this.core.body.wrap.appendChild(popup);

											body.appendChild(dl);
											this.core.body.errors.appendChild(body);
											this.core.body.wrap.appendChild(this.core.body.errors);

											document.body.appendChild(this.core.body.wrap);

											// Запись в документ HTML-данных через буфер
											list.outerHTML = data.market;

											// Инициализация переменных для окна с ошибками (12 - это значение gap из div#popup)
											function top(errors) {
												errors.style.setProperty("transition", "0s");
												errors.style.setProperty(
													"--top",
													popup.offsetTop + popup.offsetHeight + 12 + "px"
												);
												setTimeout(
													() => errors.style.removeProperty("transition"),
													100
												);
											}
											top(this.core.body.errors);
											const resize = new ResizeObserver(() =>
												top(this.core.body.errors)
											);
											resize.observe(this.core.body.wrap);

											// Инициалиация маски идентификатора магазина в поле ввода идентификатора магазина
											IMask(input, { mask: "000000000" });

											// Инициализация функции закрытия всплывающего окна
											const click = () => {
												// Блокировка
												if (this.core.freeze) return;

												// Удаление всплывающего окна
												this.core.body.wrap.remove();

												// Инициализация буфера выбранных строк
												const buffer = [
													...document.querySelectorAll(
														'div[data-selected="true"]'
													),
												];

												// Удаление статуса активной строки у остальных строк
												for (const element of buffer) {
													element.removeAttribute("data-selected");
												}

												// Деинициализация быстрых действий по кнопкам
												document.removeEventListener(
													"keydown",
													this.core.buttons
												);

												// Сброс блокировки
												this.core.freeze = false;
											};

											// Инициализация функции добавления функции закрытия всплывающего окна
											const enable = () =>
												this.core.body.wrap.addEventListener("click", click);

											// Инициализация функции удаления функции закрытия всплывающего окна
											const disable = () =>
												this.core.body.wrap.removeEventListener("click", click);

											// Первичная активация функции удаления всплывающего окна
											enable();

											// Инициализация блокировки удаления окна при взаимодействии с select-элементом
											for (const select of popup.getElementsByTagName(
												"select"
											)) {
												// Перебор всех select-элементов

												// Инициализация функции блокировки удаления окна по событию
												select.addEventListener("click", () => {
													// Блокировка удаления окна
													this.core.freeze = true;

													// Разблокировка удаления окна
													setTimeout(() => (this.core.freeze = false), 100);
												});

												for (const option of select.getElementsByTagName(
													"option"
												)) {
													// Перебор всех option-элементов

													// Инициализация функции блокировки удаления окна по событию
													option.addEventListener("click", () => {
														// Блокировка удаления окна
														this.core.freeze = true;

														// Разблокировка удаления окна
														setTimeout(() => (this.core.freeze = false), 100);
													});
												}
											}

											// Инициализация блокировки удаления окна при взаимодействии с textarea-элементом
											for (const textarea of popup.getElementsByTagName(
												"textarea"
											)) {
												// Перебор всех textarea-элементов

												// Обновлять позицию окна с ошибками при изменении размера textarea (там position: absolute)
												new MutationObserver(() =>
													top(this.core.body.errors)
												).observe(textarea, {
													attributes: true,
													attributeFilter: ["style"],
												});

												// Инициализация функции игнорирования блокировки для выбранных кнопок
												textarea.addEventListener("keydown", (e) => {
													if (e.keyCode === 27) {
														// Нажата кнопка: "escape"

														// Вызов глобальной функции управления кнопками
														this.core.buttons(e, true);
													} else if (e.ctrlKey && e.keyCode === 13) {
														// Нажаты кнопки: "control", "enter"

														// Вызов глобальной функции управления кнопками
														this.core.buttons(e, true);
													}
												});

												// Добавление функции блокировки удаления окна и клавиш по событиям
												textarea.addEventListener(
													"focus",
													() => (this.core.freeze = true)
												);
												textarea.addEventListener(
													"focusout",
													() => (this.core.freeze = false)
												);
											}

											// Инициализация функции управления кнопками
											this.core.buttons = (e, force = false) => {
												// Блокировка
												if (!force && this.core.freeze) return;

												if (e.keyCode === 27) {
													// Нажата кнопка: "escape"

													// Удаление окна
													click();
												} else if (event.keyCode === 13) {
													// Нажата кнопка: "enter"

													// Инициализация буфера с текущим статусом блокировки закрытия окна
													const freeze = this.core.freeze;

													// Блокировка закрытия окна (чтобы не вызвался click() через событие onclick)
													this.core.freeze = true;

													// Активация виртуальной кнопки "заменить"
													replace.click();

													// Возвращение статуса блокировки закрытия окна
													this.core.freeze = freeze;
												}
											};

											// Инициализация быстрых действий по кнопкам
											document.addEventListener("keydown", this.core.buttons);

											// Добавление функции удаления всплывающего окна по событиям
											popup.addEventListener("mouseenter", disable);
											popup.addEventListener("mouseleave", enable);

											// Фокусировка
											input.focus();
										} else {
											// Не получены данные (подразумевается, что магазин не найден)

											// Открытие окна инициализации магазина
											this.init(row);
										}
									}
								});
						}
					} else {
						// Не инициализирован идентификатор магазина

						// Открытие окна инициализации магазина
						this.init(row);
					}
				}
			}

			static init(row) {
				// Инициализация идентификатора строки
				const task = row.getAttribute("id");

				if (task.length > 0) {
					// Инициализирован идентификатор строки

					// Инициализация буфера выбранных строк
					const buffer = [
						...document.querySelectorAll('div[data-selected="true"]'),
					];

					// Удаление статуса активной строки у остальных строк
					for (const element of buffer) {
						element.removeAttribute("data-selected");
					}

					// Инициализация статуса активной строки (Магазин обрабатываемой в данный момент)
					row.setAttribute("data-selected", "true");

					// Инициализация оболочки всплывающего окна
					this.core.body.wrap = document.createElement("div");
					this.core.body.wrap.setAttribute("id", "popup");

					// Инициализация всплывающего окна
					const popup = document.createElement("section");
					popup.classList.add("window", "list", "small");

					// Инициализация оболочки с основной информацией
					const main = document.createElement("section");
					main.classList.add("main");

					// Инициализация колонки
					const column = document.createElement("div");
					column.classList.add("column");

					// Инициализация оболочки для кнопок
					const buttons = document.createElement("div");
					buttons.classList.add("row", "buttons");

					// Инициализация оболочки для строки с полем ввода
					const label = document.createElement("label");

					// Инициализация иконки для поля ввода замены
					const icon = document.createElement("i");
					icon.classList.add("icon", "shopping", "cart");

					// Инициализация поля ввода замены
					const input = document.createElement("input");
					input.classList.add("cloud");
					input.setAttribute("placeholder", "Магазин");
					input.setAttribute("autocomplete", "username");
					input.setAttribute("autofocus", "true");
					input.setAttribute("title", "Идентификатор магазина");
					input.setAttribute("list", "popup_market_datalist");

					// Инициализация кнопки замены
					const connect = document.createElement("button");
					connect.classList.add("grass");
					connect.innerText = "Назначить";
					connect.setAttribute(
						"onclick",
						`tasks.market.update(document.getElementById('${task}'), this.previousElementSibling, this)`
					);

					// Инициализация списка сотружников
					const datalist = document.createElement("datalist");
					datalist.setAttribute("id", "popup_market_datalist");
					markets.list().then((html) => (datalist.innerHTML = html));

					// Инициализация окна с ошибками
					this.core.body.errors = document.createElement("section");
					this.core.body.errors.classList.add(
						"errors",
						"window",
						"list",
						"small",
						"hidden"
					);
					this.core.body.errors.setAttribute("data-errors", true);

					// Инициализация элемента-тела (оболочки) окна с ошибками
					const body = document.createElement("section");
					body.classList.add("body");

					// Инициализация элемента-списка ошибок
					const dl = document.createElement("dl");

					// Инициализация активного всплывающего окна
					const old = document.getElementById("popup");

					if (old instanceof HTMLElement) {
						// Найдено активное окно

						// Деинициализация быстрых действий по кнопкам
						document.removeEventListener("keydown", this.core.buttons);

						// Сброс блокировки
						this.core.freeze = false;

						// Удаление активного окна
						old.remove();
					}

					// Запись в документ
					label.appendChild(icon);
					label.appendChild(input);
					label.appendChild(connect);
					label.appendChild(datalist);
					buttons.appendChild(label);
					column.appendChild(buttons);

					main.appendChild(column);
					popup.appendChild(main);
					this.core.body.wrap.appendChild(popup);

					body.appendChild(dl);
					this.core.body.errors.appendChild(body);
					this.core.body.wrap.appendChild(this.core.body.errors);

					document.body.appendChild(this.core.body.wrap);

					// Инициализация переменных для окна с ошибками (12 - это значение gap из div#popup)
					function top(errors) {
						errors.style.setProperty("transition", "0s");
						errors.style.setProperty(
							"--top",
							popup.offsetTop + popup.offsetHeight + 12 + "px"
						);
						setTimeout(() => errors.style.removeProperty("transition"), 100);
					}
					top(this.core.body.errors);
					const resize = new ResizeObserver(() => top(this.core.body.errors));
					resize.observe(this.core.body.wrap);

					// Инициалиация маски идентификатора магазина
					IMask(input, { mask: "000000000" });

					// Инициализация функции закрытия всплывающего окна
					const click = () => {
						// Блокировка
						if (this.core.freeze) return;

						// Удаление всплывающего окна
						this.core.body.wrap.remove();

						// Инициализация буфера выбранных строк
						const buffer = [
							...document.querySelectorAll('div[data-selected="true"]'),
						];

						// Удаление статуса активной строки у остальных строк
						for (const element of buffer) {
							element.removeAttribute("data-selected");
						}

						// Деинициализация быстрых действий по кнопкам
						document.removeEventListener("keydown", this.core.buttons);

						// Сброс блокировки
						this.core.freeze = false;
					};

					// Инициализация функции добавления функции закрытия всплывающего окна
					const enable = () =>
						this.core.body.wrap.addEventListener("click", click);

					// Инициализация функции удаления функции закрытия всплывающего окна
					const disable = () =>
						this.core.body.wrap.removeEventListener("click", click);

					// Первичная активация функции удаления всплывающего окна
					enable();

					// Инициализация блокировки удаления окна при взаимодействии с select-элементом
					for (const select of popup.getElementsByTagName("select")) {
						// Перебор всех select-элементов

						// Инициализация функции блокировки удаления окна по событию
						select.addEventListener("click", () => {
							// Блокировка удаления окна
							this.core.freeze = true;

							// Разблокировка удаления окна
							setTimeout(() => (this.core.freeze = false), 100);
						});

						for (const option of select.getElementsByTagName("option")) {
							// Перебор всех option-элементов

							// Инициализация функции блокировки удаления окна по событию
							option.addEventListener("click", () => {
								// Блокировка удаления окна
								this.core.freeze = true;

								// Разблокировка удаления окна
								setTimeout(() => (this.core.freeze = false), 100);
							});
						}
					}

					// Инициализация блокировки удаления окна при взаимодействии с textarea-элементом
					for (const textarea of popup.getElementsByTagName("textarea")) {
						// Перебор всех textarea-элементов

						// Обновлять позицию окна с ошибками при изменении размера textarea (там position: absolute)
						new MutationObserver(() => top(this.core.body.errors)).observe(
							textarea,
							{
								attributes: true,
								attributeFilter: ["style"],
							}
						);

						// Инициализация функции игнорирования блокировки для выбранных кнопок
						textarea.addEventListener("keydown", (e) => {
							if (e.keyCode === 27) {
								// Нажата кнопка: "escape"

								// Вызов глобальной функции управления кнопками
								this.core.buttons(e, true);
							} else if (e.ctrlKey && e.keyCode === 13) {
								// Нажаты кнопки: "control", "enter"

								// Вызов глобальной функции управления кнопками
								this.core.buttons(e, true);
							}
						});

						// Добавление функции блокировки удаления окна и клавиш по событиям
						textarea.addEventListener("focus", () => (this.core.freeze = true));
						textarea.addEventListener(
							"focusout",
							() => (this.core.freeze = false)
						);
					}

					// Инициализация функции управления кнопками
					this.core.buttons = (e, force = false) => {
						// Блокировка
						if (!force && this.core.freeze) return;

						if (e.keyCode === 27) {
							// Нажата кнопка: "escape"

							// Удаление окна
							click();
						} else if (event.keyCode === 13) {
							// Нажата кнопка: "enter"

							// Инициализация буфера с текущим статусом блокировки закрытия окна
							const freeze = this.core.freeze;

							// Блокировка закрытия окна (чтобы не вызвался click() через событие onclick)
							this.core.freeze = true;

							// Активация виртуальной кнопки "назначить"
							connect.click();

							// Возвращение статуса блокировки закрытия окна
							this.core.freeze = freeze;
						}
					};

					// Инициализация быстрых действий по кнопкам
					document.addEventListener("keydown", this.core.buttons);

					// Добавление функции удаления всплывающего окна по событиям
					popup.addEventListener("mouseenter", disable);
					popup.addEventListener("mouseleave", enable);

					// Фокусировка
					input.focus();
				}
			}

			/**
			 * Обновить
			 *
			 * @param {HTMLElement} row Строка
			 * @param {HTMLElement} input Поле для ввода идентификатора магазина
			 * @param {HTMLElement} button Кнопка
			 *
			 * @return {void}
			 */
			static update(row, input, button) {
				// Блокировка поля ввода
				input.setAttribute("readonly", true);
				button.setAttribute("disabled", true);

				// Деинициализация индикатора и анимации об ошибке
				input.classList.remove("error");
				input.previousElementSibling.classList.remove("error");

				// Сброс анимации
				this.core.body.errors.classList.add("hidden");

				// Запуск выполнения
				this._update(row, input, button);
			}

			/**
			 * Обновить (системное)
			 *
			 * @param {HTMLElement} row Строка
			 * @param {HTMLElement} input Поле для ввода идентификатора магазина
			 * @param {HTMLElement} button Кнопка
			 *
			 * @return {void}
			 */
			static _update = damper(async (row, input, button) => {
				if (
					row instanceof HTMLElement &&
					input instanceof HTMLElement &&
					button instanceof HTMLElement
				) {
					// Получена строка, поле для ввода и кнопка

					// Инициализация идентификатора строки
					const id = row.getAttribute("id");

					if (typeof id === "string") {
						// Инициализирован идентификатор

						// Инициализация функции разблокировки
						function unblock() {
							// Разблокировка поля ввода
							input.removeAttribute("readonly");
							button.removeAttribute("disabled");
						}

						// Запуск отсрочки разблокировки на случай, если сервер не отвечает
						const timeout = setTimeout(() => {
							this.core.errors(["Сервер не отвечает"]);
							unblock();
						}, 5000);

						// Запрос к серверу
						return await fetch(`/task/${id}/market/update`, {
							method: "POST",
							headers: {
								"Content-Type": "application/x-www-form-urlencoded",
							},
							body: `market=${input.value}`,
						})
							.then((response) => response.json())
							.then((data) => {
								// Удаление отсрочки разблокировки
								clearTimeout(timeout);

								if (this.core.errors(data.errors)) {
									// Сгенерированы ошибки

									// Инициализация отображения ошибки
									input.classList.add("error");
									input.previousElementSibling.classList.add("error");

									// Фокусировка на поле ввода
									input.focus();

									// Разблокировка полей ввода и кнопок
									unblock();
								} else {
									// Не сгенерированы ошибки (подразумевается их отсутствие)

									if (data.updated) {
										// Записано обновление

										// Инициализация буфера списка классов
										// const buffer = [...row.classList];

										// Инициализация статуса активной строки
										const selected = row.getAttribute("data-selected");

										// Реинициализация строки
										row.outerHTML = data.row;

										// Реинициализация строки (выражение странное, но правильное)
										row = document.getElementById(row.getAttribute("id"));

										// Копирование классов из буфера классов удалённой строки
										// row.classList.add(...buffer);

										// Копирование статуса активной строки
										if (
											typeof selected === "string" &&
											selected === "true" &&
											document.body.contains(
												document.getElementById("popup")
											) &&
											!document.body.contains(
												document.querySelector('[data-selected="true"]')
											)
										) {
											row.setAttribute("data-selected", "true");
										}
									}

									if (this.core.body.wrap instanceof HTMLElement) {
										// Найдено активное окно

										// Деинициализация быстрых действий по кнопкам
										document.removeEventListener("keydown", this.core.buttons);

										// Сброс блокировки
										this.core.freeze = false;

										// Реинициализация активного окна
										tasks.market.popup(row);
									}
								}
							});
					}
				}
			}, 300);

			/**
			 * Удалить
			 *
			 * @param {HTMLElement} row Строка
			 * @param {HTMLElement} button Кнопка
			 *
			 * @return {void}
			 */
			static remove(row, button) {
				// Запуск выполнения
				this._remove(row, button);
			}

			/**
			 * Удалить (системное)
			 *
			 * @param {HTMLElement} row Строка
			 * @param {HTMLElement} button Кнопка
			 *
			 * @return {void}
			 */
			static _remove = damper(async (row, button) => {
				if (row instanceof HTMLElement && button instanceof HTMLElement) {
					// Получена строка и кнопка

					// Инициализация идентификатора строки
					const id = row.getAttribute("id");

					if (typeof id === "string") {
						// Инициализирован идентификатор

						// Запуск отсрочки разблокировки на случай, если сервер не отвечает
						const timeout = setTimeout(() => {
							this.core.errors(["Сервер не отвечает"]);
							unblock();
						}, 5000);

						// Запрос к серверу
						return await fetch(`/task/${id}/market/update`, {
							method: "POST",
							headers: {
								"Content-Type": "application/x-www-form-urlencoded",
							},
							body: `market=delete`,
						})
							.then((response) => response.json())
							.then((data) => {
								// Удаление отсрочки разблокировки
								clearTimeout(timeout);

								if (this.core.errors(data.errors)) {
									// Сгенерированы ошибки

									// Разблокировка полей ввода и кнопок
									unblock();
								} else {
									// Не сгенерированы ошибки (подразумевается их отсутствие)

									if (data.updated) {
										// Записано обновление

										// Инициализация буфера списка классов
										// const buffer = [...row.classList];

										// Инициализация статуса активной строки
										const selected = row.getAttribute("data-selected");

										// Реинициализация строки
										row.outerHTML = data.row;

										// Реинициализация строки (выражение странное, но правильное)
										row = document.getElementById(row.getAttribute("id"));

										// Копирование классов из буфера классов удалённой строки
										// row.classList.add(...buffer);

										// Копирование статуса активной строки
										if (
											typeof selected === "string" &&
											selected === "true" &&
											document.body.contains(
												document.getElementById("popup")
											) &&
											!document.body.contains(
												document.querySelector('[data-selected="true"]')
											)
										) {
											row.setAttribute("data-selected", "true");
										}
									}

									if (this.core.body.wrap instanceof HTMLElement) {
										// Найдено активное окно

										// Деинициализация быстрых действий по кнопкам
										document.removeEventListener("keydown", this.core.buttons);

										// Сброс блокировки
										this.core.freeze = false;

										// Реинициализация активного окна
										tasks.market.popup(row);
									}
								}
							});
					}
				}
			}, 300);
		};

		/**
		 * Комментарий
		 */
		static commentary = class {
			/**
			 * Ссылка на ядро (родительский класс)
			 */
			static core;

			/**
			 * Сгенерировать всплывающее окно c комментарием задачи
			 *
			 * @param {HTMLElement} row Строка
			 *
			 * @return {void}
			 */
			static popup = damper((row) => {
				if (
					row instanceof HTMLElement &&
					typeof core === "function" &&
					core.interface !== "market" &&
					core.interface !== "worker"
				) {
					// Получена строка и аккаунт не является магазином или сотрудником

					// Инициализация идентификатора сотрудника
					const task = row.getAttribute("id");

					// Инициализация буфера выбранных строк
					const buffer = [
						...document.querySelectorAll('div[data-selected="true"]'),
					];

					// Удаление статуса активной строки у остальных строк
					for (const element of buffer) {
						element.removeAttribute("data-selected");
					}

					// Инициализация статуса активной строки (обрабатываемой в данный момент)
					row.setAttribute("data-selected", "true");

					// Инициализация оболочки всплывающего окна
					this.core.body.wrap = document.createElement("div");
					this.core.body.wrap.setAttribute("id", "popup");

					// Инициализация всплывающего окна
					const popup = document.createElement("section");
					popup.classList.add("list", "small");

					// Инициализация заголовка всплывающего окна
					const title = document.createElement("h3");
					title.innerText = "Комментарий";

					// Инициализация оболочки с основной информацией
					const main = document.createElement("section");
					main.classList.add("main");

					// Инициализация колонки
					const column = document.createElement("div");
					column.classList.add("column");

					// Инициализация строки
					const row_1 = document.createElement("div");
					row_1.classList.add("row", "stretchable");

					// Инициализация оболочки для поля ввода комментария
					const label = document.createElement("label");

					// Инициализация поля ввода комментария
					const textarea = document.createElement("textarea");
					textarea.classList.add("snow");
					this.core
						.value(row, "commentary")
						.then((text) => (textarea.value = text));
					textarea.setAttribute("autofocus", "true");
					textarea.setAttribute("maxlength", "800");
					textarea.setAttribute(
						"onkeyup",
						`tasks.commentary.update(document.getElementById('${task}'), this)`
					);
					textarea.setAttribute("title", "Дополнительная информация");
					textarea.setAttribute(
						"placeholder",
						"Дополнительная информация о заявке"
					);

					// Инициализация окна с ошибками
					this.core.body.errors = document.createElement("section");
					this.core.body.errors.classList.add(
						"errors",
						"window",
						"list",
						"small",
						"hidden"
					);
					this.core.body.errors.setAttribute("data-errors", true);

					// Инициализация элемента-тела (оболочки) окна с ошибками
					const errors = document.createElement("section");
					errors.classList.add("body");

					// Инициализация элемента-списка ошибок
					const dl = document.createElement("dl");

					// Инициализация активного всплывающего окна
					const old = document.getElementById("popup");

					if (old instanceof HTMLElement) {
						// Найдено активное окно

						// Деинициализация быстрых действий по кнопкам
						document.removeEventListener("keydown", this.core.buttons);

						// Сброс блокировки
						this.core.freeze = false;

						// Удаление активного окна
						old.remove();
					}

					// Удаление блокировки выполнения закрытия всплывающего окна
					this.core.freeze = false;

					// Запись в документ
					popup.appendChild(title);

					label.appendChild(textarea);
					row_1.appendChild(label);
					column.appendChild(row_1);

					main.appendChild(column);
					popup.appendChild(main);
					this.core.body.wrap.appendChild(popup);

					errors.appendChild(dl);
					this.core.body.errors.appendChild(errors);
					this.core.body.wrap.appendChild(this.core.body.errors);

					document.body.appendChild(this.core.body.wrap);

					// Инициализация переменных для окна с ошибками (12 - это значение gap из div#popup)
					function top(errors) {
						errors.style.setProperty("transition", "0s");
						errors.style.setProperty(
							"--top",
							popup.offsetTop + popup.offsetHeight + 12 + "px"
						);
						setTimeout(() => errors.style.removeProperty("transition"), 100);
					}
					top(this.core.body.errors);
					const resize = new ResizeObserver(() => top(this.core.body.errors));
					resize.observe(this.core.body.wrap);

					// Инициализация функции закрытия всплывающего окна
					const click = () => {
						// Блокировка
						if (this.core.freeze) return;

						// Удаление всплывающего окна
						this.core.body.wrap.remove();

						// Инициализация буфера выбранных строк
						const buffer = [
							...document.querySelectorAll('div[data-selected="true"]'),
						];

						// Удаление статуса активной строки у остальных строк
						for (const element of buffer) {
							element.removeAttribute("data-selected");
						}

						// Деинициализация быстрых действий по кнопкам
						document.removeEventListener("keydown", this.core.buttons);

						// Сброс блокировки
						this.core.freeze = false;
					};

					// Инициализация функции добавления функции закрытия всплывающего окна
					const enable = () =>
						this.core.body.wrap.addEventListener("click", click);

					// Инициализация функции удаления функции закрытия всплывающего окна
					const disable = () =>
						this.core.body.wrap.removeEventListener("click", click);

					// Первичная активация функции удаления всплывающего окна
					enable();

					// Инициализация блокировки удаления окна при взаимодействии с select-элементом
					for (const select of popup.getElementsByTagName("select")) {
						// Перебор всех select-элементов

						// Инициализация функции блокировки удаления окна по событию
						select.addEventListener("click", () => {
							// Блокировка удаления окна
							this.core.freeze = true;

							// Разблокировка удаления окна
							setTimeout(() => (this.core.freeze = false), 100);
						});

						for (const option of select.getElementsByTagName("option")) {
							// Перебор всех option-элементов

							// Инициализация функции блокировки удаления окна по событию
							option.addEventListener("click", () => {
								// Блокировка удаления окна
								this.core.freeze = true;

								// Разблокировка удаления окна
								setTimeout(() => (this.core.freeze = false), 100);
							});
						}
					}

					// Инициализация блокировки удаления окна при взаимодействии с textarea-элементом
					for (const textarea of popup.getElementsByTagName("textarea")) {
						// Перебор всех textarea-элементов

						// Обновлять позицию окна с ошибками при изменении размера textarea (там position: absolute)
						new MutationObserver(() => top(this.core.body.errors)).observe(
							textarea,
							{
								attributes: true,
								attributeFilter: ["style"],
							}
						);

						// Инициализация функции игнорирования блокировки для выбранных кнопок
						textarea.addEventListener("keydown", (e) => {
							if (e.keyCode === 27) {
								// Нажата кнопка: "escape"

								// Вызов глобальной функции управления кнопками
								this.core.buttons(e, true);
							} else if (e.ctrlKey && e.keyCode === 13) {
								// Нажаты кнопки: "control", "enter"

								// Вызов глобальной функции управления кнопками
								this.core.buttons(e, true);
							}
						});

						// Добавление функции блокировки удаления окна и клавиш по событиям
						textarea.addEventListener("focus", () => (this.core.freeze = true));
						textarea.addEventListener(
							"focusout",
							() => (this.core.freeze = false)
						);
					}

					// Инициализация функции управления кнопками
					this.core.buttons = (e, force = false) => {
						// Блокировка
						if (!force && this.core.freeze) return;

						if (e.keyCode === 27) {
							// Нажата кнопка: "escape"

							// Удаление окна
							click();
						}
					};

					// Инициализация быстрых действий по кнопкам
					document.addEventListener("keydown", this.core.buttons);

					// Добавление функции удаления всплывающего окна по событиям
					popup.addEventListener("mouseenter", disable);
					popup.addEventListener("mouseleave", enable);

					// Фокусировка
					textarea.focus();
				}
			}, 300);

			/**
			 * Записать обновление
			 *
			 * @param {HTMLElement} row Строка
			 * @param {HTMLElement} textarea HTML-элемент <textarea>
			 *
			 * @return {void}
			 */
			static update(row, textarea) {
				// Сброс анимации ошибки
				textarea.classList.remove("error");

				// Запуск выполнения
				this._update(row, textarea);
			}

			/**
			 * Записать обновление (системное)
			 *
			 * @param {HTMLElement} row Строка
			 * @param {HTMLElement} textarea HTML-элемент <textarea>
			 *
			 * @return {void}
			 */
			static _update = damper(async (row, textarea) => {
				if (row instanceof HTMLElement && textarea instanceof HTMLElement) {
					// Получена строка и select-элемент

					// Инициализация идентификатора строки
					const id = row.getAttribute("id");

					if (typeof id === "string") {
						// Инициализирован идентификатор

						// Запрос к серверу
						return await fetch(`/task/${id}/commentary`, {
							method: "POST",
							headers: {
								"Content-Type": "application/x-www-form-urlencoded",
							},
							body: `commentary=${textarea.value}`,
						})
							.then((response) => response.json())
							.then((data) => {
								if (this.core.errors(data.errors)) {
									// Сгенерированы ошибки

									// Запись анимации ошибки
									textarea.classList.add("error");
								} else {
									// Не сгенерированы ошибки (подразумевается их отсутствие)

									if (data.writed) {
										// Записано новое значение в базу данных

										// Удаление анимации ошибки
										textarea.classList.remove("error");

										// Инициализация буфера списка классов
										// const buffer = [...row.classList];

										// Инициализация статуса активной строки
										const selected = row.getAttribute("data-selected");

										// Реинициализация строки
										row.outerHTML = data.row;

										// Реинициализация строки (выражение странное, но правильное)
										row = document.getElementById(row.getAttribute("id"));

										// Копирование классов из буфера классов удалённой строки
										// row.classList.add(...buffer);

										// Копирование статуса активной строки
										if (
											typeof selected === "string" &&
											selected === "true" &&
											document.body.contains(
												document.getElementById("popup")
											) &&
											!document.body.contains(
												document.querySelector('[data-selected="true"]')
											)
										) {
											row.setAttribute("data-selected", "true");
										}
									} else {
										// Не записано новое значение в базу данных

										// Запись анимации ошибки
										textarea.classList.add("error");
									}
								}
							});
					}
				}
			}, 300);
		};

		static reinitializer = class {
			/**
			 * Ссылка на ядро (родительский класс)
			 */
			static core;

			/**
			 * Запустить
			 *
			 * @param {HTMLElement|null} target Строка
			 */
			static start(target) {
				// Инициализация оболочки
				const tasks = document.getElementById("tasks");

				for (let row of typeof target === "undefined"
					? tasks.querySelectorAll(':scope > div[data-row="task"]')
					: [target]) {
					// Перебор строк

					// Инициализация номера итерации по умолчанию
					if (typeof row.counter === "undefined") {
						// Не инициализирован счётчик итерации

						row.counter = Math.floor(Math.random() * 280 + 20);
						row.setAttribute("data-counter", row.counter);
					}

					// Инициализация самообновления
					if (typeof row.updater === "undefined") {
						// Не инициализирована функция самообновления

						row.updater = setInterval(() => {
							if (--row.counter <= 0) {
								// Отсчёт таймера завершён

								// Блокировка строки

								// Деинициализация реинициализатора строки (для защиты от повторного запроса)
								this.stop(row);

								// Запись анимации (запуск)
								row.classList.add("reinitialized");

								// Запрос к серверу
								fetch("/tasks/read", {
									method: "POST",
									headers: {
										"Content-Type": "application/x-www-form-urlencoded",
									},
									body: `row=${row.getAttribute("id")}`,
								})
									.then((response) => response.json())
									.then((data) => {
										if (this.core.errors(data.errors, false, false)) {
											// Сгенерированы ошибки
										} else {
											// Не сгенерированы ошибки (подразумевается их отсутствие)

											// Инициализация идентифиатора
											const id = row.getAttribute("id");

											// Инициализация количества непрочитанных сообщений
											const messages = row.lastElementChild.innerText;

											// Инициализация статуса активной строки
											const selected = row.getAttribute("data-selected");

											// Реинициализация строки
											row.outerHTML = data.rows;

											// Реинициализация перезаписанной строки
											row = document.getElementById(id);

											// Копирование статуса активной строки
											if (
												typeof selected === "string" &&
												selected === "true" &&
												document.body.contains(document.getElementById("popup"))
											) {
												row.setAttribute("data-selected", "true");
											}

											// Если непрочитанных сообщений стало больше, то проиграть звук уведомления
											if (row.lastElementChild.innerText > messages) {
												window.notification.play();
											}

											// Инициализация реинициализатора строки (для пересчёта таймера для setInterval)
											if (row instanceof HTMLElement) {
												setTimeout(() => this.start(row), 5000);
											}
										}
									});
							} else row.setAttribute("data-counter", row.counter);
						}, Math.floor(Math.random() * tasks.querySelectorAll(':scope > div[data-row="task"]').length * 200 + 300));
					}
				}
			}

			/**
			 * Остановить
			 *
			 * @param {HTMLElement|null} target Строка
			 */
			static stop(target) {
				// Инициализация оболочки
				const tasks = document.getElementById("tasks");

				for (const row of typeof target === "undefined"
					? tasks.querySelectorAll(':scope > div[data-row="task"]')
					: [target]) {
					// Перебор строк

					// Деинициализация самообновления
					clearInterval(row.updater);

					// Удаление идентификатора
					row.updater = row.counter = undefined;

					// Удаление анимации (сброс)
					row.classList.remove("reinitialized");
				}
			}
		};
	};

	// Инициализация ссылок на ядро
	window.tasks.worker.core =
		window.tasks.market.core =
		window.tasks.commentary.core =
		window.tasks.reinitializer.core =
			window.tasks;
}

// Вызов события: "инициализировано"
document.dispatchEvent(
	new CustomEvent("tasks.initialized", {
		detail: { tasks: window.tasks },
	})
);
