diff --git a/Dashboard/Dashboard.ino b/Dashboard/Dashboard.ino
index e2b245bb383ce8be8b0f68c654392b1cf89a7d56..9fe3b501a1678db3091b689ea53e2106f53baa42 100644
--- a/Dashboard/Dashboard.ino
+++ b/Dashboard/Dashboard.ino
@@ -27,8 +27,11 @@
 #include <MHZ19_uart.h>
 /********************************/
 
-#include "font.h"
+/************Marcos**************/
+#define timer(tim, del) if(millis() - (tim) > (del))
+/********************************/
 
+#define LANG_RU_RU
 #define LEDsPin 2
 #define CO2RX A0
 #define CO2TX A1
@@ -38,7 +41,8 @@
 #define WIDTH 16
 #define HEIGHT 9
 #define numLeds (WIDTH * HEIGHT)
-#define COLOR mHEX(0x9aa100)
+#define COLOR1 mHEX(0x9aa100)
+#define COLOR2 mHEX(0x000aa0)
 
 microLED<numLeds, LEDsPin, MLED_NO_CLOCK, LED_WS2812, ORDER_GRB, CLI_AVER/*, SAVE_MILLIS*/> matrix(WIDTH, HEIGHT, ZIGZAG, RIGHT_TOP, DIR_LEFT);
 #include "textbox.h"
@@ -58,29 +62,47 @@ void setup()
   co2.begin(CO2TX, CO2RX);
   co2.setAutoCalibration(false);
   delay(500);
-  tb.setup("Mama", TB_STATIC, 0, 0, 16);
-  tb.render();
+  tb.setup("Ghbdtn vbh!", 0xFFFF, COLOR1, TB_BOUNCE, 1, 1, 14, 500, 2000);
 }
 
 void loop()
 {
-  for (uint8_t i = 0; i < 9; i++)
+  // Terminate if buttuns are holded
+  static uint64_t timer_debug0 = 0;
+  static bool button = 0;
+  static bool last_button = 0;
+  last_button = button;
+  button = digitalRead(LBTN) | digitalRead(RBTN);
+  if(!button)
+    timer_debug0 = millis();
+  timer(timer_debug0, 5000)
   {
-    matrix.set(matrix.getPixNumber(15, i), mHEX(0));
+    timer_debug0 = millis();
+    Serial.end();
   }
-  uint16_t CO2 = co2.getPPM();
-  Serial.print(CO2);
-  Serial.print(" ");
-  Serial.print(digitalRead(LBTN));
-  Serial.print(" ");
-  Serial.println(digitalRead(RBTN));
-
-  CO2 = map(CO2, 300, 1500, 0, 9);
-  for (uint8_t i = 0; i < CO2; i++)
+
+  static uint64_t timer0 = 0;
+  timer(timer0, 3000)
   {
-    matrix.set(15, i, mHEX(0x0aa100));
+    timer0 = millis();
+    uint16_t CO2 = co2.getPPM();
+    Serial.print(CO2);
+    Serial.print(" ");
+    Serial.print(digitalRead(LBTN));
+    Serial.print(" ");
+    Serial.println(digitalRead(RBTN));
+
+    CO2 = map(CO2, 300, 1500, 0, 9);
+    for (uint8_t i = 0; i < 9; i++)
+    {
+      matrix.set(matrix.getPixNumber(15, i), mHEX(0));
+    }
+    for (uint8_t i = 0; i < CO2; i++)
+    {
+      matrix.set(15, i, mHEX(0x0aa100));
+    }
   }
-  //matrix.fill(mHEX(0x9aa100));
+
+  tb.render();
   matrix.show();
-  delay(3000);
 }
diff --git a/Dashboard/font.h b/Dashboard/font.h
index b8d70a63c589753e44cf6b8799f00b65da30a54f..da2cf0c2162022c20c3aef7831b28c9c2c052534 100644
--- a/Dashboard/font.h
+++ b/Dashboard/font.h
@@ -255,7 +255,6 @@ const uint8_t* const font[] /*PROGMEM*/ =   {   font_notdef, //     NONE    NONE
                                                 
                                                 // Russian QWERTY-ЙЦУКЕН
                                                 #ifdef LANG_RU_RU
-                                                font_notdef, //     NONE    NONE    1
                                                 font_space, //              32      1
                                                 font_exclamation, //!       33      1
                                                 font_ru_ru_Ae, //   Э       34      1
@@ -292,7 +291,7 @@ const uint8_t* const font[] /*PROGMEM*/ =   {   font_notdef, //     NONE    NONE
                                                 font_ru_ru_F, //    Ф       65      1
                                                 font_ru_ru_I, //    И       66      1
                                                 font_C, //          С       67      1
-                                                font_ru_ru_V, //    Ð’       68      1
+                                                font_B, //          Ð’       68      1
                                                 font_ru_ru_U, //    У       69      1
                                                 font_A, //          А       70      1
                                                 font_ru_ru_P, //    П       71      1
diff --git a/Dashboard/textbox.h b/Dashboard/textbox.h
index 10438c9e46cb4074c674ffe958c16e57ee1844eb..661964f7d3b6486d1fe2543bd2612e3f917e8785 100644
--- a/Dashboard/textbox.h
+++ b/Dashboard/textbox.h
@@ -1,136 +1,234 @@
-#pragma once
-
-#define TB_DISABLED 0
-#define TB_STATIC 1
-#define TB_REPEAT 2
-#define TB_LOOP 3
-#define TB_LOOP_WITH_DELAY 4
-#define TB_BOUNCE 5
-
-class textbox
-{
-private:
-    /* data */
-    uint8_t x;
-    uint8_t y;
-    uint8_t w;
-    uint8_t mode;
-    uint8_t speed;
-    uint16_t delay;
-    uint16_t offset;
-    char text[64];
-    uint8_t letter[8];
-    uint64_t lang;
-    void getLetter(char c);
-public:
-    textbox(void);
-    void setup(char _text[], uint8_t _mode, uint8_t _x, uint8_t _y, uint8_t _w, uint8_t _speed = 0, uint16_t _delay = 0);
-    void render(void);
-    void disable(void);
-};
-
-textbox::textbox(void)
-{
-    x = 0;
-    y = 0;
-    w = 0;
-    mode = 0;
-    speed = 0;
-    delay = 0;
-    memset(text, NULL, 64 * sizeof(char));
-    lang = 0;
-}
-
-void textbox::setup(char _text[], uint8_t _mode, uint8_t _x, uint8_t _y, uint8_t _w, uint8_t _speed = 0, uint16_t _delay = 0)
-{
-    memset(text, NULL, 64 * sizeof(char));
-    strcpy(text, _text);
-    mode = _mode;
-    x = _x;
-    y = _y;
-    w = _w;
-    offset = 0;
-    switch(mode)
-    {
-        case TB_LOOP:
-            delay = 0;
-        goto NO_DELAY;
-        case TB_REPEAT:
-        case TB_LOOP_WITH_DELAY:
-        case TB_BOUNCE:
-            delay = _delay;
-        NO_DELAY:
-            speed = _speed;
-        break;
-        case TB_DISABLED:
-        case TB_STATIC:
-        default:
-            speed = 0;
-            delay = 0;
-        break;
-    }
-    render();
-}
-
-void textbox::render(void)
-{
-    if(mode == TB_DISABLED) return;
-    uint8_t index = 0;
-    uint8_t position = 0;
-    while(position < 16 && index < strlen(text))
-    {
-        getLetter(text[index]);
-        uint8_t y = letter[1];
-        uint8_t x = 0;
-        uint8_t maxX = letter[0];
-        for(uint8_t i = 0; i < letter[2]; i++)
-        {
-            for(int8_t j = 7; j >= 0; j--)
-            {
-                //char sprf[25];
-                uint8_t state = bitRead(letter[i + 3], j);
-                //sprintf(sprf, "%d %d %d %d %d %d %d\n", index, letter[0], letter[1], letter[2], i, j, state);
-                //Serial.print(sprf);
-                if(state) matrix.set(x + position, 8 - y, mHSVfast((i + j + 1) * 10, 255, 255));
-                // matrix.show();
-                // volatile int val = 666;
-                // for(volatile int v = 0; v < 5000; v++)
-                // {
-                //     val = sin(val);
-                // }
-                x++;
-                if(x >= maxX)
-                {
-                    x = 0; y++;
-                }
-                if(y > 6) goto BREAKFORS;
-            }
-        }
-        BREAKFORS:
-        position += maxX + 1;
-        index++;
-    }
-    
-}
-
-void textbox::disable(void)
-{
-    setup("", TB_DISABLED, 0, 0, 0);
-}
-
-void textbox::getLetter(char c)
-{
-    memset(letter, 0, 8 * sizeof(uint8_t));
-    uint8_t index;
-    uint8_t ctoi = (uint8_t)c;
-    if(ctoi >= 32 && ctoi <= 126) index = ctoi - 31;
-    else index = 0;
-    uint8_t readed = pgm_read_byte(font[index]);
-    letter[0] = readed / 49 + 1;    // width
-    letter[1] = readed % 7;     // offset
-    letter[2] = readed / 7 % 7; // bytes
-    for(uint8_t i = 0; i < letter[2]; i++)
-    {
-        letter[i + 3] = pgm_read_byte(font[index] + (i + 1) * sizeof(uint8_t));
-    }
+#pragma once
+
+#include "font.h"
+
+enum TB_MODES
+{
+    TB_DISABLED,
+    TB_STATIC,
+    TB_REPEAT,
+    TB_LOOP,
+    TB_LOOP_WITH_DELAY,
+    TB_BOUNCE,
+};
+
+class textbox
+{
+private:
+    /* data */
+    uint8_t cord_x;
+    uint8_t cord_y;
+    uint8_t w;
+    uint8_t mode;
+    uint16_t speed;
+    uint16_t delay;
+    int16_t offset;
+    bool direction;
+    bool state;
+    mData color;
+    char text[64];
+    uint8_t textlen;
+    uint16_t textwidth;
+    uint8_t letter[8];
+    uint64_t langMask;
+    bool native;
+    void getLetter(uint8_t i, bool skipBitmap = 0);
+    uint64_t timer0;
+public:
+    textbox(void);
+    void setup(     char _text[], uint64_t _langMask,
+                    mData _color,
+                    uint8_t _mode,
+                    uint8_t _x, uint8_t _y, uint8_t _w,
+                    uint8_t _reciprocal_speed = 0, uint16_t _delay = 0);
+    void render(void);
+    void disable(void);
+};
+
+textbox::textbox(void)
+{
+    cord_x = 0;
+    cord_y = 0;
+    w = 0;
+    mode = 0;
+    speed = 0;
+    delay = 0;
+    memset(text, NULL, 64 * sizeof(char));
+    langMask = 0;
+    // If 96th symbol is font_null there is no native language except for English
+    native = pgm_read_byte(font[96]) != 0;
+    uint8_t debugByte = pgm_read_byte(font[0]);
+    Serial.println(debugByte);
+    uint8_t debugCounter = 1;
+    while(debugByte != 0)
+    {
+        Serial.println(debugByte);
+        debugByte = pgm_read_byte(font[debugCounter]);
+        debugCounter++;
+    }
+}
+
+void textbox::setup(char _text[], uint64_t _langMask,
+                    mData _color,
+                    uint8_t _mode,
+                    uint8_t _x, uint8_t _y, uint8_t _w,
+                    uint8_t _reciprocal_speed = 0, uint16_t _delay = 0)
+{
+    memset(text, NULL, 64 * sizeof(char));
+    strcpy(text, _text);
+    textlen = strlen(text);
+    langMask = _langMask;
+    textwidth = 0;
+    for(uint16_t i = 0; i < textlen; i++)
+    {
+        getLetter(i, true);
+        textwidth += letter[0] + 1;
+    }
+    textwidth--;
+    color = _color;
+    mode = _mode;
+    cord_x = _x;
+    cord_y = _y;
+    w = _w;
+    offset = 0;
+    switch(mode)
+    {
+        case TB_LOOP:
+            delay = 0;
+        goto NO_DELAY;
+        case TB_REPEAT:
+        case TB_LOOP_WITH_DELAY:
+        case TB_BOUNCE:
+            delay = _delay;
+        NO_DELAY:
+            speed = _reciprocal_speed;
+        break;
+        case TB_DISABLED:
+        case TB_STATIC:
+        default:
+            speed = 0;
+            delay = 0;
+        break;
+    }
+    timer0 = 0;
+    render();
+}
+
+void textbox::render(void)
+{
+    // Do nothing if disabled
+    if(mode != TB_DISABLED) 
+    {
+        if(timer0 == 0) 
+        {
+            offset = 0 + (mode == TB_REPEAT) * w;
+            direction = 0;
+            timer0 = millis();
+        }
+        else
+        {
+            if((millis() - timer0) > (((mode != TB_LOOP) && !state) ? delay : speed))
+            {
+                state = 1;
+                timer0 = millis();
+                if(mode == TB_BOUNCE)
+                {
+                    if((!direction && offset == -textwidth + w) || (direction && offset == 0))
+                    {
+                        direction = !direction;
+                        state = 0;
+                    }
+                    else offset += direction ? 1 : -1;
+                }
+                else
+                {
+                    offset += -1;
+                    if(offset < (-textwidth - 2 * (mode == TB_LOOP || mode == TB_LOOP_WITH_DELAY) + w * (mode == TB_REPEAT)))
+                    {
+                        offset = 0 + (mode == TB_REPEAT) * w;
+                        state = 0;
+                    }
+                }
+
+            }
+            else return;
+        }
+    }
+    else return;
+    // Clear spot
+    for(uint8_t i = cord_x; (i < cord_x + w) && (i < WIDTH); i++)
+    for(uint8_t j = cord_y; (j < cord_y + 7) && (j < HEIGHT);  j++)
+        matrix.set(i, j, mBlack);
+    // Init letter counter, start X and Y
+    uint8_t index = 0;
+    int16_t positionX = cord_x + offset;
+    int16_t positionY = cord_y;
+    // Draw while in bounds
+    while((positionX < cord_x + w) && (index < textlen))
+    {
+        // Recieve letter
+        getLetter(index);
+        // Relative X and Y
+        uint8_t x = 0;
+        uint8_t y = letter[1];
+        // X bound
+        uint8_t maxX = letter[0];
+        // Run thougth bytes
+        for(uint8_t i = 0; (i < letter[2]) && (y < 7); i++)
+        {
+            // Run througth bits
+            for(int8_t j = 7; (j >= 0) && (y < 7); j--)
+            {
+                // Set pixel
+                bool state = bitRead(letter[i + 3], j);
+                int16_t mx = x + positionX;
+                int16_t my = HEIGHT - 1 - y - positionY;
+                if(state && mx >= cord_x && mx < cord_x + w && my >= cord_y && my < cord_y + 7)
+                    matrix.set(mx, my, color);
+                // Next pixel
+                x++;
+                if(x >= maxX)
+                {
+                    x = 0; y++;
+                }
+            }
+        }
+        // Shift X and index
+        positionX += maxX + 1;
+        index++;
+    }
+    
+}
+
+void textbox::disable(void)
+{
+    setup("", 0, 0, TB_DISABLED, 0, 0, 0);
+}
+
+void textbox::getLetter(uint8_t i, bool skipBitmap = 0)
+{
+    // Letter and it's position in ASCII table
+    char c = text[i];
+    uint8_t ctoi = (uint8_t)c;
+    // Language (0 - English, 1 - Native)
+    bool lang = bitRead(langMask, i);
+    // Clear place for letter in RAM
+    memset(letter, 0, 8 * sizeof(uint8_t));
+    uint8_t index;
+    // Translate ASCII index to local
+    if(ctoi >= 32 && ctoi <= 126) index = ctoi - 31 + 95 * lang * native;
+    else index = 0;
+    // Read properties from semeric number
+    uint8_t readed = pgm_read_byte(font[index]);
+    letter[0] = readed / 49 + 1;    // width
+    letter[1] = readed % 7;         // offset
+    letter[2] = readed / 7 % 7;     // bytes
+    // Read bitmaps
+    if(!skipBitmap)
+    {
+        for(uint8_t i = 0; i < letter[2]; i++)
+        {
+            letter[i + 3] = pgm_read_byte(font[index] + (i + 1) * sizeof(uint8_t));
+        }
+    }
 }
\ No newline at end of file