text: /**
   * This base class contains utility methods for dealing with formats such as CSV (Comma
   * Separated Values) as specified in <a href="http://tools.ietf.org/html/rfc4180">RFC 4180</a>.
   *
   * The base class implements the mechanics and is governed by these config options:
   *
   *  * `{@link #delimiter}`
   *  * `{@link #lineBreak}`
   *  * `{@link #quote}`
   *
   * These options affect the `{@link #method-encode}` and `{@link #method-decode}` methods.
   * When *decoding*, however, `{@link #lineBreak}` is ignored and instead each line can
   * be separated by any standard line terminator character or character sequence:
   *
   *  * ```\u000a```
   *  * ```\u000d```
   *  * ```\u000d\u000a```
   *
   * Strings which contain the {@link #delimiter} character are quoted using the
   * {@link #quote} character, and any internal {@link #quote} characters are doubled.
   *
   * *Important*
   * While the primary use case is to encode strings, other atomic data types can be encoded
   * as values within a line such as:
   *
   *  * Number
   *  * Boolean
   *  * Date (encoded as an <a href="http://www.iso.org/iso/home/standards/iso8601.htm">ISO 8601</a> date string.)
   *  * null (encoded as an empty string.)
   *  * undefined (encoded as an empty string.)
   *
   * Not that when *decoding*, all data is read as strings. This class does not convert
   * incoming data. To do that, use an {@link Ext.data.reader.Array ArrayReader}.
   *
   * See `{@link Ext.util.CSV}` and  `{@link Ext.util.TSV}` for pre-configured instances.
   *
   * @since 5.1.0
   */
  Ext.define('Ext.util.DelimitedValue', {
      /**
       * @cfg {String} dateFormat
       * The {@link Ext.Date#format format} to use for dates
       */
      dateFormat: 'C',
  
      /**
       * @cfg {String} delimiter
       * The string used to separate the values in a row. Common values for this config
       * are comma (",") and tab ("\t"). See `{@link Ext.util.CSV}` and  `{@link Ext.util.TSV}`
       * for pre-configured instances of these formats.
       */
      delimiter: '\t',
  
      /**
       * @cfg {String} lineBreak
       * The string used by `{@link #encode}` to separate each row. The `{@link #decode}`
       * method accepts all forms of line break.
       */
      lineBreak: '\n',
  
      /**
       * @cfg {String} quote
       * The character to use as to quote values that contain the special `delimiter`
       * or `{@link #lineBreak}` characters.
       */
      quote: '"',
      
      parseREs: {},
      quoteREs: {},
  
      lineBreakRe: /\r?\n/g,
  
      constructor: function (config) {
          if (config) {
              Ext.apply(this, config);
          }
      },
  
      /**
       * Decodes a string of encoded values into an array of rows. Each row is an array of
       * strings.
       *
       * Note that this function does not convert the string values in each column into
       * other data types. To do that, use an {@link Ext.data.reader.Array ArrayReader}.
       *
       * For example:
       *
       *     Ext.util.CSV.decode('"foo ""bar"", bletch",Normal String,2010-01-01T21:45:32.004Z\u000a3.141592653589793,1,false');
       *
       * produces the following array of string arrays:
       *
       *     [
       *         ['foo "bar", bletch','Normal String', '2010-01-01T21:45:32.004Z'],
       *         ['3.141592653589793', '1', 'false']
       *     ]
       *
       * @param {String} input The string to parse.
       *
       * @param {String} [delimiter] The column delimiter to use if the default value
       * of {@link #cfg-delimiter delimiter} is not desired.
       *
       * @return {String[][]} An array of rows where each row is an array of Strings.
       */
      decode: function (input, delimiter) {
          var me = this,
              // Check to see if the column delimiter is defined. If not,
              // then default to comma.
              delim = (delimiter || me.delimiter),
              row = [],
              result = [row],
              quote = me.quote,
              quoteREs = me.quoteREs,
              parseREs = me.parseREs,
  
              // Create a regular expression to parse the CSV values unless we already have
              // one for this delimiter.
              parseRE = parseREs[delim] ||
                  (parseREs[delim] = new RegExp(
                      // Delimiters.
                      "(\\" + delim + "|\\r?\\n|\\r|^)" +
  
                      // Quoted fields.
                      "(?:\\" + quote + "([^\\" + quote + "]*(?:\\" + quote + "\\" + quote +
                              "[^\\" + quote + "]*)*)\\" + quote + "|" +
  
                      // Standard fields.
                      "([^\"\\" + delim + "\\r\\n]*))",
                  "gi")),
  
              dblQuoteRE = quoteREs[quote] ||
                  (quoteREs[quote] = new RegExp('\\' + quote + '\\' + quote, 'g')),
  
              arrMatches, strMatchedDelimiter, strMatchedValue;
  
          // Keep looping over the regular expression matches
          // until we can no longer find a match.
          while (arrMatches = parseRE.exec(input)) {
              strMatchedDelimiter = arrMatches[1];
  
              // Check to see if the given delimiter has a length
              // (is not the start of string) and if it matches
              // field delimiter. If id does not, then we know
              // that this delimiter is a row delimiter.
              if (strMatchedDelimiter.length && strMatchedDelimiter !== delim) {
                  // Since we have reached a new row of data,
                  // add an empty row to our data array.
                  result.push(row = []);
              }
  
              // Now that we have our delimiter out of the way,
              // let's check to see which kind of value we
              // captured (quoted or unquoted).
              if (arrMatches[2]) {
                  // We found a quoted value. When we capture
                  // this value, unescape any double quotes.
                  strMatchedValue = arrMatches[2].replace(dblQuoteRE, '"');
              } else {
                  // We found a non-quoted value.
                  strMatchedValue = arrMatches[3];
              }
  
              row.push(strMatchedValue);
          }
  
          return result;
      },
  
      /**
       * Converts a two-dimensional array into an encoded string.
       *
       * For example:
       *
       *     Ext.util.CSV.encode([
       *         ['foo "bar", bletch', 'Normal String', new Date()],
       *         [Math.PI, 1, false]
       *     ]);
       *
       * The above produces the following string:
       *
       *     '"foo ""bar"", bletch",Normal String,2010-01-01T21:45:32.004Z\u000a3.141592653589793,1,false'
       *
       * @param {Mixed[][]} input An array of row data arrays.
       *
       * @param {String} [delimiter] The column delimiter to use if the default value
       * of {@link #cfg-delimiter delimiter} is not desired.
       *
       * @return {String} A string in which data items are separated by {@link #delimiter}
       * characters, and rows are separated by {@link #lineBreak} characters.
       */
      encode: function (input, delimiter) {
          var me = this,
              delim = delimiter || me.delimiter,
              dateFormat = me.dateFormat,
              quote = me.quote,
              twoQuotes = quote + quote,
              rowIndex = input.length,
              lineBreakRe = me.lineBreakRe,
              result = [],
              outputRow = [],
              col, columnIndex, inputRow;
  
          while (rowIndex-- > 0) {
              inputRow = input[rowIndex];
              outputRow.length = columnIndex = inputRow.length;
  
              while (columnIndex-- > 0) {
                  col = inputRow[columnIndex];
  
                  if (col == null) { // == null || === undefined
                      col = '';
                  } else if (typeof col === 'string') {
                      if (col) {
                          // If the value contains quotes, double them up, and wrap with quotes
                          if (col.indexOf(quote) > -1) {
                              col = quote + col.split(quote).join(twoQuotes) + quote;
                          } else if (col.indexOf(delim) > -1 || lineBreakRe.test(col)) {
                              col = quote + col + quote;
                          }
                      }
                  } else if (Ext.isDate(col)) {
                      col = Ext.Date.format(col, dateFormat);
                  }
                  //<debug>
                  else if (col && (isNaN(col) || Ext.isArray(col))) {
                      Ext.Error.raise('Cannot serialize ' + Ext.typeOf(col) + ' into CSV');
                  }
                  //</debug>
  
                  outputRow[columnIndex] = col;
              }
  
              result[rowIndex] = outputRow.join(delim);
          }
  
          return result.join(me.lineBreak);
      }
  });
  