Files

179 lines
33 KiB
Bash

#!/usr/bin/env bash
grep -q $'\r' "$0" 2>/dev/null && tr -d '\r' < "$0" > "$0.lf" && chmod +x "$0.lf" && exec bash "$0.lf" "$@"
Esc=$'\033'
Reset="${Esc}[0m"
BlockFull=$'\u2588'
BlockLower=$'\u2584'
BlockUpper=$'\u2580'
BlockLeft=$'\u258C'
get_rgb() {
local r=$1 g=$2 b=$3
echo "${Esc}[38;2;${r};${g};${b}m"
}
OrangeLight=$(get_rgb 255 140 66)
OrangeDark=$(get_rgb 224 123 57)
OrangeMid=$(get_rgb 240 131 61)
GreenAnsi=$(get_rgb 140 255 140)
RedAnsi=$(get_rgb 255 110 110)
GrayAnsi=$(get_rgb 130 130 130)
get_gradient_color() {
local index=$1 total=$2
local r1=255 g1=140 b1=66
local r2=224 g2=123 b2=57
local t=0
if [ "$total" -gt 1 ]; then
t=$(awk -v i="$index" -v t="$total" 'BEGIN { printf "%.6f", i/(t-1) }')
fi
local r g b
r=$(awk -v r1="$r1" -v r2="$r2" -v t="$t" 'BEGIN { printf "%d", r1+(r2-r1)*t }')
g=$(awk -v g1="$g1" -v g2="$g2" -v t="$t" 'BEGIN { printf "%d", g1+(g2-g1)*t }')
b=$(awk -v b1="$b1" -v b2="$b2" -v t="$t" 'BEGIN { printf "%d", b1+(b2-b1)*t }')
get_rgb "$r" "$g" "$b"
}
get_ascii_art_line() {
local out="$1"
out="${out//A/$BlockFull}"
out="${out//B/$BlockLower}"
out="${out//C/$BlockUpper}"
out="${out//D/$BlockLeft}"
echo "$out"
}
show_header() {
clear
local templates=(
" BAAAAAAAA BAAAAAAAB BAAAAAAAB AAA AAA AB BA "
" AAA AAA AAA AAA AAA AAA CAAAAAAAAAB AAA AAA AAA "
" AAA AC AAA AAA AAA AAA CAAACCAA AAA AAA AAAD "
" AAA AAA AAA AAA AAA AAA C AAA AAA AAAD "
"CAAAAAAAAAAA CAAAAAAAAAC AAA AAA AAA AAA AAA AAAD "
" AAA AAA AAA AAA AAA AAA AAA AAA "
" BA AAA AAA AAA AAA AAA AAA AAA AAA "
" BAAAAAAAAC BAAAAC CAAAAAAC BAAAAC AAAAAAAAC AC "
)
echo ""
local total=${#templates[@]}
local i=0
for tmpl in "${templates[@]}"; do
local color
color=$(get_gradient_color "$i" "$total")
local line
line=$(get_ascii_art_line "$tmpl")
echo "${color}${line}${Reset}"
i=$((i + 1))
done
echo ""
echo "${OrangeMid} Installer${Reset}"
echo "${OrangeDark} =============================================================${Reset}"
echo ""
}
SpinnerFrames=($'\u280B' $'\u2819' $'\u2839' $'\u2838' $'\u283C' $'\u2834' $'\u2826' $'\u2827' $'\u2807' $'\u280F')
CheckMark=$'\u2713'
CrossMark=$'\u2715'
CR=$'\r'
invoke_step() {
local label="$1"
local workfn="$2"
tput civis 2>/dev/null
local tmpfile
tmpfile=$(mktemp)
"$workfn" >"$tmpfile" 2>&1 &
local pid=$!
local frameIndex=0
while kill -0 "$pid" 2>/dev/null; do
local frame="${SpinnerFrames[$((frameIndex % ${#SpinnerFrames[@]}))]}"
local color
color=$(get_gradient_color $((frameIndex % 8)) 8)
printf "%s %s%s%s %s" "$CR" "$color" "$frame" "$Reset" "$label"
sleep 0.08
frameIndex=$((frameIndex + 1))
done
wait "$pid"
local status=$?
rm -f "$tmpfile"
local pad
pad=$(printf ' %.0s' {1..40})
if [ "$status" -ne 0 ]; then
printf "%s %s%s%s %s%s\n" "$CR" "$RedAnsi" "$CrossMark" "$Reset" "$label" "$pad"
else
printf "%s %s%s%s %s%s\n" "$CR" "$GreenAnsi" "$CheckMark" "$Reset" "$label" "$pad"
fi
tput cnorm 2>/dev/null
return $status
}
show_header
targetDir="$HOME/.local/share/spotui"
scriptPath="$targetDir/install.sh"
wrapperPath="$targetDir/spotui.sh"
binDir="$HOME/.local/bin"
binPath="$binDir/spotui"
spotuiScriptContentBase64="IyEvdXNyL2Jpbi9lbnYgYmFzaA0KDQppZiBbIC16ICIkQkFTSF9WRVJTSU9OIiBdOyB0aGVuDQogICAgZXhlYyBiYXNoICIkMCIgIiRAIg0KZmkNCg0KVEhFTUVfTkFNRT0iU3BvVFVJIg0KUkVQT19VUkw9Imh0dHBzOi8vZ2l0aHViLmNvbS9Ta2VuU01hc3RlUi9TcG9UVUkiDQpUSEVNRVNfRElSPSIkSE9NRS8uY29uZmlnL3NwaWNldGlmeS9UaGVtZXMiDQpUSEVNRV9QQVRIPSIkVEhFTUVTX0RJUi8kVEhFTUVfTkFNRSINCg0KRVNDPSQnXDAzMycNClJFU0VUPSIkRVNDWzBtIg0KDQpCTE9DS19GVUxMPSQnXHhlMlx4OTZceDg4Jw0KQkxPQ0tfTE9XRVI9JCdceGUyXHg5Nlx4ODQnDQpCTE9DS19VUFBFUj0kJ1x4ZTJceDk2XHg4MCcNCkJMT0NLX0xFRlQ9JCdceGUyXHg5Nlx4OGMnDQoNCmdldF9yZ2IoKSB7DQogICAgbG9jYWwgcj0kMSBnPSQyIGI9JDMNCiAgICBwcmludGYgJyVzWzM4OzI7JWQ7JWQ7JWRtJyAiJEVTQyIgIiRyIiAiJGciICIkYiINCn0NCg0KT1JBTkdFX0xJR0hUPSQoZ2V0X3JnYiAyNTUgMTQwIDY2KQ0KT1JBTkdFX0RBUks9JChnZXRfcmdiIDIyNCAxMjMgNTcpDQpPUkFOR0VfTUlEPSQoZ2V0X3JnYiAyNDAgMTMxIDYxKQ0KR1JFRU5fQU5TST0kKGdldF9yZ2IgMTQwIDI1NSAxNDApDQpTRUxFQ1RfQkc9IiR7RVNDfVs0ODsyOzI1NTsxNDA7NjZtJHtFU0N9WzM4OzI7MDswOzBtIg0KDQpXSElURT0iJEVTQ1s5N20iDQpHUkFZPSIkRVNDWzkwbSINClJFRD0iJEVTQ1s5MW0iDQpHUkVFTj0iJEVTQ1s5Mm0iDQpDWUFOPSIkRVNDWzk2bSINCg0KUEtHX1JFRlJFU0hfQVRURU1QVEVEPTANCg0KZ2V0X2dyYWRpZW50X2NvbG9yKCkgew0KICAgIGxvY2FsIGluZGV4PSQxIHRvdGFsPSQyDQogICAgbG9jYWwgcjE9MjU1IGcxPTE0MCBiMT02Ng0KICAgIGxvY2FsIHIyPTIyNCBnMj0xMjMgYjI9NTcNCiAgICBsb2NhbCBzY2FsZT0xMDAwDQogICAgbG9jYWwgdA0KICAgIGlmIFsgIiR0b3RhbCIgLWxlIDEgXTsgdGhlbg0KICAgICAgICB0PTANCiAgICBlbHNlDQogICAgICAgIHQ9JCgoIGluZGV4ICogc2NhbGUgLyAodG90YWwgLSAxKSApKQ0KICAgIGZpDQogICAgbG9jYWwgciBnIGINCiAgICByPSQoKCByMSArIChyMiAtIHIxKSAqIHQgLyBzY2FsZSApKQ0KICAgIGc9JCgoIGcxICsgKGcyIC0gZzEpICogdCAvIHNjYWxlICkpDQogICAgYj0kKCggYjEgKyAoYjIgLSBiMSkgKiB0IC8gc2NhbGUgKSkNCiAgICBnZXRfcmdiICIkciIgIiRnIiAiJGIiDQp9DQoNCmdldF9hc2NpaV9hcnRfbGluZSgpIHsNCiAgICBsb2NhbCBvdXQ9IiQxIg0KICAgIG91dD0iJHtvdXQvL0EvJEJMT0NLX0ZVTEx9Ig0KICAgIG91dD0iJHtvdXQvL0IvJEJMT0NLX0xPV0VSfSINCiAgICBvdXQ9IiR7b3V0Ly9DLyRCTE9DS19VUFBFUn0iDQogICAgb3V0PSIke291dC8vRC8kQkxPQ0tfTEVGVH0iDQogICAgcHJpbnRmICclcycgIiRvdXQiDQp9DQoNCmdldF9oZWFkZXJfbGluZXMoKSB7DQogICAgbG9jYWwgdGVtcGxhdGVzPSgNCiAgICAgICAgIiAgIEJBQUFBQUFBQSAgICBCQUFBQUFBQUIgIEJBQUFBQUFBQiAgICAgIEFBQSAgICBBQUEgICAgQUIgICBCQSAgIg0KICAgICAgICAiICBBQUEgICAgQUFBICAgQUFBICAgIEFBQSBBQUEgICAgQUFBIENBQUFBQUFBQUFCIEFBQSAgICBBQUEgQUFBICAiDQogICAgICAgICIgIEFBQSAgICBBQyAgICBBQUEgICAgQUFBIEFBQSAgICBBQUEgICAgQ0FBQUNDQUEgQUFBICAgIEFBQSBBQUFEICINCiAgICAgICAgIiAgQUFBICAgICAgICAgIEFBQSAgICBBQUEgQUFBICAgIEFBQSAgICAgQUFBICAgQyBBQUEgICAgQUFBIEFBQUQgIg0KICAgICAgICAiQ0FBQUFBQUFBQUFBIENBQUFBQUFBQUFDICBBQUEgICAgQUFBICAgICBBQUEgICAgIEFBQSAgICBBQUEgQUFBRCAiDQogICAgICAgICIgICAgICAgICBBQUEgICBBQUEgICAgICAgIEFBQSAgICBBQUEgICAgIEFBQSAgICAgQUFBICAgIEFBQSBBQUEgICINCiAgICAgICAgIiAgIEJBICAgIEFBQSAgIEFBQSAgICAgICAgQUFBICAgIEFBQSAgICAgQUFBICAgICBBQUEgICAgQUFBIEFBQSAgIg0KICAgICAgICAiIEJBQUFBQUFBQUMgICBCQUFBQUMgICAgICAgQ0FBQUFBQUMgICAgIEJBQUFBQyAgIEFBQUFBQUFBQyAgQUMgICAiDQogICAgKQ0KICAgIEhFQURFUl9MSU5FUz0oKQ0KICAgIEhFQURFUl9MSU5FUys9KCIiKQ0KICAgIGxvY2FsIHRvdGFsPSR7I3RlbXBsYXRlc1tAXX0NCiAgICBsb2NhbCBpIGxpbmUgY29sb3INCiAgICBmb3IgKChpID0gMDsgaSA8IHRvdGFsOyBpKyspKTsgZG8NCiAgICAgICAgY29sb3I9JChnZXRfZ3JhZGllbnRfY29sb3IgIiRpIiAiJHRvdGFsIikNCiAgICAgICAgbGluZT0kKGdldF9hc2NpaV9hcnRfbGluZSAiJHt0ZW1wbGF0ZXNbJGldfSIpDQogICAgICAgIEhFQURFUl9MSU5FUys9KCIke2NvbG9yfSR7bGluZX0ke1JFU0VUfSIpDQogICAgZG9uZQ0KICAgIEhFQURFUl9MSU5FUys9KCIiKQ0KICAgIEhFQURFUl9MSU5FUys9KCIke09SQU5HRV9NSUR9ICAgICAgICAgICAgICAgICAgICAgU3BpY2V0aWZ5IFRoZW1lIE1hbmFnZXIke1JFU0VUfSIpDQogICAgSEVBREVSX0xJTkVTKz0oIiR7T1JBTkdFX0RBUkt9ICA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09JHtSRVNFVH0iKQ0KICAgIEhFQURFUl9MSU5FUys9KCIiKQ0KfQ0KDQpzaG93X2hlYWRlcigpIHsNCiAgICBjbGVhcg0KICAgIGdldF9oZWFkZXJfbGluZXMNCiAgICBsb2NhbCBsaW5lDQogICAgZm9yIGxpbmUgaW4gIiR7SEVBREVSX0xJTkVTW0BdfSI7IGRvDQogICAgICAgIHByaW50ZiAnJXNcbicgIiRsaW5lIg0KICAgIGRvbmUNCn0NCg0KZ2V0X3Zpc2libGVfbGVuZ3RoKCkgew0KICAgIGxvY2FsIHRleHQ9IiQxIg0KICAgIGxvY2FsIHN0cmlwcGVkDQogICAgc3RyaXBwZWQ9JChwcmludGYgJyVzJyAiJHRleHQiIHwgc2VkIC1FICJzLyR7RVNDfVxbWzAtOTtdKm0vL2ciKQ0KICAgIHByaW50ZiAnJWQnICIkeyNzdHJpcHBlZH0iDQp9DQoNCndyaXRlX2ZyYW1lKCkgew0KICAgIGxvY2FsIC1uIGZyYW1lX2xpbmVzPSQxDQogICAgcHJpbnRmICclc1tIJyAiJEVTQyINCiAgICBsb2NhbCB3aWR0aA0KICAgIHdpZHRoPSQodHB1dCBjb2xzIDI+L2Rldi9udWxsKQ0KICAgIFsgLXogIiR3aWR0aCIgXSAmJiB3aWR0aD04MA0KICAgIGxvY2FsIGxpbmUgdmlzaWJsZSBwYWQNCiAgICBmb3IgbGluZSBpbiAiJHtmcmFtZV9saW5lc1tAXX0iOyBkbw0KICAgICAgICB2aXNpYmxlPSQoZ2V0X3Zpc2libGVfbGVuZ3RoICIkbGluZSIpDQogICAgICAgIHBhZD0kKCh3aWR0aCAtIHZpc2libGUgLSAxKSkNCiAgICAgICAgWyAiJHBhZCIgLWx0IDAgXSAmJiBwYWQ9MA0KICAgICAgICBwcmludGYgJyVzJSpzXG4nICIkbGluZSIgIiRwYWQiICIiDQogICAgZG9uZQ0KfQ0KDQpnZXRfY29uc29sZV9oZWlnaHQoKSB7DQogICAgbG9jYWwgaGVpZ2h0DQogICAgaGVpZ2h0PSQodHB1dCBsaW5lcyAyPi9kZXYvbnVsbCkNCiAgICBbIC16ICIkaGVpZ2h0IiBdICYmIGhlaWdodD0zMA0KICAgIHByaW50ZiAnJWQnICIkaGVpZ2h0Ig0KfQ0KDQpyZWZyZXNoX3BhdGgoKSB7DQogICAgbG9jYWwgY2FuZGlkYXRlDQogICAgZm9yIGNhbmRpZGF0ZSBpbiAiJEhPTUUvLmxvY2FsL2JpbiIgIiRIT01FLy5zcGljZXRpZnkiICIvdXNyL2xvY2FsL2JpbiI7IGRvDQogICAgICAgIGlmIFtbICI6JFBBVEg6IiAhPSAqIjokY2FuZGlkYXRlOiIqIF1dICYmIFsgLWQgIiRjYW5kaWRhdGUiIF07IHRoZW4NCiAgICAgICAgICAgIFBBVEg9IiRjYW5kaWRhdGU6JFBBVEgiDQogICAgICAgIGZpDQogICAgZG9uZQ0KICAgIGV4cG9ydCBQQVRIDQp9DQoNCmRldGVjdF9wa2dfbWFuYWdlcigpIHsNCiAgICBpZiBjb21tYW5kIC12IGFwdC1nZXQgPi9kZXYvbnVsbCAyPiYxOyB0aGVuIGVjaG8gImFwdCINCiAgICBlbGlmIGNvbW1hbmQgLXYgZG5mID4vZGV2L251bGwgMj4mMTsgdGhlbiBlY2hvICJkbmYiDQogICAgZWxpZiBjb21tYW5kIC12IHBhY21hbiA+L2Rldi9udWxsIDI+JjE7IHRoZW4gZWNobyAicGFjbWFuIg0KICAgIGVsaWYgY29tbWFuZCAtdiB6eXBwZXIgPi9kZXYvbnVsbCAyPiYxOyB0aGVuIGVjaG8gInp5cHBlciINCiAgICBlbGlmIGNvbW1hbmQgLXYgYXBrID4vZGV2L251bGwgMj4mMTsgdGhlbiBlY2hvICJhcGsiDQogICAgZWxzZSBlY2hvICIiDQogICAgZmkNCn0NCg0KcmVmcmVzaF9wa2dfbWFuYWdlcigpIHsNCiAgICBsb2NhbCBtZ3INCiAgICBtZ3I9JChkZXRlY3RfcGtnX21hbmFnZXIpDQogICAgcHJpbnRmICclcyAgUmVmcmVzaGluZyBwYWNrYWdlIGxpc3RzLi4uJXNcbicgIiRPUkFOR0VfTUlEIiAiJFJFU0VUIg0KICAgIGNhc2UgIiRtZ3IiIGluDQogICAgICAgIGFwdCkgICAgIHN1ZG8gYXB0LWdldCB1cGRhdGUgLXkgOzsNCiAgICAgICAgZG5mKSAgICAgc3VkbyBkbmYgY2hlY2stdXBkYXRlIC15IHx8IHRydWUgOzsNCiAgICAgICAgcGFjbWFuKSAgc3VkbyBwYWNtYW4gLVN5IC0tbm9jb25maXJtIDs7DQogICAgICAgIHp5cHBlcikgIHN1ZG8genlwcGVyIHJlZnJlc2ggOzsNCiAgICAgICAgYXBrKSAgICAgc3VkbyBhcGsgdXBkYXRlIDs7DQogICAgICAgICopDQogICAgICAgICAgICBwcmludGYgJyAgTm8gc3VwcG9ydGVkIHBhY2thZ2UgbWFuYWdlciBmb3VuZCAobG9va2VkIGZvciBhcHQsIGRuZiwgcGFjbWFuLCB6eXBwZXIsIGFwaykuJXNcbicgIiIgXA0KICAgICAgICAgICAgICAgIDI+L2Rldi9udWxsDQogICAgICAgICAgICBwcmludGYgJyVzICBObyBzdXBwb3J0ZWQgcGFja2FnZSBtYW5hZ2VyIGZvdW5kLiBJbnN0YWxsIGdpdCBtYW51YWxseS4lc1xuJyAiJFJFRCIgIiRSRVNFVCINCiAgICAgICAgICAgIDs7DQogICAgZXNhYw0KfQ0KDQppbnN0YWxsX2RlcGVuZGVuY3koKSB7DQogICAgbG9jYWwgbmFtZT0iJDEiDQogICAgaWYgWyAiJG5hbWUiID0gImdpdCIgXTsgdGhlbg0KICAgICAgICBsb2NhbCBtZ3INCiAgICAgICAgbWdyPSQoZGV0ZWN0X3BrZ19tYW5hZ2VyKQ0KICAgICAgICBpZiBbIC1uICIkbWdyIiBdOyB0aGVuDQogICAgICAgICAgICBwcmludGYgJyVzICBJbnN0YWxsaW5nIGdpdCB2aWEgJXMuLi4lc1xuJyAiJEdSQVkiICIkbWdyIiAiJFJFU0VUIg0KICAgICAgICAgICAgY2FzZSAiJG1nciIgaW4NCiAgICAgICAgICAgICAgICBhcHQpICAgICBzdWRvIGFwdC1nZXQgaW5zdGFsbCAteSBnaXQgOzsNCiAgICAgICAgICAgICAgICBkbmYpICAgICBzdWRvIGRuZiBpbnN0YWxsIC15IGdpdCA7Ow0KICAgICAgICAgICAgICAgIHBhY21hbikgIHN1ZG8gcGFjbWFuIC1TIC0tbm9jb25maXJtIGdpdCA7Ow0KICAgICAgICAgICAgICAgIHp5cHBlcikgIHN1ZG8genlwcGVyIGluc3RhbGwgLXkgZ2l0IDs7DQogICAgICAgICAgICAgICAgYXBrKSAgICAgc3VkbyBhcGsgYWRkIGdpdCA7Ow0KICAgICAgICAgICAgZXNhYw0KICAgICAgICAgICAgbG9jYWwgZXhpdF9jb2RlPSQ/DQogICAgICAgICAgICBwcmludGYgJyAgcGFja2FnZSBtYW5hZ2VyIGV4aXRlZCB3aXRoIGNvZGUgJWRcbicgIiRleGl0X2NvZGUiDQoNCiAgICAgICAgICAgIGlmIFsgIiRleGl0X2NvZGUiIC1uZSAwIF0gJiYgWyAiJFBLR19SRUZSRVNIX0FUVEVNUFRFRCIgLWVxIDAgXTsgdGhlbg0KICAgICAgICAgICAgICAgIHByaW50ZiAnJXMgIEluc3RhbGwgZmFpbGVkLiBSZWZyZXNoaW5nIHBhY2thZ2UgbGlzdHMgYW5kIHJldHJ5aW5nLi4uJXNcbicgIiRSRUQiICIkUkVTRVQiDQogICAgICAgICAgICAgICAgUEtHX1JFRlJFU0hfQVRURU1QVEVEPTENCiAgICAgICAgICAgICAgICByZWZyZXNoX3BrZ19tYW5hZ2VyDQoNCiAgICAgICAgICAgICAgICBwcmludGYgJyVzICBSZXRyeWluZyBnaXQgaW5zdGFsbC4uLiVzXG4nICIkR1JBWSIgIiRSRVNFVCINCiAgICAgICAgICAgICAgICBjYXNlICIkbWdyIiBpbg0KICAgICAgICAgICAgICAgICAgICBhcHQpICAgICBzdWRvIGFwdC1nZXQgaW5zdGFsbCAteSBnaXQgOzsNCiAgICAgICAgICAgICAgICAgICAgZG5mKSAgICAgc3VkbyBkbmYgaW5zdGFsbCAteSBnaXQgOzsNCiAgICAgICAgICAgICAgICAgICAgcGFjbWFuKSAgc3VkbyBwYWNtYW4gLVMgLS1ub2NvbmZpcm0gZ2l0IDs7DQogICAgICAgICAgICAgICAgICAgIHp5cHBlcikgIHN1ZG8genlwcGVyIGluc3RhbGwgLXkgZ2l0IDs7DQogICAgICAgICAgICAgICAgICAgIGFwaykgICAgIHN1ZG8gYXBrIGFkZCBnaXQgOzsNCiAgICAgICAgICAgICAgICBlc2FjDQogICAgICAgICAgICBmaQ0KDQogICAgICAgICAgICByZWZyZXNoX3BhdGgNCiAgICAgICAgZWxzZQ0KICAgICAgICAgICAgcHJpbnRmICclcyAgTm8gc3VwcG9ydGVkIHBhY2thZ2UgbWFuYWdlciB3YXMgZm91bmQuIEluc3RhbGwgZ2l0IG1hbnVhbGx5IGZvciB5b3VyIGRpc3Ryby4lc1xuJyAiJFJFRCIgIiRSRVNFVCINCiAgICAgICAgZmkNCiAgICBlbGlmIFsgIiRuYW1lIiA9ICJzcGljZXRpZnkiIF07IHRoZW4NCiAgICAgICAgcHJpbnRmICclcyAgSW5zdGFsbGluZyBTcGljZXRpZnkuLi4lc1xuJyAiJEdSQVkiICIkUkVTRVQiDQogICAgICAgIGN1cmwgLWZzU0wgaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3NwaWNldGlmeS9jbGkvbWFpbi9pbnN0YWxsLnNoIHwgc2gNCiAgICAgICAgcHJpbnRmICclcyAgU3BpY2V0aWZ5IGluc3RhbGxlciBmaW5pc2hlZC4lc1xuJyAiJEdSQVkiICIkUkVTRVQiDQogICAgICAgIHJlZnJlc2hfcGF0aA0KICAgIGZpDQp9DQoNCnRlc3RfZGVwZW5kZW5jaWVzKCkgew0KICAgIGxvY2FsIG1pc3Npbmc9KCkNCiAgICBjb21tYW5kIC12IGdpdCA+L2Rldi9udWxsIDI+JjEgfHwgbWlzc2luZys9KCJnaXQiKQ0KICAgIGNvbW1hbmQgLXYgc3BpY2V0aWZ5ID4vZGV2L251bGwgMj4mMSB8fCBtaXNzaW5nKz0oInNwaWNldGlmeSIpDQoNCiAgICBpZiBbICR7I21pc3NpbmdbQF19IC1lcSAwIF07IHRoZW4NCiAgICAgICAgcmV0dXJuIDANCiAgICBmaQ0KDQogICAgcHJpbnRmICclcyAgTWlzc2luZyBkZXBlbmRlbmNpZXM6ICVzJXNcbicgIiRSRUQiICIkKElGUz0nLCAnOyBlY2hvICIke21pc3NpbmdbKl19IikiICIkUkVTRVQiDQogICAgZWNobyAiIg0KICAgIHJlYWQgLXJwICIgIFByZXNzIEkgdG8gaW5zdGFsbCB0aGVtIG5vdywgb3IgYW55IG90aGVyIGtleSB0byBjYW5jZWw6ICIgY29uZmlybQ0KICAgIGlmIFsgIiRjb25maXJtIiAhPSAiSSIgXSAmJiBbICIkY29uZmlybSIgIT0gImkiIF07IHRoZW4NCiAgICAgICAgcmV0dXJuIDENCiAgICBmaQ0KDQogICAgbG9jYWwgZGVwDQogICAgZm9yIGRlcCBpbiAiJHttaXNzaW5nW0BdfSI7IGRvDQogICAgICAgIGVjaG8gIiINCiAgICAgICAgcHJpbnRmICclcyAgSW5zdGFsbGluZyAlcy4uLiVzXG4nICIkT1JBTkdFX01JRCIgIiRkZXAiICIkUkVTRVQiDQogICAgICAgIGluc3RhbGxfZGVwZW5kZW5jeSAiJGRlcCINCiAgICBkb25lDQoNCiAgICBlY2hvICIiDQogICAgcHJpbnRmICclcyAgUmVmcmVzaGluZyBlbnZpcm9ubWVudCBQQVRILi4uJXNcbicgIiRPUkFOR0VfTUlEIiAiJFJFU0VUIg0KICAgIHJlZnJlc2hfcGF0aA0KDQogICAgbG9jYWwgc3RpbGxfbWlzc2luZz0oKQ0KICAgIGNvbW1hbmQgLXYgZ2l0ID4vZGV2L251bGwgMj4mMSB8fCBzdGlsbF9taXNzaW5nKz0oImdpdCIpDQogICAgY29tbWFuZCAtdiBzcGljZXRpZnkgPi9kZXYvbnVsbCAyPiYxIHx8IHN0aWxsX21pc3NpbmcrPSgic3BpY2V0aWZ5IikNCg0KICAgIGlmIFsgJHsjc3RpbGxfbWlzc2luZ1tAXX0gLWd0IDAgXTsgdGhlbg0KICAgICAgICBlY2hvICIiDQogICAgICAgIHByaW50ZiAnJXMgIFN0aWxsIG1pc3Npbmc6ICVzLiBZb3UgbWF5IG5lZWQgdG8gcmVzdGFydCB5b3VyIHRlcm1pbmFsLiVzXG4nICIkUkVEIiAiJChJRlM9JywgJzsgZWNobyAiJHtzdGlsbF9taXNzaW5nWypdfSIpIiAiJFJFU0VUIg0KICAgICAgICByZXR1cm4gMQ0KICAgIGZpDQoNCiAgICBlY2hvICIiDQogICAgcHJpbnRmICclcyAgQWxsIGRlcGVuZGVuY2llcyBpbnN0YWxsZWQgc3VjY2Vzc2Z1bGx5LiVzXG4nICIkR1JFRU4iICIkUkVTRVQiDQogICAgcmV0dXJuIDANCn0NCg0KZ2V0X2RlZmF1bHRfYnJhbmNoKCkgew0KICAgIGxvY2FsIHJlZg0KICAgIHJlZj0kKGdpdCAtQyAiJFRIRU1FX1BBVEgiIHN5bWJvbGljLXJlZiByZWZzL3JlbW90ZXMvb3JpZ2luL0hFQUQgMj4vZGV2L251bGwpDQogICAgaWYgWyAtbiAiJHJlZiIgXTsgdGhlbg0KICAgICAgICBwcmludGYgJyVzJyAiJHtyZWYjIyovfSINCiAgICBlbHNlDQogICAgICAgIHByaW50ZiAnbWFpbicNCiAgICBmaQ0KfQ0KDQp0ZXN0X2lzX2RldGFjaGVkKCkgew0KICAgIGlmIGdpdCAtQyAiJFRIRU1FX1BBVEgiIHN5bWJvbGljLXJlZiAtcSBIRUFEID4vZGV2L251bGwgMj4mMTsgdGhlbg0KICAgICAgICByZXR1cm4gMQ0KICAgIGVsc2UNCiAgICAgICAgcmV0dXJuIDANCiAgICBmaQ0KfQ0KDQpnZXRfdGhlbWVfc3RhdHVzX3RleHQ9IiINCmdldF90aGVtZV9zdGF0dXNfY29sb3I9IiINCg0KZ2V0X3RoZW1lX3N0YXR1c19kZXRhaWxlZCgpIHsNCiAgICBpZiBbICEgLWQgIiRUSEVNRV9QQVRIIiBdOyB0aGVuDQogICAgICAgIGdldF90aGVtZV9zdGF0dXNfdGV4dD0iTm90IEluc3RhbGxlZCINCiAgICAgICAgZ2V0X3RoZW1lX3N0YXR1c19jb2xvcj0iJFJFRCINCiAgICAgICAgcmV0dXJuDQogICAgZmkNCg0KICAgIGlmICEgY29tbWFuZCAtdiBnaXQgPi9kZXYvbnVsbCAyPiYxOyB0aGVuDQogICAgICAgIGdldF90aGVtZV9zdGF0dXNfdGV4dD0iSW5zdGFsbGVkIg0KICAgICAgICBnZXRfdGhlbWVfc3RhdHVzX2NvbG9yPSIkR1JFRU4iDQogICAgICAgIHJldHVybg0KICAgIGZpDQoNCiAgICBnaXQgLUMgIiRUSEVNRV9QQVRIIiBmZXRjaCBvcmlnaW4gLS1xdWlldCAyPi9kZXYvbnVsbA0KICAgIGxvY2FsIGxvY2FsX2hhc2gNCiAgICBsb2NhbF9oYXNoPSQoZ2l0IC1DICIkVEhFTUVfUEFUSCIgcmV2LXBhcnNlIEhFQUQgMj4vZGV2L251bGwpDQoNCiAgICBpZiB0ZXN0X2lzX2RldGFjaGVkOyB0aGVuDQogICAgICAgIGxvY2FsIHNob3J0X2hhc2g9InVua25vd24iDQogICAgICAgIFsgLW4gIiRsb2NhbF9oYXNoIiBdICYmIHNob3J0X2hhc2g9IiR7bG9jYWxfaGFzaDowOjd9Ig0KICAgICAgICBnZXRfdGhlbWVfc3RhdHVzX3RleHQ9Ikluc3RhbGxlZCAoY3VzdG9tIGNvbW1pdCAkc2hvcnRfaGFzaCkiDQogICAgICAgIGdldF90aGVtZV9zdGF0dXNfY29sb3I9IiRDWUFOIg0KICAgICAgICByZXR1cm4NCiAgICBmaQ0KDQogICAgbG9jYWwgYnJhbmNoIHJlbW90ZV9oYXNoDQogICAgYnJhbmNoPSQoZ2V0X2RlZmF1bHRfYnJhbmNoKQ0KICAgIHJlbW90ZV9oYXNoPSQoZ2l0IC1DICIkVEhFTUVfUEFUSCIgcmV2LXBhcnNlICJvcmlnaW4vJGJyYW5jaCIgMj4vZGV2L251bGwpDQoNCiAgICBpZiBbIC16ICIkbG9jYWxfaGFzaCIgXSB8fCBbIC16ICIkcmVtb3RlX2hhc2giIF07IHRoZW4NCiAgICAgICAgZ2V0X3RoZW1lX3N0YXR1c190ZXh0PSJJbnN0YWxsZWQiDQogICAgICAgIGdldF90aGVtZV9zdGF0dXNfY29sb3I9IiRHUkVFTiINCiAgICAgICAgcmV0dXJuDQogICAgZmkNCg0KICAgIGlmIFsgIiRsb2NhbF9oYXNoIiA9ICIkcmVtb3RlX2hhc2giIF07IHRoZW4NCiAgICAgICAgZ2V0X3RoZW1lX3N0YXR1c190ZXh0PSJJbnN0YWxsZWQgKHVwIHRvIGRhdGUpIg0KICAgICAgICBnZXRfdGhlbWVfc3RhdHVzX2NvbG9yPSIkR1JFRU4iDQogICAgZWxzZQ0KICAgICAgICBnZXRfdGhlbWVfc3RhdHVzX3RleHQ9Ikluc3RhbGxlZCAob3V0ZGF0ZWQpIg0KICAgICAgICBnZXRfdGhlbWVfc3RhdHVzX2NvbG9yPSIkUkVEIg0KICAgIGZpDQp9DQoNCmluc3RhbGxfdGhlbWUoKSB7DQogICAgc2hvd19oZWFkZXINCiAgICBwcmludGYgJyVzICBJbnN0YWxsaW5nICVzLi4uJXNcbicgIiRPUkFOR0VfTElHSFQiICIkVEhFTUVfTkFNRSIgIiRSRVNFVCINCiAgICBlY2hvICIiDQoNCiAgICBpZiAhIHRlc3RfZGVwZW5kZW5jaWVzOyB0aGVuDQogICAgICAgIHBhdXNlX3JldHVybg0KICAgICAgICByZXR1cm4NCiAgICBmaQ0KDQogICAgbWtkaXIgLXAgIiRUSEVNRVNfRElSIg0KDQogICAgaWYgWyAtZCAiJFRIRU1FX1BBVEgiIF07IHRoZW4NCiAgICAgICAgcHJpbnRmICclcyAgVGhlbWUgYWxyZWFkeSBleGlzdHMgbG9jYWxseS4gUHVsbGluZyBsYXRlc3QgY2hhbmdlcy4uLiVzXG4nICIkT1JBTkdFX01JRCIgIiRSRVNFVCINCiAgICAgICAgZ2l0IC1DICIkVEhFTUVfUEFUSCIgcHVsbA0KICAgIGVsc2UNCiAgICAgICAgKGNkICIkVEhFTUVTX0RJUiIgJiYgZ2l0IGNsb25lICIkUkVQT19VUkwiICIkVEhFTUVfTkFNRSIpDQogICAgZmkNCg0KICAgIGlmIFsgLWQgIiRUSEVNRV9QQVRIIiBdOyB0aGVuDQogICAgICAgIGVjaG8gIiINCiAgICAgICAgcHJpbnRmICclcyAgU2V0dGluZyBjdXJyZW50IHRoZW1lIHRvICVzLi4uJXNcbicgIiRPUkFOR0VfTUlEIiAiJFRIRU1FX05BTUUiICIkUkVTRVQiDQogICAgICAgIHNwaWNldGlmeSBjb25maWcgY3VycmVudF90aGVtZSAiJFRIRU1FX05BTUUiDQoNCiAgICAgICAgcHJpbnRmICclcyAgQXBwbHlpbmcgU3BpY2V0aWZ5Li4uJXNcbicgIiRPUkFOR0VfTUlEIiAiJFJFU0VUIg0KICAgICAgICBzcGljZXRpZnkgYXBwbHkNCg0KICAgICAgICBlY2hvICIiDQogICAgICAgIHByaW50ZiAnJXMgICVzIGluc3RhbGxlZCBhbmQgYXBwbGllZCBzdWNjZXNzZnVsbHkuJXNcbicgIiRHUkVFTiIgIiRUSEVNRV9OQU1FIiAiJFJFU0VUIg0KICAgIGVsc2UNCiAgICAgICAgZWNobyAiIg0KICAgICAgICBwcmludGYgJyVzICBJbnN0YWxsYXRpb24gZmFpbGVkLiBDaGVjayB0aGUgZXJyb3JzIGFib3ZlLiVzXG4nICIkUkVEIiAiJFJFU0VUIg0KICAgIGZpDQoNCiAgICBwYXVzZV9yZXR1cm4NCn0NCg0KdXBkYXRlX3RoZW1lKCkgew0KICAgIHNob3dfaGVhZGVyDQogICAgcHJpbnRmICclcyAgVXBkYXRpbmcgJXMuLi4lc1xuJyAiJE9SQU5HRV9MSUdIVCIgIiRUSEVNRV9OQU1FIiAiJFJFU0VUIg0KICAgIGVjaG8gIiINCg0KICAgIGlmIFsgISAtZCAiJFRIRU1FX1BBVEgiIF07IHRoZW4NCiAgICAgICAgcHJpbnRmICclcyAgJXMgaXMgbm90IGluc3RhbGxlZC4gVXNlIEluc3RhbGwgaW5zdGVhZC4lc1xuJyAiJFJFRCIgIiRUSEVNRV9OQU1FIiAiJFJFU0VUIg0KICAgICAgICBwYXVzZV9yZXR1cm4NCiAgICAgICAgcmV0dXJuDQogICAgZmkNCg0KICAgIGlmICEgdGVzdF9kZXBlbmRlbmNpZXM7IHRoZW4NCiAgICAgICAgcGF1c2VfcmV0dXJuDQogICAgICAgIHJldHVybg0KICAgIGZpDQoNCiAgICBpZiB0ZXN0X2lzX2RldGFjaGVkOyB0aGVuDQogICAgICAgIGxvY2FsIGJyYW5jaA0KICAgICAgICBicmFuY2g9JChnZXRfZGVmYXVsdF9icmFuY2gpDQogICAgICAgIHByaW50ZiAnJXMgIEN1cnJlbnRseSBvbiBhIGN1c3RvbSBjb21taXQuIFJldHVybmluZyB0byAlcy4uLiVzXG4nICIkT1JBTkdFX01JRCIgIiRicmFuY2giICIkUkVTRVQiDQogICAgICAgIGdpdCAtQyAiJFRIRU1FX1BBVEgiIGNoZWNrb3V0ICIkYnJhbmNoIiAtLXF1aWV0DQogICAgZmkNCg0KICAgIGdpdCAtQyAiJFRIRU1FX1BBVEgiIHB1bGwNCg0KICAgIGVjaG8gIiINCiAgICBwcmludGYgJyVzICBSZS1hcHBseWluZyBTcGljZXRpZnkuLi4lc1xuJyAiJE9SQU5HRV9NSUQiICIkUkVTRVQiDQogICAgc3BpY2V0aWZ5IGFwcGx5DQoNCiAgICBlY2hvICIiDQogICAgcHJpbnRmICclcyAgJXMgdXBkYXRlZCBzdWNjZXNzZnVsbHkuJXNcbicgIiRHUkVFTiIgIiRUSEVNRV9OQU1FIiAiJFJFU0VUIg0KICAgIHBhdXNlX3JldHVybg0KfQ0KDQp1bmluc3RhbGxfdGhlbWUoKSB7DQogICAgc2hvd19oZWFkZXINCiAgICBwcmludGYgJyVzICBVbmluc3RhbGxpbmcgJXMuLi4lc1xuJyAiJE9SQU5HRV9MSUdIVCIgIiRUSEVNRV9OQU1FIiAiJFJFU0VUIg0KICAgIGVjaG8gIiINCg0KICAgIGlmIFsgISAtZCAiJFRIRU1FX1BBVEgiIF07IHRoZW4NCiAgICAgICAgcHJpbnRmICclcyAgJXMgaXMgbm90IGluc3RhbGxlZC4lc1xuJyAiJFJFRCIgIiRUSEVNRV9OQU1FIiAiJFJFU0VUIg0KICAgICAgICBwYXVzZV9yZXR1cm4NCiAgICAgICAgcmV0dXJuDQogICAgZmkNCg0KICAgIHByaW50ZiAnJXMgIFRoaXMgd2lsbCByZW1vdmUgdGhlIHRoZW1lIGZvbGRlciBhbmQgc3dpdGNoIHRvIE1hcmtldHBsYWNlLiVzXG4nICIkR1JBWSIgIiRSRVNFVCINCiAgICByZWFkIC1ycCAiICBUeXBlIFkgdG8gY29uZmlybTogIiBjb25maXJtDQogICAgaWYgWyAiJGNvbmZpcm0iICE9ICJZIiBdICYmIFsgIiRjb25maXJtIiAhPSAieSIgXTsgdGhlbg0KICAgICAgICBwcmludGYgJyVzICBDYW5jZWxsZWQuJXNcbicgIiRHUkFZIiAiJFJFU0VUIg0KICAgICAgICBwYXVzZV9yZXR1cm4NCiAgICAgICAgcmV0dXJuDQogICAgZmkNCg0KICAgIGlmIGNvbW1hbmQgLXYgc3BpY2V0aWZ5ID4vZGV2L251bGwgMj4mMTsgdGhlbg0KICAgICAgICBwcmludGYgJyVzICBTd2l0Y2hpbmcgU3BpY2V0aWZ5IHRoZW1lLi4uJXNcbicgIiRPUkFOR0VfTUlEIiAiJFJFU0VUIg0KICAgICAgICBzcGljZXRpZnkgY29uZmlnIGN1cnJlbnRfdGhlbWUgIlNwb1RVSS0iDQogICAgICAgIHNwaWNldGlmeSBjb25maWcgY3VycmVudF90aGVtZSBtYXJrZXRwbGFjZQ0KICAgICAgICBzcGljZXRpZnkgYXBwbHkNCiAgICBmaQ0KDQogICAgcm0gLXJmICIkVEhFTUVfUEFUSCINCg0KICAgIGVjaG8gIiINCiAgICBwcmludGYgJyVzICAlcyBoYXMgYmVlbiB1bmluc3RhbGxlZC4lc1xuJyAiJEdSRUVOIiAiJFRIRU1FX05BTUUiICIkUkVTRVQiDQogICAgcGF1c2VfcmV0dXJuDQp9DQoNCnJlYWRfa2V5KCkgew0KICAgIGxvY2FsIGtleSByZXN0DQogICAgSUZTPSByZWFkIC1yc24xIGtleQ0KICAgIGlmIFsgIiRrZXkiID0gIiRFU0MiIF07IHRoZW4NCiAgICAgICAgcmVhZCAtcnNuMiAtdCAwLjAxIHJlc3QNCiAgICAgICAgY2FzZSAiJHJlc3QiIGluDQogICAgICAgICAgICAiW0EiKSBlY2hvICJVUCIgOzsNCiAgICAgICAgICAgICJbQiIpIGVjaG8gIkRPV04iIDs7DQogICAgICAgICAgICAqKSAgICBlY2hvICJFU0MiIDs7DQogICAgICAgIGVzYWMNCiAgICBlbGlmIFsgLXogIiRrZXkiIF07IHRoZW4NCiAgICAgICAgZWNobyAiRU5URVIiDQogICAgZWxzZQ0KICAgICAgICBlY2hvICJPVEhFUiINCiAgICBmaQ0KfQ0KDQpyZWFkX2Fycm93X3NlbGVjdGlvbigpIHsNCiAgICBsb2NhbCAtbiBvdXRfcmVzdWx0PSQxDQogICAgbG9jYWwgLW4gX3Jhc19pdGVtcz0kMg0KICAgIGxvY2FsIGN1cnJlbnRfaW5kZXg9JDMNCiAgICBsb2NhbCAtbiBfcmFzX3RpdGxlX2xpbmVzPSQ0DQoNCiAgICBsb2NhbCBzZWxlY3RlZF9pbmRleD0wDQogICAgWyAiJGN1cnJlbnRfaW5kZXgiIC1nZSAwIF0gJiYgc2VsZWN0ZWRfaW5kZXg9JGN1cnJlbnRfaW5kZXgNCg0KICAgIGdldF9oZWFkZXJfbGluZXMNCiAgICBsb2NhbCBvdmVyaGVhZD0kKCggJHsjSEVBREVSX0xJTkVTW0BdfSArICR7I19yYXNfdGl0bGVfbGluZXNbQF19ICsgNCApKQ0KDQogICAgbG9jYWwgcGFnZV9zaXplDQogICAgcGFnZV9zaXplPSQoKCAkKGdldF9jb25zb2xlX2hlaWdodCkgLSBvdmVyaGVhZCApKQ0KICAgIFsgIiRwYWdlX3NpemUiIC1ndCAiJHsjX3Jhc19pdGVtc1tAXX0iIF0gJiYgcGFnZV9zaXplPSR7I19yYXNfaXRlbXNbQF19DQogICAgWyAiJHBhZ2Vfc2l6ZSIgLWx0IDEgXSAmJiBwYWdlX3NpemU9MQ0KDQogICAgY2xlYXINCiAgICBwcmludGYgJyVzWz8yNWwnICIkRVNDIg0KDQogICAgd2hpbGUgdHJ1ZTsgZG8NCiAgICAgICAgbG9jYWwgdG90YWxfcGFnZXM9JCgoICgkeyNfcmFzX2l0ZW1zW0BdfSArIHBhZ2Vfc2l6ZSAtIDEpIC8gcGFnZV9zaXplICkpDQogICAgICAgIFsgIiR0b3RhbF9wYWdlcyIgLWx0IDEgXSAmJiB0b3RhbF9wYWdlcz0xDQogICAgICAgIGxvY2FsIGN1cnJlbnRfcGFnZT0kKCggc2VsZWN0ZWRfaW5kZXggLyBwYWdlX3NpemUgKSkNCiAgICAgICAgbG9jYWwgcGFnZV9zdGFydD0kKCggY3VycmVudF9wYWdlICogcGFnZV9zaXplICkpDQogICAgICAgIGxvY2FsIHBhZ2VfZW5kPSQoKCBwYWdlX3N0YXJ0ICsgcGFnZV9zaXplIC0gMSApKQ0KICAgICAgICBbICIkcGFnZV9lbmQiIC1ndCAkKCgkeyNfcmFzX2l0ZW1zW0BdfSAtIDEpKSBdICYmIHBhZ2VfZW5kPSQoKCR7I19yYXNfaXRlbXNbQF19IC0gMSkpDQoNCiAgICAgICAgbG9jYWwgZnJhbWU9KCkNCiAgICAgICAgZnJhbWUrPSgiJHtIRUFERVJfTElORVNbQF19IikNCiAgICAgICAgZnJhbWUrPSgiJHtfcmFzX3RpdGxlX2xpbmVzW0BdfSIpDQoNCiAgICAgICAgbG9jYWwgaSBwcmVmaXggdGV4dA0KICAgICAgICBmb3IgKChpID0gcGFnZV9zdGFydDsgaSA8PSBwYWdlX2VuZDsgaSsrKSk7IGRvDQogICAgICAgICAgICBpZiBbICIkaSIgLWVxICIkY3VycmVudF9pbmRleCIgXTsgdGhlbg0KICAgICAgICAgICAgICAgIHByZWZpeD0iPiAiDQogICAgICAgICAgICBlbHNlDQogICAgICAgICAgICAgICAgcHJlZml4PSIgICINCiAgICAgICAgICAgIGZpDQogICAgICAgICAgICB0ZXh0PSIke3ByZWZpeH0ke19yYXNfaXRlbXNbJGldfSINCiAgICAgICAgICAgIGlmIFsgIiRpIiAtZXEgIiRzZWxlY3RlZF9pbmRleCIgXTsgdGhlbg0KICAgICAgICAgICAgICAgIGZyYW1lKz0oIiR7U0VMRUNUX0JHfSR7dGV4dH0ke1JFU0VUfSIpDQogICAgICAgICAgICBlbGlmIFsgIiRpIiAtZXEgIiRjdXJyZW50X2luZGV4IiBdOyB0aGVuDQogICAgICAgICAgICAgICAgZnJhbWUrPSgiJHtHUkVFTl9BTlNJfSR7dGV4dH0ke1JFU0VUfSIpDQogICAgICAgICAgICBlbHNlDQogICAgICAgICAgICAgICAgZnJhbWUrPSgiJHRleHQiKQ0KICAgICAgICAgICAgZmkNCiAgICAgICAgZG9uZQ0KDQogICAgICAgIGxvY2FsIGxpbmVzX3VzZWQ9JCgoIHBhZ2VfZW5kIC0gcGFnZV9zdGFydCArIDEgKSkNCiAgICAgICAgbG9jYWwgcA0KICAgICAgICBmb3IgKChwID0gbGluZXNfdXNlZDsgcCA8IHBhZ2Vfc2l6ZTsgcCsrKSk7IGRvDQogICAgICAgICAgICBmcmFtZSs9KCIiKQ0KICAgICAgICBkb25lDQoNCiAgICAgICAgZnJhbWUrPSgiIikNCiAgICAgICAgZnJhbWUrPSgiJHtPUkFOR0VfREFSS30gID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0ke1JFU0VUfSIpDQogICAgICAgIGZyYW1lKz0oIiAgVXAvRG93biB0byBtb3ZlLCBFbnRlciB0byBzZWxlY3QsIEVzYyB0byBnbyBiYWNrICAgUGFnZSAkKChjdXJyZW50X3BhZ2UgKyAxKSkgb2YgJHRvdGFsX3BhZ2VzIikNCg0KICAgICAgICB3cml0ZV9mcmFtZSBmcmFtZQ0KDQogICAgICAgIGxvY2FsIGtleQ0KICAgICAgICBrZXk9JChyZWFkX2tleSkNCg0KICAgICAgICBjYXNlICIka2V5IiBpbg0KICAgICAgICAgICAgVVApDQogICAgICAgICAgICAgICAgaWYgWyAiJHNlbGVjdGVkX2luZGV4IiAtZ3QgMCBdOyB0aGVuDQogICAgICAgICAgICAgICAgICAgIHNlbGVjdGVkX2luZGV4PSQoKHNlbGVjdGVkX2luZGV4IC0gMSkpDQogICAgICAgICAgICAgICAgZWxzZQ0KICAgICAgICAgICAgICAgICAgICBzZWxlY3RlZF9pbmRleD0kKCgkeyNfcmFzX2l0ZW1zW0BdfSAtIDEpKQ0KICAgICAgICAgICAgICAgIGZpDQogICAgICAgICAgICAgICAgOzsNCiAgICAgICAgICAgIERPV04pDQogICAgICAgICAgICAgICAgaWYgWyAiJHNlbGVjdGVkX2luZGV4IiAtbHQgJCgoJHsjX3Jhc19pdGVtc1tAXX0gLSAxKSkgXTsgdGhlbg0KICAgICAgICAgICAgICAgICAgICBzZWxlY3RlZF9pbmRleD0kKChzZWxlY3RlZF9pbmRleCArIDEpKQ0KICAgICAgICAgICAgICAgIGVsc2UNCiAgICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRfaW5kZXg9MA0KICAgICAgICAgICAgICAgIGZpDQogICAgICAgICAgICAgICAgOzsNCiAgICAgICAgICAgIEVOVEVSKQ0KICAgICAgICAgICAgICAgIHByaW50ZiAnJXNbPzI1aCcgIiRFU0MiDQogICAgICAgICAgICAgICAgb3V0X3Jlc3VsdD0kc2VsZWN0ZWRfaW5kZXgNCiAgICAgICAgICAgICAgICByZXR1cm4NCiAgICAgICAgICAgICAgICA7Ow0KICAgICAgICAgICAgRVNDKQ0KICAgICAgICAgICAgICAgIHByaW50ZiAnJXNbPzI1aCcgIiRFU0MiDQogICAgICAgICAgICAgICAgb3V0X3Jlc3VsdD0tMQ0KICAgICAgICAgICAgICAgIHJldHVybg0KICAgICAgICAgICAgICAgIDs7DQogICAgICAgIGVzYWMNCiAgICBkb25lDQp9DQoNCmdldF9jb21taXRfbGlzdCgpIHsNCiAgICBnaXQgLUMgIiRUSEVNRV9QQVRIIiBmZXRjaCBvcmlnaW4gLS1xdWlldCAyPi9kZXYvbnVsbA0KICAgIENPTU1JVF9GVUxMPSgpDQogICAgQ09NTUlUX1NIT1JUPSgpDQogICAgQ09NTUlUX0RBVEU9KCkNCiAgICBDT01NSVRfU1VCSkVDVD0oKQ0KICAgIGxvY2FsIGxpbmUgZnVsbCBzaG9ydCBkYXRlIHN1YmplY3QNCiAgICB3aGlsZSBJRlM9J3wnIHJlYWQgLXIgZnVsbCBzaG9ydCBkYXRlIHN1YmplY3Q7IGRvDQogICAgICAgIFsgLXogIiRmdWxsIiBdICYmIGNvbnRpbnVlDQogICAgICAgIENPTU1JVF9GVUxMKz0oIiRmdWxsIikNCiAgICAgICAgQ09NTUlUX1NIT1JUKz0oIiRzaG9ydCIpDQogICAgICAgIENPTU1JVF9EQVRFKz0oIiRkYXRlIikNCiAgICAgICAgQ09NTUlUX1NVQkpFQ1QrPSgiJHN1YmplY3QiKQ0KICAgIGRvbmUgPCA8KGdpdCAtQyAiJFRIRU1FX1BBVEgiIGxvZyAtLWFsbCAtLXByZXR0eT1mb3JtYXQ6IiVIfCVofCVhZHwlcyIgLS1kYXRlPXNob3J0KQ0KfQ0KDQpzaG93X2NvbW1pdF9oaXN0b3J5KCkgew0KICAgIGlmIFsgISAtZCAiJFRIRU1FX1BBVEgiIF07IHRoZW4NCiAgICAgICAgc2hvd19oZWFkZXINCiAgICAgICAgcHJpbnRmICclcyAgJXMgaXMgbm90IGluc3RhbGxlZC4lc1xuJyAiJFJFRCIgIiRUSEVNRV9OQU1FIiAiJFJFU0VUIg0KICAgICAgICBwYXVzZV9yZXR1cm4NCiAgICAgICAgcmV0dXJuDQogICAgZmkNCg0KICAgIGlmICEgdGVzdF9kZXBlbmRlbmNpZXM7IHRoZW4NCiAgICAgICAgcGF1c2VfcmV0dXJuDQogICAgICAgIHJldHVybg0KICAgIGZpDQoNCiAgICBsb2NhbCB2aWV3aW5nPTENCiAgICB3aGlsZSBbICIkdmlld2luZyIgLWVxIDEgXTsgZG8NCiAgICAgICAgZ2V0X2NvbW1pdF9saXN0DQogICAgICAgIGlmIFsgJHsjQ09NTUlUX0ZVTExbQF19IC1lcSAwIF07IHRoZW4NCiAgICAgICAgICAgIHNob3dfaGVhZGVyDQogICAgICAgICAgICBwcmludGYgJyVzICBObyBjb21taXRzIGZvdW5kLiVzXG4nICIkUkVEIiAiJFJFU0VUIg0KICAgICAgICAgICAgcGF1c2VfcmV0dXJuDQogICAgICAgICAgICByZXR1cm4NCiAgICAgICAgZmkNCg0KICAgICAgICBsb2NhbCBjdXJyZW50X2hhc2gNCiAgICAgICAgY3VycmVudF9oYXNoPSQoZ2l0IC1DICIkVEhFTUVfUEFUSCIgcmV2LXBhcnNlIEhFQUQgMj4vZGV2L251bGwpDQoNCiAgICAgICAgbG9jYWwgY3VycmVudF9pbmRleD0tMQ0KICAgICAgICBsb2NhbCBpdGVtcz0oKQ0KICAgICAgICBsb2NhbCBpDQogICAgICAgIGZvciAoKGkgPSAwOyBpIDwgJHsjQ09NTUlUX0ZVTExbQF19OyBpKyspKTsgZG8NCiAgICAgICAgICAgIGl0ZW1zKz0oIiR7Q09NTUlUX1NIT1JUWyRpXX0gICR7Q09NTUlUX0RBVEVbJGldfSAgJHtDT01NSVRfU1VCSkVDVFskaV19IikNCiAgICAgICAgICAgIGlmIFsgIiR7Q09NTUlUX0ZVTExbJGldfSIgPSAiJGN1cnJlbnRfaGFzaCIgXTsgdGhlbg0KICAgICAgICAgICAgICAgIGN1cnJlbnRfaW5kZXg9JGkNCiAgICAgICAgICAgIGZpDQogICAgICAgIGRvbmUNCiAgICAgICAgbG9jYWwgcmV0dXJuX2xhdGVzdF9pbmRleD0keyNpdGVtc1tAXX0NCiAgICAgICAgaXRlbXMrPSgiUmV0dXJuIHRvIGxhdGVzdCB2ZXJzaW9uIikNCiAgICAgICAgbG9jYWwgYmFja19pbmRleD0keyNpdGVtc1tAXX0NCiAgICAgICAgaXRlbXMrPSgiQmFjayIpDQoNCiAgICAgICAgbG9jYWwgdGl0bGVfbGluZXM9KCIke09SQU5HRV9MSUdIVH0gIENvbW1pdCBIaXN0b3J5JHtSRVNFVH0iICIiKQ0KDQogICAgICAgIGxvY2FsIHNlbGVjdGlvbg0KICAgICAgICByZWFkX2Fycm93X3NlbGVjdGlvbiBzZWxlY3Rpb24gaXRlbXMgIiRjdXJyZW50X2luZGV4IiB0aXRsZV9saW5lcw0KDQogICAgICAgIGlmIFsgIiRzZWxlY3Rpb24iIC1lcSAtMSBdIHx8IFsgIiRzZWxlY3Rpb24iIC1lcSAiJGJhY2tfaW5kZXgiIF07IHRoZW4NCiAgICAgICAgICAgIHZpZXdpbmc9MA0KICAgICAgICBlbGlmIFsgIiRzZWxlY3Rpb24iIC1lcSAiJHJldHVybl9sYXRlc3RfaW5kZXgiIF07IHRoZW4NCiAgICAgICAgICAgIHVwZGF0ZV90aGVtZQ0KICAgICAgICBlbGlmIFsgIiRzZWxlY3Rpb24iIC1nZSAwIF0gJiYgWyAiJHNlbGVjdGlvbiIgLWx0ICR7I0NPTU1JVF9GVUxMW0BdfSBdOyB0aGVuDQogICAgICAgICAgICBjaGVja291dF9jb21taXQgIiR7Q09NTUlUX0ZVTExbJHNlbGVjdGlvbl19IiAiJHtDT01NSVRfU0hPUlRbJHNlbGVjdGlvbl19IiAiJHtDT01NSVRfREFURVskc2VsZWN0aW9uXX0iICIke0NPTU1JVF9TVUJKRUNUWyRzZWxlY3Rpb25dfSINCiAgICAgICAgZmkNCiAgICBkb25lDQp9DQoNCmNoZWNrb3V0X2NvbW1pdCgpIHsNCiAgICBsb2NhbCBmdWxsPSIkMSIgc2hvcnQ9IiQyIiBkYXRlPSIkMyIgc3ViamVjdD0iJDQiDQogICAgc2hvd19oZWFkZXINCiAgICBwcmludGYgJyVzICBDaGVja2luZyBvdXQgY29tbWl0ICVzLi4uJXNcbicgIiRPUkFOR0VfTElHSFQiICIkc2hvcnQiICIkUkVTRVQiDQogICAgcHJpbnRmICclcyAgJXMgICVzJXNcbicgIiRHUkFZIiAiJGRhdGUiICIkc3ViamVjdCIgIiRSRVNFVCINCiAgICBlY2hvICIiDQogICAgcHJpbnRmICclcyAgVGhpcyB3aWxsIHN3aXRjaCB0aGUgdGhlbWUgdG8gdGhpcyBzcGVjaWZpYyB2ZXJzaW9uLiVzXG4nICIkR1JBWSIgIiRSRVNFVCINCiAgICByZWFkIC1ycCAiICBUeXBlIFkgdG8gY29uZmlybTogIiBjb25maXJtDQogICAgaWYgWyAiJGNvbmZpcm0iICE9ICJZIiBdICYmIFsgIiRjb25maXJtIiAhPSAieSIgXTsgdGhlbg0KICAgICAgICBwcmludGYgJyVzICBDYW5jZWxsZWQuJXNcbicgIiRHUkFZIiAiJFJFU0VUIg0KICAgICAgICBwYXVzZV9yZXR1cm4NCiAgICAgICAgcmV0dXJuDQogICAgZmkNCg0KICAgIGdpdCAtQyAiJFRIRU1FX1BBVEgiIGNoZWNrb3V0ICIkZnVsbCIgLS1xdWlldA0KDQogICAgaWYgY29tbWFuZCAtdiBzcGljZXRpZnkgPi9kZXYvbnVsbCAyPiYxOyB0aGVuDQogICAgICAgIGVjaG8gIiINCiAgICAgICAgcHJpbnRmICclcyAgQXBwbHlpbmcgU3BpY2V0aWZ5Li4uJXNcbicgIiRPUkFOR0VfTUlEIiAiJFJFU0VUIg0KICAgICAgICBzcGljZXRpZnkgYXBwbHkNCiAgICBmaQ0KDQogICAgZWNobyAiIg0KICAgIHByaW50ZiAnJXMgICVzIGlzIG5vdyBvbiBjb21taXQgJXMuJXNcbicgIiRHUkVFTiIgIiRUSEVNRV9OQU1FIiAiJHNob3J0IiAiJFJFU0VUIg0KICAgIHBhdXNlX3JldHVybg0KfQ0KDQpjaGVja19mb3JfdXBkYXRlcygpIHsNCiAgICBzaG93X2hlYWRlcg0KICAgIHByaW50ZiAnJXMgIENoZWNraW5nIGZvciB1cGRhdGVzLi4uJXNcbicgIiRPUkFOR0VfTElHSFQiICIkUkVTRVQiDQogICAgZWNobyAiIg0KDQogICAgaWYgWyAhIC1kICIkVEhFTUVfUEFUSCIgXTsgdGhlbg0KICAgICAgICBwcmludGYgJyVzICAlcyBpcyBub3QgaW5zdGFsbGVkLiVzXG4nICIkUkVEIiAiJFRIRU1FX05BTUUiICIkUkVTRVQiDQogICAgICAgIHBhdXNlX3JldHVybg0KICAgICAgICByZXR1cm4NCiAgICBmaQ0KDQogICAgaWYgISB0ZXN0X2RlcGVuZGVuY2llczsgdGhlbg0KICAgICAgICBwYXVzZV9yZXR1cm4NCiAgICAgICAgcmV0dXJuDQogICAgZmkNCg0KICAgIGdldF90aGVtZV9zdGF0dXNfZGV0YWlsZWQNCiAgICBwcmludGYgJyVzICBTdGF0dXM6ICVzJXMlc1xuJyAiJFdISVRFIiAiJGdldF90aGVtZV9zdGF0dXNfY29sb3IiICIkZ2V0X3RoZW1lX3N0YXR1c190ZXh0IiAiJFJFU0VUIg0KDQogICAgaWYgWyAiJGdldF90aGVtZV9zdGF0dXNfdGV4dCIgPSAiSW5zdGFsbGVkIChvdXRkYXRlZCkiIF07IHRoZW4NCiAgICAgICAgZWNobyAiIg0KICAgICAgICBwcmludGYgJyVzICBBIG5ld2VyIHZlcnNpb24gaXMgYXZhaWxhYmxlLiVzXG4nICIkR1JBWSIgIiRSRVNFVCINCiAgICAgICAgcmVhZCAtcnAgIiAgVHlwZSBZIHRvIHVwZGF0ZSBub3c6ICIgY29uZmlybQ0KICAgICAgICBpZiBbICIkY29uZmlybSIgPSAiWSIgXSB8fCBbICIkY29uZmlybSIgPSAieSIgXTsgdGhlbg0KICAgICAgICAgICAgdXBkYXRlX3RoZW1lDQogICAgICAgICAgICByZXR1cm4NCiAgICAgICAgZmkNCiAgICBmaQ0KDQogICAgcGF1c2VfcmV0dXJuDQp9DQoNCnBhdXNlX3JldHVybigpIHsNCiAgICBlY2hvICIiDQogICAgcHJpbnRmICclcyAgUHJlc3MgYW55IGtleSB0byByZXR1cm4gdG8gdGhlIG1lbnUuLi4lc1xuJyAiJEdSQVkiICIkUkVTRVQiDQogICAgSUZTPSByZWFkIC1yc24xDQp9DQoNCnNob3dfbWVudSgpIHsNCiAgICBzaG93X2hlYWRlcg0KICAgIGdldF90aGVtZV9zdGF0dXNfZGV0YWlsZWQNCg0KICAgIHByaW50ZiAnJXMgIFN0YXR1czogJXMlcyVzXG4nICIkV0hJVEUiICIkZ2V0X3RoZW1lX3N0YXR1c19jb2xvciIgIiRnZXRfdGhlbWVfc3RhdHVzX3RleHQiICIkUkVTRVQiDQogICAgZWNobyAiIg0KICAgIHByaW50ZiAnJXMgIFsxXSBJbnN0YWxsICVzJXNcbicgIiRXSElURSIgIiRUSEVNRV9OQU1FIiAiJFJFU0VUIg0KICAgIHByaW50ZiAnJXMgIFsyXSBVcGRhdGUgJXMlc1xuJyAiJFdISVRFIiAiJFRIRU1FX05BTUUiICIkUkVTRVQiDQogICAgcHJpbnRmICclcyAgWzNdIFVuaW5zdGFsbCAlcyVzXG4nICIkV0hJVEUiICIkVEhFTUVfTkFNRSIgIiRSRVNFVCINCiAgICBwcmludGYgJyVzICBbNF0gQ29tbWl0IEhpc3RvcnkgLyBEb3duZ3JhZGUlc1xuJyAiJFdISVRFIiAiJFJFU0VUIg0KICAgIHByaW50ZiAnJXMgIFs1XSBDaGVjayBmb3IgVXBkYXRlcyVzXG4nICIkV0hJVEUiICIkUkVTRVQiDQogICAgcHJpbnRmICclcyAgWzZdIEV4aXQlc1xuJyAiJFdISVRFIiAiJFJFU0VUIg0KICAgIGVjaG8gIiINCiAgICBwcmludGYgJyVzICA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09JXNcbicgIiRPUkFOR0VfREFSSyIgIiRSRVNFVCINCiAgICBlY2hvICIiDQogICAgcmVhZCAtcnAgIiAgU2VsZWN0IGFuIG9wdGlvbjogIiBjaG9pY2UNCiAgICBNRU5VX0NIT0lDRT0iJGNob2ljZSINCn0NCg0KcnVubmluZz0xDQp3aGlsZSBbICIkcnVubmluZyIgLWVxIDEgXTsgZG8NCiAgICBzaG93X21lbnUNCiAgICBjaG9pY2U9IiRNRU5VX0NIT0lDRSINCiAgICBjYXNlICIkY2hvaWNlIiBpbg0KICAgICAgICAxKSBpbnN0YWxsX3RoZW1lIDs7DQogICAgICAgIDIpIHVwZGF0ZV90aGVtZSA7Ow0KICAgICAgICAzKSB1bmluc3RhbGxfdGhlbWUgOzsNCiAgICAgICAgNCkgc2hvd19jb21taXRfaGlzdG9yeSA7Ow0KICAgICAgICA1KSBjaGVja19mb3JfdXBkYXRlcyA7Ow0KICAgICAgICA2KSBydW5uaW5nPTAgOzsNCiAgICAgICAgKikNCiAgICAgICAgICAgIHNob3dfaGVhZGVyDQogICAgICAgICAgICBwcmludGYgJyVzICBJbnZhbGlkIG9wdGlvbi4lc1xuJyAiJFJFRCIgIiRSRVNFVCINCiAgICAgICAgICAgIHBhdXNlX3JldHVybg0KICAgICAgICAgICAgOzsNCiAgICBlc2FjDQpkb25lDQoNCmNsZWFy"
ok=true
step1() {
mkdir -p "$targetDir"
}
invoke_step "Creating install directory" step1 || ok=false
step2() {
echo "$spotuiScriptContentBase64" | base64 -d | tr -d '\r' > "$scriptPath"
chmod +x "$scriptPath"
}
invoke_step "Writing SpoTUI script" step2 || ok=false
step3() {
printf '#!/usr/bin/env bash\nexec "%s" "$@"\n' "$scriptPath" > "$wrapperPath"
chmod +x "$wrapperPath"
}
invoke_step "Creating wrapper script" step3 || ok=false
step4() {
mkdir -p "$binDir"
local profileFile="$HOME/.bashrc"
if [ -n "$ZSH_VERSION" ] || [ -f "$HOME/.zshrc" ]; then
profileFile="$HOME/.zshrc"
fi
if ! grep -q "$binDir" "$profileFile" 2>/dev/null; then
echo "export PATH=\"\$PATH:$binDir\"" >> "$profileFile"
fi
}
invoke_step "Updating PATH" step4 || ok=false
export PATH="$PATH:$binDir"
step5() {
printf '#!/usr/bin/env bash\nexec "%s" "$@"\n' "$wrapperPath" > "$binPath"
chmod +x "$binPath"
}
invoke_step "Creating launcher" step5 || ok=false
echo ""
echo "${OrangeDark} =============================================================${Reset}"
echo ""
if $ok; then
echo " ${GreenAnsi}${CheckMark} SpoTUI installed successfully.${Reset}"
echo " ${GrayAnsi} Open a new terminal and run: spotui${Reset}"
else
echo " ${RedAnsi}${CrossMark} Installation finished with errors. See above.${Reset}"
fi
echo ""