Преглед изворни кода

SVI Обновление вендоринга

SVI пре 1 година
родитељ
комит
ce0fd0bb61
97 измењених фајлова са 2088 додато и 852 уклоњено
  1. 18 13
      app/lev0/bfunc/bf_ammo_make/bf_ammo_make.go
  2. 8 2
      app/lev0/bfunc/bf_ammo_stat/bf_ammo_stat.go
  3. 86 0
      app/lev0/bfunc/bf_arsenal_build/bf_bank_build.go
  4. 86 0
      app/lev0/bfunc/bf_bank_build/bf_bank_build.go
  5. 3 21
      app/lev0/bfunc/bf_glory_make/bf_glory_make.go
  6. 104 0
      app/lev0/bfunc/bf_mine_accelerate/bf_mine_accelerate.go
  7. 63 0
      app/lev0/bfunc/bf_mine_build/bf_mine_build.go
  8. 11 45
      app/lev0/bfunc/bf_mission_simple/bf_missin_simple.go
  9. 10 4
      app/lev0/bfunc/bf_polygon_activate/bf_polygon_activate.go
  10. 86 0
      app/lev0/bfunc/bf_polygon_build/bf_polygon_build.go
  11. 8 2
      app/lev0/bfunc/bf_silver_prod/bf_silver_prod.go
  12. 3 5
      app/lev0/bfunc/bf_tank_stat/bf_tank_stat.go
  13. 9 3
      app/lev0/cons/cons.go
  14. 2 2
      app/lev0/types/iarena.go
  15. 4 11
      app/lev0/types/iarena_state.go
  16. 1 1
      app/lev0/types/icounttime.go
  17. 1 1
      app/lev0/types/iparser_simple.go
  18. 1 7
      app/lev1/health/health.go
  19. 1 6
      app/lev1/manevr/manevr.go
  20. 7 11
      app/lev1/product/parser_time/parse_hour/parse_hour.go
  21. 7 19
      app/lev1/product/parser_time/parse_hour/parse_hour_test.go
  22. 6 8
      app/lev1/product/parser_time/parse_min/parse_min.go
  23. 3 9
      app/lev1/product/parser_time/parse_min/parse_min_test.go
  24. 7 8
      app/lev1/product/parser_time/parse_sec/parse_sec.go
  25. 6 20
      app/lev1/product/parser_time/parse_sec/parse_sec_test.go
  26. 16 42
      app/lev1/product/parser_time/parser_time.go
  27. 10 30
      app/lev1/product/parser_time/parser_time_test.go
  28. 1 6
      app/lev1/shot/shot.go
  29. 3 5
      app/lev1/shot/shot_time/shot_time.go
  30. 14 22
      app/lev2/arena/arena.go
  31. 5 20
      app/lev2/arena/arena_angar/arena_angar.go
  32. 2 7
      app/lev2/arena/arena_arsenal/arena_arsenal.go
  33. 1 4
      app/lev2/arena/arena_battle/battle_register/battle_register.go
  34. 1 4
      app/lev2/arena/arena_battle/battle_wait/battle_wait.go
  35. 3 4
      app/lev2/arena/arena_context/arena_context.go
  36. 55 44
      app/lev2/arena/arena_context/arena_state/arena_state.go
  37. 6 38
      app/lev2/arena/arena_convoy/arena_convoy.go
  38. 1 4
      app/lev2/arena/arena_death/death_register/death_register.go
  39. 1 4
      app/lev2/arena/arena_death/death_wait/death_wait.go
  40. 1 4
      app/lev2/arena/arena_death/death_worker/process_death/health/health.go
  41. 3 13
      app/lev2/arena/arena_division/div_war/div_war.go
  42. 3 13
      app/lev2/arena/arena_division/divwar/divwar.go
  43. 2 8
      app/lev2/arena/arena_market/arena_market.go
  44. 3 11
      app/lev2/arena/arena_masters/arena_masters.go
  45. 41 209
      app/lev2/arena/arena_mine/arena_mine.go
  46. 1 3
      app/lev2/arena/arena_net/arena_net.go
  47. 13 43
      app/lev2/arena/arena_polygon/arena_polygon.go
  48. 8 14
      app/lev2/arena/down_time/down_time.go
  49. 15 0
      app/lev3/bot/bot.go
  50. 2 2
      app/lev3/serv_web/serv_web.go
  51. 3 3
      app/lev3/serv_web/web_api/web_api.go
  52. 4 4
      app/lev3/serv_web/web_gui/page_bot_show/page_bot_show.go
  53. 3 2
      app/lev3/serv_web/web_gui/page_login/page_login.go
  54. 1 1
      go.mod
  55. 2 2
      go.sum
  56. 7 0
      vendor/gitp78su.ipnodns.ru/svi/kern/kern.go
  57. 0 2
      vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_kctx/mod_kctx.go
  58. 0 2
      vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_keeper/mod_keeper.go
  59. 5 3
      vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/btn_modules/block_modules.html
  60. 0 0
      vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/btn_modules/block_row.html
  61. 66 0
      vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/btn_modules/btn_modules.go
  62. 16 0
      vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/btn_monolit/block_monolit.html
  63. 34 0
      vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/btn_monolit/btn_monolit.go
  64. 0 2
      vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/mod_serv_http.go
  65. 0 70
      vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_modules/page_modules.go
  66. 17 3
      vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_monolit/page_monolit.go
  67. 4 4
      vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_monolit/page_monolit.html
  68. 84 0
      vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_wui/mod_wui.go
  69. 42 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/hx_swap/hx_swap.go
  70. 42 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/hx_swap_oob/hx_swap_oob.go
  71. 42 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/hx_target/hx_target.go
  72. 42 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/hx_trigger/hx_trigger.go
  73. 39 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/hx_url/hx_url.go
  74. 37 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/hx_url_method/hx_url_method.go
  75. 39 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/hx_url_patch/hx_url_patch.go
  76. 69 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/hx_vals/hx_vals.go
  77. 64 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/wbutton/wbutton.go
  78. 27 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/wctx/wctx.go
  79. 92 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/whx/whx.go
  80. 54 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtext/wtext.go
  81. 57 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/ihx_swap.go
  82. 29 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/ihx_swap_oob.go
  83. 47 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/ihx_target.go
  84. 157 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/ihx_trigger.go
  85. 11 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/ihx_url.go
  86. 15 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/ihx_url_method.go
  87. 9 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/ihx_url_patch.go
  88. 30 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/ihx_vals.go
  89. 12 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/iwui_button.go
  90. 11 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/iwui_ctx.go
  91. 19 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/iwui_hx.go
  92. 8 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/iwui_label.go
  93. 10 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/iwui_text.go
  94. 9 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/iwui_widget.go
  95. 20 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/wui.go
  96. 38 0
      vendor/gitp78su.ipnodns.ru/svi/kern/wui/wwidget/wui_widget.go
  97. 19 2
      vendor/modules.txt

+ 18 - 13
app/lev0/bfunc/bf_ammo_make/bf_ammo_make.go

@@ -8,6 +8,7 @@ import (
 	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
 	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
 
+	"wartank/app/lev0/cons"
 	. "wartank/app/lev0/types"
 )
 
@@ -20,16 +21,20 @@ const (
 
 // СнарядыСделать -- делает снаряды в арсенале
 func СнарядыСделать(конт ILocalCtx) {
-	арсенал:=конт.Get("арсенал")
-	if арсенал==nil{ // Арсенала может и не быть
+	арсенал_ := конт.Get("арсенал")
+	if арсенал_ == nil { // Арсенала может и не быть
+		return
+	}
+	арсенал := арсенал_.Val().(ИАренаАрсенал)
+	if арсенал.АренаСостояние().Получ() != cons.РежимОжидание {
 		return
 	}
 	приоритет(конт)
 }
 
 // ищет приоритет производства
-func приоритет(конт ILocalCtx){
-	арсенал:=конт.Get("арсенал").Val().(ИАренаАрсенал)
+func приоритет(конт ILocalCtx) {
+	арсенал := конт.Get("арсенал").Val().(ИАренаАрсенал)
 	var (
 		ремкаКол  = арсенал.Ремки().Получ()
 		фугасКол  = арсенал.Фугасы().Получ()
@@ -68,8 +73,8 @@ func приоритет(конт ILocalCtx){
 }
 
 // Создать бронебойные
-func сделатьБронебойки(конт ILocalCtx)  {
-	арсенал:=конт.Get("арсенал").Val().(ИАренаАрсенал)
+func сделатьБронебойки(конт ILocalCtx) {
+	арсенал := конт.Get("арсенал").Val().(ИАренаАрсенал)
 	var (
 		стрВых      string
 		lstArsenal  = арсенал.СписПолучить()
@@ -103,8 +108,8 @@ func сделатьБронебойки(конт ILocalCtx)  {
 }
 
 // Создать кумулятивные
-func сделатьКумули(конт ILocalCtx)  {
-	арсенал:=конт.Get("арсенал").Val().(ИАренаАрсенал)
+func сделатьКумули(конт ILocalCtx) {
+	арсенал := конт.Get("арсенал").Val().(ИАренаАрсенал)
 	var (
 		стрВых      string
 		lstArsenal  = арсенал.СписПолучить()
@@ -138,8 +143,8 @@ func сделатьКумули(конт ILocalCtx)  {
 }
 
 // Создать фугасы
-func сделатьФугасы(конт ILocalCtx)  {
-	арсенал:=конт.Get("арсенал").Val().(ИАренаАрсенал)
+func сделатьФугасы(конт ILocalCtx) {
+	арсенал := конт.Get("арсенал").Val().(ИАренаАрсенал)
 	var (
 		lstArsenal  = арсенал.СписПолучить()
 		стрВых      string
@@ -174,8 +179,8 @@ func сделатьФугасы(конт ILocalCtx)  {
 }
 
 // Создать ремку. Выполняется если подходят условия
-func сделатьРемку(конт ILocalCtx)  {
-	арсенал:=конт.Get("арсенал").Val().(ИАренаАрсенал)
+func сделатьРемку(конт ILocalCtx) {
+	арсенал := конт.Get("арсенал").Val().(ИАренаАрсенал)
 	var (
 		стрВых      string
 		еслиНайдено bool
@@ -203,4 +208,4 @@ func сделатьРемку(конт ILocalCtx)  {
 	time.Sleep(time.Millisecond * 50)
 	_ = арсенал.Сеть().ВебВоркер().Получ(ссылка)
 	арсенал.ПродуктСейчас().ИмяУст(стрРемки)
-}
+}

+ 8 - 2
app/lev0/bfunc/bf_ammo_stat/bf_ammo_stat.go

@@ -8,13 +8,19 @@ import (
 	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
 	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
 
+	"wartank/app/lev0/cons"
 	. "wartank/app/lev0/types"
 )
 
 // СнарядыСтат -- получает статистику снарядов
 func СнарядыСтат(конт ILocalCtx) {
-	арсенал := конт.Get("арсенал")
-	if арсенал == nil { // Может быть не построен
+	арсенал_ := конт.Get("арсенал")
+	if арсенал_ == nil { // Может быть не построен
+		return
+	}
+	арсенал := арсенал_.Val().(ИАренаАрсенал)
+
+	if арсенал.АренаСостояние().Получ() != cons.РежимОжидание {
 		return
 	}
 	фугасыНайти(конт)

+ 86 - 0
app/lev0/bfunc/bf_arsenal_build/bf_bank_build.go

@@ -0,0 +1,86 @@
+// package bf_arsenal_build -- бизнес-функция строительства арсенала
+package bf_arsenal_build
+
+import (
+	"strings"
+
+	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
+
+	"wartank/app/lev0/cons"
+	. "wartank/app/lev0/types"
+)
+
+// БанкПостроить -- постройка арсенала
+func АрсеналПостроить(конт ILocalCtx) {
+	арсенал := конт.Get("арсенал").Val().(ИАренаАрсенал)
+	if арсенал.АренаСостояние().Получ() == cons.РежимНеСуществует {
+		банкПостроить(конт)
+	}
+}
+
+func банкПостроить(конт ILocalCtx) {
+	база := конт.Get("база").Val().(ИАренаБаза)
+	арсенал := конт.Get("арсенал").Val().(ИАренаАрсенал)
+	списСтр := база.Сеть().ВебВоркер().Получ("https://wartank.ru/buildings")
+	ссыльПостроить := "" // ссылка на постройку
+
+	{ // Поиск ссылки на покупку
+		// <td style="width:50%;padding-left:1px;"><a class="simple-but border mb5" href="building-upgrade/Armory"><span><span>Построить</span></span></a></td>
+		for _, стр := range списСтр {
+			if strings.Contains(стр, `href="building-upgrade/Armory">`) {
+				ссыльПостроить = стр
+				break
+			}
+		}
+		if ссыльПостроить == "" {
+			арсенал.АренаСостояние().Уст(cons.РежимАпгрейдПлатный)
+			return
+		}
+		// <td style="width:50%;padding-left:1px;"><a class="simple-but border mb5" href="building-upgrade/Armory"><span><span>Построить</span></span></a></td>
+		ссыльПостроить = strings.TrimPrefix(ссыльПостроить, `<td style="width:50%;padding-left:1px;"><a class="simple-but border mb5" href="`)
+		ссыльПостроить = strings.TrimSuffix(ссыльПостроить, `"><span><span>Построить</span></span></a></td>`)
+		// https://wartank.ru/building-upgrade/Armory
+		ссыльПостроить = "http://wartank.ru/" + ссыльПостроить
+		списСтр = база.Сеть().ВебВоркер().Получ(ссыльПостроить)
+	}
+	ссыльПодтвердить := "" // ссылка на улучшение здания
+
+	{ // Выбор покупки
+		// <a class="simple-but border mb5" href="Armory?29-1.ILinkListener-upgradeLink-link">
+		for _, стр := range списСтр {
+			if strings.Contains(стр, `ILinkListener-upgradeLink-link`) {
+				ссыльПодтвердить = стр
+				break
+			}
+		}
+		if ссыльПодтвердить == "" {
+			арсенал.АренаСостояние().Уст(cons.РежимАпгрейдПлатный)
+			return
+		}
+		ссыльПодтвердить = strings.TrimPrefix(ссыльПодтвердить, `<a class="simple-but border mb5" href="`)
+		ссыльПодтвердить = strings.TrimSuffix(ссыльПодтвердить, `">`)
+		// https://wartank.ru/building-upgrade/Armory?28-1.ILinkListener-upgradeLink-link
+		ссыльПодтвердить = "http://wartank.ru/building-upgrade/" + ссыльПодтвердить
+		списСтр = база.Сеть().ВебВоркер().Получ(ссыльПодтвердить)
+	}
+	ссыльДа := "" // подтверждение покупки
+	{             // Подтверждение покупки
+		// <a class="simple-but border w50 mXa mb10" w:id="confirmLink" href="../wicket/page?31-1.ILinkListener-confirmLink"><span><span>да, подтверждаю</span></span></a>
+		for _, стр := range списСтр {
+			if strings.Contains(стр, `confirmLink`) {
+				ссыльДа = стр
+				break
+			}
+		}
+		if ссыльДа == "" {
+			арсенал.АренаСостояние().Уст(cons.РежимАпгрейдПлатный)
+			return
+		}
+		ссыльДа = strings.TrimPrefix(ссыльДа, `<a class="simple-but border w50 mXa mb10" w:id="confirmLink" href="../`)
+		ссыльДа = strings.TrimSuffix(ссыльДа, `"><span><span>да, подтверждаю</span></span></a>`)
+		// https://wartank.ru/wicket/page?52-1.ILinkListener-confirmLink
+		ссыльДа = "http://wartank.ru/" + ссыльДа
+		_ = база.Сеть().ВебВоркер().Получ(ссыльДа)
+		арсенал.АренаСостояние().Уст(cons.РежимАпгрейдПлатный)
+	}
+}

+ 86 - 0
app/lev0/bfunc/bf_bank_build/bf_bank_build.go

@@ -0,0 +1,86 @@
+// package bf_bank_build -- бизнес-функция строительства банка
+package bf_bank_build
+
+import (
+	"strings"
+
+	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
+
+	"wartank/app/lev0/cons"
+	. "wartank/app/lev0/types"
+)
+
+// БанкПостроить -- постройка банка
+func БанкПостроить(конт ILocalCtx) {
+	банк := конт.Get("арена_банк").Val().(ИАренаБанк)
+	if банк.АренаСостояние().Получ() == cons.РежимНеСуществует {
+		банкПостроить(конт)
+	}
+}
+
+func банкПостроить(конт ILocalCtx) {
+	база := конт.Get("база").Val().(ИАренаБаза)
+	банк := конт.Get("арена_банк").Val().(ИАренаБанк)
+	списСтр := база.Сеть().ВебВоркер().Получ("https://wartank.ru/buildings")
+	ссыльПостроить := "" // ссылка на постройку
+
+	{ // Поиск ссылки на покупку
+		// <td style="width:50%;padding-left:1px;"><a class="simple-but border mb5" href="building-upgrade/Bank"><span><span>Построить</span></span></a></td>
+		for _, стр := range списСтр {
+			if strings.Contains(стр, `href="building-upgrade/Bank">`) {
+				ссыльПостроить = стр
+				break
+			}
+		}
+		if ссыльПостроить == "" {
+			банк.АренаСостояние().Уст(cons.РежимАпгрейдПлатный)
+			return
+		}
+		// <td style="width:50%;padding-left:1px;"><a class="simple-but border mb5" href="building-upgrade/Bank"><span><span>Построить</span></span></a></td>
+		ссыльПостроить = strings.TrimPrefix(ссыльПостроить, `<td style="width:50%;padding-left:1px;"><a class="simple-but border mb5" href="`)
+		ссыльПостроить = strings.TrimSuffix(ссыльПостроить, `"><span><span>Построить</span></span></a></td>`)
+		// https://wartank.ru/building-upgrade/Bank
+		ссыльПостроить = "http://wartank.ru/" + ссыльПостроить
+		списСтр = база.Сеть().ВебВоркер().Получ(ссыльПостроить)
+	}
+	ссыльПодтвердить := "" // ссылка на улучшение здания
+
+	{ // Выбор покупки
+		// <a class="simple-but border mb5" href="Bank?29-1.ILinkListener-upgradeLink-link">
+		for _, стр := range списСтр {
+			if strings.Contains(стр, `ILinkListener-upgradeLink-link`) {
+				ссыльПодтвердить = стр
+				break
+			}
+		}
+		if ссыльПодтвердить == "" {
+			банк.АренаСостояние().Уст(cons.РежимАпгрейдПлатный)
+			return
+		}
+		ссыльПодтвердить = strings.TrimPrefix(ссыльПодтвердить, `<a class="simple-but border mb5" href="`)
+		ссыльПодтвердить = strings.TrimSuffix(ссыльПодтвердить, `">`)
+		// https://wartank.ru/building-upgrade/Bank?28-1.ILinkListener-upgradeLink-link
+		ссыльПодтвердить = "http://wartank.ru/building-upgrade/" + ссыльПодтвердить
+		списСтр = база.Сеть().ВебВоркер().Получ(ссыльПодтвердить)
+	}
+	ссыльДа := "" // подтверждение покупки
+	{             // Подтверждение покупки
+		// <a class="simple-but border w50 mXa mb10" w:id="confirmLink" href="../wicket/page?31-1.ILinkListener-confirmLink"><span><span>да, подтверждаю</span></span></a>
+		for _, стр := range списСтр {
+			if strings.Contains(стр, `confirmLink`) {
+				ссыльДа = стр
+				break
+			}
+		}
+		if ссыльДа == "" {
+			банк.АренаСостояние().Уст(cons.РежимАпгрейдПлатный)
+			return
+		}
+		ссыльДа = strings.TrimPrefix(ссыльДа, `<a class="simple-but border w50 mXa mb10" w:id="confirmLink" href="../`)
+		ссыльДа = strings.TrimSuffix(ссыльДа, `"><span><span>да, подтверждаю</span></span></a>`)
+		// https://wartank.ru/wicket/page?52-1.ILinkListener-confirmLink
+		ссыльДа = "http://wartank.ru/" + ссыльДа
+		_ = база.Сеть().ВебВоркер().Получ(ссыльДа)
+		банк.АренаСостояние().Уст(cons.РежимАпгрейдПлатный)
+	}
+}

+ 3 - 21
app/lev0/bfunc/bf_glory_make/bf_glory_make.go

@@ -4,7 +4,6 @@ package bf_glory_make
 import (
 	"strings"
 
-	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
 	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
 
 	. "wartank/app/lev0/types"
@@ -25,25 +24,9 @@ func атакаНачать(конт ILocalCtx, strOut string) {
 	strLink := strOut
 	// Можно начать разведку
 	lstConvoy := конвой.Сеть().ВебВоркер().Получ(strLink)
-	if err := конвой.СтрОбновить(lstConvoy); err != nil {
-		for _, strOut = range lstConvoy {
-			if strings.Contains(strOut, `<title>Ошибка на сервере. Сообщение админу уже отправлено.</title>`) {
-				// log._rintf("ERRO Конвой.атакаНачать(): при обновлении lstConvoy, strOut=\n\t%v\n", strOut)
-				return
-			}
-		}
-		for _, strOut = range lstConvoy {
-			if strings.Contains(strOut, `<title>База</title>`) {
-				// log._rintf("ERRO Конвой.атакаНачать(): при обновлении lstConvoy (найдено lstBase), strOut=\n\t%v\n", strOut)
-				return
-			}
-		}
-		// log._rintf("ERRO Конвой.атакаНачать(): при обновлении lstConvoy, err=\n\t%v\n", err)
-		return
-	}
+	конвой.СтрОбновить(lstConvoy)
 	начатьРазведку(конт)
-	err := конвой.ОбратВремяУст("01")
-	Hassert(err == nil, "Конвой.атакаНачать(): при установке CountDown, err=\n\t%v", err)
+	конвой.ОбратВремяУст("01")
 }
 
 func атакаПроверить(конт ILocalCtx) string {
@@ -123,7 +106,6 @@ func начатьРазведку(конт ILocalCtx) {
 	link := "https://wartank.ru/" + _link
 	{ // Выполнить атаку
 		lstConvoy = конвой.Сеть().ВебВоркер().Получ(link)
-		err := конвой.СтрОбновить(lstConvoy)
-		Hassert(err == nil, "Конвой.attack(): при обновлении lstConvoy, err=\n\t%v", err)
+		конвой.СтрОбновить(lstConvoy)
 	}
 }

+ 104 - 0
app/lev0/bfunc/bf_mine_accelerate/bf_mine_accelerate.go

@@ -0,0 +1,104 @@
+// package bf_mine_accelerate -- бизнес-функция ускорения строительства или апгрейда
+package bf_mine_accelerate
+
+import (
+	"fmt"
+	"strings"
+
+	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
+
+	"wartank/app/lev0/cons"
+	. "wartank/app/lev0/types"
+)
+
+// ШахтаУскорить -- пробует ускорить строительство шахты или апгрейда
+func ШахтаУскорить(конт ILocalCtx) {
+	шахта := конт.Get("шахта").Val().(ИАренаШахта)
+	еслиАпгрейд := шахта.АренаСостояние().Получ() == cons.РежимАпгрейд
+	еслиПлатный := шахта.АренаСостояние().Получ() == cons.РежимАпгрейдПлатный
+	if !(еслиАпгрейд || еслиПлатный) {
+		return
+	}
+	шахтаАпгрейд(конт)
+}
+
+func шахтаАпгрейд(конт ILocalCtx) {
+	база := конт.Get("база").Val().(ИАренаБаза)
+	шахта := конт.Get("шахта").Val().(ИАренаШахта)
+	var (
+		еслиНайти = false
+		списСтр   []string
+		стр       = ""
+	)
+	фнКупитьАпгрейд := func() (bool, error) {
+		списСтр = база.Сеть().ВебВоркер().Получ("https://wartank.ru/building-upgrade/Mine")
+		for _, стр = range списСтр {
+			// <a class="simple-but border mb5" href="Mine?5-1.ILinkListener-upgradeLink-link">
+			if strings.Contains(стр, `ILinkListener-upgradeLink-link`) {
+				еслиНайти = true
+				break
+			}
+		}
+		if !еслиНайти {
+			return false, nil
+		}
+		// Пробуем улучшить шахту
+		_стр := strings.TrimPrefix(стр, "<a class=\"simple-but border mb5\" href=\"")
+		_стр = strings.TrimSuffix(_стр, "\">")
+		// https://wartank.ru/building-upgrade/Mine?4-1.ILinkListener-upgradeLink-link
+		// <a class="simple-but border mb5" href="FuelStorage?50-1.ILinkListener-upgradeLink-link">
+		ссылка := "https://wartank.ru/building-upgrade/" + _стр
+		списСтр = база.Сеть().ВебВоркер().Получ(ссылка)
+		// Проверить, что постройка состоялась
+		for _, стр := range списСтр {
+			if strings.Contains(стр, "ILinkListener-upgradeLink-link") {
+				return false, fmt.Errorf("покупка шахты не прошла") // Покупка не оплачена
+			}
+		}
+		return true, nil
+	}
+
+	фнПодтверждение := func() bool {
+		for _, стр = range списСтр {
+			// <a class="simple-but border w50 mXa mb10" w:id="confirmLink" href="../wicket/page?7-1.ILinkListener-confirmLink"><span><span>да, подтверждаю</span></span></a>
+			if strings.Contains(стр, `ILinkListener-confirmLink`) {
+				еслиНайти = true
+				break
+			}
+		}
+		if !еслиНайти {
+			return true
+		}
+		// Пробуем построить шахту
+		_стр := strings.TrimPrefix(стр, `<a class="simple-but border w50 mXa mb10" w:id="confirmLink" href="..`)
+		_стр = strings.TrimSuffix(_стр, `"><span><span>да, подтверждаю</span></span></a>`)
+		// https://wartank.ru/wicket/page?6-1.ILinkListener-confirmLink
+		ссылка := "https://wartank.ru" + _стр
+		списСтр = база.Сеть().ВебВоркер().Получ(ссылка)
+		// Проверить, что постройка состоялась
+		for _, стр := range списСтр {
+			if strings.Contains(стр, "<title>Вы сделали слишком большую паузу</title>") {
+				return false // Покупка не оплачена
+			}
+		}
+		return true
+	}
+
+	фнКомплекс := func() {
+		еслиОк, ош := фнКупитьАпгрейд()
+		switch {
+		case ош == nil && еслиОк: // покупка апгрейда шахты прошла
+			if фнПодтверждение() {
+				шахта.АренаСостояние().Уст(cons.РежимАпгрейдПлатный)
+				return
+			}
+		case ош == nil && !еслиОк: // покупка шахты не нужна
+			шахта.АренаСостояние().Уст(cons.РежимОжидание)
+			return
+		case ош != nil: // ошибка при работе с сетью
+			шахта.АренаСостояние().Уст(cons.РежимАпгрейд)
+			return
+		}
+	}
+	фнКомплекс()
+}

+ 63 - 0
app/lev0/bfunc/bf_mine_build/bf_mine_build.go

@@ -0,0 +1,63 @@
+// package bf_mine_build -- бизнес-функция постройки шахты
+package bf_mine_build
+
+import (
+	"strings"
+
+	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
+
+	"wartank/app/lev0/cons"
+	. "wartank/app/lev0/types"
+)
+
+// ШахтаПостроить -- постройка шахты
+func ШахтаПостроить(конт ILocalCtx) {
+	шахта := конт.Get("шахта").Val().(ИАренаШахта)
+	if шахта.АренаСостояние().Получ() == cons.РежимНеСуществует {
+		шахтаПостроить(конт)
+	}
+}
+
+func шахтаПостроить(конт ILocalCtx) {
+	база := конт.Get("база").Val().(ИАренаБаза)
+	шахта := конт.Get("шахта").Val().(ИАренаШахта)
+	// <td style="width:50%;padding-left:1px;"><a class="simple-but border mb5" href="building-upgrade/Mine"><span><span>Построить</span></span></a></td>
+	var (
+		еслиНайти = false
+		стр       = ""
+	)
+	списСтр := база.Сеть().ВебВоркер().Получ("http://wartank.ru/buildings")
+	for _, стр = range списСтр {
+		if strings.Contains(стр, `href="building-upgrade/Mine"><span><span>Построить</span></span>`) {
+			еслиНайти = true
+			break
+		}
+	}
+	if !еслиНайти {
+		шахта.АренаСостояние().Уст(cons.РежимАпгрейдПлатный)
+		return
+	}
+	// Пробуем построить шахту
+	_стр := strings.TrimPrefix(стр, `<td style="width:50%;padding-left:1px;"><a class="simple-but border mb5" href="`)
+	_стр = strings.TrimSuffix(_стр, `"><span><span>Построить</span></span></a></td>`)
+	ссылка := "https://wartank.ru/" + _стр
+	списСтр = база.Сеть().ВебВоркер().Получ(ссылка)
+	еслиНайти = false
+	// "<a class=\"simple-but border mb5\" href=\"Mine?14-1.ILinkListener-upgradeLink-link\">"
+	for _, стр = range списСтр {
+		if strings.Contains(стр, `ILinkListener-upgradeLink-link`) {
+			еслиНайти = true
+			break
+		}
+	}
+	if !еслиНайти {
+		шахта.АренаСостояние().Уст(cons.РежимАпгрейдПлатный)
+		return
+	}
+	_стр = strings.TrimPrefix(стр, "<a class=\"simple-but border mb5\" href=\"")
+	_стр = strings.TrimSuffix(_стр, "\">")
+	// http://wartank.ru/building-upgrade/Mine?16-1.ILinkListener-upgradeLink-link
+	ссылка = "https://wartank.ru/building-upgrade/" + _стр
+	_ = база.Сеть().ВебВоркер().Получ(ссылка)
+	шахта.АренаСостояние().Уст(cons.РежимАпгрейдПлатный)
+}

+ 11 - 45
app/lev0/bfunc/bf_mission_simple/bf_missin_simple.go

@@ -57,10 +57,7 @@ func kill3tanks(конт ILocalCtx) {
 		// log._rintf("ERRO Миссии.kill3tanks(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	if err := арена.СтрОбновить(lstMissions); err != nil {
-		// log._rintf("ERRO Миссии.kill3tanks(): при обновлении lstMissions, err=\n\t%v\n", err)
-		return
-	}
+	арена.СтрОбновить(lstMissions)
 }
 
 // Проверяет награду оборонительного сражения
@@ -91,10 +88,7 @@ func сражениеЗащита(конт ILocalCtx) {
 		// log._rintf("ERRO Миссии.battleDefence(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	if err := арена.СтрОбновить(списМиссия); err != nil {
-		// log._rintf("ERRO Миссии.battleDefence(): при обновлении lstMissions, err=\n\t%v\n", err)
-		return
-	}
+	арена.СтрОбновить(списМиссия)
 }
 
 // Проверяет награду за одну войну
@@ -130,10 +124,7 @@ func проведиВойну(конт ILocalCtx) {
 		// log._rintf("ERRO Миссии.battleWar(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	if err := арена.СтрОбновить(lstMissions); err != nil {
-		// log._rintf("ERRO Миссии.battleWar(): при обновлении lstMissions, err=\n\t%v\n", err)
-		return
-	}
+	арена.СтрОбновить(lstMissions)
 }
 
 // Проверяет награду наступательного сражения
@@ -173,10 +164,7 @@ func сражениеНаступление(конт ILocalCtx) {
 		// log._rintf("ERRO Миссии.battleAttack(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	if err := арена.СтрОбновить(lstMissions); err != nil {
-		// log._rintf("ERRO Миссии.battleAttack(): при обновлении lstMissions, err=\n\t%v\n", err)
-		return
-	}
+	арена.СтрОбновить(lstMissions)
 }
 
 // Проверяет награду за схватку
@@ -212,10 +200,7 @@ func battleDogFyting(конт ILocalCtx) {
 		// log._rintf("ERRO Миссии.battleDogFyting(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	if err := арена.СтрОбновить(lstMissions); err != nil {
-		// log._rintf("ERRO Миссии.battleDogFyting(): при обновлении lstMissions, err=\n\t%v\n", err)
-		return
-	}
+	арена.СтрОбновить(lstMissions)
 }
 
 // Проверяет награду за ресурсы
@@ -251,10 +236,7 @@ func makeResource(конт ILocalCtx) {
 		// log._rintf("ERRO Миссии.makeResource(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	if err := арена.СтрОбновить(lstMissions); err != nil {
-		// log._rintf("ERRO Миссии.makeResource(): при обновлении lstMissions, err=\n\t%v\n", err)
-		return
-	}
+	арена.СтрОбновить(lstMissions)
 }
 
 // Проверяет награду за ресурсы
@@ -290,10 +272,7 @@ func upMan(конт ILocalCtx) {
 		// log._rintf("ERRO Миссии.upMan(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	if err := арена.СтрОбновить(lstMissions); err != nil {
-		// log._rintf("ERRO Миссии.upMan(): при обновлении lstMissions, err=\n\t%v\n", err)
-		return
-	}
+	арена.СтрОбновить(lstMissions)
 	// log._rintf("INFO Миссии.upMan(): награда получена\n")
 }
 
@@ -330,11 +309,7 @@ func топливоДив(конт ILocalCtx) {
 		// log._rintf("ERRO Миссии.makeFuel(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	if err := арена.СтрОбновить(lstMissions); err != nil {
-		// log._rintf("ERRO Миссии.makeFuel(): при обновлении lstMissions, err=\n\t%v\n", err)
-		return
-	}
-	// log._rintf("INFO Миссии.makeFuel(): награда получена")
+	арена.СтрОбновить(lstMissions)
 }
 
 // Проверяет награду 5 боёв
@@ -370,10 +345,7 @@ func battle5Fiting(конт ILocalCtx) {
 		// log._rintf("ERRO Миссии.battle5Fiting(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	if err := арена.СтрОбновить(lstMissions); err != nil {
-		// log._rintf("ERRO Миссии.battle5Fiting(): при обновлении lstMissions, err=\n\t%v\n", err)
-		return
-	}
+	арена.СтрОбновить(lstMissions)
 }
 
 // Проверяет награду 10 боёв
@@ -409,10 +381,7 @@ func battle10Fiting(конт ILocalCtx) {
 		// log._rintf("ERRO Миссии.battle10Fiting(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	if err := арена.СтрОбновить(lstMissions); err != nil {
-		// log._rintf("ERRO Миссии.battle10Fiting(): при обновлении lstMissions, err=\n\t%v\n", err)
-		return
-	}
+	арена.СтрОбновить(lstMissions)
 }
 
 // Проверяет награду за 6 побед подряд
@@ -448,8 +417,5 @@ func battle6win(конт ILocalCtx) {
 		// log._rintf("ERRO Миссии.battle6win(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	if err := арена.СтрОбновить(lstMissions); err != nil {
-		// log._rintf("ERRO Миссии.battle6win(): при обновлении lstMissions, err=\n\t%v\n", err)
-		return
-	}
+	арена.СтрОбновить(lstMissions)
 }

+ 10 - 4
app/lev0/bfunc/bf_polygon_activate/bf_polygon_activate.go

@@ -8,6 +8,7 @@ import (
 	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
 	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
 
+	"wartank/app/lev0/cons"
 	. "wartank/app/lev0/types"
 )
 
@@ -26,6 +27,11 @@ func ПолигонАктивировать(конт ILocalCtx) {
 	if полигон_ == nil { // Может быть ещё не построен
 		return
 	}
+	полигон := полигон_.Val().(ИАренаПолигон)
+	еслиОжидание := полигон.АренаСостояние().Получ() == cons.РежимОжидание
+	if !еслиОжидание {
+		return
+	}
 	усилениеДобавить(конт)
 }
 
@@ -111,7 +117,7 @@ func усилениеДобавить(конт ILocalCtx) {
 			iForce, err := strconv.Atoi(strForce)
 			Hassert(err == nil, "усилениеДобавить(): strForceAttack(%v) not int, err=\n\t%v", strForce, err)
 			танкСтат.ФорсажОбнов("attack", iForce)
-			полигон.АренаСостояние().РаботаИмяУст(стрАтака)
+			полигон.ПродуктСейчас().ИмяУст(стрАтака)
 		}
 	case стрБроня: // Усиливаем броню
 		еслиНайдено = false
@@ -144,7 +150,7 @@ func усилениеДобавить(конт ILocalCtx) {
 			iForce, err := strconv.Atoi(strForce)
 			Hassert(err == nil, "усилениеДобавить(): стрБроня(%v) not int, err=\n\t%v\n", strForce, err)
 			танкСтат.ФорсажОбнов(стрБроня, iForce)
-			полигон.АренаСостояние().РаботаИмяУст(стрБроня)
+			полигон.ПродуктСейчас().ИмяУст(стрБроня)
 		}
 	case стрТочность: // Усиливаем точность
 		еслиНайдено = false
@@ -177,7 +183,7 @@ func усилениеДобавить(конт ILocalCtx) {
 			iForce, err := strconv.Atoi(strForce)
 			Hassert(err == nil, "усилениеДобавить(): стрТочность(%v) not int, err=\n\t%v", strForce, err)
 			танкСтат.ФорсажОбнов(стрТочность, iForce)
-			полигон.АренаСостояние().РаботаИмяУст(стрТочность)
+			полигон.ПродуктСейчас().ИмяУст(стрТочность)
 		}
 	case стрПрочность: // Усиливаем мощность
 		еслиНайдено = false
@@ -207,7 +213,7 @@ func усилениеДобавить(конт ILocalCtx) {
 			iForce, err := strconv.Atoi(strForce)
 			Hassert(err == nil, "усилениеДобавить(): стрПрочность(%v) not int, err=\n\t%v", strForce, err)
 			танкСтат.ФорсажОбнов(стрПрочность, iForce)
-			полигон.АренаСостояние().РаботаИмяУст(стрПрочность)
+			полигон.ПродуктСейчас().ИмяУст(стрПрочность)
 		}
 	default: // Неизвестно что
 		Hassert(false, "усилениеДобавить(): усиление(%v) неизвестно", strParam)

+ 86 - 0
app/lev0/bfunc/bf_polygon_build/bf_polygon_build.go

@@ -0,0 +1,86 @@
+// package bf_polygon_build -- бизнес-функция постройки полигона
+package bf_polygon_build
+
+import (
+	"strings"
+
+	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
+
+	"wartank/app/lev0/cons"
+	. "wartank/app/lev0/types"
+)
+
+// ПолигонПостроить -- постройка полигон
+func ПолигонПостроить(конт ILocalCtx) {
+	полигон := конт.Get("полигон").Val().(ИАренаПолигон)
+	if полигон.АренаСостояние().Получ() == cons.РежимНеСуществует {
+		полигонПостроить(конт)
+	}
+}
+
+func полигонПостроить(конт ILocalCtx) {
+	база := конт.Get("база").Val().(ИАренаБаза)
+	полигон := конт.Get("полигон").Val().(ИАренаПолигон)
+	списСтр := база.Сеть().ВебВоркер().Получ("https://wartank.ru/buildings")
+	ссыльПостроить := "" // ссылка на постройку
+
+	{ // Поиск ссылки на покупку
+		// <td style="width:50%;padding-left:1px;"><a class="simple-but border mb5" href="building-upgrade/Polygon"><span><span>Построить</span></span></a></td>
+		for _, стр := range списСтр {
+			if strings.Contains(стр, `href="building-upgrade/Polygon">`) {
+				ссыльПостроить = стр
+				break
+			}
+		}
+		if ссыльПостроить == "" {
+			полигон.АренаСостояние().Уст(cons.РежимАпгрейдПлатный)
+			return
+		}
+		// <td style="width:50%;padding-left:1px;"><a class="simple-but border mb5" href="building-upgrade/Polygon"><span><span>Построить</span></span></a></td>
+		ссыльПостроить = strings.TrimPrefix(ссыльПостроить, `<td style="width:50%;padding-left:1px;"><a class="simple-but border mb5" href="`)
+		ссыльПостроить = strings.TrimSuffix(ссыльПостроить, `"><span><span>Построить</span></span></a></td>`)
+		// https://wartank.ru/building-upgrade/Polygon
+		ссыльПостроить = "http://wartank.ru/" + ссыльПостроить
+		списСтр = база.Сеть().ВебВоркер().Получ(ссыльПостроить)
+	}
+	ссыльПодтвердить := "" // ссылка на улучшение здания
+
+	{ // Выбор покупки
+		// <a class="simple-but border mb5" href="Polygon?2-1.ILinkListener-upgradeLink-link">
+		for _, стр := range списСтр {
+			if strings.Contains(стр, `ILinkListener-upgradeLink-link`) {
+				ссыльПодтвердить = стр
+				break
+			}
+		}
+		if ссыльПодтвердить == "" {
+			полигон.АренаСостояние().Уст(cons.РежимАпгрейдПлатный)
+			return
+		}
+		ссыльПодтвердить = strings.TrimPrefix(ссыльПодтвердить, `<a class="simple-but border mb5" href="`)
+		ссыльПодтвердить = strings.TrimSuffix(ссыльПодтвердить, `">`)
+		// https://wartank.ru/building-upgrade/Polygon?2-1.ILinkListener-upgradeLink-link
+		ссыльПодтвердить = "http://wartank.ru/building-upgrade/" + ссыльПодтвердить
+		списСтр = база.Сеть().ВебВоркер().Получ(ссыльПодтвердить)
+	}
+	ссыльДа := "" // подтверждение покупки
+	{             // Подтверждение покупки
+		// <a class="simple-but border w50 mXa mb10" w:id="confirmLink" href="../wicket/page?53-1.ILinkListener-confirmLink"><span><span>да, подтверждаю</span></span></a>
+		for _, стр := range списСтр {
+			if strings.Contains(стр, `confirmLink`) {
+				ссыльДа = стр
+				break
+			}
+		}
+		if ссыльДа == "" {
+			полигон.АренаСостояние().Уст(cons.РежимАпгрейдПлатный)
+			return
+		}
+		ссыльДа = strings.TrimPrefix(ссыльДа, `<a class="simple-but border w50 mXa mb10" w:id="confirmLink" href="../`)
+		ссыльДа = strings.TrimSuffix(ссыльДа, `"><span><span>да, подтверждаю</span></span></a>`)
+		// https://wartank.ru/wicket/page?52-1.ILinkListener-confirmLink
+		ссыльДа = "http://wartank.ru/" + ссыльДа
+		_ = база.Сеть().ВебВоркер().Получ(ссыльДа)
+		полигон.АренаСостояние().Уст(cons.РежимАпгрейдПлатный)
+	}
+}

+ 8 - 2
app/lev0/bfunc/bf_silver_prod/bf_silver_prod.go

@@ -9,6 +9,7 @@ import (
 	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
 
 	. "wartank/app/lev0/alias"
+	"wartank/app/lev0/cons"
 	. "wartank/app/lev0/types"
 )
 
@@ -18,6 +19,12 @@ func СереброПроизводить(конт ILocalCtx) {
 	if банк_ == nil { // Возможно ещё не построен
 		return
 	}
+	банк := банк_.Val().(ИАренаБанк)
+	еслиРабота := банк.АренаСостояние().Получ() == cons.РежимРабота
+	еслиОжидание := банк.АренаСостояние().Получ() == cons.РежимОжидание
+	if !(еслиРабота || еслиОжидание) {
+		return
+	}
 	получитьВсеРежимы(конт)
 	сделатьСеребро(конт)
 }
@@ -110,7 +117,6 @@ func сделатьСеребро(конт ILocalCtx) {
 		strLink = "https://wartank.ru/production/" + lstLink[0]
 		_, err := банк.Сеть().Get(strLink)
 		Hassert(err == nil, "сделатьСеребро(): при выполнении GET-запроса, ош=\n\t%v", err)
-		err = банк.ОбратВремяУст(АВремя(time1))
-		Hassert(err == nil, "сделатьСеребро(): при установке времени производства банка(%v), err=\n\t%v", time1, err)
+		банк.ОбратВремяУст(АВремя(time1))
 	}
 }

+ 3 - 5
app/lev0/bfunc/bf_tank_stat/bf_tank_stat.go

@@ -20,8 +20,6 @@ func ТанкСтатПолучить(конт ILocalCtx) {
 	найтиМощь(конт)
 }
 
-
-
 func найтиМощь(конт ILocalCtx) {
 	ангар := конт.Get("ангар").Val().(ИАренаАнгар)
 	списАнгар := ангар.СписПолучить()
@@ -30,8 +28,8 @@ func найтиМощь(конт ILocalCtx) {
 		списАнгар = ангар.СписПолучить()
 	}
 	var (
-		стрМощь string
-		еслиЕсть    bool
+		стрМощь  string
+		еслиЕсть bool
 	)
 	// alt="Точность" title="Точность"/> Точность <span class="green2">
 	for _, стр := range списАнгар {
@@ -62,7 +60,7 @@ func найтиПрочность(конт ILocalCtx) {
 	}
 	var (
 		стрПрочность string
-		еслиЕсть    bool
+		еслиЕсть     bool
 	)
 	// alt="Точность" title="Точность"/> Точность <span class="green2">
 	for _, стр := range списАнгар {

+ 9 - 3
app/lev0/cons/cons.go

@@ -14,10 +14,16 @@ const ( // Задержки для работы
 )
 
 const ( // Режимы работы
+	// РежимНеСуществует -- объект не существует
 	РежимНеСуществует = alias.ААренаСостояние("режим_не_существует")
-	РежимАпгрейд      = alias.ААренаСостояние("режим_апгрейд")
-	РежимОжидание     = alias.ААренаСостояние("режим_ожидание")
-	РежимРабота       = alias.ААренаСостояние("режим_работа")
+	// РежимАпгрейд -- объект в режиме апгрейда
+	РежимАпгрейд = alias.ААренаСостояние("режим_апгрейд")
+	// РежимАпгрейдПлатный -- объект в режиме платного апгрейда
+	РежимАпгрейдПлатный = alias.ААренаСостояние("режим_апгрейд_платный")
+	// РежимОжидание -- ожидание работы или апгрейда
+	РежимОжидание = alias.ААренаСостояние("режим_ожидание")
+	// РежимРабота -- объект что-то делает
+	РежимРабота = alias.ААренаСостояние("режим_работа")
 )
 
 // const (

+ 2 - 2
app/lev0/types/iarena.go

@@ -10,9 +10,9 @@ type ИАрена interface {
 	// СписПолучить -- возвращает список строк арены
 	СписПолучить() []string
 	// СтрОбновить -- обновляет список строк арены
-	СтрОбновить(lstString []string) error
+	СтрОбновить(lstString []string)
 	// ОбратВремяУст -- устанавливает новое значение обратного счётчика времени
-	ОбратВремяУст(времяСек alias.АВремя) error
+	ОбратВремяУст(времяСек alias.АВремя)
 	// Обновить -- обновляет список строк арены
 	Обновить()
 	// Пуск -- запускает арену в обработку на текущий шаг

+ 4 - 11
app/lev0/types/iarena_state.go

@@ -4,15 +4,8 @@ import "wartank/app/lev0/alias"
 
 // ИАренаСостояние -- состояние арены
 type ИАренаСостояние interface {
-	// СостояниеУст -- устанавливает состояние арены (не существует, ожидание, апгрейд. работа)
-	СостояниеУст(alias.ААренаСостояние)
-	// Состояние -- возвращает состояние арены (не существует, ожидание, апгрейд, работа)
-	Состояние() alias.ААренаСостояние
-	// РаботаИмя -- возвращает имя текущей работы (зависит от режим-1/2, если позволяет режим)
-	РаботаИмя() alias.АРаботаИмя
-	// РаботаИмяУст -- устанавливает имя текущей работы(зависит от режим-1/2, если позволяет режим)
-	РаботаИмяУст(name alias.АРаботаИмя)
-	// РежимНомер -- возвращает номер режима
-	РежимНомер() alias.АРежим
-	// РежимНомерУст -- возвращает имя режима
+	// Уст -- устанавливает состояние арены (не существует, ожидание, апгрейд. работа)
+	Уст(alias.ААренаСостояние)
+	// Получ -- возвращает состояние арены (не существует, ожидание, апгрейд, работа)
+	Получ() alias.ААренаСостояние
 }

+ 1 - 1
app/lev0/types/icounttime.go

@@ -4,7 +4,7 @@ package types
 	Интерфейс к счётчику оставшегося времени
 */
 
-// ИВремяОстат -- нтерфейс к счётчику оставшегося времени
+// ИВремяОстат -- интерфейс к счётчику оставшегося времени
 type ИВремяОстат interface {
 	ИПарсерПростой
 	// КаналСиг -- возвращает канал тиков

+ 1 - 1
app/lev0/types/iparser_simple.go

@@ -7,7 +7,7 @@ import (
 // ИПарсерПростой -- базовый интерфейс парсеру времени
 type ИПарсерПростой interface {
 	// Уст -- устанавливает часы
-	Уст(АВремя) error
+	Уст(АВремя)
 	// Сброс -- сбрасывает хранимое значение
 	Сброс()
 	// String -- возвращает строковое представление

+ 1 - 7
app/lev1/health/health.go

@@ -222,14 +222,8 @@ func (сам *Здоровье) repair() {
 		сам.fnCancel()
 		return
 	}
-	if err = сам.СтрОбновить(lstBattleOn); err != nil {
-		// log._rintf("ERRO Health.repair(): при обновлении lstBattle, err=\n\t%v\n", err)
-		сам.isEnd.Set()
-		сам.Отменить()
-		return
-	}
+	сам.СтрОбновить(lstBattleOn)
 	// sound.Repair()
-	// log._rintf("INFO Health.repair(): здоровье восстановлено\n")
 }
 
 // Ищет своё здоровье (~)

+ 1 - 6
app/lev1/manevr/manevr.go

@@ -183,12 +183,7 @@ func (сам *манёвр) Выполнить() {
 			time.Sleep(time.Second * 1)
 			return
 		}
-		if err = сам.СтрОбновить(lstBattleOn); err != nil {
-			сам.лог.Err("манёвр.Выполнить(): при обновлении lstBattle, ош=\n\t%v", err)
-			сам.еслиГотов.Reset()
-			time.Sleep(time.Second * 1)
-			return
-		}
+		сам.СтрОбновить(lstBattleOn)
 		// sound.манёвр()
 	}
 }

+ 7 - 11
app/lev1/product/parser_time/parse_hour/parse_hour.go

@@ -4,6 +4,9 @@ import (
 	"fmt"
 	"strconv"
 	"sync"
+
+	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
+
 	. "wartank/app/lev0/alias"
 	. "wartank/app/lev0/types"
 )
@@ -55,20 +58,13 @@ func (сам *ПарсерЧас) Сброс() {
 // Уст -- устанавливает значение часов
 //
 //	Значение часов может быть больше 24
-func (сам *ПарсерЧас) Уст(часы АВремя) error {
+func (сам *ПарсерЧас) Уст(часы АВремя) {
 	сам.блок.Lock()
 	defer сам.блок.Unlock()
 	цЧасы, err := strconv.Atoi(string(часы))
-	if err != nil {
-		return fmt.Errorf("ПарсерЧас.Уст(): часы(%q) не число, err=\n\t%w", часы, err)
-	}
-	if цЧасы < 0 {
-		return fmt.Errorf("ПарсерЧас.Уст(): часы(%q) меньше нуля, err=\n\t%w", часы, err)
-	}
-	if err := сам.уст(АЧас(цЧасы)); err != nil {
-		return fmt.Errorf("ПарсерЧас.Уст(): in internal set hour(%q), err=\n\t%w", часы, err)
-	}
-	return nil
+	Hassert(err == nil, "ПарсерЧас.Уст(): часы(%q) не число, err=\n\t%v", часы, err)
+	err = сам.уст(АЧас(цЧасы))
+	Hassert(err == nil, "ПарсерЧас.Уст(): in internal set hour(%q), err=\n\t%w", часы, err)
 }
 
 // УстЧас -- устанавливает числовое значение часов

+ 7 - 19
app/lev1/product/parser_time/parse_hour/parse_hour_test.go

@@ -41,17 +41,13 @@ func (сам *tester) set() {
 }
 func (сам *tester) setGood1() {
 	сам.t.Logf("=setGood1=\n")
-	if err := сам.ph.Уст("8"); err != nil {
-		сам.t.Errorf("setGood1(): err=\n\t%v\n", err)
-	}
+	сам.ph.Уст("8")
 }
 
 // Отрицательное значение часа
 func (сам *tester) setBad1() {
 	сам.t.Logf("=setBad1=\n")
-	if err := сам.ph.Уст("-1"); err == nil {
-		сам.t.Errorf("setBad1(): err==nil\n")
-	}
+	сам.ph.Уст("-1")
 }
 
 // Устанавливает значение часов
@@ -63,12 +59,10 @@ func (сам *tester) parse() {
 	сам.parseGood2()
 }
 
-// Установка правильных большихчасов
+// Установка правильных больших часов
 func (сам *tester) parseGood2() {
 	сам.t.Logf("=parseGood2=\n")
-	if err := сам.ph.Уст("867"); err != nil {
-		сам.t.Errorf("parseGood2(): err=\n\t%v\n", err)
-	}
+	сам.ph.Уст("867")
 	if strHour := сам.ph.String(); strHour != "867" {
 		сам.t.Errorf("parseGood2(): strHour(%q)!='867'\n", strHour)
 	}
@@ -77,9 +71,7 @@ func (сам *tester) parseGood2() {
 // Установка правильных часов
 func (сам *tester) parseGood1() {
 	сам.t.Logf("=parseGood1=\n")
-	if err := сам.ph.Уст("8"); err != nil {
-		сам.t.Errorf("parseGood1(): err=\n\t%v\n", err)
-	}
+	сам.ph.Уст("8")
 	if strHour := сам.ph.String(); strHour != "08" {
 		сам.t.Errorf("parseGood1(): strHour(%q)!='08'\n", strHour)
 	}
@@ -88,17 +80,13 @@ func (сам *tester) parseGood1() {
 // Установка отрицательных часов
 func (сам *tester) parseBad2() {
 	сам.t.Logf("=parseBad2=\n")
-	if err := сам.ph.Уст("-1"); err == nil {
-		сам.t.Errorf("parseBad2(): err==nil\n")
-	}
+	сам.ph.Уст("-1")
 }
 
 // Установка не часов
 func (сам *tester) parseBad1() {
 	сам.t.Logf("=parseBad1=\n")
-	if err := сам.ph.Уст("abc"); err == nil {
-		сам.t.Errorf("parseBad1(): err==nil\n")
-	}
+	сам.ph.Уст("abc")
 }
 
 // Создание парсера часов

+ 6 - 8
app/lev1/product/parser_time/parse_min/parse_min.go

@@ -5,6 +5,8 @@ import (
 	"strconv"
 	"sync"
 
+	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
+
 	. "wartank/app/lev0/alias"
 	. "wartank/app/lev0/types"
 )
@@ -54,18 +56,14 @@ func (сам *ПарсерМинут) Сброс() {
 }
 
 // Уст -- устанавливает значение минут
-func (сам *ПарсерМинут) Уст(стрМин АВремя) error {
+func (сам *ПарсерМинут) Уст(стрМин АВремя) {
 	сам.блок.Lock()
 	defer сам.блок.Unlock()
 	_цМин, err := strconv.Atoi(string(стрМин))
-	if err != nil {
-		return fmt.Errorf("ПарсерМинут.Parse(): минуты(%v) не число, err=%w", стрМин, err)
-	}
+	Hassert(err == nil, "ПарсерМинут.Parse(): минуты(%v) не число, err=%v", стрМин, err)
 	цМин := АМин(_цМин)
-	if err := сам.уст(цМин); err != nil {
-		return fmt.Errorf("ПарсерМинут.Parse(): in internal set, err=\n\t%w", err)
-	}
-	return nil
+	err = сам.уст(цМин)
+	Hassert(err == nil, "ПарсерМинут.Parse(): in internal set, err=\n\t%v", err)
 }
 
 // УстМин -- устанавливает целочисленное значение минут

+ 3 - 9
app/lev1/product/parser_time/parse_min/parse_min_test.go

@@ -72,9 +72,7 @@ func (сам *tester) parse() {
 // Установка правильных минут
 func (сам *tester) parseGood1() {
 	сам.t.Logf("=parseGood1=\n")
-	if err := сам.ph.Уст("8"); err != nil {
-		сам.t.Errorf("parseGood1(): err=\n\t%v\n", err)
-	}
+	сам.ph.Уст("8")
 	if strHour := сам.ph.String(); strHour != "08" {
 		сам.t.Errorf("parseGood1(): strHour(%q)!='08'\n", strHour)
 	}
@@ -83,17 +81,13 @@ func (сам *tester) parseGood1() {
 // Установка отрицательных минут
 func (сам *tester) parseBad2() {
 	сам.t.Logf("=parseBad2=\n")
-	if err := сам.ph.Уст("-1"); err == nil {
-		сам.t.Errorf("parseBad2(): err==nil\n")
-	}
+	сам.ph.Уст("-1")
 }
 
 // Установка не минут
 func (сам *tester) parseBad1() {
 	сам.t.Logf("=parseBad1=\n")
-	if err := сам.ph.Уст("abc"); err == nil {
-		сам.t.Errorf("parseBad1(): err==nil\n")
-	}
+	сам.ph.Уст("abc")
 }
 
 // Создание парсера минут

+ 7 - 8
app/lev1/product/parser_time/parse_sec/parse_sec.go

@@ -4,6 +4,9 @@ import (
 	"fmt"
 	"strconv"
 	"sync"
+
+	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
+
 	. "wartank/app/lev0/alias"
 	. "wartank/app/lev0/types"
 )
@@ -53,18 +56,14 @@ func (сам *ПарсерСекунд) Сброс() {
 }
 
 // Уст -- устанавливает значение секунд
-func (сам *ПарсерСекунд) Уст(стрСек АВремя) error {
+func (сам *ПарсерСекунд) Уст(стрСек АВремя) {
 	сам.блок.Lock()
 	defer сам.блок.Unlock()
 	_цСек, err := strconv.Atoi(string(стрСек))
-	if err != nil {
-		return fmt.Errorf("ПарсерСекунд.Уст(): секунды(%v) не число, ош=\n\t%w", стрСек, err)
-	}
+	Hassert(err == nil, "ПарсерСекунд.Уст(): секунды(%v) не число, ош=\n\t%v", стрСек, err)
 	цСек := АСек(_цСек)
-	if err := сам.уст(цСек); err != nil {
-		return fmt.Errorf("ПарсерСекунд.Уст(): при внутренней установке, ош=\n\t%w", err)
-	}
-	return nil
+	err = сам.уст(цСек)
+	Hassert(err == nil, "ПарсерСекунд.Уст(): при внутренней установке, ош=\n\t%v", err)
 }
 
 // УстСек -- устанавливает хранимое значение секунд

+ 6 - 20
app/lev1/product/parser_time/parse_sec/parse_sec_test.go

@@ -32,9 +32,7 @@ func (сам *tester) set() {
 
 func (сам *tester) setGood1() {
 	сам.t.Logf("=setGood1=\n")
-	if err := сам.ph.УстСек(26); err != nil {
-		сам.t.Errorf("setGood1(): err=\n\t%v\n", err)
-	}
+	сам.ph.УстСек(26)
 	if strHour := сам.ph.String(); strHour != "26" {
 		сам.t.Errorf("setGood1(): strHour(%q)!='26'\n", strHour)
 	}
@@ -67,10 +65,7 @@ func (сам *tester) parseGood2() {
 			сам.t.Errorf("parseGood2(): panic=\n\t%v\n", _panic)
 		}
 	}()
-	ош := сам.ph.Уст("59")
-	if ош != nil {
-		сам.t.Errorf("parseGood2(): ош=\n\t%v\n", ош)
-	}
+	сам.ph.Уст("59")
 	if strHour := сам.ph.String(); strHour != "59" {
 		сам.t.Errorf("parseGood2(): strHour(%q)!='867'\n", strHour)
 	}
@@ -84,10 +79,7 @@ func (сам *tester) parseGood1() {
 			сам.t.Errorf("parseGood1(): panic=\n\t%v\n", _panic)
 		}
 	}()
-	ош := сам.ph.Уст("8")
-	if ош != nil {
-		сам.t.Errorf("parseGood1(): ош=\n\t%v\n", ош)
-	}
+	сам.ph.Уст("8")
 	if strHour := сам.ph.String(); strHour != "08" {
 		сам.t.Errorf("parseGood1(): strHour(%q)!='08'\n", strHour)
 	}
@@ -96,25 +88,19 @@ func (сам *tester) parseGood1() {
 // Установка больших часов
 func (сам *tester) parseBad3() {
 	сам.t.Logf("=parseBad3=\n")
-	if err := сам.ph.Уст("61"); err == nil {
-		сам.t.Errorf("parseBad3(): err==nil\n")
-	}
+	сам.ph.Уст("61")
 }
 
 // Установка отрицательных часов
 func (сам *tester) parseBad2() {
 	сам.t.Logf("=parseBad2=\n")
-	if err := сам.ph.Уст("-1"); err == nil {
-		сам.t.Errorf("parseBad2(): err==nil\n")
-	}
+	сам.ph.Уст("-1")
 }
 
 // Установка не часов
 func (сам *tester) parseBad1() {
 	сам.t.Logf("=parseBad1=\n")
-	if err := сам.ph.Уст("abc"); err == nil {
-		сам.t.Errorf("parseBad1(): err==nil\n")
-	}
+	сам.ph.Уст("abc")
 }
 
 // Создание парсера часов

+ 16 - 42
app/lev1/product/parser_time/parser_time.go

@@ -1,10 +1,11 @@
 package parser_time
 
 import (
-	"fmt"
 	"strings"
 	"sync"
 
+	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
+
 	. "wartank/app/lev0/alias"
 	. "wartank/app/lev0/types"
 	"wartank/app/lev1/product/parser_time/parse_hour"
@@ -52,68 +53,41 @@ func (сам *ПарсерВремя) ПолучМилСек() АМилСек {
 }
 
 // Уст -- разбирает строковое представление на части
-func (сам *ПарсерВремя) Уст(стрВремя АВремя) error {
+func (сам *ПарсерВремя) Уст(стрВремя АВремя) {
 	сам.блок.Lock()
 	defer сам.блок.Unlock()
-	if стрВремя == "" {
-		return fmt.Errorf("CountTime.Set(): val is empty")
-	}
+	Hassert(стрВремя != "", "CountTime.Set(): val is empty")
 	сам.Сброс()
 	списВремя := strings.Split(string(стрВремя), ":")
-	фнСекУст := func(стрВремя АВремя) error {
-		if ош := сам.сек.Уст(стрВремя); ош != nil {
-			return fmt.Errorf("ПарсерВремя.Уст().фнСекУст(): при установке секунд, ош=\n\t%w", ош)
-		}
-		return nil
-	}
-	фнМинУст := func() error {
+	фнМинУст := func() {
 		стрСек := АВремя(списВремя[1])
-		if ош := фнСекУст(стрСек); ош != nil {
-			return fmt.Errorf("ПарсерВремя.Уст().фнМинУст(): при установке секунд, ош=\n\t%w", ош)
-		}
+		сам.сек.Уст(стрСек)
+
 		стрМин := АВремя(списВремя[0])
-		if ош := сам.мин.Уст(стрМин); ош != nil {
-			return fmt.Errorf("ПарсерВремя.Уст().фнМинУст(): при установке минут, ош=\n\t%w", ош)
-		}
-		return nil
+		сам.мин.Уст(стрМин)
 	}
-	фнЧасУст := func() error {
+	фнЧасУст := func() {
 		стрСек := АВремя(списВремя[2])
-		if ош := фнСекУст(стрСек); ош != nil {
-			return fmt.Errorf("ПарсерВремя.Уст().фнЧасУст(): при установке секунд, ош=\n\t%w", ош)
-		}
+		сам.сек.Уст(стрСек)
 		стрМин := АВремя(списВремя[1])
-		if ош := сам.мин.Уст(стрМин); ош != nil {
-			return fmt.Errorf("ПарсерВремя.Уст().фнЧасУст(): при установке минут, ош=\n\t%w", ош)
-		}
+		сам.мин.Уст(стрМин)
 		стрЧас := АВремя(списВремя[0])
-		if ош := сам.час.Уст(стрЧас); ош != nil {
-			return fmt.Errorf("ПарсерВремя.Уст().фнЧасУст(): при установке часов, ош=\n\t%w", ош)
-		}
-
-		return nil
+		сам.час.Уст(стрЧас)
 	}
 
 	// Разбить время, перевести в секунды
 	switch len(списВремя) {
 	case 1: // Только секунды
 		стрСек := АВремя(списВремя[0])
-		if ош := фнСекУст(стрСек); ош != nil {
-			return ош
-		}
+		сам.сек.Уст(стрСек)
 	case 2: // Минуты, секунды
-		if ош := фнМинУст(); ош != nil {
-			return ош
-		}
+		фнМинУст()
 	case 3:
-		if ош := фнЧасУст(); ош != nil {
-			return ош
-		}
+		фнЧасУст()
 	default:
-		return fmt.Errorf("ПарсерВремя.Уст(): сбойная строка времени(%q)", стрВремя)
+		Hassert(false, "ПарсерВремя.Уст(): сбойная строка времени(%q)", стрВремя)
 	}
 	сам.всегоМилСек = сам.час.ПолучМилСек() + сам.мин.ПолучМилСек() + сам.сек.ПолучМилСек()
-	return nil
 }
 
 // Час -- возвращает хранимые часы

+ 10 - 30
app/lev1/product/parser_time/parser_time_test.go

@@ -58,9 +58,7 @@ func (сам *tester) parse() {
 
 func (сам *tester) parseHourHourBad1() {
 	сам.t.Logf("=parseHourHourBad1=\n")
-	if err := сам.pars.Уст("-11:14:54"); err == nil {
-		сам.t.Errorf("parseHourHourBad1(): err==nil\n")
-	}
+	сам.pars.Уст("-11:14:54")
 	if val := сам.pars.ПолучМилСек(); val != 5820 {
 		сам.t.Errorf("parseHourHourBad1(): valInt(%d)!=5820\n", val)
 	}
@@ -77,9 +75,7 @@ func (сам *tester) parseHourHourBad1() {
 
 func (сам *tester) parseHourMinBad1() {
 	сам.t.Logf("=parseHourMinBad1=\n")
-	if err := сам.pars.Уст("01:-4:01"); err == nil {
-		сам.t.Errorf("parseHourMinBad1(): err==nil\n")
-	}
+	сам.pars.Уст("01:-4:01")
 	if val := сам.pars.ПолучМилСек(); val != 5820 {
 		сам.t.Errorf("parseHourMinBad1(): valInt(%d)!=5820\n", val)
 	}
@@ -87,9 +83,7 @@ func (сам *tester) parseHourMinBad1() {
 
 func (сам *tester) parseHourSecBad1() {
 	сам.t.Logf("=parseHourSecBad1=\n")
-	if err := сам.pars.Уст("01:37:a"); err == nil {
-		сам.t.Errorf("parseHourSecBad1(): err==nil\n")
-	}
+	сам.pars.Уст("01:37:a")
 	if val := сам.pars.ПолучМилСек(); val != 5820 {
 		сам.t.Errorf("parseHourSecBad1(): valInt(%d)!=5820\n", val)
 	}
@@ -97,9 +91,7 @@ func (сам *tester) parseHourSecBad1() {
 
 func (сам *tester) parseHour() {
 	сам.t.Logf("=parseHour=\n")
-	if err := сам.pars.Уст("01:37:00"); err != nil {
-		сам.t.Errorf("parseHour(): err=\n\t%v\n", err)
-	}
+	сам.pars.Уст("01:37:00")
 	if val := сам.pars.ПолучМилСек(); val != 5820 {
 		сам.t.Errorf("parseHour(): valInt(%d)!=5820\n", val)
 	}
@@ -107,9 +99,7 @@ func (сам *tester) parseHour() {
 
 func (сам *tester) parseMinMinBad1() {
 	сам.t.Logf("=parseMinMinBad1=\n")
-	if err := сам.pars.Уст("60:25"); err == nil {
-		сам.t.Errorf("parseMinMinBad1(): err==nil\n")
-	}
+	сам.pars.Уст("60:25")
 	if val := сам.pars.ПолучМилСек(); val != 444 {
 		сам.t.Errorf("parseMinMinBad1(): valInt(%d)!=444\n", val)
 	}
@@ -117,9 +107,7 @@ func (сам *tester) parseMinMinBad1() {
 
 func (сам *tester) parseMinSecBad1() {
 	сам.t.Logf("=parseMinSecBad1=\n")
-	if err := сам.pars.Уст("07:-1"); err == nil {
-		сам.t.Errorf("parseMinSecBad1(): err==nil\n")
-	}
+	сам.pars.Уст("07:-1")
 	if val := сам.pars.ПолучМилСек(); val != 7*60+24 {
 		сам.t.Errorf("parseMinSecBad1(): valInt(%d)!=7*60+24\n", val)
 	}
@@ -127,9 +115,7 @@ func (сам *tester) parseMinSecBad1() {
 
 func (сам *tester) parseMin() {
 	сам.t.Logf("=parseMin=\n")
-	if err := сам.pars.Уст("07:24"); err != nil {
-		сам.t.Errorf("parseMin(): err=\n\t%v\n", err)
-	}
+	сам.pars.Уст("07:24")
 	if val := сам.pars.ПолучМилСек(); val != 7*60+24 {
 		сам.t.Errorf("parseMin(): valInt(%d)!=7*60+24\n", val)
 	}
@@ -138,9 +124,7 @@ func (сам *tester) parseMin() {
 // Слишком большие секунды
 func (сам *tester) parseSecBad1() {
 	сам.t.Logf("=parseSecBad1=\n")
-	if err := сам.pars.Уст("60"); err == nil {
-		сам.t.Errorf("parseSecBad1(): err==nil\n")
-	}
+	сам.pars.Уст("60")
 	if val := сам.pars.ПолучМилСек(); val != 28 {
 		сам.t.Errorf("parseSecBad1(): valInt(%d)!=28\n", val)
 	}
@@ -148,9 +132,7 @@ func (сам *tester) parseSecBad1() {
 
 func (сам *tester) parseSec() {
 	сам.t.Logf("=parseSec=\n")
-	if err := сам.pars.Уст("28"); err != nil {
-		сам.t.Errorf("parseSec(): err=\n\t%v\n", err)
-	}
+	сам.pars.Уст("28")
 	if val := сам.pars.ПолучМилСек(); val != 28 {
 		сам.t.Errorf("parseSec(): valInt(%d)!=28\n", val)
 	}
@@ -159,7 +141,5 @@ func (сам *tester) parseSec() {
 // Нет строки для парсинга
 func (сам *tester) parseBad1() {
 	сам.t.Logf("=parseBad1=\n")
-	if err := сам.pars.Уст(""); err == nil {
-		сам.t.Errorf("parseBad1(): err==nil\n")
-	}
+	сам.pars.Уст("")
 }

+ 1 - 6
app/lev1/shot/shot.go

@@ -156,12 +156,7 @@ func (сам *выстрел) shot() {
 		сам.Бот().КонтБот().Cancel()
 		return
 	}
-	if err = сам.СтрОбновить(lstBattle); err != nil {
-		// log._rintf("ERRO Shot.shot(): при обновлении lstBattle, err=\n\t%v\n", err)
-		сам.isEnd.Set()
-		сам.Бот().КонтБот().Cancel()
-		return
-	}
+	сам.СтрОбновить(lstBattle)
 	// sound.Shot()
 	сам.Манёвр()
 }

+ 3 - 5
app/lev1/shot/shot_time/shot_time.go

@@ -1,9 +1,10 @@
 package shot_time
 
 import (
-	"log"
 	"sync"
 
+	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
+
 	. "wartank/app/lev0/alias"
 )
 
@@ -67,9 +68,6 @@ func (сам *ShotTime) IsZero() bool {
 func (сам *ShotTime) Set(val АМилСек) {
 	сам.block.Lock()
 	defer сам.block.Unlock()
-	if val > 500_000 {
-		log.Printf("ShotTime.Set(): отрицательное значение, val=%v\n", val)
-		return
-	}
+	Hassert(val <= 500_000, "ShotTime.Set(): значение(%v)>500_000", val)
 	сам.val = val
 }

+ 14 - 22
app/lev2/arena/arena.go

@@ -2,10 +2,9 @@
 package arena
 
 import (
-	"fmt"
-	"log"
 	"sync"
 
+	. "gitp78su.ipnodns.ru/svi/kern"
 	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
 	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
 
@@ -45,21 +44,24 @@ type Арена struct {
 	уровень    ИСтатПарам
 	сеть       ИАренаСеть
 	блок       sync.RWMutex
+	лог        ILogBuf
 }
 
 // НовАрена -- возвращает новую арену игры
 func НовАрена(конт ILocalCtx, конф АренаКонфиг) ИАрена {
-	log.Printf("НовАрена(): стрКонтроль=%q\n", конф.СтрКонтроль_)
+	лог := NewLogBuf()
+	лог.Debug("НовАрена(): стрКонтроль=%q\n", конф.СтрКонтроль_)
 	конф.контроль()
-	аренаКонтекст := arena_context.НовАренаКонтекст(конт, конф.Бот_, конф.АренаИмя_)
+	аренаКонтекст := arena_context.НовАренаКонтекст(конт, конф.АренаИмя_)
 	сам := &Арена{
 		ИАренаКонтекст: аренаКонтекст,
 		уровень:        lev1.НовСтатПарам("уровень"),
 		времяОстат:     down_time.НовВремОбрат(аренаКонтекст, 5),
 		списСтр:        arena_string.НовАренаСтроки(конт, конф.СтрКонтроль_),
 		конф:           конф,
+		лог:            лог,
 	}
-	сам.сеть = arena_net.НовАренаСеть_(конт, сам, конф.СтрУрл_) //"https://wartank.ru/angar")
+	сам.сеть = arena_net.НовАренаСеть_(конт, сам, конф.СтрУрл_) //"https://wartank.ru/polygon")
 	return сам
 }
 
@@ -74,21 +76,15 @@ func (сам *Арена) Обновить() {
 	сам.сеть.Обновить()
 	списСтр := сам.СписПолучить()
 	if len(списСтр) == 0 {
-		списСтр = сам.Бот().Сеть().ВебВоркер().Получ(сам.конф.СтрУрл_)
-	}
-	ош := сам.СтрОбновить(списСтр)
-	if ош != nil {
-		log.Printf("Арена.Обновить(): ош=\n\t%v\n", ош)
-		сам.Отменить()
+		списСтр = сам.сеть.ВебВоркер().Получ(сам.конф.СтрУрл_)
 	}
+	сам.СтрОбновить(списСтр)
 }
 
 // СтрОбновить -- обновляет список строк секции по требованию
-func (сам *Арена) СтрОбновить(lstString []string) error {
-	if err := сам.списСтр.Set(lstString); err != nil {
-		return fmt.Errorf("Арена.СтрОбновить(): при установке lstString, err=\n\t%w", err)
-	}
-	return nil
+func (сам *Арена) СтрОбновить(lstString []string) {
+	err := сам.списСтр.Set(lstString)
+	Hassert(err == nil, "Арена.СтрОбновить(): при установке lstString, err=\n\t%v", err)
 }
 
 // Уровень -- возвращает уровень арены
@@ -102,12 +98,8 @@ func (сам *Арена) СписПолучить() []string {
 }
 
 // ОбратВремяУст -- устанавливает новое значение обратного счётчика времени
-func (сам *Арена) ОбратВремяУст(времяСек alias.АВремя) error {
-	ош := сам.времяОстат.Уст(времяСек)
-	if ош != nil {
-		return fmt.Errorf("Арена.ОбратВремяУст(): ош=\n\t%w", ош)
-	}
-	return nil
+func (сам *Арена) ОбратВремяУст(времяСек alias.АВремя) {
+	сам.времяОстат.Уст(времяСек)
 }
 
 // ВремяОстат -- объект оставшегося времени

+ 5 - 20
app/lev2/arena/arena_angar/arena_angar.go

@@ -1,7 +1,6 @@
 package arena_angar
 
 import (
-	"log"
 	"time"
 
 	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
@@ -86,35 +85,21 @@ func (сам *АренаАнгар) Серебро() ИСтатПарам {
 func (сам *АренаАнгар) пуск() {
 	{ // Запуск компонентов
 	}
-	фнЦикл := func() bool {
+	фнЦикл := func() {
 		сам.Обновить()
 		// сам.конвойПроверить()
-		if err := сам.ОбратВремяУст("01:00"); err != nil {
-			сам.конт.Cancel()
-			log.Printf("Ангар.Run(): in update ICountTime, err=\n\t%v\n", err)
-			return false
-		}
-		return true
+		сам.ОбратВремяУст("01:00")
 	}
 	go func() {
-		ош := сам.ОбратВремяУст("01")
-		if ош != nil {
-			log.Printf("Ангар.Run(): in update ICountTime, ош=\n\t%v\n", ош)
-			сам.конт.Cancel()
-			return
-		}
+		сам.ОбратВремяУст("01")
 		for {
 			select {
 			case <-сам.конт.Ctx().Done(): // Отмена контекста
 				return
 			case <-сам.ВремяОстат().КаналСиг(): // Метка времени
-				if !фнЦикл() {
-					return
-				}
+				фнЦикл()
 			default: // Запускается раз в минуту
-				if !фнЦикл() {
-					return
-				}
+				фнЦикл()
 				time.Sleep(time.Minute * 1)
 			}
 		}

+ 2 - 7
app/lev2/arena/arena_arsenal/arena_arsenal.go

@@ -51,7 +51,7 @@ func НовАрсенал(конт ILocalCtx) ИАренаАрсенал {
 		бронебойка: lev1.НовСтатПарам(стрБронебойки),
 		кумулятив:  lev1.НовСтатПарам(стрКумулятивы),
 		ремка:      lev1.НовСтатПарам(стрРемки),
-		продукт: lev1.НовСтатПарам("свинец"),
+		продукт:    lev1.НовСтатПарам("свинец"),
 		конт:       конт,
 
 		лог: лог,
@@ -339,12 +339,7 @@ func (сам *АренаАрсенал) забрать() bool {
 			return false
 		}
 	}
-	if ош = сам.СтрОбновить(лстАрсенал); ош != nil {
-		log.Printf("Арсенал.checkArsenalGet(): при обновлении lstBase, err=\n\t%v\n", ош)
-	}
-	if ош = сам.СтрОбновить(лстАрсенал); ош != nil {
-		log.Printf("Арсенал.checkArsenalGet(): при обновлении lstArsenal, err=\n\t%v\n", ош)
-	}
+	сам.СтрОбновить(лстАрсенал)
 	return true
 }
 

+ 1 - 4
app/lev2/arena/arena_battle/battle_register/battle_register.go

@@ -68,8 +68,5 @@ func (сам *СхваткаРегистрация) Зарегистрирова
 		}
 	}
 
-	if ош := сам.СтрОбновить(фнГеис()); ош != nil {
-		log.Printf("СражениеРегистрация.Зарегистрироваться(): при обновлении lstBattle, err=\n\t%v\n", ош)
-	}
-	// log._rintf("INFO СражениеРегистрация.Зарегистрироваться(): регистрация прошла успешно\n")
+	сам.СтрОбновить(фнГеис())
 }

+ 1 - 4
app/lev2/arena/arena_battle/battle_wait/battle_wait.go

@@ -104,9 +104,6 @@ func (сам *СхваткаОжидание) ждать() string {
 	strTime := lstTime[1]
 	lstTime = strings.Split(strTime, ` (`)
 	strTime = lstTime[0]
-	if err := сам.ОбратВремяУст(АВремя(strTime)); err != nil { // Возможно уже всё
-		// log._rintf("WARN BattleWait.Wait(): при установке времени ожидания сражения(%v)\n\terr=%v\n", strTime, err)
-		return ""
-	}
+	сам.ОбратВремяУст(АВремя(strTime))
 	return strTime
 }

+ 3 - 4
app/lev2/arena/arena_context/arena_context.go

@@ -26,15 +26,14 @@ type АренаКонтекст struct {
 }
 
 // НовАренаКонтекст -- возвращает новый контекст арены
-func НовАренаКонтекст(конт ILocalCtx, бот ИБот, сценаИмя alias.ААренаИмя) *АренаКонтекст {
-	Hassert(бот != nil, "НовАренаКонтекст(): ИБот==nil")
+func НовАренаКонтекст(конт ILocalCtx, сценаИмя alias.ААренаИмя) *АренаКонтекст {
 	Hassert(сценаИмя != "", "НовАренаКонтекст(): сценаИмя не задано")
 	Hassert(конт != nil, "НовАренаКонтекст(): ИЯдроКонтекст==пусто")
 	лог := NewLogBuf()
 	лог.Info("НовАренаКонтекст() " + string(сценаИмя) + "\n")
-	кнт, фнОтмена := context.WithCancel(бот.КонтБот().Ctx())
+	кнт, фнОтмена := context.WithCancel(конт.Ctx())
 	сам := &АренаКонтекст{
-		бот:       бот,
+		бот:       конт.Get("бот").Val().(ИБот),
 		аренаИмя:  сценаИмя,
 		кнт:       кнт,
 		фнОтмена:  фнОтмена,

+ 55 - 44
app/lev2/arena/arena_context/arena_state/arena_state.go

@@ -3,72 +3,83 @@ package arena_state
 
 import (
 	"sync"
+
+	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
+
 	"wartank/app/lev0/alias"
+	"wartank/app/lev0/cons"
 	. "wartank/app/lev0/types"
 )
 
 // СценаСостояние -- состояние сцены
 type АренаСостояние struct {
-	состояниеИмя alias.ААренаСостояние // Имя режима
-	работаИмя    alias.АРаботаИмя      // Имя работы
-	режимНомер   alias.АРежим
-	block        sync.RWMutex
+	знач  alias.ААренаСостояние // Имя режима
+	block sync.RWMutex
 }
 
 // НовСекцияРежим -- возвращает новый *СценаРежим
 func НовАренаСостояние() *АренаСостояние {
 	сам := &АренаСостояние{
-		состояниеИмя: "старт",
+		знач: cons.РежимНеСуществует,
 	}
 	_ = ИАренаСостояние(сам)
 	return сам
 }
 
-// РежимНомер -- возвращает номер режима арены
-func (сам *АренаСостояние) РежимНомер() alias.АРежим {
-	сам.block.RLock()
-	defer сам.block.RUnlock()
-	return сам.режимНомер
-}
-
-// РаботаИмяУст -- устанавливает имя текущей работы арены
-func (сам *АренаСостояние) РаботаИмяУст(имя alias.АРаботаИмя) {
-	сам.block.Lock()
-	defer сам.block.Unlock()
-	сам.работаИмя = имя
-}
-
-// РаботаИмя -- возвращает имя текущей работы арены
-func (сам *АренаСостояние) РаботаИмя() alias.АРаботаИмя {
-	сам.block.RLock()
-	defer сам.block.RUnlock()
-	return сам.работаИмя
-}
-
 // СостояниеУст -- устанавливает состояние арены
-func (сам *АренаСостояние) СостояниеУст(состояние alias.ААренаСостояние) {
+func (сам *АренаСостояние) Уст(состояние alias.ААренаСостояние) {
 	сам.block.Lock()
 	defer сам.block.Unlock()
-	сам.состояниеИмя = состояние
+	switch сам.знач {
+	case cons.РежимНеСуществует:
+		if состояние != cons.РежимАпгрейдПлатный {
+			Hassert(false, "АренаСостояние.Уст(): нельзя из не существует перейти в '%v'", состояние)
+		}
+	case cons.РежимАпгрейд:
+		if состояние == cons.РежимАпгрейдПлатный {
+			сам.знач = состояние
+			return
+		}
+		if состояние == cons.РежимОжидание {
+			сам.знач = состояние
+			return
+		}
+	case cons.РежимАпгрейдПлатный:
+		if состояние == cons.РежимОжидание {
+			сам.знач = состояние
+			return
+		}
+		if состояние == cons.РежимАпгрейд {
+			сам.знач = состояние
+			return
+		}
+	case cons.РежимОжидание:
+		if состояние == cons.РежимРабота {
+			сам.знач = состояние
+			return
+		}
+		if состояние == cons.РежимАпгрейдПлатный {
+			сам.знач = состояние
+			return
+		}
+	case cons.РежимРабота:
+		if состояние == cons.РежимОжидание {
+			сам.знач = состояние
+			return
+		}
+		if состояние == cons.РежимАпгрейдПлатный {
+			сам.знач = состояние
+			return
+		}
+	default:
+		Hassert(false, "АренаСостояние.Уст(): нельзя из '%v' перейти в '%v'", сам.знач, состояние)
+	}
+	сам.знач = состояние
 }
 
 // Состояние -- возвращает состояние арены
-func (сам *АренаСостояние) Состояние() alias.ААренаСостояние {
+func (сам *АренаСостояние) Получ() alias.ААренаСостояние {
 	сам.block.RLock()
 	defer сам.block.RUnlock()
-	return сам.состояниеИмя
-}
-
-// Работа -- возвращает хранимое имя работы арены
-func (сам *АренаСостояние) Работа() alias.АРаботаИмя {
-	сам.block.RLock()
-	defer сам.block.RUnlock()
-	return сам.работаИмя
-}
-
-// РаботаУст -- устанавливает хранимое имя работы арены
-func (сам *АренаСостояние) РаботаУст(работаИмя alias.АРаботаИмя) {
-	сам.block.Lock()
-	defer сам.block.Unlock()
-	сам.работаИмя = работаИмя
+	return сам.знач
 }

+ 6 - 38
app/lev2/arena/arena_convoy/arena_convoy.go

@@ -1,7 +1,6 @@
 package arena_convoy
 
 import (
-	"log"
 	"strconv"
 	"strings"
 	"time"
@@ -120,12 +119,7 @@ func (сам *АренаКонвой) Обновить() {
 func (сам *АренаКонвой) обновитьВремя() {
 	// Время подходит надо обновляться
 	сам.Обновить()
-	ош := сам.ОбратВремяУст("20")
-	if ош != nil {
-		log.Printf("Конвой.обновитьВремя(): при обновлении времени, ош=\n\t%v\n", ош)
-		сам.Отменить()
-		return
-	}
+	сам.ОбратВремяУст("20")
 	// Найти строку с упоминанием оставшегося времени конвоя
 	lstConvoy := сам.СписПолучить()
 	var (
@@ -161,26 +155,12 @@ func (сам *АренаКонвой) обновитьВремя() {
 		// Ждём окончания ожидания конвоя
 		lstTime := strings.Split(strLastTime, `До следующего конвоя: `)
 		strLastTime = lstTime[1]
-		if err := сам.ОбратВремяУст(АВремя(strLastTime)); err != nil {
-			// log._rintf("WARN Конвой.обновитьВремя(): при установке времени ожидания конвоя(%v)\n\terr=%v\n", strLastTime, err)
-			err := сам.ОбратВремяУст("10")
-			if err != nil {
-				log.Printf("Конвой.обновитьВремя(): при установке времени ожидания конвоя(%v)\n\terr=%v\n", strLastTime, err)
-				сам.Отменить()
-			}
-		}
+		сам.ОбратВремяУст(АВремя(strLastTime))
 	case isMask: // Если маскировка между конвоями
 		// Ждём окончания ожидания конвоя
 		lstTime := strings.Split(strLastTime, `Полная маскировка через `)
 		strLastTime = lstTime[1]
-		if err := сам.ОбратВремяУст(АВремя(strLastTime)); err != nil {
-			// log._rintf("ERRO BКонвой.обновитьВремя(): при установке времени банка для 1го режима(%v)\n\terr=%v\n", strLastTime, err)
-			err := сам.ОбратВремяУст("10")
-			if err != nil {
-				log.Printf("Конвой.обновитьВремя(): при установке времени банка для 1го режима(%v)\n\terr=%v\n", strLastTime, err)
-				сам.Отменить()
-			}
-		}
+		сам.ОбратВремяУст(АВремя(strLastTime))
 	}
 }
 
@@ -208,11 +188,7 @@ func (сам *АренаКонвой) проверитьМиссияРазвед
 	// https://wartank.ru/convoy?23-1.ILinkListener-missions-cc-0-c-awardLink
 	ссылка := "https://wartank.ru/" + _ссылка
 	lstConvoy = сам.Сеть().ВебВоркер().Получ(ссылка)
-	if err := сам.СтрОбновить(lstConvoy); err != nil {
-		log.Printf("Конвой.проверитьМиссияРазведкаКонвой(): пр обновлении lstConvoy, err=\n\t%v\n", err)
-		return
-	}
-	log.Printf("Конвой.проверитьМиссияРазведкаКонвой(): награда получена\n")
+	сам.СтрОбновить(lstConvoy)
 }
 
 // Забирает награду в конвое "Мастер дозора"
@@ -252,11 +228,7 @@ func (сам *АренаКонвой) проверитьМиссияМастер
 		// log._rintf("ERRO Конвой.checkMaster(): при выполнении команды GET, err=\n\t%v\n", err)
 		return
 	}
-	if err := сам.СтрОбновить(lstConvoy); err != nil {
-		// log._rintf("ERRO Конвой.checkMaster(): пр обновлении lstConvoy, err=\n\t%v\n", err)
-		return
-	}
-	// log._rintf("INFO Конвой.checkMaster(): награда получена\n")
+	сам.СтрОбновить(lstConvoy)
 }
 
 // Забирает награду в конвое "Уничтожь 6 врагов в конвое"
@@ -283,9 +255,5 @@ func (сам *АренаКонвой) проверитьМиссия6фраго
 	// https://wartank.ru/convoy?15-1.ILinkListener-missions-cc-1-c-awardLink
 	ссылка := "https://wartank.ru/" + _ссылка
 	lstConvoy = сам.Сеть().ВебВоркер().Получ(ссылка)
-	if err := сам.СтрОбновить(lstConvoy); err != nil {
-		log.Printf("Конвой.проверитьМиссия6фрагов(): при обновлении lstConvoy, ош=\n\t%v\n", err)
-		return
-	}
-	log.Printf("Конвой.проверитьМиссия6фрагов(): награда получена\n")
+	сам.СтрОбновить(lstConvoy)
 }

+ 1 - 4
app/lev2/arena/arena_death/death_register/death_register.go

@@ -67,8 +67,5 @@ func (сам *СхваткаРегистрация) Зарегистрирова
 		}
 	}
 
-	if ош := сам.СтрОбновить(фнРегис()); ош != nil {
-		log.Printf("СхваткаРегистрация.Зарегистрироваться(): при обновлении lstBattle, err=\n\t%v\n", ош)
-	}
-	// log._rintf("INFO СхваткаРегистрация.Зарегистрироваться(): регистрация прошла успешно\n")
+	сам.СтрОбновить(фнРегис())
 }

+ 1 - 4
app/lev2/arena/arena_death/death_wait/death_wait.go

@@ -105,9 +105,6 @@ func (сам *СражениеОжидание) ждать() string {
 	strTime := lstTime[1]
 	lstTime = strings.Split(strTime, ` (`)
 	strTime = lstTime[0]
-	if err := сам.ОбратВремяУст(АВремя(strTime)); err != nil { // Возможно уже всё
-		// log._rintf("WARN BattleWait.Wait(): при установке времени ожидания сражения(%v)\n\terr=%v\n", strTime, err)
-		return ""
-	}
+	сам.ОбратВремяУст(АВремя(strTime))
 	return strTime
 }

+ 1 - 4
app/lev2/arena/arena_death/death_worker/process_death/health/health.go

@@ -95,8 +95,5 @@ func (сам *Здоровье) лечить() {
 		// log._rintf("ERRO Здоровье.repair(): при выполнении GET-команды ремонта, err=\n\t%v\n", err)
 		return
 	}
-	if err = сам.СтрОбновить(lstBattleOn); err != nil {
-		// log._rintf("ERRO Здоровье.repair(): при обновлении lstBattle, err=\n\t%v\n", err)
-		return
-	}
+	сам.СтрОбновить(lstBattleOn)
 }

+ 3 - 13
app/lev2/arena/arena_division/div_war/div_war.go

@@ -2,7 +2,6 @@ package div_war
 
 import (
 	"fmt"
-	"log"
 	"strings"
 	"sync"
 	"time"
@@ -151,10 +150,7 @@ func (сам *DivWar) findTimeCount() {
 	strTime := lstTime[1]
 	lstTime = strings.Split(strTime, `</span>`)
 	strTime = lstTime[0]
-	if err := сам.ОбратВремяУст(alias.АВремя(strTime)); err != nil {
-		// log._rintf("WARN DivWar.findTimeCount(): при установке времени ожидания битвы дивизий(%v)\n\terr=%v\n", strTime, err)
-		return
-	}
+	сам.ОбратВремяУст(alias.АВремя(strTime))
 }
 
 // При необходимости поднимает взвод в атаку, вызывается только если обнаружено приглашение (+)
@@ -187,10 +183,7 @@ func (сам *DivWar) upDivWar() {
 		// log._rintf("ERRO DivWar.upDivWar(): при выполнении GET-команды на подъём в атаку, err=\n\t%v\n", err)
 		return
 	}
-	if err = сам.СтрОбновить(lstDivWar); err != nil {
-		log.Printf("DivWar.upDivWar(): при обновлении lstDivWar, err=\n\t%v\n", err)
-	}
-	// log._rintf("INFO DivWar.upDivWar(): регистрация прошла успешно\n")
+	сам.СтрОбновить(lstDivWar)
 }
 
 // Ведёт сражение
@@ -198,10 +191,7 @@ func (сам *DivWar) DivWar() {
 	defer func() {
 		сам.процВойна = nil
 		сам.block.Unlock()
-		if err := сам.ОбратВремяУст("01"); err != nil {
-			panic(fmt.Errorf("DivWar.DivWar(): при установке CountDown, err=\n\t%w", err))
-		}
-		// log.Printf("INFO DivWar.DivWar(): сражение завершено\n")
+		сам.ОбратВремяУст("01")
 	}()
 	сам.процВойна = process_divwar.НовПроцессДивизияВойна(сам.конт) // IDivWarOn (онлайн)
 	// Цикл ожидания окончания сражения

+ 3 - 13
app/lev2/arena/arena_division/divwar/divwar.go

@@ -2,7 +2,6 @@ package div_war
 
 import (
 	"fmt"
-	"log"
 	"strings"
 	"sync"
 	"time"
@@ -152,10 +151,7 @@ func (сам *DivWar) findTimeCount() {
 	strTime := lstTime[1]
 	lstTime = strings.Split(strTime, `</span>`)
 	strTime = lstTime[0]
-	if err := сам.ОбратВремяУст(АВремя(strTime)); err != nil {
-		// log._rintf("WARN DivWar.findTimeCount(): при установке времени ожидания битвы дивизий(%v)\n\terr=%v\n", strTime, err)
-		return
-	}
+	сам.ОбратВремяУст(АВремя(strTime))
 }
 
 // При необходимости поднимает взвод в атаку, вызывается только если обнаружено приглашение (+)
@@ -188,10 +184,7 @@ func (сам *DivWar) upDivWar() {
 		// log._rintf("ERRO DivWar.upDivWar(): при выполнении GET-команды на подъём в атаку, err=\n\t%v\n", err)
 		return
 	}
-	if err = сам.СтрОбновить(lstDivWar); err != nil {
-		log.Printf("DivWar.upDivWar(): при обновлении lstDivWar, err=\n\t%v\n", err)
-	}
-	// log._rintf("INFO DivWar.upDivWar(): регистрация прошла успешно\n")
+	сам.СтрОбновить(lstDivWar)
 }
 
 // Ведёт сражение
@@ -199,10 +192,7 @@ func (сам *DivWar) DivWar() {
 	defer func() {
 		сам.дивОн = nil
 		сам.block.Unlock()
-		if err := сам.ОбратВремяУст("01"); err != nil {
-			panic(fmt.Errorf("DivWar.DivWar(): при установке CountDown, err=\n\t%w", err))
-		}
-		// log.Printf("INFO DivWar.DivWar(): сражение завершено\n")
+		сам.ОбратВремяУст("01")
 	}()
 	сам.дивОн = process_divwar.НовПроцессДивизияВойна(сам.конт) // IDivWarOn (онлайн)
 	// Цикл ожидания окончания сражения

+ 2 - 8
app/lev2/arena/arena_market/arena_market.go

@@ -337,10 +337,7 @@ func (сам *АренаРынок) проверОжидание() {
 		}
 		lstTime := strings.Split(strOut, `Минимальная цена через `)
 		strTime := lstTime[1]
-		if err := сам.ОбратВремяУст(АВремя(strTime)); err != nil {
-			// log._rintf("ERRO Market.checkTime(): при установке времени ожидания рынка(%v)\n\terr=%v\n", strTime, err)
-			return // Возможно минимальная цена
-		}
+		сам.ОбратВремяУст(АВремя(strTime))
 	}
 	if фнЕслиСеребро() {
 		return
@@ -405,9 +402,6 @@ func (сам *АренаРынок) купитьЗолото() bool {
 			return false
 		}
 	}
-	if err = сам.СтрОбновить(lstMarket); err != nil {
-		// log._rintf("Market.buyGold(): при обновлении lstMarket, err=\n\t%v\n", err)
-		return true
-	}
+	сам.СтрОбновить(lstMarket)
 	return true
 }

+ 3 - 11
app/lev2/arena/arena_masters/arena_masters.go

@@ -1,7 +1,6 @@
 package arena_masters
 
 import (
-	"log"
 	"strings"
 	"time"
 
@@ -75,18 +74,13 @@ func (сам *БитваМастеров) goBatMas() bool {
 	}
 	countTime := сам.ВремяОстат().String()
 	if countTime > "00:25:00" {
-		if err := сам.ОбратВремяУст(АВремя(countTime)); err != nil {
-			сам.лог.Err("goBatMas(): при установке времени ожидания битвы мастеров(%v)\n\terr=%v\n", countTime, err)
-		}
-		return false
+		сам.ОбратВремяУст(АВремя(countTime))
 	}
 
 	// Время меньше 25 сек, надо уточнять (тут возможна ошибка с экраном ожидания)
 	сам.Обновить()
 	// Время ожидания вышло, надо начать атаку
-	if err := сам.ОбратВремяУст("00"); err != nil {
-		log.Printf("ERRO BatMas.goBatMas(): при установке времени ожидания битвы мастеров(0)\n\terr=%v\n", err)
-	}
+	сам.ОбратВремяУст("00")
 	return false
 }
 
@@ -110,9 +104,7 @@ func (сам *БитваМастеров) findTimeCount() {
 		lstTime = strings.Split(strTime, ` (`)
 		strTime = lstTime[0]
 
-		if err := сам.ОбратВремяУст(АВремя(strTime)); err != nil {
-			log.Printf("WARN BatMas.findTimeCount(): при установке времени ожидания битвы мастеров(%v)\n\terr=%v\n", strTime, err)
-		}
+		сам.ОбратВремяУст(АВремя(strTime))
 	}
 }
 

+ 41 - 209
app/lev2/arena/arena_mine/arena_mine.go

@@ -10,6 +10,7 @@ import (
 	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
 
 	. "wartank/app/lev0/alias"
+	"wartank/app/lev0/cons"
 	. "wartank/app/lev0/types"
 	"wartank/app/lev1"
 	"wartank/app/lev2/arena"
@@ -90,16 +91,6 @@ func (сам *АренаШахта) пуск() {
 			}
 		}
 		сам.уровеньОбновить()
-		сам.ускорениеПровер()
-		{ // Проапгрейдить
-			счёт := 5
-			for счёт > 0 {
-				if сам.проапгрейдить() {
-					break
-				}
-				счёт--
-			}
-		}
 		{ // Получить продукцию
 			счёт := 5
 			for счёт > 0 {
@@ -233,9 +224,7 @@ func (сам *АренаШахта) количествоПолучить() (bool
 	strTime = strings.TrimPrefix(strTime, `<td><div class="value-block lh1"><span><span>`)
 	strTime = strings.TrimSuffix(strTime, `</span></span></div></td>`)
 	сам.продуктВремя = strTime
-	if err := сам.ОбратВремяУст(АВремя(strTime)); err != nil {
-		сам.лог.Добавить("ОШИБКА Шахта.количествоПолучить(): при установке времени производства(%v), err=\n\t%v\n", strTime, err)
-	}
+	сам.ОбратВремяУст(АВремя(strTime))
 	сам.лог.Добавить("Шахта.количествоПолучить(): время=%q\n", strTime)
 	return true, nil
 }
@@ -264,35 +253,33 @@ func (сам *АренаШахта) шахтаЗабрать() bool {
 	ссылка := "https://wartank.ru/" + _ссылка
 	// http://wartank.ru/buildings?5-1.ILinkListener-buildings-0-building-rootBlock-actionPanel-takeProductionLink
 	lstBase1 := сам.Сеть().ВебВоркер().Получ(ссылка)
-	if err := сам.СтрОбновить(lstBase1); err != nil {
-		сам.лог.Добавить("Шахта.шахтаЗабрать(): при обновлении lstMine, err=\n\t%v\n", err)
-		return false
-	}
+	сам.СтрОбновить(lstBase1)
 	сам.лог.Добавить("Шахта.шахтаЗабрать(): ОК\n")
+	сам.АренаСостояние().Уст(cons.РежимОжидание)
 	return true
 }
 
-// Проверяет ускорение строительства FIXME: не работает
-func (сам *АренаШахта) ускорениеПровер() {
-	сам.лог.Добавить("")
-	списСтр := сам.Сеть().ВебВоркер().Получ("http://wartank.ru/buildings")
-	// <span class="green2">Шахта - 0</span><br/>
-	var (
-		еслиНайти bool
-		стр       string
-	)
-	for _, стр = range списСтр {
-		if strings.Contains(стр, `<span class="green2">Шахта - `) {
-			еслиНайти = true
-			break
-		}
-	}
-	if !еслиНайти {
-		сам.лог.Добавить("Шахта.ускорениеПровер(): не надо\n")
-		return
-	}
-	сам.лог.Добавить("Шахта.ускорениеПровер(): надо\n")
-}
+// // Проверяет ускорение строительства FIXME: не работает
+// func (сам *АренаШахта) ускорениеПровер() {
+// 	сам.лог.Добавить("")
+// 	списСтр := сам.Сеть().ВебВоркер().Получ("http://wartank.ru/buildings")
+// 	// <span class="green2">Шахта - 0</span><br/>
+// 	var (
+// 		еслиНайти bool
+// 		стр       string
+// 	)
+// 	for _, стр = range списСтр {
+// 		if strings.Contains(стр, `<span class="green2">Шахта - `) {
+// 			еслиНайти = true
+// 			break
+// 		}
+// 	}
+// 	if !еслиНайти {
+// 		сам.лог.Добавить("Шахта.ускорениеПровер(): не надо\n")
+// 		return
+// 	}
+// 	сам.лог.Добавить("Шахта.ускорениеПровер(): надо\n")
+// }
 
 // Уровень -- возвращает уровень шахты
 func (сам *АренаШахта) Уровень() ИСтатПарам {
@@ -330,142 +317,6 @@ func (сам *АренаШахта) уровеньОбновить() bool {
 	return true
 }
 
-/*
-// Строит шахту при нулевом уровне
-func (сам *АренаШахта) построить() bool {
-	сам.лог.Добавить("Шахта.построить()\n")
-	// <td style="width:50%;padding-left:1px;"><a class="simple-but border mb5" href="building-upgrade/Mine"><span><span>Построить</span></span></a></td>
-	var (
-		еслиНайти = false
-		стр       = ""
-	)
-	списСтр := сам.Сеть().ВебВоркер().Получ("http://wartank.ru/buildings")
-	for _, стр = range списСтр {
-		if strings.Contains(стр, `href="building-upgrade/Mine"><span><span>Построить</span></span>`) {
-			еслиНайти = true
-			break
-		}
-	}
-	if !еслиНайти {
-		сам.лог.Добавить("Шахта.построить(): не надо\n")
-		return true
-	}
-	// Пробуем построить шахту
-	_стр := strings.TrimPrefix(стр, `<td style="width:50%;padding-left:1px;"><a class="simple-but border mb5" href="`)
-	_стр = strings.TrimSuffix(_стр, `"><span><span>Построить</span></span></a></td>`)
-	ссылка := "https://wartank.ru/" + _стр
-	списСтр = сам.Сеть().ВебВоркер().Получ(ссылка)
-	еслиНайти = false
-	// "<a class=\"simple-but border mb5\" href=\"Mine?14-1.ILinkListener-upgradeLink-link\">"
-	for _, стр = range списСтр {
-		if strings.Contains(стр, `ILinkListener-upgradeLink-link`) {
-			еслиНайти = true
-			break
-		}
-	}
-	if !еслиНайти {
-		сам.лог.Добавить("Шахта.построить(): не найдена команда постройки\n")
-		return true
-	}
-	_стр = strings.TrimPrefix(стр, "<a class=\"simple-but border mb5\" href=\"")
-	_стр = strings.TrimSuffix(_стр, "\">")
-	// http://wartank.ru/building-upgrade/Mine?16-1.ILinkListener-upgradeLink-link
-	ссылка = "https://wartank.ru/building-upgrade/" + _стр
-	_ = сам.Сеть().ВебВоркер().Получ(ссылка)
-	return true
-}
-*/
-
-// Пытается проапгрейдить топливный склад
-func (сам *АренаШахта) проапгрейдить() bool {
-	сам.лог.Добавить("Шахта.проапгрейдить()\n")
-	var (
-		еслиНайти = false
-		списСтр   []string
-		стр       = ""
-	)
-	фнКупить := func() (bool, error) {
-		defer time.Sleep(time.Millisecond * 1000)
-		списСтр = сам.Сеть().ВебВоркер().Получ("https://wartank.ru/building-upgrade/Mine")
-		for _, стр = range списСтр {
-			// <a class="simple-but border mb5" href="Mine?5-1.ILinkListener-upgradeLink-link">
-			if strings.Contains(стр, `ILinkListener-upgradeLink-link`) {
-				еслиНайти = true
-				break
-			}
-		}
-		if !еслиНайти {
-			сам.лог.Добавить("Шахта.проапгрейдить().фнКупить(): не надо\n")
-			return false, nil
-		}
-		// Пробуем улучшить шахту
-		_стр := strings.TrimPrefix(стр, "<a class=\"simple-but border mb5\" href=\"")
-		_стр = strings.TrimSuffix(_стр, "\">")
-		// https://wartank.ru/building-upgrade/Mine?4-1.ILinkListener-upgradeLink-link
-		// <a class="simple-but border mb5" href="FuelStorage?50-1.ILinkListener-upgradeLink-link">
-		ссылка := "https://wartank.ru/building-upgrade/" + _стр
-		списСтр = сам.Сеть().ВебВоркер().Получ(ссылка)
-		// Проверить, что постройка состоялась
-		for _, стр := range списСтр {
-			if strings.Contains(стр, "ILinkListener-upgradeLink-link") {
-				сам.лог.Добавить("ОШИБКА Шахта.проапгрейдить().фнКупить(): покупка шахты не прошла\n\tlink=%v\n\tстр=\n\t%v\n", ссылка, стр)
-				return false, fmt.Errorf("покупка шахты не прошла") // Покупка не оплачена
-			}
-		}
-		сам.лог.Добавить("Шахта.проапгрейдить().фнКупить(): покупка шахты прошла\n")
-		return true, nil
-	}
-
-	фнПодтверждение := func() bool {
-		for _, стр = range списСтр {
-			// <a class="simple-but border w50 mXa mb10" w:id="confirmLink" href="../wicket/page?7-1.ILinkListener-confirmLink"><span><span>да, подтверждаю</span></span></a>
-			if strings.Contains(стр, `ILinkListener-confirmLink`) {
-				еслиНайти = true
-				break
-			}
-		}
-		if !еслиНайти {
-			сам.лог.Добавить("Шахта.проапгрейдить().фнПодтверждение(): нет подтверждения\n")
-			return true
-		}
-		// Пробуем построить шахту
-		_стр := strings.TrimPrefix(стр, `<a class="simple-but border w50 mXa mb10" w:id="confirmLink" href="..`)
-		_стр = strings.TrimSuffix(_стр, `"><span><span>да, подтверждаю</span></span></a>`)
-		// https://wartank.ru/wicket/page?6-1.ILinkListener-confirmLink
-		ссылка := "https://wartank.ru" + _стр
-		списСтр = сам.Сеть().ВебВоркер().Получ(ссылка)
-		// Проверить, что постройка состоялась
-		for _, стр := range списСтр {
-			if strings.Contains(стр, "<title>Вы сделали слишком большую паузу</title>") {
-				сам.лог.Добавить("Шахта.проапгрейдить().фнПодтверждение(): подтверждение покупка шахты не прошла\n\tlink=%v\n\tстр=\n\t%v\n", ссылка, стр)
-				return false // Покупка не оплачена
-			}
-		}
-		сам.лог.Добавить("Шахта.проапгрейдить().фнПодтверждение(): подтверждение покупка шахты прошла\n")
-		return true
-	}
-
-	фнКомплекс := func() {
-		сам.лог.Добавить("Шахта.проапгрейдить().фнКомплекс()\n")
-		count := 5
-		for count > 0 {
-			еслиОк, ош := фнКупить()
-			switch {
-			case ош == nil && еслиОк: // покупка шахты прошла
-				if фнПодтверждение() {
-					return
-				}
-			case ош == nil && !еслиОк: // покупка шахты не нужна
-				return
-			case ош != nil: // ошибка при работе с сетью
-				count--
-			}
-		}
-	}
-	фнКомплекс()
-	return true
-}
-
 // Сделать -- вызывается с базы, если она обнаружила, что пора сделать продукцию
 func (сам *АренаШахта) Сделать() {
 	сам.Сеть().Обновить()
@@ -473,8 +324,8 @@ func (сам *АренаШахта) Сделать() {
 		сам.лог.Добавить("ERRO Шахта.Сделать(): при выборе продукции, err=\n\t%v\n", err)
 		return
 	}
-	работа := сам.АренаСостояние().РаботаИмя()
-	switch работа {
+	продукт := сам.ПродуктСейчас().Имя()
+	switch продукт {
 	case "руда":
 		for !сам.рудаСделать() {
 		}
@@ -488,8 +339,9 @@ func (сам *АренаШахта) Сделать() {
 		for !сам.свинецСделать() {
 		}
 	default:
-		сам.лог.Добавить("ERRO Шахта.Сделать(): неизвестный режим производства, режим=%q\n", работа)
+		сам.лог.Добавить("ERRO Шахта.Сделать(): неизвестный режим производства, режим=%q\n", продукт)
 	}
+	сам.АренаСостояние().Уст(cons.РежимРабота)
 }
 
 // Свинец -- возвращает объект свинца
@@ -562,26 +414,26 @@ func (сам *АренаШахта) выбратьМеталл() error {
 		}
 	}
 	фнВыбратьПродукт()
-	сам.АренаСостояние().РаботаИмяУст("руда")
+	сам.ПродуктСейчас().ИмяУст("руда")
 	руда := сам.Руда().Получ()
 	железо := сам.Железо().Получ()
 	if диктПродукция["железо"] {
 		if руда > железо*2 {
-			сам.АренаСостояние().РаботаИмяУст("железо")
+			сам.ПродуктСейчас().ИмяУст("железо")
 		}
 	}
 
 	сталь := сам.Сталь().Получ()
 	if диктПродукция["сталь"] {
 		if железо > сталь*2 {
-			сам.АренаСостояние().РаботаИмяУст("сталь")
+			сам.ПродуктСейчас().ИмяУст("сталь")
 		}
 	}
 
 	свинец := сам.Свинец().Получ()
 	if диктПродукция["свинец"] {
 		if сталь > свинец*2 {
-			сам.АренаСостояние().РаботаИмяУст("свинец")
+			сам.ПродуктСейчас().ИмяУст("свинец")
 		}
 	}
 
@@ -636,13 +488,8 @@ func (сам *АренаШахта) рудаСделать() bool {
 			return false
 		}
 	}
-	if err = сам.СтрОбновить(lstMine); err != nil {
-		// log._rintf("ERRO Шахта.сделатьРуду(): при обновлении lstMine, err=\n\t%v\n", err)
-		return false
-	}
-	if err := сам.ОбратВремяУст(АВремя(strTime)); err != nil {
-		сам.лог.Добавить("ERRO Шахта.сделатьРуду(): при установке времени ожидания добычи руды(%v)\n\terr=%v\n", strTime, err)
-	}
+	// сам.СтрОбновить(lstMine)
+	сам.ОбратВремяУст(АВремя(strTime))
 	lstNum := strings.Split(strNum, `Кол-во: <span class="green2">`)
 	strNum = lstNum[1]
 	lstNum = strings.Split(strNum, `</span><br/>`)
@@ -699,13 +546,8 @@ func (сам *АренаШахта) железоСделать() bool {
 			return false
 		}
 	}
-	if err = сам.СтрОбновить(lstMine); err != nil {
-		// log._rintf("ERRO MineNet.makeFerrum(): при обновлении lstMine, err=\n\t%v\n", err)
-		return false
-	}
-	if err := сам.ОбратВремяУст(АВремя(strTime)); err != nil {
-		сам.лог.Добавить("ERRO Mine.makeFerrum(): при установке времени производства железа(%v)\n\terr=%v\n", strTime, err)
-	}
+	сам.СтрОбновить(lstMine)
+	сам.ОбратВремяУст(АВремя(strTime))
 	lstNum := strings.Split(strNum, `Кол-во: <span class="green2">`)
 	strNum = lstNum[1]
 	lstNum = strings.Split(strNum, `</span><br/>`)
@@ -759,13 +601,8 @@ func (сам *АренаШахта) стальСделать() bool {
 			return false
 		}
 	}
-	if err = сам.СтрОбновить(lstMine); err != nil {
-		// log._rintf("ERRO MineNet.makeSteel(): при обновлении lstMine, err=\n\t%v\n", err)
-		return false
-	}
-	if err := сам.ОбратВремяУст(АВремя(strTime)); err != nil {
-		сам.лог.Добавить("ERRO Mine.makeSteel(): при установке времени производства железа(%v)\n\terr=%v\n", strTime, err)
-	}
+	сам.СтрОбновить(lstMine)
+	сам.ОбратВремяУст(АВремя(strTime))
 	lstNum := strings.Split(strNum, `Кол-во: <span class="green2">`)
 	strNum = lstNum[1]
 	lstNum = strings.Split(strNum, `</span><br/>`)
@@ -819,13 +656,8 @@ func (сам *АренаШахта) свинецСделать() bool {
 			return false
 		}
 	}
-	if err = сам.СтрОбновить(lstMine); err != nil {
-		// log._rintf("ERRO Шахта.сделатьСвинец(): при обновлении lstMine, err=\n\t%v\n", err)
-		return false
-	}
-	if err := сам.ОбратВремяУст(АВремя(strTime)); err != nil {
-		сам.лог.Добавить("ERRO Шахта.сделатьСвинец(): при установке времени производства железа(%v)\n\terr=%v\n", strTime, err)
-	}
+	сам.СтрОбновить(lstMine)
+	сам.ОбратВремяУст(АВремя(strTime))
 	lstNum := strings.Split(strNum, `Кол-во: <span class="green2">`)
 	strNum = lstNum[1]
 	lstNum = strings.Split(strNum, `</span><br/>`)

+ 1 - 3
app/lev2/arena/arena_net/arena_net.go

@@ -48,9 +48,7 @@ func (сам *АренаСеть) Обновить() {
 	// time.Sleep(time.Millisecond * 500)
 	сам.лог.Debug("Обновить(): бот=%s\tсцена=%v\n", сам.арена.Бот().Имя(), сам.арена.Имя())
 	lstString := сам.клиент.Получ(сам.стрУрл)
-	if ош := сам.арена.СтрОбновить(lstString); ош != nil {
-		сам.лог.Err("Обновить(): при обновлении строк сцены, ош=\n\t%v\n", ош)
-	}
+	сам.арена.СтрОбновить(lstString)
 }
 
 // Get -- выполняет GET-запрос по указанному URL

+ 13 - 43
app/lev2/arena/arena_polygon/arena_polygon.go

@@ -74,23 +74,13 @@ func (сам *АренаПолигон) ПродуктВремяСейчас() s
 	return сам.ВремяОстат().String()
 }
 
-// Пуск -- запускает работу полигона в отдельном потоке
-func (сам *АренаПолигон) Пуск() {
-	go сам.пуск()
-}
-
 const (
 	стрАпгрейд = "апгрейд"
 )
 
 // выполняет опрос полигона базы.
 func (сам *АренаПолигон) пуск() {
-	ош := сам.ОбратВремяУст("02")
-	if ош != nil {
-		log.Printf("Полигон(): при установке времени обратного отсчета, ош=\n\t%v\n", ош)
-		сам.Отменить()
-		return
-	}
+	сам.ОбратВремяУст("02")
 	фнРабота := func() {
 		defer func() {
 			for сам.ВремяОстат().ПолучМилСек() > 0 {
@@ -112,12 +102,7 @@ func (сам *АренаПолигон) пуск() {
 		сам.времяОбнов()
 
 		if сам.продукт.Имя() == стрАпгрейд {
-			ош := сам.ВремяОстат().Уст("00:10:00")
-			if ош != nil {
-				log.Printf("Полигон(): при установке времени обратного отсчета, ош=\n\t%v\n", ош)
-				сам.Отменить()
-				return
-			}
+			сам.ВремяОстат().Уст("00:10:00")
 		}
 		счёт := 5
 		for счёт > 0 {
@@ -240,11 +225,9 @@ func (сам *АренаПолигон) проверитьУскорение() b
 	// Проверка на платное ускорение апгрейда + время
 	{ // Платное ускорение
 		if strings.Contains(strOut, `Ускорить за`) {
-			if err := сам.ОбратВремяУст(времОжидПлат); err != nil {
-				log.Printf("WARN Base.checkArsenalForce(): при установке платного времени ускорения апгрейда арсенала(%v)\n\terr=%v\n", времОжидПлат, err)
-			}
-			сам.АренаСостояние().РаботаИмяУст("")
-			сам.АренаСостояние().СостояниеУст(cons.РежимАпгрейд)
+			сам.ОбратВремяУст(времОжидПлат)
+			сам.ПродуктСейчас().ИмяУст("пусто")
+			сам.АренаСостояние().Уст(cons.РежимАпгрейдПлатный)
 			сам.продукт.Уст(-1)
 			сам.продукт.ИмяУст(стрАпгрейд)
 			return true
@@ -265,7 +248,7 @@ func (сам *АренаПолигон) проверитьУскорение() b
 		if !strings.Contains(strOut, `>Ускорение<`) {
 			return false
 		}
-		сам.АренаСостояние().СостояниеУст(cons.РежимАпгрейд)
+		сам.АренаСостояние().Уст(cons.РежимАпгрейд)
 		сам.продукт.ИмяУст(стрАпгрейд)
 		сам.продукт.Уст(-1)
 		lstLink := strings.Split(strOut, `<td style="width:50%;padding-left:1px;"><a class="simple-but border" href="`)
@@ -278,19 +261,14 @@ func (сам *АренаПолигон) проверитьУскорение() b
 			return false
 		}
 		// sound.ArsenalForce()
-		if err := сам.СтрОбновить(lstBase); err != nil {
-			// log._rintf("ERRO NetBank.checkArsenalForce(): при обновлении lstBase, err=\n\t%v\n", err)
-			return false
-		}
-		сам.АренаСостояние().РаботаИмяУст("")
-		сам.АренаСостояние().СостояниеУст(cons.РежимАпгрейд)
+		сам.СтрОбновить(lstBase)
+		сам.ПродуктСейчас().ИмяУст("пусто")
+		сам.АренаСостояние().Уст(cons.РежимАпгрейд)
 		сам.продукт.Уст(-1)
-		if err := сам.ОбратВремяУст(времОжидБесплат); err != nil {
-			log.Printf("WARN Base.checkArsenalForce(): при установке бесплатного времени ускорения апгрейда арсенала(%v)\n\terr=%v\n", времОжидБесплат, err)
-		}
+		сам.ОбратВремяУст(времОжидБесплат)
 	}
 	// Все проверки прошли -- это просто работа
-	сам.АренаСостояние().РаботаИмяУст("work")
+	сам.АренаСостояние().Уст(cons.РежимРабота)
 	return true
 }
 
@@ -322,12 +300,7 @@ func (сам *АренаПолигон) времяОбнов() {
 	)
 	defer func() {
 		if !isSet {
-			ош := сам.ОбратВремяУст("05")
-			if ош != nil {
-				log.Printf("Полигон.времяОбнов(): при установке обратного времени ожидания полигона, ош=\n\t%v\n", ош)
-				сам.Отменить()
-				return
-			}
+			сам.ОбратВремяУст("05")
 		}
 	}()
 	for _, lastTime := range lstPolygon {
@@ -344,10 +317,7 @@ func (сам *АренаПолигон) времяОбнов() {
 	strLastTime = lstTime[1]
 	lstTime = strings.Split(strLastTime, `</span>`)
 	strLastTime = lstTime[0]
-	if err := сам.ОбратВремяУст(АВремя(strLastTime)); err != nil {
-		// log._rintf("ERRO Polygon.updateTime(): при установке времени ожидания полигона(%v)\n\terr=%v\n", strLastTime, err)
-		return
-	}
+	сам.ОбратВремяУст(АВремя(strLastTime))
 	isSet = true
 }
 

+ 8 - 14
app/lev2/arena/down_time/down_time.go

@@ -3,17 +3,16 @@ package down_time
 
 import (
 	"context"
-	"fmt"
-
-	// "log"
 	"sync"
 	"time"
-	. "wartank/app/lev0/alias"
-	. "wartank/app/lev0/types"
-	"wartank/app/lev1/product/parser_time"
 
 	. "gitp78su.ipnodns.ru/svi/kern"
+	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
 	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
+
+	. "wartank/app/lev0/alias"
+	. "wartank/app/lev0/types"
+	"wartank/app/lev1/product/parser_time"
 )
 
 const (
@@ -40,9 +39,7 @@ type ВремОбрат struct {
 
 // НовВремОбрат -- возвращает новый *CountTime
 func НовВремОбрат(сцена ИАренаКонтекст, время АМилСек) *ВремОбрат {
-	if сцена == nil {
-		panic("НовВремОбрат(): ИСцена == nil")
-	}
+	Hassert(сцена != nil, "НовВремОбрат(): ИСцена == nil")
 	кнт, фнОтмена := context.WithCancel(сцена.Контекст())
 	сам := &ВремОбрат{
 		сцена:        сцена,
@@ -109,17 +106,14 @@ func (сам *ВремОбрат) Стоп() {
 }
 
 // Уст -- устанавливает число оставшихся сек
-func (сам *ВремОбрат) Уст(время АВремя) error {
+func (сам *ВремОбрат) Уст(время АВремя) {
 	сам.блок.Lock()
 	defer сам.блок.Unlock()
-	if ош := сам.остатПарсер.Уст(время); ош != nil {
-		return fmt.Errorf("ВремОбрат(): ошибка при установке времени, ош=\n\t%w", ош)
-	}
+	сам.остатПарсер.Уст(время)
 	_val := сам.остатПарсер.ПолучМилСек()
 	сам.текущ.Set(int(_val))
 	val := int(time.Now().UTC().UnixMilli()) + сам.текущ.Get()
 	сам.лимит.Set(val)
-	return nil
 }
 
 // String -- возвращает строковое представление оставшихся сек

+ 15 - 0
app/lev3/bot/bot.go

@@ -14,12 +14,17 @@ import (
 	. "wartank/app/lev0/alias"
 	"wartank/app/lev0/bfunc/bf_ammo_make"
 	"wartank/app/lev0/bfunc/bf_ammo_stat"
+	"wartank/app/lev0/bfunc/bf_arsenal_build"
+	"wartank/app/lev0/bfunc/bf_bank_build"
 	"wartank/app/lev0/bfunc/bf_fuel_attack"
 	"wartank/app/lev0/bfunc/bf_fuel_find"
 	"wartank/app/lev0/bfunc/bf_glory_make"
 	"wartank/app/lev0/bfunc/bf_gold_find"
+	"wartank/app/lev0/bfunc/bf_mine_accelerate"
+	"wartank/app/lev0/bfunc/bf_mine_build"
 	"wartank/app/lev0/bfunc/bf_mission_simple"
 	"wartank/app/lev0/bfunc/bf_polygon_activate"
+	"wartank/app/lev0/bfunc/bf_polygon_build"
 	"wartank/app/lev0/bfunc/bf_silver_find"
 	"wartank/app/lev0/bfunc/bf_silver_get"
 	"wartank/app/lev0/bfunc/bf_silver_prod"
@@ -172,6 +177,16 @@ func (сам *Бот) пуск() {
 		default:
 			time.Sleep(time.Second * 5)
 			сам.ангар.Обновить()
+
+			bf_mine_build.ШахтаПостроить(сам.конт)
+			bf_mine_accelerate.ШахтаУскорить(сам.конт)
+
+			bf_polygon_build.ПолигонПостроить(сам.конт)
+
+			bf_bank_build.БанкПостроить(сам.конт)
+
+			bf_arsenal_build.АрсеналПостроить(сам.конт)
+
 			bf_gold_find.ЗолотоНайти(сам.конт)
 			bf_silver_find.СереброНайти(сам.конт)
 			bf_fuel_find.ТопливоНайти(сам.конт)

+ 2 - 2
app/lev3/serv_web/serv_web.go

@@ -90,14 +90,14 @@ func (сам *СервВеб) постБотСтат(кнт *fiber.Ctx) error {
 
 	шахта := бот.КонтБот().Get("шахта").(ИАренаШахта)
 	диктБот["шахта_уровень"] = шахта.Уровень().ЗначСтр()
-	диктБот["шахта_режим"] = string(шахта.АренаСостояние().Состояние())
+	диктБот["шахта_режим"] = string(шахта.АренаСостояние().Получ())
 	диктБот["шахта_сделать_кол"] = шахта.ПродуктСейчас().ЗначСтр()
 	диктБот["шахта_сделать_назв"] = шахта.ПродуктСейчас().Имя()
 	диктБот["шахта_сделать_время"] = шахта.ПродуктВремяСейчас()
 
 	полигон := бот.КонтБот().Get("полигон").(ИАренаПолигон)
 	диктБот["полигон_уровень"] = полигон.Уровень().ЗначСтр()
-	диктБот["полигон_режим"] = string(полигон.АренаСостояние().Состояние())
+	диктБот["полигон_режим"] = string(полигон.АренаСостояние().Получ())
 	диктБот["полигон_сделать_кол"] = полигон.ПродуктСейчас().ЗначСтр()
 	диктБот["полигон_сделать_назв"] = полигон.ПродуктСейчас().Имя()
 	диктБот["полигон_сделать_время"] = полигон.ПродуктВремяСейчас()

+ 3 - 3
app/lev3/serv_web/web_api/web_api.go

@@ -283,7 +283,7 @@ func (сам *ВебАпи) арсеналРежим(кнт *fiber.Ctx) error {
 	}
 	арсенал := бот.КонтБот().Get("арсенал").Val().(ИАренаАрсенал)
 	сценаРежим := арсенал.АренаСостояние()
-	стрРежим := fmt.Sprint(сценаРежим.Состояние())
+	стрРежим := fmt.Sprint(сценаРежим.Получ())
 	if стрРежим == "" {
 		return кнт.SendString("[Режим: пустой режим]")
 	}
@@ -449,7 +449,7 @@ func (сам *ВебАпи) полигонРежим(кнт *fiber.Ctx) error {
 	}
 	полигон := бот.КонтБот().Get("полигон").Val().(ИАренаПолигон)
 	сценаРежим := полигон.АренаСостояние()
-	стрРежим := fmt.Sprint(сценаРежим.Состояние())
+	стрРежим := fmt.Sprint(сценаРежим.Получ())
 	if стрРежим == "" {
 		return кнт.SendString("[Режим: пустой режим]")
 	}
@@ -591,7 +591,7 @@ func (сам *ВебАпи) шахтаРежим(кнт *fiber.Ctx) error {
 	}
 	шахта := бот.КонтБот().Get("шахта").Val().(ИАренаШахта)
 	сценаРежим := шахта.АренаСостояние()
-	стрРежим := fmt.Sprint(сценаРежим.Состояние())
+	стрРежим := fmt.Sprint(сценаРежим.Получ())
 	if стрРежим == "" {
 		return кнт.SendString("[Режим: пустой режим]")
 	}

+ 4 - 4
app/lev3/serv_web/web_gui/page_bot_show/page_bot_show.go

@@ -78,7 +78,7 @@ func (сам *СтраницаБотПоказать) гетБотПоказ(к
 	{ // Шахта
 		шахта := бот.КонтБот().Get("шахта").Val().(ИАренаШахта)
 		сам.рендер.Доб("{.шахта_уровень}", шахта.Уровень().Получ())
-		сам.рендер.Доб("{.шахта_режим}", шахта.АренаСостояние().Состояние())
+		сам.рендер.Доб("{.шахта_режим}", шахта.АренаСостояние().Получ())
 		сам.рендер.Доб("{.шахта_сделать_кол}", шахта.ПродуктСейчас().ЗначСтр())
 		сам.рендер.Доб("{.шахта_сделать_назв}", шахта.ПродуктСейчас().Имя())
 		сам.рендер.Доб("{.шахта_сделать_время}", шахта.ПродуктВремяСейчас())
@@ -86,7 +86,7 @@ func (сам *СтраницаБотПоказать) гетБотПоказ(к
 	{ // Полигон
 		полигон := бот.КонтБот().Get("полигон").Val().(ИАренаПолигон)
 		сам.рендер.Доб("полигон_уровень", полигон.Уровень().ЗначСтр())
-		сам.рендер.Доб("полигон_режим", полигон.АренаСостояние().Состояние())
+		сам.рендер.Доб("полигон_режим", полигон.АренаСостояние().Получ())
 		сам.рендер.Доб("полигон_сделать_кол", полигон.ПродуктСейчас().ЗначСтр())
 		сам.рендер.Доб("полигон_сделать_назв", полигон.ПродуктСейчас().Имя())
 		сам.рендер.Доб("полигон_сделать_время", полигон.ПродуктВремяСейчас())
@@ -94,8 +94,8 @@ func (сам *СтраницаБотПоказать) гетБотПоказ(к
 	{ // Арсенал
 		арс := бот.КонтБот().Get("арсенал").Val().(ИАренаАрсенал)
 		сам.рендер.Доб("оружейная_уровень", арс.Уровень().ЗначСтр())
-		сам.рендер.Доб("оружейная_работа", арс.АренаСостояние().РаботаИмя())
-		сам.рендер.Доб("оружейная_режим", арс.АренаСостояние().Состояние())
+		сам.рендер.Доб("оружейная_работа", арс.ПродуктСейчас().Имя())
+		сам.рендер.Доб("оружейная_режим", арс.АренаСостояние().Получ())
 		сам.рендер.Доб("оружейная_кумул", арс.Кумулятивы().ЗначСтр())
 		сам.рендер.Доб("оружейная_бронебойки", арс.Бронебойки().ЗначСтр())
 		сам.рендер.Доб("оружейная_фугасы", арс.Фугасы().ЗначСтр())

+ 3 - 2
app/lev3/serv_web/web_gui/page_login/page_login.go

@@ -39,11 +39,12 @@ func НовСтраницаЛогин(конт IKernelCtx) *СтраницаЛо
 	return сам
 }
 
-var(
-	strBotList=`
+var (
+	strBotList = `
 	<div id="main" hx-post="/gui/bot/list/show" hx-trigger="load"  hx-swap-oob""></div>
 	`
 )
+
 // Возвращает страницу логина
 func (сам *СтраницаЛогин) получЛогин(кнт *fiber.Ctx) error {
 	сам.лог.Debug("СтраницаЛогин.логин()\n")

+ 1 - 1
go.mod

@@ -4,7 +4,7 @@ go 1.24.0
 
 require (
 	github.com/gofiber/fiber/v2 v2.52.6
-	gitp78su.ipnodns.ru/svi/kern v1.6.0
+	gitp78su.ipnodns.ru/svi/kern v1.10.0
 )
 
 require (

+ 2 - 2
go.sum

@@ -55,8 +55,8 @@ github.com/valyala/fasthttp v1.59.0/go.mod h1:GTxNb9Bc6r2a9D0TWNSPwDz78UxnTGBViY
 github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
 github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-gitp78su.ipnodns.ru/svi/kern v1.6.0 h1:kdwhSTy4SocFfdz91/DZOT0Cjd4lzZZVNYYz7TZYCDc=
-gitp78su.ipnodns.ru/svi/kern v1.6.0/go.mod h1:+8wsxQThUx9wegfPZffhRJx+s+hnyDHv4n3ODMQm6+w=
+gitp78su.ipnodns.ru/svi/kern v1.10.0 h1:TUSGNCeXGfXdHVip2hqva2JVrKTWTEtyLmJH1DtToNA=
+gitp78su.ipnodns.ru/svi/kern v1.10.0/go.mod h1:+8wsxQThUx9wegfPZffhRJx+s+hnyDHv4n3ODMQm6+w=
 go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
 go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
 go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=

+ 7 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/kern.go

@@ -25,6 +25,7 @@ import (
 	"gitp78su.ipnodns.ru/svi/kern/mds/mod_kctx"
 	"gitp78su.ipnodns.ru/svi/kern/mds/mod_keeper"
 	"gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http"
+	"gitp78su.ipnodns.ru/svi/kern/mds/mod_wui"
 )
 
 // GetKernelCtx -- возвращает контекст ядра
@@ -131,6 +132,12 @@ func GetModuleKernelKeeper() IKernelModule {
 	return modKernelKeeper
 }
 
+// GetModuleWui -- возвращает модуль для WUI
+func GetModuleWui() IKernelModule {
+	mod := mod_wui.GetModuleWui()
+	return mod
+}
+
 // NewLogBuf -- возвращает новый буферизованный лог
 func NewLogBuf() ILogBuf {
 	log := log_buf.NewLogBuf()

+ 0 - 2
vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_kctx/mod_kctx.go

@@ -10,7 +10,6 @@ import (
 	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
 	"gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/http_api"
 	"gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_module"
-	"gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_modules"
 	"gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_monolit"
 )
 
@@ -41,7 +40,6 @@ func GetModuleKernelCtx() *ModuleKernelCtx {
 	}
 	sf.log = sf.Ctx().Log()
 	_ = page_monolit.GetPageMonolit()
-	_ = page_modules.GetPageModules()
 	_ = page_module.GetPageModule()
 
 	_ = http_api.NewHttpApi()

+ 0 - 2
vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_keeper/mod_keeper.go

@@ -10,7 +10,6 @@ import (
 	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
 	"gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/http_api"
 	"gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_module"
-	"gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_modules"
 	"gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_monolit"
 )
 
@@ -41,7 +40,6 @@ func GetModuleKeeper() *ModuleKeeper {
 	}
 	sf.log = sf.kCtx.Keeper().Log()
 	_ = page_monolit.GetPageMonolit()
-	_ = page_modules.GetPageModules()
 	_ = page_module.GetPageModule()
 
 	_ = http_api.NewHttpApi()

+ 5 - 3
vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_modules/mod_row_block.html → vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/btn_modules/block_modules.html

@@ -1,8 +1,10 @@
 <div id="monolit" hx-swap-oob="true"></div>
 <div id="module" hx-swap-oob="true"></div>
-<div id="modules" class="container border rounded m-3 text-center">
-    <h2>Modules</h2>
-
+<title>Modules</title>
+<div id="modules" hx-swap-oob="true" class="container border rounded m-3 text-center">
+    <div class="container border rounded m-3 text-center">
+        <h2>Modules</h2>
+    </div>
     <p></p>
     <div id="modules_state" class="container" x-post="/modules" hx-trigger="every 2s">
         <div class="row">

+ 0 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_modules/mod_row_val.html → vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/btn_modules/block_row.html


+ 66 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/btn_modules/btn_modules.go

@@ -0,0 +1,66 @@
+package btn_modules
+
+import (
+	_ "embed"
+	"fmt"
+	"strings"
+
+	"gitp78su.ipnodns.ru/svi/kern/krn/kctx"
+	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
+	"gitp78su.ipnodns.ru/svi/kern/wui"
+	. "gitp78su.ipnodns.ru/svi/kern/wui/wtypes"
+)
+
+type BtnModules struct {
+	btn  IWuiButton
+	kCtx IKernelCtx
+}
+
+// NewBtnModules -- возвращает новую кнопку модулей
+func NewBtnModules() *BtnModules {
+	sf := &BtnModules{
+		kCtx: kctx.GetKernelCtx(),
+	}
+	sf.btn = wui.NewWuiButton("Modules", sf.clickMonolit)
+	sf.btn.Hx().Target().Set("#modules")
+	return sf
+}
+
+// Html -- возвращает HTML-представление кнопки
+func (sf *BtnModules) Html() string {
+	return sf.btn.Html()
+}
+
+//go:embed block_modules.html
+var strBlockModules string
+
+//go:embed block_row.html
+var strBlockRow string
+
+// Событие клика по кнопке
+func (sf *BtnModules) clickMonolit() string {
+	mon := sf.kCtx.Get("monolit").Val().(IKernelMonolit)
+	chLst := mon.Ctx().SortedList()
+	strOut := ``
+	for _, val := range chLst {
+		if !strings.Contains(val.Key(), "module_") {
+			continue
+		}
+		lstKey := strings.Split(val.Key(), "_")
+		id := lstKey[1]
+		strRow := strBlockRow
+		strRow = strings.ReplaceAll(strRow, "{.id}", id)
+		strRow = strings.ReplaceAll(strRow, "{.key}", val.Key())
+		moduleName := string(val.Val().(IKernelModule).Name())
+		strRow = strings.ReplaceAll(strRow, "{.name}", moduleName)
+		type_ := fmt.Sprintf("%#T", val.Val())
+		type_ = strings.ReplaceAll(type_, ".", ".<br>")
+		strRow = strings.ReplaceAll(strRow, "{.type}", type_)
+		strRow = strings.ReplaceAll(strRow, "{.createAt}", string(val.CreateAt()))
+		strRow = strings.ReplaceAll(strRow, "{.updateAt}", string(val.UpdateAt()))
+		strRow = strings.ReplaceAll(strRow, "{.comment}", val.Comment())
+		strOut += strRow
+	}
+	strOut = strings.ReplaceAll(strBlockModules, "{.mod_block}", strOut)
+	return strOut
+}

+ 16 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/btn_monolit/block_monolit.html

@@ -0,0 +1,16 @@
+<title>Monolit</title>
+<div id="monolit" hx-swap-oob="true" class="container border rounded m-3 text-center">
+    <div class="container border rounded m-3 text-center">
+        <h2>Monolit</h2>
+    </div>
+    <p></p>
+    <div class="container border rounded m-3 text-center">
+        <span class="btn btn-primary" hx-post="/monolit_state" hx-target="#monolit_state">Monolit</span>
+        <span class="btn btn-primary" hx-post="/monolit_ctx" hx-target="#monolit_state">ctx</span>
+        <span class="btn btn-primary" hx-post="/monolit_log" hx-target="#monolit_state">log</span>
+    </div>
+    <div id="monolit_state" class="container" hx-post="/monolit_state" hx-trigger="load">
+    </div>
+</div>
+<div id="modules" hx-swap-oob="true"></div>
+<div id="module" hx-swap-oob="true"></div>

+ 34 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/btn_monolit/btn_monolit.go

@@ -0,0 +1,34 @@
+// package btn_monolit -- обработчик для показа блока монолита
+package btn_monolit
+
+import (
+	_ "embed"
+
+	"gitp78su.ipnodns.ru/svi/kern/wui"
+	. "gitp78su.ipnodns.ru/svi/kern/wui/wtypes"
+)
+
+type BtnMonolit struct {
+	btn IWuiButton
+}
+
+// NewBtnMonolit -- возвращает новую кнопку монолита
+func NewBtnMonolit() *BtnMonolit {
+	sf := &BtnMonolit{}
+	sf.btn = wui.NewWuiButton("Monolit", sf.clickMonolit)
+	sf.btn.Hx().Target().Set("#monolit")
+	return sf
+}
+
+// Html -- возвращает HTML-представление кнопки
+func (sf *BtnMonolit) Html() string {
+	return sf.btn.Html()
+}
+
+//go:embed block_monolit.html
+var strBlockMonolit string
+
+// Событие клика по кнопке
+func (sf *BtnMonolit) clickMonolit() string {
+	return strBlockMonolit
+}

+ 0 - 2
vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/mod_serv_http.go

@@ -9,7 +9,6 @@ import (
 	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
 	"gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/http_api"
 	"gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_module"
-	"gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_modules"
 	"gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_monolit"
 )
 
@@ -38,7 +37,6 @@ func GetModuleServHttp() *ModuleServHttp {
 	}
 	sf.log = sf.Ctx().Log()
 	_ = page_monolit.GetPageMonolit()
-	_ = page_modules.GetPageModules()
 	_ = page_module.GetPageModule()
 
 	_ = http_api.NewHttpApi()

+ 0 - 70
vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_modules/page_modules.go

@@ -1,70 +0,0 @@
-// package page_modules -- страница представления модулей
-package page_modules
-
-import (
-	_ "embed"
-	"fmt"
-	"strings"
-
-	"github.com/gofiber/fiber/v2"
-
-	"gitp78su.ipnodns.ru/svi/kern/krn/kctx"
-	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
-)
-
-// PageModules -- отображает модули модулей
-type PageModules struct {
-	ctx IKernelCtx
-}
-
-var page *PageModules
-
-// GetPageModules -- возвращает страницу модулей
-func GetPageModules() *PageModules {
-	if page != nil {
-		return page
-	}
-	kCtx := kctx.GetKernelCtx()
-	sf := &PageModules{
-		ctx: kCtx,
-	}
-	fiberApp := kCtx.Get("fiberApp").Val().(*fiber.App)
-	fiberApp.Post("/modules", sf.postModules)
-	page = sf
-	return sf
-}
-
-//go:embed mod_row_block.html
-var strModRowBlock string
-
-//go:embed mod_row_val.html
-var strModRowBlank string
-
-// Индексная страница модулей
-func (sf *PageModules) postModules(ctx *fiber.Ctx) error {
-	ctx.Set("Content-type", "text/html; charset=utf8;\n\n")
-	mon := sf.ctx.Get("monolit").Val().(IKernelMonolit)
-	chLst := mon.Ctx().SortedList()
-	strOut := ``
-	for _, val := range chLst {
-		if !strings.Contains(val.Key(), "module_") {
-			continue
-		}
-		lstKey := strings.Split(val.Key(), "_")
-		id := lstKey[1]
-		strRow := strModRowBlank
-		strRow = strings.ReplaceAll(strRow, "{.id}", id)
-		strRow = strings.ReplaceAll(strRow, "{.key}", val.Key())
-		moduleName := string(val.Val().(IKernelModule).Name())
-		strRow = strings.ReplaceAll(strRow, "{.name}", moduleName)
-		type_ := fmt.Sprintf("%#T", val.Val())
-		type_ = strings.ReplaceAll(type_, ".", ".<br>")
-		strRow = strings.ReplaceAll(strRow, "{.type}", type_)
-		strRow = strings.ReplaceAll(strRow, "{.createAt}", string(val.CreateAt()))
-		strRow = strings.ReplaceAll(strRow, "{.updateAt}", string(val.UpdateAt()))
-		strRow = strings.ReplaceAll(strRow, "{.comment}", val.Comment())
-		strOut += strRow
-	}
-	strOut = strings.ReplaceAll(strModRowBlock, "{.mod_block}", strOut)
-	return ctx.SendString(strOut)
-}

+ 17 - 3
vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_monolit/page_monolit.go

@@ -10,11 +10,15 @@ import (
 
 	"gitp78su.ipnodns.ru/svi/kern/krn/kctx"
 	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
+	"gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/btn_modules"
+	"gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/btn_monolit"
 )
 
 // PageMonolit -- страница показа монолита
 type PageMonolit struct {
-	ctx IKernelCtx
+	ctx        IKernelCtx
+	btnMonolit *btn_monolit.BtnMonolit
+	btnModules *btn_modules.BtnModules
 }
 
 var page *PageMonolit
@@ -26,8 +30,11 @@ func GetPageMonolit() *PageMonolit {
 	}
 	kCtx := kctx.GetKernelCtx()
 	sf := &PageMonolit{
-		ctx: kCtx,
+		ctx:        kCtx,
+		btnMonolit: btn_monolit.NewBtnMonolit(),
+		btnModules: btn_modules.NewBtnModules(),
 	}
+
 	fiberApp := kCtx.Get("fiberApp").Val().(*fiber.App)
 	fiberApp.Get("/monolit", sf.getMonolit)
 	fiberApp.Post("/monolit_state", sf.postMonolitState)
@@ -37,6 +44,11 @@ func GetPageMonolit() *PageMonolit {
 	return sf
 }
 
+// Функция обратного вызова при клике на кнопку "Монолит"
+func (sf *PageMonolit) clickMonolit() string {
+	return ""
+}
+
 //go:embed log_block.html
 var strLogBlock string
 
@@ -108,5 +120,7 @@ var strPageMonolit string
 // Индексная страница монолита
 func (sf *PageMonolit) getMonolit(ctx *fiber.Ctx) error {
 	ctx.Set("Content-type", "text/html; charset=utf8;\n\n")
-	return ctx.SendString(strPageMonolit)
+	strOut := strings.ReplaceAll(strPageMonolit, "{.btn_monolit}", sf.btnMonolit.Html())
+	strOut = strings.ReplaceAll(strOut, "{.btn_modules}", sf.btnModules.Html())
+	return ctx.SendString(strOut)
 }

+ 4 - 4
vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_monolit/page_monolit.html

@@ -23,8 +23,8 @@
                         <h1>kern</h1>
                     </div>
                     <div class="col">
-                        <span class="btn btn-primary" hx-get="/monolit" hx-target="body">Monolit</span>
-                        <span class="btn btn-primary" hx-post="/modules" hx-target="#modules">Modules</span>
+                        {.btn_monolit}
+                        {.btn_modules}
                         <a class="btn btn-primary" href="/monitor" hx-boost="false">Monitor</a>
                     </div>
                 </div>
@@ -42,8 +42,8 @@
         </div>
 
         <!-- main -->
-        <div id="main">
-            <div id="monolit">
+        <div id="main" class="container">
+            <div id="monolit" class="container">
                 <div class="container border rounded m-3 text-center">
                     <h2>Monolit</h2>
                 </div>

+ 84 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/mds/mod_wui/mod_wui.go

@@ -0,0 +1,84 @@
+// package mod_wui -- модуль WUI
+package mod_wui
+
+import (
+	"fmt"
+	"sync"
+
+	"github.com/gofiber/fiber/v2"
+	"gitp78su.ipnodns.ru/svi/kern/krn/kctx"
+	"gitp78su.ipnodns.ru/svi/kern/krn/kmodule"
+	"gitp78su.ipnodns.ru/svi/kern/krn/kserv_http"
+	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
+	"gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/http_api"
+	"gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_module"
+	"gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_monolit"
+	"gitp78su.ipnodns.ru/svi/kern/wui"
+	. "gitp78su.ipnodns.ru/svi/kern/wui/wtypes"
+)
+
+// ModuleWui -- модуль WUI
+type ModuleWui struct {
+	IKernelModule
+	kCtx      IKernelCtx
+	wCtx      IWuiCtx
+	kServHttp IKernelServerHttp
+	log       ILogBuf
+}
+
+var (
+	mod   *ModuleWui
+	block sync.Mutex
+)
+
+// GetModuleWui -- возвращает новый модуль WUI
+func GetModuleWui() *ModuleWui {
+	block.Lock()
+	defer block.Unlock()
+	if mod != nil {
+		return mod
+	}
+	sf := &ModuleWui{
+		kCtx:          kctx.GetKernelCtx(),
+		wCtx:          wui.GetWuiCtx(),
+		IKernelModule: kmodule.NewKernelModule("wui"),
+		kServHttp:     kserv_http.GetKernelServHttp(),
+	}
+	sf.log = sf.Ctx().Log()
+	_ = page_monolit.GetPageMonolit()
+	_ = page_module.GetPageModule()
+
+	_ = http_api.NewHttpApi()
+	fibApp := sf.kCtx.Get("fiberApp").Val().(*fiber.App)
+	fibApp.Post("/wui/click/:id", sf.wuiClick)
+	mod = sf
+	return sf
+}
+
+// Run -- запускает модуль в работу
+func (sf *ModuleWui) Run() {
+	sf.log.Info("ModuleWui.Run(): module=%v, is run", sf.Name())
+	go sf.kServHttp.Run()
+}
+
+// IsWork -- признак работы модуля
+func (sf *ModuleWui) IsWork() bool {
+	return sf.kCtx.Wg().IsWork()
+}
+
+// Получает событие из сети
+func (sf *ModuleWui) wuiClick(ctx *fiber.Ctx) error {
+	id := ctx.Params("id")
+	widget0 := sf.wCtx.Get(id)
+	if widget0 == nil {
+		strOut := fmt.Sprintf("ModuleWui.wuiClick(): id(%v), widget not exists", id)
+		return ctx.SendString(strOut)
+	}
+	widget1, isOk := widget0.Val().(IWuiButton)
+	if !isOk {
+		strOut := fmt.Sprintf("ModuleWui.wuiClick(): widget(%T) not button", widget0.Val())
+		return ctx.SendString(strOut)
+	}
+	strOut := widget1.Click()
+	return ctx.SendString(strOut)
+}

+ 42 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/hx_swap/hx_swap.go

@@ -0,0 +1,42 @@
+// package hx_swap -- атрибут HTMX (политика замены)
+package hx_swap
+
+import (
+	"sync"
+
+	. "gitp78su.ipnodns.ru/svi/kern/wui/wtypes"
+)
+
+// HxSwap -- атрибут HTMX (политика замены)
+type HxSwap struct {
+	sync.RWMutex
+	val string
+}
+
+// NewHxSwap -- возвращает новую политику замены
+func NewHxSwap() *HxSwap {
+	sf := &HxSwap{}
+	_ = IHxSwap(sf)
+	return sf
+}
+
+// String -- возвращает строковое представление тэга
+func (sf *HxSwap) String() string {
+	sf.RLock()
+	defer sf.RUnlock()
+	return `hx-swap="` + sf.val + `"`
+}
+
+// Get -- возвращает хранимое значение политики замена
+func (sf *HxSwap) Get() string {
+	sf.RLock()
+	defer sf.RUnlock()
+	return sf.val
+}
+
+// Set -- устанавливает значение политики обмена
+func (sf *HxSwap) Set(val string) {
+	sf.Lock()
+	defer sf.Unlock()
+	sf.val = val
+}

+ 42 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/hx_swap_oob/hx_swap_oob.go

@@ -0,0 +1,42 @@
+// package hx_swap_oob -- объект внеполосной подкачки
+package hx_swap_oob
+
+import (
+	"sync"
+
+	. "gitp78su.ipnodns.ru/svi/kern/wui/wtypes"
+)
+
+// HxSwapOob -- объект внеполосной подкачки
+type HxSwapOob struct {
+	sync.RWMutex
+	val string
+}
+
+// NewHxSwapOob -- возвращает новую внеполосную подкачку
+func NewHxSwapOob() *HxSwapOob {
+	sf := &HxSwapOob{}
+	_ = IHxSwapOob(sf)
+	return sf
+}
+
+// String -- возвращает строковое представление тэга
+func (sf *HxSwapOob) String() string {
+	sf.RLock()
+	defer sf.RUnlock()
+	return `hx-swap-oob="` + sf.val + `"`
+}
+
+// Get -- возвращает хранимое значение внеполосной подкачки
+func (sf *HxSwapOob) Get() string {
+	sf.RLock()
+	defer sf.RUnlock()
+	return sf.val
+}
+
+// Set -- устанавливает значение внеполосной подкачки
+func (sf *HxSwapOob) Set(val string) {
+	sf.Lock()
+	defer sf.Unlock()
+	sf.val = val
+}

+ 42 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/hx_target/hx_target.go

@@ -0,0 +1,42 @@
+// package hx_target -- атрибут HTMX (цель замены)
+package hx_target
+
+import (
+	"sync"
+
+	. "gitp78su.ipnodns.ru/svi/kern/wui/wtypes"
+)
+
+// HxSwap -- атрибут HTMX (цель замены)
+type HxSwap struct {
+	sync.RWMutex
+	val string
+}
+
+// NewHxTarget -- возвращает новую цель замены
+func NewHxTarget() *HxSwap {
+	sf := &HxSwap{}
+	_ = IHxTarget(sf)
+	return sf
+}
+
+// String -- возвращает строковое представление тэга
+func (sf *HxSwap) String() string {
+	sf.RLock()
+	defer sf.RUnlock()
+	return `hx-target="` + sf.val + `"`
+}
+
+// Get -- возвращает хранимое значение цели замена
+func (sf *HxSwap) Get() string {
+	sf.RLock()
+	defer sf.RUnlock()
+	return sf.val
+}
+
+// Set -- устанавливает значение цели обмена
+func (sf *HxSwap) Set(val string) {
+	sf.Lock()
+	defer sf.Unlock()
+	sf.val = val
+}

+ 42 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/hx_trigger/hx_trigger.go

@@ -0,0 +1,42 @@
+// package hx_trigger -- атрибут HTMX (триггер запроса)
+package hx_trigger
+
+import (
+	"sync"
+
+	. "gitp78su.ipnodns.ru/svi/kern/wui/wtypes"
+)
+
+// HxTrigger -- атрибут HTMX (триггер запроса)
+type HxTrigger struct {
+	sync.RWMutex
+	val string
+}
+
+// NewHxTrigger -- возвращает новый триггер запроса
+func NewHxTrigger() *HxTrigger {
+	sf := &HxTrigger{}
+	_ = IHxSwap(sf)
+	return sf
+}
+
+// String -- возвращает строковое представление тэга
+func (sf *HxTrigger) String() string {
+	sf.RLock()
+	defer sf.RUnlock()
+	return `hx-trigger="` + sf.val + `"`
+}
+
+// Get -- возвращает хранимое значение триггера запроса
+func (sf *HxTrigger) Get() string {
+	sf.RLock()
+	defer sf.RUnlock()
+	return sf.val
+}
+
+// Set -- устанавливает значение триггера запроса
+func (sf *HxTrigger) Set(val string) {
+	sf.Lock()
+	defer sf.Unlock()
+	sf.val = val
+}

+ 39 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/hx_url/hx_url.go

@@ -0,0 +1,39 @@
+// package hx_url -- атрибут HTMX (URL запроса)
+package hx_url
+
+import (
+	"gitp78su.ipnodns.ru/svi/kern/wui/hx_url_method"
+	"gitp78su.ipnodns.ru/svi/kern/wui/hx_url_patch"
+	. "gitp78su.ipnodns.ru/svi/kern/wui/wtypes"
+)
+
+// HxUrl -- атрибут HTMX (URL запроса)
+type HxUrl struct {
+	method IHxUrlMethod
+	patch  IHxUrlPatch
+}
+
+// NewHxUrl -- возвращает новый URL запроса
+func NewHxUrl(patch string) *HxUrl {
+	sf := &HxUrl{
+		method: hx_url_method.NewHxUrlMethod(),
+		patch:  hx_url_patch.NewHxUrlPatch(patch),
+	}
+	_ = IHxUrl(sf)
+	return sf
+}
+
+// String -- возвращает строковое представление тэга
+func (sf *HxUrl) String() string {
+	return sf.method.Get() + `="` + sf.patch.Get() + `"`
+}
+
+// Method -- возвращает метод запроса
+func (sf *HxUrl) Method() IHxUrlMethod {
+	return sf.method
+}
+
+// Patch -- возвращает путь запроса
+func (sf *HxUrl) Patch() IHxUrlPatch {
+	return sf.patch
+}

+ 37 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/hx_url_method/hx_url_method.go

@@ -0,0 +1,37 @@
+// package hx_url_method -- атрибут HTMX (метод запроса)
+package hx_url_method
+
+import (
+	"sync"
+
+	. "gitp78su.ipnodns.ru/svi/kern/wui/wtypes"
+)
+
+// HxSwap -- атрибут HTMX (метод запроса)
+type HxSwap struct {
+	sync.RWMutex
+	val string
+}
+
+// NewHxUrlMethod -- возвращает новый метод запроса
+func NewHxUrlMethod() *HxSwap {
+	sf := &HxSwap{
+		val: "hx-post",
+	}
+	_ = IHxUrlMethod(sf)
+	return sf
+}
+
+// Get -- возвращает хранимое значение метода запроса
+func (sf *HxSwap) Get() string {
+	sf.RLock()
+	defer sf.RUnlock()
+	return sf.val
+}
+
+// Set -- устанавливает значение метода запроса
+func (sf *HxSwap) Set(val string) {
+	sf.Lock()
+	defer sf.Unlock()
+	sf.val = val
+}

+ 39 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/hx_url_patch/hx_url_patch.go

@@ -0,0 +1,39 @@
+// package hx_url_patch -- атрибут HTMX (путь запроса)
+package hx_url_patch
+
+import (
+	"sync"
+
+	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
+	. "gitp78su.ipnodns.ru/svi/kern/wui/wtypes"
+)
+
+// HxUrlPatch -- атрибут HTMX (путь запроса)
+type HxUrlPatch struct {
+	sync.RWMutex
+	val string
+}
+
+// NewHxUrlPatch -- возвращает новый путь запроса
+func NewHxUrlPatch(patch string) *HxUrlPatch {
+	Hassert(patch != "", "NewHxUrlPatch(): patch isempty")
+	sf := &HxUrlPatch{
+		val: patch,
+	}
+	_ = IHxUrlMethod(sf)
+	return sf
+}
+
+// Get -- возвращает хранимое значение пути запроса
+func (sf *HxUrlPatch) Get() string {
+	sf.RLock()
+	defer sf.RUnlock()
+	return sf.val
+}
+
+// Set -- устанавливает значение пути запроса
+func (sf *HxUrlPatch) Set(val string) {
+	sf.Lock()
+	defer sf.Unlock()
+	sf.val = val
+}

+ 69 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/hx_vals/hx_vals.go

@@ -0,0 +1,69 @@
+// package hx_vals -- атрибут HTMX (словарь значений)
+package hx_vals
+
+import (
+	"encoding/json"
+	"sync"
+
+	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
+	. "gitp78su.ipnodns.ru/svi/kern/wui/wtypes"
+)
+
+// HxVals -- атрибут HTMX (словарь значений)
+type HxVals struct {
+	sync.RWMutex
+	dict map[string]any
+}
+
+// NewHxVals -- возвращает новый словарь значений
+func NewHxVals() *HxVals {
+	sf := &HxVals{
+		dict: map[string]any{},
+	}
+	_ = IHxVals(sf)
+	return sf
+}
+
+// Len -- возвращает размер словаря
+func (sf *HxVals) Len() int {
+	sf.RLock()
+	defer sf.RUnlock()
+	return len(sf.dict)
+}
+
+// Del -- удаляет ключ словаря
+func (sf *HxVals) Del(key string) {
+	sf.Lock()
+	defer sf.Unlock()
+	delete(sf.dict, key)
+}
+
+// Clear -- очищает словарь значений
+func (sf *HxVals) Clear() {
+	sf.Lock()
+	defer sf.Unlock()
+	sf.dict = map[string]any{}
+}
+
+// String -- возвращает строковое представление тэга
+func (sf *HxVals) String() string {
+	sf.RLock()
+	defer sf.RUnlock()
+	binJson, _ := json.Marshal(sf.dict)
+	return `hx-vals='` + string(binJson) + `'`
+}
+
+// Get -- возвращает хранимое значение словарь значений
+func (sf *HxVals) Get(key string) any {
+	sf.RLock()
+	defer sf.RUnlock()
+	return sf.dict[key]
+}
+
+// Set -- устанавливает значение словарь значений
+func (sf *HxVals) Set(key string, val any) {
+	sf.Lock()
+	defer sf.Unlock()
+	Hassert(key != "", "HxVals.Set(): key is empty")
+	sf.dict[key] = val
+}

+ 64 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/wbutton/wbutton.go

@@ -0,0 +1,64 @@
+// package wbutton -- WUI-кнопка
+package wbutton
+
+import (
+	"strings"
+
+	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
+
+	"gitp78su.ipnodns.ru/svi/kern/wui/wctx"
+	"gitp78su.ipnodns.ru/svi/kern/wui/whx"
+	"gitp78su.ipnodns.ru/svi/kern/wui/wtext"
+	. "gitp78su.ipnodns.ru/svi/kern/wui/wtypes"
+	"gitp78su.ipnodns.ru/svi/kern/wui/wwidget"
+)
+
+// WuiButton -- WUI-кнопка
+type WuiButton struct {
+	IWuiWidget
+	text   IWuiText
+	fnBack func() string
+	hx     IWuiHx
+}
+
+// NewWuiButton -- возвращает новую WUI-кнопку
+func NewWuiButton(text string, fnBack func() string) *WuiButton {
+	Hassert(fnBack != nil, "NewWuiButton(): fnBack==nil")
+	sf := &WuiButton{
+		IWuiWidget: wwidget.NewWuiWidget(),
+		text:       wtext.NewWuiText(text),
+		fnBack:     fnBack,
+	}
+	sf.hx = whx.NewWuiHx("/wui/click/" + sf.Id())
+	wCtx := wctx.GetWuiCtx()
+	wCtx.Set(sf.Id(), sf, "WUI-кнопка")
+	_ = IWuiButton(sf)
+	return sf
+}
+
+// Hx -- возвращает атрибуты HTMX
+func (sf *WuiButton) Hx() IWuiHx {
+	return sf.hx
+}
+
+// Text -- возвращает текст кнопки
+func (sf *WuiButton) Text() IWuiText {
+	return sf.text
+}
+
+// Click -- событие нажатия
+func (sf *WuiButton) Click() string {
+	return sf.fnBack()
+}
+
+const (
+	strBeg = `<span id="{.id}" class="btn btn-primary" {.hx}>{.txt}</span>`
+)
+
+// Html -- возвращает HTML-представление текста
+func (sf *WuiButton) Html() string {
+	strRes := strings.ReplaceAll(strBeg, "{.id}", sf.Id())
+	strRes = strings.ReplaceAll(strRes, "{.txt}", sf.text.Get())
+	strRes = strings.ReplaceAll(strRes, "{.hx}", sf.hx.String())
+	return strRes
+}

+ 27 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/wctx/wctx.go

@@ -0,0 +1,27 @@
+// package wctx -- глобальный контекст графики
+package wctx
+
+import (
+	"sync"
+
+	"gitp78su.ipnodns.ru/svi/kern/kc/local_ctx"
+	"gitp78su.ipnodns.ru/svi/kern/krn/kctx"
+	. "gitp78su.ipnodns.ru/svi/kern/wui/wtypes"
+)
+
+var (
+	wCtx  IWuiCtx
+	block sync.Mutex
+)
+
+// GetWuiCtx -- возвращает глобальный контекст графики
+func GetWuiCtx() IWuiCtx {
+	block.Lock()
+	defer block.Unlock()
+	if wCtx != nil {
+		return wCtx
+	}
+	kCtx := kctx.GetKernelCtx()
+	wCtx = local_ctx.NewLocalCtx(kCtx.Ctx())
+	return wCtx
+}

+ 92 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/whx/whx.go

@@ -0,0 +1,92 @@
+// package whx -- HTMX-атрибуты WUI-объекта
+package whx
+
+import (
+	"gitp78su.ipnodns.ru/svi/kern/wui/hx_swap"
+	"gitp78su.ipnodns.ru/svi/kern/wui/hx_swap_oob"
+	"gitp78su.ipnodns.ru/svi/kern/wui/hx_target"
+	"gitp78su.ipnodns.ru/svi/kern/wui/hx_trigger"
+	"gitp78su.ipnodns.ru/svi/kern/wui/hx_url"
+	"gitp78su.ipnodns.ru/svi/kern/wui/hx_vals"
+	. "gitp78su.ipnodns.ru/svi/kern/wui/wtypes"
+)
+
+// WuiHx -- HTMX-атрибуты WUI-объекта
+type WuiHx struct {
+	url     IHxUrl
+	trigger IHxTrigger
+	target  IHxTarget
+	swap    IHxSwap
+	oob     IHxSwapOob
+	vals    IHxVals
+}
+
+// NewWuiHx -- возвращает новые атрибуты HTMX для WUI-объекта
+func NewWuiHx(path string) *WuiHx {
+	sf := &WuiHx{
+		url:     hx_url.NewHxUrl(path),
+		trigger: hx_trigger.NewHxTrigger(),
+		target:  hx_target.NewHxTarget(),
+		swap:    hx_swap.NewHxSwap(),
+		oob:     hx_swap_oob.NewHxSwapOob(),
+		vals:    hx_vals.NewHxVals(),
+	}
+	_ = IWuiHx(sf)
+	return sf
+}
+
+// String -- возвращает строку тэгов
+func (sf *WuiHx) String() string {
+	strOut := sf.url.String() + " " // Не может быть пустым
+	trig := sf.trigger.Get()
+	if trig != "" {
+		strOut += sf.trigger.String() + " "
+	}
+	targ := sf.target.Get()
+	if targ != "" {
+		strOut += sf.target.String() + " "
+	}
+	swap := sf.swap.Get()
+	if swap != "" {
+		strOut += sf.swap.String() + " "
+	}
+	oob := sf.oob.Get()
+	if oob != "" {
+		strOut += sf.oob.String() + " "
+	}
+	valsLen := sf.vals.Len()
+	if valsLen != 0 {
+		strOut += sf.vals.String()
+	}
+	return strOut
+}
+
+// Vals -- возвращает тэг переменных запроса
+func (sf *WuiHx) Vals() IHxVals {
+	return sf.vals
+}
+
+// Url -- возвращает тэг URL
+func (sf *WuiHx) Url() IHxUrl {
+	return sf.url
+}
+
+// Trigger -- возвращает тэг триггера запроса
+func (sf *WuiHx) Trigger() IHxTrigger {
+	return sf.trigger
+}
+
+// Target -- возвращает объект цели замены
+func (sf *WuiHx) Target() IHxTarget {
+	return sf.target
+}
+
+// Oob -- возвращает тэг внеполосной замены
+func (sf *WuiHx) Oob() IHxSwapOob {
+	return sf.oob
+}
+
+// Swap -- возвращает тэг замены
+func (sf *WuiHx) Swap() IHxSwap {
+	return sf.swap
+}

+ 54 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtext/wtext.go

@@ -0,0 +1,54 @@
+// package wtext -- WUI текст
+package wtext
+
+import (
+	"strings"
+	"sync"
+
+	. "gitp78su.ipnodns.ru/svi/kern/wui/wtypes"
+	"gitp78su.ipnodns.ru/svi/kern/wui/wwidget"
+)
+
+// WuiText -- текст для WUI
+type WuiText struct {
+	IWuiWidget
+	sync.RWMutex
+	val string
+}
+
+// NewWuiText -- возвращает новый текст WUI
+func NewWuiText(val string) *WuiText {
+	sf := &WuiText{
+		IWuiWidget: wwidget.NewWuiWidget(),
+		val:        val,
+	}
+	_ = IWuiText(sf)
+	return sf
+}
+
+const (
+	strBeg = `<span id="{.id}">{.txt}</span>`
+)
+
+// Html -- возвращает HTML-представление текста
+func (sf *WuiText) Html() string {
+	sf.RLock()
+	defer sf.RUnlock()
+	strRes := strings.ReplaceAll(strBeg, "{.id}", sf.Id())
+	strRes = strings.ReplaceAll(strRes, "{.txt}", sf.val)
+	return strRes
+}
+
+// Set -- устанавливает хранимое значение
+func (sf *WuiText) Set(val string) {
+	sf.Lock()
+	defer sf.Unlock()
+	sf.val = val
+}
+
+// Get -- возвращает хранимое значение
+func (sf *WuiText) Get() string {
+	sf.RLock()
+	defer sf.RUnlock()
+	return sf.val
+}

+ 57 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/ihx_swap.go

@@ -0,0 +1,57 @@
+package wtypes
+
+// IHxSwap -- политика замены элемента (hx-swap)
+//
+//	Возможными значениями этого атрибута являются:
+//
+// innerHTML - Замените внутренний html-код целевого элемента
+//
+// outerHTML - Замените весь целевой элемент ответом
+//
+// textContent - Замените содержимое целевого элемента, не анализируя ответ как HTML
+//
+// beforebegin - Вставьте ответ перед целевым элементом
+//
+// afterbegin - Вставить ответ перед первым дочерним элементом целевого элемента
+//
+// beforeend - Вставить ответ после последнего дочернего элемента целевого элемента
+//
+// afterend - Вставьте ответ после целевого элемента
+//
+// delete - Удаляет целевой элемент независимо от ответа
+//
+// none- Не добавляет контент из ответа (внешние элементы всё равно будут обрабатываться).
+//
+//	Модификаторы
+//
+// Атрибуты hx-swap поддерживают модификаторы для изменения поведения обмена. Они
+// описаны ниже.
+//
+// Переходный период: transition
+// Вы можете изменить время ожидания htmx после получения ответа для замены содержимого,
+// добавив модификатор swap:
+//
+// <div hx-get="/example" hx-swap="innerHTML swap:1s">Get Some HTML & Append It</div>
+//
+// Название: ignoreTitle
+//
+// По умолчанию htmx обновляет заголовок страницы, если находит тег <title> в содержимом
+// ответа. Вы можете отключить это поведение, установив для параметра ignoreTitle
+// значение true.
+//
+//	Прокрутка: scroll & show
+//
+// Вы также можете изменить поведение прокрутки целевого элемента с помощью модификаторов
+// scroll и show, которые принимают значения top и bottom:
+//
+// hx-swap="beforeend scroll:bottom"
+//
+// hx-swap="innerHTML show:top"
+type IHxSwap interface {
+	// Get -- возвращает политику замены элемента
+	Get() string
+	// Set -- устанавливает политику замены элемента
+	Set(string)
+	// String -- возвращает строковое представление тэга
+	String() string
+}

+ 29 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/ihx_swap_oob.go

@@ -0,0 +1,29 @@
+package wtypes
+
+// IHxSwapOob -- внеполосная подкачка (hx-swap-oob)
+//
+// Атрибут 'hx-swap-oob' позволяет указать, что некоторый контент в ответе должен
+// быть добавлен в DOM не в целевом элементе, а в другом месте, то есть
+// «вне диапазона». Это позволяет добавлять обновления к другим элементам в ответе.
+//
+// В одном ответе может быть несколько целей внеполосной замены
+//
+//	Примеры
+//
+// <div id="alerts" hx-swap-oob="true">
+//
+// Saved!
+//
+// </div>
+//
+// hx-swap-oob="beforeend:#table2"
+//
+// hx-swap-oob="true"
+type IHxSwapOob interface {
+	// Get -- получает атрибут HTMX
+	Get() string
+	// Set -- устанавливает атрибут HTMX
+	Set(string)
+	// String -- возвращает строковое представление тэга
+	String() string
+}

+ 47 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/ihx_target.go

@@ -0,0 +1,47 @@
+package wtypes
+
+// IHxTarget -- атрибут цели HTMX (hx-target)
+//
+// Атрибут hx-target позволяет выбрать для замены другой элемент, отличный от того,
+// к которому был отправлен AJAX-запрос. Значение этого атрибута может быть:
+//
+//	Селектор CSS-запроса целевого элемента.
+//
+// this что указывает на то, что элемент, на котором находится атрибут hx-target,
+// является целевым.
+//
+// closest <CSS selector> который найдёт ближайший элемент-предок или сам элемент,
+// соответствующий заданному селектору CSS (например, closest tr выберет ближайшую
+// к элементу строку таблицы).
+//
+// find <CSS selector> который найдёт первый дочерний элемент, соответствующий
+// заданному селектору CSS.
+//
+// next который преобразуется в element.nextElementSibling
+//
+// next <CSS selector> который будет сканировать DOM в направлении вперёд в поисках
+// первого элемента, соответствующего заданному селектору CSS. (например,
+// next .error будет нацелен на ближайший следующий элемент с классом error)
+//
+// previous который преобразуется в element.previousElementSibling
+//
+// previous <CSS selector> который будет сканировать DOM в обратном направлении в
+// поисках первого элемента, соответствующего заданному селектору CSS. (например,
+// previous .error будет нацелен на ближайшего предыдущего брата с классом error)
+//
+//	Примеры
+//
+// hx-target="#response-div"
+//
+// В этом примере используется hx-target="this" для создания ссылки,
+// которая обновляется сама по себе при нажатии:
+//
+// <a hx-post="/new-link" hx-target="this" hx-swap="outerHTML">New link</a>
+type IHxTarget interface {
+	// Set -- устанавливает цель атрибута
+	Set(string)
+	// Get -- возвращает цель атрибута
+	Get() string
+	// String -- возвращает строковое значение тэга
+	String() string
+}

+ 157 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/ihx_trigger.go

@@ -0,0 +1,157 @@
+package wtypes
+
+// IHxTrigger -- атрибут триггера HTMX (hx-trigger)
+//
+// # Список событий разделяется запятыми
+//
+// click -- простой щелчок
+//
+// click[ctrlKey] -- щелчок с удержанием CTRL
+//
+// click[ctrlKey&&shiftKey]
+//
+// click[checkGlobalState()]
+//
+//	Модификаторы:
+//
+// once — событие будет срабатывать только один раз (например, при первом нажатии)
+//
+// changed — событие сработает только в том случае, если значение элемента изменилось.
+// Пожалуйста, обратите внимание, что change — это название события, а changed —
+// название модификатора.
+//
+// delay:<timing declaration> — перед тем как событие вызовет запрос, произойдёт
+// задержка. Если событие произойдёт снова, задержка сбросится.
+//
+// throttle:<timing declaration> — дросселирование произойдёт после того, как событие
+// вызовет запрос. Если событие произойдёт снова до завершения задержки, оно будет
+// проигнорировано, а элемент сработает в конце задержки.
+//
+// from:<Extended CSS selector> — позволяет событию, запускающему запрос, исходить от
+// другого элемента в документе (например, прослушивание события нажатия клавиши в теле
+// документа для поддержки горячих клавиш). Подробнее
+// https://htmx.org/attributes/hx-trigger/
+//
+// target:<CSS selector> — позволяет фильтровать события с помощью CSS-селектора по цели
+// события.
+//
+//	queue:<queue option> — определяет, как события ставятся в очередь, если событие
+//
+// происходит во время выполнения запроса на другое событие. Возможные варианты:
+//
+// first - поставить в очередь первое событие
+//
+// last - поставить в очередь последнее событие (по умолчанию)
+//
+// all - поставить в очередь все события (отправить запрос для каждого события)
+//
+// none - не ставить в очередь новые события
+//
+//	Основные события DOM
+//
+// click - Срабатывает при клике на элемент.
+//
+// dblclick - Срабатывает при двойном клике на элемент.
+//
+// mouseenter - Срабатывает, когда курсор мыши наводится на элемент.
+//
+// mousemove -- Срабатывает, когда мышь двигается по элементу
+//
+// mouseleave - Срабатывает, когда курсор мыши покидает элемент.
+//
+// mouseover - Срабатывает, когда курсор мыши наводится на элемент или его потомков.
+//
+// mouseout - Срабатывает, когда курсор мыши покидает элемент или его потомков.
+//
+// mousedown - Срабатывает при нажатии кнопки мыши на элементе.
+//
+// mouseup - Срабатывает при отпускании кнопки мыши на элементе.
+//
+// keydown - Срабатывает при нажатии клавиши на клавиатуре.
+//
+// keyup - Срабатывает при отпускании клавиши на клавиатуре.
+//
+// keypress - Срабатывает при нажатии и удержании клавиши на клавиатуре.
+//
+// focus - Срабатывает при фокусировке на элементе.
+//
+// blur - Срабатывает при потере фокуса элементом.
+//
+// change - Срабатывает при изменении значения элемента (например, в input или select).
+//
+// input - Срабатывает при вводе данных в элемент (например, в input или textarea).
+//
+// submit - Срабатывает при отправке формы.
+//
+// load - Срабатывает при загрузке элемента (например, изображения).
+//
+// scroll - Срабатывает при прокрутке элемента.
+//
+// resize - Срабатывает при изменении размеров окна.
+//
+//	Нестандартные события
+//
+// load - срабатывает при загрузке (полезно для отложенной загрузки чего-либо)
+//
+// revealed - срабатывает при прокрутке элемента в область просмотра (также полезно
+// для отложенной загрузки). См. документацию.
+//
+// intersect — срабатывает один раз, когда элемент впервые пересекает область просмотра.
+//
+//	Поддерживает два дополнительных параметра:
+//
+// root:<selector> - CSS-селектор корневого элемента для пересечения
+//
+// threshold:<float> — число с плавающей запятой от 0,0 до 1,0, указывающее,
+// при каком проценте пересечения должно срабатывать событие
+//
+// htmx:afterRequest - Срабатывает после завершения AJAX-запроса.
+//
+// htmx:beforeRequest - Срабатывает перед отправкой AJAX-запроса.
+//
+// htmx:configRequest - Срабатывает перед настройкой AJAX-запроса.
+//
+// htmx:afterSettle - Срабатывает после применения изменений в DOM.
+//
+// htmx:afterSwap - Срабатывает после замены содержимого в DOM.
+//
+//	Примеры
+//
+// hx-trigger="every 1s">
+//
+// hx-trigger="load, click delay:1s"></div>
+//
+// В этом примере ресурс будет загружаться сразу после загрузки страницы, а затем
+// снова с задержкой в одну секунду после каждого нажатия.
+//
+// <div hx-trigger="mouseenter delay:500ms" hx-get="/example">Hover me</div>
+//
+//	Указывает элемент, от которого будет считываться событие:
+//
+// <div hx-trigger="click from:#button" hx-get="/example">Click the button</div>
+//
+// <button id="button">Click me</button>
+//
+//	Получение абсолютных координат курсора
+//
+// <div hx-trigger="mousemove"  hx-get="/get-coordinates"
+//
+//	hx-vals='js:{x: event.clientX, y: event.clientY}'
+//
+//	style="width: 300px; height: 200px; border: 1px solid black;">
+//
+//	Наведите курсор на меня
+//
+// </div>
+//
+//	Для относительной позиции:
+//
+// hx-vals='js:{x: event.offsetX, y: event.offsetY}'
+type IHxTrigger interface {
+	// Set -- устанавливает триггер атрибута
+	Set(string)
+	// Get -- возвращает триггер атрибута
+	Get() string
+	// String -- возвращает строковое значение тэга
+	String() string
+}

+ 11 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/ihx_url.go

@@ -0,0 +1,11 @@
+package wtypes
+
+// IHxUrl -- атрибут метода HTMX
+type IHxUrl interface {
+	// Method -- возвращает метод атрибута
+	Method() IHxUrlMethod
+	// Patch -- возвращает путь атрибута
+	Patch() IHxUrlPatch
+	// String -- возвращает полное значение
+	String() string
+}

+ 15 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/ihx_url_method.go

@@ -0,0 +1,15 @@
+package wtypes
+
+// IHxUrlMethod -- атрибут метода HTMX
+//
+// hx-get    // READ
+// hx-post   // CREATE (универсальный, по умолчанию)
+// hx-patch  // UPDATE
+// hx-put    // UPDATE PARTIAL
+// hx-delete // DELETE
+type IHxUrlMethod interface {
+	// Get -- возвращает метод атрибута
+	Get() string
+	// Set -- устанавливает метод атрибута
+	Set(string)
+}

+ 9 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/ihx_url_patch.go

@@ -0,0 +1,9 @@
+package wtypes
+
+// IHxUrlPatch -- атрибут пути HTMX
+type IHxUrlPatch interface {
+	// Get -- возвращает путь атрибута
+	Get() string
+	// Set -- устанавливает путь атрибута
+	Set(string)
+}

+ 30 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/ihx_vals.go

@@ -0,0 +1,30 @@
+package wtypes
+
+// IHxVals -- словарь значений в элементе HTMX (hx-vals)
+//
+// Атрибут hx-vals позволяет добавлять параметры, которые будут отправляться с запросом AJAX.
+//
+// По умолчанию значением этого атрибута является список значений имени-выражения
+// в формате JSON
+//
+//	Примеры
+//
+// hx-vals='{"myVal": "My Value"}'
+//
+// hx-vals='js:{lastKey: event.key}'
+//
+// hx-vals='js:{x: event.clientX, y: event.clientY}'
+type IHxVals interface {
+	// Get --  возвращает элемент словаря
+	Get(key string) any
+	// Set -- устанавливает элемент словаря
+	Set(key string, val any)
+	// Del -- удаляет элемент из словаря
+	Del(key string)
+	// Clear -- очищает весь словарь
+	Clear()
+	// Len -- возвращает размер словаря
+	Len() int
+	// String -- возвращает строковое представление тэга
+	String() string
+}

+ 12 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/iwui_button.go

@@ -0,0 +1,12 @@
+package wtypes
+
+// IWuiButton -- WUI-кнопка
+type IWuiButton interface {
+	IWuiWidget
+	// Text -- возвращает текст кнопки
+	Text() IWuiText
+	// Click -- нажатие кнопки
+	Click() string
+	// Hx -- атрибуты HTMX
+	Hx() IWuiHx
+}

+ 11 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/iwui_ctx.go

@@ -0,0 +1,11 @@
+// package wtypes -- интерфейсы WebUI
+package wtypes
+
+import (
+	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
+)
+
+// IWuiCtx -- контекст веб-интерфейса
+type IWuiCtx interface {
+	ILocalCtx
+}

+ 19 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/iwui_hx.go

@@ -0,0 +1,19 @@
+package wtypes
+
+// IWuiHx -- атрибуты HTMX
+type IWuiHx interface {
+	// Url -- возвращает URL HTMX
+	Url() IHxUrl
+	// Trigger -- возвращает триггер HTMX
+	Trigger() IHxTrigger
+	// Target -- возвращает цель HTMX
+	Target() IHxTarget
+	// Swap -- политика замены элемента
+	Swap() IHxSwap
+	// Oob -- политика внеполосной подкачки
+	Oob() IHxSwapOob
+	// Vals -- словарь дополнительных значений
+	Vals() IHxVals
+	// String -- возвращает строку тэгов
+	String() string
+}

+ 8 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/iwui_label.go

@@ -0,0 +1,8 @@
+package wtypes
+
+// IWuiLabel -- текстовая метка
+type IWuiLabel interface {
+	IWuiWidget
+	// Text -- возвращает текст метки
+	Text() IWuiText
+}

+ 10 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/iwui_text.go

@@ -0,0 +1,10 @@
+package wtypes
+
+// IWuiText -- текст WUI
+type IWuiText interface {
+	IWuiWidget
+	// Get -- возвращает текст
+	Get() string
+	// Set -- устанавливает текст
+	Set(string)
+}

+ 9 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/wtypes/iwui_widget.go

@@ -0,0 +1,9 @@
+package wtypes
+
+// IWuiWidget -- WUI виджет
+type IWuiWidget interface {
+	// Id -- возвращает Id виджета
+	Id() string
+	// Html -- возвращает HTML-представление виджета
+	Html() string
+}

+ 20 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/wui.go

@@ -0,0 +1,20 @@
+// package wui -- пакет веб-интерфейса
+package wui
+
+import (
+	"gitp78su.ipnodns.ru/svi/kern/wui/wbutton"
+	"gitp78su.ipnodns.ru/svi/kern/wui/wctx"
+	. "gitp78su.ipnodns.ru/svi/kern/wui/wtypes"
+)
+
+// NewWuiButton -- возвращает новую WUI-кнопку
+func NewWuiButton(text string, fnClick func() string) IWuiButton {
+	btn := wbutton.NewWuiButton(text, fnClick)
+	return btn
+}
+
+// GetWuiCtx -- возвращает контекст WUI
+func GetWuiCtx() IWuiCtx {
+	wCtx := wctx.GetWuiCtx()
+	return wCtx
+}

+ 38 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/wui/wwidget/wui_widget.go

@@ -0,0 +1,38 @@
+// package wwidget -- базовый виджет WUI
+package wwidget
+
+import (
+	"crypto/rand"
+	"strings"
+
+	. "gitp78su.ipnodns.ru/svi/kern/wui/wtypes"
+)
+
+// WuiWidget -- базовый виджет WUI
+type WuiWidget struct {
+	id string
+}
+
+// NewWuiWidget -- возвращает новый базовый виджет WUI
+func NewWuiWidget() *WuiWidget {
+	sf := &WuiWidget{
+		id: "wui_" + rand.Text(),
+	}
+	_ = IWuiWidget(sf)
+	return sf
+}
+
+// Id - возвращает ID виджета
+func (sf *WuiWidget) Id() string {
+	return sf.id
+}
+
+const (
+	strBeg = `<div id="{.id}"> WuiWidget.Html(): id={.id}, not implemented </div>`
+)
+
+// Html -- возвращает HTML представление виджета
+func (sf *WuiWidget) Html() string {
+	strRes := strings.ReplaceAll(strBeg, "{.id}", sf.id)
+	return strRes
+}

+ 19 - 2
vendor/modules.txt

@@ -102,7 +102,7 @@ github.com/valyala/fasthttp/fasthttputil
 github.com/valyala/fasthttp/reuseport
 github.com/valyala/fasthttp/stackless
 github.com/valyala/fasthttp/tcplisten
-# gitp78su.ipnodns.ru/svi/kern v1.6.0
+# gitp78su.ipnodns.ru/svi/kern v1.10.0
 ## explicit; go 1.24.0
 gitp78su.ipnodns.ru/svi/kern
 gitp78su.ipnodns.ru/svi/kern/kc/helpers
@@ -142,11 +142,28 @@ gitp78su.ipnodns.ru/svi/kern/krn/ktypes
 gitp78su.ipnodns.ru/svi/kern/mds/mod_kctx
 gitp78su.ipnodns.ru/svi/kern/mds/mod_keeper
 gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http
+gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/btn_modules
+gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/btn_monolit
 gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/http_api
 gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_module
-gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_modules
 gitp78su.ipnodns.ru/svi/kern/mds/mod_serv_http/page_monolit
+gitp78su.ipnodns.ru/svi/kern/mds/mod_wui
 gitp78su.ipnodns.ru/svi/kern/mock/mock_hand_sub_http
+gitp78su.ipnodns.ru/svi/kern/wui
+gitp78su.ipnodns.ru/svi/kern/wui/hx_swap
+gitp78su.ipnodns.ru/svi/kern/wui/hx_swap_oob
+gitp78su.ipnodns.ru/svi/kern/wui/hx_target
+gitp78su.ipnodns.ru/svi/kern/wui/hx_trigger
+gitp78su.ipnodns.ru/svi/kern/wui/hx_url
+gitp78su.ipnodns.ru/svi/kern/wui/hx_url_method
+gitp78su.ipnodns.ru/svi/kern/wui/hx_url_patch
+gitp78su.ipnodns.ru/svi/kern/wui/hx_vals
+gitp78su.ipnodns.ru/svi/kern/wui/wbutton
+gitp78su.ipnodns.ru/svi/kern/wui/wctx
+gitp78su.ipnodns.ru/svi/kern/wui/whx
+gitp78su.ipnodns.ru/svi/kern/wui/wtext
+gitp78su.ipnodns.ru/svi/kern/wui/wtypes
+gitp78su.ipnodns.ru/svi/kern/wui/wwidget
 # go.opentelemetry.io/auto/sdk v1.1.0
 ## explicit; go 1.22.0
 go.opentelemetry.io/auto/sdk