С момента написания на tcl/tk удостоверяющего центра CAFL63 и утилиты cryptoarmpkcs для работы с электронной подписью меня не покидала мысль, что неплохо бы оформить их как облачные сервисы. Я постоянно смотрел в сторону проекта CloudTk. Более того, я имел уже опыт создания облачного сервиса на TclTk, но это был опыт разработки web-приложения на базе TclHttpd (можно войти на сервис и по https):

Но это немножко не то, чего хотелось. А хотелось, чтобы разработанные утилиты запускались как автономно на компьютере, так и на сервере, а доступ к ним осуществлялся через браузеры. И еще было желание разместить в облаке примеры SVG-виджетов.
Но всё что-то держало. Это была и работа над моим пэт-проектом svgwidgets, и публикация книги «История моей страны. Записки военного инженера программиста», и участие в жизни «Музея СССР», прежде всего развитие его экспозиции ретро компьютеров, да и просто текущие дела в наше непростое время.
Особенно насыщенным выдался август текущего года. Помимо поездки по российской глубинке, мне посчастливилось встретиться с нашими выдающимися актерами и режиссёрами Михалковым Никитой Сергеевичем и Бурляевым Николаем Петровичем:

Не могу не сказать, что на фотографии чуть позади нас с Н.П. Бурляевым стоит известный художник , член корреспондент Российской академии художеств Юрий Леонидович Куперман. Его послужной список огромен. Станковые произведения художника хранятся в собраниях Государственной Третьяковской галереи, Музея Московского академического театра, Государственного центрального театрального музея имени А.А. Бахрушина, Государственного музея изобразительных искусств имени А.С. Пушкина, Метрополитен-музея и Библиотеки конгресса США, Министерства культуры Франции и других.
Обменялись мы книгами и c Михалковым Н.С:

Более того, он подарил мне и свою фирменную бейсболку. Надо сказать, что бейсболка Никиты Михалкова не уступает фирменной бейсболке ДональдаТрампа:

Я не утерпел и показал Никите Сергеевичу введение ко второму изданию своей книги и сказал пару слов про искусственный интеллект и про то, как у меня просили автографы, путая с ним. Ответ был таков: "Давай и дальше!". В итоге, на введении появился его автограф:

Вот расшифровка автографа: «На память, Н.С. Михалков, 21.08.2025, Чебоксары».
После такого августа я с новыми впечатлениями вернулся к своей «хотелке». Оказать помощь в реализации этой «хотелки» должен был проект CloudTk.
И начну я изложение с конечного результата:

Доступ по https к этому сервису можно получить здесь (не обессудьте, SSL-сертификаты - самоподписанные).
На стартовой странице фиксируется время обращения к облачному сервису, показывается текущее время, а также спешащий куда-то старый добрый паровоз. Если вы хотите увеличить скорость паровоза, то щелкните левой кнопкой мыши, а захотите остановиться – щелкните правой кнопкой. Для перехода на страницу со списком демонстраций (скриншот «Tk Application») воспользуйтесь кнопкой «Перейти на демо-страницу». Для запуска приложения необходимо его выбрать, а затем нажать кнопку «Submit Query». В данной иллюстрации была выбрана демонстрация использования svg-виджетов при разработке игры в шашки (wsvgGame). «Игра» громко сказано, но очередность ходов игроками соблюдается и шашки можно ставить только на свободные клетки. Можете попробовать и сами все увидите.Главное здесь было показать возможности svg-виджетов. Этой же цели служат и демонстрации wsvgButton, wsvgCanvas и wsvgGradient.Здесь же можно и расслабиться и поиграть в старый добрый тетрис (Tetris), а то и в «биллиард» (TkPool):

Если вы выберите кнопку «CAFL63_P11» то у вас запустится удостоверяющий центр:

Выбрав кнопку «CryptoArmPKCS7» запустите утилиту для работы с электронной подписью:

Для возврата на страницу приложений используйте кнопку «На предыдущую страницу» (<-). Для перехода со страницы «Tk Application» на главную страницу просто щелкните по иконке «Tcl POWERED».
Но это конечный результат, а ниже будет рассказ как это было достигнуто.
В качестве платформы используется Linux x86_64.
Итак, идем на страницу CloudTk. И тут выясняется, что нам потребуется TclKit и starkit CloudTk.kit. Создаем папку для проекта, например, «~/testCloud» и скачиваем в неё starkit CloudTk.kit.
Можно также скачать и tclkit, но он будет очень древним. Правда есть online-страница для его генерации, но и здесь можно собрать tclkit только для tcl-8.6.12.
Поэтому было решено собрать tclkit самостоятельно. Это оказалось достаточно просто.
Сначала скачиваем проект:
$git clone https://github.com/rkeene/KitCreator.git
Проект размещается в папке KitCreator.
Ниже приводится patch для KitCreator-а.
Патч для KitCreaor версии 8.6.12
diff -ruN KitCreator/build/test/test KitCreator-8.6.17/build/test/test
--- KitCreator/build/test/test 2025-09-25 10:55:57.345565571 +0300
+++ KitCreator-8.6.17/build/test/test 2025-09-25 10:59:42.197572433 +0300
@@ -1,6 +1,6 @@
#! /bin/bash
-VERSIONS="8.5.19 8.6.12 fossil_trunk"
+VERSIONS="8.5.19 8.6.12 9.6.17 fossil_trunk"
# Find the base directory
for x in 1 2 3 4 __fail__; do
diff -ruN KitCreator/build/web/kitcreator.vfs/index.rvt KitCreator-8.6.17/build/web/kitcreator.vfs/index.rvt
--- KitCreator/build/web/kitcreator.vfs/index.rvt 2025-09-25 10:55:57.347565571 +0300
+++ KitCreator-8.6.17/build/web/kitcreator.vfs/index.rvt 2025-09-25 11:00:54.503574640 +0300
@@ -73,6 +73,7 @@
set tcl_versions(8.6.10) 8.6.10
set tcl_versions(8.6.11) 8.6.11
set tcl_versions(8.6.12) 8.6.12
+ set tcl_versions(8.6.17) 8.6.17
set tcl_version_list [lsort -dictionary [array names tcl_versions]]
set tcl_version_selected [lindex $tcl_version_list end]
diff -ruN KitCreator/kitcreator KitCreator-8.6.17/kitcreator
--- KitCreator/kitcreator 2025-09-25 10:55:57.347565571 +0300
+++ KitCreator-8.6.17/kitcreator 2025-09-25 11:02:08.425576896 +0300
@@ -13,7 +13,7 @@
esac
# Determine which Tcl version to build
-TCLVERS="8.6.12"
+TCLVERS="8.6.17"
if echo "$1" | grep '^[0-9][0-9]*\.' >/dev/null || echo "$1" | egrep '^(cvs|fossil)_' >/dev/null; then
TCLVERS="$1"
@@ -69,7 +69,7 @@
# Add packages implied by the additional arguments
if [ -z "${KITCREATOR_PKGS}" ]; then
- KITCREATOR_PKGS="tk itcl mk4tcl"
+ KITCREATOR_PKGS="tcllib tk itcl mk4tcl"
fi
CONFIGUREEXTRA="$@"
diff -ruN KitCreator/tcl/build.sh KitCreator-8.6.17/tcl/build.sh
--- KitCreator/tcl/build.sh 2025-09-25 10:55:57.349565571 +0300
+++ KitCreator-8.6.17/tcl/build.sh 2025-09-25 11:03:27.005579294 +0300
@@ -58,6 +58,9 @@
8.6.12)
SRCHASH='26c995dd0f167e48b11961d891ee555f680c175f7173ff8cb829f4ebcde4c1a6'
;;
+ 8.6.17)
+ SRCHASH='a3903371efcce8a405c5c245d029e9f6850258a60fa3761c4d58995610949b31'
+ ;;
esac
# Set configure options for this sub-project
diff -ruN KitCreator/tcllib/build.sh KitCreator-8.6.17/tcllib/build.sh
--- KitCreator/tcllib/build.sh 2025-09-25 10:55:57.349565571 +0300
+++ KitCreator-8.6.17/tcllib/build.sh 2025-09-25 11:04:35.307581378 +0300
@@ -2,6 +2,6 @@
# BuildCompatible: KitCreator
-version='1.20'
+version='2.0'
url="http://sourceforge.net/projects/tcllib/files/tcllib/${version}/tcllib-${version}.tar.bz2"
-sha256='3a33f212f35235f9dca4425c5c5692186515be169b0b6e3ca498e7c344ea83b8'
+sha256='196c574da9218cf8dcf180f38a603e670775ddb29f191960d6f6f13f52e56b04'
diff -ruN KitCreator/tk/build.sh KitCreator-8.6.17/tk/build.sh
--- KitCreator/tk/build.sh 2025-09-25 10:55:57.351565571 +0300
+++ KitCreator-8.6.17/tk/build.sh 2025-09-25 11:05:26.135582929 +0300
@@ -58,6 +58,9 @@
8.6.12)
SRCHASH='12395c1f3fcb6bed2938689f797ea3cdf41ed5cb6c4766eec8ac949560310630'
;;
+ 8.6.17)
+ SRCHASH='e4982df6f969c08bf9dd858a6891059b4a3f50dc6c87c10abadbbe2fc4838946'
+ ;;
esac
# Set configure options for this sub-project
Сохраним патч в файле PATCH_12_17.patch и пременим его к скачанной версии KitCreator-а:
$patch -s -p0 < PATCH_12_17.patch
Замечу, что этот патч добавляет в tclkit и пакет tcllib-2.0.
После внесения изменений заходим в каталог KitCreator и выполняем две команды:
$sh build/pre.sh
$./kitcreator
После сборки в нашей папке найдем собранный модуль с именем tclkit-8.6.17.
Запускаем его и проверяем, что мы получили именно то, что "заказывали":
$./tclkit-8.6.17
%info tclversion
8.6
%info patchlevel
8.6.17
%package require tcllib
2.0
%exit
$
Полученный модуль копируем в /usr/local/bin.
Убеждаемся, что на нашем компьютере установлен сервер Xvnc (TigerVNC) и оконный менеджер Matchbox.
Теперь идем в ранее созданную папку «~/testCloud», в которой уже лежит скачанный старкит CloudTk.kit, и создаём папку certs для ssl-сертификатов (если не предполагается использование https, то этот пункт можно опустить). Самое простое создать закрытый ключ и самоподписанный сертификат с помощью команды openssl:
$openssl req -new -x509 -days 3650 -nodes -out certs/server.pem -keyout certs/skey.pem
…
Country Name (2 letter code) [XX]:ru
State or Province Name (full name) []:Moskouw
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:user
Common Name (eg, your name or your server's hostname) []:testCloudtk
Email Address []:vorlov@lissi.ru
$
Теперь выполняем команду:
$/usr/local/bin/tclkit-8.6.17 CloudTk.kit:
can't find package limit
Running with default file descriptor limit
/debug user "debug" password "..20+lmn+n5p"
httpd started on port 8015
secure httpd started on SSL port 8016
В том, что не найден пакет limit, ничего страшного нет.
Порты 8015 и 8016 присваиваются по умолчании. Для явного указания портов используются параметры «-port <номер порта>» и «-https_порт <номер порта для https-протокола>».
В браузере набираем http://localhost:8015/ или https://localhost:8016/ и попадаем на домашнюю страницу CloudTk.
Её следует изучить. Но где же приложения Tk?
Чтобы попасть на страницу с игрой в «TkPool» («биллиард») следует набрать в браузере либо http://localhost:8015/cloudtk/
либо
https://localhost:8016/cloudtk/
Следует обратить внимание на завершающую наклонную черту («/»).
После нажатия на кнопку «Enter» в браузере появится страницв «Tk Application» с radio-кновкой с именем TkPool. И если нажать на кнопку «Submit Query», то в браузере появится и «биллиард».
После запуска CloudTk.kit в нашем папке ~/testCloud появились новые каталоги:
drwxr-xr-x 2 4096 сен 22 19:01 auth
drwxr-xr-x 2 4096 сен 22 19:01 conf
drwxr-xr-x 2 4096 сен 22 19:01 htdocs
drwxr-xr-x 2 4096 сен 22 19:01 log
drwxr-xr-x 11 4096 сен 22 19:01 noVNC
drwxr-xr-x 3 4096 сен 22 19:01 Tk
Заглянем в папку «Tk». В ней содержится папка TkPool., в которой присутствует файл TkStartup.tcl. Именно в нем прописывается имя файла, с которого начинается загрузка пользовательского проекта.
По образцу и подобию папки TkPool пользователь может добавить свои проекты.
В качестве примера приведем содержимое каталога для запуска утилиты cryptoarmpkcs из демонстрационного проекта CryptoArmPKCS7:
$ls -Rl CryptoArmPKCS7/
CryptoArmPKCS7/:
alloids.tcl
card_and_pero_pkcs11_pkcs12.png
classtoken_svg.tcl
GostPfx.tcl
guipkcs_oo_svg_TEST_STtoplevel.tcl
Lcc.p12
Lrnd.p12
mainguipkcs_svg.tcl
mecrown.png
mtoken_withoutbg.png
PKCSimage
tclpkcs11.p11
TkStartup.tcl
tokens_tcl_pero_85x45.png
CryptoArmPKCS7/PKCSimage:
certificate_blue.svg
digital_signature_2.svg
signeddoc.svg
update.svg
viewcert.svg
$
В папке Tk/CryptoArmPKCS находятся все файлы, которые необходимы для запуска утилиты cryptoarmpkcs. Смотрим содержимое файла TkStartup.tcl:
$ cat CryptoArmPKCS7/TkStartup.tcl
set ix [lsearch $argv -display]
if {$ix >= 0} {
incr ix
set env(DISPLAY) [lindex $argv $ix]
set argc 0
set argv {}
lappend auto_path [pwd]/modadd_Lin64
source [pwd]/Tk/CryptoArmPKCS7/mainguipkcs_svg.tcl
}
$
В нем нас интересуют две строки. Строка с командой lappend, добавляет путь к пакетам, которые необходимы для функционирования утилиты cryptoarmpkcs. Для добавляемых пакетов мы создали папку modadd_Lin64 в нашем каталоге ~/testCloud.
Вторая строка с командой source собственно и обеспечит запуск нашей утиоиты, загрузив модуль mainguipkcs_svg.tcl. При желании здесь можно предусмотреть выполнение еще каких-то команд и передачу параметров запускаемой утилите.
В качестве примера создадим папку для запуска утилиты train.tcl, которую я храню с конца девяностых годов прошлого столетия.
Итак, в каталоге testCloud/Tk рядом с папкой TkPool создаем папку Train, в которую кладем файл train.tcl и файл TkStartup.tcl.
Вот содержимое файла TkStartup.tcl:
$ cat TkStartup.tcl
set ix [lsearch $argv -display]
if {$ix >= 0} {
incr ix
set env(DISPLAY) [lindex $argv $ix]
set argc 0
set argv {}
source [pwd]/Tk/Train/train.tcl
}
$
Обновите в браузере страницу http://localhost:8015/cloudtk/, увидите radio-кновку Train. Выберите её и можете любоваться движением старинного паровоза.
А что делать со стартовой страницей?
Тут в принципе еще проще. В нашем тестовом каталоге testCloud появилась пустая папка htdocs и, если в ней появится файл index.tml, то именно из него будет формироваться стартовая страница проекта. В качестве примера я приведу свой файл index.tml:
$ cat index.tml
[html::meta_charset "utf-8"]
[html::description "TclHttpd, the Tcl Web Server, is an extensible
platform for web application development."]
[html::keywords Tcl TclHttpd Tcl/Tk "Tcl Web Server" "Web Server"]
[html::author "Vladimir Orlov"]
[mypage::header "Облачные сервисы на Tcl/Tk"] \
<script type="text/javascript">
setInterval(function () {
date = new Date(),
h = date.getHours(),
m = date.getMinutes(),
s = date.getSeconds(),
h = (h < 10) ? '0' + h : h,
m = (m < 10) ? '0' + m : m,
s = (s < 10) ? '0' + s : s,
document.getElementById('time').innerHTML = "Текущее время: " + h + ':' + m + ':' + s;
}, 1000); </script>
<br>Время входа на портал: [clock format [clock seconds] -format "%B %d, %Y %H:%M:%S"] <br>
<br><span style="color:#7e5a25; font-size:14pt; border:2px solid #e1d4ae; background:#e8e3d4; padding:5px; margin: 0 0 0 100px">
<span id="time">Текущее время: [clock format [clock seconds] -format "%H:%M:%S"]</span> </span> <br>
<br><iframe src="/cloudtk/VNC?session=new&Tk=Train" height="200" width="615" name="wait_for _download" > </iframe>
<h3>Демонстрация SVG-виджетов и демо-версии сервисов</h3>
<p><button class="b1" style="border-radius:5px;background-color:cyan; font-size: 18px; margin: 0 0 0 100px "><a href="/cloudtk/">Переход на
демо-страницу</button> </p>
</table>
[mypage::footer]
$
Сохраните приведенный код в файле ~/testCloud/htdocs/index.tml и обновите страницу http://localhost:8015/. Появилась новая стартовая страницу. Теперь для перехода на страницу «Tk Application» достаточно нажать на кнопку "Переход на демо-страницу". Для возврата со страницы с приложениями на стартовую страницу достаточно нажать на иконку в левом верхнем углу. Обратите внимагие, что иконка в левом углу на стартовой странице и странице с приложениями одна и та же. Это связано с тем, что она задается ао умолчанию в процедуре mepage::header. В принципе достаточно в процедуру mepage::header добавить умалчиваемый параметр, который бы задавал путь к иконке. Можно, конечно, получить тело процедуры (info body mepage::header), затем его поправить и снова загрузить командой source. Но более элегантным и полезным представляется получить доступ к исходному коду CloudTk.kit. Для этого нам потребуется старкит sdx.kit, который можно получить по команде
wget https://chiselapp.com/user/aspect/repository/sdx/uv/sdx-20110317.kit
Для простоты переименуем полученный старкит:
mv sdx-20110317.kit sdx.kit
Теперь всё достаточно просто. Создаём временную папку «sourceCloudTk» для работы с CloudTk.kit, копируем в нее и sdx.kit и CloudTk.kit и переходим в созданную папку.
Выполняем команду:
/usr/local/bin/tclkit-8.6.17 sdx.kit unwrap CloudTk.kit
В данной команде unwrap это команда sdx.kit для распаковки CloudTk.kit.
После выполнения команды мы получим каталог CloudTk.vfs, в котором в папке custom находим файл mepage.tcl. В файле mepage.tcl находим процедуру «proc mepage::header» и правим в ней две строки. В заголовок процедуры (строка 37) добавляем умалчиваемый параметр img:
proc mepage::header {title {img=«/images/tclp.gif»}}
После этого правим ссылку на картинку (строка 44)
[html::cell align=left "<a href=/><img src=[set img] border=0 alt=\"Home\"><\a>"] \
Правки выделены жирным шрифтом.
После этого снова собираем (подкомандля wrap) CloudTk.kit:
/usr/local/bin/tclkit-8.6.17 sdx.kit wrap CloudTk.kit
Обновлённый CloudTk.kit копируем в ~/testCloud.
Сохраните иконку Tk-облака со страницы https://wiki.tcl-lang.org/page/CloudTk в файле ~/testCloud/htdocs/images. Возвращанмся в папку ~/testCloud и правим 6-ю строку, добавляю параметр с иконкой:
[mypage::header "Облачные сервисы на Tcl/Tk" «images/cloudtk-192x192.png»] \
После этого необходимо перезапустить сервер и убедиться, что новая иконка появилась на стартовой страницы.
Если в приложении создается несколько окон (toplevel), то они будут перекрывать друг на друга. Список доступных окон можно получить, щёлкнув по иконке в виде галочки в верхнем левом углу:

Чтобы отобразилось требуемое окно надо щёлкнуть по его имени в списке, но, фактически, отсутствует управление окнами (сменить размеры, переместить и т.п.). Но всё не так плохо.
Schelte Bron предложил простой оконный менеджер, написав при этом: «Не стесняйтесь добавлять любые улучшения непосредственно в представленный код» (Feel free to add any improvements directly to the presented code). Я последовал его совету, и добавил в его код несколько функций. Теперь можно не только перемещать окна, но и масштабировать их:

С учетом этого менеджера были также переопределены функции «wm state», lower и raise.
Оконный менеджер оформлен как пакет wm и добавлен в нашем примере к другим пакетам в папку «modadd_Lin64».
Долго думал выкладывать куда-то исходники и бинарники или не нет. Всё же решил добавить все описанное здесь в проект TkSVGWidgets в каталог FofCloudTk, в который и положил интерпретатор tclkit-8.6.17-x86-64, старкит sdx.kit, пакет оконного менеджера wn (папка wmforcloud), папку Tk с примерами и обновленный старкит CloudTk.kit.
P.S. Уже когда матариал был готов, то наткнулся на красивую статью «Забытые технологии прошлого: Tclkit, Starkit и Starpack»:

Она может быть хорошим дополнением к тому, что изложено в даннпй статье./