########################
# Automation Functions #
########################

#############################################################################
#                                                                           #
#                      DO NOT TRY TO EDIT ANYTHING BELOW                    #
#                                                                           #
#############################################################################
# Enable job control
set -m

# Force the client encoding for PostgreSQL 9.x
export PGCLIENTENCODING="LATIN1"

# Prevent the shell command history shrink to 1000 line by hitting Ctrl + C
export HISTSIZE="1000000"
export HISTFILESIZE="1000000000"

# Trying to get the PostgreSQL data directory
PGDATA="$(awk -F= '/^PGDATA=/ {print $2}' /etc/init.d/postgre* 2> /dev/null)"

# Force the locale vars to "en_US.utf8" to prevent some country that use comma as the decimal mark.
# If you want to use your own locale setting, please export LC_ALL and LANG after the .gamerc line in ~/.bashrc
export LC_ALL="en_US.utf8"
export LANG="en_US.utf8"

# Python 2.7.5(python27) goes first(if exist)
which python27 > /dev/null 2>&1 || [ -d $HOME/python ] && export PATH="$(find ~/python/* -maxdepth 0 -type d 2> /dev/null | xargs stat -c "%Z %n" 2> /dev/null | sort -g | tail -1 | awk '{print $NF}')/bin/:$PATH"

# IPython home directory
[ -d $HOME/ipython ] && export IPYTHONHOME="$(find ~/ipython/* -maxdepth 0 -type d 2> /dev/null | xargs stat -c "%Z %n" 2> /dev/null | sort -g | tail -1 | awk '{print $NF}')"

# Server ID ( Zone / Channel length )
SERVER_ID_ZONEID_NUM_LENGTH="$(echo -n $SERVER_ID_FORMAT|sed 's/[^Z]//g'|wc -c)"
SERVER_ID_CH_NUM_LENGTH="$(echo -n $SERVER_ID_FORMAT|sed 's/[^C]//g'|wc -c)"

# Server List (Deprecated)
#GAMEDB_SERVER_LIST="$(sed -n '/BELOW/,/ABOVE/p' /etc/hosts|grep -v "^#"|grep "GAMEDB[$SUC]"|awk '{print $1}')"
#WZ_SERVER_LIST="$(    sed -n '/BELOW/,/ABOVE/p' /etc/hosts|grep -v "^#"|grep "WZ[$SUC][0-9]"|awk '{print $1}')"
#GUILD_SERVER_LIST="$( sed -n '/BELOW/,/ABOVE/p' /etc/hosts|grep -v "^#"|grep "WZ[$SUC]$HC"|awk '{print $1}')"
#ALL_SERVER_LIST="$(   sed -n '/BELOW/,/ABOVE/p' /etc/hosts|grep -v "^#"|grep "^[0-9].*[ABLTGW][ACGIOZ][CGMW0-9]"|awk '!/PATCH[0-9]/ {print $1}')"
#PATCH_SERVER_LIST="$( sed -n '/BELOW/,/ABOVE/p' /etc/hosts|grep -v "^#"|grep "PATCH[0-9]"|awk '{print $1}')"

# Max set number (Deprecated)
#MAX_SET_NUMBER="$(sed -n '/BELOW/,/ABOVE/p' /etc/hosts|tr ' ' '\n'|grep "GAMEDB[0-9]"|sort -g|wc -l)"

# Set number list
SET_NUMBER_LIST="$(sed -n '/BELOW/,/ABOVE/p' /etc/hosts|tr '[[:blank:]]' '\n'|grep GAMEDB|awk -FGAMEDB '{print $NF}'|sort -n)"

# World number list
WORLD_NUMBER_LIST="$(sed -n '/BELOW/,/ABOVE/p' /etc/hosts|tr '[[:blank:]]' '\n'|grep WORLDDB|awk -FWORLDDB '{print $NF}'|sort -n)"

# TEST server default channels for each set
[ "$TEST_SERVER_CHANNELS" == "" ] && TEST_SERVER_CHANNELS="5"

# ARGs
[ "$ACTION" == "" ] && ACTION="$1"
[ "$ARG2" == "" ] && ARG2="$2"
[ "$ARG3" == "" ] && ARG3="$3"
[ "$ARG4" == "" ] && ARG4="$4"
[ "$ARG5" == "" ] && ARG5="$5"
[ "$ARG6" == "" ] && ARG6="$6"
[ "$ARG7" == "" ] && ARG7="$7"
[ "$ARG8" == "" ] && ARG8="${8}"
[ "$ARG9" == "" ] && ARG9="${9}"
[ "$ARG10" == "" ] && ARG10="${10}"
[ "$ARG11" == "" ] && ARG11="${11}"
[ "$ARG12" == "" ] && ARG12="${12}"
[ "$ARG13" == "" ] && ARG13="${13}"
[ "$ARG14" == "" ] && ARG14="${14}"
[ "$ARG15" == "" ] && ARG15="${15}"
[ "$ARG16" == "" ] && ARG16="${16}"
[ "$ARG17" == "" ] && ARG17="${17}"
[ "$ARG18" == "" ] && ARG18="${18}"
[ "$ARG19" == "" ] && ARG19="${19}"
[ "$ARG20" == "" ] && ARG20="${20}"
[ "$ARG21" == "" ] && ARG21="${21}"
[ "$ARG22" == "" ] && ARG22="${22}"
[ "$ARG23" == "" ] && ARG23="${23}"
[ "$ARG24" == "" ] && ARG24="${24}"
[ "$ARG25" == "" ] && ARG25="${25}"
[ "$ARG26" == "" ] && ARG26="${26}"
[ "$ARG27" == "" ] && ARG27="${27}"
[ "$ARG28" == "" ] && ARG28="${28}"
[ "$ARG29" == "" ] && ARG29="${29}"
[ "$ALLARGS" == "" ] && ALLARGS="$1 $2 $3 $4 $5 $6 $7 ${8} ${9} ${10} ${11} ${12} ${13} ${14} ${15} ${16} ${17} ${18} ${19} ${20} ${21} ${22} ${23} ${24} ${25} ${26} ${27} ${28} ${29}"

# TEST server login username
[ "$TEST_SERVER_LOGINUSER" == "" ] && TEST_SERVER_USER="$LOGINUSER" || TEST_SERVER_USER="$TEST_SERVER_LOGINUSER"

# ApexItemServer binary
[ "$APEXITEMSERVER_BIN" == "" ] && APEXITEMSERVER_BIN="AHNetServer"

# TicketServer port(If left empty will use default 7777)
grep -q "^[0-9]\+$" <<< "$TICKETSERVER_PORT"  || TICKETSERVER_PORT="7777"

# GatewayServer port(If left empty, will use default 5560)
grep -q "^[0-9]\+$" <<< "$GATEWAYSERVER_PORT" || GATEWAYSERVER_PORT="5560"

# HTTPAgent port(If left empty, will use default 1234)
grep -q "^[0-9]\+$" <<< "$HTTPAGENT_PORT" || HTTPAGENT_PORT="1234"

# AccountDBServer port(If left empty, will use default 7553)
grep -q "^[0-9]\+$" <<< "$ACCOUNTDBSERVER_PORT" || ACCOUNTDBSERVER_PORT="7553"

# GameDBServer port(If left empty, will use default 9800)
#grep -q "^[0-9]\+$" <<< "$GAMEDBSERVER_PORT" || GAMEDBSERVER_PORT="9800"

# GameAgent port(If left empty, will use default 6969)
grep -q "^[0-9]\+$" <<< "$GAMEAGENT_PORT" || GAMEAGENT_PORT="6969"

# Default maxnum_user
MAX_PLAYER_PER_CHANNEL="800"

# Terminal recording
[ "$TERMINAL_RECORDING" == "" ] && TERMINAL_RECORDING="0"
[ "$TERMINAL_RECORDING_DIRECTORY" == "" ] && TERMINAL_RECORDING_DIRECTORY="$HOME/.terminalrecording"
if [ "$PS2" != "" ] && [ "${BASH_ARGC[3]}" == "1" ] && [ "${BASH_LINENO[3]}" == "0" ] && [ "$TERMINAL_RECORDING" == "1" ] && [ "$SSH_CLIENT" != "" ] \
   && [ "$(ps -o comm -p $PPID h)" == "sshd" ] || [ "$(ps -o comm -p $PPID h)" == "screen" ] && echo "$HOST_NAME" | grep -E -q "TEST|CTRL"; then
    mkdir -p "$TERMINAL_RECORDING_DIRECTORY"
    RECORD_FILENAME="$(date +%Y%m%dT%H%M%S)-$(awk '{print $1}' <<< $SSH_CLIENT)-$(sed 's@/dev/@@g;s@/@-@g' <<< $SSH_TTY)"
    [ "$SHLVL" != "1" ] && [ "$WINDOW" != "" ] && RECORD_FILENAME="$RECORD_FILENAME-SCREEN_WINDOW-$WINDOW-$STY"
    #which --skip-alias script | grep -q "/script$" \
    #which script | grep -q "/script$" \
    #&& exec script -q -f "$TERMINAL_RECORDING_DIRECTORY/$RECORD_FILENAME"
    if ! [[ "$(type -t 'script')" == "alias" ]]; then
        if which script | grep -q "/script$"; then
		#exec script -q -f -c "source $HOME/.bash_xl"
        	exec script -q -f -a "$TERMINAL_RECORDING_DIRECTORY/$RECORD_FILENAME"
        fi
    fi
fi

# PATCH_FILES
SERVER_NAME="$(echo $*|tr '/' '\n'|grep server)"
CLIENT_NAME="$(echo $*|tr '/' '\n'|grep zip)"
PATCH_FILES_TO_GET="$SERVER_NAME $CLIENT_NAME"

# Ctrl script log file
CTRL_LOGFILE="$WORKING_DIRECTORY/.ctrl.log"

# SKServer script log file
SKSERVER_LOGFILE="$WORKING_DIRECTORY/.skserver.log"

# Test Ctrl script log file
TESTCTRL_LOGFILE="$WORKING_DIRECTORY/.testctrl.log"

# Length of the process name
PROCESS_NAME_LENGTH="16"

# Universal Logger
# ARGS:
# $1 = Script file name(You can use "$0" or leave it blank by "", it will automatically detect.)
# $2 = State, like "Begin", "=End=", "N/A", ...
# $3 = Action, like "Start", "Stop", "DBbackup", ...
# $4 = Answer, "y" or "n"(automatically get result from $ANSWER(which come from yesno2()))
#
# This function will log everything from Standard Input to the log file test:~/www/ulog
# Usage:
# echo "Message to ulogger" | ulogger $0 Begin logtest
#
# e.g.
# echo "Add GM Vincent successfully" | ulogger $0 N/A Add
ulogger () {
   # VARS
   DATE="$(date +%Y/%m/%d)"
   TIME="$(date +%H:%M:%S)"
   TTY="$(awk -F/dev/ '{print $2}' <<< "$SSH_TTY")"
   SOURCEIP="$(try_to_get_full_hostname $(awk '{print $1}' <<< "$SSH_CLIENT"))"
   FORKEDBY="$(ps -p $PPID -o ucmd h)"

   # SCRIPT FILE
   if [ "$1" == "" ] ; then
	[ "${BASH_SOURCE[1]}" == "" ] && SCRIPTFILE="FROM-SHELL" || SCRIPTFILE="$(awk -F/ '{print $NF}' <<< ${BASH_SOURCE[1]})"
   else
	SCRIPTFILE="$(awk -F/ '{print $NF}' <<< $1)"
   fi

   # STATE
   [ "$2" == "" ] && STATE="N/A" || STATE="$2"

   # ACTION
   if [ "$3" == "" ] ; then
        if [ "$ACTION" == "" ] ; then
                ACT="N/A"
        else
                ACT="$ACTION"
        fi
   else
        ACT="$3"
   fi

   # ANS
   if [ "$4" == "" ] ; then
        if [ "$ANSWER" == "" ] ; then
                ANS=""
        else
                ANS="$ANSWER"
        fi
   else
        ANS="$4"
   fi

#echo SCRIPT_FILE: $SCRIPTFILE
#echo STATE: $STATE
#echo ACTION: $ACTION
#echo ANS: $ANS

   cat \
   | LC_ALL=C sed "s|^|$DATE\t$TIME\t$SCRIPTFILE\t$STATE\t$FORKEDBY\tA:$ANS\t$LOGINUSER\t$USER\t$TTY\t$SOURCEIP\t$ACT\t$HOST_NAME\t|g" \
   | ssh $TEST_SERVER_USER@TEST "cat >> ~/www/ulog"
}

# This is a one-shot command line function for Universal Logger.
# It's easy to modify your script to apply ulogger, Like:
# Original:
# echo "Add GM Vincent successfully" | colorize green
# To apply ulogger:
# ulogger_echo "Add GM Vincent successfully" | colorize green
ulogger_echo () {
   ulogger ${BASH_SOURCE[1]} <<< "$*"
   echo "$*"
}

ulogger_echo_no_nl () {
   ulogger ${BASH_SOURCE[1]} <<< "$*"
   echo -n "$*"
}

vime () {
   vim "$(which $1)"
}

# Colorize
colorize() {
# Colorize stream editor by Rickz <iamrickz@gmail.com>
#                                       21:50, 2007/10/03.
FG="$1" ; BG="$2" ; EF1="$3" ; EF2="$4" ; EF3="$5"
echo "$3 $4 $5"|grep "1" 2>&1 > /dev/null && FG="39"
OLDFG="$FG";case "$FG" in
        black)  FG="30";;
        red)    FG="31";;
        green)  FG="32";;
        yellow) FG="33";;
        blue)   FG="34";;
        magenta)FG="35";;
        purple) FG="35";;
        cyan)   FG="36";;
        white)  FG="37";;
        default)FG="39";;
esac;[ "$OLDFG" == "$FG" ] && FG="39"
OLDBG="$BG";case "$BG" in
        black)  BG="40";;
        red)    BG="41";;
        green)  BG="42";;
        yellow) BG="43";;
        blue)   BG="44";;
        magenta)BG="45";;
        purple) BG="45";;
        cyan)   BG="46";;
        white)  BG="47";;
        default)BG="49";;
esac;[ "$OLDBG" == "$BG" ] && BG="49"
[ "$EF3" != "" ] && exec sed "s/\(.*\)/\x1b\x5b$BG\x3b$FG\x3b\x31\x6d\x1b\x5b$EF1\x6d\x1b\x5b$EF2\x6d\x1b\x5b$EF3\x6d\1\x1b\x5b\x30\x6d/g" -
[ "$EF2" != "" ] && exec sed "s/\(.*\)/\x1b\x5b$BG\x3b$FG\x3b\x31\x6d\x1b\x5b$EF1\x6d\x1b\x5b$EF2\x6d\1\x1b\x5b\x30\x6d/g" -
[ "$EF1" != "" ] && exec sed "s/\(.*\)/\x1b\x5b$BG\x3b$FG\x3b\x31\x6d\x1b\x5b$EF1\x6d\1\x1b\x5b\x30\x6d/g" -
[ "$BG" != "" ] && exec sed "s/\(.*\)/\x1b\x5b$BG\x3b$FG\x3b\x31\x6d\1\x1b\x5b\x30\x6d/g" -
[ "$FG" != "" ] && exec sed "s/\(.*\)/\x1b\x5b0\x3b$FG\x3b\x31\x6d\1\x1b\x5b\x30\x6d/g" -
}

uncolorize () {
   sed -r "s/\x1B\[([0-9]{1,3}((;[0-9]{1,3})*)?)?[m|K]//g"
}

print_serverip () {
   until [ "$HOSTS_IS_OKAY" == "1" ] ; do
	HOSTS_TIMESTAMP="$(date +%s.%N)"
	[ "$(cat /etc/hosts > /tmp/hosts.$HOSTS_TIMESTAMP ; md5sum /tmp/hosts.$HOSTS_TIMESTAMP;sleep 0.015)" == \
	  "$(sleep 0.015;cat /etc/hosts > /tmp/hosts.$HOSTS_TIMESTAMP ; md5sum /tmp/hosts.$HOSTS_TIMESTAMP)" ] \
	&& HOSTS_IS_OKAY="1" \
	|| HOSTS_IS_OKAY="0"
	[ "$HOSTS_IS_OKAY" == "1" ] \
	&& sed -n '/BELOW/,/ABOVE/p' /tmp/hosts.$HOSTS_TIMESTAMP | grep -E -i "[[:blank:]]$1[[:blank:]]|[[:blank:]]$1$"|awk '{print $1}'|head -1
	rm -f /tmp/hosts.$HOSTS_TIMESTAMP
   done
   HOSTS_IS_OKAY="0"
}

print_serverip_from_whole_hosts () {
   until [ "$HOSTS_IS_OKAY" == "1" ] ; do
	HOSTS_TIMESTAMP="$(date +%s.%N)"
	[ "$(cat /etc/hosts > /tmp/hosts.$HOSTS_TIMESTAMP ; md5sum /tmp/hosts.$HOSTS_TIMESTAMP;sleep 0.015)" == \
	  "$(sleep 0.015;cat /etc/hosts > /tmp/hosts.$HOSTS_TIMESTAMP ; md5sum /tmp/hosts.$HOSTS_TIMESTAMP)" ] \
	&& HOSTS_IS_OKAY="1" \
	|| HOSTS_IS_OKAY="0"
	[ "$HOSTS_IS_OKAY" == "1" ] \
	&& cat /tmp/hosts.$HOSTS_TIMESTAMP | grep -E -i "[[:blank:]]$1[[:blank:]]|[[:blank:]]$1$"|awk '{print $1}'|head -1
	rm -f /tmp/hosts.$HOSTS_TIMESTAMP
   done
   HOSTS_IS_OKAY="0"
}

print_servername () {
   until [ "$HOSTS_IS_OKAY" == "1" ] ; do
	HOSTS_TIMESTAMP="$(date +%s.%N)"
	[ "$(cat /etc/hosts > /tmp/hosts.$HOSTS_TIMESTAMP ; md5sum /tmp/hosts.$HOSTS_TIMESTAMP;sleep 0.015)" == \
	  "$(sleep 0.015;cat /etc/hosts > /tmp/hosts.$HOSTS_TIMESTAMP ; md5sum /tmp/hosts.$HOSTS_TIMESTAMP)" ] \
	&& HOSTS_IS_OKAY="1" \
	|| HOSTS_IS_OKAY="0"
	[ "$HOSTS_IS_OKAY" == "1" ] \
	&& sed -n '/BELOW/,/ABOVE/p' /tmp/hosts.$HOSTS_TIMESTAMP | grep -E -i "^$1[[:blank:]]|[[:blank:]]$1[^0-9]|[[:blank:]]$1$|[[:blank:]]$1[[:blank:]]"|sed "s/^[0-9\.]*[[:blank:]]//g;s/ *$//g;s/ /_/g"
	rm -f /tmp/hosts.$HOSTS_TIMESTAMP
   done
   HOSTS_IS_OKAY="0"
}

print_hosts () {
   until [ "$HOSTS_IS_OKAY" == "1" ] ; do
	HOSTS_TIMESTAMP="$(date +%s.%N)"
	[ "$(cat /etc/hosts > /tmp/hosts.$HOSTS_TIMESTAMP ; md5sum /tmp/hosts.$HOSTS_TIMESTAMP;sleep 0.015)" == \
	  "$(sleep 0.015;cat /etc/hosts > /tmp/hosts.$HOSTS_TIMESTAMP ; md5sum /tmp/hosts.$HOSTS_TIMESTAMP)" ] \
	&& HOSTS_IS_OKAY="1" \
	|| HOSTS_IS_OKAY="0"
	[ "$HOSTS_IS_OKAY" == "1" ] \
	&& sed -n '/BELOW/,/ABOVE/p' /tmp/hosts.$HOSTS_TIMESTAMP | grep "^[0-9].*[ABLTGWPSMC][ACGIOZSR][CGMTWS0-9]"|sed 's/^[0-9\.]* \([A-Z]*.*\)$/\1/g'|tr ' ' '\n;'|sort -g|grep "$1"
	rm -f /tmp/hosts.$HOSTS_TIMESTAMP
   done
   HOSTS_IS_OKAY="0"
}

print_hosts_ip () {
   for host in $(print_hosts $1) ;do
	print_serverip $host
   done|sort|uniq
}

print_hosts_from_whole_hosts () {
   until [ "$HOSTS_IS_OKAY" == "1" ] ; do
	HOSTS_TIMESTAMP="$(date +%s.%N)"
	[ "$(cat /etc/hosts > /tmp/hosts.$HOSTS_TIMESTAMP ; md5sum /tmp/hosts.$HOSTS_TIMESTAMP;sleep 0.015)" == \
	  "$(sleep 0.015;cat /etc/hosts > /tmp/hosts.$HOSTS_TIMESTAMP ; md5sum /tmp/hosts.$HOSTS_TIMESTAMP)" ] \
	&& HOSTS_IS_OKAY="1" \
	|| HOSTS_IS_OKAY="0"
	[ "$HOSTS_IS_OKAY" == "1" ] \
	&& cat /tmp/hosts.$HOSTS_TIMESTAMP | grep "^[0-9].*[ABLTGWPSH][ACGIOZTD][CGMTWS0-9]"|sed 's/^[0-9\.]* \([A-Z]*.*\)$/\1/g'|tr ' ' '\n;'|sort -g|grep "$1"
	rm -f /tmp/hosts.$HOSTS_TIMESTAMP
   done
   HOSTS_IS_OKAY="0"
}

print_hosts_ip_from_whole_hosts () {
   for host in $(print_hosts_from_whole_hosts $1) ;do
	print_serverip_from_whole_hosts $host
   done|sort|uniq
}

print_hosts_uniq () {
    keyword=$1
    sed -n '/BELOW/,/ABOVE/p' /etc/hosts | \
    awk -v key="$keyword" '
    {
        for (i=2; i<=NF; i++) {
            if ($i ~ "^" key"[0-9]+") {
                print $i
                next
            }
        }
    }'
}

try_to_get_full_hostname () {
   if [ "$1" == "" ] ; then
	[ "$HOST_NAME" == "" ] \
	&& echo "$HOSTNAME" \
	|| echo "$HOST_NAME"
   else
	grep -E -i "^$1[[:blank:]]|[[:blank:]]$1[^0-9]|[[:blank:]]$1$|[[:blank:]]$1[[:blank:]]" /etc/hosts | grep "^[0-9]" | sed 's/^[^[:blank:]]\+[[:blank:]]\+//g;s/[[:blank:]]/_/g' \
	| grep "^." || echo "$1"
   fi
}

hostname2server () {
    sed 's/TICKET/TicketServer/g
	     s/ACCTDBS/AccountDBServer/g
         s/LWEBSPS\([0-9]\+\)/LWebSocketProxyServer\1/g
         s/LOGIN\([0-9]\+\)/LoginServer\1/g
         s/HTTPA\([0-9]\+\)/HTTPAServer\1/g
         s/GDS\([0-9]\+\)/GameDBServer\1/g
         s/MS\([0-9]\+\)/MissionServer\1/g
         s/SOCIETYS\([0-9]\+\)/SocietyServer\1/g
         s/RANKS\([0-9]\+\)/RankServer\1/g
         s/CHATS\([0-9]\+\)/ChatServer\1/g
         s/WS\([0-9]\+\)/WorldServer\1/g
         s/WHS\([0-9]\+\)\([0-9]\)/WHTTPAServer\1\2/g
         s/WWEBSPS\([0-9]\+\)\([0-9]\)/WWebSocketProxyServer\1\2/g
        ' <<< "$1" | grep -v "ACCOUNTDB"
}

hostname2build () {
   SERVER_NAME=$1
   SET_ID=$(get_set_id ${SERVER_NAME})
   #FULL_SERVER_ID=$(get_full_server_id ${SERVER_NAME})   

   sed "s/TICKET/Ticket ${SET_ID}/g
        s/ACCTDBS/AcctDBS ${SET_ID}/g
        s/LWEBSPS\([0-9]\+\)/LWebSocketProxyS ${SET_ID} \1/g
        s/LOGIN\([0-9]\+\)/Login ${SET_ID} \1/g
        s/HTTPA\([0-9]\+\)/Httpa ${SET_ID} \1/g
        s/GDS\([0-9]\+\)/GameDBS ${SET_ID}/g
        s/MS\([0-9]\+\)/Mission ${SET_ID}/g
        s/SOCIETYS\([0-9]\+\)/SocietyS ${SET_ID}/g
        s/RANKS\([0-9]\+\)/RankS ${SET_ID}/g
        s/CHATS\([0-9]\+\)/ChatS ${SET_ID}/g
        s/WS\([0-9]\+\)/WorldS ${SET_ID} \1/g
        s/WHS\([0-9]\+\)/WorldHttpa ${SET_ID} \1/g
        s/WWEBSPS\([0-9]\+\)/WWebSocketProxyS ${SET_ID} \1/g
	" <<< "${SERVER_NAME}"
}

check_server_exist () {
   OLDIFS="$IFS"
   IFS="
"
   #for server in $(echo $1 $(get_world_num $2) $(echo 0000$3|tail -c $(($SERVER_ID_CH_NUM_LENGTH+1))|sed 's/^0\+$//g') \
   #echo "ORIG $1 $2 $3"
   SERVER_TYPE="$1"
   SET_NUM="$2"
   ADDITIONAL_PARAMS="$3"
   for server in $(echo $1 $2 $3|sed 's/^0\+$//g' \
        | sed "s/Ticket \([0-9]\+\)/TicketServer/g
            s/AcctDBS \([0-9]\+\)/AccountDBServer/g
            s/LWebSocketProxyS \([0-9]\+\) \([0-9]\+\)/LWebSocketProxyServer\2/g
            s/Login \([0-9]\+\) \([0-9]\+\)/LoginServer\2/g
            s/WorldHttpa \([0-9]\+\) \([0-9]\+\)/WHTTPAServer\2/g
            s/Httpa \([0-9]\+\) \([0-9]\+\)/HTTPAServer\2/g
            s/GameDBS \([0-9]\+\)/GameDBServer\1/g
            s/Mission \([0-9]\+\)/MissionServer\1/g
            s/SocietyS \([0-9]\+\)/SocietyServer\1/g
            s/RankS \([0-9]\+\)/RankServer\1/g
            s/ChatS \([0-9]\+\)/ChatServer\1/g
            s/WorldS \([0-9]\+\) \([0-9]\+\)/WorldServer\2/g
            s/WWebSocketProxyS \([0-9]\+\) \([0-9]\+\)/WWebSocketProxyServer\2/g"); do
			
        echo "check_server_exist in: server => $server"
        if grep -E -q "GameDBServer|MissionServer|SocietyServer|RankServer|ChatServer|WorldServer|WHTTPAServer|WWebSocketProxyServer" <<< "$server" ; then
        	[ -f $WORKING_DIRECTORY/servers$2/$server/auto_start ] && return 0 || return 1
        elif grep -E -q "LoginServer|TicketServer|HTTPAServer|AccountDBServer|LWebSocketProxyServer" <<< "$server" ; then
        	[ -f $WORKING_DIRECTORY/servers1/$server/auto_start ] && return 0 || return 1
        elif grep -E -q "SetDir" <<< "$server" ; then
        	[ -f $WORKING_DIRECTORY/servers$2/setup.ini ] && return 0 || return 1
        elif grep -E -q "GAMEDB" <<< "$server" ; then
        	check_db_exist $GAME_DB_NAME$2 && return 0 || return 1
        elif grep -E -q "WORLDDB" <<< "$server" ; then
        	check_db_exist $WORLD_DB_NAME$3 && return 0 || return 1
        elif grep -E -q "ACCOUNTDB" <<< "$server" ; then
        	check_db_exist $ACCOUNT_DB_NAME && check_db_exist $MEMBER_DB_NAME && return 0 || return 1
        elif grep -E -q "SOCIETYDB" <<< "$server" ; then
        	check_db_exist $SOCIETY_DB_NAME$2 && return 0 || return 1
        else
        	return 1
        fi

   done
   IFS="$OLDIFS"
}

another_ip () {
   if [ "$NAT" == "1" ] ; then
        ifconfig | awk '/inet addr:/ {print $2}'|sed 's/addr://g'|grep -E -v "^127.0.0.1|^$1$"|head -1
   else
        ifconfig | awk '/inet addr:/ {print $2}'|sed 's/addr://g'|grep -E -v "^127.0.0.1|^192\.168\.|^172\.3|^10\.|^$1$"|head -1
   fi | grep "^.\+$" || ifconfig | awk '/inet addr:/ {print $2}'|sed 's/addr://g'|grep -E "^192\.168\.|^172\.|^10\."|head -1
}

show_all_ip () {
   sendscript allall <<< "ifconfig|grep -E 'inet addr|eth'|grep -v 127.0.0.1"
}

yesno () {
  while true ; do
    echo " "
    echo "Are you sure to do this? [$ACTION][y/N]"
    read answer
    if [ -n $answer ] ; then
      case "$answer" in
        y|Y|yes|YES)
          return 0
          ;;
        n|N|no|NO)
          exit
          ;;
        *)
          echo " "
          echo "ERROR: Invalid response, expected \"yes\" or \"no\"."
          continue
          ;;
      esac
    else
      exit
    fi
  done
}

yesno2 () {
        GET_ANSWER=0
        OLD_DESCRIPTION="$DESCRIPTION"
        CMD="$1"
        [ "$2" == "" ] \
        && DESCRIPTION="$(grep "^$1 .*" $0 ~/bin/customized_function|tail -1|awk -F"# " '{print $2}'|awk -F'..argument' '{print $1}'|tr -d '\n'|colorize red)" \
        || DESCRIPTION="$(colorize red <<< "$2")"
        until [ "$GET_ANSWER" == "1" ] ; do
                read -n 1 -p "Are you sure you want to $DESCRIPTION? " ANSWER
                if echo $ANSWER | grep -qi y ; then
                        echo
                        echo "Answer is yes, now $DESCRIPTION ..."
                        GET_ANSWER=1
                        $CMD && echo "$DESCRIPTION is done." || echo "$DESCRIPTION is done(return: $?)."
                else
                        if echo $ANSWER | grep -qi n ; then
                                echo
                                echo "Answer is no, won't $DESCRIPTION."
                                GET_ANSWER=1
                        else
                                echo
                                echo "Accept only Y/N."
                        fi
                fi

        done
        DESCRIPTION="$OLD_DESCRIPTION"
}

get_zone_category_num_length () {
   SERVER_ID=$(echo $1|sed "s/[a-zA-Z]*//g")
   SERVER_ID_FORMAT_NUM_LENGTH="$(echo -n $SERVER_ID|wc -c)"
   if grep -E -q "MS|MissionServer|GAMEDB|GDS|GameDBServer|SOCIETYS|SocietyServer|SOCIETYDB|RANKS|RankServer|CHATS|ChatServer" <<< "$1" ; then
      SERVER_ID_ZONECATEGORY_NUM_LENGTH=$((SERVER_ID_FORMAT_NUM_LENGTH - SERVER_ID_ZONEID_NUM_LENGTH))
   elif grep -E -q "WorldServer|WS|WORLDDB" <<< "$1" ; then
      SERVER_ID_ZONECATEGORY_NUM_LENGTH=$((SERVER_ID_FORMAT_NUM_LENGTH - SERVER_ID_ZONEID_NUM_LENGTH - SERVER_ID_CH_NUM_LENGTH))
   elif grep -E -q "WHS|WHTTPAServer|WWEBSPS|WWebSocketProxyServer" <<< "$1" ; then
      SERVER_ID_ZONECATEGORY_NUM_LENGTH=$((SERVER_ID_FORMAT_NUM_LENGTH - SERVER_ID_ZONEID_NUM_LENGTH - SERVER_ID_CH_NUM_LENGTH - 1))
   fi
   echo "$SERVER_ID_ZONECATEGORY_NUM_LENGTH"
}

get_zone_category () {
   SERVER_ID_ZONECATEGORY_NUM_LENGTH="$(get_zone_category_num_length $1)"
   if grep -E -q "MS|MissionServer|GAMEDB|GDS|GameDBServer|SOCIETYS|SocietyServer|SOCIETYDB|RANKS|RankServer|CHATS|ChatServer" <<< "$1" ; then
	ZONECATEGORY_GOT="$(($(sed "s/[a-zA-Z]*\([0-9]\+\)[0-9]\{$SERVER_ID_ZONEID_NUM_LENGTH\}$/\1/g" <<< "$1" | grep -v "[^0-9]")))" \
	&& echo "$ZONECATEGORY_GOT" || echo "Error: cannot get the ZONECATEGORY number from \"$1\"" | colorize red black 1>&2
   elif grep -E -q "WorldServer|WS|WORLDDB" <<< "$1" ; then
	ZONECATEGORY_GOT="$(($(sed "s/[a-zA-Z]*\([0-9]\+\)[0-9]\{$SERVER_ID_ZONEID_NUM_LENGTH\}[0-9]\{$SERVER_ID_CH_NUM_LENGTH\}$/\1/g" <<< "$1" | grep -v "[^0-9]")))" \
	&& echo "$ZONECATEGORY_GOT" || echo "Error: cannot get the ZONECATEGORY number from \"$1\"" | colorize red black 1>&2
   elif grep -E -q "WHS|WHTTPAServer|WWEBSPS|WWebSocketProxyServer" <<< "$1" ; then
	ZONECATEGORY_GOT="$(($(sed "s/[a-zA-Z]*\([0-9]\+\)[0-9]\{$SERVER_ID_ZONEID_NUM_LENGTH\}[0-9]\{$SERVER_ID_CH_NUM_LENGTH\}[0-9]$/\1/g" <<< "$1" | grep -v "[^0-9]")))" \
	&& echo "$ZONECATEGORY_GOT" || echo "Error: cannot get the ZONECATEGORY number from \"$1\"" | colorize red black 1>&2
   fi
}

get_zone_id () {
   SERVER_ID_ZONECATEGORY_NUM_LENGTH="$(get_zone_category_num_length $1)"
   if grep -E -q "MS|MissionServer|GAMEDB|GDS|GameDBServer|SOCIETYS|SocietyServer|SOCIETYDB|RANKS|RankServer|CHATS|ChatServer" <<< "$1" ; then
	ZONEID_GOT="$(($(sed "s/[a-zA-Z]*[0-9]\{$SERVER_ID_ZONECATEGORY_NUM_LENGTH\}\([0-9]\{$SERVER_ID_ZONEID_NUM_LENGTH\}\)$/\1/g" <<< "$1" | grep -v "[^0-9]")))" \
	&& echo "$ZONEID_GOT" || echo "Error: cannot get the ZONEID number from \"$1\"" | colorize red black 1>&2
   elif grep -E -q "WorldServer|WS|WORLDDB" <<< "$1" ; then
	ZONEID_GOT="$(($(sed "s/[a-zA-Z]*[0-9]\{$SERVER_ID_ZONECATEGORY_NUM_LENGTH\}\([0-9]\{$SERVER_ID_ZONEID_NUM_LENGTH\}\)[0-9]\{$SERVER_ID_CH_NUM_LENGTH\}$/\1/g" <<< "$1" | grep -v "[^0-9]")))" \
	&& echo "$ZONEID_GOT" || echo "Error: cannot get the ZONEID number from \"$1\"" | colorize red black 1>&2
   elif grep -E -q "WHS|WHTTPAServer|WWEBSPS|WWebSocketProxyServer" <<< "$1" ; then
	ZONEID_GOT="$(($(sed "s/[a-zA-Z]*[0-9]\{$SERVER_ID_ZONECATEGORY_NUM_LENGTH\}\([0-9]\{$SERVER_ID_ZONEID_NUM_LENGTH\}\)[0-9]\{$SERVER_ID_CH_NUM_LENGTH\}[0-9]$/\1/g" <<< "$1" | grep -v "[^0-9]")))" \
	&& echo "$ZONEID_GOT" || echo "Error: cannot get the ZONEID number from \"$1\"" | colorize red black 1>&2
   fi
}

get_ch_id () {
   if grep -E -q "WorldServer|WS|WORLDDB" <<< "$1" ; then
	CH_GOT="$(sed "s/.*[0-9]\+\([0-9]\{$SERVER_ID_CH_NUM_LENGTH\}\)$/\1/g" <<< "$1" | grep -v "[^0-9]")" \
	&& echo "$CH_GOT" || echo "Error: cannot get the channel number from \"$1\"" | colorize red black 1>&2
   elif grep -E -q "WHS|WHTTPAServer|WWEBSPS|WWebSocketProxyServer" <<< "$1" ; then
	CH_GOT="$(sed "s/.*[0-9]\+\([0-9]\{$SERVER_ID_CH_NUM_LENGTH\}\)[0-9]$/\1/g" <<< "$1" | grep -v "[^0-9]")" \
	&& echo "$CH_GOT" || echo "Error: cannot get the channel number from \"$1\"" | colorize red black 1>&2
   fi
}

get_set_id () {
   if grep -E -q "MS|MissionServer|GAMEDB|GDS|GameDBServer|WorldServer|WS|WORLDDB|SOCIETYS|SocietyServer|SOCIETYDB|RANKS|RankServer|CHATS|ChatServer|WHS|WHTTPAServer|WWEBSPS|WWebSocketProxyServer" <<< "$1" ; then
      ZONE_CATEGORY=$(get_zone_category $1)
      ZONE_ID=$(get_zone_id $1)
      SET_ID="$ZONE_CATEGORY$ZONE_ID"
   else
      SET_ID="1"
   fi
   echo "$SET_ID"
}

get_world_id () {
   if grep -E -q "WorldServer|WS|WORLDDB" <<< "$1" ; then
	WORLDID_GOT="$(sed "s/[a-zA-Z]*\([0-9]\+\)$/\1/g" <<< "$1" | grep -v "[^0-9]")" \
	&& echo "$WORLDID_GOT" || echo "Error: cannot get the WORLDID number from \"$1\"" | colorize red black 1>&2
   elif grep -E -q "WHS|WHTTPAServer|WWEBSPS|WWebSocketProxyServer" <<< "$1" ; then
	WORLDID_GOT="$(sed "s/[a-zA-Z]*\([0-9]\+\)[0-9]$/\1/g" <<< "$1" | grep -v "[^0-9]")" \
	&& echo "$WORLDID_GOT" || echo "Error: cannot get the WORLDID number from \"$1\"" | colorize red black 1>&2
   fi
}

get_world_httpa_id () {
   if grep -E -q "WHS|WHTTPAServer" <<< "$1" ; then
	WORLD_HTTPA_GOT="$(sed "s/.*[0-9]\+\([0-9]\)$/\1/g" <<< "$1" | grep -v "[^0-9]")" \
	&& echo "$WORLD_HTTPA_GOT" || echo "Error: cannot get the WORLD HTTPA number from \"$1\"" | colorize red black 1>&2
   fi
}

get_full_server_id () {
   echo "$1" | sed 's/[^0-9]//g'
}

get_server_id () {
   GOT_SET_NUM="$1"
   GOT_CH_NUM="$2"
   GOT_WZ="$3"
   grep -q  "^[0-9]\+$" <<< "$GOT_SET_NUM" || return 1
   grep -q  "^[0-9]\+$" <<< "$GOT_CH_NUM"  || return 1
   grep -qi "^[a-z]\+$" <<< "$GOT_WZ"      || return 1
   #SERVER_ID_SET="$(seq -w $(for((digis=1;digis<=$SERVER_ID_SET_NUM_LENGTH;digis++));do echo -n 9;done)|head -$(($SET_NUMBER_SEQUENCE_START_WITH-1+$GOT_SET_NUM))|tail -1)"
   SERVER_ID_SET="$(seq 999|head -$(($SET_NUMBER_SEQUENCE_START_WITH-1+$GOT_SET_NUM))|tail -1)"
   [ "$GOT_CH_NUM" == "0" ] && SERVER_ID_CH="$(echo -n 0000|head -c $SERVER_ID_CH_NUM_LENGTH)" || \
   SERVER_ID_CH="$((for((digis=1;digis<=$SERVER_ID_CH_NUM_LENGTH;digis++));do echo -n 0;done;echo;seq -w $(for((digis=1;digis<=$SERVER_ID_CH_NUM_LENGTH;digis++));do echo -n 9;done))|\
                    head -$(bc <<< "$CHANNEL_NUMBER_SEQUENCE_START_WITH+$GOT_CH_NUM")|tail -1)"
   grep -qi w <<< "$GOT_WZ" && SERVER_ID_WZ="0" || SERVER_ID_WZ="1"
   echo "$SERVER_ID_SET$SERVER_ID_CH$SERVER_ID_WZ"
}

get_wz_num () {
   GOT_SET_NUM="$1"
   GOT_CH_NUM="$2"
   grep -q  "^[0-9]\+$" <<< "$GOT_SET_NUM" || return 1
   grep -q  "^[0-9]\+$" <<< "$GOT_CH_NUM"  || return 1
   WZ_NUM_SET="$GOT_SET_NUM"
   [ "$GOT_CH_NUM" == "0" ] && WZ_NUM_CH="$(echo -n 0000|head -c $SERVER_ID_CH_NUM_LENGTH)" || \
   WZ_NUM_CH="$((for((digis=1;digis<=$SERVER_ID_CH_NUM_LENGTH;digis++));do echo -n 0;done;echo;seq -w $(for((digis=1;digis<=$SERVER_ID_CH_NUM_LENGTH;digis++));do echo -n 9;done))|\
                    head -$(bc <<< "$CHANNEL_NUMBER_SEQUENCE_START_WITH+$GOT_CH_NUM")|tail -1)"
   echo "$WZ_NUM_SET$WZ_NUM_CH"
}

get_port () {
   SERVER_TYPE="$1"
   GOT_PORT="$(grep "$SERVER_TYPE " $WORKING_DIRECTORY/.min_ports|awk '{print $2}')"
   echo $GOT_PORT
   sed -i -e "s/$SERVER_TYPE [0-9]*/$SERVER_TYPE $(($GOT_PORT+1))/g" $WORKING_DIRECTORY/.min_ports
}

get_local_internal_ip () {
    IFACE="$(get_network_interface_id)"
    GOT_INT_IP=$(/usr/bin/ip -4 addr show dev "${IFACE}" | awk '/inet / {print $2}' | cut -d/ -f1)
	echo $GOT_INT_IP
}

get_local_public_ip () {
	GOT_PUBLIC_IP="$(curl -s icanhazip.com)"
	echo $GOT_PUBLIC_IP
}

get_login_internal_ip () {
   LOGIN_ID_NUM="$1"
   if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
	GOT_LOGIN_INT_IP="$(get_local_internal_ip)"
   else
	GOT_LOGIN_INT_IP="$(grep -E " LOGIN${LOGIN_ID_NUM} | LOGIN${LOGIN_ID_NUM}$" /etc/hosts | awk -F" " '{print $1}')"
   fi
   echo $GOT_LOGIN_INT_IP
}

get_public_ip () {
   SERVER_TYPE="$1"
   ID_NUM="$2"
   if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
	GOT_PUBLIC_IP="$(curl -s icanhazip.com)"
   else
	GOT_PUBLIC_IP="$(ssh -o StrictHostKeyChecking=no $SERVER_TYPE$ID_NUM "curl -s icanhazip.com")"
   fi
   echo $GOT_PUBLIC_IP
}

get_internal_ip () {
   SERVER_TYPE="$1"
   ID_NUM="$2"
   if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
	GOT_INT_IP="$(get_local_internal_ip)"
   else
	GOT_INT_IP="$(grep -E " ${SERVER_TYPE}${ID_NUM} | ${SERVER_TYPE}${ID_NUM}$" /etc/hosts | awk -F" " '{print $1}')"
   fi
   echo $GOT_INT_IP
}

get_society_ip () {
   SET_ID="$1"
   IP_TYPE="$2"
   if [ "$IP_TYPE" == "EXT" ]; then
   	if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
        	SOCIETY_IP="$(grep -E 'ExtSocietyServerIP=' $WORKING_DIRECTORY/servers$SET_ID/SocietyServer$SET_ID/setup.ini 2>/dev/null | awk -F= '{print $2}')"
	else
		if [ "$SET_ID" != "1" ]; then
			SOCIETY_IP="$(ssh -o StrictHostKeyChecking=no SOCIETYS$SET_ID "grep -E 'ExtSocietyServerIP=' $WORKING_DIRECTORY/servers$SET_ID/SocietyServer$SET_ID/setup.ini 2>/dev/null | awk -F= '{print \$2}'")"
		fi
	fi
   elif [ "$IP_TYPE" == "INT" ]; then
   	if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
        	SOCIETY_IP="$(grep -E 'IntSocietyServerIP=' $WORKING_DIRECTORY/servers$SET_ID/SocietyServer$SET_ID/setup.ini 2>/dev/null | awk -F= '{print $2}')"
	else
		if [ "$SET_ID" != "1" ]; then
			SOCIETY_IP="$(ssh -o StrictHostKeyChecking=no SOCIETYS$SET_ID "grep -E 'IntSocietyServerIP=' $WORKING_DIRECTORY/servers$SET_ID/SocietyServer$SET_ID/setup.ini 2>/dev/null | awk -F= '{print \$2}'")"
		fi
	fi
   fi
   echo $SOCIETY_IP
}

update_society_ip () {
   IP_TYPE="$1"
   if [ "$IP_TYPE" == "EXT" ]; then
        for file in $(ls $WORKING_DIRECTORY/servers*/setup.ini) ; do
                SET_ID=$(echo $file | sed "s|$WORKING_DIRECTORY/servers||;s|/setup.ini||")
                ExtSocietyServerIP=$(get_society_ip $SET_ID EXT)
                sed -i -r "s/ExtSocietyServerIP=(.*)$/ExtSocietyServerIP=$ExtSocietyServerIP/" $file
        done
   elif [ "$IP_TYPE" == "INT" ]; then
        for file in $(ls $WORKING_DIRECTORY/servers*/setup.ini) ; do
                SET_ID=$(echo $file | sed "s|$WORKING_DIRECTORY/servers||;s|/setup.ini||")
                IntSocietyServerIP=$(get_society_ip $SET_ID INT)
                sed -i -r "s/IntSocietyServerIP=(.*)$/IntSocietyServerIP=$IntSocietyServerIP/" $file
        done
   fi
}

get_society_port () {
   SET_ID="$1"
   PORT_TYPE="$2"
   if [ "$PORT_TYPE" == "EXT" ]; then
   	if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
		GOT_SOCIETY_PORT="$(grep -E 'ExtSocietyServerPort=' $WORKING_DIRECTORY/servers$SET_ID/SocietyServer$SET_ID/setup.ini 2>/dev/null | awk -F= '{print $2}')"
   	else
		if [ "$SET_ID" != "1" ]; then
			GOT_SOCIETY_PORT="$(ssh -o StrictHostKeyChecking=no SOCIETYS$SET_ID "grep -E 'ExtSocietyServerPort=' $WORKING_DIRECTORY/servers$SET_ID/SocietyServer$SET_ID/setup.ini 2>/dev/null | awk -F= '{print \$2}'")"
		fi
   	fi
   elif [ "$PORT_TYPE" == "INT" ]; then
   	if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
		GOT_SOCIETY_PORT="$(grep -E 'IntSocietyServerPort=' $WORKING_DIRECTORY/servers$SET_ID/SocietyServer$SET_ID/setup.ini 2>/dev/null | awk -F= '{print $2}')"
   	else
		if [ "$SET_ID" != "1" ]; then
			GOT_SOCIETY_PORT="$(ssh -o StrictHostKeyChecking=no SOCIETYS$SET_ID "grep -E 'IntSocietyServerPort=' $WORKING_DIRECTORY/servers$SET_ID/SocietyServer$SET_ID/setup.ini 2>/dev/null | awk -F= '{print \$2}'")"
		fi
   	fi
   fi
   echo $GOT_SOCIETY_PORT
}

update_empty_society_port () {
   PORT_TYPE="$1"
   if [ "$PORT_TYPE" == "EXT" ]; then
   	for file in $(ls $WORKING_DIRECTORY/servers*/setup.ini) ; do
   	   SET_ID=$(echo $file | sed "s|$WORKING_DIRECTORY/servers||;s|/setup.ini||")
   	   EMPTY=$(grep "ExtSocietyServerPort=$" $file)
   	   if [ ! -z "$EMPTY" ] ; then
   	      SOCIETYSERVER_EXT_PORT=$(get_society_port $SET_ID EXT)
   	      sed -i "s/ExtSocietyServerPort=/ExtSocietyServerPort=$SOCIETYSERVER_EXT_PORT/" $file
   	   fi
   	done
   elif [ "$PORT_TYPE" == "INT" ]; then
   	for file in $(ls $WORKING_DIRECTORY/servers*/setup.ini) ; do
   	   SET_ID=$(echo $file | sed "s|$WORKING_DIRECTORY/servers||;s|/setup.ini||")
   	   EMPTY=$(grep "IntSocietyServerPort=$" $file)
   	   if [ ! -z "$EMPTY" ] ; then
   	      SOCIETYSERVER_INT_PORT=$(get_society_port $SET_ID INT)
   	      sed -i "s/IntSocietyServerPort=/IntSocietyServerPort=$SOCIETYSERVER_INT_PORT/" $file
   	   fi
   	done
   fi
}

get_gds_port () {
   SET_ID="$1"
   if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
	GOT_GDS_PORT="$(grep -E 'GameDBServerPort=' $WORKING_DIRECTORY/servers$SET_ID/GameDBServer$SET_ID/setup.ini 2>/dev/null | awk -F= '{print $2}')"
   else
	if [ "$SET_ID" != "1" ]; then
		GOT_GDS_PORT="$(ssh -o StrictHostKeyChecking=no GDS$SET_ID "grep -E 'GameDBServerPort=' $WORKING_DIRECTORY/servers$SET_ID/GameDBServer$SET_ID/setup.ini 2>/dev/null | awk -F= '{print \$2}'")"
	fi
   fi
   echo $GOT_GDS_PORT
}

update_empty_gds_port () {
   for file in $(ls $WORKING_DIRECTORY/servers*/setup.ini) ; do
      SET_ID=$(echo $file | sed "s|$WORKING_DIRECTORY/servers||;s|/setup.ini||")
      EMPTY=$(grep "GameDBServerPort=$" $file)
      if [ ! -z "$EMPTY" ] ; then
         GAMEDBSERVER_PORT=$(get_gds_port $SET_ID)
         sed -i "s/GameDBServerPort=/GameDBServerPort=$GAMEDBSERVER_PORT/" $file
      fi
   done
}

get_ms_ip () {
   SET_ID="$1"
   if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
        GOT_MS_IP="$(grep -E 'MissionServerIP=' $WORKING_DIRECTORY/servers$SET_ID/MissionServer$SET_ID/setup.ini 2>/dev/null | awk -F= '{print $2}')"
   else
        if [ "$SET_ID" != "1" ]; then
                GOT_MS_IP="$(ssh -o StrictHostKeyChecking=no MS$SET_ID "grep -E 'MissionServerIP=' $WORKING_DIRECTORY/servers$SET_ID/MissionServer$SET_ID/setup.ini 2>/dev/null | awk -F= '{print \$2}'")"
        fi
   fi
   echo $GOT_MS_IP
}

update_empty_ms_ip () {
   for file in $(ls $WORKING_DIRECTORY/servers*/setup.ini) ; do
      SET_ID=$(echo $file | sed "s|$WORKING_DIRECTORY/servers||;s|/setup.ini||")
      EMPTY=$(grep "MissionServerIP=$" $file)
      if [ ! -z "$EMPTY" ] ; then
         MISSIONSERVER_IP=$(get_ms_ip $SET_ID)
         sed -i "s/MissionServerIP=/MissionServerIP=$MISSIONSERVER_IP/" $file
      fi
   done
} 

get_ms_port () {
   SET_ID="$1"
   if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
	GOT_MS_PORT="$(grep -E 'MissionServerPort=' $WORKING_DIRECTORY/servers$SET_ID/MissionServer$SET_ID/setup.ini 2>/dev/null | awk -F= '{print $2}')"
   else
	if [ "$SET_ID" != "1" ]; then
		GOT_MS_PORT="$(ssh -o StrictHostKeyChecking=no MS$SET_ID "grep -E 'MissionServerPort=' $WORKING_DIRECTORY/servers$SET_ID/MissionServer$SET_ID/setup.ini 2>/dev/null | awk -F= '{print \$2}'")"
	fi
   fi
   echo $GOT_MS_PORT
}

update_empty_ms_port () {
   for file in $(ls $WORKING_DIRECTORY/servers*/setup.ini) ; do
      SET_ID=$(echo $file | sed "s|$WORKING_DIRECTORY/servers||;s|/setup.ini||")
      EMPTY=$(grep "MissionServerPort=$" $file)
      if [ ! -z "$EMPTY" ] ; then
         MISSIONSERVER_PORT=$(get_ms_port $SET_ID)
         sed -i "s/MissionServerPort=/MissionServerPort=$MISSIONSERVER_PORT/" $file
      fi
   done
}

get_ranks_port () {
   SET_ID="$1"
   if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
	GOT_RANKS_PORT="$(grep -E 'RankServerPort=' $WORKING_DIRECTORY/servers$SET_ID/RankServer$SET_ID/setup.ini 2>/dev/null | awk -F= '{print $2}')"
   else
	if [ "$SET_ID" != "1" ]; then
		GOT_RANKS_PORT="$(ssh -o StrictHostKeyChecking=no RANKS$SET_ID "grep -E 'RankServerPort=' $WORKING_DIRECTORY/servers$SET_ID/RankServer$SET_ID/setup.ini 2>/dev/null | awk -F= '{print \$2}'")"
	fi
   fi
   echo $GOT_RANKS_PORT
}

update_empty_ranks_port () {
   for file in $(ls $WORKING_DIRECTORY/servers*/setup.ini) ; do
      SET_ID=$(echo $file | sed "s|$WORKING_DIRECTORY/servers||;s|/setup.ini||")
      EMPTY=$(grep "RankServerPort=$" $file)
      if [ ! -z "$EMPTY" ] ; then
         RANKSERVER_PORT=$(get_ranks_port $SET_ID)
         sed -i "s/RankServerPort=/RankServerPort=$RANKSERVER_PORT/" $file
      fi
   done
}

get_chats_port () {
   SET_ID="$1"
   if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
	GOT_CHATS_PORT="$(grep -E 'ChatServerPort=' $WORKING_DIRECTORY/servers$SET_ID/ChatServer$SET_ID/setup.ini 2>/dev/null | awk -F= '{print $2}')"
   else
	if [ "$SET_ID" != "1" ]; then
		GOT_CHATS_PORT="$(ssh -o StrictHostKeyChecking=no CHATS$SET_ID "grep -E 'ChatServerPort=' $WORKING_DIRECTORY/servers$SET_ID/ChatServer$SET_ID/setup.ini 2>/dev/null | awk -F= '{print \$2}'")"
	fi
   fi
   echo $GOT_CHATS_PORT
}

update_empty_chats_port () {
   for file in $(ls $WORKING_DIRECTORY/servers*/setup.ini) ; do
      SET_ID=$(echo $file | sed "s|$WORKING_DIRECTORY/servers||;s|/setup.ini||")
      EMPTY=$(grep "ChatServerPort=$" $file)
      if [ ! -z "$EMPTY" ] ; then
         CHATSERVER_PORT=$(get_chats_port $SET_ID)
         sed -i "s/ChatServerPort=/ChatServerPort=$CHATSERVER_PORT/" $file
      fi
   done
}

get_login_http_ip () {
   ID_NUM="$1"
   if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
        GOT_LOGIN_HTTP_IP="$(grep -E 'LoginHttpServerIP' $WORKING_DIRECTORY/servers1/LoginServer$ID_NUM/setup.ini 2>/dev/null | awk -F= '{print $2}')"
   else
        GOT_LOGIN_HTTP_IP="$(ssh -o StrictHostKeyChecking=no LOGIN$ID_NUM "grep -E 'LoginHttpServerIP' $WORKING_DIRECTORY/servers1/LoginServer$ID_NUM/setup.ini 2>/dev/null | awk -F= '{print \$2}'")"
   fi
   echo $GOT_LOGIN_HTTP_IP
}

get_login_http_port () {
   ID_NUM="$1"
   if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
        GOT_LOGIN_HTTP_PORT="$(grep -E 'LoginHttpServerPort' $WORKING_DIRECTORY/servers1/LoginServer$ID_NUM/setup.ini 2>/dev/null | awk -F= '{print $2}')"
   else
	if [ "$SET_ID" != "1" ]; then
        	GOT_LOGIN_HTTP_PORT="$(ssh -o StrictHostKeyChecking=no LOGIN$ID_NUM "grep -E 'LoginHttpServerPort' $WORKING_DIRECTORY/servers1/LoginServer$ID_NUM/setup.ini 2>/dev/null | awk -F= '{print \$2}'")"
	fi
   fi
   echo $GOT_LOGIN_HTTP_PORT
}

get_world_http_ip () {
   SET_ID="$1"
   ID_NUM="$2"
   if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
        GOT_WORLD_HTTP_IP="$(grep -E 'WorldHttpServerIP' $WORKING_DIRECTORY/servers$SET_ID/WorldServer$ID_NUM/setup.ini 2>/dev/null | awk -F= '{print $2}')"
   else
	if [ "$SET_ID" != "1" ]; then
        	GOT_WORLD_HTTP_IP="$(ssh -o StrictHostKeyChecking=no WS$ID_NUM "grep -E 'WorldHttpServerIP' $WORKING_DIRECTORY/servers$SET_ID/WorldServer$ID_NUM/setup.ini 2>/dev/null | awk -F= '{print \$2}'")"
	fi
   fi
   echo $GOT_WORLD_HTTP_IP
}

get_world_http_port () {
   SET_ID="$1"
   ID_NUM="$2"
   if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
        GOT_WORLD_HTTP_PORT="$(grep -E 'WorldHttpServerPort' $WORKING_DIRECTORY/servers$SET_ID/WorldServer$ID_NUM/setup.ini 2>/dev/null | awk -F= '{print $2}')"
   else
	if [ "$SET_ID" != "1" ]; then
        	GOT_WORLD_HTTP_PORT="$(ssh -o StrictHostKeyChecking=no WS$ID_NUM "grep -E 'WorldHttpServerPort' $WORKING_DIRECTORY/servers$SET_ID/WorldServer$ID_NUM/setup.ini 2>/dev/null | awk -F= '{print \$2}'")"
	fi
   fi
   echo $GOT_WORLD_HTTP_PORT
}

generate_login_ip_port_data () {
    TEMP_FILE="/tmp/login_ip_port_data"
    [ -f "${TEMP_FILE}" ] && rm -rf "${TEMP_FILE}"
    echo "# LoginServer Group" > $TEMP_FILE
    if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
        INTERNAL_IP=$(/sbin/ifconfig ens4 | grep 'inet' | grep -v 'inet6' | awk -F' ' '{print $2}' | awk '{print $1}')
        for login_port in $(grep LoginServerPort ~/servers1/LoginServer*/setup.ini | awk -F"=" '{print $2}'); do
            echo "LoginServer=${INTERNAL_IP}:${login_port}" >> $TEMP_FILE
        done
    else
        for server_name in $(print_hosts LOGIN); do
            INTERNAL_IP=$(grep ${server_name} /etc/hosts | awk -F' ' '{print $1}')
            LOGIN_ID_NUM=$(echo $server_name | sed 's/LOGIN//')
            login_port=$(ssh LOGIN${LOGIN_ID_NUM} "awk -F'=' '/LoginServerPort=/ {print \$2}' ~/servers1/LoginServer${LOGIN_ID_NUM}/setup.ini")
            echo "LoginServer=${INTERNAL_IP}:${login_port}" >> $TEMP_FILE
        done
    fi
}      

generate_login_wsp_allow_cidr_data () {
    TEMP_FILE="/tmp/login_wsp_allow_cidr_data"
    [ -f "${TEMP_FILE}" ] && rm -rf "${TEMP_FILE}"
    if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
        internal_ip=$(/sbin/ifconfig ens4 | grep 'inet' | grep -v 'inet6' | awk -F' ' '{print $2}' | awk '{print $1}')
        echo "AllowIP_CIDR=${internal_ip}/32" >> $TEMP_FILE
    else
        declare -a ip_array
        for server_name in $(print_hosts LWEBSPS); do
            internal_ip=$(awk "/${server_name}/ {print \$1}" /etc/hosts)
            if [[ ! " ${ip_array[@]} " =~ " ${internal_ip} " ]]; then
                ip_array+=("${internal_ip}")
                echo "AllowIP_CIDR=${internal_ip}/32" >> $TEMP_FILE
            fi
        done
    fi
}  

generate_live_login_data_to_setup_txt () {
    TEMP_FILE="/tmp/live_login_data_to_setup_txt"
    [ -f "${TEMP_FILE}" ] && rm -rf "${TEMP_FILE}"
    for server_name in $(print_hosts LOGIN); do
        LOGIN_ID_NUM=$(echo $server_name | sed 's/LOGIN//')
        login_public_ip=$(ssh LOGIN${LOGIN_ID_NUM} 'echo $(wget -q -O- --header="Metadata-Flavor: Google" http://icanhazip.com)')
        login_port=$(ssh LOGIN${LOGIN_ID_NUM} "awk -F'=' '/LoginServerPort=/ {print \$2}' ~/servers1/LoginServer${LOGIN_ID_NUM}/setup.ini")
        echo "login=${login_public_ip}:${login_port}" >> $TEMP_FILE
    done
}

generate_live_wsproxy_data_to_setup_txt () {
    TEMP_FILE="/tmp/live_wsproxy_data_to_setup_txt"
    [ -f "${TEMP_FILE}" ] && rm -rf "${TEMP_FILE}"
    for server_name in $(print_hosts LWEBSPS); do
        LWSP_ID_NUM=$(echo $server_name | sed 's/LWEBSPS//')
	    login_wsproxy_domain_sub=$(ssh LWEBSPS${LWSP_ID_NUM} "hostname")
	    login_wsproxy_domain_main="${WEB_SOCKET_PROXY_DOMAIN}"
	    login_wsproxy_domain="${login_wsproxy_domain_sub}.${login_wsproxy_domain_main}"
        login_wsproxy_port=$(ssh LWEBSPS${LWSP_ID_NUM} "awk -F':' '/WebSocketProxyServer=/ {print \$2}' ~/servers1/LWebSocketProxyServer${LWSP_ID_NUM}/setup.ini")
        echo "wsproxy=${login_wsproxy_domain}:${login_wsproxy_port}" >> $TEMP_FILE
    done
}

generate_wsp_domain_for_local_machine () {
    PUBLIC_IP=$(curl -s icanhazip.com)

    BINARY_LOCALTION="$HOME/support/"
    BINARY_NAME="n1-support"

    if [ ! -f ${BINARY_LOCALTION}/${n1-support} ]; then
        mkdir -p ${BINARY_LOCALTION}
        rsync -avz TEST:$HOME/support/* ${BINARY_LOCALTION}/.
    fi

    cd ${BINARY_LOCALTION}
    ./${BINARY_NAME} domain

    if [ "$?" -eq 0 ]; then
        WEB_SOCKET_PROXY_DOMAIN="pps.x-legend.jp"
        echo "Gernerate ${HOSTNAME}.${WEB_SOCKET_PROXY_DOMAIN} for ${PUBLIC_IP} successfully."
        $HOME/bin/automatic_send_chatbot_text_only_by_thread_tag "generate_wsp_domain" "Domain ${HOSTNAME}.${WEB_SOCKET_PROXY_DOMAIN} for ${PUBLIC_IP} 設定完成" minute 10
    else
        $HOME/bin/automatic_send_chatbot_text_only_by_thread_tag "generate_wsp_domain" "Domain ${HOSTNAME}.${WEB_SOCKET_PROXY_DOMAIN} for ${PUBLIC_IP} 設定失敗" minute 10
    fi
}

verify_and_update_pem () {
    BINARY_LOCALTION="$HOME/support/"
    BINARY_NAME="n1-support"

    if [ ! -d ${BINARY_LOCALTION} ]; then
        mkdir -p ${BINARY_LOCALTION};
        rsync -avz TEST:$HOME/support/* ${BINARY_LOCALTION}/.
    fi

    cd ${BINARY_LOCALTION}
    ./${BINARY_NAME} cert

    if [ "$?" -eq 0 ]; then
        [ ! -d "$HOME/common-TEST/bin/cert" ] && mkdir -p $HOME/common-TEST/bin/cert
        chmod 644 privkey.pem fullchain.pem
        rsync -avzq privkey.pem $HOME/common-TEST/bin/cert/game-server.local-key.pem
        rsync -avzq fullchain.pem $HOME/common-TEST/bin/cert/game-server.local.pem
        $HOME/bin/automatic_send_chatbot_text_only_by_thread_tag "verify_pem" "檢查與驗證憑證完成" minute 10
    else
        $HOME/bin/automatic_send_chatbot_text_only_by_thread_tag "verify_pem" "檢查與驗證憑證失敗" minute 10        
    fi
}            

get_server_pid () {
   PROCESS_NAME="$1"
   if [ ${#PROCESS_NAME} -ge $PROCESS_NAME_LENGTH ]; then
        PID_OF_PROCESS="$(ps -ef | grep "$PROCESS_NAME" | grep -E -v 'grep|SKServer' | awk -F" " '{print $2}' 2>/dev/null|tr -d ' '|head -1)"
   else
        PID_OF_PROCESS="$(ps -o pid -C "$PROCESS_NAME" h|sed 's/ //g'|head -1)"
   fi

   echo $PID_OF_PROCESS
}

get_network_interface_id () {
    IFACE=$(/usr/bin/ip route show default | awk '{print $5}' | head -n1)
    echo $IFACE
}

generate_node_stream () {
   SET_ID=$1

   FILE="/tmp/node_stream.sql"
   rm -rf ${FILE}

   NODE_STREAM_CNT=$(psql ${GAME_DB_NAME}${SET_ID} -c "COPY (SELECT COUNT(*) FROM node_stream) TO STDOUT")
   if [ "$NODE_STREAM_CNT" -eq 0 ]; then
	for node_id in $(echo $NODE_STREAM_IDS); do
		echo "INSERT INTO node_stream (node_id, world_id) VALUES ('${node_id}','${SET_ID}010');" >> ${FILE}
	done
	psql ${GAME_DB_NAME}${SET_ID} -c "\i ${FILE}"
   fi
}

split_id () {
   SET_NUM=$1

   if [ "$ENABLE_SPLIT_ID" -eq 1 ]; then
	SEGMENT_CNT=$(psql ${GAME_DB_NAME}${SET_NUM} -c "COPY (SELECT COUNT(*) FROM segment_status) TO STDOUT")
	if [ "$SEGMENT_CNT" -eq 0 ]; then
		cd $WORKING_DIRECTORY/servers$SET_NUM/GameDBServer$SET_NUM/; ./GameDBServer$SET_NUM -rs
	fi
   fi
}

build_set () {
   SET_ID=$1

   if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
	SERVER_DIR="common-TEST"
	#CROSS_ROUTER_SID=$(cat $HOME/.gamerc | grep "CROSS_ROUTER_SID_TEST=" | sed 's/"//g' | awk -F"=" '{print $2}')
	#ENABLE_CROSS_SID=$(cat $HOME/.gamerc | grep "ENABLE_CROSS_SID_TEST=" | sed 's/"//g' | awk -F"=" '{print $2}')
	CROSS_ROUTER_SID=$CROSS_ROUTER_SID_TEST
	ENABLE_CROSS_SID=$ENABLE_CROSS_SID_TEST
   else
	SERVER_DIR="common"
	#CROSS_ROUTER_SID=$(cat $HOME/.gamerc | grep "CROSS_ROUTER_SID_LIVE=" | sed 's/"//g' | awk -F"=" '{print $2}')
	#ENABLE_CROSS_SID=$(cat $HOME/.gamerc | grep "ENABLE_CROSS_SID_LIVE=" | sed 's/"//g' | awk -F"=" '{print $2}')
	CROSS_ROUTER_SID=$CROSS_ROUTER_SID_LIVE
	ENABLE_CROSS_SID=$ENABLE_CROSS_SID_LIVE
   fi
   #CROSS_CHANNEL=$(cat $HOME/.gamerc | sed -n "/# ${GAME_TYPE}/,/CROSS_CHANNEL/p" | grep CROSS_CHANNEL | sed 's/ //g;s/"//g' | awk -F"=" '{print $2}')

   yes|SKServer BuildIfNotExist SetDir $SET_ID
   cd $WORKING_DIRECTORY/servers$SET_ID/
   unlink bin; unlink Data; unlink db
   ln -s ../$SERVER_DIR/bin
   ln -s ../$SERVER_DIR/Data
   ln -s ../$SERVER_DIR/db
   cd - > /dev/null

   yes|SKServer BuildIfNotExist GAMEDB $SET_ID
   cd $WORKING_DIRECTORY/$SERVER_DIR/db/; perl dbalter :${GAME_DB_NAME}${SET_ID}
   cd - > /dev/null

   yes|SKServer BuildIfNotExist Mission $SET_ID

   if [ "$SET_ID" == "$CROSS_ROUTER_SID" ]; then
	yes|SKServer BuildIfNotExist WorldZone $SET_ID $CROSS_CHANNEL
   else
	for((CH=1;CH<=$TEST_SERVER_CHANNELS;CH++));do
		yes|SKServer BuildIfNotExist WorldZone $SET_ID $CH
	done
   fi

   yes|SKServer BuildIfNotExist GameDBServer $SET_ID
   update_empty_gds_port

   yes|SKServer BuildIfNotExist GameAgentServer $SET_ID
   update_empty_gag_port

   NODE_STREAM_CNT=$(psql ${GAME_DB_NAME}${SET_ID} -c "COPY (SELECT COUNT(*) FROM node_stream) TO STDOUT")
   if [ "$NODE_STREAM_CNT" -eq 0 ]; then
	generate_node_stream ${SET_ID}
   fi

   if [ "$SET_ID" == "$CROSS_ROUTER_SID" ]; then
	yes|SKServer BuildIfNotExist CrossRouterServer $CROSS_ROUTER_SID
   	sed -i 's/CrossMission=0/CrossMission=1/' $WORKING_DIRECTORY/servers$CROSS_ROUTER_SID/setup.ini
   else
	yes|SKServer BuildIfNotExist SatelliteServer $SET_ID 1
   fi

   if [ ! -z "$ENABLE_CROSS_SID" ]; then
	upsert_cross_setup $CROSS_ROUTER_SID
   fi
}

log_rotate () {
   [ "$2" == "" ] && LEAVE_IN_DIR=$LOG_LEAVE_IN_DIR || LEAVE_IN_DIR="$1"
   [ "$2" == "" ] && SERVER="$1" || SERVER="$2"
   DATE_NOW="$(date +%Y%m%d)"
   LOG_ROTATE_DIR="../Log/$DATE_NOW/$SERVER"
   TODAY_UNIXTIME="$(date -d "TODAY 00:00:00" +%s)"

   cd "$WORKING_DIRECTORY/servers$(get_set_id $SERVER)/$SERVER"
   [ -f no_log_rotate ] && return 1
   mkdir -p "$LOG_ROTATE_DIR" || return 1

   # Do not rotate anything if the server just started
   [ "$(date -d @$(stat -c %Z pid 2> /dev/null) +%Y%m%d%H 2> /dev/null)" == "$(date +%Y%m%d%H)" ] && return 1

   echo -n "LogRotate: $SERVER ... " | colorize green

   ORIG_DU=$(du -sm .|awk '{print $1}')

   # Remove any log that generated by bugs
   rm -f *log.????.????_*

   grep -qi WORLD   <<< "$SERVER" && TO_DELETE="$WORLD_TO_DELETE"
   grep -qi ZONE    <<< "$SERVER" && TO_DELETE="$ZONE_TO_DELETE"
   grep -qi MISSION <<< "$SERVER" && TO_DELETE="$MISSION_TO_DELETE"
   grep -qi LOGIN   <<< "$SERVER" && TO_DELETE="$LOGIN_TO_DELETE"
   grep -qi GATEWAY <<< "$SERVER" && TO_DELETE="$GATEWAY_TO_DELETE"
   [ "$TO_DELETE" == "" ] && TO_DELETE="Nothing"

   # Rotate every log
   if [ "$LEAVE_IN_DIR" == "0" ] ; then

	# Is the server started in 2 hours?
	if [ "$(($(date -d @$(stat -c %Z pid 2> /dev/null) +%Y%m%d%H 2> /dev/null)+1))" != "$(date +%Y%m%d%H)" ] ; then
		for LOG_TYPE in $TO_DELETE ; do
			for LOG_FILE in $(ls -tr $LOG_TYPE[0-9.]*log* 2> /dev/null);do
				rm -f "$LOG_FILE"
			done
		done
	fi

	for LOG_TYPE in $(ls *log.*|awk -F[0-9.] '{print $1}'|sort|uniq|grep -E -v "$(for TYPE in $TO_DELETE;do echo -n "^$TYPE$|";done|sed 's/|$//g')") ; do
		for LOG_FILE in $(ls -tr $LOG_TYPE[0-9.]*log* 2> /dev/null);do
			mv "$LOG_FILE" "$LOG_ROTATE_DIR"
                        if [ "$USE_XZ_INSTEAD_OF_GZIP" == "1" ] ; then
                                ionice -c 3 nice -n 19 $HOME/bin/xz -3 "$LOG_ROTATE_DIR/$LOG_FILE" 2> /dev/null
                        else
			        ionice -c 3 nice -n 19 gzip -3 "$LOG_ROTATE_DIR/$LOG_FILE" 2> /dev/null
                        fi
		done
	done

   else #if [ "$LEAVE_IN_DIR" == "0" ] ; then

	# Is the server started in 2 hours?
	if [ "$(($(date -d @$(stat -c %Z pid 2> /dev/null) +%Y%m%d%H 2> /dev/null)+1))" != "$(date +%Y%m%d%H)" ] ; then

		# not in 2 hours (Delete and rotate)

		# Delete log files in $TO_DELETE
		for LOG_TYPE in $TO_DELETE ; do
			for LOG_FILE in $(ls -tr $LOG_TYPE[0-9.]*log* 2> /dev/null | grep -v "$(ls -tr $LOG_TYPE[0-9.]*log* 2> /dev/null | tail -$LEAVE_IN_DIR)");do
				rm -f "$LOG_FILE"
			done
		done

		for LOG_TYPE in $(ls *log.*|awk -F[0-9.] '{print $1}'|sort|uniq|grep -E -v "$(for TYPE in $TO_DELETE;do echo -n "^$TYPE$|";done|sed 's/|$//g')") ; do

			# Leave $LEAVE_IN_DIR log files of this type
			for LOG_FILE in $(ls -tr $LOG_TYPE[0-9.]*log* 2> /dev/null | grep -v "$(ls -tr $LOG_TYPE[0-9.]*log* 2> /dev/null | tail -$LEAVE_IN_DIR)");do
				mv "$LOG_FILE" "$LOG_ROTATE_DIR"
	                        if [ "$USE_XZ_INSTEAD_OF_GZIP" == "1" ] ; then
       	                        	ionice -c 3 nice -n 19 $HOME/bin/xz -3 "$LOG_ROTATE_DIR/$LOG_FILE" 2> /dev/null
       				else
					ionice -c 3 nice -n 19 gzip -3 "$LOG_ROTATE_DIR/$LOG_FILE" 2> /dev/null
                                fi
			done

			# Move every log file generated not today
			if ! grep -E -q "00|01" <<< "$(date +%H)" ; then
				for LOG_FILE in $(ls -tr $LOG_TYPE[0-9.]*log* 2> /dev/null | grep -v Error.log) ;do
					if [ $(date -r $LOG_FILE +%s) -lt $TODAY_UNIXTIME ] ; then
						#echo $LOG_FILE: $(date -r $LOG_FILE +%s) : $TODAY_UNIXTIME
						mv "$LOG_FILE" "$LOG_ROTATE_DIR"
				                if [ "$USE_XZ_INSTEAD_OF_GZIP" == "1" ] ; then
			                                ionice -c 3 nice -n 19 $HOME/bin/xz -3 "$LOG_ROTATE_DIR/$LOG_FILE" 2> /dev/null
			                        else
							ionice -c 3 nice -n 19 gzip -3 "$LOG_ROTATE_DIR/$LOG_FILE" 2> /dev/null
						fi
					fi
				done
			fi

		done # for LOG_TYPE in

	else # if [ "$(($(date -d @$(stat -c %Z pid) +%Y%m%d%H)+1))" != "$(date +%Y%m%d%H)" ] ; then

		# in 2 hours (Don't delete, only rotate)
		for LOG_TYPE in $(ls *log.*|awk -F[0-9.] '{print $1}'|sort|uniq) ; do

			# Leave only 1 log file of this type
			for LOG_FILE in $(ls -tr $LOG_TYPE[0-9.]*log* 2> /dev/null | grep -v "$(ls -tr $LOG_TYPE[0-9.]*log* 2> /dev/null | tail -1)");do
				mv "$LOG_FILE" "$LOG_ROTATE_DIR"
	                        if [ "$USE_XZ_INSTEAD_OF_GZIP" == "1" ] ; then
	                                ionice -c 3 nice -n 19 $HOME/bin/xz -3 "$LOG_ROTATE_DIR/$LOG_FILE" 2> /dev/null
	                        else
					ionice -c 3 nice -n 19 gzip -3 "$LOG_ROTATE_DIR/$LOG_FILE" 2> /dev/null
                                fi
			done

			# Move every log file generated not today
			if ! grep -E -q "00|01" <<< "$(date +%H)" ; then
				for LOG_FILE in $(ls -tr $LOG_TYPE[0-9.]*log* 2> /dev/null | grep -v Error.log) ;do
					if [ $(date -r $LOG_FILE +%s) -lt $TODAY_UNIXTIME ] ; then
						#echo $LOG_FILE: $(date -r $LOG_FILE +%s) : $TODAY_UNIXTIME
						mv "$LOG_FILE" "$LOG_ROTATE_DIR"
				                if [ "$USE_XZ_INSTEAD_OF_GZIP" == "1" ] ; then
			                                ionice -c 3 nice -n 19 $HOME/bin/xz -3 "$LOG_ROTATE_DIR/$LOG_FILE" 2> /dev/null
			                        else
							ionice -c 3 nice -n 19 gzip -3 "$LOG_ROTATE_DIR/$LOG_FILE" 2> /dev/null
						fi
					fi
				done
			fi

		done # for LOG_TYPE in
	fi


   fi #if [ "$LEAVE_IN_DIR" == "0" ] ; then

   # remove empty dir
   rmdir "$LOG_ROTATE_DIR" > /dev/null 2>&1
   rmdir ../Log/$DATE_NOW  > /dev/null 2>&1
   [ $(du -sm .|awk '{print $1}') == $ORIG_DU ] \
   && echo "no log to rotate..." | colorize green \
   || echo "$ORIG_DU MB -> $(du -sm .|awk '{print $1}') MB." | colorize green
}

check_log_files_date () {
   for SET_LOG_DIRECTORY in $(find $WORKING_DIRECTORY/servers*/Log -maxdepth 0 -type d 2> /dev/null);do
	# default 7 days
	grep -q "^[0-9]\+$" <<< "$CHECK_LOG_FILE_DATE_IN_DAYS" \
	|| CHECK_LOG_FILE_DATE_IN_DAYS="7"
	echo -n "Checking log files date in $SET_LOG_DIRECTORY ... " | colorize yellow
	cd "$SET_LOG_DIRECTORY"
	MOVED_LOGFILE=0
	for LOGFILE in $(find -type f -mtime -$CHECK_LOG_FILE_DATE_IN_DAYS|grep "\.log\.");do
		SERVER_DIRECTORY="$(awk -F/ '{print $3}' <<< "$LOGFILE")"
		CORRECT_DATE_DIRECTORY="$(date -d "$(stat -c %y "$LOGFILE")" +%Y%m%d)"
		mkdir -p "$CORRECT_DATE_DIRECTORY/$SERVER_DIRECTORY/" > /dev/null 2>&1
		mv -v "$LOGFILE" "$CORRECT_DATE_DIRECTORY/$SERVER_DIRECTORY/" > /dev/null 2>&1 \
		&& MOVED_LOGFILE=$(($MOVED_LOGFILE+1))
	done
	rmdir */*/* */* * > /dev/null 2>&1
	echo "$MOVED_LOGFILE log files has been corrected" | colorize green
   done
}

waiting_process_down () {
   PROCESS_NAME="$1"
   SLEEP_MICROSECONDS=100000
   NO_IO_MICROSECONDS=0
   TIMEOUT_MICROSECONDS="$(($SERVER_STOP_TIMEOUT*1000000))"
   SLEEP_SECONDS=1
   NO_IO_SECONDS=0
   TIMEOUT_SECONDS="$(($SERVER_STOP_TIMEOUT*1))"
   echo -n "Waiting for process $PROCESS_NAME down ...  " | colorize magenta
   if [ ${#PROCESS_NAME} -ge $PROCESS_NAME_LENGTH ]; then
	PID_OF_PROCESS="$(ps -ef | grep "$PROCESS_NAME" | grep -E -v 'grep|SKServer' | awk -F" " '{print $2}' 2>/dev/null|tr -d ' '|head -1)"
   else
   	PID_OF_PROCESS="$(ps -o pid -C "$PROCESS_NAME" h|sed 's/ //g'|head -1)"
   fi
   while true;do
	echo -en "\b-" #| colorize red
   	if [ ${#PROCESS_NAME} -ge $PROCESS_NAME_LENGTH ]; then
		ps -ef | grep -E "$PROCESS_NAME" | grep -E -v 'grep|SKServer' > /dev/null 2>&1 || break
	else
		ps -C "$PROCESS_NAME" > /dev/null 2>&1 || break
	fi
	sleep "$SLEEP_SECONDS"
	echo -en "\b\\" #| colorize yellow
   	if [ ${#PROCESS_NAME} -ge $PROCESS_NAME_LENGTH ]; then
		ps -ef | grep -E "$PROCESS_NAME" | grep -E -v 'grep|SKServer' > /dev/null 2>&1 || break
	else
		ps -C "$PROCESS_NAME" > /dev/null 2>&1 || break
	fi
	sleep "$SLEEP_SECONDS"
	echo -en "\b|" #| colorize blue
	if [ ${#PROCESS_NAME} -ge $PROCESS_NAME_LENGTH ]; then
		ps -ef | grep -E "$PROCESS_NAME" | grep -E -v 'grep|SKServer' > /dev/null 2>&1 || break
	else
		ps -C "$PROCESS_NAME" > /dev/null 2>&1 || break
	fi
	sleep "$SLEEP_SECONDS"
	echo -en "\b/" #| colorize cyan
	if [ ${#PROCESS_NAME} -ge $PROCESS_NAME_LENGTH ]; then
		ps -ef | grep "$PROCESS_NAME" | grep -E -v 'grep|SKServer' > /dev/null 2>&1 || break
	else
		ps -C "$PROCESS_NAME" > /dev/null 2>&1 || break
	fi
	sleep "$SLEEP_SECONDS"
	IO_STATUS_CHECKSUM="$(md5sum /proc/$PID_OF_PROCESS/io 2> /dev/null|awk '{print $1}')"
	if [ "$OLD_IO_STATUS_CHECKSUM" == "$IO_STATUS_CHECKSUM" ] ; then
		NO_IO_MICROSECONDS="$(($NO_IO_MICROSECONDS+$SLEEP_MICROSECONDS*4))"
	else
		NO_IO_MICROSECONDS=0
	fi
	if [ $NO_IO_MICROSECONDS -gt $TIMEOUT_MICROSECONDS ] ; then
		echo -en "\bthere is no I/O for $SERVER_STOP_TIMEOUT seconds, " | colorize magenta
		echo -en "directly send the SIGTERM to the process ... " | colorize magenta
		ulogger <<< "Kill $PROCESS_NAME($PID_OF_PROCESS) by SIGTERM"
		kill $PID_OF_PROCESS
	fi
	OLD_IO_STATUS_CHECKSUM="$IO_STATUS_CHECKSUM"
   done
   exec echo -e "\bOK" | colorize green
}

check_setdir () {
   if ! [ -d $WORKING_DIRECTORY/servers$1 ] ;then
	echo "Set Directory \"servers$1\" not found"
	echo "Please run \"SKServer Build SetDir $1\""
   fi
}

start_server () {
   if [ -n "$1" ] ; then
	ulogger_echo_no_nl "Starting $1 ... " | colorize yellow
	SET_NUM="$(get_set_id $1)"
	#CURRENT_PID="$(ps -o pid -C "$1" h|awk '{print $1}' 2>&1|head -1)"
	if [ ${#1} -ge $PROCESS_NAME_LENGTH ]; then
		CURRENT_PID="$(ps -ef | grep "$1" | grep -E -v 'grep|SKServer' | awk -F" " '{print $2}' 2>/dev/null|tr -d ' '|head -1)"
	else
		CURRENT_PID="$(ps -o pid -C "$1" h|awk '{print $1}' 2>/dev/null|tr -d ' '|head -1)"
	fi
	PIDFILE_PID="$(cat $WORKING_DIRECTORY/servers$SET_NUM/$1/pid 2>/dev/null)"
	if grep -q Ticket <<< "$1" ; then
		SERVER_ARGS="-p $TICKETSERVER_PORT"
	fi
	if [ ! -f $WORKING_DIRECTORY/servers$SET_NUM/$1/$1 ] ; then
		ulogger_echo "Error: server $1 does not exist." | colorize red
	elif [ "$CURRENT_PID" ==  "" ] && [ "$PIDFILE_PID" == "" ] ; then
		core_backup $1
		#egrep -q "Mission|World|Zone" <<< "$1" && log_rotate 2 "$1" | tr '\n' ' ' &
		(cd $WORKING_DIRECTORY/servers$SET_NUM/$1
	        chmod a+x $1
		./$* $SERVER_ARGS >& Error.log.$(date +%m%d.%H%M) &
		echo $! > pid)
		grep -q Mission <<< "$server" && sleep 10 || sleep 1
		grep -q World   <<< "$server" && sleep 5  || sleep 1
		echo "OK" | colorize green
	elif [ "$CURRENT_PID" == "$PIDFILE_PID" ] ; then
		echo "already running:" | colorize green
		if [ ${#1} -ge $PROCESS_NAME_LENGTH ]; then
			ps -eo pid,lstart,cp,cmd | grep "$1" | grep -E -v 'grep|SKServer' | colorize magenta
		else
			ps -o pid,lstart,cp,cmd -C "$1" h | colorize magenta
		fi
	elif [ -n "$CURRENT_PID" ] ; then
		echo "already running, but PID is different:" | colorize red
		if [ ${#1} -ge $PROCESS_NAME_LENGTH ]; then
			ps -eo pid,lstart,cp,cmd | grep "$1" | grep -E -v 'grep|SKServer' | colorize red
		else
			ps -o pid,lstart,cp,cmd -C "$1" h | colorize red
		fi
		CURRENT_PID_MD5="$(md5sum /proc/$CURRENT_PID/exe|head -c 32)"
		BINARY_FILE_MD5="$(md5sum $WORKING_DIRECTORY/servers$SET_NUM/$1/$1|head -c 32)"
		if [ "$CURRENT_PID_MD5" == "$BINARY_FILE_MD5" ] ; then
			echo "but the running process same as binary, it should be okay." | colorize cyan
		else
			ulogger_echo "the running process($1) is not the correct binary, not good ... " | colorize red
			#ulogger_echo "WARNING: Gonna restart the server right now." | colorize yellow
			#killall -9 "$1"
			#rm -f $WORKING_DIRECTORY/servers$SET_NUM/$1/pid
			#start_server "$1"
		fi
	elif [ -f $WORKING_DIRECTORY/servers$SET_NUM/$1/pid ] ; then
		ulogger_echo_no_nl "Warning: $1 pid file exist, shutdown not correctly... " | colorize red
		core_backup $1
		#egrep -q "Mission|World|Zone" <<< "$1" && log_rotate 2 "$1" | tr '\n' ' ' &
		(cd $WORKING_DIRECTORY/servers$SET_NUM/$1
	        chmod a+x $1
		./$* $SERVER_ARGS >& Error.log.$(date +%m%d.%H%M) &
		echo $! > pid)
		grep -q Mission <<< "$server" && sleep 10 || sleep 1
		grep -q World   <<< "$server" && sleep 5  || sleep 1
		echo "OK" | colorize green

	fi
	SERVER_ARGS=""
   fi
}

stop_server () {
    if [ -n "$1" ] ; then
	ulogger_echo_no_nl "Stopping $1 ... " | colorize yellow
	SET_NUM="$(get_set_id $1)"
	#CURRENT_PID="$(ps -o pid -C "$1" h|awk '{print $1}' 2>&1|head -1)"
	if [ ${#1} -ge $PROCESS_NAME_LENGTH ]; then
		CURRENT_PID="$(ps -ef | grep "$1" | grep -E -v 'grep|SKServer' | awk -F" " '{print $2}' 2>/dev/null|tr -d ' '|head -1)"
	else
		CURRENT_PID="$(ps -o pid -C "$1" h|awk '{print $1}' 2>/dev/null|tr -d ' '|head -1)"
	fi
	PIDFILE_PID="$(cat $WORKING_DIRECTORY/servers$SET_NUM/$1/pid 2>&1)"
	if [ "$CURRENT_PID" == "$PIDFILE_PID" ] ; then
		[ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] \
		&& killall "$1" \
		|| killall -USR1 "$1"
		waiting_process_down "$1"
	elif [ -n "$CURRENT_PID" ] ; then
		[ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] \
		&& killall "$1" \
		|| killall -USR1 "$1"
		waiting_process_down "$1"
	else
		ulogger_echo "Process $1 is shut down already" | colorize cyan
	fi
	rm -f $WORKING_DIRECTORY/servers$SET_NUM/$1/pid
        rm -f $WORKING_DIRECTORY/servers$SET_NUM/$1/core.[0-9]*
        rm -f $WORKING_DIRECTORY/servers$SET_NUM/$1/core
   fi
}

all_running_servers () {
   ps -Ao cmd|grep "\./[A-Za-z]\+Server[0-9]*"|sed 's/\.\///g;s/^\([A-Za-z0-9]*\).*/\1/g' | grep -E -v "AHNetServer|axloader|$APEXITEMSERVER_BIN|avahi|CTU|SKServer"
}

parallel_stop () {
   for SERVER in $(all_running_servers|grep "$1");do
	SKServer stop $SERVER &
   done
}

get_world_name () {
   SET="$1"
   if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
	[ -f $WORKING_DIRECTORY/bin/worlds.test_set_name ] \
	&& WORLDS_TEST_SET_NAME_FILE="worlds.test_set_name" \
	|| WORLDS_TEST_SET_NAME_FILE="worlds.test"
	sed -n "$SET,${SET}p" $WORKING_DIRECTORY/bin/$WORLDS_TEST_SET_NAME_FILE 2> /dev/null | grep ".*" | tr -d '\r' || echo "World$SET"
   else
	sed -n "$SET,${SET}p" $WORKING_DIRECTORY/bin/worlds.live 2> /dev/null | grep ".*" | tr -d '\r' || echo "World$SET"
   fi
}

get_world_num () {
   NAME="$1"
   if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
	grep -q "^[0-9]\+$" <<< "$NAME" \
	&& echo "$NAME" \
	|| grep -nh "^$NAME$" $WORKING_DIRECTORY/bin/worlds.test|awk -F: '{print $1}'
   else
	grep -q "^[0-9]\+$" <<< "$NAME" \
	&& echo "$NAME" \
	|| grep -nh "^$NAME$" $WORKING_DIRECTORY/bin/worlds.live|awk -F: '{print $1}'
   fi
}

servers_should_running () {
   ls servers*/*/auto_start servers*/*/pid 2> /dev/null|awk -F/ '{print $2}'|sort|uniq -c|awk '$1 > 1 {print $NF}'
}

check_and_restart () {
   if [ -n "$1" ] ; then
	echo -n "Checking $1 ... " | colorize yellow
	SET_NUM="$(get_set_id $1)"
	#CURRENT_PID="$(ps -o pid -C "$1" h|awk '{print $1}' 2>/dev/null|tr -d ' '|head -1)"
	if [ ${#1} -ge $PROCESS_NAME_LENGTH ]; then
		CURRENT_PID="$(ps -ef | grep "$1" | grep -v grep | awk -F" " '{print $2}' 2>/dev/null|tr -d ' '|head -1)"
	else
		CURRENT_PID="$(ps -o pid -C "$1" h|awk '{print $1}' 2>/dev/null|tr -d ' '|head -1)"
	fi
	PIDFILE_PID="$(cat $WORKING_DIRECTORY/servers$SET_NUM/$1/pid 2>/dev/null)"
	if [ ! -f $WORKING_DIRECTORY/servers$SET_NUM/$1/$1 ] ; then
                echo "Error: server $1 does not exist." | colorize red
        elif [ "$CURRENT_PID" ==  "" ] && [ "$PIDFILE_PID" == "" ] ; then
		echo "The server is not started. Doing nothing." | colorize green
	elif [ "$CURRENT_PID" == "$PIDFILE_PID" ] ; then
		echo "Running:" | colorize green
		if [ ${#1} -ge $PROCESS_NAME_LENGTH ]; then
			ps -ef | grep "$1" | grep -v grep | colorize magenta
		else
			ps -o pid,lstart,cp,cmd -C "$1" h | colorize magenta
		fi
	elif [ -n "$CURRENT_PID" ] ; then
		echo -n "already running, but PID file is different ... " | colorize red
		CURRENT_PID_MD5="$(md5sum /proc/$CURRENT_PID/exe|head -c 32)"
		BINARY_FILE_MD5="$(md5sum $WORKING_DIRECTORY/servers$SET_NUM/$1/$1|head -c 32)"
		if [ "$CURRENT_PID_MD5" == "$BINARY_FILE_MD5" ] ; then
			echo "but the running process same as binary, it should be okay." | colorize cyan
		else
			ulogger_echo "the running process($1) is not the correct binary, not good ... " | colorize red
			#ulogger_echo "WARNING: Gonna restart the server right now." | colorize yellow
			#killall -9 "$1"
			#rm -f $WORKING_DIRECTORY/servers$SET_NUM/$1/pid
			#start_server "$1"
		fi
	elif [ -n "$PIDFILE_PID" ] ; then
		ulogger_echo "WARNING: $1 PID file exist, but binary is not running. Going to restart right now." | colorize red
		[ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] || PGPASSWORD="$LIVE_SERVER_DB_PASSWORD" psql -q -h accountdb $ACCOUNT_DB_NAME <<< "insert into crashlog (host, process, eth0, eth1) values ('$HOST_NAME', '$1', '$(another_ip $(print_serverip $(echo $HOST_NAME|awk -F_ '{print $1}')))', '$(print_serverip $(echo $HOST_NAME|awk -F_ '{print $1}'))');" 2> /dev/null
		rm -f $WORKING_DIRECTORY/servers$SET_NUM/$1/pid
		start_server "$1"
	fi
   fi
}

core_backup () {
   if [ -n "$1" ] ; then
	if [ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] ; then
		CORE_DUMP_BACKUP_PATH="$CORE_DUMP_BACKUP_PATH_TEST"
	else
		CORE_DUMP_BACKUP_PATH="$CORE_DUMP_BACKUP_PATH_LIVE"
	fi
	echo -n "Checking core dump ... " | colorize yellow
	SET_NUM="$(get_set_id $1)"
	if ls $WORKING_DIRECTORY/servers$SET_NUM/$1/|grep -E -q "^core\.[0-9]+$|^core$" ; then
		CRASH_DATE="$(date -d "$(stat -c %z $(ls -tr $WORKING_DIRECTORY/servers$SET_NUM/$1/core.[0-9]* $WORKING_DIRECTORY/servers$SET_NUM/$1/core | tail -1) 2> /dev/null)" +%Y%m%dT%H%M%S  2> /dev/null)"
		log_rotate 1 $1 | tr -d '\n'
		ulogger_echo_no_nl " $1 crashed at $CRASH_DATE, " | colorize red
		(
                        echo "===================== $1 crashed at $CRASH_DATE START ====================="
			[ "$HOST_NAME" == "TEST" -o "$HOST_NAME" == "SUB" -o "$HOST_NAME" == "SUBMIT" -o "$HOST_NAME" == "DATA" -o "$HOST_NAME" == "DLC" -o "$HOST_NAME" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ] || PGPASSWORD="$LIVE_SERVER_DB_PASSWORD" psql -e -h accountdb $ACCOUNT_DB_NAME <<< "insert into crashlog (  host, process, eth0, eth1, regdate) values ('$HOST_NAME', '$1', '$(another_ip $(print_serverip $(echo $HOST_NAME|awk -F_ '{print $1}')))', '$(print_serverip $(echo $HOST_NAME|awk -F_ '{print $1}'))', '$CRASH_DATE');" 2> /dev/null
			cd $WORKING_DIRECTORY/servers$SET_NUM/
			mkdir -v "$GAME_TYPE-$COUNTRY_CODE-$1.core_dump.$CRASH_DATE"
			touch $1/no_log_rotate && echo "$1/no_log_rotate created"
			for file in $1/*.log* $1/setup.ini $1/core.[0-9]* $1/core;do
				ln -v "$file" "$(echo $file|sed "s/$1/$GAME_TYPE-$COUNTRY_CODE-$1.core_dump.$CRASH_DATE/g")" 2>&1
			done
			cp -v $1/$1 $GAME_TYPE-$COUNTRY_CODE-$1.core_dump.$CRASH_DATE/
			rm -rf $GAME_TYPE-$COUNTRY_CODE-$1.core_dump.$CRASH_DATE/{one,two}level.log.*
			tar zcvf $GAME_TYPE-$COUNTRY_CODE-$1.core_dump.$CRASH_DATE.tar.gz $GAME_TYPE-$COUNTRY_CODE-$1.core_dump.$CRASH_DATE
			ssh TEST "mkdir -pv ~/www/core/test"
			scp -o StrictHostKeyChecking=no $GAME_TYPE-$COUNTRY_CODE-$1.core_dump.$CRASH_DATE.tar.gz $CORE_DUMP_BACKUP_PATH \
			&& rm -rfv $GAME_TYPE-$COUNTRY_CODE-$1.core_dump.$CRASH_DATE.tar.gz $GAME_TYPE-$COUNTRY_CODE-$1.core_dump.$CRASH_DATE $1/core.[0-9]* $1/core $1/no_log_rotate \
			|| ulogger_echo_no_nl "Error: scp $GAME_TYPE-$COUNTRY_CODE-$1.core_dump.$CRASH_DATE.tar.gz to $CORE_DUMP_BACKUP_PATH failed."
                        rm -fv $1/no_log_rotate
                        echo "===================== $1 crashed at $CRASH_DATE END ====================="
		) >> $HOME/.core_backup.log 2>&1 &
                disown > /dev/null
                echo -n "backing up the core, binary and log files in background ... " | colorize red
	else
		echo -n "looks good... " | colorize green
	fi
   fi
}

get_patch_from_remote () {
   for remote_dir in $REMOTE_PATCH_DIRS ; do
#     if [ "$GAME_TYPE" == "FN" ] ; then
#	lftp -e "lcd $LOCAL_PATCH_DIR;cd $remote_dir;mirror -c .;exit" http://$REMOTE_PATCH_SERVER/
#     elif [ "$GAME_TYPE" == "FF" ] || [ "$GAME_TYPE" == "DS" ] || [ "$GAME_TYPE" == "AR" ] || [ "$GAME_TYPE" == "LA" ] || [ "$GAME_TYPE" == "AK" ] || [ "$GAME_TYPE" == "M3" ] || [ "$GAME_TYPE" == "M11" ] || [ "$GAME_TYPE" == "M12" ] || [ "$GAME_TYPE" == "UG1" ] || [ "$GAME_TYPE" == "G1" ] || [ "$GAME_TYPE" == "G2" ]; then
     if [ "$GAME_TYPE" == "DJ" ] || [ "$GAME_TYPE" == "FN" ] || [ "$GAME_TYPE" == "FF" ] || [ "$GAME_TYPE" == "DS" ] || [ "$GAME_TYPE" == "AR" ] || [ "$GAME_TYPE" == "LA" ] || [ "$GAME_TYPE" == "AK" ] || [ "$GAME_TYPE" == "M3" ] || [ "$GAME_TYPE" == "M11" ] || [ "$GAME_TYPE" == "M12" ] || [ "$GAME_TYPE" == "UG1" ] || [ "$GAME_TYPE" == "G1" ] || [ "$GAME_TYPE" == "G2" ] || [ "$GAME_TYPE" == "GD" ] || [ "$GAME_TYPE" == "N1" ] || [ "$GAME_TYPE" == "H2" ] ; then
        VERSION="$(awk -F/ '{print $NF}' <<< "$1")"
        lftp -e "lcd $LOCAL_PATCH_DIR;mirror -c $VERSION;exit" http://$REMOTE_PATCH_SERVER/$COUNTRY_CODE/
     elif [ "$GAME_TYPE" == "M2" ] ; then
        lftp -e "lcd $LOCAL_PATCH_DIR;mget -c $1 $2 $3 $4;exit" http://$REMOTE_PATCH_SERVER/$REMOTE_PATCH_DIRS/
     else
	lftp -e "lcd $LOCAL_PATCH_DIR;cd $remote_dir;mirror -c $1;exit" ftp://$REMOTE_PATCH_SERVER/
     fi
   done
}

check_gm_command_config () {
   sendscript allwz <<< 'source ~/.gamerc;echo -n "Checking the GM Commands configuration file ... "|colorize magenta ; LC_ALL=C grep "^<encode>" $WORKING_DIRECTORY/common/Data/db/S_RootCmds.ini > /dev/null 2>&1 && ulogger_echo "NOT GOOD, THE FILE IS ENCRYPTED. THE PLAYERS CAN USE THE GM COMMANDS." | colorize red ; grep ,0, $WORKING_DIRECTORY/common/Data/db/S_RootCmds.ini > /dev/null 2>&1 && ulogger_echo "NOT GOOD, THE PLAYERS CAN USE THE GM COMMANDS." | colorize red || echo "OK" | colorize green'
}

max_set () {
   sed -n '/BELOW/,/ABOVE/p' /etc/hosts|tr ' ' '\n'|grep GAMEDB|sort -g|tail -1|sed 's/GAMEDB//g'
}

change_family_statue_world_id () {
   if [ "$GAME_TYPE" == "FN" ] || [ "$GAME_TYPE" == "GD" ] || [ "$GAME_TYPE" == "FF" ] || [ "$GAME_TYPE" == "AR" ] || [ "$GAME_TYPE" == "DJ" ] ; then
	for SET in $SET_NUMBER_LIST ; do
		echo -n "Change the family statues to world id $(get_server_id $SET $CROSS_CHANNEL world) for set $SET ... " | colorize yellow
		ssh gamedb$SET "psql -q $GAME_DB_NAME$SET <<< 'update statues_scenes set worldserver_id = $(get_server_id $SET $CROSS_CHANNEL world) where family_id > 0 ;'" \
		&& echo "OK" | colorize green \
		|| echo "FAILED" | colorize red
	done
   fi
}

clean_currentuser () {
  if print_serverip BGW | grep -q "^[0-9]" ; then
    for mid in $(
        psql -t $MEMBER_DB_NAME <<< "select mid from currentuser ;");do
		echo "select char_logout('$mid', 0, 0);"
	done | psql $MEMBER_DB_NAME > /dev/null 2>&1
  else
    return 0
  fi
}

game_db () {
   if grep -E -q "TEST|SUB|DATA|DLC|TIME|MEDIA|MERGE" <<< "$HOST_NAME" ; then
	psql $* "${GAME_DB_NAME}10"
   else
	SET_NUMBER=$(get_set_id $(awk -F_ '{print $1}' <<< "$HOST_NAME"))
	psql -h GAMEDB$SET_NUMBER $GAME_DB_NAME$SET_NUMBER
   fi
}

account_db () {
   if grep -E -q "ACCOUNTDB|TEST|SUB|DATA|DLC|TIME|MEDIA|MERGE" <<< "$HOST_NAME" ; then
	psql $* "$ACCOUNT_DB_NAME"
   else
	psql -h ACCOUNTDB $ACCOUNT_DB_NAME
   fi
}

member_db () {
   if grep -E -q "ACCOUNTDBDB|TEST|SUB|DATA|DLC|TIME|MEDIA|MERGE" <<< "$HOST_NAME" ; then
	psql $* "$MEMBER_DB_NAME"
   else
	psql -h ACCOUNTDB $MEMBER_DB_NAME
   fi
}

society_db () {
   if grep -E -q "TEST|SUB|DATA|DLC|TIME|MEDIA|MERGE" <<< "$HOST_NAME" ; then
        psql $* "${SOCIETY_DB_NAME}10"
   else
	SET_NUMBER=$(get_set_id $(awk -F_ '{print $1}' <<< "$HOST_NAME"))
        psql -h SOCIETYDB$SET_NUMBER $SOCIETY_DB_NAME$SET_NUMBER
   fi
}

world_db () {
   if grep -E -q "TEST|SUB|DATA|DLC|TIME|MEDIA|MERGE" <<< "$HOST_NAME" ; then
        psql $* "${WORLD_DB_NAME}1001"
   else
	WORLD_NUMBER=$(get_world_id $(awk -F_ '{print $1}' <<< "$HOST_NAME"))
        psql -h WORLDDB$WORLD_NUMBER $WORLD_DB_NAME$WORLD_NUMBER
   fi
}

tools_db () {
   if grep -E -q "TEST" <<< "$HOST_NAME" ; then
        psql $* "Tools"
   else
        psql -h TEST Tools
   fi
}

get_nat_ext_ip () {
   grep "^$1 " ~/bin/NAT_IP_table | awk '{print $NF}'
}

check_db_exist () {
   if [ "$(psql -U postgres <<< "copy (select count(*) from pg_catalog.pg_database where datname = '$1')to STDOUT csv;")" == "1" ] ; then
        return 0
   else
        return 1
   fi
}

goto () {
   if [ "$1" == "" ] ; then
        echo "Usage: goto <W|Z|HOSTNAME><Set><Channel>
for ex.
Go to Set 1 Channel 2 WorldServer directory:
$ goto W12

Go to Set 1 Channel 2 ZoneServer directory:
$ goto W12
"
        return 1
   fi
   TARGET_HOST="$(tr '[a-z]' '[A-Z]' <<< $1)"
   if grep -q "^W[0-9]" <<< "$TARGET_HOST"; then
        TARGET_HOST="$(sed 's/^W/WZ/g' <<< "$TARGET_HOST")"
   elif grep -q "^Z[0-9]" <<< "$TARGET_HOST" ; then
        TARGET_HOST="$(sed 's/^Z/WZ/g' <<< "$TARGET_HOST")"
   fi
   SET="$(get_set_id $TARGET_HOST)"
   CHANNEL="$(get_ch $TARGET_HOST 2> /dev/null)"
   if grep -qi "^W[0-9]" <<< "$1"; then
        SERVER_DIR="WorldServer$SET$CHANNEL"
   elif grep -qi "^Z[0-9]" <<< "$1" ; then
        SERVER_DIR="ZoneServer$SET$CHANNEL"
   elif grep -qi "^WZ[0-9]" <<< "$1" ; then
        SERVER_DIR=""
   elif grep -q "^GAMEDB" <<< "$TARGET_HOST" ; then
        SERVER_DIR="MissionServer$SET"
   elif grep -q "^BGW" <<< "$TARGET_HOST" ; then
        SERVER_DIR="GatewayServer"
   elif grep -q "^TICKET" <<< "$TARGET_HOST" ; then
        SERVER_DIR="TicketServer"
   else
        SERVER_DIR=""
   fi
   ssh -o StrictHostKeyChecking=no -t $TARGET_HOST "cd ~/servers$SET/$SERVER_DIR;/bin/bash --login"
}

fix_goto () {
   sendscript allall <<< "sed -i -e 's/^source \.gamerc/source ~\/.gamerc/g' ~/.bashrc"
}

fix_log () {
   LC_ALL=C sed ':x;N;$!bx;s/\n/|/g;s/|\([\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x20]\{6,\},\)/\n\1/g'
}

generate_config00_ini () {
   sed "s/__CrossWorldID__/$CrossWorldID/g
        s/__TerritoryWorldID__/$TerritoryWorldID/g
        s/__ColosseumWorldID__/$ColosseumWorldID/g
        s/__PlayerRoomWorldID__/$PlayerRoomWorldID/g
        s/__FightZoneWroldID__/$FightZoneWroldID/g" \
    ~/bin/config00.ini_$GAME_TYPE_LOWER
}

compare_test_setup_ini () {
   cat ~/servers*/setup.ini | awk -F= '/=/ {print $1}'|sort|uniq > /tmp/setup_ini_local
   ssh test "source ~/.gamerc ; cat ~/servers\$(get_set_id TEST)/setup.ini | awk -F= '/=/ {print \$1}'|sort|uniq" > /tmp/setup_ini_test
   ssh test "source ~/.gamerc ; cat ~/servers\$(get_set_id TEST)/setup.ini | grep '=1$' | awk -F= '/=/ {print \$1}' | sort | uniq" > /tmp/setup_ini_should_turn_on
   DIFF="$(diff -p -u /tmp/setup_ini_local /tmp/setup_ini_test | grep "^+[^+]" | sed 's/^+//g' | grep -E -v "MaintenanceDate|MissionServerID")"
   SHOULD_TURN_ON="$(cat /tmp/setup_ini_should_turn_on | while read ; do grep -q "$REPLY=1" ~/servers*/setup.ini || echo "$REPLY=1" ; done | grep -E -v "MaintenanceDate|MissionServerID")"

   if [ "$DIFF" == "" ] && [ "$SHOULD_TURN_ON" == "" ] ; then
       echo "Looks good, nothing different in setup.ini between LIVE and TEST." | colorize green black
   else
       echo '                  WARNING!! WARNING!! WARNING!!                 ' | colorize red black 5
       echo 'There is something different in setup.ini between LIVE and TEST.' | colorize red black
       if [ "$DIFF" != "" ] ; then
           echo "Needs to be add:" | colorize red black
           echo "$DIFF"
           echo
       fi
       if [ "$SHOULD_TURN_ON" != "" ] ; then
           echo "Needs to be turn on:" | colorize red black
           echo "$SHOULD_TURN_ON"
           echo
       fi
       echo 'Please contact X-Legend for more details.' | colorize magenta black
   fi

   rm -f /tmp/setup_ini_local /tmp/setup_ini_test /tmp/setup_ini_should_turn_on
}

compare_test_srootcmds_ini () {
    SET=$(getmws_setid)

    if [ "$MOBILE" == "1" ] ; then
        CHECK_FILE="s_rootcmds.ini"
    else
        CHECK_FILE="S_RootCmds.ini"
    fi

    if [ "$HOST_NAME" != "CTRL" ]; then
    	#md5_srootcmds_test=$(ssh test "/usr/bin/md5sum ~/servers\$(get_set_id TEST)/Data/db/${CHECK_FILE} | awk -F\" \" '{print \$1}'")
    	md5_srootcmds_test=$(ssh test "/usr/bin/md5sum ${WORKING_DIRECTORY}/servers1/Data/db/${CHECK_FILE} | awk -F\" \" '{print \$1}'")
	if [ -f "${WORKING_DIRECTORY}/servers${SET}/Data/db/${CHECK_FILE}" ]; then
    		md5_srootcmds_live=$(/usr/bin/md5sum ${WORKING_DIRECTORY}/servers${SET}/Data/db/${CHECK_FILE} | awk -F" " '{print $1}')

    		if [ "${md5_srootcmds_test}" == "${md5_srootcmds_live}" ]; then
		    echo "TEST: ${md5_srootcmds_test} v.s. ${HOST_NAME}: ${md5_srootcmds_live}"
    		    echo '                  WARNING!! WARNING!! WARNING!!                 ' | colorize red black 5
    		    echo "${CHECK_FILE} between LIVE and TEST is the same. Please check it." | colorize red black
    		else
    		    echo "Looks good, ${CHECK_FILE} between LIVE and TEST is different." | colorize green black
    		fi
	fi
    fi
}

detailed_return_compare_test_srootcmds_ini () {
    SET=$(getmws_setid)

    if [ "$MOBILE" == "1" ] ; then
        CHECK_FILE="s_rootcmds.ini"
    else
        CHECK_FILE="S_RootCmds.ini"
    fi

    if [ "$HOST_NAME" != "CTRL" ]; then
    	#md5_srootcmds_test=$(ssh test "/usr/bin/md5sum ~/servers\$(get_set_id TEST)/Data/db/${CHECK_FILE} | awk -F\" \" '{print \$1}'")
    	md5_srootcmds_test=$(ssh test "/usr/bin/md5sum ${WORKING_DIRECTORY}/servers1/Data/db/${CHECK_FILE} | awk -F\" \" '{print \$1}'")
	if [ -f "${WORKING_DIRECTORY}/servers${SET}/Data/db/${CHECK_FILE}" ]; then
    		md5_srootcmds_live=$(/usr/bin/md5sum ${WORKING_DIRECTORY}/servers${SET}/Data/db/${CHECK_FILE} | awk -F" " '{print $1}')

    		if [ "${md5_srootcmds_test}" == "${md5_srootcmds_live}" ]; then
    		    echo "0 $HOST_NAME,"
    		else
    		    echo "1 $HOST_NAME,"
    		fi
	fi
    else
    	echo "0 $HOST_NAME,"
    fi

}

final_return_compare_test_srootcmds_ini () {
    CHECK_SROOTCMDSINI_RESULT=$(sendscript allms nosave nohostname <<< "source ~/.gamerc ; detailed_return_compare_test_srootcmds_ini")

    TOTAL_FIELDS=$(echo ${CHECK_SROOTCMDSINI_RESULT} | awk -F"," '{print NF}')
    for (( FIELD=1; FIELD<${TOTAL_FIELDS}; FIELD++ )); do
        STATUS=$(echo ${CHECK_SROOTCMDSINI_RESULT} | awk -F',' "{print \$${FIELD}}" | awk -F' ' "{print \$1}")
        MACHINE=$(echo ${CHECK_SROOTCMDSINI_RESULT} | awk -F',' "{print \$${FIELD}}" | awk -F' ' "{print \$2}")

        if [[ ${STATUS} == "0" ]]; then
                OUTPUT="${OUTPUT}${MACHINE} "
        fi
    done

    echo $OUTPUT
}

getms_setid () {
    TOTAL_FIELDS=$(echo $HOST_NAME | awk -F"_" '{print NF}')
	if [[ ${TOTAL_FIELDS} -eq 0 ]]; then
		TOTAL_FIELDS=1
	fi

    for (( FIELD=1; FIELD<=${TOTAL_FIELDS}; FIELD++ )); do
        STRING=$(echo $HOST_NAME | awk -F'_' "{print \$${FIELD}}")
	    #STRING_LENGTH=$(expr length ${STRING})
	    #SET=$(echo ${STRING} | sed 's/MS//')
	    if [[ ${STRING} == MS* ]]; then
	    	SET=$(get_set_id ${STRING})
	    	echo ${SET}
	    fi
    done
}

getmws_setid () {
    TOTAL_FIELDS=$(echo $HOST_NAME | awk -F"_" '{print NF}')
	if [[ ${TOTAL_FIELDS} -eq 0 ]]; then
		TOTAL_FIELDS=1
	fi

    for (( FIELD=1; FIELD<=${TOTAL_FIELDS}; FIELD++ )); do
        STRING=$(echo $HOST_NAME | awk -F'_' "{print \$${FIELD}}")
	if [[ ${STRING} == MS* || ${STRING} == WS* ]]; then
		SET=$(get_set_id ${STRING})
		echo ${SET}
	fi
    done
}

check_server_exist_from_hosts () {
	SERVER_TYPE="$1"
	SERVER_LISTS=$(print_hosts)
	CHECK_SERVER_EXIST=$(echo $SERVER_LISTS | grep $SERVER_TYPE)
	[ -n "$CHECK_SERVER_EXIST" ] && echo 1 || echo 0
}

string_length () {
	STRING="$1"
	echo ${#STRING}
}

initialize_node_stream () {
	SET="$1"
	LOWER_GAME_TYPE=$(echo $GAME_TYPE | tr '[A-Z]' '[a-z]')
	GAMEDB_NUM=$(get_gamedb_from_ms $SET)
	GAMEDB_IP=$(cat /etc/hosts | grep "GAMEDB${GAMEDB_NUM}" | awk -F" " '{print $1}')

	MS_STR_LENGTH=$(string_length MS)
	WZ_STR_LENGTH=$(string_length WZ)
	SET_STR_LENGTH=$(string_length $SET)

	MS_STR_LENGTH_REAL=$((MS_STR_LENGTH + SET_STR_LENGTH))
	WZ_STR_LENGTH_REAL=$((WZ_STR_LENGTH + SET_STR_LENGTH + 2))

	for server_name in $(print_hosts MS$SET); do
		SET_ID=$(echo $server_name | sed 's/MS//')
		if [ "$SET_ID" -eq "$SET" ]; then
			for channel_name in $(print_hosts WZ$SET); do
				if [ "${#channel_name}" -eq $WZ_STR_LENGTH_REAL ]; then
					TMP_CHANNEL_ID=$(echo $channel_name | sed 's/WZ//')
					if [ -z "${CHANNEL_ID}" ] || [ "$TMP_CHANNEL_ID" -gt "$CHANNEL_ID" ]; then
						CHANNEL_ID="$TMP_CHANNEL_ID"
					fi
				fi
			done
		fi
		CHANNEL_ID="${CHANNEL_ID}0"
	done

	if [ -e "$HOME/bin/node_stream_${LOWER_GAME_TYPE}.sql" ]; then
		cat $HOME/bin/node_stream_${LOWER_GAME_TYPE}.sql | sed "s/XXXX/$CHANNEL_ID/g;s/999/$SET/g" > /tmp/node_stream_${LOWER_GAME_TYPE}_live_s${SET}.sql
		PGPASSWORD="$LIVE_SERVER_DB_PASSWORD" psql -h $GAMEDB_IP -U $PGUSER $GAME_DB_NAME$GAMEDB_NUM < /tmp/node_stream_${LOWER_GAME_TYPE}_live_s${SET}.sql 2>&1 | sed 's/^/node_stream: /g'
	fi
}

reset_db_password () {
	TARGET="$1"

	if [ "$#" -eq "1" ]; then
		if [ "$TARGET" == "LIVE" ]; then
			for ip in $(cat /etc/hosts | sed -n '/\# PLEASE/,/# DO/p' | grep -E 'CTRL|GAMEDB|WZ|ACCOUNTDB|BGW|LOGIN|ACCTDB|GDS|GAMEAGENT|SAT' | grep -v '^#' | awk -F" " '{print $1}'); do
				echo ${ip} | colorize blue black
				print_servername ${ip} | colorize yellow black
				ssh ${ip} "source $HOME/.gamerc; sed -i -r \"s/GameDBPassword=(.*)/GameDBPassword=$LIVE_SERVER_DB_PASSWORD/;s/AccountDBPW=(.*)/AccountDBPW=$LIVE_SERVER_DB_PASSWORD/\" $HOME/servers*/setup.ini"
			done
			for ip in $(cat /etc/hosts | sed -n '/\# PLEASE/,/# DO/p' | grep -E 'BGW' | grep -v '^#' | awk -F" " '{print $1}'); do
				echo ${ip} | colorize blue black
				print_servername ${ip} | colorize yellow black
				ssh ${ip} "source $HOME/.gamerc; sed -i -r \"s/AccountDBPW=(.*)/AccountDBPW=$LIVE_SERVER_DB_PASSWORD/\" $HOME/servers1/GatewayServer/setup.ini"
			done
			for ip in $(cat /etc/hosts | sed -n '/\# PLEASE/,/# DO/p' | grep -E 'CTRL|GAMEDB|ACCOUNTDB|BGW' | grep -v '^#' | awk -F" " '{print $1}'); do
				echo ${ip} | colorize blue black
				print_servername ${ip} | colorize yellow black
				ssh ${ip} "source $HOME/.gamerc; psql -U postgres -c \"ALTER USER spiritking WITH PASSWORD '$LIVE_SERVER_DB_PASSWORD';\""
			done
		elif [ "$TARGET" == "TEST" -o "$TARGET" == "SUB" -o "$TARGET" == "SUBMIT" -o "$TARGET" == "DATA" -o "$TARGET" == "DLC" -o "$TARGET" == "TIME1" -o "$HOST_NAME" == "MEDIA" -o "$HOST_NAME" == "MERGE" ]; then

			for ip in $(cat /etc/hosts | grep -E "$TARGET" | grep -v '^#' | awk -F" " '{print $1}'); do
				echo ${ip} | colorize blue black
				print_servername ${ip} | colorize yellow black
				ssh ${ip} "source $HOME/.gamerc; sed -i -r \"s/GameDBPassword=(.*)/GameDBPassword=$TEST_SERVER_DB_PASSWORD/;s/AccountDBPW=(.*)/AccountDBPW=$TEST_SERVER_DB_PASSWORD/\" $HOME/servers*/setup.ini"
			done
			for ip in $(cat /etc/hosts | grep -E "$TARGET" | grep -v '^#' | awk -F" " '{print $1}'); do
				echo ${ip} | colorize blue black
				print_servername ${ip} | colorize yellow black
				ssh ${ip} "source $HOME/.gamerc; sed -i -r \"s/AccountDBPW=(.*)/AccountDBPW=$TEST_SERVER_DB_PASSWORD/\" $HOME/servers1/GatewayServer/setup.ini"
			done
			for ip in $(cat /etc/hosts | grep -E "$TARGET" | grep -v '^#' | awk -F" " '{print $1}'); do
				echo ${ip} | colorize blue black
				print_servername ${ip} | colorize yellow black
				ssh ${ip} "source $HOME/.gamerc; psql -U postgres -c \"ALTER USER spiritking WITH PASSWORD '$TEST_SERVER_DB_PASSWORD';\""
			done
		else
			echo "Wrong target" | colorize red black
			echo "Usage: reset_db_password <LIVE|TEST|SUB|SUBMIT|DATA|DLC|TIME1|MEDIA|MERGE>"
		fi
	else
		echo "Wrong parameter numbers" | colorize red black
		echo "Usage: reset_db_password <LIVE|TEST|SUB|SUBMIT|DATA|DLC|TIME1|MEDIA|MERGE>"
	fi
}

rewrite_etc_hosts () {
   if [ -w /etc/hosts ] ; then
       [ -f $HOME/.hosts ] && cat $HOME/.hosts $HOME/bin/hosts > /etc/hosts 2> /dev/null
       echo "Notice: /etc/hosts updated!" | colorize green
   else
       echo "Error: /etc/hosts is not writable" | colorize red
   fi
}

# Package Mover and URL Showing by Vincent
move_app_for_download () {
   if [ "$GAME_TYPE" == "AK" ] ; then
      GAME_TYPE="M7"
   fi
   LOWER_GAME_TYPE=$(echo ${GAME_TYPE,,})
   LOWER_COUNTRY_CODE=$(echo ${COUNTRY_CODE,,})
   APP_PREFIX=${LOWER_GAME_TYPE}${LOWER_COUNTRY_CODE}

   PATCH_DIR_NAME=$1
   LOCAL_PATCH_DIR_FILES="$LOCAL_PATCH_DIR/$PATCH_DIR_NAME/*"
   DOWNLOAD_DIR_ROOT_PATH="$WORKING_DIRECTORY/www/app/"

   for full_path_file in $LOCAL_PATCH_DIR_FILES ; do
      file=$(basename $full_path_file)
      if [[ "$file" =~ ^.*\.apk$ ]] ; then
         if [ ! -d $DOWNLOAD_DIR_ROOT_PATH/android ] ; then
            mkdir -p $DOWNLOAD_DIR_ROOT_PATH/android
         fi
         echo
         echo "SOURCE: $file"
         FILE_MD5=$(md5sum $full_path_file | awk -F" " '{print $1}')
         APP_PUBLISH_VERSION=$(echo $file | cut -d '_' -f2,3,4 | sed 's/\.apk//;s/[a-zA-Z]*//;s/^_//')
         echo "TARGET: ${APP_PREFIX}_${PATCH_DIR_NAME}_${APP_PUBLISH_VERSION}.apk (MD5: ${FILE_MD5})"
         mv -v $LOCAL_PATCH_DIR/$PATCH_DIR_NAME/$file $DOWNLOAD_DIR_ROOT_PATH/android/${APP_PREFIX}_${PATCH_DIR_NAME}_${APP_PUBLISH_VERSION}.apk
         echo "HREF: http://$TEST_SERVER_GLOBAL_IP/app/android/${APP_PREFIX}_${PATCH_DIR_NAME}_${APP_PUBLISH_VERSION}.apk"
	 unpack_apk_info $DOWNLOAD_DIR_ROOT_PATH/android/${APP_PREFIX}_${PATCH_DIR_NAME}_${APP_PUBLISH_VERSION}.apk
      elif [[ "$file" =~ ^.*\.ipa$ ]] ; then
         if [[ "$file" =~ ^.*(ad|Ad|aD|AD).*\.ipa$ ]] ; then
            if [ ! -d $DOWNLOAD_DIR_ROOT_PATH/ios/build_ad ] ; then
               mkdir -p $DOWNLOAD_DIR_ROOT_PATH/ios/build_ad
            fi
            echo
            echo "SOURCE: $file"
            FILE_MD5=$(md5sum $full_path_file | awk -F" " '{print $1}')
            APP_PUBLISH_VERSION=$(echo $file | cut -d '_' -f2,3,4 | sed 's/\.ipa//;s/[a-zA-Z]*//;s/^_//')
            echo "TARGET: ${APP_PREFIX}_${PATCH_DIR_NAME}_${APP_PUBLISH_VERSION}_ad.ipa (MD5: ${FILE_MD5})"
            mv -v $LOCAL_PATCH_DIR/$PATCH_DIR_NAME/$file $DOWNLOAD_DIR_ROOT_PATH/ios/build_ad/${APP_PREFIX}_${PATCH_DIR_NAME}_${APP_PUBLISH_VERSION}_ad.ipa
            echo "HREF: http://$TEST_SERVER_GLOBAL_IP/app/ios/build_ad/${APP_PREFIX}_${PATCH_DIR_NAME}_${APP_PUBLISH_VERSION}_ad.ipa"
	    unpack_ipa_info $DOWNLOAD_DIR_ROOT_PATH/ios/build_ad/${APP_PREFIX}_${PATCH_DIR_NAME}_${APP_PUBLISH_VERSION}_ad.ipa
         else
            if [ ! -d $DOWNLOAD_DIR_ROOT_PATH/ios/build ] ; then
               mkdir -p $DOWNLOAD_DIR_ROOT_PATH/ios/build
            fi
            echo
            echo "SOURCE: $file"
            FILE_MD5=$(md5sum $full_path_file | awk -F" " '{print $1}')
            APP_PUBLISH_VERSION=$(echo $file | cut -d '_' -f2,3,4 | sed 's/\.ipa//;s/[a-zA-Z]*//;s/^_//')
            echo "TARGET: ${APP_PREFIX}_${PATCH_DIR_NAME}_${APP_PUBLISH_VERSION}.ipa (MD5: ${FILE_MD5})"
            mv -v $LOCAL_PATCH_DIR/$PATCH_DIR_NAME/$file $DOWNLOAD_DIR_ROOT_PATH/ios/build/${APP_PREFIX}_${PATCH_DIR_NAME}_${APP_PUBLISH_VERSION}.ipa
            echo "HREF: http://$TEST_SERVER_GLOBAL_IP/app/ios/build/${APP_PREFIX}_${PATCH_DIR_NAME}_${APP_PUBLISH_VERSION}.ipa"
	    unpack_ipa_info $DOWNLOAD_DIR_ROOT_PATH/ios/build/${APP_PREFIX}_${PATCH_DIR_NAME}_${APP_PUBLISH_VERSION}.ipa
         fi
      fi
   done
   echo
}

# OBB Mover and URL Showing by Vincent
move_obb_for_download () {
   PATCH_DIR_NAME=$1
   LOCAL_PATCH_DIR_FILES="$LOCAL_PATCH_DIR/$PATCH_DIR_NAME/*.obb"
   DOWNLOAD_DIR_ROOT_PATH="$WORKING_DIRECTORY/www/app/"

   if [ -f $LOCAL_PATCH_DIR_FILES ] ; then
      for full_path_file in $LOCAL_PATCH_DIR_FILES ; do
         file=$(basename $full_path_file)
         if [ ! -d $DOWNLOAD_DIR_ROOT_PATH/android ] ; then
            mkdir -p $DOWNLOAD_DIR_ROOT_PATH/android
         fi
         echo
         echo "OBB SOURCE: $file"
         FILE_MD5=$(md5sum $full_path_file | awk -F" " '{print $1}')
         echo "TARGET: ${file} (MD5: ${FILE_MD5})"
         mv -v $LOCAL_PATCH_DIR/$PATCH_DIR_NAME/$file $DOWNLOAD_DIR_ROOT_PATH/android/
         echo "HREF: http://$TEST_SERVER_GLOBAL_IP/app/android/${file}"
      done
      echo
   fi
}

rename_client_extension () {
    TEST_CLIENT_DIRECTORY="$HOME/www/${GAME_TYPE}-TEST"
    SYNC2LIVE_DIRECTORY="$HOME/www/${GAME_TYPE}-TEST_SYNCTOLIVE"
    CHECK_FILE="setup.txt"
    VERSION_FILE="version"
    TRANSLATE_FILE="TranslateFileList"
    OLD_NFSExtension=$(grep -E -a 'NFSExtension' ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE} | sed 's/NFSExtension=//')

    if [ ! -d "${SYNC2LIVE_DIRECTORY}" ]; then
        rsync -avz --progress ${TEST_CLIENT_DIRECTORY}/ ${SYNC2LIVE_DIRECTORY}/
    else
        CHECK_VERSION="0"
        PLATFORM_COUNT=$(find ${TEST_CLIENT_DIRECTORY} -maxdepth 1 -mindepth 1 -type d | wc -l)
        for platform_fullpath in $(find ${TEST_CLIENT_DIRECTORY} -maxdepth 1 -mindepth 1 -type d); do
            platform=$(basename ${platform_fullpath})
            MD5_TEST_VERSION=$(md5sum ${TEST_CLIENT_DIRECTORY}/${platform}/${VERSION_FILE} | awk -F' ' '{print $1}')
            MD5_SYNCTOLIVE_VERSION=$(md5sum ${SYNC2LIVE_DIRECTORY}/${platform}/${VERSION_FILE}${OLD_NFSExtension} | awk -F' ' '{print $1}')

            if [ "${MD5_TEST_VERSION}" == "${MD5_SYNCTOLIVE_VERSION}" ]; then
                ((CHECK_VERSION ++))
            fi
        done

        CHECK_TRANSLATE="0"
        TRANSLATE_COUNT=$(find ${TEST_CLIENT_DIRECTORY}/Android/translate_data/db_* -type f -name "*_${TRANSLATE_FILE}" | wc -l)
        TOTAL_TRANSLATE_COUNT=$((PLATFORM_COUNT * TRANSLATE_COUNT))
        for platform_fullpath in $(find ${TEST_CLIENT_DIRECTORY} -maxdepth 1 -mindepth 1 -type d); do
            platform=$(basename ${platform_fullpath})

            for translate_fullpath in $(find ${TEST_CLIENT_DIRECTORY}/${platform}/translate_data/db_* -type f -name "*_${TRANSLATE_FILE}"); do
                FILENAME_RELATIVE_PATH=$(echo "${translate_fullpath}" | sed -r "s|${TEST_CLIENT_DIRECTORY}/${platform}/translate_data/*||")
                MD5_TEST_TRANSLATE=$(md5sum ${TEST_CLIENT_DIRECTORY}/${platform}/translate_data/${FILENAME_RELATIVE_PATH} | awk -F' ' '{print $1}')
                MD5_SYNCTOLIVE_TRANSLATE=$([ -f ${SYNC2LIVE_DIRECTORY}/${platform}/translate_data/${FILENAME_RELATIVE_PATH}${OLD_NFSExtension} ] && md5sum ${SYNC2LIVE_DIRECTORY}/${platform}/translate_data/${FILENAME_RELATIVE_PATH}${OLD_NFSExtension} | awk -F' ' '{print $1}' || echo "null")

                if [ "${MD5_TEST_TRANSLATE}" == "${MD5_SYNCTOLIVE_TRANSLATE}" ]; then
                    ((CHECK_TRANSLATE ++))
                fi
            done
        done

        CHECK_SETUP="0"
        MD5_TEST_SETUP=$(sed '/wsproxy=/d;/login=/d' ${TEST_CLIENT_DIRECTORY}/${CHECK_FILE} | md5sum | awk -F' ' '{print $1}')
        MD5_SYNCTOLIVE_SETUP=$([ -f ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE} ] && sed '/wsproxy=/d;/login=/d;/NFSExtension=/d' ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE} | md5sum | awk -F' ' '{print  $1}' || echo "null")
        if [ "${MD5_TEST_SETUP}" != "${MD5_SYNCTOLIVE_SETUP}" ]; then
            ((CHECK_SETUP ++))
        fi

        CHECK_NOTICE="0"
        MD5_CHECK_NOTICE_CURRENT_FILE="/tmp/MD5_NOTICE_CURRENT"
        MD5_CHECK_NOTICE_OLD_FILE="/tmp/MD5_NOTICE_OLD"
        if find ${TEST_CLIENT_DIRECTORY} -maxdepth 1 -name "*notice.txt" | grep -q .; then
            md5sum ${TEST_CLIENT_DIRECTORY}/*notice.txt | sort | sed "s|${TEST_CLIENT_DIRECTORY}/||" | sort > ${MD5_CHECK_NOTICE_CURRENT_FILE}
            if find ${SYNC2LIVE_DIRECTORY} -maxdepth 1 -name "*notice.txt" | grep -q .; then
                md5sum ${SYNC2LIVE_DIRECTORY}/*notice.txt | sort | sed "s|${SYNC2LIVE_DIRECTORY}/||" | sort > ${MD5_CHECK_NOTICE_OLD_FILE}
            else
                echo "null" > ${MD5_CHECK_NOTICE_OLD_FILE}
            fi
            MD5_TEST_NOTICE=$(md5sum ${MD5_CHECK_NOTICE_CURRENT_FILE} | awk -F' ' '{print $1}')
            MD5_SYNCTOLIVE_NOTICE=$(md5sum ${MD5_CHECK_NOTICE_OLD_FILE} | awk -F' ' '{print $1}')
            if [ "${MD5_TEST_NOTICE}" != "${MD5_SYNCTOLIVE_NOTICE}" ] ; then
                ((CHECK_NOTICE ++))
            fi
        fi

        CHECK_MAINTENANCE="0"
        MD5_CHECK_MAINTENANCE_CURRENT_FILE="/tmp/MD5_MAINTENANCE_CURRENT"
        MD5_CHECK_MAINTENANCE_OLD_FILE="/tmp/MD5_MAINTENANCE_OLD"
        if find ${TEST_CLIENT_DIRECTORY} -maxdepth 1 -name "*maintenance.txt" | grep -q .; then
            md5sum ${TEST_CLIENT_DIRECTORY}/*maintenance.txt | sort | sed "s|${TEST_CLIENT_DIRECTORY}/||" | sort > ${MD5_CHECK_MAINTENANCE_CURRENT_FILE}
            if find ${SYNC2LIVE_DIRECTORY} -maxdepth 1 -name "*maintenance.txt" | grep -q .; then
                md5sum ${SYNC2LIVE_DIRECTORY}/*maintenance.txt | sort | sed "s|${SYNC2LIVE_DIRECTORY}/||" | sort > ${MD5_CHECK_MAINTENANCE_OLD_FILE}
            else
                echo "null" > ${MD5_CHECK_MAINTENANCE_OLD_FILE}
            fi
            MD5_TEST_MAINTENANCE=$(md5sum ${MD5_CHECK_MAINTENANCE_CURRENT_FILE} | awk -F' ' '{print $1}')
            MD5_SYNCTOLIVE_MAINTENANCE=$(md5sum ${MD5_CHECK_MAINTENANCE_OLD_FILE} | awk -F' ' '{print $1}')
            if [ "${MD5_TEST_MAINTENANCE}" != "${MD5_SYNCTOLIVE_MAINTENANCE}" ] ; then
                ((CHECK_MAINTENANCE ++))
            fi
        fi

        if [ "${CHECK_VERSION}" -eq "${PLATFORM_COUNT}" -a "${CHECK_TRANSLATE}" -eq "${TOTAL_TRANSLATE_COUNT}" -a "${CHECK_SETUP}" -eq 0 -a "${CHECK_NOTICE}" -eq 0 -a "${CHECK_MAINTENANCE}" -eq 0 ]; then
            $HOME/bin/automatic_send_chatbot_text_only_by_thread_tag "client_sync" "Client 全部 沒有差異 無需同步" minute 10
            exec echo "ERROR: No client file to flush or cannot compare with synctolive directory, please try again."
        else
            echo "CHECK_VERSION: ${CHECK_VERSION}"
            echo "PLATFORM_COUNT: ${PLATFORM_COUNT}"
            echo "CHECK_TRANSLATE: ${CHECK_TRANSLATE}"
            echo "TOTAL_TRANSLATE_COUNT: ${TOTAL_TRANSLATE_COUNT}"
            echo "CHECK_SETUP: ${CHECK_SETUP}"
            echo "CHECK_NOTICE: ${CHECK_NOTICE}"
            echo "CHECK_MAINTENANCE: ${CHECK_MAINTENANCE}"
            cd ${SYNC2LIVE_DIRECTORY}

            find . -type f -exec rename "s/${OLD_NFSExtension}$//" {} +
            rsync -avz --progress ${TEST_CLIENT_DIRECTORY}/ ${SYNC2LIVE_DIRECTORY}/.
        fi
    fi

    YEAR=$(date +"%y")
    echo "[ Prepare for Sync Client ]"
    if test -z "${OLD_NFSExtension}"; then
        # Change Patch System From Old to New ( 1st Run )
        echo "Rule: 1"
        echo "Current NFSExtension: "
        if test -z $CLIENT_PATCH_NFS_START; then
            NEW_NFSExtension=".${YEAR}0001"
        else
            NEW_NFSExtension=".${CLIENT_PATCH_NFS_START}"
        fi
    else
        # Check Cross New Year or not ( 9999 times quota / year )
        if eval [[ ${OLD_NFSExtension} == "\.${YEAR}*" ]]; then
            echo "Rule: 2"
            echo "Current NFSExtension: ${OLD_NFSExtension}"
            OLD_NFSEx_NUM=$(echo ${OLD_NFSExtension} | sed "s/\.//;s/^${YEAR}0*//")
            echo "OLD_NFSEx_NUM: ${OLD_NFSEx_NUM}"
            let NEW_NFSEx_NUM=${OLD_NFSEx_NUM}+1
            NEW_NFSExtension=$(printf ".${YEAR}%04d" ${NEW_NFSEx_NUM})
        else
            echo "Rule: 3"
            echo "Current NFSExtension: ${OLD_NFSExtension}"
            NEW_NFSExtension=".${YEAR}0001"
        fi
    fi

    # /tmp/live_login_data_to_setup_txt
    generate_live_login_data_to_setup_txt
    # /tmp/live_wsproxy_data_to_setup_txt
    generate_live_wsproxy_data_to_setup_txt

    # Remove Web Socket Proxy & Login from TEST
    sed -i '/wsproxy=/d;/login=/d' ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE}
    # Add new NFSExtension
    sed -i "$ aNFSExtension=${NEW_NFSExtension}" ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE}
    echo "New NFSExtension: ${NEW_NFSExtension}"

    # Add LIVE LoginServer info
    cat /tmp/live_login_data_to_setup_txt >> ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE}
    # Add Live Web Socket Proxy
    cat /tmp/live_wsproxy_data_to_setup_txt >> ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE}

    cd ${SYNC2LIVE_DIRECTORY}
    CURRENT_DIRECTORY=$(pwd)
    if [ "${CURRENT_DIRECTORY}" == "${SYNC2LIVE_DIRECTORY}" ]; then
        find . -maxdepth 1 -mindepth 1 -type d -exec find {} -type f -print0 \; | xargs -0 -I{} bash -c 'mv "$1" "$1'"${NEW_NFSExtension}"'"' _ {}
    fi
}  

rename_translate_extension () {
    TEST_CLIENT_DIRECTORY="$HOME/www/${GAME_TYPE}-TEST"
    SYNC2LIVE_DIRECTORY="$HOME/www/${GAME_TYPE}-TEST_SYNCTOLIVE"
    CHECK_FILE="setup.txt"
    TRANSLATE_FILE="TranslateFileList"
    OLD_NFSExtension=$(grep -E -a 'NFSExtension' ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE} | sed 's/NFSExtension=//')
        
    if [ -z "${TRANSLATED_INI_UPLOAD_DIR_}" ]; then
        # 全國別翻譯檔
        if [ "$1" == "" ]; then
            CHECK_TRANSLATE="0"
            PLATFORM_COUNT=$(find ${TEST_CLIENT_DIRECTORY} -maxdepth 1 -mindepth 1 -type d | wc -l)
            TRANSLATE_COUNT=$(find ${TEST_CLIENT_DIRECTORY}/Android/translate_data/db_* -type f -name "*_${TRANSLATE_FILE}" | wc -l)
            TOTAL_TRANSLATE_COUNT=$((PLATFORM_COUNT * TRANSLATE_COUNT))
            for platform_fullpath in $(find ${TEST_CLIENT_DIRECTORY} -maxdepth 1 -mindepth 1 -type d); do
                platform=$(basename ${platform_fullpath})
                    
                for translate_fullpath in $(find ${TEST_CLIENT_DIRECTORY}/${platform}/translate_data/db_* -type f -name "*_${TRANSLATE_FILE}"); do
                    FILENAME_RELATIVE_PATH=$(echo "${translate_fullpath}" | sed -r "s|${TEST_CLIENT_DIRECTORY}/${platform}/translate_data/*||")
                    MD5_TEST_TRANSLATE=$(md5sum ${TEST_CLIENT_DIRECTORY}/${platform}/translate_data/${FILENAME_RELATIVE_PATH} | awk -F' ' '{print $1}')
                    MD5_SYNCTOLIVE_TRANSLATE=$([ -f ${SYNC2LIVE_DIRECTORY}/${platform}/translate_data/${FILENAME_RELATIVE_PATH}${OLD_NFSExtension} ] && md5sum ${SYNC2LIVE_DIRECTORY}/${platform}/translate_data/${FILENAME_RELATIVE_PATH}${OLD_NFSExtension} | awk -F' ' '{print $1}' || echo "null")
                        
                    if [ "${MD5_TEST_TRANSLATE}" == "${MD5_SYNCTOLIVE_TRANSLATE}" ]; then
                        ((CHECK_TRANSLATE ++))
                    fi
                done
            done
                
            if [ "${CHECK_TRANSLATE}" -eq "${TOTAL_TRANSLATE_COUNT}" ]; then
                $HOME/bin/automatic_send_chatbot_text_only_by_thread_tag "translate_sync" "Client 翻譯 全語系 沒有差異 無需同步" minute 10
                exec echo "ERROR: No translate file to flush or cannot compare with synctolive directory, please try again."
            else
                cd ${SYNC2LIVE_DIRECTORY}
                find . -type f -exec rename "s/${OLD_NFSExtension}$//" {} +
                    
                for multi_lang_directory in $(cat ${HOME}/.gamerc | grep TRANSLATED_INI_UPLOAD_DIR_ | grep -v '#' | awk -F"=" '{print $2}'); do
                    LCOUNTRY=$(echo ${multi_lang_directory} | sed 's/"//g' | awk -F"/" '{print $(NF-1)}' | awk -F"_" '{print $NF}')
                    COUNTRY=$(echo ${LCOUNTRY} | tr '[:lower:]' '[:upper:]')
                        
                    TEST_TRANSLATE_DIRECTORY=$(echo ${multi_lang_directory} | sed 's/"//g')
                        
                    if [ ! -f "$TEST_TRANSLATE_DIRECTORY/${LCOUNTRY}_${TRANSLATE_FILE}" ]; then
                        $HOME/bin/automatic_send_chatbot_text_only_by_thread_tag "translate_sync" "Client 翻譯 ( ${COUNTRY} ) 不存在 請檢查看看!" minute 10
                        echo "ERROR: No ${COUNTRY} translate file exists!" | colorize red black
                    else
                        echo "CHECK_TRANSLATE: ${CHECK_TRANSLATE}"
                        echo "TOTAL_TRANSLATE_COUNT: ${TOTAL_TRANSLATE_COUNT}"
                        cd ${SYNC2LIVE_DIRECTORY}
                        for platform_fullpath in $(find ${SYNC2LIVE_DIRECTORY} -maxdepth 1 -mindepth 1 -type d); do
                            platform=$(basename ${platform_fullpath})
                            
                            cd ${TEST_TRANSLATE_DIRECTORY}
                            rsync -av --progress ${TEST_TRANSLATE_DIRECTORY}/${LCOUNTRY}_* ${SYNC2LIVE_DIRECTORY}/${platform}/translate_data/db_${LCOUNTRY}/.
                        done
                    fi
                done
            fi
                
            YEAR=$(date +"%y")
            echo "[ Prepare for Sync Translate ]"
            # Check Cross New Year or not ( 9999 times quota / year )
            if eval [[ ${OLD_NFSExtension} == "\.${YEAR}*" ]]; then
                echo "Rule: 4"
                echo "Current NFSExtension: ${OLD_NFSExtension}"
                OLD_NFSEx_NUM=$(echo ${OLD_NFSExtension} | sed "s/\.//;s/^${YEAR}0*//")
                echo "OLD_NFSEx_NUM: ${OLD_NFSEx_NUM}"
                let NEW_NFSEx_NUM=${OLD_NFSEx_NUM}+1
                NEW_NFSExtension=$(printf ".${YEAR}%04d" ${NEW_NFSEx_NUM})
            else
                echo "Rule: 5"
                echo "Current NFSExtension: ${OLD_NFSExtension}"
                NEW_NFSExtension=".${YEAR}0001"
            fi
                
            # /tmp/live_login_data_to_setup_txt
            generate_live_login_data_to_setup_txt
            # /tmp/live_wsproxy_data_to_setup_txt
            generate_live_wsproxy_data_to_setup_txt
                
            # Remove Web Socket Proxy & Login from TEST
            sed -i '/wsproxy=/d;/login=/d' ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE}
            # Change NFSExtension to new
            sed -i "s/NFSExtension=${OLD_NFSExtension}/NFSExtension=${NEW_NFSExtension}/" ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE}
            echo "New NFSExtension: ${NEW_NFSExtension}"
                
            # Add LIVE LoginServer info
            cat /tmp/live_login_data_to_setup_txt >> ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE}
            # Add Live Web Socket Proxy
            cat /tmp/live_wsproxy_data_to_setup_txt >> ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE}

            cd ${SYNC2LIVE_DIRECTORY}
            CURRENT_DIRECTORY=$(pwd)
            if [ "${CURRENT_DIRECTORY}" == "${SYNC2LIVE_DIRECTORY}" ]; then
                find . -maxdepth 1 -mindepth 1 -type d -exec find {} -type f -print0 \; | xargs -0 -I{} bash -c 'mv "$1" "$1'"${NEW_NFSExtension}"'"' _ {}
            fi          
        # 單一國別翻譯檔
        else
            COUNTRY=$1
            LCOUNTRY=$(echo $1 | tr '[:upper:]' '[:lower:]')
            
            CHECK_TRANSLATE="0"
            PLATFORM_COUNT=$(find ${TEST_CLIENT_DIRECTORY} -maxdepth 1 -mindepth 1 -type d | wc -l)
            TRANSLATE_COUNT=1
            TOTAL_TRANSLATE_COUNT=$((PLATFORM_COUNT * TRANSLATE_COUNT))
            for platform_fullpath in $(find ${TEST_CLIENT_DIRECTORY} -maxdepth 1 -mindepth 1 -type d); do
                platform=$(basename ${platform_fullpath})
                    
                for translate_fullpath in $(find ${TEST_CLIENT_DIRECTORY}/${platform}/translate_data/db_${LCOUNTRY} -type f -name "*_${TRANSLATE_FILE}"); do
                    FILENAME_RELATIVE_PATH=$(echo "${translate_fullpath}" | sed -r "s|${TEST_CLIENT_DIRECTORY}/${platform}/translate_data/*||")
                    MD5_TEST_TRANSLATE=$(md5sum ${TEST_CLIENT_DIRECTORY}/${platform}/translate_data/${FILENAME_RELATIVE_PATH} | awk -F' ' '{print $1}')
                    MD5_SYNCTOLIVE_TRANSLATE=$([ -f ${SYNC2LIVE_DIRECTORY}/${platform}/translate_data/${FILENAME_RELATIVE_PATH}${OLD_NFSExtension} ] && md5sum ${SYNC2LIVE_DIRECTORY}/${platform}/translate_data/${FILENAME_RELATIVE_PATH}${OLD_NFSExtension} | awk -F' ' '{print $1}' || echo "null")
                        
                    if [ "${MD5_TEST_TRANSLATE}" == "${MD5_SYNCTOLIVE_TRANSLATE}" ]; then
                        ((CHECK_TRANSLATE ++))
                    fi
                done
            done
            if [ "${CHECK_TRANSLATE}" -eq "${TOTAL_TRANSLATE_COUNT}" ]; then
                $HOME/bin/automatic_send_chatbot_text_only_by_thread_tag "translate_sync" "Client 翻譯 ( ${COUNTRY} ) 沒有差異 無需同步" minute 10
                exec echo "ERROR: No ${COUNTRY} translate file to flush or cannot compare with synctolive directory, please try again."
            else
                cd ${SYNC2LIVE_DIRECTORY}
                find . -type f -exec rename "s/${OLD_NFSExtension}$//" {} +
                    
                for multi_lang_directory in $(cat ${HOME}/.gamerc | grep TRANSLATED_INI_UPLOAD_DIR_${COUNTRY} | grep -v '#' | awk -F"=" '{print $2}'); do
                    LCOUNTRY=$(echo ${multi_lang_directory} | sed 's/"//g' | awk -F"/" '{print $(NF-1)}' | awk -F"_" '{print $NF}')
                    COUNTRY=$(echo ${LCOUNTRY} | tr '[:lower:]' '[:upper:]')
                        
                    TEST_TRANSLATE_DIRECTORY=$(echo ${multi_lang_directory} | sed 's/"//g')
                        
                    if [ ! -f "$TEST_TRANSLATE_DIRECTORY/${LCOUNTRY}_${TRANSLATE_FILE}" ]; then
                        $HOME/bin/automatic_send_chatbot_text_only_by_thread_tag "translate_sync" "Client 翻譯 ( ${COUNTRY} ) 不存在 請檢查看看!" minute 10
                        echo "ERROR: No ${COUNTRY} translate file exists!" | colorize red black
                    else
                        echo "CHECK_TRANSLATE: ${CHECK_TRANSLATE}"
                        echo "TOTAL_TRANSLATE_COUNT: ${TOTAL_TRANSLATE_COUNT}"
                        cd ${SYNC2LIVE_DIRECTORY}
                        for platform_fullpath in $(find ${SYNC2LIVE_DIRECTORY} -maxdepth 1 -mindepth 1 -type d); do
                            platform=$(basename ${platform_fullpath})
                            
                            cd ${TEST_TRANSLATE_DIRECTORY}
                            rsync -av --progress ${TEST_TRANSLATE_DIRECTORY}/${LCOUNTRY}_* ${SYNC2LIVE_DIRECTORY}/${platform}/translate_data/db_${LCOUNTRY}/.
                        done
                    fi
                done
            fi
                
            YEAR=$(date +"%y")
            echo "[ Prepare for Sync Translate ]"
            # Check Cross New Year or not ( 9999 times quota / year )
            if eval [[ ${OLD_NFSExtension} == "\.${YEAR}*" ]]; then
                echo "Rule: 4"
                echo "Current NFSExtension: ${OLD_NFSExtension}"
                OLD_NFSEx_NUM=$(echo ${OLD_NFSExtension} | sed "s/\.//;s/^${YEAR}0*//")
                echo "OLD_NFSEx_NUM: ${OLD_NFSEx_NUM}"
                let NEW_NFSEx_NUM=${OLD_NFSEx_NUM}+1
                NEW_NFSExtension=$(printf ".${YEAR}%04d" ${NEW_NFSEx_NUM})
            else
                "Rule: 5"
                echo "Current NFSExtension: ${OLD_NFSExtension}"
                NEW_NFSExtension=".${YEAR}0001"
            fi
                
            # /tmp/live_login_data_to_setup_txt
            generate_live_login_data_to_setup_txt
            # /tmp/live_wsproxy_data_to_setup_txt
            generate_live_wsproxy_data_to_setup_txt
                
            # Remove Web Socket Proxy from TEST
            sed -i '/wsproxy=/d' ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE}
            # Change NFSExtension to new
            sed -i "s/NFSExtension=${OLD_NFSExtension}/NFSExtension=${NEW_NFSExtension}/" ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE}
            echo "New NFSExtension: ${NEW_NFSExtension}"
                
            # Add LIVE LoginServer info
            cat /tmp/live_login_data_to_setup_txt >> ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE}
            # Add Live Web Socket Proxy
            cat /tmp/live_wsproxy_data_to_setup_txt >> ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE}

            cd ${SYNC2LIVE_DIRECTORY}
            CURRENT_DIRECTORY=$(pwd)
            if [ "${CURRENT_DIRECTORY}" == "${SYNC2LIVE_DIRECTORY}" ]; then
                find . -maxdepth 1 -mindepth 1 -type d -exec find {} -type f -print0 \; | xargs -0 -I{} bash -c 'mv "$1" "$1'"${NEW_NFSExtension}"'"' _ {}
            fi
        fi
    fi
}

norename_setup_update () {
    TEST_CLIENT_DIRECTORY="$HOME/www/${GAME_TYPE}-TEST"
    SYNC2LIVE_DIRECTORY="$HOME/www/${GAME_TYPE}-TEST_SYNCTOLIVE"
    CHECK_FILE="setup.txt"
    OLD_NFSExtension=$(grep -E -a 'NFSExtension' ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE} | sed 's/NFSExtension=//')

    MD5_TEST_SETUP=$(sed '/wsproxy=/d;/login=/d' ${TEST_CLIENT_DIRECTORY}/${CHECK_FILE} | md5sum | awk -F' ' '{print $1}')
    MD5_SYNCTOLIVE_SETUP=$([ -f ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE} ] && sed '/wsproxy=/d;/login=/d;/NFSExtension=/d' ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE} | md5sum | awk -F' ' '{print $1}' || echo "null")

    if [ "${MD5_TEST_SETUP}" == "${MD5_SYNCTOLIVE_SETUP}" ]; then
        $HOME/bin/automatic_send_chatbot_text_only_by_thread_tag "setup_sync" "Client setup.txt 沒有差異 無需同步" minute 10           
        exec echo "ERROR: No setup file to flush or cannot compare with synctolive directory, please try again."
    else
        # /tmp/live_login_data_to_setup_txt
        generate_live_login_data_to_setup_txt
        # /tmp/live_wsproxy_data_to_setup_txt
        generate_live_wsproxy_data_to_setup_txt

        cd ${SYNC2LIVE_DIRECTORY}
        rsync -avz --progress ${TEST_CLIENT_DIRECTORY}/${CHECK_FILE} ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE}
        # Remove Web Socket Proxy & Login from TEST
        sed -i '/wsproxy=/d;/login=/d' ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE}
        # Add previous old NFSExtension
        sed -i "$ aNFSExtension=${OLD_NFSExtension}" ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE}

        # Add LIVE LoginServer info
        cat /tmp/live_login_data_to_setup_txt >> ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE}
        # Add Live Web Socket Proxy
        cat /tmp/live_wsproxy_data_to_setup_txt >> ${SYNC2LIVE_DIRECTORY}/${CHECK_FILE}
    fi
}

norename_notice_update () {
    TEST_CLIENT_DIRECTORY="$HOME/www/${GAME_TYPE}-TEST"
    SYNC2LIVE_DIRECTORY="$HOME/www/${GAME_TYPE}-TEST_SYNCTOLIVE"

    # 全國別遊戲內公告檔
    if [ "$1" == "" ] ; then
        MD5_CHECK_CURRENT_FILE="/tmp/MD5_NOTICE_CURRENT"
        MD5_CHECK_OLD_FILE="/tmp/MD5_NOTICE_OLD"

        if find ${TEST_CLIENT_DIRECTORY} -maxdepth 1 -name "*notice.txt" | grep -q .; then
            md5sum ${TEST_CLIENT_DIRECTORY}/*notice.txt | sort | sed "s|${TEST_CLIENT_DIRECTORY}/||" | sort > ${MD5_CHECK_CURRENT_FILE}
            if find ${SYNC2LIVE_DIRECTORY} -maxdepth 1 -name "*notice.txt" | grep -q .; then
                md5sum ${SYNC2LIVE_DIRECTORY}/*notice.txt | sort | sed "s|${SYNC2LIVE_DIRECTORY}/||" | sort > ${MD5_CHECK_OLD_FILE}
            else
                echo "null" > ${MD5_CHECK_OLD_FILE}
            fi

            MD5_TEST_NOTICE=$(md5sum ${MD5_CHECK_CURRENT_FILE} | awk -F' ' '{print $1}' || echo "null")
            MD5_SYNCTOLIVE_NOTICE=$(md5sum ${MD5_CHECK_OLD_FILE} | awk -F' ' '{print $1}' || echo "null")

            if [ "${MD5_TEST_NOTICE}" == "${MD5_SYNCTOLIVE_NOTICE}" ] ; then
                $HOME/bin/automatic_send_chatbot_text_only_by_thread_tag "notice_sync" "Client 遊戲內公告 全語系 沒有差異 無需同步" minute 10
                exec echo "ERROR: No notice files to flush or cannot compare with synctolive directory, please try again."
            else
                cd ${SYNC2LIVE_DIRECTORY}
                rsync -av --progress ${TEST_CLIENT_DIRECTORY}/*notice.txt ${SYNC2LIVE_DIRECTORY}/
            fi
        else
            $HOME/bin/automatic_send_chatbot_text_only_by_thread_tag "notice_sync" "Client 遊戲內公告 全語系 不存在!" minute 10
            exec echo "ERROR: No notice files exist!"       
        fi
    # 單一國別遊戲內公告檔
    else
        UCOUNTRY=$(echo $1 | tr '[:lower:]' '[:upper:]')
        LCOUNTRY=$(echo $1 | tr '[:upper:]' '[:lower:]')
        if find ${TEST_CLIENT_DIRECTORY} -maxdepth 1 -name "*${LCOUNTRY}_notice.txt" | grep -q .; then
            MD5_TEST_NOTICE=$(md5sum ${TEST_CLIENT_DIRECTORY}/${LCOUNTRY}_notice.txt | awk -F' ' '{print $1}')
            MD5_SYNCTOLIVE_NOTICE=$([ -f ${SYNC2LIVE_DIRECTORY}/${LCOUNTRY}_notice.txt ] && md5sum ${SYNC2LIVE_DIRECTORY}/${LCOUNTRY}_notice.txt | awk -F' ' '{print $1}' || echo "null")

            if [ "${MD5_TEST_NOTICE}" == "${MD5_SYNCTOLIVE_NOTICE}" ] ; then
                $HOME/bin/automatic_send_chatbot_text_only_by_thread_tag "notice_sync" "Client 遊戲內公告 ${UCOUNTRY} 沒有差異 無需同步" minute 10
                exec echo "ERROR: No ${LCOUNTRY} notice file to flush or cannot compare with synctolive directory, please try again."
            else
                cd ${SYNC2LIVE_DIRECTORY}
                rsync -av --progress ${TEST_CLIENT_DIRECTORY}/${LCOUNTRY}_notice.txt ${SYNC2LIVE_DIRECTORY}/${LCOUNTRY}_notice.txt
            fi
        else
            $HOME/bin/automatic_send_chatbot_text_only_by_thread_tag "notice_sync" "Client 遊戲內公告 ${UCOUNTRY} 不存在!" minute 10
            exec echo "ERROR: No ${LCOUNTRY} notice file exist!"        
        fi
    fi
}

norename_maintenance_update () {
    TEST_CLIENT_DIRECTORY="$HOME/www/${GAME_TYPE}-TEST"
    SYNC2LIVE_DIRECTORY="$HOME/www/${GAME_TYPE}-TEST_SYNCTOLIVE"

    # 全國別維護公告檔
    if [ "$1" == "" ] ; then
        MD5_CHECK_CURRENT_FILE="/tmp/MD5_MAINTENANCE_CURRENT"
        MD5_CHECK_OLD_FILE="/tmp/MD5_MAINTENANCE_OLD"
        
        if find ${TEST_CLIENT_DIRECTORY} -maxdepth 1 -name "*maintenance.txt" | grep -q .; then
            md5sum ${TEST_CLIENT_DIRECTORY}/*maintenance.txt | sort | sed "s|${TEST_CLIENT_DIRECTORY}/||" | sort > ${MD5_CHECK_CURRENT_FILE}
            if find ${SYNC2LIVE_DIRECTORY} -maxdepth 1 -name "*maintenance.txt" | grep -q .; then
                md5sum ${SYNC2LIVE_DIRECTORY}/*maintenance.txt | sort | sed "s|${SYNC2LIVE_DIRECTORY}/||" | sort > ${MD5_CHECK_OLD_FILE}
            else
                echo "null" > ${MD5_CHECK_OLD_FILE}
            fi

            MD5_TEST_MAINTENANCE=$(md5sum ${MD5_CHECK_CURRENT_FILE} | awk -F' ' '{print $1}' || echo "null")
            MD5_SYNCTOLIVE_MAINTENANCE=$(md5sum ${MD5_CHECK_OLD_FILE} | awk -F' ' '{print $1}' || echo "null")      

            if [ "${MD5_TEST_MAINTENANCE}" == "${MD5_SYNCTOLIVE_MAINTENANCE}" ] ; then
                automatic_send_chatbot_text_only_by_thread_tag "maintenance_sync" "Client 維護公告 全語系 沒有差異 無需同步" minute 10
                exec echo "ERROR: No maintenance files to flush or cannot compare with synctolive directory, please try again."
            else
                cd ${SYNC2LIVE_DIRECTORY}
                rsync -av --progress ${TEST_CLIENT_DIRECTORY}/*maintenance.txt ${SYNC2LIVE_DIRECTORY}/
            fi
        else
            automatic_send_chatbot_text_only_by_thread_tag "maintenance_sync" "Client 維護公告 全語系 不存在!" minute 10
            exec echo "ERROR: No maintenance files exist!"      
        fi
    # 單一國別維護公告檔
    else
        UCOUNTRY=$(echo $1 | tr '[:lower:]' '[:upper:]')
        LCOUNTRY=$(echo $1 | tr '[:upper:]' '[:lower:]')
        if find ${TEST_CLIENT_DIRECTORY} -maxdepth 1 -name "*${LCOUNTRY}_maintenance.txt" | grep -q .; then
            MD5_TEST_MAINTENANCE=$(md5sum ${TEST_CLIENT_DIRECTORY}/${LCOUNTRY}_maintenance.txt | awk -F' ' '{print $1}')
            MD5_SYNCTOLIVE_MAINTENANCE=$([ -f ${SYNC2LIVE_DIRECTORY}/${LCOUNTRY}_maintenance.txt ] && md5sum ${SYNC2LIVE_DIRECTORY}/${LCOUNTRY}_maintenance.txt | awk -F' ' '{print $1}' || echo "null")

            if [ "${MD5_TEST_MAINTENANCE}" == "${MD5_SYNCTOLIVE_MAINTENANCE}" ] ; then
                automatic_send_chatbot_text_only_by_thread_tag "maintenance_sync" "Client 維護公告 ${UCOUNTRY} 沒有差異 無需同步" minute 10
                exec echo "ERROR: No ${LCOUNTRY} maintenance file to flush or cannot compare with synctolive directory, please try again."
            else
                cd ${SYNC2LIVE_DIRECTORY}
                rsync -av --progress ${TEST_CLIENT_DIRECTORY}/${LCOUNTRY}_maintenance.txt ${SYNC2LIVE_DIRECTORY}/${LCOUNTRY}_maintenance.txt
            fi
        else
            automatic_send_chatbot_text_only_by_thread_tag "maintenance_sync" "Client 維護公告 ${UCOUNTRY} 不存在!" minute 10
            exec echo "ERROR: No ${LCOUNTRY} maintenance file exist!"       
        fi
    fi
}

dbpatch_precheck () {

if [ "$1" == "WORLDDB" ]; then
	worlddb_flag=1
	echo "###### WORLD DBPatch PreCheck ######" | colorize pink black
	echo ""
	### WORLDDB ###
	for server in $(print_hosts WORLDDB) ; do
	        zone_category=$(get_zone_category $server)
		zone_id=$(get_zone_id $server)
		ch_id=$(get_ch_id $server)
	        set_id=$(get_set_id $server)
		world_id=$(get_world_id $server)
		DBNAME="${GAME_TYPE}World${world_id}"
	        print_servername $server | colorize blue black
	        echo "Region $zone_category, Zone $zone_id, Channel $ch_id => SET $set_id => ${DBNAME}" | colorize yellow black
		TABLE_COUNTS=$(ssh $server "psql -U postgres ${DBNAME} -c \"COPY (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema NOT IN ('information_schema', 'pg_catalog') AND table_type = 'BASE TABLE') TO STDOUT\"")
		if [ "$TABLE_COUNTS" -gt "0" ]; then
	        	ROW_NUM=$(ssh $server "psql -U postgres ${DBNAME} -c 'COPY (SELECT COUNT(*) FROM configuration) TO STDOUT'")
	        	DB_CONFIG=$(ssh $server "psql -U postgres ${DBNAME} -c 'COPY (SELECT schema_version FROM configuration ORDER BY schema_version DESC LIMIT 1) TO STDOUT'")
	        	FILE_CONFIG=$(ssh $server "cat ~/common/db/world_schema_alter | grep ^version | tail -n 1 | awk -F' ' '{print \$2}' | tr '\\r' '\\n' | sed '/^\$/d'")
	        	if [ "$ROW_NUM" -eq "0" ]; then
	        	        echo "${DBNAME}'s schema configuration is empty!" | colorize red black
	        	        echo "ROW_NUM: $ROW_NUM, DB_CONFIG: $DB_CONFIG, FILE_CONFIG: $FILE_CONFIG" | colorize red black
	        	        worlddb_flag=0
	        	elif [ "$ROW_NUM" -eq "1" ]; then
	        	        if [ ${DB_CONFIG} -ge ${FILE_CONFIG} ]; then
	        	                echo "DBPatch is unnecessary ( X )" | colorize green black
	        	        else
	        	                echo "DBPatch is necessary ( O )" | colorize red black
	        	        fi
	        	        echo "ROW_NUM: $ROW_NUM, DB_CONFIG: $DB_CONFIG, FILE_CONFIG: $FILE_CONFIG" | colorize green black
	        	else
	        	        echo "${DBNAME}'s schema configuration has multiple records" | colorize red black
	        	        echo "ROW_NUM: $ROW_NUM, DB_CONFIG: $DB_CONFIG, FILE_CONFIG: $FILE_CONFIG" | colorize red black
	        	        worlddb_flag=0
	        	fi
	        	echo ""
		fi
	done
	echo "###### WORLD DBPatch PreCheck ######" | colorize pink black

	echo $worlddb_flag > /tmp/worlddb_flag
elif [ "$1" == "GAMEDB" ]; then
	gamedb_flag=1
	echo "###### GAME DBPatch PreCheck ######" | colorize pink black
	echo ""
	### GAMEDB ###
	for server in $(print_hosts GAMEDB) ; do
	        zone_category=$(get_zone_category $server)
		zone_id=$(get_zone_id $server)
	        set_id=$(get_set_id $server)
		DBNAME="${GAME_TYPE}DB${set_id}"
	        print_servername $server | colorize blue black
	        echo "Region $zone_category, Zone $zone_id => SET $set_id => ${DBNAME}" | colorize yellow black
		TABLE_COUNTS=$(ssh $server "psql -U postgres ${DBNAME} -c \"COPY (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema NOT IN ('information_schema', 'pg_catalog') AND table_type = 'BASE TABLE') TO STDOUT\"")
		if [ "$TABLE_COUNTS" -gt "0" ]; then
	        	ROW_NUM=$(ssh $server "psql -U postgres ${DBNAME} -c 'COPY (SELECT COUNT(*) FROM configuration) TO STDOUT'")
	        	DB_CONFIG=$(ssh $server "psql -U postgres ${DBNAME} -c 'COPY (SELECT schema_version FROM configuration ORDER BY schema_version DESC LIMIT 1) TO STDOUT'")
	        	FILE_CONFIG=$(ssh $server "cat ~/common/db/game_schema_alter | grep ^version | tail -n 1 | awk -F' ' '{print \$2}' | tr '\\r' '\\n' | sed '/^\$/d'")
	        	if [ "$ROW_NUM" -eq "0" ]; then
	        	        echo "${DBNAME}'s schema configuration is empty!" | colorize red black
	        	        echo "ROW_NUM: $ROW_NUM, DB_CONFIG: $DB_CONFIG, FILE_CONFIG: $FILE_CONFIG" | colorize red black
	        	        gamedb_flag=0
	        	elif [ "$ROW_NUM" -eq "1" ]; then
	        	        if [ ${DB_CONFIG} -ge ${FILE_CONFIG} ]; then
	        	                echo "DBPatch is unnecessary ( X )" | colorize green black
	        	        else
	        	                echo "DBPatch is necessary ( O )" | colorize red black
	        	        fi
	        	        echo "ROW_NUM: $ROW_NUM, DB_CONFIG: $DB_CONFIG, FILE_CONFIG: $FILE_CONFIG" | colorize green black
	        	else
	        	        echo "${DBNAME}'s schema configuration has multiple records" | colorize red black
	        	        echo "ROW_NUM: $ROW_NUM, DB_CONFIG: $DB_CONFIG, FILE_CONFIG: $FILE_CONFIG" | colorize red black
	        	        gamedb_flag=0
	        	fi
	        	echo ""
		fi
	done
	echo "###### GAME DBPatch PreCheck ######" | colorize pink black

	echo $gamedb_flag > /tmp/gamedb_flag
elif [ "$1" == "SOCIETYDB" ]; then
	societydb_flag=1
	echo "###### SOCIETY DBPatch PreCheck ######" | colorize pink black
	echo ""
	### SOCIETYDB ###
	for server in $(print_hosts SOCIETYDB) ; do
	        zone_category=$(get_zone_category $server)
		zone_id=$(get_zone_id $server)
	        set_id=$(get_set_id $server)
		DBNAME="${GAME_TYPE}Society${set_id}"
	        print_servername $server | colorize blue black
	        echo "Region $zone_category, Zone $zone_id => SET $set_id => ${DBNAME}" | colorize yellow black
		TABLE_COUNTS=$(ssh $server "psql -U postgres ${DBNAME} -c \"COPY (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema NOT IN ('information_schema', 'pg_catalog') AND table_type = 'BASE TABLE') TO STDOUT\"")
		if [ "$TABLE_COUNTS" -gt "0" ]; then
	        	ROW_NUM=$(ssh $server "psql -U postgres ${DBNAME} -c 'COPY (SELECT COUNT(*) FROM configuration) TO STDOUT'")
	        	DB_CONFIG=$(ssh $server "psql -U postgres ${DBNAME} -c 'COPY (SELECT schema_version FROM configuration ORDER BY schema_version DESC LIMIT 1) TO STDOUT'")
	        	FILE_CONFIG=$(ssh $server "cat ~/common/db/society_schema_alter | grep ^version | tail -n 1 | awk -F' ' '{print \$2}' | tr '\\r' '\\n' | sed '/^\$/d'")
	        	if [ "$ROW_NUM" -eq "0" ]; then
	        	        echo "${DBNAME}'s schema configuration is empty!" | colorize red black
	        	        echo "ROW_NUM: $ROW_NUM, DB_CONFIG: $DB_CONFIG, FILE_CONFIG: $FILE_CONFIG" | colorize red black
	        	        societydb_flag=0
	        	elif [ "$ROW_NUM" -eq "1" ]; then
	        	        if [ ${DB_CONFIG} -ge ${FILE_CONFIG} ]; then
	        	                echo "DBPatch is unnecessary ( X )" | colorize green black
	        	        else
	        	                echo "DBPatch is necessary ( O )" | colorize red black
	        	        fi
	        	        echo "ROW_NUM: $ROW_NUM, DB_CONFIG: $DB_CONFIG, FILE_CONFIG: $FILE_CONFIG" | colorize green black
	        	else
	        	        echo "${DBNAME}'s schema configuration has multiple records" | colorize red black
	        	        echo "ROW_NUM: $ROW_NUM, DB_CONFIG: $DB_CONFIG, FILE_CONFIG: $FILE_CONFIG" | colorize red black
	        	        societydb_flag=0
	        	fi
	        	echo ""
		fi
	done
	echo "###### SOCIETY DBPatch PreCheck ######" | colorize pink black

	echo $societydb_flag > /tmp/societydb_flag
elif [ "$1" == "ACCOUNTDB" ]; then
	accountdb_flag=1
	echo "###### ACCOUNT DBPatch PreCheck ######" | colorize pink black
	echo ""
	### ACCOUNTDB ###
	DBNAME="${GAME_TYPE}Account"
	print_servername accountdb | colorize blue black
	echo "ACCOUNTDB => ${DBNAME}" | colorize yellow black
	TABLE_COUNTS=$(ssh accountdb "psql -U postgres ${DBNAME} -c \"COPY (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema NOT IN ('information_schema', 'pg_catalog') AND table_type = 'BASE TABLE') TO STDOUT\"")
	if [ "$TABLE_COUNTS" -gt "0" ]; then
		ROW_NUM=$(ssh accountdb "psql -U postgres ${DBNAME} -c 'COPY (SELECT COUNT(*) FROM configuration) TO STDOUT'")
		DB_CONFIG=$(ssh accountdb "psql -U postgres ${DBNAME} -c 'COPY (SELECT schema_version FROM configuration ORDER BY schema_version DESC LIMIT 1) TO STDOUT'")
		FILE_CONFIG=$(ssh accountdb "cat ~/common/db/account_schema_alter | grep ^version | tail -n 1 | awk -F' ' '{print \$2}' | tr '\\r' '\\n' | sed '/^\$/d'")
		if [ "$ROW_NUM" -eq "0" ]; then
		        echo "ACCOUNTDB's schema configuration is empty!" | colorize red black
		        echo "ROW_NUM: $ROW_NUM, DB_CONFIG: $DB_CONFIG, FILE_CONFIG: $FILE_CONFIG" | colorize red black
		        accountdb_flag=0
		elif [ "$ROW_NUM" -eq "1" ]; then
		        if [ ${DB_CONFIG} -ge ${FILE_CONFIG} ]; then
		                echo "DBPatch is unnecessary ( X )" | colorize green black
			else
				echo "DBPatch is necessary ( O )" | colorize red black
			fi
			echo "ROW_NUM: $ROW_NUM, DB_CONFIG: $DB_CONFIG, FILE_CONFIG: $FILE_CONFIG" | colorize green black
		else
			echo "ACCOUNTDB's schema configuration has multiple records" | colorize red black
			echo "ROW_NUM: $ROW_NUM, DB_CONFIG: $DB_CONFIG, FILE_CONFIG: $FILE_CONFIG" | colorize red black
			accountdb_flag=0
		fi
		echo ""
		echo "###### ACCOUNT DBPatch PreCheck ######" | colorize pink black

		echo $accountdb_flag > /tmp/accountdb_flag
	fi
fi
}

# Android Data Mover and URL Showing by Vincent
move_android_file_for_download () {
   PATCH_DIR_NAME=$1
   EXTENSION=$2
   EXTENSION_UPPER=$(echo ${EXTENSION} | tr [a-z] [A-Z])
   LOCAL_PATCH_DIR_FILES="$LOCAL_PATCH_DIR/$PATCH_DIR_NAME/*.${EXTENSION}"
   DOWNLOAD_DIR_ROOT_PATH="$WORKING_DIRECTORY/www/app/"

   if [ -f $LOCAL_PATCH_DIR_FILES ] ; then
      for full_path_file in $LOCAL_PATCH_DIR_FILES ; do
         file=$(basename $full_path_file)
         if [ ! -d $DOWNLOAD_DIR_ROOT_PATH/android ] ; then
            mkdir -p $DOWNLOAD_DIR_ROOT_PATH/android
         fi
         echo
         echo "${EXTENSION_UPPER} SOURCE: $file"
         FILE_MD5=$(md5sum $full_path_file | awk -F" " '{print $1}')
         echo "TARGET: ${file} (MD5: ${FILE_MD5})"
         mv -v $LOCAL_PATCH_DIR/$PATCH_DIR_NAME/$file $DOWNLOAD_DIR_ROOT_PATH/android/
         #echo "HREF: http://$TEST_SERVER_GLOBAL_IP/app/android/${file}"
         echo "HREF: https://$TEST_SERVER_DOMAIN/app/android/${file}"
      done
      echo
   fi
}

# iOS Data Mover and URL Showing by Vincent
move_ios_file_for_download () {
   PATCH_DIR_NAME=$1
   EXTENSION=$2
   EXTENSION_UPPER=$(echo ${EXTENSION} | tr [a-z] [A-Z])
   LOCAL_PATCH_DIR_FILES="$LOCAL_PATCH_DIR/$PATCH_DIR_NAME/*.${EXTENSION}"
   DOWNLOAD_DIR_ROOT_PATH="$WORKING_DIRECTORY/www/app/"

   if [ -f $LOCAL_PATCH_DIR_FILES ] ; then
      for full_path_file in $LOCAL_PATCH_DIR_FILES ; do
         file=$(basename $full_path_file)
         if [ ! -d $DOWNLOAD_DIR_ROOT_PATH/ios ] ; then
            mkdir -p $DOWNLOAD_DIR_ROOT_PATH/ios
         fi
         echo
         echo "${EXTENSION_UPPER} SOURCE: $file"
         FILE_MD5=$(md5sum $full_path_file | awk -F" " '{print $1}')
         echo "TARGET: ${file} (MD5: ${FILE_MD5})"
         mv -v $LOCAL_PATCH_DIR/$PATCH_DIR_NAME/$file $DOWNLOAD_DIR_ROOT_PATH/ios/
         #echo "HREF: http://$TEST_SERVER_GLOBAL_IP/app/ios/${file}"
         echo "HREF: https://$TEST_SERVER_DOMAIN/app/ios/${file}"
      done
      echo
   fi
}

iptables_port_range () {
P_ACTION=$1
PORT_START=$2
PORT_END=$3

if [ "$P_ACTION" == "ADD" ]; then
        ACTION="-A"
elif [ "$P_ACTION" == "REMOVE" ]; then
        ACTION="-D"
fi


for PORT in $(seq $PORT_START $PORT_END); do
        for IP in $LOGIN_SERVER_ALLOW_IP; do
                iptables -v $ACTION INPUT -p tcp -s $IP --dport $PORT -j ACCEPT
        done
        iptables -v $ACTION INPUT -p tcp --dport $PORT -j DROP
done
iptables -L -v -n

}

iptables_port_range_class_c () {
P_ACTION=$1
IP_RANGE=$2

if [ "$P_ACTION" == "ADD" ]; then
	ACTION="-A"
elif [ "$P_ACTION" == "REMOVE" ]; then
	ACTION="-D"
fi

for IP in $IP_RANGE; do
	iptables -v $ACTION INPUT -p tcp -s ${IP}/24 -j ACCEPT
done
iptables -L -v -n

}

version_def_check () {
        TARGET=$1
        PATCH=$2

        if [ ! -d "$HOME/common-${TARGET}/VersionDef" ]; then
                mkdir -p $HOME/common-${TARGET}/VersionDef
        fi

        cd $HOME/patch/${PATCH}
        cp -arf VersionDef.h $HOME/common-${TARGET}/VersionDef/VersionDef.h-${PATCH}

        cd $HOME/common-${TARGET}/VersionDef/
        if [ ! -L "$HOME/common-${TARGET}/VersionDef/VersionDef.h-current" ]; then
                ln -s VersionDef.h-${PATCH} VersionDef.h-current
                touch /tmp/VersionDef.h-diff
        else
                if [ -L "$HOME/common-${TARGET}/VersionDef/VersionDef.h-previous" ]; then
                        unlink VersionDef.h-previous
                fi

                PREVIOUS=$(readlink $HOME/common-${TARGET}/VersionDef/VersionDef.h-current)
                unlink VersionDef.h-current
                ln -s ${PREVIOUS} VersionDef.h-previous
                ln -s VersionDef.h-${PATCH} VersionDef.h-current

                diff -u VersionDef.h-previous VersionDef.h-current > /tmp/VersionDef.h-diff
        fi
}

server_name_to_set_id () {
	SERVER_NAME=$1

	if [[ ${SERVER_NAME} == *"MissionServer"* ]]; then
		SET_ID=$(echo ${SERVER_NAME}|sed 's/MissionServer//')
	elif [[ ${SERVER_NAME} == *"WorldServer"* ]]; then
		SET_ID_TMP=$(echo ${SERVER_NAME}|sed 's/WorldServer//')
		SET_ID="${SET_ID_TMP%??}"
	elif [[ ${SERVER_NAME} == *"ZoneServer"* ]]; then
		SET_ID_TMP=$(echo ${SERVER_NAME}|sed 's/ZoneServer//')
		SET_ID="${SET_ID_TMP%??}"
	elif [[ ${SERVER_NAME} == *"GameAgentServer"* ]]; then
		SET_ID=$(echo ${SERVER_NAME}|sed 's/GameAgentServer//')
	else
		SET_ID="Common"
	fi

	echo ${SET_ID}
}

function_loaded () {
        echo 1
}

server_online_check () {
        COUNT=$(ssh ACCOUNTDB "psql -U postgres ${ACCOUNT_DB_NAME} -c \"COPY (SELECT COUNT(*) FROM worlds WHERE state = 1) TO STDOUT;\"")

        if (( COUNT > 0 )); then
                return 1
        else
                return 0
        fi
}


check_table_uploading () {
	name="$1"

	ret=$(psql -U postgres ${ACCOUNT_DB_NAME} -c "COPY (SELECT status FROM xl_system_table_check WHERE name = '${table_name}') TO STDOUT;")

	if [ ! -z "$ret" ]; then
		echo "$ret"
	else
		echo "1"
	fi
}

get_env_tag_output () {
	env="$1"

	if [ "${env}" == "0" ]; then
		ENV_TAG="(測試)"
	elif [ "${env}" == "1" ]; then
		ENV_TAG="(正式)"
	else
		ENV_TAG="(Unknown)"
	fi

	echo "${ENV_TAG}"
}

urlencode() {
        local string="$1"
        local encoded=""
        for (( i=0; i<${#string}; i++ )); do
                char="${string:$i:1}"
                case "$char" in
                        [a-zA-Z0-9.~_-]) encoded+="$char" ;;
                        *) encoded+=$(printf '%%%02X' "'$char") ;;
                esac
        done
        echo "$encoded"
}

# 等待直到 $("$HOME/bin/check_running_parallel" open <targets...>) 回傳 "2"
wait_until_open_result_eq2() {
    local start now elapsed result
    start=$(date +%s)

    while true; do
        # 以參數為目標呼叫 check_running_parallel open
        result=$("$HOME/bin/check_running_parallel" open "$@") || result=""
        if [[ "$result" == "2" ]]; then
            return 0
        fi

        # 逾時判斷（若 WAIT_TIMEOUT_SEC=0 則不檢查）
        if (( WAIT_TIMEOUT_SEC > 0 )); then
            now=$(date +%s)
            elapsed=$(( now - start ))
            if (( elapsed >= WAIT_TIMEOUT_SEC )); then
                echo "Timeout (${WAIT_TIMEOUT_SEC}s) waiting for result==2; last result='${result}'" >&2
                return 1
            fi
        fi

        sleep "${WAIT_INTERVAL_SEC}"
    done
}

# 等待直到 $("$HOME/bin/check_running_parallel" close <targets...>) 回傳 "2"
wait_until_close_result_eq2() {
    local start now elapsed result
    start=$(date +%s)

    while true; do
        # 以參數為目標呼叫 check_running_parallel close
        result=$("$HOME/bin/check_running_parallel" close "$@") || result=""
        if [[ "$result" == "2" ]]; then
            return 0
        fi

        # 逾時判斷（若 WAIT_TIMEOUT_SEC=0 則不檢查）
        if (( WAIT_TIMEOUT_SEC > 0 )); then
            now=$(date +%s)
            elapsed=$(( now - start ))
            if (( elapsed >= WAIT_TIMEOUT_SEC )); then
                echo "Timeout (${WAIT_TIMEOUT_SEC}s) waiting for result==2; last result='${result}'" >&2
                return 1
            fi
        fi

        sleep "${WAIT_INTERVAL_SEC}"
    done
} 

hostname2db () {
    DB_NAME=$1
    SET_ID=$(get_set_id ${DB_NAME})
    WORLD_ID=$(get_world_id ${DB_NAME})

    case ${DB_NAME} in
        ACCOUNTDB*)
            sed "s/ACCOUNTDB/${ACCOUNT_DB_NAME}/g" <<< "${DB_NAME}"
            ;;
        GAMEDB*)
            sed "s/GAMEDB\([0-9]\+\)/${GAME_DB_NAME}${SET_ID}/g" <<< "${DB_NAME}"
            ;;
        WORLDDB*)
            sed "s/WORLDDB\([0-9]\+\)/${WORLD_DB_NAME}${WORLD_ID}/g" <<< "${DB_NAME}"
            ;;
        SOCIETYDB*)
            sed "s/SOCIETYDB\([0-9]\+\)/${SOCIETY_DB_NAME}${SET_ID}/g" <<< "${DB_NAME}"
            ;;
        *)
            echo "Unknown DB Type for ${DB_NAME}"
            ;;
    esac
}

# 等待直到 $("$HOME/bin/check_dbpatch_parallel" <DB_TYPE> <targets...>) 回傳 "2"
wait_until_dbpatch_result_eq2() {
    DB_TYPE="$1"; shift

    local start now elapsed result
    start=$(date +%s)

    # 單次 check 的 hard timeout（避免 command substitution 卡死）
    : "${CHECK_HARD_TIMEOUT_SEC:=30}"

    while true; do
        result="$(
          timeout "${CHECK_HARD_TIMEOUT_SEC}" \
            "$HOME/bin/check_dbpatch_parallel" "$DB_TYPE" "$@" 2>/dev/null \
          || true
        )"

        # 正規化輸出，避免 "2\r\n" 之類造成比對失敗
        result="$(printf '%s' "$result" | tr -d '\r\n' | xargs || true)"

        if [[ "$result" == "2" ]]; then
            return 0
        fi

        if (( WAIT_TIMEOUT_SEC > 0 )); then
            now=$(date +%s)
            elapsed=$(( now - start ))
            if (( elapsed >= WAIT_TIMEOUT_SEC )); then
                echo "Timeout (${WAIT_TIMEOUT_SEC}s) waiting for result==2; last result='${result}'" >&2
                return 1
            fi
        fi

        sleep "${WAIT_INTERVAL_SEC}"
    done
}

if [ "$SSH_TTY" != "" ] && [ "$HOST_NAME" == "TEST" ] && [ "$SHLVL" == "1" ] ; then

   # Check PostgreSQL error log
   if [ "$POSTGRESQL_ERROR_CHECK_ON_LOGIN" != "0" ] && [ "$PGUSER" == "" ] ; then
        ~/bin/pg_error_log 2> /dev/null
        ~/bin/sendscript alldb nohostname nosave <<< "pg_error_log" 2> /dev/null

        echo
#        echo "NOTICE: pg_error_log still in experimental. If you want to filter
#non-important error message or statement, please add the keyword
#to the files:
#~/bin/pg_error_log.ignore_error
#~/bin/pg_error_log.ignore_statement
#"
   fi


   # Check low disk space on login
   if [ "$LOW_DISK_SPACE_CHECK_ON_LOGIN" != "0" ] ; then

	# Default values for server directory, /var and PGDATA
	[ "$LOW_DISK_SPACE_WARNING_SERVER_DIR" == "" ] && LOW_DISK_SPACE_WARNING_SERVER_DIR=30000
	[ "$LOW_DISK_SPACE_WARNING_VAR" == "" ] && LOW_DISK_SPACE_WARNING_VAR=1000
	[ "$LOW_DISK_SPACE_WARNING_PGDATA" == "" ] && LOW_DISK_SPACE_WARNING_PGDATA=3000
	ls "$PGDATA" > /dev/null 2>&1 && LOW_DISK_SPACE_CHECK_PGDATA="1"

	# Check if the LIVE server exist
	if [ "$(sed -n '/BELOW/,/ABOVE/p' /etc/hosts|grep -v "^#"|wc -l)" != "0" ] ; then
		# Low disk space warning (Server directory)
		~/bin/sendscript allall -p nosave nohostname <<< 'source ~/.gamerc;df -m $WORKING_DIRECTORY|grep "% /"|awk "\$(NF-2) < '$LOW_DISK_SPACE_WARNING_SERVER_DIR' {print \"WARNING: LOW DISK SPACE ON $HOST_NAME(\"\$NF\"), Used:\"\$(NF-1)\", Free:\"\$(NF-2)/1024 \"GB\"}" | colorize red black'
		# Low disk space warning (/var)
		~/bin/sendscript allall -p nosave nohostname <<< 'source ~/.gamerc;df -m /var|grep "% /"|awk "\$(NF-2) < '$LOW_DISK_SPACE_WARNING_VAR' {print \"WARNING: LOW DISK SPACE ON $HOST_NAME(/var), Used:\"\$(NF-1)\", Free:\"\$(NF-2)/1024 \"GB\"}" | colorize red black'
		# Low disk space warning (PGDATA)
		if [ "$LOW_DISK_SPACE_CHECK_PGDATA" == "1" ] ; then
			~/bin/sendscript allall -p nosave nohostname <<< 'source ~/.gamerc;df -m '$PGDATA' 2> /dev/null |grep "% /"|awk "\$(NF-2) < '$LOW_DISK_SPACE_WARNING_PGDATA' {print \"WARNING: LOW DISK SPACE ON $HOST_NAME(PGDATA), Used:\"\$(NF-1)\", Free:\"\$(NF-2)/1024 \"GB\"}" | colorize red black'
		fi
	fi # if [ "$(sed -n '/BELOW/,/ABOVE/p' /etc/hosts|grep -v "^#"|wc -l)" != "0" ] ; then

	# Low disk space warning (Server directory)
	df -m $WORKING_DIRECTORY|grep "% /"|awk '$(NF-2) < '$LOW_DISK_SPACE_WARNING_SERVER_DIR'  {print "WARNING: LOW DISK SPACE ON TEST("$NF"), Used:"$(NF-1)", Free:"$(NF-2)/1024" GB"}' | colorize red black
	# Low disk space warning (/var)
	df -m /var|grep "% /"              |awk '$(NF-2) < '$LOW_DISK_SPACE_WARNING_VAR' {print "WARNING: LOW DISK SPACE ON TEST(/var), Used:"$(NF-1)", Free:"$(NF-2)/1024" GB"}' | colorize red black
	# Low disk space warning (PGDATA)
	if [ "$LOW_DISK_SPACE_CHECK_PGDATA" == "1" ] ; then
		df -m "$PGDATA" 2> /dev/null |grep "% /" |awk '$(NF-2) < '$LOW_DISK_SPACE_WARNING_PGDATA' {print "WARNING: LOW DISK SPACE ON TEST(PGDATA), Used:"$(NF-1)", Free:"$(NF-2)/1024" GB"}' | colorize red black
	fi

   fi # if [ "$LOW_DISK_SPACE_CHECK_ON_LOGIN" != "0" ] ; then


   # Check any duplicated IP in /etc/hosts
   cat ~/bin/hosts|grep "^[0-9]"|awk '{print $1}'|sort|uniq -d|grep -q "^[0-9]" \
   && echo -e "WARNING: Duplicated IP in ~/bin/hosts:\n$(
	cat ~/bin/hosts|grep "^[0-9]"|awk '{print $1}'|sort|uniq -d
   )" | colorize red black

   # Check any existed game server host name setting in the origin hosts
   grep -E -q "WZ|GAMEDB|ACCOUNTDB|TICKET|BGW|LOGIN" ~/.hosts \
   && echo -e "WARNING: There are some game server host name already in the origin hosts(~/.hosts)
This may confuse the Ctrl scripts to build up game servers:
$(grep -E "WZ|GAMEDB|ACCOUNTDB|TICKET|BGW|LOGIN" ~/.hosts)" | colorize red black

   # Check APEX expire date if APEX exist
   if ! [ "$CHECK_APEX_EXPIRE_DATE_ON_LOGIN" == "0" ] ; then
       if eval test -d $APEXITEMSERVER_PATH ; then
           DAYS_TO_EXPIRE="$((($(date -d "$($HOME/bin/sendscript allwz -p nohostname nosave <<< 'source ~/.gamerc;eval ls -tr $APEXITEMSERVER_PATH/hook_log/MainServer* 2> /dev/null | tail | xargs grep -a Authorized' | awk -F">" '{print $NF}' | sed 's/-\([0-9]\)-/-0\1-/g' | sort -g | tail -1)" +%s)-$(date +%s))/86400))"
           if [ $DAYS_TO_EXPIRE == 0 ] ; then
               echo "WARNING: APEX expire date cannot be estimate." | colorize red black
           elif [ $DAYS_TO_EXPIRE -lt 30 ] ; then
               echo "WARNING: APEX will be expired in $DAYS_TO_EXPIRE days." | colorize red black 5
           fi
       fi
   fi

fi # if [ "$SSH_TTY" != "" ] && [ "$HOST_NAME" == "TEST" ] && [ "$SHLVL" == "1" ] ; then
if [ "$SSH_TTY" != "" ] && [ "$SHLVL" == "1" ] ; then
    echo LogRotate | ulogger
fi

# Force load customized functions
NANO_SECOND="$(date +%N)"
CUSTFUNC="/tmp/customized_function.$NANO_SECOND"
sed -n '/() {$/,/^}$/p' ~/bin/customized_function > $CUSTFUNC
echo >> $CUSTFUNC
source $CUSTFUNC
rm -f $CUSTFUNC
