(function($) {
  var blinkSpeed = 150;

  $.fn.typewriter = function() {
    this.each(function() {
      var $ele = $(this), str = $ele.text(), progress = 0;
      $ele.text('');
      var timer = setInterval(function() {
        $ele.text(str.substring(0, progress++) + (progress & 1 ? '_' : ''));
        if (progress >= str.length) clearInterval(timer);
      }, 100);
    });
    return this;
  };

  $.fn.blink = function(times, after) {
    this.each(function() {
      var $ele = $(this), 
          str = $ele.text(), 
          toggle = true, 
          count = 0;
      var blinkTimer = setInterval(function() {
        if (count >= times) {
          clearInterval(blinkTimer);
          after();
          return;
        }
        $ele.text(str + (toggle ? '_' : ''));
        if (toggle) {
          toggle = false;
        } else {
          toggle = true;
          count++;
        }
      }, blinkSpeed);
    });
    return this;
  };

  $.fn.type = function(str, append, after) {
    this.each(function() {
      var $ele = $(this), progress = 0, beginText = '';
      if (append) {
        beginText = $ele.text();
      }
      var timer = setInterval(function() {
        $ele.text(beginText + str.substring(0, progress++) +  (progress & 1 ? '_' : ''));
        if (progress > str.length) {
          clearInterval(timer);
          if ($ele.text().charAt($ele.text().length - 1) == '_') {
            $ele.text($ele.text().substr(0, $ele.text().length - 1)); 
          }
          if (after) after();
        }
      }, 150);
    });
    return this;
  };

  $.fn.backspace = function(from, after) {
    this.each(function() {
      var $ele = $(this), 
          str = $ele.text(); 
      if (!from) {
        from = str.length;
      }
      var endText = str.slice(from);
      var progress = from;
      var timer = setInterval(function() {
        $ele.text(str.substring(0, progress--) + (progress & 1 ? '_' : '') + endText);
        if (progress < 0) {
          clearInterval(timer);
          $ele.text(endText);
          if (after) after();
        }
      }, 150);
    });
    return this;
  };
})(jQuery);
