docs: function handleData(stream, asString, data, dataLimit) {
          var dataLen = data.length,
              i = dataLen,
              trailingDataIndex = -1, //index of data after the last delimiter match in data
              lastMatchIndex = 0,
              matchLimit  = dataLimit || Infinity,
              len = 0;
  
          //first start going back through data to find the last match
          //we do this loop separately so we can just store the index of the last match and then add that to the buffer at the end for the next packet
          while (i--) {
              if (data[i] === stream.delimiter) {
                  //now that we found the match, store the index (+1 so we don't store the delimiter)
                  trailingDataIndex = i + 1;
                  break;
              }
          }
  
          //if we didn't find a match at all, just push the data onto the buffer
          if (trailingDataIndex === -1) {
              //don't use dataLimit here since we shouldn't pass in infinity to concatBuffer
              stream.buffer = concatBuffer(stream.buffer, data, dataLimit);
              return;
          }
          lastMatchIndex = i;
          while (i--) {
              if (data[i] === stream.delimiter) {
                  //make sure we ignore back-to-back delimiters
                  len = lastMatchIndex - (i + 1); //i + 1 so we don't include the delimiter we just matched
                  if (len > matchLimit) {
                      stream.matches.push(data.slice(lastMatchIndex - matchLimit, lastMatchIndex));
                  } else if (len > 0) {
                      stream.matches.push(data.slice(i + 1, lastMatchIndex));
                  }
                  lastMatchIndex = i;
              }
          }
          //since the loop stops at the beginning of data we need to store the bytes before the first match in the string
          if (lastMatchIndex > 0) {
              stream.buffer = concatBuffer(stream.buffer, data.slice(0, lastMatchIndex), dataLimit);
          }
          //add the leftover buffer to the matches at the end (beginning when we emit events)
          if (asString) {
              if (isNode) {
                  stream.matches.push(stream.buffer.toString());
                  stream.buffer = new BUFFER_CONSTRUCTOR(0);
              } else {
                  stream.matches.push(stream.buffer.splice(0, stream.buffer.length).join(''));
              }
          } else {
              stream.matches.push(stream.buffer);
              stream.buffer = new BUFFER_CONSTRUCTOR(0);
          }
  
          //todo: optimize this to not make an empty buffer just to fill it with a new thing immediately after
          //make sure the lastMatchIndex isn't the end
          if (lastMatchIndex < dataLen) {
              //don't use dataLimit here since we shouldn't pass in infinity to concatBuffer
              stream.buffer = concatBuffer(stream.buffer, data.slice(trailingDataIndex), dataLimit);
          }
  
          if (stream.emitEvents) {
              emitEvents(stream);
          }
      }