|
v8sqlite в клиент-серверной базе | ☑ | ||
---|---|---|---|---|
0
zelenprog
24.10.23
✎
13:23
|
Добрый день!
Есть обработка, которая использует компоненту v8sqlite. На файловых базах все прекрасно работало. Сегодня попробовал запустить эту обработку на клиент-сервеной базе. При запуске обработки при подключении компоненты выдается ошибка. Подключаю вот так:
Работаю с одного и того же компьютера и с файловыми базами и с серверными. Как можно сделать, чтобы v8sqlite заработала и на серверных базах? |
|||
1
OneMan1
24.10.23
✎
13:36
|
а что за модуль? откуда запускается ?
клиент/сервер ? |
|||
2
OneMan1
24.10.23
✎
13:37
|
в макет запихать не хочешь ее ?
|
|||
3
OneMan1
24.10.23
✎
13:38
|
При работе в тонком и web клиенте обязательно использования метода УстановитьВнешнююКомпоненту(). (ИТС)
|
|||
4
Галахад
гуру
24.10.23
✎
13:41
|
(0) Наверное стоит проанализировать текст ошибки и понять почему она происходит.
|
|||
5
zelenprog
24.10.23
✎
13:44
|
(3) УстановитьВнешнююКомпоненту()
"Не рекомендуется использовать, начиная с версии 8.3.16." |
|||
6
zelenprog
24.10.23
✎
13:46
|
(1) Просто внешняя обработка.
В ней читаются данные из sqlite-файла. (2) А как это сделать? |
|||
7
zelenprog
24.10.23
✎
13:53
|
(4) Никакой ошибки не выдается.
Метод "ПодключитьВнешнююКомпоненту" просто возвращает Ложь. |
|||
8
arsik
гуру
24.10.23
✎
13:56
|
Ну если ты запускаешь это в серверном контексте - нет у тебя на сервере этой компоненты.
|
|||
9
zelenprog
24.10.23
✎
14:03
|
(8) Да, запускаю в серверном контексте.
Почему тогда для файловых баз все работает? |
|||
10
arsik
гуру
24.10.23
✎
14:10
|
(9) Потому что в файловой - где у тебя клиент там у тебя и сервер
|
|||
11
yopQua
24.10.23
✎
14:12
|
зеленый чтоле)
|
|||
12
zelenprog
24.10.23
✎
14:14
|
(11) Лучше подскажи, как сделать, чтобы заработало
|
|||
13
yopQua
24.10.23
✎
14:17
|
длл в архив, архив в макет двоичными данными, потом
Если Не ПодключитьВнешнююКомпоненту("ОбщийМакет.", "Имя", ТипВнешнейКомпоненты.Native) Тогда УстановитьВнешнююКомпоненту("ОбщийМакет."); ПодключитьВнешнююКомпоненту("ОбщийМакет.", "Имя", ТипВнешнейКомпоненты.Native); Конецесли; комп= Новый("Имя"); |
|||
14
yopQua
24.10.23
✎
14:23
|
комп= Новый("Имя");
Имя как регается в системе + .Имя из ПодключитьВнешнююКомпоненту() может быть вроде такого AddIn.InputDevice.InputDevice, если указано ПодключитьВнешнююКомпоненту("ОбщийМакет.", "InputDevice", ТипВнешнейКомпоненты.Native); здесь Имя произвольное, его добавлять в комп= Новый("Имя"); |
|||
15
yopQua
24.10.23
✎
14:29
|
+ вк должна быть сделана по технологии ВК 1С, судя по названию v8sqlite должна быть такой, не запускал ее
|
|||
16
zelenprog
24.10.23
✎
14:36
|
Это все надо делать в контексте &НаСервере?
|
|||
17
zelenprog
24.10.23
✎
14:39
|
Если сервер 1С крутится под Линуксом это тоже будет работать?
|
|||
18
yopQua
24.10.23
✎
14:45
|
(16) а как надо? телепаты в отпуске
в целом это доступно и там и там, где надо, там и запускается |
|||
19
yopQua
24.10.23
✎
14:48
|
(17) смотря как сделана вк, если эта
https://github.com/orefkov/v8sqlite то по заверению автора v8sqlite - нативная ВК для работы из 1С c базами sqlite умеет |
|||
20
zelenprog
24.10.23
✎
15:06
|
(18) Вообще надо прочитать данные из sqlite-файла, в ТаблицуЗначений, и обработать эту ТЗ.
Так как ТаблицаЗначений доступна только на $НаСервере, то получается и подключение компоненты надо делать на сервере. Верно? |
|||
21
yopQua
24.10.23
✎
15:26
|
(20) вк из (19) возвращает сериализованную строку, если правильно понял, ее можно и на сервер отдать. больше от задачи зависит, есть подозрение что это какя то фоновая загрузка, если так, то соответственно сервер
|
|||
22
zelenprog
25.10.23
✎
08:48
|
(21) Загрузка пока выполняется не фоновая, а сразу в цикле все читается из sqlite-файла.
Файл лежит на клиентском компьютере. Получается, есть два варианта. 1) Загрузить компоненту, прочитать файл на клиенте. На сервер отдать прочитанные данные, чтобы сервер их обработал, и записал в БД. 2) Сделать все то же самое на сервере. В этом варианте придется и исходный файл и файлы компоненты v8sqlite передать на сервер. Так ведь? Как лучше сделать? |
|||
23
OneMan1
25.10.23
✎
09:29
|
Обычно рекомендуется большие или длинные операции передавать на сервер, так как он справится с ним быстрее чем клиент.
В вашем случаем клиент и является сервером, разницы вроде как не будет, но я бы все же рекомендовал второй вариант. Мало ли разделите клиент и сервер. Ну и для себя хорошая привычка. |
|||
24
yopQua
25.10.23
✎
09:48
|
(22) ну не в циклах дело, а в ситуации. если надо разово загрузить то можно и клиент, а если постоянный обмен какой то, то клиент же не будет сидеть постоянно кнопку запуска обмена нажимать, значит регламентное, значит фоновое, значит сервер. файл расшарить, необязательно же его передавать куда то.
ну либо клиент с подключенным обработчиком ожидания. Смотря как нужно. а вобще нормальный вариант, это когда софтина, которая сейчас в sqlite данные льет, будет напрямую в 1С отдавать эти данные, через сервисы, через сокеты или любой другой удобной технологией. сейчас это технология "Файл", что не совсем как бы зы. файл компоненты чтобы не передавать туда сюда разместить в макете конфы |
|||
25
zelenprog
25.10.23
✎
10:40
|
(23), (24)
Понятно - лучше сделать на сервере. Но тогда проблема, которую я так и не могу решить - компонента не подключается на сервере. Выше советовали использовать "УстановитьВнешнююКомпоненту", "ПодключитьВнешнююКомпоненту"... Но метод "УстановитьВнешнююКомпоненту" не доступен на сервере. А "ПодключитьВнешнююКомпоненту" на сервере возвращает Ложь, то есть компонента не подключается :( Напомню, что серверная часть работает под Линуксом. |
|||
26
Djelf
25.10.23
✎
11:17
|
(25) Ну ладно, сервер на Linux, а в (0) ты пишешь
Подключаю вот так: ПолноеИмяФайлаВК = "C:\v8sqlite.dll"; Как на Linux может существовать диск C: ??? Как виндовая dll может быть подключена на Linux сервере? |
|||
27
zelenprog
25.10.23
✎
12:12
|
(26) Так я после (10) переделал.
Сделал вот так: Код
С файловой базой все работает. А в клиент-серверной базе в последней строке всегда возвращает Ложь, типа не подключена. А при попытке создания компоненты - Новый("AddIn.v8sqlite.v8sqlite") - просто вываливается с ошибкой. Что у меня неправильно сделано? |
|||
28
Смотрящий
25.10.23
✎
12:14
|
(12) В тебя компонента в корне С:
Файловая запускается под юзером под которым ты залогинен в систему. Под ним доступ есть к корню С: Клиент-серверная запускается от юзера 1CB8USR (по умолчанию, или что там у тебя при установке было прописано). Этот юзер не имеет прав на корень С: Перенесли компоненту или дать права юзеру клиентсерерной |
|||
29
arsik
гуру
25.10.23
✎
12:22
|
(28) Какой еще c:? У него серверная часть вообще на линуксе :)
|
|||
30
Смотрящий
25.10.23
✎
12:24
|
(29) Отож, он бы про линь еще к 100 посту написал
|
|||
31
zelenprog
25.10.23
✎
12:33
|
Переделанный код под Линукс в (27).
Что в этом коде неправильно? (30) >> он бы про линь еще к 100 посту написал Ну как стала понятна причина, тогда я и сообщил про Линукс. И сразу попробовал переделать. |
|||
32
spiller26
25.10.23
✎
13:41
|
Линукс вам не Винда, там всё по другому работает.
Первая ссылка из (19) довольно не плохо написан мануал. |
|||
33
Смотрящий
25.10.23
✎
13:42
|
(31) Тогда однозначно права.
|
|||
34
zelenprog
25.10.23
✎
13:57
|
(33) По идее, если на сервер передается файл с помощью "ПоместитьФайл", то на него должны быть доступны все права.
|
|||
35
Djelf
25.10.23
✎
14:03
|
(31) Доступ до линуксовки то есть? Файлы во временном хранилище должны в /tmp появлятся. Если не появляются или появляются, но не той системы, то в этом и проблема.
Сделай очень подробное логирование всех переменных и всех действий. (33) Не думаю, без доступа к /tmp сервер 8ки вообще бы не запустился. |
|||
36
arsik
гуру
25.10.23
✎
14:14
|
Попробуй поместить so-шник в общие макеты и подключать из общего макета.
|
|||
37
yopQua
25.10.23
✎
14:45
|
(36) до сотого поста надо было подождать, что так рано то. всмысле это к тс. пока 100го поста не будет, он не воспримет этот совет
|
|||
38
zelenprog
25.10.23
✎
15:09
|
(35) >> Доступ до линуксовки то есть?
Доступ к серверу Линукс есть. >> Сделай очень подробное логирование всех переменных и всех действий. Как это сделать? И каких "действий"? Вызовы всех методов? |
|||
39
Djelf
25.10.23
✎
15:54
|
(38) Вывод любых переменных в лог и вызова всех методов.
Отладчик последовательную трассировку не может, а тебе нужна именно трассирока и вылов того что не так. |
|||
40
zelenprog
25.10.23
✎
16:01
|
(39) Понял. Завтра попробую сделать
|
|||
41
zelenprog
25.10.23
✎
17:10
|
(39) А какой лучше использовать лог?
Внешний txt-файл? |
|||
42
zelenprog
26.10.23
✎
09:44
|
(39) Вот что выдается в лог:
--------- *** ПодключитьВК_v8sqlite (&НаКлиенте) Имя файла библиотеки: C:\1C_Dlls\libv8sqlite.so ПоместитьФайл. Результат: Да Имя файла в хранилище: e1cib/tempstorage/2bf1c5dc-331b-4d61-b675-3d9726838f55?seanceId=2913f23c-dd09-4a51-8de3-c1d94511a36e *** ПодключитьВК (&НаСервере) Имя файла для подключения на сервере: e1cib/tempstorage/2bf1c5dc-331b-4d61-b675-3d9726838f55?seanceId=2913f23c-dd09-4a51-8de3-c1d94511a36e существует: Нет ПодключитьВнешнююКомпоненту: рез = Нет --------- Получается, что файла на сервере нету! А куда он пропадает? Команда, с помощью которой файл передается на сервер - "стандартная":
|
|||
43
Djelf
26.10.23
✎
10:34
|
(42) Так файл во временном хранилище, а не во временном файле.
Его надо получить на сервере с помощью функции ПолучитьИзВременногоХранилища() и сохранить во временный файл на сервере с помощью функции ПолучитьИмяВременногоФайла() |
|||
44
zelenprog
26.10.23
✎
11:47
|
(43) Сделал ПолучитьИзВременногоХранилища() и ПолучитьИмяВременногоФайла().
В файловой базе работает. В клиент-серверной по прежнему не работает. Вот что выдает лог: ----------------- (*) Метод ПодключитьВК_v8sqlite (&НаКлиенте) Имя файла библиотеки: C:\1C_Dlls\libv8sqlite.so существует: Да ПоместитьФайл. Результат: Да Имя файла в хранилище: e1cib/tempstorage/43bcb0e3-caff-4307-a485-3f61a885452f?seanceId=db9671bd-2b22-4f79-8b72-e9dc48dca5e0 (*) Метод ПодключитьВК (&НаСервере) Имя временного файла на сервере: /tmp/libv8sqlite_v8_HXxHly_1a0.so Имя файла для подключения на сервере: /tmp/libv8sqlite_v8_HXxHly_1a0.so существует: Да ПодключитьВнешнююКомпоненту: рез = Нет (*) Метод УстановитьСоединение (&НаСервере) !!!! здесь вываливается при попытке выполнить !!!! лБаза = Новый("AddIn.v8sqlite.v8sqlite") --------------------------- Файл во временной папке лежит. |
|||
45
arsik
гуру
26.10.23
✎
12:27
|
(44) В линуксе выполни и покажи нам выхлоп.
ldd libv8sqlite.so Или вот почитай https://www.opennet.ru/base/dev/lib_dependence.txt.html |
|||
46
Djelf
26.10.23
✎
13:47
|
(44) Точно, на линуксовке не подключается. Надо пересобирать ВК с более старым libc, даже на Uvuntu 20.04 LTS libc всего лишь версии 2.31
root@server83:/opt/11# ldd v8sqlite_x64.so ./v8sqlite_x64.so: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.33' not found (required by ./v8sqlite_x64.so) ./v8sqlite_x64.so: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found (required by ./v8sqlite_x64.so) linux-vdso.so.1 (0x00007ffe1910d000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fbc75d8c000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fbc75b9a000) /lib64/ld-linux-x86-64.so.2 (0x00007fbc760a0000) root@server83:/opt/11# |
|||
47
zelenprog
26.10.23
✎
14:39
|
(45)
[sysadmin@hataraku tmp]$ ldd libv8sqlite.so ldd: предупреждение: у вас нет прав на выполнение `./libv8sqlite.so' ./libv8sqlite.so: /lib64/libm.so.6: version `GLIBC_2.29' not found (required by ./libv8sqlite.so) ./libv8sqlite.so: /lib64/libc.so.6: version `GLIBC_2.28' not found (required by ./libv8sqlite.so) ./libv8sqlite.so: /lib64/libc.so.6: version `GLIBC_2.33' not found (required by ./libv8sqlite.so) ./libv8sqlite.so: /lib64/libc.so.6: version `GLIBC_2.34' not found (required by ./libv8sqlite.so) linux-vdso.so.1 => (0x00007ffe4bff1000) libm.so.6 => /lib64/libm.so.6 (0x00007f5972398000) libc.so.6 => /lib64/libc.so.6 (0x00007f5971fca000) /lib64/ld-linux-x86-64.so.2 (0x00007f597269a000) |
|||
48
arsik
гуру
26.10.23
✎
15:11
|
(46) (47) У вас старье какое то стоит :)
Выхода 3 1) Поднять версию glibc - но это слишком ссыкотно. Много поломаться может. 2) Пересобрать библиотеку с пониженной версией 3) Не использовать данный инструмент, а написать какую ни будь вебобертку на go (Garykom) . |
|||
49
Djelf
26.10.23
✎
15:20
|
(49) Ты прав, нельзя использовать Ubuntu LTS!
Надо сразу же переходить на неподдерживаемые сервером 1С версии, нападать на грабли, получать от них шишки и сразу же увольнятся. Ибо нехрен с диназаврами, которые работают на актуальных и еще не устревших версиях работать. А вот компилировать компоненту для Винды, тоже надо было бы уже под W11 делать, да еще и под ARM, чтобы больно было всем, а не только линуксоидам! |
|||
50
zelenprog
26.10.23
✎
15:29
|
(46)
>> Надо пересобирать ВК с более старым libc (48) >> 2) Пересобрать библиотеку с пониженной версией Я с таким низкоуровневым программированием дела не имел. Лет 15 назад писал десктопные несложные программы. Работал с Borland C++, Foxpro, Microsoft Visual Studio, C#. Как это пересобирать - не знаю :( Тем более под Линукс. |
|||
51
zelenprog
26.10.23
✎
15:32
|
Разработчик этой компоненты это же orefkov?
orefkov |
|||
52
Djelf
26.10.23
✎
15:48
|
(51) Да, он.
Но там еще и cmake догнан до чуть ли не последней версии, и использует новые расширения, это быстро не исправить, надо изучать что они там делают. |
|||
53
zelenprog
26.10.23
✎
17:31
|
(52) Ясно...
Придется переделывать обработку, чтобы она локально на клиенте под Windows читала данные, и передавала их на сервер для обработки. |
|||
54
Djelf
26.10.23
✎
21:30
|
(53) Потом переделать на серверный вариант не так долго, ничего особенно по времени не потеряешь.
Будет время покопаюсь, не охота засорять рабочие сервера всякой хренью, нужно поднимать стэнд, а я их все потер недавно ;) Что там у тебя за система? Какая libc? В принципе совместность поддерживается, т.е. если собрать на древней верии то работать должно, бывают конечно анекдоты типа такого: https://github.com/dimbor-ru/freenx-server/issues/5 https://sourceware.org/bugzilla/show_bug.cgi?id=1190 Это был вообще улётный случай! Второй топик сейчас подчистили, он был значительно веселее! Грубо говоря, был баг чтения данных за пределом текущего размера файла, и он был в libc черт знает сколько лет, и пока товарищи из NoMachine не столкнулись с неработоспособностью своего NXClient, вроде на солярке, и не завопили "какая хрень там творится" никто на это внимания не обращал. После этого внимание обратили и поняли что слегка нарушили POSIX, иииии... Склепали патч для libc который убил NXClient под Linux с новым libc! Бинго 👍 NoMachine видимо обиделся, и чинить свой клиент не стал, пришлось мне это сделать ;) Но это очень редкий и очень специфичный случай. |
|||
55
zelenprog
27.10.23
✎
08:43
|
(54)
>> ... был баг чтения данных за пределом текущего размера файла, и он был в libc черт знает сколько лет ... Вот это да. Так это получается, что старой libc нельзя пользоваться. >> >> Придется переделывать обработку, чтобы она локально на клиенте под Windows читала данные, и передавала их на сервер для обработки. >> Потом переделать на серверный вариант не так долго Переделал. >> Будет время покопаюсь ... Это разовая обработка по загрузке данных. Потом может быть уже будет лень переделывать. |
|||
56
orefkov
27.10.23
✎
16:04
|
Если весь сыр-бор из-за таблицы значений, которая есть только на сервере, то ВК умеет и в виде массива возвращать, который и на клиенте есть.
По поводу сборки под пониже libc- посмотрю. |
|||
57
zelenprog
27.10.23
✎
17:00
|
(56) >> Если весь сыр-бор из-за таблицы значений, которая есть только на сервере ...
В общем-то да, сыр-бор из-за этого. >> ... то ВК умеет и в виде массива возвращать, который и на клиенте есть. А как это сделать? Хотя все равно данные нужны на сервере, так как вся обработка этих данных выполняется на сервере. Но все-таки получение массива тоже интересно, вдруг потом где-нибудь понадобится. |
|||
58
zelenprog
27.10.23
✎
16:59
|
(56) >> По поводу сборки под пониже libc- посмотрю.
ОК, будем ждать. |
|||
59
orefkov
30.10.23
✎
14:26
|
(57)
https://github.com/orefkov/v8sqlite#%D0%B2%D1%8B%D0%BF%D0%BE%D0%BB%D0%BD%D0%B8%D1%82%D1%8C%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81-%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D0%B0-%D0%BA%D0%BE%D0%BB%D0%BE%D0%BD%D0%BA%D0%B8%D1%81%D0%B4%D0%B0%D1%82%D0%BE%D0%B9--execqueryquery-answerformat-datecolumns Вторым параметром указываешь "JSON", потом через СериализаторXDTO преобразуешь в Массив массивов. |
|||
60
zelenprog
31.10.23
✎
16:46
|
(59) Ага, спасибо
|
|||
61
zelenprog
31.10.23
✎
17:05
|
А как делать, если на сервере надо записать какие-то данные в sqlite-файл?
По логике, так как работа с компонентой происходит на клиенте, то надо будет с сервера вызвать клиентскую процедуру. Но так ведь 1С-ка не работает. Как это лучше организовать? |
|||
62
Djelf
03.11.23
✎
15:08
|
(56) Нашлось немного свободного времени для шаманства...
Тестовая обработка со вшитой в бинарный шаблон библиотекой на GLIBC_2.16: https://cloud.mail.ru/public/bAJQ/oVB68FetH Рецепт изготовления: Ставим ubuntu 18.04 (первый который поддерживает 1С 8.3). Это lts релиз и если на 19.10 половины пакетов вообще не найти, то для 18.04 они есть. После установки обновляем, ставим apt install mc git build-essential libssl-dev Может что-то не запомнил, по ходу дела найдется что еще поставить придется... Находим первый необходимый хинт на https://apt.llvm.org # Needs 'sudo add-apt-repository ppa:ubuntu-toolchain-r/test' for libstdc++ with C++20 support Добовляем репу, обновляем систему, устанавливаем g++13, вроде можно и 11й, но я сразу поставил последний. Второй хинт рецепта оттуда же: sudo ./llvm.sh 16 Забираем с гита cmake, собираем через ./bootstrap и make, ставим. Потребуется libssl-dev, но мы его уже поставили. Дальше, как обычно, танцы с бубном, надо ставить libstdc++-dev, линкеру надо -pthread добавить, явно указать что сборка clang`ом делается и т.д. и т.п. Ничего нового... P.S. Локаль ошибок получилась английская, русская в режиме "НаСервере" на похватиласть, имхо не критично, но имхо в ВК стоило бы добавить метод переключения локали. (0) Проверяй! На гигег 20.04 все тесты прошли без ошибок, кроме одного, там локаль проверяется, а см. выше она получается английская. P.P.S. Надо бы проверить, работает ли по факту или нет, но уже поздно и лень... ldd -v ./1cv8|grep GLIBC ... libc.so.6 (GLIBC_2.30) => /lib/x86_64-linux-gnu/libc.so.6 ... И как это может запуститься на ubuntu 18.04 с GLIBC_2.16? |
|||
63
zelenprog
10.11.23
✎
08:41
|
(62) Вот что получилось:
-------------- Компонента v8sqlite загружена Версия ВК:1.0.0.4 Версия sqlite: 3.39.4 Тест ПроверкаОткрытияБазы Пройден Тест ПроверкаВыполнить >> Database error: incomplete input << >> Произошла ошибка базы данных: incomplete input << Провал: {ВнешняяОбработка.v8sqlite.Форма.ФормаУФ.Форма(42)}: Неправильный текст ошибки Тест ПроверкаВыборкиВТЗ Пройден Тест ПроверкаВыборкиВJson Пройден Тест ПроверкаПараметризированного Пройден Тест ПроверкаПараметров Пройден Тест ПроверкаБольшогоРезультата Пройден Тест ПроверкаЮникода Пройден Пройдено тестов: 7 Провалено тестов: 1 -------------- |
|||
64
zelenprog
10.11.23
✎
08:46
|
Получается, если использовать эту серверную компоненту, то sqlite-файл с данными тоже надо на сервер передавать?
Это как-то неудобно. А если 1С-ка будет вносить в него изменения, то его потом надо назад на клиента тащить, и заменить исходный файл, чтобы изменения оказались в исходном файле. Сомнительный сценарий :( Есть какой-нибудь другой способ работы с локальным файлом с сервера? |
|||
65
orefkov
13.11.23
✎
23:13
|
Выпустил 1.0.0.5
Sqlite обновлён до версии 3.44.0 Ряд небольших оптимизаций. Доработана работа с локалью сообщений об ошибках. Под Линукс две сборки - одна с GLIBC 2.25 (Ubuntu 18.04), другая с GLIBC 2.34 (Ubuntu 22) https://github.com/orefkov/v8sqlite/releases/tag/Release_1_0_0_5 |
|||
66
zelenprog
17.11.23
✎
08:21
|
(65) Спасибо.
|
|||
67
lEvGl
гуру
17.11.23
✎
09:30
|
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |