<commit_before>/************************************************************************************
** The MIT License (MIT)
**
** Copyright (c) 2015 Serg "EXL" Koles
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
** copies of the Software, and to permit persons to whom the Software is
** furnished to do so, subject to the following conditions:
**
** The above copyright notice and this permission notice shall be included in all
** copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
** SOFTWARE.
************************************************************************************/

var TelegramBot = require('node-telegram-bot-api');
var FileSystem = require('fs');
var Http = require('http');
var Request = require('request');

var token = getTokenAccess();
var catchPhrases = getCatchPhrases();
var httpOptions = [
    {
        host: 'www.cbr.ru',
        port: 80,
        path: '/scripts/XML_daily.asp?'
    },
    {
        host: 'www.bank-ua.com',
        port: 80,
        path: '/export/currrate.xml'
    }
];

var botOptions = {
    polling: true
};

var bot = new TelegramBot(token, botOptions);

var globalCountOfMessagesWithDigest = 0;
var globalUserNameIs;
var globalBotUserName;

var globalStackListDigestMessages = [ ];

// CURRENCY SECTION
var xmlContent = '';

var bankForeignCurrency = ['UAH', 'RUB'];
var bankLocalCurrency = ['RUB', 'UAH'];

var bankCBR = 0;
var bankNBU = 1;

var globalMetallJson = 'http://api.z-lab.me/charts/metall.json';

var globalUSD = [0.0, 0.0];
var globalCurrencyList =  {
    'USD': 0.0,
    'EUR': 0.0,
    'RUB': 0.0,
    'UAH': 0.0,
    'KZT': 0.0,
    'BYR': 0.0,
    'GBP': 0.0
};

initilizeCurrencyListAndGetUsdValue();

var globalExchangeList = {
    'mmvb': {
        desc: 'MMVB (MOEX) Index.',
        url: 'http://api.z-lab.me/charts/mmvb.png'
    },
    'usd_rub': {
        desc: 'USD/RUB from Nasdaq, Nyse.',
        url: 'http://api.z-lab.me/charts/usd_rub.png'
    },
    'usd_uah': {
        desc: 'USD/UAH from Nasdaq, Nyse.',
        url: 'http://api.z-lab.me/charts/usd_uah.png'
    },
    'eur_rub': {
        desc: 'EUR/RUB from Nasdaq, Nyse.',
        url: 'http://api.z-lab.me/charts/eur_rub.png'
    },
    'eur_uah': {
        desc: 'EUR/UAH from Nasdaq, Nyse.',
        url: 'http://api.z-lab.me/charts/eur_uah.png'
    },
    'gold': {
        desc: 'Gold from Nasdaq.',
        url: 'http://api.z-lab.me/charts/gold.png'
    },
    'palladium': {
        desc: 'Palladium from Nasdaq.',
        url: 'http://api.z-lab.me/charts/palladium.png'
    },
    'platinum': {
        desc: 'Platinum from Nasdaq.',
        url: 'http://api.z-lab.me/charts/platinum.png'
    },
    'rhodium': {
        desc: 'Rhodium from Nasdaq.',
        url: 'http://api.z-lab.me/charts/rhodium.png'
    },
    'silver': {
        desc: 'Silver from Nasdaq.',
        url: 'http://api.z-lab.me/charts/silver.png'
    },
    'rts': {
        desc: 'RTS Index from MMVB (MOEX).',
        url: 'http://api.z-lab.me/charts/rts.png'
    },
    'btc_usd': {
        desc: 'BTC/USD from BTC-E.',
        url: 'http://api.z-lab.me/btce/btc_usd.php'
    },
    'btc_rub': {
        desc: 'BTC/RUB from BTC-E.',
        url: 'http://api.z-lab.me/btce/btc_rur.php'
    },
    'forex': {
        desc: 'USD/RUB from Forex.',
        url: 'http://j1.forexpf.ru/delta/prochart?type=USDRUB&amount=335&chart_height=170&chart_width=330&grtype=2&tictype=0&iId=5'
    },
    'brent': {
        desc: 'Brent from Nasdaq, Nyse.',
        url: 'http://api.z-lab.me/charts/brent.png'
    },
    'wti': {
        desc: 'WTI from Nasdaq, Nyse.',
        url: 'http://api.z-lab.me/charts/wti.png'
    }
};

var globalExchange;
// END CURRENCY SECTION

bot.getMe().then(function(me)
{
    console.log('Hello! My name is %s!', me.first_name);
    console.log('My id is %s.', me.id);
    console.log('And my username is @%s.', me.username);
    globalBotUserName = me.username;
});

bot.on('text', function(msg)
{
    // Set main variables
    var messageChatId = msg.chat.id;
    var messageText = msg.text;
    var messageDate = msg.date;
    globalUserNameIs = msg.from.username;

    // DEBUG SECTION
    // console.log(msg);
    // END DEBUG SECTION

    // DIGEST TAG
    if (messageText.indexOf('#digest') >= 0) {
        if (messageText.length < 3000) {
            globalCountOfMessagesWithDigest++;
            var normalMessage = normalizeMessage(messageText);
            if (!(isBlank(normalMessage))) {
                var messageInfoStruct = {
                    's_chatID': messageChatId,
                    's_date': messageDate,
                    's_message': normalMessage,
                    's_username': globalUserNameIs
                };

                globalStackListDigestMessages.push(messageInfoStruct);

                // Send message by bot.
                sendMessageByBot(messageChatId,
                                 catchPhrases.digestTag[getRandomInt(0, catchPhrases.digestTag.length - 1)]);
            }
        } else {
            sendMessageByBot(messageChatId,
                             catchPhrases.debugCommandMessages[5]);
        }
    }

    // DIGEST COMMAND
    if (messageText.indexOf('/digest') === 0 || messageText.indexOf('/digest@'+globalBotUserName) === 0) {
        var bGoodCommand = false;
        var messageDelay = 0;

        messageText = messageText.trim();

        if (messageText === '/digest' || messageText === '/digest@'+globalBotUserName) {
            bGoodCommand = true;
            messageDelay = getMessageDelay(1);
        }

        if (messageText.length === 9) {
            var arg = parseInt(messageText[8]);
            if (parseInt(messageText[8])) {
                if (arg >= 1 && arg <= 7) {
                    bGoodCommand = true;
                    messageDelay = getMessageDelay(arg);
                }
            }
        }

        if (bGoodCommand) {
            // Digest delay.
            // 45 sec for debug.
            // 43 200 for 12-hours.
            // 86 400 for 24-hours.
            // 172 800 for 48-hours.
            // 604 800 for a week.
            var mainDelay = 604800 + 43200;
            var dayDelay = messageDate - messageDelay;

            var bSendDigest = false;

            if (globalStackListDigestMessages.length > 0) {
                // Delete all obsolete digest messages from globalStackListDigestMessages
                bSendDigest = deleteObsoleteDigestMessages(messageDate - mainDelay);
            }

            // Generate Bot Answer
            if (bSendDigest) {
                var botAnswer = '';
                var endLineString = '\n';
                var stackSize = globalStackListDigestMessages.length;

                // Count of digest messages from one chat.
                var countOfDigestMessagesByChat = getCountDigestMessagesOfChat(messageChatId, dayDelay);

                // Check countOfDigestMessagesByChat.
                if (countOfDigestMessagesByChat > 0) {
                    // Append answer string.
                    // botAnswer += 'Hola amigos!\nThere is digest of this chat:\n';
                    for (var i = 0; i < stackSize; ++i) {
                        if (globalStackListDigestMessages[i].s_chatID === messageChatId) {
                            if (globalStackListDigestMessages[i].s_date > dayDelay) {
                                botAnswer += globalStackListDigestMessages[i].s_message + endLineString;
                            }
                        }
                    }

                    // Trim strings
                    botAnswer = botAnswer.trim();
                    botAnswer = trimEachString(botAnswer);

                    // Capitalize first letter of each string
                    botAnswer = capitalizeFirstLetterOfEachString(botAnswer);

                    // Replace all line breaks by semicolon, line break and digestMarker.
                    botAnswer = catchPhrases.digestMarker + replaceLineBreaksByYourString(botAnswer, ';\n' + catchPhrases.digestMarker);

                    // Delete last characters (;\n<marker><space>).
                    // Don't need
                    // botAnswer = botAnswer.substring(0, botAnswer.length - 4);

                    // Remove username URI
                    botAnswer = botAnswer.replace(/@/g,'');

                    // Add dot to end of line.
                    if (botAnswer.substr(botAnswer.length - 1) !== '.') {
                        botAnswer += '.';
                    }

                    // Add digest header
                    botAnswer = getDigestReportHeader() + botAnswer;

                    // Send botAnswer as chunks
                    sendChunksMessagesByBot(messageChatId, botAnswer, 3500);
                } else {
                    sendNoDigestMessages(messageChatId);
                }
            } else {
                sendNoDigestMessages(messageChatId);
            }
        } else {
            sendMessageByBot(messageChatId, catchPhrases.helpCommand[2]);
        }
    }

    // ROUBLE AND GRIVNA COMMAND
    if (messageText === '/rouble' || messageText === '/grivna' ||
            messageText === '/rouble@'+globalBotUserName || messageText === '/grivna@'+globalBotUserName) {
        var bankID = bankCBR;
        
        if (messageText === '/grivna' || messageText === '/grivna@'+globalBotUserName) {
            bankID = bankNBU;
        }
        
        // Store last USD value.
        var lastForeignValue = globalUSD[bankID];

        // Update currency list.
        updateGlobalCurrencyList(bankID, lastForeignValue, messageChatId);
    }

    // CHART COMMAND
    if (messageText.indexOf('/chart') === 0 || messageText.indexOf('/chart@'+globalBotUserName) === 0) {
        messageText = messageText.trim();
        var splitCommandList = messageText.split(' ');
        if (splitCommandList.length === 2) {
            sendChartToChat(messageChatId, splitCommandList[1]);
        } else {
            sendMessageByBot(messageChatId,
                             generateChartsHelpString());
        }
    }

    // METALL COMMAND
    if (messageText === '/metall' || messageText === '/metall@'+globalBotUserName) {
        Request(globalMetallJson, function(aErr, aRes, aBody) {
            if (!aErr) {
                sendMetallValues(messageChatId, aBody);
            } else {
                sendMessageByBot(messageChatId, 'Error: ' + aErr);
            }
        });
    }

    // HELP COMMAND
    if (messageText === '/help' || messageText === '/help@'+globalBotUserName) {
        sendMessageByBot(messageChatId, generateHelpString());
    }

    // START COMMAND
    if (messageText === '/start' || messageText === '/start@'+globalBotUserName) {
        sendMessageByBot(messageChatId, catchPhrases.startCommand[0]);
    }
    
    // DEBUG SECTION
    // HELLO COMMAND
    if (messageText === '/hello' || messageText === '/hi'
            || messageText === '/hello@'+globalBotUserName || messageText === '/hi@'+globalBotUserName) {
        if (getAdminRights()) {
            sendMessageByBot(messageChatId,
                             catchPhrases.helloCommand[getRandomInt(0, catchPhrases.helloCommand.length - 1)]);
        }
    }

    // ADMINISTRATION COMMANDS
    // SEND COMMAND
    if (messageText.indexOf('/send') === 0) {
        if (getAdminRights()) {
            messageText = messageText.trim();
            var splitSendList = messageText.split(' ');
            if (splitSendList.length > 2) {
                var targetChatID = splitSendList[1];
                sendMessageByBot(targetChatID, getSendMessage(messageText, '/send ' + targetChatID));
            } else {
                sendMessageByBot(messageChatId,
                                 catchPhrases.debugCommandMessages[8]);
            }
        } else {
            sendNoAccessMessage(messageChatId);
        }
    }

    // CLEARSTACK COMMAND
    if (messageText === '/stackClear' || messageText === '/clearStack') {
        if (getAdminRights()) {
            globalStackListDigestMessages = [ ];
            sendMessageByBot(messageChatId,
                             catchPhrases.debugCommandMessages[1]);
        } else {
            sendNoAccessMessage(messageChatId);
        }
    }

    // DIGESTCOUNT COMMAND
    if (messageText === '/count') {
        if (getAdminRights()) {
            sendMessageByBot(messageChatId,
                             catchPhrases.debugCommandMessages[4] + globalCountOfMessagesWithDigest);
        } else {
            sendNoAccessMessage(messageChatId);
        }
    }

    // DELETE COMMAND
    if (messageText.indexOf('/delete') === 0) {
        if (getAdminRights()) {
            var stackLength = globalStackListDigestMessages.length;
            if (stackLength > 0) {
                var chunksMsg = messageText.split(' ');
                if (chunksMsg.length === 2) {
                    var delArg = parseInt(chunksMsg[1]);
                    if (delArg <= stackLength) {
                        globalStackListDigestMessages.splice(delArg - 1, 1);
                        sendMessageByBot(messageChatId, catchPhrases.debugCommandMessages[6] + ' ' + delArg + '.');
                    } else {
                        sendMessageByBot(messageChatId, catchPhrases.debugCommandMessages[7] + ' ' + delArg + '.');
                    }
                }
            } else {
                sendMessageByBot(messageChatId,
                                 catchPhrases.debugCommandMessages[2]);
            }
        } else {
            sendNoAccessMessage(messageChatId);
        }
    }

    // VIEWSTACK COMMAND
    if (messageText === '/stackView' || messageText === '/viewStack') {
        if (getAdminRights()) {
            var stack = '\n';
            var sizeOfStack = globalStackListDigestMessages.length;
            if (sizeOfStack > 0) {
                for (var j = 0; j < sizeOfStack; ++j) {
                    stack += j + 1 + ' ';
                    stack += globalStackListDigestMessages[j].s_chatID + ' ';
                    stack += globalStackListDigestMessages[j].s_username + ' ';
                    stack += globalStackListDigestMessages[j].s_date + ' ';
                    stack += globalStackListDigestMessages[j].s_message + '\n';
                }
                sendChunksMessagesByBot(messageChatId,
                                        catchPhrases.debugCommandMessages[3] + stack, 3500);
            } else {
                sendMessageByBot(messageChatId,
                                 catchPhrases.debugCommandMessages[2]);
            }
        } else {
            sendNoAccessMessage(messageChatId);
        }
    }

    // SAVESTACK COMMAND
    if (messageText === '/stackSave' || messageText === '/saveStack') {
        if (getAdminRights()) {
            writeJSONFileToFileSystem('DigestBotStackLog.json', messageChatId);
        } else {
            sendNoAccessMessage(messageChatId);
        }
    }

    // RESTORESTACK COMMAND
    if (messageText === '/stackRestore' || messageText === '/restoreStack') {
        if (getAdminRights()) {
            readSavedStackFromFileSystem('DigestBotStackLog.json', messageChatId);
        } else {
            sendNoAccessMessage(messageChatId);
        }
    }
    // END DEBUG SECTION
});

function generateChartsHelpString()
{
    var helpChartsAnswer = '';
    for (var i = 0; i < catchPhrases.chartHelp.length; ++i) {
        helpChartsAnswer += catchPhrases.chartHelp[i] + '\n';
    }

    // Delete last line break
    helpChartsAnswer.trim();

    return helpChartsAnswer;
}

function downloadImageAndSendToChat(aUri, aFileName, aChatId)
{
    Request.head(aUri, function(aErr, aRes, aBody) {
        Request(aUri).pipe(FileSystem.createWriteStream(aFileName)).on('close', function() {
            sendChartFileToChat(aChatId, aFileName);
        });
    });
}

function sendChartFileToChat(aChatId, aImageName)
{
    if (aImageName) {
        bot.sendPhoto(aChatId, aImageName, { caption: catchPhrases.debugCommandMessages[9] + ' ' + globalExchange.desc });
    }
}

function sendChartToChat(aChatId, aExchangeId)
{
    if (globalExchangeList[aExchangeId]) {
        globalExchange = globalExchangeList[aExchangeId];
        downloadImageAndSendToChat(globalExchangeList[aExchangeId].url,
                                   addYourStringToString('./', globalExchangeList[aExchangeId].name + '_image.png'),
                                   aChatId);
    } else {
        sendMessageByBot(aChatId,
                         generateChartsHelpString());
    }
}

function sendChunksMessagesByBot(aChatId, aMesssage, aChunkSize)
{
    for (var j = 0, botAnswerLength = aMesssage.length; j < botAnswerLength; j+=aChunkSize) {
        sendMessageByBot(aChatId,  aMesssage.substring(j, j + aChunkSize));
    }
}

function generateHelpString()
{
    var botAnswer = '';
    for (var i = 0; i < catchPhrases.helpCommand.length; ++i) {
        botAnswer += catchPhrases.helpCommand[i] + '\n';
    }

    if (getAdminRights()) {
        for (var j = 0; j < catchPhrases.helpCommandAdmin.length; ++j) {
            botAnswer += catchPhrases.helpCommandAdmin[j] + '\n';
        }
    }

    // Delete last line break<commit_msg>Fix file name of chart image<commit_after>/************************************************************************************
** The MIT License (MIT)
**
** Copyright (c) 2015 Serg "EXL" Koles
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
** copies of the Software, and to permit persons to whom the Software is
** furnished to do so, subject to the following conditions:
**
** The above copyright notice and this permission notice shall be included in all
** copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
** SOFTWARE.
************************************************************************************/

var TelegramBot = require('node-telegram-bot-api');
var FileSystem = require('fs');
var Http = require('http');
var Request = require('request');

var token = getTokenAccess();
var catchPhrases = getCatchPhrases();
var httpOptions = [
    {
        host: 'www.cbr.ru',
        port: 80,
        path: '/scripts/XML_daily.asp?'
    },
    {
        host: 'www.bank-ua.com',
        port: 80,
        path: '/export/currrate.xml'
    }
];

var botOptions = {
    polling: true
};

var bot = new TelegramBot(token, botOptions);

var globalCountOfMessagesWithDigest = 0;
var globalUserNameIs;
var globalBotUserName;

var globalStackListDigestMessages = [ ];

// CURRENCY SECTION
var xmlContent = '';

var bankForeignCurrency = ['UAH', 'RUB'];
var bankLocalCurrency = ['RUB', 'UAH'];

var bankCBR = 0;
var bankNBU = 1;

var globalMetallJson = 'http://api.z-lab.me/charts/metall.json';

var globalUSD = [0.0, 0.0];
var globalCurrencyList =  {
    'USD': 0.0,
    'EUR': 0.0,
    'RUB': 0.0,
    'UAH': 0.0,
    'KZT': 0.0,
    'BYR': 0.0,
    'GBP': 0.0
};

initilizeCurrencyListAndGetUsdValue();

var globalExchangeList = {
    'mmvb': {
        desc: 'MMVB (MOEX) Index.',
        url: 'http://api.z-lab.me/charts/mmvb.png'
    },
    'usd_rub': {
        desc: 'USD/RUB from Nasdaq, Nyse.',
        url: 'http://api.z-lab.me/charts/usd_rub.png'
    },
    'usd_uah': {
        desc: 'USD/UAH from Nasdaq, Nyse.',
        url: 'http://api.z-lab.me/charts/usd_uah.png'
    },
    'eur_rub': {
        desc: 'EUR/RUB from Nasdaq, Nyse.',
        url: 'http://api.z-lab.me/charts/eur_rub.png'
    },
    'eur_uah': {
        desc: 'EUR/UAH from Nasdaq, Nyse.',
        url: 'http://api.z-lab.me/charts/eur_uah.png'
    },
    'gold': {
        desc: 'Gold from Nasdaq.',
        url: 'http://api.z-lab.me/charts/gold.png'
    },
    'palladium': {
        desc: 'Palladium from Nasdaq.',
        url: 'http://api.z-lab.me/charts/palladium.png'
    },
    'platinum': {
        desc: 'Platinum from Nasdaq.',
        url: 'http://api.z-lab.me/charts/platinum.png'
    },
    'rhodium': {
        desc: 'Rhodium from Nasdaq.',
        url: 'http://api.z-lab.me/charts/rhodium.png'
    },
    'silver': {
        desc: 'Silver from Nasdaq.',
        url: 'http://api.z-lab.me/charts/silver.png'
    },
    'rts': {
        desc: 'RTS Index from MMVB (MOEX).',
        url: 'http://api.z-lab.me/charts/rts.png'
    },
    'btc_usd': {
        desc: 'BTC/USD from BTC-E.',
        url: 'http://api.z-lab.me/btce/btc_usd.php'
    },
    'btc_rub': {
        desc: 'BTC/RUB from BTC-E.',
        url: 'http://api.z-lab.me/btce/btc_rur.php'
    },
    'forex': {
        desc: 'USD/RUB from Forex.',
        url: 'http://j1.forexpf.ru/delta/prochart?type=USDRUB&amount=335&chart_height=170&chart_width=330&grtype=2&tictype=0&iId=5'
    },
    'brent': {
        desc: 'Brent from Nasdaq, Nyse.',
        url: 'http://api.z-lab.me/charts/brent.png'
    },
    'wti': {
        desc: 'WTI from Nasdaq, Nyse.',
        url: 'http://api.z-lab.me/charts/wti.png'
    }
};

var globalExchange;
// END CURRENCY SECTION

bot.getMe().then(function(me)
{
    console.log('Hello! My name is %s!', me.first_name);
    console.log('My id is %s.', me.id);
    console.log('And my username is @%s.', me.username);
    globalBotUserName = me.username;
});

bot.on('text', function(msg)
{
    // Set main variables
    var messageChatId = msg.chat.id;
    var messageText = msg.text;
    var messageDate = msg.date;
    globalUserNameIs = msg.from.username;

    // DEBUG SECTION
    // console.log(msg);
    // END DEBUG SECTION

    // DIGEST TAG
    if (messageText.indexOf('#digest') >= 0) {
        if (messageText.length < 3000) {
            globalCountOfMessagesWithDigest++;
            var normalMessage = normalizeMessage(messageText);
            if (!(isBlank(normalMessage))) {
                var messageInfoStruct = {
                    's_chatID': messageChatId,
                    's_date': messageDate,
                    's_message': normalMessage,
                    's_username': globalUserNameIs
                };

                globalStackListDigestMessages.push(messageInfoStruct);

                // Send message by bot.
                sendMessageByBot(messageChatId,
                                 catchPhrases.digestTag[getRandomInt(0, catchPhrases.digestTag.length - 1)]);
            }
        } else {
            sendMessageByBot(messageChatId,
                             catchPhrases.debugCommandMessages[5]);
        }
    }

    // DIGEST COMMAND
    if (messageText.indexOf('/digest') === 0 || messageText.indexOf('/digest@'+globalBotUserName) === 0) {
        var bGoodCommand = false;
        var messageDelay = 0;

        messageText = messageText.trim();

        if (messageText === '/digest' || messageText === '/digest@'+globalBotUserName) {
            bGoodCommand = true;
            messageDelay = getMessageDelay(1);
        }

        if (messageText.length === 9) {
            var arg = parseInt(messageText[8]);
            if (parseInt(messageText[8])) {
                if (arg >= 1 && arg <= 7) {
                    bGoodCommand = true;
                    messageDelay = getMessageDelay(arg);
                }
            }
        }

        if (bGoodCommand) {
            // Digest delay.
            // 45 sec for debug.
            // 43 200 for 12-hours.
            // 86 400 for 24-hours.
            // 172 800 for 48-hours.
            // 604 800 for a week.
            var mainDelay = 604800 + 43200;
            var dayDelay = messageDate - messageDelay;

            var bSendDigest = false;

            if (globalStackListDigestMessages.length > 0) {
                // Delete all obsolete digest messages from globalStackListDigestMessages
                bSendDigest = deleteObsoleteDigestMessages(messageDate - mainDelay);
            }

            // Generate Bot Answer
            if (bSendDigest) {
                var botAnswer = '';
                var endLineString = '\n';
                var stackSize = globalStackListDigestMessages.length;

                // Count of digest messages from one chat.
                var countOfDigestMessagesByChat = getCountDigestMessagesOfChat(messageChatId, dayDelay);

                // Check countOfDigestMessagesByChat.
                if (countOfDigestMessagesByChat > 0) {
                    // Append answer string.
                    // botAnswer += 'Hola amigos!\nThere is digest of this chat:\n';
                    for (var i = 0; i < stackSize; ++i) {
                        if (globalStackListDigestMessages[i].s_chatID === messageChatId) {
                            if (globalStackListDigestMessages[i].s_date > dayDelay) {
                                botAnswer += globalStackListDigestMessages[i].s_message + endLineString;
                            }
                        }
                    }

                    // Trim strings
                    botAnswer = botAnswer.trim();
                    botAnswer = trimEachString(botAnswer);

                    // Capitalize first letter of each string
                    botAnswer = capitalizeFirstLetterOfEachString(botAnswer);

                    // Replace all line breaks by semicolon, line break and digestMarker.
                    botAnswer = catchPhrases.digestMarker + replaceLineBreaksByYourString(botAnswer, ';\n' + catchPhrases.digestMarker);

                    // Delete last characters (;\n<marker><space>).
                    // Don't need
                    // botAnswer = botAnswer.substring(0, botAnswer.length - 4);

                    // Remove username URI
                    botAnswer = botAnswer.replace(/@/g,'');

                    // Add dot to end of line.
                    if (botAnswer.substr(botAnswer.length - 1) !== '.') {
                        botAnswer += '.';
                    }

                    // Add digest header
                    botAnswer = getDigestReportHeader() + botAnswer;

                    // Send botAnswer as chunks
                    sendChunksMessagesByBot(messageChatId, botAnswer, 3500);
                } else {
                    sendNoDigestMessages(messageChatId);
                }
            } else {
                sendNoDigestMessages(messageChatId);
            }
        } else {
            sendMessageByBot(messageChatId, catchPhrases.helpCommand[2]);
        }
    }

    // ROUBLE AND GRIVNA COMMAND
    if (messageText === '/rouble' || messageText === '/grivna' ||
            messageText === '/rouble@'+globalBotUserName || messageText === '/grivna@'+globalBotUserName) {
        var bankID = bankCBR;
        
        if (messageText === '/grivna' || messageText === '/grivna@'+globalBotUserName) {
            bankID = bankNBU;
        }
        
        // Store last USD value.
        var lastForeignValue = globalUSD[bankID];

        // Update currency list.
        updateGlobalCurrencyList(bankID, lastForeignValue, messageChatId);
    }

    // CHART COMMAND
    if (messageText.indexOf('/chart') === 0 || messageText.indexOf('/chart@'+globalBotUserName) === 0) {
        messageText = messageText.trim();
        var splitCommandList = messageText.split(' ');
        if (splitCommandList.length === 2) {
            sendChartToChat(messageChatId, splitCommandList[1]);
        } else {
            sendMessageByBot(messageChatId,
                             generateChartsHelpString());
        }
    }

    // METALL COMMAND
    if (messageText === '/metall' || messageText === '/metall@'+globalBotUserName) {
        Request(globalMetallJson, function(aErr, aRes, aBody) {
            if (!aErr) {
                sendMetallValues(messageChatId, aBody);
            } else {
                sendMessageByBot(messageChatId, 'Error: ' + aErr);
            }
        });
    }

    // HELP COMMAND
    if (messageText === '/help' || messageText === '/help@'+globalBotUserName) {
        sendMessageByBot(messageChatId, generateHelpString());
    }

    // START COMMAND
    if (messageText === '/start' || messageText === '/start@'+globalBotUserName) {
        sendMessageByBot(messageChatId, catchPhrases.startCommand[0]);
    }
    
    // DEBUG SECTION
    // HELLO COMMAND
    if (messageText === '/hello' || messageText === '/hi'
            || messageText === '/hello@'+globalBotUserName || messageText === '/hi@'+globalBotUserName) {
        if (getAdminRights()) {
            sendMessageByBot(messageChatId,
                             catchPhrases.helloCommand[getRandomInt(0, catchPhrases.helloCommand.length - 1)]);
        }
    }

    // ADMINISTRATION COMMANDS
    // SEND COMMAND
    if (messageText.indexOf('/send') === 0) {
        if (getAdminRights()) {
            messageText = messageText.trim();
            var splitSendList = messageText.split(' ');
            if (splitSendList.length > 2) {
                var targetChatID = splitSendList[1];
                sendMessageByBot(targetChatID, getSendMessage(messageText, '/send ' + targetChatID));
            } else {
                sendMessageByBot(messageChatId,
                                 catchPhrases.debugCommandMessages[8]);
            }
        } else {
            sendNoAccessMessage(messageChatId);
        }
    }

    // CLEARSTACK COMMAND
    if (messageText === '/stackClear' || messageText === '/clearStack') {
        if (getAdminRights()) {
            globalStackListDigestMessages = [ ];
            sendMessageByBot(messageChatId,
                             catchPhrases.debugCommandMessages[1]);
        } else {
            sendNoAccessMessage(messageChatId);
        }
    }

    // COUNT COMMAND
    if (messageText === '/count') {
        if (getAdminRights()) {
            sendMessageByBot(messageChatId,
                             catchPhrases.debugCommandMessages[4] + globalCountOfMessagesWithDigest);
        } else {
            sendNoAccessMessage(messageChatId);
        }
    }

    // DELETE COMMAND
    if (messageText.indexOf('/delete') === 0) {
        if (getAdminRights()) {
            var stackLength = globalStackListDigestMessages.length;
            if (stackLength > 0) {
                var chunksMsg = messageText.split(' ');
                if (chunksMsg.length === 2) {
                    var delArg = parseInt(chunksMsg[1]);
                    if (delArg <= stackLength) {
                        globalStackListDigestMessages.splice(delArg - 1, 1);
                        sendMessageByBot(messageChatId, catchPhrases.debugCommandMessages[6] + ' ' + delArg + '.');
                    } else {
                        sendMessageByBot(messageChatId, catchPhrases.debugCommandMessages[7] + ' ' + delArg + '.');
                    }
                }
            } else {
                sendMessageByBot(messageChatId,
                                 catchPhrases.debugCommandMessages[2]);
            }
        } else {
            sendNoAccessMessage(messageChatId);
        }
    }

    // VIEWSTACK COMMAND
    if (messageText === '/stackView' || messageText === '/viewStack') {
        if (getAdminRights()) {
            var stack = '\n';
            var sizeOfStack = globalStackListDigestMessages.length;
            if (sizeOfStack > 0) {
                for (var j = 0; j < sizeOfStack; ++j) {
                    stack += j + 1 + ' ';
                    stack += globalStackListDigestMessages[j].s_chatID + ' ';
                    stack += globalStackListDigestMessages[j].s_username + ' ';
                    stack += globalStackListDigestMessages[j].s_date + ' ';
                    stack += globalStackListDigestMessages[j].s_message + '\n';
                }
                sendChunksMessagesByBot(messageChatId,
                                        catchPhrases.debugCommandMessages[3] + stack, 3500);
            } else {
                sendMessageByBot(messageChatId,
                                 catchPhrases.debugCommandMessages[2]);
            }
        } else {
            sendNoAccessMessage(messageChatId);
        }
    }

    // SAVESTACK COMMAND
    if (messageText === '/stackSave' || messageText === '/saveStack') {
        if (getAdminRights()) {
            writeJSONFileToFileSystem('DigestBotStackLog.json', messageChatId);
        } else {
            sendNoAccessMessage(messageChatId);
        }
    }

    // RESTORESTACK COMMAND
    if (messageText === '/stackRestore' || messageText === '/restoreStack') {
        if (getAdminRights()) {
            readSavedStackFromFileSystem('DigestBotStackLog.json', messageChatId);
        } else {
            sendNoAccessMessage(messageChatId);
        }
    }
    // END DEBUG SECTION
});

function generateChartsHelpString()
{
    var helpChartsAnswer = '';
    for (var i = 0; i < catchPhrases.chartHelp.length; ++i) {
        helpChartsAnswer += catchPhrases.chartHelp[i] + '\n';
    }

    // Delete last line break
    helpChartsAnswer.trim();

    return helpChartsAnswer;
}

function downloadImageAndSendToChat(aUri, aFileName, aChatId)
{
    Request.head(aUri, function(aErr, aRes, aBody) {
        Request(aUri).pipe(FileSystem.createWriteStream(aFileName)).on('close', function() {
            sendChartFileToChat(aChatId, aFileName);
        });
    });
}

function sendChartFileToChat(aChatId, aImageName)
{
    if (aImageName) {
        bot.sendPhoto(aChatId, aImageName, { caption: catchPhrases.debugCommandMessages[9] + ' ' + globalExchange.desc });
    }
}

function sendChartToChat(aChatId, aExchangeId)
{
    if (globalExchangeList[aExchangeId]) {
        globalExchange = globalExchangeList[aExchangeId];
        downloadImageAndSendToChat(globalExchangeList[aExchangeId].url,
                                   addYourStringToString('./', aExchangeId + '_image.png'),
                                   aChatId);
    } else {
        sendMessageByBot(aChatId,
                         generateChartsHelpString());
    }
}

function sendChunksMessagesByBot(aChatId, aMesssage, aChunkSize)
{
    for (var j = 0, botAnswerLength = aMesssage.length; j < botAnswerLength; j+=aChunkSize) {
        sendMessageByBot(aChatId,  aMesssage.substring(j, j + aChunkSize));
    }
}

function generateHelpString()
{
    var botAnswer = '';
    for (var i = 0; i < catchPhrases.helpCommand.length; ++i) {
        botAnswer += catchPhrases.helpCommand[i] + '\n';
    }

    if (getAdminRights()) {
        for (var j = 0; j < catchPhrases.helpCommandAdmin.length; ++j) {
            botAnswer += catchPhrases.helpCommandAdmin[j] + '\n';
        }
    }

    // Delete last line break
{'fraction_non_alphanumeric': 0.13077179529921654, 'fraction_numerical': 0.008168028004667444, 'mean_word_length': 1.9319051885639815, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6088353', 'n_tokens_mistral': 10955, 'n_tokens_neox': 10198, 'n_words': 2158}