Полезные ссылки: Tutorial Videos
Обучающее видео (Tutorial Videos):
Добавлены комментарии в блоге.
В качестве движка используется gitalk.
Как его добавить в light-тему Hexo:
Создайте репозиторий для хранения Issues. Я создал с названием gitalk.
Создайте приложение в github: тынц.

Это приложение потом можно будет увидеть в списке Settings / Developer settings.
Сгенерируйте “секрет” (Generate a new client secret); запомните (запишите) его.
В light-теме Hexo в layout\_partial создайте файл gitalk_comment.ejs со следующим содержанием:
<div id="gitalk-container" style="margin: 30px;"></div> |
В layout\_partial\comment.ejs подключите gitalk_comment.ejs:
<% if (theme.comment_provider == "gitalk") { |
В _config.yml light-темы включите использование gitalk-комментариев:
comment_provider: gitalk |
В корневом _config.yml вашего блога выполните настройку gitalk:
# gitalk comment |
clientID - значение Client ID из настроек приложения, созданного на шаге 2.clientSecret - “секрет” (Client secret), созданный на шаге 3.repo - название репозитория (шаг 1).owner и admin - имя Вашего пользователя в Github.Если при установке соединения вылазит ошибка:
10:57 AM OpenSSL: error:0A00018E:SSL routines::ca md too weak |
, то нужно отредактировать настройки на вкладке ADVANCED: промотать до пункта Enable Custom Options, включить его и ввести в Custom Options:
tls-cipher "DEFAULT:@SECLEVEL=0" |
Я считаю, что поиск по блогу - “must-have feature”. К сожалению, в выбранной мною простенькой теме hexo-light поиска не предусмотрено. Поэтому, нужно либо использовать сервисы типа Гугл или Яндекс, либо автоматически создавать индексный файл (xml или json) каждый раз при перегенерации блога и реализовать поиск на клиенте с помощью javascript. Я решил идти по второму пути.
Для генерации индекса выбран плагин для hexo: hexo-generator-searchdb. Устанавливается он с помощью:
npm install hexo-generator-searchdb |
Конфигурирование делается в _config.yml блога:
search: |
Следующим шагом нужно создать страницу для поиска. Делается это так:
hexo new page "search" |
В source каталоге создастся подкаталог search и в нем index.md. Содержание надо сделать наподобие такого:
--- |
Я добавил layout search в тему hexo-theme-light-plus. title лучше оставить пустым, тогда в качестве заголовка страницы поиска будет использоваться локализованная строка “search”.
Скрипт для поиска лежит в js/local-search.js. Я его сделал на основе вот этого. Убрал “popup”. Сделал постраничный показ результатов поиска (по 10 на страницу). Настройки в самом local-search.js:
const CONFIG = { |
В общем, получилось так: поиск.
При обновлении MySQL Server на CentOS вылезла ошибка:
The GPG keys listed for the "MySQL 8.0 Community Server" repository are already installed but they are not correct for this package. |
Победить можно выполнив команду:
rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022 |
Гугл прислал письмо о том, что бесплатная версия G Suite прекратит работать с 1 июля 2022 года. И это послужило толчком для переезда блога с blogspot на другую платформу. После недолгих поисков подходящего движка для блога, я остановил свой выбор на Hexo (https://hexo.io).
Тему для блога я выбрал простенькую “light”, которую пришлось немного “допилить”. “Допиленная” тема получила название “light plus” и лежит тут: https://github.com/coolsoftware/hexo-theme-light-plus
В теме было сделано следующее:
Кроме работы над темой, пришлось разбираться с импортом записей из старого блога. Для миграции из blogger в hexo нашелся “hexo-migrator-blogger”. Однако, он сильно устарел, некоторые зависимости уже не устанавливаются. А кроме того, мне хотелось, чтобы сохранились все внешние ссылки на записи. Поэтому пришлось писать свой “мигратор”: https://github.com/coolsoftware/hexo-migrator-blogspot.
Чтобы сохранить ссылки на существующие посты нужно:
В новом блоге сделать такую же структуру записей, что была в старом, т.е. /<год>/<месяц>/<заголовок>. _config.yml:
permalink: :year/:month/:name/ |
Прописать mod_rewrite-правила (для Апача):
RewriteEngine on |
Генерация случайной строки (например, пароля) в nodejs в одну строку:
(function(length,charset){return [...Array(length)].reduce(x=>x+charset[Math.floor(Math.random()*charset.length)],'')})(16,'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'); |
Base64 -> hex (nodejs)
(function(b64){return Buffer.from(b64, 'base64').toString('hex');})('AQAB'); |
Base64url -> hex (nodejs)
(function(b64url){return Buffer.from(b64url.replaceAll(/[_-]/g, function(m){return '/+'['_-'.indexOf(m)];}), 'base64').toString('hex'); })('AQAB_A='); |
String -> Base64 (nodejs)
(function(s){return Buffer.from(s).toString('base64');})('test'); |
String -> Base64url (nodejs)
(function(s){return Buffer.from(s).toString('base64').replaceAll(/[+/=]/g,m=>'-_'['+/'.indexOf(m)]||'');})('test'); |
SHA-256 Digest (nodejs)
crypto.createHash('sha256').update('12345').digest().toString('hex'); |
Переименование файлов: “Сериал.Part-1.mkv” -> “Сериал.S01E01.mkv”, “Сериал.Part-2.mkv” -> “Сериал.S01E02.mkv” и т.д. (bash)
for i in *.mkv; do mv $i $(echo $i | sed 's/Part-\([0-9]\)/S01E0\1/'); done; |
ROT13 (“шифр Цезаря”)
(function(s){return s.split('').reduce((x,y) => x + ('nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM'['abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.indexOf(y)] || y), '')})('Test12345'); |
Base64 to Pascal array of bytes:
(function(b64){return Buffer.from(b64, 'base64').reduce((s,b,i)=>s+(i?(i%16==0?',\n':', '):'')+'$'+b.toString('16').padStart(2, '0'), '')})('AQAB'); |
Format hsk markdown table:
sed '1,/---/d' hsk.md | awk -v OFS="|" -F"|" "/^\| [0-9]/{for(i=3;i<NF;i++){gsub(/ /,\"\",$i);$i=\" [\"$i\"](https://bkrs.info/slovo.php?ch=\"$i\") \"} }{print}" > temp_hsk.txt |
Сгенерировать случайную перестановку целых чисел от 0 до (n-1):
(function(n){var a=Array.from({length:n},(_,i)=>i);for(var i=a.length-1;i>0;i--){var j=Math.floor(Math.random()*(i+1));[a[i],a[j]]=[a[j],a[i]];};return a})(5) |
Выбрать элементы массива a в соответствии с перестановкой p:
(function(a,p){return Array.from({length:p.length},(_,i)=>a[p[i]])})(a,p) |
Find the latest 100 modified files in a folder and its subfolders on Windows:
Get-ChildItem -Path . -Recurse | Where-Object { !$_.PSIsContainer } | Sort-Object LastWriteTime -Descending | Select-Object -First 100 Directory, Name, LastWriteTime |
Декодировать JWT:
(function(token){return JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString())})('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNzA4MzQ1MTIzLCJleHAiOjE3MDgzNTUxMjN9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c') |
===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru