#!/bin/bash

alias aliases='alias && cat /home/pi/.bash_aliases | grep -vi "^[#]" | grep -v aliases | grep "()" | cut -d" " -f1'
alias alias-edit='sudo nano /home/pi/.bash_aliases'
alias 'thd_conf'='cd /home/pi/ADMIN/.sys/thd/conf'
alias 'cd..'='cd ..'
alias volts='echo "$(vcgencmd measure_volts | cut -d= -f2)"'
alias txt='sudo nano'
alias run='sudo bash'
alias dump='sudo tee'
alias ll='ls -lah --color=always --group-directories-first'
alias sizes='sudo du -sh ./* | sort -hr'
alias sizeof='sudo du -sh'
alias wget='wget --no-check-certificate'
alias vlc='vlc -vvv'
alias py='sudo python3'
alias colon='printf ":"'
alias ascii='man ascii | sed -n "/Oct/,/Tables/p" | head -n -2'
alias myip='hostname -I | cut -d" " -f1'
alias res='cat /sys/class/graphics/fb0/virtual_size'
alias ansicolors='for code in {0..255}; do echo -e "\e[38;05;${code}m $code: Test"; sleep 0.2; done'
alias drawrnd='cat /dev/urandom | dd bs=1 count=$(cat /sys/class/graphics/fb0/stride) | dd bs=1 seek=1 of=/dev/fb0'
alias stride='echo "  $(cat /sys/class/graphics/fb0/stride)"'
alias psset='export PS1="> $ "'
alias psdump='echo "  PS1: $PS1"'
alias decolor.styles='sed -E "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})*)?[m,K,H,f,J]//gm"'
alias decolor.reset='sed -E "s/\x1B\([A-Z]{1}(\x1B\[[m,K,H,f,J])?//gm"'
alias decolor='decolor.styles | decolor.reset'

alias outbox='cat /home/pi/ADMIN/.log/serial.log'
alias backup='sudo bash /home/pi/ADMIN/CMD/BACKUP/BACKUP.sh'
alias ftp='sudo sshpass -f /home/pi/ADMIN/CMD/BACKUP/.pass sftp dogenigt@data.dogenigt.dk'
alias reload='clear && source /home/pi/.bashrc'
alias lsdev='ls -l --color=always /dev/ | cut -c 49- | less -R'
alias autostart='sudo nano /opt/retropie/configs/all/autostart.sh'
alias retroarch='/opt/retropie/emulators/retroarch/bin/retroarch'

cputmp=$(( $(cat /sys/class/thermal/thermal_zone0/temp)/100 ));cputmp=$(echo "$cputmp" | sed 's/./&./2')
alias temp='echo -e "GPU: $( sudo vcgencmd measure_temp | cut -d'=' -f2)";echo -e "CPU: $(echo -e $cputmp )\x27C"'
#alias blanktime='cat /sys/module/kernel/parameters/consoleblank'

# --------------------------------------------------------------------------------------

# QUICK COMMANDS:

alias settings='cat /home/pi/ADMIN/.sys/.settings'
alias state='cat /home/pi/ADMIN/.sys/thd/devices.log'
alias states='cat /home/pi/ADMIN/.sys/thd/states.log | tail -n +2'
alias serial_log='cat /home/pi/ADMIN/.log/serial.log'

alias gamemenu='sudo bash /home/pi/ADMIN/MENU/GAMES.sh "$@"'
alias menu='sudo bash /home/pi/ADMIN/MENU/MENU.sh "$@"'
alias saver='sudo bash /home/pi/ADMIN/MENU/.assets/saver/.source.sh'
alias saverfifo='sudo bash /home/pi/ADMIN/MENU/saver_fifo.sh'
#alias savertest='sudo bash /home/pi/ADMIN/MENU/.assets/saver/bgSaver.sh &'
alias savertest='sudo bash /home/pi/ADMIN/MENU/.assets/saver/tests/saver_test.sh'
alias saverkill='sudo pkill -f "menu_saver" &>/dev/null; sleep 1; clear; sudo setterm --cursor on'

alias scancoin='sudo scanmem -p `pidof retroarch` -c"option region_scan_level 3;reset"'
alias cafcatail="tail -F /home/pi/CAFCA/log/CAFCA.log"
alias teensytest='evtest /dev/input/by-id/usb-Teensyduino_Serial_Keyboard_Mouse_Joystick_1008140-if02-event-kbd'
alias mamecfg='cd /home/pi/RetroPie/roms/mame-libretro/mame2003/cfg; ls -la'
alias pageedit='sudo bash /home/pi/ADMIN/MENU/.assets/helpers/page_editor.sh'

alias testvid='sudo bash '
#alias testvid='omxplayer --genlog --aspect-mode fill --key-config /home/pi/ADMIN/MENU/.assets/config/omx_config.cfg /home/pi/ADMIN/MENU/.assets/media/screensaver/vid/arcade.mp4 >/dev/null 2>&1'

# --------------------------------------------------------------------------------------


blanktime() {
  local settings='/home/pi/ADMIN/.sys/.settings'
  local timeout="$(( $(cat /sys/module/kernel/parameters/consoleblank) / 60 ))"
  local console=/dev/tty1
  local val=$2

  [[ $(grep -c "console='.*'" $settings) -gt 0 ]] && console=$(sed -n '/console=/ { s/\(.*\)=//g; s/\x27//g; p }' $settings)

  echo -e "blanktime:"

  if [[ ${1,,} == set ]]; then
    if [[ $val =~ ^[0-9]+$ ]]; then
      [[ $val -ge 60 ]] && val=$(( val / 60 ));
      echo "setting timeout to $val minute(s)."
      echo -ne "\033[9;$val]" > $console
    else
      echo "unable to set timeout. invalid value."
    fi
  elif [[ ${1,,} == get ]] || [[ $# -lt 1 ]]; then
    [[ $timeout -eq 0 ]] && echo "0 (OFF)" || echo "$timeout minute(s)"
  fi
}

trigger() {
  [ $# -lt 2 ] && return
  local action=$1; local target=$2
  local script='/home/pi/ADMIN/.sys/thd/states.sh'
  local settings=/home/pi/ADMIN/.sys/.settings
  local cmd="sudo th-cmd --socket /run/thd.socket"

  for i in $(seq 1 $#); do [ $i -eq $# ] && param="${!i}" || { [ "${!i}" == grab ] && cmd="${cmd} --add"; cmd="${cmd} --${!i}"; }; done
  [[ "$param" == @(joystick|teensy) ]] && { id=$(sed -n "/^.*\s${param}=/ { s/\(.*\)=//g; s/\x27//g; p }" $settings); param="$id --tag ${param}"; }; cmd="${cmd} $param";

  echo -e "RUN COMMAND? [y/n]:\n'${cmd}'\n"
  [[ ! $(read -sn1 a</dev/stdin;echo $a) == [yY] ]] && return

  if [[ "$action" == @(add|remove|grab|mode) ]]; then
    [[ "$action" == mode ]] || [[ "$target" == @(teensy|joystick|gun|udev) ]] && sudo bash "$script" "${action}" "${target}" && cat /home/pi/ADMIN/.sys/thd/devices.log
  fi
}

trigger_old() {
  local script='/home/pi/ADMIN/.sys/thd/states.sh'
  [ $# -lt 2 ] && return
  local action=$1; local target=$2

  if [[ "$action" == @(add|remove|grab|mode) ]]; then [[ "$action" == mode ]] || [[ "$target" == @(teensy|joystick|gun|udev) ]] && sudo bash "$script" "${action}" "${target}"; fi
}

txtf() {
  local file=
  local arg=''
  local colors=''

  declare -A txtfiles=( \
    [asoundrc]='/home/pi/.asoundrc' \
    [autostart]='/opt/retropie/configs/all/autostart.sh' \
    [backup]='/home/pi/ADMIN/CMD/BACKUP/BACKUP.sh' \
    [bgsaver]='/home/pi/ADMIN/.sys/saver/bg.sh' \
    [boot]='/boot/boot.sh' \
    [bootlog]='/boot/boot.log' \
    [cafca]='/home/pi/CAFCA/CAFCA.sh' \
    [cafca_cfg]='/home/pi/CAFCA/cfg/cafca.cfg' \
    [cafca_log]='/home/pi/CAFCA/log/CAFCA.log' \
    [cafca_states]='/home/pi/CAFCA/data/.states' \
    [cafca_settings]='/home/pi/CAFCA/data/.settings' \
    [cafca_table]='/home/pi/CAFCA/data/mame-libretro/table' \
    [cafca_timers]='/home/pi/CAFCA/data/mame-libretro/timers' \
    [cafca_clearram]='/home/pi/CAFCA/data/mame-libretro/clearram' \
    [cmdline]='/boot/cmdline.txt' \
    [config]='/boot/config.txt' \
    [emulationstation]='/opt/retropie/supplementary/emulationstation/emulationstation.sh' \
    [es_log]='/home/pi/ADMIN/.log/es.log'
    [es_debug]='/home/pi/ADMIN/.log/emulationstation.log'
    [es-end]='/home/pi/ADMIN/CMD/ES/es-onend.sh' \
    [es-script]="/home/pi/.emulationstation/scripts/${2}/0_serial.sh"
    [es-start]='/home/pi/ADMIN/CMD/ES/es-onstart.sh' \
    [es_settings]='/home/pi/.emulationstation/es_settings.cfg' \
    [es_systems]='/home/pi/.emulationstation/es_systems.cfg' \
    [ra_log]='/home/pi/CAFCA/log/retroarch/retroarch.log' \
    [menu]='/home/pi/ADMIN/MENU/MENU.sh' \
    [menu_index]='/home/pi/ADMIN/MENU/.assets/index' \
    [menu_commands]='/home/pi/ADMIN/MENU/.assets/helpers/commands.sh' \
    [menu_saver]='/home/pi/ADMIN/MENU/.assets/saver/bgSaver.sh' \
    [menu_settings]='/home/pi/ADMIN/MENU/.assets/.settings' \
    [games_menu]='/home/pi/ADMIN/MENU/GAMES.sh' \
    [runcmd-start]='/opt/retropie/configs/all/runcommand-onstart.sh' \
    [runcmd-end]='/opt/retropie/configs/all/runcommand-onend.sh' \
    [saver]='/home/pi/ADMIN/MENU/.assets/saver/saver.sh' \
    [serial]='/home/pi/ADMIN/CMD/SERIAL/SERIAL.sh' \
    [serial_log]='/home/pi/ADMIN/.log/serial.log' \
    [settings]='/home/pi/ADMIN/.sys/.settings' \
    [sleep]='/home/pi/ADMIN/CMD/SLEEP/SLEEP.sh' \
    [states]='/home/pi/ADMIN/.sys/thd/states.sh' \
    [states_devlog]='/home/pi/ADMIN/.sys/thd/devices.log' \
    [states_log]='/home/pi/ADMIN/.sys/thd/states.log' \
    [sys_settings]='/boot/sys_settings' \
    [thd_conf_teensy]='/home/pi/ADMIN/.sys/thd/conf/triggers/teensy.conf' \
    [thd_conf_joystick]='/home/pi/ADMIN/.sys/thd/conf/triggers/joystick.conf' \
    [thd_conf_term]='/home/pi/ADMIN/.sys/thd/conf/triggers/term.conf' \
    [thd_conf_saver]='/home/pi/ADMIN/.sys/thd/conf/triggers/saver.conf' \
    [thd_conf_udev]='/home/pi/ADMIN/.sys/thd/conf/triggers/udev.conf' \
    [thd_cmd_teensy]='/home/pi/ADMIN/CMD/THD/TEENSY.sh' \
    [thd_cmd_joystick]='/home/pi/ADMIN/CMD/THD/JOYSTICK.sh' \
  )

  clear

  if [ "${#}" -lt 1 ]; then
    for i in "${!txtfiles[@]}"; do echo -ne "\x27$i\x27: ${txtfiles[$i]}"; [ ! -f "${txtfiles[$i]}" ] && echo " - not found!" || echo ""; done
  else
    if [ "${#}" -gt 1 ]; then
      arg="${1}"; file="${2}"

      if [[ $arg == run ]]; then
        sudo bash "${txtfiles[$file]}"
      elif [[ $arg == cat ]]; then
        cat "${txtfiles[$file]}"
      else
        [[ $arg == es-script ]] && txt_file="${txtfiles[$arg]}" || txt_file="${txtfiles[$file]}"
        case $arg in 'n'|'-n'|'--n'|'none'|'--none'|'-none') colors='-Ynone' ;; esac
        sudo nano "$colors" "$txt_file"
      fi
    else
      file="${1}"; sudo nano "${txtfiles[$file]}"
    fi
  fi
}


loadtyper() {
  sudo bash /home/pi/ADMIN/.sys/joytyper/joytyper.sh RESTART
  clear; echo "joytyper initialized."
}

vfdtester() {
  local str=''; local count=1; local valid=0
  clear; echo -e "VFD CHAR TESTER v0.1"

  if [ $# -gt 0 ]; then
    if [[ $1 =~ [Xx][0-9A-Fa-f]{1,}$ ]]; then
      if [[ ! $(echo "$(( 0x${1##*x} ))") == 92 ]]; then
        echo -e " - printing hex: '0x${1##*x}' ( $(( 0x${1##*x} )) )\n"
        str=$(printf "\x$(printf %x $(( 0x${1##*x} )))"); valid=1
      fi
    elif [[ $1 =~ ^[0-9]+$ ]]; then
      if [[ $2 =~ ^[0-9]+$ ]]; then
        for i in $(seq $1 $2); do
          str=$(printf "\x$(printf %x $i)"); echo -e "printing $i ($(printf '0x%x' $i))"
          echo "VFD 0 $i ($(printf '0x%x' $i)) : ${str}" > /tmp/serial.fifo; sleep 5
        done; return
      else
        if [[ ! $1 == 92 ]]; then
          echo -e " - printing: '${1}' ( $(printf '0x%x' $1) )\n"
          str=$(printf "\x$(printf %x $1)"); valid=1
        fi
      fi
    fi
  fi

  if [[ $valid -gt 0 ]]; then
    echo "VFD 0 ${str}" > /tmp/serial.fifo;
  else
    echo -e " - press ESC to exit\n"
    for i in {1..255}; do
      [[ $i -ne 92 ]] && str+=$(printf "\x$(printf %x $i)")
      [[ $count -gt 0 ]] && [[ $(( count % 16 )) -eq 0 ]] && { echo -e "press key to send $(( count - 16 )) - $count"; read -rsn1 input >/dev/null; read -rsn5 -t 0.01 input2 >/dev/null; case $input$input2 in $'\E') return ;; esac; echo "VFD 0 ${str}" > /tmp/serial.fifo; str=''; }
      (( count++ ))
    done;
    [[ ${#str} -gt 0 ]] && { echo -e "press key to send $(( count - 16 )) - $count"; read -rsn1 input >/dev/null; read -rsn5 -t 0.01 input2 >/dev/null; case $input$input2 in $'\E') return ;; esac; echo "VFD 0 ${str}" > /tmp/serial.fifo; str=''; }
  fi
}

printterm() {
  echo -e "  term: '$TERM'\n  tty:  '$(tty)'\n  proc: '$(ps -o 'cmd=' -p $(ps -o 'ppid=' -p $$))'"
}

printheader() {
  local width=$(( $(tput cols)-1 ))
  local pos=0
  local str="${@:-games}"
  local text=$(printf "$(figlet -w $width -c ${str} -f /usr/share/figlet/fonts/Calvin_S.flf)")

  clear; tput cup 0 0
  for i in $(seq 0 $width); do printf " "; done
  tput cup 0 0; echo "${text}"; pos=$(printf "${text}" | wc -l); (( pos++ ))
  tput cup $pos 0
  for i in $(seq 0 $width); do printf "-"; done; printf "\n"
}

figprint() {
 local font_path='/usr/share/figlet/fonts'
 local fonts=$(find /usr/share/figlet/fonts -type f -iname '*.flf' | grep -o '[^/]*$')
 local count=$(echo "${fonts}" | wc -l)
 local str="${@:2}"; str="${str:-TEST}"

 # local index="${@:1:1}"; index="${index:-$(( RANDOM % count ))}"; [[ $index -gt $count ]] && index=$(( RANDOM % count ))
 local index="${@:1:1}";

 if [[ $index =~ ^[0-9]+$ ]]; then
   [[ $index -eq 0 ]] || [[ $index -gt $count ]] && index=$(( RANDOM % count ))
   local font=$(echo "${fonts}" | sed -n "${index}p"); font="$font_path/$font"
 elif [[ $index =~ ^[A-Za-z_]+$ ]]; then
   local font=$(find $font_path -type f -iname "$index.flf")
 fi

 #echo "# $index: $font_path/$font - str: $str"
 clear; printf "\n\n"
 figlet -w $(tput cols) -c "${str}" -f $font
}

#footer() { [ $# -gt 0 ] && { tput sc; tput cup $(tput lines) 0; printf "$@"; tput rc; }; }

footer() {
 local msg="${1:-$(date '+%F %T')}"
 local float=${2:-0}
 echo "$msg"
}


lastcmd() { w --no-header -u | grep tty1 | awk '{$1=$1;print}' | cut -d' ' -f8-; }

readInput() {
  local tty='/dev/tty1'; local lnbreak=0
  [[ $# -gt 0 ]] && [ -c "${1}" ] && tty="${1}"
  [[ $# -gt 1 ]] && [[ $2 -gt 0 ]] && lnbreak=1

  clear; echo -e "Reading input from '$tty'\n"

  while true; do
        read -rs -N 1 -u 6 Event1 6<$tty
        case "$Event1" in
            [[:graph:]])    Event="${Event1^^}" 		;;
            $'\n')          Event="ENTER"   			;;
            ' ')            Event="SPACE"   			;;
            [[:blank:]])    Event="TAB"     			;;
            *)
                read -t 0.01 -rsn5 -u 6 Event2 6<$tty
                case "$Event2" in
                    "[A")       Event="UP"          		;;
                    "[B")       Event="DOWN"        		;;
                    "[D")       Event="LEFT"        		;;
                    "[C")       Event="RIGHT"       		;;

                    "[P"|"[3~")     Event="DEL"         	;;
                    "[4h"|"[2~")    Event="INS"         	;;
                    "[4~"|"[F")     Event="END"         	;;
                    "[H"|"[1~")     Event="HOM"         	;;
                    "[5~")          Event="PGUP"        	;;
                    "[6~")          Event="PGDO"        	;;

                    "OP"|"[[A")     Event="F1"          	;;
                    "OQ"|"[[B")     Event="F2"          	;;
                    "OR"|"[[C")     Event="F3"          	;;
                    "OS"|"[[D")     Event="F4"          	;;
                    "[15~"|"[[E")   Event="F5"          	;;
                    "[17~")         Event="F6"          	;;
                    "[18~")         Event="F7"          	;;
                    "[19~")         Event="F8"          	;;
                    "[20~")         Event="F9"         		;;
                    "[21~")         Event="F10"         	;;
                    "[23~")         Event="F11"         	;;
                    "[24~")         Event="F12"         	;;
                    *)

                case "$Event1$Event2" in
                    $'\E')          Event="ESC"     		;;
                    $'\177')  	    Event="BCKSPC"  		;;
		    [[:graph:]])    Event="$Event1$Event2" 	;;
                    *)  	    Event="?"       		;;
                esac
                ;;
                esac
        esac
        printf "${Event} "; (( lnbreak > 0 )) && printf "\n"
  done
}

readhexkey() {
  local tty='/dev/tty1'
  [[ $# -gt 0 ]] && [ -c "${1}" ] && tty="${1}"

  clear; echo -e "tty: $tty\nPress key..\n"
  read -srn1 -u 6 a 6<$tty; read -sr -t 0.2 -u 6 b 6<$tty

  echo $a$b | hexdump -C | head -n 1 | sed 's/^[[:digit:]]\+[[:blank:]]\+//g;s/0a.*$//g'

  #local fd=$([ $# -gt 0 ] && [[ "$1" =~ ^[0-9]+$ ]] && echo $1 || echo 6)
  #read -srn1 -u $fd a $fd</dev/tty1		# wait for input
  #read -sr -t 0.2 -u $fd b $fd</dev/tty1 	# append rest of input
  #local output=$(echo $a$b | hexdump -C | head -n 1 | sed 's/^[[:digit:]]\+[[:blank:]]\+//g;s/0a.*$//g')
  #echo "${output^^}"
}

getEvents() {
  local count=$(ls /sys/class/input | grep event | sed 's/event//g' | sort -n | tail -n 1)
  for i in $(seq 0 $count); do
    local name=$(cat "/sys/class/input/event$i/device/name")
    local index=$(cat "/sys/class/input/event$i/device/uevent" | grep '^PHYS' | sed 's/\(\"\|.*\/\)//g')
    echo -e "/dev/input/event$i:\t$name ($index)"
  done
}

mnu() { export NEWT_COLORS="$(cat /home/pi/ADMIN/MENU/.assets/config/whiptail_theme.cfg)"; whiptail "$@" 2>&1 1>/dev/tty ; }

msgbox() {
  dialog --create-rc /home/pi/.dialogrc
  cp -f /home/pi/ADMIN/MENU/.assets/config/.dialogrc /home/pi/.dialogrc
  dialog --colors --title "MENU" --yesno "ITEM" 20 40
  clear
  [[ ! "$1" -eq 0 ]] && rm /home/pi/.dialogrc || echo "preserved .dialogrc"
}

whipbox() {
  export NEWT_COLORS="$(cat /home/pi/ADMIN/MENU/.assets/config/whiptail_theme.cfg)"
  whiptail --yesno "$(echo 'HERE IS SOME TEXT')" 0 0 2>&1 1>/dev/tty
  [ $? -eq 0 ] && msgbox
  clear
  #echo -e "\nEXIT CODE: $?"
}


#menu() { whiptail "$@" 3>&1 1>&2 2>&3 3>&- ; }

menu_functions() {
  local index='/home/pi/ADMIN/MENU/.assets/index'

  while read line; do
    str=$(echo "${line^^}" | cut -d_ -f2- ); str=$(for (( c=0; c<=${#str}; c++ )); do printf "${str:$c:1} "; done | sed 's/_/ /g'); echo -e "$line() { clear; echo \x22 $(echo "${str}")\x22; sleep 2; } ";
  done< <(cat $index | sed -E 's/\t|@//g' | grep -v '^$\|^\s*#' | awk -F'\x27' '{print $2}' | grep -v '^$\|^\s*#') > "${index%/*}/functions" && clear; cat "${index%/*}/functions"
}

showtime() {
  local state="$(case ${1,,} in '1'|'on'|'true'|'enabled') echo 1 ;; '0'|'off'|'false'|'disabled') echo 0;; *) echo '-1' ;; esac;)"
  (( $state )) && export TIME_STYLE=long-iso || export TIME_STYLE='+%Y-%m-%d'
  echo "show time: $state"
}

joytyper() {
  local pos=0
  local input=
  local count=0
  local chars=($( \
    for i in {97..123}; do printf "\\x$(printf %02x $i)\n"; done; \
    for i in {48..57}; do printf "\\x$(printf %02x $i)\n"; done; \
    for i in 46 44 45 33 63 47 59 58 61 34 39 60 62; do printf "\\x$(printf %02x $i)\n"; done; \
    for i in {90..65}; do printf "\\x$(printf %02x $i)\n"; done \
  ))

  #[[ $# -gt 0 ]] && [[ "$1" =~ ^[0-9]+$ ]] && echo "${chars[$1]}"

  clear
  read -rs -t 1 void >/dev/null; tput sc

  while true; do
    while [[ ${#input} -lt 1 ]]; do read -rs -N 3 -t 0.1 input >/dev/null; done; sleep 0.1
    read -rsn3 -t 0.01 input2 >/dev/null
    case $input$input2 in $'\E') input=00 ;; *) input=$(echo ${input} | hexdump -C | awk '{print $4}' | head -n 1) ;; esac
    [[ $input == 00 ]] && break
    [[ $input == 43 ]] && { (( pos++ )); tput cup 0 $pos; tput sc; }
    [[ $input == 44 ]] && [[ $pos -gt 0 ]] && { (( pos-- )); tput cup 0 $pos; tput sc; }
    [[ $input == 41 ]] && count=$(( count + 1 )); [[ $input == 42 ]] && count=$(( count - 1 ));
    [[ $count -lt 0 ]] && count=$(( ${#chars[@]} - 1 )) || { [[ $count -ge ${#chars[@]} ]] && count=0; }

    printf "${chars[$count]}"; tput rc; input=
    #echo -e "$input - ${chars[$count]} ($count)"; input=
  done
}

typecode() {
  local key=$(grep -w -m1 'admin_menu_pass' /home/pi/ADMIN/.sys/.settings | cut -d\' -f2 | base64 -d)
  [[ $(type -t joy) == 'function' ]] && for (( c=0; c<${#key}; c++ )); do joy $(echo "${key:$c:1}" | tr '[:upper:]' '[:lower:]'); done
}


fbdraw() {
  local WIDTH=$(cat /sys/class/graphics/fb0/stride)
  local HEIGHT=$(cat /sys/class/graphics/fb0/virtual_size | cut -d, -f2)
  local COLOR=`printf "\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\\\\\x00%0.s" $(seq 1 $WIDTH)`
  for i in $(seq 0 $HEIGHT); do printf $COLOR | dd bs=1 seek=$(( WIDTH * i )) of=/dev/fb0 >/dev/null 2>&1; done
}

fberase() {
  local WIDTH=$(cat /sys/class/graphics/fb0/stride)
  local HEIGHT=$(cat /sys/class/graphics/fb0/virtual_size | cut -d, -f2)

  local COLOR=''
  [[ $# -lt 1 ]] && COLOR=`printf '\\\\x00\\\\x00\\\\x00\\\\x00%0.s' $(seq 1 $WIDTH)` \
  || COLOR=`printf "\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\\\\\x00%0.s" $(seq 1 $WIDTH)`

  for i in $(seq 0 $HEIGHT | shuf); do printf $COLOR | dd bs=1 seek=$(( WIDTH * i )) of=/dev/fb0 >/dev/null 2>&1; done
}

drawimg() {
  sudo bash /home/pi/ADMIN/MENU/.assets/media/marquees/overlay.sh
}

menu_list() {
  local list='/home/pi/ADMIN/MENU/.assets/list'
  [ $# -lt 1 ] && { cat "$list"; return; }
  grep -i -m1 "$@" "$list"
}

cafcamode() {
  if [ $# -gt 0 ]; then
    local MODE="${@^^}"
    [[ "${MODE}" == @(DUMP|SCAN) ]] && sudo sed -i 's|ACTION[=].*$|ACTION='"\x27$MODE\x27"'|g' /home/pi/CAFCA/data/.settings
  fi
  echo -e "/home/pi/CAFCA/data/.settings:\n  $(cat /home/pi/CAFCA/data/.settings | grep -m1 '^ACTION' | cat)"
}

scandump() {
  [ $# -lt 1 ] && return
  local ADDR="${1}"

  if [[ $(echo "$ADDR" | grep -c "[[:xdigit:]]") -gt 0 ]]; then
    ADDR=$(printf '0x%02x' "$ADDR")
    sudo scanmem -p `pidof retroarch` -c"dump $ADDR 1;exit" 2>&1 | awk 'NR==15' | awk -F' ' '{print $2}'
  fi
}

cfg() {
  [ $# -lt 1 ] && return
  local name="${@%%.*}"
  local path="/home/pi/RetroPie/roms/mame-libretro/${name,,}.zip"

  [ -f $path ] && { \
    echo "nano $path"; nano "${path}.cfg"; \
  } || echo "'${path}' not found"
}

getmod() {
  stat -c'%a %U %n' "$@"
}

histgrep() {
  grep "${@}" /home/pi/.bash_history
}

dim() {
  [ $# -lt 1 ] && return
  file "${@}" | grep -oe '\([0-9.]*\)x\([0-9.]*\)' | grep --color=never -E '[0-9]{2}'
}

dur() {
  local dur=$(ffmpeg -i "$@" 2>&1 | grep "Duration" | cut -d: -f3- | cut -d, -f1 | cut -d. -f1)
  echo "$(( ( $(echo $dur | cut -d: -f1) * 60 ) + $(echo $dur | cut -d: -f2) ))"
}

bgsaver() {
  sudo bash /home/pi/ADMIN/MENU/.assets/saver/saver.sh
}

sshcmd() {
  local cmd="${1:-''}"

  case "${cmd}" in
    'clear')    printf 'clear\rsleep\x201\rclear\r' 	> /tmp/vkbdd.fifo ;;
    'silent')   printf 'stty\x20/echo\r'	 	> /tmp/vkbdd.fifo ;;
    'verbose')  printf 'stty\x20echo\r'	 		> /tmp/vkbdd.fifo ;;
    *) 		printf "$cmd\r" 			> /tmp/vkbdd.fifo ;;
  esac
}

fbdump() {
  [[ $# -lt 1 ]] && return || \
  local mode="${1}"
  local path="${2:-/home/pi/fb0.dump}"
  [[ "${mode^^}" == @(SET|-SET|--SET|STORE|-STORE|--STORE|S|-S|--S) ]] && { \
    sudo cat /dev/fb0 > "$path"; }
    #sudo cp -r /dev/fb0 "$path"; }
  [[ "${mode^^}" == @(GET|-GET|--GET|RESTORE|-RESTORE|--RESTORE|R|-R|--R) ]] && { \
    [ -e "$path" ] && { echo "found!"; sleep 2; sudo cat "$path" > /dev/fb0; }; \
  }
}

hexstring() {
  local param=; local args=()
  [[ $# -lt 1 ]] && return || args=("${@}")
  [[ ${args[0]:1:1} == - ]] && { param=$(echo "${args[0]}" | sed "s/\-//g"); args="${args[@]:1}"; }
  local string=$(printf "${args[@]}")

  if [[ ${param} == d ]] || [[ $param == decode ]]; then
    echo "${string}" | awk 'BEGIN{RS=","}{$1=$1}1' | xxd -r -p; echo ""
  else
    string=$(printf "${string}" | hexdump -C | grep -o ' \([0-9aA-fF]\{2\}\)' | awk '{$1=$1;print}')
    [[ ${param} == n ]] || [[ $param == line ]] && echo "${string^^}" ||  echo "${string^^}" | awk 'BEGIN{RS=","}{$1=$1}1'
  fi
}

chod() {
  [ ! -e "${@}" ] && return || { \
    [ -f "${@}" ] && echo -e "set '${@}' to 775 and pi:root? y/n"; \
    [ -d "${@}" ] && echo -e "set all in '${@}' to 775 and pi:root? y/n"; \
    read -sN1 confirm; \
    case $confirm in [yY]) sudo chown -R pi:root "${@}" && sudo chmod -R 775 "${@}"; ls -lah $PWD ;; *) return ;; esac; \
  }
}

bak() {
  [ $# -lt 1 ] && return || input="${1}"

  [ -d "$input" ] \
  && { path="$input"; } \
  || { \
    [[ "$input" =~ '/' ]] \
    && { dir="$(echo $input | rev | cut -d/ -f2- | rev)"; file="$(echo $input | grep -o '[^/]*$')"; } \
    || { dir=$(echo "${PWD##}"); file="$input"; }; \
    [ -f "$dir/$file" ] && { path="$dir/$file"; } || { echo "$dir/file not found.."; return; } \
  }

  target="${path}.bak$(date +%y%m%d%H%M%S)"

  [ -e "$path" ] \
  && { sudo cp -R "${path}" "${target}"; [ $? -lt 1 ] && echo -e "path:   $path\ntarget: $target"; } \
  || {  echo "'$path' is not a valid path."; }
}

bootmode() {
  if [ $# -gt 0 ]; then
    case $@ in
      'es'|'menu'|'game'|'term'|'none')
        sudo sed -i 's|boot_mode[=].*$|boot_mode='"\x27$@\x27"'|g' /boot/sys_settings
        echo -e "Changed boot mode!\n"
        ;;
      *)
        echo -e "Plese type a valid mode:\n  'es', 'menu', 'game', 'none'\n"
        ;;
    esac
  fi
  echo -e "/boot/sys_settings:\n  $(cat /boot/sys_settings | grep boot_mode | cat)"
}


ns() {
  tail=${1:-'13'}; head=${2:-'6'}
  [ $# -gt 0 ] && [[ ${1} =~ ^[0-9]+$ ]] && tail=${1} || tail='13'
  [ $# -gt 1 ] && [[ ${2} =~ ^[0-9]+$ ]] && head=${2:-'6'} || head='6'

  echo $(date +%s%N | tail -c $tail | head -c $head);
}

elapsed() {
  s=$(printf $(date +%s) | tail -c 3)
  [[ "${@}" == set ]] && export elapsed=$s
}

th() {
  [ $# -gt 0 ] && args=("${@}") || return

  cmd="sudo th-cmd --socket /run/thd.socket"

  for ((i=0; i<${#args[@]}; i++)); do
    [[ $i == $(( ${#args[@]}-1 )) ]] && param="${args[$i]}" || cmd="${cmd} --${args[$i]}"
  done

  case $param in
    'joystick') param="/dev/input/by-id/usb-SHANWAN_Skyuan_F16-event-joystick --tag $param" ;;
    'teensy') param="/dev/input/by-id/usb-Teensyduino_Serial_Keyboard_Mouse_Joystick_1008140-if02-event-kbd --tag $param" ;;
    *) ;;
  esac

  cmd="${cmd} $param"; echo -e "'${cmd}'\n"

  read -rN1 -p "eval cmd? [Y/n]: " choice && echo -e "\n"
  [[ ${choice,,} != y ]] && { echo "User aborted.."; return; }

  #eval "$cmd"
}

cafca_dump() {
  declare -A DATA=()

  game_info=$(grep ACTIVE_GAME "/home/pi/CAFCA/data/.states" | cut -d\' -f 2)

  while read line; do
    k=$(echo $line | cut -d' ' -f1); v=$(echo $line | cut -d\" -f2)
    DATA["$k"]="$v"
  done< <(cat "/home/pi/CAFCA/data/$game_info" | sed '/^$/d')

  data="${DATA[CAFCA_COIN]}"
  data_offs=$(echo "$data" | awk '{print $1}')
  data_reg=$(echo "$data" | awk '{print $2}')
  data_nom=$(echo "$data" | awk '{print $3}')

  scan_args="option region_scan_level 3; reset; dregions !$data_reg; lregions; exit"
  reg_offs=$(sudo scanmem -p `pidof retroarch` -c"$scan_args" 2>&1 |& grep --line-buffered -A1 "lregions" | awk 'NR==2' | awk '$1=$1 {print}' | cut -d] -f2 | awk -F" " '{print $1}' | cut -d, -f1)
  reg_offs="0x${reg_offs}"
  echo "data_offs: $data_offs"
  echo "reg_offs:  $reg_offs"

  printf -v ADDR "0x%X\n" $(( reg_offs + data_offs )) &>/dev/null
  ADDR=$(echo "$ADDR" | tr '[A-Z]' '[a-z]')

  while :; do
    VAL=$(sudo scanmem -p `pidof retroarch` -c"dump $ADDR 1;exit" 2>&1 | awk 'NR==15' | awk -F' ' '{print $2}')
    echo "ADDR: $ADDR - VAL: $VAL" && sleep 1
  done
}

cafca_array() {
  declare -A DATA=()
  game_info=$(grep ACTIVE_GAME data/.states | cut -d\' -f 2)
  while read line; do
    k=$(echo $line | cut -d' ' -f1)
    v=$(echo $line | cut -d\" -f2)
    DATA["$k"]="$v"
  done< <(cat "/home/pi/CAFCA/data/$game_info" | sed '/^$/d')
  for i in "${!DATA[@]}"; do printf "%s\t%s\n" "$i" "${DATA[$i]}"; done
}

cafca_addr() {
  for i in /home/pi/CAFCA/data/mame-libretro/*; do
    [[ $(grep CAFCA "$i" | cut -d\"  -f2 | wc -c) -gt 1 ]] && \
    { \
      echo -n $(cat $i | grep GAME_NAME | cut -d\" -f2); \
      printf "  ->  "; echo $(cat $i | grep CAFCA | cut -d\" -f2); \
    }
  done
}

cafca_kill() {
  while read line; do
    sudo kill -9 $line;
  done< <(ps -ef | grep -v grep | grep CAFCA.sh | awk '{$1=$1; print}' | cut -d' ' -f2)
}

doc() {
  [ "${#}" -lt 1 ] && return
  local doc_dir="/home/pi/ADMIN/DOCS"
  local args="${@}"
  local action=''
  local cmd=''
  local name=''

  if [[ ${#} -lt 2 ]]; then
    case "${1,,}" in
      'list'|'view'|'help'|'l'|'v'|'h'|'-l'|'-v'|'-h'|'--l'|'--v'|'--h')
        find "$doc_dir" -type f -name "*.doc" | sort | awk -F'\\/' '{print $NF}' | less -XKEFR
        return
        ;;
      *)
        action='write'
        name="${1}"
        [ -f "$doc_dir/$name.doc" ] && action='read' || action='write'
        ;;
    esac
  else
    name="${2}"; action='write'

    case "${1,,}" in
      'read'|'r'|'-r'|'--r')
	 [ -f "$doc_dir/$name.doc" ] && action='read' || action='write';;
      'write'|'w'|'-w'|'--w'|'man')
	 action='write' ;;
      *) ;;
    esac
  fi

  echo -e "action: $action, name: $name"

  if [[ $action == 'read' ]]; then
    echo -e "found doc file!\n"
  else
    echo -e "writing doc file..\n"
    cmd="PAGER='cat' man $name"
    rc=$(sudo -- bash -c "$cmd &>/dev/null"; echo $?)
    [[ $rc -lt 1 ]] && sudo -- bash -c "$cmd 2>&1 | sudo tee $doc_dir/$name.doc" &>/dev/null \
    || { echo "man page not found for $name"; return; }
  fi

  echo -e "Read '$doc_dir/$name.doc' ? (Y/n)" && read -srN1 choice
  case $choice in [yY]) sudo -- bash -c "nano $doc_dir/$name.doc" ;; esac
}

key() {
  [ "${#}" -lt 1 ] && return

  local device='/dev/input/by-id/usb-Teensyduino_Serial_Keyboard_Mouse_Joystick_1008140-if02-event-kbd'
  local data_path='/home/pi/ADMIN/FILES'
  local arg="${@^^}"
  #local arg=$(echo "$@" | tr '[:lower:]' '[:upper:]')

  if [[ "${arg:0:2}" == '-H' ]] || [[ "${arg:0:3}" == '--H' ]]; then
    cat "$data_path/KEY_NAMES.doc" | less -EKRX
  else
    [[ $(echo "$arg" | grep -co --color=never "KEY_") -gt 0 ]] && arg=$(echo "$arg" | awk -F'KEY_' '{print $2}')
    code="KEY_${arg}"

    if [[ $(grep -c -m1 "$code" "$data_path/KEY_NAMES.lst") -gt 0 ]]; then
      echo -e "pressing \x27$code\x27"
      (timeout 2 /usr/bin/evtest "$device" |& grep -P "(?=.*($code))(?=.*Event:)" 2>&1 & PID=$!)
      sudo -- bash -c "evemu-event $device --type EV_KEY --code $code --value 1 --sync; evemu-event $device --type EV_KEY --code $code --value 0 --sync"
      wait $PID
    else
      echo "key '$arg' not found.."
    fi
  fi
}

joy() {
  local device='/dev/input/by-id/usb-SHANWAN_Skyuan_F16-event-joystick'
  local type=
  local code=
  local val_high=
  local val_low=

  [ "${#}" -lt 1 ] && return; arg="${@}"

  case "${arg,,}" in
   'up'|'u') type='EV_ABS'; code='ABS_Y'; val_high='255'; val_low='127' ;;
   'down'|'d') type='EV_ABS'; code='ABS_Y'; val_high='0'; val_low='127' ;;
   'left'|'l') type='EV_ABS'; code='ABS_X'; val_high='255'; val_low='128' ;;
   'right'|'r') type='EV_ABS'; code='ABS_X'; val_high='0'; val_low='128' ;;
   'a'|'0'|'thumb') type='EV_KEY'; code='BTN_THUMB'; val_high='1'; val_low='0' ;;
   'b'|'1'|'trigger') type='EV_KEY'; code='BTN_TRIGGER'; val_high='1'; val_low='0' ;;
   'y'|'2'|'top') type='EV_KEY'; code='BTN_TOP'; val_high='1'; val_low='0' ;;
   'x'|'3'|'thumb2') type='EV_KEY'; code='BTN_THUMB2'; val_high='1'; val_low='0' ;;
   *) return ;;
  esac
  sudo -- bash -c "evemu-event $device --type $type --code $code --value $val_high --sync; evemu-event $device --type $type --code $code --value $val_low --sync "
}

ev() {
  key=${1:-'ENTER'}
  dev=${2:-'1'}
  type=${3:-'KEY'}

  echo "1: $key, 2: $dev, 3: $type"

  key="${type}_${key}"; key=$(echo "${key}" | tr '[:lower:]' '[:upper:]')
  type="EV_${type}"; type=$(echo "${type}" | tr '[:lower:]' '[:upper:]')
  dev="/dev/input/event${dev}"

  echo "key: $key, dev: $dev, type: $type"

  cmd=
  for i in {1..0}; do
    cmd+="evemu-event $dev --type $type --code $key --value $i --sync;"
  done

  sudo -- bash -c "$cmd"
}


blank() {
  tty=$(tty)

  local arg=${1}
  arg=$(echo "$arg" | sed -e "s/ \+//g")

  [[ "${arg:0:2}" == "--" ]] && arg="${arg:2}"
  [[ "${arg:0:1}" == "-" ]] && arg="${arg:1}"

  arg=$(echo "$arg" | tr '[:upper:]' '[:lower:]')

  case $arg in
   '1'|'on'|'true'|'enabled')
     [[ $tty == /dev/tty* ]] && setterm --blank force || sudo setterm --blank force --term linux </dev/tty1
     ;;
   '0'|'off'|'false'|'disabled')
    [[ $tty == /dev/tty* ]] && setterm --blank poke   || sudo setterm --blank poke --term linux </dev/tty1
     ;;
  esac

}

findstr() {
  [ "${#}" -lt 1 ] && return
  local str=${1}
  local dir=${2:-'/home/pi/'}
  grep -lR "$str" "$dir" | sort -u
}

mem() {
  cat /proc/meminfo
}

hex() {
  printf "%02x\n" "${1}" | tr '[[:lower:]]' '[[:upper:]]'

}

config() {
  sudo bash /home/pi/ADMIN/CMD/CONFIG/CONFIG.sh "$@"
}

checkvolts() {
  STATUS=$(vcgencmd get_throttled | sed -n 's|^throttled=\(.*\)|\1|p')
  echo "$STATUS"
  if [[ ${STATUS} -ne 0 ]]; then
    echo ""
    if [ $((${STATUS} & 0x00001)) -ne 0 ]; then
      echo "Power is currently Under Voltage"
    elif [ $((${STATUS} & 0x10000)) -ne 0 ]; then
      echo "Power has previously been Under Voltage"
    fi
    if [ $((${STATUS} & 0x00002)) -ne 0 ]; then
      echo "ARM Frequency is currently Capped"
    elif [ $((${STATUS} & 0x20000)) -ne 0 ]; then
      echo "ARM Frequency has previously been Capped"
    fi
    if [ $((${STATUS} & 0x00004)) -ne 0 ]; then
      echo "CPU is currently Throttled"
    elif [ $((${STATUS} & 0x40000)) -ne 0 ]; then
      echo "CPU has previously been Throttled"
    fi
    if [ $((${STATUS} & 0x00008)) -ne 0 ]; then
      echo "Currently at Soft Temperature Limit"
    elif [ $((${STATUS} & 0x80000)) -ne 0 ]; then
      echo "Previously at Soft Temperature Limit"
    fi
    echo ""
  fi
}

joytest() {
  local arg=${1:-8}
  local del=${2:-1}
  while true; do clear && evdev-joystick --s "/dev/input/event$arg"; sleep "$del"; done
}

joy2key() {
  if [[ ${#} -gt 0 ]]; then
    local arg=$(echo "${1}" | tr '[:lower:]' '[:upper:]')
    bash /home/pi/ADMIN/CMD/joy2key/joy2key.sh "$arg"
  else
    echo -e "\nPlease provide argument!\n[ start | stop ]\n"
  fi
}

vkdump() {
  if [[ ! ${1} == help ]]; then
    event=$(while read -r line; do
      [ "$(echo $line | grep -c Virtual)" -gt 0 ] \
      && echo "$line" | grep "Virtual Keyboard" | cut -d: -f1
    done< <(sudo timeout 1 evtest 2>&1))

    while true; do
      clear
      echo -e "Virtual Keyboard: $event\n"
      echo -e " Type your octal code now.\n i.e. \x27\\\033\x27 without apostrophes.\n"
      echo -n " > "

      read -r str

      timeout 2 evtest "$event" | grep -A100 --line-buffered Testing &

      printf "$str" > /tmp/vkbdd.fifo
      sleep 1
      printf "\n"
      echo -e "\nPress ENTER to continue."
      read -sr dummy
    done
  else
    clear
    printf "\n OCTAL CODES:\n\n \
    '\\\015' : ENTER \n \
    '\\\040' : SPACE \n \
    '\\\033' : ESC \n \
    '\\\210' : BACKSPACE \n \
    '\\\212' : F1 \n \
    '\\\216' : F5 \n \
    '\\\010' : R_ALT \n\n"
  fi
}

#dump_coin() { sudo bash /home/pi/CAFCA/cmd/.test_dump.sh "$@"; }

compare() {
  [ "${#}" -lt 2 ] && return

  local file1=${1}
  local file2=${2}
  local arg_str=${*}
  local new_str=

  file1_str=$(echo "$file1" | sed 's|/home/pi|~|')
  file2_str=$(echo "$file2" | sed 's|/home/pi|~|')

  new_str=$(echo "$file1_str $file2_str" | sed 's|/home/pi|~|g')

  if [[ ${#new_str} < $(tput cols) ]]; then
    new_str="$new_str"
  else
    file1_str=$(echo "$file1" | sed 's/[^/]*\//..\//g; s/[^/]\+//')
    file2_str=$(echo "$file2" | sed 's/[^/]*\//..\//g; s/[^/]\+//')
    new_str=$(echo "$file1_str $file2_str" | sed 's|/home/pi|~|g')
  fi

  clear
  echo ""
  echo -e "\n$new_str\n"

  local width=$(tput cols)
  diff -sy --width=55 "$file1" "$file2"

}

pkgdump() {
  [ "${#}" -lt 1 ] && return

  if [[ ${1} == "--installed" ]] \
  || [[ ${1} == "-installed" ]] \
  || [[ ${1} == "installed" ]] \
  || [[ ${1} == "--i" ]] \
  || [[ ${1} == "-i" ]] \
  || [[ ${1} == "i" ]]; then
    sudo apt list --installed \
    | awk '{$1=$1;print" "$0}' \
    | cut -d[ -f1 | cut -c -56 \
    | sudo tee /home/pi/ADMIN/.log/apt.list 2>&1
    sleep 2
    echo -e "\n SUCCES writing list to \x27/home/pi/ADMIN/.log/apt.list\x27\n"
  fi
}


curs() {
  local arg=${1}
  arg=$(echo "$arg" | sed -e "s/ \+//g")

  [[ "${arg:0:2}" == "--" ]] && arg="${arg:2}"
  [[ "${arg:0:1}" == "-" ]] && arg="${arg:1}"

  arg=$(echo "$arg" | tr '[:upper:]' '[:lower:]')

  case $arg in
   '1'|'on'|'true'|'yes'|'enabled')
     setterm --cursor on
     ;;
   '0'|'off'|'false'|'no'|'disabled')
     setterm --cursor off
     ;;
  esac
}


lsusr() {
  local stdoutput=$(sudo w)

  clear
  echo "$stdoutput" | awk '{$1=$1;print}' | \
  awk '{
   if(NR==1){
     split($0,users,",");
     print "\n"users[2]":\n"
   }else if(NR>2) {
     print " "$2"\t"$3
   }
  }'
}


#backup() {
#  local backup_dir='/home/pi/ADMIN/.backup'
#  local script_dir='/home/pi/ADMIN/CMD/BACKUP'
#
#  if [[ "${#}" < 1 ]]; then
#    clear
#    sudo bash "$script_dir/backup.sh"
#
#  elif [[ "${1}" == list ]]; then
#    sudo 7z l "$backup_dir/BACKUP.zip" | awk '{print $6}' | tail -n +16
#  fi
#}

pids() {
  if [[ $1 == -v ]]; then
    ps -ef | grep -v grep | grep -i "${@:2}"
  elif [[ $1 == kill ]]; then
    while read -r line; do echo "killing pid $line"; sudo kill -9 "$line"; done< <(ps -ef | grep -v grep | grep -i "${@:2}" | awk '{print $2}')
  else
    ps -ef | grep -v grep | grep -i "${@}" | awk '{print $2}'
  fi
}


kill() {
 arg=${@}
 sudo kill -9 "$arg"
}


CRT() {
 local arg=${1:-'CONF'}
 arg=$(echo $arg | tr '[:lower:]' '[:upper:]')
 [ "$#" -lt 1 ] && return || echo "$arg"

 if [[ $arg == CONF ]]; then
   python3 "/opt/retropie/configs/all/CRT/config/Configuration Utility.py"

 elif [[ $arg == UTILITY ]]; then
   sudo nano /opt/retropie/configs/all/CRT/bin/ScreenUtilityFiles/config_files/utility.cfg

 elif [[ $arg == BGM ]]; then
   sudo nano /opt/retropie/configs/all/CRT/bin/ScreenUtilityFiles/bin/service_bgm/bgm.py

 fi
}

send() {
  [ ${#} -lt 1 ] && return
  /usr/bin/printf "$*" > /tmp/vkbdd.fifo
}

serial() {
  echo -e "$@" > /tmp/serial.fifo
}

server() {
  sudo sshpass -p $(cat ~/ADMIN/.sys/.pass | base64 -d) sftp dogenigt@data.dogenigt.dk
  #sudo sshpass -p $(echo YTJKY3V6S05hNjdOV1U5NlZKeGEK | base64 -d) sftp dogenigt@data.dogenigt.dk
}

upload() {
  expect /home/pi/ADMIN/CMD/FTP/sftp-upload.exp "$@"
}

exists() {
  [ -f "$@" ] && echo -e "\nfile \x27$@\x27 exists!\n" || echo -e "\nfile doesn't exist.\n"
}

play() {
  SDL_AUDIODRIVER='alsa' AUDIODEV='hw:1,0'
  ffplay -nodisp -autoexit -loglevel quiet "$@"
}

mod() {
  local path=
  [[ ${1} == ADMIN ]] && sudo chmod -R 775 /home/pi/ADMIN
}

tab() {
  local first=${1}
  local args="${*}"

  stdout="$(eval $args)"; echo "$stdout" | awk '{print "  "$0}'
}


img() {
  tty=$(tty)

  if [[ $tty == /dev/tty* ]]; then
    sudo fbi -t 0 --once --noverbose "$@"
  elif [[ $tty == /dev/pts* ]]; then
    sudo fbi -T 1 -d /dev/fb0 --once --noverbose "$@"
  fi
  reset
}


press() {
  [ $# -lt 1 ] && return
  local key=${1}
  key=$(echo $key | tr '[:upper:]' '[:lower:]')

  case $key in
    [aA-zZ])
      /usr/bin/printf $key > /tmp/vkbdd.fifo
      ;;
    [0-9])
      /usr/bin/printf $key > /tmp/vkbdd.fifo
      ;;
    'esc')
      /usr/bin/printf '\033' > /tmp/vkbdd.fifo
      ;;
    'f4')
      /usr/bin/printf '\215' > /tmp/vkbdd.fifo
      ;;
    *)
      ;;
  esac
}


clocks() {
  printf "\nCLOCKS:\n\n"
  for src in arm core gpu emmc uart v3d h264 isp pwm vec pixel dpi hdmi; do
    echo -e "$src: $(vcgencmd measure_clock $src)" | \
    awk -v OFS=\n -F':|=' '{
      name = $1;
      val = $3;
      val /= 1000;
      unit=" hz"

      unit=(val >= 10000 ? "Mhz" : (val >= 100 ? "Khz" : " hz" ))
      val >= 10000 ? val /= 1000 : val=val;

      cmd = "echo \"" val "\" | sed \x27s/./&./4\x27";
      cmd | getline val_form;
      close(cmd);

      printf "%s\t%8.2f %s\n", name, val_form, unit

    }'
  done
  printf "\n\n"
}

psef() {
  [ $# ] && arg="$1"
  clear
  case $arg in
    [rR])
      _psf | cut -c -56 | tail -n 999 | tac | head -n -2 | less -EKRX
      ;;
    [sS])
      _psf | awk '{$2=$3="";print first" "$0}' | sed 's/ \+/ /g' | awk '{first=$1;$1="";printf "%4d%s\n",first,$0}' | tail -n +4 | cut -c -56 | less -EKRX
      ;;
    *)
      _psf | cut -c -56 | less -EKRX
      ;;
  esac
}


_psf() {
  printf "\n" && ps -ef | \
  awk '{$1=$1;print}' | \
  awk -F' ' '{
    $3=$4=$6=$7="";
    rest=$0;
    print rest;
  }' | sed -e "s/ \+/ /g" | \
  awk '{
    if (NR == 1){
      print "    "$2"  "$1" "$3" "$4"\n";
    }
    if (NR > 1){
      user=substr($1,0,5);
      printf " %6d %4s", $2, user;
      $1=$2=" ";
      print " "substr($0,5,length($0));
    }
  }'
}


installer() {
  [ ! $# ] && return
  args="${@}"
  arg="$1"
  file="$2"
  logfile="/home/pi/ADMIN/.log/installer.log"
  arc_name='/home/pi/ADMIN/.install/install.zip'
  [ -f $arc_name ] && sudo cp $arc_name "$arc_name.bak"

  echo "args: $args"
  echo "arg: $arg"
  echo "file: $file"

  if [[ $arg == "add" ]]; then
    ( sudo 7z a -r -tzip -p1234 "$arc_name" "$file" && sudo 7z l "$arc_name" 2>&1 )> >(sudo tee $logfile)
  elif [[ $arg == del ]]; then
    ( sudo 7z d -r -p1234 "$arc_name" "$file" && sudo 7z l "$arc_name" 2>&1 )> >(sudo tee $logfile)
  elif [[ $arg == list ]]; then
    sudo 7z l "$arc_name"
  fi
  echo -e "\nDONE!\n\nOutput logged in \x27$logfile\x27"
}

download() {
  local url=${1}
  local dir=${2:-'/home/pi/downloads'}

  valid=$(wget --method=HEAD --no-check-certificate $url 2>&1 | cut -d' ' -f 3 | grep -xcm1 exists.) &>/dev/null

  clear
  echo -e "\nRequesting $url\n"
  sleep 1
  echo -e "\n$(date):\n" | sudo tee ~/ADMIN/log/download.log &>/dev/null
  if ! (( valid )); then
    echo -e "URL Invalid.\n" && return
  else
    echo -n "URL valid." && sleep 1 && echo -e "..downloading to:"
    wget -v --no-check-certificate -P $dir $url 2>&1 \
    | grep --line-buffered -A100 "Length:" \
    | awk '{$1=$1;print}' | cut -d'(' -f1 \
    | awk -vDIR="$dir" -F'\\% ' '{
      if (NR == 2) {
        n=split($0,A,"/");
        lastf = substr(A[n],0,length(A[n])-2);
        delimiter = "\\=";
        print DIR"/"lastf
      } else {
        n=split($2, parts, delimiter);

        if (n >= 2 ) {
          split($0,fields);
          split(fields[1],first,".");
          split(fields[2],second,"\\=");

          print "\nDONE! ("first[1]"in "second[2]")\n"
        }
      } \
    }' 
  fi
}


alias-func() {
  [ $# -gt 0 ] && arg=${1}

  aliasfile='/home/pi/.bash_aliases'
  funcs=$(cat $aliasfile | grep -c "() {")

  declare -a rownums=()
  declare -a names=()
  declare -A entries=()

  empty_row="                                                        "
  tty_height=$(( $(tput lines) - 8 ))
  found_long_lines=0

  clear

  for ((i=1;i<=$funcs;i++)); do
    last_i=$((i - 1))
    grepstr=$(cat $aliasfile | grep -m"$i" "() {" | tail -n -1)

    name=$(echo "$grepstr" | cut -d'(' -f1)
    names["$i"]="$name"

    rownum=$(cat $aliasfile | grep -w -n -m1 "$grepstr" | cut -d: -f1)
    rownums["$i"]="$rownum"

    if [ "$i" -gt 1 ]; then
      lastrow="${rownums[$last_i]}"
      rownums["$last_i"]="$lastrow $rownum"

      skip=0

      [[ $( echo "${names[$last_i]}" | cut -c -1 ) == "_" ]] && skip=1
      [[ $( echo "${names[$last_i]}" | rev | cut -c -1 ) == '$' ]] && skip=1

      [[ $skip == 0 ]] && entries["${names[$last_i]}"]="${rownums[$last_i]}"

    fi
  done

   while true; do

     [ "${#entries[@]}" -gt 24 ] \
     && _list_entries | less -EKR \
     || _list_entries

     tput sc

     if [ ${#arg} -gt 0 ]; then
       entry="$arg"
       arg=
     else
       read -rp "  type entry: " entry
     fi

     if [[ -v entries[$entry] ]]; then
       sleep 0.5
       range="${entries[$entry]}"
       start=$(echo "$range" | cut -d' ' -f1)
       end=$(  echo "$range" | cut -d' ' -f2)

       page=$(cat $aliasfile | \
        awk -v page_start="$start" -v page_end="$end" '{
         if (NR >= page_start && NR < page_end) {
          if (NR == page_start || NR > (page_end)-3) {
            print "  \033[36m"$0"\033[0m"
          }else{
            if (length($0 > 56)) {
              print substr($0, 1, 56);
            } else {
              print "  "$0;
            }
          }
         }
        }')

       clear
       page_len=$(echo "$page" | wc -l)

       if [ "$page_len" -gt "$tty_height" ]; then
         echo "$page" | awk '{print $0}' | less -ERKX
       else
         echo "$page" | awk '{print $0}'
       fi

       long_lines=$(echo "$page" | grep -c ".\{55\}")

       if [ "$long_lines" -gt 0 ]; then
         found_long_lines=1
       fi

     else
       echo -e "\n  entry doesn't exist."
     fi

     echo -e "\n  press any key to return."
     read -srN1 dummy

     if [ "$found_long_lines" -gt 0 ]; then
       echo "$page" | decolor | sudo tee /tmp/alias-func
       clear
       echo -e "\nfound $long_lines long lines\n - read with nano? (Y/n)"

       read -srN1 read_choice
       case $read_choice in
         [yY])
           sudo nano /tmp/alias-func
           clear && sleep 1
           ;;
         *)
           ;;
       esac
     fi

     for ((r=17;r< "$(($(tput lines) - 2))";r++)); do
       tput cup $r 0
       echo "$empty_row"
     done
     tput rc
   done
}

_list_entries() {
   clear
   sleep 1
   echo -e "\n  ~/.bash_aliases functions:"
   echo -e "  ____________________________________________________\n"

   for i in "${!entries[@]}"; do
     val1=$(echo "${entries[$i]}" | cut -d' ' -f1)
     val2=$(echo "${entries[$i]}" | cut -d' ' -f2)
     printf "  %9s\t%4d %4d\n" "$i" "$val1" "$val2"
   done
   echo -e "\npress any key."
   read -srN1 dummy
}

#unalias ll
ll_ignore() {
  arg=${1:-$PWD}

  [ ! -d $arg ] && arg="$PWD"
  [ $(ls -l $arg | wc -l) -lt 2 ] && ls -l $arg && return

  clear
  _ll_list "$arg" | less -EKXR

}
_ll_list() {
  local folder="$1"
  local abs_path="$(realpath "$folder")"
  echo -e "$abs_path:\n"
  count=$(ls -l | awk 'NR==1 {print $0"\n"}')

  ls -la --group-directories-first $folder \
  | awk -vdir="$folder" '{

    RESET="\033[0m";RED="\033[31m";RED="\033[31m";CYAN="\033[36m";WHITE="\033[37m";
    BGCOLOR="\033[40m\033[37m";DIRCOLOR="\033[40m\033[36m";ROWCOLOR=WHITE;

    fname=$9;
    sub(".\\/","",fname);
    hidden=substr(fname,0,2);

    user=$3
    user == "root" ? user="su" : user=user;

    type=substr($1,0,2);

    if (type == "l") next;
    type=(type == "d" ? "D" : (hidden == "." ? hidden : type));
    type == "D" ? fname=fname "/" : fname=fname

    if (NF>9){
      for (i=9+1;i<=NF;i++){ fname = fname" "$i }
      fname = "\x27" fname "\x27";
    } else { fname=$9 }

    cmd = "stat -c \x27%a %n\x27 "dir"/"fname;
    cmd | getline statout
    close(cmd);

    split(statout,octal);
    rights=octal[1];

    size=$5;
    if (size >= 1024 * 1024) {
      size /= (1024 * 1024);
      unit="M"
    } else if (size >= 1024) {
      size /= 1024;
      unit="K"
    } else { unit="B" }

    date_str = $6" "$7" "$8;
    cmd = "date -d \"" date_str "\" +%m-%d\ %R";
    cmd | getline date_formatted;
    close(cmd);
    cmd = "date -d \"" time_str "\" +%R";
    cmd | getline time_formatted;
    close(cmd);

    if (NR > 3) {
      type == "D" ? ROWCOLOR=DIRCOLOR : ROWCOLOR=BGCOLOR
      printf "%s %s %s %s %3.0f%s %s %s\n", ROWCOLOR, type, rights, date_formatted, size, unit, fname, RESET
    }
  }'
  echo -e "\n $(find $folder -maxdepth 1 -type f | wc -l) files. - $(find $folder -maxdepth 1 -type d | wc -l) dir(s)\n"
}

fb() {
  local WIDTH=$(cat /sys/class/graphics/fb0/stride)
  local HEIGHT=$(cat /sys/class/graphics/fb0/virtual_size | cut -d, -f2)
}

fbcolor() {
  #R=${1:-$(( RANDOM % 255 ))}; G=${2:-$(( RANDOM % 255 ))}; B=${3:-$(( RANDOM % 255 ))}; A=${4:-0}
  WIDTH=$(cat /sys/class/graphics/fb0/stride); HEIGHT=$(cut -d, -f2 /sys/class/graphics/fb0/virtual_size)
  LINE=`printf "\\\\x$(printf '%02x' $1)\\\\x$(printf '%02x' $2)\\\\x$(printf '%02x' $3)\\\\x00%0.s" $(seq 1 $WIDTH)` >/dev/null 2>&1
  ( clear; sleep 1; for (( i=0; i<$HEIGHT; i++ )); do printf $LINE | dd bs=1 seek=$(( i * WIDTH )) of=/dev/fb0; done | head -n 1 ) >/dev/null 2>&1
}

_fbdraw() {
  local WIDTH=$(cat /sys/class/graphics/fb0/stride)
  local HEIGHT=$(cat /sys/class/graphics/fb0/virtual_size | cut -d, -f2)
  local MAX=${1:-1}
  local PS1_STORED=$PS1; export PS=
  local ARG=${1:-0}
  clear

  case $ARG in
  0)
    (cat /dev/urandom | dd bs=1 count=$(cat /sys/class/graphics/fb0/stride) > /tmp/dump) >/dev/null 2>&1
    for i in $(seq 1 $HEIGHT); do cat /tmp/dump | dd bs=1 seek=$(( $WIDTH * i )) of=/dev/fb0 >/dev/null 2>&1; done #) >/dev/null 2>&1
    ;;
  1)
    local COLOR=`printf "\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\\\\\x00%0.s" $(seq 1 $WIDTH)`
    for i in $(seq 1 $HEIGHT | shuf); do printf $COLOR | dd bs=1 seek=$(( WIDTH * i )) of=/dev/fb0 >/dev/null 2>&1; done
    ;;
  2)
    for l in $(seq 1 $HEIGHT); do (cat /dev/urandom | dd bs=1 count=$(cat /sys/class/graphics/fb0/stride) | dd bs=1 seek=$(( WIDTH * l )) of=/dev/fb0) >/dev/null 2>&1; done
    ;;
  3)
    (cat /dev/urandom | dd bs=1 count=$(cat /sys/class/graphics/fb0/stride) > /tmp/dump) >/dev/null 2>&1
    for i in $(seq 1 $HEIGHT | shuf); do cat /tmp/dump | dd bs=1 seek=$(( $WIDTH * i )) of=/dev/fb0 >/dev/null 2>&1; done #) >/dev/null 2>&1
    ;;
  4)
    local COLOR=`printf "\\\\\\\\x00\\\\\\\\x00\\\\\\\\x00\\\\\\\\x00%0.s" $(seq 1 $WIDTH)`
    for i in $(seq 1 $HEIGHT); do printf $COLOR | dd bs=1 seek=$(( WIDTH * i )) of=/dev/fb0 >/dev/null 2>&1; done
    #local COLOR=`printf "\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\\\\\x00%0.s" $(seq 1 $WIDTH)`
    #for l in $(seq 1 $HEIGHT); do (cat /dev/urandom | dd bs=1 count=$(cat /sys/class/graphics/fb0/stride) | dd bs=1 seek=$(( WIDTH * l )) of=/dev/fb0) >/dev/null 2>&1; done
    ;;
  5)
    for l in $(seq 1 $HEIGHT | shuf); do (cat /dev/urandom | dd bs=1 count=$(cat /sys/class/graphics/fb0/stride) | dd bs=1 seek=$(( WIDTH * l )) of=/dev/fb0) >/dev/null 2>&1; done
    ;;
  6)
    (cat /dev/zero > /dev/fb0 | head -n 1) >/dev/null 2>&1
    seq 1 $(( WIDTH * HEIGHT )) | shuf > /tmp/fbmatrix
    #while read p; do printf '\\\\x00\\\\x80\\\\x00\\\\x00' | dd bs=1 seek=$p of=/dev/fb0 >/dev/null 2>&1; done< <(cat /tmp/fbmatrix)
    rm /tmp/fbmatrix
    ;;
  7)
    local DIV=
    local H=4
    for l in $(seq 0 $HEIGHT); do
    #for l in {1..10}; do
      local COUNT=0
      while [[ $COUNT -lt $WIDTH ]]; do
        DIV=$(( (RANDOM % 20) + 8 ))
        local COLOR=`printf "\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\\\\\x00%0.s" $(seq 1 $(( WIDTH / DIV )) )`

        #COLOR=`printf "\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\\\\\x00%0.s" $(seq 1 $(( WIDTH / DIV )) )` >/dev/null 2>&1
        printf $COLOR | dd bs=1 count=$(( WIDTH / DIV )) seek=$(( COUNT + (WIDTH * l) )) of=/dev/fb0 >/dev/null 2>&1
        COUNT=$(( COUNT + ( WIDTH / DIV ) ))
      done
    done
    ;;
  8)
    local COUNT_H=0
    local COUNT_W=0
    local LINE=
    local DIV=
    local ADD=$(( ( RANDOM % 14 ) + 2 ))

    while [[ $COUNT_H -lt $HEIGHT ]]; do
      COUNT_W=0; LINE=''
      while [[ $COUNT_W -lt $WIDTH ]]; do
        DIV=$(( (RANDOM % 20) + 8 ))
        COLOR=`printf "\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\x$(printf %02x $(( RANDOM % 255 )))\\\\\\\\x00%0.s" $(seq 1 $(( WIDTH / DIV )) )`
        LINE=${LINE}${COLOR}
        COUNT_W=$(( COUNT_W + ( WIDTH / DIV ) ))
      done
      for c in $(seq 1 $ADD); do
        printf $LINE | dd bs=1 count=$WIDTH seek=$(( WIDTH * COUNT_H )) of=/dev/fb0 >/dev/null 2>&1
        (( COUNT_H++ ))
      done
    done
    ;;
  99)
    sudo bash /home/pi/fbdraw.sh >/dev/null 2>&1
    ;;
  *)
    ;;
  esac
  sleep 2; export PS1=$PS1_STORED
}
#unalias fbdraw
#alias fbdraw='_fbdraw > /dev/null 2>&1'
