Влад : другие произведения.

Исходные тексты скриптов задач "siTop…"

Самиздат: [Регистрация] [Найти] [Рейтинги] [Обсуждения] [Новинки] [Обзоры] [Помощь|Техвопросы]
Ссылки:
Школа кожевенного мастерства: сумки, ремни своими руками
 Ваша оценка:
  • Аннотация:
    По состоянию на 19 октября 2024 года.

См. также:
? Как узнать популярность произведения в "Самиздате" ("где/что смотреть" - основное, вкратце).
~ Рейтинг siTopTexts "Произведения" ("Самиздат", самое популярное за 30 дней).
+ Рейтинг siTopAuthors "Авторы" ("Самиздат" намедни).
* История-Р, "прикопанное" прошлое (ссылки на подборки старых рейтингов по полугодиям).
Disclaimer: Я не несу никакой ответственности за последствия касаемо. Далеко не факт, что у вас получится то, на что вы рассчитываете, если станете использовать нижеприведённое. Пользуйтесь оным исключительно на свой страх и риск. ;-|
… В любом случае, на вопросы касаемо — отвечу, если смогу…
  /\    /\  
 ·--·--·--· 
     \/     
     /\     
    ·--·    
Исходные тексты скриптов задач "siTop…"
(от: 2024.10.19)
    NB. В публикации приведен комплект оригинальных исходных текстов скриптов, не подвергавшихся какой-либо предварительной правке (за исключением преобразования: «OEM→ANSI» кириллицы в скриптах CMD). Этот комплект работает в ОС WindowsXP-x86-RUS+SP3+SRK, использует некоторые бесплатные утилиты (порт из UNIX) и ориентирован на полуавтоматическое применение в моей рабочей среде. Влад.

Перечень задействованных скриптов:

  1. Задача: «Разделы "Самиздата"»
    1. Задание: "0form" — выявление скрытых разделов /"потеряшки"/
    2. Задание: "1hidn" — вычленение активных "потеряшек"
    3. Задание: "aHits" — обновление локальной копии рейтинга "по количеству посетителей"

  2. Задача: «Рейтинг siTopTexts "Произведения"»
    1. Задание: "bStat" — обновление локальных копий статистик топовых разделов, сборка шорт-листа к siTopTexts
    2. Задание: "cChkH" — контроль даты "Размещен" произведений в шорт-листе siTopTexts
    3. Задание: "dText" — сбор сведений о произведениях (объём, оценки, отклики, …)
    4. Задание: "fHtml" — оформление таблиц рейтинга siTopTexts

  3. Задача: «Рейтинг siTopAuthors "Авторы"»
    1. Задание: "gAuth" — составление и наполнение шорт-листа siTopAuthors
    2. Задание: "iNetR" — оформление таблиц siTopAuthors

  4. Задача: «Оценка доступа к доменам "Самиздата", ожидание обновления статистик разделов »
    1. Задание: "zChk.cmd" — обнаружение факта "«сегодня» обновлено"

  5. Универсальный скрипт "качалка" для скачивания страниц "Самиздата"

    Имя файла скрипта: "0form.awk" V-текст скрипта-V
- - - - - - - - -
BEGIN{                              #  0form.awk - вычленение a_Id отсутствующих в aHits разделов
# 2023.07.08, nvv, creation на входе - страницы произведений по 18 формам СИ
# 2023.07.13, nvv, turning
# 2024.05.23, nvv, вых.список упорядочен НЕ по числу текстов у автора, а по алфавиту
# 2024.09.09, nvv, в шапку добавлен отчёт по изменению сосотава:


#  на выходе - список id разделов, ОТСУТСТВУЮЩИХ в aHits
#   test=1
  errS="no inPut files"
  jDat=strftime("%Y.%m.%d")
  if(ARGV[1]=="")exit                             #  защита от случайного пуска
  for(str2 in ENVIRON){                     #  ! регистр букв в имени переменной может быть любой
    if(tolower(str2)=="fhit")fHit=ENVIRON[str2]   #  опорный aHits список
    if(tolower(str2)=="jlst")jLst=ENVIRON[str2]   #  место для итогового списка
  }
  if(fHit==""){                                   #  если вызов НЕ из CMD, aHits ищем сами
    if(test){
    str0="U:\\Jobs\\_siTop.#"
    while((getline line<str0)>0){       #  ищем последнюю запись успешного скачивания этого списка
# ;1A hits 5:xNam 457:xNum 104555:xPas 2023.06.15:hDat 505501:hMax 1051:hPag 1111:dnLd 0.08~ratW 2023.06.16:done 05:22:08~wrks 14:47
      if(match(line,/^;1A .+ 20([\.0-9]{8}):hDat /,arr0))fHit=arr0[1]
    }
    close(str0)
    if(fHit==""){
      errS="] NO *.aHits found in "str0
      exit
    }
    jLst="_lost.addF"
    fHit="U:\\Jobs\\20"fHit".aHits"               #  строим полное имя нужного списка
    }else{
      errS="NO fHit envVar"
      exit
    }
  }
# ; 18:form 7934:pags 1584692:txts 105335:auth 1928:hidn 2024.09.06:done
# ;txTot id_P
#     2 2/2021mart
  while((getline line<jLst)>0){
    split(line,aj)
    if(match(aj[1],/^[0-9]+$/)){
      aOld[aj[2]]=aj[1]                         # 
    }else if(match(line,/^; 18:form .+ ([^ ]+):done/,aj)){
      oldD=aj[1]
    }
  }
  close(jLst)                                     #  всё/не_всё, - старый список тогось
# # 201661   21  846    3 k/kadawr "Кадавр" "no•comments"
# # ] hitP numP sizK sizN id_P     "namP"   "moto"
# #      1    2    3    4  5        6        7
  while((getline line<fHit)>0){                   #  fHit: like 2020.03.01.aHits
    split(line,aj)
    if(match(aj[1],/^[0-9]+$/)){                  #  в опоре "потеряшки" неуместны
      if(aj[2])aHit[ aj[5]]=line  #  aj[1] == 201661 aj[5] == k/kadawr p_id
    }else                       aHre[++nHre]=line
    j0++
  }
  close(fHit)                                     #  всё/не_всё, - старый список тогось
  if(99999-j0>0){
    errS=j0" LOW aHits.recs"
    exit
  }
  errS=""
  nCam=0
  nGon=0
}

{
  if(FNR==1){
    pagF++                                        #  учитываем страницы форм
    if(pagF%10){printf(".")}else{printf(":")}     #  оживляж...
    if(!(pagF%100))printf("%5s\n",pagF)
  }
  if(match($0,/<DL><DT><li>.*<a href=\/([^>]+)><font color=#555555>([^<]*)</,aj)){
    aFrm[aj[1]]++                                 #  учитываем id_P и тексты в них
  }
}

function mkSec(dat){      #  дата "гггг.мм.дд" -> UNIX-секунды с 1970.01.01
  return(mktime(\
substr(dat,1,4)" "substr(dat,6,2)" "substr(dat,9,2)" 00 00 00"\
))
}

END{
  if(errS!=""){                                   #  проблем-с...
    print("] "errS)
    exit -1
  }
  printf("%5s\n",pagF)
  txtF=0
  autF=0
  for(j0 in aFrm){
    if(!(j0 in aHit)){
      aNot[++nNot]=j0
      if(j0 in aOld)delete aOld[j0]
      else nCam++
    }
    txtF=txtF+aFrm[j0]
    autF++
  }
  nGon=length(aOld)
  j3="; 18:form "pagF":pags "txtF":txts "autF":auth "nNot":hidn "jDat":done"
  asort(aNot)
  print(j3) > jLst
  print(aHre[nHre])                     > jLst
  j3=(mkSec(jDat)-mkSec(oldD))/86400
  j3=oldD":preD "j3".dGap "nCam".came "nGon".gone"
  print(";txTot id_P",j3)               > jLst
  for(j0=1;j0<=nNot;j0++)printf("%5s %s\n",aFrm[aNot[j0]],aNot[j0]) > jLst
#     if(!(j0 in aHit))aNot[++nNot]=sprintf("%5s %s",aFrm[j0],j0)
  print(j3)
}

    Имя файла скрипта: "0form.cmd" V-текст скрипта-V
- - - - - - - - -
@if not defined pMod @echo off
set nJob=addF
echo %date% %time:~0,8% %nJob% Begs
:: 1hidn.cmd - составление /по спискам форм/ списка _lost.addF разделов, отсутствующих в aHits- 
:: 0. для старта нужнен список aHits (хиты)
:: 1. обновляется страницы списков "формы" 01.0001.form.htm .. 18.NNNN.form.htm

::  основной и резервный URL Самиздата (желательно работать с резервом)
if NOT defined siUrl if exist \siUrl.budclub set siUrl=budclub.ru
if NOT defined siUrl set siUrl=samlib.ru

:: 2024.10.19, nvv, +выдача в протокол изменений: "K.dGap L.came M.gone"
:: история изменений в подвале скрипта!

:: основные сеты и прочая подготовка к работе...
set jDat=%date%
set errInf=
::  wrks - общее время работы процесса (пуск общего таймера)
for /F %%A in ('gawk.exe "BEGIN{print(systime());exit}"') do set wrks=%%A
::  aScr - скрипт вычленения потеряшек из страниц списков произведений по формам
set aScr=%~dpn0.awk
if NOT exist %aScr% set errInf=NO %aScr% found & goto errExit
::  wDir - общее рабочее место
set wDir=%~d0\Jobs
::  jDir - место для оперативных файлов
set jDir=%wDir%\_%nJob%
::  zDir - общий подкаталог для посуточных подкаталогов с итоговыми списками
set zDir=%~d0\Stor\wOld\%jDat%
::  jLst - конечный результат процесса в формате *.mig.bStat
set jLst=%wDir%\_lost.%nJob%
::  jRpt - общий отчёт с итоговыми сводками процессов
set jRpt=%wDir%\_siTop.#
::  fil1 - первая страница первой формы
set fil1=%jDir%\01.0001.form.htm
::  fOld дата файла наличного рейтинга *.aHits
set fOld=
::  dnLd - счётчик скачанного ([пере]запустим "таймер" ratW)
set dnLd=0
::  wGetSiz - размер скачанного файла (default 1b минимум)
set wGetSiz=1
:: проверить/создать нужные структуры для работы (оперативные площадки)
if NOT exist %jDir%\*.* (
  mkDir %jDir%
  if errorLevel 1 set errInf=fail mkDir %jDir% & goto errExit
)
if NOT exist %zDir%\*.* (
  mkDir %zDir%
  if errorLevel 1 set errInf=fail mkDir %zDir% & goto errExit
)
:: проверка наличия,.. для корректной работы нужен aHits /рейтинг по хитам/
set fHit=
for %%A in (%wDir%\20??.??.??.aHits) do set fHit=%%A
if NOT defined fHit set errInf=NO *.aHits found, no job 2do & goto errExit
:: ок, работать можно, смотрим наше хозяйство сегодняшнего нет... побежали дальше
:: htm jLst
:: non any  качаем
:: old any чистим+качаем
:: cur non/older качаем
:: cur newer -- нечего делать, всё уже
if NOT exist %jDir%\*.form.htm goto chkDl
:: смотрим дату создания 01.0001.form.htm
set oDat=
for %%A in (%fil1%) do set oDat=%%~tA
:: если НЕ сегодняшняя, надо чистить и качать
if NOT %jDat%. == %oDat:~0,10%. goto doJob
:: смотрим U:\Jobs\_lost.addF /список годных "потеряшек"/ берём дату в нём
set tmp0=
for %%A in (%jLst%) do set tmp0=%%~tA
:: итог свежий или нет?
if NOT defined tmp0 goto chkDl
:: в накопителе файлы *.html свежее, чем итог _lost.addF
if "%oDat%" GEQ "%tmp0%" (
  goto chkDl
) else (
  echo == all is done today already
  goto :eof
)

:doJob чистим старое в накопителе
echo erasing ~7.7k old pages of 18 form...
if exist %jDir%\*.htm (
  erase /F /Q %jDir%\*.htm
  if errorLevel 1 set errInf=fail erase %jDir%\*.htm & goto errExit
)
:chkDl скачивание недостающего; ratW - темп скачивания
for /F %%A in ('gawk.exe "BEGIN{print(systime());exit}"') do set ratW=%%A
:: собственно перебор/запуск_скачивания
echo ? dnLd %nJob% fresh pages...
for /L %%A in ( 1, 1, 18 ) do if NOT defined errInf call :gainThis %%A
if defined errInf goto nExit
:: вычислим темп скачивания ratW
if %dnLd% == 0 (set ratW=0) else (
  for /F %%A in (
    ' gawk.exe "BEGIN{print(sprintf(\"%%3.2f\",(systime()-%ratW%)/%dnLd%));exit}" '
  ) do set ratW=%%A
)
echo.
echo = %dnLd%:pages 18:forms %ratW%:ratW scaning...
:: формы у нас, соберём из них список скрытых id_P
gawk.exe -f %aScr% %jDir%\*.form.htm
if NOT %errorLevel% == 0 set errInf=%aScr% problem in %jDir%\*.form.htm & goto errExit
rem ; 18:form 7687:pags 1535762.txts 104310:auth 1948:hidn 2023.06.28:done
for /F "tokens=1-9,*" %%A in (
  ' gawk.exe "{if(match($2,/^18:form$/))print($3,$4,$5,$6);exit}" %jLst% '
) do (
  set pags=%%A
  set txts=%%B
  set auth=%%C
  set hidn=%%D
)
:: почистим, вычленив цифры
set pags=%pags:~0,-5%
set txts=%txts:~0,-5%
set auth=%auth:~0,-5%
set hidn=%hidn:~0,-5%

rem ;txTot id_P 2024.09.18:preD 10.dGap 2.came 5.gone
for /F "tokens=1-9,*" %%A in (
  ' gawk.exe "{if(NR==3){print($4,$5,$6);exit}}" %jLst% '
) do (
  set dGap=%%A
  set came=%%B
  set gone=%%C
)
:: почистим, вычленив цифры
set dGap=%dGap:~0,-5%
set came=%came:~0,-5%
set gone=%gone:~0,-5%

:: остановим "таймер", : преобразуем секунды в время работы (в обычном формате "чч:мм:сс")
for /F %%A in ('gawk.exe "BEGIN{print(strftime(\"%%H:%%M:%%S\",systime()-%wrks%+46800));exit}"') do set wrks=%%A

:: ;0F addF 1943:hidn 7338:FdlS 1.21~FrwS 2023.07.02:done 02:29:22~wrks 16:38 
set tmp0=;0F form ^
%pags%:pags ^
%auth%:auth ^
%hidn%:hidn ^
%dGap%:dGap ^
%came%:came ^
%gone%:gone ^
%ratW%~ratW ^
%jDat%:done ^
%wrks%~wrks ^
%time:~0,5%
echo %tmp0% >> %jLst%
echo %tmp0% >> %jRpt%
rem echo = Ok %hidn%.hidn %dnLd%:FdlS %ratW%~FrwS
:: скинем результаты в хранилище
copy /y /b %jLst% %zDir%\ > nul
if errorLevel 1 set errInf=fail copy %jLst% TO %zDir% & goto errExit
:: подудим где нада "готово-с!"
set itog=%jLst%

:nExit
if defined errInf if NOT defined errF echo ! %errInf%
echo %date% %time:~0,8% %~nx0 Ends
goto :eof

rem gawk.exe -f %aScr% %jDir%\*.htm
rem goto :eof

:gainThis %%Z скачивание всех страниц указанного типа
set typB=0%1
set typB=%typB:~-2%
::  wReq - общая часть адреса страниц указанного рейтинга
set wReq=%siUrl%/type/index_type_%1-
call :reqSI 1
if defined errInf goto :eof
:: выясним pMax /общее число страниц рейтинга/
set pMax=
for /F %%J in (
  ' gawk.exe "{if(match($0,/<\/td><\/tr><\/table><center><b>.+\.shtml>([0-9]+)<\/a> *<\/center>/,a)){print(a[1]);exit}}" %wFil% '
) do set pMax=%%J
if NOT defined pMax (
  set errInf=NO pMax in %wFil%
  goto errExit
)
gawk.exe "BEGIN{printf(\" next.%pMax% ones \n.\");exit}"
for /L %%J in (2,1,%pMax%) do if NOT defined errInf call :reqSI %%J
if defined errInf goto :eof
if NOT "%pNum:~-2%" == "00" echo.
rem echo.= %typB%.%pNum% pages
gawk.exe "BEGIN{printf(\"= %typB%.%pNum% pages\");exit}"
goto :eof

:reqSI %%J притаскивает type в кодировке cp1251 (win)
set wUrl=%wReq%%1.shtml
set pNum=000%1
set tmp0=   %1
::  pNum - 4-х значное число с лидирующими нулями (для красивой сортировки пронумерованных страниц рейтинга)
set pNum=%pNum:~-4%
set tmp0=%tmp0:~0,2%
::  wFil - конечный локальный файл для скачиваемого
set wFil=%jDir%\%typB%.%pNum%.form.htm
if %pNum:~-1% == 0 (set mark=%pNum:~-2,1%) else (set mark=.)
:: оживляж, если уже есть
if exist %wFil% (
  if NOT %pNum:~-1% == 0 (set mark=~)
)
:: первая странимца очередного списка по форме нужна для выяснения числа страниц этой формы
if %1 == 1 goto doDl
gawk.exe "BEGIN{printf(\"%mark%\");exit}"
if NOT "%pNum:~-2%" == "00" goto doDl
echo. = %pNum:~0,2% %time:~0,8%
:doDl
if exist %wFil% goto :eof
call wGetUrl2fil.cmd %wUrl% %wFil%
:: проблема?
if %wGetErr% == 1 set errInf=no %wUrl%
if %wGetErr% == 3 set errInf=no web{SI}

:errExit реакция на проблему: в пакете - выход
if defined pMod goto :eof
:: автономно - на экран + прекращение работы
echo %errInf%
exit

:: 2023.06.20, nvv, сознано на основе aHits.cmd от 2023.05.30
:: 2023.07.10, nvv, turning...
:: 2024.03.03, nvv, исправлена реакция на проблемы запуска /NO z!!!.!!!/
:: 2024.03.10, nvv, minor cosmetics
:: 2024.03.24, nvv, запрос для: обновления старого ИЛИ перестройки ЗАНОВО сегодняшнего 
:: 2024.05.23, nvv, вых.список упорядочен НЕ по числу текстов у автора, а по алфавиту
:: 2024.08.12, nvv, вместо вопроса или работа, или выход по "уже есть"

    Имя файла скрипта: "1hidn.awk" V-текст скрипта-V
- - - - - - - - -
BEGIN{                            #  0addS.awk scan+select *.stat.htm for addition 2 top SI stats
# 2023.06.26, nvv, creation на основе bStat.awk 2023.06.22
# 2024.03.03, nvv, last upDates
# 2024.06.03, nvv, п/п pack -> pack4cmd
# 2024.09.15, nvv, отключено условие "datJ == maxD"
# ; stat 1939:allS 824:good 2023.07.19:dEnd 2023.07.23:done
# ;     datS_timS.1    datJ.2    hitP.3 id_P.4 "namP".5 "moto".6 id_F.7
# 2023.07.20_01:54:05 2023.07.19   9073 n/neon13 "Neon13" "Авторский" n~neon13
#  у ГОДНЫХ скрытых разделов:
#  - в порядке шапка,
#  + hitP >0 - хиты за 12мес.
# X + datJ == maxD - т.е. статистика обновлена к расчёту
#  id_P == n/neon13
#  ~ прочие данные носят справочный характер /для наблюдателя/
#  на выходе:
#  allS - число не нулевых файлов *.stat.htm
#  good - число годных скрытых разделов для включения в aHits
#  dEnd - граница расчёта 

  nMig=0                                          #  число годных к расчёту разделов-потеряшек
  maxD="----.--.--"                               #  верзняя граница интервала дат расчёта
  errS="NO file"
  if(ARGV[1]=="")exit                             #  защита от случайного пуска

# объявим массивыы для общего использования в подпрограммах
  split("",aSel)    #  в ячейках статистики: url,title,hits:all,12mon,mon0..monC-11,day0..day0-61
  split("",aMig)                                  #  список timeStamp's статистик
  split("",aj)                                  #  рабочий массив

  for(str2 in ENVIRON){                     #  ! регистр букв в имени переменной может быть любой
    str1=tolower(str2)                            #  Temp и temp - РАЗНЫЕ имена для gAwk...
    if(str1=="wdir")wDir=ENVIRON[str2]"\\"        #  место для всех ВЫХ.списков
  }
#   if((wDir=="")&&!test){
#     errS="NO wDir envVar"
#     exit
#   }
# массив имён месяцев для преобразования их в числа с лидирующим нулём 01..12
  mNum["Jan"]="01"                                #  .1 January . Jan. 31 . winter wint
  mNum["Feb"]="02"                                #  .2 February .Feb. 28/29
  mNum["Mar"]="03"                                #  .3 March . . Mar. 31 . spring sprn
  mNum["Apr"]="04"                                #  .4 April . . Apr. 30
  mNum["May"]="05"                                #  .5 May . . . May. 31
  mNum["Jun"]="06"                                #  .6 June . . .Jun. 30 . summer summ
  mNum["Jul"]="07"                                #  .7 July . . .Jul. 31
  mNum["Aug"]="08"                                #  .8 August . .Aug. 31
  mNum["Sep"]="09"                                #  .9 September Sep. 30 . autumn autm
  mNum["Oct"]="10"                                #  10 October . Oct. 31
  mNum["Nov"]="11"                                #  11 November .Nov. 30
  mNum["Dec"]="12"                                #  12 December .Dec. 31 . winter wint
  errS=""
  tIni=systime()
}
#   ; upDat_datS  1-st_day   numS xDel/=Keep hitP  numP   hitT id_P id_T
# ; 0000.00.00-_bad_file_      2  0.0% x       ~     ~      ~ ~    ~
# ; 2024.07.31-2024.07.30      1  0.0% x       ~     ~      ~ ~    ~
# ; 2024.08.01-2024.07.31      1  0.0% x       ~     ~      ~ ~    ~
# ; 2024.08.15-2024.08.14      1  0.0% x       ~     ~      ~ ~    ~
# ; 2024.08.17-2024.08.16      1  0.0% x       ~     ~      ~ ~    ~
# ; 2024.08.19-2024.08.18      3  0.0% x       ~     ~      ~ ~    ~
# ; 2024.08.20-2024.08.19      1  0.0% x       ~     ~      ~ ~    ~
# ; 2024.08.21-2024.08.20      1  0.0% x       ~     ~      ~ ~    ~
# ; 2024.08.25-2024.08.24      7  0.0% x       ~     ~      ~ ~    ~
# ; 2024.08.26-2024.08.25     15  0.0% x       ~     ~      ~ ~    ~
# ; 2024.08.27-2024.08.26     11  0.0% x       ~     ~      ~ ~    ~
# ; 2024.08.28-2024.08.27     14  0.0% x       ~     ~      ~ ~    ~
# ; 2024.08.29-2024.08.28     27  0.1% x       ~     ~      ~ ~    ~
# ; 2024.08.30-2024.08.29     60  0.2% x       ~     ~      ~ ~    ~
# ; 2024.08.31-2024.08.30    117  0.4% x       ~     ~      ~ ~    ~
# ; 2024.09.01-2024.08.31    121  0.4% x       ~     ~      ~ ~    ~
# ; 2024.09.02-2024.09.01    109  0.4% x       ~     ~      ~ ~    ~
# ; 2024.09.03-2024.09.02    192  0.6% x       ~     ~      ~ ~    ~
# ; 2024.09.04-2024.09.03    275  0.9% x       ~     ~      ~ ~    ~
# ; 2024.09.05-2024.09.04    663  2.2% x       ~     ~      ~ ~    ~
# ; 2024.09.06-2024.09.05   3697 12.2% x       ~     ~      ~ ~    ~
# ; 2024.09.07-2024.09.06   4575 15.1% x     374  20256    286 w/wolkowa_natalxja_stepanowna kosturiaballadadocx
# ; 2024.09.08-2024.09.07  20457 67.4% x  434577      1  43816 r/raba_b_i molitva-112

function mkLn() {
#   if(hitP-9>0){
  if(hitP+0){
    aMig[++nMig]=datS"_"timS" "datJ sprintf("%7s %s %s %s %s",hitP,id_P,namP,moto,fNam)
    if(maxD<datJ)maxD=datJ
    dGap=datS"-"datJ
    aDat[dGap]++
    if(aHit[dGap]-hitP<0)aHit[dGap]=hitP
    numS++
  }
}

{                                                 #  // -=- основной блок скрипта begs
  if(FNR==1){         #  секция завершения работ с одним файлом и подготовки к работе со следущим
    if(NR!=1)mkLn()                         #  оценка данных обработанной статистики, отбор годных
    step=0        #  0-владелец, 1-дата обновления, 2-id раздела, 3-разбор строк таблиц статистики
    fNam=split(FILENAME,aj,"\\")                #  NEW/NEXT входной файл as-is (с полным путём)
    fNam=split(aj[fNam],aj,".")               #  файл: чистое nam.ext (like "0~0.stat.htm")
    fNam=aj[1]                                #  fNam чистое имя (like "0~0" in "0~0.stat.htm")
    hitP=0                                        #  выясняется в stat
    id_P=substr(fNam,1,1)"/"substr(fNam,3)        #  - "" -- "" -- "" -
    namP="\"\""                                   #  - "" -- "" -- "" -
    moto="\"\""                                   #  - "" -- "" -- "" -
    inTab=0                                       #  сначала - мы НЕ "в таблице"
    numT=0                                        #  счётчик таблиц в файле статистики
    numR=0                                        #  счётчик строк в текущей таблице
    selN=0                                        #  счётчик ячеекк в строке таблицы
    fNum++
    if(fNum%100==0) print(sprintf(": %4s",fNum/100))
    else if(fNum%10)printf(".")
    else            printf(":")                   #  оживляж...
  }
  gsub(/(&nbsp;)+|\xA0+|[\0-\31]+/," ",$0) #  цепочки "&nbsp;" и прочих "пробелов" -> " " (пробел)
  if(step==0) {                                   #  ищем (для контроля) ФИО автора
# <h3>Статистика раздела &quot;<a href=./>Влад</a>&quot;:</h3>
    if (match($0,/<h3>Статистика раздела \&quot;<a href=\.\/>(.*)<\/a>\&quot;:<\/h3>/,aj)) {
      if(aj[1]==""){                            #  errS="] step."step" (NO nick in: " fNam " )"
        nextfile
      }else namP=pack4cmd(aj[1])
      step=5                                      #  проверка ОК
    }
  }else if(step==5){                              #  вычленеие даты обновления статистики
# <center><h2>Журнал &quot;Самиздат&quot;: Живопись</h2>
    if (match($0,/<center><h2>Журнал \&quot;Самиздат\&quot;: (.*)<\/h2>/,aj)) {
      moto=pack4cmd(aj[1])
      step=1                                      #  проверка ОК
    }
  }else if(step==1){                              #  вычленеие даты обновления статистики
    if(match($0,\
/<li><i>Статистика рассчитывается .+\. \(.+ (...) +([0-9]+) (..:..:..) (20[0-9][0-9])\)<\/i>/\
,aj)){
      if(length(aj[2])==1) aj[2]="0"aj[2]   #  причешем первые дни месяца "1" -> "01"
      ticS=mktime(aj[4]" "mNum[aj[1]]" "aj[2]" 12 00 00") # тики на 12 часов даты статистики
      datS=aj[4]"."mNum[aj[1]]"."aj[2]      #  дата обновления статистики
      timS=aj[3]                                #  время обновления статистики
      step++                                      #  дату статистики оптичили
    }
  }else if(step==2){            #  ищем authID (!должен быть и совпадать с префиксом имени файла)
# [<a href=http://top.mail.ru/pages?id=77427&period=0&date=2018-10-02&filter_type=0
# &filter=n/nosow_w_w&pp=20&gender=0&agegroup=0>по дням</a>]
    if (match($0,/\[<a href=http.+&filter=([0-9a-z]\/[\-0-9a-z_]+)&pp=.+>по дням<\/a>]/,aj)) {
      if(id_P!=aj[1]){  #  это ПОЛНЫЙ криминал!# errS="] step."step" ("aj[1]" != fNam:"fNam")"
        nextfile
      }
      step++                                      #  проверка ОК
    }
  }else if(step==3){                #  таблицы статистики, просмотр строк, сборка данных в ячейках
    if($0=="<!--------- Подножие ------------------------------->"){  #  разбор закончен
      step++
      nextfile
    }
    if(inTab){                      #  Мы ВНУТРИ таблицы, собираем строки таблицы с хитами текстов
      buf0=buf0" "$0                              #  gain inpLines to buf0, then check contents
      while((match(buf0,/<tr ?[^>]*>/))||(int0=index(buf0,"</tr"))){ # seek <tr .. </tr for tabRow
        if(RSTART){                               #  new/next line begs
          numR++                                  #  счётчик строк
          buf0=substr(buf0,RSTART+RLENGTH)  #  del всё до начала строки таблицы <tr>, в т.ч. и его
        }
        if(int0=index(buf0,"</tr")){              #  this line ends
          getSels(substr(buf0,1,int0-1))          #  tabl_row -> arrow:sell_values
          buf0=substr(buf0,int0+4)              #  убрали эту строку из буфера и окультуриваем...
          id_T=aSel[0]                        #  имя+расшир файла с текстом (или "./" для раздела)
          namT=aSel[1]                    #  пока фактическое (as-is) название текста в статистике
#           if(minT-aSel[3]>0)nextfile # в ЭТОЙ строке за "12мес" МЕНЬШЕ границы, дальше неинтересно
          if((numT==1)&&(numR==2)){               #  хиты по разделу (спец.обслуживание)
            hitP=aSel[3]                          #  хиты раздела за "12мес" ЕСЛИ нет в aHits
            nextfile
          }
        }
      }
      if(int0=index(buf0,"</table")){             #  this tabl ends
        buf0=substr(buf0,int0+4)                  #  update buf0
        inTab=0
      }
    }else{                                        #  ищем начало таблицы
      if(int0=index($0\
,"<table border=1 cellspacing=0 cellpadding=0><tr><td><td colspan=2><b>Итого</b></td>")){
        numT++                                    #  new table
        numR=1                #  певая строка каждой таблицы - календарь хитов статистики раздела
        buf0=substr($0,int0+80)
        if(numT==1){                              #  1-st table 1-st row -> get col-dates & so-on
          match(buf0,/<tr[^>]*>(.+)<\/tr[^>]*>/,aj) #  собственно строка с календарём
          getSels(aj[1])                        #  но самую первую такую - разберём-с
          tic0=ticS           #  и привяжем дату к нулевому (самому левому) дню посуточных данных
          while(strftime("%d",tic0)!=aSel[16])tic0=tic0-86400 #  сдвинем стат.дату к нулевому дню
          datJ=strftime("%Y.%m.%d",tic0-86400)    #  полная дата первого дня в интервале 30 дней
        }
        inTab=1                                   #  мы ВНУТРИ таблицы
        buf0=""                                   #  буфер чист!
      }
    }
  }
}                                                 #  // -=- основной блок скрипта ends

function getSels(rowLn){                #  разделение строки таблицы статистики на массив значений
  selN=0                                          #  sells count
  split("",aSel)
  aSel[0]=""
  while(match(rowLn,/<td[^>]*>/)){                #  это объявление ячейки
    selN++                  #  0.1-имя/ссылка; хиты: 2-всего, 3-12мес, 4..15-заМес, 16..77-заСутки
    rowLn=substr(rowLn,RSTART+RLENGTH)            #  выкусим объявление ячейки
    f3n2=index(rowLn,"</td")                      #  это конец ячейки
    f3s2=substr(rowLn,1,f3n2-1)               #  это сама ячейка (с возможными внутренними тегами)
    if(selN==1){                            #  в ПЕРВОЙ ячейке - название текста и ссылка на него
      match(f3s2,/<a href=([^>]+)>(.*)<\/a>/,f3a1)  #  выцепим и разложим:
      aSel[1]=f3a1[2]                             #  название текста
      aSel[0]=f3a1[1]                             #  ссылка на текст: name.shtml
    }else aSel[selN]=rmTags(f3s2) #  в ПРОЧИХ ячейках - только значение ячейки, очищенное от тегов
    rowLn=substr(rowLn,f3n2)                      #  выкусим оптиченную ячейку
  }
  if(selN==77)return                              #  row HAVE had 77 sells
  nextfile                                        #  битая таблица == битый файл
}

function rmTags(f2s1){                            #  удаление ВСЕХ тегов в литерале
  while(match(f2s1,/<\/?[a-zA-Z][1-6a-zA-Z]?[a-zA-Z]*[ \/]?[^>]*>/))
      f2s1=substr(f2s1,1,RSTART-1) substr(f2s1,RSTART+RLENGTH)
  return(f2s1)
}

function pack4cmd(s0){ #  упаковка строки для CMD; s0 - вх.строка; вых. - в двойных кавычках
#  Меняутся на HTML-эквивалент символ: "•" на "&#x95;"
#  + меняются на HTML-эквиваленты символы: "&", "%" и '"' /двойные кавычки/
#  + левые символы в диапазоне 0-31 таблицы ASCII, пробел и неразрывный_пробел меняются на "•"
#  + эти символы /"•"/ - оставляются НЕ БОЛЬШЕ одного ПОДРЯД и только ВНУТРИ строки
#  nvv, 2024.06.03
  while(n1=index(s0,"•") ){s0=substr(s0,1,n1-1)"&#x95;"substr(s0,n1+1)} #  '•' -> '&#x95;'
  while(n1=index(s0,"%") ){s0=substr(s0,1,n1-1)"&#x25;"substr(s0,n1+1)} #  '%' -> '&#x25;'
  while(n1=index(s0,"\"")){s0=substr(s0,1,n1-1)"&quot;"substr(s0,n1+1)} #  '"' -> '&quot;'
  gsub(/[\x0-\x9\xB\xC\xE-\x1F \xA0]+/,"•",s0) #  замена ЦЕПОЧЕК пробелов/левых_символов на "•"
  gsub(/^•/,"",s0)                              #  удаление лидирующего пробела
  gsub(/•$/,"",s0)                              #  удаление завершающего пробела
  return ("\""s0"\"")                           #  возвращается свёрнутая строка
}

END{                                              #  отстрелялись; ну почти...
  if(errS!=""){
    print("")
    print("] "errS)                               #  есть проблем-с => подудим
    exit 1                                        #  и на выход с вещами
  }
  mkLn()
  if(fNum%100)print("")
  else print(" = "fNum)

  jDat=strftime("%Y.%m.%d")
  jLst=wDir maxD".hidn.addS"
  split("",aSel)
  nSel=0
  for(j0=1;j0<=nMig;j0++){                        #  вычленим записи со свежей datJ
    split(aMig[j0],aj)
#     if(aj[2]==maxD)aSel[++nSel]=aMig[j0]
    aSel[++nSel]=aMig[j0]
  }
  asort(aSel)
  j1=fNum":allS "nSel":good "maxD":dEnd "jDat":done"
  print("; stat "j1)                                                                  > jLst
# ; 2024.09.07-2024.09.06   4575 15.1% x     374  20256    286 w/wolkowa_natalxja_stepanowna kosturiaballadadocx
  for(dGap in aDat){
    if(aHit[dGap])j0=aHit[dGap]
    else          j0=0
    aLst[++nLst]="; "dGap sprintf("%5s %4.1f%% %5s",aDat[dGap],aDat[dGap]*100/numS,j0)
  }
  asort(aLst)
  print("; upDat_datS  1-st_day  numS  %%    hitP") > jLst
  for(j0=1;j0<=nLst;j0++)print(aLst[j0])            > jLst
  print(";     datS_timS.1    datJ.2    hitP.3 id_P.4 \"namP\".5 \"moto\".6 id_F.7")  > jLst
  for(j0=1;j0<=nSel;j0++)print(aSel[j0])            > jLst
  print(j1,systime()-tIni":sec")
}

    Имя файла скрипта: "1hidn.cmd" V-текст скрипта-V
- - - - - - - - -
@if not defined pMod @echo off
set nJob=addS
echo %date% %time:~0,8% %nJob% Begs
:: 0addS.cmd - сборка дополнительного списка гггг.мм.дд.hidn.addS разделов-невидипок по спискам форм
:: 0. нужны списки: _lost.addF /что качать/ и *.~.mig.bStat (можно строить наше новое)
:: 1. проверяется наличность и окружение
:: 2. скачиваются статистики скрытников
:: 3. строится список "datJ.stat,aadS" с пригодными статистиками 200 или более хитов за "12мес"
:: 4. обновляется U:\Jobs\1hidn.err - недоступные статистики /для контроля ситуации/

::  основной и резервный URL Самиздата (желательно работать с резервом)
if NOT defined siUrl if exist \siUrl.budclub set siUrl=budclub.ru
if NOT defined siUrl set siUrl=samlib.ru

:: 2024.08.12, nvv, вместо вопроса или работа, или выход по "уже есть"
:: история изменений в подвале скрипта!

:: основные сеты и прочая подготовка к работе...
set jDat=%date%
set errInf=
::  wrks - общее время работы процесса (пуск общего таймера)
for /F %%A in ('gawk.exe "BEGIN{print(systime());exit}"') do set wrks=%%A
::  aScr - скрипт вычленения годных потеряшек по страницам их статистик
set aScr=%~dpn0.awk
if NOT exist %aScr% set errInf=NO %aScr% found & goto errExit
::  wDir - общее рабочее место
set wDir=%~d0\Jobs
::  jDir - место для оперативных файлов
set jDir=%wDir%\_%nJob%
::  zDir - общий подкаталог для посуточных подкаталогов с итоговыми списками
set zDir=%~d0\Stor\wOld\%jDat%
::  jRpt - общий отчёт с итоговыми сводками процессов
set jRpt=%wDir%\_siTop.#
::  jErr - перечень отсутствующих статистик разделов
set jErr=%wDir%\%~n0.err
echo. >nul 2>%jErr%
::  nErr - счётчик отсутствующих статистик разделов
set nErr=0
::  dnLd - счётчик скачанного ([пере]запустим "таймер" ratW)
set dnLd=0
::  wGetSiz - размер скачанного файла (default 1b минимум)
set wGetSiz=1
:: проверить/создать нужные структуры для работы (оперативные площадки)
if NOT exist %jDir%\*.* (
  mkDir %jDir%
  if errorLevel 1 set errInf=fail mkDir %jDir% & goto errExit
)
if NOT exist %zDir%\*.* (
  mkDir %zDir%
  if errorLevel 1 set errInf=fail mkDir %zDir% & goto errExit
)
:: для работы нужно наличие *.~.lst.bStat /ПОЧТИ готовый расчёт/ из имени берём datJ
:: htm jLst
:: non any  качаем
:: old any чистим+качаем
:: cur non/older качаем
:: cur newer -- нечего делать, всё уже
:: для работы нужен список потеряшек _lost.addF
set inFl=%wDir%\_lost.addF
if NOT exist %inFl% set errInf=NO %inFl% found & goto errExit
set tmp0=
for %%A in ( %wDir%\*.hidn.%nJob% ) do set tmp0=%%~tA
if NOT defined tmp0 goto chkDl
if %tmp0:~0,10% == %jDat% (
  echo == all is done today already
  goto :eof
)
:doJob сегодня ничего пока не сделано... а старое есть/?/ проверим-с
set tmp0=
for %%A in ( %jDir%\*.stat.htm ) do if NOT defined tmp0 call :chkDat %%~tA
if NOT defined tmp0 goto chkDl
if exist %jDir%\*.stat.htm (
  erase /F /Q %jDir%\*.stat.htm
  if errorLevel 1 set errInf=fail erase %jDir%\*.stat.htm & goto nExit
)
:: и устаревший итоговый список туда же /нафик/
erase /F /Q %wDir%\*.hidn.%nJob%
if errorLevel 1 set errInf=fail erase *.hidn.%nJob% & goto nExit

rem ; 18:form 7689:pags 1536388:txts 104325:auth 1927:hidn 2023.07.03:done

:chkDl выясним имеющийся расклад по потеряшкам после обработки /процессом rAddF.cmd/ форм
for /F "tokens=1-9,*" %%A in (
  ' gawk.exe "{if(match($2,/^18:form$/))print($3,$4,$5,$6);exit}" %inFl% '
) do (
  set pags=%%A
  set txts=%%B
  set auth=%%C
  set hidn=%%D
)
:: почистим, вычленив цифры
set pags=%pags:~0,-5%
set txts=%txts:~0,-5%
set auth=%auth:~0,-5%
set hidn=%hidn:~0,-5%
echo = %pags%.pags %txts%.txts %auth%.auth %hidn%.hidn.stats dnLd...

:: ок, скачаем статистики ВСЕХ этих /скрытых/ разделов
set cNum=0
set dnLd=0
::  ratW - темп скачивания
for /F %%J in ('gawk.exe "BEGIN{print(systime());exit}"') do set ratW=%%J
:: скачивание недостающего
for /F "tokens=*" %%A in (%inFl%) do if NOT defined errInf call :dLit %%A
if defined errInf goto :eof
:: вычислим темп скачивания ratW
if %dnLd% == 0 (
  set ratW=0
) else (
  for /F %%A in (
    ' gawk.exe "BEGIN{print(sprintf(\"%%3.2f\",(systime()-%ratW%)/%dnLd%));exit}" ' 
  ) do set ratW=%%A
)
:: ок, статистики у нас
echo = %dnLd%:dnLd.stats %ratW%:ratW looking for good id_P
:: вычленим годные/нужные для расчёта /в список %datJ%.stat.add2h/
gawk.exe -f %aScr% %jDir%\*.stat.htm
if NOT %errorLevel% == 0 set errInf=%aScr% problem in %jDir%\*.stat.htm & goto nExit
rem ; stat 1940:allS 20:good 2023.06.28:dEnd 41:tNum 2023.07.03:done
rem ; stat 1939:allS 1112:good 2023.07.19:dEnd 2023.07.23:done
set jLst=
for %%A in ( %wDir%\*.hidn.%nJob% ) do set jLst=%%A
if NOT defined jLst set errInf=AWK fails make *.hidn.%nJob% & goto nExit
for /F "tokens=1-9,*" %%A in (
  ' gawk.exe "{if(match($2,/^stat$/))print($3,$4,$5);exit}" %jLst% '
) do (
  set allS=%%A
  set good=%%B
  set dEnd=%%C
)
:: почистим, вычленив цифры
set allS=%allS:~0,-5%
set good=%good:~0,-5%
set dEnd=%dEnd:~0,-5%
echo = %allS%.allS %good%.good %dEnd%.dEnd

:: остановим общий "таймер", : преобразуем секунды в время работы (в обычном формате "чч:мм:сс")
for /F %%A in ('gawk.exe "BEGIN{print(strftime(\"%%H:%%M:%%S\",systime()-%wrks%+46800));exit}"') do set wrks=%%A

set tmp0=;0S add2 ^
%pags%.pags ^
%txts%.txts ^
%auth%.auth ^
%hidn%.hidn ^
%good%.good ^
%dnLd%:dnLd ^
%nErr%:nErr ^
%dEnd%:dEnd ^
%ratW%~ratW ^
%jDat%:done ^
%wrks%~wrks ^
%time:~0,5%
echo %tmp0% >> %jLst%
echo %tmp0% >> %jRpt%
echo = Ok %hidn%:hidn %good%:good %dnLd%:dnLd %ratW%~ratW
:: скинем результаты в хранилище
copy /y /b %jLst% %zDir%\ > nul
if errorLevel 1 set errInf=fail copy %jLst% TO %zDir% & goto nExit
:: подудим где нада "готово-с!"
set itog=%jLst%

:nExit
if defined errInf if NOT defined errF echo ! %errInf%
echo %date% %time:~0,8% %~nx0 Ends %nErr%:nErr
goto :eof

rem ;txTot id_P
rem    25 k/koroljuk_m_a

:dLit %%A скачивание статистик по id_P {like e/etno} из списка lost.add2h
set id_P=%2
set wFil=%id_P%
set wFil=%jDir%\%wFil:~0,1%~%wFil:~2%.stat.htm
if exist %wFil% (
  call :show ~
  goto :eof
)
call :show .
set wUrl=%siUrl%/%id_P%/stat.shtml
call wGetUrl2fil.cmd %wUrl% %wFil%
if %wGetErr% == 0 goto :eof
:: проблема?
if %wGetErr% == 1 (
  if exist %wFil% erase %wFil%
  echo %id_P% >> %jErr%
  set /A nErr+=1
  set errInf=
  goto :eof
)
set errInf=no web{SI} {%wUrl%}
goto :eof

:show оживляж скачивания статистик
set /a cNum+=1
set mark=%1
rem if exist %wFil% set mark=~
if %cNum:~-1% == 0 set mark=%cNum:~-2,1%
gawk.exe "BEGIN{printf(\"%mark%\");exit}"
rem if NOT "%cNum:~-2%" == "00" if NOT "%cNum:~-2%" == "50" goto :eof
if NOT "%cNum:~-2%" == "00" goto :eof
:: по 50 отметок на строку
set tmp0=    %cNum%
set tmp0=%tmp0:~-5,3%
gawk.exe "BEGIN{printf(strftime(\"%tmp0% %%H:%%M:%%S\n\",systime()-%ratW%,-1));exit}"
goto :eof

:chkDat %%~tA "сегодня"==ОК, иначе - старьё-с
if %1 == %jDat% goto :eof
set tmp0=%1
goto :eof

:errExit реакция на проблему: в пакете - выход
if defined pMod goto :eof
:: автономно - на экран + прекращение работы
echo %errInf%
exit

:: 2023.06.28, nvv, сознано на основе aHits.cmd от 2023.05.30
:: 2023.08.12, nvv, last upDates
:: 2024.02.05, nvv, исправлена обработка отсутствия сети или файла в ней
:: 2024.02.23, nvv, исправлена ошибка НЕ переключения по переменной siUrl
:: 2024.03.03, nvv, исправлена ошибка в п/п скачивания статистик
::   + работа отвязана от даты в bStat + мелкие изменения в логике
:: 2024.03.17, nvv, no toDay`s job == no toDay`s wait
:: 2024.06.24, nvv, errs count added and file: U:\Jobs\1hidn.err

    Имя файла скрипта: "aHits.awk" V-текст скрипта-V
- - - - - - - - -
BEGIN{  #  aHits.awk - просмотр локальных страниц рейтинга и создание списка разделов с хитами
#   add2="U:\\Jobs\\2024.06.02.hidn.addS"         #  если вызов НЕ из CMD

# 2024.10.02, nvv, иначе ищем h30k и n30k +a30k /после добавки add2, а НЕ до/
#  ! прочая история в подвале

# В процессе: считывается дата обновления рейтинга, и количество страница рейтинга хитов
# Источник - рейтинг "по хитам": /rating/hits/ может использоваться самостоятельно.
# Для правильной нумерации мест разделов, ИМЯ входных файлов должно начинаться с ЧИСЛА
# (номер страницы рейтинга,например: 0025.html). Расширение - любое.
# Причём, итоговые списки (пере)создаются РЯДОМ (jDir) с входными файлами:
# - fOut=jDir"]aHits.lst" # основной список - OK_элементы ]aHits.lst
# - fBad=jDir"]aHits.bad" # список брака - BAD_элементы ]aHits.bad
# + выдача на StdUot: hDat,pMax,xNam,xNum,xPas,hMax,h30k,hTot
# hitP - par.hits - хиты раздела за "год"
# numP - par.number - место раздела в рейтинге СИ по посещаемости (1..10000) первые 10k
# sizK - общий объём (в kb) текстов раздела
# sizN - общее количество текстов в разделе
# id_P - partition (par.) - раздел СИ (like: n/nosow_w_w)
# namP - "par.name" - название раздела (псевдоним автора, like: "Влад" или "Уксус•Сергей")

# НЕштат (НЕ рейтинг или НЕ в порядке)  выдача на StdUot:
# "] Hole or no data ("step" lines) in file:" fNam)
# "] DifDates;" hDat "!=" cYea"."cMth"."cDay "! in file:" fNam)
# "] DifPageNums;" pMax "!=" pNum "! in file:" fNam)
# с немедленным завершением работы

# в fOut: исправные записи с хитами разделов за "12мес":
#   hitP  numP    sizK   sizN id_P        "namP" "sigP"
#  24620   192   14754     25 n/nosow_w_w "Влад" "nvv_Lazy_Tiger"
# 901899     1     931      5 d/dront_n "Дронт•Николай" "Записки•о•том,•чего•не•было"
#  18625   385   18053     29 n/nosow_w_w "Влад" "nvv_Lazy_Tiger"

# в fBad: записи с проблемами:
# ] Err:2 no nick:    829  8443 u/ulybin_w_w ""
# ] Err:1 no text:  44158   147 s/sherbakow_a "Щербаков•Александр"

  if(ARGV[1]=="")exit                           #  защита от случайного пуска
#   j1=split(ARGV[1],aj,"\\")
  for(str2 in ENVIRON){                   #  ! регистр букв в имени переменной может быть любой
    if(tolower(str2)=="wdir")wDir=ENVIRON[str2]"\\" #  место для итогового списка aHits
    if(tolower(str2)=="add2")add2=ENVIRON[str2] #  место для итогового списка aHits
  }
# ;     datS_timS.1    datJ.2    hitP.3 id_P.4 "namP".5 "moto".6 id_F.7
# 2023.07.20_01:54:05 2023.07.19   9073 n/neon13 "Neon13" "Авторский" n~neon13
  if(add2=="")add2="U:\\Jobs\\2024.09.30.hidn.addS"
  nAdd=0
  while((getline line<add2)>0){                 #  список потеряшек
    split(line,aj)
    if(match(aj[1],/^20/)){                     #  строка с данными скрытого раздела
      j0=1000000-aj[3]
      aAdd[++nAdd]=sprintf("%7s%7s%9s%7s",j0,0,0,1)" "aj[4]" "aj[5] #  это на включение в итог
      aIdA[aj[5]]=nAdd                      #  это для контроля отсутствия включаемого в итоге
    }
  }
  close(add2)                                   #  всё/не_всё, - старый список тогось
  add2=0
# 500779 1 46664 126 g/goncharowa_g_d "Гончарова•Галина•Дмитриевна" "Писатель•должен•быть•талантлив•и•дьявольски•трудолюбив"
#       3 105072       0      0 d/dura "Не•Писатель" 
# ; hitP.1 numP.2 sizK.3 sizN.4 id_P.5 "namP".6 "moto".6 
    
#   if(j1==1)jDir=".\\"                           # иесто для результатов ТАМ ЖЕ, где исходные файлы
#   else for(j2=1;j1-j2>0;j2++)jDir=jDir aj[j2]"\\"
#   fBad=jDir"]aHits.bad"                           # список брака - BAD_элементы ]aHits.bad
  jTic=systime()                                #  ДВЕ проверки: дата(step==-1) + полнота(==0)
  jYea=strftime("%Y",jTic)
  jMth=strftime("%m",jTic)
  xNam=0                                        #  счёчик разделов (записей) без ФИО
  xNum=0                #  счёчик разделов без наполнения (без объёмя и кол-ва файлов раздела)
  xPas=0                                        #  счёчик разделов "всего OK"
  hTot=0                                        #  счёчик "hits total"
  hMax=0                                        #  хиты 30k разделов "макс"
  h30k=0                                        #  хиты 30k разделов "мин"
  n30k=0                                  #  номер замыкающего раздела в aHits с хитами == h30k
  a30k=0                    #  число скрытых разделов в первых 30k разделов
  pMax=""                                       #  номер страницы рейтинга (в имени файлов)
}

{                                               #  // -=- основной блок скрипта
  if(FNR==1){       #  секция завершения работ с одним файлом и подготовки к работе со следущим
    if(NR!=1)chkSteps()                         #  страница пройдена; она в порядке?
    fNam=FILENAME                               #  U:\Jobs\#aHits\0001.hits.htm
    p100=split(FILENAME,aj,"\\") # NEW/NEXT входной файл разделим на подкаталоги и имя.расширение
    p100=split(aj[p100],aj,".")             #  имя.расширение входного файла разделим на части
    p100=(aj[1]-1)*100  #  p100 чистые сотни (начиная с нуля, like: "1400" для "0015.hits.htm")
    step=-1                                     #  -1 == date, 0 - nPgs, 1..100 dataLine
    fNum++
    if(fNum%100==0) print(sprintf(": %4s",fNum/100))
    else if(fNum%10)printf(".")
    else            printf(":")                 #  оживляж...
  }
# <b>СТАТИСТИКА за 22/11:</b>
  if (step==-1) {                               #  считывание обязательной ДАТЫ рейтига
    if(match($0,/^<b>СТАТИСТИКА за ([0-3][0-9])\/([01][0-9]):<\/b>$/,aj)){  #  30 09 (30/09)
      cMth=aj[2]
      cDay=aj[1]
      step++
    }
  }
# <center><b>Страниц (970):</b>  <b>1</b> <a href=
  if (step==0) {                                #  проверка ПОЛНОТЫ статистики
    if(match($0,/^<center><b>Страниц \(([0-9]+)\):<\/b> /,a2)){
      pNum=a2[1]
      step++
    }
  }
# <DL><b>44158</b> <a href=/s/sherbakow_a/>Щербаков Александр</a> "Творчество как бы"<DD><font color=#555555><i>Почитал ГкН, Лунного скульптора, Игру... и зачесались ручки как бы... что получится - будет видно)</i></font></DD></DL>
# <DL><b>43514</b> <a href=/a/aizmash/>Aizmash</a> "aizmash" (1603k,5)</DL>
# <DL><b>721</b> <a href=/g/glinka_i_s/></a> "Ярина" (924k,16)</DL>
# <DL><b>593</b> <a href=/a/amelichewa_a_a/>Амеличева Алиса Анатольевна</a> "" (4k,23)</DL>

  if (step+0>0) {                               #  извлечение хитов, authID и ФИО(псевдонима)
    numP=p100+step
    if (match($0,/<b>([0-9]+)<\/b> <a href=\/(.)\/(.+)\/>(.*)<\/a>/,aj)){ #  это обязательно!
      hitP=aj[1]                                #  хиты раздела за "12мес"
      id_P=aj[2]"/"aj[3]                        #  ID раздела
      if(aj[4]==""){                            #  no: ФИО/псевдоним/nick
        xNam++                                  #  errInf hitP numP id_P
        namP="\"\""                             #  ВМЕСТО ФИО/ник_владельца - спец.отметка
      }else{
        namP=pack4cmd(aj[4])                    #  ФИО/ник_владельца раздела
      }
      if(match($0,/<\/a> "(.*)" \(([0-9]+)k,([0-9]+)\)/,a2)){ #  (3776k,10) это - если не пусто
        xPas++
        moto=pack4cmd(a2[1])                    #  девиз раздела (может отсутствовать)
        sizK=a2[2]                              #  общий объём текстов в разделе
        sizN=a2[3]                              #  кол-во текстов в разделе
      } else {                                  #  пусто (нет наполнения раздела)
        xNum++                                  #  список брака - BAD_элементы ]aHits.bad
        moto=""
        sizK=0
        sizN=0
      }
      aHit[++nHit]=sprintf("%7s%7s%9s%7s",1000000-hitP,numP,sizK,sizN)" "id_P" "namP" "moto
      aIdH[id_P]=numP
      hTot=hTot+hitP                            #  счёчик "hits total"
#       if(!h30k){                                #  хиты 30.000-го раздела выяснены?
#         if(numP==30000)h30k=hitP                #  хиты 30-и тысячного раздела
#       }
      if(hMax-hitP<0)hMax=hitP                  #  хиты - "макс"
      step++
    }
  }
}

function pack4cmd(s0){    #  упаковка строки для CMD; s0 - вх.строка; вых. - в двойных кавычках
#  Меняутся на HTML-эквивалент символ: "•" на "&#x95;"
#  + меняются на HTML-эквиваленты символы: "&", "%" и '"' /двойные кавычки/
#  + левые символы в диапазоне 0-31 таблицы ASCII, пробел и неразрывный_пробел меняются на "•"
#  + эти символы /"•"/ - оставляются НЕ БОЛЬШЕ одного ПОДРЯД и только ВНУТРИ строки
#  nvv, 2024.06.03
  while(n1=index(s0,"•") ){s0=substr(s0,1,n1-1)"&#x95;"substr(s0,n1+1)} #  '•' -> '&#x95;'
  while(n1=index(s0,"%") ){s0=substr(s0,1,n1-1)"&#x25;"substr(s0,n1+1)} #  '%' -> '&#x25;'
  while(n1=index(s0,"\"")){s0=substr(s0,1,n1-1)"&quot;"substr(s0,n1+1)} #  '"' -> '&quot;'
  gsub(/[\x0-\x9\xB\xC\xE-\x1F \xA0]+/,"•",s0) #  замена ЦЕПОЧЕК пробелов/левых_символов на "•"
  gsub(/^•/,"",s0)                              #  удаление лидирующего пробела
  gsub(/•$/,"",s0)                              #  удаление завершающего пробела
  return ("\""s0"\"")                           #  возвращается свёрнутая строка
}

function chkSteps() {                           #  страница пройдена; она в порядке?
  if((step!=101)&&(pNum*100!=p100+100)){ #количество записей на странице штатное? если НЕ последняя
    print pNum*100,p100
    print("] Hole or no data ("step-1" lines) in file:" fNam) # нет! (мало записей)
    exit 3
  }else{
    if(hDat==""){                               #  это ПЕРВЫЙ файл страницы с хитами
      cYea=jYea                     #  отпределимся с датой статистики (относительно "сегодня")
      if(jMth!=cMth) if(cMht==12)cYea-- # если месяц иной + предыдущий - декабрь => прошлый год
      hDat=cYea"."cMth"."cDay                   #  полная дата для: "СТАТИСТИКА за дд/мм"
    }else if(hDat!=cYea"."cMth"."cDay){     #  это второй и последующие файлы, даты совпабают?
      print("] DifDates: " hDat "!=" cYea"."cMth"."cDay " in file:" fNam) # нет!
      exit 1
    }
    if(pMax=="")pMax=pNum #  это ПЕРВЫЙ файл с хитами, запомним общее кол-во страниц в рейтинге
    else if(pMax!=pNum){  #  это вторай и последующие файлы "с хитами", это кол-во тоже самое?
      print("] DifPageNums: " pMax "!=" pNum " in file:" fNam)  # нет!
      exit 2
    }
  }
}
# 2018.10.25, nvv, created
# ...
# 2019.01.02, nvv, update
# 2019.02.05, nvv, ФИО/nick упаковывается + новое поле size,num раздела (like "10496k,32")
# 2019.04.19, nvv, added hTot - summ for all hits of 100 partitions, paged
# 2019.07.10, nvv, мелкая косметика
# 2019.07.27, nvv, добавлено поле "девиз раздела"
# +наполнение раздела - теперь это два поля(объём/кол-во) +поля слегка переставлены
# 2020.01.27, nvv, мелкая косметика
# 2020.03.13, nvv, переделано и обустроено всё потребное (слегка-с новая концепция)
# 2020.08.21, nvv, исправлена мелкая, но неприятная ошибка отбраковки разделов с пустым девизом
# 2020.09.10, nvv, нештат НЕ исключается из итогового списка, НО кол-во у них всегда(!) 0
#   + соответственно, список "плохого" (fBad) НЕ создаётся
# 2020.11.01, nvv, последняя страница рейтинга не обязана иметь 100 записей. ;)
#   + на прочих - показывает точное число (без +1)
# 2021.05.02, nvv, переименовано (убран префикс "siTip-")
# 2023.07.23, nvv, переделано для включения потеряшек add2 в aHits
# 2024.05.09, nvv, param:n30k added /last h30k.hits line number in aHits/
# 2024.06.05, nvv, п/п pack -> pack4cmd
# 2024.09.08, nvv, место под sizK увеличено до 99Gb (8+1 знако-место)

END{
  if(ARGV[1]==""){                              #  защита от случайного пуска
    print("NO in file(s)")
    exit -1
  }
  if(fNum%100)print("")
  else print(" = "fNum)
  chkSteps()                                    #  страница пройдена; она в порядке?
  for(id_P in aIdA)if(!(id_P in aIdH)){
    aHit[++nHit]=aAdd[aIdA[id_P]]
    add2++
  }
  fOut=wDir hDat".aHits"                        #  основной список - OK_элементы ]aHits.lst
  jDat=strftime("%Y.%m.%d")
# ;1A hits 5:xNam 451:xNum 104642:xPas 2023.07.09:hDat 507217:hMax 1051:hPag 15:add2 1086:dnLd 0.17~ratW 2023.07.11:done 03:12:17~wrks 15:02
# ; aHit 5:xNum 451:xNum 104642:xPas 507217:hMax 1051:hPag 15:add2 381:h30k 42411880:hTot 2023.07.09:hDat 2023.07.14:done
  asort(aHit)
  for(j0=1;j0<=nHit;j0++){
    j1=1000000-substr(aHit[j0],1,7)
    print(sprintf("%7s",j1),substr(aHit[j0],9)) > fOut
    if(j0==30000)h30k=j1              #  запись 30k
    if(!n30k){
      if(h30k-j1>0){
        n30k=j0-1      #  место последнего раздела с хитами h30k
      }else if(substr(aHit[j0],8,7)+0==0){  #  это скрытый раздел
        a30k++                        #  сосчитаем-с
      }
    }
  }                                             #  общая сводка работы с рейтингом "по хитам"
  print("; hitP.1 numP.2 sizK.3 sizN.4 id_P.5 \"namP\".6 \"moto\".6")     > fOut
  print("; aHit "xNam":xNam",xNum":xNum",xPas":xPas",hMax":hMax",pMax":hPag",add2":add2"\
,n30k":n30k",h30k":h30k",a30k":a30k",hTot":hTot",hDat":hDat",jDat":done ") >fOut # общая сводка работы с рейтингом "по хитам"
  print("; aHit "hDat,pMax":pMax",xPas":xPas "add2":add2 "n30k":n30k "h30k":h30k "a30k":a30k")
}

    Имя файла скрипта: "aHits.cmd" V-текст скрипта-V
- - - - - - - - -
@if not defined pMod @echo off
set nJob=aHits
echo %date% %time:~0,8% %nJob% Begs
:: aHits.cmd - сборка полного списка авторов СИ по рейтнгу хитов
::  основной и резервный URL Самиздата (желательно работать с резервом)
if NOT defined siUrl if exist \siUrl.budclub set siUrl=budclub.ru
if NOT defined siUrl set siUrl=samlib.ru
:: %time% - HH:MM:SS,tt HH<=9 -> "HH" == " H" лидирующий пробел для часа меньше 10
:: %date% - YYYY.mm.dd

:: 2024.10.13, nvv, minor cosmetic + ini wait == 10 min
:: история изменений в подвале скрипта!

:: основные сеты и прочая подготовка к работе...
set jDat=%date%
set errInf=
set jSiD=%jDat:~8%/%jDat:~5,2%
::  wrks - общее время работы процесса (пуск общего таймера)
for /F %%A in ('gawk.exe "BEGIN{print(systime());exit}"') do set wrks=%%A
::  aScr - скрипт обработки страниц рейтинга "по хитам"
set aScr=%~dpn0.awk
if NOT exist %aScr% set errInf=! NO %aScr% found & goto errExit
::  wDir - общее рабочее место
set wDir=%~d0\Jobs
::  jDir - место для оперативных файлов
set jDir=%wDir%\#%nJob%
::  jRpt - общий отчёт с итоговыми сводками процессов
set jRpt=%wDir%\_siTop.#
::  zDir - общий подкаталог для посуточных подкаталогов с итоговыми списками
set zDir=%~d0\Stor\wOld\%jDat%
::  hDir - скоад первых страниц скачанных рейтингов aHits
set hDir=%~d0\Stor\hist.aHits
:: проверить/создать нужные структуры для работы (оперативные площадки)
if NOT exist %jDir%\*.* (
  mkDir %jDir%
  if errorLevel 1 set errInf=fail mkDir %jDir% & goto nExit
)
if NOT exist %zDir%\*.* (
  mkDir %zDir%
  if errorLevel 1 set errInf=fail mkDir %zDir% & goto nExit
)
if NOT exist %hDir%\*.* (
  mkDir %hDir%
  if errorLevel 1 set errInf=fail mkDir %hDir% & goto nExit
)
::  0. ищем последний aHits в логе общей истории jRpt _siTop.#
rem ;1A hits 6:xNam 450:xNum 103984:xPas 2024.10.02:hDat 436220:hMax 1045:hPag 1884:add2 30022:n30k 271:h30k 1045:dnLd 0.08~ratW 2024.10.03:done 00:18:58~wrks  9:03 
set oDrD=
for /F "tokens=1-9,*" %%A in (
  ' gawk.exe "{if(match($0,/^;1A hits.* ([^ ]+):hDat,* ([^ ]+):hMax ([^ ]+):hPag .* ([^ ]+):done/,a))print a[1],a[2],a[3],a[4]}" %wDir%\_siTop.#  '
) do (
  set oDat=%%A
  set oMax=%%B
  set oPgs=%%C
  set oDrD=%%D
)
if NOT defined oDrD set errInf=NO aHits rec(s) in %jRpt% & goto errExit
if %oDat% == %jDat% (
  echo == all is done today already
  goto :eof
)
::  add2 - список потеряшек к расчёту для включений в aHits
set add2=
rem set tmp0=
for %%A in ( %wDir%\20??.??.??.hidn.addS ) do (
  set add2=%%A
  set tmp0=%%~tA
)
if NOT defined add2           set errInf=NO *.hidn.addS &  goto errExit
if NOT %tmp0:~0,10% == %jDat% set errInf=OLD *.hidn.addS & goto errExit
::  last - последний актуальный список aHits
set last=%~d0\Stor\wOld\%oDrD%\%oDat%.%nJob%
if NOT exist %last% set errInf=no last %last% found & goto nExit
set oSiD=%oDat:~8%/%oDat:~5,2%
rem # loc: 02/10 oMax:436220 pOld:1045
echo # loc: %oSiD% oMax:%oMax% pOld:%oPgs% oDat:%oDat% add2.Ok
::  fil1 - первый файл комплекта страниц aHits
set fil1=%jDir%\0001.hits.htm
::  dnLd - счётчик скачанного ([пере]запустим "таймер" ratW)
set dnLd=0
::  wGetErr - уточнённый статус завершения wGet
set wGetErr=0
::  wait - ФЛАГ/таймер зацикливания ожидания полного списка aHits
set wait=%1
set wait=600
:: 1. смотрим наличие aHits в Jobs - нет == переходим к п.4
if NOT exist %wDir%\%oDat%.%nJob% goto doJob

:begJob 4. нужно! ...а старые *,htm есть/?/ == стираем
if exist %jDir%\*.hits.htm (
  erase /F /Q %jDir%\*.hits.htm
  if errorLevel 1 set errInf=fail erase %jDir%\*.hits.htm & goto nExit
)
:: и устаревший итоговый список *.aHits туда же /нафик/
if exist %wDir%\%oDat%.%nJob% (
  move /Y  %wDir%\%oDat%.%nJob% %wDir%\%oDat%.%nJob%.old
  if errorLevel 1 set errInf=fail move %oDat%.%nJob% 2old & goto nExit
)

:doJob выяснение ситуации с "потеряшками" Добавляем их?
:: - скачиваем fil1 и переходим на анализ п.1....
:: 4. смотрим fil1
:: -  нет fil1 или он НЕ сегодняшний == СКАЧИВАЕМ сегодняшний dnLd++
:: 5.  анализ сегодняшнего статуса
:: - fil1 - "НЕ годный" 
:: -- dnLd>=1 выход или цикл ожидания
:: -- dnLd==0 скачиваем свежую копию + переход на р5.
:: - fil1 - "ГОДНЫЙ" докачиваем и строим
:Again  curM - кол-во секунд с момента начала цикла ожидания
if NOT exist %fil1% (
  call :reqSI 1
  if defined errInf goto nExit
)
if NOT exist %fil1% set errInf=fail dnLd 0001.hits.htm & goto nExit
call :scan01
if defined errInf goto nExit
:: если в СИ дата СЕГОДНЯ, скачиваем!
if %jSiD% == %cDat% goto dlAll
:: в СИ или то же самое, или мало страниц, скачивать нельзя.
erase %fil1%
if errorLevel 1 set errInf=fail erase %fil1% & goto nExit
rem if %oMax% == %hMax% (
rem   set tmp2=NO diff {was:%oMax%.oMax}
rem ) else (
rem   set tmp2=too LOW {was:%oPgs%.oPgs}
rem )
:: неполный список; цикл заказывали?
if NOT defined wait (
  set errInf=x web: %cDat% hMax:%hMax% pMax:%pMax% NOT toDay, no wait, exit
  goto nExit
)
:: если заказано зацикливание, цикл ожидания - 10 мин. ДО 10:30, 1 мин после
set /a tmp0=((%time:~0,2%*60)+1%time:~3,2%)-100
rem set wait=60
set wait=600
if %tmp0% GTR 615 set wait=60
:: а заказано именно ЧИСЛО (секунд в цикле ожидания)?
for /F %%A in (
  'gawk "BEGIN{print(strftime(\"%%H:%%M:%%S\",systime()+%wait%));exit}"'
) do set tmp0=%%A
:: не число - не судьба... ;)
if %tmp0% == 0 goto nExit
:: иначе ждём-с ;)
echo ! web: %cDat% hMax:%hMax% pMax:%pMax% now:%jSiD%, WAITing till %tmp0%
call :waitSecs %wait%
rem gawk "BEGIN{t=systime()+%wait%;while(t>systime()){printf(\"%%s\",\".\");j=systime()+1;while(j>systime()){k=1}};exit}"
rem echo.
goto Again

:dlAll скачивание всего комплекта страниц aHits
echo v web: %cDat% hMax:%hMax% pMax:%pMax% OK, dnLd...

::  ratW - темп скачивания (секунд на один файл в среднем)
for /F %%A in ('gawk.exe "BEGIN{print(systime());exit}"') do set ratW=%%A
gawk.exe "BEGIN{printf(\"%pMax%.pMax %hMax%.hMax\n.\");exit}"
for /L %%A in (2,1,%pMax%) do if NOT defined errInf call :reqSI %%A
if defined errInf goto :eof
if NOT "%pNum:~-2%" == "00" echo. = %pNum% %time:~0,8%
:: вычислим темп скачивания ratW
if %dnLd% == 0 (set ratW=0) else (
for /F %%A in ('gawk.exe "BEGIN{print(sprintf(\"%%3.2f\",(systime()-%ratW%)/%dnLd%-1));exit}"') do set ratW=%%A
)

echo = dnLd ok, scaning...
gawk.exe -f %aScr% %jDir%\*.hits.htm
if NOT %errorLevel% == 0 set errInf=fail %aScr% with *.hits.htm & goto nExit
set jLst=
:: ищем готовый ПОЛНЫЙ 20??.??.??.aHits, берём дату в его имени
for %%A in (%wDir%\20??.??.??.%nJob%) do (
  set hDat=%%~nA
  set jLst=%%A
)
if NOT defined jLst set errInf=fail make %jLst% & goto nExit
rem ; aHit 5:xNam 451:xNum 104642:xPas 507217:hMax 1051:hPag 15:add2 381:h30k 42411880:hTot 2023.07.09:hDat 2023.07.14:done 
rem  1 ;
rem  2 aHit
rem  3          5 xNam 1
rem  4        451 xNum 2
rem  5     104642 xPas 3
rem  6     507217 hMax 4
rem  7       1051 hPag 5
rem  8         15 add2 6
rem  9        381 h30k 7
rem 10   42411880 hTot 8
rem 11 2023.07.09 hDat 9
rem 12 2023.07.14 done
:: считаем итоги сборки списка aHits
for /F "tokens=1-9,*" %%A in (
 ' gawk.exe "{if(match($2,/^aHit$/)){print $3,$4,$5,$6,$7,$8,$9,$10;exit}}" %jLst% '
) do (
  set xNam=%%A
  set xNum=%%B
  set xPas=%%C
  set hMax=%%D
  set hPag=%%E
  set add_=%%F
  set n30k=%%G
  set h30k=%%H
)
:: вычленим значения данных
set xNam=%xNam:~0,-5%
set xNum=%xNum:~0,-5%
set xPas=%xPas:~0,-5%
set hMax=%hMax:~0,-5%
set hPag=%hPag:~0,-5%
set add_=%add_:~0,-5%
set n30k=%n30k:~0,-5%
set h30k=%h30k:~0,-5%
:: остановим "таймер", : преобразуем секунды в время работы (в обычном формате "чч:мм:сс")
for /F %%A in ('gawk.exe "BEGIN{print(strftime(\"%%H:%%M:%%S\",systime()-%wrks%+46800));exit}"') do set wrks=%%A
:: оформим подвал списка...
:: ;1A hits 5:xNam 451:xNum 104642:xPas 2023.07.09:hDat 507217:hMax 1051:hPag 15:add_ 1086:dnLd 0.17~ratW 2023.07.11:done 03:12:17~wrks 15:02 
set tmp0=;1A hits ^
%xNam%:xNam ^
%xNum%:xNum ^
%xPas%:xPas ^
%hDat%:hDat ^
%hMax%:hMax ^
%hPag%:hPag ^
%add_%:add2 ^
%n30k%:n30k ^
%h30k%:h30k ^
%dnLd%:dnLd ^
%ratW%~ratW ^
%jDat%:done ^
%wrks%~wrks ^
%time:~0,5%
echo %tmp0% >> %jLst%
echo %tmp0% >> %jRpt%
echo = Ok %xNam%:xNam %xNum%:xNum %xPas%:xPas %hMax%:hMax %h30k%:h30k %add_%:add2 %hDat%
:: прикопаем итоги для истории...
copy /b %jLst% %zDir% > nul
if errorLevel 1 set errInf=fail copy %jLst% TO %zDir% & goto nExit
rem copy /b %fil1% U:\Jobs\#aHits\hist.aHits\0001.hits.%jDat%.htm  > nul
copy /b %fil1% %hDir%\0001.hits.%jDat%.htm  > nul
if errorLevel 1 set errInf=fail copy %fil1% TO hist.aHits & goto nExit
rem for %%A in ( %fil1% ) do echo %%~tA >> U:\Jobs\#aHits\hist.aHits\daTim_of_0001.hits.~.htm.#
for %%A in ( %fil1% ) do echo %%~tA >> %hDir%\daTim_of_0001.hits.~.htm.#
:: и устаревший итоговый список *.aHits туда же /нафик/
if exist %wDir%\%oDat%.%nJob%.old (
  erase /F /Q %wDir%\%oDat%.%nJob%.old
  if errorLevel 1 set errInf=fail erase %oDat%.%nJob%.old & goto nExit
)
:: подудим где нада "готово-с!"
set itog=%jLst%

:nExit
if defined errInf (
  echo ! %errInf%
  if NOT defined wait set errInf=
)
echo %date% %time:~0,8% %~nx0 Ends
goto :eof

:reqSI %%J притаскивает file:///U:/Jobs/#aHits/index-3.shtml
set pNum=000%1
set tmp0=   %1
::  pNum - 4-х значное число с лидирующими нулями (для красивой сортировки пронумерованных страниц рейтинга)
set pNum=%pNum:~-4%
set tmp0=%tmp0:~0,2%
::  wUrl - первая /дефолтная/ страница рейтинга
set wUrl=%siUrl%/rating/hits/index-%1.shtml
::  wFil - конечный локальный файл для скачиваемого
set wFil=%jDir%\%pNum%.hits.htm
:: оживляж...
set mark=.
if exist %wFil% set mark=~
if %pNum:~-1% == 0 set mark=%pNum:~-2,1%
:: первая странимца нужна для выяснения числа страниц
if %1 == 1 (
  set wUrl=%siUrl%/rating/hits/index.shtml
  goto doDl
)
gawk.exe "BEGIN{printf(\"%mark%\");exit}"
if NOT "%pNum:~-2%" == "00" goto doDl
echo. %pNum:~0,2% %time:~0,8%
:doDl
if exist %wFil% goto :eof
call wGetUrl2fil.cmd %wUrl% %wFil%
:: проблема?
if %wGetErr% == 1 set errInf=no %wUrl%
if %wGetErr% == 3 set errInf=no web{SI}
goto :eof

rem <DL><b>95347</b> <a href=/z/zhan/>Tony</a>
:scan01 выченение кличевых значений из первой страницы рейтинга aHits
::  pMax - общее число страниц
set pMax=
::  hMax - хиты топового раздела /лидер/
set hMax=
::  cDat - СИ-шная дата рейтинга
set cDat=
set tmp0=
for /F "tokens=1-9,*" %%J in (
  ' gawk.exe "{if(match($0,/\.shtml>([0-9]+)<\/a> *<\/center><DL><b>([0-9]+)</,a)){print(a[1],a[2]);exit}}" %fil1% '
) do (
  set pMax=%%J
  set hMax=%%K
)
for /F "tokens=1-9,*" %%J in (
  ' gawk.exe "{if(match($0,/ ([0-3][0-9]\/[01][0-9]):<\/b>/,a)){print(a[1]);exit}}" %fil1% '
) do set cDat=%%J
if NOT defined pMax set tmp0=NO pMax
if NOT defined cDat set tmp0=NO cDat %tmp0%
if defined tmp0 set errInf=%tmp0% in %fil1%
goto :eof

:errExit реакция на проблему: в пакете - выход
if defined pMod goto :eof
:: автономно - на экран + прекращение работы
echo %errInf%
exit

===v=== комплект п/п для обустройства заданных ожиданий в CMD
:waitSecs %%A организовать паузу в заданное число секунд /%1/ оживляж с новой строки, если /%2/
for /f "tokens=1-9,*" %%Q in (
  ' gawk.exe "BEGIN{t=systime();print(t,t+%1);exit}" '
) do (
  set jSec=%%Q
  set eSec=%%R
)
if NOT %2. == . echo.
:: начальная фиксация момента старта
call :ticSet
goto sleep6

:ticShow оживляж - это наше всё
gawk.exe "BEGIN{if(%curM%==%preM%){printf(\".\")}else{printf(%curM%)}exit}"
:: строка терминируется 10-й минутой /"0"/
if %curM% == 0 if NOT %curM% == %preM% echo.
rem  %curT%
:: проверка истечения заданного срока; "да"==вЫход
if %curS% GEQ %eSec% (
  if NOT %curM% == 0 echo.
rem  %curT%
  goto :eof
)
:sleep6  шаг задержки - 6 секунд
sleep 6
:: рабочая фиксация очередного момента
call :ticSet
goto ticShow

:ticSet запомним старое значение момента времени относительно начального /jSec/
set preM=%curM%
for /f "tokens=1-9,*" %%P in (
  ' gawk.exe "BEGIN{t=systime();print(t,strftime(\"%%H:%%M %%M\",t-%jSec%,1));exit}" '
) do (
  set curS=%%P
  set curT=%%Q
  set curM=%%R
)
:: и текущее /новое/ значение минут /последняя цифра/
set curM=%curM:~1%
goto :eof
===^=== комплект п/п для обустройства заданных ожиданий в CMD

:: 2018.08.05, nvv, creation
:: ...
:: 2019.11.29, nvv, samlib.ru budclub.ru - основной и альтернативный адреса "Самиздата"
::     + переменная nJob блокирует пилотную команду @echo off
:: 2019.12.06, nvv, current unification
:: 2020.03.13, nvv, улучшайзинг послегка-с...
:: 2020.04.06, nvv, улучшен алгоритм распознавания свежека, ЕСЛИ дата та же, а данные - свежие
:: 2020.04.29, nvv, minor corrections
:: 2020.05.23, nvv, set pGet=115 -> 120; set oPag=990 -> 999
:: 2020.05.23, nvv, set pGet=200
:: 2020.07.29, nvv, set pGet=250
:: 2020.09.12, nvv, set pGet=300 + отказ от отделения брака, всё вместе + у брака sizN==0
:: 2020.11.13, nvv, будКлуб - глупость
:: 2020.11.16, nvv, будКлуб - глупость? не факт... ;(
:: 2020.11.28, nvv, будКлуб - отнюдь... + мелкая косметика
:: 2021.05.11, nvv, очередная оптимизация с унификацией...
:: 2022.02.04, nvv, мелкий улучшайзинг оживляжа
:: 2022.02.07, nvv, прикапывание первой страницы полного рейтинга в U:\Jobs\#aHits\2022.hist.aHits 
:: 2022.02.16, nvv, мелкое улучцение оживляжа
:: 2022.06.07, nvv, мелкое улучшение оживляжа и логики + возможность возобновления после падения сети
:: 2023.07.11, nvv, пауза между запросами свежака в СИ через sleep, а не через цикл в gawk
:: 2023.07.22, nvv, поддержка включения "потеряшек" add2 в общий список aHits
:: 2023.07.30, nvv, исправлена мелкая неточность выхода по несоблюдению условий для работы
:: 2023.10.11, nvv, до 10:00 и после 14:00 интервал опроса СИ - 1 минута, иначе - 20 минут
:: 2024.03.01, nvv, изменился рисунок публикации данных учёта посетителей СИ, выясняем детали...
:: 2024.03.05, nvv, ожидание в цикле теперь всегда 1 минута /wait=60/ для выяснения-с расписания для
:: 2024.03.16, nvv, ожидание в цикле теперь 5 минута ДО 10:00 и 1 ПОСЛЕ /wait=60/ + мелочь
:: 2024.03.17, nvv, no toDay`s job == no toDay`s wait
:: 2024.04.03, nvv, за сутки список похудел сразу на 11 страниц == контроль числа оных /oPag/ отключен
:: 2024.04.06, nvv, склад первых страничек переехал в hDir
:: 2024.05.08, nvv, param:n30k added /last h30k.hits line number in aHits/
:: 2024.05.22, nvv, убрана в CMD работа с значением hTot /хитов всего/
:: 2024.08.13, nvv, вместо вопроса или работа, или выход по "уже есть"
:: 2024.09.19, nvv, ожидание в цикле готовности и БЕЗ параметра
:: 2024.10.03, nvv, нужен именно сегодняшний список: "СТАТИСТИКА за дд/мм"

    Имя файла скрипта: "bStat.awk" V-текст скрипта-V
- - - - - - - - -
BEGIN{                      #  bStat.awk scan+check *.stat.htm +mkLst книг-кандидатов в siTopTexts
# 2024.05.27, nvv, уточнения и подгонка под ежедневное обновление статистик

# ! история изменений - в подвале
# (!) для СКРЫТЫХ разделов нужны только эти данные:
#  из stat aHitP == 201661 p12m хиты за 12мес.
#  из stat aNamP == "Кадавр"
#  "0" (!) aNumP == 21 pNum место в aHits
  minT=200    #  минимальное кол-во хитов текста "за 30 дней", дабы "прорехи штопать" (если есть;)
  hitL=0      #  нижняя граница хитов "12мес" для отсечения от учёта неуспешных текстов и разделов
#   hitL=374                                      #  !!! 2024.04.29
  nHit=0                                          #  число учитываемых топовых разделов в aHits
  gisF=1                                          #  флаг "нужны гистограммы"
  nTxt=0                                          #  кол-во отобранных текстов
  tNum=0                                          #  число принятых ГОДНЫХ текстов
  hitT=0                                          #  сумма хитов "за 30 дней"
  ripN=0                                          #  число пустых суток (там же)
  ripP=0                                          #  число разделов-кандидатов на "штопку"
  endH=0                                          #  последний НЕ ноль "за 30 дней"
  rip1=0                                          #  первый ноль (там же)
  hitY=0                                          #  хиты произведения за "12мес"
  mifN=0                                          #  счётчик призраков СИ (текстов нет, хиты есть)
  nErr=0                                          #  счётчик проблемных файлов
  nGis=0                                          #  счётчик строк в файле с гистограммами
  nLow=0                          #  счётчик текстов, выпавших из-за НЕ обновлённых статристик
  dEnd="2000.01.01"                           #  макс.дата: 'datJ' (самая последняя - оперативная)
  dPre="2000.01.01"                               #  макс.дата: 'datJ' (предыдущая - "рассчётная"
  errS="] step.0 (NO file)"
  if(ARGV[1]=="")exit                             #  защита от случайного пуска

# объявим массивыы для общего использования в подпрограммах
  split("",aDatI)                                 #  чьи-с ;) -v- max хиты
  split("",aDatM)                                 #  макс хиты каждой найденной пары дат
  split("",aDatN)                                 #  счётчики пар дат: "fresh"-"datJ"
  split("",aHitP)                                 #  хиты раздела за 12мес. (из aHits)
  split("",aNamP)                                 #  ник автора в aHits
  split("",aNumP)                                 #  место раздела в aHits
  split("",aErr)                                  #  описания замеченных проблем со статистиками
  split("",aLow)                                # массив текстов с хитами >= hitL, но < hStD
  split("",aSel)    #  в ячейках статистики: url,title,hits:all,12mon,mon0..monC-11,day0..day0-61
  split("",aMig)                                  #  список timeStamp's статистик
  split("",aTxt)                                  #  перечень принятых текстов
  split("",aGis)                                  #  перечень гистограммных разделов
  split("",aStD)                                  #  перечень "хиты_текста datJ id_P id_T"
  split("",arr0)                                  #  рабочий массив
  split("",arr1)                                  #  рабочий массив
# print hitL".hitL"

  mark=""                                         #  max dateTime statRefresh
  for(str2 in ENVIRON){                     #  ! регистр букв в имени переменной может быть любой
    str1=tolower(str2)                            #  Temp и temp - РАЗНЫЕ имена для gAwk...
    if(str1=="fhit")fHit=ENVIRON[str2]            #  опорный aHits список
    if(str1=="mint")minT=ENVIRON[str2]    #  минимальные допустимые хиты текста (меньше - брак)
    if(!hitL)if(str1=="hitl")hitL=ENVIRON[str2] #  нижняя граница хитов "12мес" (для отсечения)
    if(str1=="wdir")wDir=ENVIRON[str2]"\\"        #  место для всех ВЫХ.списков
    if(str1=="ratw")ratW=ENVIRON[str2]            #  минимальное кол-во топовых разделов из aHits
# print "hitL."hitL,str1
  }
  if(!ratW)ratW=0                               #  ratW сетится прискачивании, нужно для итога
  if(fHit==""){                                   #  если вызов НЕ из CMD, aHits ищем сами
    str0="U:\\Jobs\\_siTop.#"
    while((getline line<str0)>0){       #  ищем последнюю запись успешного скачивания этого списка
# ;1A hits 5:xNam 457:xNum 104555:xPas 2023.06.15:hDat 505501:hMax 1051:hPag 1111:dnLd 0.08~ratW 2023.06.16:done 05:22:08~wrks 14:47 
      if(match(line,/^;1A .+ 20([\.0-9]{8}):hDat /,arr0))fHit=arr0[1]
    }
    close(str0)
    if(fHit==""){
      errS="] step.0 NO *.aHits found in "str0
      exit
    }
    fHit="U:\\Jobs\\20"fHit".aHits"               #  строим полное имя нужного списка
#     fHit="\\Jobs\\2024.05.21.aHits"               #  строим полное имя нужного списка
    topN=30000
#     topN=200
  }
  fErr=wDir".upDatBad.bStat.#"                  #  список проблем и проблемных статистик (если-с;)
  fGis=wDir".upDatGis.bStat.#"              #  гистограммы посуточных хитов разделов с "прорехами"
  fLow=wDir".upDatLow.bStat.#"                  # список текстов с хитами >= hitL, но < hStD
# 201661   21  846    3 k/kadawr "Кадавр" "no•comments"
# ;  hitP numP sizK sizN id_P     "namP"   "moto"
#      1    2    3    4 5         6        7
  print("? load "fHit,"...")                      #  заполним массив атрибутов разделов в *.aHits
  int1=0
  while((getline line<fHit)>0){                   #  fHit: like 2020.03.01.aHits
    split(line,arr0)                              #  arr0[5] == k/kadawr p_id
    if(match(arr0[1],/^[0-9]+$/)){              #  это строка данных раздела
      aHitP[arr0[5]]=arr0[1]                      #  hitP arr0[1] == 201661 p12m хиты за 12мес.
      aNumP[arr0[5]]=arr0[2]                      #  numP arr0[2] == 21 место в aHits
      aNamP[arr0[5]]=arr0[6]                      #  namP arr0[6] == "Кадавр"
      int1++
      if((!hitL)&&(int1==topN))hitL=arr0[1]     #  мин. достаточные хиты текста
      if((!nHit)&&(hitL-arr0[1]>0))nHit=int1-1    #  число учитываемых топовых разделов в aHits
      if((arr0[4])&&(!nHit))r2do++                #  должное число непустых разделов в $bStat
# ;1A hits 6:xNam 456:xNum 103830:xPas 2024.05.26:hDat 463185:hMax 1043:hPag 899:add2 30663:n30k 294:h30k 1043:dnLd 0.33~ratW 2024.05.26:done 00:23:15~wrks 11:08 
    }else if(match(line,/^;1A .+ ([0-9]+):h30k .+ 20([\.0-9]{8}):done /,arr0)){
      hitL=arr0[1]                                #  дата скачивания aHits
      datH=arr0[2]                                #  дата скачивания aHits
      infH=line                                   #  для итогового списка отобранных текстов
    }
  }
  close(fHit)                                     #  всё/не_всё, - старый список тогось
#   nHit=0
#   for(int1=1;)
# print("= loaded; nHit:"nHit"."hitL" minT:"minT) #  всё готово, начинаем сканирование статистик
# exit
  int7=(r2do-(r2do%100))/100
  if(r2do%100)int7=int7"+"
  if(int1==0){
    errS="] step.0 (no or empty %fHit%: "fHit " )"
    exit
  }
# массив имён месяцев для преобразования их в числа с лидирующим нулём 01..12
  mNum["Jan"]="01"                                #  .1 January . Jan. 31 . winter wint
  mNum["Feb"]="02"                                #  .2 February .Feb. 28/29
  mNum["Mar"]="03"                                #  .3 March . . Mar. 31 . spring sprn
  mNum["Apr"]="04"                                #  .4 April . . Apr. 30
  mNum["May"]="05"                                #  .5 May . . . May. 31
  mNum["Jun"]="06"                                #  .6 June . . .Jun. 30 . summer summ
  mNum["Jul"]="07"                                #  .7 July . . .Jul. 31
  mNum["Aug"]="08"                                #  .8 August . .Aug. 31
  mNum["Sep"]="09"                                #  .9 September Sep. 30 . autumn autm
  mNum["Oct"]="10"                                #  10 October . Oct. 31
  mNum["Nov"]="11"                                #  11 November .Nov. 30
  mNum["Dec"]="12"                                #  12 December .Dec. 31 . winter wint
  errS=""
  print("= loaded; nHit:"nHit"."hitL" minT:"minT) #  всё готово, начинаем сканирование статистик
  tIni=systime()
#   exit
}

{                                                 #  // -=- основной блок скрипта begs
  if(FNR==1){         #  секция завершения работ с одним файлом и подготовки к работе со следущим
    if(NR!=1)chkSteps()                           #  чем закончилась обработка предыдущего файла?
    step=0        #  0-владелец, 1-дата обновления, 2-id раздела, 3-разбор строк таблиц статистики
    fPth=FILENAME
    fNam=split(fPth,arr0,"\\")                    #  NEW/NEXT входной файл as-is (с полным путём)
    fNam=split(arr0[fNam],arr0,".")               #  файл: чистое nam.ext (like "0~0.stat.htm")
    fNam=arr0[1]                                #  fNam чистое имя (like "0~0" in "0~0.stat.htm")
    id_P=substr(fNam,1,1)"/"substr(fNam,3)
    if(id_P in aHitP){                            #  этот раздел ЕСТЬ в рейтинге "по хитам"
      numP=aNumP[id_P]
      hitP=aHitP[id_P]
      namP=aNamP[id_P]
    }else{
      numP=0
      hitP=999                                    #  выясняется в stat
      namP="\""id_P"\""                           #  - "" - - "" -
    }
    inTab=0                                       #  сначала - мы НЕ "в таблице"
    numT=0                                        #  счётчик таблиц в файле статистики
    numR=0                                        #  счётчик строк в текущей таблице
    selN=0                                        #  счётчик ячеекк в строке таблицы
    int8++
# if(int8%100==0) print(sprintf(": %4s.%-4s",int8/100,int7),strftime("%H:%M:%S",systime()-tIni,-1))
    if(int8%100==0) print(sprintf(": %4s.%-4s",int8/100,int7))  #  оживляж
    else if(int8%10)printf(".")                 #  оживляж...
    else            printf(":")                 #  оживляж
  }
  gsub(/(&nbsp;)+|\xA0+|[\0-\31]+/," ",$0) #  цепочки "&nbsp;" и прочих "пробелов" -> " " (пробел)
  if(step==0) {                                   #  ищем (для контроля) ФИО автора
# <h3>Статистика раздела &quot;<a href=./>Влад</a>&quot;:</h3>
    if (match($0,/<h3>Статистика раздела \&quot;<a href=\.\/>(.*)<\/a>\&quot;:<\/h3>/,arr0)) {
      if(arr0[1]==""){
        errS="] step."step" (NO nick in: " fNam " )"
        nextfile
      }else namP=pack(arr0[1])
      step++                                      #  проверка ОК
    }
  }else if(step==1){                              #  вычленеие даты обновления статистики
    if(match($0,\
/<li><i>Статистика рассчитывается .+\. \(.+ (...) +([0-9]+) (..:..:..) (20[0-9][0-9])\)<\/i>/\
,arr0)){
      if(length(arr0[2])==1) arr0[2]="0"arr0[2]   #  причешем первые дни месяца "1" -> "01"
      ticS=mktime(arr0[4]" "mNum[arr0[1]]" "arr0[2]" 12 00 00") # тики на 12 часов даты статистики
      datS=arr0[4]"."mNum[arr0[1]]"."arr0[2]      #  дата обновления статистики
      timS=arr0[3]                                #  время обновления статистики
      if(mark<datS"/"timS)mark=datS"/"timS
      step++                                      #  дату статистики оптичили
    }
  }else if(step==2){            #  ищем authID (!должен быть и совпадать с префиксом имени файла)
# [<a href=http://top.mail.ru/pages?id=77427&period=0&date=2018-10-02&filter_type=0
# &filter=n/nosow_w_w&pp=20&gender=0&agegroup=0>по дням</a>]
    if (match($0,/\[<a href=http.+&filter=([0-9a-z]\/[\-0-9a-z_]+)&pp=.+>по дням<\/a>]/,arr0)) {
      if(id_P!=arr0[1]){                          #  это ПОЛНЫЙ криминал!
        errS="] step."step" ("arr0[1]" != fNam: " fNam " )"
        nextfile
      }
      step++                                      #  проверка ОК
    }
  }else if(step==3){                #  таблицы статистики, просмотр строк, сборка данных в ячейках
    if($0=="<!--------- Подножие ------------------------------->"){  #  разбор закончен
      step++
      nextfile
    }
    if(inTab){                      #  Мы ВНУТРИ таблицы, собираем строки таблицы с хитами текстов
      buf0=buf0" "$0                              #  gain inpLines to buf0, then check contents
      while((match(buf0,/<tr ?[^>]*>/))||(int0=index(buf0,"</tr"))){ # seek <tr .. </tr for tabRow
        if(RSTART){                               #  new/next line begs
          numR++                                  #  счётчик строк
          buf0=substr(buf0,RSTART+RLENGTH)  #  del всё до начала строки таблицы <tr>, в т.ч. и его
        }
        if(int0=index(buf0,"</tr")){              #  this line ends
          getSels(substr(buf0,1,int0-1))          #  tabl_row -> arrow:sell_values
          buf0=substr(buf0,int0+4)              #  убрали эту строку из буфера и окультуриваем...
          id_T=aSel[0]                        #  имя+расшир файла с текстом (или "./" для раздела)
          namT=aSel[1]                    #  пока фактическое (as-is) название текста в статистике
          if((numT==1)&&(numR==2)){               #  хиты по разделу (спец.обслуживание)
            if(!numP)hitP=aSel[3]                 #  хиты раздела за "12мес" ЕСЛИ нет в aHits
            aMig[++nMig]=datS"_"timS" "datJ sprintf("%7s%8s %s %s %s"\
,numP,hitP,fNam,id_P,namP)                        #  момент обновления
            if((hitT-minT>0)&&(rip1!=0)&&((endH-rip1>0)||rip1==1)){
              ripP++                              #  число разделов-кандидатов на "штопку"
              id_T="~"                            #  prt 8-раздел: 'хиты за 30 дней'
              namT="\"<!>\""
              selsOutG()                          #  гистограмма: хитов много + есть "прореха"
            }
          }else{                                  #  обычная строка статистики текста
            int0=split(id_T,arr0,".")
            if(     int0!=2){}                #  sErr="zOrg" нарушен формат имени файла: name.ext
            else if(arr0[2]!="shtml"){}           #  sErr="xExt" расширенеие не то-с
            else if(gensub(/[\-0-9a-z_]/,"","g",arr0[1])!=""){} # sErr="vNam" левизна в имени файла
            else if(namT==""){}                   #  sErr="tHdr" "пустое" название текста
            else if(minT-hitT>0){}                #  sErr="hLow" хитов таки мало
            else {                #  0-"всё ОК" поток строк с текстами и хитами для выбора top1000
              namT=pack(namT)                     #  запакованное (свёрнутое!) название текста
              if(match(namT,/^""$/)){
                namT=hitT":noNamT"
                hitT=2
              }else{
                tNum++                            #  число принятых ГОДНЫХ текстов
              }
              aTxt[++nTxt]=sprintf("%7s%8s %6s",hitT,hitP,numP)" "id_P\
" "arr0[1]" "namP" "namT" "fNam" "datJ            #  строка для итогового списка текстов
              aStD[nTxt]=datJ" "sprintf("%7s",hitT)" "id_P" "arr0[1]  #  "datJ хиты id_P id_T"
              if(hitT-aDatM[dGap]>0){             #  максимум - только у принятых!
                aDatM[dGap]=hitT                  #  <- max хиты, v- чьи-с ;)
                aDatI[dGap]=sprintf("%7s %6s %6s",hitP,numP,hitT)" "id_P" "arr0[1]
              }
            }
            if(minT-hitY>0){                      #  хиты за "12мес", дальше - хитов ещё меньше
              step=4
              nextfile
            }
          }
        }
      }
      if(int0=index(buf0,"</table")){             #  this tabl ends
        buf0=substr(buf0,int0+4)                  #  update buf0
        inTab=0
      }
    }else{                                        #  ищем начало таблицы
      if(int0=index($0\
,"<table border=1 cellspacing=0 cellpadding=0><tr><td><td colspan=2><b>Итого</b></td>")){
        numT++                                    #  new table
        numR=1                #  певая строка каждой таблицы - календарь хитов статистики раздела
        buf0=substr($0,int0+80)
        if(numT==1){                              #  1-st table 1-st row -> get col-dates & so-on
          match(buf0,/<tr[^>]*>(.+)<\/tr[^>]*>/,arr0) #  собственно строка с календарём
          getSels(arr0[1])                        #  но самую первую такую - разберём-с
          tic0=ticS           #  и привяжем дату к нулевому (самому левому) дню посуточных данных
          while(strftime("%d",tic0)!=aSel[16])tic0=tic0-86400 #  сдвинем стат.дату к нулевому дню
          datJ=strftime("%Y.%m.%d",tic0-86400)    #  полная дата первого дня в интервале 30 дней
          dGap=datS"-"datJ
          aDatN[dGap]++                           #  счётчики "datJ" дат в статистиках
          if( dEnd<datJ)               dEnd=datJ  #  оперативная 'datJ'
          if((dPre<datJ)&&(datJ<dEnd))dPre=datJ   #  предыдущая 'datJ'
        }
        inTab=1                                   #  мы ВНУТРИ таблицы
        buf0=""                                   #  буфер чист!
      }
    }
  }
}                                                 #  // -=- основной блок скрипта ends

function getSels(rowLn){                #  разделение строки таблицы статистики на массив значений
  hitT=0                                          #  + сумма хитов "за 30 дней"
  ripN=0                                          #  число пустых суток (там же)
  endH=0                                          #  последний НЕ ноль "за 30 дней"
  rip1=0                                          #  первый ноль (там же)
  selN=0                                          #  sells count
  split("",aSel)
  aSel[0]=""
  while(match(rowLn,/<td[^>]*>/)){                #  это объявление ячейки
    selN++                  #  0.1-имя/ссылка; хиты: 2-всего, 3-12мес, 4..15-заМес, 16..77-заСутки
    rowLn=substr(rowLn,RSTART+RLENGTH)            #  выкусим объявление ячейки
    f3n2=index(rowLn,"</td")                      #  это конец ячейки
    f3s2=substr(rowLn,1,f3n2-1)               #  это сама ячейка (с возможными внутренними тегами)
    if(selN==1){                            #  в ПЕРВОЙ ячейке - название текста и ссылка на него
      match(f3s2,/<a href=([^>]+)>(.*)<\/a>/,f3a1)  #  выцепим и разложим:
      aSel[1]=f3a1[2]                             #  название текста
      aSel[0]=f3a1[1]                             #  ссылка на текст: name.shtml
    }else aSel[selN]=rmTags(f3s2) #  в ПРОЧИХ ячейках - только значение ячейки, очищенное от тегов
    rowLn=substr(rowLn,f3n2)                      #  выкусим оптиченную ячейку
    if((selN-16>0)&&(47-selN>0)){
      hitT=hitT+aSel[selN]                        #  сразу подсчитаем сумму хитов "за 30 дней"
      if(aSel[selN]==0){                          #  и уточним важные подробности
        ripN++                                    #  + число пустых суток (там же)
        if(rip1==0)rip1=selN-16                   #  первый ноль "за 30 дней"
      }else        endH=selN-16                   #  последний НЕ ноль (там же)
    }
  }
  hitY=aSel[3]                                    #  хиты произведения за "12мес"
  if(selN==77)return                              #  row HAVE had 77 sells
  nextfile                                        #  битая таблица == битый файл
}

function rmTags(f2s1){                            #  удаление ВСЕХ тегов в литерале
  while(match(f2s1,/<\/?[a-zA-Z][1-6a-zA-Z]?[a-zA-Z]*[ \/]?[^>]*>/))
      f2s1=substr(f2s1,1,RSTART-1) substr(f2s1,RSTART+RLENGTH)
  return(f2s1)
}

function selsOutG() { # отладка: на StdOut гистограмма значений массива aSel +маркировка "прорехи"
  int0=0                                      #  +с посуточной шкалой +справочные сведения касаемо
  hSum=0
  for(int1=17;int1<47;int1++){
    if(aSel[int1]-int0>0)int0=aSel[int1]          #  ищем максимальные хиты за сутки
    hSum+=aSel[int1]                              #  +фактическию сумму хитов "за 30 дней"
  }
  int0=length(int0"")
  ++nGis
  split("",arr1)                                  #  готовим (собираем гистаграмму)
  for(int1=1;int1<31;int1++){
    str0=sprintf("%"int0"s",aSel[int1+16])
    for(int2=1;int2<=int0;int2++){                #  в виде горизонтальных строк цифр
      str2=substr(str0,int2,1)
      if((int2==int0)&&(aSel[int1+16]==0))str2="_"  #  ЭТО суточная "прореха" (0 хитов)
      arr1[int2]=arr1[int2] str2
    }
  }
  str0=strftime("%d",tic0-86400) "  "             #  строим шкалу времени; привязанную к границам
  for(int2=5;int2<30;int2+=5)str0=str0 strftime("%d",tic0-86400*int2) "   "
  str0=str0 strftime("%d.%m.%Y",tic0-86400*30)" hSum="hSum
  aGis[++nGis]=str0                               #  оформляем всё от...
#        |19 15   10   05   31   26   21.01.2020  # пример посуточной шкалы времени
  aGis[++nGis]="v...:....v....:....v....:....v"
#        31302922396567855______0629939   # пример самой нижней строки гистограммы (с "прорехой")
  for(int2=1;int2<=int0;int2++)aGis[++nGis]=arr1[int2]
  aGis[++nGis]="|...:....|....:....|....:....|"
  aGis[++nGis]=id_P"/"id_T" "namT" " fNam         #  ... и до
}

function pack(f1s1) {       #  мешающие chars -> нейтральные + cut too long + закавычить результат
  f1n1=split(f1s1,f1a1)
  f1s1=f1a1[1]                                    #  обихаживание пробелов... " " -> "•"
  for(f1n2=2;f1n2<=f1n1;f1n2++)f1s1=f1s1"•"f1a1[f1n2]
  f1s2=""                                         #  двойные кавычки -> "&quot;"
  while(f1n1=index(f1s1,"\"")){f1s2=f1s2 substr(f1s1,1,f1n1-1)"&quot;"; f1s1=substr(f1s1,f1n1+1)}
  f1s1=f1s2 f1s1
  f1s2=""                                         #  "%" -> "&#x25;"
  while(f1n1=index(f1s1,"%")){f1s2=f1s2 substr(f1s1,1,f1n1-1)"&#x25;"; f1s1=substr(f1s1,f1n1+1)}
  f1s1=f1s2 f1s1
  if(length(f1s1)>999){                           #  обрезка слишком длинных литералов
    f1n1=index(substr(f1s1,1000),"•")
    if(!f1n1)f1n1=1000
    else   f1n1=f1n1+999                          #  v-вместо обрезанного - справка о факте ;)
    f1s1=substr(f1s1,1,f1n1-1)"•(+"(length(f1s1)-f1n1)" chars)"
  }
  return ("\""f1s1"\"")                           #  результат "закавычивается!"
}

function chkSteps() {                     #  проверка чем закончилась обработка очередного файла?
  if((step==4)&&(errS=="")){                      #  всё штатно ("ОК")
    return
  }else{
    if(errS==""){                                 #  что-то не так, но нужно уточнить...
      if(step==3){
        if(inTab==1){                             #  уточним проблему...
          if(selN!=77){                           #  row HAVE had 77 sells
        errS="] step."step" (selN:"selN" Tab:"numT" Row:"numR"{not 77}): " fNam " )"
          }else if((numT==1)&&(numR==2)){
        errS="] step."step" (bad 1-st table 2-nd row in: "    fNam " )"
          }else{
        errS="] step."step" (unClosed table in: "             fNam " )"
          }
        }else{
        errS="] step."step" (no or bad table in: "            fNam " )"
        }
      }else if(step==2){
        errS="] step."step" (no or bad author's ID in: "      fNam " )"
      }else if(step==1){
        errS="] step."step" (no or bad refresh date:{"$0"}: " fNam " )"
      }else if(step==0){
        errS="] step."step" (no partition`s owner in: "       fNam " )"
      }
    }
    aErr[++nErr]=errS
    aMig[++nMig]="0000.00.00_00:00:00 _bad_file_"sprintf("%7s%8s %s %s %s"\
,numP,hitP,fNam,id_P,namP)                        #  этот файл "на вынос"
    aDatN["0000.00.00-_bad_file_"]++
# 2021.03.05-14:21:54 2021.03.04 29076     514 a/ass "Асс"
# aBad[nErr]=datS"-"timS" "datJ sprintf("%6s%8s %s %s"\
# ,numP,hitP,id_P,namP)   # заполняем массив моментов обновления статистик
    errS=""                                       #  и очистим флаг-инфо
  }
}

function mkRpt1(ln2rpt) {                   #  дабы нужное отправлять и в отчёт, и на экран, и...
  print(ln2rpt)                                                         >fLst #  список текстов
  print(ln2rpt)                                                         >fMig # список разделов
  print(ln2rpt)                                                         >fLow # список выпавшего
#   print(ln2rpt)                                                         >fRpt
  print(ln2rpt)
}

function mkRpt2(ln2rpt) {                         #  дабы правильно отправлять нужное куда след...
  print("; "ln2rpt)                                                     >fMig
#   print(ln2rpt)                                                         >fRpt
  print(ln2rpt)
}

END{                                              #  отстрелялись; ну почти...

  if(errS!=""){
    print("")
    print(errS)                                   #  есть проблем-с => подудим
    exit 1                                        #  и на выход с вещами
  }
  chkSteps()                                      #  чем закончилась обработка последнего файла?
  if(errS!=""){
    print("")
    print(errS)                                   #  есть проблем-с => подудим
    exit 1                                        #  и на выход с вещами
  }

  if(int8%100)print("")
  print(" == " nMig,strftime("%H:%M:%S"),strftime("~%H:%M:%S~",systime()-tIni,-1))  #  проблем нет

  asort(aMig)                                 #  подготовка списка дата/времы обновления day01
  asort(aTxt)           #  подготовка (прямая сортировка) и выдача (в обратном порядке!) списка
  asort(aStD)
  split(aStD[nTxt],arr0)
  dStD=arr0[1]                                  #  опорная дата расчёта /dEnd/
  hStD=hitL       #  def: нижняя граница хитов "по обновлению" == нижняя граница хитов по aHits
  for(int1=nTxt;int1>0;int1--){
    split(aStD[int1],arr0)
    if((hStD-arr0[2]<0)&&(dStD!=arr0[1]))hStD=arr0[2]+1 #  новая граница "по обновлению"
  }
  for(int1=nTxt;int1>0;int1--){                 #  вычленение и выдача в список
    split(aTxt[int1],arr0)
    if((hStD-arr0[1]>0)&&(hitL-arr0[1]<=0)){
      nLow++                                  #  выпавших их-ха не обновления значимых разделов
      print(aTxt[int1])                                                 >fLow
    }
# aTxt[++nTxt]=sprintf("%7s%8s %6s",hitT,hitP,numP)" "id_P" "arr0[1]" "namP" "namT" "fNam" "datJ            #  строка для итогового списка текстов
# printf("%s %s %7s %s %s\n",hStD,(hStD-arr0[1]>0),arr0[1],hitL,(hitL-arr0[1]<=0)) > "x.x"
  }
# print hitL".hitL",hStD".hStD"
#   if(hitL-hStD<0)hitL=hStD
# print hitL".hitL",hStD".hStD"

  split("",aSel)                                  #  сборка итогового отчёта
  split(aMig[nMig],arr0)
  keep=" = "
  sEnd=substr(arr0[1],1,10)                       #  дата самого последного обновления статистик
  dEnd=arr0[2]                                    #  последний datJ (верхняя граница расчёта)
  hEnd=aDatM[str0]                                #  макс. хиты текста за datJ
  nEnd=1                                          #  число статистик с datJ
  hPre=0                                          #  макс. хиты текста ВНЕ datJ
  nPre=0                                          #  число статистик ВНЕ datJ
  nSel=1
  str0=sEnd"-"dEnd                                #  самая свежая (последняя) пара дат datS-datJ
  aSel[nSel]=str0 sprintf("%7s %4.1f%",aDatN[str0],aDatN[str0]*100/nMig) keep aDatI[str0]
  frst=0                                    #  первая строка итоговой сводки с "xDel/=Keep" == "="

  for(int1=nMig-1;int1>0;int1--){                 #  сканируем aMig собирая отчёт
    split(aMig[int1],arr0)
    arr0[1]=substr(arr0[1],1,10)
    if(str0!=arr0[1]"-"arr0[2]){                  #  перешли границу суток в датах обновления
      if(!frst&&(arr0[2]!=dEnd))frst=nSel         #  у этой строки возможно будет смена "=" на "x"
      nSel++
      str0=arr0[1]"-"arr0[2]                      #  новая пара дат datS-datJ
      if(aDatI[str0]==""){                        #  если в ней нет значимых текстов, то...
        aDatI[str0]="      ~     ~      ~ ~    ~" #  отметим факт
        keep=" x "                                #  и назначение: "на удаление"
      }else if(arr0[2]!=dEnd)keep=" x "           #  и назначение: "на удаление"
      aSel[nSel]=str0 sprintf("%7s %4.1f%",aDatN[str0],aDatN[str0]*100/nMig) keep aDatI[str0]
    }
    if(arr0[2]==dEnd){
      if(hEnd-aDatM[str0]<0)hEnd=aDatM[str0]      #  макс. хиты текста за datJ
      nEnd++                                      #  число статистик с datJ
    }else{
      if(aDatM[str0]&&(hPre-aDatM[str0]<0))hPre=aDatM[str0] #  макс. хиты текста ВНЕ datJ
      nPre++                                      #  число статистик ВНЕ datJ
    }
  }

  if(hStD-hPre>0){                            #  в Pre НЕТ хитового текста => рейтинг собирается!
    split(aSel[frst],arr0,"% = ")                 #  у этой строки НУЖНО сменить "="...
    aSel[frst]=arr0[1]"% x "arr0[2]               #  ... на "x"
    if(datH==strftime("%y.%m.%d"))vOk="v"
    else                          vOk="~"
    preF=wDir dEnd "." vOk
    vOk="mod:"vOk
  }else{                                          #  иначе - увы...
    preF=wDir dEnd ".!"                           #  собирать НЕЛЬЗЯ!
    vOk="mod:!"
  }
  fLst=preF".lst.bStat"                           #  итоговый список текстов-кандидатов siTopTexts
  fMig=preF".mig.bStat"                           #  сортированные моменты обновления статистик
  fStD=preF".std.bStat"                           #  сортированные моменты обновления статистик

  if(nErr)for(int1=1;int1<=nErr;int1++)print(aErr[int1])               >>fErr
  if(gisF){                                       #  заказана гистограмма, выдадим, что нашлось
    if(nGis)for(int1=1;int1<=nGis;int1++)print(aGis[int1])             >fGis
    else                                 print("")                     >fGis
  }

  for(int1=nTxt;int1>0;int1--)print(aTxt[int1])                         >fLst #  ОТОБРАННЫЕ тексты
# . . . . . 9560  365732     6 k/kadawr n "Кадавр" "Псион" k~kadawr 2021.04.03
  print("; hitT.1 hitP.2 numP.3 id_P.4 id_T.5 \"namP\".6 \"namT\".7 id_F.8 datJ.9") >fLst
  print("; hitT.1 hitP.2 numP.3 id_P.4 id_T.5 \"namP\".6 \"namT\".7 id_F.8 datJ.9") >fLow

  mkRpt2( "upDat_datS  1-st_day   numS xDel/=Keep hitP  numP   hitT id_P id_T")
  for(int1=nSel;int1>0;int1--)mkRpt2(aSel[int1])
  print(";     datS_timS.1     datJ.2  numP.3  hitP.4 id_F.5 id_P.6 \"namP\".7") >fMig
  for(int1=1;int1<=nMig;int1++)print(aMig[int1])                        >fMig
#        2021.04.04_00:22:48 2021.04.03   186   15887 a~arh a/arh "Арх"

# upDat_datS  1-st_day   numS xDel/=Keep hitP  numP   hitT id_P id_T
# 2021.04.17-2021.04.16     4  0.0% x       ~     ~      ~ ~    ~
# 2021.04.18-2021.04.17     3  0.0% x       ~     ~      ~ ~    ~
# 2021.04.21-2021.04.20  1985  6.6% x  200017    14  20113 z/zhan flibustain
# 2021.04.22-2021.04.21 19691 65.7% =  791291     1  61567 m/metelxskij_n_a wtt-2
# 2021.04.23-2021.04.21  8266 27.6% =  241332    13  29405 r/raba_b_i molitva-113

  print(infH)                                                           >fLst
  print(infH)                                                           >fMig
  print(infH)                                                           >fLow
#   print(infH)                                                           >fRpt
# ;2B stat 2021.04.26:sEnd 1457:nPre 20102:hPre 1457:miss 300:minT 548:hitL 30075:nHit last~01:01:31~
  mkRpt1(";2B stat"sprintf(" %s:sEnd %5s:nPre %6s:hPre %5s:miss"\
,sEnd,nPre,hPre,nMig-nEnd)" "minT":minT "hStD":hitL "nHit":nHit last~"substr(mark,12)"~")
# ;2C scan 2021.04.24:dEnd 28554:nEnd 60688:hEnd 30011:nMig 1592:tNum 10:nGis 29173:nLow mod:! OkV:95.1%
  str1=substr(sprintf("%1.1f",nEnd*100/nMig),1,4)
  mkRpt1(";2C scan"sprintf(" %s:dEnd %5s:nEnd %6s:hEnd %5s:nMig %s:tNum %s:nGis %s:nLow %s OkV:%s% "\
,dEnd,nEnd,hEnd,nMig,tNum,ripP,nLow,vOk,str1))
# ;2D =Пн= 1116:tNum OkV:89.0% mod:v 2024.04.28:dEnd 0:sNul 2024.04.29:done 19:50 00:15:09~wrks 1.06~ratW 32:dnLd 

# 2020.02.20, nvv, первые прикидки "что и как НАДА делать-с"
# 2020.03.28, nvv, рабочий макет (будем посмотреть...)
# 2020.05.25, nvv, aHits - 120 pages-! => midS=8000 -> 9600; minS=9750 -> 11700
# 2020.06.25, nvv, minor updates
#   + это излишне:  fDel=wDir"]bStat.del" - список списков оставляемых статистик
# 2020.05.31, nvv, полнота нужной выборки вычисляются по % в наличных статистиках:
#   >97% - всё ОК (выборка достаточна для сборки рейтинга), на завтра - 1 последний список
#   >75% - 2-е сутки 3-х суточного такта, на завтра - 2 последних списка
#   <=75% - 1-е сутки, на завтра - 1 последний список
# 2020.07.16, nvv, битые статистики теперь просто фиксируются в "]bStat.bad",
#     не прерывая весь процесс + уточнён алгоритм разграничения списков: xDel/=Keep
# 2020.08.29, nvv, мелкая косметика
# 2020.09.07, nvv, имя файла *.aHits (если пуста переменная fHist) ищется в общем логе "_siTop.#"
# 2020.09.18, nvv, слегка перепахано для более тонкого разбора наличности
#   + итоговый отчёты см. переменную wDir
#   + итоговый fLst формируется сразу отсортированный и оформленный
#     + в конце строк с атрибутами отобранных текстов - datJ (1-й_полный_день в прошлое)
# 2020.10.07, nvv, переделано (упорядочено) накопление, оценка и оформление итогов по датам
#     (для оценки пригодности к рассчёту, см. dEnd и dPre)
# 2020.11.03, nvv, добавленена работа с хитами 12мес раздела
# 2020.11.07, nvv, исправлена мелкая неточность вчисления "недостающего" в итоговом отчёте
# 2021.01.09, nvv, исправлена сборка масива aMig (для fTim даты обновления и Ко)
#     + изменен учёт и оформление разделов с низкими хитами за "12мес." или за "30дн." fLow
# 2021.01.29, nvv, minor turning
# 2021.03.25, nvv, в итогах явно указывается % годных к расчёту статистик
# 2021.04.09, nvv, серьёзно переделано (логика работы и унификация)
# 2021.04.09, nvv, minor changes
# 2021.05.02, nvv, косметика средней тяжести... ;)
# 2021.06.18, nvv, иной формат *.mig.bStat
# 2022.02.17, nvv, мелкое улучшение оживляжа + устранена мелкая неточность логики
# 2022.04.13, nvv, для расчёта дата aHits /см. datH/ должна быть "сегодня" (== "v", иначе "~")
# 2022.05.02, nvv, сводка по *.!.mig.bStat теперь в шапке этого списка
# 2022.12.30, nvv, сменил разрешение экрана /меньше пикселей/, пришлось менять оживляж
# 2023.03.09, nvv, was: set minT=300, now: 200
# 2023.06.22, nvv, нет в aHits(?), возьмём прямо из stat
# 2024.05.04, nvv, теперь НЕ обновлённые статистики с хитовыми текстами поднимают нижнюю
}

    Имя файла скрипта: "bStat.cmd" V-текст скрипта-V
- - - - - - - - -
@if not defined pMod @echo off
set nJob=bStat
echo %date% %time:~0,8% %nJob% Begs

::  основной и резервный URL Самиздата (желательно работать с резервом)
if NOT defined siUrl if exist \siUrl.budclub set siUrl=budclub.ru
if NOT defined siUrl set siUrl=samlib.ru

rem 2024.09.01, nvv, восстановлена полная выдача в общий лог jRpt
rem ! история изменений - в подвале

set jDat=%date%
:: примерно 1000 записей /ограничители для отладки ! НЕ нужны в штате/
rem set hitL=2200
:: примерно 200 записей
rem set hitL=6400
:: примерно 3000 записей
rem set hitL=1200
rem wDir - общее рабочее место
set wDir=%~d0\Jobs\
rem zDir - место для сегодняшних итоговых списков
set zDir=%~d0\Stor\wOld\%jDat%\
rem bStat.cmd - "обновлятель" статистик 30k разделов +список самых посещаемых за 30 дней произведений
rem ! обязателен список U:\Jobs\20??.??.??.aHits
rem = *.lst.bStat - итоговый "черновой" список топовых текстов {2021.04.20.v.lst.bStat}
rem + *.mig.bStat - отсортированный по моментам список файлов статистик{2021.04.20.v.mig.bStat}
rem ~ .upDatBad.bStat.# - список проблемных разделов {в этот раз}
rem ~ .upDatGis.bStat.# - список разделов с прорехами в статистике
rem ~ .upDatLow.bStat.# - список разделов, набравших h30k+ хитов, но меньше УТОЧНЁННОГО hitL

rem после запуска и проверки комплектности:
rem - если нет или пусто в #bStat или нет файла *.mig.bStat - тупо скачивается всё по aHits
rem иначе смотрится на наличие сегодняшнего файла %jDat%.upd.2do.2do {"надо сделать"}
rem   есть - значит была авария и следует продолжит с места, где прервали
rem   нет - смотрится расклад в: fHIt и fMig
rem NB. ДО начала скачивания на экран выдаётся оный расклад и запрашивается явное "ОК" {"Y"}

rem OS windows - должны быть настроены системные переменные окружения:
rem %time% - HH:MM:SS,tt HH<=9 -> "HH" == " H" лидирующий пробел для часа меньше 10
rem %date% - YYYY.mm.dd

rem основные сеты и прочая подготовка инструментария...
set errInf=
rem dnLd - счётчик /формально/ успешно скачанного {НЕ 0b}
set dnLd=0
rem ratW - темп скачивания {секунд на один файл в среднем}
set ratW=0
rem cNum - счётчик-индикатор числа скачиваемых статистик
set cNum=0
rem minT - минимальные допустимые хиты текста {меньше - брак/отсев/etc - для bStat.awk}
set minT=200
rem jDir - место для оперативных файлов
set jDir=%wDir%#%nJob%\
if NOT exist %jDir%*.* mkDir %jDir%
if errorLevel 1 set errInf=fail mkDir %jDir% & goto errExit
rem aChk - анализатор текущего расклада по спискам, выдаёт что следует: грузить/удалить/не_трогать
set aChk=%~dpn00.awk
rem aScn - сканер статистик, строит черновой список топовых текстов {и *.mig.%nJob% в частности}
set aScn=%~dpn0.awk
rem эти скрипты обязаны быть
for %%A in (%aChk% %aScn%) do if NOT exist %%A set errInf=NO %%A found & goto errExit
rem jRpt - общий отчёт с итоговыми сводками процессов
set jRpt=%wDir%_siTop.#
rem sNul счётчик "статистик недоступно" {скачано 0b}
set sNul=0
rem wGetSiz - размер скачанного файла {default 1b минимум}
set wGetSiz=1
rem wGetTot - размер скачанного файла {default 1b минимум}
rem set wGetTot=0
rem bErr - оперативный {обнуляемый} файл для пометок CMD{скачивание} + AWK{сканирование}
set bErr=%wDir%.upDatBad.%nJob%.#
rem f2do - список "НАДО сделать сегодня"
set f2do=%wDir%%jDat%.upd.2do.2do
rem fPas - список "игнорировать" /пропустить/
set fPas=%wDir%%jDat%.upd.pas.2do
rem fDon - список "УЖЕ сделано сегодня"
set fDon=%wDir%%jDat%.upd.don.2do
rem rDon - число уже сделанного
set rDon=0
rem  fSta - файлы статистики в #bStat
set fSta=%jDir%?~*.stat.htm
::  nSuf - файл статистики nvv /общая часть/
set nSuf=n~nosow_w_w.stat.htm
::  nFil - полное имя обновляемого файла статистики nvv
set nFil=%jDir%%nSuf%
::  nDat - последняя наличная дата статистики nvv в формате "yyyy.Mns.d" /like: "2022.Jul.3"/
set nDat=
::  nDir - склад для накопления nvv.stats /должен быть/
set nDir=%~d0\Stor\nvv\
if NOT exist %nDir%*.* mkDir %nDir%
if errorLevel 1 set errInf=fail mkDir %nDir% & goto errExit
:: выясним последнюю дату обновления статистики nvv на складе для
for %%A in (%nDir%*%nSuf%) do set tmp0=%%A
if defined tmp0 (
  for /F "tokens=1-9,*" %%A in (
'gawk.exe "{if(match($0,/<li><i>.+\. \(... (...) (..) ..:..:.. (20..)\)<\/i>/,a)){print(a[3],a[1],a[2]);exit}}" %tmp0%'
  ) do set nDat=%%A.%%B.%%C
)
:: и обрадуем наблюдатеоя касаемо
echo nDat:%nDat%
if NOT exist %zDir%*.* mkDir %zDir%
if errorLevel 1 set errInf=fail mkDir %zDir% & goto errExit

:: fHit - ВХОДНОЙ список *.aHits {последний из и запомнить его имя} ОБЯЗАТЕЛЕН
set fHit=
for %%A in (%wDir%20??.??.??.aHits) do set fHit=%%A
if NOT defined fHit set errInf=20??.??.??.aHits NOT found & goto errExit
rem ;1A hits 6:xNam 453:xNum 103786:xPas 2024.05.10:hDat 446433:hMax 1043:hPag 1050:add2 30591:n30k 280:h30k 1081:dnLd 0.11~ratW 2024.05.10:done 01:15:04~wrks 10:58 
for /F "tokens=1-2,*" %%A in (
  'gawk.exe "{if(match($0,/^;1A .+ ([0-9]+):n30k ([0-9]+):h30k /,a)){print(a[1],a[2]);exit}}" %fHit%'
) do (
  set hitN=%%A
  set h30k=%%B
)
if NOT defined hitL set hitL=%h30k%
for /F "tokens=1-2,*" %%A in (
  'gawk.exe "{if(match($0,/^;1A .+ ([0-9]+):hMax .+ ([^ ]+):done /,a)){print(a[1],a[2]);exit}}" %fHit%'
) do (
  set hMax=%%A
  set hitD=%%B
)
rem э ключи fHit: hMax и hitD
set tmp0=*
if .%hitD% == .%jDat% set tmp0==
echo %tmp0% fHit:%fHit% - - - - %hitD%:hitD %hitN%:hitN %hitL%:hitL

rem  fMig - отсортированный и размеченный список дат обновления статистик 2022.01.21.!.mig.bStat ЖЕЛАТЕЛЕН
set fMig=
for %%A in (%wDir%20??.??.??.?.mig.%nJob%) do (
  set fMig=%%A
  set migD=%%~tA
)
if defined migD set migD=%migD:~0,10%
if .%migD% == .%jDat% (
  echo = fMig:%fMig% - %sEnd%:sEnd %nPre%:nPre
) else (
  set fMig=
  set migD=
  echo X fMig: -- NO or OLD
)

:: смотрим дату файлов статистик по r~raba_b_i.stat.htm
set rabD=
for %%A in (%jDir%r~raba_b_i.stat.htm) do set rabD=%%~tA
if defined rabD set rabD=%rabD:~0,10%
if .%rabD% == .%jDat% (
  echo = staF:%rabD%
) else (
  set rabD=
  echo X staF: -- NO or OLD
)

:: -1 rabD пусто /сегодняшних статистик нет/ & migD есть /сегодняшний/  - криминал!
if defined migD if NOT defined rabD set errInf=err: NO 2day *.stat`s BUT is 2day fMig & goto errExit

rem НЕ сегодняшние 2do точно НЕ нужны! разбипаемся касаемо сегодняшних
set c2do=0
for %%A in (%wDir%*.2do) do call :chkDel2do %%A
if defined errInf set errInf=%errInf% & goto errExit

:: если НЕ падало уже начатое, то идём начинать...
if %c2do% == 0 goto beg2day

:: таки начинали, но списков 2do некомплект! НЕ хорошо-с...
if NOT %c2do% == 3 set errInf=NOT 3 2day.*.2do files & goto errExit
:: c2do == 3 /упало в процессе скачивания, надо бы продолжить.../
set m2do=3
for /F "tokens=1-9,*" %%A in ('gAwk.exe -f %aChk%') do (
  set rDon=%%A
  set r2do=%%B
)
set j2do=reSume
set jInf=RESUME dnLding
:: - выдать сводку "сделано/осталось" - req - ВОЗОБНОВИТЬ!
echo [!] f2do{%s2do%}: %rDon%:done %r2do%:2do
goto reqOK

:beg2day rabD есть & migD пусто /упало при сборке списка/ - строим mig НЕ глядя!
if NOT defined migD if defined rabD (
  echo ! NO fMig, but upDated staF, HAVE to scan staF...
  call :reCreMig
  if defined errInf goto nExit
  goto ending
)

:: ОК, НЕ законченного нема, а что исть?
set m2do=1
for /F "tokens=1-9,*" %%A in (
  'gawk.exe -f %aChk%'
) do (
  set nPas=%%A
  set nDel=%%B
  set nUpd=%%C
  set r2do=%%D
)
if "%nPas%" == "]" (
  set errInf=err in gAwk %m2do%:m2do %nDel%:nDel %nUpd%;nUpd %r2do%:r2do & goto errExit
)

:: если СЕГОДНЯШНИЙ собран по СЕГОДНЯШНЕМУ fHit - делать нечего - озадачим...
if NOT %r2do% == 0 goto next0
if defined pMod (
  echo == all is done today already
  goto :eof
)
echo NOTHING to do NOW: %nDel%:nDel %nUpd%;nUpd %r2do%:r2do
echo ?WHAT do you want repeat: dnLd OR Scan
set tmp0=
echo ?ok to goOn [L/S] == y
set /p tmp0=?[no]?
if /i %tmp0%. == L. (
  echo Ok, REPEAT files dnLoading
  for /F %%A in ('gawk.exe "BEGIN{print(systime());exit}"') do set wrks=%%A
  goto dlHist
)
if /i %tmp0%. == S. (
  echo Ok, REPEAT files Scanning
  call :reCreMig
  if defined errInf goto nExit
  goto ending
)
set errInf=job canceled & goto errExit

:next0 если нет файла fMig или он НЕ сегодняшний, нужно скачивать ВСЁ
if %nPas% == -- (
  set j2do=dlHist
  set jInf=DnLd ALL %r2do%
  goto reqOK
)
:: со свежим aHits нужно лишь удалить ненужное и притащить отсутствующее
set j2do=updMig
set jInf=fresh: %nDel%:nDel %nUpd%;nUpd %r2do%:r2do

:reqOK что можно и следует делать, определились, надо запросить "добро" на...
echo [!] HAVE to %jInf% files
set tmp0=
echo ?ok to goOn [yes] == y
if defined pMod goto noReq
set /p tmp0=?[no]?
if /i NOT %tmp0%. == y. (
  set errInf=job canceled & goto errExit
)
:noReq таки нада работать... wrks - общее время работы процесса /после "y" в ответ на запрос/
for /F %%A in ('gawk.exe "BEGIN{print(systime());exit}"') do set wrks=%%A
goto %j2do%

:updMig подготовка к выборочному по fMig скачиванию статистик
set m2do=2
gawk.exe -f %aChk%
if errorLevel 1 set errInf=err in gAwk with %m2do%:m2do & goto errExit
rem список ошибок должно освобождать от старья
echo. >nul 2>%bErr%
goto reSume

:dlHist подготовка к скачиванию всех годных статистик по списку в fHit
set m2do=2
gawk.exe -f %aChk%
if errorLevel 1 set errInf=err in gAwk with %m2do%:m2do & goto errExit
:: проверяем: создаём/чистим рабочий каталог
if NOT exist %jDir%*.* (
  mkDir %jDir%
  if errorLevel 1 set errInf=fail mkDir %jDir% & goto errExit
)
if     exist %jDir%*.* (
:: !!!
  erase /Q/F %jDir%*.*
  if errorLevel 1 set errInf=fail erase %jDir%*.* & goto errExit
)
rem список ошибок должно освобождать от старья
echo. >nul 2>%bErr%

:reSume (ре)старт скачивания, нужны: f2do и fDon скачивается разницы (есть в первом, но нет во втором)
set m2do=4
:: мало ли что, без f2do ловить нечего!
if NOT exist %f2do% set errInf=NO %f2do% no dnLd continue & goto errExit
rem красивый оживляж уместен всегда!
set begT=%time:~0,8%
echo ~ curDLjob: %rDon%:nDon %r2do%:r2do %begT%
:: а кратно ли 100 число в r2do?
for /F %%A in ('gawk.exe "BEGIN{print(%r2do%%%100);exit}"') do set tmp0=%%A
set /a jMax=%r2do%/100
:: если НЕ кратно, то добавим плюсик к скачиваемым сотням
if NOT %tmp0% == 0 set jMax=%jMax%+
set jMax=%jMax%      .
set jMax=%jMax:~0,5%
rem запустим "таймер" качалки
for /F %%A in ('gawk.exe "BEGIN{print(systime());exit}"') do set r100=%%A
set ratW=%r100%
for /F "tokens=*" %%A in ('gAwk.exe -f %aChk%') do (
  if errorLevel 1 set errInf=gawk err: %%A & goto nExit
  call :reqSfil %%A
  if defined errInf goto nExit
)
rem остановим "таймер" качалки время работы в секундах
for /F %%A in ('gawk.exe "BEGIN{print(systime()-%ratW%);exit}"') do set ratW=%%A
rem среднее время скачивания файла в секундах
if %dnLd% == 0 (set ratW=0) else (
  for /F %%A in ('gawk.exe "BEGIN{print(sprintf(\"%%3.2f\",%ratW%/%dnLd%));exit}"') do set ratW=%%A
)
echo.
echo. == %cNum% %begT%-%time:~0,8% %ratW%~ratW
rem если дошли досюда - скачивание ОК
call :reCreMig
if defined errInf goto nExit
goto ending

:ending  выцепим главные итоги разбора статистик
rem ;2B stat 2021.04.26:sEnd  1457:nPre  20102:hPre  1457:miss 300:minT 548:hitL 30075:nHit last~01:01:31~
for /F %%A in ('gawk.exe "{if(match($0,/ ([0-9]+):miss /  ,a))print(a[1])}" %fMig%') do set miss=%%A
rem ;2C scan 2021.04.24:dEnd 19719:nEnd  60688:hEnd 30012:nMig 1657:tNum 11:nGis 29154:nLow mod:! OkV:65.7%
for /F %%A in ('gawk.exe "{if(match($0,/ ([0-9]+):tNum /  ,a))print(a[1])}" %fMig%') do set tNum=  %%A
for /F %%A in ('gawk.exe "{if(match($0,/ ([\.0-9]+):dEnd /,a))print(a[1])}" %fMig%') do set dEnd=%%A
for /F %%A in ('gawk.exe "{if(match($0,/ mod:(.) /        ,a))print(a[1])}" %fMig%') do set  mod=%%A
for /F %%A in ('gawk.exe "{if(match($0,/ OkV:([0-9\.]+)%%/,a))print(a[1])}" %fMig%') do set  OkV=%%A
set tNum=%tNum:~-4%
rem если грандов обнесли - готовый список использовать НЕЛЬЗЯ!
if "%mod%" == "!" (
  set jYes==NO
  set mark=~
) else (
  set jYes==OK
  set mark==
)
rem преобразуем секунды в время работы {в обычном формате "чч:мм:сс"}
for /F %%A in ('gawk.exe "BEGIN{print(strftime(\"%%H:%%M:%%S\",systime()-%wrks%+46800));exit}"') do set wrks=%%A
rem оформим подвал списка... соственно сборка закончена; jLst - итоговый список топовых текстов
gawk.exe "BEGIN{printf(\";2D %%s \",strftime(\"%mark%%%a%mark%\",systime()));exit}" >>%jLst%
echo.^
%tNum%:tNum ^
OkV:%OkV%%% ^
mod:%mod% ^
%dEnd%:dEnd ^
%sNul%:sNul ^
%jDat%:done ^
%time:~0,5% ^
%wrks%~wrks ^
%ratW%~ratW ^
%dnLd%:dnLd >> %jLst%
echo = itog ^
%tNum%:tNum ^
%sNul%:sNul ^
%ratW%~ratW ^
%jDat%:done ^
%wrks%~wrks ^
%time:~0,5%
rem и в общий отчёт ентот итог занесть нада-с
gawk.exe "{if(match($1,/^;2[BCD]$/))print($0)}" %jLst%  >> %jRpt%
rem и в fMig строку ;2D тож
gawk.exe "{if(match($1,/^;2D$/))print($0)}" %jLst%  >> %fMig%
rem уложим свежак в склад на полочку-с...
for %%A in (%wDir%*.%nJob%) do (
  copy /b /y %%A %zDir% > nul
  if errorLevel 1 set errInf=fail copy %%A to %zDir% & goto nExit
)
rem уложим туда же замеченные "дыры" и "недобрало", ЕСЛИ сборка ВОЗМОЖНА
if "%mod%" == "v" (
  copy /b /y %wDir%.upDatGis.bStat.# %zDir%%dEnd%.%mod%.gis.%nJob% > nul
  if errorLevel 1 set errInf=fail copy .upDatGis.bStat.# to %zDir% & goto nExit
  copy /b /y %wDir%.upDatLow.bStat.# %zDir%%dEnd%.%mod%.low.%nJob% > nul
  if errorLevel 1 set errInf=fail copy .upDatLow.bStat.# to %zDir% & goto nExit
)
rem подудим где нада "готово-с!"
set itog=%fMig%

:nExit если было проблем-с - известим всяко (особливо при запуске "с выключение компа")
if defined errInf echo !?. %errInf% & goto :eof
rem как оказалось, нулевые файлы таки заводятся иногда, проверим и прибьём найденное
for /F %%A in (
  'dir /a:-d /-c /o:s %fSta% ^| gawk "{if(NR>5)if($3>0){print NR-6;exit}}"'
) do set nulF=%%A
if NOT %nulF% == 0 (
  echo finds: %nulF% zero file{s} *.stat.htm, erasing...
  for /F %%A in (
    'dir /a:-d /-c /o:s %fSta% ^|gawk "{if(NR>5){if($3==0){print $4}else{exit}}}"'
  ) do (
    erase %jDir%%%A
    if errorLevel 1 set errInf=fail erase %%A & goto :eof
  )
)
rem  <li><i>Статистика рассчитывается раз в сутки. (Thu May 18 02:05:32 2023)</i>
:: смотрим дату обновления свежескачанной статистики nvv
for /F "tokens=1-9,*" %%A in (
'gawk.exe "{if(match($0,/<li><i>.+\. \(... (...) (..) ..:..:.. (20..)\)<\/i>/,a)){print(a[3],a[1],a[2]);exit}}" %nFil%'
) do (
  set tmp0=%%A.%%B.%%C
  set tmpA=%%A
  set tmpB=%%B
  set tmpC=%%C
)
:: НЕ изменилась в сравнении с уже имещщейся - значит и суетиться касаемо не надо
if %nDat%. == %tmp0%. goto nvvOk

:: ! иная дата, перекодируем месяц, построив дату в стандартном формате "гггг.мм.дд"
if %tmpB% == Jan set tmpB=01
if %tmpB% == Feb set tmpB=02
if %tmpB% == Mar set tmpB=03
if %tmpB% == Apr set tmpB=04
if %tmpB% == May set tmpB=05
if %tmpB% == Jun set tmpB=06
if %tmpB% == Jul set tmpB=07
if %tmpB% == Aug set tmpB=08
if %tmpB% == Sep set tmpB=09
if %tmpB% == Oct set tmpB=10
if %tmpB% == Nov set tmpB=11
if %tmpB% == Dec set tmpB=12
:: +добавляем /при нужде/ лидирующий ноль в день месяца
if %tmpC:~1,1%. == . set tmpC=0%TmpC%
:: и прикапываем...
echo nDat: %nDat% - %tmp0%
rem echo copy /b %nFil% %nDir%%tmpA%.%tmpB%.%tmpC%.%nSuf%
copy /b %nFil% %nDir%%tmpA%.%tmpB%.%tmpC%.%nSuf% >nul
rem echo run: D:\#ProgFile\Viewer\Viewer.exe %nDir%%tmpA%.%tmpB%.%tmpC%.%nSuf%
echo ! new NVV.stat, use U:\zNvvStat.cmd
:nvvOk
rem set /a wGetTot=%wGetTot:~0,-3%.%wGetTot:~-3% + 500
echo %jDat% %time:~0,8% %~nx0 Ends (%dnLd%:dnLd %miss%:miss jYes=%jYes%)
goto :eof

:reqSfil 2do id_P - обслуживание раздела согласно операции 2do /+оживляж +пополнение fDon/
set /a cNum+=1
set id_P=%2
set wFil=%jDir%%id_P:~0,1%~%id_P:~2%.stat.htm
set wUrl=%siUrl%/%id_P%/stat.shtml
rem 1 - pas - "-" - пропустить /даже если нету-с/
set tmp0=-
if %1 == 1 goto show
rem 3 - del - "X" - удалить /если есть/
if %1 == 3 (
  set tmp0=-
  if exist %wFil% (
    set tmp0=x
    erase /F/Q %wFil%
    if errorLevel 1 set errInf=fail erase %wFil% & goto :eof
  )
  goto show
)
rem 2 - upd - "*" - если нет - скачать
if exist %wFil% (
  set tmp0=~
  goto show
)
set tmp0=.
call wGetUrl2fil.cmd %wUrl% %wFil%
if defined errInf goto :eof
rem     set /a wGetTot+=%wGetSiz%
if %wGetSiz% == 0 (
  set /a sNul+=1
  echo x sNul %wUrl% >> %bErr%
  erase /F/Q %wFil%
  if errorLevel 1 set errInf=fail erase %wFil% & goto :eof
)

:show
echo %* >> %fDon%
if "%cNum:~-1%" == "0" set tmp0=%cNum:~-2,1%
gawk.exe "BEGIN{printf(\"%tmp0%\");exit}"
if NOT "%cNum:~-2%" == "00" goto :eof
set tmp0=    %cNum%
set tmp0=%tmp0:~-6,4%.%jMax%
for /F "tokens=1-9,*" %%J in (
  ' gawk.exe "BEGIN{s=systime();printf(\"%%s %%9.2f\",s,(s-%r100%)/100);exit}" '
) do (
  set r100=%%J
  set tmp0=%tmp0% %%K
)
echo. %tmp0% f/s
goto :eof

:reCreMig разбор содержимого файлов статистики, сначала убираем точно устаревшее когда-то ранее
for %%J in (%wDir%*.old) do (
  erase /F/Q %%J
  if errorLevel 1 set errInf=fail erase %%J & goto :eof
)
rem двигаем в .old то, что устареет сейчас
for %%J in (%wDir%*.%nJob% %wDir%*.2do) do (
  move /y %%J %%J.old
  if errorLevel 1 set errInf=fail move %%J 2old & goto :eof
)
:noUpdNow собственно построение с нуля jLst и fMig
echo ! minT.%minT% hitL.%hitL% wDir.%wDir% fHit.%fHit%
gawk.exe -f %aScn% %jDir%*.stat.htm
if errorLevel 1 set errInf=fail scaning *.stat.htm
rem затем выявляем свежак jLst - итоговый список годных "начерно" текстов, набравших minT хитов за 30 дней
set jLst=
for %%J in (%wDir%20*.lst.%nJob%) do set jLst=%%J
if NOT defined jLst set errInf=fail mk 20*.lst.%nJob% & goto :eof
rem и свежак fMig - итоговый список годных "начерно" текстов, набравших minT хитов за 30 дней
set fMig=
for %%J in (%wDir%20*.mig.%nJob%) do set fMig=%%J
if NOT defined fMig set errInf=fail make 20*.mig.%nJob%
goto :eof

:chkDel2do %%A НЕ сегодняшние 2do точно НЕ нужны!
if /i %1 == %f2do% set /a c2do+=1 & goto :eof
if /i %1 == %fDon% set /a c2do+=1 & goto :eof
if /i %1 == %fPas% set /a c2do+=1 & goto :eof
erase /F/Q %1
if errorLevel 1 set errInf=fail erase %1
goto :eof

:errExit реакция на проблему: в пакете - выход
if defined pMod goto :eof
:: автономно - на экран + прекращение работы
echo %errInf%
exit

rem 2019.07.15 creation from siTop-dStat.cmd {2019.07.11}
rem ...
rem 2020.01.06, nvv, {!}ЕСЛИ гранд СИ попал в отсеянные по ДАТЕ обновления - сборка рейтинга НЕВОЗМОЖНА!
rem 2020.03.27, nvv, радикально переделано {ВСЕ проверки и ВСЕ итоги - в bStat1.awk}
rem   + более тонкая работа с наличностью {с уже имеющимися файлами статистик}
rem 2020.04.25, nvv, some updates
rem 2020.05.31, nvv, нижняя граница для разделов из списка *.aHits - hitP>hitL {==670}, а не конец списка
rem 2020.06.05, nvv, hitL=665
rem         08            650
rem         10            645
rem         14            610
rem 2020.06.18, nvv, нижнюю границу {hitL=NNN} можно задать файлом-маркой "NNN.lowHits"
rem 2020.08.21, nvv, статистики, обновлённые "СЕГОДНЯ" или с той же датой ВЕРХНЕЙ границы интервала
rem   НЕ удаляются! Т.е. киллер не трогает сегодняшний комплект для рассчёта
rem 2020.09.18, nvv, слегка перепахано для более тонкого разбора наличности
rem   + итоговый jLst формируется сразу отсортированный и оформленный
rem     + в конце строк с атрибутами отобранных текстов - datJ {1-й_полный_день}
rem 2020.09.30, nvv, исправлена неточность в работе со списком BadStats {если упомянут в ]bStat.rpt}
rem 2020.10.12, nvv, мелкая косметика
rem 2020.11.02, nvv, исправлена ошибка обработки списка LowStats
rem 2020.11.13, nvv, будКлуб - глупость
rem 2020.11.16, nvv, будКлуб - глупость? не факт... ;{
rem 2020.12.18, nvv, добавлена возможность принудительно задавать дату верхней границы интервала
rem     в 30 дней для обсчёта {занадобилось после аварий 2020.11.19 - "ледяной дождь" + паралич в СИ}
rem 2020.12.28, nvv, \siUrl.budclub turn to budclub.ru
rem 2021.01.29, nvv, если в корне нет NNN.lowHits, hitL == хиты "за 12мес" 30000-го раздела в *.aHits
rem 2021.03.23, nvv, gawk для вычленения первых 30000+ записей aHits
rem 2021.03.25, nvv, в итогах явно указывается % годных к расчёту статистик
rem 2021.05.17, nvv, очередная оптимизация с унификацией...
rem 2021.05.27, nvv, границы "от-доНЕвключая" запоминаются ДО обновления и юзаются ПОСЛЕ падения {если}
rem 2021.06.19, nvv, иной формат {подчерк "_" вместо пробела " " в границах updB & updE}
rem 2021.07.30, nvv, мелкая косметика
rem 2021.11.16, nvv, мелкая косметика касаемо tNum {пробелы слева до 4-х знаков}
rem 2022.01.19, nvv, начало оптимизации при рестарте {за день; ресканирование ВСЕХ статистик избыточно}
rem 2022.02.06, nvv, радикально переделано, теперь готово работать сразу /без дум глубоких пред/
rem 2022.02.16, nvv, таки заработало(!) вменяемо сие радикально-с переделанное
rem 2022.02.23, nvv, исправлена пара неточностей
rem 2022.03.04, nvv, нулевые файлы статистик удаляются /если найдутся/ перед завершением работы
rem 2022.03.23, nvv, теперь список статистик из aHIts /при скачивании ВСЕХ/ сортируется по алфавиту
rem 2022.04.04, nvv, теперь таймеры показывают не текущее время, а прошедшее с запуска
rem 2022.07.11, nvv, если делать нечего, то и нефик искать нулевые файлы статистики
rem 2022.08.10, nvv, +updNum==updN - возможнось явно задать в .upDatSet.bStat.# кол-во обновляемых статистик
rem 2022.09.03, nvv, minor improvements
rem 2022.09.20, nvv, обихожено взаимодействие с bStat0.awk
rem 2022.09.29, nvv, исправлены ошибки считывания r2do при перезапуске упавшего процесса
rem 2022.10.15, nvv, minor improve
rem 2023.01.03, nvv, сменил разрешение экрана /меньше пикселей/, пришлось менять оживляж
rem   + добавлено прикапывание файла статистики nvv
rem 2023.01.15, nvv, minor cosmetics
rem 2023.03.09, nvv, was: set minT=300, now: 200
rem 2023.03.23, nvv, добавлено прикапывание "дыр" *.v.gis.bStat в статистике в Stor
rem 2023.04.16, nvv, сущая мелочь не нужная удалена
rem 2023.05.06, nvv, папка nDir перемещена в Stor и лишилась префикса '#'
rem 2023.05.21, nvv, исправлена ошибка в имени целефого файла в папке nDir + "DLобъём"
rem 2023.06.28, nvv, +поддержка: add2 - список разделов-потеряшек для добавления в расчёт
rem 2023.07.05, nvv, удалена поддержка: add2 потерянное вносится в список aHits
rem 2023.07.28, nvv, сокращена выдача в общий лог jRpt
rem 2023.12.18, nvv, мелкая правка в диалоге выхода с паузой "== EXIT"
rem 2024.01.02, nvv, пауза после формирования списка 2do дабы убедиться при сомнениях
rem 2024.02.20, nvv, исправлена работа с изменившимся aHits
rem 2024.02.20, nvv, исправлена работа с изменившимся aHits
rem 2024.06.01 16:47 серьёзно переделано под ежедневное пополнение статистик
rem 2024.08.14 поддержка пакетного режима /без запросов по-мелочи и EXIT-ов/

    Имя файла скрипта: "bStat0.awk" V-текст скрипта-V
- - - - - - - - -
BEGIN{          #  bStat0.awk анализатор текущего расклада статистик по спискам и по наличности
#   test=1          #  режим отладки - формируется выборка из *.mig.bStat удаляемого/обновляемого

#  режим/источники при составлении списка удалить/скачать
#  режимы (m2do): 1-сводка"dlAll" 2(1)-построчно.file 3-сводка"2doDif" 4(3)-построчно.StdOut
#  "1","2" - \Jobs\*.aHits - ОБЯЗАТЕЛЕН для этих режимов (без - бессмысленно)
#  "1","2" - \Jobs\*.mig.bStat - ОБЯЗАТЕЛЕН для ОБНОВЛЕНИЯ по свежему aHits
#  "3","4" - \Jobs\*.2do - списки .2do. .don. и .pas. за "СЕГОДНЯ"
# [!] envVar m2do задаёт режим работы (1..4); нечётные: "справка", чётные:
#  "2" == "комплект файлов 2do"; "4" == не "оптиченное" на StdOut

# 2024.05.28, nvv, исправоена ошибка в отработке уделения статистик, выпавших из aHits
# ! прочая история в подвале

#   hitL=6400
  jDat=strftime("%Y.%m.%d")                     #  "сегодня"
#       jDat="2022.09.17"
  if(test){
    m2do=1  #  job: 1-сводка"dlAll" 2(1)-построчно.file 3-сводка"2doDif" 4(3)-построчно.StdOut
    jDir=".\\"                                  #  место рабочих файлов
    wDir="V:\\Jobs\\"                           #  место общих файлов-списков
    fHit=wDir "2024.05.21.aHits"                #  ВХОДНОЙ список *.aHits
    fMig=wDir "2024.05.19.v.mig.bStat"  #  отсортированный список моментов обновления статистик
  }else{
    m2do=getEnv("m2do") # 1-сводка"upgMig" 2-построчно.file 3-сводка"2doDif" 4-построчно.StdOut
    hitL=getEnv("hitL")                       #  принудительное задание нижней границы по хитам
    jDir=getEnv("jDir")                         #  место рабочих файлов
    wDir=getEnv("wDir")                         #  место общих файлов-списков
    fHit=getEnv("fHit")                         #  ВХОДНОЙ список *.aHits
    fMig=getEnv("fMig")                 #  отсортированный список моментов обновления статистик
  }
# print hitL"---"h30k"---"jDir"---"f2do
  if(wDir==""){
    errS="] NO envVar: 'wDir'"
    exit
  }
  f2do=wDir jDat".upd.2do.2do"                  #  то, что НУЖНО "удалить/обновить"
  fDon=wDir jDat".upd.don.2do"                  #  то, что УЖЕ "удалено/обновлено"
  fPas=wDir jDat".upd.pas.2do"                  #  то, что пропущено (для полноты картины-с)

  if((m2do==3)||(m2do==4)){                     #  секция "ПРОДОЛЖИМ?"
    nDon=0        #  загрузка списка fDon - "уже сделано" (может быть пуст) - защита от падений
    while((getline jj<fDon)>0){
      if(match(jj,/^([23]) ([^ ]+)/,aj)){       #  "2 m/moskalenko" - обновить
        nDon++                                  #  "3 s/s_w" . . . . - удалить
        aDon[aj[2]]=aj[1]                       #  статус "КАК" /раздел/ был "оптИчен"
      }
    }
    close(fDon)
    n2do=0                          #  загрузка списка f2do - то, что НУЖНО "удалить/обновить"
    while((getline jj<f2do)>0){
      if(match(jj,/^([23]) ([^ ]+)/,aj)){
        if(!(aj[2] in aDon)){
          a2do[++n2do]=aj[1]" "aj[2]            #  статус: "КАК птИчить" этог раздел
        }
      }
    }
    close(f2do)

    if(nDon+n2do==0){
      errS="] Nothing2do: '*2do' - empty"
    }else{
      if(m2do==3)print(nDon,n2do)       #  выдача итога на StdOut - СВОДКА: "сделано НЕсделано"
      else for(jj=1;jj<=n2do;jj++)print(a2do[jj])  #  - ПЕРЕЧЕНЬ не оптиченных ID
    }
    exit
  }

# секция "НАЧНЁМ": читаем aHits (+ mig.bStat) => 3 файла: "сделать"+"готово"(пуст)+"пропустить"
  nHit=0    #  загрузка списка aHits. первичное заполнение массива id_P (дОлжных быть раздлов)
  while((getline jj<fHit)>0){                   #  чтение aHits
#  362225      6    1133      3 k/kadawr "Кадавр" "no•comments"
# ; hitP.1 numP.2 sizK.3 4.sizN 5.id_P 6."namP" 7."moto"
    split(jj,aj)
    if(match(aj[1],/^[0-9]+$/)){
      if(aj[4])aHiH[aj[5]]=aj[1]                #  пустые разделы нам не интересны...
    }else{
# ;1A hits 6:xNam 453:xNum 103792:xPas 2024.05.12:hDat 447277:hMax 1043:hPag 1146:add2 30664:n30k 282:h30k 1085:dnLd 0.22~ratW 2024.05.12:done 01:13:24~wrks 11:04
      if(match(jj,/;1A .+ ([^ ]+):hMax .+ ([0-9]+):n30k ([0-9]+):h30k .+ ([^ ]+):done/,aj)){
        hMax=aj[1]                              #  хиты топового раздела
        h30k=aj[3]                              #  хиты 30k раздела
        n30k=aj[2]                              #  разделов с хитани h30k+
        hitD=aj[4]                              #  дата в aHits
      }
    }
  }
  close(fHit)
  if(!length(aHiH)){
    errS="] "fHit" NO recs"                 #  а пусто!
    exit
  }
  if(hitL!="")h30k=hitL
  for(j0 in aHiH){              #  вычленяем топовые разделы для работы (хитов НЕ меньше h30k)
    if(aHiH[j0]-h30k>=0){                       #  отбираем в рабочий массив...
      aHit[j0]=aHiH[j0]                   #  разделы с достаточной посещаемостью (И не пустые)
      nHit++                                    #  число таких, годных разделов
    }
  }
  
#  чтение списка fMig. формирование массива статусов наличных id_P
  migD="-"                                      #  fMig нет (или НЕ "сегодня")
  if(fMig!=""){ #  вообще-то этот файл может отсутствовать, но если есть, то не может быть пуст
    while((getline jj<fMig)>0){                 #  чтение mig.bStat
      split(jj,aj)
      if(match(aj[1],/^;/)){ # различие записей в секциях: "справка" и "данные" (даты статистик)
# ;2B stat 2022.02.10:sEnd 0:nPre 0:hPre 0:miss 300:minT 4530:hitL 500:nHit last~01:11:36~
        if(match(jj,/^;1A .+ ([^ ]+):hMax .+ ([^ ]+):done/,ak)){  #  данные "заюзанного" aHits
          hitM=ak[1]":"ak[2]              #  ключ ("hMax":"hitD"),aHits использованный в bStat
        }
# ;2D ~Пт~  624:tNum OkV:100.% mod:! 2024.05.23:dEnd 0:sNul 2024.05.24:done 13:51 00:00:15~wrks 0~ratW 0:dnLd 
        if(match(jj,/^;2D .+ ([^ ]+):done /,ak)){  #  данные "заюзанного" aHits
          migD=ak[1]                            #  дата сборки bStat
        }
      }else{                                    #  это /основная/ запись дат статистики раздела
# 0000.00.00_00:00:00 _bad_file_   0     0 w~wladimir_kasxjanow not_IN_aHits w/wladimir_kasxjanow
# 0000.00.00_00:00:00 _bad_file_ 891  3967 g~goncharow_d_a "No.Wen" g/goncharow_d_a
# 2022.09.14_00:39:10 2022.09.11 129 11429 s~sks s/sks "Скс"
# 2022.09.17_00:52:48 2022.09.15  92 15152 n~nosow_w_w n/nosow_w_w "Влад"
#  1                  2            3     4  5           6           7
        aMig[aj[6]]=aj[1] # "дата_время" обновления статистики этого id_P (2022.09.14_00:39:10)
        aNum[++nNum]=aj[6]                      #  место id_P в *.mig.*
      }
    }
    close(fMig)
  }

#  варианты разбраковки/построения 2do списков
  if(migD!=jDat){                   #  1 fMig - НЕ за "сегодня" (или нет) == качать ВСЁ по fHit
    if(m2do==1){
      if(test)print("nPas nDel nUpd nTot")      #  выдача справки по "2do" (качаем ВСЁ!)
      print("--","--",nHit,nHit)
    }else{                                      #  m2do==2 строим комплект файлов "2do"
      for(id_P in aHit)aUpd[++jj]=id_P
      jk=";9N "strftime("%H:%S")"~ "hMax":hMax "hitD":hitD 0:nDel "nHit":nUpd 0:nPas "
      asort(aUpd)
      for(jj=1;jj<=nHit;jj++)print(2,aUpd[jj]" ") >f2do #  затем (туда же) - на обновление
      print(jk)>fDon                            #  текущая метка для порядка
      print(jk)>fPas                            #  во все
      print(jk)>f2do                            #  три созданных списка
    }
  }else if(hMax":"hitD==hitM){      #  2 fMig - "сегодня" И по наличному fHit == НЕЧЕГО делать
    if(m2do==1){
      if(test)print("nPas nDel nUpd nTot")      #  выдача справки по "2do"
      print(nHit,"--","--",0)
    }else{
      print("")
    }
  }else{      #  3 fMig - "сегодня" И не по наличному fHit == нужно отрабатывать РАЗНИЦУ с fHit
    nPas=0
    nDel=0
    nUpd=0
    for(id_P in aMig){                          #  проекция aMig на aHit
      if(id_P in aHit){                         #  есть в aHits
        aPas[++nPas]=id_P                       #  1 pas "оставить"
      }else{
        aDel[++nDel]=id_P                       #  3 del "удалить"
      }
    }
    for(id_P in aHit){                          #  проекция aHit на aMig
      if(!(id_P in aMig)){                      #  нет в aMig?
        aUpd[++nUpd]=id_P                       #  2 скачать!
      }
    }
    if(m2do==1){
      if(test)print("nPas nDel nUpd nTot")      #  выдача справки по "2do"
      print(nPas,nDel,nUpd,nDel+nUpd)
    }else{                                      #  m2do==2 строим комплект файлов "2do"
      asort(aPas)
      asort(aDel)
      asort(aUpd)
  # ;9N 21:04~ 571717:hMax 2022.02.06:hitD --:nPre --:sEnd 0:nDel 493:nUpd 0:nPas 
      jk=";9N "strftime("%H:%S")"~ "hMax":hMax "hitD":hitD "nDel":nDel "nUpd":nUpd "nPas":nPas "
      for(jj=1;jj<=nPas;jj++)print(1,aPas[jj]" ") >fPas #  пропускаемое - в отдельный список
      for(jj=1;jj<=nDel;jj++)print(3,aDel[jj]" ") >f2do #  обрабатываемое - в другой, на удаление
      for(jj=1;jj<=nUpd;jj++)print(2,aUpd[jj]" ") >f2do #  затем (туда же) - на обновление
      print(jk)>fDon                              #  текущая метка для порядка
      print(jk)>fPas                              #  во все
      print(jk)>f2do                              #  три созданных списка
    }
  }
  exit
}

function getEnv(env1) {           #  найти в массиве ENVIRON значение переменной с именем env1
  for(env0 in ENVIRON){                   #  ! реГИстр букв в имени переменной МОЖЕТ быть лЮбОй
    if(tolower(env0)==tolower(env1)){           #  имя переменной совпадает с указанным?
      return(ENVIRON[env0])                     #  вернём значение этой переменной
    }
  }
  return("")                                    #  ничего нет? знать не судьба...
}

END{                                            #  отстрелялись; ну почти...
  if(errS!=""){
    print("")
    print(errS)                                 #  есть проблем-с => подудим
    exit -1                                     #  и на выход с вещами
  }
# 2021.04.20, nvv, created
# 2021.04.26, nvv, выходной список сортируется в порядке mig.bStat
# 2021.05.02, nvv, мелкая косметика
# 2021.05.29, nvv, полу-автоматический выбор границ удалить/обновить/скачать теперь здесь
# 2021.06.18, nvv, иной формат *.mig.bStat
# 2021.11.07, nvv, мелкая косметика
# 2022.02.14, nvv, радикально переделано и наконец-то заработало как надо
# 2022.02.23, nvv, исправлена пара неточностей
# 2022.03.12, nvv, уточнена интерпретация явно заданых границ обновления
# 2022.08.11, nvv, +updNum==updN - путь задать в .upDatSet.bStat.# кол-во обновляемых статистик
# 2022.08.22, nvv, уточнена работа с явными границами в .upDatSet.bStat.#
# а. updBeg~2022.08.20~ == с этого момента в дате обновления статистики НУЖНО скачать свежую копию
#     ! может быть пусто ~~ == "с начала списка"
#   б. updEnd~2022.08.20_01:18~  == с этого момента НЕ обновлять
#     ! может быть пусто ~~ == "до конца списка"
#   в. updNum~10~  == кол-во скачиваемых ТЫСЯЧ статистик с момента updBeg
#     ! или сначала, если updBeg не задано
#     + updEnd ИГНОРИРУЕТСЯ!
# !!! параметр (updBeg/updEnd/updNum) должен быть терминирован пробелом и стоять первым в строке
#     + иначе он игнорируется (считается пустым)
#     + используется ПОСЛЕДНЕЕ непустое вхождение параметра, если таковых не одно
#     + если пусты все три == явных (заданных вручную) границ нет
# 2022.09.22, nvv, исправлена работа с "ручными" границами в .upDatSet.bStat.# /более вменяемая/
# 2022.09.29, nvv, откат ненужного улучшения выдачи в m2do=3
# 2022.10.18, nvv, обустроен altStop - иное вычленение статистик "на upDat" /не по bStat.awk/
# 2023.01.14, nvv, altStop теперь не флаг, а число самых свежих НЕ обноляемых статистик
# 2023.01.18, nvv, altStop теперь не нужен, изменился рисунок обновления статистик
# 2023.04.20, nvv, более гибкий алгоритм поиска даты "до не включая" updEnd по вчерашнему раскладу
# 2023.05.21-2023.07.02, nvv, +поддержка: add2 - список разделов-потеряшек для добавления в расчёт
# 2023.07.05, nvv, удалена поддержка add2, потерянное вносится в список aHits
# 2023.07.15, nvv, исправлена неточность в обработке списка aHits
# 2023.10.15, nvv, иное разделение aMig на "обновить"/"пропустить" по самому старому "толстяку"
# 2023.12.18, nvv, статистики со статусом "_bad_file_" НЕ пропускаются а считаются отсутствующими
# 2024.04.01, nvv, изменился рисунок пополнения статистик - теперь ежедневно
#   ergo при ПЕРВОМ запуске ВСЁ, что есть в *.mig.bStat и aHits - на ОБНОВЛЕНИЕ
# 2024.05.21, nvv, радикально переделано (упрощено) под ежедневное полное обновление статистик
}

    Имя файла скрипта: "cChkH.awk" V-текст скрипта-V
- - - - - - - - -
BEGIN{      # cChkH.awk - хиты текста по факту в интервале от "Размещен:" до верхней границы
  if(ARGV[1]=="")exit                             # защита от случайного пуска

# 2020.06.10, nvv, creation, на основе siTop-bStat.awk от 2020.05.31
# 2020.06.16, nvv, it's working! =)
# 2020.12.19, nvv, добавлена принудительная установка верхней даты (datJ) нашего интервала
# 2021.05.02, nvv, мелкая косметика

  for ( str2 in ENVIRON ) {                   # ! регистр букв в имени переменной может быть любой
    str1 = tolower( str2 )                        # Temp и temp - РАЗНЫЕ имена для gAwk...
    if ( str1 == "begd" ) begD=ENVIRON[str2]      # дата "Размещен:"
    if ( str1 == "datj" ) datJ=ENVIRON[str2]      #  верхняя граница интервала: datJ
    if ( str1 == "id_t" ) t_id=ENVIRON[str2]".shtml"  # имя файла с текстом, чьи хиты нужны
  }
#  begD="2020.11.23"
#  datJ="2020.12.08"
#  t_id="19.shtml"

# массив имён месяцев для преобразования их в числа с лидирующим нулём 01..12
  mNum["Jan"]="01"                                # .1 January . Jan. 31 . winter wint
  mNum["Feb"]="02"                                # .2 February .Feb. 28/29
  mNum["Mar"]="03"                                # .3 March . . Mar. 31 . spring sprn
  mNum["Apr"]="04"                                # .4 April . . Apr. 30
  mNum["May"]="05"                                # .5 May . . . May. 31
  mNum["Jun"]="06"                                # .6 June . . .Jun. 30 . summer summ
  mNum["Jul"]="07"                                # .7 July . . .Jul. 31
  mNum["Aug"]="08"                                # .8 August . .Aug. 31
  mNum["Sep"]="09"                                # .9 September Sep. 30 . autumn autm
  mNum["Oct"]="10"                                # 10 October . Oct. 31
  mNum["Nov"]="11"                                # 11 November .Nov. 30
  mNum["Dec"]="12"                                # 12 December .Dec. 31 . winter wint
  hitT=0                                          # сумма хитов "за 30 дней"
  step=0          # 0-владелец, 1-дата обновления, 2-id раздела, 3-разбор строк таблиц статистики
  inTab=0                                         # сначала - мы НЕ "в таблице"
  numT=0                                          # счётчик таблиц в файле статистики
  numR=0                                          # счётчик строк в текущей таблице
  selN=0                                          # номер в строке обрабатываемой ячейки
  selE=0                                      # номер ячейки с датой "Размещён:" (последней НЕ 0!)
# объявим массивыы для общего использования в подпрограммах
  split("",aSel)      # в ячейках статистики: url,title,hits:all,12mon,mon0..monC-11,day0..day0-61
}

{                                                 # // -=- основной блок скрипта begs
  if(step==0) {                                   # ищем/проверяем ФИО автора
# <h3>Статистика раздела &quot;<a href=./>Влад</a>&quot;:</h3>
    if (match($0,/<h3>Статистика раздела \&quot;<a href=\.\/>(.*)<\/a>\&quot;:<\/h3>/,aj)) {
      step++                                      # проверка ОК
    }
  }else if(step==1){                              # вычленеие даты обновления статистики
    if(match($0,\
/<li><i>Статистика рассчитывается .+\. \(.+ (...) +([0-9]+) (..:..:..) (20[0-9][0-9])\)<\/i>/,aj)){
      if(length(aj[2])==1) aj[2]="0"aj[2]         # причешем первые дни месяца "1" -> "01"
      ticS=mktime(aj[4]" "mNum[aj[1]]" "aj[2]" 12 00 00") # тики на 12 часов даты статистики
      datS=aj[4]"."mNum[aj[1]]"."aj[2]
      step++                                      # дату статистики оптичили
    }
  }else if(step==2){                              # ищем authID (!должен быть)
#[<a href=http://top.mail.ru/pages?id=77427&period=0&date=2018-10-02&filter_type=0
#&filter=n/nosow_w_w&pp=20&gender=0&agegroup=0>по дням</a>]
    if (match($0,/\[<a href=http.+&filter=([0-9a-z]\/[\-0-9a-z_]+)&pp=.+>по дням<\/a>]/,aj)) {
      step++                                      # проверка ОК
    }
  }else if(step==3){                # таблицы статистики, просмотр строк, сборка данных в ячейках
    if($0=="<!--------- Подножие ------------------------------->"){  # разбор закончен
      step++
      nextfile
    }
    if(inTab){                      # Мы ВНУТРИ таблицы, собираем строки таблицы с хитами текстов
      buf0=buf0" "$0                              # gain inpLines to buf0, then check contents
      while((match(buf0,/<tr ?[^>]*>/))||(int0=index(buf0,"</tr"))){ # seek <tr .. </tr for tabRow
        if(RSTART){                               # new/next line begs
          numR++
          buf0=substr(buf0,RSTART+RLENGTH)
        }
        if(int0=index(buf0,"</tr")){              # this line ends
          sel0=0                                  # хиты до накануне-v
          sel1=0                                  # хиты накануне даты "Размешен:"
          getSels(substr(buf0,1,int0-1))          # tabl_row -> arrow:sell_values
          buf0=substr(buf0,int0+4)                # убрали эту строку из буфера и окультуриваем...
          id_T=aSel[0]                        # имя+расшир файла с текстом (или "./" для раздела)
          if((numT==1)&&(numR==2)){               # хиты по разделу (спец.обслуживание)
          }else{                                  # обычная строка статистики текста
            if(id_T==t_id){
              if(!sel0)hitT=hitT+sel1     # если это глюк СИ (хиты накануне размещения), учтём их
              print(hitT)
              exit
            }
          }
        }
      }
      if(int0=index(buf0,"</table")){             # this tabl ends
        buf0=substr(buf0,int0+4)                  # update buf0
        inTab=0
      }
    }else{                                        # ищем начало таблицы
      if(int0=index($0\
,"<table border=1 cellspacing=0 cellpadding=0><tr><td><td colspan=2><b>Итого</b></td>")){
        numT++                                    # new table
        numR=1                  # певая строка каждой таблицы - календарь хитов статистики раздела
        buf0=substr($0,int0+80)
        if(numT==1){                              # 1-st table 1-st row -> get col-dates & so-on
          match(buf0,/<tr[^>]*>(.+)<\/tr[^>]*>/,aj) # собственно строка с календарём
          getSels(aj[1])                          # но самую первую такую - разберём-с
          tic0=ticS             # и привяжем дату к нулевому (самому левому) дню посуточных данных
          while(strftime("%d",tic0)!=aSel[16])tic0=tic0-86400 # сдвинем стат.дату к нулевому дню
          for(dev0=0;dev0<30;dev0++)if(strftime("%Y.%m.%d",tic0-86400*dev0)==datJ)break
          tic0=tic0-86400*(dev0-1)
          dev0=dev0+15
          for(selE=1;selE<31;selE++)if(begD>=strftime("%Y.%m.%d",tic0-86400*selE))break
        }                                         # ^- поиск номера яцейки с датой "Размещен:"
        inTab=1                                   # мы ВНУТРИ таблицы
        buf0=""                                   # буфер чист!
      }
    }
  }
}                                                 # // -=- основной блок скрипта ends

function getSels(rowLn){                # разделение строки таблицы статистики на массив значений
  hitT=0                                          # сумма хитов "за 30 дней"
  selN=0                                          # sells count
  split("",aSel)
  aSel[0]=""
  while(match(rowLn,/<td[^>]*>/)){                # это объявление ячейки
    selN++                  # 0.1-имя/ссылка; хиты: 2-всего, 3-12мес, 4..15-заМес, 16..77-за сутки
    rowLn=substr(rowLn,RSTART+RLENGTH)            # выкусим объявление ячейки
    f3n2=index(rowLn,"</td")                      # это конец ячейки
    f3s2=substr(rowLn,1,f3n2-1)               # это сама ячейка (с возможными внутренними тегами)
    if(selN==1){                              # в ПЕРВОЙ ячейке - название текста и ссылка на него
      match(f3s2,/<a href=([^>]+)>(.*)<\/a>/,f3a1)  # выцепим и разложим:
      aSel[1]=f3a1[2]                             # название текста
      aSel[0]=f3a1[1]                             # ссылка на текст: name.shtml
    }else aSel[selN]=rmTags(f3s2) # в ПРОЧИХ ячейках - только значение ячейки, очищенное от тегов
    rowLn=substr(rowLn,f3n2)                      # выкусим оптиченную ячейку
    if((selN-dev0>0)&&(selN-dev0-selE<=0)){                 # 21 = dev0+5<=21 17..21
      hitT=aSel[selN]+hitT                        # сразу подсчитаем сумму хитов "за 30 дней"
    }else if(selN-dev0-selE==1){                     # ячейка сразу за границей
      sel1=aSel[selN]
    }else if(selN-dev0-selE>1){                      # прочие ячейки за границей
      sel0=aSel[selN]+sel0
    }
  }
}

function rmTags(f2s1){                            # удаление ВСЕХ тегов в литерале
  while(match(f2s1,/<\/?[a-zA-Z][1-6a-zA-Z]?[a-zA-Z]*[ \/]?[^>]*>/))
      f2s1=substr(f2s1,1,RSTART-1) substr(f2s1,RSTART+RLENGTH)
  return(f2s1)
}

END{                                              # отстрелялись; ну почти...
  if(ARGV[1]==""){
    print("No file in")
    exit                             # защита от случайного пуска
  }
}

    Имя файла скрипта: "cChkH.cmd" V-текст скрипта-V
- - - - - - - - -
@if not defined nJob @echo off
:: cChkH.cmd - просмотр списка *?.lst.bStat [?==v/~], скачивание ВСЕХ текстов из (кривое оставляется!)
:: смотрится дата "Размещён", если она ПОСЛЕ верхней границы выцепляемого интервала - игнорировать!
:: если ПОСЛЕ нижней границы - уточняются фактичкеи хиты в интервале
:: по результатам собирается уточнённый ОТсортированный список *.cChkH (а`ля *.bStat)

:: OS windows - должны быть настроены системные переменные окружения:
:: %time% - HH:MM:SS,tt HH<=9 -> "HH" == " H" лидирующий пробел для часа меньше 10
:: %date% - YYYY.mm.dd

:: 2022.03.31, nvv, годный mod теперь или "v" или "~"
:: ! история изменений - в подвале

echo %date% %time:~0,8% %~nx0 Begs
::  siUrl - основной и резервный URL Самиздата (желательно работать с резервом)
set siUrl=samlib.ru
if exist \siUrl.budclub set siUrl=budclub.ru
::  dnLd - счётчик /формально/ успешно скачанного (НЕ 0b)
set dnLd=0
::  ratW - темп скачивания (секунд на один файл в среднем)
set ratW=0
::  wrks - общее время работы процесса (пуск общего таймера)
for /F %%A in ('gawk.exe "BEGIN{print(systime());exit}"') do set wrks=%%A
:: основные сеты и прочая подготовка к работе...
set errInf=
set nJob=cChkH
set jDat=%date%
::  noReGet - запрет повторного скачивания пустых/битых текстов
set noReGet=%1
::  minT - минимальные допустимые хиты текста (берётся из подвала .v.lst.bStat)
set minT=
::  hitL - хитов за "30дн." (у ТЕКСТА должно быть НЕ меньше), уточняется в *.bStat (по nHit)
set hitL=
::  aChk - скрипт поиска атрибутов текста СИ, может создать очищенную копию
set aChk=%~dp0%nJob%.awk
::  aTxt - скрипт поиска атрибутов текста СИ, может создать очищенную копию
set aTxt=%~dp0dText.awk
set jDat=%date%
::  wDir - общее рабочее место
set wDir=%~d0\Jobs
::  zDir - общий подкаталог для посуточных подкаталогов с итоговыми списками
set zDir=%~d0\Stor\wOld\%jDat%
::  tDir - папка для текстов "наших" 30-дней (like: 2019.08.02.text)
set tDir=
::  jRpt - общий отчёт с итоговыми сводками процессов
set jRpt=%wDir%\_siTop.#
::  nulT текст - недоступен: 0b
set nulT=0
::  badT текст - битый (нет любого): begD,endD,sizT,namA,namT
set badT=0
::  badZ текст с ограниченным доступом
set badZ=0
::  down - хиты изменены
set down=0
::  datJ - верхняя граница интервала дат расчёта (дата в имени файла-списка yyyy.mm.dd.v.lst.bStat)
set datJ=
:: найти 20??.??.??.v.lst.bStat и запомнить его имя (т.е. дату в нём, например, 2019.07.14.v.lst.bStat)
for %%A in (%wDir%\20??.??.??.?.lst.bStat) do set datJ=%%~nA
if NOT defined datJ echo ? NO 20??.??.??.?.lst.bStat found & exit
set tmp0=%datJ:~11,1%
if NOT "%tmp0%" == "~" if NOT "%tmp0%" == "v" (
  echo ? bad mod "%tmp0%" in %datJ%
  goto nExit
)

::  sLst - входной список принятых "начерно" текстов (для скачивания и проверки, дат в первую очередь;)
set sLst=%wDir%\%datJ%.bStat
:: вырежем чистую дату datJ
set datJ=%datJ:~0,10%
::  dBeg - нижняя граница нашего интервала (datJ-29)
set dBeg=mktime(\"%datJ:~0,4% %datJ:~5,2% %datJ:~8,2% 12 00 00\")
for /F %%A in ('gawk.exe "BEGIN{print(strftime(\"%%Y.%%m.%%d\",%dBeg%-86400*29));exit}"') do set dBeg=%%A
::  jDir - место для страниц сканируемых гостевых и рабочих файлов
set jDir=%wDir%\#mRepl
::  jLst - НЕ сортированный список для "siTopTexts" с проверенными хитами за 30дн.
set jLst=%jDir%\]%nJob%.lst
::  eLst - список ПРОБЛЕМ с текстами/гостевыми
set eLst=%wDir%\]%nJob%.bad
::  hold - опорная дата в имени склада с текстами 
set hold=%jDat%
set tDir=%~d0\Stor\Text\%hold%.text
:: если уже собирали именно этот день - запрос "повторить?"
if NOT exist %wDir%\%datJ%.%nJob% goto goOn
set tmp0=
echo %datJ%.%nJob% found; tDir.*\%hold%.text\ reBuild? [yes] == y
set /p tmp0=?[no]?
if /i NOT %tmp0%. == y. echo job canceled {NO to reBuild} & exit
:goOn
if NOT exist %tDir%\ mkDir %tDir%\
if NOT exist %tDir%\ set errInf=fail mkDir %tDir%\ & goto nExit
if NOT exist %jDir%\ mkDir %jDir%\
if NOT exist %jDir%\ set errInf=fail mkDir %jDir%\ & goto nExit
if NOT exist %zDir%\*.* mkDir %zDir%
if NOT exist %zDir%\ set errInf=fail mkDir %zDir%\ & goto nExit
:: очистим будущие списки рейтинга и ошибок
echo. >nul 2> %jLst%
echo. >nul 2> %eLst%
::  tmpF - времянка для скачиваемых текстов
set tmpF=%tDir%\siTextDL.tmp
if exist %tmpF% erase %tmpF%
if errorLevel 1 set errInf=FAIL erase %tmpF%& goto nExit
::  linN - счётчик текстов
set linN=0
:: установим счётчик текстов на максимум...
:: ;2C scan 2021.04.24:dEnd 19719:nEnd  60688:hEnd 30012:nMig 1657:tNum 11:nGis 29154:nLow mod:! OkV:65.7% 
for /F %%A in ('gawk.exe "{if(match($0,/ ([0-9]+):tNum /,a))print(a[1])}" %sLst%') do set linN=%%A
:: ;2B stat 2021.04.26:sEnd  1457:nPre  20102:hPre  1457:miss 300:minT 548:hitL 30075:nHit 801964:hMax last~01:01:31~
for /F %%A in ('gawk.exe "{if(match($0,/ ([0-9]+):hitL /,a))print(a[1])}" %sLst%') do set hitL=%%A
if NOT defined hitL set errInf=fail read 'hitL' (noOrBad in %sLst%) & goto nExit
::  wGetSiz - объём файла, полученного с СИ (default 1b)
set wGetSiz=1
echo req topTexts... linN:%linN%
:: запустим "таймер" качалки
for /F %%A in ('gawk.exe "BEGIN{print(systime());exit}"') do set ratW=%%A
:: hitT hitP numP id_P id_T xDat "namA" "namT" - собственно сборка списка cChkH
for /F "tokens=*" %%A in (
  'gawk.exe "{if(match($1,/^[0-9]+$/))print($0)}" %sLst%'
) do if NOT defined errInf call :reqSiText %%A 
if defined errInf goto nExit
:: остановим "таймер" качалки время работы в секундах
for /F %%A in ('gawk.exe "BEGIN{print(systime()-%ratW%);exit}"') do set ratW=%%A
:: среднее время скачивания файла в секундах
if %dnLd% == 0 (set ratW=0) else (
  for /F %%A in ('gawk.exe "BEGIN{print(sprintf(\"%%3.2f\",%ratW%/%dnLd%));exit}"') do set ratW=%%A
)
if exist %wDir%\*.%nJob% move /y %wDir%\*.%nJob% %jDir% >nul
sort /rec 65535 /r %jLst% > %wDir%\%datJ%.%nJob%
if errorLevel 1 set errInf=FAIL sort %jLst% & goto nExit
:: теперь у нас свежий jLst
set jLst=%wDir%\%datJ%.%nJob%
:: выясним число текстов с хитами НЕ ниже hitL
for /F %%A in ('gawk.exe "{if(%hitL%-$1>0){print(NR-1);exit}}" %jLst%') do set topN=%%A
:: преобразуем секунды в время работы (в обычном формате "чч:мм:сс")
for /F %%A in ('gawk.exe "BEGIN{print(strftime(\"%%H:%%M:%%S\",systime()-%wrks%+46800));exit}"') do set wrks=%%A
:: оформим подвал списка...
echo ;  hitT   oldH.    hitP  numP id_P id_T "namP" "namT" sFil >> %jLst%
:: сначала сводки от aHits и bStat
gawk.exe "{if(match($1,/^;[1-3].$/))print($0)}" %sLst% >> %jLst%
:: затем собственная сводка
rem ;3C chkH dInt:2021.03.23-2021.04.21 topN:767 down:14 nulT:0 badT:1 badZ:0 741:dnLd done:2021.04.24 gap3:16:11-16:16 
set tmp0=;3C chkH ^
dInt~%dBeg%-%datJ%~ ^
%topN%:topN ^
%down%:down ^
%nulT%:nulT ^
%badT%:badT ^
%badZ%:badZ ^
%dnLd%:dnLd ^
%ratW%~ratW ^
%jDat%:done ^
%wrks%~wrks ^
%time:~0,5%
echo %tmp0% >>                  %jLst%
if NOT defined noReGet echo %tmp0% >> %jRpt%
echo %tmp0%
:: да и результат прикопать надлежитЪ
copy /b/y %jLst% %zDir% > nul
if errorlevel 1 set errInf=fail copy %jLst% to %zDir%
:: подудим где нада "готово-с!"
set itog=%jLst%

:nExit
if NOT defined tmpF goto nExit1
if exist %tmpF% erase %tmpF%
:nExit1
if defined errInf echo ! %errInf%
echo %date% %time:~0,8% %~nx0 Ends
goto :eof

:reqSiText работа с очередным тектстом
set /a linN-=1
set linR=       %linN%
set linR=%linR:~-4%
:: 1    2    3    4        5    6        7      8        9
:: hitT hitP numP id_P     id_T "namP"   "namT" sFil     datJ
:: 9241 365732 6  k/kadawr n    Кадавр" "Псион" k~kadawr 2021.04.06

set hitT=%1
set hitP=%2
set numP=%3
set id_P=%4
set id_T=%5
set namP=%6
set namT=%7
set gFil=%8
set curT=      %hitT%
set curT=%curT:~-6%

::  tFil - конечный файл для склада
set tFil=%tDir%\%gFil%.%id_T%.text.html
:: глянем, может этот текст уже у нас...
set tmp0=
for %%J in ( %tFil% ) do set tmp0=%%~zJ
:: пусто == нужно тащить с СИ
if NOT defined tmp0 goto getTxt
:: есть, но нулевой - нужно горхнуть и тащить с СИ
if %tmp0% == 0 (
if defined noReGet goto keepNul
erase %tFil%
goto getTxt
)
:: есть и ненулевой, разберёмся...
set fOut=
for /F "tokens=*" %%J in ('gawk.exe -f %aTxt% %tFil%') do call :chkTxt %%J
:: если OK - займёмся оформлением этого текста
if NOT "%begD%"  == "]" echo. %linR% = %curT%.Text: %gFil%.%id_T% & goto txtInOK
:: если битый, то грохнуть и тащить заново
if defined noReGet goto keepBad
erase %tFil%

:getTxt тащим топовый текст на склад-с
set wUrl=%siUrl%/%id_P%/%id_T%.shtml
if exist %tmpF% erase %tmpF%
echo. %linR% ? %curT%.Text: %gFil%.%id_T%
call wGetUrl2fil.cmd %wUrl% %tmpF%
if defined errInf goto :eof
if NOT %wGetSiz% == 0 goto mark0
:: если файл текста недоступен...
set errT=] err:T nulT: %curT%
move /y %tmpF% %tFil%
if errorLevel 1 set errInf=FAIL move inpF 2 %tFil%& goto :eof
:keepNul
set /a nulT+=1
set typT=%hitT%.
set hitT=1
set namA="x"
set namT="x"
goto fixErr

:mark0 смотрим атрибуты (в т.ч. дату создания, точно название и автор[а/ов]) текста...
set fOut=%tFil%
for /F "tokens=*" %%J in ('gawk.exe -f %aTxt% %tmpF%') do call :chkTxt %%J
set fOut=
:: если свежий текст OK, надо дату вструмить
if NOT "%begD%"  == "]" touch.exe -t %endD:~0,4%%endD:~5,2%%endD:~8,2%0100 %tFil% & goto txtInOK
 :: если с текстом проблемы, ставим на нём крест
move /y %tmpF% %tFil%
if errorLevel 1 set errInf=FAIL move inpF 2 %tFil%& goto :eof
:keepBad
set /a badT+=1
set typT=%hitT%?
set hitT=2

:fixErr с текстом всё плохо...
rem set /a linN-=1
echo.     -X- %errT% %wUrl%
echo %errT% %gFil%.%id_T%.text.html %wUrl% >> %eLst%
touch.exe -t 199001010100 %tFil%
:: и что с того, что брак? Изъятия в перетряхиваемом списке - только вручную!
call :formIt %hitT% %typT% %hitP% %numP% %id_P% %id_T% %namP% %namT% %gFil%
goto :eof

:txtInOK текст как-бы не битый, а доступ?
if %sizT:~-2% == .0 (
  set /a badZ+=1
  set typT=%hitT%z
  set hitT=4
  set errT=] err:Z unAv: %curT%
  goto fixErr
)
:: доступ OK, а хиты текста?
set typT=lowH
if %hitL% GTR %hitT% goto BegDatOk
::  а дата "Размещен:" - ОК?
set typT=:
if %begD% LEQ %dBeg% goto BegDatOk
set typT=%hitT%!
if %begD% GTR %datJ% set hitT=3& goto BegDatOk
set typT=v
:: дата после начала интервала => хиты текста как бы под подозрением...
set filS=U:\Jobs\#bStat\%id_P:~0,1%~%id_P:~2%.stat.htm 
set tmp0=
for /F %%J in ('gawk.exe -f %aChk% %filS%') do set tmp0=%%J
if %hitT% == %tmp0% goto BegDatOk
:: не совпало; наследство отдельно
set typT=%hitT%]
set hitT=%tmp0%
set /a down+=1
:BegDatOk выгрузка собранных данных в накопительный список пефоманс
call :formIt %hitT% %typT% %hitP% %numP% %id_P% %id_T% %namP% %namT% %gFil%
goto :eof

::   9241       :  362225     6 k/kadawr n  "Кадавр" "Псион" k~kadawr
::;  hitT   oldH.    hitP  numP id_P   id_T "namP"   "namT"  sFil 
::   1       2        3     4    5       6     7      8      9

:formIt %hitT% %typT% %hitP% %numP% %id_P% %id_T% %namP% %namT% %gFil%
set typT=        %typT%
set typT=%typT:~-7%
gawk.exe "BEGIN{printf(\"%%7s%%8s%%8s%%6s\",%1,\"%typT%\",%3,%4);exit}" >> %jLst%
echo. %id_P% %id_T% %namA% %namT% %gFil% >>   %jLst%
goto :eof

:chkTxt begD endD sizT namA namT votT jnrT fNam - вычленение данных по тексту
:: . . . 1 .. 2 .. 3 .. 4 .. 5 .. 6 .. 7 .. 8
set begD=%1
set endD=%2
set namA=%4
set namT=%5
set sizT=%3
set votT=%6
set jnrT=%7
set errT=%*
goto :eof

:: 2018.08.10, nvv, creation
:: ...
:: 2020.03.14, nvv, мелкие изменения
:: 2020.06.14, nvv, разделено и реорганизовано. здесь - первая часть, вторая (основная) в siTop-dText.cmd
:: 2020.06.26, minor updates
:: 2020.07.06, minor updates
:: 2020.11.13, nvv, будКлуб - глупость
:: 2020.12.19, nvv, ^- не факт...
:: 2020.12.31, nvv, hitL check added (no datCheck for low text's hits)
:: 2021.01.09, nvv, minor mistake corrected
:: 2021.01.29, nvv, если доступ ограничен (sizT N.0) текст отбраковывается
:: 2021.04.09, nvv, *.bStat turned to *.lst.bStat + minor updates
:: 2021.04.19, nvv, minor updates
:: 2021.04.26, nvv, updates унификация формата передаваемых итоговых значений
:: 2021.05.11, nvv, очередная оптимизация с унификацией...
:: 2021.11.16, nvv, добавлен запрос на пересборку итога, если он уже собирался (защита от случайного пуска)

    Имя файла скрипта: "dText.awk" V-текст скрипта-V
- - - - - - - - -
BEGIN{ # siTop-dText.awk - (для siTop-mText.cmd) взять инфу из текста + очистить сам файл от мусора
#  fOut="nvv.shtml" # при запуске НЕ из CMD, для создания(!) очищенного текста раскомментировать
  fErr="F eInP:NO input file"
  if(ARGV[1]=="")exit                             # защита от случайного пуска
# 2024.03.06 nvv, теперь 2 варианте оформления ФИО в шапке текста
#  ! прочая история в подвале

# Скрипт выдаёт на StdOut 9 литералов:
# :: begD endD sizT namA namT votT jnrT fNam
# 1  begD(11) - дата размещения текста (2018.04.19)
# 3  endD(11) - дата последнего изменения текста (2018.10.21, "!" == "битое")
# 4  sizT(6)  - размер текста kb (427) + суффикс ".1" (Ok) или ".0" (доступ ограничен)
# 5 "namA"    - ФИО ("Федорочев•Алексей" или "Калашников•Сергей•Александрович,•Андрей_М11")
# 6 "namT"    - заголовок текста ("Мажор")
# 7  votT     - оценки (7.07*811, может быть "0" без кавычек)
# 8 "jnrT"    - жанр(ы) (может быть пусто "0" без кавычек)
# 9  fNam     - чистое ИМЯ файла текста/гостевой (f-fedorochew_a.major)

# ЕСЛИ это проблемный файл, выдача меняется (вместо begD - признак проблемы: "]"):
# ] 190001010100 "err:E erId:description" gFil

#  fDat="190001010100"                             # 1900.01.01 01:00 (12:00 ВЛД)
  begD=0                                          # дата размещения текста
  endD=0                                          # дата последней редакции этого текста
  sizT=-1                                         # объём (в килобайтах) этого текста
  maxL=99                                         #  максимальная допустимая длина ника или заголовка
  namA="-"                                        # автор(ы) текста (as-is)
  namT="-"                                        # заголовок текста (as-is)
  votT=0                                          # оценки текста (like 7.07*811) или диагноз
  jnrT=0                                          # жанр(ы) текста (упаковано, если есть)
  step=0                                      # шаг "разбора" страницы текста/гостевой "Самиздата"
  j1=split(ARGV[1],jArr,":")                      # drv+rest
  j1=split(jArr[j1],jArr,"\\")                    # path+name+ext
  j1=split(jArr[j1],jArr,".")                     # name+ext
  fNam=jArr[1]
  for(j2=2;j2<j1;j2++)fNam=fNam"."jArr[j2]        # a-abwow_a_s.fp.text [.html]
  for ( j2 in ENVIRON ) {                     # ! регистр букв в имени переменной может быть любой
    j1 = tolower( j2 )                            # Temp и temp - РАЗНЫЕ имена для gAwk...
    if ( j1 == "fout" ) fOut=ENVIRON[j2]          # очищенный si-HTML текст
    if ( j1 == "hitt" ) hitT=ENVIRON[j2]          # очищенный si-HTML текст
  }
  if(fOut!=""){                                   #  PATH + id_F +.+ id_T +.+ text.html
    j1=split(fOut,aj,"\\")            #  like: V:\Stor\Text\2022.04.13.text\s~sej_p_s.ms.text.html
    j2=split(aj[j1],aj,".")
    fTxt=aj[1]                       #  чистое имя БЕЗ расширения ".html" like: s~sej_p_s.ms.text
    for(j1=2;j1<j2;j1++)fTxt=fTxt"."aj[j1]
  }else fTxt=fNam
  if(hitT)hitT=sprintf("%7s",hitT)
  fErr="P eAvt:"hitT" NO owner FIO"               # бывает-с, хотя и очень редко...
  flgA=0
  flgO=1
  split("",aOut)                                # массив под строки обихоженной страницы с текстом
  aNum=0                                          # счётчик строк в массиве aOut
}

function pack(j1,j0) {          #  заменить мешающие символы на нейтральные + закавычить результат
  j2=""                                           # TAB -> "•"
  while(n1=index(j1,"\x09")) { j2 = j2 substr( j1, 1, n1-1 ) "•"; j1 = substr( j1, n1+1 ) }
  j1=j2 j1
  j2=""                                           # пробел -> "•"
  while(n1=index(j1," ")) { j2 = j2 substr( j1, 1, n1-1 ) "•"; j1 = substr( j1, n1+1 ) }
  j1=j2 j1
  j2=""                                           # неразрывный_пробел -> "•"
  while(n1=index(j1,"\xA0")) { j2 = j2 substr( j1, 1, n1-1 ) "•"; j1 = substr( j1, n1+1 ) }
  j1=j2 j1
  j2=""                                           # двойные кавычки -> "”"
#  while(n1=index(j1,"\"")) { j2 = j2 substr( j1, 1, n1-1 ) "”"; j1 = substr( j1, n1+1 ) }
  while(n1=index(j1,"\"")) { j2 = j2 substr( j1, 1, n1-1 ) "&quot;"; j1 = substr( j1, n1+1 ) }
  j1=j2 j1
  j2=""                                           # "%" -> "&#x25;"
  while(n1=index(j1,"%")) { j2 = j2 substr( j1, 1, n1-1 ) "&#x25;"; j1 = substr( j1, n1+1 ) }
  j1=j2 j1
#   j2=""                                           # "••" -> "•"
#   while(n1=index(j1,"••")) { j2 = j2 substr( j1, 1, n1-1 ); j1 = substr( j1, n1+1 ) }
#   j1=j2 j1
  n0=length(j1)
  if(j0&&(n0-maxL>0))j0=maxL
  else               j0=n0
  n1=split(j1,ak,"•")
  j1=ak[1]
  for(j2=2;j2<=n1;j2++){
    if(j0<length(j1)+1+length(ak[j2])){
      j1=j1"•(nvv:•+"n0-length(j1)"•знаков)"
# •(nvv:•+1•знаков)"
# 123456789.123456789.123456789.
      break
    }
    if(ak[j2]!="")j1=j1"•"ak[j2]
  }
#   if(substr(j1,1,1)=="•") j1 = substr( j1, 2 )    # del "•" at beg
#   n1=length(j1)
#   if(substr(j1,n1,1)=="•") j1 = substr( j1, 1, n1-1 ) # del "•" at end
  return ("\""j1"\"")
}

{                                                 # scan text head (шапка текста)
  outP($0)
# 6 "namA" ФИО ("Федорочев Алексей" или "Калашников Сергей Александрович, Андрей_М11")
# Буревой Андрей: <small><a href=/b/burewojandrej/>другие произведения.</a></small>
# Ил Саган, Кейн Алекс: <small><a href=/s/sagan_i/>другие произведения.</a></small>

# <div align=right><h3>Шерман Елена Михайловна : 
# <small><a href=/s/sherman_e_m/>другие произведения.</a></small></h3></div>

# <div align=right><h3>
# Boris : <small><a href=/b/boris/>другие произведения.</a></small>

  if (!step) {                                    # нулевой шаг - автор
    if (match($0,/^<div align=right><h3>([^:]+)? ?:? ?/,aj)){
      if(length(aj[1]))namA=pack(aj[1],1)
      flgA=1
    }
    if(flgA){
      if (match($0,/^([^:]+)? ?:? ?<small><a href=(.+)>другие произведения\.</,aj)){
        if(length(aj[1]))namA=pack(aj[1],1)
        id_P=aj[2]
        fErr="H eHdr:"hitT" no title"
        step=1
        next
      }
    }
  }
# 7 "namT" заголовок текста ("Мажор")
# <center><h2>Чего бы почитать?</h2>
  if (step==1) {                                  # первый шаг - название текста
    if (match($0, /^<center><h2>(.+)<\/h2>$/, aj)) {
      namS=aj[1]
      namT=pack(aj[1],1)
      outP("</center>")
      outP("<hr>")
      flgO=0
      fErr="I eInf:"hitT" bad date/size"
      step=2
      next
    }
  }
# 1  endD(11) дата последнего изменения текста (2018.10.21, "!" == "битое")
# 2  begD(11) дата размещения текста (2018.04.19)
# 3  sizT(6)     размер текста kb (427)
# <li>Размещен: 03/09/2018, изменен: 09/11/2018. 410k. <a href=stat.shtml#psv.shtml>Статистика.</a>
# <li>Размещен: 15/08/2003, изменен: 17/02/2009. 246k. <a href="stat.shtml#xu43.shtml">Статистика.</a>
  if (step==2) {                                  # второй шаг - основные атрибуты текста
    if(index($0,"<table width=90% border=0 cellpadding=0 cellspacing=0><tr>")){
      flgO=1
      outP($0)
      next
    }
# if (match($0,/^<li>Размещен: ([0-3][0-9])\/([01][0-9])\/(20)?([0-9]{2})\, изменен: ([0-3][0-9])\/([01][0-9])\/(20)?([0-9]{2})\. ([0-9]+)k\. <a href=.+>Статистика\.<\/a>$/,aj)){
#      begD="20"aj[4]"."aj[2]"."aj[1]
#      endD="20"aj[8]"."aj[6]"."aj[5]
if (match($0,/^<li>Размещен: ([0-3][0-9])\/([01][0-9])\/(..)?([0-9]{2})\, изменен: ([0-3][0-9])\/([01][0-9])\/(..)?([0-9]{2})\. ([0-9]+)k\. <a href=.+>Статистика\.<\/a>$/,aj)){
      if(aj[3]=="")aj[3]="20"
      begD=aj[3] aj[4]"."aj[2]"."aj[1]
      if(aj[7]=="")aj[7]="20"
      endD=aj[7] aj[8]"."aj[6]"."aj[5]
#  fDat=strftime("%Y%m%d%H%M",mktime(aj[6]" "aj[5]" "aj[4]" 01 00 00"))  # YYYYMMDDhhmm (12:00 VLD)
      sizT=aj[9]
      fErr="J eJnr:"hitT" bad janr info"
      step=3
      next
    }
  }
# 9 "jnrT"     - жанр(ы) (может быть пусто "-")
# <li><a href="http://budclub.ru/type/index_type_18-1.shtml">Справочник</a>: <a href="http://budclub.ru/janr/index_janr_20-1.shtml">Естествознание</a>
# <li><a href=/type/index_type_16-1.shtml>Глава</a>: <a href="/janr/index_janr_25-1.shtml">Приключения</a>, <a href="/janr/index_janr_1-1.shtml">Фантастика</a>
  if (step==3) {                            # третий шаг - дополнительные атрибуты текста, жанр(ы)
    if (match($0, /<li>(<a href=[^>]*\/type\/index_type_.+<\/a>: .*)$/, aj)){
      if(aj[1]=="")jnrT=0
      else jnrT=pack(aj[1])
      fErr="V eVot:"hitT" someThing wrongWith votes"
      step=4
      next
    } else if (namT=="\"Информация•о•владельце•раздела\"") {  # тут жанров нет в прнципе!
      jnrT=0
      fErr="V eVot:"hitT" someThing wrongWith votes"
      step=4
      next
    }
  }
# <form action="http://budclub.ru/cgi-bin/votecounter" method=POST>
# <form action="/cgi-bin/votecounter" method=POST>
# <input type=hidden name=FILE value=fant016 >
# <input type=hidden name=DIR value=a/abbakumow_i_n >
# <!-- 1 
  if (step==4) {                                  # четвёртый шаг - оценки...
    if(match($0,/<form action="[^"]*\/cgi-bin\/votecounter\" method=POST>/)){
      step=5
      chkLn=NR+2                                # 3 обязательные строки в начале блока голосования
      next
    }
  }
# 8  votT      - оценки (7.07*811, может быть "0")
# Оценка: <b>6.71*23</b>
# Оценка: <b>5.78*1204</b>
# Оценка: <b><a href=/cgi-bin/vote_show?DIR=b/burewojandrej&FILE=knigi>*</a></b>
# Оценка: <b><a href=/cgi-bin/vote_show?DIR=s/sagan_i&FILE=psv>7.16*117</a></b>
  if (step==5) {                                  # пятый шаг - дополнительные атрибуты текста
    if((NR-chkLn)>0){
      if(index($0,"<!--")){                     # оценки отключены; в тексте больше нечего делать
        step=6
        fErr="T eTxt:"hitT" someThing wrongWith text1"
        next
      }
      if(match($0,/Оценка: <b><a href=\/cgi-bin\/vote_show\?DIR=.+>(.*\*.*)<\/a><\/b>$/,aj)){
        votT=aj[1]
        if(votT=="*") votT=0
        else          votT=pack(votT)
        step=6
        fErr="T eTxt:"hitT" someThing wrongWith text2"
        next
      }
      if (match($0, /Оценка: <b>(.*\*.*)<\/b>$/, aj)) {
        votT=aj[1]
        if(votT=="*") votT=0
        else          votT=pack(votT)
        step=6
        fErr="T eTxt:"hitT" someThing wrongWith text3"
        next
      }
    }
  }
  if (step==6) {                                  # шестой шаг
    if(match($0,/<!--[^>]*Собственно произведение[^>]*-->/))chkLn=NR+4 # nvv 2021.05.14 changed
#     if($0=="<!----------- Собственно произведение --------------->")chkLn=NR+4
    if(NR==chkLn){
      if(index($0,"<h3>Извините, доступ к этому произведению ограничен.</h3>"))sizT=sizT".0"
      else sizT=sizT".1"                          # для обычных текстов, ".0" для -^- хитромудрых
#       print(sprintf("%11s%11s%8.1f %s %s %s %s",begD,endD,sizT,namA,namT,votT,jnrT),fTxt,fNam)
      print(sprintf("%11s%11s%8.1f %s %s %s %s",begD,endD,sizT,namA,namT,votT,jnrT),"",fTxt)
      step=NR
      next
    }
  }
  if ((step-6)>0) {                               # завершающмй шаг
    if(match($0,/<!--[^>]*Блок описания произведения \(слева внизу\)[^>]*-->/)){  #  nvv 2021.05.14
#     if($0=="<!---- Блок описания произведения (слева внизу) ----------------------->")
      flgO=1
#       if(substr($0,RSTART,5)=="<!---")nNew=0
#       else                            nNew=1
#       print nNew,id_P,namP,namT >> "u:\\z.z"
#      outP($0)
#      outP("<hr size=2 noshade>")
      outP("</body>")
      outP("</html>")
      fErr=""
      exit
    }
  }
}

function outP(j1){                                # п/п ПЕРЕсоздания чистой копии входного файла
  if((fOut=="")||(!flgO)) return
  aOut[++aNum]=j1
}

END{
  if(fErr!=""){
    print("] err:"fErr,fTxt,ARGV[1])           # у нас проблема...
    exit -1
  }
  for(j1=1;j1<=aNum;j1++)print(aOut[j1])>fOut
# 2018.02.25, nvv, creation (siReplsChk.awk)
# ...
# 2019.01.04, nvv, update
# 2019.04.04, nvv, sizB added (== ".0" if "доступ ... ограничен", else == ".1")
# 2019.07.04, nvv, работаеи ТОЛЬКО с текстами
# 2019.08.05, nvv, update
# 2019.12.06, nvv, current unification
# 2020.06.13, nvv, обрабатываемая страница буфферизируется; выдача - только если всё ОК
# 2021.05.15, nvv, иначе (с доп.пробелами) оформлены некоторые HTML-комментарии у части текстов
#     пришлось менять метод распознания: независящий от использованного варианта оформления оных
# 2021.09.29, nvv, символ 0x1A (Ctrl+Z) - для gAwk == "конец файла" (даже если это не так)
# 2022.03.09, nvv, уточнён алгоритм вычленения данных в служебке (при разной подработке текста)
# 2022.04.13 nvv, теперь (fOut) в выдаче указывается конечное ИМЯ файла ПОСЛЕ преобразования
# 2022.06.29 nvv, введено ограничение maxL длины ника и заголовка текста (защита от идиотов)
# 2022.08.16 nvv, исправлена неточность в имени файла с текстом /fTxt/ в выдаче скрипта
}

    Имя файла скрипта: "dText.cmd" V-текст скрипта-V
- - - - - - - - -
@if not defined nJob @echo off
:: dText.cmd - сборка и оснащение 30d списка 1k топовых текстов доп.данными о них и их гостевых
::  основной и резервный URL Самиздата (желательно работать с резервом)
:: %time% - HH:MM:SS,tt HH<=9 -> "HH" == " H" лидирующий пробел для часа меньше 10
:: %date% - YYYY.mm.dd

:: 2021.11.16, nvv, добавлен запрос на пересборку итога, если он уже собирался (защита от случайного пуска)
:: ! история изменений - в подвале

echo %date% %time:~0,8% %~nx0 Begs
::  siUrl - основной и резервный URL Самиздата (желательно работать с резервом)
set siUrl=samlib.ru
if exist \siUrl.budclub set siUrl=budclub.ru
::  dnLd - счётчик /формально/ успешно скачанного (НЕ 0b)
set dnLd=0
::  ratW - темп скачивания (секунд на один файл в среднем)
set ratW=0
::  wrks - общее время работы процесса (пуск общего таймера)
for /F %%A in ('gawk.exe "BEGIN{print(systime());exit}"') do set wrks=%%A
:: основные сеты и прочая подготовка к работе...
set errInf=
set nJob=dText
set mark=;m
set awkV=%~dp0%nJob%V.awk
set awkR=%~dp0%nJob%R.awk
set awkT=%~dp0%nJob%.awk
set jDat=%date%
::  wDir - общее рабочее место
set wDir=%~d0\Jobs
::  sDir - общее складское хранилище
set sDir=%~d0\Stor
set jRpt=%wDir%\_siTop.#
::  dirT - склад для топовых текстов (лидеры рейтингов)
set dirT=%sDir%\Text
::  tHit - сумма всех хитов призёров, попавших в тор1000
set tHit=0
:: счётчики проблем...
set errInf=
::  nulG гостевая - недоступна: 0b
set nulG=0
::  badG гостевая - битая (нет любого на проверяемых страницах): endD,sizT
set badG=0
::  rNot гостевая - пуста (нет любого): Dat,rNum
set rNot=0
::  zipR гостевая - архив(ы)
set zipR=0
::  datJ - верхняя граница интервала дат расчёта (дата в имени файла-списка yyyy.mm.dd.v.lst.bStat)
set datJ=
:: найти 20??.??.??.v.lst.bStat и запомнить его имя (т.е. дату в нём, например, 2019.07.14.v.lst.bStat)
for %%A in (%wDir%\20??.??.??.?.lst.bStat) do set datJ=%%~nA
if NOT defined datJ echo ? NO 20??.??.??.?.lst.bStat found & exit
set tmp0=%datJ:~11,1%
if NOT "%tmp0%" == "~" if NOT "%tmp0%" == "v" (
  echo BAD mod "%tmp0%" in %datJ%
  exit
)
set datJ=%datJ:~0,10%
set cLst=%wDir%\%datJ%.cChkH
:: найти последний 20??.??.??.cChkH и запомнить его имя (т.е. дату в нём, например, 2019.07.14.cChkH)
if NOT exist %cLst% echo NO %cLst% found, exit & exit
:: если уже собирали именно этот день - запрос "повторить?"
if NOT exist %wDir%\%datJ%.%nJob% goto goOn
set tmp0=
echo %datJ%.%nJob% found; reBuild it? [yes] == y
set /p tmp0=?[no]?
if /i NOT %tmp0%. == y. echo job canceled {NO to reBuild} & exit
:goOn  jDir - место для страниц сканируемых гостевых и рабочих файлов
set jDir=%wDir%\#mRepl
if NOT exist %jDir%\ mkDir %jDir%\
if NOT exist %jDir%\ set errInf=fail mkDir %jDir%\ & goto nExit
:: если итоговый список уже принят "к публикации" (суффикс "#"), трогать низя
if exist %wDir%\%datJ%.#.%nJob% set errInf=found %wDir%\%datJ%.#.%nJob% (published?!) & goto nExit
:: если есть пока непринятый итоговый список, он берётся как опорный для пересборки
if exist %wDir%\%datJ%.%nJob% move /y %wDir%\%datJ%.%nJob% %jDir%
::  lstJ - список для "siTopTexts" - популярные тексты за 30 дней (со всеми атрибутами)
set lstJ=%jDir%\%datJ%.%nJob%
::  eLst - несортированный список ПРОБЛЕМ с текстами/гостевыми
set eLst=%wDir%\]%nJob%.bad
::  hold - опорная дата привязки реплик
set hold=
:: если перезапуск (есть lstJ) - считать дату привязки, иначе - проверить почистить jDir
if exist %lstJ% (
  for /F %%J in ('gawk.exe "{if(match($1,/^%mark%$/)){print($3);exit}}" %lstJ%') do set hold=%%J
) else (
  if exist %jDir%\*.* erase /F/Q %jDir%\*.*
  if errorlevel 1 set errInf=fail erase %jDir%\*.* & goto nExit
  set hold=%jDat%
)
:: собирать список должно СЕГОДНЯ! Завтра (если не успели) - всё с начала
if NOT %hold%. == %jDat%. (
  set hold=%jDat%
  if exist %jDir%\*.* erase /F/Q %jDir%\*.*
  if errorlevel 1 set errInf=fail erase %jDir%\*.* & goto nExit
)
:: очистим будущие списки рейтинга и ошибок
echo %mark% hold %hold% >           %lstJ% 2> %eLst%
::  tDir - папка для топовых текстов "наших" 30-дней (like: 2019.08.02.text)
set tDir=%dirT%\%hold%.text
:: должОн бысть (после cChkH.cmd)
if NOT exist %tDir%\ set errInf=%tDir% not found & goto nExit
::  tmpF - времянка для скачиваемых текстов
set tmpF=%tDir%\siTextDL.tmp
if exist %tmpF% erase %tmpF%
if errorLevel 1 set errInf=FAIL erase %tmpF%& goto nExit
::  ok1k - устанавливается, когда оптичены все принятые топовые тексты (+оценки +гостевые к ним)
set ok1k=
::  linN - счётчик текстов
set linN=0
::  wGetSiz - объём файла, полученного с СИ (default 1b)
set wGetSiz=1
echo req topTexts...
:: запустим "таймер" качалки
for /F %%A in ('gawk.exe "BEGIN{print(systime());exit}"') do set ratW=%%A
:: hitT hitP numP id_P id_T xDat "namA" "namT"
for /F "tokens=*" %%A in (%cLst%) do if NOT defined errInf if NOT defined ok1k call :reqSiText %%A 
if defined errInf goto nExit
:: остановим "таймер" качалки время работы в секундах
for /F %%A in ('gawk.exe "BEGIN{print(systime()-%ratW%);exit}"') do set ratW=%%A
:: среднее время скачивания файла в секундах
if %dnLd% == 0 (set ratW=0) else (
  for /F %%A in ('gawk.exe "BEGIN{print(sprintf(\"%%3.2f\",%ratW%/%dnLd%));exit}"') do set ratW=%%A
)
:: jLst - конечный список-итог
set jLst=%wDir%\%datJ%.%nJob%
copy /b/y %lstJ% %jLst% > nul
if errorlevel 1 set errInf=fail copy %lstJ% to %wDir%
:: преобразуем секунды в время работы (в обычном формате "чч:мм:сс")
for /F %%A in ('gawk.exe "BEGIN{print(strftime(\"%%H:%%M:%%S\",systime()-%wrks%+46800));exit}"') do set wrks=%%A
:: оформим подвал списка...
::  .   3333   159   49066  1821.0  -993  993 2014.07.10 2017.11.30 2018.01.26 "Скс." "Режим•бога" s/sks 111 "6.05*126" 0 "Скс" 10_3834 s-sks.111 
rem echo ; hitT.1 numP.2 hitP.3 sizT.4 aNum.5 rNum.6 begD.7    endD.8     aDat.9   ^
rem "namA".10 "namT".11 id_P.12 id_T.13 "votT".14 "jnrT".15 gFil.16 >> %jLst%
set tmp0=; hitT.1 numP.2 hitP.3 sizT.4 aNum.5 rNum.6 begD.7    endD.8     aDat.9
set tmp0=%tmp0%   "namA".10 "namT".11 id_P.12 id_T.13 "votT".14 "jnrT".15 gFil.16
echo %tmp0% >> %jLst%
:: затем сводки от aHits и cChkH
gawk.exe "{if(match($1,/^;[1-3].$/))print($0)}" %cLst% >> %jLst%
:: ;4T text nulG:0 badG:0 rNot:85 zipR:253 1456:dnLd done:2019.11.28 17:17-17:31 <- штат
:: затем собственная сводка
set tmp0=;4T text ^
%nulG%:nulG ^
%badG%:badG ^
%rNot%:rNot ^
%zipR%:zipR ^
%tHit%:tHit ^
%dnLd%:dnLd ^
%ratW%~ratW ^
%jDat%:done ^
%wrks%~wrks ^
%time:~0,5%
echo %tmp0% >>                  %jLst%
echo %tmp0% >>                  %jRpt%
echo %tmp0%
:: подудим где нада "готово-с!"
set itog=%jLst%

:nExit
if exist %tDir%\siTextDL.tmp erase %tDir%\siTextDL.tmp
if defined errInf echo !!! %errInf%
echo %date% %time:~0,8% %~nx0 Ends
goto :eof

:reqSiText работа с очередным тектстом и его гостевой
if defined ok1k goto :eof
set hitT=%1
set oldH=%2
:: всё годно было ДО lowH дальше не интересно
if %oldH%. == lowH. (set ok1k=yes & goto :eof)
set /a linN+=1
set linR=       %linN%
set linR=%linR:~-4%
:: 1    2    3      4    5    6     7      8      9
:: hitT oldH hitP   numP id_P id_T "namP" "namT"  sFil 
:: 9241    : 362225 6 k/kadawr n "Кадавр" "Псион" k~kadawr 

set hitP=%3
set numP=%4
set id_P=%5
set id_T=%6
set namP=%7
set namT=%8
set gFil=%id_P:~0,1%~%id_P:~2%.%id_T%
set curT=      %hitT%
set curT=%curT:~-6%

::  tFil - конечный файл для склада (дОлжен быть!)
set tFil=%tDir%\%gFil%.text.html
if NOT exist %tFil% set errInf=no %tFil% found & goto :eof
set tmp0=
for %%J in ( %tFil% ) do set tmp0=%%~zJ
:: есть, но нулевой - нужно горхнуть и тащить с СИ
if %tmp0% == 0 set errInf=zeroSize %tFil% found & goto :eof
:: есть и ненулевой, разберёмся...
set fOut=
for /F "tokens=*" %%J in ('gawk.exe -f %awkT% %tFil%') do call :chkTxt %%J
:: если OK - займёмся оформлением этого текста
if "%begD%"  == "]" set errInf=bad %tFil% found & goto :eof
echo. %linR% = %curT%.Text: %gFil%

:: txtInOK теперь оценки, если есть-с... ;) budclub.ru/cgi-bin/vote_show?DIR=n/nosow_w_w&FILE=si_tq1k-curr
if exist %tDir%\siTextDL.tmp erase %tDir%\siTextDL.tmp
if %votT% == 0 goto votesOK
set wUrl="%siUrl%/cgi-bin/vote_show?DIR=%id_P%&FILE=%id_T%"
set tmpF=%jDir%\%gFil%.vote.htm
if exist %tmpF% (
echo.     =Votes
goto voteIs
)
echo.     ? Votes
call wGetUrl2fil.cmd %wUrl% %tmpF%
if defined errInf goto :eof
:: если файл оценок недоступен => текст удалить
set errT=] err:V badV %curT% %gFil%.text
if %wGetSiz% == 0  set /a nulT+=1 & goto killZero
:voteIs проверяем полученное
set chkN=0
for /F "tokens=1-4*" %%J in ('gawk.exe -f %awkV% %tmpF%') do (
set balN=%%J& ^
set balM=%%K& ^
set balS=%%L& ^
set balD=%%M) 
:: если с оценками проблема => текст удалить
if "%balN%"  == "]]" set /a nulT+=1 & goto killZero
set votT="%balM%»%balS%*%balN%"

:votesOK теперь гостевая этого текста; страница самых последних реплик
rem !!! 2019.11.25, nvv NO guestBooks == NO scanning them atALL
rem if defined noRepl goto noRepl
rem !!!
set wUrl=%siUrl%/comment/%id_P%/%id_T%
set tmpF=%jDir%\%gFil%.z00.z1.repl.htm
if exist %tmpF% (
echo.     =Repls
goto replIs
)
echo.     ? Repls
call wGetUrl2fil.cmd %wUrl% %tmpF%
if defined errInf goto :eof
:: если файл гостевой недоступен...
set errT=] err:N nulG %curT% %gFil%.z00.z1.repl
if %wGetSiz% ==  0  set /a nulG+=1 & goto killZero
:replIs проверяем полученное
set chkN=0
for /F "tokens=*" %%J in ('gawk.exe -f %awkR% %tmpF%') do call :chkRpl %%J
:: если с гостевой текста проблемы, ставим на тексте крест
if "%dat0%"  == "]" set /a badG+=1 & goto fixErr
:: если гостевая пуста, так и запишем...
if %dat0% == 0 goto noRepl
set aDat=%dat0%
set arcN=%num0%
set rNum=%num1%
set pagN=%num2%
:: если ОДНА реплика, без архивов; всё ясно БЕЗ второго запроса
if "%arcN%%rNum%" == "01" (
  set aNum=%rNum%
  goto fixNews
)
:: архива нет, реплик: 2..1012 == НЕ одна реплика, нужен запрос самой первой в текущих
if %arcN% == 0 goto reqCur
:: == архив(!) запрос архива
set tmp0=0%pagN%
set tmp2=00%arcN%
set wUrl="%siUrl%/comment/%id_P%/%id_T%.%arcN%?ORDER=reverse&PAGE=%pagN%"
set tmpF=%jDir%\%gFil%.%tmp2:~-3%.%tmp0:~-2%.repl.htm
if exist %tmpF% (
echo.     =Arch
goto replA
)
echo.     ? Arch
call wGetUrl2fil.cmd %wUrl% %tmpF%
if defined errInf goto :eof
:: если файл гостевой недоступен...
set errT=] err:N nulG %curT% %gFil%.%tmp2:~-3%.%tmp0:~-2%.repl
if %wGetSiz% ==  0  set /a nulG+=1 & goto killZero
:replA ищем в последнем архиве реплику с тем же номером (или радом;)
set chkN=%rNum%
for /F "tokens=*" %%J in ('gawk.exe -f %awkR% %tmpF%') do call :chkRpl %%J
:: если с гостевой текста проблемы, ставим на тексте крест
if "%dat0%"  == "]" set /a badG+=1 & goto fixErr
:: если гостевая пуста, так и запишем...
if %dat0% == 0 goto noRepl
:: - архив(ы) сосчитаем
set /a zipR+=1
:: pref "-" == number is IN archive
set aNum=-%num1%
set aDat=%dat0%
goto fixNews

:reqCur дата первой реплики в текущих
set wUrl="%siUrl%/comment/%id_P%/%id_T%?ORDER=reverse&PAGE=1"
set tmpF=%jDir%\%gFil%.z00.01.repl.htm
if exist %tmpF% (
echo.     =Curr#1
goto repl1
)
echo.     ? Curr#1
call wGetUrl2fil.cmd %wUrl% %tmpF%
if defined errInf goto :eof
set errT=] err:N nulG %curT% %gFil%.z00.01.repl
:: если файл гостевой недоступен...
if %wGetSiz% ==  0  set /a nulG+=1 & goto killZero
:repl1
set chkN=1
for /F "tokens=*" %%J in ('gawk.exe -f %awkR% %tmpF%') do call :chkRpl %%J
:: если с гостевой текста проблемы, ставим на тексте крест
if "%dat0%"  == "]" set /a badG+=1 & goto fixErr
:: если гостевая пуста, так и запишем...
if %dat0% == 0 goto noRepl
set aDat=%dat0%
set aNum=%num1%
goto fixNews

:noRepl  гостевая пуста, отклик по нулям
set /a rNot+=1
set aDat=         0
set aNum=0
set rNum=0
:fixNews выгрузка собранных данных в накопительный список
set /a tHit+=%hitT%
call :formIt %hitT% %numP% %hitP% %sizT% %aNum% %rNum%
goto :eof

:formIt %hitT% %numP% %hitP% %sizT% %aNum% %rNum%
gawk.exe "BEGIN{printf(\"%%7s%%6s%%8s%%8.1f%%6s%%5s\",%1,%2,%3,%4,%5,%6);exit}" >> %lstJ%
echo. %begD% %endD% %aDat% %namA% %namT% %id_P% %id_T% %votT% %jnrT% %oldH% %gFil% >> %lstJ%
goto :eof

:chkTxt begD endD sizT namA namT votT jnrT fNam - вычленение данных по тексту/гостевой
:: . . . 1 .. 2 .. 3 .. 4 .. 5 .. 6 .. 7 .. 8
set begD=%1
set endD=%2
set namA=%4
set namT=%5
set sizT=%3
set votT=%6
set jnrT=%7
set errT=%*
goto :eof

:chkVot %%J balN balM balS 
set balN=%1
set balM=%2
set balS=%4 
goto :eof

:chkRpl 1 2 .. 3 .. 4 .. 5 - вычленение данных по тексту/гостевой
:: . aDat arcN aNum pagN fNam
:: . dat0 num0 num1 num2
set dat0=%1
set num0=%2
set num1=%3
set num2=%4
set errT=%*
goto :eof

:killZero
if exist %tmpF% erase %tmpF%
:fixErr с текстом или его гостевой всё плохо, пропускаем (игнорируем этот текст)
set /a linN-=1
echo.     -X- %errT%
echo %errT% %wUrl% >> %eLst%
goto :eof

:: 2018.08.10, nvv, creation
:: ...
:: 2020.01.08, nvv, добавлен счётчик tHit - подсчёт суммы хитов всех призёров
:: 2020.03.14, nvv, мелкие изменения
:: 2020.06.14, nvv, работа не с *.bStat а с *.cChkH <- список с нормализованными хитами за 302 дней
:: 2020.08.08, nvv, подправлен оживляж (нагляднее-с;)
:: 2020.11.16, nvv, будКлуб - глупость? не факт... ;(
:: 2020.12.31, nvv, hitL check added (no votes & repls for low text's hits)
:: 2021.04.09, nvv, minor updates
:: 2021.04.19, nvv, minor updates
:: 2021.05.11, nvv, очередная оптимизация с унификацией...

    Имя файла скрипта: "dTextR.awk" V-текст скрипта-V
- - - - - - - - -
BEGIN{            # siTop-dTextR.awk - (для рейтингов T1000) взять инфу со страниц гостевой текста
  fErr="] eInP:NO input file"
  if(ARGV[1]=="")exit                             # защита от случайного пуска
# 2018.02.25, nvv, creation (siReplsChk.awk)
# ...
# 2019.01.04, nvv, update
# 2019.04.04, nvv, sizB added (== ".0" if "доступ ... ограничен", else == ".1")
# 2019.07.28, nvv, переименовано + убрана работа с текстами, - только гостевые + реорганизовано
# 2019.12.06, nvv, current unification

# Скрипт выдаёт на StdOut 5 литералов:
#:: aDat,arcN,rNum,pagN,gFil
#1 aDat - дата нужной/последней реплики в интервале, в гостевой (2018.07.20)
#2 arcN - кол-во архивов (0..999)
#3 rNum - номер нужной/последней реплики в интервале, в гостевой (0..1012, может быть пусто "-")
#4 pagN - номер нужной/последней страницы гостевой (1..26)
#5 gFil - чистое ИМЯ файла текста/гостевой (f-fedorochew_a.major)

  arcN=0                                          # кол-во архивов (значения по умолчанию)
  pagN=1                                      # кол-во страниц, pageN==1 is default, ever if none
  rNum=0                                          # номер найденной реплики
  aDat=0                                          # дата этой найденной реплики
  step=0                                      # шаг "разбора" страницы текста/гостевой "Самиздата"
  modSI=1                         # ОБРАТНАЯ сортировка реплик на странице гостевой (штатная в СИ)
  chkN=""           # 0==последняя реплика; >0==номер искомой реплики; ""(пусто) - атрибуты текста
  gFil=""                                         # имя файла, БЕЗ пути и расширения
  for ( tmp0 in ENVIRON ) {                   # ! регистр букв в имени переменной может быть любой
    tmp1 = tolower( tmp0 )                        # Temp и temp - РАЗНЫЕ имена для gAwk...
    if ( tmp1 == "chkn" ) chkN=ENVIRON[tmp0]      # номер первой реплики в последней 1000-е
    if ( tmp1 == "gfil" ) gFil=ENVIRON[tmp0] #чистое ИМЯ файла текста/гостевой (f-fedorochew_a.major)
    if ( tmp1 == "hitt" ) hitT=ENVIRON[tmp0]      # очищенный si-HTML текст
  }
  if(hitT)hitT=sprintf("%7s",hitT)
  fErr="P eAvt:"hitT" NO owner FIO"               # бывает-с, хотя и очень редко...
  if(gFil==""){                               # при автономной работе приходится вычленять нужное
    jr=split(ARGV[1],jArr,":")                    # drv
    jr=split(jArr[jr],jArr,"\\")                  # path
    tmp1=split(jArr[jr],jArr,".")                 # name+ext
    gFil=jArr[1]
    for(jr=2;jr<tmp1;jr++)gFil=gFil"."jArr[jr]    # a-abwow_a_s.fp.z00.01.repl.htm
  }
}

function getDat(tmp2) {                           # выдернуть дату реплики
#"<small>91.</small> <b>Алена Николаева</b> <small><i>2018/07/03 12:23  </i>  ") {
  if (match(tmp2, /([0-9]{4})\/([0-9]{2})\/([0-9]{2}) ([0-9]{2}:[0-9]{2}) *<\/i>/,aj)) { 
  return aj[1]"."aj[2]"."aj[3];                   # aj[4] игнорируем, только дата, время не нужно
  } else {return "~???~"}; 
}

function pack(j1) {             # заменить мешающие символы на нейтральные + закавычить результат
  j2=""                                           # TAB -> "•"
  while(n=index(j1,"\x09")) { j2 = j2 substr( j1, 1, n-1 ) "•"; j1 = substr( j1, n+1 ) }
  j1=j2 j1
  j2=""                                           # пробел -> "•"
  while(n=index(j1," ")) { j2 = j2 substr( j1, 1, n-1 ) "•"; j1 = substr( j1, n+1 ) }
  j1=j2 j1
  j2=""                                           # неразрывный_пробел -> "•"
  while(n=index(j1,"\xA0")) { j2 = j2 substr( j1, 1, n-1 ) "•"; j1 = substr( j1, n+1 ) }
  j1=j2 j1
  j2=""                                           # двойные кавычки -> "”"
#  while(n=index(j1,"\"")) { j2 = j2 substr( j1, 1, n-1 ) "”"; j1 = substr( j1, n+1 ) }
  while(n=index(j1,"\"")) { j2 = j2 substr( j1, 1, n-1 ) "&quot;"; j1 = substr( j1, n+1 ) }
  j1=j2 j1
  j2=""                                           # "••" -> "•"
  while(j0=index(j1,"%")) { j2 = j2 substr( j1, 1, j0-1 ) "&#x25;"; j1 = substr( j1, j0+1 ) }
  j1=j2 j1
  j2=""                                           # "••" -> "•"
  while(n=index(j1,"••")) { j2 = j2 substr( j1, 1, n-1 ); j1 = substr( j1, n+1 ) }
  j1=j2 j1
  if(substr(j1,1,1)=="•") j1 = substr( j1, 2 )    # del "•" at beg
  n=length(j1)
  if(substr(j1,n,1)=="•") j1 = substr( j1, 1, n-1 ) # del "•" at end
  return ("\""j1"\"")
}

{
# <h3>Влад
  if (!step) {                                    # нулевой шаг - автор
    if (match($0, /<h3>(.*)$/, aj)) {
      if(aj[1]=="") exit                          # == "битая" гостевая (нет ника автора)
      fErr="H eHdr:"hitT" no title"
      step=1
      next
    }
  }
# <center><h2>Комментарии: <a href=
#<h2>Комментарии: <a href="/k/koshienko_a_g/kniga3.shtml">6 Косплей Сергея Юркина (книга четвёртая)</a><br><small>&nbsp;()</small></h2>
#<center><h2>Комментарии: <a href="/f/fedorochew_a/2018.shtml">Лось</a><br><small>&nbsp;
#(Оценка:<b><a href=/cgi-bin/vote_show?DIR=f/fedorochew_a&FILE=2018>8.26*694</a></b>,)</small></h2>
#        <center><h2>Комментарии: <a href="/p/polishuk_w/zenitchic.shtml">Зенитчик</a>
#<br><small>&nbsp;(Оценка:<b><a href=/cgi-bin/vote_show?DIR=p/polishuk_w&FILE=zenitchic
#>5.98*169</a></b>,)</small></h2>
#  {if(match($0,/:<b><a href=\/cgi-bin\/vote_show\?DIR=.+>(.+)<\/a>/,a)) print a[1];exit}
  if (step==1) {
    if (tmp0=index($0,"<h2>Комментарии: <a href=")) {
      $0=substr($0,tmp0+30)
      match($0, />(.*)<\/a><br>/, aj)             # выдернуть название текста, к которому гостевая
      namT=pack(aj[1])
      if ((aj[1]=="")||(aj[1]=="Управление")) exit #== "битая" гостевая (нет или "левое" название)
      fErr="I eInf:"hitT" bad dates/size"
      step=2
      next
    }
  }
#<li>Обновлено: 21/05/2018. 1123k. <a
#<li>Размещен: 30/04/2019, изменен: 29/06/2019. 231k. <a
  if (step==2) {
if (match($0,/^<li>Размещен: [0-9]{2}\/[0-9]{2}\/(..)?[0-9]{2}\, изменен: [0-9]{2}\/[0-9]{2}\/(..)?[0-9]{2}\. [0-9]+k\. <a/,aj)){
      fErr="J eJnr:"hitT" bad janr info"
      step=3
      next
    }
  }
#<li><a href=/type/index_type_15-1.shtml>Новелла</a>: <a href="/janr/index_janr_5-1.shtml">Проза</a>, <a href="/janr/index_janr_1-1.shtml">Фантастика</a>, <a href="/janr/index_janr_35-1.shtml">Фанфик</a>
#<li><a href=/type/index_type_5-1.shtml>Статья</a>: <a href="/janr/index_janr_15-1.shtml">Философия</a>, <a href="/janr/index_janr_10-1.shtml">Переводы</a>
#<li><a href=/type/index_type_4-1.shtml>Очерк</a>: 
  if (step==3) {
    if(match($0, /<li><a href=\/type\/index_type_.+<\/a>: /, aj)){
      fErr=""
      step=4
      next
    }
    if (namT=="\"Информация•о•владельце•раздела\"") { # тут жанров нет в прнципе!
      fErr=""
      step=4
      next
    }
  }
#6 arcN["namA"] кол-во архивов (0..999)
#7 pagN["namT"] номер нужной/последней страницы гостевой (1..26)
#<center><small> Отсортировано по:[убыванию][<a href=/comment/k/koshienko_a_g/kniga3?ORDER=reverse>возрастанию</a>]</small></center><center><b>Страниц (8):</b> <b>1</b> <a href=/comment/k/koshienko_a_g/kniga3?PAGE=2>2</a> <a href=/comment/k/koshienko_a_g
# … <b>Страниц (2) …
# … <b>Архивы (46) …
  if ((step-3)>0) {     # навигация есть ТОЛЬКО если ВОЗМОЖНА пересортировка (даже невидимого-с;)
    if ( index( $0, "> Отсортировано по:[" )) {   # в СИ (по умолчанию) сортировка по убыванию,
      if ( match($0,/<b>Страниц \(([0-9]{1,2})\)/, aj ) ) {
        pagN=aj[1]
        if ( match($0,/<b>Архивы \(([0-9]+)\)/, aj ) ) {
          arcN=aj[1]
        }
      }
      if ((pagN-26)>0) pagN=26
      modSI=index($0," по:[убыванию") # признак сортировки: 0==прямая, >0==обратная (по умолчанию)
    }
#1  aDat(11)    дата нужной/последней реплики в интервале, в гостевой (2018.07.20)
#4 rNum(5) - номер нужной/последней реплики в интервале, в гостевой (0..1012, может быть пусто "-")
#"<small>91.</small> <b>Алена Николаева</b> <small><i>2018/07/03 12:23  </i>  ") {
    if ( match($0,/<small>([0-9]+)\.<\/small>/, aj ) ) {
      step++
      rNum=aj[1]                                  # номер очередной реплики ("91")
      aDat=getDat($0)                             # дата очередной реплики ("2018,07,03)
      if(modSI) exit
      else {
        if (!chkN) exit
        else if ((rNum-chkN)>=0) exit             # первая в границах
      }
    }
  }
}

END{
  if(fErr!="") print("] err:"fErr,fNam)           # у нас проблема
  print(sprintf("%11s%5s%5s%3s",aDat,arcN,rNum,pagN),gFil)
}

    Имя файла скрипта: "dTextV.awk" V-текст скрипта-V
- - - - - - - - -
BEGIN{            # siTop-dTextV.awk - (для рейтингов T1000) взять инфу со страницы оценок текста
  fErr="]] NO or bad file"
  if(ARGV[1]=="")exit                             # защита от случайного пуска
# 2019.12.08, nvv, creation
  gFil=""                                         # имя файла, БЕЗ пути и расширения
  for ( tmp0 in ENVIRON ) {                   # ! регистр букв в имени переменной может быть любой
    tmp1 = tolower( tmp0 )                        # Temp и temp - РАЗНЫЕ имена для gAwk...
    if ( tmp1 == "gfil" ) gFil=ENVIRON[tmp0] #чистое ИМЯ файла текста/гостевой (f-fedorochew_a.major)
  }
  if(gFil==""){                               # при автономной работе приходится вычленять нужное
    jr=split(ARGV[1],jArr,":")                    # drv
    jr=split(jArr[jr],jArr,"\\")                  # path
    tmp1=split(jArr[jr],jArr,".")                 # name+ext
    tmp1--
    gFil=jArr[1]
    for(jr=2;jr<tmp1;jr++)gFil=gFil"."jArr[jr]    # a-abwow_a_s.fp.z00.01.repl.htm
  }
}

# budclub.ru/cgi-bin/vote_show?DIR=n/nosow_w_w&FILE=si_tq1k-curr
# budclub.ru/cgi-bin/vote_show?DIR=m/metelxskij_n_a&FILE=wtt-1

#голосования.<br><table align=right cellspacing=0 cellpadding=10 border=0 bgcolor=#e0e0e0>
#<tr><td valign=top><b>ВСЕГО: 8.00 * 3</b>
#</br><b>8</b>: 2 (отличная книга)
#<br><b>6</b>: 1 (нормально)
#<br></td>
#<tr><td colspan=2 bgcolor=#e5e5e5>Сред. <b>7.33</b> Дисп. <b>0.89</b>
#<br><br>
#Всего оценок: 1585376</a><br><a href=/rating/top40/>Рейтинг: Сорок лучших</a><br><a href=/rating/top100/>Рейтинг: Топ-500</a><br><a href=/rating/expert/>Рейтинг: Избранное</a></td></tr></td></table><pre><small> <a href=http://samlib.ru/cgi-bin/vote_show?

#голосования.<br><table align=right cellspacing=0 cellpadding=10 border=0 bgcolor=#e0e0e0>
#<tr><td valign=top><b>ВСЕГО:  * 2</b>
#</br><b>8</b>: 1 (отличная книга)
#<br><b>7</b>: 1 (хорошая книга)
#<br></td><tr><td colspan=2 bgcolor=#e5e5e5>Сред. <b>7.50</b> Дисп. <b>0.25</b>. Cnt <b>2</b>
#<br><br>Всего оценок: 1584436</a><br><a href=/rating/top40/>Рейтинг: Сорок лучших</a><br><a href=/rating/top100/>Рейтинг: Топ-500</a><br><a href=/rating/expert/>Рейтинг: Избранное</a></td></tr></td></table><pre><small>  <a href=http://samlib.ru/cgi-bin/vote_show?ITEM=seVBNdpdUckiE&DIR=n/nilin_a&FILE=plenniki1>66.102.x.xx</a>        8  2019/10/28 10:07:31 Mozilla/5.0 

{                             # вычленение итогов по оценкам: СИ_баллы; кол-во; среднее; дисперсия
  if(match($0,/=top><b>\
ВСЕГО: ([0-9]+)?\.?([0-9]+)? \* ([0-9]+)<\/b>.+>\
Сред. <b>([0-9]+)\.([0-9]+)<\/b> \
Дисп. <b>([0-9]+)\.([0-9]+)\
.+<br><br>/,aj)){
    if(!aj[1])aj[1]=0                             # оценок меньше 3-х, балловСИ просто нет
    if(!aj[2])aj[2]=0                             # значит ставим 0.0 вместо
    fErr=""                                       # N . <-средн.--> <-СИ балл--> <-дисп.-->
    print sprintf("%4s %2s.%-2s %2s.%-2s %2s.%-2s",aj[3],aj[4],aj[5],aj[1],aj[2],aj[6],aj[7]), gFil
    exit
  }
}

END{
  if(fErr!=""){
    print fErr,fNam                               # у нас проблема...
    exit 1
  }
}

    Имя файла скрипта: "fHtml.awk" V-текст скрипта-V
- - - - - - - - -
BEGIN{                                      #  fHtml.awk - оформление в HTML рейтинга "siTopTexts"
  if(ARGV[1]=="")exit                             # защита от случайного пуска

# 2024.08.27, nvv, отключена отметка "Upd" для: "Исходные тексты скриптов"
#   + """ -> "&#xB7;"
# ! прочая история - в подвале

  rTyp="<b>si&#x54;op&#x54;exts</b>"              # siTopTexts
  ancW="t"                                # общий признак типа рейтинга в якорях, комментах и т.п.
  ancS=":"                                  # частный признак якоря места (в формате: "ггммвв:NNN"
  nAnc="nvv"                                      # спец.якорь для первой МОЕЙ вещи ;)
  flag=0                                          # флаг для чередующейся раскраски строк таблиц
  tGap=100                                        # строк в одной таблице
  tMax=0                                          # строк в списке всего
  maxH=0                                          # максимальные хиты текста (1-й в рейтингше)
  totH=0                                          # сумма хитов всех текстов
  nAv1=0                                          # новый автор
  oldT=0                                          # размещено более года назад
  curT=0                                          # размещено в границах обсчитываемого интервала
  ficT=0                                          # фикция (за верхней границы интервала)
  nTx1=0                                          # вверх
  nTx2=0                                          # новинки
  nTx3=0                                          # вниз
  nSz1=0                                          # объём+
  nSz2=0                                          # объём-
  nUs1=0                                          # успех+
  nUs2=0                                          # успех-
  rNew=0                                          # число гостевых со свежими репликами
  tNot=0                                          # число мошенников с ограниченным доступом
  mNot="<b>~ ? ~</b>"
  updH=0                                          # поправленные хиты за "30 дн."
  dOld=""
  hDat=-1                                         # 
  donH=-1
  hPag=-1
  nHit=-1
  hitL=-1
  hMax=-1
  nulG=-1
  badG=-1
  rNot=-1
  zipR=-1
# "/" == общий префикс урла СИ: samlib.ru
  nUrl="n/nosow_w_w"                              # nvv-с...
#  jDat=strftime("%y%m%d%H%M%S",systime())         # дата для якорей таблиц

  for ( jj in ENVIRON ) {                     # ! регистр букв в имени переменной может быть любой
    j1=tolower(jj)
    if ( j1 == "fold" ) fOld=ENVIRON[jj]          # ИМЯ опорного файла (like 2018.11.29.mText)
    if ( j1 == "hdir" ) hDir=ENVIRON[jj]"\\"      #  место для файлов *.HTML
  }
  if(fOld==""){
    fOld="U:\\Stor\\Text\\zOld.dTexts\\2023.10.24.dText"
    fOld="U:\\Jobs\\2023.10.24.dText"
    hDir=".\\"
  }

  nMth[ 1]="января"
  nMth[ 2]="февраля"
  nMth[ 3]="марта"
  nMth[ 4]="апреля"
  nMth[ 5]="мая"
  nMth[ 6]="июня"
  nMth[ 7]="июля"
  nMth[ 8]="августа"
  nMth[ 9]="сентября"
  nMth[10]="октября"
  nMth[11]="ноября"
  nMth[12]="декабря"

   color[0]="\"#FFFFE0\""                     # (четная строка таблицы) светло-жёлтый line color 0
   color[1]="\"#F5F5DC\""                   # (НЕчетная строка таблицы) грязно-жёлтый line color 1
   color[2]="\"#C0C0C0\""                         # gray серый (всё плохо)
   color[3]="\"#FFF4E0\""                         # светло-розовый (ниже, меньше, плохо, нет)
   color[4]="\"#F0FFE0\""                         # светло-зелёный (выше, больше, хорошо)
   color[5]="\"#FFFFB0\""                         # светло-жёлтый - новое
   color[6]="\"#FFFF70\""                       # yellow желтый (нечётные ячейки в шапках таблиц)
   color[7]="\"#F8F8F8\""                         # светло-серый - наш рейтинг
   color[8]="\"#0000FF\""                         # синий (птичка nvv)
   color[9]="\"#000000\""                         # чёрный (вратый объём)
  color[10]="\"#E8F8B8\""                         # зелёный - ячейки с текстом нашего рейтинга
  color[11]="\"#E0F8FF\""                 # светло-сиреневый - размещено "давно" больше года назад
  color[12]="\"#FFD700\""                         #  оранжевый "потеряшки" /скрытые разделы/ aad2

  jr=split(ARGV[1],aq,"\\")                       # U:\Jobs\#qMonths\ +2020.06.03.vText
  dEnd=substr(aq[jr],1,10)
  fOut=hDir aq[jr] ".html"                        #  U:\Stor\Html\ +2020.06.08.dText +.html
  fPre=hDir aq[jr] ".z.html"                      #  U:\Stor\Html\ +2020.06.08.dText +.z.html
  rYea=substr(aq[jr],1,4)                         # год рейтинга !привязан к верхней дате выборки
  rMth=substr(aq[jr],6,2)                         # месяц его же
  rDay=substr(aq[jr],9,2)                         # день его же

  dBeg=strftime("%Y.%m.%d",mktime(rYea" "rMth" "rDay" 12 00 00")-86400*29) # дата 1-го дня выборки
  yBeg=substr(dBeg,1,4)                           # год этого 1-го дня интервала нашей выборки
  oldD=rYea-1"."rMth"."rDay                       # "год назад" - привязка к КОНЦУ нашей выборки
  tOld="года"
  qGap="30дн."
  info="<!-- (L) nvv; type: '30days' done: }"strftime("%Y.%m.%d %H:%M")"{ -->" # mark HTML
  inf2="<!-- (L) nvv; type: '30days' \"prev siTopTexts\" "strftime("%Y.%m.%d %H:%M")" -->"
  print "--- " strftime("%H:%M:%S") " Begs..."  # начали работу (оживляж;)

# † массив строк шапки общий
# # информационная вставка --> • ¦ » &#x95; &#xA6; &#xBB;
  if(strftime("%j")-355>0)jj="С наступающим"
  else if(strftime("%j")-11<0)jj="С"
  else jj=""
  if(jj!=""){
    aHnY[++nHnY]="<table align=center border=0 cellspacing=0 cellpadding=2>"
    aHnY[++nHnY]="<tr align=center bgcolor=navy><td><font size=+2 color=aqua>"
    aHnY[++nHnY]="<b>&nbsp;&#x2744; "jj" новым годом! <font color=white>&#x2744;"
    aHnY[++nHnY]="<font size=+2 color=lime>Happy New Year! &#x2744;&nbsp;</b></td>"
    aHnY[++nHnY]="</tr></table>"
    aHnY[++nHnY]="<hr>"
  }
#  aHdr[++nHdr]="<table align=center border=1 cellspacing=0 cellpadding=2>"
#  aHdr[++nHdr]="<tr align=center bgcolor=LightYellow><td><font size=+1><b>&nbsp;NB."
#  aHdr[++nHdr]="В <a href=/comment/"nUrl"/si_top500look-curr>гостевой</a>"
#  aHdr[++nHdr]="(реплика #58.) - <font color=brown>ОПРОС..." # <font color=brown>
#  aHdr[++nHdr]="</font>Мне интересно ваше мнение. :-!&nbsp;</b></td>"
#  aHdr[++nHdr]="</tr></table>"
#  aHdr[++nHdr]="<hr>"
# # <!-- информационная вставка (справка в шапке)
  aHdr[++nHdr]="См. <i>также</i>:"
  aHdr[++nHdr]="<br>?"
  aHdr[++nHdr]="<a href=/"nUrl"/si_pop-brief.shtml>Как узнать<b>"
  aHdr[++nHdr]="популярность произведения</b> в \"Самиздате\"</a>"
  aHdr[++nHdr]="(\"<b>где/что смотреть</b>\" - основное, вкратце)."

# † массив строк шапки ТОЛЬКО у последнего рейтинга
  aHdr[++nHdr]="<br>+"
  aHdr[++nHdr]="<a href=/"nUrl"/si_top6author-curr.shtml>"
  aHdr[++nHdr]="Рейтинг <b>siTopAuthors</b> \"Авторы\"</a>"
  aHdr[++nHdr]="(\"Самиздат\" <b>намедни</b>, приложение к "rTyp")."
  aHd1[++nHd1]="<br>#"
#   aHd1[++nHd1]="<font color=\"#DC143C\">Upd</font>" #  2024.07.27 11:43
  aHd1[++nHd1]="<a href=/"nUrl"/sitopscriptslist.shtml>"
  aHd1[++nHd1]="Исходные <b>тексты скриптов</b> задач \"<b>siTop…</b>\"</a>"
#   aHd1[++nHd1]="<br>="
#   aHd1[++nHd1]="<a href=/"nUrl"/si_top100repls-current.shtml>"
#   aHd1[++nHd1]="Сборка "rTyp"</a> (среда,"
#   aHd1[++nHd1]="<i>скрипты</i>, обстоятельства и рекомендации)."
  aHd1[++nHd1]="<br>*"
#   aHd1[++nHd1]="<font color=\"#DC143C\">Upd</font>" #  2024.02.07 11:51
  aHd1[++nHd1]="<a href=/"nUrl"/si_top-old_ones.shtml>История-<b>Р</b>,"
  aHd1[++nHd1]="\"<i>прикопанное</i>\" <b>прошлое</b></a>"
  aHd1[++nHd1]="(ссылки на подборки старых рейтингов по полугодиям)."
  aHd1[++nHd1]="<br>&#x00B1;" # <font color=red size=-2>New</font>"
  aHd1[++nHd1]="<a href=/n/nosow_w_w/si_votes-brief.shtml><b>Оценка произведений</b>"
  aHd1[++nHd1]="в \"Самиздате\"</a> (<b>что, где, как</b> и почему&hellip;)."
  aHd1[++nHd1]="<br>&#x221A;"
  aHd1[++nHd1]="<a href=/n/nosow_w_w/si-ini_reg.shtml><b>Регистрация</b> в \"Самиздате\" для получения"
  aHd1[++nHd1]="статуса &#171;<b>пользователь</b>&#187;</a> (оформление своего аккаунта)."
  aHd1[++nHd1]="<hr>"

  aHd1[++nHd1]="<b>NB.</b> <i>Названия</i> произведений и <i>псевдонимы</i>"
  aHd1[++nHd1]="авторов (как и прочие <i>сведения</i> в таблицах) приведены"
  aHd1[++nHd1]="<i>\"<a title=\"как есть\""
  aHd1[++nHd1]="href=\"https://ru.wikipedia.org/wiki/%D0%9A%D0%B0%D0%BA_%D0%B5%D1%81%D1%82%D1%8C\"><u>as"
  aHd1[++nHd1]="is</u></a>\", по состоянию на момент</i> сбора"
  aHd1[++nHd1]="данных. <i>Текущее</i> состояние можно узнать, пройдя"
  aHd1[++nHd1]="<i>по ссылкам</i> (в ячейках таблиц)."
  aHd1[++nHd1]="<br><b>(!)</b> <i><u>Если</u></i> на месте некоторых букв"
  aHd1[++nHd1]="(символов) в <i>названии</i> произведения или в <i>псевдониме</i>"
  aHd1[++nHd1]="автора вы видите \"<i><u>пустоту</u></i>\", то <i><u>у"
  aHd1[++nHd1]="вас</u></i>, скорей всего, <i><u>отсутствует</u></i>"
  aHd1[++nHd1]="шрифт с такими символами (иероглифы, руны, etc.)."
  aHd1[++nHd1]="<br><b>(#)</b>"
  aHd1[++nHd1]="<i>Скрытые</i> авторы <u><i>отсутствуют</i></u>" # <font color=\"#A52A2A\"></font>
  aHd1[++nHd1]="в \"<a href=/rating/hits/>Рейтинге по количеству посетителей</a>\"."
  aHd1[++nHd1]="<br><b>(~)</b>"
  aHd1[++nHd1]="<i>Новые</i> авторы/произведения отсутствовали в <i><u>предыдущем</u></i> рейтинге."
  aHd1[++nHd1]="<br><b>(+)</b>"
#   aHd1[++nHd1]="<font color=\"#DC143C\">NEW</font>" #  2023.10.28 crimson
  aHd1[++nHd1]="<i>Новые</i> отклики\" появились в гостевой" # <font color=\"#884700\">\"</font>
  aHd1[++nHd1]="<u><i>после</i></u> сборки предыдущего рейтинга."
}

function dat_str(d0,d2) {       # "2020.05.23" -> "23 мая" (d2==nul) or "23 мая 2020 г." (d2!=nul)
  d1=split(d0,ad,".")
  if(!d2)return("<b>"ad[3]+0" "nMth[ad[2]+0]"</b>")
  else   return("<b>"ad[3]+0" "nMth[ad[2]+0]"</b> "ad[1]" г.")
}

function mkPage() {               # сборка всей страницы рейтинга/приложения (тип, строк, куда-с)

# † массив строк шапки краткой справки последнего рейтинга
  aTb1[++nTb1]="<hr>"
  aTb1[++nTb1]=""
  aTb1[++nTb1]="<table align=center border=1 cellspacing=0 cellpadding=2>"
  aTb1[++nTb1]="<tr align=center>"
  aTb1[++nTb1]="<td bgcolor="color[1]" colspan=\"14\">Краткая сводка + цвет некоторых"
  aTb1[++nTb1]="ячеек таблиц (<i>предыдущий рейтинг -"
  aTb1[++nTb1]="<a href=/"nUrl"/si_top500look-prev.shtml><b>"dOld"</b></a></i>)</td></tr>"

# † массив строк шапки краткой справки ПРЕДпоследнего рейтинга
  aTb2[++nTb2]="<hr>"
  aTb2[++nTb2]=""
  aTb2[++nTb2]="<table align=center border=1 cellspacing=0 cellpadding=2>"
  aTb2[++nTb2]="<tr align=center>"
  aTb2[++nTb2]="<td bgcolor=\"#F5F5DC\" colspan=\"14\">Краткая сводка + цвет некоторых"
  aTb2[++nTb2]="ячеек таблиц (<i>предыдущий рейтинг - "dOld"</i>, последующий"
  aTb2[++nTb2]="- <a href=/"nUrl"/si_top500look-curr.shtml><b>здесь</b></a>)</td></tr>"

# † массив строк тела краткой справки общий
  aTbl[++nTbl]="<tr align=center><td bgcolor="color[0]" colspan=\"1\"><b>N</b>,"
  aTbl[++nTbl]="сдвиг места</td></td>"
  aTbl[++nTbl]="<td rowspan=\"4\"></td>"
  aTbl[++nTbl]="<td bgcolor="color[0]"><b>Произведения</b></td>"
  aTbl[++nTbl]="<td rowspan=\"4\"></td>"
  aTbl[++nTbl]="<td bgcolor="color[0]"><b>Авторы</b></td>"
  aTbl[++nTbl]="<td rowspan=\"4\"></td>"
  aTbl[++nTbl]="<td bgcolor="color[0]"><b>Размещено</b></td>"
  aTbl[++nTbl]="<td rowspan=\"4\"></td>"
  aTbl[++nTbl]="<td bgcolor="color[0]"><b>Объём</b> стал</td>"
  aTbl[++nTbl]="<td rowspan=\"4\"></td>"
  aTbl[++nTbl]="<td bgcolor="color[0]"><b>Оценки</b></td>"
  aTbl[++nTbl]="<td rowspan=\"4\"></td>"
  aTbl[++nTbl]="<td bgcolor="color[0]"><b>Отклики</b></td>"
  aTbl[++nTbl]="</tr><tr align=center>"
  aTbl[++nTbl]="<td bgcolor="color[4]">вверх.<b>" nTx1"</b></td>"
  aTbl[++nTbl]="<td bgcolor="color[5]"rowspan=\"2\">новые.<b>"newN"</b></td>"
#   aTbl[++nTbl]="<td bgcolor="color[5]">новые.<b>"newN"</b></td>"
#   aTbl[++nTbl]="<td bgcolor="color[5]"rowspan=\"2\">новые.<b>"nAv1"</b></td>"
  aTbl[++nTbl]="<td bgcolor="color[5]">новые.<b>"nAv1"</b></td>"
  aTbl[++nTbl]="<td bgcolor="color[4]">"qGap"<b>"curT"</b></td>"
  aTbl[++nTbl]="<td bgcolor="color[4]">больше.<b>"nSz1"</b></td>"
  aTbl[++nTbl]="<td bgcolor="color[4]">хорошие.<b>"nUs1"</b></td>"
  aTbl[++nTbl]="<td bgcolor="color[5]">новые.<b>"rNew"</b></td>"
  aTbl[++nTbl]="</tr><tr align=center>"
  aTbl[++nTbl]="<td bgcolor="color[3]">вниз.<b>" nTx3"</b></td>"
#   aTbl[++nTbl]="<td bgcolor="color[12]">скрытые.<b>"newN"</b></td>"
  aTbl[++nTbl]="<td bgcolor="color[12]">скрытые.<b>"length(a90)"</b></td>"
  aTbl[++nTbl]="<td bgcolor="color[11]">давно.<b>"oldT"</b></td>"
  aTbl[++nTbl]="<td bgcolor="color[3]">меньше.<b>"nSz2"</b></td>"
  aTbl[++nTbl]="<td bgcolor="color[3]">плохие.<b>"nUs2"</b></td>"
  aTbl[++nTbl]="<td bgcolor="color[3]">нет.<b>"rNot"</b></td>"
  if(tNot){
    aTbl[++nTbl]="</tr><tr align=center>"
    aTbl[++nTbl]="<td></td><td></td><td></td><td></td>"
    aTbl[++nTbl]="<td title=\"Доступ ограничен\" bgcolor="color[9]\
"><font color="color[6]">"mNot" "tNot"</font></td>"
  }
  aTbl[++nTbl]="</tr></table>"
  aTbl[++nTbl]="<table align=center border=0 cellspacing=0 cellpadding=2><tr>"
  aTbl[++nTbl]="<td>(</td>"
  aTbl[++nTbl]="<td bgcolor="color[11]"><b><i>давно</i></b> –"
  aTbl[++nTbl]="больше <b>"tOld"</b> назад</td>"
  aTbl[++nTbl]="<td>)</td>"
  aTbl[++nTbl]="</tr></table>"
#  aTbl[++nTbl]="<table align=center border=0 cellspacing=0 cellpadding=2><tr>"
#  aTbl[++nTbl]="<td bgcolor="color[4]"><b>NB.</b> Хиты"
#  aTbl[++nTbl]="произведений, опубликованных <b>после</b>"
#  aTbl[++nTbl]=dat_str(dBeg)", учтены <u>по факту</u>"
#  aTbl[++nTbl]="(„<b>&#xA6;</b>“ - с даты размещения)"
#  aTbl[++nTbl]="</tr></table>"
  aTbl[++nTbl]="<hr>"
  aTbl[++nTbl]=""
  aTbl[++nTbl]="<font size=\"-2\" face=monospace color="color[8]">"
  aTbl[++nTbl]="&nbsp;&nbsp;/\\&nbsp;&nbsp;&nbsp;&nbsp;/\\&nbsp;&nbsp;<br>"
  aTbl[++nTbl]="&nbsp;&#xB7;--&#xB7;--&#xB7;--&#xB7;&nbsp;<br>"
  aTbl[++nTbl]="&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\\/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>"
  aTbl[++nTbl]="&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/\\&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>"
  aTbl[++nTbl]="&nbsp;&nbsp;&nbsp;&nbsp;&#xB7;--&#xB7;&nbsp;&nbsp;&nbsp;&nbsp;<br></font>"

# † титулы (названия) и рейтинга и его копии "Предыдущий"
  Ttl1="<center><font size=\"+2\">Рейтинг "rTyp"-"ancD"</font>"
  Ttl2="<center><font size=\"+2\">Предпоследний рейтинг "rTyp"-"ancD"</font>"

# † массив строк тела рейтинга (всё оставшееся кроме последней строки)
  aOut[++nOut]="<br>\"Самиздат\", самые популярные произведения"
  aOut[++nOut]="<table align=center border=0 cellspacing=0 cellpadding=2>"
  aOut[++nOut]="<tr bgcolor="color[4]">"
  j0="с "dat_str(dBeg)
  if(yBeg!=rYea)j0=j0" "yBeg" г."
  j0=j0" по "dat_str(dEnd,1)"&nbsp;"
  aOut[++nOut]="<td>&nbsp;за 30 дней: "j0"</td>"
#  if(dOff!="0.0")aOut[++nOut]="<td bgcolor="color[3]">(<i><u>нет данных</u> за: "dOff"</i>)</td>"
  aOut[++nOut]="</tr></table></center></blockquote>"
  bLin=mkCap()                                    # шапка - первая (нулевая-с) строка таблиц
  lMax=tMax                                       # всего строк в таблице
  for ( tIni=1; tIni<=lMax; tIni=tIni+tGap ) {
    aOut[++nOut]="<blockquote>"  # начало очередной таблицы
    aOut[++nOut]="<table align=center border=1 cellspacing=0 cellpadding=2>"  # навигация в
    aOut[++nOut]="<caption><a id=\""ancD ancW tIni"\"></a>"mkGoTo(tIni)"</caption>"  # заголовке
    aOut[++nOut]=bLin  # шапка таблицы
    tEnd=tIni+tGap
    for (tBeg=tIni;tBeg<tEnd;tBeg++) {
      if(tBeg<=lMax) aOut[++nOut]=mkTabLn(tBeg,ordr[tBeg])  # строка данных в таблице
    }
    if ((tBeg-tMax)>=0) aOut[++nOut]=bLin
    aOut[++nOut]="</table>"  # таблица готова
    aOut[++nOut]="</blockquote>"  # закрытие блока
  }
  aOut[++nOut]="<blockquote>"  # подвал страницы
  aOut[++nOut]="<center>" mkGoTo(0) "</center>"  # заголовке
  aOut[++nOut]="<ul>"
  aOut[++nOut]="<table border=0 cellspacing=0 cellpadding=2><tr>"  # навигация в
  aOut[++nOut]="<td><b>Попутные сведения</b> (к "rTyp"-"ancD")"
  aOut[++nOut]="<td></tr></table>"
  aOut[++nOut]="<li>Справочник ИСС-СИ"
  aOut[++nOut]="\"<a href=/rating/hits/index.shtml><i><b>Рейтинг по количеству"
  aOut[++nOut]="посетителей</b></i></a>\" за <b>"hDat"</b>."
  aOut[++nOut]="<br>(от "dat_str(donH)", всего страниц: "hPag")"
  aOut[++nOut]="<br>Интервал хитов (<u>за 12мес</u>) у отобранных разделов:"
  aOut[++nOut]="<ul>"
  aOut[++nOut]="<li><i>Лидер</i> (1-е место): <b>"hMax"</b>."
  aOut[++nOut]="<li><i>Замыкающий</i> ("nHit"-е): <b>"hitL"</b>."
  aOut[++nOut]="</ul>"
  aOut[++nOut]="<li><i>Прочие</i> данные - по состоянию на "dat_str(hold)"."
  if(updH)aOut[++nOut]="<li>Произведения с хитами <i>по факту</i> „<b>&#xA6;</b>“: <b>"updH"</b>."
  j0=0
  for(j1 in a90)j0=j0+a90[j1]
  if(j0)aOut[++nOut]="<li>Произведения из „<i>скрытых</i>“ разделов: <b>"j0"</b>."
  aOut[++nOut]="<li>Среди гостевых (у <b>"tMax"</b> произведений списка):"
  aOut[++nOut]="<ul>"
  if(nulG)aOut[++nOut]="<li><i>недоступные</i>: <b>"nulG"</b>;"
  if(badG)aOut[++nOut]="<li><i>повреждёные</i>: <b>"badG"</b>;"
  if(rNot)aOut[++nOut]="<li><i>пустые</i> (кулуары&#x95;\"<i>антимат</i>\"&#x95;без реплик): <b>"rNot"</b>;"
  if(zipR)aOut[++nOut]="<li><i>с архивами</i>: <b>"zipR"</b>."
  aOut[++nOut]="</ul>"
  if(tNot){
    aOut[++nOut]="<br><table border=0 cellspacing=0 cellpadding=2><tr bgcolor="color[9]">"
    aOut[++nOut]="<td><font color="color[6]">&nbsp;Произведения с <b>ограниченным</b>"
    aOut[++nOut]="("mNot") <i>доступом</i>: <b>"tNot"</b>.&nbsp;</td>"
    aOut[++nOut]="</tr></table>"
  }
  aOut[++nOut]="</ul>"
  aOut[++nOut]="<table align=center border=0 cellspacing=0 cellpadding=2>"  # навигация в
  aOut[++nOut]="<tr><td>(copyleft "rYea"</td>"
  aOut[++nOut]="<td bgcolor="color[6]"><b>/\\/.\\/.\\/.</b></td><td>)</td></tr></table>"
}

function mkCap() {        # сборка шапки соответствующего типа таблиц (птичка или ссылка в ячейке)
  tmp0= "<tr align=center bgcolor="color[flag]">" # шапки начало; v-место:хиты
  tmp0=tmp0 "<td title=\"Место:сдвиг в списке, Хиты:за "qGap"\" bgcolor="color[6]"><b>N</b>: Хиты</td>"
  tmp0=tmp0 "<td><b>Произведение</b></a></td>"    # Произведение
  tmp0=tmp0 "<td bgcolor="color[6]"><a title=\"Раздел за 12мес: хиты, место\"><b>Автор(ы)</b></a></td>" # Автор
  tmp0=tmp0 "<td><a title=\"Дата создания текста + дата его последнего изменения\"" # Создан +v
  tmp0=tmp0 "><small>Размещено *<b>Изменено</b></small></a></td>" # ^+ Создан
  tmp0=tmp0 "<td bgcolor="color[6]"><a title=\"Текст в килобайтах\""  # Объём +v
  tmp0=tmp0 "><small><b>Объём</b></small></a></td>" # ^+ Объём
  tmp0=tmp0 "<td><a title=\"Текста\"><small><b>Форма</b>: Жанр(ы)</small></a></td>" # Форма: Жанр(ы)
  tmp0=tmp0 "<td bgcolor="color[6]"><a title=\"Уровень=(Оценки-5.5)*ln(голоса)\"" # Оценки +v
  tmp0=tmp0 "><small><b>Оценка</b></small></a></td>"  # ^+ Оценки
  tmp0=tmp0 "<td><a title=\"Реплик в сутки\""     # Отклик +v
  tmp0=tmp0 "><small><b>Отклик</b></small></a></td>"  # ^+ Отклик
  return( tmp0 "</tr>" )                          # шапка готова
}

function mkTabLn(nLn,tLn) { # таблица: сборка строки номер nLn (строка siTopTexts за номером tLn)
  flag=!flag                                      # чередующаяся раскраска строк
  hLin="<tr align=center bgcolor="color[flag]">"  # собираем очередную строку...
  hLin=hLin"<td "a00[tLn]" title=\""a02[tLn]"\"><a id=\""ancD ancS nLn"\"></a><b>"nLn"</b>: "  # <- место:хиты -v
  if(a23[tLn]!="")hLin=hLin"<a title=\"Хиты по факту.\""
  else            hLin=hLin"<a title=\"Хиты за "qGap"\""
  hLin=hLin "href=/"a10[tLn]"/stat.shtml#"a20[tLn]".shtml>"a22[tLn] a23[tLn]"</a></td>" # <-место:хиты-^
  hLin=hLin "<td align=left"                      # <- text -v
  if(a10[tLn]==nUrl) hLin=hLin " bgcolor=" color[10]  # nvv line ;)
  else if(a00[tLn]==" bgcolor="color[5])hLin=hLin " bgcolor="color[5] # new text
  hLin=hLin "><a href=/" a10[tLn] "/" a20[tLn] ".shtml id=\"" ancA[tLn] ancS a20[tLn] # <- text -^
  hLin=hLin "\">" a21[tLn] "</a></td><td align=left"  # ^- text -> <- автор-v
  if(a10[tLn]==nUrl) hLin=hLin " bgcolor=" color[10]  # nvv line ;)
  else{
    if(a12[tLn]) hLin=hLin a77[tLn] # у автора/раздела ЕСТЬ место в рейтинге "по хитам" 2023.06.24
    else hLin=hLin " bgcolor=" color[12]
  }
  hLin=hLin "><a href=/"a10[tLn]"/ id=\"" ancA[tLn] "\" title=\"Хиты:"a13[tLn]
  if(a12[tLn]) hLin=hLin ", место:"a12[tLn]a78[tLn]"\">" a11[tLn] "</a></td>" # <- автор -^
  else         hLin=hLin ", скрытый\">" a11[tLn] "</a></td>" # <- автор -^
  hLin=hLin "<td "a34[tLn]"><small>"a30[tLn]" *<b>"a31[tLn]"</b></small></td>" # изменено/размещено (текст)
  if(a33[tLn]) hLin=hLin "<td align=right"a81[tLn]">" a82[tLn] a32[tLn] "k"a83[tLn]"</td>" # <- объём
  else hLin=hLin "<td align=right title=\"Доступ ограничен\" bgcolor="color[9]"><font color="\
color[6]">"a32[tLn] "</font></td>"               # <- объём, "доступ ограничен" -^
  hLin=hLin "<td><small>" a40[tLn] "</small></td>"  # жанр(ы)
  if(a50[tLn]==0)hLin=hLin "<td><small>--</small></td>" # оценки+успех +v
  else{
    hLin=hLin "<td"a52[tLn]"><a title=\"Среднее &#xBB; баллыСИ *шт. ==Уровень: "a51[tLn]
    hLin=hLin "\" href=/cgi-bin/vote_show?DIR="a10[tLn]"&FILE="a20[tLn]">"
    hLin=hLin "<small>"a50[tLn]"</small></a></td>"  # ^+ оценки+успех
  }
  if(a62[tLn]==-1)hLin=hLin"<td bgcolor="color[2]"><small>-X-</small></td>" # <- недоступно-с
  else if(a62[tLn]==0){                           # <- гостевая пуста
    hLin=hLin "<td bgcolor="color[3]" title=\"Пусто или кулуары\"><small>"
    hLin=hLin "<a href=/comment/"a10[tLn]"/"a20[tLn]">:)(:</a></small></td>"
  }else{
    hLin=hLin "<td"
    if(a65[tLn])hLin=hLin " bgcolor="color[5]
    hLin=hLin "><small><a href=/comment/"a10[tLn]"/"a20[tLn] # отклик -v
    hLin=hLin " title=\"Реплик в сутки (шт./дни): "a63[tLn] # v- отклик -^
    if(a65[tLn])hLin=hLin "++"
    hLin=hLin "\">"a64[tLn]"</a></small></td>"    #  ^- отклик
  }
  return (hLin "</tr>")                           # строку собрали, вываливаем!
}

function mkGoTo(lCur) {                           # сборка строки навигации для титула таблиц
  lBeg=1                                          # начало очередного интервала
  lEnd=lBeg+tGap-1                                # и его конец
  if ((lEnd-lMax)>0) lEnd=lMax                    # но не выше общего конца
  sNav="<center>Интервал <b>N</b>: <b>"           # начало строки навигации
  for(j0=1;j0<=lMax;j0++) {
    if (j0==lBeg) {                               # компоновка очередного элемента навигации
      if ((lBeg-1)>0) sNav=sNav " | "             # первый разделитель опускаем
      if (lBeg==lCur) sNav=sNav "<big>" lBeg "-" lEnd "</big>"  # это у своей таблицы, v-иначе
      else {
        sNav=sNav "<a title=\"Перейти к интервалу: " lBeg "-" lEnd "\" href=\"#"
        sNav=sNav ancD ancW j0"\">" lBeg "-" lEnd "</a>" # оформление как ссылка на ЯКОРЬ
      }
      lBeg=lEnd+1                                 # сдвинем границы на шаг tGap
      lEnd=lEnd+tGap
      if ((lEnd-lMax)>0) lEnd=lMax
    }
  }
  sNav=sNav"</b></center>"                        # завершение строки
  return(sNav)
}

# hitT numP hitP sizT  aNum rNum   begD      endD       aDat     "namA" "namT" id_P id_T votT jnrT down gFil
# $1    $2   $3   $4    $5   $6     $7        $8         $9       $10    $11   $12  $13  $14  $15  $16  $17
# 24659 12 332071 275.1 -478 478 2018.07.01 2018.11.11 2018.07.18 "Федорочев•Алексей" "Лось" f/fedorochew_a 2018 "6.89*760" 0 v f-fedorochew_a.2018
# 1966 116 59167 1821.1 -199 199 2014.07.10 2017.11.30 2018.02.23 "Скс." "Режим•бога" s/sks 111 0 0 : s-sks.111

{         # загрузка исходного списка (с разборкой и оформлением значений, отображаемых в ячейках)
  if(match($1,/^[0-9]+$/)){                       # признак - "строка основных данных"
    tMax++
    jj=NR-1                                       # 1-st line - hold date
    a00[jj]=0                       # пока неизвестная позиция текста в предыдущем bStat.20??.??.#
    a01[jj]=jj                                    # позиция текста в siTopTexts
    a02[$12"/"$13]=jj                             # обратная ссылка на позицию по урлу текста
    a10[jj]=$12                                   # автор, id_P - урл раздела (мой - n/nosow_w_w;)
    a11[jj]=unpack($10)                           # автор, namA - ФИО
    a12[jj]=$2      #  автор, numP - позиция раздела в рейтинге посещаемости "по зитам" 2023.06.24
    if(!a12[jj])a90[$12]++                    #  СКРЫТЫЙ раздел, учтём произведение из 2023.06.23
    a13[jj]=$3                              # автор, hitP - хиты раздела (в рейтинге посещаемости)
    a20[jj]=$13                                 # текст, id_T - имя файла (без расширения .shtml)
    ancA[jj]=substr($12,1,1)"~"substr($12,3)      # формат: "aChr~aNik"
    a21[jj]=unpack($11)                           # текст, namT - заголовок
    a22[jj]=$1                                  # текст, hitT - хиты текста (в статистике раздела)
    if(match($16,/^[0-9]+\]$/)){
      a23[jj]="<b>&#xA6;</b>"        # 16317.
      updH++
    }else a23[jj]=""
    a30[jj]=rusDat($7)                            # текст, begD - дата размещения в разделе
    a31[jj]=rusDat($8)                            # текст, endD - дата последнего изменения
    split($4,aq,".")
    a32[jj]=aq[1]                                 # текст, sizT - объём в килобайтах
    a33[jj]=aq[2]                       # текст, sizB - "1"==объёмOk, "0"=="доступ ... ограничен"
    if(!aq[2]){
      tNot++                                      # учтём и сосчитаем мошенника... :(
      a32[jj]=mNot                                # и покажем фигу, ВМЕСТО "размера"
    }
    a34[jj]=$7                                    # текст, создан в формате гггг.мм.дд
    a40[jj]=unquot(unpack($15))                   # текст, jnrT - жанр(ы) (может отсутствовать)
    a50[jj]=unpack($14)                           # текст, votT - оценки (могут отсутствовать)
    a60[jj]=$5            # гостевая, aNum номер первой реплики интервала (с минусом == в архиве)
    a61[jj]=$6                        # гостевая, rNum номер последней реплики интервала (текущая)
    a62[jj]=$9                                    # гостевая, aDat дата первой реплики интервала
    if(jj==1)maxH=$1                              # максимальные хиты текста (1-й в рейтингше)
    totH=totH+$1                                  # сумма хитов всех текстов
  }else{
    if($1 $2==";m""hold") {         # сводки сведения + проблемы, замеченные при сборе данных
# ;m hold 2019.07.29
      hold=$3                                     #  дата сборки "yyyy.MM.dd"
      ancD=substr(hold,3,2) substr(hold,6,2) substr(hold,9,2) #  дата сборки "yyMMdd"
    }else{
# ;1A hits 2:xNam 445:xNum 101285:xPas 2021.04.22:hDat 1018:hPag 806772:hMax 1018:DnLd 2021.04.27:done 25:mins gapT~14:53-15:18~ 
# ;2B stat 2021.04.27:sEnd    23:nPre      0:hPre    23:miss 300:minT 552:hitL 30072:nHit 806772:hMax last~00:26:00~
# ;2C scan 2021.04.24:dEnd 29987:nEnd  60688:hEnd 30010:nMig 1593:tNum 10:nGis 29174:nLow mod:v OkV:99.9% 
# ;4T text 0:nulG 0:badG 78:rNot 197:zipR 1479659:tHit 0:dnLd 2021.04.27:done 2:mins 16:07-16:09:gapT 
      if(match($0,/^;1A .+ 20..\.(.+)\.(.+):hDat /,aj))hDat=aj[2]"/"aj[1]  #  дата aHits по СИ-шному
      if(match($0,/^;1A .+ ([\.0-9]+):done /,aj))      donH=aj[1] #  дата "скачан" (aHits)
      if(match($0,/^;1A .+ ([0-9]+):hPag /,aj))        hPag=aj[1] #  страниц aHits
      if(match($0,/^;1A .+ ([0-9]+):hMax /,aj))        hMax=aj[1] #  хиты раздела-лидера aHits
      if(match($0,/^;2B .+ ([0-9]+):nHit /,aj))        nHit=aj[1] #  точное число топовых разделов
      if(match($0,/^;2B .+ ([0-9]+):hitL /,aj))        hitL=aj[1] #  хиты замыкающего за "12мес"
      if(match($0,/^;4T .+ ([0-9]+):nulG /,aj))        nulG=aj[1] #  гостевая недоступна
      if(match($0,/^;4T .+ ([0-9]+):badG /,aj))        badG=aj[1] #  гостевая повреждена
      if(match($0,/^;4T .+ ([0-9]+):rNot /,aj))        rNot=aj[1] #  гостевая пуста
      if(match($0,/^;4T .+ ([0-9]+):zipR /,aj))        zipR=aj[1] #  гостевая с арховом
    }
  }
}

function rusDat(jj) {                             # 2019.19.25 -> 25.19.2019
  split(jj,aq,".")
  return(aq[3]"."aq[2]"."aq[1])
}

function cutR(jj) {                               # из литерала типа "rNot=80"
  split(jj,aq,":")                                # выделяет правую часть
  return(aq[2])                                   # типа "80"
}

function unpack(j1) {               # восстановление литерала, свёрнутого при сборе сведений с СИ
  if (substr(j1,1,1)=="\"") j1=substr(j1,2,length(j1)-2)  # откусим обрамляющие двойные кавычки
  j2=""                                           # "•" -> пробел
  while(n=index(j1,"•")) { j2 = j2 substr( j1, 1, n-1 ) " "; j1 = substr( j1, n+1 ) }
  j1=j2 j1
  j2=""                                           # "”" -> двойные кавычки
  while(n=index(j1,"”")) { j2 = j2 substr( j1, 1, n-1 ) "&quot;"; j1 = substr( j1, n+1 ) }
  j1=j2 j1
  return( j1 )
}

function unquot(j1) {       # восстановление литерала "жанр(ы), свёрнутого при сборе сведений с СИ
  j2=""                                           # '&quot;' -> '"'
  while(n=index(j1,"&quot;")) { j2 = j2 substr( j1, 1, n-1 ) "\""; j1 = substr( j1, n+6 ) }
  j1=j2 j1
  return( j1 )
}

END{                            # данные загружены и разобраны, оформляем рейтинг и приложения...
  if(ARGV[1]==""){
    print "NO input file!"                        # защита от случайного пуска
    exit -1
  }
  if(hold=="") {
    print "NO date to bind guesbooks (no ';m' in 1-st line)"
    exit -1
  }
  if(hDat==-1)aVar["hDat"]=1                      #  дата aHits по СИ-шному
  if(donH==-1)aVar["donH"]=1                      #  дата "скачан" (aHits)
  if(hPag==-1)aVar["hPag"]=1                      #  страниц aHits
  if(nHit==-1)aVar["nHit"]=1                      #  точное число топовых разделов
  if(hitL==-1)aVar["hitL"]=1                      #  хиты замыкающего за "12мес"
  if(hMax==-1)aVar["hMax"]=1                      #  хиты раздела-лидера aHits
  if(nulG==-1)aVar["nulG"]=1                      #  гостевая недоступна
  if(badG==-1)aVar["badG"]=1                      #  гостевая повреждена
  if(rNot==-1)aVar["rNot"]=1                      #  гостевая пуста
  if(zipR==-1)aVar["zipR"]=1                      #  гостевая с арховом
  if(j0=length(aVar)){
    tmp0="? no var(s):"
    for(j1 in aVar)tmp0=tmp0" "j1
    print(tmp0" in "FILENAME)
    exit -1
  }
  endS=mktime(substr(hold,1,4)" "substr(hold,6,2)" "substr(hold,9,2)" 00 00 00")  # seconds "до"

# подвязка позиций прошлого рейтинга, для отметок "сдвиг" (места)
# hitT numP hitP sizT  aNum rNum   begD      endD       aDat     "namA" "namT" id_P id_T votT jnrT gFil
# $1    $2   $3   $4    $5   $6     $7        $8         $9       $10    $11   $12  $13  $14  $15  $16
# 6093 156 27017 1821.1 -291 291 2014.07.10 2017.11.30 2018.03.24 "Скс." "Режим•бога" s/sks 111 0 0 s~sks.111

  tmp0=0
  while ((getline line < fOld) > 0) {             # fOld: like 2018.11.29.mText
    split(line,aj)
#  ;m hold 2019.12.02 первая строка
    if(!tmp0)dOld= substr(aj[3],3,2) substr(aj[3],6,2) substr(aj[3],9,2) #"191202" (ID старого рейтинга)
    else if(match(aj[1],/^[0-9]+$/)){             # это именно строка с хитами текста &Co
      a76[aj[12]]++                               # старые авторы
      j0=aj[12]"/"aj[13]                          # полный ID старого текста
      a80[j0]=aj[4]                               #  размер старого текста
      a84[j0]=aj[6]                               #  реплик в гостевой старого текста
#      split(aj[4],aq,".")                         # объём 50.1 =ok, 50.0 =fake
#      if(aq[2]) a80[j0]=aq[1]                     # реальный объём старого текста
#      else      a80[j0]=0                         # вратый-с
      if(!a00[a02[j0]])a00[a02[j0]]=tmp0    # если этот текст неоптичен запомним, текст был здесь:
    }
    tmp0++                                      # старая позиция текста в старом списке
  }
  close(fOld)                                     # всё/не_всё, - старый список тогось
#   while(hitL-a22[tMax]>0)tMax--           # реальное число строк (текстов) с хитами НЕ менее hitL
  print("tMax:"tMax)
# siTopTexts - оформление заготовок строк (для основного рейтинга)
  split("", ordr)                                 # очистим массив
  newN=0
  for (jj=1;jj<=tMax;jj++){                 # порядок строк (основной цикл построчной подготовки)
    ordr[jj]=jj                                   # - как в источнике
    if(!a00[jj]){                                 # признак "новый текст в рейтинге"
      newN++                                      # и сосчитаем
    }
    if(!(a10[jj] in a76)){                        # новый автор
      a77[jj]=" bgcolor="color[5]                 # новый автор
      a78[jj]=" (Новый)"
      if(!(a10[jj] in a79)){                      # новый автор, первое вхождение
        a79[a10[jj]]++                            # запомним этого нового автора
        nAv1++                                    # и сосчитаем его же-с
      }
    }
# NN - место_в_рейтинге
    if(dEnd<a34[jj]){
      a00[jj]=" bgcolor="color[2]                 # место - "фикция" (до нашего интервала)
      a02[jj]="Фикция"
    }else{
      if(a00[jj]){                                # место в старом рейтинге нашлось?
        j0=a00[jj]-a01[jj]
        if(!j0){                                  # нулевой сдвиг
          a00[jj]=""                              # default color - основной цвет строки
          a02[jj]="Сдвиг:0=="
        }else if(j0>0){                           # "сдвиг" вверх "N-^"
          a00[jj]=" bgcolor="color[4]             # "сдвиг" вверх "N-^"
          a02[jj]="Сдвиг:"j0"-^"
          nTx1++                                  # вверх
        }else{                                    # "сдвиг" вниз "M-v"
          j0=0-j0
          a00[jj]=" bgcolor="color[3]             # "сдвиг" вниз "M-v"
          a02[jj]="Сдвиг:"j0"-v"
          nTx3++                                  # вниз
        }
      }else{                                      # новое "NEW" - светло-желтый
        a02[jj]="Новое"                           # подсказка в этой ячейке
        a00[jj]=" bgcolor="color[5]               # новое "NEW"
        nTx2++                                    # новинки
      }
    }
# изменение размера текста
    if(a33[jj]){                        # текст, sizB - "1"==объёмOk, "0"=="доступ ... ограничен"
      j0=a10[jj]"/"a20[jj]                        # id_P/id_T
      if(split(a80[j0],aq,".")==2){               # в старом рейтинге текст есть
        if(!aq[2])a80[j0]=0                       # "0"=="доступ ... ограничен" (враньё-с)
        else      a80[j0]=aq[1]                   # "1"==объёмOk
        j0=a32[jj]-a80[j0]
        if(!j0) a83[jj]="</a>"
        if(j0>0){
          a81[jj]=" bgcolor="color[4]             # стало больше
          a82[jj]="<a title=\"+"j0"k\">"          # стало больше
          nSz1++
        }
        if(j0<0){
#          j0=-j0
          a81[jj]=" bgcolor="color[3]             # стало меньше
          a82[jj]="<a title=\""j0"k\">"           # стало меньше
          nSz2++
        }
      }
    }
# Жанр(ы)
    split(a40[jj],aq,":")                         # разделим форму и жано(ы)
    if(aq[2]=="") aq[2]="--"                     # два дефиса подряд смотрятся красивше (jnrT;)
    a40[jj]="<b>"aq[1]"</b>: "aq[2]
# Оценки текста (7.25*15) пляски с бубном...
    if(a50[jj]!=0){
      split(a50[jj],aj,"*")
      j1=split(aj[1],az,"»")                      # az[1] - среднее, az[2] - SI баллы
      a50[jj]=az[1]"&#xBB;<b>"az[2]"</b> *"aj[2]
      if(j1==1)j1=aj[1]
      else     j1=az[1]
      a51[jj]=sprintf("%3.2f",(j1-5.5)*log(aj[2]))  # уровень оценок
      if((a51[jj]+0)==0){
        a51[jj]=0                                 # ни рыба, ни мясо
        a52[jj]=""
      }else if(a51[jj]<0){
        a52[jj]=" bgcolor="color[3]               # плохие
        nUs2++                                    # успех-
      }else{
        a52[jj]=" bgcolor="color[4]               # хорошие
        nUs1++                                    # успех+
      }
    }
# Отклик в гостевых
    if(substr(a62[jj],5,1)=="."){     #  aDat (like 2018.07.18) гостевая НЕ пуста, считаем отклик
      j0=mktime(substr(a62[jj],1,4)" "substr(a62[jj],6,2)" "substr(a62[jj],9,2)" 00 00 00") # seconds "от"
      j0=(endS-j0+86400)/86400                    # days - интервал в днях
      j1=a60[jj]
      if(j1<0)j1=a61[jj]+j1+1000                  # nums - реплик в интервале
      else    j1=a61[jj]-j1+1
      a64[jj]=sprintf("%4.2f",j1/j0)              # reac - реплик в сутки (для сортировки)
      a63[jj]=j1"/"j0                             # сборка для вывода (Реплик в сутки (шт./дни))
      if(a60[jj]>0)a64[jj]=a64[jj]"&#x95;"             # архивов нет
      a65[jj]=0                                   #  по умолчанию гостевая без цвета
      j0=a10[jj]"/"a20[jj]                        # id_P/id_T
      if(j0 in a84){                              #  этот текст был в старом рейтинге
        a65[jj]=(a84[j0]!=a61[jj])                #  изменилось ли число реплик?
        if(a65[jj])rNew++
      }
    }
# выявим "свежак", влетевший в рейтинг менее чем за 30 дней a30 и "старьё"
    if(dEnd<a34[jj]){                             # до нашего интервала
      a34[jj]=" bgcolor="color[3]                 # фикция т.е. ПОСЛЕ нашего интервала
      ficT++                                      # счётчик "фикция"
    }else if(dBeg<=a34[jj]){                      # в нашем интервале до верхней границы
      a34[jj]=" bgcolor="color[4]
      curT++
    }else if(oldD>a34[jj]){                       # в нашем интервале до верхней границы
      a34[jj]=" bgcolor="color[11]
      oldT++                                      # счётчик "давно"
    }else  a34[jj]=""
  }
# собственно сборка файла с таблицами...
  if(500-tMax>=0)tGap=50
  if(250-tMax>=0)tGap=25
  mkPage()

  print("<blockquote>")                   >fOut
  print(info)                             >fOut   #  служебная отметка (для порядку)
  if(nHnY)for(jj=1;jj<=nHnY;jj++)print(aHnY[jj])  >fOut
  for(jj=1;jj<=nHdr;jj++)print(aHdr[jj])  >fOut
  for(jj=1;jj<=nHd1;jj++)print(aHd1[jj])  >fOut
  for(jj=1;jj<=nTb1;jj++)print(aTb1[jj])  >fOut
  for(jj=1;jj<=nTbl;jj++)print(aTbl[jj])  >fOut
  print(Ttl1)                             >fOut
  for(jj=1;jj<=nOut;jj++)print(aOut[jj])  >fOut
  print(info)                             >fOut   #  служебная отметка (для порядку)
  printf("</blockquote>")                 >fOut

  print("<blockquote>")                   >fPre
  print(inf2)                             >fPre
  if(nHnY)for(jj=1;jj<=nHnY;jj++)print(aHnY[jj])  >fPre
  for(jj=1;jj<=nHdr;jj++)print(aHdr[jj])  >fPre
  for(jj=1;jj<=nHd2;jj++)print(aHd2[jj])  >fPre
  for(jj=1;jj<=nTb2;jj++)print(aTb2[jj])  >fPre
  for(jj=1;jj<=nTbl;jj++)print(aTbl[jj])  >fPre
  print(Ttl2)                             >fPre
  for(jj=1;jj<=nOut;jj++)print(aOut[jj])  >fPre
  print(inf2)                             >fPre
  printf("</blockquote>")                 >fPre

  print "--- " strftime("%H:%M:%S") " Ends..."  # закончили работу (оживляж;)
# 2018.09.30, nvv creation
# ...
# 2020.05.09, nvv, +дополнения, + мелкая косметика
# 2020.05.21, nvv, раскраска по "Размещено" - "намедни", "недавно" и "давно"
# 2020.06.12, nvv, исправление замеченных неточностей + updates:
# 2020.06.27, nvv, anchors "place" added (теперь можно сослаться извне на любое место рейтинга)
# 2020.07.09, nvv, minor updates
#   = причёсана работа с датами границ потребных интервалов
#   = ведена поддержка "фикций" (хиты ДО размещения текста)
#   = немного обихожены даты и уточнено разграничение: "давно", "недавно", "фикция"
#   = немного изменена палитра раскраски ячеек
# 2020.08.21, nvv, подготовка к отказу от козырного числа 1000 в названии рейтинга
#   вместо "siTop1000texts" стало "siTopTexts"
# 2020.09.23, nvv, поддержка (ссылки на) предыдущего рейтинга
# 2020.09.28, nvv, число текстов в списке определяется по границе выборки bStat:
#   ;2D =Вс= hitL:20223.630 <- т.е. 20223 разделов с хитами "12мес" НЕ ниже 630
#   ergo -> в списке тексты с хитами "30дн." НЕ меньше 630.
# 2020.10.14, nvv, к жанрам текста добавлена форма (роман/повесть/справочник/etc.)
#     + исправлена мелкая ошибка в алгоритме + добавлен спец.якорь "nvvA" ;)
# 2020.10.31, nvv, мелкая косметика
# 2020.11.05, nvv, добавлены якоря ancA на авторов
#     и на сами произведения в формате: "aChr~aNik:id_T" ("ancT")
# 2020.11.09, nvv, добавлено отображение tNot числа текстов "для френдов"
#     (т.е. НЕ доступных "mNot" читателям) в списке
# 2020.11.18, nvv, мелкая косметика
# 2020.12.31, nvv, новогоднее поздравление... ;)
# 2021.01.02, nvv, мелочёвка
# 2021.01.09, nvv, мелочёвка
# 2021.02.12, nvv, мелочёвка
# 2021.03.20, nvv, мелочёвка
# 2021.04.24, nvv, переделки задачи bStat влекут переделки сопряжения
# 2021.05.10, nvv, теперь скрипт создаёт сразу и рейтинг (HTML) и копию в варианте "Предыдущий"
# 2021.05.23, nvv, исправлена устаревшая ссылка на "Историю-Р"
# 2021.06.09, nvv, мелкая косметика
# 2021.09.03, nvv, мелкая неточность (строка "по факту" ненужна, если таковых нет)
# 2021.11.22, nvv, разбиение на таблицы, макс число строк в одной (tGap) - зависит от общего оных числа
# 2021.12.26, nvv, автоматическая вставка поздравления с новым годом
# 2022.01.13, nvv, исправлена неточность в выявлении новогоднего периода
# 2022.10.19, nvv, в шапку добавлена ссылка на текст: "Регистрация в СИ""
# 2022.12.01, nvv, текст: "Регистрация в СИ" перестал быть New
# 2023.06.24, nvv, добавлена поддержка aad2 произведений из скрытых разделов
# 2023.07.29, nvv, мелкая косметика
# 2023.11.01, nvv, "(+)"==отмечаются цветом гостевые с изменившимся числом реплик "свежее"
# 2023.11.30, nvv, снято извещение о: отмечаются цветом гостевые с изменившимся числом реплик
# 2024.02.07, nvv, добавлена отметка "Upd" для обновлённой истории в шапке рейтинга
# 2024.03.04, nvv, удалена отметка "Upd" для обновлённой истории в шапке рейтинга
# 2024.03.09, nvv, изменился рисунок работы СИ - изменено оформление NB. в шапке
# 2024.02.07, nvv, добавлена отметка "Upd" для: "Исходные тексты скриптов"
# 2024.08.19, nvv, """ -> "&#xB7;"
}

    Имя файла скрипта: "fHtml.cmd" V-текст скрипта-V
- - - - - - - - -
@if not defined nJob @echo off
echo %date% %time:~0,8% %~nx0 Begs
:: fHtml.cmd - оформление в HTML списка топовых текстов последних 30 дней
:: + 20??.??.??.dText (like 2018.12.30.dText) - оформляемый последний список
:: + 20??.??.??.dText (like 2018.11.29.dText) - опорный ПРЕД последний список

:: проверить-найти:
:: - свежий *.dText, например: 2021.04.27.dText
:: - старый *.dText, например: 2021.04.24.dText

:: - свежий *.dText, например: 2021.04.27.dText.html
:: - старый *.dText, например: 2021.04.24.z.dText.html


:: 2018.11.26, nvv, creation
:: ...
:: 2019.03.06, nvv, оформляемый месяц можно задать ЯВНО (вместо дефолтного)
:: 2019.07.31, nvv, мелкая косметика...
:: 2019.11.29, nvv, переменная nJob блокирует пилотную команду @echo off
:: 2019.12.06, nvv, current unification
:: 2020.03.21, nvv, some updates
:: 2021.05.29, nvv, очередная оптимизация с унификацией...
:: 2021.06.13, nvv, confirmation to move PREV data off
:: 2023.06.24, nvv, hidden authors debugging see: rem goto mkHtm
set nJob=fHtml
if NOT defined jDat set jDat=%date%
set ok2upDt=%1
set aHtm=%~dp0%nJob%.awk
::  wDir - общее рабочее место
set wDir=%~d0\Jobs
::  sDir - общее складское хранилище
set sDir=%~d0\Stor
::  dDir - склад для уже ненужных списков 20??.??.??.dText
set dDir=%sDir%\Text\zOld.dTexts
if NOT exist %dDir% set errInf=NO %dDir% found & goto nExit
::  hDir - склад под выходные файлы с таблицами *.html
set hDir=%sDir%\Html
set pDir=%hDir%\dTexts
if NOT exist %hDir%\ mkDir %hDir%
if errorLevel 1 set errInf=fail mkDir %hDir% & goto nExit

::  fOld - прошлый опорный список для "siTopTexts"
set fOld=
::  fCur - свежий список для "siTopTexts" - 1k популярных текстов (со всеми атрибутами)
set fCur=
for %%A in (%wDir%\20??.??.??.dText) do call :findCurOld %%A
if NOT defined fOld set errInf=!? NO old 20*.dText found & goto nExit
if defined errInf goto nExit

set fHtm=%hDir%\%dCur%.dText.html
echo prev:%fOld%
echo curr:%fCur%
echo fHtm:%fHtm%
if NOT exist %fHtm% goto mkHtm

:: итоговый файл есть. если нужно прибрать - идём прибирать, иначе выясняем...
if defined ok2upDt goto upDt

:: запрос (конечный HTML уже есть!)
set tmp0=
rem goto mkHtm
echo fHtm found; reBuild it? [yes] == y
set /p tmp0=?[no]?
if /i NOT %tmp0%. == y. (
  echo job canceled {NO to reBuild}
  exit
)
:mkHtm собственно оформлялка ("от и до";)
gawk.exe -f %aHtm% %fCur%
if errorLevel 1 set errInf=!!! X someThing's wrong with %~n0.awk & goto nExit
:: блокируется оптичивание преобразованного в HTML
goto nExit

:upDt  запрос (точно ненада?)
set tmp0=
echo confirm PREV data OFF? [yes] == y
set /p tmp0=?[no]?
if /i NOT %tmp0%. == y. (
  echo job canceled {NO to reBuild}
  exit
)
:: уберём уже ненужный старый список рейтинга на склад Text\zOld.dTexts
if exist %fOld% (
echo move %fOld% to %dDir%
move /Y %fOld% %dDir%
if errorLevel 1 set errInf=!! fail to move old *.dText to %dDir% & goto nExit
)
:: уберём опубликованное (в HTML)
set tmp0=%hDir%\%dCur%.dText.html
if exist %tmp0% (
echo move %tmp0% to %pDir%
move /Y %tmp0% %pDir%
if errorLevel 1 set errInf=!! fail to move %tmp0% to %pDir% & goto nExit
)
:: убьём опубликованное "предыдущее" (в HTML)
set tmp0=%hDir%\%dOld%.dText.z.html
if exist %tmp0% (
echo erase %tmp0%
erase %tmp0%
if errorLevel 1 set errInf=!! fail to erase %tmp0% & goto nExit
)

:nExit
if defined errInf (
  echo ! %errInf%
  set errInf=
)
echo %date% %time:~0,8% Job:%nJob% Ends
goto :eof

:findCurOld ::  dOld dCur - даты в именах файлов опорного и текущего списков
if defined fOld if defined fCur set errInf=too many *.dText files in %wDir% & goto :eof
set fOld=%fCur%
set dOld=%dCur%
set fCur=%1
set dCur=%~n1
goto :eof

    Имя файла скрипта: "gAuth.cmd" V-текст скрипта-V
- - - - - - - - -
@if not defined pMod @echo off
set nJob=gAuth
echo %date% %time:~0,8% %nJob% Begs
:: gAuth.cmd - построение диф-списка (изменение хитов "12мес") за цикл обновления статистик
:: в _siTop.# ищутся два последних aHits, выявляются даты их расчётов (и интервал в днях;)
:: вычисляется среднесуточная посещаемость разделов (за последний интервал, по умочанию - 3 дня)
:: последовательность сборки рейтинга siTopAuthors "Авторы":

:: 2024.08.13, nvv, вместо вопроса или работа, или выход по "уже есть"
:: ! прочая история в подвале

:: порядок запросов при сборке списка годного:
:: 1 ищется годная пара aHits для расчёта
:: 2 по этой паре строим список авторов с успехом не меньше 10-и и скачиваем их статистики
:: 3 по этим статистикам выявляются самые популярные тексты с успехом не менее 20-и
:: 4 у таких авторов проверяютмя их титулы и сами тексты-кандидаты в рейтинг
:: 5 годные собираются в свежий список gAuth

:: основные сеты и прочая подготовка к работе...
set jDat=%date%
set nJob=gAuth
::  siUrl - URL Самиздата (будКлуб - глупость -- НЕ факт-с;)
if NOT defined siUrl if exist \siUrl.budclub set siUrl=budclub.ru
if NOT defined siUrl set siUrl=samlib.ru
::  dLjb - общий счётчик /формально/ успешно скачанного (НЕ 0b)
set dLjb=0
::  ratW - темп скачивания (секунд на один файл в среднем)
rem set ratW=0
::  minL - минимальная удача раздела (число посетителей в сутки)*10 - граница отбора для последующей обработки
set minL=100
set errInf=
::  awkH - скрипт сравнения двух последних списков fHits
set awkH=%~p0%nJob%H.awk
::  awkI - скрипт разбора титула раздела (объём, обновлялось и проч.)
set awkI=%~p0%nJob%I.awk
::  awkS - скрипт поиска текста-лидера в статистике раздела
set awkS=%~p0%nJob%S.awk
::  awk_ - скрипт поиска текста-лидера в статистике раздела
set awk_=%~p0%nJob%_.awk
::  awkT - скрипт разбора и обустройства текста СИ
set awkT=%~p0dText.awk
:: - проверить комплектность AWK
for %%A in ( %awkH% %awkI% %awkS% %awkT% %awk_% ) do if NOT exist %%A (
  set errInf=NO %%A & goto errExit
)
::  wGetSiz - размер скачанного файла (default 1b минимум)
set wGetSiz=1
::  wDir - общее рабочее место
set wDir=\Jobs
::  sDir - общее складское хранилище
set sDir=\Stor
::  jDir - место для оперативных файлов
set jDir=%wDir%\#%nJob%
if NOT exist %jDir%\ mkDir %jDir%
if errorLevel 1 (
  set errInf=fail mkDir %jDir% & goto errExit
)
::  jBad - список проблемных файлов процесса
set jBad=%jDir%\]%nJob%.bad
::  jRpt - общий сводный отчёт с итоговыми сводками процессов
set jRpt=%wDir%\_siTop.#
::  xDir - складское хранилище справочников рассчётов и окрестностей...
set xDir=%sDir%\wOld
::  zDir - общий подкаталог для посуточных подкаталогов с итоговыми списками
set zDir=%xDir%\%jDat%
if NOT exist %zDir%\ mkDir %zDir%
if errorLevel 1 (
  set errInf=fail mkDir %zDir% & goto errExit
)
::  datJ - верхняя дата обсчитываемого интервала /с 2024.02.23 это "ВЧЕРА"/ вычислим...
for /F %%A in (
  ' gawk.exe "BEGIN{print(strftime(\"%%Y.%%m.%%d\",systime()-86400));exit}" '
) do set datJ=%%A
::  gTop - итоговый список; если нет - начнём /спросив/ или продолжим работу /если что-то уже есть/
set gTop=
for %%A in (%wDir%\%datJ%.*.gAuth) do set gTop=%%A
:: если свежего gAuth нет, можно сразу начинать, иначе запрос на повторение всего с нуля
if NOT defined gTop goto chkCur
echo == all is done today already
goto :eof

:chkCur  0-й шаг: надо к последнему aHits выбрать опорный для вычисления прироста хитов в интервале
:: - 1-й шаг: ищется сортированый по посещаемости список разделов /есть == есть интервал, нет - смотрим расклад/
set /a step+=1
set itog=%jDir%\%datJ%.??.gAuthH
call :lookFor %itog%
if NOT defined found goto chk1st
for %%A in (%found%) do set gapD=%%~xA
set gapD=%gapD:~1%
goto gAuthH_done
:chk1st
echo ? check dates and so on...
set modG=0
rem for /F "tokens=*" %%A in (' gAwk.exe -f %awkH% ') do echo %%A
rem echo gDif.%gDif% gapD.%gapD% itog.%itog% found.%found%
for /F "tokens=*" %%A in (' gAwk.exe -f %awkH% ') do call :echoH %%A
set itog=%gDif%
set j2do=gAuthH

:mkReq п/п: ЗАПРОС на действие /%j2do%/ + ВЫЗОВ оного + ПРОВЕРКА итога /%itog%/ + ПЕРЕХОД дальше + ОЖИВЛЯЖ
echo. -%step%- HAVE to make: %j2do%
set tmp0=
echo ?ok to goOn [yes] == y
:: !!!
goto reqOk
rem if NOT %step% == 1 if NOT defined errInf goto reqOk
rem if %step% == 5 if NOT defined errInf goto reqOk
set /p tmp0=?[no]?
:: "y/Y" - "да" - идём делать упомянутое, иначе - досвидания
if /i NOT "%tmp0%" == "y" set errInf=job canceled & goto errExit
:reqOk
call :make_%j2do%
if defined errInf echo %errInf% & goto :eof
if NOT exist %itog% set errInf=! fail make %itog% & goto errExit
:: !!!
if NOT defined errF if %step% GTR 4 start D:\MEW11\Mew32.exe %itog%
goto %j2do%_done

:gAuthH_done  gapD - текущий интервал "намедни", ergo можно указать имена всеъ потребных списков
set /a step+=1
rem set gapD=%found:~11%
set gDif=%jDir%\%datJ%.%gapD%.gAuthH
set gSta=%jDir%\%datJ%.%gapD%.gAuthS
set gInd=%jDir%\%datJ%.%gapD%.gAuthI
set gTxt=%jDir%\%datJ%.%gapD%.gAuthT
set gTop=%wDir%\%datJ%.%gapD%.gAuth
set gNum=
for /F "tokens=1,*" %%A in (
  ' gawk.exe "END{match($0,/^;5G .+ ([0-9]+):gNum /,a);print(a[1])}" %gDif% '
) do set gNum=%%A
if NOT defined gNum set errInf=! NO gNum in %gDif% & goto errExit
:: - 2-й шаг: сборка статистик разделов 100+ составление списка текстов 200+
set itog=%gSta%
call :lookFor %itog%
if defined found goto gAuthS_done
set j2do=gAuthS
goto mkReq

:gAuthS_done - 3-й шаг: сборка титулов подходячих разделов составление списка недастающих атрибутов разделов
set /a step+=1
set nTxL=
for /F "tokens=1,*" %%A in (
  ' gawk.exe "END{match($0,/^;5H .+ ([0-9]+):nTxL /,a);print(a[1])}" %gSta% '
) do set nTxL=%%A
if NOT defined nTxL set errInf=! NO nTxL in %gSta% & goto errExit
set itog=%gInd%
call :lookFor %itog%
if defined found goto gAuthI_done
set j2do=gAuthI
goto mkReq

:gAuthI_done - 4-й шаг: сборка текстов 200+ составление списка раздел-текст
set /a step+=1
set nTit=
for /F "tokens=1,*" %%A in (
  ' gawk.exe "END{match($0,/^;5I .+ ([0-9]+):nTit /,a);print(a[1])}" %gInd% '
) do set nTit=%%A
if NOT defined nTit set errInf=! NO nTit in %gSta% & goto errExit
set itog=%gTxt%
call :lookFor %gTxt%
if defined found goto gAuthT_done
set j2do=gAuthT
goto mkReq

:gAuthT_done все рабочие списки есть, смотрим/собираем итоговый...
set /a step+=1
set itog=%gTop%
call :lookFor %gTop%
:: ЕСЛИ всё УЖЕ сделано - досвидание
if defined found set errInf=== OK, all is done, ITOG: %gTop% & goto errExit
set j2do=gAuth
goto mkReq

:gAuth_done
goto :eof

:: потребные для работы п/п

:lookFor %1 == %itog% - смотрим - есть ли такой файл \с маской\
set found=
for %%J in ( %itog% ) do if exist %%J (set found=%%~nJ&set tmp0=%%J)
if defined found (
  echo = ok: %tmp0%
) else (
  echo x NO: %itog%
)
goto :eof

:make_gAuthH сборка списка *.gAuthH /самые посещаемые разделы по разнице хитов 100+ в aHits/
echo ? make *gAuthH list...
:: чистим рабочий каталог от уже устаревших файлов
if exist %jDir%\*.* erase /Q/F %jDir%\*.*
if errorLevel 1 echo ! fail erase %jDir%\*.* & goto :eof
set modG=1
gAwk.exe -f %awkH% 
goto :eof

:make_gAuthS сборка списка *.gAuthS /докомплектация и обработка статистик 100-200+/
echo checkGet %gNum% stats
:: взведём таймер со компанией
call :setTimer %gNum%
:: сборка комплекта нужных статистик
for /F %%J in (
  ' gawk.exe "{if(match($0,/^ *([0-9]+):.+:([^ !:]+):/,a)&&(100-a[1]<=0)){print(a[2])}else{exit}}" %gDif% '
) do (
  call :chkGet %%J /stat.shtml stat %jDir%
  if defined errInf goto :eof
)
rem остановим "таймер" качалки время работы в секундах
for /F %%J in ('gawk.exe "BEGIN{print(strftime(\"%%M:%%S\",systime()-%ratW%,-1));exit}"') do set ratW=%%J
echo.
echo. == %gNum% %ratW% ? make *gAuthS list...
:: построение списка *gAuthS
gAwk.exe -f %awkS% %jDir%\*.stat.htm
goto :eof

:make_gAuthI сборка списка *.gAuthI /комплектация и обработка Титулов разделов 200+/
echo checkGet %nTxL% Titles
:: взведём таймер со компанией
call :setTimer %nTxL%
:: сборка комплекта нужных титулов
for /F "tokens=*" %%J in (
  ' gawk.exe "{if(match($0,/:!:([^ !:]+):!:./,a))print(a[1])}" %gSta% '
) do (
  call :chkGet %%J / titl %jDir%
  if defined errInf goto :eof
)
rem остановим "таймер" качалки время работы в секундах
for /F %%J in ('gawk.exe "BEGIN{print(strftime(\"%%M:%%S\",systime()-%ratW%,-1));exit}"') do set ratW=%%J
echo.
echo. == %nTxL% %ratW% ? make *gAuthI list...
:: построение списка *gAuthI
gAwk.exe -f %awkI% %jDir%\*.titl.htm
goto :eof

:make_gAuthT сборка списка *.gAuthT //докомплектация текстов 200+/
echo checkGet %nTit% Texts
:: вычленим актуальный путь в складу текстов "к расчёту" (like: U:\Stor\Text\2020.11.18.text\)
rem ;2D =Ср=  998:tNum OkV:99.8% mod:v 2022.04.09:dEnd 0:sNul 2022.04.13:done 11:14 00:16:09~wrks 0~ratW 0:dnLd 
set tDir=%sDir%\Text\%jDat%.text
if NOT exist %tDir% mkDir %tDir%
if errorLevel 1 (
  set errInf=fail mkDir %tDir% & goto errExit
)
::  tmpF времянка для текстов
set tmpF=%jDir%\tmp.text.html
::  tmpL пустая времянка для списка
set tmpL=%jDir%\tmp.text.lst
echo. >nul 2> %tmpL%
:: взведём таймер со компанией
call :setTimer %nTit%
:: сборка комплекта нужных титулов
for /F "tokens=1,2*" %%J in (
  ' gawk.exe "{if(match($0,/:!:([^ !:]+):!:([^ !:]+) ./,a))print(a[1],a[2])}" %gInd% '
) do (
  call :chkGet %%J /%%K.shtml text %tDir% %%K
  if defined errInf goto :eof
)
rem остановим "таймер" качалки время работы в секундах
for /F %%J in ('gawk.exe "BEGIN{print(strftime(\"%%M:%%S\",systime()-%ratW%,-1));exit}"') do set ratW=%%J
echo.
echo. == %nTit% %ratW% ? make *gAuthT list...
for /F "tokens=1,2*" %%J in (
  ' gawk.exe "{if(match($1,/^20[\.0-9]{8}/)){n++}else{if($1==\"]\")e++}}END{print(n,0+e)}" %tmpL% '
) do (
  set nTxt=%%J
  set nErr=%%K
)
echo ;   begD       endD     sizT.Ok "namA" "namT" "votT" "jnrT" fNam fTmp >>               %tmpL%
gawk.exe "{if(match($1,/^;[0-9][^ ]/,a))print($0)}" %gInd% >>                               %tmpL%
echo ;5T txtL %datJ%:datJ %gapD%:gapD %nTxt%:nTxt %nErr%:nErr %jDat%:done at~%time:~0,5% >> %tmpL%
move /y %tmpL% %gTxt%
if errorLevel 1 set errInf=! fail move %tmpL% %gTxt% & goto gAuth_err
echo. == %nTxt%:nTxt %nErr%:nTxt
goto :eof

:make_gAuth  сборка списка *.gAuth /итоговый: "всё в одном"/
for /F "tokens=*" %%A in ( ' gawk.exe -f %awk_% ' ) do call :mkRpt %%A
if NOT defined errInf echo == OK all is done, itog: %gTop%
goto :eof

:mkRpt
if %1 == ] set errInf=fail %awk_% & goto :eof
echo ;5Q gapQ %* %jDat%:done
echo ;5Q gapQ %* %jDat%:done >> %gTop%
echo ;5Q gapQ %* %jDat%:done >> %jRpt%
copy /b /y %gTop% %zDir% >nul
if errorLevel 1 set errInf=fail copy %gTop% 2 %xDir%
goto :eof

:setTimer cNum
set cNum=%1
set /a jMax=%cNum%/100
if NOT %cNum:~-2% == 00 set jMax=%jMax%+
set jMax=%jMax%      .
set jMax=%jMax:~0,4%
set cNum=0
for /F %%J in ('gawk.exe "BEGIN{print(systime());exit}"') do set ratW=%%J
::  dnLd - счётчик /формально/ успешно скачанного (НЕ 0b)
set dnLd=0
goto :eof

rem           id_P.1 2          3     4    
rem call :chkGet %%A /stat.shtml stat %jDir%
rem call :chkGet %%A /%%B.shtml text %tDir% %%B
:chkGet id_W wSuf
set /a cNum+=1
set id_P=%1
:: если ненужен - просто "/" без кавычек /скачивание титулов разделов/
set wSuf=%2
set fSuf=%3
set outD=%4
set outT=%5
set id_F=%id_P:~0,1%~%id_P:~2%
if defined outT set id_F=%id_F%.%outT%
:: имя локального файла из authID (d/dront -> d~dront)
set fSuf=%id_F%.%fSuf%.htm
if defined outT set fSuf=%fSuf%l
set wFil=%outD%\%fSuf%
set /a count+=1
:: возможно уже есть?
set mark=.
set mrk1=:
if exist %wFil% goto show
:: нет, нужно скачивать...
set mark=~
set mrk1=!
set wUrl=%siUrl%/%id_P%%wSuf%
set gFil=%wFil%
if NOT defined outT goto chk_Get
set gFil=%tmpF%
if exist %tmpF% erase %tmpF%
if errorLevel 1 set errInf=fail erase %tmpF% & goto :eof
:chk_Get
call wGetUrl2fil.cmd %wUrl% %gFil%
if %wGetErr% == 0 goto show
:: проблема?
if %wGetErr% == 1 (
  if exist %gFil% erase %gFil%
  echo ] nulFil %wUrl% >> %jBad%
  set /a nulP+=1
  set errInf=
  goto :eof
)
:: если титул раздела недоступен...
set errInf=no web{SI} {%wUrl%}
goto :eof

:show оживляж + конкретная доп обработка текстов /чистка+дата_изменения/
if %cNum:~-1% == 0 set mark=%mrk1%
gawk.exe "BEGIN{printf(\"%mark%\");exit}"
set tmp0=    %cNum%
set tmp0=%tmp0:~-5,3%.%jMax%
if "%cNum:~-2%" == "00" (
  gawk.exe "BEGIN{printf(\" %%s\",\"%tmp0%\"strftime(\"%%M:%%S\",systime()-%ratW%,-1));exit}"
  echo.
)
:: если это НЕ текст - всё
if NOT defined outT goto :eof

:: если текста у нас /и должного вида/ НЕТ нужно его причесать, иначе - лишь взять его атрибуты
if exist %wFil% goto readTxt
set fOut=%wFil%
gawk.exe -f %awkT% %gFil% > nul
if NOT exist %wFil% (
  echo bad %wUrl% >> %jDir%\%datJ%.%gapD%.gAuthT.err
  goto :eof
)
:: для свежескачанного надоть дату конечного результата вструмить...
for /F "tokens=1,2,*" %%J in (' gawk.exe -f %awkT% %wFil% ') do set touc=%%K
touch.exe -t %touc:~0,4%%touc:~5,2%%touc:~8,2%0100 %wFil%
if NOT %errorLevel% == 0 set errInf=fail touch %touc% with %wFil% & goto :eof

::    0          1           2     3
:: 2014.07.10 2017.11.30  1821.1 "Скс." "Режим•бога" 0 "<a•href=/type/index_type_1-1.shtml>Роман</a>:"  s~sks.111.text
:readTxt
set fOut=
gawk.exe -f %awkT% %wFil% >> %tmpL%
goto :eof

:: 2024.03.04..07-dates 3:gapD 441:gNum \Stor\wOld\2024.03.04\2024.03.03.aHits \Stor\wOld\2024.03.07\2024.03.07.aHits
:echoH разбор выдачи %awkH%
set gapD=%1
set gNum=%2
set nErr=%3
set gDif=%4
set found=%~n4
if NOT "%1" == "]" if NOT "%1" == "gAuthH" goto :eof
echo %*
:: ! проблема - досвидания!
if "%1" == "]" (
  set errInf=%* & goto errExit
)
goto :eof

:errExit реакция на проблему: в пакете - выход
if defined pMod goto :eof
:: автономно - на экран + прекращение работы
echo %errInf%
exit

:: 2020.11.04, nvv, creation
:: 2020.11.13, nvv, будКлуб - глупость
:: 2020.11.28, nvv, процесс делает вроде-бы всё нужное, хить и с заглушками ;(!!! без сети)...
:: 2021.01.15, nvv, всё работает +несколько лидеров в разделе учитываются без фиксации
::     +текст с "ограниченным доступом" в разделе => раздел исключён из списка
:: 2021.02.02, nvv, minor turning
:: 2021.02.12, nvv, minor turning (gNum)
:: 2021.03.15, nvv, minor turning (gNum)
:: 2021.03.26, nvv, minor turning (tmpF)
:: 2021.04.09, nvv, *.bStat turned to *.lst.bStat
:: 2021.05.11, nvv, очередная оптимизация с унификацией...
:: 2021.06.02, nvv, minor turnings {job's timing added - ratW & wrks)
:: 2021.10.11, nvv, minor turnings {в пакетном режкме на экране выбранные aHits}
:: 2021.11.20, nvv, ещё одно улучшение оживляжа-с ;)
:: 2021.12.10, nvv, ещё одно улучшение оживляжа-с ;)
:: 2022.01.01, nvv, ещё одно улучшение оживляжа-с ;)
:: 2022.01.19, nvv, исправлена неточность в выдачи ошибки в работе gAuthH.awk
:: 2022.02.26, nvv, исправлена неточность в выдаче объёмов раздела/произведения (1.1Gb и 17 Mb однако...)
:: 2022.03.04, nvv, изменена реакция на проблемы с aHits - теперь просто выход с уведомлением
:: 2022.03.31, nvv, времянка minL из-за силных пертурбаций учёта в марте
:: 2022.04.17, nvv, радикально переделано: унифицировано и оптимизировано
:: 2022.06.24, nvv, исправлена неточность контроля успеха чистки скачанного текста
:: 2022.08.03, nvv, if datJ == ПОСЛЕДНИЙ день месяца, then свежий aHits - со СКАЧКОМ /непригоден для/
:: 2022.08.19, nvv, отключены промежуточные: запросы на продолжение работы и выдача результатов в MEW
:: 2023.01.21, nvv, сменил разрешение экрана /меньше пикселей/, пришлось слегка менять оживляж
:: 2024.03.08, nvv, новый рисунок работы СИ: ежедневное полное обновление статистик в т.ч. aHits
:: 2024.03.21, nvv, исправлена процедура пестарта после падения ОС
::   соответственно привязка теперь только к aHits безотносительно ситуации с bStat.

    Имя файла скрипта: "gAuth_.awk" V-текст скрипта-V
- - - - - - - - -
BEGIN{                                      #  gAuth.awk сборка итогового списка для siTopAuthors
#  2022.04.13, nvv, creation
#  2023.07.28, nvv, rearrange inpChk & outPut
#  2024.09.08, nvv, место под sizK увеличено до 99Gb (8+1 знако-место)
#   + 6+1 под sizN
# test=1
  bRd=":!:"                                       #  разделитель блоков в строке
  tIni=systime()
  for(str2 in ENVIRON){                       # ! регистр букв в имени переменной может быть любой
    str1=tolower(str2)                            # Temp и temp - РАЗНЫЕ имена для gAwk...
    if(str1=="gsta") gSta=ENVIRON[str2]           #  исходный список
    if(str1=="gind") gInd=ENVIRON[str2]           #  исходный список
    if(str1=="gtxt") gTxt=ENVIRON[str2]           #  исходный список
    if(str1=="gtop") fOut=ENVIRON[str2]           #  исходный список
  }
  if(gSta==""){
    if(test){
      jj="2023.07.25.3"
      gSta="\\Jobs\\#gAuth\\"jj".gAuthS"
      gInd="\\Jobs\\#gAuth\\"jj".gAuthI"
      gTxt="\\Jobs\\#gAuth\\"jj".gAuthT"
      fOut=jj".gAuth"
    }else{
      errS="] no envVar 'gSta'"
      exit
    }
  }

#  формат списка gSta, нужное: id_P txtL txtG id_T hitP numP new
#    277  0   277 0  58367     29    1159     3 :!:k/kadawr:!:n "Псион":!:"Кадавр" "no•comments"
# ;txtL txtG.2 Luck new.4 hitP numP.6 sizK sizN.8 ! id_P ! id_T.10 "namT" ! "namP".12 "moto"
#  <- - - - - - - block.1 - - - - - - - - - - ->   block.2 <- block.3 ->    <- block.4 ->
  if(test)printf("load gAuthS ... ")
  while((getline line<gSta)>0){
    jj=split(line,aj,bRd)
    if(jj==4){                                    #  строка раздела
      id_P=aj[2]                                  #  его ID
      aStH[id_P]=aj[1]                            #  txtL txtG Luck new hitP numP sizK sizN
      aStT[id_P]=aj[3]                            #  id_T "namT"
      aStP[id_P]=aj[4]                            #  "namP" "moto"
      nSta++                                      #  счётчик разделов-кандидатов в рейтинг
    }
  }
  close(gSta)
  if(test)print("nSta:"nSta)

#  формат списка gInd, нужное: id_P datP sizK sizN "namP" "moto"
# 2021.09.22   1159     3:!:k/kadawr:!:n "Псион":!:"Кадавр" "no•comments"
# ; datP       sizK  sizN ! id_P ! id_T "namT" ! "namP" "moto"
  if(test)printf("load gAuthI ... ")
  while((getline line<gInd)>0){
    jj=split(line,aj,bRd)
    if(jj==4){                                    #  строка раздела
      id_P=aj[2]                                  #  его ID
      aInH[id_P]=aj[1]                            #  datP sizK sizN
      aInT[id_P]=aj[3]                            #  id_T "namT"
      aInP[id_P]=aj[4]                            #  "namP" "moto"
      nInd++                                      #  счётчик разделов-кандидатов в рейтинг
#     }else{                                        #  строка подвала
#       if(match(aj[1],/^;[0-9]/))aEnd[++nEnd]=line                           #  прикопаем...
    }
  }
  close(gInd)
  if(test)print("nInd:"nInd)

#  формат списка gTxt, нужное: id_P id_T sizT endD "namT" "jnrT"
#  2014.07.10 2017.11.30  1821.1 "Скс." "Режим•бога" 0 "<a•href=/type/index_type_1-1.shtml>Роман</a>:"  s~sks.111.text
# ;   begD.1     endD.2   sizT.Ok "namA".4 "namT" "votT".6 "jnrT" fNam.8 fTmp
  if(test)printf("load gAuthT ... ")
  while((getline line<gTxt)>0){
    split(line,aj)
    if(match(aj[1],/^[0-9\.]{10}$/)){             #  строка текста раздела
      split(aj[8],ak,".")
      id_P=substr(ak[1],1,1)"/"substr(ak[1],3)    #  его ID
      if(match(aj[3],/^[0-9]+.1$/)){              #  нам недоступные тексты неинтересны
        aTxt[id_P]=line                   #  begD endD sizT.Ok "namA" "namT" "votT" "jnrT" fNam fTmp
        aTxI[id_P]=ak[2]                            #  id_T
        aTxF[id_P]=aj[8]                            #  id_F
        nTxt++                                      #  счётчик разделов-кандидатов в рейтинг
      }
    }else{                                        #  блок в подвале
# ;1aPre hits 5:xNam 451:xNum 104684:xPas 2023.07.20:hDat 522207:hMax 1052:hPag 12:add2 388:h30k 1058:dnLd 0.08~ratW 2023.07.22:done 01:19:32~wrks 15:03 
# ;1aCur hits 5:xNam 451:xNum 104693:xPas 2023.07.23:hDat 525898:hMax 1052:hPag 1250:add2 390:h30k 1076:dnLd 0.18~ratW 2023.07.25:done 04:22:17~wrks 15:03 
# ;5G gapP 2023.07.22:datJ 3:gapD 1646:gNum 0:nErr 100:minL 1248:newH 2023.07.25:done at~15:43
# ;5H txL1 2023.07.22:datJ 3:gapD 122:nTxL 0:nErr 200:minT 0:txtD 2023.07.25:done at~15:55
# ;5I titl 2023.07.22:datJ 3:gapD 122:nTit 0:nErr 2023.07.25:done at~15:57
# ;5T txtL 2023.07.22:datJ 3:gapD 122:nTxt 0:nErr 2023.07.25:done at~15:57 
      if(match(aj[1],/^;[0-9][^ ]/))aEnd[++nEnd]=line   #  прикопаем...
#  соберём данные для отчёта
      if      (match(line,/^;1aPre .+ ([0-9\.]+):hDat /,aj)){
        dat1=aj[1]
      }else if(match(line,/^;1aCur .+ ([0-9\.]+):hDat /,aj)){
        dat2=aj[1]
      }else if(match(line,/^;5G .+ ([0-9]+):gNum ([0-9]+):nErr .+ ([0-9]+):newH /,aj)){
        gNum=aj[1]
        nErr=aj[2]
        newH=aj[3]
      }else if(match(line,/^;5H .+ ([0-9]+):nTxL ([0-9]+):nErr /,aj)){
        nTxL=aj[1]
        nErr=nErr+aj[2]
      }else if(match(line,/^;5I .+ ([0-9]+):nTit ([0-9]+):nErr /,aj)){
        nTit=aj[1]
        nErr=nErr+aj[2]
      }else if(match(line,/^;5T .+ ([0-9]+):nTxt ([0-9]+):nErr /,aj)){
        nTxt=aj[1]
        nErr=nErr+aj[2]
      }
    }
  }
  close(gTxt)
  if(test)print("nTxt:"nTxt)
  if(nSta*nInd*nTxt==0){
    print("] empty or bad any of above!")
    exit
  }

# gHit: id_P hitP numP new
# gSta: id_P txtL txtG id_T hitP numP new
# gInd: id_P datP sizK sizN "namP" "moto"
# gTxt: id_P id_T sizT endD "namT" "jnrT"

# gSta: aStH[id_P] # txtL txtG Luck new hitP numP sizK sizN
# gInd: aInH[id_P] # datP sizK sizN
# gInd: aInP[id_P] # "namP" "moto"
# gTxt: aTxt[id_P] # begD endD sizT.Ok "namA" "namT" "votT" "jnrT" fNam fTmp

  for(id_P in aTxt){
    split(aStH[id_P],aS1)                         #  txtL txtG.2 Luck new.4 hitP numP.6 sizK sizN
    split(aInH[id_P],aI1)                         #  datP sizK.2 sizN
    split(aInP[id_P],aI2)                         #  "namP" "moto".2
    split(aTxt[id_P],aT1)         #  begD endD.2 sizT.Ok "namA".4 "namT" "votT".6 "jnrT" fNam fTmp
    aOut[++nOut]=sprintf("%5s %2s",aS1[1],aS1[2]) bRd    #  sort key
    aOut[nOut]=aOut[nOut] sprintf("%6s ",aS1[3])      # Luck
    aOut[nOut]=aOut[nOut] sprintf("%1s ",aS1[4])      # new
    aOut[nOut]=aOut[nOut] sprintf("%7s ",aS1[5])      # hitP
    aOut[nOut]=aOut[nOut] sprintf("%6s ",aS1[6])      # numP
    aOut[nOut]=aOut[nOut] sprintf("%8s ",aI1[2])      # sizK
    aOut[nOut]=aOut[nOut] sprintf("%6s ",aI1[3])      # sizN
    aOut[nOut]=aOut[nOut] sprintf("%5s ",aS1[1])      # txtL
    aOut[nOut]=aOut[nOut] sprintf("%2s ",aS1[2])      # txtG
    aOut[nOut]=aOut[nOut] sprintf("%7s ",aT1[3])      # sizT
    aOut[nOut]=aOut[nOut] sprintf( "%s ",aI1[1])      # datP
    aOut[nOut]=aOut[nOut] sprintf( "%s ",aT1[2])      # endD
    aOut[nOut]=aOut[nOut] sprintf( "%s ",id_P  )      # id_P
    aOut[nOut]=aOut[nOut] sprintf( "%s ",aI2[1])      # "namP"
    aOut[nOut]=aOut[nOut] sprintf( "%s ",aI2[2])      # "moto"
    aOut[nOut]=aOut[nOut] sprintf( "%s ",aTxI[id_P])  #  id_T
    aOut[nOut]=aOut[nOut] sprintf( "%s ",aT1[5])      # "namT"
    aOut[nOut]=aOut[nOut] sprintf( "%s ",aT1[7])      # "jnrT"
    aOut[nOut]=aOut[nOut] sprintf( "%s ",aTxF[id_P])  #  id_F
  }
#  старый фомат конечного списка gAuth
#   470  0 13756  139 3848    9  475  1 1821.1 2019.06.23 2017.11.30 s/sks "Скс" "Режим•бога" 111 "Режим•бога" "<a•href=/type/index_type_1-1.shtml>Роман</a>:" s~sks
# :Luck new hitP numP sizK sizN hitT txtN sizT   datP       endD id_P "namP" "moto" id_T "namT" "jnrT" fNam
#  %%7s %%2s %%8s %%7s %%8s %%6s %%6s %%3s %%8s
# :formItA %luck% %typH% %hitP% %numP% %sizK% %sizN% %hitT% %txtN% %sizT%
# gawk.exe "BEGIN{printf(\"%%7s%%2s%%8s%%7s%%8s%%6s%%6s%%3s%%8s\",%1,%2,%3,%4,%5,%6,%7,%8,%9);exit}" >> %jLst%
# echo. %datP% %endD% %id_P% %namP% %moto% %id_T% %namT% %jnrT% %fNam% >> %jLst%
  asort(aOut)
  for(jj=nOut;jj>0;jj--){
    split(aOut[jj],aj,bRd)
    print(aj[2]) >fOut
  }
  print(\
";Luck.1 new hitP.3 numP sizK.5 sizN txtL.7 txtG sizT.Ok.9  datP    endD.11   id_P \"namP\".13 \"moto\" id_T.15 \"namT\" \"jnrT\".17 fNam"\
)                >fOut
  for(jj=1;jj<=nEnd;jj++)print(aEnd[jj]) >fOut    #  <- старый подвал + свежак -v
  exit
}
# ;Luck new.2  hitP numP.4   sizK sizN.6 hitT txtN.8 sizT  datP.10   endD id_P.12 "namP" "moto".14 id_T "namT".16 "jnrT" fNam.18
#     290 0   12266    141    3848     9   293  1  1821.1 2019.06.23 2017.11.30 s/sks "Скс" "Режим•бога" 111 "Режим•бога" "<a•href=/type/index_type_1-1.shtml>Роман</a>:" s~sks
END{
  if(errS!=""){
    print(errS)
    exit -1
  }
#  выжимка для отчёта
# 5A 2023.07.23:dat1 2023.07.27:dat2 600:gNum 229:newH 118:nTxL 117:nTit 117:nTxt 1:nErr
  print(dat1":dat1",dat2":dat2",gNum":gNum",newH":newH",nTxL":nTxL",nTit":nTit",nTxt":nTxt",nErr":nErr")
}

    Имя файла скрипта: "gAuthH.awk" V-текст скрипта-V
- - - - - - - - -
BEGIN{ #                gAuthH.awk - прирост хитов двух последних списков aHits,
# Out - сортированный список дифов, если нужные переменные среды не установлены,
# работает автономно, результат - в текущем каталоге; выюор aHits: по _siTop.#
# интервал дат (т.е. число дней в нём) == разница в датах создания выбранных aHits
# modG ==0(или без параметров) == выбор/анализ ситуации с aHits с оживляжем на экране
#      ==1 == выбор/анализ ситуации с aHits, итоги на StdOut
#      ==2 на StdOut список разделов с удачей 10 для дальнейшей работы с оным

# 2024.09.08, nvv, место под sizK увеличено до 99Gb (8+1 знако-место)
#   + 6+1 под sizN
# ! прочая история в подвале

  extH="gAuthH"                       #  тип работы (расширение полного списка дифов)
  bRd=":!:"                               #  разделитель блоков в строке
  newH=0                                  #  раздела нет в предыдущем aHits
  modG=0            #  поиск/оценка; 0==оживляж на экране, 1==выдача данных на StdOut
  nErr=0

  jDat=getEnv("jDat")                     #  jDat - "сегодня"
  jRpt=getEnv("jRpt")                     #  сводный отчёт по рассчётам siTopTexts
  xDir=getEnv("xDir")"\\"                 #  склад сводок и выборок к рассчётам      
  jDir=getEnv("jDir")"\\"             #  рабочая папка с файлами выборок для_расчёта
  modG=getEnv("modG")             #  0 == поиск/оценка ситуации, 1-список разделов-^
  minL=getEnv("minL")       #  минимальные хиты в сутки для проверки текстов раздела

  if(jRpt==""){
    jRpt="\\Jobs\\_siTop.#"               #  общий лог расчётов
    xDir="\\Stor\\wOld\\"                 #  общий склад списков
    jDir=".\\"                            #  рабочая папка под файлы
    jDat=strftime("%Y.%m.%d")
    minL=100                              #  граница интереса (10 хитов в сутки)
    modG=0 # поиск/оценка; 0==оживляж на экране, 1==выдача данных на StdOut 2==список
# 2024.03.02..04-dates 
#     gapD=2
#     gNum=817
#     preF="\\Stor\\wOld\\2024.03.02\\2024.02.29.aHits
#     curF="\\Stor\\wOld\\2024.03.04\\2024.03.03.aHits
  }
  if(substr(jDat,9,2)<="02"){         #  до 3-го числа месяца считать заведомо нечего
    errS="NO "extH" now, month beginning"
    exit
  }

  numD=0
  while((getline line<jRpt)>0){   #  ищем в _siTop.# нужные нам даты aHits и gAuth
# ;1A hits 2:xNam 445:xNum 101285:xPas 2021.04.22:hDat 1018:hPag 806772:hMax 1018:DnLd 2021.04.27:done 25:mins gapT~14:53-15:18~
    if(match(line,/^;1A .+ (20[\.0-9]{8}):hDat .+ (20[\.0-9]{8}):done /,arr0)){
      curD=arr0[2]                      #  дата в имени КАТАЛОГА с нужным aHits
      aFil[curD]=arr0[1]                #  дата в имени нужного ФАЙЛА aHits
    }
    if(match(line,/^;5Q .+ (20[\.0-9]{8}):dat2 .+ (20[\.0-9]{8}):done /,arr0)){
      aFi2[arr0[2]]=arr0[1]             #  datF - дата в имени нужного aHits
    }
  }
  close(jRpt)
  curF=aFil[curD]                       #  дата в имени самого свежего aHits
  if(jDat!=curD){                         #  а этот-то свежак - сегодняшний?
    errS="NOT toDay's last: " curD".aHit"
    exit
  }
  j0=substr(jDat,1,4)" "substr(jDat,6,2)" "substr(jDat,9,2)" 11 00 00"
  tic0=mktime(j0)                       #  "сегодня" в секундах
  shft=0                                #  свиг в днях от сегодня
  gapD=""                               #  искомый интервал дат
  while(++shft){                        #  ищем оный -^
    j1=tic0-(86400*shft)
    j0=strftime("%Y.%m.%d",j1) #  это очередная проверяемая дата
    if(shft==1)datJ=j0                  #  верхняя граница обсчитываемого интервала
    if(j0 in aFil){                     #  есть aHits за ету дату!
      preD=j0                           #  возможная нижняя дата нашего интервала
      gapD=shft                         #  а это интервал дат
    }
    if(strftime("%d",j1)=="02")break    #  упёрлись в начало месяца, стоп
    if(j0 in aFi2)             break    #  -""- в предыдущий расчёт, стоп
  }
  if(!gapD){
    errS="NOT good gapDown from last: " curD".aHit"
    exit
  }
  preF=xDir preD"\\"aFil[preD]".aHits"          #  полное имя предыдущего aHits
  curF=xDir curD"\\"aFil[curD]".aHits"          #  полное имя текущего aHits

#      1     2       3      4  5        6        7
# 441971     6    1077      3 k/kadawr "Кадавр" "no•comments"
# hitP.1 numP.2 sizK.3 sizN.4 id_P.5 "namP".6 "moto".7
# загрузим опорный (aka предыдущий) список "разделы-хиты"
  if(!modG)print(extH" loading preHits "preF" ... ")  #  оживляж...
  preN=0
  while ((getline line < preF) > 0) {
    split(line,aj)            #  v- для сравнения нужны ВСЕ разделы из старого списка
# if(match(aj[1],/^[0-9]+$/)&&aj[4]&&(aj[6]!="\">?<\"")){ # нужна запись НЕ пустого раздела
    if(match(aj[1],/^[0-9]+$/)){          #  нужна запись НЕ пустого раздела
      preN++
      a2h[aj[5]]=aj[1]                    #  массив hitP[id_P]
    }else if(aj[1]==";1A")iPre=";1aPre "substr(line,5)
  }
  close(preF)                             #  всё/не_всё, - старый список тогось
  if(!preN){                              #  старый список пуст
#     if(modG)print("")
    errS="NO_or_BAD_preHits:" preF ", (jRpt:"jRpt")"
    exit
  }
  if(!modG)print(extH" found preN:"preN)  #  оживляж...
  if(!modG)print(extH" loading curHits "curF" ... ")  #  оживляж...
# сравним оперативный (aka текущий) список с предыдущим (опорным - выцепим изменения в хитах)
  curN=0
  while ((getline line < curF) > 0) {
    split(line,aj)                        #  разделяем строку на элементы
    if(match(aj[1],/^[0-9]+$/)&&aj[4]&&(aj[6]!="\">?<\"")){ # это строка НЕ пустого раздела
      id_P=aj[5]
      if(id_P in a2h){                    #  был в предыдущем, считаем
        luck=aj[1]-a2h[id_P]              #  прирост хитов за gapD дней
        typH="0"                          #  флаг "НЕ новый" раздел в aHits
      }else{
        luck=aj[1]                        #  все накопленные хиты
        typH="1"                          #  флаг "НОВЫЙ" раздел
        newH++
      }
      luck=sprintf("%7.1f",10*luck/gapD)  #  удача*10 раздела "начерно"
      split(luck,ak,".")
      luck=ak[1]                #  нам нужна целая часть (без дробной после запятой)
      if(luck-minL>=0){ # удачи "начерно" достаточно для более внимательной проверки
        hitP=aj[1]
        numP=aj[2]
        sizK=aj[3]
        sizN=aj[4]
        gNum++
        aDif[id_P]=sprintf("%5s"bRd"%s %6s %6s %8s %6s"bRd"%s"\
,luck,typH,hitP,numP,sizK,sizN,aj[6]" "aj[7])
      }
    }else if(aj[1]==";1A")iCur=";1aCur "substr(line,5)
  }
  close(curF)                             #  всё/не_всё, - новый список обработан
  if(!gNum){                              #  старый список пуст?
    errS="NO_or_BAD_curHits:" curF ", (jRpt:"jRpt")"
    exit
  } #  старый список пуст
  if(!modG)print(extH" found difN:"gNum)  #  оживляж...

# 2024.01.25:dat1 2024.01.28:dat2 817:gapD 596:gNum
  fOut=jDir datJ"."gapD"."extH            #  итоговый список "2020.11.14.3.gAuthH"
  if(!modG)print(extH" "preD".."substr(curD,9,2)"-dates",gapD":gapD", gNum":gNum", preF, curF)
  if(!modG)print(gapD,gNum,nErr,fOut)
  if(!modG)exit     #  поиск/оценка; 0==оживляж на экране, 1==выдача данных на StdOut

# ;1aPre hits 5:xNam 461:xNum 105337:xPas 2024.02.25:hDat 502917:hMax 1059:hPag 1386:add2 309:h30k 1059:dnLd 0.26~ratW 2024.02.26:done 00:22:35~wrks  9:04 
# ;1aCur hits 5:xNam 462:xNum 105343:xPas 2024.02.27:hDat 504808:hMax 1059:hPag 709:add2 310:h30k 1059:dnLd 0.14~ratW 2024.02.28:done 00:20:24~wrks  9:07 

#  формат конечного списка
#    2456:!:0     53231  38     312         8:!:f/fox:!:"Fox" "Раздел..."
# ;Luck.1 ! new hitP.3 numP sizK.5 sizN ! id_P.7 ! "namP" "moto".9
#  block.1  <- - - - block.2 - - - - ->   block.3  <- block.4 - ->
  for(j1 in aDif){
    j2=split(aDif[j1],aj,bRd)             #  разделим строку на блоки
    aOut[++nOut]=aj[1] bRd aj[2] bRd j1 bRd aj[3] # и соберём для сортировки и выдачи в файл
  }
  info=";5G gapP "datJ":datJ "gapD":gapD "gNum":gNum "nErr":nErr "minL":minL "newH":newH "strftime("%Y.%m.%d:done at~%H:%M")
  asort(aOut)                             #  сотртировка по возрастанию(!) "удачи"
# nnn 15572 #  423515       6   1094     3 k/kadawr "Кадавр" "no•comments"
  for(j1=nOut;j1>0;j1--)print(aOut[j1])                                         >fOut
  print(";Luck.1 ! new hitP.3 numP sizK.5 sizN ! id_P.7 ! \"namP\" \"moto\".9") >fOut
  print(iPre)                                                                   >fOut
  print(iCur)                                                                   >fOut
  print(info)                                                                   >fOut
  if(nErr){
    for(j1=nErr;j1>0;j1--)print(aErr[j1])                                       >fOut".err"
    print(info)                                                                 >fOut".err"
  }
  print(" == gNum:"gNum", gapD:"gapD", nErr:"nErr)
  exit
}

function mkSecs(fNam){
  n1=split(fNam,aj,":")
  n1=split(aj[n1],aj,"\\")
  n1=split(aj[n1],aj,".")
  return(mktime(aj[1]" "aj[2]" "aj[3]" 12 00 00"))
}

function getEnv(env1) {               #  найти в массиве ENVIRON значение переменной с именем env1
  for(env0 in ENVIRON){                     #  ! реГИстр букв в имени переменной МОЖЕТ быть лЮбОй
    if(tolower(env0)==tolower(env1)){             #  имя переменной совпадает с указанным?
      return(ENVIRON[env0])                       #  вернём значение этой переменной
    }
  }
  return("")                                      #  ничего нет? знать не судьба...
}

END{
  if(errS!=""){
    print("")
    print("] "errS)
    exit -1
  }
# 2020.11.01, nvv, creation
# 2020.11.27, nvv, minor improvements +comments adds +;1A-info -> ;1aPre/;1aCur
# 2020.11.29, nvv, изменен формат имены вых.файла fOut curD.datG.
# 2021.02.07, nvv, исправлена неточность в выявлении координат и имён последних *.aHits
# 2021.02.12, nvv, добавлено извещение о числе разделов с "удачей" >=100 (gNum)
# 2021.03.15, nvv, переписаны стартовые операции для корректного вычленения нужных *.aHIts
# 2021.04.27, nvv, дифер занимается именно разницей aHits, прочее - в CMD
# 2021.05.02, nvv, мелкая косметика
# 2021.05.26, nvv, очередное вструмление-с
# 2021.06.09, nvv, мелкое уточнение выявление preS и datJ
# 2021.07.21, nvv, ручное задание дат нижней границы: pre?
# 2021.09.29, nvv, ручное задание дат нижней границы: pre?
# 2021.10.11, nvv, улучшена выдача на экран в пакетном режиме (оживляж-с;)
# 2021.11.20, nvv, ещё одно улучшение оживляжа-с ;)
# 2021.12.07, nvv, ещё одно улучшение оживляжа-с ;)
# 2022.04.18, nvv, 3000+ посетителей в день - криминал! + серьёзно переделано
#  в том числе формат вых.файла (см. переменную bRd)
# 2022.08.29, nvv, для сравнения нужны ВСЕ разделы из СТАРОГО списка, в т.ч. без текстов и ника
# 2024.03.08, nvv, изменился рисунок публикации данных учёта посетителей СИ:
#  - с 2024.02.23 ЕЖЕДНЕВНО!, скрипт серьёзно переделан
}

    Имя файла скрипта: "gAuthI.awk" V-текст скрипта-V
- - - - - - - - -
BEGIN{                                            #  gAuthI.awk разбор шапкок разделов СИ
# 2020.11.28, nvv, объём (например "1899k/3") надлежит разделять (например: "1899" + "3")
# 2021.05.02, nvv, мелкая косметика
# 2022.04.17, nvv, радикально переделано 
# 2023.01.25, nvv, сменилось разрешение экрана, слегка меняем оживляж
# 2024.03.04, nvv, исчезло двоеточие ":" после ника (ФИО) в главномм индексе
# 2024.09.08, nvv, место под sizK увеличено до 99Gb (8+1 знако-место)
#   + 6+1 под sizN
  if(ARGV[1]=="")exit                             # защита от случайного пуска
  bRd=":!:"                                       #  разделитель блоков в строке
  for(str2 in ENVIRON){                       # ! регистр букв в имени переменной может быть любой
    str1=tolower(str2)                            # Temp и temp - РАЗНЫЕ имена для gAwk...
    if(str1=="gsta") gSta=ENVIRON[str2]           #  исходный список
  }
  if(gSta=="")gSta="\\Jobs\\#gAuth\\2024.03.05.2.gAuthS"
  j0=split(gSta,aj,"\\")
  fOut=aj[j0]
  if(j0==1)fPth=""
  else{
    fPth=aj[1]"\\"
    for(j1=2;j1<j0;j1++)fPth=fPth aj[j1]"\\"
  }
  split(fOut,aj,".")
  datJ=aj[1]"."aj[2]"."aj[3]
  gapD=aj[4]
  fOut=fPth datJ"."gapD".gAuthI"
#  формат входного списка
#    277  0   277 0  58367     29    1159     3 :!:k/kadawr:!:n "Псион":!:"Кадавр" "no•comments"
# ;txtL txtG.2 Luck new.4 hitP numP.6 sizK sizN.8 ! id_P ! id_T.10 "namT" ! "namP".12 "moto"
#  <- - - - - - - block.1 - - - - - - - - - - ->   block.2 <- block.3 ->    <- block.4 ->
  while((getline line<gSta)>0){       #  ищем последнюю запись успешного скачивания этого списка
    jj=split(line,aj,bRd)                            #  !!! причесать по новому!
    if(jj==4){                                    #  строка раздела
      id_P=aj[2]                                  #  его ID
      aIdT[id_P]=aj[3]                            #  его самый посещаемый текст
      aIdP[id_P]=aj[4]                            #  его описание /из aHits/
      nIdP++                                      #  счётчик разделов-кандидатов в рейтинг
    }else{                                        #  строка подвала
      if(match(aj[1],/^;[0-9][^ ]/))aEnd[++nEnd]=line                           #  прикопаем...
    }
  }
  close(gSta)
  int7=(nIdP-(nIdP%100))/100
  if(nIdP%100)int7=int7"+"
  buf=""
  errS=""
  nErr=0
  tIni=systime()
  print("scan "nIdP" titles...")
# ;Luck new.2  hitP numP.4   sizK sizN.6 hitT txtN.8 sizT  datP.10   endD id_P.12 "namP" "moto".14 id_T "namT".16 "jnrT" fNam.18 
#     290 0   12266    141    3848     9   293  1  1821.1 2019.06.23 2017.11.30 s/sks "Скс" "Режим•бога" 111 "Режим•бога" "<a•href=/type/index_type_1-1.shtml>Роман</a>:" s~sks 
# gHit: id_P hitP numP new
# gSta: id_P txtL txtG id_T hitP numP new
# gTtl: id_P datP sizK sizN "namP" "moto"
# gTxt: id_P id_T sizT endD "namT" "jnrT"

}

{
  if(FNR==1){
    if(NR!=1)chkSteps()                           #  чем закончилась обработка предыдущего файла?
    step=0        # 0-владелец, 1-дата обновления, 2-id раздела, 3-разбор строк таблиц статистики
    buf=""
    fPth=FILENAME
    fNam=split(fPth,arr0,"\\")                    # NEW/NEXT входной файл as-is (с полным путём)
    fNam=split(arr0[fNam],arr0,".")               # файл: чистое nam.ext (like "0-0.stat.htm")
    fNam=arr0[1]                                  # fNam чистое имя (like "0-0" in "0-0.stat.htm")
    id_P=substr(fNam,1,1)"/"substr(fNam,3)
    if(!(id_P in aIdP)){                          #  это левый раздел (нет во вхолном списке)
      errS="] -  NO in gAuthH: "id_P" " fNam
      nextfile                                    #  что-то не так с датой обновления
    }
    int8++
    if(int8%100==0) print(sprintf(": %3s.%-3s",int8/100,int7),strftime("%H:%M"))
    else if(int8%10)printf(".")
    else            printf(":")                   #  оживляж...
  }
  gsub(/(&nbsp;)+|\xA0+|[\0-\31]+/," ",$0) #  цепочки "&nbsp;" и прочих "пробелов" -> " " (пробел)
  buf=buf" "$0
# gTtl: id_P sizK sizN datP "namP" "moto"
  if(step==0){                                   #  ищем/проверяем ФИО автора
# <h3>Фонд А.:<br> <font color="#cc5555">всяко-разное</font></h3>
    if(match(buf,/<h3>([^:<]+):?<br> <[^>]+>([^<]+)<\/font><\/h3>/,aj)){
      namo=pack(aj[1])" "pack(aj[2])        #  "namP" "moto"
      buf=substr(buf,RSTART+RLENGTH)
      step=1
      next
    }
  }else if(step==1){                                   #  ищем/проверяем ФИО автора
#  <li><b><a href=/long.shtml><font color=#393939>Обновлялось:</font></a></b> 28/03/2022
#  <li><b><a href=/rating/size/><font color=#393939>Объем:</font></a></b> 311k/1
    if(match(buf,/>Обновлялось:<.+([0-9]{2})\/([0-9]{2})\/(20[0-9]{2}).+>Объем:<.+ ([0-9]+)k\/([0-9]+) +</,aj)){
      aIdI[++nIdI]=aj[3]"."aj[2]"."aj[1] sprintf(" %8s %6s",aj[4],aj[5]) bRd id_P bRd aIdT[id_P] bRd namo
      buf=substr(buf,RSTART+RLENGTH)
      step=2
      nextfile
    }  
  }
}

function pack(f1s1) {       #  мешающие chars -> нейтральные + cut too long + закавычить результат
  f1n1=split(f1s1,f1a1)
  f1s1=f1a1[1]                                    #  обихаживание пробелов... " " -> "•"
  for(f1n2=2;f1n2<=f1n1;f1n2++)f1s1=f1s1"•"f1a1[f1n2]
  f1s2=""                                         #  двойные кавычки -> "&quot;"
  while(f1n1=index(f1s1,"\"")){f1s2=f1s2 substr(f1s1,1,f1n1-1)"&quot;"; f1s1=substr(f1s1,f1n1+1)}
  f1s1=f1s2 f1s1
  f1s2=""                                         #  "%" -> "&#x25;"
  while(f1n1=index(f1s1,"%")){f1s2=f1s2 substr(f1s1,1,f1n1-1)"&#x25;"; f1s1=substr(f1s1,f1n1+1)}
  f1s1=f1s2 f1s1
  if(length(f1s1)>999){                           #  обрезка слишком длинных литералов
    f1n1=index(substr(f1s1,1000),"•")
    if(!f1n1)f1n1=1000
    else   f1n1=f1n1+999                          #  v-вместо обрезанного - справка о факте ;)
    f1s1=substr(f1s1,1,f1n1-1)"•(+"(length(f1s1)-f1n1)" chars)"
  }
  return ("\""f1s1"\"")                           #  результат "закавычивается!"
}

function chkSteps() {                     #  проверка чем закончилась обработка очередного файла?
  if((step==2)&&(errS=="")){                      #  всё штатно ("ОК")
    return
  }else{
    if(errS==""){
      if(step==1){
        errS="] no or bad datP/sizK for "id_P" in: " fNam
      }else if(step==0){
        errS="] no or bad namP/moto for "id_P" in: " fNam
      }
    }
    aErr[++nErr]=errS
    errS=""                                       #  и очистим флаг-инфо
  }
}

END{
  if(ARGV[1]==""){
    print("] no_file_in")
    exit 1                                        # защита от случайного пуска
  }
  chkSteps()
  if(int8%100)print("")
  print(" == "int8":titls",strftime("%H:%M:%S",systime()-tIni,-1))  #  проблем нет
# print nIdI"~"aIdI[nIdI]"~"length(aIdI)
  asort(aIdI)
  for(jj=1;jj<=nIdI;jj++)         print(aIdI[jj]) >fOut
#   for(jj=1;jj<=nIdI;jj++)         print(jj" * "aIdI[jj])
  print(";  datP       sizK  sizN ! id_P ! id_T \"namT\" ! \"namP\" \"moto\"") >fOut
  for(jj=1;jj<=nEnd;jj++)print(aEnd[jj])          >fOut #  <- старый подвал + свежак -v
  j0=";5I titl "datJ":datJ "gapD":gapD "nIdI":nTit "nErr":nErr "strftime("%Y.%m.%d:done at~%H:%M")
  print(j0) >fOut
  if(nErr){
    for(jj=1;jj<=nErr;jj++)
    print(aErr[jj]) >fOut".err"
    nErr=nErr":nErr"
  }else nErr=""
  print(" ==",nIdI":nTit",nErr)
}

    Имя файла скрипта: "gAuthS.awk" V-текст скрипта-V
- - - - - - - - -
BEGIN{                  #  gAuthS.awk выченение хитов разделов/тектов за заданный интервал дат
# отбираются тексты с 200+ удачи /по одному самому удачному на раздел/

# 2024.06.25, nvv, понижен порог отбора годных текстов с 20-и до 10-и хитов а день
# ! прочая история в подвале
  if(ARGV[1]=="")exit                           #  защита от случайного пуска
  bRd=":!:"                                     #  разделитель блоков в строке
# массив имён месяцев для преобразования их в числа с лидирующим нулём 01..12
  mNum["Jan"]="01"                              #  .1 January . Jan. 31 . winter wint
  mNum["Feb"]="02"                              #  .2 February .Feb. 28/29
  mNum["Mar"]="03"                              #  .3 March . . Mar. 31 . spring sprn
  mNum["Apr"]="04"                              #  .4 April . . Apr. 30
  mNum["May"]="05"                              #  .5 May . . . May. 31
  mNum["Jun"]="06"                              #  .6 June . . .Jun. 30 . summer summ
  mNum["Jul"]="07"                              #  .7 July . . .Jul. 31
  mNum["Aug"]="08"                              #  .8 August . .Aug. 31
  mNum["Sep"]="09"                              #  .9 September Sep. 30 . autumn autm
  mNum["Oct"]="10"                              #  10 October . Oct. 31
  mNum["Nov"]="11"                              #  11 November .Nov. 30
  mNum["Dec"]="12"                              #  12 December .Dec. 31 . winter wint
  split("",aSel)  #  в ячейках статистики: url,title,hits:all,12mon,mon0..monC-11,day0..day0-61
  for(str2 in ENVIRON){                   #  ! регистр букв в имени переменной может быть любой
    str1=tolower(str2)                          #  Temp и temp - РАЗНЫЕ имена для gAwk...
    if(str1=="gdif") gDif=ENVIRON[str2]         #  исходный список
    if(str1=="minl") minL=ENVIRON[str2]         #  минимальная удача*10 текста "начерно"
  }
  if((gDif=="")||(minL=="")){                   #  вызвали НЕ из CMD
    gDif="U:\\Jobs\\#gAuth220325\\2022.03.22.21.gAuthH"
    gDif="\\Jobs\\#gAuth\\2024.06.23.1.gAuthH"
#     gDif="2022.03.22.21.gAuthH"
    minL=100                                  #  мин. кол-во хитов в день (в среднем) "начерно"
  }
  j0=split(gDif,aj,"\\")
  fOut=aj[j0]
  if(j0==1)fPth=""
  else{
    fPth=aj[1]"\\"
    for(j1=2;j1<j0;j1++)fPth=fPth aj[j1]"\\"
  }
  split(fOut,aj,".")
  datJ=aj[1]"."aj[2]"."aj[3]
  gapD=aj[4]
  fOut=fPth datJ"."gapD".gAuthS"
# print(">"fOut"<")
# exit

#   minT=minL*2                                     #  200 минимальная удача*10 текста "набело"
  minT=minL                                     #  100 минимальная удача*10 текста "набело"
  preS=strftime("%Y.%m.%d",mktime(substr(datJ,1,4)" "substr(datJ,6,2)" "substr(datJ,9,2)" 12 00 00")-86400*(gapD-1))
#  формат входного списка
#    2456:!:0     53231  38     312         8:!:f/fox:!:"Fox" "Раздел..."
# ;Luck.1 ! new hitP.3 numP sizK.5 sizN ! id_P.7 ! "namP" "moto".9
#  block.1  <-  block.2 {aIdP[id_P]} ->   block.3  <-block.4{aIdD[id_P]} - ->
  while((getline line<gDif)>0){     #  ищем последнюю запись успешного скачивания этого списка
    split(line,aj,bRd)                          #  !!! причесать по новому!
    if(match(aj[1],/^ *[0-9]+$/)){              #  строка раздела
      id_P=aj[3]                                #  его ID
      aIdP[id_P]=aj[2]                          #  его данные из aHitc
      aIdD[id_P]=aj[4]                          #  его описаните оттуда же
      nIdP++                                    #  счётчик разделов-кандидатов в рейтинг
    }else{                                      #  строка подвала
      if(match(aj[1],/^;[0-9][^ ]/))aEnd[++nEnd]=line #  прикопаем...
    }
  }
  close(gDif)
  int7=(nIdP-(nIdP%100))/100
  if(nIdP%100)int7=int7"+"
  txtD=0                                        #  число текстов с интервалом МЕНЬШЕ заданного
  errS=""
  nErr=0
  tIni=systime()
  print("scan "nIdP" stats within: "preS"-"datJ)
}

{                                               #  // -=- основной блок скрипта begs
  if(FNR==1){
    if(NR!=1)chkSteps()                         #  чем закончилась обработка предыдущего файла?
    step=0    #  0-владелец, 1-дата обновления, 2-id раздела, 3-разбор строк таблиц статистики
    fPth=FILENAME
    fNam=split(fPth,arr0,"\\")                  #  NEW/NEXT входной файл as-is (с полным путём)
    fNam=split(arr0[fNam],arr0,".")             #  файл: чистое nam.ext (like "0-0.stat.htm")
    fNam=arr0[1]                              #  fNam чистое имя (like "0-0" in "0-0.stat.htm")
    id_P=substr(fNam,1,1)"/"substr(fNam,3)
    if(!(id_P in aIdP)){                        #  это левый раздел (нет во вхолном списке)
      errS=  "] -  NO in gAuthH: "id_P" " fNam
      nextfile                                  #  что-то не так с датой обновления
    }
    maxL=0                                      #  максимальная удача текста в разделе
    nTxt=0                                      #  кол-во отобранных текстов
    dayB=0  #  верхний день нашего интервала в таблицах статистики, значение: в диапазоне 17-77
    dayE=0                                    #  нижний день нашего интервала, НЕ входит в него
    maxT=0                                      #  хиты лидера (литеров)
    inTab=0                                     #  сначала - мы НЕ "в таблице"
    numT=0                                      #  счётчик таблиц в файле статистики
    numR=0                                      #  счётчик строк в текущей таблице
    selN=0
    int8++
    if(int8%100==0) print(sprintf(": %3s.%-3s",int8/100,int7),strftime("%H:%M"))
    else if(int8%10)printf(".")
    else            printf(":")                 #  оживляж...
  }
  gsub(/(&nbsp;)+|\xA0+|[\0-\31]+/," ",$0) # цепочки "&nbsp;" и прочих "пробелов" -> " " (пробел)
  if(step==0) {                                 #  ищем/проверяем ФИО автора
# <h3>Статистика раздела &quot;<a href=./>Влад</a>&quot;:</h3>
    if (match($0,/<h3>Статистика раздела \&quot;<a href=\.\/>(.*)<\/a>\&quot;:<\/h3>/,arr0)) {
      if(arr0[1]==""){
        errS="]  NO nick in: " fNam
        nextfile                                #  что-то не так с датой обновления
      }
#       namP=pack(arr0[1])
      step++                                    #  проверка ОК
    }
  }else if(step==1){                            #  вычленеие даты обновления статистики
    if(match($0,\
/<li><i>Статистика рассчитывается .+\. \(.+ (...) +([0-9]+) (..:..:..) (20[0-9][0-9])\)<\/i>/\
,arr0)){
      if(length(arr0[2])==1) arr0[2]="0"arr0[2] #  причешем первые дни месяца "1" -> "01"
      ticS=mktime(arr0[4]" "mNum[arr0[1]]" "arr0[2]" 12 00 00") # тики на 12 часов даты статистики
      datS=arr0[4]"."mNum[arr0[1]]"."arr0[2]    #  сама дата пополнения статистики
      timS=arr0[3]                              #  время оного-же
      step++                                    #  дату статистики оптичили
    }
  }else if(step==2){                    #  ищем authID (!должен быть) в отсылке на top.mail.ru
# [<a href=http://top.mail.ru/pages?id=77427&period=0&date=2018-10-02&filter_type=0
# &filter=n/nosow_w_w&pp=20&gender=0&agegroup=0>по дням</a>]
    if (match($0,/\[<a href=http.+&filter=([0-9a-z]\/[\-0-9a-z_]+)&pp=.+>по дням<\/a>]/,arr0)) {
      if(id_P!=arr0[1]){                        #  это ПОЛНЫЙ криминал!
        errS="]  "arr0[1]" != fNam: " fNam
        nextfile
      }
      step++                                    #  проверка ОК
    }
  }else if(step==3){            #  таблицы статистики, просмотр строк, сборка данных в ячейках
    if($0=="<!--------- Подножие ------------------------------->"){  #  разбор закончен
      step++
      nextfile
    }
    if(inTab){                  #  Мы ВНУТРИ таблицы, собираем строки таблицы с хитами текстов
      buf0=buf0" "$0                            #  gain inpLines to buf0, then check contents
      while((match(buf0,/<tr ?[^>]*>/))||(int0=index(buf0,"</tr"))){ # seek <tr .. </tr for tabRow
        if(RSTART){                             #  new/next line begs
          numR++
          buf0=substr(buf0,RSTART+RLENGTH)      #  cut <tr ?*> at the beginning of the line
        }
        if(int0=index(buf0,"</tr")){            #  this line ends
          getSels(substr(buf0,1,int0-1))        #  tabl_row -> arrow:sell_values
          buf0=substr(buf0,int0+4)            #  убрали эту строку из буфера и окультуриваем...
          sErr=""                               #  пока этот текст/раздел НЕ в браке
          id_T=aSel[0]                    #  имя+расшир файла с текстом (или "./" для раздела)
          namT=aSel[1]                #  пока фактическое (as-is) название текста в статистике
          if((numT==1)&&(numR==2)){             #  хиты по разделу (спец.обслуживание)
#             namT="\"<!>\""
#             id_T="~"                              # prt 8-раздел: 'хиты за 30 дней'
# 0.1-имя/ссылка; хиты: 2-всего, 3-12мес, 4..15-заМес, 16..77-заСутки
            if(minT-luck>0){                    #  у раздела мало хитов за нужный интервал
#               errS="] step."step" (luck:"luck"; less:"minT" in fNam: " fNam " )"
              step=4
              nextfile
            }else{
              aIdL[id_P]=luck                   #  реальная удача раздела
            }
          }else{                                #  обычная строка статистики текста
            if(minT-aSel[3]>0){                 #  дальше только неудачники
              step=4
              nextfile
            }
            int0=split(id_T,arr0,".")
            id_T=arr0[1]
            if(int0!=2){
              sErr="zOrg"                       #  нарушен формат имени файла: name.ext
            }else if(arr0[2]!="shtml"){
              sErr="xExt"                       #  расширенеие не то-с
            }else if (gensub(/[\-0-9a-z_]/,"","g",arr0[1])!=""){
              sErr="vNam"                       #  левые символы в имени файла текста
            }else if(namT==""){
              sErr="tHdr"                       #  "пустое" название текста
            }else if(minT-luck>0){                   
              sErr="lowH"                       #  у текста мало хитов за нужный интервал
            }else{
              if(maxL-luck<0){                  #  отбираем самый успешный текст
                maxL=luck
                if(nulN!=0){
                  nulN=gapD-nulN
                  txtD++
                }
                aTxL[id_P]=sprintf("%6.0f %2s ",luck,nulN)  #  удача текста за... это цифры
                aTxN[id_P]=id_T" "pack(namT)    #  и его атрибуты это цепочки символов
              }
            }
            sErr=""
          }
        }
      }
      if(int0=index(buf0,"</table")){           #  this tabl ends
        buf0=substr(buf0,int0+4)                #  update buf0
        inTab=0
      }
    }else{                                      #  ищем начало таблицы
      if(int0=index($0\
,"<table border=1 cellspacing=0 cellpadding=0><tr><td><td colspan=2><b>Итого</b></td>")){
        numT++                                  #  new table
        numR=1              #  певая строка каждой таблицы - календарь хитов статистики раздела
        buf0=substr($0,int0+80)
        if(numT==1){                            #  1-st table 1-st row -> get col-dates & so-on
          match(buf0,/<tr[^>]*>(.+)<\/tr[^>]*>/,arr0) #  собственно строка с календарём
          getSels(arr0[1])                      #  но самую первую такую - разберём-с
          tic0=ticS         #  и привяжем дату к нулевому (самому левому) дню посуточных данных
          int0=16
          while(strftime("%d",tic0)!=aSel[int0])tic0=tic0-86400 # сдвинем стат.дату к нулевому дню
          while(int0<78){
            int0++
            tic0=tic0-86400
            datS=strftime("%Y.%m.%d",tic0)
            if(datS==datJ)dayB=int0
            if(datS==preS)dayE=int0
          }
          if(!dayB){
            errS="]  NO datJ:"datJ", in " fNam
            nextfile
          }
          if(!dayE){
            errS="]  NO preS:"preS", in " fNam
            nextfile
          }
        }
        inTab=1                                 #  мы ВНУТРИ таблицы
        buf0=""                                 #  буфер чист!
      }
    }
  }
}                                               #  // -=- основной блок скрипта ends

function getSels(rowLn){            #  разделение строки таблицы статистики на массив значений
  hitT=0                                        #  + сумма хитов "за 30 дней"
  selN=0                                        #  sells count
  nulN=0                                        #  число пустых ячеек в нашем интервале
  split("",aSel)
  aSel[0]=""
  while(match(rowLn,/<td[^>]*>/)){              #  это объявление ячейки
    selN++              #  0.1-имя/ссылка; хиты: 2-всего, 3-12мес, 4..15-заМес, 16..77-заСутки
    rowLn=substr(rowLn,RSTART+RLENGTH)          #  выкусим объявление ячейки
    f3n2=index(rowLn,"</td")                    #  это конец ячейки
    f3s2=substr(rowLn,1,f3n2-1)           #  это сама ячейка (с возможными внутренними тегами)
    if(selN==1){                          #  в ПЕРВОЙ ячейке - название текста и ссылка на него
      match(f3s2,/<a href=([^>]+)>(.*)<\/a>/,f3a1)  #  выцепим и разложим:
      aSel[1]=f3a1[2]                           #  название текста
      aSel[0]=f3a1[1]                           #  ссылка на текст: name.shtml
    }else aSel[selN]=rmTags(f3s2) # в ПРОЧИХ ячейках - только значение ячейки, очищенное от тегов
    rowLn=substr(rowLn,f3n2)                    #  выкусим оптиченную ячейку
    if(selN-dayB>=0){                           #  начало /самый свежий день/ нашего интервала
      if(dayE-selN>=0){                         #  внутри этого интервала
        hitT=hitT+aSel[selN]                    #  считаем сумму хитов за gapD
        if(aSel[selN]==0)nulN++                 #  пустая ячейка В интервале(!), зачтём
      }
      if(aSel[selN]!=0)nulN=0                   #  непустая ячейка ПОСЛЕ начала интервала
    }
  }
  if(gapD==nulN)luck=0                          #  удача этой строки статистики
  else          luck=sprintf("%5.0f",10*hitT/(gapD-nulN))+0
#   print numT,numR,luck
  if(selN==77)return                            #  row HAVE had 77 sells
  nextfile                                      #  битая таблица == битый файл
}

function rmTags(f2s1){                          #  удаление ВСЕХ тегов в литерале
  while(match(f2s1,/<\/?[a-zA-Z][1-6a-zA-Z]?[a-zA-Z]*[ \/]?[^>]*>/))
      f2s1=substr(f2s1,1,RSTART-1) substr(f2s1,RSTART+RLENGTH)
  return(f2s1)
}

function pack(f1s1) {   #  мешающие chars -> нейтральные + cut too long + закавычить результат
  f1n1=split(f1s1,f1a1)
  f1s1=f1a1[1]                                  #  обихаживание пробелов... " " -> "•"
  for(f1n2=2;f1n2<=f1n1;f1n2++)f1s1=f1s1"•"f1a1[f1n2]
  f1s2=""                                       #  двойные кавычки -> "&quot;"
  while(f1n1=index(f1s1,"\"")){f1s2=f1s2 substr(f1s1,1,f1n1-1)"&quot;"; f1s1=substr(f1s1,f1n1+1)}
  f1s1=f1s2 f1s1
  f1s2=""                                       #  "%" -> "&#x25;"
  while(f1n1=index(f1s1,"%")){f1s2=f1s2 substr(f1s1,1,f1n1-1)"&#x25;"; f1s1=substr(f1s1,f1n1+1)}
  f1s1=f1s2 f1s1
  if(length(f1s1)>999){                         #  обрезка слишком длинных литералов
    f1n1=index(substr(f1s1,1000),"•")
    if(!f1n1)f1n1=1000
    else   f1n1=f1n1+999                        #  v-вместо обрезанного - справка о факте ;)
    f1s1=substr(f1s1,1,f1n1-1)"•(+"(length(f1s1)-f1n1)" chars)"
  }
  return ("\""f1s1"\"")                         #  результат "закавычивается!"
}

function chkSteps() {                   #  проверка чем закончилась обработка очередного файла?
  if((step==4)&&(errS=="")){                    #  всё штатно ("ОК")
#     if(maxL)aIdP[id_P]=aIdP[id_P]" "aTxL[id_P]    #  в разделе есть годный текст
    return
  }else{
    if(errS==""){                               #  что-то не так, но нужно уточнить...
      if(step==3){
        if(inTab==1){                           #  уточним проблему...
          if(selN!=77){                         #  row HAVE had 77 sells
        errS="] step."step" (selN:"selN" Tab:"numT" Row:"numR"{not 77}): " fNam " )"
          }else if((numT==1)&&(numR==2)){
        errS="] step."step" (bad 1-st table 2-nd row in: "    fNam " )"
          }else{
        errS="] step."step" (unClosed table in: "             fNam " )"
          }
        }else{
        errS="] step."step" (no or bad table in: "            fNam " )"
        }
      }else if(step==2){
        errS="] step."step" (no or bad author's ID in: "      fNam " )"
      }else if(step==1){
        errS="] step."step" (no or bad refresh date:{"$0"}: " fNam " )"
      }else if(step==0){
        errS="] step."step" (no partition`s owner in: "       fNam " )"
      }
    }
    aErr[++nErr]=errS
    errS=""                                     #  и очистим флаг-инфо
  }
}

END{                                            #  отстрелялись; ну почти...
  if(ARGV[1]==""){
    print("? NO file in")
    exit 1                                      #  защита от случайного пуска
  }
#   exit
  chkSteps()                                    #  чем закончилась обработка последнего файла?
  if(int8%100)print("")
  print(" == "int8":stats",strftime("%H:%M:%S",systime()-tIni,-1))  #  проблем нет
# aTxt == 10*Luck, id_P, id_T, namP, namT, fNam
# (! в массиве наверняка есть "лишние" тексты из-за алгоритма: aHit[int0] < maxT )
# id_P=aj[3] # ID раздела
# aIdL[id_P] # его реальная удача
# aIdP[id_P] # его данные из aHitc
# aTxL[id_P] # его удача текста за...
# aTxN[id_P] # и атрибуты его текста
# aIdD[id_P] # его описание оттуда же
#  для правильной сортировки по успеху именно текста припишем его спереди
  for(jj in aTxL)aOut[++nOut]=aTxL[jj] sprintf("%5s %s",aIdL[jj],aIdP[jj] bRd jj bRd aTxN[jj] bRd aIdD[jj])
#  формат вЫходного списка
#   613 0  65951     29    1159     3     613   0:!:k/kadawr:!:n "Псион":!:"Кадавр" "no•comments"
# ;Luck new.2 hitP numP.4 sizK sizN.6 txtL txtG.8 ! id_P ! id_T.10 "namT" ! "namP".12 "moto"
# <- - - - - - - block.1 - - - - - - - - - - - ->  block.2 <- block.3 ->    <- block.4 ->
  asort(aOut)
  for(jj=nOut;jj>0;jj--)print(aOut[jj]) >fOut   #  при выдаче приписанное надоть изъять!
print(";txtL txtG.2 Luck new.4 hitP numP.6 sizK sizN.8 ! id_P ! id_T.10 \"namT\" ! \"namP\".12 \"moto\"")>fOut
  for(jj=1;jj<=nEnd;jj++)print(aEnd[jj]) >fOut  #  <- старый подвал + свежак -v
j0=";5H txL1 "datJ":datJ "gapD":gapD "nOut":nTxL "nErr":nErr "minT":minT "txtD":txtD "strftime("%Y.%m.%d:done at~%H:%M")
  print(j0) >fOut
  if(nErr){
    asort(aErr)
    for(int0=1;int0<=nErr;int0++)print(aErr[int0])>fOut".err"
    print(j0)                                     >fOut".err"
    nErr=nErr":nErr"
  }else nErr=""
  print(" ==",nOut":nTxL",nErr)
# 2020.11.23, nvv, creation
# 2021.01.11, nvv, it works ok...
# 2021.05.02, nvv, мелкая косметика
# 2022.04.18, nvv, радикально переделано - теперь выдача точней и структурирована в блоки
# 2023.01.25, nvv, сменилось разрешение экрана, слегка меняем оживляж
}

    Имя файла скрипта: "iNetR.awk" V-текст скрипта-V
- - - - - - - - -
BEGIN{                                  #  iNetR.awk - оформление в HTML приложения "siTopAuthors"
  if(!(1 in ARGV))exit                             # защита от случайного пуска

  minT=333            # нижняя граница отбора в наш список: 33.3 посетителя в день, 999 за 30 дней
  minT=100

# 2024.08.27, nvv, отключена отметка "Upd" для: "Исходные тексты скриптов"
#  ! прочая история - в подвале

  rTyp="<b>si&#x54;op&#x41;uthors</b>"              # siTopAuthors
  ancW="t"                                # общий признак типа рейтинга в якорях, комментах и т.п.
  ancS=":"                                  # частный признак якоря места (в формате: "ггммвв:NNN"
  flag=0                                          # флаг для чередующейся раскраски строк таблиц
  tGap=50                                         # строк в одной таблице
  tMax=1000                                       # строк в списке всего
  oldP=0                                          # (раздел)размещено более года назад
  curP=0                                          # (-"-) - "" - в границах интервала и позже
  oldT=0                                          # (текст)размещено более года назад
  curT=0                                          # (-"-) - "" - в границах интервала и позже
  txtM=0                        # число разделов с более чем одним лидером (с одинаковым успехом)
  auUp=0                                          # раздел, сдвиг вверх
  auDn=0                                          # раздел, сдвиг вниз
  auNw=0                                          # новый автор
  upAu=0                                          # объём+ раздела
  dnAu=0                                          # объём- раздела
  nwTx=0                                          # новый текст
  upTx=0                                          # объём+ текста
  dnTx=0                                          # объём- текста
  pDat=-1                                         #  дата aHits по СИ
  preH=-1                                         #  дата "скачан" (aHits)
  pPag=-1                                         #  страниц aHits
  hDat=-1                                         #  дата aHits по СИ
  donH=-1                                         #  дата "скачан" (aHits)
  hPag=-1                                         #  страниц aHits
  hMax=-1                                         #  хиты раздела-лидера aHits
  minL=-1                                         #  минимальная "удача" раздела
  hold=-1                                         #  дата "расчёт"
# "/" == общий префикс урла СИ: samlib.ru
  nUrl="n/nosow_w_w"                              # nvv-с...
#  jDat=strftime("%y%m%d%H%M%S",systime())         # дата для якорей таблиц

  for ( jj in ENVIRON ) {                     # ! регистр букв в имени переменной может быть любой
    j1=tolower(jj)
    if ( j1 == "fold" ) fOld=ENVIRON[jj]          # ИМЯ опорного файла (like 2018.11.29.mText)
    if ( j1 == "hdir" ) hDir=ENVIRON[jj]"\\"      #  место для файлов *.HTML
    if ( j1 == "mint" ) minT=ENVIRON[jj]          #  минимальный успех*10 текста-лидера в разделе
    if ( j1 == "minl" ) minL=ENVIRON[jj]          #  минимальный успех*10 раздела
  }
  if(fOld==""){
    fOld="U:\\Stor\\Text\\zOld.gAuths\\2021.05.26.3.gAuth"
    minL=100
  }

  nMth[ 1]="января"
  nMth[ 2]="февраля"
  nMth[ 3]="марта"
  nMth[ 4]="апреля"
  nMth[ 5]="мая"
  nMth[ 6]="июня"
  nMth[ 7]="июля"
  nMth[ 8]="августа"
  nMth[ 9]="сентября"
  nMth[10]="октября"
  nMth[11]="ноября"
  nMth[12]="декабря"

   color[0]="\"#FFFFE0\""                     # (четная строка таблицы) светло-жёлтый line color 0
   color[1]="\"#F5F5DC\""                   # (НЕчетная строка таблицы) грязно-жёлтый line color 1
   color[2]="\"#C0C0C0\""                         # gray серый (всё плохо)
   color[3]="\"#FFF4E0\""                         # светло-розовый (ниже, меньше, плохо, нет)
   color[4]="\"#F0FFE0\""                         # светло-зелёный (выше, больше, хорошо)
   color[5]="\"#FFFFB0\""                         # светло-жёлтый - новое
   color[6]="\"#FFFF70\""                       # yellow желтый (нечётные ячейки в шапках таблиц)
   color[7]="\"#F8F8F8\""                         # светло-серый - наш рейтинг
   color[8]="\"#0000FF\""                         # синий (птичка nvv)
   color[9]="\"#000000\""                         # чёрный (вратый объём)
  color[10]="\"#E8F8B8\""                         # зелёный - ячейки с текстом нашего рейтинга
  color[11]="\"#E0F8FF\""                 # светло-сиреневый - размещено "давно" больше года назад
  color[12]="\"#FFD700\""                         #  оранжевый "потеряшки" /скрытые разделы/ aad2
# jDir datJ"."gapD"."nJob == U:\Jobs\2020.11.14.3.gGapR
  jr=split(ARGV[1],aq,"\\")                       # "U:" + "Jobs" + "2020.11.14.3.gGapR"
  split(aq[jr],aq,".")                            # "2020.11.14.3.gGapR"
  rYea=aq[1]                                      #  год рейтинга !привязан к верхней дате выборки
  rMth=aq[2]                                      #  месяц его же
  rDay=aq[3]                                      #  день его же
  datJ=rYea"."rMth"."rDay                         #  дата верхнего конца интервала (включая)
  gapD=aq[4]                                      #  интервал (в днях) обсчитанного периода
  fOut=hDir datJ"."gapD".gAuth.html"       #  "U:\Stor\Html\" + "2020.11.14" + ".3" + ".auth.html"
  fPre=hDir datJ"."gapD".gAuth.z.html"  #  "U:\Stor\Html\" + "2020.11.14" + ".3" + ".auth.z.html"

  dBeg=strftime("%Y.%m.%d",mktime(rYea" "rMth" "rDay" 12 00 00")-86400*(gapD-1)) # дата 1-го дня выборки
  yBeg=substr(dBeg,1,4)                           # год этого 1-го дня интервала нашей выборки
  oldD=rYea-1"."rMth"."rDay                       # "год назад" - привязка к КОНЦУ нашей выборки
  tOld="года"
  qGap=gapD"_дн."
  if(gapD==1)       sGap="день"
  else if(gapD-5<0) sGap="<b>"gapD"</b> дня"
  else              sGap="<b>"gapD"</b> дней"
  info="<!-- (L) nvv; type: 'Auth' \"curr siTopAuthors\" "strftime("%Y.%m.%d %H:%M")" -->" #  mark
  inf2="<!-- (L) nvv; type: 'Auth' \"prev siTopAuthors\" "strftime("%Y.%m.%d %H:%M")" -->" #  mark
  print "--- " strftime("%H:%M:%S") " Begs..."  # начали работу (оживляж;)
# подвязка позиций прошлого рейтинга, для отметок "сдвиг" (места)
#  $1  $2   $3   $4   $5   $6   $7   $8   $9       $10        $11    $12  $13    $14    $15   $16    $17   $18
# Luck new  hitP numP sizK sizN hitT txtN sizT     datP       endD   id_P "namP" "moto" id_T "namT" "jnrT" fNam
# 5527 0  218357 13   936  6    4937  1    7   2020.11.15 2020.08.31 z/zhan "Tony" "kjujdj•xbnfntkz" flibustain "Известные•мне•зеркала•Флибусты•и•Либрусека" "<a•href=/type/index_type_5-1.shtml>Статья</a>:" z~zhan
# 10330 0 206377 14   938  8   10333  1    7.1 2021.04.03 2020.08.31 z/zhan "Tony" "kjujdj•xbnfntkz" flibustain "Известные•мне•зеркала•Флибусты•и•Либрусека" "<a•href=/type/index_type_5-1.shtml>Статья</a>:" z~zhan 

  if(fOld!=""){
    tmp0=0
    while ((getline line < fOld) > 0) {             # fOld: like 2018.11.29.mText
      split(line,aj)
      if(match(aj[1],/^[\.0-9]+$/)){              # это именно строка с успехом раздела &Co
        if((aj[7]-minT>=0)&&(aj[1]-minL>=0)){     #  успех текста/раздела МОЖЕТ быть ниже границ
          tmp0++                                  #  старая позиция раздела в старом списке
          a0a[aj[12]]=tmp0                        #  место раздела в старом списке
          a0k[aj[12]]=aj[5]                       #  объём раздела в кбайтах
          a0n[aj[12]]=aj[6]                       #  наполнение в штуках ;)
          a0t[aj[12]]=aj[15]                      #  id_T (текста-лидера)
          split(aj[9],aq,".")
          a0z[aj[12]]=aq[1]                       #  объём текста
        }
      }else if(match(line,/^;5H .+ 20([0-9]+)\.([0-9]+)\.([0-9]+):done /,aj))oDat=aj[1] aj[2] aj[3]
    }
  }
  close(fOld)                                     # всё/не_всё, - старый список тогось
  jj=0
  split("",a90)
print "fOld: "fOld
print "fLst: "ARGV[1]
print "fOut: "fOut
print "dBeg:"dBeg,"gapD:"gapD,"datJ:"datJ,"oDat:"oDat
# exit
}

function mkPage() {               # сборка всей страницы рейтинга/приложения (тип, строк, куда-с)
  if(strftime("%j")-355>0)jj="С наступающим"
  else if(strftime("%j")-11<0)jj="С"
  else jj=""
  if(jj!=""){
    aHnY[++nHnY]="<table align=center border=0 cellspacing=0 cellpadding=2>"
    aHnY[++nHnY]="<tr align=center bgcolor=navy><td><font size=+2 color=aqua>"
    aHnY[++nHnY]="<b>&nbsp;&#x2744; "jj" новым годом! <font color=white>&#x2744;"
    aHnY[++nHnY]="<font size=+2 color=lime>Happy New Year! &#x2744;&nbsp;</b></td>"
    aHnY[++nHnY]="</tr></table>"
    aHnY[++nHnY]="<hr>"
  }
  aHdr[++nHdr]="См. <i>также</i>:"
  aHdr[++nHdr]="<br>?"
  aHdr[++nHdr]="<a href=/"nUrl"/si_pop-brief.shtml>Как узнать<b>"
  aHdr[++nHdr]="популярность произведения</b> в \"Самиздате\"</a>"
  aHdr[++nHdr]="(\"<b>где/что смотреть</b>\" - основное, вкратце)."
  aHdr[++nHdr]="<br>~"
  aHdr[++nHdr]="<a href=/"nUrl"/si_top500look-curr.shtml>Рейтинг"
  aHdr[++nHdr]="<b>siTopTexts</b> \"Произведения\"</a>"
  aHdr[++nHdr]="(\"Самиздат\", самое популярное за <b>30 дней</b>)."
# † массив строк шапки ТОЛЬКО у последнего рейтинга
  aHd1[++nHd1]="<br>#"
#   aHd1[++nHd1]="<font color=\"#DC143C\">Upd</font>" #  2024.07.27 11:43
  aHd1[++nHd1]="<a href=/"nUrl"/sitopscriptslist.shtml>"
  aHd1[++nHd1]="Исходные <b>тексты скриптов</b> задач \"<b>siTop…</b>\"</a>"
  aHd1[++nHd1]="<br>&#x00B1;" # <font color=red size=-2>New</font>" 2022.12.01 off
  aHd1[++nHd1]="<a href=/n/nosow_w_w/si_votes-brief.shtml><b>Оценка произведений</b>"
  aHd1[++nHd1]="в \"Самиздате\"</a> (<b>что, где, как</b> и почему&hellip;)."
  aHd1[++nHd1]="<br>&#x221A;"
  aHd1[++nHd1]="<a href=/n/nosow_w_w/si-ini_reg.shtml><b>Регистрация</b> в \"Самиздате\" для получения"
  aHd1[++nHd1]="статуса &#171;<b>пользователь</b>&#187;</a> (оформление своего аккаунта)."
  aHd1[++nHd1]="<hr>"

  aHd1[++nHd1]="<b>NB.</b> <i>Названия</i> произведений и <i>псевдонимы</i>"
  aHd1[++nHd1]="авторов (как и прочие <i>сведения</i> в таблицах) приведены"
  aHd1[++nHd1]="<i>\"<a title=\"как есть\""
  aHd1[++nHd1]="href=\"https://ru.wikipedia.org/wiki/%D0%9A%D0%B0%D0%BA_%D0%B5%D1%81%D1%82%D1%8C\"><u>as"
  aHd1[++nHd1]="is</u></a>\", по состоянию на момент</i> сбора"
  aHd1[++nHd1]="данных. <i>Текущее</i> состояние можно узнать, пройдя"
  aHd1[++nHd1]="<i>по ссылкам</i> (в ячейках таблиц)."
  aHd1[++nHd1]="<br><b>(!)</b> <i><u>Если</u></i> на месте некоторых букв"
  aHd1[++nHd1]="(символов) в <i>названии</i> произведения или в <i>псевдониме</i>"
  aHd1[++nHd1]="автора вы видите \"<i><u>пустоту</u></i>\", то <i><u>у"
  aHd1[++nHd1]="вас</u></i>, скорей всего, <i><u>отсутствует</u></i>"
  aHd1[++nHd1]="шрифт с такими символами (иероглифы, руны, etc.)."
  aHd1[++nHd1]="<br><b>(?!)</b> \"<i>Успех</i>\" - <i>среднее</i> число"
  aHd1[++nHd1]="посетителей за <b>сутки</b>. Нижняя граница: <b>10</b> хитов."
#   aHd1[++nHd1]="посетителей за <b>сутки</b>. Причём /за период между"
#   aHd1[++nHd1]="<i>обновлениями</i> учётных данных/ успех <b>раздела</b>"
#   aHd1[++nHd1]="должен быть <i>не ниже</i> <b>"minL"</b> (отбор начерно),"
#   aHd1[++nHd1]="а успех произведения-<b>лидера</b> (в нём) - <i>не"
#   aHd1[++nHd1]="ниже</i> <b>"sprintf("%4.1f",minT/10)"</b> (отбор начисто)."
  aHd1[++nHd1]="<br><b>(#)</b>"                   #  2023.08.02
#   aHd1[++nHd1]="<font color=\"#DC143C\">NEW</font>" #  2023.06.23 crimson
#   aHd1[++nHd1]=""                          #  2023.07.08
#   aHd1[++nHd1]="<font color=\"#A52A2A\"><b>Скрытые</b></font> авторы <u><i>отсутствуют</i></u>" # brown
  aHd1[++nHd1]="<i>Скрытые</i> авторы <u><i>отсутствуют</i></u>" # brown
  aHd1[++nHd1]="в \"<a href=/rating/hits/>Рейтинге по количеству посетителей</a>\""
  aHd1[++nHd1]="<br><b>(~)</b>"
  aHd1[++nHd1]="<i>Новые</i> авторы/произведения отсутствовали в <i><u>предыдущем</u></i> рейтинге."
#   aHd1[++nHd1]=""
#   aHd1[++nHd1]="<br><b>(!) <font color=broun>Изменён приоритет</font></b>: теперь"
#   aHd1[++nHd1]="<i>место раздела</i> определяется <i>самым успешным произведением</i> в нём."

# † массив строк шапки ТОЛЬКО у предпоследнего рейтинга

  if(!auUp)auUp=" --"                              # так красивше (чем унылый "0";)
  if(!curP)curP=" --"
  if(!upAu)upAu=" --"
  if(!curT)curT=" --"
  if(!upTx)upTx=" --"
  if(!auDn)auDn=" --"
  if(!oldP)oldP=" --"
  if(!dnAu)dnAu=" --"
  if(!oldT)oldT=" --"
  if(!dnTx)dnTx=" --"

# † массив строк шапки краткой справки последнего рейтинга
  aTb1[++nTb1]="<hr>"
  aTb1[++nTb1]=""
  aTb1[++nTb1]="<table align=center border=1 cellspacing=0 cellpadding=2>"
  aTb1[++nTb1]="<tr align=center>"
  aTb1[++nTb1]="<td bgcolor="color[1]" colspan=\"6\">Краткая сводка + цвет некоторых"
  aTb1[++nTb1]="ячеек таблиц (<i>предыдущий рейтинг -"
  aTb1[++nTb1]="<a href=/"nUrl"/si_top6author-prev.shtml><b>"oDat"</b></a></i>)</td></tr>"

# † массив строк шапки краткой справки ПРЕДпоследнего рейтинга
  aTb2[++nTb2]="<hr>"
  aTb2[++nTb2]=""
  aTb2[++nTb2]="<table align=center border=1 cellspacing=0 cellpadding=2>"
  aTb2[++nTb2]="<tr align=center>"
  aTb2[++nTb2]="<td bgcolor="color[1]" colspan=\"6\">Краткая сводка + цвет некоторых"
  aTb2[++nTb2]="ячеек таблиц (<i>предыдущий рейтинг - <b>"oDat"</b></i>, последующий"
  aTb2[++nTb2]="- <a href=/"nUrl"/si_top6author-curr.shtml><b>здесь</b></a>)</td></tr>"

# † массив строк тела краткой справки общий
  aTbl[++nTbl]="<tr align=center bgcolor="color[0]">"
  aTbl[++nTbl]="<td colspan=3><b>Авторы</b> (разделы)</td>"
  aTbl[++nTbl]="<td rowspan=\"5\"></td>"
  aTbl[++nTbl]="<td colspan=2><b>Произведения</b> (лидеры)</td></tr>"
  if(auNw+nwTx){
    aTbl[++nTbl]="<tr align=center>"
    if(auNw+length(a90)){                         #  если есть новое ИЛИ скрытое
      j0="<td bgcolor="color[12]">скрытые.<b>"length(a90)"</b></td>"
      j0=j0"<td bgcolor="color[5]" colspan=2>новые.<b>"auNw"</b></td>"  #  <td> </td>
    }else{
      j0="<td colspan=3></td>"                    #  иначе - пусто
    }
    aTbl[++nTbl]=j0
    if(nwTx)aTbl[++nTbl]="<td bgcolor="color[5]" colspan=2>новые.<b>"nwTx"</b></td></tr>"
    else    aTbl[++nTbl]="<td colspan=2></td></tr>"
  }
  aTbl[++nTbl]="<tr align=center bgcolor="color[1]">"
  aTbl[++nTbl]=                  "<td><b>N</b>(место), сдвиг</td>"
  aTbl[++nTbl]=                  "<td><b>Наполнение</b> стало</td>"
  aTbl[++nTbl]=                  "<td><b>Обновлялось</b></td>"
  aTbl[++nTbl]=                  "<td><b>Изменено</b></td>"
  aTbl[++nTbl]=                  "<td><b>Объём</b> стал</td>"
  aTbl[++nTbl]="</tr><tr align=center bgcolor="color[4]">"
  aTbl[++nTbl]=                  "<td>вверх.<b>"  auUp"</b></td>"
  aTbl[++nTbl]=                  "<td>больше.<b>" upAu"</b></td>"
  aTbl[++nTbl]=                  "<td>намедни.<b>"curP"</b></td>"
  aTbl[++nTbl]=                  "<td>намедни.<b>"curT"</b></td>"
  aTbl[++nTbl]=                  "<td>больше.<b>" upTx"</b></td>"
  aTbl[++nTbl]="</tr><tr align=center>"
  aTbl[++nTbl]="<td bgcolor="color[3]  ">вниз.<b>"auDn"</b></td>"
  aTbl[++nTbl]="<td bgcolor="color[3]">меньше.<b>"dnAu"</b></td>"
  aTbl[++nTbl]="<td bgcolor="color[11]">давно.<b>"oldP"</b></td>"
  aTbl[++nTbl]="<td bgcolor="color[11]">давно.<b>"oldT"</b></td>"
  aTbl[++nTbl]="<td bgcolor="color[3]">меньше.<b>"dnTx"</b></td>"
  aTbl[++nTbl]="</tr></table>"

  aTbl[++nTbl]="<table align=center border=0 cellspacing=0 cellpadding=2><tr>"
  aTbl[++nTbl]="<td>(</td>"
  aTbl[++nTbl]="<td bgcolor="color[11]">&nbsp;<b><i>давно</i></b>"
  aTbl[++nTbl]="– больше <b>"tOld"</b> назад&nbsp;</td>"
  aTbl[++nTbl]="<td>)</td>"
  aTbl[++nTbl]="</tr></table>"
  aTbl[++nTbl]="<hr>"
  aTbl[++nTbl]=""
  aTbl[++nTbl]="<font size=\"-2\" face=monospace color="color[8]">"
  aTbl[++nTbl]="&nbsp;&nbsp;/\\&nbsp;&nbsp;&nbsp;&nbsp;/\\&nbsp;&nbsp;<br>"
  aTbl[++nTbl]="&nbsp;&#xB7;--&#xB7;--&#xB7;--&#xB7;&nbsp;<br>"
  aTbl[++nTbl]="&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\\/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>"
  aTbl[++nTbl]="&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/\\&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>"
  aTbl[++nTbl]="&nbsp;&nbsp;&nbsp;&nbsp;&#xB7;--&#xB7;&nbsp;&nbsp;&nbsp;&nbsp;<br></font>"

# † титулы (названия) и рейтинга и его копии "Предыдущий"

  Ttl1="<center><font size=\"+2\">Рейтинг "rTyp"-"ancD"</font>"
  Ttl2="<center><font size=\"+2\">Предпоследний рейтинг "rTyp"-"ancD"</font>"

  aOut[++nOut]="<br>\"Самиздат\", самые посещаемые авторы"  #   (<i><b>намедни</b></i>)
  aOut[++nOut]="<table align=center border=0 cellspacing=0 cellpadding=2>"
  aOut[++nOut]="<tr bgcolor="color[4]">"  #  <td>(</td>
  if(gapD==1){
#          sGap="намедни"
    aOut[++nOut]="<td>&nbsp;намедни: "dat_str(dBeg)" "yBeg" г.</td>"
  }else{
    j0="с "dat_str(dBeg)
    if(yBeg!=rYea)j0=j0" "yBeg" г."
    j0=j0" по "dat_str(datJ,1)"&nbsp;"
    aOut[++nOut]="<td>&nbsp;за "sGap": "j0"</td>"
  }
#  if(dOff!="0.0")aOut[++nOut]="<td bgcolor="color[3]">(<i><u>нет данных</u> за: "dOff"</i>)</td>"
  aOut[++nOut]="</tr></table>"
#   aOut[++nOut]="(приложение к рейтингу <b>siTopTexts</b>-"ancD")"
  aOut[++nOut]="</center></blockquote>"
  bLin=mkCap()                                    # шапка - первая (нулевая-с) строка таблиц
  lMax=tMax                                       # всего строк в таблице
  for ( tIni=1; tIni<=lMax; tIni=tIni+tGap ) {
    aOut[++nOut]="<blockquote>"  # начало очередной таблицы
    aOut[++nOut]="<table align=center border=1 cellspacing=0 cellpadding=2>"  # навигация в
    aOut[++nOut]="<caption><a id=\""ancD ancW tIni"\"></a>"mkGoTo(tIni)"</caption>"  # заголовке
    if(tIni==1)aOut[++nOut]=mkCap0() # шапка "ini"
    aOut[++nOut]=bLin  # шапка таблицы
    tEnd=tIni+tGap
    for (tBeg=tIni;tBeg<tEnd;tBeg++) {
      if(tBeg<=lMax) mkTabLn(tBeg,tBeg)     # строка данных в таблице
    }
    if ((tBeg-tMax)>0) aOut[++nOut]=bLin
    aOut[++nOut]="</table>"  # таблица готова
    aOut[++nOut]="</blockquote>"  # закрытие блока
  }
  aOut[++nOut]="<blockquote>"  # подвал страницы
  aOut[++nOut]="<center>" mkGoTo(0) "</center>"  # заголовке
  aOut[++nOut]="<ul>"
  aOut[++nOut]="<table border=0 cellspacing=0 cellpadding=2><tr>"  # навигация в
  aOut[++nOut]="<td><b>Попутные сведения</b> (к "rTyp"-"ancD")"
  aOut[++nOut]="<td></tr></table>"
  aOut[++nOut]="<li>Последний <u>полный</u>"
  aOut[++nOut]="\"<a href=/rating/hits/index.shtml><i><b>Рейтинг"
  aOut[++nOut]="по количеству посетителей</b></i></a>\": за "hDat
  aOut[++nOut]="(от "dat_str(donH)")"
  aOut[++nOut]="<br>сравнивался с <i>предпоследним</i>: за "pDat
  aOut[++nOut]="(от "dat_str(preH)")."
  aOut[++nOut]="<li><i>Прочие</i> данные - по состоянию на "dat_str(hold)"."
#   if(txtM){
#     aOut[++nOut]="<li>Разделы с <i>несколькими</i> (‡) лидерами: <b>"txtM"</b>."
#   }
  aOut[++nOut]="</ul>"
  aOut[++nOut]="<table align=center border=0 cellspacing=0 cellpadding=2>"  # навигация в
  aOut[++nOut]="<tr><td>(copyleft "rYea"</td>"
  aOut[++nOut]="<td bgcolor="color[6]"><b>/\\/.\\/.\\/.</b></td><td>)</td></tr></table>"
}

function mkGoTo(lCur) {                           # сборка строки навигации для титула таблиц
  lBeg=1                                          # начало очередного интервала
  lEnd=lBeg+tGap-1                                # и его конец
  if ((lEnd-lMax)>0) lEnd=lMax                    # но не выше общего конца
  sNav="<center>Интервал <b>N</b>: <b>"           # начало строки навигации
  for(j0=1;j0<=lMax;j0++) {
    if (j0==lBeg) {                               # компоновка очередного элемента навигации
      if ((lBeg-1)>0) sNav=sNav " | "             # первый разделитель опускаем
      if (lBeg==lCur) sNav=sNav "<big>" lBeg "-" lEnd "</big>"  # это у своей таблицы, v-иначе
      else {
        sNav=sNav "<a title=\"Перейти к интервалу: " lBeg "-" lEnd "\" href=\"#"
        sNav=sNav ancD ancW j0"\">" lBeg "-" lEnd "</a>" # оформление как ссылка на ЯКОРЬ
      }
      lBeg=lEnd+1                                 # сдвинем границы на шаг tGap
      lEnd=lEnd+tGap
      if ((lEnd-lMax)>0) lEnd=lMax
    }
  }
  sNav=sNav"</b></center>"                        # завершение строки
  return(sNav)
}

function mkCap0() {                             # сборка доп.над.шапки (только для первой таблицы)
  tmp0=     "<tr align=center bgcolor="color[0]">"
  tmp0=tmp0 "<td colspan=5>Самые посещаемые <b>разделы</b></td>"
  tmp0=tmp0 "<td bgcolor="color[1]" colspan=5>Самые посещаемые <b>произведения</b> /в этих разделах/</td>"
  return( tmp0 "</tr>" )                          # шапка готова
}

function mkCap() {                                # сборка шапки таблиц
  tmp0= "<tr align=center bgcolor="color[flag]">" # шапки начало; v-место:хиты
  tmp0=tmp0 "<td bgcolor="color[6]" title=\"Местов списке, Хиты за сутки\"><b>N</b>: Успех</td>"
  tmp0=tmp0 "<td><a title=\"Раздел за 12мес: место, хиты\"><b>Автор</b></a></td>" # Автор
  tmp0=tmp0 "<td bgcolor="color[6]"><b>Девиз</b></a></td>"    # Произведение
  tmp0=tmp0 "<td><small><b>Объём</b>/шт.</small></td>"
  tmp0=tmp0 "<td bgcolor="color[6]"><small><b>Обновлялось</b></small></td>"
  tmp0=tmp0 "<td title=\"Хиты за сутки\"><small><b>Успех</b></small></td>"
  tmp0=tmp0 "<td bgcolor="color[6]" title=\"Самый популярный в разделе\"><small><b>Лидер</b></small></td>"
  tmp0=tmp0 "<td><a title=\"Дата последнего изменения текста\"" # Создан +v
  tmp0=tmp0 "><small><b>Изменено</b></small></a></td>" # ^+ Создан
  tmp0=tmp0 "<td bgcolor="color[6]"><a title=\"Текст в килобайтах\""  # Объём +v
  tmp0=tmp0 "><small><b>Объём</b></small></a></td>" # ^+ Объём
  tmp0=tmp0 "<td><a title=\"Текста\"><small><b>Форма</b>: Жанр (жанры)</small></a></td>" # Форма: Жанр(ы)
  return( tmp0 "</tr>" )                          # шапка готова
}

function mkTabLn(nLn,tLn) {     # выдача строки номер nLn (строка исходного списка за номером tLn)
  flag=!flag                                      # чередующаяся раскраска строк
  aOut[++nOut]="<tr "substr(nLn+1000,2)" align=center bgcolor="color[flag]">" # собираем строку...
  aOut[++nOut]="<td "a01[tLn]" title=\""a00[tLn]"\"><b>"nLn"</b>: "a14[tLn]"</td>" # Место(N): хиты
  if(a10[tLn] in a90)ownColor=" bgcolor="color[12]  #  "скрытый" автор /потеряшка/ 2023.07.08
  else               ownColor=""
  aOut[++nOut]="<td align=left"ownColor" title=\"место:"a12[tLn]", хиты:"a13[tLn]"\"><a href=/"a10[tLn]"/ id=\""ancA[tLn]"\">"a11[tLn]"</a></td>"
  aOut[++nOut]="<td"a03[tLn]"><i><font color=Maroon>"a15[tLn]"</font></i></td>"  # Девиз 
  aOut[++nOut]="<td"a02[tLn]" "a06[tLn]">"a16[tLn]"</td>"  # Объём
  aOut[++nOut]="<td "a18[tLn]">"rusDat(a17[tLn])"</td>"  # Обновлялось v-Успех
  aOut[++nOut]="<td><a href=/"a10[tLn]"/stat.shtml#"a20[tLn]".shtml id=\""a20[tLn]".shtml\">"a22[tLn]"</a></td>"
  if(a10[tLn]==nUrl)nvvColor=" title=\"это то, на что вы смотрите ;)\" bgcolor="color[10]
  else              nvvColor=""                   #  ^-моё? МОЁ! Моё... ;)
  aOut[++nOut]="<td"nvvColor" align=left><a href=/"a10[tLn]"/"a20[tLn]".shtml id=\""ancA[tLn]":"a20[tLn]"\">"a21[tLn]"</a></td>"
  aOut[++nOut]="<td"a34[tLn]">"rusDat(a31[tLn])"</td>"  # Изменено ^-Лидер
  aOut[++nOut]="<td"a04[tLn]" align=right "a05[tLn]">"a32[tLn]"k</td>"  # Объём
  aOut[++nOut]="<td>"a40[tLn]"</td>"  # Форма: Жанр (жанры)
  aOut[++nOut]="</tr>"
  return                                          # строку собрали, вываливаем!
}

# $1  $2   $3   $4   $5   $6   $7   $8   $9       $10        $11    $12  $13    $14    $15   $16    $17   $18
# Luck new  hitP numP sizK sizN hitT txtN sizT     datP       endD   id_P "namP" "moto" id_T "namT" "jnrT" fNam
# 5527 0  218357 13   936  6    4937  1    7   2020.11.15 2020.08.31 z/zhan "Tony" "kjujdj•xbnfntkz" flibustain "Известные•мне•зеркала•Флибусты•и•Либрусека" "<a•href=/type/index_type_5-1.shtml>Статья</a>:" z~zhan

{         # загрузка исходного списка (с разборкой и оформлением значений, отображаемых в ячейках)
  if(match($1,/^[0-9]+$/)){                       # признак - "строка основных данных"
    if($7-minT>=0){                          # !!! успех раздела МОЖЕТ быть и ниже minT
      jj++
      if($12 in a0a){                # раздел БЫЛ в старом списке
        j0=a0a[$12]-jj
        if(j0>0){                        # auth, раздел съехал вверх
          auUp++                                  # auth, счётчик, раздел, сдвиг вверх
          a00[jj]="Сдвиг:"j0"-^"                  # auth, сдвиг ()
          a01[jj]=" bgcolor="color[4]             # auth, цвет фона ()
        }else if(j0<0){                  # auth, раздел съехал вниз
          auDn++                                  # auth, счётчик, раздел, сдвиг вниз
          a00[jj]="Сдвиг:"0-j0"-v"                 # auth, сдвиг ()
          a01[jj]=" bgcolor="color[3]             # auth, цвет фона ()
        }else{                                    # auth, "на месте"
          a00[jj]="Сдвиг:0=="                     # auth, сдвиг ()
          a01[jj]=""                              # auth, цвет фона ()
        }
      }else{                              #  раздел в старом списке ОТСУТСТВУЕТ, оформляем "новьё"
        auNw++                                    # auth, счётчик, "новый"
        a00[jj]="Новый"                           # auth, сдвиг (новый)
        a01[jj]=" bgcolor="color[5]               # auth, цвет фона (новый)
      }
      a14[jj]=sprintf("%2.1f",$1/10)              # автор, "Успех" за цикл обновления статистик
      a10[jj]=$12                                 # автор, id_P - урл раздела (мой - n/nosow_w_w;)
      ancA[jj]=substr($12,1,1)"~"substr($12,3)    # формат: "aChr~aNik"
      a11[jj]=unpack($13)                         # автор, namP - ФИО
      a12[jj]=$4                          # автор, numP - позиция раздела в рейтинге посещаемости
      if(!a12[jj])a90[$12]++                  #  СКРЫТЫЙ раздел, учтём произведение из 2023.06.23
      a13[jj]=$3                            # автор, hitP - хиты раздела (в рейтинге посещаемости)
      a15[jj]=unpack($14)                         # "moto"
      if($2)a03[jj]=" title=\"создано намедни\" bgcolor="color[5]  # new Author
      else a03[jj]=""
      a16[jj]="<b>"$5"</b>k/"$6
#        a0k[aj[12]]=$5                              # объём раздела в кбайтах
#        a0n[aj[12]]=$6                              # наполнение в штуках ;)
      if($12 in a0a){                # раздел в старом списке БЫЛ, оформляем "разницу"
        if((a0k[$12]-$5<0)||(a0n[$12]-$6<0)){
          upAu++
          a02[jj]=" bgcolor="color[4]
          a06[jj]=" title=\"Наполнение стало больше\""
        }else if((a0k[$12]-$5<0)||(a0n[$12]-$6<0)){
          dnAu++
          a02[jj]=" bgcolor="color[3]
          a06[jj]=" title=\"Наполнение стало меньше\""
        }
      }else{
        a02[jj]=" bgcolor="color[5]           # auth, цвет фона (новый)
        a06[jj]=" title=\"Новый раздел\""
      }
      a17[jj]=$10                                 # раздел, datP - дата "Обновлялось"
# (разделы) выявим/отметим "свежак" и "старьё"...
      if(dBeg<=a17[jj]){                          # "свежак" (с начала нашего интервала)
        a18[jj]=" title=\"обновлено намедни\" bgcolor="color[4]
        curP++
      }else if(oldD>a17[jj]){                     # "старьё" (год и более назад)
        a18[jj]=" title=\"обновлено давно\" bgcolor="color[11]
        oldP++                                    # счётчик "давно"
      }else  a18[jj]=""                           # норма...
      a22[jj]=sprintf("%2.1f",$7/10)            # текст, hitT - хиты текста (в статистике раздела)
#       if($8-1>0){                                 #  число текстов-лидеров txtN в разделе >одного
#         txtM++
#         a22[jj]=a22[jj]"‡"
#       }
      a20[jj]=$15                               # текст, id_T - имя файла (без расширения .shtml)
      a21[jj]=unpack($16)                         # текст, namT - заголовок
      a31[jj]=$11                                 # текст, endD - дата последнего изменения
# (лидеры) выявим/отметим "свежак" и "старьё"...
      if(dBeg<=a31[jj]){                          # "свежак" (с начала нашего интервала)
        a34[jj]=" title=\"изменено намедни\" bgcolor="color[4]
        curT++
      }else if(oldD>a31[jj]){                     # "старьё" (год и более назад)
        a34[jj]=" title=\"изменено давно\" bgcolor="color[11]
        oldT++                                    # счётчик "давно"
      }else  a34[jj]=""
# $1  $2   $3   $4   $5   $6   $7   $8   $9       $10        $11    $12  $13    $14    $15   $16    $17   $18
# Luck new  hitP numP sizK sizN hitT txtN sizT     datP       endD   id_P "namP" "moto" id_T "namT" "jnrT" fNam
# 5527 0  218357 13   936  6    4937  1    7   2020.11.15 2020.08.31 z/zhan "Tony" "kjujdj•xbnfntkz" flibustain "Известные•мне•зеркала•Флибусты•и•Либрусека" "<a•href=/type/index_type_5-1.shtml>Статья</a>:" z~zhan
      split($9,aq,".")
      a32[jj]=aq[1]                               # текст, sizT - объём в килобайтах
      a33[jj]=aq[2]                     # текст, sizB - "1"==объёмOk, "0"=="доступ ... ограничен"
      if($12 in a0a){                # раздел в старом списке БЫЛ, оформляем "разницу"
        if(a0t[$12]==$15){                           #  id_T (текста-лидера) был в старом
          j0=aq[1]-a0z[$12]
          if(j0>0){
            upTx++                                # объём+ текста
            a04[jj]=" bgcolor="color[4]
            a05[jj]=" title=\"+"j0"k\""
          }else if(j0<0){
            dnTx++                                # объём- текста
            a04[jj]=" bgcolor="color[3]           #  3
            a05[jj]=" title=\""j0"k\""
          }
        }else{                                    # это новый текст того же автора
          nwTx++                                  # новый текст
          a04[jj]=" bgcolor="color[5]
          a05[jj]=" title=\"New\""
        }
#        a0t[aj[12]]=aj[15]                        # id_T (текста-лидера)
#        a0z[aj[12]]=aj[9]                         # объём текста
      }
      a40[jj]=unquot(unpack($17))                 # текст, jnrT - жанр(ы) (может отсутствовать)
# Жанр(ы)
    split(a40[jj],aq,":")                         # разделим форму и жано(ы)
    if(aq[2]=="") aq[2]="--"                      # два дефиса подряд смотрятся красивше (jnrT;)
    a40[jj]="<b>"aq[1]"</b>: "aq[2]
    } # else print(sprintf("%4s%4s",NR,$7),$12,$13,$15,$16)>"z.#"
  }else{
# /^;1aPre .+ hDat:20..\.(.+)\.(.+) hGap:([0-9]+)\..+ hPag:([0-9]+) .+ done:(20[\.0-9]+) /,aj)){
#     pDat=aj[2]"/"aj[1] # за дата
#     preH=aj[5]         # от дата
#     pPag=aj[4]                                    # страниц aHits
# /^;1aCur .+ hDat:20..\.(.+)\.(.+) hGap:([0-9]+)\..+ hPag:([0-9]+) .+ done:(20[\.0-9]+) /,aj)){
#     hDat=aj[2]"/"aj[1]
#     donH=aj[5]
#     hPag=aj[4]                                    # страниц aHits
#     hMax=aj[3]                                    # хиты раздела-лидера aHits
# /^;5H minL:([0-9]+) .+ txtM:([0-9]+) done:([\.0-9]+) /,aj)){
#     minL=sprintf("%2.1f",aj[1]/10)                # нижняя граница "успеха" в выборке
# /^;5G .+ done:([\.0-9]+)\//,aj)){
#     hold=aj[1]                                    # дата сборки "yyyy.MM.dd"

# ;1aPre hits 2:xNam 446:xNum 101267:xPas 2021.04.22:hDat 1018:hPag 801964:hMax 1009:pGet 2021.04.24:done gap1:14:43-15:04 
# ;1aCur hits 2:xNam 445:xNum 101285:xPas 2021.04.22:hDat 1018:hPag 806772:hMax 1018:DnLd 2021.04.27:done 25:mins gapT~14:53-15:18~ 
# ;5G gapP 3:gapD 100:minL 758:gNum 2021.04.27:done 19:02
# ;5H gapT 100:minL 0:nulS 0:badS 0:nulP 0:badP 0:tNul 2:tBad 0:unAv 2:txtM 133:dnLd 2021.04.27:done 6:mins 20:10-20:16:gapT 
    if(match($0,/^;1aPre .+ 20..\.(.+)\.(.+):hDat /,aj))pDat=aj[2]"/"aj[1] #  pre дата aHits по СИ
    if(match($0,/^;1aPre .+ ([\.0-9]+):done /,aj))      preH=aj[1] #  дата "скачан" (aHits)
    if(match($0,/^;1aPre .+ ([0-9]+):hPag /,aj))        pPag=aj[1] #  страниц aHits
    if(match($0,/^;1aCur .+ 20..\.(.+)\.(.+):hDat /,aj))hDat=aj[2]"/"aj[1] # дата aHits по СИ
    if(match($0,/^;1aCur .+ ([\.0-9]+):done /,aj))      donH=aj[1] #  дата "скачан" (aHits)
    if(match($0,/^;1aCur .+ ([0-9]+):hPag /,aj))        hPag=aj[1] #  страниц aHits
    if(match($0,/^;1aCur .+ ([0-9]+):hMax /,aj))        hMax=aj[1] #  хиты раздела-лидера aHits
#     if(match($0,/^;5G .+ ([0-9]+):minL /  ,aj))         minL=sprintf("%2.1f",aj[1]/10) #  minLuckP
    if(match($0,/^;5H .+ ([\.0-9]+):done /,aj))         hold=aj[1] #  дата "расчёт"
    ancD=substr(hold,3,2) substr(hold,6,2) substr(hold,9,2) # дата сборки "yyMMdd"
  }
}

function dat_str(d0,d2) {       # "2020.05.23" -> "23 мая" (d2==nul) or "23 мая 2020 г." (d2!=nul)
  d1=split(d0,ad,".")
  if(!d2)return("<b>"ad[3]+0" "nMth[ad[2]+0]"</b>")
  else   return("<b>"ad[3]+0" "nMth[ad[2]+0]"</b> "ad[1]" г.")
}

function rusDat(s0) {                             # 2019.19.25 -> 25.19.2019
  split(s0,aq,".")
  return(aq[3]"."aq[2]"."aq[1])
}

function unpack(j1) {               # восстановление литерала, свёрнутого при сборе сведений с СИ
  if (substr(j1,1,1)=="\"") j1=substr(j1,2,length(j1)-2)  # откусим обрамляющие двойные кавычки
  j2=""                                           # "•" -> пробел
  while(n=index(j1,"•")) { j2 = j2 substr( j1, 1, n-1 ) " "; j1 = substr( j1, n+1 ) }
  j1=j2 j1
  j2=""                                           # "”" -> двойные кавычки
  while(n=index(j1,"”")) { j2 = j2 substr( j1, 1, n-1 ) "&quot;"; j1 = substr( j1, n+1 ) }
  j1=j2 j1
  return( j1 )
}

function unquot(j1) {       # восстановление литерала "жанр(ы), свёрнутого при сборе сведений с СИ
  j2=""                                           # '&quot;' -> '"'
  while(n=index(j1,"&quot;")) { j2 = j2 substr( j1, 1, n-1 ) "\""; j1 = substr( j1, n+6 ) }
  j1=j2 j1
  return( j1 )
}

END{                            # данные загружены и разобраны, оформляем рейтинг и приложения...
  if(!(1 in ARGV)){
    print "NO input file!"                        # защита от случайного пуска
    exit -1
  }
  if(hold=="") {
    print "NO date to bind siTopAuthors"
    exit -1
  }
#   if(pDat==-1)aVar["pDat"]=1                      #  pre дата aHits по СИ
#   if(preH==-1)aVar["preH"]=1                      #  pre дата "скачан" (aHits)
#   if(pPag==-1)aVar["pPag"]=1                      #  pre страниц aHits
#   if(hDat==-1)aVar["hDat"]=1                      #  дата aHits по СИ
#   if(donH==-1)aVar["donH"]=1                      #  дата "скачан" (aHits)
#   if(hPag==-1)aVar["hPag"]=1                      #  страниц aHits
#   if(hMax==-1)aVar["hMax"]=1                      #  хиты раздела-лидера aHits
#   if(minL==-1)aVar["minL"]=1                      #  минимальная "удача" раздела
#   if(hold==-1)aVar["hold"]=1                      #  дата "расчёт"
#   if(j0=length(aVar)){
#     tmp0="? no var(s):"
#     for(j1 in aVar)tmp0=tmp0" "j1
#     print(tmp0" in "FILENAME)
#     exit -1
#   }
# print("-*-")
  tMax=jj
  if(500-tMax>=0)tGap=50
  if(250-tMax>=0)tGap=25
  mkPage()

  print("<blockquote>")                   >fOut
  print(info)                             >fOut   #  служебная отметка (для порядку)
  if(nHnY)for(jj=1;jj<=nHnY;jj++)print(aHnY[jj])  >fOut
  for(jj=1;jj<=nHdr;jj++)print(aHdr[jj])  >fOut
  for(jj=1;jj<=nHd1;jj++)print(aHd1[jj])  >fOut
  for(jj=1;jj<=nTb1;jj++)print(aTb1[jj])  >fOut
  for(jj=1;jj<=nTbl;jj++)print(aTbl[jj])  >fOut
  print(Ttl1)                             >fOut
  for(jj=1;jj<=nOut;jj++)print(aOut[jj])  >fOut
  print(info)                             >fOut   #  служебная отметка (для порядку)
  printf("%s","</blockquote>")            >fOut

  print("<blockquote>")                   >fPre
  print(inf2)                             >fPre
  if(nHnY)for(jj=1;jj<=nHnY;jj++)print(aHnY[jj])  >fPre
  for(jj=1;jj<=nHdr;jj++)print(aHdr[jj])  >fPre
  for(jj=1;jj<=nHd2;jj++)print(aHd2[jj])  >fPre
  for(jj=1;jj<=nTb2;jj++)print(aTb2[jj])  >fPre
  for(jj=1;jj<=nTbl;jj++)print(aTbl[jj])  >fPre
  print(Ttl2)                             >fPre
  for(jj=1;jj<=nOut;jj++)print(aOut[jj])  >fPre
  print(inf2)                             >fPre
  printf("%s","</blockquote>")            >fPre

  endS=mktime(substr(hold,1,4)" "substr(hold,6,2)" "substr(hold,9,2)" 00 00 00")  # seconds "до"
  print "--- " strftime("%H:%M:%S") " Ends..."  # закончили работу (оживляж;)
# 2020.11.29, nvv, creation by siTop-fHtml.awk (2020.11.18)
# 2020.12.03, nvv, it works! (off line, alas)
# 2021.01.11, nvv, it works ok... ;) пока без опорного предыдущего списка
# 2021.01.29, nvv, всё запланированное обустроено, включая 2 и более лидеров в разделе ("‡")
# 2021.02.06, nvv, отключена отладочная выдача в "z.#" отвергнуты записей с низкими хитами
#   + уточнен сбор данных по призёрам предыдущего приложения (именно его призёры,
#     но не присутствовавшие лишь в прошлом ОБЩЕМ списке)
# 2021.03.11, nvv, мелкая неточность вычленения даты предыдущего списка + косметика
# 2021.03.21, nvv, new text color+title added
# 2021.04.24, nvv, new text color+title off
# 2021.06.10, nvv, мелкая косметика
# 2021.07.09, nvv, исправлена неточность в маркировке цветом текстов-лидеров
# 2022.01.13, nvv, исправлена неточность в выявлении новогоднего периода
# 2022.06.07, nvv, мелочёвка
# 2022.10.19, nvv, в шапку добавлена ссылка на текст: "Регистрация в СИ""
# 2022.12.01, nvv, текст: "Регистрация в СИ" перестал быть New
# 2023.07.08, nvv, добавоена поддержка скрытых разделов место "0" /numP/ в рейтинге по хитам
# + хоть это и приложение к siTopTexts, но таки тоже рейтинг, что теперь явно сказано в заголовке
# 2023.08.02, nvv, убран анонс скрытых разделов
# 2024.03.09, nvv, изменился рисунок работы СИ - изменено оформление шапки siTopAuthors
# 2024.02.07, nvv, добавлена отметка "Upd" для: "Исходные тексты скриптов"
# 2024.08.19, nvv, """ -> "&#xB7;"
}

    Имя файла скрипта: "iNetR.cmd" V-текст скрипта-V
- - - - - - - - -
@if not defined nJob @echo off
echo %date% %time:~0,8% %~nx0 Begs
:: iNetR.cmd - оформление в HTML списка топовых разделов прошедшего цикла обновления статистик
:: + 20??.??.??.*.gAuth (like 2021.05.19.6.gAuth) - оформляемый последний список
:: + 20??.??.??.*.gAuth (like 2021.05.14.3.gAuth) - оформляемый ПРЕД последний список

:: проверить-найти:
:: - свежий *.gAuth, например: 2021.04.27.4.gAuth
:: - старый *.gAuth, например: 2021.04.24.3.gAuth
:: - свежий *.gAuth.html, например: 2021.04.27.4.gAuth.html
:: - старый *.gAuth.html, например: 2021.04.24.3.z.gAuth.html


:: 2021.05.29, nvv, creation на основе fHtml.cmd от 2021.05.25
:: 2021.06.13, nvv, confirmation to move PREV data off
set nJob=iNetR
if NOT defined jDat set jDat=%date%
set ok2upDt=%1
set aHtm=%~dp0%nJob%.awk
::  wDir - общее рабочее место
set wDir=%~d0\Jobs
::  sDir - общее складское хранилище
set sDir=%~d0\Stor
::  dDir - склад для уже ненужных списков 20??.??.??.gAuth
set dDir=%sDir%\Text\zOld.gAuths
if NOT exist %dDir% set errInf=NO %dDir% found & goto nExit
::  hDir - склад под выходные файлы с таблицами *.html
set hDir=%sDir%\Html
set pDir=%hDir%\gAuths
if NOT exist %hDir%\ mkDir %hDir%
if errorLevel 1 set errInf=fail mkDir %hDir% & goto nExit

::  fOld - прошлый опорный список для "siTopTexts"
set fOld=
::  fCur - свежий список для "siTopTexts" - 1k популярных текстов (со всеми атрибутами)
set fCur=
for %%A in (%wDir%\20??.??.??.*.gAuth) do call :findCurOld %%A
if NOT defined fOld set errInf=!? NO old 20*.gAuth found & goto nExit
if defined errInf goto nExit

set fHtm=%hDir%\%dCur%.%gCur%.gAuth.html
echo prev:%fOld%
echo curr:%fCur%
echo fHtm:%fHtm%
if NOT exist %fHtm% goto mkHtm

:: итоговый файл есть. если нужно прибрать - идём прибирать, иначе выясняем...
if defined ok2upDt goto upDt

:: запрос (конечный HTML уже есть!)
set tmp0=
echo fHtm found; reBuild it? [yes] == y
set /p tmp0=?[no]?
if /i NOT %tmp0%. == y. (
  echo job canceled {NO to reBuild}
  exit
)
:mkHtm собственно оформлялка ("от и до";)
gawk.exe -f %aHtm% %fCur%
if errorLevel 1 set errInf=!!! X someThing's wrong with %~n0.awk & goto nExit
:: блокируется оптичивание преобразованного в HTML
goto nExit

:upDt  запрос (точно ненада?)
set tmp0=
echo confirm PREV data OFF? [yes] == y
set /p tmp0=?[no]?
if /i NOT %tmp0%. == y. (
  echo job canceled {NO to reBuild}
  exit
)
:: уберём уже ненужный старый список рейтинга на склад Text\zOld.gAuths
if exist %fOld% (
echo move %fOld% to %dDir%
move /Y %fOld% %dDir%
if errorLevel 1 set errInf=!! fail to move old *.gAuth to %dDir% & goto nExit
)
:: опубликованный %dCur%.gAuth.html (убрать)
set tmp0=%hDir%\%dCur%.%gCur%.gAuth.html
if exist %tmp0% (
echo move %tmp0% to %pDir%
move /Y %tmp0% %pDir%
if errorLevel 1 set errInf=!! fail to move %tmp0% to %pDir% & goto nExit
)
:: опубликованный %dOld%.%gOld%.gAuth.z.html ("предыдущее" удалить)
set tmp0=%hDir%\%dOld%.%gOld%.gAuth.z.html
if exist %tmp0% (
echo erase %tmp0%
erase %tmp0%
if errorLevel 1 set errInf=!! fail to erase %tmp0% & goto nExit
)

:nExit
if defined errInf (
  echo ! %errInf%
  set errInf=
)
echo %date% %time:~0,8% Job:%nJob% Ends
goto :eof

:findCurOld ::  dOld dCur - даты в именах файлов опорного и текущего списков
if defined fOld if defined fCur set errInf=too many *.gAuth files in %wDir% & goto :eof
set fOld=%fCur%
set gOld=%gCur%
set dOld=%dCur%
set fCur=%1
set dCur=%~n1
set gCur=%dCur:~11%
set dCur=%dCur:~0,10%
goto :eof

    Имя файла скрипта: "zChk.cmd" V-текст скрипта-V
- - - - - - - - -
@if NOT defined pJob echo off
::  nJob - ID процесса и связанных с оным файлов
set nJob=zChk
::  itog - непустой == файл для загрузки в me по успеху
set itog=
echo %date% %time:~0,8% %nJob% Begs
:: zChk.cmd - утренние основные проверки ситуации в СИ
:: проверяется:
:: 1j - вчерашний расчёт прибран? нет == выход
:: 0j - доступ: zhurnal.lib samlib budclub /siUrl - последний ОК/
:: 2j + свежая статистика nvv: есть - выход /на сегодня всё сделано/
:: 3j + свежий /за вчера/ лог СИ: есть - запрос статистик
:: 4j + свежая отметка в протокол: доступ к СИ: есть - скачивание логов/статистик
:: 5j + проверка статуса: inSpam и inBan -} отметка в протокол
:: 6j -+ после 07:05 проверячется наличие локально вчерашнего лога /нет - скачивается/
:: 7j --+ ожидание появления статистики Tony z/zhan

:: ! с любым параметром скачивается на скорость 30MB с этих сайтов и ВЫХОД

:: 2024.08.09, nvv, zIniChk.cmd - zChk.cmd + работа в пакетном режиме
:: прочая история - в подвале

:: 0j А не забыл ли я обиходить прошедщий намедни расчёт?
call :chkOld
set jDat=%date%
::  jDay - день месяца "сегодня"
set jDay=%jDat:~-2%
set errInf=
set wGetSiz=1

:: 0j - доступ: zhurnal.lib samlib budclub /siUrl - последний ОК/
set wDir=\Jobs\
if NOT exist %wDir%*.* (
  mkDir %wDir%
  if errorLevel 1 echo fail mkDir %wDir% & exit
)
::  wFil - рабочаа времянка
set wFil=%wDir%%nJob%.tmp
::  xMin - пауза между проверками обновления статистики Tony z/zhan
set xMin=5
::  siUrl - рабочий из zhurnal.lib, samlib или budclub
set siUrl=
rem i/iw        ... примерно 30Mb статистики
rem n/nosow_w_w ... примерно 50kb статистики
set urlT=n/nosow_w_w
if NOT %1. == . set urlT=i/iw
set wLin=
set siNum=0
echo %time:~0,8%~%jDat% si Urls Checks...
call :chkRate zhurnal.lib %urlT%
if defined urlW set siUrl=%urlW%
call :chkRate samlib      %urlT%
if defined urlW set siUrl=%urlW%
call :chkRate budclub     %urlT%
if defined urlW set siUrl=%urlW%
set wLin=%time:~0,8%%wLin%
if NOT %1. == . exit
:: нет доступа ни к одноу сайту СИ
if NOT defined siUrl set errInf=NO siUrls available & exit
echo siUrl=%siUrl%

:: 2j nDir - склад для накопления nvv.stats /должен быть/
set nDir=\Stor\nvv\
if NOT exist %nDir%*.* (
  mkDir %nDir%
  if errorLevel 1 echo fail mkDir %nDir% & exit
)
::  nSuf - файл статистики nvv /общая часть/
set nSuf=n~nosow_w_w.stat.htm
::  nFil - последний наличный файл статистики nvv
::  nDat - дата -^- в формате "YYYY.mm.dd" /like: "2022.08.03"/
set nDat=
for %%A in (%nDir%*.%nSuf%) do (
  set nFil=%%A
  set nDat=%%~tA
)
if NOT defined nDat goto doLogChk
set nDat=%nDat:~0,10%
:: и обрадуем наблюдателя касаемо
if %nDat% == %jDat% (
  echo nvv.stat now: %nDat%
  goto :eof
)
echo nvv.stat old: %nDat%

:doLogChk 3j логи СИ вычислим год, месяц и день для "вчера"
for /F "tokens=1-9*" %%A in (
  'gawk "BEGIN{print(strftime(\"%%Y %%m %%d\",systime()-86400));exit}"'
) do (set Year=%%A&set Mnth=%%B&set mDay=%%C)
:: логи СИ группируютя по годам в отдельные папки
set lDir=Q:\#-Logs\%Year%\
if NOT exist %lDir%*.* (
  mkDir %lDir%
  if errorLevel 1 echo fail mkDir %lDir% & exit
)
set lFil=%lDir%%Mnth%-%mDay%.log
:: если этот лог уже у нас - значит осталась только статистика
if exist %lFil% (
  echo. == ok %lFil%
  goto doStats
)

:: 4j рабочвя папка, свежая отметка в протокол: доступ к СИ: есть - скачивание логов/статистик
::  logI - лог проверок IP
set logI=%wDir%%nJob%.log
::  logD - дата лога проверок IP - для организации в одну строку всех записей за день
set logD=
for %%A in (%logI%) do set logD=%%~tA
if NOT  defined   logD        goto doIpChk
if NOT %jDat% == %logD:~0,10% goto doIpChk
echo. == ok %lFil%
goto iniChkDon

:doIpChk 5j + проверка статуса: inSpam и inBan -} отметка в протокол
rem батник для проверки своего статуса "спамер"/"забанен" в СИ:
rem ::: http://budclub.ru/cgi-bin/ip_ban_check
rem окультуренный итог выдаётся на экран и в одноимённый лог рядом с батником
:: 2024.08.09~07:39 myIp:109.110.47.111 - NO.inSpam - NO.inBan  224_KB/s_zhurnal.lib 238_KB/s_samlib 237_KB/s_budclub
set tmp0=0
set IpErr=0
for /F "tokens=*" %%J in (
  ' wGet -q http://%siUrl%/cgi-bin/ip_ban_check -O- '
) do call :getLn %%J
if errorLevel 1 echo wGet: %siUrl% ERR %errorLevel% & exit
set tmp0=%time:~0,5%
if %tmp0:~0,1%. == . set tmp0=0%tmp0:~1%
set tmp0=%date%~%tmp0% myIp:%myIp%
echo %tmp0% IpErr.%IpErr%
gAwk.exe "BEGIN{printf(\"%tmp0% %wLin:~8%\n\");exit}" >>        %logI%
rem echo %date%~%tmp0% myIp:%myIp% >> %logI%
if %IpErr%. == 0. goto iniChkDon
:: у нас проблемы... Таки продолжим?
set tmp0=
echo my IP in troubles, ignore them? [yes] == y
set /p tmp0=?[no]?
if /i NOT %tmp0%. == y. (
  echo job canceled
  exit
)

:: 6j -+ после 07:05 проверячется наличие локально вчерашнего лога /нет - скачивается/
:: 7j --+ ожидание появления статистики Tony z/zhan

:iniChkDon  tBeg - граница ожидания {+ 0..5 секунды} ДО {в п/п waitTill в формате "чч:мм"}
set tBeg=07:05
call :waitTill %jDat%~%tBeg%
:: вчерашний лог в СИ
set wUrl=%siUrl%/logs/%Year%/%Mnth%-%mDay%.log
:: оживляж
echo. ? req %Year%/%Mnth%-%mDay%.log
call wGetUrl2fil.cmd %wUrl% %lFil% >nul
if defined errInf goto nExit
if %wGetSiz% == 0 (
  erase %lFil%
  set errInf=ZERO-size: %lFil%
  goto nExit
)
:: ну и дату лога вструмить след: touch.exe -t YYYYmmdd1200 "fNam"
touch.exe -t %Year%%Mnth%%mDay%1200 %lFil%

:doStats утренниние проверки оптичены, ждём обновления статистики Tony
set wUrl=http://%siUrl%/z/zhan/stat.shtml
:again
if exist %wFil% erase %wFil%
wGet.exe %wUrl% -t2 -O%wFil% > nul 2>&1
if NOT %errorLevel% == 0 set errInf=NO web now & goto nExit
call :getStatDay %wFil%
if defined errInf goto nExit
if %wDay% == %jDay% goto zhanOk
if %time:~1,5% GEQ 7:50 set xMin=1
rem echo.%time:~1,5% now.%jDay% Tony.%wDay% xMin.%xMin%
call :waitMins %xMin%
goto again

:zhanOk теперь статистика nvv...
echo now.%jDay% Tony.%wDay% stat upDated
:: если сегодняшняя статистика nvv уже у нас, завершаем...
if %nDat% == %jDat% goto nvvOK
set wUrl=http://%siUrl%/n/nosow_w_w/stat.shtml
if exist %wFil% erase %wFil%
wGet.exe %wUrl% -t2 -O%wFil% > nul 2>&1
if NOT %errorLevel% == 0 set errInf=NO web now & goto nExit
call :getStatDay %wFil%
if defined errInf goto nExit
if NOT %wDay% == %jDay% set errInf=NO toDay's nvvStat & goto nExit
set nFil=%nDir%%jDat%.%nSuf%
copy /b %wFil% %nFil% >nul
if NOT %errorLevel% == 0 set errInf=fail copy %wFil% %nFil%& goto nExit

:nvvOK
echo nvv.stat OK

:nExit
if defined errInf echo %errInf%
goto :eof

:getStatDay stat2check
rem  <li><i>Статистика рассчитывается раз в сутки. (Thu May 18 02:05:32 2023)</i>
set wDay=
for /F "tokens=1-9,*" %%A in (
'gawk.exe "{if(match($0,/<li><i>.+\. \(... (...) (..) ..:..:.. (20..)\)<\/i>/,a)){print(a[3],a[1],a[2]);exit}}" %1'
) do set wDay=%%C
if NOT defined wDay set errInf=BAD stat: %1 & goto :eof
if %wDay% LEQ 9 set wDay=0%wDay%
goto :eof

:getLn %%J
set /a tmp0+=1
set tmp1=%6
set tmp1=%tmp1:~1%
if %tmp0% == 1 set myIp=%3
if %tmp0% == 2 (
  if '%tmp1%' == 'not' (
    set myIp=%myIp% - NO.inSpam
  ) else (
    set myIp=%myIp% ! IS.inSpam
    set /a IpErr+=1
  )
)
if %tmp0% == 3 (
  if '%2' == 'эх' (
    set myIp=%myIp% - NO.inBan
  ) else (
    set myIp=%myIp% ! IS.inBan
    set /a IpErr+=2
  )
)
goto :eof
rem 15:37:12   55_zhurnal.lib   58_samlib   56_budclub
:chkRate siUrl id_P п/п определения времени скачивания i/iw.stat.shtml в зависимости о урл-а
:: страница для тестового скачивания -
set /a siNum+=1
gawk.exe "BEGIN{printf(\"check-%siNum%... \");exit}"
set wUrl=http://%1.ru/%2/stat.shtml
wGet.exe %wUrl% -O- -t2 -o%wFil% >nul
if NOT %errorLevel% == 0 goto errU
:: всё ОК, вычленим время скачивания
set urlW=
for /F "tokens=*" %%J in (
' gAwk.exe "{if(match($0,/ \(([0-9]+) (.+)\)/,a))print(a[1]\"_\"a[2])}" %wFil% '
) do set urlW=%%J
erase %wFil%
:: годный домен
echo %urlW% %1
:: для отчёта
set wLin=%wLin% %urlW%_%1
set urlW=%1.ru
goto :eof
:errU скачивание провалилось, уберём за собой
if exist %wFil% erase %wFil%
set urlW=       -_%1
set wLin=%wLin% -_%1
echo %urlW%
set urlW=
goto :eof


:chkOld А не забыл ли я обиходить прошедщий намедни расчёт?
set jClA=0
set jClT=0
:: должно быть
for %%A in (U:\Jobs\20??.??.??.dText) do set /a jClT=1
for %%A in (U:\Jobs\20??.??.??.*.gAuth) do set /a jClA+=1
if %jClT%%jClA% == 11 goto :eof
echo dText.%jClT% gAuth.%jClA% exit
exit

======= комплект п/п для обустройства заданных ожиданий в CMD
:waitMins minutes [с новой строки] ожидание заданное число минут
if NOT %2. == . echo.
:: jSec - UNIX-секунд в момент ВЫЗОВА п/п
:: tics - UNIX-секунд до момента ЗАВЕРШЕНИЯ ожидания: tics-jSec - время нашего ожидания
:: jTim - этот момент -^- в формате "HH:MM:SS"
for /F "tokens=1-9,*" %%W in (
  ' gawk.exe "BEGIN{t=systime();b=%1*60+t;print(t,b,strftime(\"%%H:%%M:%%S\",b-t,1));exit}"'
) do (
  set jSec=%%W
  set tics=%%X
  set jTim=%%Y
)
if %tics% == -1 echo %~nx0, bad [%1] {%waitTill%} for sub:waitTill
:: а ждать-то может и поздно уже?...
if %jSec% GEQ %tics% goto :eof
:: нет, обрадуем и побежали ждать
gawk.exe "BEGIN{print(\"now.%jDay% Tony.%wDay% xMin.%xMin% -- waiting \"strftime(\"%%M:%%S\",%tics%-systime(),1)\" unTill\",strftime(\"%%H:%%M:%%S\",%tics%));exit}"
:: ждём, известив о waitTill
set curM=0
goto sleep6

:: ждать ДО.123456789.123456789.
:waitTill  гггг.мм.дд~чч:мм [с новой строки] с оживляжем до заданного момента /%1 == /
if NOT %2. == . echo.
set curM=%1
::  waitTill -  этого момента  2024.03.10~15:57
set waitTill=%curM:~0,4% %curM:~5,2% %curM:~8,2% %curM:~11,2% %curM:~14,2% 00
for /F "tokens=1-9,*" %%W in (
  ' gawk.exe "BEGIN{t=systime();b=mktime(\"%waitTill%\");print(t,b,strftime(\"%%H:%%M:%%S\",b-t,1));exit}"'
) do (
  set jSec=%%W
  set tics=%%X
  set jTim=%%Y
)
if %tics% == -1 echo %~nx0, bad [%1] {%waitTill%} for sub:waitTill
:: а ждать-то может и поздно уже?...
if %jSec% GEQ %tics% goto :eof
:: нет, обрадуем и побежали ждать
gawk.exe "BEGIN{print(\" -- waiting \"strftime(\"%%M:%%S\",%tics%-systime(),1)\" unTill\",strftime(\"%%H:%%M:%%S\",%tics%));exit}"
:: ждём, известив о waitTill
set curM=0
goto sleep6

:ticShow оживляж - это наше всё
gawk.exe "BEGIN{if(%curM%==%preM%){printf(\".\")}else{printf(%curM%)}exit}"
:: строка терминируется 10-й минутой /"0"/
if %curM% == 0 if NOT %curM% == %preM% echo. %curT%
:: проверка истечения заданного срока; "да"==вЫход
if %curS% GEQ %tics% echo. %curT% & goto :eof
:sleep6  шаг задержки - 6 секунд
sleep 6
:: рабочая фиксация очередного момента
call :ticSet
goto ticShow

:ticSet запомним старое значение момента времени относительно начального /jSec/
set preM=%curM%
for /f "tokens=1-9,*" %%P in (
  ' gawk.exe "BEGIN{t=systime();print(t,strftime(\"%%H:%%M:%%S %%M\",t-%jSec%,1));exit}" '
) do (
  set curS=%%P
  set curT=%%Q
  set curM=%%R
)
set curT=+%curT:~1%
:: и текущее /новое/ значение минут /последняя цифра/
set curM=%curM:~1%
goto :eof

:: 2024.03.17, nvv, созданно на основе zSchk.cmd и siLogs.cmd
:: 2024.03.21, nvv, до 07:50 пауза 5 минут в проверке обновления z/zhan, после - 1 минута
:: 2024.04.06, nvv, в конце - тестовое скачивание 30 Mb /скорость канала/
:: 2024.04.20, nvv, существенное улучшение логики и интерфейса
:: 2024.05.22, nvv, улучшение вида записей в логе: все записи задень в одной строке этого дня
::   + под занавес /после запуска показа статистики nvv/ тестируется скорость скачивания 30 mb
:: 2024.06.10, nvv, мелкая прака интерфейса
:: 2024.06.19, nvv, уточнена реакция на проблемы с доступом к домену /budclub, в частности/
:: 2024.08.01, nvv, скачивание большого файла только по параметру при запуске

    Имя файла скрипта: "wGetUrl2fil.cmd" V-текст скрипта-V
- - - - - - - - -
@if not defined nJob @echo off
:: установленная переменная nJob (вызов из "моего" батника) блокирует команду echo off
set nReV=2.23, 2024.03.07
if NOT %2.==. goto nStart
:nHelp
echo CmdName: %~nx0 (wGetUrl2fil.cmd)
echo Usage: . %~nx0 iNetUrl_to_downLoad File_for_DL-ed [cmdLog]
echo Example: %~nx0 %siUrl%/n/nosow_w_w n-nosow_w_w.idx.html
echo Example: %~nx0 %siUrl%/ siTitle.idx.html my.log
echo Created: 2018.09.19
echo Author : NVV (Vladislav Nosov)
echo nReV:    %nReV%
echo.
echo Description: ФУНКЦИЯ скачивания файла из интернета в локальный файл
echo   Третий, НЕобязательный ключ задаёт лог +режим отладки для wGet.exe
echo   ^^-без, - режим "всё молча" (для всего)
echo.
echo NB#1. ! В месте размещения юзается времянка %~n0.tmp
echo NB#2. В %%wGetErr%% код ошибки: 0==Ок, 1==no_DL_файла, 3==NO_СИ
echo     + В %%wGetSiz%% - размер DL_файла (File_for_DL) == 0, если оного нет
echo.
echo При возникновении проблемы выставляется ErrorLevel 1,
echo описание проблемы помещается в переменную среды %%errInf%%
echo.
set errInf=It's HELP (params: %*)

:nErrExit
set errInf=! Error in %~nx0:%errInf%
if NOT defined nJob echo %errInf%
exit /b 1

2019.01.14 11:03, nvv, оптимизация алгоритма; по мелочам, но много где...
2019.11.29, nvv, samlib.ru budclub.ru - основной и альтернативный адреса "Самиздата"
2020.01.06, nvv, in errInf "iNet unavailable" reqURL added
2020.03.22, nvv, вместо титула моего раздела проверяется доступность логов СИ (/logs/)
2020.11.13, nvv, будКлуб - глупость
2021.04.27, nvv, ^-не факт + добавлен инкремент внешнего счётчика DnLd при успехе
2021.05.09, nvv, инкремент по-любому (если без ошибок) отсутствие файла по адресу - не ошибка!
2023.06.03, nvv, обустроена работа с wGetErr /см. nHelp/
2024.03.03, nvv, новации в СИ: урл "%siUrl%/logs" ДОЛЖЕН иметь "/" в конце, иначе НЕТУ!
  + аварийное сообщение выдаётся при вызове НЕ из CMD /пуста переменная nJob/
2024.03.07, nvv, добавлен ключ --no-cache
2024.06.16, nvv, добавлен ключ -t2 - до двух попыток попробовать при проблеме

:nStart
if NOT defined siUrl set siUrl=samlib.ru
if NOT defined wKey set wKey=-U "Mozilla/5.0" --no-cache -t2
if NOT defined wTim0 set wTim0=%time%
if NOT defined wTim2 set wTim2=%time%
set wGetLog=%3
if defined wGetLog echo {sub} %~nx0 [%*]
:: если заказанное уже у нас, пропускаем (с отметкой)
if NOT exist %2 goto wait0
for %%W in (%2) do set wGetSiz=%%~zW
if defined wGetLog echo == Ok, done already, size=%wGetSiz%
goto :eof

:wait0
set errInf=wGet.exe -q %wKey% %1 -O %2
if defined wGetLog (
  set errInf=wGet.exe %wKey% -d %1 -O %2 -a %3
  echo ? %errInf%
)
:wait1 организация паузы (секунда) на запрос к СИ
if "%wTim0%" GTR "%time%" goto gogo1
if "%wTim2%" GTR "%time%" goto wait1
:gogo1
call :wTim1sec "взвести таймер"
:: собственно скачивание заказанного...
%errInf%
set wGetErr=%errorLevel%
for %%W in (%2) do set wGetSiz=%%~zW
if defined wGetLog echo ~~~ wGetErr=%wGetErr%, size=%wGetSiz%
if %wGetErr% GTR 0 goto chkSi
set errInf=
rem set wGetErr=
:: увеличим счётчик фактов скачиваний
set /a DnLd+=1
goto :eof

коды, которые возвращает wget и пояснения к ним.
0 - ошибок нет
1 - ошибка кода общего характера (generic error code)
2 - ошибка разрбора (parse error) при аналие опций командной строки и/или .wgetrc или .netrc
3 - ошибка файлового ввода/вывода
4 - ошибка сети
5 - ошибка проверки SSL
6 - ошибка аутентификации (неверное имя или пароль)
7 - ошибка протокола
8 - сервер при ответе выдал какую-либо ошибку

:chkSi какие-то проблемы..., а Самиздат-то жив?
set errInf=wGet.exe %wKey% -q %siUrl%/logs/ -O-
if defined wGetLog (
  echo ? %errInf% to- nul
  set errInf=wGet.exe %wKey% -d -a %3  %siUrl%/logs/  -O-
)
rem echo err.%wGetErr% %wGetLog% %errInf%
:wait2 организация паузы (секунда) на запрос к СИ
if "%wTim0%" GTR "%time%" goto gogo2
if "%wTim2%" GTR "%time%" goto wait2
:gogo2 скачать требуемое не удалось, глянем заведомо существующее
call :wTim1sec "взвести таймер"
%errInf% > nul
set wGetChk=%errorLevel%
if defined wGetLog echo ~~~ wGetChk=%wGetChk%
if %wGetChk% == 0 (
set errInf=
set wGetErr=1
if  defined wGetLog echo x is gone=%1 & goto :eof
if NOT defined nLob echo x is gone=%1
goto :eof
)
set wGetErr=3
if exist %2 erase %2
set errInf=%1 is unavailable now...
goto nErrExit

:wTim1sec {sub} взведение таймера на 1 секунду
:: time is like 13:18:24.21 !!! НЕ использовать на ГРАНИЦЕ суток!
set wTim0=%wTim2%
set wTim2=%time%
:: час требует доп.плясок, т.к. при часе <10 в %time% лидирует пробел, а НЕ ноль ("0")
set /a wHou=100+%wTim2:~0,2%
:: CMD чудит на числа с лидирующими нулями... ;(
set wMin=1%wTim2:~3,2%
set wSec=1%wTim2:~6,2%
set /a wSec+=1
if %wSec% GTR 159 (
set /a wSec-=60
set /a wMin+=1
)
if %wMin% GTR 159 (
set /a wMin-=60
set /a wHou+=1
)
:: для часа пробел -v- если <10 (в %time% лидирует пробел {" "}, а НЕ ноль {"0"})
if %wHou% LEQ 109 (set wHou= %wHou:~-1%) else (set wHou=%wHou:~-2%)
:: соберём время == текущий момент + 1 секунда
set wTim2=%wHou%:%wMin:~-2%:%wSec:~-2%%wTim2:~-3%
goto :eof


(copyleft 2024 /\/.\/.\/.)

 Ваша оценка:

Связаться с программистом сайта.

Новые книги авторов СИ, вышедшие из печати:
О.Болдырева "Крадуш. Чужие души" М.Николаев "Вторжение на Землю"

Как попасть в этoт список

Кожевенное мастерство | Сайт "Художники" | Доска об'явлений "Книги"