installer: inline TUI, remove tools dir, remove installer_tui.sh
This commit is contained in:
+304
-4
@@ -6,10 +6,310 @@ INSTALLER_VERSION="2.0.1"
|
|||||||
REPO_OWNER="Dushnilin"
|
REPO_OWNER="Dushnilin"
|
||||||
REPO_NAME="tachyon"
|
REPO_NAME="tachyon"
|
||||||
|
|
||||||
# ─── Source TUI helpers (self-contained, no external deps) ───────────────────
|
# ─── TUI helpers (self-contained, no external deps) ─────────────────────────
|
||||||
_TUI_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}" 2>/dev/null)" && pwd)"
|
# POSIX-compatible, works with dash/bash/mksh on OpenWrt.
|
||||||
[ -f "$_TUI_DIR/installer_tui.sh" ] && . "$_TUI_DIR/installer_tui.sh"
|
# Degrades gracefully when TERM is dumb or stdout is not a terminal.
|
||||||
unset _TUI_DIR
|
|
||||||
|
# ─── Color detection ──────────────────────────────────────────────────────────
|
||||||
|
_tui_colors=0
|
||||||
|
if [ -t 1 ] 2>/dev/null; then
|
||||||
|
case "${TERM:-dumb}" in
|
||||||
|
dumb) _tui_colors=0 ;;
|
||||||
|
*) _tui_colors=1 ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$_tui_colors" -eq 1 ]; then
|
||||||
|
_c_reset='\033[0m'
|
||||||
|
_c_bold='\033[1m'
|
||||||
|
_c_dim='\033[2m'
|
||||||
|
_c_red='\033[31;1m'
|
||||||
|
_c_green='\033[32;1m'
|
||||||
|
_c_yellow='\033[33;1m'
|
||||||
|
_c_blue='\033[34;1m'
|
||||||
|
_c_cyan='\033[36;1m'
|
||||||
|
_c_magenta='\033[35;1m'
|
||||||
|
_c_white='\033[37;1m'
|
||||||
|
_c_bg_blue='\033[44m'
|
||||||
|
_c_bg_green='\033[42m'
|
||||||
|
_c_bg_red='\033[41m'
|
||||||
|
_c_bg_yellow='\033[43m'
|
||||||
|
_c_underline='\033[4m'
|
||||||
|
else
|
||||||
|
_c_reset=''
|
||||||
|
_c_bold=''
|
||||||
|
_c_dim=''
|
||||||
|
_c_red=''
|
||||||
|
_c_green=''
|
||||||
|
_c_yellow=''
|
||||||
|
_c_blue=''
|
||||||
|
_c_cyan=''
|
||||||
|
_c_magenta=''
|
||||||
|
_c_white=''
|
||||||
|
_c_bg_blue=''
|
||||||
|
_c_bg_green=''
|
||||||
|
_c_bg_red=''
|
||||||
|
_c_bg_yellow=''
|
||||||
|
_c_underline=''
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ─── Terminal width ──────────────────────────────────────────────────────────
|
||||||
|
_tui_width() {
|
||||||
|
if [ -t 1 ] 2>/dev/null && command -v stty >/dev/null 2>&1; then
|
||||||
|
w="$(stty size 2>/dev/null | awk '{print $2}')"
|
||||||
|
[ -n "$w" ] && [ "$w" -gt 0 ] 2>/dev/null && printf '%s' "$w" && return 0
|
||||||
|
fi
|
||||||
|
printf '72'
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─── Horizontal line ─────────────────────────────────────────────────────────
|
||||||
|
_tui_hline() {
|
||||||
|
_w="$(_tui_width)"
|
||||||
|
_char="${1:--}"
|
||||||
|
_i=0
|
||||||
|
while [ "$_i" -lt "$_w" ]; do
|
||||||
|
printf '%s' "$_char"
|
||||||
|
_i=$((_i + 1))
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─── Center text ──────────────────────────────────────────────────────────────
|
||||||
|
_tui_center() {
|
||||||
|
_text="$1"
|
||||||
|
_w="$(_tui_width)"
|
||||||
|
_len=${#_text}
|
||||||
|
_pad=$((_w - _len))
|
||||||
|
[ "$_pad" -lt 0 ] 2>/dev/null && _pad=0
|
||||||
|
_left=$((_pad / 2))
|
||||||
|
_right=$((_pad - _left))
|
||||||
|
_i=0
|
||||||
|
while [ "$_i" -lt "$_left" ]; do
|
||||||
|
printf ' '
|
||||||
|
_i=$((_i + 1))
|
||||||
|
done
|
||||||
|
printf '%s' "$_text"
|
||||||
|
_i=0
|
||||||
|
while [ "$_i" -lt "$_right" ]; do
|
||||||
|
printf ' '
|
||||||
|
_i=$((_i + 1))
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─── Pad/truncate to width ──────────────────────────────────────────────────
|
||||||
|
_tui_pad() {
|
||||||
|
_text="$1"
|
||||||
|
_target="${2:-0}"
|
||||||
|
_len=${#_text}
|
||||||
|
_i=$_len
|
||||||
|
while [ "$_i" -lt "$_target" ]; do
|
||||||
|
printf ' '
|
||||||
|
_i=$((_i + 1))
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─── Print banner ────────────────────────────────────────────────────────────
|
||||||
|
tui_banner() {
|
||||||
|
printf '\n'
|
||||||
|
printf ' %s%sTachyon Installer%s v%s%s\n' "$_c_cyan" "$_c_bold" "$_c_reset" "$_c_bold" "$INSTALLER_VERSION"
|
||||||
|
printf '%s\n' ""
|
||||||
|
printf '%s%s%s\n' "$_c_dim" "$(_tui_hline '─')" "$_c_reset"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─── Print step header ──────────────────────────────────────────────────────
|
||||||
|
tui_step() {
|
||||||
|
_step_no="$1"
|
||||||
|
_step_total="$2"
|
||||||
|
_step_text="$3"
|
||||||
|
_step_icon=""
|
||||||
|
|
||||||
|
printf '\n'
|
||||||
|
printf ' %s%s[ %s/%s ]%s %s%s%s\n' \
|
||||||
|
"$_c_blue" "$_c_bold" \
|
||||||
|
"$_step_no" "$_step_total" \
|
||||||
|
"$_c_reset" \
|
||||||
|
"$_c_bold" "$_step_text" "$_c_reset"
|
||||||
|
printf ' %s%s\n' "$_c_dim" "$(_tui_hline '·')"
|
||||||
|
printf '%s' "$_c_reset"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─── Success message ─────────────────────────────────────────────────────────
|
||||||
|
tui_ok() {
|
||||||
|
printf ' %s%s✓%s %s\n' "$_c_green" "$_c_bold" "$_c_reset" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─── Warning message ─────────────────────────────────────────────────────────
|
||||||
|
tui_warn() {
|
||||||
|
printf ' %s%s⚠%s %s%s\n' "$_c_yellow" "$_c_bold" "$_c_reset" "$1" "$_c_reset" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─── Error message ───────────────────────────────────────────────────────────
|
||||||
|
tui_err() {
|
||||||
|
printf ' %s%s✗%s %s%s\n' "$_c_red" "$_c_bold" "$_c_reset" "$1" "$_c_reset" >&2
|
||||||
|
printf ' %s%s Log: %s%s\n' "$_c_dim" "$_c_reset" "$LOG_FILE" "$_c_reset" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─── Info message ────────────────────────────────────────────────────────────
|
||||||
|
tui_info() {
|
||||||
|
printf ' %s▸%s %s\n' "$_c_cyan" "$_c_reset" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─── Download progress ───────────────────────────────────────────────────────
|
||||||
|
tui_download() {
|
||||||
|
_label="$1"
|
||||||
|
_attempt="${2:-1}"
|
||||||
|
_max="${3:-3}"
|
||||||
|
printf ' %s%s↓%s %s %s(%s/%s)%s\n' \
|
||||||
|
"$_c_cyan" "$_c_bold" "$_c_reset" \
|
||||||
|
"$_label" \
|
||||||
|
"$_c_dim" "$_attempt" "$_max" "$_c_reset"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─── Progress bar ────────────────────────────────────────────────────────────
|
||||||
|
tui_progress() {
|
||||||
|
_current="$1"
|
||||||
|
_total="$2"
|
||||||
|
_label="${3:-}"
|
||||||
|
_w=$((_tui_width() - 8))
|
||||||
|
[ "$_w" -lt 10 ] 2>/dev/null && _w=10
|
||||||
|
|
||||||
|
_pct=0
|
||||||
|
[ "$_total" -gt 0 ] 2>/dev/null && _pct=$((_current * 100 / _total))
|
||||||
|
|
||||||
|
_filled=$((_pct * _w / 100))
|
||||||
|
[ "$_filled" -gt "$_w" ] 2>/dev/null && _filled=$_w
|
||||||
|
_empty=$((_w - _filled))
|
||||||
|
|
||||||
|
printf '\r %s' "$_c_dim"
|
||||||
|
_i=0
|
||||||
|
while [ "$_i" -lt "$_filled" ]; do
|
||||||
|
printf '━'
|
||||||
|
_i=$((_i + 1))
|
||||||
|
done
|
||||||
|
_i=0
|
||||||
|
while [ "$_i" -lt "$_empty" ]; do
|
||||||
|
printf '─'
|
||||||
|
_i=$((_i + 1))
|
||||||
|
done
|
||||||
|
printf '%s' "$_c_reset"
|
||||||
|
printf ' %s%3d%%%s' "$_c_bold" "$_pct" "$_c_reset"
|
||||||
|
[ -n "$_label" ] && printf ' %s' "$_label"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─── Spinner (call in background, kill when done) ───────────────────────────
|
||||||
|
tui_spinner_start() {
|
||||||
|
_spinner_text="${1:-Working...}"
|
||||||
|
_spinner_chars='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'
|
||||||
|
_spinner_pid=""
|
||||||
|
|
||||||
|
# Only spin on real terminals
|
||||||
|
[ -t 1 ] 2>/dev/null || { printf ' %s\n' "$_spinner_text"; return 0; }
|
||||||
|
|
||||||
|
(
|
||||||
|
while true; do
|
||||||
|
for _ch in $_spinner_chars; do
|
||||||
|
printf '\r %s%s%s %s' "$_c_cyan" "$_ch" "$_c_reset" "$_spinner_text"
|
||||||
|
sleep 0.1 2>/dev/null || sleep 1
|
||||||
|
done
|
||||||
|
done
|
||||||
|
) &
|
||||||
|
_spinner_pid=$!
|
||||||
|
printf '%s' "$_spinner_pid"
|
||||||
|
}
|
||||||
|
|
||||||
|
tui_spinner_stop() {
|
||||||
|
_pid="$1"
|
||||||
|
_text="${2:-}"
|
||||||
|
if [ -n "$_pid" ] && kill -0 "$_pid" 2>/dev/null; then
|
||||||
|
kill "$_pid" 2>/dev/null
|
||||||
|
wait "$_pid" 2>/dev/null
|
||||||
|
fi
|
||||||
|
# Clear spinner line
|
||||||
|
printf '\r%s' "$(_tui_hline ' ')"
|
||||||
|
printf '\r'
|
||||||
|
[ -n "$_text" ] && tui_ok "$_text"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─── Boxed section ───────────────────────────────────────────────────────────
|
||||||
|
tui_box_start() {
|
||||||
|
_w="$(_tui_width)"
|
||||||
|
_w=$((_w - 4))
|
||||||
|
[ "$_w" -lt 10 ] 2>/dev/null && _w=10
|
||||||
|
printf '\n'
|
||||||
|
printf ' %s╔' "$_c_blue"
|
||||||
|
_i=0; while [ "$_i" -lt "$_w" ]; do printf '═'; _i=$((_i + 1)); done
|
||||||
|
printf '╗%s\n' "$_c_reset"
|
||||||
|
}
|
||||||
|
|
||||||
|
tui_box_line() {
|
||||||
|
_text="$1"
|
||||||
|
_w="$(_tui_width)"
|
||||||
|
_w=$((_w - 4))
|
||||||
|
_len=${#_text}
|
||||||
|
_pad=$((_w - _len - 2))
|
||||||
|
[ "$_pad" -lt 0 ] 2>/dev/null && _pad=0
|
||||||
|
printf ' %s║%s %s' "$_c_blue" "$_c_reset" "$_text"
|
||||||
|
_i=0; while [ "$_i" -lt "$_pad" ]; do printf ' '; _i=$((_i + 1)); done
|
||||||
|
printf '%s║%s\n' "$_c_blue" "$_c_reset"
|
||||||
|
}
|
||||||
|
|
||||||
|
tui_box_line_color() {
|
||||||
|
_text="$1"
|
||||||
|
_color="$2"
|
||||||
|
_w="$(_tui_width)"
|
||||||
|
_w=$((_w - 4))
|
||||||
|
_len=${#_text}
|
||||||
|
_pad=$((_w - _len - 2))
|
||||||
|
[ "$_pad" -lt 0 ] 2>/dev/null && _pad=0
|
||||||
|
printf ' %s║%s %s%s' "$_c_blue" "$_c_reset" "$_color" "$_text"
|
||||||
|
_i=0; while [ "$_i" -lt "$_pad" ]; do printf ' '; _i=$((_i + 1)); done
|
||||||
|
printf '%s║%s\n' "$_c_reset" "$_c_blue"
|
||||||
|
}
|
||||||
|
|
||||||
|
tui_box_end() {
|
||||||
|
_w="$(_tui_width)"
|
||||||
|
_w=$((_w - 4))
|
||||||
|
[ "$_w" -lt 10 ] 2>/dev/null && _w=10
|
||||||
|
printf ' %s╚' "$_c_blue"
|
||||||
|
_i=0; while [ "$_i" -lt "$_w" ]; do printf '═'; _i=$((_i + 1)); done
|
||||||
|
printf '╝%s\n' "$_c_reset"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─── Section divider ─────────────────────────────────────────────────────────
|
||||||
|
tui_divider() {
|
||||||
|
printf '\n %s%s%s\n' "$_c_dim" "$(_tui_hline '─')" "$_c_reset"
|
||||||
|
}
|
||||||
|
|
||||||
|
tui_box_divider() {
|
||||||
|
_w="$(_tui_width)"
|
||||||
|
_w=$((_w - 4))
|
||||||
|
[ "$_w" -lt 10 ] 2>/dev/null && _w=10
|
||||||
|
printf ' %s║%s' "$_c_blue" "$_c_reset"
|
||||||
|
_i=0; while [ "$_i" -lt "$_w" ]; do printf '─'; _i=$((_i + 1)); done
|
||||||
|
printf '%s║%s\n' "$_c_blue" "$_c_reset"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─── Interactive menu (returns choice) ──────────────────────────────────────
|
||||||
|
tui_menu() {
|
||||||
|
_prompt="$1"
|
||||||
|
shift
|
||||||
|
_options="$@"
|
||||||
|
|
||||||
|
printf '\n %s%s%s\n' "$_c_bold" "$_prompt" "$_c_reset"
|
||||||
|
_i=1
|
||||||
|
for _opt in $_options; do
|
||||||
|
printf ' %s%s)%s %s\n' "$_c_cyan" "$_c_bold" "$_c_reset" "$_opt"
|
||||||
|
_i=$((_i + 1))
|
||||||
|
done
|
||||||
|
printf '\n'
|
||||||
|
printf ' %s▸%s ' "$_c_cyan" "$_c_reset"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─── Confirmation prompt ────────────────────────────────────────────────────
|
||||||
|
tui_confirm() {
|
||||||
|
_prompt="$1"
|
||||||
|
printf ' %s%s?%s %s %s' "$_c_yellow" "$_c_bold" "$_c_reset" "$_prompt" "$_c_dim"
|
||||||
|
printf '(%s/%s)%s ' "y" "n" "$_c_reset"
|
||||||
|
}
|
||||||
|
|
||||||
REQUIRED_SPACE_KB=15360
|
REQUIRED_SPACE_KB=15360
|
||||||
CONNECT_TIMEOUT_SECONDS=15
|
CONNECT_TIMEOUT_SECONDS=15
|
||||||
|
|||||||
@@ -1,306 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# shellcheck shell=dash
|
|
||||||
# ─── TUI helpers for Tachyon installer ───────────────────────────────────────
|
|
||||||
# POSIX-compatible, works with dash/bash/mksh on OpenWrt.
|
|
||||||
# Degrades gracefully when TERM is dumb or stdout is not a terminal.
|
|
||||||
|
|
||||||
# ─── Color detection ──────────────────────────────────────────────────────────
|
|
||||||
_tui_colors=0
|
|
||||||
if [ -t 1 ] 2>/dev/null; then
|
|
||||||
case "${TERM:-dumb}" in
|
|
||||||
dumb) _tui_colors=0 ;;
|
|
||||||
*) _tui_colors=1 ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$_tui_colors" -eq 1 ]; then
|
|
||||||
_c_reset='\033[0m'
|
|
||||||
_c_bold='\033[1m'
|
|
||||||
_c_dim='\033[2m'
|
|
||||||
_c_red='\033[31;1m'
|
|
||||||
_c_green='\033[32;1m'
|
|
||||||
_c_yellow='\033[33;1m'
|
|
||||||
_c_blue='\033[34;1m'
|
|
||||||
_c_cyan='\033[36;1m'
|
|
||||||
_c_magenta='\033[35;1m'
|
|
||||||
_c_white='\033[37;1m'
|
|
||||||
_c_bg_blue='\033[44m'
|
|
||||||
_c_bg_green='\033[42m'
|
|
||||||
_c_bg_red='\033[41m'
|
|
||||||
_c_bg_yellow='\033[43m'
|
|
||||||
_c_underline='\033[4m'
|
|
||||||
else
|
|
||||||
_c_reset=''
|
|
||||||
_c_bold=''
|
|
||||||
_c_dim=''
|
|
||||||
_c_red=''
|
|
||||||
_c_green=''
|
|
||||||
_c_yellow=''
|
|
||||||
_c_blue=''
|
|
||||||
_c_cyan=''
|
|
||||||
_c_magenta=''
|
|
||||||
_c_white=''
|
|
||||||
_c_bg_blue=''
|
|
||||||
_c_bg_green=''
|
|
||||||
_c_bg_red=''
|
|
||||||
_c_bg_yellow=''
|
|
||||||
_c_underline=''
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ─── Terminal width ──────────────────────────────────────────────────────────
|
|
||||||
_tui_width() {
|
|
||||||
if [ -t 1 ] 2>/dev/null && command -v stty >/dev/null 2>&1; then
|
|
||||||
w="$(stty size 2>/dev/null | awk '{print $2}')"
|
|
||||||
[ -n "$w" ] && [ "$w" -gt 0 ] 2>/dev/null && printf '%s' "$w" && return 0
|
|
||||||
fi
|
|
||||||
printf '72'
|
|
||||||
}
|
|
||||||
|
|
||||||
# ─── Horizontal line ─────────────────────────────────────────────────────────
|
|
||||||
_tui_hline() {
|
|
||||||
_w="$(_tui_width)"
|
|
||||||
_char="${1:--}"
|
|
||||||
_i=0
|
|
||||||
while [ "$_i" -lt "$_w" ]; do
|
|
||||||
printf '%s' "$_char"
|
|
||||||
_i=$((_i + 1))
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
# ─── Center text ──────────────────────────────────────────────────────────────
|
|
||||||
_tui_center() {
|
|
||||||
_text="$1"
|
|
||||||
_w="$(_tui_width)"
|
|
||||||
_len=${#_text}
|
|
||||||
_pad=$((_w - _len))
|
|
||||||
[ "$_pad" -lt 0 ] 2>/dev/null && _pad=0
|
|
||||||
_left=$((_pad / 2))
|
|
||||||
_right=$((_pad - _left))
|
|
||||||
_i=0
|
|
||||||
while [ "$_i" -lt "$_left" ]; do
|
|
||||||
printf ' '
|
|
||||||
_i=$((_i + 1))
|
|
||||||
done
|
|
||||||
printf '%s' "$_text"
|
|
||||||
_i=0
|
|
||||||
while [ "$_i" -lt "$_right" ]; do
|
|
||||||
printf ' '
|
|
||||||
_i=$((_i + 1))
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
# ─── Pad/truncate to width ──────────────────────────────────────────────────
|
|
||||||
_tui_pad() {
|
|
||||||
_text="$1"
|
|
||||||
_target="${2:-0}"
|
|
||||||
_len=${#_text}
|
|
||||||
_i=$_len
|
|
||||||
while [ "$_i" -lt "$_target" ]; do
|
|
||||||
printf ' '
|
|
||||||
_i=$((_i + 1))
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
# ─── Print banner ────────────────────────────────────────────────────────────
|
|
||||||
tui_banner() {
|
|
||||||
printf '\n'
|
|
||||||
printf ' %s%sTachyon Installer%s v%s%s\n' "$_c_cyan" "$_c_bold" "$_c_reset" "$_c_bold" "$INSTALLER_VERSION"
|
|
||||||
printf '%s\n' ""
|
|
||||||
printf '%s%s%s\n' "$_c_dim" "$(_tui_hline '─')" "$_c_reset"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ─── Print step header ──────────────────────────────────────────────────────
|
|
||||||
tui_step() {
|
|
||||||
_step_no="$1"
|
|
||||||
_step_total="$2"
|
|
||||||
_step_text="$3"
|
|
||||||
_step_icon=""
|
|
||||||
|
|
||||||
printf '\n'
|
|
||||||
printf ' %s%s[ %s/%s ]%s %s%s%s\n' \
|
|
||||||
"$_c_blue" "$_c_bold" \
|
|
||||||
"$_step_no" "$_step_total" \
|
|
||||||
"$_c_reset" \
|
|
||||||
"$_c_bold" "$_step_text" "$_c_reset"
|
|
||||||
printf ' %s%s\n' "$_c_dim" "$(_tui_hline '·')"
|
|
||||||
printf '%s' "$_c_reset"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ─── Success message ─────────────────────────────────────────────────────────
|
|
||||||
tui_ok() {
|
|
||||||
printf ' %s%s✓%s %s\n' "$_c_green" "$_c_bold" "$_c_reset" "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ─── Warning message ─────────────────────────────────────────────────────────
|
|
||||||
tui_warn() {
|
|
||||||
printf ' %s%s⚠%s %s%s\n' "$_c_yellow" "$_c_bold" "$_c_reset" "$1" "$_c_reset" >&2
|
|
||||||
}
|
|
||||||
|
|
||||||
# ─── Error message ───────────────────────────────────────────────────────────
|
|
||||||
tui_err() {
|
|
||||||
printf ' %s%s✗%s %s%s\n' "$_c_red" "$_c_bold" "$_c_reset" "$1" "$_c_reset" >&2
|
|
||||||
printf ' %s%s Log: %s%s\n' "$_c_dim" "$_c_reset" "$LOG_FILE" "$_c_reset" >&2
|
|
||||||
}
|
|
||||||
|
|
||||||
# ─── Info message ────────────────────────────────────────────────────────────
|
|
||||||
tui_info() {
|
|
||||||
printf ' %s▸%s %s\n' "$_c_cyan" "$_c_reset" "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ─── Download progress ───────────────────────────────────────────────────────
|
|
||||||
tui_download() {
|
|
||||||
_label="$1"
|
|
||||||
_attempt="${2:-1}"
|
|
||||||
_max="${3:-3}"
|
|
||||||
printf ' %s%s↓%s %s %s(%s/%s)%s\n' \
|
|
||||||
"$_c_cyan" "$_c_bold" "$_c_reset" \
|
|
||||||
"$_label" \
|
|
||||||
"$_c_dim" "$_attempt" "$_max" "$_c_reset"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ─── Progress bar ────────────────────────────────────────────────────────────
|
|
||||||
tui_progress() {
|
|
||||||
_current="$1"
|
|
||||||
_total="$2"
|
|
||||||
_label="${3:-}"
|
|
||||||
_w=$((_tui_width() - 8))
|
|
||||||
[ "$_w" -lt 10 ] 2>/dev/null && _w=10
|
|
||||||
|
|
||||||
_pct=0
|
|
||||||
[ "$_total" -gt 0 ] 2>/dev/null && _pct=$((_current * 100 / _total))
|
|
||||||
|
|
||||||
_filled=$((_pct * _w / 100))
|
|
||||||
[ "$_filled" -gt "$_w" ] 2>/dev/null && _filled=$_w
|
|
||||||
_empty=$((_w - _filled))
|
|
||||||
|
|
||||||
printf '\r %s' "$_c_dim"
|
|
||||||
_i=0
|
|
||||||
while [ "$_i" -lt "$_filled" ]; do
|
|
||||||
printf '━'
|
|
||||||
_i=$((_i + 1))
|
|
||||||
done
|
|
||||||
_i=0
|
|
||||||
while [ "$_i" -lt "$_empty" ]; do
|
|
||||||
printf '─'
|
|
||||||
_i=$((_i + 1))
|
|
||||||
done
|
|
||||||
printf '%s' "$_c_reset"
|
|
||||||
printf ' %s%3d%%%s' "$_c_bold" "$_pct" "$_c_reset"
|
|
||||||
[ -n "$_label" ] && printf ' %s' "$_label"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ─── Spinner (call in background, kill when done) ───────────────────────────
|
|
||||||
tui_spinner_start() {
|
|
||||||
_spinner_text="${1:-Working...}"
|
|
||||||
_spinner_chars='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'
|
|
||||||
_spinner_pid=""
|
|
||||||
|
|
||||||
# Only spin on real terminals
|
|
||||||
[ -t 1 ] 2>/dev/null || { printf ' %s\n' "$_spinner_text"; return 0; }
|
|
||||||
|
|
||||||
(
|
|
||||||
while true; do
|
|
||||||
for _ch in $_spinner_chars; do
|
|
||||||
printf '\r %s%s%s %s' "$_c_cyan" "$_ch" "$_c_reset" "$_spinner_text"
|
|
||||||
sleep 0.1 2>/dev/null || sleep 1
|
|
||||||
done
|
|
||||||
done
|
|
||||||
) &
|
|
||||||
_spinner_pid=$!
|
|
||||||
printf '%s' "$_spinner_pid"
|
|
||||||
}
|
|
||||||
|
|
||||||
tui_spinner_stop() {
|
|
||||||
_pid="$1"
|
|
||||||
_text="${2:-}"
|
|
||||||
if [ -n "$_pid" ] && kill -0 "$_pid" 2>/dev/null; then
|
|
||||||
kill "$_pid" 2>/dev/null
|
|
||||||
wait "$_pid" 2>/dev/null
|
|
||||||
fi
|
|
||||||
# Clear spinner line
|
|
||||||
printf '\r%s' "$(_tui_hline ' ')"
|
|
||||||
printf '\r'
|
|
||||||
[ -n "$_text" ] && tui_ok "$_text"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ─── Boxed section ───────────────────────────────────────────────────────────
|
|
||||||
tui_box_start() {
|
|
||||||
_w="$(_tui_width)"
|
|
||||||
_w=$((_w - 4))
|
|
||||||
[ "$_w" -lt 10 ] 2>/dev/null && _w=10
|
|
||||||
printf '\n'
|
|
||||||
printf ' %s╔' "$_c_blue"
|
|
||||||
_i=0; while [ "$_i" -lt "$_w" ]; do printf '═'; _i=$((_i + 1)); done
|
|
||||||
printf '╗%s\n' "$_c_reset"
|
|
||||||
}
|
|
||||||
|
|
||||||
tui_box_line() {
|
|
||||||
_text="$1"
|
|
||||||
_w="$(_tui_width)"
|
|
||||||
_w=$((_w - 4))
|
|
||||||
_len=${#_text}
|
|
||||||
_pad=$((_w - _len - 2))
|
|
||||||
[ "$_pad" -lt 0 ] 2>/dev/null && _pad=0
|
|
||||||
printf ' %s║%s %s' "$_c_blue" "$_c_reset" "$_text"
|
|
||||||
_i=0; while [ "$_i" -lt "$_pad" ]; do printf ' '; _i=$((_i + 1)); done
|
|
||||||
printf '%s║%s\n' "$_c_blue" "$_c_reset"
|
|
||||||
}
|
|
||||||
|
|
||||||
tui_box_line_color() {
|
|
||||||
_text="$1"
|
|
||||||
_color="$2"
|
|
||||||
_w="$(_tui_width)"
|
|
||||||
_w=$((_w - 4))
|
|
||||||
_len=${#_text}
|
|
||||||
_pad=$((_w - _len - 2))
|
|
||||||
[ "$_pad" -lt 0 ] 2>/dev/null && _pad=0
|
|
||||||
printf ' %s║%s %s%s' "$_c_blue" "$_c_reset" "$_color" "$_text"
|
|
||||||
_i=0; while [ "$_i" -lt "$_pad" ]; do printf ' '; _i=$((_i + 1)); done
|
|
||||||
printf '%s║%s\n' "$_c_reset" "$_c_blue"
|
|
||||||
}
|
|
||||||
|
|
||||||
tui_box_end() {
|
|
||||||
_w="$(_tui_width)"
|
|
||||||
_w=$((_w - 4))
|
|
||||||
[ "$_w" -lt 10 ] 2>/dev/null && _w=10
|
|
||||||
printf ' %s╚' "$_c_blue"
|
|
||||||
_i=0; while [ "$_i" -lt "$_w" ]; do printf '═'; _i=$((_i + 1)); done
|
|
||||||
printf '╝%s\n' "$_c_reset"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ─── Section divider ─────────────────────────────────────────────────────────
|
|
||||||
tui_divider() {
|
|
||||||
printf '\n %s%s%s\n' "$_c_dim" "$(_tui_hline '─')" "$_c_reset"
|
|
||||||
}
|
|
||||||
|
|
||||||
tui_box_divider() {
|
|
||||||
_w="$(_tui_width)"
|
|
||||||
_w=$((_w - 4))
|
|
||||||
[ "$_w" -lt 10 ] 2>/dev/null && _w=10
|
|
||||||
printf ' %s║%s' "$_c_blue" "$_c_reset"
|
|
||||||
_i=0; while [ "$_i" -lt "$_w" ]; do printf '─'; _i=$((_i + 1)); done
|
|
||||||
printf '%s║%s\n' "$_c_blue" "$_c_reset"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ─── Interactive menu (returns choice) ──────────────────────────────────────
|
|
||||||
tui_menu() {
|
|
||||||
_prompt="$1"
|
|
||||||
shift
|
|
||||||
_options="$@"
|
|
||||||
|
|
||||||
printf '\n %s%s%s\n' "$_c_bold" "$_prompt" "$_c_reset"
|
|
||||||
_i=1
|
|
||||||
for _opt in $_options; do
|
|
||||||
printf ' %s%s)%s %s\n' "$_c_cyan" "$_c_bold" "$_c_reset" "$_opt"
|
|
||||||
_i=$((_i + 1))
|
|
||||||
done
|
|
||||||
printf '\n'
|
|
||||||
printf ' %s▸%s ' "$_c_cyan" "$_c_reset"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ─── Confirmation prompt ────────────────────────────────────────────────────
|
|
||||||
tui_confirm() {
|
|
||||||
_prompt="$1"
|
|
||||||
printf ' %s%s?%s %s %s' "$_c_yellow" "$_c_bold" "$_c_reset" "$_prompt" "$_c_dim"
|
|
||||||
printf '(%s/%s)%s ' "y" "n" "$_c_reset"
|
|
||||||
}
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
// LuCI uses this specific SuperFastHash from OpenWrt
|
|
||||||
// Let me try to match it against the reference lmo
|
|
||||||
// adblock.bg.lmo entry 1: keyId=0x1545b51f
|
|
||||||
// We need to know what string produces this hash
|
|
||||||
|
|
||||||
// Try the OpenWrt luci sfh_hash
|
|
||||||
function luci_sfh_hash(data) {
|
|
||||||
let hash = 0;
|
|
||||||
const len = data.length;
|
|
||||||
let i;
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
hash += data.charCodeAt(i);
|
|
||||||
hash = (hash << 10) + hash;
|
|
||||||
hash ^= hash >>> 6;
|
|
||||||
}
|
|
||||||
hash += hash << 3;
|
|
||||||
hash ^= hash >>> 11;
|
|
||||||
hash += hash << 15;
|
|
||||||
return hash >>> 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('luci_sfh empty:', luci_sfh_hash('').toString(16));
|
|
||||||
console.log('luci_sfh Plural-Forms:', luci_sfh_hash('Plural-Forms').toString(16));
|
|
||||||
|
|
||||||
// Now check my po2lmo sfh_hash
|
|
||||||
function po2lmo_sfh(data) {
|
|
||||||
let hash = 0;
|
|
||||||
let i = data.length;
|
|
||||||
let k;
|
|
||||||
while (i >= 4) {
|
|
||||||
k = (data.charCodeAt(i - 4) & 0xff) |
|
|
||||||
((data.charCodeAt(i - 3) & 0xff) << 8) |
|
|
||||||
((data.charCodeAt(i - 2) & 0xff) << 16) |
|
|
||||||
((data.charCodeAt(i - 1) & 0xff) << 24);
|
|
||||||
k = Math.imul(k, 0x5bd1e995);
|
|
||||||
k = k >>> 0;
|
|
||||||
k ^= k >>> 24;
|
|
||||||
k = Math.imul(k, 0x5bd1e995);
|
|
||||||
k = k >>> 0;
|
|
||||||
hash = Math.imul(hash, 0x5bd1e995) + k;
|
|
||||||
hash = hash >>> 0;
|
|
||||||
i -= 4;
|
|
||||||
}
|
|
||||||
switch (i) {
|
|
||||||
case 3: hash ^= (data.charCodeAt(0) & 0xff) << 16;
|
|
||||||
case 2: hash ^= (data.charCodeAt(i - 2) & 0xff) << 8;
|
|
||||||
case 1: hash ^= (data.charCodeAt(i - 1) & 0xff);
|
|
||||||
hash = Math.imul(hash, 0x5bd1e995);
|
|
||||||
hash = hash >>> 0;
|
|
||||||
}
|
|
||||||
hash ^= hash >>> 13;
|
|
||||||
hash = Math.imul(hash, 0x5bd1e995);
|
|
||||||
hash = hash >>> 0;
|
|
||||||
hash ^= hash >>> 15;
|
|
||||||
return hash >>> 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('po2lmo_sfh empty:', po2lmo_sfh('').toString(16));
|
|
||||||
console.log('po2lmo_sfh Plural-Forms:', po2lmo_sfh('Plural-Forms').toString(16));
|
|
||||||
|
|
||||||
// Read the reference LMO
|
|
||||||
const buf = fs.readFileSync('tools/test_ref.lmo');
|
|
||||||
const indexOffset = buf.readUInt32BE(buf.length - 4);
|
|
||||||
const entryCount = (buf.length - 4 - indexOffset) / 16;
|
|
||||||
console.log('\nReference LMO entries:');
|
|
||||||
for (let i = 0; i < Math.min(10, entryCount); i++) {
|
|
||||||
const off = indexOffset + i * 16;
|
|
||||||
const keyId = buf.readUInt32BE(off);
|
|
||||||
console.log(' keyId:', keyId.toString(16));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read payload to get actual strings
|
|
||||||
for (let i = 0; i < Math.min(10, entryCount); i++) {
|
|
||||||
const off = indexOffset + i * 16;
|
|
||||||
const keyId = buf.readUInt32BE(off);
|
|
||||||
const valId = buf.readUInt32BE(off + 4);
|
|
||||||
const offset = buf.readUInt32BE(off + 8);
|
|
||||||
const length = buf.readUInt32BE(off + 12);
|
|
||||||
|
|
||||||
// Read the payload at offset
|
|
||||||
const valBuf = buf.slice(offset, offset + length);
|
|
||||||
const valStr = valBuf.toString('utf8').replace(/\0/g, '');
|
|
||||||
|
|
||||||
console.log(` [${i}] keyId:${keyId.toString(16).padStart(8,'0')} off:${offset} len:${length} val:"${valStr}"`);
|
|
||||||
|
|
||||||
// If this is entry 1+, try to compute hash of the key
|
|
||||||
if (i > 0 && valStr.length > 0) {
|
|
||||||
console.log(` luci_sfh("${valStr}") = ${luci_sfh_hash(valStr).toString(16)}`);
|
|
||||||
console.log(` po2lmo_sfh("${valStr}") = ${po2lmo_sfh(valStr).toString(16)}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
// OpenWrt luci-core uses this hash (from lmo.c):
|
|
||||||
function lmo_hash(s) {
|
|
||||||
let h = 0;
|
|
||||||
for (let i = 0; i < s.length; i++) {
|
|
||||||
h += s.charCodeAt(i);
|
|
||||||
h = (h + (h << 10)) >>> 0;
|
|
||||||
h ^= h >>> 6;
|
|
||||||
}
|
|
||||||
h = (h + (h << 3)) >>> 0;
|
|
||||||
h ^= h >>> 11;
|
|
||||||
h = (h + (h << 15)) >>> 0;
|
|
||||||
return h >>> 0;
|
|
||||||
}
|
|
||||||
// Reference: entry 1 keyId=0x1545b51f
|
|
||||||
console.log('lmo_hash(Client):', lmo_hash('Client').toString(16), '(target: 1545b51f)');
|
|
||||||
console.log('lmo_hash(Download):', lmo_hash('Download').toString(16));
|
|
||||||
console.log('lmo_hash(Save):', lmo_hash('Save').toString(16));
|
|
||||||
console.log('lmo_hash(Action):', lmo_hash('Action').toString(16));
|
|
||||||
console.log('lmo_hash(Enabled):', lmo_hash('Enabled').toString(16));
|
|
||||||
console.log('lmo_hash(General):', lmo_hash('General').toString(16));
|
|
||||||
console.log('lmo_hash(Email):', lmo_hash('Email').toString(16));
|
|
||||||
console.log('lmo_hash(Subject):', lmo_hash('Subject').toString(16));
|
|
||||||
console.log('lmo_hash(Enable detailed logs):', lmo_hash('Enable detailed logs').toString(16));
|
|
||||||
console.log('lmo_hash(Enable):', lmo_hash('Enable').toString(16));
|
|
||||||
console.log('lmo_hash(Close):', lmo_hash('Close').toString(16));
|
|
||||||
console.log('lmo_hash(Save & Apply):', lmo_hash('Save & Apply').toString(16));
|
|
||||||
-150
@@ -1,150 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
// OpenWrt LuCI SuperFastHash (from LMO.md / template_lmo.c)
|
|
||||||
// sfh_get16 reads uint16 in little-endian
|
|
||||||
function sfh_get16(d, off) {
|
|
||||||
return (d[off] & 0xff) + ((d[off + 1] & 0xff) << 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sfh_hash(str) {
|
|
||||||
const data = Buffer.from(str, 'utf8');
|
|
||||||
const len = data.length;
|
|
||||||
if (len <= 0) return 0;
|
|
||||||
|
|
||||||
let hash = len;
|
|
||||||
let rem = len & 3;
|
|
||||||
let offset = 0;
|
|
||||||
const words = len >> 2;
|
|
||||||
|
|
||||||
// Main loop
|
|
||||||
for (let i = 0; i < words; i++) {
|
|
||||||
hash += sfh_get16(data, offset);
|
|
||||||
let tmp = (sfh_get16(data, offset + 2) << 11) ^ hash;
|
|
||||||
hash = (hash << 16) ^ tmp;
|
|
||||||
offset += 4;
|
|
||||||
hash += hash >>> 11;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle end cases
|
|
||||||
switch (rem) {
|
|
||||||
case 3:
|
|
||||||
hash += sfh_get16(data, offset);
|
|
||||||
hash ^= hash << 16;
|
|
||||||
hash ^= data[offset + 2] << 18;
|
|
||||||
hash += hash >>> 11;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
hash += sfh_get16(data, offset);
|
|
||||||
hash ^= hash << 11;
|
|
||||||
hash += hash >>> 17;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
hash += data[offset];
|
|
||||||
hash ^= hash << 10;
|
|
||||||
hash += hash >>> 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Force "avalanching" of final 127 bits
|
|
||||||
hash ^= hash << 3;
|
|
||||||
hash += hash >>> 5;
|
|
||||||
hash ^= hash << 4;
|
|
||||||
hash += hash >>> 17;
|
|
||||||
hash ^= hash << 25;
|
|
||||||
hash += hash >>> 6;
|
|
||||||
|
|
||||||
return hash >>> 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function pad4(len) {
|
|
||||||
return (4 - (len % 4)) % 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
function parsePo(content) {
|
|
||||||
const entries = [];
|
|
||||||
const lines = content.split('\n');
|
|
||||||
let state = null;
|
|
||||||
let msgid = '';
|
|
||||||
let msgstr = '';
|
|
||||||
|
|
||||||
function flush() {
|
|
||||||
if (state === 'msgstr' && msgid !== '' && msgstr !== '') {
|
|
||||||
entries.push({ key: msgid, value: msgstr });
|
|
||||||
}
|
|
||||||
msgid = '';
|
|
||||||
msgstr = '';
|
|
||||||
state = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < lines.length; i++) {
|
|
||||||
const line = lines[i];
|
|
||||||
if (line.startsWith('msgid ')) {
|
|
||||||
flush();
|
|
||||||
state = 'msgid';
|
|
||||||
msgid = line.slice(7, -1).replace(/\\n/g, '\n').replace(/\\"/g, '"');
|
|
||||||
} else if (line.startsWith('msgstr ')) {
|
|
||||||
state = 'msgstr';
|
|
||||||
msgstr = line.slice(8, -1).replace(/\\n/g, '\n').replace(/\\"/g, '"');
|
|
||||||
} else if (line.startsWith('"')) {
|
|
||||||
const val = line.slice(1, -1).replace(/\\n/g, '\n').replace(/\\"/g, '"');
|
|
||||||
if (state === 'msgid') msgid += val;
|
|
||||||
else if (state === 'msgstr') msgstr += val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
flush();
|
|
||||||
return entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
function compileLmo(entries) {
|
|
||||||
const payload = [];
|
|
||||||
const index = [];
|
|
||||||
let offset = 0;
|
|
||||||
|
|
||||||
for (const entry of entries) {
|
|
||||||
const keyBuf = Buffer.from(entry.key, 'utf8');
|
|
||||||
const valBuf = Buffer.from(entry.value, 'utf8');
|
|
||||||
|
|
||||||
const keyId = sfh_hash(entry.key);
|
|
||||||
const valId = sfh_hash(entry.value);
|
|
||||||
|
|
||||||
const paddedLen = valBuf.length + pad4(valBuf.length);
|
|
||||||
const padded = Buffer.alloc(paddedLen, 0);
|
|
||||||
valBuf.copy(padded);
|
|
||||||
payload.push(padded);
|
|
||||||
|
|
||||||
index.push({ keyId, valId, offset, length: valBuf.length });
|
|
||||||
offset += paddedLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
const indexBuf = Buffer.alloc(index.length * 16);
|
|
||||||
for (let i = 0; i < index.length; i++) {
|
|
||||||
indexBuf.writeUInt32BE(index[i].keyId, i * 16);
|
|
||||||
indexBuf.writeUInt32BE(index[i].valId, i * 16 + 4);
|
|
||||||
indexBuf.writeUInt32BE(index[i].offset, i * 16 + 8);
|
|
||||||
indexBuf.writeUInt32BE(index[i].length, i * 16 + 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
const payloadData = Buffer.concat(payload);
|
|
||||||
const totalLen = payloadData.length + indexBuf.length + 4;
|
|
||||||
const out = Buffer.alloc(totalLen);
|
|
||||||
payloadData.copy(out, 0);
|
|
||||||
indexBuf.copy(out, payloadData.length);
|
|
||||||
out.writeUInt32BE(payloadData.length, totalLen - 4);
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
const [input, output] = process.argv.slice(2);
|
|
||||||
if (!input || !output) {
|
|
||||||
console.error('Usage: node po2lmo.js input.po output.lmo');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const poContent = fs.readFileSync(input, 'utf8');
|
|
||||||
const entries = parsePo(poContent);
|
|
||||||
console.log(`Parsed ${entries.length} translation entries from ${input}`);
|
|
||||||
const lmo = compileLmo(entries);
|
|
||||||
fs.writeFileSync(output, lmo);
|
|
||||||
console.log(`Written ${lmo.length} bytes to ${output}`);
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
function sfh_hash(data) {
|
|
||||||
let hash = 0;
|
|
||||||
let i = data.length;
|
|
||||||
let k;
|
|
||||||
while (i >= 4) {
|
|
||||||
k = (data.charCodeAt(i - 4) & 0xff) | ((data.charCodeAt(i - 3) & 0xff) << 8) | ((data.charCodeAt(i - 2) & 0xff) << 16) | ((data.charCodeAt(i - 1) & 0xff) << 24);
|
|
||||||
k = (k * 0x5bd1e995) >>> 0;
|
|
||||||
k ^= k >>> 24;
|
|
||||||
k = (k * 0x5bd1e995) >>> 0;
|
|
||||||
hash = (hash * 0x5bd1e995 + k) >>> 0;
|
|
||||||
i -= 4;
|
|
||||||
}
|
|
||||||
switch (i) {
|
|
||||||
case 3: hash ^= (data.charCodeAt(i - 3) & 0xff) << 16;
|
|
||||||
case 2: hash ^= (data.charCodeAt(i - 2) & 0xff) << 8;
|
|
||||||
case 1: hash ^= (data.charCodeAt(i - 1) & 0xff);
|
|
||||||
hash = (hash * 0x5bd1e995) >>> 0;
|
|
||||||
}
|
|
||||||
hash ^= hash >>> 13;
|
|
||||||
hash = (hash * 0x5bd1e995) >>> 0;
|
|
||||||
hash ^= hash >>> 15;
|
|
||||||
return hash >>> 0;
|
|
||||||
}
|
|
||||||
console.log('Empty:', sfh_hash('').toString(16));
|
|
||||||
console.log('Plural-Forms:', sfh_hash('Plural-Forms').toString(16));
|
|
||||||
console.log('Test str:', sfh_hash('Hello').toString(16));
|
|
||||||
Binary file not shown.
@@ -1,66 +0,0 @@
|
|||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
function sfh_get16(d, off) {
|
|
||||||
return (d[off] & 0xff) + ((d[off + 1] & 0xff) << 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sfh_hash(str) {
|
|
||||||
const data = Buffer.from(str, 'utf8');
|
|
||||||
const len = data.length;
|
|
||||||
if (len <= 0) return 0;
|
|
||||||
let hash = len;
|
|
||||||
let rem = len & 3;
|
|
||||||
let offset = 0;
|
|
||||||
const words = len >> 2;
|
|
||||||
for (let i = 0; i < words; i++) {
|
|
||||||
hash += sfh_get16(data, offset);
|
|
||||||
let tmp = (sfh_get16(data, offset + 2) << 11) ^ hash;
|
|
||||||
hash = (hash << 16) ^ tmp;
|
|
||||||
offset += 4;
|
|
||||||
hash += hash >>> 11;
|
|
||||||
}
|
|
||||||
switch (rem) {
|
|
||||||
case 3:
|
|
||||||
hash += sfh_get16(data, offset);
|
|
||||||
hash ^= hash << 16;
|
|
||||||
hash ^= data[offset + 2] << 18;
|
|
||||||
hash += hash >>> 11;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
hash += sfh_get16(data, offset);
|
|
||||||
hash ^= hash << 11;
|
|
||||||
hash += hash >>> 17;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
hash += data[offset];
|
|
||||||
hash ^= hash << 10;
|
|
||||||
hash += hash >>> 1;
|
|
||||||
}
|
|
||||||
hash ^= hash << 3;
|
|
||||||
hash += hash >>> 5;
|
|
||||||
hash ^= hash << 4;
|
|
||||||
hash += hash >>> 17;
|
|
||||||
hash ^= hash << 25;
|
|
||||||
hash += hash >>> 6;
|
|
||||||
return hash >>> 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reference: adblock.bg.lmo entry 1 keyId=0x1545b51f
|
|
||||||
// msgid for "Клиент" in adblock bg is likely "Client"
|
|
||||||
console.log('sfh_hash(Client):', sfh_hash('Client').toString(16), '(target: 1545b51f)');
|
|
||||||
console.log('sfh_hash(Save):', sfh_hash('Save').toString(16));
|
|
||||||
console.log('sfh_hash(Close):', sfh_hash('Close').toString(16));
|
|
||||||
console.log('sfh_hash(Enable):', sfh_hash('Enable').toString(16));
|
|
||||||
console.log('sfh_hash(Enabled):', sfh_hash('Enabled').toString(16));
|
|
||||||
console.log('sfh_hash(General settings):', sfh_hash('General settings').toString(16));
|
|
||||||
console.log('sfh_hash(Action):', sfh_hash('Action').toString(16));
|
|
||||||
console.log('sfh_hash(Download):', sfh_hash('Download').toString(16));
|
|
||||||
console.log('sfh_hash(Email):', sfh_hash('Email').toString(16));
|
|
||||||
console.log('sfh_hash(Subject):', sfh_hash('Subject').toString(16));
|
|
||||||
console.log('sfh_hash(Enable detailed logs):', sfh_hash('Enable detailed logs').toString(16));
|
|
||||||
console.log('sfh_hash(Save & Apply):', sfh_hash('Save & Apply').toString(16));
|
|
||||||
|
|
||||||
// Now test with some of our tachyon strings
|
|
||||||
console.log('\nTachyon strings:');
|
|
||||||
console.log('sfh_hash(Periodically checks if the proxy is responding. Restarts Tachyon after consecutive failures.):', sfh_hash('Periodically checks if the proxy is responding. Restarts Tachyon after consecutive failures.').toString(16));
|
|
||||||
console.log('sfh_hash(Enable Proxy Health Monitor):', sfh_hash('Enable Proxy Health Monitor').toString(16));
|
|
||||||
-33
@@ -1,33 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
. /tachyon/installer_tui.sh
|
|
||||||
INSTALLER_VERSION="1.2.56"
|
|
||||||
|
|
||||||
tui_banner
|
|
||||||
|
|
||||||
tui_step 1 10 "Updating package lists"
|
|
||||||
tui_ok "Package lists updated"
|
|
||||||
|
|
||||||
tui_step 2 10 "Resolving latest Tachyon release version"
|
|
||||||
tui_info "Fetching release metadata..."
|
|
||||||
tui_ok "Resolved: 1.2.56"
|
|
||||||
|
|
||||||
tui_step 3 10 "Downloading Tachyon release packages"
|
|
||||||
tui_download "tachyon_1.2.56.apk" 1 3
|
|
||||||
tui_download "luci-app-tachyon_1.2.56.apk" 2 3
|
|
||||||
tui_download "sha256sums.txt" 3 3
|
|
||||||
tui_ok "All packages downloaded"
|
|
||||||
|
|
||||||
tui_step 4 10 "Installing Tachyon backend package"
|
|
||||||
tui_info "Ensuring optional kernel module dependencies..."
|
|
||||||
tui_warn "Could not install kmod-inet-diag (built-in)"
|
|
||||||
tui_ok "tachyon 1.2.56 installed"
|
|
||||||
|
|
||||||
tui_step 5 10 "Done"
|
|
||||||
|
|
||||||
tui_box_start
|
|
||||||
tui_box_line_color "Tachyon 1.2.56 installed successfully (42s)" "$_c_green"
|
|
||||||
tui_box_line "Release: Dushnilin/tachyon@1.2.56"
|
|
||||||
tui_box_line "Log: /tmp/tachyon-install.log"
|
|
||||||
tui_box_divider
|
|
||||||
tui_box_line_color "Open LuCI and review your rules before enabling Tachyon" "$_c_yellow"
|
|
||||||
tui_box_end
|
|
||||||
Reference in New Issue
Block a user