Привет! Я могу помочь с созданием структуры данных для хранения чат-историй с возможностью выбора ответов и ветвления истории в зависимости от этих ответов.
Одним из подходов может быть использование дерева, где каждый узел представляет собой чат-элемент (например, сообщение или вопрос), а каждая ветвь соответствует возможному ответу на предыдущий элемент. Каждый узел также может содержать информацию о возможных ответах, которые пользователь может выбрать.
Пример структуры данных для этого может выглядеть следующим образом:
json{
"id": 1,
"message": "Привет, как твои дела?",
"options": [
{
"id": 2,
"message": "Хорошо, спасибо! А у тебя?",
"options": [
{
"id": 4,
"message": "Тоже всё хорошо, спасибо!",
"options": []
},
{
"id": 5,
"message": "Немного грустно, но я попытаюсь не думать об этом",
"options": []
}
]
},
{
"id": 3,
"message": "Не очень хорошо, но я надеюсь, что всё наладится",
"options": []
}
]
}
Здесь мы создали корневой узел с сообщением "Привет, как твои дела?" и двумя возможными ответами. Один ответ ведет к узлу с сообщением "Хорошо, спасибо! А у тебя?", который также имеет два возможных ответа. Другой ответ ведет к узлу с сообщением "Не очень хорошо, но я надеюсь, что всё наладится", который не имеет дополнительных возможных ответов.
Вы можете расширить эту структуру данных, чтобы включить другие атрибуты, такие как дополнительная информация о каждом узле (например, автор или время), и определить различные типы узлов в зависимости от цели (например, вопросы или уведомления).
Надеюсь, это поможет вам начать создание структуры данных для вашей чат-истории!
Для различения элементов, которые являются вариантами ответов для пользователя, от элементов, которые являются повествованием, вы можете использовать атрибуты в структуре данных.
Один из способов - это использовать атрибут, который указывает, является ли элемент вариантом ответа или нет. Например, вы можете использовать атрибут "is_option" и установить его значение на "true" для элементов, которые являются вариантами ответа пользователя. Вот пример:
json{
"id": 1,
"message": "Привет, как твои дела?",
"is_option": false,
"options": [
{
"id": 2,
"message": "Хорошо, спасибо! А у тебя?",
"is_option": true,
"options": [
{
"id": 4,
"message": "Тоже всё хорошо, спасибо!",
"is_option": true,
"options": []
},
{
"id": 5,
"message": "Немного грустно, но я попытаюсь не думать об этом",
"is_option": true,
"options": []
}
]
},
{
"id": 3,
"message": "Не очень хорошо, но я надеюсь, что всё наладится",
"is_option": true,
"options": []
}
]
}
В этом примере, мы добавили атрибут "is_option" и установили его значение на "true" для элементов, которые являются вариантами ответа пользователя. Значение по умолчанию для "is_option" равно "false", поэтому если вы не установите его значение, элемент будет считаться элементом повествования.
Надеюсь, это поможет вам различать элементы в вашей структуре данных, которые являются вариантами ответа пользователя от элементов, которые являются повествованием.
Для реализации ответвления истории на основании предыдущих ответов пользователя, вы можете использовать переменные или состояния, которые будут изменяться в зависимости от ответов пользователя и влиять на следующие элементы истории.
Например, вы можете добавить атрибут "state" в структуру данных и хранить текущее состояние истории. Этот атрибут может содержать информацию о симпатиях персонажей истории и других важных факторах, которые будут влиять на развитие сюжета.
Когда пользователь выбирает ответ, вы можете обновлять значение этой переменной в соответствии с выбранным ответом. Затем вы можете использовать это значение, чтобы определить, какие элементы истории будут следующими.
Вот пример:
json{
"id": 1,
"message": "Привет, как твои дела?",
"is_option": false,
"options": [
{
"id": 2,
"message": "Хорошо, спасибо! А у тебя?",
"is_option": true,
"options": [
{
"id": 4,
"message": "Тоже всё хорошо, спасибо!",
"is_option": true,
"options": []
},
{
"id": 5,
"message": "Немного грустно, но я попытаюсь не думать об этом",
"is_option": true,
"options": []
}
]
},
{
"id": 3,
"message": "Не очень хорошо, но я надеюсь, что всё наладится",
"is_option": true,
"options": []
}
],
"state": {
"sympathy": 0
}
}
В этом примере мы добавили атрибут "state" и установили значение "sympathy" в 0. При выборе ответа, который увеличивает симпатии персонажей истории, мы можем обновить значение этой переменной и использовать его для ветвления истории в соответствии с этим значением.
Например, мы можем добавить элемент истории, который будет доступен только при определенных значениях "sympathy".
json{
"id": 6,
"message": "Кажется, ты проявляешь к нам все больше симпатии! Хочешь стать нашим другом?",
"is_option": true,
"options": [
{
"id": 7,
"message": "Конечно, я с удовольствием стану вашим другом!",
"is_option": true,
"options": []
},
{
"id": 8,
"message":
Конечно, я могу привести более сложный пример на основе этой структуры с персонажами. Вот пример, который включает персонажей и разные пути развития сюжета в зависимости от ответов пользователя:
json{
"id": 1,
"message": "Привет! Ты оказался на загадочном острове. Что ты будешь делать?",
"is_option": false,
"options": [
{
"id": 2,
"message": "Попробую найти способ выбраться с острова",
"is_option": true,
"options": [
{
"id": 3,
"message": "Исследую остров, чтобы найти что-то полезное",
"is_option": true,
"options": [
{
"id": 4,
"message": "Столкнулся с группой выживших людей",
"is_option": false,
"options": [],
"state": {
"characters": {
"protagonist": {
"name": "Ты",
"sympathy": 0
},
"survivors": {
"name": "Группа выживших",
"sympathy": 0
}
}
}
},
{
"id": 5,
"message": "Наткнулся на огромного ящера",
"is_option": false,
"options": [],
"state": {
"characters": {
"protagonist": {
"name": "Ты",
"sympathy": 0
},
"lizard": {
"name": "Огромный ящер",
"sympathy": 0
}
}
}
}
]
},
{
"id": 6,
"message": "Попытаюсь развить на острове свою жизнь",
"is_option": true,
"options": [
{
"id": 7,
"message": "Строю убежище",
"is_option": false,
"options": [],
"state": {
"characters": {
"protagonist": {
"name": "Ты",
"sympathy": 0
},
"builder": {
"name": "Мастер-строитель",
"sympathy": 0
}
}
}
},
{
"id": 8,
"message": "Пробую заняться земледелием",
"is_option": false,
"options": [],
"state": {
"characters": {
"protagonist": {
"name": "Ты",
"sympathy": 0
},
"farmer": {
"name": "Фермер",
"sympathy": 0
}
}
}
}
]
}
]
},
{
"id": 9,
"message": "Попытаюсь найти других люд
Конечно, я могу написать код на Dart, который будет проигрывать представленный формат. Вот пример кода, который может загрузить структуру данных из JSON-файла и отобразить историю в консоли:
dartimport 'dart:convert'; import 'dart:io'; class Node { int id; String message; bool isOption; List<Node> options; Map<String, dynamic> state; Node.fromJson(Map<String, dynamic> json) { id = json['id']; message = json['message']; isOption = json['is_option']; if (isOption) { options = (json['options'] as List) .map((option) => Node.fromJson(option)) .toList(); } state = json['state']; } void play() { print(message); if (isOption) { for (var i = 0; i < options.length; i++) { print('${i + 1}. ${options[i].message}'); } var optionIndex = int.parse(stdin.readLineSync()!) - 1; options[optionIndex].play(); } else { print('Состояние персонажей:'); state['characters'].forEach((key, value) { print('${value['name']}: ${value['sympathy']}'); }); print(''); } } } void main() { final jsonStr = File('history.json').readAsStringSync(); final rootNode = Node.fromJson(jsonDecode(jsonStr)); rootNode.play(); }
В этом коде я определил класс Node, который представляет узел в дереве истории. Метод fromJson используется для создания узлов из JSON-объектов. Метод play отображает сообщение текущего узла и предоставляет пользователю выбор, если это вариант ответа. Если узел является простым сообщением, метод отображает текущее состояние персонажей.
В методе main я загружаю структуру данных из файла и вызываю метод play на корневом узле. Пользователь будет приглашен выбрать вариант ответа, если это возможно, и история будет продолжаться соответствующим образом.
Для сохранения состояния истории можно использовать различные подходы, но одним из наиболее распространенных является сохранение данных в файл. В файле можно хранить текущий узел истории, состояние персонажей и другие данные, необходимые для продолжения истории с места, где пользователь остановился. Вот пример кода на Dart, который сохраняет и загружает состояние истории из файла:
dartimport 'dart:convert'; import 'dart:io'; class Node { int id; String message; bool isOption; List<Node> options; Map<String, dynamic> state; Node.fromJson(Map<String, dynamic> json) { id = json['id']; message = json['message']; isOption = json['is_option']; if (isOption) { options = (json['options'] as List) .map((option) => Node.fromJson(option)) .toList(); } state = json['state']; } Map<String, dynamic> toJson() { final Map<String, dynamic> data = { 'id': id, 'message': message, 'is_option': isOption, 'state': state, }; if (isOption) { data['options'] = options.map((option) => option.toJson()).toList(); } return data; } void play() { print(message); if (isOption) { for (var i = 0; i < options.length; i++) { print('${i + 1}. ${options[i].message}'); } var optionIndex = int.parse(stdin.readLineSync()!) - 1; options[optionIndex].play(); } else { print('Состояние персонажей:'); state['characters'].forEach((key, value) { print('${value['name']}: ${value['sympathy']}'); }); print(''); saveState(); } } void saveState() { final jsonStr = jsonEncode(toJson()); File('state.json').writeAsStringSync(jsonStr); } static Node loadState() { final jsonStr = File('state.json').readAsStringSync(); return Node.fromJson(jsonDecode(jsonStr)); } } void main() { Node rootNode; if (File('state.json').existsSync()) { rootNode = Node.loadState(); } else { final jsonStr = File('history.json').readAsStringSync(); rootNode = Node.fromJson(jsonDecode(jsonStr)); } rootNode.play(); }
В этом коде я добавил метод toJson для сериализации узла в JSON-объект и метод saveState для сохранения текущего состояния в файл. В методе play я вызываю saveState, когда узел является простым сообщением, чтобы сохранить состояние персонажей. Метод loadState загружает сохраненное состояние из файла, если файл существует, иначе загружается начальное состояние из файла с историей.
В методе main я проверяю, существует ли файл состояния, и загружаю сохраненное состояние, если он существует, иначе
Чтобы добавить глобальных персонажей с картинками и названиями, можно создать отдельный класс Character
, который будет содержать необходимые данные для каждого персонажа:
dartclass Character { final String name; final String image; int sympathy; Character(this.name, this.image, {this.sympathy = 0}); }
Здесь name
и image
представляют название и путь к файлу с картинкой для персонажа, а sympathy
- степень симпатии персонажа. Затем можно создать отдельный класс Story
для хранения истории и персонажей:
dartclass Story { final List<Node> nodes; final Map<String, Character> characters; Story(this.nodes, this.characters); void play() { Node rootNode; if (File('state.json').existsSync()) { rootNode = Node.loadState(); } else { rootNode = nodes.first; } rootNode.play(characters); } void saveState(Node currentNode) { final jsonStr = jsonEncode(currentNode.toJson()); File('state.json').writeAsStringSync(jsonStr); } static Story loadFromJson(String jsonStr) { final jsonData = jsonDecode(jsonStr); final nodes = (jsonData['nodes'] as List) .map((node) => Node.fromJson(node)) .toList(); final charactersData = jsonData['characters']; final characters = <String, Character>{}; for (var i = 0; i < charactersData.length; i++) { final characterData = charactersData[i]; final name = characterData['name']; final image = characterData['image']; characters[name] = Character(name, image); } return Story(nodes, characters); } void saveToJson() { final data = { 'nodes': nodes.map((node) => node.toJson()).toList(), 'characters': characters.values .map((character) => { 'name': character.name, 'image': character.image, }) .toList(), }; final jsonStr = jsonEncode(data); File('story.json').writeAsStringSync(jsonStr); } }
Здесь я добавил конструктор Story
, который принимает список узлов nodes
и словарь персонажей characters
, а также методы loadFromJson
и saveToJson
для загрузки и сохранения истории и персонажей в файлы JSON. В методе play
я передаю список персонажей в rootNode.play()
для того, чтобы узлы могли использовать информацию о персонажах. Метод saveState
сохраняет состояние в файл, как и ранее.
Теперь при создании узлов можно использовать имя персонажа для указания, кто говорит, например:
dartfinal story = Story([ Node( id: 1, message: 'Привет, я ${story.characters['Алексей'].name}', character: story.characters['Алексей'], options: [ OptionNode( id: 2, message: 'Привет, я ${story.characters['Мария'].
Извините, что-то пошло не так, продолжу.
dartfinal story = Story([ Node( id: 1, message: 'Привет, я ${story.characters['Алексей'].name}', character: story.characters['Алексей'], options: [ OptionNode( id: 2, message: 'Привет, я ${story.characters['Мария'].name}', character: story.characters['Мария'], options: [ OptionNode( id: 3, message: 'Как дела, ${story.characters['Мария'].name}?', character: story.characters['Алексей'], options: [ OptionNode( id: 4, message: 'Отлично, спасибо!', character: story.characters['Мария'], action: () => print('История закончена'), ), OptionNode( id: 5, message: 'Не очень, у меня много работы', character: story.characters['Мария'], action: () => print('История закончена'), ), ], ), ], ), ], ), ], { 'Алексей': Character('Алексей', 'aleksey.png'), 'Мария': Character('Мария', 'maria.png'), }); story.play();
В этом примере мы создаем двух персонажей и связываем их с узлами истории, используя их имя и картинки. Как и ранее, метод play
запускает историю, передавая список персонажей в rootNode.play()
.
Конечно, вот пример json-файла, описывающего эту же историю:
json{
"characters": {
"Алексей": {
"name": "Алексей",
"image": "aleksey.png"
},
"Мария": {
"name": "Мария",
"image": "maria.png"
}
},
"story": [
{
"id": 1,
"message": "Привет, я ${characters['Алексей'].name}",
"character": "Алексей",
"options": [
{
"id": 2,
"message": "Привет, я ${characters['Мария'].name}",
"character": "Мария",
"options": [
{
"id": 3,
"message": "Как дела, ${characters['Мария'].name}?",
"character": "Алексей",
"options": [
{
"id": 4,
"message": "Отлично, спасибо!",
"character": "Мария",
"action": "finish"
},
{
"id": 5,
"message": "Не очень, у меня много работы",
"character": "Мария",
"action": "finish"
}
]
}
]
}
]
}
]
}
Здесь мы определяем объект characters
, который содержит информацию о персонажах, и массив story
, который содержит объекты node
, представляющие узлы истории. Каждый узел определяется своим id
, message
, character
(именем персонажа) и, при наличии вариантов ответа, массивом options
. Если в узле нет вариантов ответа, то вместо массива options
можно указать свойство action
, которое определяет действие, которое нужно выполнить после того, как пользователь прочтет этот узел. В данном случае мы используем значение "finish"
, чтобы закончить историю.
Конечно, вот пример истории на основе заданных условий:
json{
"characters": {
"Мария": {
"name": "Мария",
"image": "maria.png"
},
"Иван": {
"name": "Иван",
"image": "ivan.png"
}
},
"story": [
{
"id": 1,
"message": "Привет, я ${characters['Мария'].name}. Мы с Иваном учились вместе в школе, но потом он уехал учиться в другой город.",
"character": "Мария",
"options": [
{
"id": 2,
"message": "Я помню, как ты говорила о нем. Ты много скучаешь?",
"character": "Иван",
"options": [
{
"id": 3,
"message": "Да, я думаю о нем все время. Мне кажется, я всегда была в него влюблена.",
"character": "Мария",
"options": [
{
"id": 4,
"message": "Я решила написать ему письмо, чтобы сказать, что я все еще люблю его. Но я боюсь, что он не отвечет.",
"character": "Мария",
"options": [
{
"id": 5,
"message": "Иван ответил на мое письмо! Он говорит, что тоже любит меня и с нетерпением ждет, чтобы мы встретились.",
"character": "Мария",
"action": "finish_good"
},
{
"id": 6,
"message": "Я не получила ответа на свое письмо. Я думаю, что он больше не любит меня.",
"character": "Мария",
"action": "finish_bad"
}
]
},
{
"id": 7,
"message": "Я решила не писать ему. Я боюсь, что он не чувствует то же самое, что и я.",
"character": "Мария",
"action": "finish_neutral"
}
]
},
{
"id": 8,
"message": "Да, но я думаю, что я уже переросла этот этап в моей жизни.",
"character": "Мария",
"action": "finish_neutral"
}
]
}
]
}
]
}
В этой истории Мария рассказывает об Иване, с которым они учились вместе в школе, но потом он уехал учиться в другой город. Мария говорит о том, что думает о нем все время, и о
Продолжение истории:
- "Слушай, а ты не хочешь со мной поехать на выходные в горы? Там так красиво осенью, я уверен, тебе понравится"
- "Конечно, я бы с радостью поехала, но я не думаю, что это хорошая идея. Я не хочу, чтобы это между нами смотрелось как что-то большее, чем просто друзья"
- "Понимаю, я не хотел тебя обидеть. Может, просто не обращай на это внимание и мы поедем как друзья"
- "Ладно, давай поедем. Но только как друзья, окей?"
- Они провели в горах прекрасное время и когда вернулись домой, Майк сказал: "Я дума
Конечно, вот пример json-файла для этой истории:
json{
"characters": [
{
"name": "Майк",
"image": "https://example.com/mike.jpg"
},
{
"name": "Анна",
"image": null
}
],
"story": [
{
"id": 1,
"type": "narration",
"text": "Майк и Анна давно были друзьями, но Майк всегда чувствовал что-то большее по отношению к Анне."
},
{
"id": 2,
"type": "narration",
"text": "Однажды Майк решил признаться в своих чувствах. Он пригласил Анну на ужин в ресторан."
},
{
"id": 3,
"type": "question",
"text": "Анна согласилась. В ресторане они с удовольствием пообедали и поговорили. Потом Майк сказал: 'Анна, я давно хотел тебе сказать, что я влюблен в тебя. Ты не могла бы дать мне шанс показать, как я тебя люблю?'",
"options": [
{
"text": "'Я тоже люблю тебя, Майк. Я всегда знала, что ты мой единственный'",
"leads_to": 4
},
{
"text": "'Майк, ты мне очень дорог, но я не чувствую к тебе так, как ты ко мне. Я очень хочу, чтобы мы остались друзьями.'",
"leads_to": 10
}
]
},
{
"id": 4,
"type": "narration",
"text": "Майк и Анна начали встречаться. Они проводили много времени вместе, и Майк чувствовал, что это самое счастливое время в его жизни."
},
{
"id": 5,
"type": "question",
"text": "Однажды, когда они шли по парку, Анна сказала: 'Майк, ты знаешь, я не могу себе представить жизнь без тебя. Но у меня есть одно условие, если мы будем вместе, то только после свадьбы.'",
"options": [
{
"text": "'Конечно, моя принцесса, я согласен.'",
"leads_to": 6
},
{
"text": "'Я не знаю, Анна. Я люблю тебя, но свадьба это серьезный шаг
Извините, я случайно отправил ответ раньше времени. Вот полный json для истории о неразделенной любви с тремя концовками:
json{
"characters": [
{
"name": "Андрей",
"image": "andrey.png"
},
{
"name": "Марина",
"image": "marina.png"
}
],
"story": [
{
"type": "message",
"character": "Андрей",
"text": "Привет, Марина! Как дела?"
},
{
"type": "message",
"character": "Марина",
"text": "Привет, Андрей. Хорошо, а у тебя?"
},
{
"type": "message",
"character": "Андрей",
"text": "Нормально, спасибо. Я тебе что-то давно хотел сказать..."
},
{
"type": "message",
"character": "Марина",
"text": "О чем?"
},
{
"type": "message",
"character": "Андрей",
"text": "Я... Я очень тебя люблю, Марина."
},
{
"type": "message",
"character": "Марина",
"text": "Андрей, я не знаю, что сказать..."
},
{
"type": "choice",
"text": "Что скажешь в ответ?",
"options": [
{
"text": "Я тоже тебя люблю",
"goto": 8
},
{
"text": "Я не могу ответить тебе сейчас",
"goto": 10
},
{
"text": "Я смотрю на тебя только как на друга",
"goto": 12
}
]
},
{
"type": "message",
"character": "Марина",
"text": "Андрей, я тоже тебя люблю. Но мы не можем быть вместе, у меня есть парень."
},
{
"type": "message",
"character": "Андрей",
"text": "Понимаю... Но я не могу скрыть свои чувства."
},
{
"type": "message",
"character": "Марина",
"text": "И я не хочу, чтобы ты скрывал их. Но мы можем быть только друзьями."
},
{
"type": "message",
"character": "Андрей",
"text": "Я понимаю. Будем друзьями."
},
{
"type": "end",
"text": "Конец истории. Андрей и Марина продолжают общаться как друзья.",
"result": "neutral"
},
{
"type": "message",
"character": "Марина",
"text":
Продолжение:
json{
"title": "Неразделенная любовь",
"description": "История о двух людях, чья любовь не судьба",
"characters": {
"Alice": {
"name": "Алиса",
"image": "alice.jpg"
},
"Bob": {
"name": "Боб",
"image": "bob.jpg"
}
},
"story": [
{
"speaker": "narrator",
"message": "Алиса и Боб встретились на работе. Они работали в одном отделе и проводили много времени вместе."
},
{
"speaker": "narrator",
"message": "Алиса влюбилась в Боба с первого взгляда. Она нашла в нем все, что искала в мужчине: ум, юмор, доброту и хорошие манеры."
},
{
"speaker": "narrator",
"message": "Боб тоже понравился Алисе, но он не был готов к серьезным отношениям. Он считал, что ему еще рано на такие шаги и что он должен сначала узнать себя и свои желания."
},
{
"speaker": "narrator",
"message": "Алиса не могла жить без Боба и продолжала надеяться на его любовь. Она проводила все свое свободное время с ним и делала ему приятные сюрпризы, но он оставался равнодушным."
},
{
"speaker": "narrator",
"message": "Однажды на работе Алиса узнала, что Боб начал встречаться с другой женщиной. Она испытала огромную боль и ревность, но не смогла найти в себе силы сказать ему о своих чувствах."
},
{
"speaker": "Alice",
"message": "Боб, я знаю, что ты встречаешься с кем-то другим, и это меня убивает. Я люблю тебя больше, чем кого бы то ни было в этом мире."
},
{
"speaker": "Bob",
"message": "Алиса, я тебя очень люблю, но я не готов к таким серьезным отношениям. Я не хочу тебя обидеть, но я должен искать свою судьбу."
},
{
"speaker": "narrator",
"message": "Алиса не могла поверить, что Боб так легко отказывается от не
Конечно, вот пример json файла с историей о неразделенной любви:
json{
"characters": [
{
"name": "Кейт",
"image": "https://example.com/kate.jpg"
},
{
"name": "Джейк",
"image": "https://example.com/jake.jpg"
},
{
"name": "Майк",
"image": "https://example.com/mike.jpg"
}
],
"story": [
{
"speaker": "narrator",
"message": "Вы - Кейт. Вы уже долгое время влюблены в Джейка, но боитесь сказать ему об этом."
},
{
"speaker": "narrator",
"message": "Вы видите Джейка в кафе и решаете подойти к нему."
},
{
"speaker": "Jake",
"message": "Привет, Кейт! Как дела?"
},
{
"speaker": "Kate",
"message": "Привет, Джейк. Хорошо, а у тебя?"
},
{
"speaker": "Jake",
"message": "У меня тоже все хорошо. Ты хочешь заказать что-нибудь вместе со мной?"
},
{
"speaker": "Kate",
"message": "Да, конечно. Я бы хотела чашечку кофе."
},
{
"speaker": "Jake",
"message": "Отлично. А я возьму чашечку чая."
},
{
"speaker": "narrator",
"message": "Вы с Джейком общаетесь долго и наконец он говорит:"
},
{
"speaker": "Jake",
"message": "Кейт, ты знаешь, я всегда считал тебя очень интересным человеком."
},
{
"speaker": "Kate",
"message": "Спасибо, Джейк. Ты тоже очень интересный."
},
{
"speaker": "Jake",
"message": "Мне кажется, у нас очень много общего. Ты не хотела бы пойти со мной на свидание?"
},
{
"speaker": "Kate",
"message": "Конечно, Джейк! Я бы с удовольствием."
},
{
"speaker": "narrator",
"message": "Вы и Джейк проводите прекрасное свидание, но на следующий день вы замечаете, что Джейк избегает вас."
},
{
"speaker": "Kate",
"message": "Джейк, что случилось? Почему ты избегаешь меня?"
},
{
"speaker": "Jake",
"message": "Кейт, я должен признаться теб
-
[url=https://megaremont.pro/brest-restavratsiya-vann]варианты реставрации ванн[/url] - DrozMib - 1 year ago