├── icons
└── music_by_pancaza.png
├── SECURITY.md
├── LICENSE
├── manifest_Firefox.json
├── manifest.json
├── js
├── options.js
├── content.js
├── service_worker.js
├── popup.js
└── parser.js
├── readme.md
└── html
├── options.html
├── popup.html
└── bs5
├── browser-id3-writer.6.0.0.mjs
├── bootstrap-grid.min.css
└── bootstrap.bundle.min.js
/icons/music_by_pancaza.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vectorserver/yandex_music_fisher_mod/HEAD/icons/music_by_pancaza.png
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Supported Versions
4 |
5 | Use this section to tell people about which versions of your project are
6 | currently being supported with security updates.
7 |
8 | | Version | Supported |
9 | | ------- | ------------------ |
10 | | 5.1.x | :white_check_mark: |
11 | | 5.0.x | :x: |
12 | | 4.0.x | :white_check_mark: |
13 | | < 4.0 | :x: |
14 |
15 | ## Reporting a Vulnerability
16 |
17 | Use this section to tell people how to report a vulnerability.
18 |
19 | Tell them where to go, how often they can expect to get an update on a
20 | reported vulnerability, what to expect if the vulnerability is accepted or
21 | declined, etc.
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | NEXT Yandex Music Fisher vectorserver
2 |
3 | Copyright (c) [2024] [vectorserver]
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/manifest_Firefox.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_version": 2,
3 | "name": "NEXT Yandex Music Fisher vectorserver",
4 | "version": "2.1.18",
5 | "description": "Скачивание музыки с сервисов Яндекс.Музыка и Яндекс.Радио",
6 | "icons": {
7 | "128": "icons/music_by_pancaza.png"
8 | },
9 | "action": {
10 | "default_icon": "icons/music_by_pancaza.png",
11 | "default_popup": "html/popup.html",
12 | "default_title": "NEXT Yandex Music Fisher mod by vectorserver"
13 | },
14 | "background": {
15 | "scripts": ["js/service_worker.js"],
16 | "persistent": false
17 | },
18 | "content_scripts": [
19 | {
20 | "matches": [
21 | "https://api.music.yandex.ru/*",
22 | "https://next.music.yandex.com/*",
23 | "https://next.music.yandex.kz/*",
24 | "https://next.music.yandex.by/*",
25 | "https://next.music.yandex.uz/*",
26 | "https://*.strm.yandex.net/*",
27 | "https://music.yandex.ru/*",
28 | "https://music.yandex.com/*",
29 | "https://music.yandex.kz/*",
30 | "https://music.yandex.by/*",
31 | "https://music.yandex.uz/*",
32 | "https://yastatic.net/*"
33 | ],
34 | "js": ["js/content.js"]
35 | }
36 | ],
37 | "permissions": [
38 | "tabs",
39 | "downloads",
40 | "webRequest",
41 | "scripting",
42 | "activeTab",
43 | "storage"
44 | ],
45 | "host_permissions": [
46 | "https://*.music.yandex.ru/*"
47 | ],
48 | "incognito": "split",
49 | "options_page": "html/options.html",
50 | "homepage_url": "https://vk.com/vectorserver"
51 | }
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_version": 3,
3 | "name": "NEXT Yandex Music Fisher vectorserver",
4 | "version": "2.1.18",
5 | "description": "Скачивание музыки с сервисов Яндекс.Музыка и Яндекс.Радио",
6 | "icons": {
7 | "128": "icons/music_by_pancaza.png"
8 | },
9 | "action": {
10 | "default_icon": "icons/music_by_pancaza.png",
11 | "default_popup": "html/popup.html",
12 | "default_title": "NEXT Yandex Music Fisher mod by vectorserver"
13 | },
14 | "background": {
15 | "service_worker": "js/service_worker.js"
16 | },
17 | "content_scripts": [
18 | {
19 | "matches": [
20 | "https://api.music.yandex.ru/*",
21 | "https://next.music.yandex.com/*",
22 | "https://next.music.yandex.ru/*",
23 | "https://next.music.yandex.kz/*",
24 | "https://next.music.yandex.by/*",
25 | "https://next.music.yandex.uz/*",
26 | "https://*.strm.yandex.net/*",
27 | "https://music.yandex.ru/*",
28 | "https://music.yandex.com/*",
29 | "https://music.yandex.kz/*",
30 | "https://music.yandex.by/*",
31 | "https://music.yandex.uz/*",
32 | "https://yastatic.net/*"
33 | ],
34 | "js": ["js/content.js"]
35 | }
36 | ],
37 | "permissions": [
38 | "tabs",
39 | "downloads",
40 | "webRequest",
41 | "scripting",
42 | "activeTab",
43 | "storage"
44 | ],
45 | "host_permissions": [
46 | "https://*.music.yandex.ru/*"
47 | ],
48 | "incognito": "split",
49 | "options_page": "html/options.html",
50 | "homepage_url": "https://vk.com/vectorserver",
51 | "update_url": "https://extension-updates.opera.com/api/omaha/update/"
52 | }
53 |
--------------------------------------------------------------------------------
/js/options.js:
--------------------------------------------------------------------------------
1 | document.addEventListener('DOMContentLoaded', async function () {
2 | const form = document.getElementById('settingsForm');
3 | const folderInput = document.getElementById('downloadFolder');
4 | const coverSelect = document.getElementById('coverResolution');
5 | const audioSelect = document.getElementById('audioQuality');
6 | const downlodadCount = document.getElementById('downlodadCount');
7 | const savehistory = document.getElementById('savehistory');
8 | //const checkexists = document.getElementById('checkexists');
9 |
10 | // Восстановление сохраненных настроек
11 | const data = await chrome.storage.local.get('app_setting');
12 | if (data.app_setting) {
13 | folderInput.value = data.app_setting.downloadFolder || 'music/%genre%';
14 | coverSelect.value = data.app_setting.coverQuality || 600;
15 | audioSelect.value = data.app_setting.audioQuality || 'lossless-flac___aac,he-aac,mp3,flac-mp4,aac-mp4,he-aac-mp4___encraw';
16 | downlodadCount.value = data.app_setting.downlodadCount || 4;
17 | savehistory.value = data.app_setting.savehistory || 0;
18 | //checkexists.value = data.app_setting.checkexists || 0;
19 | }
20 |
21 | const settings = {
22 | downloadFolder: folderInput.value??'music/%genre%',
23 | coverQuality: parseInt(coverSelect.value??'600'),
24 | audioQuality: audioSelect.value??'nq',
25 | downlodadCount: parseInt(downlodadCount.value??4),
26 | savehistory: savehistory.value || 0,
27 | //checkexists: checkexists.value || 0,
28 | };
29 | await chrome.storage.local.set({ app_setting: settings });
30 | console.log('Настройки получены!',settings);
31 |
32 | form.addEventListener('submit', async function (e) {
33 | e.preventDefault();
34 | const settings_submit = {
35 | downloadFolder: folderInput.value??'music/%genre%',
36 | coverQuality: parseInt(coverSelect.value??'600'),
37 | audioQuality: audioSelect.value??'nq',
38 | downlodadCount: parseInt(downlodadCount.value??4),
39 | savehistory: savehistory.value || '0',
40 | //checkexists: checkexists.value || '0',
41 | };
42 | await chrome.storage.local.set({ app_setting: settings_submit });
43 | alert('Настройки сохранены!');
44 | console.log('Настройки сохранены!',settings_submit);
45 | });
46 | });
47 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | [💰 Поддержать разработку](https://yoomoney.ru/to/410011249842897)
2 |
3 | # 🎵 Yandex Music Fisher Mod
4 |
5 | Плагин для скачивания музыки с сервиса [Yandex Music](https://music.yandex.ru/)
6 |
7 | 🧪 **NEW TEST:** https://github.com/vectorserver/yandex_music_fisher_mod/
8 |
9 | ---
10 |
11 | ## 🧩 Установка распакованного расширения в Chrome / Opera / Edge
12 |
13 | ### 📥 Шаг 1: Скачивание репозитория
14 |
15 | 1. Перейдите по ссылке: [Скачать ZIP](https://github.com/vectorserver/yandex_music_fisher_mod/archive/refs/heads/master.zip)
16 | 2. Распакуйте архив в удобное место, например: `C:\yandex_music_fisher_mod-master\`
17 |
18 | ---
19 |
20 | ### 📁 Шаг 2: Папка с расширением
21 |
22 | Перейдите в папку: `C:\yandex_music_fisher_mod-master\` — именно она будет устанавливаться в браузер.
23 |
24 | Убедитесь, что внутри есть:
25 | - `manifest.json`
26 | - другие .js и .html файлы
27 |
28 | ---
29 |
30 | ### 🌐 Шаг 3: Открой страницу расширений
31 |
32 | - **Chrome** → `chrome://extensions/`
33 | - **Opera** → `opera://extensions/`
34 | - **Edge** → `edge://extensions/`
35 |
36 | ---
37 |
38 | ### ⚙️ Шаг 4: Включи режим разработчика
39 |
40 | - Включи переключатель **Режим разработчика** (вверху или внизу страницы).
41 |
42 | ---
43 |
44 | ### 📂 Шаг 5: Установка
45 |
46 | 1. Нажми кнопку **Загрузить распакованное расширение**
47 | 2. Выбери папку `C:\yandex_music_fisher_mod-master\`
48 | 3. Подтверди выбор папки
49 |
50 | ---
51 |
52 | ### ✅ Шаг 6: Проверка
53 |
54 | - Убедись, что расширение включено
55 | - Если есть ошибки:
56 | - Проверь путь: все файлы должны быть внутри `C:\yandex_music_fisher_mod-master\`
57 | - Убедись, что браузер поддерживает `manifest_version: 3`
58 |
59 | ---
60 |
61 | ### 🎉 Шаг 7: Готово!
62 |
63 | Расширение установлено. Иконка появится в панели браузера.
64 |
65 | ---
66 |
67 | ## 🦊 Установка в Firefox
68 |
69 | 1. Перейди: `about:debugging#/runtime/this-firefox`
70 | 2. Нажми 👉 **Загрузить временное дополнение...**
71 | 3. Укажи файл `manifest_Firefox.json` внутри папки `C:\yandex_music_fisher_mod-master\`
72 | 4. Расширение активируется до перезапуска Firefox
73 |
74 | > ⚠️ Firefox поддерживает только временную установку без подписи. После перезапуска расширение будет отключено.
75 |
76 | ---
77 |
78 | ## 📝 Важные заметки:
79 |
80 | - Edge и Opera устанавливаются аналогично, т.к. работают на Chromium
81 | - Для постоянной работы расширения в Firefox — потребуется подпись или Developer Edition
82 | - Хотите автозагрузку и обновления? Используйте подписанную версию через Chrome Web Store
83 |
84 | ---
85 |
86 | 💡 **Наслаждайтесь прослушиванием и скачиванием треков с Yandex Music с помощью Fisher Mod!** 🎧
87 | [💰 Поддержать разработку](https://yoomoney.ru/to/410011249842897)
--------------------------------------------------------------------------------
/js/content.js:
--------------------------------------------------------------------------------
1 | // Выводим в консоль информацию о запуске content.js
2 | console.log('content.js loaded');
3 |
4 | // Отправляем сообщение в background.js с командой "inject_parser"
5 | chrome.runtime.sendMessage({ action: "inject_parser" }, (data) => {
6 | if (chrome.runtime.lastError) {
7 | //console.error("Ошибка при отправке inject_parser:", chrome.runtime.lastError.message);
8 | } else {
9 | //console.log('inject_parser выполнен успешно:', data);
10 | }
11 | });
12 |
13 |
14 | // Загружаем настройки из chrome.storage.local и сохраняем в localStorage
15 | chrome.storage.local.get('app_setting', (result) => {
16 | if (result.app_setting) {
17 | // Копируем каждую настройку в localStorage
18 | for (const [key, value] of Object.entries(result.app_setting)) {
19 | console.log('appYa_setting_'+key, value)
20 | localStorage.setItem('appYa_setting_'+key, value);
21 | }
22 |
23 | }
24 | });
25 |
26 |
27 |
28 |
29 | // Сохраняем начальное состояние localStorage для отслеживания изменений
30 | let previousState = JSON.stringify(localStorage);
31 | // Функция для проверки изменений в localStorage
32 | const checkLocalStorageUpdates = () => {
33 | try {
34 | // Получаем текущее состояние localStorage
35 | let currentState = JSON.stringify(localStorage);
36 |
37 | // Сравниваем текущее и предыдущее состояние
38 | if (currentState !== previousState) {
39 |
40 | // Обновляем предыдущее состояние
41 | previousState = currentState;
42 |
43 |
44 | // Отправляем обновленные данные в background.js
45 | chrome.runtime.sendMessage({
46 | action: "send_localStorage",
47 | data: { ...window.localStorage } // Передаем копию localStorage
48 | }, (response) => {
49 | if (chrome.runtime.lastError) {
50 | //console.error("Ошибка отправки данных в background.js:", chrome.runtime.lastError.message);
51 | } else {
52 | //console.log("Ответ от background.js на send_localStorage:", response);
53 | }
54 | });
55 | }
56 | } catch (error) {
57 | //console.error("Ошибка при проверке localStorage:", error);
58 | }
59 | };
60 |
61 | // Устанавливаем интервал проверки localStorage каждые 1000 мс (1 секунда)
62 | setInterval(checkLocalStorageUpdates, 1000);
63 |
64 |
65 | // Для SHIFT + D и SHIFT + В
66 | document.addEventListener('keydown', function(event) {
67 | if (event.shiftKey && (event.key === 'D' || event.key === 'В')) {
68 | event.preventDefault();
69 |
70 | // Открываем popup.html
71 | chrome.runtime.sendMessage({
72 | action: "download_SFIFTD",
73 | data: { ...window.localStorage }
74 | });
75 | }
76 | });
77 |
78 | // Для двойного клика мыши
79 | document.addEventListener('dblclick', function(event) {
80 | // Открываем popup.html
81 | chrome.runtime.sendMessage({
82 | action: "download_SFIFTD",
83 | data: { ...window.localStorage }
84 | });
85 | });
--------------------------------------------------------------------------------
/html/options.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NEXT Yandex Music Fisher
6 |
7 |
8 |
9 |
10 |
11 |
Настройки приложения
12 |
13 |
14 | Благодарности сюда:
15 | 💰yoomoney
16 |
17 |
84 |
85 |
86 |
87 | #2.1.18
88 | - checkexists deleted
89 | - artist meta exists
90 |
91 | #2.1.17
92 | - Сохранять историю в менеджере загрузок
93 | - Единовременная закачака за один проход
94 |
95 | #2.1.11
96 | - Обработчик сообщения для загрузки через SHIFT+D или двойной клик
97 |
98 | #2.1
99 | - добавлены переменные для загрузки %genre% - Жанр %year% - Год %artist% - Артист %album% - Альбом и %dir%
100 |
101 | #2.0
102 | - обновленный алгоритм закачки
103 | - добавлены метаданные (в планах текст песни)
104 | - добавлен manifest_Firefox.json
105 |
106 | #1.0.4.7
107 | - Исправлена ошибка закачки файлов по 30 сек
108 | - новый алгоритм закачки
109 | #1.0.3
110 | - Мелкие баги с именами файлов
111 | - добавлена одновременная загрузка 4 файлов за раз
112 | - включена настройки (обложка, качество, папка)
113 |
114 |
115 | #1.0.2
116 | - Исправлено имя файла {artist} - {title}
117 | - добавлена одновременная загрузка 4 файлов за раз
118 | - включена история файлов
119 |
120 | #1.0.1.18022025
121 | - добавлено псевдо lossless (320 кб/сек).
122 | - добавлен чарт https://music.yandex.ru/chart.
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/html/popup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | NEXT Yandex Music Fisher mod by vectorserver
8 |
9 |
10 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
NEXT Yandex Music Fisher
29 |
Для использования приложения нужна авторизация для доступа к методам Яндекс Музыки.
30 |
Авторизация
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
Текущий трек
40 |
41 |

43 |
44 |
Track Info
45 |
No track information available
46 |
47 |
Скачать
48 |
SHIFT+D или двойной клик
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |

59 |
60 |
61 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
85 |
86 |
87 | By: Vectorserver
88 |
89 |
90 | Token end: UP
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/js/service_worker.js:
--------------------------------------------------------------------------------
1 | // Выводим в консоль информацию о запуске service_worker.js
2 | console.log('service_worker.js loaded');
3 |
4 |
5 | const appService = {
6 | saveToStorage(key, value) {
7 | return chrome.storage.local.set({[key]: value});
8 | },
9 | getFromStorage(key) {
10 | return chrome.storage.local.get(key);
11 | }
12 | };
13 |
14 | const badgeManager = {
15 | colors: [
16 | '#FF5733', // Красный
17 | '#33FF57', // Зеленый
18 | '#3357FF', // Синий
19 | '#FF33A1', // Розовый
20 | '#FFBD33', // Оранжевый
21 | '#33FFF4', // Голубой
22 | '#B333FF', // Фиолетовый
23 | '#33FFA1', // Бирюзовый
24 | '#FFA133', // Желтый
25 | '#A133FF', // Лиловый
26 | '#33A1FF', // Лазурный
27 | '#FFA1A1' // Розовый
28 | ],
29 | usedColors: [], // Добавляем массив использованных цветов
30 | resetColors() {
31 | this.usedColors = [];
32 | },
33 | getRandomColor() {
34 | if (this.usedColors.length === this.colors.length) {
35 | this.resetColors();
36 | }
37 | const availableColors = this.colors.filter(color => !this.usedColors.includes(color));
38 | const randomColor = availableColors[Math.floor(Math.random() * availableColors.length)];
39 | this.usedColors.push(randomColor);
40 | return randomColor;
41 | },
42 | updateBadge(count, bg) {
43 | chrome.action.setBadgeText({text: count > 0 ? count.toString() : ""});
44 | chrome.action.setBadgeBackgroundColor({color: bg});
45 | }
46 | };
47 |
48 | const downloadManager = {
49 | async downloadTracks(message, globalCount) {
50 | let {tabId, playlistName, trackIds} = message;
51 |
52 | // Ждём результат get
53 | const settings = await chrome.storage.local.get('app_setting');
54 |
55 | // Получаем путь из результата
56 | const downloadFolder = settings?.app_setting?.downloadFolder || 'music';
57 | playlistName = downloadFolder + '/' + playlistName;
58 |
59 | // Проверяем, содержит ли downloadFolder переменные
60 | const hasVariables = /%[^%]+%/.test(downloadFolder);
61 |
62 |
63 | let batchSize = settings?.app_setting?.downlodadCount ?? 4;
64 | globalCount += trackIds.length;
65 | let bg = badgeManager.getRandomColor();
66 | badgeManager.updateBadge(globalCount, bg);
67 |
68 | for (let i = 0; i < trackIds.length; i += batchSize) {
69 | const batch = trackIds.slice(i, i + batchSize);
70 |
71 | await Promise.all(batch.map(trackId =>
72 | new Promise((resolve, reject) => {
73 | const dataToInject = `appYa.fetchFileInfoOne(${trackId})`;
74 |
75 | chrome.scripting.executeScript({
76 | target: {tabId: tabId},
77 | func: (injectedData) => eval(injectedData),
78 | args: [dataToInject],
79 | world: "MAIN",
80 | }, (results) => {
81 | if (chrome.runtime.lastError) {
82 | console.error("Ошибка при выполнении скрипта:", chrome.runtime.lastError);
83 | reject(chrome.runtime.lastError.message);
84 | return;
85 | }
86 |
87 | setTimeout(async () => {
88 | if (results && results.length > 0) {
89 | let inputData = await JSON.parse(results[0].result);
90 | globalCount -= 1;
91 | badgeManager.updateBadge(globalCount, bg);
92 |
93 | if (inputData !== null && inputData.download) {
94 |
95 | // Если есть переменные в downloadFolder, обрабатываем их
96 | if (hasVariables) {
97 | let artists = inputData.trackinfo.artists.map((item) => item.name).join(', ');
98 |
99 | // Если есть переменные в downloadFolder, обрабатываем их
100 | const defaultTrackInfo = {
101 | dir: playlistName,
102 | genre: inputData.trackinfo.albums[0].genre || 'Unknown',
103 | year: inputData.trackinfo.albums[0].year || new Date().getFullYear(),
104 | artist: artists || 'Unknown Artist',
105 | album: inputData.trackinfo.albums[0].title || 'Unknown Album'
106 | };
107 |
108 | // Словарь переменных
109 | const variables = {
110 | '%dir%': playlistName,
111 | '%genre%': defaultTrackInfo.genre,
112 | '%year%': defaultTrackInfo.year.toString(),
113 | '%artist%': defaultTrackInfo.artist,
114 | '%album%': defaultTrackInfo.album
115 | };
116 |
117 | // Заменяем переменные в downloadFolder
118 | let processedFolder = downloadFolder;
119 |
120 | for (const [variable, value] of Object.entries(variables)) {
121 | if (downloadFolder.includes(variable)) {
122 | // Очищаем значение от недопустимых символов
123 | const cleanValue = value.toString().replace(/[<>:"/\\|?*]/g, '_');
124 | processedFolder = processedFolder.replace(new RegExp(variable.replace(/%/g, '\\%'), 'gi'), cleanValue);
125 | }
126 | }
127 |
128 | playlistName = processedFolder;
129 | }
130 |
131 |
132 | downloadManager.downloadFile(inputData, playlistName, settings);
133 | }
134 | resolve(trackId);
135 | } else {
136 | reject("No result returned");
137 | }
138 | }, 250);
139 | });
140 | })
141 | ));
142 | }
143 | },
144 |
145 | downloadFile(inputData, playlistName, settings) {
146 |
147 | console.log('downloadFile settings', settings?.app_setting)
148 | const escapeFileName = (fileName) => fileName.replace(/[\\/:*?"<>|]/g, '_');
149 | let artists = inputData.trackinfo.artists.map((item) => item.name).join(', ');
150 | let title = inputData.trackinfo.title;
151 | let fileName = `${playlistName}/${escapeFileName(artists)} - ${escapeFileName(title)}.mp3`;
152 |
153 |
154 | //Тут нужно еще проверка о том что файл существует settings?.app_setting.checkexists если есть то не качаем
155 | chrome.downloads.download({
156 | url: inputData.download,
157 | filename: fileName,
158 | saveAs: false,
159 | conflictAction: 'overwrite'
160 | }, (downloadId) => {
161 | if (chrome.runtime.lastError) {
162 | console.error("Ошибка загрузки:", chrome.runtime.lastError.message);
163 | return;
164 | }
165 |
166 |
167 | // Отслеживаем завершение загрузки
168 | if (settings?.app_setting.savehistory === "0" || settings?.app_setting.savehistory === 0) {
169 | chrome.downloads.onChanged.addListener(function listener(delta) {
170 | if (delta.id === downloadId && delta.state && delta.state.current === 'complete') {
171 | // Удаляем запись из истории загрузок
172 | chrome.downloads.erase({id: downloadId}, () => {
173 | if (chrome.runtime.lastError) {
174 | console.warn("Не удалось удалить запись о загрузке:", chrome.runtime.lastError.message);
175 | } else {
176 | console.log(`Загрузка ${downloadId} удалена из истории`);
177 | }
178 | });
179 | // Отписываемся от слушателя, чтобы не ловить другие загрузки
180 | chrome.downloads.onChanged.removeListener(listener);
181 | }
182 | });
183 | }
184 | });
185 | }
186 | };
187 |
188 |
189 | const worker = {
190 | globalCount: 0,
191 | onMessage(message, sender, sendResponse) {
192 | if (message.action === "inject_parser") {
193 | sendResponse({success: true, message: 'parser.js OK', tabId: sender.tab.id});
194 | chrome.scripting.executeScript({
195 | target: {tabId: sender.tab.id},
196 | files: ["html/bs5/browser-id3-writer.6.0.0.mjs", "js/parser.js"],
197 | world: "MAIN"
198 | }).then(() => {
199 | chrome.scripting.executeScript({
200 | target: {tabId: sender.tab.id},
201 | func: () => {
202 | if (typeof appYa !== 'undefined' && typeof appYa.init === 'function') {
203 | appYa.init();
204 | }
205 | },
206 | world: "MAIN"
207 | }).then(() => {
208 | appService.saveToStorage('appYa_tabID', sender.tab.id);
209 | }).catch(console.error);
210 | }).catch(console.error);
211 |
212 | return true;
213 | }
214 |
215 | if (message.action === "send_localStorage") {
216 | sendResponse({success: true, data: message.data});
217 | if (message.data && !message.data.appYa_token) {
218 | appService.saveToStorage('appYa_db', {appYa_token: false});
219 | }
220 | appService.saveToStorage('appYa_db', message.data).then(() => {
221 |
222 | //console.log("Данные localStorage успешно сохранены:", { appYa_db: message.data });
223 | }).catch(console.error);
224 | return true;
225 | }
226 |
227 | if (message.action === "download_Tracks") {
228 | console.log('download_Tracks', message);
229 | sendResponse({download_Tracks: message});
230 | downloadManager.downloadTracks(message, this.globalCount);
231 | return true;
232 | }
233 |
234 | // Обработчик сообщения для загрузки через SHIFT+D или двойной клик
235 | if (message.action === "download_SFIFTD") {
236 | // Парсим информацию о файле из localStorage данных сообщения
237 | const trDinfo = JSON.parse(message.data["appYa_get-file-info"]);
238 |
239 | // Проверяем, есть ли ID трека для загрузки
240 | if (trDinfo.downloadInfo.trackId) {
241 | // Формируем данные для загрузки:
242 | // - tabId: ID вкладки отправителя (для контекста)
243 | // - trackIds: массив ID треков для загрузки (в данном случае один трек)
244 | // - playlistName: имя плейлиста (по умолчанию 'music')
245 | let downData = {
246 | tabId: sender.tab.id, // ID вкладки, откуда пришел запрос
247 | trackIds: [trDinfo.downloadInfo.trackId], // Массив ID треков для загрузки
248 | playlistName: 'music' // Имя плейлиста для организации загрузок
249 | }
250 |
251 | // Логируем данные для отладки
252 | console.log('download_SFIFT+D', downData)
253 |
254 | // Вызываем менеджер загрузок для скачивания трека(ов)
255 | // this.globalCount - глобальный счетчик загрузок (для нумерации/отслеживания)
256 | downloadManager.downloadTracks(downData, this.globalCount);
257 | }
258 | return true; // Подтверждаем получение сообщения
259 | }
260 |
261 |
262 | }
263 | };
264 |
265 | // Слушатель сообщений
266 | chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
267 | return worker.onMessage(message, sender, sendResponse);
268 | });
269 |
--------------------------------------------------------------------------------
/html/bs5/browser-id3-writer.6.0.0.mjs:
--------------------------------------------------------------------------------
1 | function e(e) {
2 | return String(e).split("").map((e => e.charCodeAt(0)))
3 | }
4 |
5 | function t(t) {
6 | return new Uint8Array(e(t))
7 | }
8 |
9 | function a(t) {
10 | const a = new ArrayBuffer(2 * t.length), r = new Uint8Array(a);
11 | return new Uint16Array(a).set(e(t)), r
12 | }
13 |
14 | function r(e) {
15 | const t = 255;
16 | return [e >>> 24 & t, e >>> 16 & t, e >>> 8 & t, e & t]
17 | }
18 |
19 | function n(e) {
20 | return 11 + e
21 | }
22 |
23 | function s(e, t, a, r) {
24 | return 11 + t + 1 + 1 + (r ? 2 + 2 * (a + 1) : a + 1) + e
25 | }
26 |
27 | function i(e) {
28 | let t = 0;
29 | return e.forEach((e => {
30 | t += 2 + 2 * e[0].length + 2 + 2 + 2 * e[1].length + 2
31 | })), 11 + t
32 | }
33 |
34 | function c(e, t) {
35 | const a = 2 * t;
36 | let r = 0;
37 | return e.forEach((e => {
38 | r += 2 + 2 * e[0].length + 2 + 4
39 | })), 18 + a + 2 + r
40 | }
41 |
42 | class ID3Writer {
43 | _setIntegerFrame(e, t) {
44 | const a = parseInt(t, 10);
45 | this.frames.push({name: e, value: a, size: n(a.toString().length)})
46 | }
47 |
48 | _setStringFrame(e, t) {
49 | const a = t.toString();
50 | let r = 13 + 2 * a.length;
51 | "TDAT" === e && (r = n(a.length)), this.frames.push({name: e, value: a, size: r})
52 | }
53 |
54 | _setPictureFrame(e, t, a, r) {
55 | const n = function (e) {
56 | if (!e || !e.length) return null;
57 | if (255 === e[0] && 216 === e[1] && 255 === e[2]) return "image/jpeg";
58 | if (137 === e[0] && 80 === e[1] && 78 === e[2] && 71 === e[3]) return "image/png";
59 | if (71 === e[0] && 73 === e[1] && 70 === e[2]) return "image/gif";
60 | if (87 === e[8] && 69 === e[9] && 66 === e[10] && 80 === e[11]) return "image/webp";
61 | const t = 73 === e[0] && 73 === e[1] && 42 === e[2] && 0 === e[3],
62 | a = 77 === e[0] && 77 === e[1] && 0 === e[2] && 42 === e[3];
63 | return t || a ? "image/tiff" : 66 === e[0] && 77 === e[1] ? "image/bmp" : 0 === e[0] && 0 === e[1] && 1 === e[2] && 0 === e[3] ? "image/x-icon" : null
64 | }(new Uint8Array(t)), i = a.toString();
65 | if (!n) throw new Error("Unknown picture MIME type");
66 | a || (r = !1), this.frames.push({
67 | name: "APIC",
68 | value: t,
69 | pictureType: e,
70 | mimeType: n,
71 | useUnicodeEncoding: r,
72 | description: i,
73 | size: s(t.byteLength, n.length, i.length, r)
74 | })
75 | }
76 |
77 | _setLyricsFrame(e, t, a) {
78 | const r = e.split("").map((e => e.charCodeAt(0))), n = t.toString(), s = a.toString();
79 | var i, c;
80 | this.frames.push({
81 | name: "USLT",
82 | value: s,
83 | language: r,
84 | description: n,
85 | size: (i = n.length, c = s.length, 16 + 2 * i + 2 + 2 + 2 * c)
86 | })
87 | }
88 |
89 | _setCommentFrame(e, t, a) {
90 | const r = e.split("").map((e => e.charCodeAt(0))), n = t.toString(), s = a.toString();
91 | var i, c;
92 | this.frames.push({
93 | name: "COMM",
94 | value: s,
95 | language: r,
96 | description: n,
97 | size: (i = n.length, c = s.length, 16 + 2 * i + 2 + 2 + 2 * c)
98 | })
99 | }
100 |
101 | _setPrivateFrame(e, t) {
102 | const a = e.toString();
103 | var r, n;
104 | this.frames.push({name: "PRIV", value: t, id: a, size: (r = a.length, n = t.byteLength, 10 + r + 1 + n)})
105 | }
106 |
107 | _setUserStringFrame(e, t) {
108 | const a = e.toString(), r = t.toString();
109 | var n, s;
110 | this.frames.push({
111 | name: "TXXX",
112 | description: a,
113 | value: r,
114 | size: (n = a.length, s = r.length, 13 + 2 * n + 2 + 2 + 2 * s)
115 | })
116 | }
117 |
118 | _setUrlLinkFrame(e, t) {
119 | const a = t.toString();
120 | var r;
121 | this.frames.push({name: e, value: a, size: (r = a.length, 10 + r)})
122 | }
123 |
124 | _setPairedTextFrame(e, t) {
125 | this.frames.push({name: e, value: t, size: i(t)})
126 | }
127 |
128 | _setSynchronisedLyricsFrame(e, t, a, r, n) {
129 | const s = n.toString(), i = r.split("").map((e => e.charCodeAt(0)));
130 | this.frames.push({
131 | name: "SYLT",
132 | value: t,
133 | language: i,
134 | description: s,
135 | type: e,
136 | timestampFormat: a,
137 | size: c(t, s.length)
138 | })
139 | }
140 |
141 | constructor(e) {
142 | if (!e || "object" != typeof e || !("byteLength" in e)) throw new Error("First argument should be an instance of ArrayBuffer or Buffer");
143 | this.arrayBuffer = e, this.padding = 4096, this.frames = [], this.url = ""
144 | }
145 |
146 | setFrame(e, t) {
147 | switch (e) {
148 | case"TPE1":
149 | case"TCOM":
150 | case"TCON": {
151 | if (!Array.isArray(t)) throw new Error(`${e} frame value should be an array of strings`);
152 | const a = "TCON" === e ? ";" : "/", r = t.join(a);
153 | this._setStringFrame(e, r);
154 | break
155 | }
156 | case"TLAN":
157 | case"TIT1":
158 | case"TIT2":
159 | case"TIT3":
160 | case"TALB":
161 | case"TPE2":
162 | case"TPE3":
163 | case"TPE4":
164 | case"TRCK":
165 | case"TPOS":
166 | case"TMED":
167 | case"TPUB":
168 | case"TCOP":
169 | case"TKEY":
170 | case"TEXT":
171 | case"TDAT":
172 | case"TSRC":
173 | this._setStringFrame(e, t);
174 | break;
175 | case"TBPM":
176 | case"TLEN":
177 | case"TYER":
178 | this._setIntegerFrame(e, t);
179 | break;
180 | case"USLT":
181 | if (t.language = t.language || "eng", "object" != typeof t || !("description" in t) || !("lyrics" in t)) throw new Error("USLT frame value should be an object with keys description and lyrics");
182 | if (t.language && !t.language.match(/[a-z]{3}/i)) throw new Error("Language must be coded following the ISO 639-2 standards");
183 | this._setLyricsFrame(t.language, t.description, t.lyrics);
184 | break;
185 | case"APIC":
186 | if ("object" != typeof t || !("type" in t) || !("data" in t) || !("description" in t)) throw new Error("APIC frame value should be an object with keys type, data and description");
187 | if (t.type < 0 || t.type > 20) throw new Error("Incorrect APIC frame picture type");
188 | this._setPictureFrame(t.type, t.data, t.description, !!t.useUnicodeEncoding);
189 | break;
190 | case"TXXX":
191 | if ("object" != typeof t || !("description" in t) || !("value" in t)) throw new Error("TXXX frame value should be an object with keys description and value");
192 | this._setUserStringFrame(t.description, t.value);
193 | break;
194 | case"WCOM":
195 | case"WCOP":
196 | case"WOAF":
197 | case"WOAR":
198 | case"WOAS":
199 | case"WORS":
200 | case"WPAY":
201 | case"WPUB":
202 | this._setUrlLinkFrame(e, t);
203 | break;
204 | case"COMM":
205 | if (t.language = t.language || "eng", "object" != typeof t || !("description" in t) || !("text" in t)) throw new Error("COMM frame value should be an object with keys description and text");
206 | if (t.language && !t.language.match(/[a-z]{3}/i)) throw new Error("Language must be coded following the ISO 639-2 standards");
207 | this._setCommentFrame(t.language, t.description, t.text);
208 | break;
209 | case"PRIV":
210 | if ("object" != typeof t || !("id" in t) || !("data" in t)) throw new Error("PRIV frame value should be an object with keys id and data");
211 | this._setPrivateFrame(t.id, t.data);
212 | break;
213 | case"IPLS":
214 | if (!Array.isArray(t) || !Array.isArray(t[0])) throw new Error("IPLS frame value should be an array of pairs");
215 | this._setPairedTextFrame(e, t);
216 | break;
217 | case"SYLT":
218 | if ("object" != typeof t || !("type" in t) || !("text" in t) || !("timestampFormat" in t)) throw new Error("SYLT frame value should be an object with keys type, text and timestampFormat");
219 | if (!Array.isArray(t.text) || !Array.isArray(t.text[0])) throw new Error("SYLT frame text value should be an array of pairs");
220 | if (t.type < 0 || t.type > 6) throw new Error("Incorrect SYLT frame content type");
221 | if (t.timestampFormat < 1 || t.timestampFormat > 2) throw new Error("Incorrect SYLT frame time stamp format");
222 | t.language = t.language || "eng", t.description = t.description || "", this._setSynchronisedLyricsFrame(t.type, t.text, t.timestampFormat, t.language, t.description);
223 | break;
224 | default:
225 | throw new Error(`Unsupported frame ${e}`)
226 | }
227 | return this
228 | }
229 |
230 | removeTag() {
231 | if (this.arrayBuffer.byteLength < 10) return;
232 | const e = new Uint8Array(this.arrayBuffer), t = e[3],
233 | a = ((r = [e[6], e[7], e[8], e[9]])[0] << 21) + (r[1] << 14) + (r[2] << 7) + r[3] + 10;
234 | var r, n;
235 | 73 !== (n = e)[0] || 68 !== n[1] || 51 !== n[2] || t < 2 || t > 4 || (this.arrayBuffer = new Uint8Array(e.subarray(a)).buffer)
236 | }
237 |
238 | addTag() {
239 | this.removeTag();
240 | const e = [255, 254], n = 10 + this.frames.reduce(((e, t) => e + t.size), 0) + this.padding,
241 | s = new ArrayBuffer(this.arrayBuffer.byteLength + n), i = new Uint8Array(s);
242 | let c = 0, o = [];
243 | return o = [73, 68, 51, 3], i.set(o, c), c += o.length, c++, c++, o = function (e) {
244 | const t = 127;
245 | return [e >>> 21 & t, e >>> 14 & t, e >>> 7 & t, e & t]
246 | }(n - 10), i.set(o, c), c += o.length, this.frames.forEach((n => {
247 | switch (o = t(n.name), i.set(o, c), c += o.length, o = r(n.size - 10), i.set(o, c), c += o.length, c += 2, n.name) {
248 | case"WCOM":
249 | case"WCOP":
250 | case"WOAF":
251 | case"WOAR":
252 | case"WOAS":
253 | case"WORS":
254 | case"WPAY":
255 | case"WPUB":
256 | o = t(n.value), i.set(o, c), c += o.length;
257 | break;
258 | case"TPE1":
259 | case"TCOM":
260 | case"TCON":
261 | case"TLAN":
262 | case"TIT1":
263 | case"TIT2":
264 | case"TIT3":
265 | case"TALB":
266 | case"TPE2":
267 | case"TPE3":
268 | case"TPE4":
269 | case"TRCK":
270 | case"TPOS":
271 | case"TKEY":
272 | case"TMED":
273 | case"TPUB":
274 | case"TCOP":
275 | case"TEXT":
276 | case"TSRC":
277 | o = [1].concat(e), i.set(o, c), c += o.length, o = a(n.value), i.set(o, c), c += o.length;
278 | break;
279 | case"TXXX":
280 | case"USLT":
281 | case"COMM":
282 | o = [1], "USLT" !== n.name && "COMM" !== n.name || (o = o.concat(n.language)), o = o.concat(e), i.set(o, c), c += o.length, o = a(n.description), i.set(o, c), c += o.length, o = [0, 0].concat(e), i.set(o, c), c += o.length, o = a(n.value), i.set(o, c), c += o.length;
283 | break;
284 | case"TBPM":
285 | case"TLEN":
286 | case"TDAT":
287 | case"TYER":
288 | c++, o = t(n.value), i.set(o, c), c += o.length;
289 | break;
290 | case"PRIV":
291 | o = t(n.id), i.set(o, c), c += o.length, c++, i.set(new Uint8Array(n.value), c), c += n.value.byteLength;
292 | break;
293 | case"APIC":
294 | o = [n.useUnicodeEncoding ? 1 : 0], i.set(o, c), c += o.length, o = t(n.mimeType), i.set(o, c), c += o.length, o = [0, n.pictureType], i.set(o, c), c += o.length, n.useUnicodeEncoding ? (o = [].concat(e), i.set(o, c), c += o.length, o = a(n.description), i.set(o, c), c += o.length, c += 2) : (o = t(n.description), i.set(o, c), c += o.length, c++), i.set(new Uint8Array(n.value), c), c += n.value.byteLength;
295 | break;
296 | case"IPLS":
297 | o = [1], i.set(o, c), c += o.length, n.value.forEach((t => {
298 | o = [].concat(e), i.set(o, c), c += o.length, o = a(t[0].toString()), i.set(o, c), c += o.length, o = [0, 0].concat(e), i.set(o, c), c += o.length, o = a(t[1].toString()), i.set(o, c), c += o.length, o = [0, 0], i.set(o, c), c += o.length
299 | }));
300 | break;
301 | case"SYLT":
302 | o = [1].concat(n.language).concat(n.timestampFormat).concat(n.type), i.set(o, c), c += o.length, o = [].concat(e), i.set(o, c), c += o.length, o = a(n.description), i.set(o, c), c += o.length, c += 2, n.value.forEach((t => {
303 | o = [].concat(e), i.set(o, c), c += o.length, o = a(t[0].toString()), i.set(o, c), c += o.length, o = [0, 0], i.set(o, c), c += o.length, o = r(t[1]), i.set(o, c), c += o.length
304 | }))
305 | }
306 | })), c += this.padding, i.set(new Uint8Array(this.arrayBuffer), c), this.arrayBuffer = s, s
307 | }
308 |
309 | getBlob() {
310 | return new Blob([this.arrayBuffer], {type: "audio/mpeg"})
311 | }
312 |
313 | getURL() {
314 | return this.url || (this.url = URL.createObjectURL(this.getBlob())), this.url
315 | }
316 |
317 | revokeURL() {
318 | URL.revokeObjectURL(this.url)
319 | }
320 | }
--------------------------------------------------------------------------------
/js/popup.js:
--------------------------------------------------------------------------------
1 | console.log('js/popup.js');
2 |
3 |
4 | const section = document.querySelector('section');
5 | const col_one = document.getElementById('col1');
6 | const col_two = document.getElementById('col2');
7 | const workPanel = document.getElementById('work_panel');
8 | const playlistPanel = document.getElementById('playlistPanel');
9 | const playlistPanelTitle = document.getElementById('playlistPanelTitle');
10 | const playlistPanelImage = document.getElementById('playlistPanelImage');
11 | const playlistPanelMeta = document.getElementById('playlistPanelMeta');
12 | const playlistPanelMetaotherData = document.getElementById('playlistPanelMetaotherData');
13 | const playlistPanelMetaDownloadBtn = document.getElementById('playlistPanelMetaDownloadBtn');
14 | const tokenEnd = document.getElementById('tokenEnd');
15 | const tokenEndUrl = document.getElementById('tokenEndUrl');
16 | const escapeFileName = (fileName) => fileName.replace(/[\\/:*?"<>|]/g, '_');
17 |
18 |
19 | document.getElementById('open-settings').addEventListener('click', function () {
20 | if (chrome.runtime.openOptionsPage) {
21 | chrome.runtime.openOptionsPage();
22 | } else {
23 | window.open(chrome.runtime.getURL('html/options.html'));
24 | }
25 | });
26 |
27 |
28 | // Сервис для работы с chrome.storage.local
29 | const storageService = {
30 | getStorageData(callback) {
31 | chrome.storage.local.get((result) => callback(result));
32 | },
33 | saveStorageData(key, value) {
34 | chrome.storage.local.set({[key]: value});
35 | },
36 | monitorStorageChanges(callback) {
37 | chrome.storage.onChanged.addListener((changes, areaName) => {
38 |
39 | callback(changes);
40 |
41 | });
42 | }
43 | };
44 |
45 | // Обновление пользовательского интерфейса
46 | const uiUpdater = {
47 | updateUI(data, appYa_tabID, app) {
48 | const parsedData = parser.parseStorage(data);
49 | const cQ = app?.app_setting?.coverQuality ?? 300;
50 | var cQR = `${cQ}x${cQ}`;
51 | console.log('coverQuality', cQR)
52 |
53 | const authorizationPanel = document.getElementById('authorization');
54 | const authorizationBtn = authorizationPanel.querySelector('#authorize');
55 |
56 |
57 | if (parsedData.appYa_token) {
58 | this.updateTrackInfo(parsedData, appYa_tabID, cQR);
59 | this.updatePlaylistInfo(parsedData, appYa_tabID, cQR);
60 | let checktokenData = uiUpdater.getTokenExpirationDate(parsedData.appYa_token);
61 | tokenEnd.innerText = checktokenData;
62 | tokenEndUrl.addEventListener('click', function () {
63 | //localStorage.clear()
64 | const dataToInject = `localStorage.clear();window.location.reload();`;
65 | chrome.scripting.executeScript({
66 | target: {tabId: appYa_tabID},
67 | func: (injectedData) => eval(injectedData),
68 | args: [dataToInject],
69 | world: "MAIN",
70 | }, (results) => {
71 | window.close();
72 | });
73 | });
74 | //console.log('parsedData',parsedData)
75 | //console.log('appYa_page',parsedData.appYa_page)
76 | } else {
77 | authorizationPanel.style.display = 'flex';
78 | authorizationBtn.setAttribute('href', parsedData.appYa_authorizationUrl);
79 |
80 | setTimeout(() => {
81 | authorizationBtn.addEventListener('click', () => {
82 | chrome.tabs.remove(appYa_tabID, (error) => {
83 | if (chrome.runtime.lastError) {
84 | console.error(chrome.runtime.lastError);
85 | } else {
86 | console.log('Вкладка закрыта.');
87 | }
88 | });
89 | });
90 | }, 1500);
91 | }
92 | },
93 |
94 | updateTrackInfo(parsedData, appYa_tabID, cQR) {
95 | if (!parsedData.appYa_cureitTrack) {
96 | document.querySelector('body .container-fluid').innerHTML =
97 | 'Включите трек, Яндекс Музыки, потом вернитесь сюда)';
98 | return;
99 | }
100 |
101 | workPanel.style.display = 'flex';
102 | const track = parsedData.appYa_cureitTrack.trackinfo;
103 | const imageURL = `https://${track.coverUri.replace(/%%/g, cQR)}`;
104 | const artists = track.artists.map((item) => item.name).join(', ');
105 | const albums = track.albums.map((item) => item.year).join(', ');
106 |
107 | document.getElementById('trackName').innerText = track.title;
108 | document.getElementById('artistsList').innerHTML = `${artists}
${albums}`;
109 | document.getElementById('trackImage').src = imageURL;
110 |
111 | //section.style.backgroundColor = track.derivedColors.average;
112 | //section.style.color = track.derivedColors.waveText;
113 | //playlistPanelMetaDownloadBtn.style.backgroundColor = track.derivedColors.miniPlayer;
114 | document.querySelector('#trackPanel').style.backgroundColor = track.derivedColors.accent;
115 |
116 | document.getElementById('downloadButton').addEventListener('click', () => {
117 | eventHandlers.downloadTracks(appYa_tabID, [track.id], 'music');
118 | });
119 | },
120 |
121 | updatePlaylistInfo(parsedData, appYa_tabID, cQR) {
122 | const playlist = parsedData.appYa_page.playlist;
123 | const artist = parsedData.appYa_page.artist;
124 | const album = parsedData.appYa_page.album;
125 | const chart = parsedData.appYa_page.chart;
126 |
127 | //console.log('updatePlaylistInfo_type',parsedData.appYa_page)
128 |
129 |
130 | if (playlist && playlist.items && playlist.meta) {
131 | const title = playlist.meta.title.replace(':', '_');
132 | const trackIds = playlist.items.map(track => track.id);
133 | const coverUri = `https://${playlist.meta.coverUri.replace(/%%/g, cQR)}`;
134 | const meta = `Автор плейлиста: ${playlist.meta.owner.name}
Кол-во треков: ${playlist.items.length}`;
135 |
136 | playlistPanelTitle.innerText = `Плейлист: ${title}`;
137 | playlistPanelMeta.innerHTML = meta;
138 | playlistPanelImage.src = coverUri;
139 |
140 |
141 | playlistPanelMetaDownloadBtn.innerText = 'Скачать плейлист';
142 | playlistPanelMetaDownloadBtn.style.display = 'flex';
143 | playlistPanelMetaDownloadBtn.addEventListener('click', () => {
144 | eventHandlers.downloadTracks(appYa_tabID, trackIds, `playlist/${title}`);
145 | });
146 | } else if (artist && artist?.fullTracksListSubpage?.ids?.length) {
147 | console.log('artist', artist)
148 | let title = 'Артист...';
149 | let coverUri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wlseKgAAAABJRU5ErkJggg==';
150 | if (artist.meta) {
151 | title = artist.meta.artist.name.replace(':', '_');
152 | coverUri = `https://${artist.meta.artist.coverUri.replace(/%%/g, cQR)}`;
153 | } else {
154 |
155 | if(artist.commonSubPage.artistName) title = artist.commonSubPage.artistName.replace(':', '_');
156 | if(artist.lastRelease.coverUri) coverUri = `https://${artist.lastRelease.coverUri.replace(/%%/g, cQR)}`;
157 |
158 | }
159 | const trackIds = artist.fullTracksListSubpage.ids;
160 | playlistPanelTitle.innerText = `Артист: ${title}`;
161 | playlistPanelImage.src = coverUri;
162 |
163 | playlistPanelMetaDownloadBtn.querySelector('.text').innerText = 'Скачать все треки артиста';
164 | playlistPanelMetaDownloadBtn.querySelector('.counter').innerText = `${trackIds.length}`;
165 |
166 |
167 | playlistPanelMetaDownloadBtn.style.display = 'flex';
168 | playlistPanelMetaDownloadBtn.addEventListener('click', () => {
169 |
170 | eventHandlers.downloadTracks(appYa_tabID, trackIds, `artist/${escapeFileName(title)}`);
171 | });
172 |
173 | //popularTracks
174 |
175 | //albums
176 | let tpl_albums = `
177 |
Альбомы
178 |
184 |
`
185 | playlistPanelMetaotherData.innerHTML += tpl_albums;
186 | document.addEventListener('click', function (event) {
187 | const url = event.target.getAttribute('data-urlTab');
188 | eventHandlers.changeTabUrl(appYa_tabID, url)
189 | });
190 |
191 |
192 | } else if (album && album?.items?.length) {
193 |
194 | const year = album.meta?.year ? ' - ' + album.meta.year : '';
195 | const title = album.meta.title.replace(':', '_') + year;
196 | const trackIds = album.items.map(track => track.id);
197 | const coverUri = `https://${album.meta.coverUri.replace(/%%/g, cQR)}`;
198 |
199 | playlistPanelTitle.innerText = `Альбом: ${title}`;
200 | playlistPanelImage.src = coverUri;
201 |
202 | playlistPanelMetaDownloadBtn.querySelector('.text').innerText = 'Скачать все треки альбома';
203 | playlistPanelMetaDownloadBtn.querySelector('.counter').innerText = `${trackIds.length}`;
204 |
205 | playlistPanelMetaDownloadBtn.style.display = 'flex';
206 | playlistPanelMetaDownloadBtn.addEventListener('click', () => {
207 | eventHandlers.downloadTracks(appYa_tabID, trackIds, `album/${escapeFileName(title)}`);
208 | });
209 |
210 |
211 | } else if (chart && chart?.tracksSubPage?.items?.length) {
212 |
213 | const trackIds = chart.tracksSubPage.items.map(track => track.id);
214 | //const coverUri = `https://${album.meta.coverUri.replace(/%%/g, cQR)}`;
215 |
216 | //playlistPanelTitle.innerText = `Чарт`;
217 | //playlistPanelImage.src = coverUri;
218 |
219 | playlistPanelMetaDownloadBtn.querySelector('.text').innerText = 'Скачать ЧАРТ';
220 | playlistPanelMetaDownloadBtn.querySelector('.counter').innerText = `${trackIds.length}`;
221 |
222 | playlistPanelMetaDownloadBtn.style.display = 'flex';
223 | playlistPanelMetaDownloadBtn.addEventListener('click', () => {
224 | eventHandlers.downloadTracks(appYa_tabID, trackIds, `chart`);
225 | });
226 |
227 |
228 | } else {
229 | col_one.classList.add('col-12');
230 | col_two.classList.add('d-none');
231 | section.style.width = '280px';
232 |
233 | }
234 |
235 | },
236 | getTokenExpirationDate(tokenData) {
237 | // Получаем текущее время в миллисекундах
238 | const currentTime = Date.now();
239 |
240 | // Преобразуем expires_in из секунд в миллисекунды
241 | const expiresInMillis = tokenData.expires_in * 1000;
242 |
243 | // Рассчитываем дату истечения токена
244 | const expirationDate = new Date(currentTime + expiresInMillis);
245 |
246 | // Форматируем дату в формате "день.месяц.год"
247 | const day = String(expirationDate.getDate()).padStart(2, '0');
248 | const month = String(expirationDate.getMonth() + 1).padStart(2, '0'); // Месяцы в JavaScript начинаются с 0
249 | const year = expirationDate.getFullYear();
250 |
251 | return `${day}.${month}.${year}`;
252 | }
253 | };
254 |
255 | // Обработчики событий
256 | const eventHandlers = {
257 | init() {
258 | document.addEventListener('DOMContentLoaded', this.onDOMContentLoaded);
259 | },
260 |
261 | onDOMContentLoaded() {
262 | storageService.getStorageData((result) => {
263 | //console.log('ss',result)
264 | if (result.appYa_db) {
265 |
266 |
267 | uiUpdater.updateUI(result.appYa_db, result.appYa_tabID, result);
268 |
269 | storageService.monitorStorageChanges((changes) => {
270 | const {newValue, oldValue} = changes.appYa_db;
271 | if (newValue?.appYa_cureitTrack !== oldValue?.appYa_cureitTrack || newValue?.appYa_page !== oldValue?.appYa_page) {
272 | window.location.reload();
273 | }
274 | });
275 |
276 |
277 | } else {
278 | console.log('Нет данных в chrome.storage.local');
279 | document.querySelector('body .container-fluid').innerHTML = 'Обновите страницу, Яндекс Музыки, потом вернитесь сюда)';
280 | window.location.reload();
281 | }
282 | });
283 | },
284 |
285 | downloadTracks(tabId, trackIds, playlistName) {
286 | chrome.runtime.sendMessage({
287 | action: "download_Tracks",
288 | tabId: tabId,
289 | trackIds: trackIds,
290 | playlistName: playlistName
291 | }, (response) => {
292 | if (chrome.runtime.lastError) {
293 | console.error("Ошибка отправки данных в service_worker.js:", chrome.runtime.lastError.message);
294 | } else {
295 | console.log("Ответ от service_worker.js:", response);
296 | }
297 | });
298 | },
299 | changeTabUrl(tabId, url) {
300 | if (url) {
301 | window.close();
302 | chrome.tabs.update(tabId, {url: url}, function (tab) {
303 | if (chrome.runtime.lastError) {
304 | console.error('Ошибка при изменении URL:', chrome.runtime.lastError);
305 | } else {
306 | console.log('URL успешно изменен на:', url);
307 | }
308 | });
309 | }
310 |
311 |
312 | }
313 | };
314 |
315 | // Парсинг данных
316 | const parser = {
317 | parseStorage(data) {
318 | return Object.keys(data).reduce((acc, key) => {
319 | const value = data[key];
320 | try {
321 | if (typeof value === 'string' && (value.startsWith('{') || value.startsWith('['))) {
322 | acc[key] = JSON.parse(value);
323 | } else {
324 | acc[key] = value;
325 | }
326 | } catch (error) {
327 | console.error(`Ошибка парсинга JSON для ключа ${key}:`, error);
328 | acc[key] = value;
329 | }
330 | return acc;
331 | }, {});
332 | }
333 | };
334 |
335 | // Инициализация событий
336 | eventHandlers.init();
337 |
--------------------------------------------------------------------------------
/js/parser.js:
--------------------------------------------------------------------------------
1 | (() => {
2 |
3 |
4 | console.log('parser.js loaded:', window.location.href);
5 |
6 | let appYa = {
7 | location_origin: 'https://music.yandex.ru/?yamusic=ok',
8 | redirect_uri: 'https://music.yandex.ru/oauth',
9 | apiUrl: 'https://api.music.yandex.ru/',
10 | oauthUrl: 'https://oauth.yandex.ru/',
11 | client_id: '97fe03033fa34407ac9bcf91d5afed5b',
12 | tokenData: {},
13 |
14 | /**
15 | * Инициализация приложения.
16 | */
17 | init: function () {
18 |
19 | //Проверка происходит до всего остального, чтобы сброс был моментальным.
20 | if (this.client_id !== '97fe03033fa34407ac9bcf91d5afed5b') {
21 | localStorage.clear();
22 | }
23 |
24 |
25 | // Получаем токен из localStorage
26 | let appYa_token = localStorage.getItem('appYa_token');
27 | if (!appYa_token) {
28 | // Если токена нет, запрашиваем новый
29 | appYa.reToken();
30 | } else {
31 | localStorage.setItem('appYa_hosting', window.location.origin);
32 |
33 | // Если токен есть, парсим его и сохраняем в tokenData
34 | appYa_token = JSON.parse(appYa_token);
35 | appYa.tokenData = appYa_token;
36 | //console.log('appYa_token', appYa_token);
37 |
38 | // Сохраняем текущий URL
39 | let previousHref = window.location.href;
40 |
41 | // Создаем наблюдатель за изменениями в DOM
42 | const observer = new MutationObserver(() => {
43 | if (window.location.href !== previousHref) {
44 | //console.log("URL has changed to:", window.location.href);
45 | previousHref = window.location.href;
46 | // Вызов функции обработки нового URL
47 | appYa.parsePage();
48 | }
49 |
50 | let plListcontent = [
51 | 'MainPage',
52 | 'AlbumPage',
53 | 'PlaylistPage',
54 | 'ArtistTracksPage',
55 | 'MusicHistoryPage',
56 | 'CollectionPage',
57 | 'ArtistPage',
58 | 'TrackModal',
59 | 'SearchPage',
60 | 'ChartTracksPage',
61 | ]
62 | let seletors = plListcontent.map(sel => `div[class*="${sel}_content__"]`);
63 |
64 |
65 | const playButtonsContent = document.querySelector(seletors.join(","));
66 | if (playButtonsContent) {
67 | // Ваши действия при обнаружении изменений
68 |
69 |
70 | appYa.processPlayButtons(playButtonsContent);
71 | }
72 |
73 | });
74 |
75 | // Начинаем наблюдение за изменениями в DOM
76 | observer.observe(document, {childList: true, subtree: true});
77 | }
78 |
79 | // Парсим текущую страницу
80 | appYa.parsePage();
81 |
82 | // Начинаем мониторинг fetch-запросов
83 | appYa.monitorFetchRequests();
84 | },
85 |
86 | processPlayButtons: function (playButtonsContent) {
87 |
88 |
89 | const playButtons = playButtonsContent.querySelectorAll('div[class*="Track_root__"],div[class*="TrackCard_root__"]');
90 | //console.log('playButtons',playButtons)
91 |
92 |
93 | playButtons.forEach((playButton) => {
94 | const link = playButton.querySelector('a[class*="Meta_albumLink__"],a[class*="TrackCard_titleLink__"]');
95 | //console.log('link',link)
96 | const meta = playButton.querySelector('div[class*="Meta_titleContainer"],div[class*="TrackCard_titleContainer"]');
97 |
98 | if (link) {
99 | const regex = /\/track\/(\d+)/;
100 | const match = link.href.match(regex);
101 | const trackId = match ? match[1] : null;
102 | if (trackId) {
103 |
104 |
105 | // Проверяем, была ли уже добавлена кнопка
106 | if (!meta.querySelector('button.added')) {
107 |
108 | //console.log('trackId', trackId);
109 |
110 | const downloadButton = document.createElement('button');
111 | let style = 'background-color: #fc3;color: black;border-radius: 4px;display: flex;cursor: pointer;border: none;padding: 4px 10px;position: absolute;left: 40%;top: 15px;z-index:9999;';
112 | downloadButton.textContent = 'Скачать';
113 | downloadButton.classList.add('added');
114 | downloadButton.setAttribute('style', style);
115 |
116 |
117 | meta.appendChild(downloadButton);
118 |
119 |
120 | downloadButton.addEventListener('click', function () {
121 | appYa.fetchFileInfoOne(trackId).then(result => {
122 | let downloadData = JSON.parse(result);
123 | let artist = downloadData.trackinfo.artists.map(art => art.name).join(", ");
124 | let filename = `${artist} - ${downloadData.trackinfo.title}.mp3`
125 |
126 | downloadButton.textContent = 'Загрузка...';
127 | downloadButton.setAttribute('disabled', 'disabled');
128 |
129 | // Создание скрытого элемента для загрузки файла
130 | const downloadLink = document.createElement('a');
131 | downloadLink.href = downloadData.download;
132 | downloadLink.download = filename; // Установите имя файла по вашему усмотрению
133 | downloadLink.style.display = 'none';
134 | document.body.appendChild(downloadLink);
135 |
136 | // Программно вызываем клик на скрытом элементе
137 | downloadLink.click();
138 |
139 | // Удаляем скрытый элемент после загрузки
140 | if (document.body.removeChild(downloadLink)) {
141 | setTimeout(function () {
142 | downloadButton.textContent = 'Загрузка...';
143 | downloadButton.removeAttribute('disabled');
144 | downloadButton.textContent = 'Скачать';
145 | }, 1000)
146 | }
147 | });
148 | });
149 |
150 |
151 | }
152 |
153 |
154 | }
155 | }
156 | // Ваши действия с найденными кнопками playButtons
157 | });
158 | // Поиск всех div с классом, содержащим PlayButtonWithCover
159 |
160 | /*playButtons.forEach(playButton => {
161 | // Проверка наличия кнопки с классом download-button
162 | let meta = playButton.querySelector('div[class*="Meta_titleContainer"]');
163 | const link = playButton.querySelector('a[class*="Meta_albumLink__"]');
164 |
165 | if (link) {
166 | const regex = /\/track\/(\d+)/;
167 | const match = link.href.match(regex);
168 | const trackId = match ? match[1] : null;
169 | if (trackId) {
170 | console.log('trackId', trackId);
171 |
172 | // Создание кнопки загрузки
173 | const downloadButton = document.createElement('button');
174 | downloadButton.textContent = 'Download';
175 | downloadButton.classList.add('download-button'); // Добавляем класс для стилизации
176 |
177 | meta.appendChild(downloadButton);
178 |
179 | downloadButton.addEventListener('click', function () {
180 | appYa.fetchFileInfoOne(trackId).then(result => {
181 | let download = JSON.parse(result.download);
182 |
183 | // Создание скрытого элемента для загрузки файла
184 | const downloadLink = document.createElement('a');
185 | downloadLink.href = download;
186 | downloadLink.download = 'track.mp3'; // Установите имя файла по вашему усмотрению
187 | downloadLink.style.display = 'none';
188 | document.body.appendChild(downloadLink);
189 |
190 | // Программно вызываем клик на скрытом элементе
191 | downloadLink.click();
192 |
193 | // Удаляем скрытый элемент после загрузки
194 | document.body.removeChild(downloadLink);
195 | });
196 | });
197 | }
198 | }
199 | });*/
200 | },
201 |
202 | /**
203 | * Обновление токена.
204 | */
205 | reToken: function () {
206 | if (window.location.hash) {
207 | // Удаляем символ '#' в начале строки
208 | const cleanedString = window.location.hash.substring(1);
209 |
210 | // Разбиваем строку на массив пар "ключ=значение"
211 | const pairs = cleanedString.split('&');
212 |
213 | // Создаем объект для хранения пар "ключ=значение"
214 | const params = {};
215 |
216 | // Проходим по каждой паре и добавляем в объект
217 | pairs.forEach(pair => {
218 | const [key, value] = pair.split('=');
219 | params[key] = value;
220 | });
221 |
222 | // Сохраняем объект в localStorage
223 | localStorage.setItem('appYa_token', JSON.stringify(params));
224 | window.location.href = appYa.location_origin;
225 |
226 | // Выводим объект в консоль для проверки
227 | //console.log(params);
228 | } else {
229 | // Перенаправляем на страницу авторизации Яндекса
230 | let appYa_authorizationUrl = (`${appYa.oauthUrl}authorize?response_type=token&client_id=${appYa.client_id}&redirect_uri=${appYa.redirect_uri}`);
231 | localStorage.setItem('appYa_authorizationUrl', appYa_authorizationUrl)
232 |
233 | }
234 | },
235 |
236 | /**
237 | * Генерация подписи для запроса.
238 | * @param {string} secretKey - Секретный ключ.
239 | * @param {string} data - Данные для подписи.
240 | * @returns {Promise} - Подпись.
241 | */
242 | generateSign: async function (secretKey, data) {
243 | // Создаем кодировщик
244 | const encoder = new TextEncoder();
245 |
246 | // Кодируем секретный ключ
247 | const keyData = encoder.encode(secretKey);
248 |
249 | // Импортируем ключ для HMAC
250 | const cryptoKey = await crypto.subtle.importKey(
251 | 'raw',
252 | keyData,
253 | {name: 'HMAC', hash: {name: 'SHA-256'}},
254 | false,
255 | ['sign']
256 | );
257 |
258 | // Кодируем данные
259 | const dataEncoded = encoder.encode(data);
260 |
261 | // Генерируем подпись
262 | const signature = await crypto.subtle.sign(
263 | 'HMAC',
264 | cryptoKey,
265 | dataEncoded
266 | );
267 |
268 | // Возвращаем подпись в формате base64
269 | return btoa(String.fromCharCode(...new Uint8Array(signature))).replace(/=+$/, '');
270 | },
271 |
272 | /**
273 | * Получение информации о файле трека.
274 | * @param {string} trackId - Идентификатор трека.
275 | * @returns {Promise} - Информация о файле трека.
276 | */
277 |
278 | fetchFileInfoOne: async function (trackId) {
279 | // Секретный ключ
280 | const secretKey = 'kzqU4XhfCaY6B6JTHODeq5';
281 |
282 | // Текущее время в секундах
283 | const timestamp = Math.floor(Date.now() / 1000);
284 |
285 | // Данные для подписи
286 | const appYa_setting_audioQuality = localStorage.getItem('appYa_setting_audioQuality') ?? 'lossless';
287 | console.log('appYa_setting_audioQuality', appYa_setting_audioQuality)
288 |
289 | const dataToSign = `${timestamp}${trackId}${appYa_setting_audioQuality}flacraw`;
290 |
291 | // Генерируем подпись
292 | const sign = await appYa.generateSign(secretKey, dataToSign);
293 |
294 | // Создаем параметры запроса
295 | //Добавлен lossless
296 | const params = new URLSearchParams({
297 | ts: timestamp,
298 | trackId: trackId,
299 | quality: appYa_setting_audioQuality,
300 | codecs: 'flac',
301 | transports: 'raw',
302 | sign: sign
303 | });
304 |
305 | // Создаем заголовки запроса
306 | const headers = new Headers({
307 | 'Authorization': `OAuth ${appYa.tokenData.access_token}`,
308 | 'X-Yandex-Music-Client': 'YandexMusicDesktopAppWindows/1'
309 | });
310 |
311 | // Формируем URL запроса
312 | const url = `${appYa.apiUrl}get-file-info?${params.toString()}&byVectorserver=1`;
313 | const urlInfo = `${appYa.apiUrl}tracks?trackIds=${trackId}&byVectorserver=1`;
314 |
315 |
316 | try {
317 | // Выполняем оба запроса параллельно
318 | const [response1, response2] = await Promise.all([
319 | fetch(url, {headers}),
320 | fetch(urlInfo, {headers})
321 | ]);
322 |
323 | // Проверяем статусы ответов
324 | if (!response1.ok) {
325 | throw new Error(`HTTP error! status: ${response1.status}`);
326 | }
327 | if (!response2.ok) {
328 | throw new Error(`HTTP error! status: ${response2.status}`);
329 | }
330 |
331 | // Получаем данные из ответов
332 | const data1 = await response1.json();
333 | const data2 = await response2.json();
334 |
335 | const downloadUrl = data1.result.downloadInfo.url;
336 | const trackInfo = data2.result[0];
337 | console.log('appYa_trackInfo', (trackInfo));
338 |
339 | // Загружаем MP3-файл
340 | const response = await fetch(downloadUrl);
341 | if (!response.ok) {
342 | throw new Error(`Ошибка загрузки MP3: ${response.statusText}`);
343 | }
344 | const mp3Data = new Uint8Array(await response.arrayBuffer());
345 |
346 | // Загружаем обложку
347 | const appYa_setting_coverQuality = localStorage.getItem('appYa_setting_coverQuality') ?? '400';
348 | let qq = `${appYa_setting_coverQuality}x${appYa_setting_coverQuality}`
349 |
350 | const coverUrl = trackInfo.albums[0].coverUri.replace('%%', qq); // Подставляем размер
351 | const artistUrl = trackInfo.artists[0].cover?.uri?.replace('%%', qq); // Подставляем размер
352 |
353 | const coverResponse = await fetch(`https://${coverUrl}`);
354 | const artistcoverResponse = await fetch(`https://${artistUrl}`);
355 |
356 | if (!coverResponse.ok) {
357 | throw new Error(`Ошибка загрузки обложки: ${coverResponse.statusText}`);
358 | }
359 |
360 | const coverData = new Uint8Array(await coverResponse.arrayBuffer());
361 | const artistcoverResponseData = new Uint8Array(await artistcoverResponse.arrayBuffer());
362 |
363 | // Обновляем метаданные
364 | const writer = new ID3Writer(mp3Data);
365 | // Получаем данные из trackInfo
366 | const currentTrackNumber = trackInfo.albums[0].trackPosition.index || '1';
367 | const totalTracksInAlbum = trackInfo.albums[0].trackCount || '1';
368 |
369 | writer.setFrame('TIT2', trackInfo.title) // Название трека
370 | .setFrame('TPE1', [trackInfo.artists.map(a => a.name).join(', ')]) // Исполнители
371 | .setFrame('TALB', trackInfo.albums[0].title) // Альбом
372 | .setFrame('TYER', trackInfo.albums[0].year) // Год выпуска
373 | .setFrame('TCON', trackInfo.albums[0]?.genre?.split(',') || ['Unknown']) // Жанр (например, "Pop", "Rock")
374 | .setFrame('TRCK', `${currentTrackNumber}/${totalTracksInAlbum}`) //TPOS (позиция трека в альбоме)
375 | //Обложка альбома (спереди)
376 | .setFrame('APIC', {
377 | type: 3,
378 | data: coverData,
379 | description: 'Cover (front)'
380 | })// Логотип группы/артиста
381 | .setFrame('APIC', {
382 | type: 17, // Band/Artist Logotype
383 | data: artistcoverResponseData,
384 | description: 'Band Logo'
385 | })
386 | .addTag();
387 |
388 | console.log('appYa_trackInfo_writer', (writer));
389 |
390 | // Создаем Blob с обновленными данными
391 | const updatedMp3 = writer.arrayBuffer;
392 | const blob = new Blob([updatedMp3], {type: 'audio/mpeg'});
393 |
394 | // Генерируем URL и загружаем через chrome.downloads.download
395 | const blobUrl = URL.createObjectURL(blob);
396 | // Устанавливаем тайм-аут для загрузки
397 |
398 | const allData = JSON.stringify({'download': blobUrl, 'trackinfo': trackInfo});
399 | // Объединяем данные и возвращаем их
400 | return allData;
401 | } catch (error) {
402 | console.error('Error fetching file info:', error);
403 | }
404 | },
405 |
406 | /**
407 | * Парсинг текущей страницы.
408 | */
409 | parsePage: async function () {
410 | try {
411 | // Получаем текущий URL
412 | let url = window.location.href;
413 | //Если стрница Артиста
414 | if (url.includes('/artist') && !url.endsWith('/tracks')) {
415 | url = `${url}/tracks`;
416 | }
417 |
418 | // Выполняем запрос на текущий URL
419 | const response = await fetch(url);
420 |
421 | // Проверяем статус ответа
422 | if (!response.ok) {
423 | //console.error(`Error loading page: ${response.status}`);
424 | return;
425 | }
426 |
427 | // Получаем HTML-код страницы
428 | const html = await response.text();
429 |
430 | // Создаем парсер
431 | const parser = new DOMParser();
432 |
433 | // Парсим HTML-код в документ
434 | const doc = parser.parseFromString(html, 'text/html');
435 |
436 | // Получаем все скрипты в теле документа
437 | const scriptElements = doc.querySelectorAll("body > script");
438 |
439 | // Регулярное выражение для поиска данных
440 | const pushRegex = /\(window\.__STATE_SNAPSHOT__\s*=\s*window\.__STATE_SNAPSHOT__\s*\|\|\s*\[\]\)\.push\(([\s\S]*?)\);/g;
441 |
442 | // Массив для хранения объединенных данных
443 | const mergedObject = [];
444 |
445 | // Проходим по каждому скрипту
446 | scriptElements.forEach((script) => {
447 | const content = script.textContent;
448 | const matches = content.matchAll(pushRegex);
449 |
450 | // Проходим по каждому совпадению
451 | for (const match of matches) {
452 | const pushData = match[1];
453 |
454 | try {
455 | // Парсим данные и добавляем в массив
456 | const parsedData = JSON.parse(pushData);
457 | mergedObject.push(parsedData);
458 | } catch (e) {
459 | //console.warn('Ошибка парсинга JSON:', e, pushData);
460 | }
461 | }
462 | });
463 |
464 | // Получаем последний элемент массива
465 | const last = mergedObject.at(-1);
466 |
467 | // Получаем данные из localStorage
468 | const storedData = localStorage.getItem('appYa_page');
469 |
470 | // Проверяем, изменились ли данные
471 | if (JSON.stringify(last) !== storedData) {
472 | // Сохраняем данные в localStorage, если они изменились
473 | localStorage.setItem('appYa_page', JSON.stringify(last));
474 | }
475 |
476 | } catch (error) {
477 | //console.error('Error in parsePage:', error);
478 | }
479 | },
480 |
481 | /**
482 | * Извлечение папки из URL.
483 | * @param {string} url - URL.
484 | * @returns {string} - Название папки.
485 | */
486 | extractFolderFromUrl(url) {
487 | try {
488 | // Получаем путь из URL
489 | const path = new URL(url).pathname;
490 |
491 | // Разбиваем путь на сегменты и фильтруем пустые сегменты
492 | return path.split('/').filter(segment => segment !== '')[0] || 'root';
493 | } catch (error) {
494 | //console.error('Error extracting folder from URL:', error);
495 | return 'unknown';
496 | }
497 | },
498 |
499 | /**
500 | * Получение информации о треке.
501 | * @param {string} trackId - Идентификатор трека.
502 | */
503 | fetchTrackInfo: async function (trackId) {
504 | // Формируем URL запроса
505 | const newUrl = `https://api.music.yandex.ru/tracks?trackIds=${trackId}`;
506 |
507 | try {
508 | // Выполняем запрос
509 | const response = await fetch(newUrl);
510 |
511 | // Проверяем статус ответа
512 | if (!response.ok) {
513 | //console.error(`Error fetching track with ID: ${trackId}`);
514 | return;
515 | }
516 |
517 | // Получаем данные в формате JSON
518 | const data = await response.json();
519 | //console.log('appYa_TrackInfo:', data.result[0]);
520 |
521 | // Сохраняем данные в localStorage
522 | //localStorage.setItem('appYa_TrackInfo', JSON.stringify(data.result[0]));
523 | } catch (error) {
524 | //console.error('Error in fetchTrackInfo:', error);
525 | }
526 | },
527 |
528 | /**
529 | * Мониторинг fetch-запросов.
530 | */
531 | monitorFetchRequests() {
532 | const originalFetch = window.fetch;
533 | window.fetch = async (url, options) => {
534 | try {
535 |
536 |
537 | const response = await originalFetch(url, options);
538 | const clonedResponse = response.clone();
539 | const contentType = clonedResponse.headers.get("content-type");
540 |
541 | const folder = this.extractFolderFromUrl(response.url);
542 |
543 |
544 | // Добавляем проверку download=1
545 | const parsedUrl = new URL(response.url);
546 | const byVectorserver = parsedUrl.searchParams.get('byVectorserver') === '1';
547 | if (!byVectorserver) {
548 | if (contentType?.includes("application/json")) {
549 | const data = await clonedResponse.json();
550 | if (data && Object.entries(data).length) {
551 | let setParamNAme = `appYa_${folder}`;
552 | localStorage.setItem(`appYa_${folder}`, JSON.stringify(data));
553 | const trackId = new URL(response.url).searchParams.get('trackId');
554 | if (trackId) {
555 |
556 | await appYa.fetchFileInfoOne(trackId).then(cureitTrack => {
557 | if (cureitTrack) {
558 | localStorage.setItem('appYa_cureitTrack', cureitTrack);
559 | } else {
560 | console.error('Failed to fetch file info');
561 | }
562 | });
563 |
564 | }
565 |
566 | }
567 |
568 | }
569 |
570 |
571 | }
572 |
573 |
574 | return response;
575 | } catch (error) {
576 | //console.error('Error in fetch interception:', error);
577 | throw error;
578 | }
579 | };
580 |
581 | //console.log('Fetch monitoring with trackId handling enabled.');
582 | },
583 | addImageToAudio: async function (audioURL, imageURL) {
584 | return new Promise(async (resolve, reject) => {
585 | try {
586 | // Скачиваем аудиофайл
587 | const audioResponse = await fetch(audioURL);
588 | const audioArrayBuffer = await audioResponse.arrayBuffer();
589 |
590 | // Скачиваем изображение
591 | const imageResponse = await fetch(imageURL);
592 | const imageArrayBuffer = await imageResponse.arrayBuffer();
593 | //const imageData = new Uint8Array(imageArrayBuffer);
594 |
595 |
596 | if (imageResponse && audioResponse) {
597 |
598 | var writer = new ID3Writer(audioArrayBuffer);
599 | writer
600 | .setFrame('APIC', {
601 | type: 3,
602 | data: imageArrayBuffer,
603 | description: 'Super picture',
604 | });
605 | writer.addTag();
606 |
607 |
608 | const newBlob = new Blob([writer.arrayBuffer], {type: 'audio/mpeg'});
609 | const url = URL.createObjectURL(newBlob);
610 | resolve(url);
611 | }
612 | } catch (error) {
613 | reject(new Error(`Ошибка при добавлении изображения: ${error.message}`));
614 | }
615 | });
616 | }
617 | }
618 |
619 | window.appYa = appYa;
620 | })();
--------------------------------------------------------------------------------
/html/bs5/bootstrap-grid.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Grid v5.3.3 (https://getbootstrap.com/)
3 | * Copyright 2011-2024 The Bootstrap Authors
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5 | */.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{--bs-gutter-x:1.5rem;--bs-gutter-y:0;width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}:root{--bs-breakpoint-xs:0;--bs-breakpoint-sm:576px;--bs-breakpoint-md:768px;--bs-breakpoint-lg:992px;--bs-breakpoint-xl:1200px;--bs-breakpoint-xxl:1400px}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-right:calc(-.5 * var(--bs-gutter-x));margin-left:calc(-.5 * var(--bs-gutter-x))}.row>*{box-sizing:border-box;flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.66666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.66666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.66666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.66666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.66666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.66666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-inline-grid{display:inline-grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}@media (min-width:576px){.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-inline-grid{display:inline-grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}}@media (min-width:768px){.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-inline-grid{display:inline-grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}}@media (min-width:992px){.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-inline-grid{display:inline-grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}}@media (min-width:1200px){.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-inline-grid{display:inline-grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}}@media (min-width:1400px){.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-inline-grid{display:inline-grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-inline-grid{display:inline-grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}}
6 | /*# sourceMappingURL=bootstrap-grid.min.css.map */
--------------------------------------------------------------------------------
/html/bs5/bootstrap.bundle.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap v5.3.3 (https://getbootstrap.com/)
3 | * Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5 | */
6 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t=new Map,e={set(e,i,n){t.has(e)||t.set(e,new Map);const s=t.get(e);s.has(i)||0===s.size?s.set(i,n):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`)},get:(e,i)=>t.has(e)&&t.get(e).get(i)||null,remove(e,i){if(!t.has(e))return;const n=t.get(e);n.delete(i),0===n.size&&t.delete(e)}},i="transitionend",n=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),s=t=>{t.dispatchEvent(new Event(i))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(n(t)):null,a=t=>{if(!o(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},l=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),c=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?c(t.parentNode):null},h=()=>{},d=t=>{t.offsetHeight},u=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,f=[],p=()=>"rtl"===document.documentElement.dir,m=t=>{var e;e=()=>{const e=u();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(f.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of f)t()})),f.push(e)):e()},g=(t,e=[],i=t)=>"function"==typeof t?t(...e):i,_=(t,e,n=!0)=>{if(!n)return void g(t);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let r=!1;const a=({target:n})=>{n===e&&(r=!0,e.removeEventListener(i,a),g(t))};e.addEventListener(i,a),setTimeout((()=>{r||s(e)}),o)},b=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},v=/[^.]*(?=\..*)\.|.*/,y=/\..*/,w=/::\d+$/,A={};let E=1;const T={mouseenter:"mouseover",mouseleave:"mouseout"},C=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function O(t,e){return e&&`${e}::${E++}`||t.uidEvent||E++}function x(t){const e=O(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function k(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function L(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=I(t);return C.has(o)||(o=t),[n,s,o]}function S(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=L(e,i,n);if(e in T){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=x(t),c=l[a]||(l[a]={}),h=k(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=O(r,e.replace(v,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return P(s,{delegateTarget:r}),n.oneOff&&N.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return P(n,{delegateTarget:t}),i.oneOff&&N.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function D(t,e,i,n,s){const o=k(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function $(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&D(t,e,i,r.callable,r.delegationSelector)}function I(t){return t=t.replace(y,""),T[t]||t}const N={on(t,e,i,n){S(t,e,i,n,!1)},one(t,e,i,n){S(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=L(e,i,n),a=r!==e,l=x(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))$(t,l,i,e.slice(1));for(const[i,n]of Object.entries(c)){const s=i.replace(w,"");a&&!e.includes(s)||D(t,l,r,n.callable,n.delegationSelector)}}else{if(!Object.keys(c).length)return;D(t,l,r,o,s?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=u();let s=null,o=!0,r=!0,a=!1;e!==I(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());const l=P(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function P(t,e={}){for(const[i,n]of Object.entries(e))try{t[i]=n}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>n})}return t}function j(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function M(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const F={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${M(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${M(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const n of i){let i=n.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1,i.length),e[i]=j(t.dataset[n])}return e},getDataAttribute:(t,e)=>j(t.getAttribute(`data-bs-${M(e)}`))};class H{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=o(e)?F.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...o(e)?F.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[n,s]of Object.entries(e)){const e=t[n],r=o(e)?"element":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(s).test(r))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${n}" provided type "${r}" but expected type "${s}".`)}var i}}class W extends H{constructor(t,i){super(),(t=r(t))&&(this._element=t,this._config=this._getConfig(i),e.set(this._element,this.constructor.DATA_KEY,this))}dispose(){e.remove(this._element,this.constructor.DATA_KEY),N.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){_(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return e.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.3"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const B=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e?e.split(",").map((t=>n(t))).join(","):null},z={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode.closest(e);for(;n;)i.push(n),n=n.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!l(t)&&a(t)))},getSelectorFromElement(t){const e=B(t);return e&&z.findOne(e)?e:null},getElementFromSelector(t){const e=B(t);return e?z.findOne(e):null},getMultipleElementsFromSelector(t){const e=B(t);return e?z.find(e):[]}},R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,n=t.NAME;N.on(document,i,`[data-bs-dismiss="${n}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),l(this))return;const s=z.getElementFromSelector(this)||this.closest(`.${n}`);t.getOrCreateInstance(s)[e]()}))},q=".bs.alert",V=`close${q}`,K=`closed${q}`;class Q extends W{static get NAME(){return"alert"}close(){if(N.trigger(this._element,V).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),N.trigger(this._element,K),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=Q.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(Q,"close"),m(Q);const X='[data-bs-toggle="button"]';class Y extends W{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=Y.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}N.on(document,"click.bs.button.data-api",X,(t=>{t.preventDefault();const e=t.target.closest(X);Y.getOrCreateInstance(e).toggle()})),m(Y);const U=".bs.swipe",G=`touchstart${U}`,J=`touchmove${U}`,Z=`touchend${U}`,tt=`pointerdown${U}`,et=`pointerup${U}`,it={endCallback:null,leftCallback:null,rightCallback:null},nt={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class st extends H{constructor(t,e){super(),this._element=t,t&&st.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return it}static get DefaultType(){return nt}static get NAME(){return"swipe"}dispose(){N.off(this._element,U)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),g(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&g(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(N.on(this._element,tt,(t=>this._start(t))),N.on(this._element,et,(t=>this._end(t))),this._element.classList.add("pointer-event")):(N.on(this._element,G,(t=>this._start(t))),N.on(this._element,J,(t=>this._move(t))),N.on(this._element,Z,(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const ot=".bs.carousel",rt=".data-api",at="next",lt="prev",ct="left",ht="right",dt=`slide${ot}`,ut=`slid${ot}`,ft=`keydown${ot}`,pt=`mouseenter${ot}`,mt=`mouseleave${ot}`,gt=`dragstart${ot}`,_t=`load${ot}${rt}`,bt=`click${ot}${rt}`,vt="carousel",yt="active",wt=".active",At=".carousel-item",Et=wt+At,Tt={ArrowLeft:ht,ArrowRight:ct},Ct={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},Ot={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class xt extends W{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=z.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===vt&&this.cycle()}static get Default(){return Ct}static get DefaultType(){return Ot}static get NAME(){return"carousel"}next(){this._slide(at)}nextWhenVisible(){!document.hidden&&a(this._element)&&this.next()}prev(){this._slide(lt)}pause(){this._isSliding&&s(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?N.one(this._element,ut,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void N.one(this._element,ut,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?at:lt;this._slide(n,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&N.on(this._element,ft,(t=>this._keydown(t))),"hover"===this._config.pause&&(N.on(this._element,pt,(()=>this.pause())),N.on(this._element,mt,(()=>this._maybeEnableCycle()))),this._config.touch&&st.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of z.find(".carousel-item img",this._element))N.on(t,gt,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(ct)),rightCallback:()=>this._slide(this._directionToOrder(ht)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new st(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=Tt[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=z.findOne(wt,this._indicatorsElement);e.classList.remove(yt),e.removeAttribute("aria-current");const i=z.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(yt),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),n=t===at,s=e||b(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>N.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(dt).defaultPrevented)return;if(!i||!s)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=s;const l=n?"carousel-item-start":"carousel-item-end",c=n?"carousel-item-next":"carousel-item-prev";s.classList.add(c),d(s),i.classList.add(l),s.classList.add(l),this._queueCallback((()=>{s.classList.remove(l,c),s.classList.add(yt),i.classList.remove(yt,c,l),this._isSliding=!1,r(ut)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return z.findOne(Et,this._element)}_getItems(){return z.find(At,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return p()?t===ct?lt:at:t===ct?at:lt}_orderToDirection(t){return p()?t===lt?ct:ht:t===lt?ht:ct}static jQueryInterface(t){return this.each((function(){const e=xt.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}N.on(document,bt,"[data-bs-slide], [data-bs-slide-to]",(function(t){const e=z.getElementFromSelector(this);if(!e||!e.classList.contains(vt))return;t.preventDefault();const i=xt.getOrCreateInstance(e),n=this.getAttribute("data-bs-slide-to");return n?(i.to(n),void i._maybeEnableCycle()):"next"===F.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),N.on(window,_t,(()=>{const t=z.find('[data-bs-ride="carousel"]');for(const e of t)xt.getOrCreateInstance(e)})),m(xt);const kt=".bs.collapse",Lt=`show${kt}`,St=`shown${kt}`,Dt=`hide${kt}`,$t=`hidden${kt}`,It=`click${kt}.data-api`,Nt="show",Pt="collapse",jt="collapsing",Mt=`:scope .${Pt} .${Pt}`,Ft='[data-bs-toggle="collapse"]',Ht={parent:null,toggle:!0},Wt={parent:"(null|element)",toggle:"boolean"};class Bt extends W{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=z.find(Ft);for(const t of i){const e=z.getSelectorFromElement(t),i=z.find(e).filter((t=>t===this._element));null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return Ht}static get DefaultType(){return Wt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>Bt.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(N.trigger(this._element,Lt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Pt),this._element.classList.add(jt),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(jt),this._element.classList.add(Pt,Nt),this._element.style[e]="",N.trigger(this._element,St)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(N.trigger(this._element,Dt).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,d(this._element),this._element.classList.add(jt),this._element.classList.remove(Pt,Nt);for(const t of this._triggerArray){const e=z.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(jt),this._element.classList.add(Pt),N.trigger(this._element,$t)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(Nt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=r(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Ft);for(const e of t){const t=z.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=z.find(Mt,this._config.parent);return z.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=Bt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}N.on(document,It,Ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of z.getMultipleElementsFromSelector(this))Bt.getOrCreateInstance(t,{toggle:!1}).toggle()})),m(Bt);var zt="top",Rt="bottom",qt="right",Vt="left",Kt="auto",Qt=[zt,Rt,qt,Vt],Xt="start",Yt="end",Ut="clippingParents",Gt="viewport",Jt="popper",Zt="reference",te=Qt.reduce((function(t,e){return t.concat([e+"-"+Xt,e+"-"+Yt])}),[]),ee=[].concat(Qt,[Kt]).reduce((function(t,e){return t.concat([e,e+"-"+Xt,e+"-"+Yt])}),[]),ie="beforeRead",ne="read",se="afterRead",oe="beforeMain",re="main",ae="afterMain",le="beforeWrite",ce="write",he="afterWrite",de=[ie,ne,se,oe,re,ae,le,ce,he];function ue(t){return t?(t.nodeName||"").toLowerCase():null}function fe(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function pe(t){return t instanceof fe(t).Element||t instanceof Element}function me(t){return t instanceof fe(t).HTMLElement||t instanceof HTMLElement}function ge(t){return"undefined"!=typeof ShadowRoot&&(t instanceof fe(t).ShadowRoot||t instanceof ShadowRoot)}const _e={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];me(s)&&ue(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});me(n)&&ue(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function be(t){return t.split("-")[0]}var ve=Math.max,ye=Math.min,we=Math.round;function Ae(){var t=navigator.userAgentData;return null!=t&&t.brands&&Array.isArray(t.brands)?t.brands.map((function(t){return t.brand+"/"+t.version})).join(" "):navigator.userAgent}function Ee(){return!/^((?!chrome|android).)*safari/i.test(Ae())}function Te(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1);var n=t.getBoundingClientRect(),s=1,o=1;e&&me(t)&&(s=t.offsetWidth>0&&we(n.width)/t.offsetWidth||1,o=t.offsetHeight>0&&we(n.height)/t.offsetHeight||1);var r=(pe(t)?fe(t):window).visualViewport,a=!Ee()&&i,l=(n.left+(a&&r?r.offsetLeft:0))/s,c=(n.top+(a&&r?r.offsetTop:0))/o,h=n.width/s,d=n.height/o;return{width:h,height:d,top:c,right:l+h,bottom:c+d,left:l,x:l,y:c}}function Ce(t){var e=Te(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Oe(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&ge(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function xe(t){return fe(t).getComputedStyle(t)}function ke(t){return["table","td","th"].indexOf(ue(t))>=0}function Le(t){return((pe(t)?t.ownerDocument:t.document)||window.document).documentElement}function Se(t){return"html"===ue(t)?t:t.assignedSlot||t.parentNode||(ge(t)?t.host:null)||Le(t)}function De(t){return me(t)&&"fixed"!==xe(t).position?t.offsetParent:null}function $e(t){for(var e=fe(t),i=De(t);i&&ke(i)&&"static"===xe(i).position;)i=De(i);return i&&("html"===ue(i)||"body"===ue(i)&&"static"===xe(i).position)?e:i||function(t){var e=/firefox/i.test(Ae());if(/Trident/i.test(Ae())&&me(t)&&"fixed"===xe(t).position)return null;var i=Se(t);for(ge(i)&&(i=i.host);me(i)&&["html","body"].indexOf(ue(i))<0;){var n=xe(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function Ie(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}function Ne(t,e,i){return ve(t,ye(e,i))}function Pe(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function je(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const Me={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=be(i.placement),l=Ie(a),c=[Vt,qt].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return Pe("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:je(t,Qt))}(s.padding,i),d=Ce(o),u="y"===l?zt:Vt,f="y"===l?Rt:qt,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=$e(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,A=Ne(v,w,y),E=l;i.modifiersData[n]=((e={})[E]=A,e.centerOffset=A-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Oe(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function Fe(t){return t.split("-")[1]}var He={top:"auto",right:"auto",bottom:"auto",left:"auto"};function We(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=t.isFixed,u=r.x,f=void 0===u?0:u,p=r.y,m=void 0===p?0:p,g="function"==typeof h?h({x:f,y:m}):{x:f,y:m};f=g.x,m=g.y;var _=r.hasOwnProperty("x"),b=r.hasOwnProperty("y"),v=Vt,y=zt,w=window;if(c){var A=$e(i),E="clientHeight",T="clientWidth";A===fe(i)&&"static"!==xe(A=Le(i)).position&&"absolute"===a&&(E="scrollHeight",T="scrollWidth"),(s===zt||(s===Vt||s===qt)&&o===Yt)&&(y=Rt,m-=(d&&A===w&&w.visualViewport?w.visualViewport.height:A[E])-n.height,m*=l?1:-1),s!==Vt&&(s!==zt&&s!==Rt||o!==Yt)||(v=qt,f-=(d&&A===w&&w.visualViewport?w.visualViewport.width:A[T])-n.width,f*=l?1:-1)}var C,O=Object.assign({position:a},c&&He),x=!0===h?function(t,e){var i=t.x,n=t.y,s=e.devicePixelRatio||1;return{x:we(i*s)/s||0,y:we(n*s)/s||0}}({x:f,y:m},fe(i)):{x:f,y:m};return f=x.x,m=x.y,l?Object.assign({},O,((C={})[y]=b?"0":"",C[v]=_?"0":"",C.transform=(w.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",C)):Object.assign({},O,((e={})[y]=b?m+"px":"",e[v]=_?f+"px":"",e.transform="",e))}const Be={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:be(e.placement),variation:Fe(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s,isFixed:"fixed"===e.options.strategy};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,We(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,We(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var ze={passive:!0};const Re={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=fe(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,ze)})),a&&l.addEventListener("resize",i.update,ze),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,ze)})),a&&l.removeEventListener("resize",i.update,ze)}},data:{}};var qe={left:"right",right:"left",bottom:"top",top:"bottom"};function Ve(t){return t.replace(/left|right|bottom|top/g,(function(t){return qe[t]}))}var Ke={start:"end",end:"start"};function Qe(t){return t.replace(/start|end/g,(function(t){return Ke[t]}))}function Xe(t){var e=fe(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Ye(t){return Te(Le(t)).left+Xe(t).scrollLeft}function Ue(t){var e=xe(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ge(t){return["html","body","#document"].indexOf(ue(t))>=0?t.ownerDocument.body:me(t)&&Ue(t)?t:Ge(Se(t))}function Je(t,e){var i;void 0===e&&(e=[]);var n=Ge(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=fe(n),r=s?[o].concat(o.visualViewport||[],Ue(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Je(Se(r)))}function Ze(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function ti(t,e,i){return e===Gt?Ze(function(t,e){var i=fe(t),n=Le(t),s=i.visualViewport,o=n.clientWidth,r=n.clientHeight,a=0,l=0;if(s){o=s.width,r=s.height;var c=Ee();(c||!c&&"fixed"===e)&&(a=s.offsetLeft,l=s.offsetTop)}return{width:o,height:r,x:a+Ye(t),y:l}}(t,i)):pe(e)?function(t,e){var i=Te(t,!1,"fixed"===e);return i.top=i.top+t.clientTop,i.left=i.left+t.clientLeft,i.bottom=i.top+t.clientHeight,i.right=i.left+t.clientWidth,i.width=t.clientWidth,i.height=t.clientHeight,i.x=i.left,i.y=i.top,i}(e,i):Ze(function(t){var e,i=Le(t),n=Xe(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ve(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ve(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Ye(t),l=-n.scrollTop;return"rtl"===xe(s||i).direction&&(a+=ve(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Le(t)))}function ei(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?be(s):null,r=s?Fe(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case zt:e={x:a,y:i.y-n.height};break;case Rt:e={x:a,y:i.y+i.height};break;case qt:e={x:i.x+i.width,y:l};break;case Vt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?Ie(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case Xt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Yt:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ii(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.strategy,r=void 0===o?t.strategy:o,a=i.boundary,l=void 0===a?Ut:a,c=i.rootBoundary,h=void 0===c?Gt:c,d=i.elementContext,u=void 0===d?Jt:d,f=i.altBoundary,p=void 0!==f&&f,m=i.padding,g=void 0===m?0:m,_=Pe("number"!=typeof g?g:je(g,Qt)),b=u===Jt?Zt:Jt,v=t.rects.popper,y=t.elements[p?b:u],w=function(t,e,i,n){var s="clippingParents"===e?function(t){var e=Je(Se(t)),i=["absolute","fixed"].indexOf(xe(t).position)>=0&&me(t)?$e(t):t;return pe(i)?e.filter((function(t){return pe(t)&&Oe(t,i)&&"body"!==ue(t)})):[]}(t):[].concat(e),o=[].concat(s,[i]),r=o[0],a=o.reduce((function(e,i){var s=ti(t,i,n);return e.top=ve(s.top,e.top),e.right=ye(s.right,e.right),e.bottom=ye(s.bottom,e.bottom),e.left=ve(s.left,e.left),e}),ti(t,r,n));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}(pe(y)?y:y.contextElement||Le(t.elements.popper),l,h,r),A=Te(t.elements.reference),E=ei({reference:A,element:v,strategy:"absolute",placement:s}),T=Ze(Object.assign({},v,E)),C=u===Jt?T:A,O={top:w.top-C.top+_.top,bottom:C.bottom-w.bottom+_.bottom,left:w.left-C.left+_.left,right:C.right-w.right+_.right},x=t.modifiersData.offset;if(u===Jt&&x){var k=x[s];Object.keys(O).forEach((function(t){var e=[qt,Rt].indexOf(t)>=0?1:-1,i=[zt,Rt].indexOf(t)>=0?"y":"x";O[t]+=k[i]*e}))}return O}function ni(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?ee:l,h=Fe(n),d=h?a?te:te.filter((function(t){return Fe(t)===h})):Qt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ii(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[be(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const si={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=be(g),b=l||(_!==g&&p?function(t){if(be(t)===Kt)return[];var e=Ve(t);return[Qe(t),e,Qe(e)]}(g):[Ve(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(be(i)===Kt?ni(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,A=new Map,E=!0,T=v[0],C=0;C=0,S=L?"width":"height",D=ii(e,{placement:O,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),$=L?k?qt:Vt:k?Rt:zt;y[S]>w[S]&&($=Ve($));var I=Ve($),N=[];if(o&&N.push(D[x]<=0),a&&N.push(D[$]<=0,D[I]<=0),N.every((function(t){return t}))){T=O,E=!1;break}A.set(O,N)}if(E)for(var P=function(t){var e=v.find((function(e){var i=A.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},j=p?3:1;j>0&&"break"!==P(j);j--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function oi(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function ri(t){return[zt,qt,Rt,Vt].some((function(e){return t[e]>=0}))}const ai={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ii(e,{elementContext:"reference"}),a=ii(e,{altBoundary:!0}),l=oi(r,n),c=oi(a,s,o),h=ri(l),d=ri(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},li={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=ee.reduce((function(t,i){return t[i]=function(t,e,i){var n=be(t),s=[Vt,zt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[Vt,qt].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},ci={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=ei({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},hi={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ii(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=be(e.placement),b=Fe(e.placement),v=!b,y=Ie(_),w="x"===y?"y":"x",A=e.modifiersData.popperOffsets,E=e.rects.reference,T=e.rects.popper,C="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,O="number"==typeof C?{mainAxis:C,altAxis:C}:Object.assign({mainAxis:0,altAxis:0},C),x=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,k={x:0,y:0};if(A){if(o){var L,S="y"===y?zt:Vt,D="y"===y?Rt:qt,$="y"===y?"height":"width",I=A[y],N=I+g[S],P=I-g[D],j=f?-T[$]/2:0,M=b===Xt?E[$]:T[$],F=b===Xt?-T[$]:-E[$],H=e.elements.arrow,W=f&&H?Ce(H):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},z=B[S],R=B[D],q=Ne(0,E[$],W[$]),V=v?E[$]/2-j-q-z-O.mainAxis:M-q-z-O.mainAxis,K=v?-E[$]/2+j+q+R+O.mainAxis:F+q+R+O.mainAxis,Q=e.elements.arrow&&$e(e.elements.arrow),X=Q?"y"===y?Q.clientTop||0:Q.clientLeft||0:0,Y=null!=(L=null==x?void 0:x[y])?L:0,U=I+K-Y,G=Ne(f?ye(N,I+V-Y-X):N,I,f?ve(P,U):P);A[y]=G,k[y]=G-I}if(a){var J,Z="x"===y?zt:Vt,tt="x"===y?Rt:qt,et=A[w],it="y"===w?"height":"width",nt=et+g[Z],st=et-g[tt],ot=-1!==[zt,Vt].indexOf(_),rt=null!=(J=null==x?void 0:x[w])?J:0,at=ot?nt:et-E[it]-T[it]-rt+O.altAxis,lt=ot?et+E[it]+T[it]-rt-O.altAxis:st,ct=f&&ot?function(t,e,i){var n=Ne(t,e,i);return n>i?i:n}(at,et,lt):Ne(f?at:nt,et,f?lt:st);A[w]=ct,k[w]=ct-et}e.modifiersData[n]=k}},requiresIfExists:["offset"]};function di(t,e,i){void 0===i&&(i=!1);var n,s,o=me(e),r=me(e)&&function(t){var e=t.getBoundingClientRect(),i=we(e.width)/t.offsetWidth||1,n=we(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=Le(e),l=Te(t,r,i),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==ue(e)||Ue(a))&&(c=(n=e)!==fe(n)&&me(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:Xe(n)),me(e)?((h=Te(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=Ye(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function ui(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var fi={placement:"bottom",modifiers:[],strategy:"absolute"};function pi(){for(var t=arguments.length,e=new Array(t),i=0;iNumber.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(F.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...g(this._config.popperConfig,[t])}}_selectMenuItem({key:t,target:e}){const i=z.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>a(t)));i.length&&b(i,e,t===Ti,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=qi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=z.find(Ni);for(const i of e){const e=qi.getInstance(i);if(!e||!1===e._config.autoClose)continue;const n=t.composedPath(),s=n.includes(e._menu);if(n.includes(e._element)||"inside"===e._config.autoClose&&!s||"outside"===e._config.autoClose&&s)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,n=[Ei,Ti].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=this.matches(Ii)?this:z.prev(this,Ii)[0]||z.next(this,Ii)[0]||z.findOne(Ii,t.delegateTarget.parentNode),o=qi.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}N.on(document,Si,Ii,qi.dataApiKeydownHandler),N.on(document,Si,Pi,qi.dataApiKeydownHandler),N.on(document,Li,qi.clearMenus),N.on(document,Di,qi.clearMenus),N.on(document,Li,Ii,(function(t){t.preventDefault(),qi.getOrCreateInstance(this).toggle()})),m(qi);const Vi="backdrop",Ki="show",Qi=`mousedown.bs.${Vi}`,Xi={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Yi={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class Ui extends H{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return Xi}static get DefaultType(){return Yi}static get NAME(){return Vi}show(t){if(!this._config.isVisible)return void g(t);this._append();const e=this._getElement();this._config.isAnimated&&d(e),e.classList.add(Ki),this._emulateAnimation((()=>{g(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(Ki),this._emulateAnimation((()=>{this.dispose(),g(t)}))):g(t)}dispose(){this._isAppended&&(N.off(this._element,Qi),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=r(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),N.on(t,Qi,(()=>{g(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){_(t,this._getElement(),this._config.isAnimated)}}const Gi=".bs.focustrap",Ji=`focusin${Gi}`,Zi=`keydown.tab${Gi}`,tn="backward",en={autofocus:!0,trapElement:null},nn={autofocus:"boolean",trapElement:"element"};class sn extends H{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return en}static get DefaultType(){return nn}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),N.off(document,Gi),N.on(document,Ji,(t=>this._handleFocusin(t))),N.on(document,Zi,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,N.off(document,Gi))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=z.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===tn?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?tn:"forward")}}const on=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",rn=".sticky-top",an="padding-right",ln="margin-right";class cn{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,an,(e=>e+t)),this._setElementAttributes(on,an,(e=>e+t)),this._setElementAttributes(rn,ln,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,an),this._resetElementAttributes(on,an),this._resetElementAttributes(rn,ln)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(s))}px`)}))}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&F.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=F.getDataAttribute(t,e);null!==i?(F.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(o(t))e(t);else for(const i of z.find(t,this._element))e(i)}}const hn=".bs.modal",dn=`hide${hn}`,un=`hidePrevented${hn}`,fn=`hidden${hn}`,pn=`show${hn}`,mn=`shown${hn}`,gn=`resize${hn}`,_n=`click.dismiss${hn}`,bn=`mousedown.dismiss${hn}`,vn=`keydown.dismiss${hn}`,yn=`click${hn}.data-api`,wn="modal-open",An="show",En="modal-static",Tn={backdrop:!0,focus:!0,keyboard:!0},Cn={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class On extends W{constructor(t,e){super(t,e),this._dialog=z.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new cn,this._addEventListeners()}static get Default(){return Tn}static get DefaultType(){return Cn}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||N.trigger(this._element,pn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(wn),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(N.trigger(this._element,dn).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(An),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){N.off(window,hn),N.off(this._dialog,hn),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Ui({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=z.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),d(this._element),this._element.classList.add(An),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,N.trigger(this._element,mn,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){N.on(this._element,vn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),N.on(window,gn,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),N.on(this._element,bn,(t=>{N.one(this._element,_n,(e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(wn),this._resetAdjustments(),this._scrollBar.reset(),N.trigger(this._element,fn)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(N.trigger(this._element,un).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(En)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(En),this._queueCallback((()=>{this._element.classList.remove(En),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=p()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=p()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=On.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}N.on(document,yn,'[data-bs-toggle="modal"]',(function(t){const e=z.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),N.one(e,pn,(t=>{t.defaultPrevented||N.one(e,fn,(()=>{a(this)&&this.focus()}))}));const i=z.findOne(".modal.show");i&&On.getInstance(i).hide(),On.getOrCreateInstance(e).toggle(this)})),R(On),m(On);const xn=".bs.offcanvas",kn=".data-api",Ln=`load${xn}${kn}`,Sn="show",Dn="showing",$n="hiding",In=".offcanvas.show",Nn=`show${xn}`,Pn=`shown${xn}`,jn=`hide${xn}`,Mn=`hidePrevented${xn}`,Fn=`hidden${xn}`,Hn=`resize${xn}`,Wn=`click${xn}${kn}`,Bn=`keydown.dismiss${xn}`,zn={backdrop:!0,keyboard:!0,scroll:!1},Rn={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class qn extends W{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return zn}static get DefaultType(){return Rn}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||N.trigger(this._element,Nn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new cn).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(Dn),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(Sn),this._element.classList.remove(Dn),N.trigger(this._element,Pn,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(N.trigger(this._element,jn).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add($n),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove(Sn,$n),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new cn).reset(),N.trigger(this._element,Fn)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Ui({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():N.trigger(this._element,Mn)}:null})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_addEventListeners(){N.on(this._element,Bn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():N.trigger(this._element,Mn))}))}static jQueryInterface(t){return this.each((function(){const e=qn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}N.on(document,Wn,'[data-bs-toggle="offcanvas"]',(function(t){const e=z.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this))return;N.one(e,Fn,(()=>{a(this)&&this.focus()}));const i=z.findOne(In);i&&i!==e&&qn.getInstance(i).hide(),qn.getOrCreateInstance(e).toggle(this)})),N.on(window,Ln,(()=>{for(const t of z.find(In))qn.getOrCreateInstance(t).show()})),N.on(window,Hn,(()=>{for(const t of z.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&qn.getOrCreateInstance(t).hide()})),R(qn),m(qn);const Vn={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],dd:[],div:[],dl:[],dt:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Kn=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Qn=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,Xn=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!Kn.has(i)||Boolean(Qn.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},Yn={allowList:Vn,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:""},Un={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},Gn={entry:"(string|element|function|null)",selector:"(string|element)"};class Jn extends H{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Yn}static get DefaultType(){return Un}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},Gn)}_setContent(t,e,i){const n=z.findOne(i,t);n&&((e=this._resolvePossibleFunction(e))?o(e)?this._putElementInTemplate(r(e),n):this._config.html?n.innerHTML=this._maybeSanitize(e):n.textContent=e:n.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(const t of s){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const n=[].concat(...t.attributes),s=[].concat(e["*"]||[],e[i]||[]);for(const e of n)Xn(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return g(t,[this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const Zn=new Set(["sanitize","allowList","sanitizeFn"]),ts="fade",es="show",is=".modal",ns="hide.bs.modal",ss="hover",os="focus",rs={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},as={allowList:Vn,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},ls={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class cs extends W{constructor(t,e){if(void 0===vi)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return as}static get DefaultType(){return ls}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._activeTrigger.click=!this._activeTrigger.click,this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),N.off(this._element.closest(is),ns,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=N.trigger(this._element,this.constructor.eventName("show")),e=(c(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:n}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(n.append(i),N.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.on(t,"mouseover",h);this._queueCallback((()=>{N.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!N.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.off(t,"mouseover",h);this._activeTrigger.click=!1,this._activeTrigger[os]=!1,this._activeTrigger[ss]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),N.trigger(this._element,this.constructor.eventName("hidden")))}),this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(ts,es),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(ts),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new Jn({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{".tooltip-inner":this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(ts)}_isShown(){return this.tip&&this.tip.classList.contains(es)}_createPopper(t){const e=g(this._config.placement,[this,t,this._element]),i=rs[e.toUpperCase()];return bi(this._element,t,this._getPopperConfig(i))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return g(t,[this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...g(this._config.popperConfig,[e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)N.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if("manual"!==e){const t=e===ss?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===ss?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");N.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?os:ss]=!0,e._enter()})),N.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?os:ss]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},N.on(this._element.closest(is),ns,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=F.getDataAttributes(this._element);for(const t of Object.keys(e))Zn.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const e=cs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(cs);const hs={...cs.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},ds={...cs.DefaultType,content:"(null|string|element|function)"};class us extends cs{static get Default(){return hs}static get DefaultType(){return ds}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{".popover-header":this._getTitle(),".popover-body":this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=us.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(us);const fs=".bs.scrollspy",ps=`activate${fs}`,ms=`click${fs}`,gs=`load${fs}.data-api`,_s="active",bs="[href]",vs=".nav-link",ys=`${vs}, .nav-item > ${vs}, .list-group-item`,ws={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},As={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Es extends W{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return ws}static get DefaultType(){return As}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=r(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(N.off(this._config.target,ms),N.on(this._config.target,ms,bs,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,n=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:n,behavior:"smooth"});i.scrollTop=n}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},n=(this._rootElement||document.documentElement).scrollTop,s=n>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=n;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(s&&t){if(i(o),!n)return}else s||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=z.find(bs,this._config.target);for(const e of t){if(!e.hash||l(e))continue;const t=z.findOne(decodeURI(e.hash),this._element);a(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(_s),this._activateParents(t),N.trigger(this._element,ps,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))z.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(_s);else for(const e of z.parents(t,".nav, .list-group"))for(const t of z.prev(e,ys))t.classList.add(_s)}_clearActiveClass(t){t.classList.remove(_s);const e=z.find(`${bs}.${_s}`,t);for(const t of e)t.classList.remove(_s)}static jQueryInterface(t){return this.each((function(){const e=Es.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(window,gs,(()=>{for(const t of z.find('[data-bs-spy="scroll"]'))Es.getOrCreateInstance(t)})),m(Es);const Ts=".bs.tab",Cs=`hide${Ts}`,Os=`hidden${Ts}`,xs=`show${Ts}`,ks=`shown${Ts}`,Ls=`click${Ts}`,Ss=`keydown${Ts}`,Ds=`load${Ts}`,$s="ArrowLeft",Is="ArrowRight",Ns="ArrowUp",Ps="ArrowDown",js="Home",Ms="End",Fs="active",Hs="fade",Ws="show",Bs=".dropdown-toggle",zs=`:not(${Bs})`,Rs='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',qs=`.nav-link${zs}, .list-group-item${zs}, [role="tab"]${zs}, ${Rs}`,Vs=`.${Fs}[data-bs-toggle="tab"], .${Fs}[data-bs-toggle="pill"], .${Fs}[data-bs-toggle="list"]`;class Ks extends W{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),N.on(this._element,Ss,(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?N.trigger(e,Cs,{relatedTarget:t}):null;N.trigger(t,xs,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(Fs),this._activate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),N.trigger(t,ks,{relatedTarget:e})):t.classList.add(Ws)}),t,t.classList.contains(Hs)))}_deactivate(t,e){t&&(t.classList.remove(Fs),t.blur(),this._deactivate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),N.trigger(t,Os,{relatedTarget:e})):t.classList.remove(Ws)}),t,t.classList.contains(Hs)))}_keydown(t){if(![$s,Is,Ns,Ps,js,Ms].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!l(t)));let i;if([js,Ms].includes(t.key))i=e[t.key===js?0:e.length-1];else{const n=[Is,Ps].includes(t.key);i=b(e,t.target,n,!0)}i&&(i.focus({preventScroll:!0}),Ks.getOrCreateInstance(i).show())}_getChildren(){return z.find(qs,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=z.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const n=(t,n)=>{const s=z.findOne(t,i);s&&s.classList.toggle(n,e)};n(Bs,Fs),n(".dropdown-menu",Ws),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(Fs)}_getInnerElement(t){return t.matches(qs)?t:z.findOne(qs,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=Ks.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(document,Ls,Rs,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this)||Ks.getOrCreateInstance(this).show()})),N.on(window,Ds,(()=>{for(const t of z.find(Vs))Ks.getOrCreateInstance(t)})),m(Ks);const Qs=".bs.toast",Xs=`mouseover${Qs}`,Ys=`mouseout${Qs}`,Us=`focusin${Qs}`,Gs=`focusout${Qs}`,Js=`hide${Qs}`,Zs=`hidden${Qs}`,to=`show${Qs}`,eo=`shown${Qs}`,io="hide",no="show",so="showing",oo={animation:"boolean",autohide:"boolean",delay:"number"},ro={animation:!0,autohide:!0,delay:5e3};class ao extends W{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return ro}static get DefaultType(){return oo}static get NAME(){return"toast"}show(){N.trigger(this._element,to).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(io),d(this._element),this._element.classList.add(no,so),this._queueCallback((()=>{this._element.classList.remove(so),N.trigger(this._element,eo),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(N.trigger(this._element,Js).defaultPrevented||(this._element.classList.add(so),this._queueCallback((()=>{this._element.classList.add(io),this._element.classList.remove(so,no),N.trigger(this._element,Zs)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(no),super.dispose()}isShown(){return this._element.classList.contains(no)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){N.on(this._element,Xs,(t=>this._onInteraction(t,!0))),N.on(this._element,Ys,(t=>this._onInteraction(t,!1))),N.on(this._element,Us,(t=>this._onInteraction(t,!0))),N.on(this._element,Gs,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=ao.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(ao),m(ao),{Alert:Q,Button:Y,Carousel:xt,Collapse:Bt,Dropdown:qi,Modal:On,Offcanvas:qn,Popover:us,ScrollSpy:Es,Tab:Ks,Toast:ao,Tooltip:cs}}));
7 | //# sourceMappingURL=bootstrap.bundle.min.js.map
--------------------------------------------------------------------------------