/**

* Center a string using non-breaking spaces
*
* @param {String} `str`
* @param {String} `spaces`
* @return {String}
* @api public
*/

helpers.center = function(str, spaces) {

if (!util.isString(str)) return '';
var space = '';
var i = 0;
while (i < spaces) {
  space += '&nbsp;';
  i++;
}
return space + str + space;

};

/**

* Like trim, but removes both extraneous whitespace **and
* non-word characters** from the beginning and end of a string.
*
* ```handlebars
* {{chop "_ABC_"}}
* <!-- results in:  'ABC' -->
*
* {{chop "-ABC-"}}
* <!-- results in:  'ABC' -->
*
* {{chop " ABC "}}
* <!-- results in:  'ABC' -->
* ```
* @param {String} `string` The string to chop.
* @return {String}
* @api public
*/

helpers.chop = function(str) {

if (!util.isString(str)) return '';
return utils.chop(str);

};

/**

* Truncates a string to the specified `length`, and appends
* it with an elipsis, `…`.
*
* ```handlebars
* {{ellipsis (sanitize "<span>foo bar baz</span>"), 7}}
* <!-- results in:  'foo bar…' -->
* {{ellipsis "foo bar baz", 7}}
* <!-- results in:  'foo bar…' -->
* ```
* @param {String} `str`
* @param {Number} `length` The desired length of the returned string.
* @return {String} The truncated string.
* @api public
*/

helpers.ellipsis = function(str, limit) {

if (util.isString(str)) {
  if (str.length <= limit) {
    return str;
  }
  return helpers.truncate(str, limit) + '…';
}

};

/**

* Return true if `value` is a string.
*
* ```handlebars
* {{isString "foo"}}
* <!-- results in:  'true' -->
* ```
* @param {String} `value`
* @return {Boolean}
* @api public
*/

helpers.isString = function(value) {

return typeof value === 'string';

};

/**

* Return the number of occurrences of `substring` within the
* given `string`.
*
* ```handlebars
* {{occurrences "foo bar foo bar baz" "foo"}}
* <!-- results in:  2 -->
* ```
* @param {String} `str`
* @param {String} `substring`
* @return {Number} Number of occurrences
* @api public
*/

helpers.occurrences = function(str, substring) {

if (!util.isString(str)) return '';
var len = substring.length;
var pos = 0;
var n = 0;

while ((pos = str.indexOf(substring, pos)) > -1) {
  n++;
  pos += len;
}
return n;

};

/**

* Replace spaces in the given string with pluses.
*
* ```handlebars
* {{plusify "foo bar baz"}}
* <!-- results in:  'foo+bar+baz' -->
* ```
* @param {String} `str` The input string
* @return {String} Input string with spaces replaced by plus signs
* @source Stephen Way <https://github.com/stephenway>
* @api public
*/

helpers.plusify = function(str, ch) {

if (!util.isString(str)) return '';
if (!util.isString(ch)) ch = ' ';
return str.split(ch).join('+');

};

/**

* Prepends the given `string` with the specified `prefix`.
*
* ```handlebars
* <!-- given that "val" is "bar" -->
* {{prepend val "foo-"}}
* <!-- results in:  'foo-bar' -->
* ```
* @param {String} `str`
* @param {String} `prefix`
* @return {String}
* @api public
*/

helpers.prepend = function(str, prefix) {

return typeof str === 'string' && typeof prefix === 'string'
  ? (prefix + str)
  : str;

};

/**

* Render a block without processing mustache templates inside the block.
*
* ```handlebars
* {{{{#raw}}}}
* {{foo}}
* {{{{/raw}}}}
* <!-- results in:  '{{foo}}' -->
* ```
*
* @param {Object} `options`
* @return {String}
* @block
* @api public
*/

helpers.raw = function(options) {

var str = options.fn();
var opts = util.options(this, options);
if (opts.escape !== false) {
  var idx = 0;
  while (((idx = str.indexOf('{{', idx)) !== -1)) {
    if (str[idx - 1] !== '\\') {
      str = str.slice(0, idx) + '\\' + str.slice(idx);
    }
    idx += 3;
  }
}
return str;

};

/**

* Remove all occurrences of `substring` from the given `str`.
*
* ```handlebars
* {{remove "a b a b a b" "a "}}
* <!-- results in:  'b b b' -->
* ```
* @param {String} `str`
* @param {String} `substring`
* @return {String}
* @api public
*/

helpers.remove = function(str, ch) {

if (!util.isString(str)) return '';
if (!util.isString(ch)) return str;
return str.split(ch).join('');

};

/**

* Remove the first occurrence of `substring` from the given `str`.
*
* ```handlebars
* {{remove "a b a b a b" "a"}}
* <!-- results in:  ' b a b a b' -->
* ```
* @param {String} `str`
* @param {String} `substring`
* @return {String}
* @api public
*/

helpers.removeFirst = function(str, ch) {

if (!util.isString(str)) return '';
if (!util.isString(ch)) return str;
return str.replace(ch, '');

};

/**

* Replace all occurrences of substring `a` with substring `b`.
*
* ```handlebars
* {{replace "a b a b a b" "a" "z"}}
* <!-- results in:  'z b z b z b' -->
* ```
* @param {String} `str`
* @param {String} `a`
* @param {String} `b`
* @return {String}
* @api public
*/

helpers.replace = function(str, a, b) {

if (!util.isString(str)) return '';
if (!util.isString(a)) return str;
if (!util.isString(b)) b = '';
return str.split(a).join(b);

};

/**

* Replace the first occurrence of substring `a` with substring `b`.
*
* ```handlebars
* {{replace "a b a b a b" "a" "z"}}
* <!-- results in:  'z b a b a b' -->
* ```
* @param {String} `str`
* @param {String} `a`
* @param {String} `b`
* @return {String}
* @api public
*/

helpers.replaceFirst = function(str, a, b) {

if (!util.isString(str)) return '';
if (!util.isString(a)) return str;
if (!util.isString(b)) b = '';
return str.replace(a, b);

};

/**

* Reverse a string.
*
* ```handlebars
* {{reverse "abcde"}}
* <!-- results in:  'edcba' -->
* ```
* @param {String} `str`
* @return {String}
* @api public
*/

helpers.reverse = function(str) {

if (!util.isString(str)) return '';
return str.split('').reverse().join('');

};

/**

* Sentence case the given string
*
* ```handlebars
* {{sentence "hello world. goodbye world."}}
* <!-- results in:  'Hello world. Goodbye world.' -->
* ```
* @param {String} `str`
* @return {String}
* @api public
*/

helpers.sentence = function(str) {

if (!util.isString(str)) return '';
return str.replace(/((?:\S[^\.\?\!]*)[\.\?\!]*)/g, function(txt) {
  return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
});

};

/**

* snake_case the characters in the given `string`.
*
* ```handlebars
* {{snakecase "a-b-c d_e"}}
* <!-- results in:  'a_b_c_d_e' -->
* ```
* @param {String} `string`
* @return {String}
* @api public
*/

helpers.snakecase = function(str) {

if (!util.isString(str)) return '';
return utils.changecase(str, function(ch) {
  return '_' + ch;
});

};

/**

* Split `string` by the given `character`.
*
* ```handlebars
* {{split "a,b,c" ","}}
* <!-- results in:  ['a', 'b', 'c'] -->
* ```
* @param {String} `string` The string to split.
* @return {String} `character` Default is an empty string.
* @api public
*/

helpers.split = function(str, ch) {

if (!util.isString(str)) return '';
if (!util.isString(ch)) ch = ',';
return str.split(ch);

};

/**

* Tests whether a string begins with the given prefix.
*
* ```handlebars
* {{#startsWith "Goodbye" "Hello, world!"}}
*   Whoops
* {{else}}
*   Bro, do you even hello world?
* {{/startsWith}}
* ```
* @contributor Dan Fox <http://github.com/iamdanfox>
* @param {String} `prefix`
* @param {String} `testString`
* @param {String} `options`
* @return {String}
* @block
* @api public
*/

helpers.startsWith = function(prefix, str, options) {

var args = [].slice.call(arguments);
options = args.pop();
if (util.isString(str) && str.indexOf(prefix) === 0) {
  return options.fn(this);
}
if (typeof options.inverse === 'function') {
  return options.inverse(this);
}
return '';

};

/**

* Title case the given string.
*
* ```handlebars
* {{titleize "this is title case"}}
* <!-- results in:  'This Is Title Case' -->
* ```
* @param {String} `str`
* @return {String}
* @api public
*/

helpers.titleize = function(str) {

if (!util.isString(str)) return '';
var title = str.replace(/[- _]+/g, ' ');
var words = title.split(' ');
var len = words.length;
var res = [];
var i = 0;
while (len--) {
  var word = words[i++];
  res.push(exports.capitalize(word));
}
return res.join(' ');

};

/**

* Removes extraneous whitespace from the beginning and end
* of a string.
*
* ```handlebars
* {{trim " ABC "}}
* <!-- results in:  'ABC' -->
* ```
* @param {String} `string` The string to trim.
* @return {String}
* @api public
*/

helpers.trim = function(str) {

return typeof str === 'string' ? str.trim() : '';

};

/**

* Removes extraneous whitespace from the beginning of a string.
*
* ```handlebars
* {{trim " ABC "}}
* <!-- results in:  'ABC ' -->
* ```
* @param {String} `string` The string to trim.
* @return {String}
* @api public
*/

helpers.trimLeft = function(str) {

if (util.isString(str)) {
  return str.replace(/^\s+/, '');
}

};

/**

* Removes extraneous whitespace from the end of a string.
*
* ```handlebars
* {{trimRight " ABC "}}
* <!-- results in:  ' ABC' -->
* ```
* @param {String} `string` The string to trim.
* @return {String}
* @api public
*/

helpers.trimRight = function(str) {

if (util.isString(str)) {
  return str.replace(/\s+$/, '');
}

};

/**

* Truncate a string to the specified `length`. Also see [ellipsis](#ellipsis).
*
* ```handlebars
* truncate("foo bar baz", 7);
* <!-- results in:  'foo bar' -->
* truncate(sanitize("<span>foo bar baz</span>", 7));
* <!-- results in:  'foo bar' -->
* ```
* @param {String} `str`
* @param {Number} `limit` The desired length of the returned string.
* @param {String} `suffix` Optionally supply a string to use as a suffix to
* denote when the string has been truncated. Otherwise an ellipsis (`…`) will be used.
* @return {String} The truncated string.
* @api public
*/

helpers.truncate = function(str, limit, suffix) {

if (util.isString(str)) {
  if (typeof suffix !== 'string') {
    suffix = '';
  }
  if (str.length > limit) {
    return str.slice(0, limit - suffix.length) + suffix;
  }
  return str;
}

};

/**

* Truncate a string to have the specified number of words.
* Also see [truncate](#truncate).
*
* ```handlebars
* truncateWords("foo bar baz", 1);
* <!-- results in:  'foo…' -->
* truncateWords("foo bar baz", 2);
* <!-- results in:  'foo bar…' -->
* truncateWords("foo bar baz", 3);
* <!-- results in:  'foo bar baz' -->
* ```
* @param {String} `str`
* @param {Number} `limit` The desired length of the returned string.
* @param {String} `suffix` Optionally supply a string to use as a suffix to
* denote when the string has been truncated.
* @return {String} The truncated string.
* @api public
*/

helpers.truncateWords = function(str, count, suffix) {

if (util.isString(str) && isNumber(count)) {
  if (typeof suffix !== 'string') {
    suffix = '…';
  }

  var num = Number(count);
  var arr = str.split(/[ \t]/);
  if (num > arr.length) {
    arr = arr.slice(0, num);
  }

  var val = arr.join(' ').trim();
  return val + suffix;
}

};