whole_func_string: function Colog() {
  
      /**
       * Always create new object
       */
      if ((this instanceof Colog) === false) {
          return new Colog();
      }
  
      /**
       * Self
       * @type Colog
       */
      var self                        = this;
  
      /**
       * This is base for all effects. Replace %d [ or use util.format() ] with code number
       * @type {string}
       */
      var base                        = '\x1B[%dm';
  
      /**
       * This will reset all effects
       * @type {number}
       */
      var reset                       = 0;
  
      /**
       * Add 60 to color number to bright it out
       * @type {number}
       */
      var colorLightValueChange       = 60;
  
      /**
       * Last command executed
       */
      var lastCommand                 = 'log';
  
      /**
       * Last line printed in console
       * @type {number}
       */
      var lastLineLength              = 0;
  
      /**
       * Available colors
       * @type {{black: Array, red: Array, green: Array, yellow: Array, blue: Array, magenta: Array, cyan: Array, white: Array}}
       */
      var color = {
          'black':            [30, 39],
          'red':              [31, 39],
          'green':            [32, 39],
          'yellow':           [33, 39],
          'blue':             [34, 39],
          'magenta':          [35, 39],
          'cyan':             [36, 39],
          'white':            [37, 39]
      };
  
      /**
       * Available backgrounds
       * @type {{black: Array, red: Array, green: Array, yellow: Array, blue: Array, magenta: Array, cyan: Array, white: Array}}
       */
      var background = {
          'black':        [40, 49],
          'red':          [41, 49],
          'green':        [42, 49],
          'yellow':       [43, 49],
          'blue':         [44, 49],
          'magenta':      [45, 49],
          'cyan':         [46, 49],
          'white':        [47, 49]
      };
  
      /**
       * Available effects
       * @type {{bold: Array, underline: Array, strike: Array, inverse: Array}}
       */
      var effect = {
          'b':            [1, 22],
          'u':            [4, 24],
          'i':            [7, 27],
          's':            [9, 29],
          'bold':         [1, 22],
          'underline':    [4, 24],
          'inverse':      [7, 27],
          'strike':       [9, 29]
      };
  
      /**
       * Progress bar values
       * @type {Array}
       */
      var progress = [
          0,
          100
      ];
  
      /**
       * Default progress bar values
       * @type {{progress: {zero: string, one: string, left: string, right: string, showPostfix: boolean, prefixText: string}}}
       */
      var defaults = {
          progress: {
              zero: '░',
              one: '▓',
              length: 40,
              sufix: ' ~ %d%% (%s / %s)',
              effects: ['colorYellow'],
              description: ''
          }
      };
  
      var beSilent = false;
  
      var consoleWidth    = 100;
      if (process.stdout.isTTY) {
          consoleWidth = process.stdout.getWindowSize()[0];
          process.stdout.on('resize', function () {
              consoleWidth = process.stdout.getWindowSize()[0];
          });
      }
  
  
      /**
       * Create effect from code. For colors set lightColor true to bright them up
       * @param code
       * @param lightColor
       * @returns {*}
       */
      function use(code, lightColor) {
          return util.format(base, (lightColor === true) ? code + colorLightValueChange : code);
      }
  
  
      /**
       * Apply effect on both side of the string
       * @param message
       * @param effect
       * @param lightColor
       * @returns {string}
       */
      function text(message, effect, lightColor) {
          return [
              use(effect[0], lightColor),
              String(message),
              use(effect[1], lightColor)
          ].join('');
      }
  
  
      /**
       * Clear line until last new line white character
       */
      function clearLine() {
          if (process.stdout.clearLine) {
              process.stdout.clearLine();
              process.stdout.cursorTo(0);
          } else {
              var str = '\r',
                  i = 0;
              for (i = 0; i < lastLineLength; i++) {
                  str += ' ';
              }
              process.stdout.write(str);
          }
          lastLineLength = 0;
  
          return self;
      }
  
  
      this.silent = function (isSilent) {
          beSilent = (isSilent) ? true : false;
      }
  
  
      this.getWidth = function () {
          return consoleWidth;
      };
  
  
      /**
       * Configure progress bar
       * @param zero - character for 0 status
       * @param one - character for 1 status
       * @param left - character on the left of the bar
       * @param right - character on the right of the bar
       * @param showPostfix - show postfix after bar [like: (19 of 20)]
       * @param prefixText - show prefix text before bar
       * @returns {*}
       */
      this.configureProgress = function (zero, one, length, effects) {
          length = Math.abs(parseInt(length, 10));
  
          defaults.progress.zero = (zero !== undefined) ? zero : defaults.progress.zero;
          defaults.progress.one = (one !== undefined) ? one : defaults.progress.one;
          defaults.progress.length = (length > 0) ? length : defaults.progress.length;
          defaults.progress.effects = (effects instanceof Array) ? effects : defaults.progress.effects;
  
          return this;
      };
  
  
      this.setProgressDescription = function (text) {
          text = String(text);
          defaults.progress.description = text;
  
          return this;
      };
  
  
      /**
       * Generate progress bar. Don't pass arguments to increase progress bar value
       * @param int - each int will add one more progress bar
       */
      this.progress = function (minOrChange, max, effects, returnString) {
          if (beSilent) {
              return this;
          }
          if (lastCommand === 'progress') {
              clearLine();
          }
  
          var i = 0,
              prc = 0,
              fullBarsToDraw = 0,
              emptyBarsToDraw = 0,
              totalBars = defaults.progress.length;
  
          // Prepare values
          minOrChange = Math.abs(parseInt(minOrChange, 10));
          max = Math.abs(parseInt(max, 10));
          if (isNaN(minOrChange)) {
              minOrChange = 0;
          }
          if (isNaN(max)) {
              max = 0;
          }
  
          if (max > 0) {
              // create new progress bar
              progress[0] = minOrChange;
              progress[1] = max;
          } else {
              if (minOrChange === 0) {
                  minOrChange = 1;
              }
              // add to current progress bar
              progress[0] += minOrChange;
          }
  
          minOrChange     = progress[0];
          max             = progress[1];
          if (minOrChange > max) {
              minOrChange = max;
          }
  
          if (max === 0) {
              prc = 100;
          } else {
              prc = Math.floor((minOrChange / max) * 100);
          }
          fullBarsToDraw = Math.floor((prc / 100) * totalBars);
          emptyBarsToDraw = totalBars - fullBarsToDraw;
  
          var str = '\r';
  
          if (returnString !== true) {
              clearLine();
          }
  
          for (i = 0; i < fullBarsToDraw; i++) {
              str = str + defaults.progress.one;
          }
          for (i = 0; i < emptyBarsToDraw; i++) {
              str = str + defaults.progress.zero;
          }
          str = str + this.getFormat(defaults.progress.sufix, prc, minOrChange, max);
  
          if (effects instanceof Array) {
              str = this.apply(str, effects);
          } else {
              str = this.apply(str, defaults.progress.effects);
          }
  
          if (defaults.progress.description.length) {
              str = str + ' ' + this.getFormat(defaults.progress.description);
          }
  
          //str = str.substr(0, consoleWidth);
  
          if (returnString === true) {
              lastCommand = 'progress';
              return str;
          }
  
          this.write(str);
          lastCommand = 'progress';
  
          return this;
      };
  
  
      /**
       * Return "reset all effects" code
       * @returns {*}
       */
      this.reset = function () {
          return use(reset);
      };
  
  
      /**
       * Short alias for bold
       * @param message
       * @returns {string}
       */
      this.b = function (message) {
          return text(message, effect.bold);
      };
  
  
      /**
       * Short alias for underline
       * @param message
       * @returns {string}
       */
      this.u = function (message) {
          return text(message, effect.underline);
      };
  
  
      /**
       * Short alias for strike
       * @param message
       * @returns {string}
       */
      this.s = function (message) {
          return text(message, effect.strike);
      };
  
  
      /**
       * Short alias for inverse
       * @param message
       * @returns {string}
       */
      this.i = function (message) {
          return text(message, effect.inverse);
      };
  
  
      /**
       * Make given text bold
       * @param message
       * @returns {string}
       */
      this.bold = function (message) {
          return this.b(message);
      };
  
  
      /**
       * Apply underline to text
       * @param message
       * @returns {string}
       */
      this.underline = function (message) {
          return this.u(message);
      };
  
  
      /**
       * Draw line on the text
       * @param message
       * @returns {string}
       */
      this.strike = function (message) {
          return this.s(message);
      };
  
  
      /**
       * Switch foreground and background colors
       * @param message
       * @returns {string}
       */
      this.inverse = function (message) {
          return this.i(message);
      };
  
  
      /**
       * Apply color on text by name
       * @param message
       * @param name
       * @param light
       * @returns {string}
       */
      this.color = function (message, name, light) {
          if (color[name] === undefined) {
              var colors = [],
                  c;
  
              for (c in color) {
                  if (color.hasOwnProperty(c)) {
                      colors.push(c);
                  }
              }
              throw new Error('Undefined color. Use: ' + colors.join(', '));
          }
          return text(message, color[name], light);
      };
  
  
      /**
       * Apply black color
       * @param message
       * @param light
       * @returns {string}
       */
      this.black = function (message, light) {
          return text(message, color.black, light);
      };
  
  
      /**
       * Apply red color
       * @param message
       * @param light
       * @returns {string}
       */
      this.red = function (message, light) {
          return text(message, color.red, light);
      };
  
  
      /**
       * Apply green color
       * @param message
       * @param light
       * @returns {string}
       */
      this.green = function (message, light) {
          return text(message, color.green, light);
      };
  
  
      /**
       * Apply yellow color
       * @param message
       * @param light
       * @returns {string}
       */
      this.yellow = function (message, light) {
          return text(message, color.yellow, light);
      };
  
  
      /**
       * Apply blue color
       * @param message
       * @param light
       * @returns {string}
       */
      this.blue = function (message, light) {
          return text(message, color.blue, light);
      };
  
  
      /**
       * Apply magenta color
       * @param message
       * @param light
       * @returns {string}
       */
      this.magenta = function (message, light) {
          return text(message, color.magenta, light);
      };
  
  
      /**
       * Apply cyan color
       * @param message
       * @param light
       * @returns {string}
       */
      this.cyan = function (message, light) {
          return text(message, color.cyan, light);
      };
  
  
      /**
       * Apply white color
       * @param message
       * @param light
       * @returns {string}
       */
      this.white = function (message, light) {
          return text(message, color.white, light);
      };
  
  
      /**
       * Apply black color
       * @param message
       * @param light
       * @returns {string}
       */
      this.colorBlack = function (message, light) {
          return this.black(message, light);
      };
  
  
      /**
       * Apply red color
       * @param message
       * @param light
       * @returns {string}
       */
      this.colorRed = function (message, light) {
          return this.red(message, light);
      };
  
  
      /**
       * Apply green color
       * @param message
       * @param light
       * @returns {string}
       */
      this.colorGreen = function (message, light) {
          return this.green(message, light);
      };
  
  
      /**
       * Apply yellow color
       * @param message
       * @param light
       * @returns {string}
       */
      this.colorYellow = function (message, light) {
          return this.yellow(message, light);
      };
  
  
      /**
       * Apply blue color
       * @param message
       * @param light
       * @returns {string}
       */
      this.colorBlue = function (message, light) {
          return this.blue(message, light);
      };
  
  
      /**
       * Apply magenta color
       * @param message
       * @param light
       * @returns {string}
       */
      this.colorMagenta = function (message, light) {
          return this.magenta(message, light);
      };
  
  
      /**
       * Apply cyan color
       * @param message
       * @param light
       * @returns {string}
       */
      this.colorCyan = function (message, light) {
          return this.cyan(message, light);
      };
  
  
      /**
       * Apply white color
       * @param message
       * @param light
       * @returns {string}
       */
      this.colorWhite = function (message, light) {
          return this.white(message, light);
      };
  
  
      /**
       * Apply background color by name
       * @param message
       * @param name
       * @param light
       * @returns {string}
       */
      this.background = function (message, name, light) {
          if (background[name] === undefined) {
              var backgrounds = [],
                  b;
  
              for (b in background) {
                  if (background.hasOwnProperty(b)) {
                      backgrounds.push(b);
                  }
              }
              throw new Error('Undefined color. Use: ' + backgrounds.join(', '));
          }
          return text(message, background[name], light);
      };
  
  
      /**
       * Apply black background
       * @param message
       * @param light
       * @returns {string}
       */
      this.bgBlack = function (message, light) {
          return text(message, background.black, light);
      };
  
  
      /**
       * Apply red background
       * @param message
       * @param light
       * @returns {string}
       */
      this.bgRed = function (message, light) {
          return text(message, background.red, light);
      };
  
  
      /**
       * Apply green background
       * @param message
       * @param light
       * @returns {string}
       */
      this.bgGreen = function (message, light) {
          return text(message, background.green, light);
      };
  
  
      /**
       * Apply yellow background
       * @param message
       * @param light
       * @returns {string}
       */
      this.bgYellow = function (message, light) {
          return text(message, background.yellow, light);
      };
  
  
      /**
       * Apply blue background
       * @param message
       * @param light
       * @returns {string}
       */
      this.bgBlue = function (message, light) {
          return text(message, background.blue, light);
      };
  
  
      /**
       * Apply magenta background
       * @param message
       * @param light
       * @returns {string}
       */
      this.bgMagenta = function (message, light) {
          return text(message, background.magenta, light);
      };
  
  
      /**
       * Apply cyan background
       * @param message
       * @param light
       * @returns {string}
       */
      this.bgCyan = function (message, light) {
          return text(message, background.cyan, light);
      };
  
  
      /**
       * Apply white background
       * @param message
       * @param light
       * @returns {string}
       */
      this.bgWhite = function (message, light) {
          return text(message, background.white, light);
      };
  
  
      /**
       * Apply black background
       * @param message
       * @param light
       * @returns {string}
       */
      this.backgroundBlack = function (message, light) {
          return this.bgBlack(message, light);
      };
  
  
      /**
       * Apply red background
       * @param message
       * @param light
       * @returns {string}
       */
      this.backgroundRed = function (message, light) {
          return this.bgRed(message, light);
      };
  
  
      /**
       * Apply green background
       * @param message
       * @param light
       * @returns {string}
       */
      this.backgroundGreen = function (message, light) {
          return this.bgGreen(message, light);
      };
  
  
      /**
       * Apply yellow background
       * @param message
       * @param light
       * @returns {string}
       */
      this.backgroundYellow = function (message, light) {
          return this.bgYellow(message, light);
      };
  
  
      /**
       * Apply blue background
       * @param message
       * @param light
       * @returns {string}
       */
      this.backgroundBlue = function (message, light) {
          return this.bgBlue(message, light);
      };
  
  
      /**
       * Apply magenta background
       * @param message
       * @param light
       * @returns {string}
       */
      this.backgroundMagenta = function (message, light) {
          return this.bgMagenta(message, light);
      };
  
  
      /**
       * Apply cyan background
       * @param message
       * @param light
       * @returns {string}
       */
      this.backgroundCyan = function (message, light) {
          return this.bgCyan(message, light);
      };
  
  
      /**
       * Apply white background
       * @param message
       * @param light
       * @returns {string}
       */
      this.backgroundWhite = function (message, light) {
          return this.bgWhite(message, light);
      };
  
  
      /**
       * Alias for console.log
       * @param message
       * @param light
       * @returns {string}
       */
      this.log = function (message) {
          if (beSilent) {
              return this;
          }
          if (lastCommand === 'progress' || lastCommand === 'write') {
              this.write('\n');
          }
          lastCommand = 'log';
          console.log(message);
          message += '';
          lastLineLength = message.length;
  
          return this;
      };
  
  
      /**
       * Write to stdout
       * @param message
       * @param light
       * @returns {string}
       */
      this.write = function (message) {
          if (beSilent) {
              return this;
          }
          lastCommand = 'write';
          process.stdout.write(message);
  
          message = String(message);
          if (lastCommand === 'write') {
              lastLineLength += message.length;
          } else {
              lastLineLength = message.length;
          }
  
          return this;
      };
  
  
      /**
       * Log with bold white text
       * @param message
       * @returns {string}
       */
      this.info = function (message, returnString) {
          var str = this.apply(message, ['bold', 'white']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold green text
       * @param message
       * @returns {string}
       */
      this.success = function (message, returnString) {
          var str = this.apply(message, ['bold', 'green']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold yellow text
       * @param message
       * @returns {string}
       */
      this.warning = function (message, returnString) {
          var str = this.apply(message, ['bold', 'yellow']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold red text
       * @param message
       * @returns {string}
       */
      this.error = function (message, returnString) {
          var str = this.apply(message, ['bold', 'red']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold cyan text
       * @param message
       * @returns {string}
       */
      this.question = function (message, returnString) {
          var str = this.apply(message, ['bold', 'cyan']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold magenta text
       * @param message
       * @returns {string}
       */
      this.answer = function (message, returnString) {
          var str = this.apply(message, ['bold', 'magenta']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold black text and white background
       * @param message
       * @returns {string}
       */
      this.headerInfo = function (message, returnString) {
          var str = this.apply(message, ['bold', 'black', 'bgWhite']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold white text and green background
       * @param message
       * @returns {string}
       */
      this.headerSuccess = function (message, returnString) {
          var str = this.apply(message, ['bold', 'white', 'bgGreen']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold black text and yellow background
       * @param message
       * @returns {string}
       */
      this.headerWarning = function (message, returnString) {
          var str = this.apply(message, ['bold', 'black', 'bgYellow']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold white text and red background
       * @param message
       * @returns {string}
       */
      this.headerError = function (message, returnString) {
          var str = this.apply(message, ['bold', 'white', 'bgRed']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold white text and cyan background
       * @param message
       * @returns {string}
       */
      this.headerQuestion = function (message, returnString) {
          var str = this.apply(message, ['bold', 'white', 'bgCyan']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold white text and magenta background
       * @param message
       * @returns {string}
       */
      this.headerAnswer = function (message, returnString) {
          var str = this.apply(message, ['bold', 'white', 'bgMagenta']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Apply effects to message
       * @param message
       * @param effects
       * @returns {*}
       */
      this.apply = function (message, effects) {
          if ((effects instanceof Array) === false) {
              throw new Error('Effects must be an array');
          }
          if (!effects.length) {
              return message;
          }
          var i = 0,
              limit = effects.length;
  
          for (i = 0; i < limit; i++) {
              if (this.hasOwnProperty(effects[i]) && typeof this[effects[i]] === 'function') {
                  message = this[effects[i]](message);
              } else {
                  var allEffects = [],
                      e = '';
  
                  for (e in this) {
                      if (this.hasOwnProperty(e) && ((e.indexOf('color') === 0 && e !== 'color') || (e.indexOf('background') === 0 && e !== 'background') || effect[e] !== undefined)) {
                          allEffects.push(e);
                      }
                  }
                  throw new Error(util.format('Invalid effect "%s", you can use "%s"', effects[i], allEffects.join('", "')));
              }
          }
  
          return message;
      };
  
  
      /**
       * Alias for console.log that allow you to apply effects to dump
       * @param variable
       * @param effects
       * @returns {*}
       */
      this.dump = function (variable, effects) {
          if (beSilent) {
              return this;
          }
          if (!(effects instanceof Array)) {
              effects = [];
          }
  
          effects = this.apply('\n', effects);
          effects = effects.split('\n');
          this.write(effects[0]);
          this.write(util.inspect((typeof variable === 'function') ? variable.toString() : variable));
          this.write(effects[1] + '\n');
  
          return this;
      };
  
  
      /**
       * Get list of available effects
       * @returns {Array}
       */
      this.getAllEffects = function () {
          var allEffects = [],
              e = '';
  
          for (e in this) {
              if (this.hasOwnProperty(e) && ((e.indexOf('color') === 0 && e !== 'color') || ((e.indexOf('background') === 0 || e.indexOf('bg') === 0) && e !== 'background') || effect[e] !== undefined || color[e] !== undefined)) {
                  allEffects.push(e);
              }
          }
  
          return allEffects;
      };
  
  
      /**
       * Log message with xml tags using effects name. For example <b>text</b>
       * @param message
       * @param log
       * @returns {*}
       */
      this.format = function () {
          if (beSilent) {
              return this;
          }
          this.log(this.getFormat.apply(this.getFormat, arguments));
          return this;
      };
  
  
      /**
       * Log message with xml tags using effects name. For example <b>text</b>
       * @param message
       * @param log
       * @returns {*}
       */
      this.getFormat = function () {
          var message = arguments.length > 0 ? arguments[0] : '';
          message = util.format.apply(util.format, arguments);
          var all = self.getAllEffects(),
              i = 0,
              limit = all.length,
              applyCallback = function (match, content) {
                  return self.apply(content, [all[i]]);
              };
          for (i = 0; i < limit; i++) {
              message = message.replace(new RegExp(util.format('<%s>([\\s\\S]*?)<\/%s>', all[i], all[i]), 'g'), applyCallback);
          }
  
          return message;
      };
  
  
      this.stripFormat = function () {
          var message = arguments.length > 0 ? arguments[0] : '';
          message = util.format.apply(util.format, arguments);
  
          var all = this.getAllEffects(),
              i = 0,
              limit = all.length,
              applyCallback = function (match, content) {
                  return content;
              };
          for (i = 0; i < limit; i++) {
              message = message.replace(new RegExp(util.format('<%s>([\\s\\S]*?)<\/%s>', all[i], all[i]), 'g'), applyCallback);
          }
  
          return message;
      };
  
  
      /**
       * Print new line
       * @returns {*}
       */
      this.nl = function () {
          this.write('\n');
          return this;
      };
  
  
      /**
       * Alias for nl
       * @type {*}
       */
      this.newLine = this.nl;
  
  
      this.status = function (text, status, textEffects, statusEffects, returnString) {
          if (beSilent) {
              return this;
          }
          if (text instanceof Object) {
              text = text.toString();
          }
          if (status instanceof Object) {
              status = status.toString();
          }
  
          var textLen = this.stripFormat(text).length,
              statusLen = this.stripFormat(status).length,
              emptyLength = consoleWidth - (textLen + statusLen),
              emptyString = '',
              i = 0,
              str = '';
  
          text = this.getFormat(text);
          status = this.getFormat(status);
          if (textEffects instanceof Array) {
              text = this.apply(text, textEffects);
          }
          if (statusEffects instanceof Array) {
              status = this.apply(status, statusEffects);
          }
  
          if (emptyLength < 2) {
              emptyLength = 2;
          }
          emptyLength -= 1;
  
          for (i = 0; i < emptyLength; i++) {
              emptyString = emptyString + ' ';
          }
  
          str = text + emptyString + status;
  
          if (returnString === true) {
              return str;
          }
          this.log(str);
          return this;
      };
  }
func_code_string: function Colog() {
  
      /**
       * Always create new object
       */
      if ((this instanceof Colog) === false) {
          return new Colog();
      }
  
      /**
       * Self
       * @type Colog
       */
      var self                        = this;
  
      /**
       * This is base for all effects. Replace %d [ or use util.format() ] with code number
       * @type {string}
       */
      var base                        = '\x1B[%dm';
  
      /**
       * This will reset all effects
       * @type {number}
       */
      var reset                       = 0;
  
      /**
       * Add 60 to color number to bright it out
       * @type {number}
       */
      var colorLightValueChange       = 60;
  
      /**
       * Last command executed
       */
      var lastCommand                 = 'log';
  
      /**
       * Last line printed in console
       * @type {number}
       */
      var lastLineLength              = 0;
  
      /**
       * Available colors
       * @type {{black: Array, red: Array, green: Array, yellow: Array, blue: Array, magenta: Array, cyan: Array, white: Array}}
       */
      var color = {
          'black':            [30, 39],
          'red':              [31, 39],
          'green':            [32, 39],
          'yellow':           [33, 39],
          'blue':             [34, 39],
          'magenta':          [35, 39],
          'cyan':             [36, 39],
          'white':            [37, 39]
      };
  
      /**
       * Available backgrounds
       * @type {{black: Array, red: Array, green: Array, yellow: Array, blue: Array, magenta: Array, cyan: Array, white: Array}}
       */
      var background = {
          'black':        [40, 49],
          'red':          [41, 49],
          'green':        [42, 49],
          'yellow':       [43, 49],
          'blue':         [44, 49],
          'magenta':      [45, 49],
          'cyan':         [46, 49],
          'white':        [47, 49]
      };
  
      /**
       * Available effects
       * @type {{bold: Array, underline: Array, strike: Array, inverse: Array}}
       */
      var effect = {
          'b':            [1, 22],
          'u':            [4, 24],
          'i':            [7, 27],
          's':            [9, 29],
          'bold':         [1, 22],
          'underline':    [4, 24],
          'inverse':      [7, 27],
          'strike':       [9, 29]
      };
  
      /**
       * Progress bar values
       * @type {Array}
       */
      var progress = [
          0,
          100
      ];
  
      /**
       * Default progress bar values
       * @type {{progress: {zero: string, one: string, left: string, right: string, showPostfix: boolean, prefixText: string}}}
       */
      var defaults = {
          progress: {
              zero: '░',
              one: '▓',
              length: 40,
              sufix: ' ~ %d%% (%s / %s)',
              effects: ['colorYellow'],
              description: ''
          }
      };
  
      var beSilent = false;
  
      var consoleWidth    = 100;
      if (process.stdout.isTTY) {
          consoleWidth = process.stdout.getWindowSize()[0];
          process.stdout.on('resize', function () {
              consoleWidth = process.stdout.getWindowSize()[0];
          });
      }
  
  
      /**
       * Create effect from code. For colors set lightColor true to bright them up
       * @param code
       * @param lightColor
       * @returns {*}
       */
      function use(code, lightColor) {
          return util.format(base, (lightColor === true) ? code + colorLightValueChange : code);
      }
  
  
      /**
       * Apply effect on both side of the string
       * @param message
       * @param effect
       * @param lightColor
       * @returns {string}
       */
      function text(message, effect, lightColor) {
          return [
              use(effect[0], lightColor),
              String(message),
              use(effect[1], lightColor)
          ].join('');
      }
  
  
      /**
       * Clear line until last new line white character
       */
      function clearLine() {
          if (process.stdout.clearLine) {
              process.stdout.clearLine();
              process.stdout.cursorTo(0);
          } else {
              var str = '\r',
                  i = 0;
              for (i = 0; i < lastLineLength; i++) {
                  str += ' ';
              }
              process.stdout.write(str);
          }
          lastLineLength = 0;
  
          return self;
      }
  
  
      this.silent = function (isSilent) {
          beSilent = (isSilent) ? true : false;
      }
  
  
      this.getWidth = function () {
          return consoleWidth;
      };
  
  
      /**
       * Configure progress bar
       * @param zero - character for 0 status
       * @param one - character for 1 status
       * @param left - character on the left of the bar
       * @param right - character on the right of the bar
       * @param showPostfix - show postfix after bar [like: (19 of 20)]
       * @param prefixText - show prefix text before bar
       * @returns {*}
       */
      this.configureProgress = function (zero, one, length, effects) {
          length = Math.abs(parseInt(length, 10));
  
          defaults.progress.zero = (zero !== undefined) ? zero : defaults.progress.zero;
          defaults.progress.one = (one !== undefined) ? one : defaults.progress.one;
          defaults.progress.length = (length > 0) ? length : defaults.progress.length;
          defaults.progress.effects = (effects instanceof Array) ? effects : defaults.progress.effects;
  
          return this;
      };
  
  
      this.setProgressDescription = function (text) {
          text = String(text);
          defaults.progress.description = text;
  
          return this;
      };
  
  
      /**
       * Generate progress bar. Don't pass arguments to increase progress bar value
       * @param int - each int will add one more progress bar
       */
      this.progress = function (minOrChange, max, effects, returnString) {
          if (beSilent) {
              return this;
          }
          if (lastCommand === 'progress') {
              clearLine();
          }
  
          var i = 0,
              prc = 0,
              fullBarsToDraw = 0,
              emptyBarsToDraw = 0,
              totalBars = defaults.progress.length;
  
          // Prepare values
          minOrChange = Math.abs(parseInt(minOrChange, 10));
          max = Math.abs(parseInt(max, 10));
          if (isNaN(minOrChange)) {
              minOrChange = 0;
          }
          if (isNaN(max)) {
              max = 0;
          }
  
          if (max > 0) {
              // create new progress bar
              progress[0] = minOrChange;
              progress[1] = max;
          } else {
              if (minOrChange === 0) {
                  minOrChange = 1;
              }
              // add to current progress bar
              progress[0] += minOrChange;
          }
  
          minOrChange     = progress[0];
          max             = progress[1];
          if (minOrChange > max) {
              minOrChange = max;
          }
  
          if (max === 0) {
              prc = 100;
          } else {
              prc = Math.floor((minOrChange / max) * 100);
          }
          fullBarsToDraw = Math.floor((prc / 100) * totalBars);
          emptyBarsToDraw = totalBars - fullBarsToDraw;
  
          var str = '\r';
  
          if (returnString !== true) {
              clearLine();
          }
  
          for (i = 0; i < fullBarsToDraw; i++) {
              str = str + defaults.progress.one;
          }
          for (i = 0; i < emptyBarsToDraw; i++) {
              str = str + defaults.progress.zero;
          }
          str = str + this.getFormat(defaults.progress.sufix, prc, minOrChange, max);
  
          if (effects instanceof Array) {
              str = this.apply(str, effects);
          } else {
              str = this.apply(str, defaults.progress.effects);
          }
  
          if (defaults.progress.description.length) {
              str = str + ' ' + this.getFormat(defaults.progress.description);
          }
  
          //str = str.substr(0, consoleWidth);
  
          if (returnString === true) {
              lastCommand = 'progress';
              return str;
          }
  
          this.write(str);
          lastCommand = 'progress';
  
          return this;
      };
  
  
      /**
       * Return "reset all effects" code
       * @returns {*}
       */
      this.reset = function () {
          return use(reset);
      };
  
  
      /**
       * Short alias for bold
       * @param message
       * @returns {string}
       */
      this.b = function (message) {
          return text(message, effect.bold);
      };
  
  
      /**
       * Short alias for underline
       * @param message
       * @returns {string}
       */
      this.u = function (message) {
          return text(message, effect.underline);
      };
  
  
      /**
       * Short alias for strike
       * @param message
       * @returns {string}
       */
      this.s = function (message) {
          return text(message, effect.strike);
      };
  
  
      /**
       * Short alias for inverse
       * @param message
       * @returns {string}
       */
      this.i = function (message) {
          return text(message, effect.inverse);
      };
  
  
      /**
       * Make given text bold
       * @param message
       * @returns {string}
       */
      this.bold = function (message) {
          return this.b(message);
      };
  
  
      /**
       * Apply underline to text
       * @param message
       * @returns {string}
       */
      this.underline = function (message) {
          return this.u(message);
      };
  
  
      /**
       * Draw line on the text
       * @param message
       * @returns {string}
       */
      this.strike = function (message) {
          return this.s(message);
      };
  
  
      /**
       * Switch foreground and background colors
       * @param message
       * @returns {string}
       */
      this.inverse = function (message) {
          return this.i(message);
      };
  
  
      /**
       * Apply color on text by name
       * @param message
       * @param name
       * @param light
       * @returns {string}
       */
      this.color = function (message, name, light) {
          if (color[name] === undefined) {
              var colors = [],
                  c;
  
              for (c in color) {
                  if (color.hasOwnProperty(c)) {
                      colors.push(c);
                  }
              }
              throw new Error('Undefined color. Use: ' + colors.join(', '));
          }
          return text(message, color[name], light);
      };
  
  
      /**
       * Apply black color
       * @param message
       * @param light
       * @returns {string}
       */
      this.black = function (message, light) {
          return text(message, color.black, light);
      };
  
  
      /**
       * Apply red color
       * @param message
       * @param light
       * @returns {string}
       */
      this.red = function (message, light) {
          return text(message, color.red, light);
      };
  
  
      /**
       * Apply green color
       * @param message
       * @param light
       * @returns {string}
       */
      this.green = function (message, light) {
          return text(message, color.green, light);
      };
  
  
      /**
       * Apply yellow color
       * @param message
       * @param light
       * @returns {string}
       */
      this.yellow = function (message, light) {
          return text(message, color.yellow, light);
      };
  
  
      /**
       * Apply blue color
       * @param message
       * @param light
       * @returns {string}
       */
      this.blue = function (message, light) {
          return text(message, color.blue, light);
      };
  
  
      /**
       * Apply magenta color
       * @param message
       * @param light
       * @returns {string}
       */
      this.magenta = function (message, light) {
          return text(message, color.magenta, light);
      };
  
  
      /**
       * Apply cyan color
       * @param message
       * @param light
       * @returns {string}
       */
      this.cyan = function (message, light) {
          return text(message, color.cyan, light);
      };
  
  
      /**
       * Apply white color
       * @param message
       * @param light
       * @returns {string}
       */
      this.white = function (message, light) {
          return text(message, color.white, light);
      };
  
  
      /**
       * Apply black color
       * @param message
       * @param light
       * @returns {string}
       */
      this.colorBlack = function (message, light) {
          return this.black(message, light);
      };
  
  
      /**
       * Apply red color
       * @param message
       * @param light
       * @returns {string}
       */
      this.colorRed = function (message, light) {
          return this.red(message, light);
      };
  
  
      /**
       * Apply green color
       * @param message
       * @param light
       * @returns {string}
       */
      this.colorGreen = function (message, light) {
          return this.green(message, light);
      };
  
  
      /**
       * Apply yellow color
       * @param message
       * @param light
       * @returns {string}
       */
      this.colorYellow = function (message, light) {
          return this.yellow(message, light);
      };
  
  
      /**
       * Apply blue color
       * @param message
       * @param light
       * @returns {string}
       */
      this.colorBlue = function (message, light) {
          return this.blue(message, light);
      };
  
  
      /**
       * Apply magenta color
       * @param message
       * @param light
       * @returns {string}
       */
      this.colorMagenta = function (message, light) {
          return this.magenta(message, light);
      };
  
  
      /**
       * Apply cyan color
       * @param message
       * @param light
       * @returns {string}
       */
      this.colorCyan = function (message, light) {
          return this.cyan(message, light);
      };
  
  
      /**
       * Apply white color
       * @param message
       * @param light
       * @returns {string}
       */
      this.colorWhite = function (message, light) {
          return this.white(message, light);
      };
  
  
      /**
       * Apply background color by name
       * @param message
       * @param name
       * @param light
       * @returns {string}
       */
      this.background = function (message, name, light) {
          if (background[name] === undefined) {
              var backgrounds = [],
                  b;
  
              for (b in background) {
                  if (background.hasOwnProperty(b)) {
                      backgrounds.push(b);
                  }
              }
              throw new Error('Undefined color. Use: ' + backgrounds.join(', '));
          }
          return text(message, background[name], light);
      };
  
  
      /**
       * Apply black background
       * @param message
       * @param light
       * @returns {string}
       */
      this.bgBlack = function (message, light) {
          return text(message, background.black, light);
      };
  
  
      /**
       * Apply red background
       * @param message
       * @param light
       * @returns {string}
       */
      this.bgRed = function (message, light) {
          return text(message, background.red, light);
      };
  
  
      /**
       * Apply green background
       * @param message
       * @param light
       * @returns {string}
       */
      this.bgGreen = function (message, light) {
          return text(message, background.green, light);
      };
  
  
      /**
       * Apply yellow background
       * @param message
       * @param light
       * @returns {string}
       */
      this.bgYellow = function (message, light) {
          return text(message, background.yellow, light);
      };
  
  
      /**
       * Apply blue background
       * @param message
       * @param light
       * @returns {string}
       */
      this.bgBlue = function (message, light) {
          return text(message, background.blue, light);
      };
  
  
      /**
       * Apply magenta background
       * @param message
       * @param light
       * @returns {string}
       */
      this.bgMagenta = function (message, light) {
          return text(message, background.magenta, light);
      };
  
  
      /**
       * Apply cyan background
       * @param message
       * @param light
       * @returns {string}
       */
      this.bgCyan = function (message, light) {
          return text(message, background.cyan, light);
      };
  
  
      /**
       * Apply white background
       * @param message
       * @param light
       * @returns {string}
       */
      this.bgWhite = function (message, light) {
          return text(message, background.white, light);
      };
  
  
      /**
       * Apply black background
       * @param message
       * @param light
       * @returns {string}
       */
      this.backgroundBlack = function (message, light) {
          return this.bgBlack(message, light);
      };
  
  
      /**
       * Apply red background
       * @param message
       * @param light
       * @returns {string}
       */
      this.backgroundRed = function (message, light) {
          return this.bgRed(message, light);
      };
  
  
      /**
       * Apply green background
       * @param message
       * @param light
       * @returns {string}
       */
      this.backgroundGreen = function (message, light) {
          return this.bgGreen(message, light);
      };
  
  
      /**
       * Apply yellow background
       * @param message
       * @param light
       * @returns {string}
       */
      this.backgroundYellow = function (message, light) {
          return this.bgYellow(message, light);
      };
  
  
      /**
       * Apply blue background
       * @param message
       * @param light
       * @returns {string}
       */
      this.backgroundBlue = function (message, light) {
          return this.bgBlue(message, light);
      };
  
  
      /**
       * Apply magenta background
       * @param message
       * @param light
       * @returns {string}
       */
      this.backgroundMagenta = function (message, light) {
          return this.bgMagenta(message, light);
      };
  
  
      /**
       * Apply cyan background
       * @param message
       * @param light
       * @returns {string}
       */
      this.backgroundCyan = function (message, light) {
          return this.bgCyan(message, light);
      };
  
  
      /**
       * Apply white background
       * @param message
       * @param light
       * @returns {string}
       */
      this.backgroundWhite = function (message, light) {
          return this.bgWhite(message, light);
      };
  
  
      /**
       * Alias for console.log
       * @param message
       * @param light
       * @returns {string}
       */
      this.log = function (message) {
          if (beSilent) {
              return this;
          }
          if (lastCommand === 'progress' || lastCommand === 'write') {
              this.write('\n');
          }
          lastCommand = 'log';
          console.log(message);
          message += '';
          lastLineLength = message.length;
  
          return this;
      };
  
  
      /**
       * Write to stdout
       * @param message
       * @param light
       * @returns {string}
       */
      this.write = function (message) {
          if (beSilent) {
              return this;
          }
          lastCommand = 'write';
          process.stdout.write(message);
  
          message = String(message);
          if (lastCommand === 'write') {
              lastLineLength += message.length;
          } else {
              lastLineLength = message.length;
          }
  
          return this;
      };
  
  
      /**
       * Log with bold white text
       * @param message
       * @returns {string}
       */
      this.info = function (message, returnString) {
          var str = this.apply(message, ['bold', 'white']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold green text
       * @param message
       * @returns {string}
       */
      this.success = function (message, returnString) {
          var str = this.apply(message, ['bold', 'green']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold yellow text
       * @param message
       * @returns {string}
       */
      this.warning = function (message, returnString) {
          var str = this.apply(message, ['bold', 'yellow']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold red text
       * @param message
       * @returns {string}
       */
      this.error = function (message, returnString) {
          var str = this.apply(message, ['bold', 'red']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold cyan text
       * @param message
       * @returns {string}
       */
      this.question = function (message, returnString) {
          var str = this.apply(message, ['bold', 'cyan']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold magenta text
       * @param message
       * @returns {string}
       */
      this.answer = function (message, returnString) {
          var str = this.apply(message, ['bold', 'magenta']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold black text and white background
       * @param message
       * @returns {string}
       */
      this.headerInfo = function (message, returnString) {
          var str = this.apply(message, ['bold', 'black', 'bgWhite']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold white text and green background
       * @param message
       * @returns {string}
       */
      this.headerSuccess = function (message, returnString) {
          var str = this.apply(message, ['bold', 'white', 'bgGreen']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold black text and yellow background
       * @param message
       * @returns {string}
       */
      this.headerWarning = function (message, returnString) {
          var str = this.apply(message, ['bold', 'black', 'bgYellow']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold white text and red background
       * @param message
       * @returns {string}
       */
      this.headerError = function (message, returnString) {
          var str = this.apply(message, ['bold', 'white', 'bgRed']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold white text and cyan background
       * @param message
       * @returns {string}
       */
      this.headerQuestion = function (message, returnString) {
          var str = this.apply(message, ['bold', 'white', 'bgCyan']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Log with bold white text and magenta background
       * @param message
       * @returns {string}
       */
      this.headerAnswer = function (message, returnString) {
          var str = this.apply(message, ['bold', 'white', 'bgMagenta']);
          return returnString === true ? str : this.log(str);
      };
  
  
      /**
       * Apply effects to message
       * @param message
       * @param effects
       * @returns {*}
       */
      this.apply = function (message, effects) {
          if ((effects instanceof Array) === false) {
              throw new Error('Effects must be an array');
          }
          if (!effects.length) {
              return message;
          }
          var i = 0,
              limit = effects.length;
  
          for (i = 0; i < limit; i++) {
              if (this.hasOwnProperty(effects[i]) && typeof this[effects[i]] === 'function') {
                  message = this[effects[i]](message);
              } else {
                  var allEffects = [],
                      e = '';
  
                  for (e in this) {
                      if (this.hasOwnProperty(e) && ((e.indexOf('color') === 0 && e !== 'color') || (e.indexOf('background') === 0 && e !== 'background') || effect[e] !== undefined)) {
                          allEffects.push(e);
                      }
                  }
                  throw new Error(util.format('Invalid effect "%s", you can use "%s"', effects[i], allEffects.join('", "')));
              }
          }
  
          return message;
      };
  
  
      /**
       * Alias for console.log that allow you to apply effects to dump
       * @param variable
       * @param effects
       * @returns {*}
       */
      this.dump = function (variable, effects) {
          if (beSilent) {
              return this;
          }
          if (!(effects instanceof Array)) {
              effects = [];
          }
  
          effects = this.apply('\n', effects);
          effects = effects.split('\n');
          this.write(effects[0]);
          this.write(util.inspect((typeof variable === 'function') ? variable.toString() : variable));
          this.write(effects[1] + '\n');
  
          return this;
      };
  
  
      /**
       * Get list of available effects
       * @returns {Array}
       */
      this.getAllEffects = function () {
          var allEffects = [],
              e = '';
  
          for (e in this) {
              if (this.hasOwnProperty(e) && ((e.indexOf('color') === 0 && e !== 'color') || ((e.indexOf('background') === 0 || e.indexOf('bg') === 0) && e !== 'background') || effect[e] !== undefined || color[e] !== undefined)) {
                  allEffects.push(e);
              }
          }
  
          return allEffects;
      };
  
  
      /**
       * Log message with xml tags using effects name. For example <b>text</b>
       * @param message
       * @param log
       * @returns {*}
       */
      this.format = function () {
          if (beSilent) {
              return this;
          }
          this.log(this.getFormat.apply(this.getFormat, arguments));
          return this;
      };
  
  
      /**
       * Log message with xml tags using effects name. For example <b>text</b>
       * @param message
       * @param log
       * @returns {*}
       */
      this.getFormat = function () {
          var message = arguments.length > 0 ? arguments[0] : '';
          message = util.format.apply(util.format, arguments);
          var all = self.getAllEffects(),
              i = 0,
              limit = all.length,
              applyCallback = function (match, content) {
                  return self.apply(content, [all[i]]);
              };
          for (i = 0; i < limit; i++) {
              message = message.replace(new RegExp(util.format('<%s>([\\s\\S]*?)<\/%s>', all[i], all[i]), 'g'), applyCallback);
          }
  
          return message;
      };
  
  
      this.stripFormat = function () {
          var message = arguments.length > 0 ? arguments[0] : '';
          message = util.format.apply(util.format, arguments);
  
          var all = this.getAllEffects(),
              i = 0,
              limit = all.length,
              applyCallback = function (match, content) {
                  return content;
              };
          for (i = 0; i < limit; i++) {
              message = message.replace(new RegExp(util.format('<%s>([\\s\\S]*?)<\/%s>', all[i], all[i]), 'g'), applyCallback);
          }
  
          return message;
      };
  
  
      /**
       * Print new line
       * @returns {*}
       */
      this.nl = function () {
          this.write('\n');
          return this;
      };
  
  
      /**
       * Alias for nl
       * @type {*}
       */
      this.newLine = this.nl;
  
  
      this.status = function (text, status, textEffects, statusEffects, returnString) {
          if (beSilent) {
              return this;
          }
          if (text instanceof Object) {
              text = text.toString();
          }
          if (status instanceof Object) {
              status = status.toString();
          }
  
          var textLen = this.stripFormat(text).length,
              statusLen = this.stripFormat(status).length,
              emptyLength = consoleWidth - (textLen + statusLen),
              emptyString = '',
              i = 0,
              str = '';
  
          text = this.getFormat(text);
          status = this.getFormat(status);
          if (textEffects instanceof Array) {
              text = this.apply(text, textEffects);
          }
          if (statusEffects instanceof Array) {
              status = this.apply(status, statusEffects);
          }
  
          if (emptyLength < 2) {
              emptyLength = 2;
          }
          emptyLength -= 1;
  
          for (i = 0; i < emptyLength; i++) {
              emptyString = emptyString + ' ';
          }
  
          str = text + emptyString + status;
  
          if (returnString === true) {
              return str;
          }
          this.log(str);
          return this;
      };
  }
func_documentation_string: Colorful console logging
  @returns {Log}
  @constructor