text: "use strict";
  
  var reAnsi        = require("ansi-regex")
    , stringifiable = require("es5-ext/object/validate-stringifiable-value")
    , length        = require("./get-stripped-length")
    , sgr           = require("./lib/sgr")
    , max           = Math.max;
  
  var Token = function (token) { this.token = token; };
  
  var tokenize = function (str) {
  	var match = reAnsi().exec(str);
  
  	if (!match) {
  		return [str];
  	}
  
  	var index = match.index, head, prehead, tail;
  
  	if (index === 0) {
  		head = match[0];
  		tail = str.slice(head.length);
  
  		return [new Token(head)].concat(tokenize(tail));
  	}
  
  	prehead = str.slice(0, index);
  	head = match[0];
  	tail = str.slice(index + head.length);
  
  	return [prehead, new Token(head)].concat(tokenize(tail));
  };
  
  var isChunkInSlice = function (chunk, index, begin, end) {
  	var endIndex = chunk.length + index;
  
  	if (begin > endIndex) return false;
  	if (end < index) return false;
  	return true;
  };
  
  // eslint-disable-next-line max-lines-per-function
  var sliceSeq = function (seq, begin, end) {
  	var sliced = seq.reduce(
  		function (state, chunk) {
  			var index = state.index;
  
  			if (chunk instanceof Token) {
  				var code = sgr.extractCode(chunk.token);
  
  				if (index <= begin) {
  					if (code in sgr.openers) {
  						sgr.openStyle(state.preOpeners, code);
  					}
  					if (code in sgr.closers) {
  						sgr.closeStyle(state.preOpeners, code);
  					}
  				} else if (index < end) {
  					if (code in sgr.openers) {
  						sgr.openStyle(state.inOpeners, code);
  						state.seq.push(chunk);
  					} else if (code in sgr.closers) {
  						state.inClosers.push(code);
  						state.seq.push(chunk);
  					}
  				}
  			} else {
  				var nextChunk = "";
  
  				if (isChunkInSlice(chunk, index, begin, end)) {
  					var relBegin = Math.max(begin - index, 0)
  					  , relEnd = Math.min(end - index, chunk.length);
  
  					nextChunk = chunk.slice(relBegin, relEnd);
  				}
  
  				state.seq.push(nextChunk);
  				state.index = index + chunk.length;
  			}
  
  			return state;
  		},
  		{
  			index: 0,
  			seq: [],
  
  			// preOpeners -> [ mod ]
  			// preOpeners must be prepended to the slice if they wasn't closed til the end of it
  			// preOpeners must be closed if they wasn't closed til the end of the slice
  			preOpeners: [],
  
  			// inOpeners  -> [ mod ]
  			// inOpeners already in the slice and must not be prepended to the slice
  			// inOpeners must be closed if they wasn't closed til the end of the slice
  			inOpeners: [], // opener CSI inside slice
  
  			// inClosers -> [ code ]
  			// closer CSIs for determining which pre/in-Openers must be closed
  			inClosers: []
  		}
  	);
  
  	sliced.seq = [].concat(
  		sgr.prepend(sliced.preOpeners), sliced.seq,
  		sgr.complete([].concat(sliced.preOpeners, sliced.inOpeners), sliced.inClosers)
  	);
  
  	return sliced.seq;
  };
  
  module.exports = function (str/*, begin, end*/) {
  	var seq, begin = Number(arguments[1]), end = Number(arguments[2]), len;
  
  	str = stringifiable(str);
  	len = length(str);
  
  	if (isNaN(begin)) {
  		begin = 0;
  	}
  	if (isNaN(end)) {
  		end = len;
  	}
  	if (begin < 0) {
  		begin = max(len + begin, 0);
  	}
  	if (end < 0) {
  		end = max(len + end, 0);
  	}
  
  	seq = tokenize(str);
  	seq = sliceSeq(seq, begin, end);
  	return seq
  		.map(function (chunk) {
  			if (chunk instanceof Token) {
  				return chunk.token;
  			}
  
  			return chunk;
  		})
  		.join("");
  };
  