Коммит 745d8c89 создал по автору avathar's avatar avathar
Просмотр файлов

#140 продолжен рефакторинг типизации

1 запрос на слияние!89um#217 Проект на Quasar+Phaser выделен в отдельный репозиторий
Конвейер #7178 пройдено in 6 минут и 12 секунд
Отображение с 132 дополнений и 117 удаления
+132 -117
......@@ -23,7 +23,7 @@
"**/*.vue"
],
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
"editor.defaultFormatter": "Vue.volar"
},
"editor.fontLigatures": true,
"diffEditor.codeLens": true,
......
import { ObjectWrapper, TreeNode } from 'src/types/stores/kanvaso';
import { ObjectWrapper } from 'src/types/stores/kanvaso';
import {
COLOR_LIGHT,
COLOR_PRIMARY,
......@@ -6,14 +6,16 @@ import {
DefaultDepth,
DragObjectDepth,
} from '../kanbans/Const';
import { Label, Scene } from 'src/types/kanban_types';
import { EndlessCanvas } from 'src/types/kanban_types';
const CreateItem = (
scene: Scene,
scene: EndlessCanvas,
card: ObjectWrapper,
registry: Phaser.Data.DataManager,
): Label => {
const item: Label = scene.rexUI.add.label({
) => {
const item = scene.rexUI.add.label({
//@ts-ignore
background: scene.rexUI.add.roundRectangle({
radius: 10,
color: COLOR_PRIMARY,
......@@ -40,7 +42,7 @@ const CreateItem = (
return item;
};
const SetDraggable = (item: Label): void => {
const SetDraggable = (item): void => {
item
.setDraggable({
sensor: item,
......@@ -50,12 +52,12 @@ const SetDraggable = (item: Label): void => {
.on('sizer.dragend', () => OnItemDragEnd.call(item));
};
const OnItemDragStart = function (this: Label): void {
const OnItemDragStart = function (this): void {
this.setDepth(DragObjectDepth);
this.getElement('background').setStrokeStyle(3, 0xff0000);
};
const OnItemDragEnd = function (this: Label): void {
const OnItemDragEnd = function (this): void {
this.setDepth(DefaultDepth);
this.getElement('background').setStrokeStyle();
// console.log(this);
......
// import { COLOR_LIGHT, COLOR_PRIMARY, COLOR_DARK } from './Const';
import CreateItem from './CreateItem';
import AddDragDropItemBehavior from '../kanbans/AddDragDropItemBehavior';
import { ObjectWrapper, TreeNode } from 'src/types/stores/kanvaso';
import { ItemsBoxType, Scene, Sizer } from 'src/types/kanban_types';
import { ObjectWrapper } from 'src/types/stores/kanvaso';
import { ItemsBoxType, EndlessCanvas } from 'src/types/kanban_types';
const CreateItemsBox = (
scene: Scene,
scene: EndlessCanvas,
cards: ObjectWrapper[],
registry: Phaser.Data.DataManager,
): Sizer => {
const itemsBox: ItemsBoxType = scene.rexUI.add.sizer({
) => {
const itemsBox = scene.rexUI.add.sizer({
orientation: 'y',
space: {
left: 5,
......@@ -19,6 +19,7 @@ const CreateItemsBox = (
item: 5,
},
}) as undefined as ItemsBoxType;
//@ts-ignore
itemsBox.addBackground(scene.rexUI.add.roundRectangle({}), 'background');
if (cards.length) {
......
// @ts-nocheck
import { ItemType, ItemsBoxType } from 'src/types/kanban_types';
import GetNeighborObjects from './GetNeighborObjects';
const AddDragDropItemBehavior = (itemsBox: ItemsBoxType): void => {
......@@ -56,9 +56,14 @@ const AddDragDropItemBehavior = (itemsBox: ItemsBoxType): void => {
const currentItemsBox = dropZone.getData('itemsBox') as ItemsBoxType;
const previousItemsBox = item.getData('itemsBox') as ItemsBoxType;
currentItemsBox.insertAtPosition(pointer.x, pointer.y, item, {
expand: true,
});
currentItemsBox.insertAtPosition(
pointer.x,
pointer.y,
item as unknown as Phaser.GameObjects.Text,
{
expand: true,
},
);
ArrangeItems(previousItemsBox, currentItemsBox);
const neighbors = GetNeighborObjects(item);
......@@ -79,7 +84,9 @@ type InteractiveItemType = ItemType & {
};
const AddDropZone = (itemsBox: ItemsBoxType): void => {
const background = itemsBox.getElement('background') as InteractiveItemType;
const background = itemsBox.getElement(
'background',
) as unknown as InteractiveItemType;
if (background && typeof background.setInteractive === 'function') {
background.setInteractive({ dropZone: true });
background.setData('itemsBox', itemsBox);
......@@ -108,6 +115,8 @@ const ArrangeItems = (
const fromX = item.getData('startX') as number;
const fromY = item.getData('startY') as number;
if (item.x !== fromX || item.y !== fromY) {
//@ts-ignore
item.moveFrom({ x: fromX, y: fromY, duration: 300 });
}
}
......
// @ts-nocheck
// import stretchingIcon from './Stretching_icon1.png';
const AddResizeController = (sizer: Phaser.GameObjects.Container): void => {
const AddResizeController = (sizer): void => {
const scene = sizer.scene;
const offsetX = 20;
......
......@@ -2,18 +2,19 @@ import { ObjectWrapper, TreeNode } from 'src/types/stores/kanvaso';
import { COLOR_LIGHT, COLOR_PRIMARY, COLOR_DARK } from './Const';
import { DefaultDepth, DragObjectDepth } from './Const';
import CreateItemsBox from '../cards/CreateItemsBox';
import UIPlugin from 'src/types/ui-plugin';
import { Scene } from 'src/types/kanban_types';
import { EndlessCanvas } from 'src/types/kanban_types';
const CreateColumnPanel = (
scene: Scene,
scene: EndlessCanvas,
column: ObjectWrapper,
registry: Phaser.Data.DataManager,
) => {
const panel: UIPlugin.Dialog = scene.rexUI.add
const panel = scene.rexUI.add
.dialog({
width: 120,
space: { left: 10, right: 10, top: 10, bottom: 10 },
//@ts-ignore
background: scene.rexUI.add.roundRectangle({
strokeColor: COLOR_DARK,
radius: 0,
......@@ -36,11 +37,13 @@ const CreateColumnPanel = (
};
const CreateTitle = (
scene: Scene,
scene: EndlessCanvas,
column: ObjectWrapper,
registry: Phaser.Data.DataManager,
) => {
const title = scene.rexUI.add.label({
//@ts-ignore
background: scene.rexUI.add.roundRectangle({
color: COLOR_LIGHT,
}),
......
import { COLOR_LIGHT, COLOR_PRIMARY, COLOR_DARK } from './Const';
import CreateColumnPanel from './CreateColumnPanel';
import AddDragDropColumnPanelBehavior from './AddDragDropColumnPanelBehavior';
import { ObjectWrapper, TreeNode } from 'src/types/stores/kanvaso';
import { Sizer } from 'src/types/ui-components';
import { PanelsBoxType, Scene, SizerConfig } from 'src/types/kanban_types';
import { ObjectWrapper } from 'src/types/stores/kanvaso';
import { PanelsBoxType, EndlessCanvas } from 'src/types/kanban_types';
const CreateColumnPanelsBox = (
scene: Scene,
scene: EndlessCanvas,
swimlane: ObjectWrapper,
registry: Phaser.Data.DataManager,
): Sizer => {
const config: SizerConfig = {
) => {
const config = {
orientation: 'x',
space: {
left: 10,
......@@ -19,10 +18,9 @@ const CreateColumnPanelsBox = (
bottom: 10,
},
};
//@ts-ignore
const columnPanelsBox: PanelsBoxType = scene.rexUI.add.sizer(
config,
) as unknown as PanelsBoxType;
const columnPanelsBox = scene.rexUI.add.sizer(config) as PanelsBoxType;
// .addBackground(
// scene.rexUI.add.roundRectangle({
// strokeColor: COLOR_PRIMARY,
......
......@@ -2,20 +2,20 @@ import { COLOR_LIGHT, COLOR_PRIMARY, COLOR_DARK } from './Const';
import GetMaxTextObjectSize from './GetMaxTextObjectSize';
import CreateTextObject from './CreateTextObject';
import CreatePopupList from './CreatePopupList';
import { Scene, TextObject } from 'src/types/kanban_types';
import { Label, Menu } from 'src/types/ui-components';
import { EndlessCanvas } from 'src/types/kanban_types';
const CreateDropDownList = function (scene: Scene): Label {
const CreateDropDownList = function (scene: EndlessCanvas) {
const options = ['Добавить столбец', 'Переименовать доску'];
const maxTextSize = GetMaxTextObjectSize(scene, options);
const label: Label = scene.rexUI.add
const label = scene.rexUI.add
.label({
background: scene.rexUI.add
.roundRectangle(0, 0, 2, 2, 0, COLOR_PRIMARY)
.setAlpha(0),
text: (
CreateTextObject(scene, '...') as unknown as TextObject
).setFixedSize(maxTextSize.width, maxTextSize.height),
text: CreateTextObject(scene, '...').setFixedSize(
maxTextSize.width,
maxTextSize.height,
),
space: {
left: 10,
right: 10,
......@@ -26,10 +26,12 @@ const CreateDropDownList = function (scene: Scene): Label {
})
.setData('value', '');
let menu: Menu;
let menu;
scene.rexUI.add.click(label).on('click', () => {
if (!menu || !menu.scene) {
//@ts-ignore
const menuX = label.getElement('text').getTopLeft().x;
const menuY = label.bottom;
menu = CreatePopupList(scene, menuX, menuY, options, function (button) {
......
import { ObjectWrapper, TreeNode } from 'src/types/stores/kanvaso';
import { COLOR_LIGHT, COLOR_PRIMARY, COLOR_DARK } from './Const';
import CreateDropDownList from './CreateDropDownList';
import { Scene } from 'src/types/kanban_types';
import { Sizer } from 'src/types/ui-components';
import { EndlessCanvas } from 'src/types/kanban_types';
const CreateHeader = function (
scene: Scene,
scene: EndlessCanvas,
board: ObjectWrapper,
registry: Phaser.Data.DataManager,
) {
const sizer: Sizer = scene.rexUI.add
const sizer = scene.rexUI.add
.sizer({
orientation: 'x',
})
......
import { Scene } from 'src/types/kanban_types';
import { EndlessCanvas } from 'src/types/kanban_types';
const CreateModalLabel = (
scene: Scene,
text: string,
): Phaser.GameObjects.Container => {
const CreateModalLabel = (scene: EndlessCanvas, text: string) => {
const normalBackground = scene.rexUI.add.roundRectangle(
0,
0,
......@@ -50,6 +47,6 @@ const CreateModalLabel = (
button.setElement('background', normalBackground);
});
return label as any;
return label;
};
export default CreateModalLabel;
......@@ -2,16 +2,15 @@ import { COLOR_LIGHT, COLOR_PRIMARY, COLOR_DARK } from './Const';
import CreateTextObject from './CreateTextObject';
import CreateRequestModalColumn from './CreateRequestModalColumn';
import CreateRequestModalBoard from './CreateRequestModalBoard';
import { Scene } from 'src/types/kanban_types';
import { Menu } from 'src/types/ui-components';
import { EndlessCanvas } from 'src/types/kanban_types';
const CreatePopupList = function (
scene: Scene,
scene: EndlessCanvas,
x: number,
y: number,
options: string[],
onClick: (button: Phaser.GameObjects.Text) => void,
): Menu {
) {
const items = options.map((option) => ({ label: option }));
const menu = scene.rexUI.add.menu({
x: x,
......@@ -21,7 +20,7 @@ const CreatePopupList = function (
createButtonCallback: (item, i, options) => {
return scene.rexUI.add.label({
background: scene.rexUI.add.roundRectangle(0, 0, 2, 2, 0, COLOR_DARK),
text: CreateTextObject(scene, item.label) as any,
text: CreateTextObject(scene, item.label),
space: {
left: 10,
right: 10,
......@@ -41,13 +40,13 @@ const CreatePopupList = function (
},
});
menu.on('button.click', function (button) {
menu.on('button.click', function (button: Phaser.GameObjects.Text) {
if (button.text === 'Добавить столбец') {
CreateRequestModalColumn(scene)
.setPosition(400, 300)
.layout()
.modalPromise({
manaulClose: true,
manualClose: true,
duration: {
in: 500,
out: 500,
......@@ -61,7 +60,7 @@ const CreatePopupList = function (
.setPosition(400, 300)
.layout()
.modalPromise({
manaulClose: true,
manualClose: true,
duration: {
in: 500,
out: 500,
......
import { Scene } from 'src/types/kanban_types';
import { EndlessCanvas } from 'src/types/kanban_types';
import { COLOR_LIGHT, COLOR_PRIMARY, COLOR_DARK } from './Const';
import CreateModalLabel from './CreateModalLabel';
const CreateRequestModalBoard = (scene: Scene): any => {
const CreateRequestModalBoard = (scene: EndlessCanvas) => {
const content = '1';
const textArea = scene.rexUI.add
......@@ -28,6 +28,8 @@ const CreateRequestModalBoard = (scene: Scene): any => {
style: {
fontSize: 20,
//@ts-ignore
backgroundBottomY: 1,
backgroundHeight: 20,
cursor: {
......@@ -78,6 +80,8 @@ const CreateRequestModalBoard = (scene: Scene): any => {
.setDepth(3);
const dialog = scene.rexUI.add
.dialog({
//@ts-ignore
minWidth: 650,
background: scene.rexUI.add
.roundRectangle(0, 0, 1020, 100, 20, 0xffffff) // Увеличена ширина
......
import { Scene } from 'src/types/kanban_types';
import { EndlessCanvas } from 'src/types/kanban_types';
import { COLOR_LIGHT, COLOR_PRIMARY, COLOR_DARK } from './Const';
import CreateModalLabel from './CreateModalLabel';
import { TextAreaInput } from 'src/types/ui-components';
const CreateRequestModalColumn = (scene: Scene): any => {
const CreateRequestModalColumn = (scene: EndlessCanvas) => {
const content = '';
const textArea: TextAreaInput = scene.rexUI.add
const textArea = scene.rexUI.add
.textAreaInput({
x: 400,
y: 300,
......@@ -28,6 +27,8 @@ const CreateRequestModalColumn = (scene: Scene): any => {
},
style: {
fontSize: 20,
//@ts-ignore
backgroundBottomY: 1,
backgroundHeight: 20,
cursor: {
......@@ -78,6 +79,8 @@ const CreateRequestModalColumn = (scene: Scene): any => {
.setDepth(3);
const dialog = scene.rexUI.add
.dialog({
//@ts-ignore
minWidth: 650,
background: scene.rexUI.add
.roundRectangle(0, 0, 1020, 100, 20, 0xffffff) // Увеличена ширина
......
......@@ -7,19 +7,19 @@ import CreateHeader from './CreateHeader';
import AddResizeController from './AddResizeController';
import { ObjectWrapper, TreeNode } from 'src/types/stores/kanvaso';
import CreateSwimlanePanelsBox from './CreateSwimlanePanelsBox';
import { Container, ScrollablePanel } from 'src/types/ui-components';
import { Scene } from 'src/types/kanban_types';
import { EndlessCanvas } from 'src/types/kanban_types';
const CreateScrollablePanel = (
scene: Scene,
scene: EndlessCanvas,
board: ObjectWrapper,
registry: Phaser.Data.DataManager,
size: { w: number; h: number },
): ScrollablePanel => {
const config: ScrollablePanel.SizerConfig = {
) => {
const config = {
adaptThumbSizeMode: true,
width: size.w - 30,
height: size.h - 30,
//@ts-ignore
background: scene.rexUI.add.roundRectangle({
radius: 10,
strokeColor: COLOR_DARK,
......@@ -57,8 +57,9 @@ const CreateScrollablePanel = (
};
// Создаем ScrollablePanel
const scrollablePanel: ScrollablePanel =
scene.rexUI.add.scrollablePanel(config);
//@ts-ignore
const scrollablePanel = scene.rexUI.add.scrollablePanel(config);
// Устанавливаем возможность перетаскивания
scrollablePanel.setDraggable('header');
......@@ -73,7 +74,7 @@ const CreateScrollablePanel = (
};
const CreateMoreScrollablePanels = (
scene: Scene,
scene: EndlessCanvas,
boards: ObjectWrapper[],
registry: Phaser.Data.DataManager,
size: { h: number; w: number },
......@@ -82,4 +83,4 @@ const CreateMoreScrollablePanels = (
CreateScrollablePanel(scene, board, registry, size),
);
//@ts-ignore
export default CreateMoreScrollablePanels as CreateScrollablePanel;
export default CreateMoreScrollablePanels;
import { COLOR_LIGHT, COLOR_PRIMARY, COLOR_DARK } from './Const';
import CreateColumnPanel from './CreateColumnPanel';
import AddDragDropColumnPanelBehavior from './AddDragDropColumnPanelBehavior';
import { ObjectWrapper, TreeNode } from 'src/types/stores/kanvaso';
import { ObjectWrapper } from 'src/types/stores/kanvaso';
import CreateColumnPanelsBox from './CreateColumnPanelsBox';
import CreateHeader from './CreateHeader';
import { PanelsBoxType, Scene, SizerConfig } from 'src/types/kanban_types';
import { Sizer } from 'src/types/ui-components';
import { PanelsBoxType, EndlessCanvas } from 'src/types/kanban_types';
const CreateSwimlanePanelBox = (
scene: Scene,
scene: EndlessCanvas,
board: ObjectWrapper,
registry: Phaser.Data.DataManager,
): Sizer => {
const config: SizerConfig = {
) => {
const config = {
orientation: 'y',
sliderX: {
track: { width: 20, radius: 10, color: COLOR_DARK },
......@@ -37,10 +36,9 @@ const CreateSwimlanePanelBox = (
sliderY: 10,
},
};
//@ts-ignore
const swimlanePanelsBox: PanelsBoxType = scene.rexUI.add.sizer(
config,
) as undefined as PanelsBoxType;
const swimlanePanelsBox = scene.rexUI.add.sizer(config) as PanelsBoxType;
// .addBackground(
// scene.rexUI.add.roundRectangle({
// strokeColor: COLOR_PRIMARY,
......
import { Scene } from 'src/types/kanban_types';
import { EndlessCanvas } from 'src/types/kanban_types';
const CreateTextObject = function (scene: Scene, text: string): any {
const CreateTextObject = function (scene: EndlessCanvas, text: string): any {
return scene.add.text(0, 0, text, {
fontSize: '20px',
});
......
import { Scene } from 'src/types/kanban_types';
import { EndlessCanvas } from 'src/types/kanban_types';
import { COLOR_LIGHT, COLOR_PRIMARY, COLOR_DARK } from './Const';
import CreateTextObject from './CreateTextObject';
const GetMaxTextObjectSize = function (
scene: Scene,
scene: EndlessCanvas,
contentArray: string[],
): { width: number; height: number } {
const textObject = CreateTextObject(
......
<template>
<div
id="loading-screen"
style="
<div id="loading-screen" style="
position: absolute;
width: 100%;
height: 100%;
......@@ -10,8 +8,7 @@
display: flex;
align-items: center;
justify-content: center;
"
>
">
<img src="images/logo.png" alt="Loading..." id="loading-logo" />
</div>
<div id="phaser-container"></div>
......@@ -21,7 +18,7 @@
import 'phaser';
// import 'phaser3-rex-plugins/templates/ui/ui-plugin';
// import 'phaser3-rex-plugins/templates/ui/ui-components';
import CreateScrollablePanel from '../kanbans/CreateScrollablePanel';
import CreateMoreScrollablePanels from '../kanbans/CreateScrollablePanel';
import { useKanvasoStore } from 'src/stores/kanvaso';
import { mapActions, mapState } from 'pinia';
// import PreloadScene from './PreloadScene';
......@@ -29,17 +26,20 @@ import { mapActions, mapState } from 'pinia';
import { KanvasojKanvaso, TreeNode } from 'src/types/stores/kanvaso';
import CreateToolbar from '../toolbar/CreateToolbar';
import { watch, computed } from 'vue';
import { Router, useRouter } from 'vue-router';
import UIPlugin from 'src/types/ui-plugin';
import { Router } from 'vue-router';
import UIPlugin from 'phaser3-rex-plugins/templates/ui/ui-plugin';
declare const window: {
router: Router;
} & Window;
class EndlessCanvas extends Phaser.Scene {
[x: string]: any;
rexUI: UIPlugin;
registry: Phaser.Data.DataManager;
toolbarWidth: number;
store: any;
router: Router;
objectFields: string[];
constructor() {
super({
key: 'endless-canvas',
......@@ -73,7 +73,6 @@ class EndlessCanvas extends Phaser.Scene {
this.store.getMap.forEach((element) => {
this.registry.set(element.uuid, element);
});
// console.log('this.registry :>> ', this.registry);
//организуем слежение за getMap и в случае его изменения выясняем что изменилось и обновляем данные в registry
const map = computed(() => this.store.getMap);
watch(map, (newData, oldData) => {
......@@ -104,7 +103,9 @@ class EndlessCanvas extends Phaser.Scene {
}
create(): void {
const toolbar = CreateToolbar(this, this.router);
const scene = this;
//@ts-ignore
const toolbar = CreateToolbar(scene, scene.router);
// const back = this.add
// .text(0, 0, '<<', {
// fontSize: '24px',
......@@ -116,27 +117,28 @@ class EndlessCanvas extends Phaser.Scene {
// back.on('pointerdown', () => {
// this.router.push('/projects');
// });
this.cameras.main.setBackgroundColor('#abcdef');
scene.cameras.main.setBackgroundColor('#abcdef');
// Скрываем экран загрузки здесь, потому что на этом этапе preload уже завершен
document.getElementById('loading-screen').style.display = 'none';
let parent = this.sys.game.canvas.parentElement;
let parent = scene.sys.game.canvas.parentElement;
let parentWidth = parent.offsetWidth;
let parentHeight = parent.offsetHeight;
const numberOfPanels = this.store.getTree.length;
let panelWidth = parentWidth - this.toolbarWidth;
const numberOfPanels = scene.store.getTree.length;
let panelWidth = parentWidth - scene.toolbarWidth;
let panelHeight = parentHeight / numberOfPanels;
let topPanelsArr = CreateScrollablePanel(
this,
this.store.getTree,
this.registry,
let topPanelsArr = CreateMoreScrollablePanels(
//@ts-ignore
scene,
scene.store.getTree,
scene.registry,
{ h: panelHeight, w: panelWidth },
);
for (let i = 0; i < topPanelsArr.length; i++) {
topPanelsArr[i]
.setPosition(
parentWidth / 2 + this.toolbarWidth / 2,
parentWidth / 2 + scene.toolbarWidth / 2,
panelHeight / 2 + i * panelHeight,
)
.layout();
......@@ -144,9 +146,9 @@ class EndlessCanvas extends Phaser.Scene {
// .drawBounds(this.add.graphics(), 0xff0000)}
this.registry.events.on(
scene.registry.events.on(
'changedata',
(parent, key, data, previousData) => {},
(parent, key, data, previousData) => { },
);
}
}
......@@ -166,7 +168,6 @@ const config: Phaser.Types.Core.GameConfig = {
// scene: [
// {
// key: 'rexUI',
// //@ts-ignore
// plugin: RexPlugins,
// mapping: 'rexUI',
// },
......@@ -211,6 +212,7 @@ export default {
const canvas = container.querySelector('canvas');
canvas.style.width = window.innerWidth + 'px';
canvas.style.height = window.innerHeight + 'px';
//FIXME: Ещё можно способом ниже изменять напрямую размеры холста, но это не даёт нужного результата. Размер меняется, но по краям появляются чёрные полосы :(
// //@ts-ignore
// canvas.attributes.width.value = window.innerWidth;
// //@ts-ignore
......@@ -276,7 +278,7 @@ export default {
};
</script>
<style>
#phaser-container > canvas {
#phaser-container>canvas {
margin-top: 0 !important;
}
</style>
import { EndlessCanvas } from 'src/types/kanban_types';
import { Router } from 'vue-router';
function CreateToolbar(scene: Phaser.Scene, router: Router) {
//@ts-ignore
function CreateToolbar(scene: EndlessCanvas, router: Router) {
let toolbarWidth = scene.toolbarWidth; // Ширина панели инструментов
let screenHeight = parseInt(scene.sys.game.config.height as string, 10); // Высота экрана
......
......@@ -111,8 +111,6 @@
</q-page>
</template>
<script lang="ts">
//@ts-nocheck
import { useKanvasoStore } from '../stores/kanvaso';
import { mapActions, mapState } from 'pinia';
import { defineComponent } from 'vue';
......
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать