'use strict';

var _defineProperty = require('@babel/runtime/helpers/defineProperty');
var _toConsumableArray = require('@babel/runtime/helpers/toConsumableArray');
var _slicedToArray = require('@babel/runtime/helpers/slicedToArray');
var React = require('react');
var formik = require('formik');
var Upload = require('@bigbinary/neeto-icons/Upload');
var Button = require('@bigbinary/neetoui/Button');
var Toastr = require('@bigbinary/neetoui/Toastr');
var MultiEmailInput = require('@bigbinary/neetoui/formik/MultiEmailInput');
var reactI18next = require('react-i18next');
var classnames = require('classnames');
var Typography = require('@bigbinary/neetoui/Typography');
var Pane = require('@bigbinary/neetoui/Pane');
var reactDropzone = require('react-dropzone');
var withT = require('@bigbinary/neeto-commons-frontend/react-utils/withT');
var Download = require('@bigbinary/neeto-icons/Download');
var Callout = require('@bigbinary/neetoui/Callout');
var jsxRuntime = require('react/jsx-runtime');
var i18next = require('i18next');
var _commonjsHelpers = require('./_commonjsHelpers-BJu3ubxk.js');
var require$$0 = require('stream');
var ramda = require('ramda');
var yup = require('yup');

var CSV_FILE_SIZE_IN_KB = 32;
var ONE_KILOBYTE_IN_BYTES = 1024;
var DOWNLOAD_SAMPLE_EMAIL_CSV_FILE = "https://d2v7kzglnr2dnh.cloudfront.net/others/sample-bulk-email.csv";

var Requirements = withT(function (_ref) {
  var t = _ref.t,
    fileSize = _ref.fileSize;
  return /*#__PURE__*/jsxRuntime.jsxs(Callout, {
    className: "flex flex-col items-center py-6",
    style: "info",
    children: [/*#__PURE__*/jsxRuntime.jsxs("ul", {
      className: "flex list-outside list-disc flex-col gap-y-1 font-normal leading-normal",
      children: [fileSize && /*#__PURE__*/jsxRuntime.jsx("li", {
        children: t("neetoMolecules.shareViaLink.requirements.fileTypeAndSize", {
          limit: fileSize
        })
      }), /*#__PURE__*/jsxRuntime.jsx("li", {
        children: /*#__PURE__*/jsxRuntime.jsx(reactI18next.Trans, {
          components: {
            strong: /*#__PURE__*/jsxRuntime.jsx("strong", {
              className: "font-semibold"
            })
          },
          i18nKey: "neetoMolecules.shareViaLink.requirements.shouldContainColumns"
        })
      })]
    }), /*#__PURE__*/jsxRuntime.jsx(Button, {
      href: DOWNLOAD_SAMPLE_EMAIL_CSV_FILE,
      icon: Download,
      iconPosition: "left",
      label: t("neetoMolecules.shareViaLink.bulkUploadPane.downloadSampleCSV"),
      style: "link"
    })]
  });
});
var Requirements$1 = /*#__PURE__*/React.memo(Requirements);

function ownKeys$1(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread$1(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$1(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$1(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
var BulkUploadPane = function BulkUploadPane(_ref) {
  var _fileRejections$;
  var isOpen = _ref.isOpen,
    fileSize = _ref.fileSize,
    onClose = _ref.onClose,
    handleFileSubmit = _ref.handleFileSubmit;
  var _useDropzone = reactDropzone.useDropzone({
      accept: {
        "text/csv": []
      },
      maxFiles: 1,
      maxSize: fileSize * ONE_KILOBYTE_IN_BYTES,
      onDrop: function onDrop(files) {
        return files[0] && handleFileSubmit(files[0]);
      }
    }),
    getRootProps = _useDropzone.getRootProps,
    getInputProps = _useDropzone.getInputProps,
    isDragActive = _useDropzone.isDragActive,
    fileRejections = _useDropzone.fileRejections;
  var errors = (_fileRejections$ = fileRejections[0]) === null || _fileRejections$ === void 0 ? void 0 : _fileRejections$.errors.map(function (_ref2) {
    var message = _ref2.message,
      code = _ref2.code;
    return /*#__PURE__*/jsxRuntime.jsx(Typography, {
      className: "neeto-ui-text-error-500 items",
      "data-cy": "file-input-error-message",
      style: "body3",
      children: message
    }, code);
  });
  var _useTranslation = reactI18next.useTranslation(),
    t = _useTranslation.t;
  return /*#__PURE__*/jsxRuntime.jsx(Pane, {
    isOpen: isOpen,
    onClose: onClose,
    "data-testid": "bulk-upload-pane",
    children: /*#__PURE__*/jsxRuntime.jsxs("div", {
      tabIndex: 0,
      children: [/*#__PURE__*/jsxRuntime.jsx(Pane.Header, {
        children: /*#__PURE__*/jsxRuntime.jsx(Typography, {
          "data-testid": "bulk-upload-header",
          style: "h2",
          weight: "semibold",
          children: t("neetoMolecules.shareViaLink.bulkUpload")
        })
      }), /*#__PURE__*/jsxRuntime.jsx(Pane.Body, {
        children: /*#__PURE__*/jsxRuntime.jsxs("div", {
          className: "flex w-full flex-col gap-y-4",
          children: [/*#__PURE__*/jsxRuntime.jsx(Requirements$1, {
            fileSize: fileSize
          }), /*#__PURE__*/jsxRuntime.jsxs("div", _objectSpread$1(_objectSpread$1({}, getRootProps({
            className: classnames("flex flex-col p-2 border neeto-ui-border-primary-500 border-dashed neeto-ui-rounded-md transition duration-500 ease-in-out hover:neeto-ui-bg-gray-100 cursor-pointer items-center", {
              "neeto-ui-border-gray-100": isDragActive,
              "neeto-ui-border-error neeto-ui-bg-pastel-red hover:neeto-ui-bg-pastel-red": fileRejections.length
            })
          })), {}, {
            children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
              className: "flex flex-col items-center gap-y-3 p-4",
              children: [/*#__PURE__*/jsxRuntime.jsx(Upload, {
                className: "neeto-ui-text-primary-500",
                size: 32
              }), /*#__PURE__*/jsxRuntime.jsx("input", _objectSpread$1(_objectSpread$1({}, getInputProps()), {}, {
                "data-cy": "csv-upload-input",
                "data-testid": "csv-upload-input"
              })), isDragActive ? /*#__PURE__*/jsxRuntime.jsx(Typography, {
                style: "body2",
                children: t("neetoMolecules.shareViaLink.bulkUploadPane.dropFileHere")
              }) : /*#__PURE__*/jsxRuntime.jsxs("div", {
                className: "flex flex-col items-center gap-y-1",
                children: [/*#__PURE__*/jsxRuntime.jsx("div", {
                  className: "flex w-full items-center justify-center gap-x-1",
                  children: /*#__PURE__*/jsxRuntime.jsx(reactI18next.Trans, {
                    i18nKey: "neetoMolecules.shareViaLink.bulkUploadPane.dragNDrop",
                    components: {
                      Button: /*#__PURE__*/jsxRuntime.jsx(Button, {
                        style: "link"
                      })
                    }
                  })
                }), /*#__PURE__*/jsxRuntime.jsxs(Typography, {
                  className: "neeto-ui-text-gray-700",
                  style: "body3",
                  children: [/*#__PURE__*/jsxRuntime.jsx(reactI18next.Trans, {
                    i18nKey: "neetoMolecules.shareViaLink.bulkUploadPane.supportedFormat",
                    values: {
                      fileType: "csv"
                    },
                    components: {
                      code: /*#__PURE__*/jsxRuntime.jsx("code", {
                        className: "neeto-ui-typography neeto-ui-text-body3 neeto-ui-bg-white m-0 border-l-0 p-0"
                      })
                    }
                  }), " ", fileSize && t("neetoMolecules.shareViaLink.bulkUploadPane.supportedSize", {
                    fileSize: fileSize
                  })]
                })]
              })]
            }), errors]
          }))]
        })
      }), /*#__PURE__*/jsxRuntime.jsx(Pane.Footer, {
        className: "flex items-center gap-x-2",
        children: /*#__PURE__*/jsxRuntime.jsx(Button, {
          "data-cy": "bulk-upload-cancel-button",
          "data-testid": "bulk-upload-cancel-button",
          label: t("neetoMolecules.common.actions.cancel"),
          style: "text",
          type: "reset",
          onClick: onClose
        })
      })]
    })
  });
};

var papaparse = {exports: {}};

/* @license
Papa Parse
v5.5.3
https://github.com/mholt/PapaParse
License: MIT
*/

(function (module, exports) {
	(function(root, factory)
	{
		/* globals define */
		{
			// Node. Does not work with strict CommonJS, but
			// only CommonJS-like environments that support module.exports,
			// like Node.
			module.exports = factory();
		}
		// in strict mode we cannot access arguments.callee, so we need a named reference to
		// stringify the factory method for the blob worker
		// eslint-disable-next-line func-name
	}(_commonjsHelpers.commonjsGlobal, function moduleFactory()
	{

		var global = (function() {
			// alternative method, similar to `Function('return this')()`
			// but without using `eval` (which is disabled when
			// using Content Security Policy).

			if (typeof self !== 'undefined') { return self; }
			if (typeof window !== 'undefined') { return window; }
			if (typeof global !== 'undefined') { return global; }

			// When running tests none of the above have been defined
			return {};
		})();


		function getWorkerBlob() {
			var URL = global.URL || global.webkitURL || null;
			var code = moduleFactory.toString();
			return Papa.BLOB_URL || (Papa.BLOB_URL = URL.createObjectURL(new Blob(["var global = (function() { if (typeof self !== 'undefined') { return self; } if (typeof window !== 'undefined') { return window; } if (typeof global !== 'undefined') { return global; } return {}; })(); global.IS_PAPA_WORKER=true; ", '(', code, ')();'], {type: 'text/javascript'})));
		}

		var IS_WORKER = !global.document && !!global.postMessage,
			IS_PAPA_WORKER = global.IS_PAPA_WORKER || false;

		var workers = {}, workerIdCounter = 0;

		var Papa = {};

		Papa.parse = CsvToJson;
		Papa.unparse = JsonToCsv;

		Papa.RECORD_SEP = String.fromCharCode(30);
		Papa.UNIT_SEP = String.fromCharCode(31);
		Papa.BYTE_ORDER_MARK = '\ufeff';
		Papa.BAD_DELIMITERS = ['\r', '\n', '"', Papa.BYTE_ORDER_MARK];
		Papa.WORKERS_SUPPORTED = !IS_WORKER && !!global.Worker;
		Papa.NODE_STREAM_INPUT = 1;

		// Configurable chunk sizes for local and remote files, respectively
		Papa.LocalChunkSize = 1024 * 1024 * 10;	// 10 MB
		Papa.RemoteChunkSize = 1024 * 1024 * 5;	// 5 MB
		Papa.DefaultDelimiter = ',';			// Used if not specified and detection fails

		// Exposed for testing and development only
		Papa.Parser = Parser;
		Papa.ParserHandle = ParserHandle;
		Papa.NetworkStreamer = NetworkStreamer;
		Papa.FileStreamer = FileStreamer;
		Papa.StringStreamer = StringStreamer;
		Papa.ReadableStreamStreamer = ReadableStreamStreamer;
		if (typeof PAPA_BROWSER_CONTEXT === 'undefined') {
			Papa.DuplexStreamStreamer = DuplexStreamStreamer;
		}

		if (global.jQuery)
		{
			var $ = global.jQuery;
			$.fn.parse = function(options)
			{
				var config = options.config || {};
				var queue = [];

				this.each(function(idx)
				{
					var supported = $(this).prop('tagName').toUpperCase() === 'INPUT'
									&& $(this).attr('type').toLowerCase() === 'file'
									&& global.FileReader;

					if (!supported || !this.files || this.files.length === 0)
						return true;	// continue to next input element

					for (var i = 0; i < this.files.length; i++)
					{
						queue.push({
							file: this.files[i],
							inputElem: this,
							instanceConfig: $.extend({}, config)
						});
					}
				});

				parseNextFile();	// begin parsing
				return this;		// maintains chainability


				function parseNextFile()
				{
					if (queue.length === 0)
					{
						if (isFunction(options.complete))
							options.complete();
						return;
					}

					var f = queue[0];

					if (isFunction(options.before))
					{
						var returned = options.before(f.file, f.inputElem);

						if (typeof returned === 'object')
						{
							if (returned.action === 'abort')
							{
								error('AbortError', f.file, f.inputElem, returned.reason);
								return;	// Aborts all queued files immediately
							}
							else if (returned.action === 'skip')
							{
								fileComplete();	// parse the next file in the queue, if any
								return;
							}
							else if (typeof returned.config === 'object')
								f.instanceConfig = $.extend(f.instanceConfig, returned.config);
						}
						else if (returned === 'skip')
						{
							fileComplete();	// parse the next file in the queue, if any
							return;
						}
					}

					// Wrap up the user's complete callback, if any, so that ours also gets executed
					var userCompleteFunc = f.instanceConfig.complete;
					f.instanceConfig.complete = function(results)
					{
						if (isFunction(userCompleteFunc))
							userCompleteFunc(results, f.file, f.inputElem);
						fileComplete();
					};

					Papa.parse(f.file, f.instanceConfig);
				}

				function error(name, file, elem, reason)
				{
					if (isFunction(options.error))
						options.error({name: name}, file, elem, reason);
				}

				function fileComplete()
				{
					queue.splice(0, 1);
					parseNextFile();
				}
			};
		}


		if (IS_PAPA_WORKER)
		{
			global.onmessage = workerThreadReceivedMessage;
		}




		function CsvToJson(_input, _config)
		{
			_config = _config || {};
			var dynamicTyping = _config.dynamicTyping || false;
			if (isFunction(dynamicTyping)) {
				_config.dynamicTypingFunction = dynamicTyping;
				// Will be filled on first row call
				dynamicTyping = {};
			}
			_config.dynamicTyping = dynamicTyping;

			_config.transform = isFunction(_config.transform) ? _config.transform : false;

			if (_config.worker && Papa.WORKERS_SUPPORTED)
			{
				var w = newWorker();

				w.userStep = _config.step;
				w.userChunk = _config.chunk;
				w.userComplete = _config.complete;
				w.userError = _config.error;

				_config.step = isFunction(_config.step);
				_config.chunk = isFunction(_config.chunk);
				_config.complete = isFunction(_config.complete);
				_config.error = isFunction(_config.error);
				delete _config.worker;	// prevent infinite loop

				w.postMessage({
					input: _input,
					config: _config,
					workerId: w.id
				});

				return;
			}

			var streamer = null;
			if (_input === Papa.NODE_STREAM_INPUT && typeof PAPA_BROWSER_CONTEXT === 'undefined')
			{
				// create a node Duplex stream for use
				// with .pipe
				streamer = new DuplexStreamStreamer(_config);
				return streamer.getStream();
			}
			else if (typeof _input === 'string')
			{
				_input = stripBom(_input);
				if (_config.download)
					streamer = new NetworkStreamer(_config);
				else
					streamer = new StringStreamer(_config);
			}
			else if (_input.readable === true && isFunction(_input.read) && isFunction(_input.on))
			{
				streamer = new ReadableStreamStreamer(_config);
			}
			else if ((global.File && _input instanceof File) || _input instanceof Object)	// ...Safari. (see issue #106)
				streamer = new FileStreamer(_config);

			return streamer.stream(_input);

			// Strip character from UTF-8 BOM encoded files that cause issue parsing the file
			function stripBom(string) {
				if (string.charCodeAt(0) === 0xfeff) {
					return string.slice(1);
				}
				return string;
			}
		}






		function JsonToCsv(_input, _config)
		{
			// Default configuration

			/** whether to surround every datum with quotes */
			var _quotes = false;

			/** whether to write headers */
			var _writeHeader = true;

			/** delimiting character(s) */
			var _delimiter = ',';

			/** newline character(s) */
			var _newline = '\r\n';

			/** quote character */
			var _quoteChar = '"';

			/** escaped quote character, either "" or <config.escapeChar>" */
			var _escapedQuote = _quoteChar + _quoteChar;

			/** whether to skip empty lines */
			var _skipEmptyLines = false;

			/** the columns (keys) we expect when we unparse objects */
			var _columns = null;

			/** whether to prevent outputting cells that can be parsed as formulae by spreadsheet software (Excel and LibreOffice) */
			var _escapeFormulae = false;

			unpackConfig();

			var quoteCharRegex = new RegExp(escapeRegExp(_quoteChar), 'g');

			if (typeof _input === 'string')
				_input = JSON.parse(_input);

			if (Array.isArray(_input))
			{
				if (!_input.length || Array.isArray(_input[0]))
					return serialize(null, _input, _skipEmptyLines);
				else if (typeof _input[0] === 'object')
					return serialize(_columns || Object.keys(_input[0]), _input, _skipEmptyLines);
			}
			else if (typeof _input === 'object')
			{
				if (typeof _input.data === 'string')
					_input.data = JSON.parse(_input.data);

				if (Array.isArray(_input.data))
				{
					if (!_input.fields)
						_input.fields = _input.meta && _input.meta.fields || _columns;

					if (!_input.fields)
						_input.fields =  Array.isArray(_input.data[0])
							? _input.fields
							: typeof _input.data[0] === 'object'
								? Object.keys(_input.data[0])
								: [];

					if (!(Array.isArray(_input.data[0])) && typeof _input.data[0] !== 'object')
						_input.data = [_input.data];	// handles input like [1,2,3] or ['asdf']
				}

				return serialize(_input.fields || [], _input.data || [], _skipEmptyLines);
			}

			// Default (any valid paths should return before this)
			throw new Error('Unable to serialize unrecognized input');


			function unpackConfig()
			{
				if (typeof _config !== 'object')
					return;

				if (typeof _config.delimiter === 'string'
	                && !Papa.BAD_DELIMITERS.filter(function(value) { return _config.delimiter.indexOf(value) !== -1; }).length)
				{
					_delimiter = _config.delimiter;
				}

				if (typeof _config.quotes === 'boolean'
					|| typeof _config.quotes === 'function'
					|| Array.isArray(_config.quotes))
					_quotes = _config.quotes;

				if (typeof _config.skipEmptyLines === 'boolean'
					|| typeof _config.skipEmptyLines === 'string')
					_skipEmptyLines = _config.skipEmptyLines;

				if (typeof _config.newline === 'string')
					_newline = _config.newline;

				if (typeof _config.quoteChar === 'string')
					_quoteChar = _config.quoteChar;

				if (typeof _config.header === 'boolean')
					_writeHeader = _config.header;

				if (Array.isArray(_config.columns)) {

					if (_config.columns.length === 0) throw new Error('Option columns is empty');

					_columns = _config.columns;
				}

				if (_config.escapeChar !== undefined) {
					_escapedQuote = _config.escapeChar + _quoteChar;
				}

				if (_config.escapeFormulae instanceof RegExp) {
					_escapeFormulae = _config.escapeFormulae;
				} else if (typeof _config.escapeFormulae === 'boolean' && _config.escapeFormulae) {
					_escapeFormulae =  /^[=+\-@\t\r].*$/;
				}
			}

			/** The double for loop that iterates the data and writes out a CSV string including header row */
			function serialize(fields, data, skipEmptyLines)
			{
				var csv = '';

				if (typeof fields === 'string')
					fields = JSON.parse(fields);
				if (typeof data === 'string')
					data = JSON.parse(data);

				var hasHeader = Array.isArray(fields) && fields.length > 0;
				var dataKeyedByField = !(Array.isArray(data[0]));

				// If there a header row, write it first
				if (hasHeader && _writeHeader)
				{
					for (var i = 0; i < fields.length; i++)
					{
						if (i > 0)
							csv += _delimiter;
						csv += safe(fields[i], i);
					}
					if (data.length > 0)
						csv += _newline;
				}

				// Then write out the data
				for (var row = 0; row < data.length; row++)
				{
					var maxCol = hasHeader ? fields.length : data[row].length;

					var emptyLine = false;
					var nullLine = hasHeader ? Object.keys(data[row]).length === 0 : data[row].length === 0;
					if (skipEmptyLines && !hasHeader)
					{
						emptyLine = skipEmptyLines === 'greedy' ? data[row].join('').trim() === '' : data[row].length === 1 && data[row][0].length === 0;
					}
					if (skipEmptyLines === 'greedy' && hasHeader) {
						var line = [];
						for (var c = 0; c < maxCol; c++) {
							var cx = dataKeyedByField ? fields[c] : c;
							line.push(data[row][cx]);
						}
						emptyLine = line.join('').trim() === '';
					}
					if (!emptyLine)
					{
						for (var col = 0; col < maxCol; col++)
						{
							if (col > 0 && !nullLine)
								csv += _delimiter;
							var colIdx = hasHeader && dataKeyedByField ? fields[col] : col;
							csv += safe(data[row][colIdx], col);
						}
						if (row < data.length - 1 && (!skipEmptyLines || (maxCol > 0 && !nullLine)))
						{
							csv += _newline;
						}
					}
				}
				return csv;
			}

			/** Encloses a value around quotes if needed (makes a value safe for CSV insertion) */
			function safe(str, col)
			{
				if (typeof str === 'undefined' || str === null)
					return '';

				if (str.constructor === Date)
					return JSON.stringify(str).slice(1, 25);

				var needsQuotes = false;

				if (_escapeFormulae && typeof str === "string" && _escapeFormulae.test(str)) {
					str = "'" + str;
					needsQuotes = true;
				}

				var escapedQuoteStr = str.toString().replace(quoteCharRegex, _escapedQuote);

				needsQuotes = needsQuotes
								|| _quotes === true
								|| (typeof _quotes === 'function' && _quotes(str, col))
								|| (Array.isArray(_quotes) && _quotes[col])
								|| hasAny(escapedQuoteStr, Papa.BAD_DELIMITERS)
								|| escapedQuoteStr.indexOf(_delimiter) > -1
								|| escapedQuoteStr.charAt(0) === ' '
								|| escapedQuoteStr.charAt(escapedQuoteStr.length - 1) === ' ';

				return needsQuotes ? _quoteChar + escapedQuoteStr + _quoteChar : escapedQuoteStr;
			}

			function hasAny(str, substrings)
			{
				for (var i = 0; i < substrings.length; i++)
					if (str.indexOf(substrings[i]) > -1)
						return true;
				return false;
			}
		}


		/** ChunkStreamer is the base prototype for various streamer implementations. */
		function ChunkStreamer(config)
		{
			this._handle = null;
			this._finished = false;
			this._completed = false;
			this._halted = false;
			this._input = null;
			this._baseIndex = 0;
			this._partialLine = '';
			this._rowCount = 0;
			this._start = 0;
			this._nextChunk = null;
			this.isFirstChunk = true;
			this._completeResults = {
				data: [],
				errors: [],
				meta: {}
			};
			replaceConfig.call(this, config);

			this.parseChunk = function(chunk, isFakeChunk)
			{
				// First chunk pre-processing
				const skipFirstNLines = parseInt(this._config.skipFirstNLines) || 0;
				if (this.isFirstChunk && skipFirstNLines > 0) {
					let _newline = this._config.newline;
					if (!_newline) {
						const quoteChar = this._config.quoteChar || '"';
						_newline = this._handle.guessLineEndings(chunk, quoteChar);
					}
					const splitChunk = chunk.split(_newline);
					chunk = [...splitChunk.slice(skipFirstNLines)].join(_newline);
				}
				if (this.isFirstChunk && isFunction(this._config.beforeFirstChunk))
				{
					var modifiedChunk = this._config.beforeFirstChunk(chunk);
					if (modifiedChunk !== undefined)
						chunk = modifiedChunk;
				}
				this.isFirstChunk = false;
				this._halted = false;

				// Rejoin the line we likely just split in two by chunking the file
				var aggregate = this._partialLine + chunk;
				this._partialLine = '';
				var results = this._handle.parse(aggregate, this._baseIndex, !this._finished);

				if (this._handle.paused() || this._handle.aborted()) {
					this._halted = true;
					return;
				}

				var lastIndex = results.meta.cursor;

				if (!this._finished)
				{
					this._partialLine = aggregate.substring(lastIndex - this._baseIndex);
					this._baseIndex = lastIndex;
				}

				if (results && results.data)
					this._rowCount += results.data.length;

				var finishedIncludingPreview = this._finished || (this._config.preview && this._rowCount >= this._config.preview);

				if (IS_PAPA_WORKER)
				{
					global.postMessage({
						results: results,
						workerId: Papa.WORKER_ID,
						finished: finishedIncludingPreview
					});
				}
				else if (isFunction(this._config.chunk) && !isFakeChunk)
				{
					this._config.chunk(results, this._handle);
					if (this._handle.paused() || this._handle.aborted()) {
						this._halted = true;
						return;
					}
					results = undefined;
					this._completeResults = undefined;
				}

				if (!this._config.step && !this._config.chunk) {
					this._completeResults.data = this._completeResults.data.concat(results.data);
					this._completeResults.errors = this._completeResults.errors.concat(results.errors);
					this._completeResults.meta = results.meta;
				}

				if (!this._completed && finishedIncludingPreview && isFunction(this._config.complete) && (!results || !results.meta.aborted)) {
					this._config.complete(this._completeResults, this._input);
					this._completed = true;
				}

				if (!finishedIncludingPreview && (!results || !results.meta.paused))
					this._nextChunk();

				return results;
			};

			this._sendError = function(error)
			{
				if (isFunction(this._config.error))
					this._config.error(error);
				else if (IS_PAPA_WORKER && this._config.error)
				{
					global.postMessage({
						workerId: Papa.WORKER_ID,
						error: error,
						finished: false
					});
				}
			};

			function replaceConfig(config)
			{
				// Deep-copy the config so we can edit it
				var configCopy = copy(config);
				configCopy.chunkSize = parseInt(configCopy.chunkSize);	// parseInt VERY important so we don't concatenate strings!
				if (!config.step && !config.chunk)
					configCopy.chunkSize = null;  // disable Range header if not streaming; bad values break IIS - see issue #196
				this._handle = new ParserHandle(configCopy);
				this._handle.streamer = this;
				this._config = configCopy;	// persist the copy to the caller
			}
		}


		function NetworkStreamer(config)
		{
			config = config || {};
			if (!config.chunkSize)
				config.chunkSize = Papa.RemoteChunkSize;
			ChunkStreamer.call(this, config);

			var xhr;

			if (IS_WORKER)
			{
				this._nextChunk = function()
				{
					this._readChunk();
					this._chunkLoaded();
				};
			}
			else
			{
				this._nextChunk = function()
				{
					this._readChunk();
				};
			}

			this.stream = function(url)
			{
				this._input = url;
				this._nextChunk();	// Starts streaming
			};

			this._readChunk = function()
			{
				if (this._finished)
				{
					this._chunkLoaded();
					return;
				}

				xhr = new XMLHttpRequest();

				if (this._config.withCredentials)
				{
					xhr.withCredentials = this._config.withCredentials;
				}

				if (!IS_WORKER)
				{
					xhr.onload = bindFunction(this._chunkLoaded, this);
					xhr.onerror = bindFunction(this._chunkError, this);
				}

				xhr.open(this._config.downloadRequestBody ? 'POST' : 'GET', this._input, !IS_WORKER);
				// Headers can only be set when once the request state is OPENED
				if (this._config.downloadRequestHeaders)
				{
					var headers = this._config.downloadRequestHeaders;

					for (var headerName in headers)
					{
						xhr.setRequestHeader(headerName, headers[headerName]);
					}
				}

				if (this._config.chunkSize)
				{
					var end = this._start + this._config.chunkSize - 1;	// minus one because byte range is inclusive
					xhr.setRequestHeader('Range', 'bytes=' + this._start + '-' + end);
				}

				try {
					xhr.send(this._config.downloadRequestBody);
				}
				catch (err) {
					this._chunkError(err.message);
				}

				if (IS_WORKER && xhr.status === 0)
					this._chunkError();
			};

			this._chunkLoaded = function()
			{
				if (xhr.readyState !== 4)
					return;

				if (xhr.status < 200 || xhr.status >= 400)
				{
					this._chunkError();
					return;
				}

				// Use chunckSize as it may be a diference on reponse lentgh due to characters with more than 1 byte
				this._start += this._config.chunkSize ? this._config.chunkSize : xhr.responseText.length;
				this._finished = !this._config.chunkSize || this._start >= getFileSize(xhr);
				this.parseChunk(xhr.responseText);
			};

			this._chunkError = function(errorMessage)
			{
				var errorText = xhr.statusText || errorMessage;
				this._sendError(new Error(errorText));
			};

			function getFileSize(xhr)
			{
				var contentRange = xhr.getResponseHeader('Content-Range');
				if (contentRange === null) { // no content range, then finish!
					return -1;
				}
				return parseInt(contentRange.substring(contentRange.lastIndexOf('/') + 1));
			}
		}
		NetworkStreamer.prototype = Object.create(ChunkStreamer.prototype);
		NetworkStreamer.prototype.constructor = NetworkStreamer;


		function FileStreamer(config)
		{
			config = config || {};
			if (!config.chunkSize)
				config.chunkSize = Papa.LocalChunkSize;
			ChunkStreamer.call(this, config);

			var reader, slice;

			// FileReader is better than FileReaderSync (even in worker) - see http://stackoverflow.com/q/24708649/1048862
			// But Firefox is a pill, too - see issue #76: https://github.com/mholt/PapaParse/issues/76
			var usingAsyncReader = typeof FileReader !== 'undefined';	// Safari doesn't consider it a function - see issue #105

			this.stream = function(file)
			{
				this._input = file;
				slice = file.slice || file.webkitSlice || file.mozSlice;

				if (usingAsyncReader)
				{
					reader = new FileReader();		// Preferred method of reading files, even in workers
					reader.onload = bindFunction(this._chunkLoaded, this);
					reader.onerror = bindFunction(this._chunkError, this);
				}
				else
					reader = new FileReaderSync();	// Hack for running in a web worker in Firefox

				this._nextChunk();	// Starts streaming
			};

			this._nextChunk = function()
			{
				if (!this._finished && (!this._config.preview || this._rowCount < this._config.preview))
					this._readChunk();
			};

			this._readChunk = function()
			{
				var input = this._input;
				if (this._config.chunkSize)
				{
					var end = Math.min(this._start + this._config.chunkSize, this._input.size);
					input = slice.call(input, this._start, end);
				}
				var txt = reader.readAsText(input, this._config.encoding);
				if (!usingAsyncReader)
					this._chunkLoaded({ target: { result: txt } });	// mimic the async signature
			};

			this._chunkLoaded = function(event)
			{
				// Very important to increment start each time before handling results
				this._start += this._config.chunkSize;
				this._finished = !this._config.chunkSize || this._start >= this._input.size;
				this.parseChunk(event.target.result);
			};

			this._chunkError = function()
			{
				this._sendError(reader.error);
			};

		}
		FileStreamer.prototype = Object.create(ChunkStreamer.prototype);
		FileStreamer.prototype.constructor = FileStreamer;


		function StringStreamer(config)
		{
			config = config || {};
			ChunkStreamer.call(this, config);

			var remaining;
			this.stream = function(s)
			{
				remaining = s;
				return this._nextChunk();
			};
			this._nextChunk = function()
			{
				if (this._finished) return;
				var size = this._config.chunkSize;
				var chunk;
				if(size) {
					chunk = remaining.substring(0, size);
					remaining = remaining.substring(size);
				} else {
					chunk = remaining;
					remaining = '';
				}
				this._finished = !remaining;
				return this.parseChunk(chunk);
			};
		}
		StringStreamer.prototype = Object.create(StringStreamer.prototype);
		StringStreamer.prototype.constructor = StringStreamer;


		function ReadableStreamStreamer(config)
		{
			config = config || {};

			ChunkStreamer.call(this, config);

			var queue = [];
			var parseOnData = true;
			var streamHasEnded = false;

			this.pause = function()
			{
				ChunkStreamer.prototype.pause.apply(this, arguments);
				this._input.pause();
			};

			this.resume = function()
			{
				ChunkStreamer.prototype.resume.apply(this, arguments);
				this._input.resume();
			};

			this.stream = function(stream)
			{
				this._input = stream;

				this._input.on('data', this._streamData);
				this._input.on('end', this._streamEnd);
				this._input.on('error', this._streamError);
			};

			this._checkIsFinished = function()
			{
				if (streamHasEnded && queue.length === 1) {
					this._finished = true;
				}
			};

			this._nextChunk = function()
			{
				this._checkIsFinished();
				if (queue.length)
				{
					this.parseChunk(queue.shift());
				}
				else
				{
					parseOnData = true;
				}
			};

			this._streamData = bindFunction(function(chunk)
			{
				try
				{
					queue.push(typeof chunk === 'string' ? chunk : chunk.toString(this._config.encoding));

					if (parseOnData)
					{
						parseOnData = false;
						this._checkIsFinished();
						this.parseChunk(queue.shift());
					}
				}
				catch (error)
				{
					this._streamError(error);
				}
			}, this);

			this._streamError = bindFunction(function(error)
			{
				this._streamCleanUp();
				this._sendError(error);
			}, this);

			this._streamEnd = bindFunction(function()
			{
				this._streamCleanUp();
				streamHasEnded = true;
				this._streamData('');
			}, this);

			this._streamCleanUp = bindFunction(function()
			{
				this._input.removeListener('data', this._streamData);
				this._input.removeListener('end', this._streamEnd);
				this._input.removeListener('error', this._streamError);
			}, this);
		}
		ReadableStreamStreamer.prototype = Object.create(ChunkStreamer.prototype);
		ReadableStreamStreamer.prototype.constructor = ReadableStreamStreamer;


		function DuplexStreamStreamer(_config) {
			var Duplex = require$$0.Duplex;
			var config = copy(_config);
			var parseOnWrite = true;
			var writeStreamHasFinished = false;
			var parseCallbackQueue = [];
			var stream = null;

			this._onCsvData = function(results)
			{
				var data = results.data;
				if (!stream.push(data) && !this._handle.paused()) {
					// the writeable consumer buffer has filled up
					// so we need to pause until more items
					// can be processed
					this._handle.pause();
				}
			};

			this._onCsvComplete = function()
			{
				// node will finish the read stream when
				// null is pushed
				stream.push(null);
			};

			config.step = bindFunction(this._onCsvData, this);
			config.complete = bindFunction(this._onCsvComplete, this);
			ChunkStreamer.call(this, config);

			this._nextChunk = function()
			{
				if (writeStreamHasFinished && parseCallbackQueue.length === 1) {
					this._finished = true;
				}
				if (parseCallbackQueue.length) {
					parseCallbackQueue.shift()();
				} else {
					parseOnWrite = true;
				}
			};

			this._addToParseQueue = function(chunk, callback)
			{
				// add to queue so that we can indicate
				// completion via callback
				// node will automatically pause the incoming stream
				// when too many items have been added without their
				// callback being invoked
				parseCallbackQueue.push(bindFunction(function() {
					this.parseChunk(typeof chunk === 'string' ? chunk : chunk.toString(config.encoding));
					if (isFunction(callback)) {
						return callback();
					}
				}, this));
				if (parseOnWrite) {
					parseOnWrite = false;
					this._nextChunk();
				}
			};

			this._onRead = function()
			{
				if (this._handle.paused()) {
					// the writeable consumer can handle more data
					// so resume the chunk parsing
					this._handle.resume();
				}
			};

			this._onWrite = function(chunk, encoding, callback)
			{
				this._addToParseQueue(chunk, callback);
			};

			this._onWriteComplete = function()
			{
				writeStreamHasFinished = true;
				// have to write empty string
				// so parser knows its done
				this._addToParseQueue('');
			};

			this.getStream = function()
			{
				return stream;
			};
			stream = new Duplex({
				readableObjectMode: true,
				decodeStrings: false,
				read: bindFunction(this._onRead, this),
				write: bindFunction(this._onWrite, this)
			});
			stream.once('finish', bindFunction(this._onWriteComplete, this));
		}
		if (typeof PAPA_BROWSER_CONTEXT === 'undefined') {
			DuplexStreamStreamer.prototype = Object.create(ChunkStreamer.prototype);
			DuplexStreamStreamer.prototype.constructor = DuplexStreamStreamer;
		}


		// Use one ParserHandle per entire CSV file or string
		function ParserHandle(_config)
		{
			// One goal is to minimize the use of regular expressions...
			var MAX_FLOAT = Math.pow(2, 53);
			var MIN_FLOAT = -MAX_FLOAT;
			var FLOAT = /^\s*-?(\d+\.?|\.\d+|\d+\.\d+)([eE][-+]?\d+)?\s*$/;
			var ISO_DATE = /^((\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z)))$/;
			var self = this;
			var _stepCounter = 0;	// Number of times step was called (number of rows parsed)
			var _rowCounter = 0;	// Number of rows that have been parsed so far
			var _input;				// The input being parsed
			var _parser;			// The core parser being used
			var _paused = false;	// Whether we are paused or not
			var _aborted = false;	// Whether the parser has aborted or not
			var _delimiterError;	// Temporary state between delimiter detection and processing results
			var _fields = [];		// Fields are from the header row of the input, if there is one
			var _results = {		// The last results returned from the parser
				data: [],
				errors: [],
				meta: {}
			};

			if (isFunction(_config.step))
			{
				var userStep = _config.step;
				_config.step = function(results)
				{
					_results = results;

					if (needsHeaderRow())
						processResults();
					else	// only call user's step function after header row
					{
						processResults();

						// It's possbile that this line was empty and there's no row here after all
						if (_results.data.length === 0)
							return;

						_stepCounter += results.data.length;
						if (_config.preview && _stepCounter > _config.preview)
							_parser.abort();
						else {
							_results.data = _results.data[0];
							userStep(_results, self);
						}
					}
				};
			}

			/**
			 * Parses input. Most users won't need, and shouldn't mess with, the baseIndex
			 * and ignoreLastRow parameters. They are used by streamers (wrapper functions)
			 * when an input comes in multiple chunks, like from a file.
			 */
			this.parse = function(input, baseIndex, ignoreLastRow)
			{
				var quoteChar = _config.quoteChar || '"';
				if (!_config.newline)
					_config.newline = this.guessLineEndings(input, quoteChar);

				_delimiterError = false;
				if (!_config.delimiter)
				{
					var delimGuess = guessDelimiter(input, _config.newline, _config.skipEmptyLines, _config.comments, _config.delimitersToGuess);
					if (delimGuess.successful)
						_config.delimiter = delimGuess.bestDelimiter;
					else
					{
						_delimiterError = true;	// add error after parsing (otherwise it would be overwritten)
						_config.delimiter = Papa.DefaultDelimiter;
					}
					_results.meta.delimiter = _config.delimiter;
				}
				else if(isFunction(_config.delimiter))
				{
					_config.delimiter = _config.delimiter(input);
					_results.meta.delimiter = _config.delimiter;
				}

				var parserConfig = copy(_config);
				if (_config.preview && _config.header)
					parserConfig.preview++;	// to compensate for header row

				_input = input;
				_parser = new Parser(parserConfig);
				_results = _parser.parse(_input, baseIndex, ignoreLastRow);
				processResults();
				return _paused ? { meta: { paused: true } } : (_results || { meta: { paused: false } });
			};

			this.paused = function()
			{
				return _paused;
			};

			this.pause = function()
			{
				_paused = true;
				_parser.abort();

				// If it is streaming via "chunking", the reader will start appending correctly already so no need to substring,
				// otherwise we can get duplicate content within a row
				_input = isFunction(_config.chunk) ? "" : _input.substring(_parser.getCharIndex());
			};

			this.resume = function()
			{
				if(self.streamer._halted) {
					_paused = false;
					self.streamer.parseChunk(_input, true);
				} else {
					// Bugfix: #636 In case the processing hasn't halted yet
					// wait for it to halt in order to resume
					setTimeout(self.resume, 3);
				}
			};

			this.aborted = function()
			{
				return _aborted;
			};

			this.abort = function()
			{
				_aborted = true;
				_parser.abort();
				_results.meta.aborted = true;
				if (isFunction(_config.complete))
					_config.complete(_results);
				_input = '';
			};

			this.guessLineEndings = function(input, quoteChar)
			{
				input = input.substring(0, 1024 * 1024);	// max length 1 MB
				// Replace all the text inside quotes
				var re = new RegExp(escapeRegExp(quoteChar) + '([^]*?)' + escapeRegExp(quoteChar), 'gm');
				input = input.replace(re, '');

				var r = input.split('\r');

				var n = input.split('\n');

				var nAppearsFirst = (n.length > 1 && n[0].length < r[0].length);

				if (r.length === 1 || nAppearsFirst)
					return '\n';

				var numWithN = 0;
				for (var i = 0; i < r.length; i++)
				{
					if (r[i][0] === '\n')
						numWithN++;
				}

				return numWithN >= r.length / 2 ? '\r\n' : '\r';
			};

			function testEmptyLine(s) {
				return _config.skipEmptyLines === 'greedy' ? s.join('').trim() === '' : s.length === 1 && s[0].length === 0;
			}

			function testFloat(s) {
				if (FLOAT.test(s)) {
					var floatValue = parseFloat(s);
					if (floatValue > MIN_FLOAT && floatValue < MAX_FLOAT) {
						return true;
					}
				}
				return false;
			}

			function processResults()
			{
				if (_results && _delimiterError)
				{
					addError('Delimiter', 'UndetectableDelimiter', 'Unable to auto-detect delimiting character; defaulted to \'' + Papa.DefaultDelimiter + '\'');
					_delimiterError = false;
				}

				if (_config.skipEmptyLines)
				{
					_results.data = _results.data.filter(function(d) {
						return !testEmptyLine(d);
					});
				}

				if (needsHeaderRow())
					fillHeaderFields();

				return applyHeaderAndDynamicTypingAndTransformation();
			}

			function needsHeaderRow()
			{
				return _config.header && _fields.length === 0;
			}

			function fillHeaderFields()
			{
				if (!_results)
					return;

				function addHeader(header, i)
				{
					if (isFunction(_config.transformHeader))
						header = _config.transformHeader(header, i);

					_fields.push(header);
				}

				if (Array.isArray(_results.data[0]))
				{
					for (var i = 0; needsHeaderRow() && i < _results.data.length; i++)
						_results.data[i].forEach(addHeader);

					_results.data.splice(0, 1);
				}
				// if _results.data[0] is not an array, we are in a step where _results.data is the row.
				else
					_results.data.forEach(addHeader);
			}

			function shouldApplyDynamicTyping(field) {
				// Cache function values to avoid calling it for each row
				if (_config.dynamicTypingFunction && _config.dynamicTyping[field] === undefined) {
					_config.dynamicTyping[field] = _config.dynamicTypingFunction(field);
				}
				return (_config.dynamicTyping[field] || _config.dynamicTyping) === true;
			}

			function parseDynamic(field, value)
			{
				if (shouldApplyDynamicTyping(field))
				{
					if (value === 'true' || value === 'TRUE')
						return true;
					else if (value === 'false' || value === 'FALSE')
						return false;
					else if (testFloat(value))
						return parseFloat(value);
					else if (ISO_DATE.test(value))
						return new Date(value);
					else
						return (value === '' ? null : value);
				}
				return value;
			}

			function applyHeaderAndDynamicTypingAndTransformation()
			{
				if (!_results || (!_config.header && !_config.dynamicTyping && !_config.transform))
					return _results;

				function processRow(rowSource, i)
				{
					var row = _config.header ? {} : [];

					var j;
					for (j = 0; j < rowSource.length; j++)
					{
						var field = j;
						var value = rowSource[j];

						if (_config.header)
							field = j >= _fields.length ? '__parsed_extra' : _fields[j];

						if (_config.transform)
							value = _config.transform(value,field);

						value = parseDynamic(field, value);

						if (field === '__parsed_extra')
						{
							row[field] = row[field] || [];
							row[field].push(value);
						}
						else
							row[field] = value;
					}


					if (_config.header)
					{
						if (j > _fields.length)
							addError('FieldMismatch', 'TooManyFields', 'Too many fields: expected ' + _fields.length + ' fields but parsed ' + j, _rowCounter + i);
						else if (j < _fields.length)
							addError('FieldMismatch', 'TooFewFields', 'Too few fields: expected ' + _fields.length + ' fields but parsed ' + j, _rowCounter + i);
					}

					return row;
				}

				var incrementBy = 1;
				if (!_results.data.length || Array.isArray(_results.data[0]))
				{
					_results.data = _results.data.map(processRow);
					incrementBy = _results.data.length;
				}
				else
					_results.data = processRow(_results.data, 0);


				if (_config.header && _results.meta)
					_results.meta.fields = _fields;

				_rowCounter += incrementBy;
				return _results;
			}

			function guessDelimiter(input, newline, skipEmptyLines, comments, delimitersToGuess) {
				var bestDelim, bestDelta, fieldCountPrevRow, maxFieldCount;

				delimitersToGuess = delimitersToGuess || [',', '\t', '|', ';', Papa.RECORD_SEP, Papa.UNIT_SEP];

				for (var i = 0; i < delimitersToGuess.length; i++) {
					var delim = delimitersToGuess[i];
					var delta = 0, avgFieldCount = 0, emptyLinesCount = 0;
					fieldCountPrevRow = undefined;

					var preview = new Parser({
						comments: comments,
						delimiter: delim,
						newline: newline,
						preview: 10
					}).parse(input);

					for (var j = 0; j < preview.data.length; j++) {
						if (skipEmptyLines && testEmptyLine(preview.data[j])) {
							emptyLinesCount++;
							continue;
						}
						var fieldCount = preview.data[j].length;
						avgFieldCount += fieldCount;

						if (typeof fieldCountPrevRow === 'undefined') {
							fieldCountPrevRow = fieldCount;
							continue;
						}
						else if (fieldCount > 0) {
							delta += Math.abs(fieldCount - fieldCountPrevRow);
							fieldCountPrevRow = fieldCount;
						}
					}

					if (preview.data.length > 0)
						avgFieldCount /= (preview.data.length - emptyLinesCount);

					if ((typeof bestDelta === 'undefined' || delta <= bestDelta)
						&& (typeof maxFieldCount === 'undefined' || avgFieldCount > maxFieldCount) && avgFieldCount > 1.99) {
						bestDelta = delta;
						bestDelim = delim;
						maxFieldCount = avgFieldCount;
					}
				}

				_config.delimiter = bestDelim;

				return {
					successful: !!bestDelim,
					bestDelimiter: bestDelim
				};
			}

			function addError(type, code, msg, row)
			{
				var error = {
					type: type,
					code: code,
					message: msg
				};
				if(row !== undefined) {
					error.row = row;
				}
				_results.errors.push(error);
			}
		}

		/** https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions */
		function escapeRegExp(string)
		{
			return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
		}

		/** The core parser implements speedy and correct CSV parsing */
		function Parser(config)
		{
			// Unpack the config object
			config = config || {};
			var delim = config.delimiter;
			var newline = config.newline;
			var comments = config.comments;
			var step = config.step;
			var preview = config.preview;
			var fastMode = config.fastMode;
			var quoteChar;
			var renamedHeaders = null;
			var headerParsed = false;

			if (config.quoteChar === undefined || config.quoteChar === null) {
				quoteChar = '"';
			} else {
				quoteChar = config.quoteChar;
			}
			var escapeChar = quoteChar;
			if (config.escapeChar !== undefined) {
				escapeChar = config.escapeChar;
			}

			// Delimiter must be valid
			if (typeof delim !== 'string'
				|| Papa.BAD_DELIMITERS.indexOf(delim) > -1)
				delim = ',';

			// Comment character must be valid
			if (comments === delim)
				throw new Error('Comment character same as delimiter');
			else if (comments === true)
				comments = '#';
			else if (typeof comments !== 'string'
				|| Papa.BAD_DELIMITERS.indexOf(comments) > -1)
				comments = false;

			// Newline must be valid: \r, \n, or \r\n
			if (newline !== '\n' && newline !== '\r' && newline !== '\r\n')
				newline = '\n';

			// We're gonna need these at the Parser scope
			var cursor = 0;
			var aborted = false;

			this.parse = function(input, baseIndex, ignoreLastRow)
			{
				// For some reason, in Chrome, this speeds things up (!?)
				if (typeof input !== 'string')
					throw new Error('Input must be a string');

				// We don't need to compute some of these every time parse() is called,
				// but having them in a more local scope seems to perform better
				var inputLen = input.length,
					delimLen = delim.length,
					newlineLen = newline.length,
					commentsLen = comments.length;
				var stepIsFunction = isFunction(step);

				// Establish starting state
				cursor = 0;
				var data = [], errors = [], row = [], lastCursor = 0;

				if (!input)
					return returnable();

				if (fastMode || (fastMode !== false && input.indexOf(quoteChar) === -1))
				{
					var rows = input.split(newline);
					for (var i = 0; i < rows.length; i++)
					{
						row = rows[i];
						cursor += row.length;

						if (i !== rows.length - 1)
							cursor += newline.length;
						else if (ignoreLastRow)
							return returnable();
						if (comments && row.substring(0, commentsLen) === comments)
							continue;
						if (stepIsFunction)
						{
							data = [];
							pushRow(row.split(delim));
							doStep();
							if (aborted)
								return returnable();
						}
						else
							pushRow(row.split(delim));
						if (preview && i >= preview)
						{
							data = data.slice(0, preview);
							return returnable(true);
						}
					}
					return returnable();
				}

				var nextDelim = input.indexOf(delim, cursor);
				var nextNewline = input.indexOf(newline, cursor);
				var quoteCharRegex = new RegExp(escapeRegExp(escapeChar) + escapeRegExp(quoteChar), 'g');
				var quoteSearch = input.indexOf(quoteChar, cursor);

				// Parser loop
				for (;;)
				{
					// Field has opening quote
					if (input[cursor] === quoteChar)
					{
						// Start our search for the closing quote where the cursor is
						quoteSearch = cursor;

						// Skip the opening quote
						cursor++;

						for (;;)
						{
							// Find closing quote
							quoteSearch = input.indexOf(quoteChar, quoteSearch + 1);

							//No other quotes are found - no other delimiters
							if (quoteSearch === -1)
							{
								if (!ignoreLastRow) {
									// No closing quote... what a pity
									errors.push({
										type: 'Quotes',
										code: 'MissingQuotes',
										message: 'Quoted field unterminated',
										row: data.length,	// row has yet to be inserted
										index: cursor
									});
								}
								return finish();
							}

							// Closing quote at EOF
							if (quoteSearch === inputLen - 1)
							{
								var value = input.substring(cursor, quoteSearch).replace(quoteCharRegex, quoteChar);
								return finish(value);
							}

							// If this quote is escaped, it's part of the data; skip it
							// If the quote character is the escape character, then check if the next character is the escape character
							if (quoteChar === escapeChar &&  input[quoteSearch + 1] === escapeChar)
							{
								quoteSearch++;
								continue;
							}

							// If the quote character is not the escape character, then check if the previous character was the escape character
							if (quoteChar !== escapeChar && quoteSearch !== 0 && input[quoteSearch - 1] === escapeChar)
							{
								continue;
							}

							if(nextDelim !== -1 && nextDelim < (quoteSearch + 1)) {
								nextDelim = input.indexOf(delim, (quoteSearch + 1));
							}
							if(nextNewline !== -1 && nextNewline < (quoteSearch + 1)) {
								nextNewline = input.indexOf(newline, (quoteSearch + 1));
							}
							// Check up to nextDelim or nextNewline, whichever is closest
							var checkUpTo = nextNewline === -1 ? nextDelim : Math.min(nextDelim, nextNewline);
							var spacesBetweenQuoteAndDelimiter = extraSpaces(checkUpTo);

							// Closing quote followed by delimiter or 'unnecessary spaces + delimiter'
							if (input.substr(quoteSearch + 1 + spacesBetweenQuoteAndDelimiter, delimLen) === delim)
							{
								row.push(input.substring(cursor, quoteSearch).replace(quoteCharRegex, quoteChar));
								cursor = quoteSearch + 1 + spacesBetweenQuoteAndDelimiter + delimLen;

								// If char after following delimiter is not quoteChar, we find next quote char position
								if (input[quoteSearch + 1 + spacesBetweenQuoteAndDelimiter + delimLen] !== quoteChar)
								{
									quoteSearch = input.indexOf(quoteChar, cursor);
								}
								nextDelim = input.indexOf(delim, cursor);
								nextNewline = input.indexOf(newline, cursor);
								break;
							}

							var spacesBetweenQuoteAndNewLine = extraSpaces(nextNewline);

							// Closing quote followed by newline or 'unnecessary spaces + newLine'
							if (input.substring(quoteSearch + 1 + spacesBetweenQuoteAndNewLine, quoteSearch + 1 + spacesBetweenQuoteAndNewLine + newlineLen) === newline)
							{
								row.push(input.substring(cursor, quoteSearch).replace(quoteCharRegex, quoteChar));
								saveRow(quoteSearch + 1 + spacesBetweenQuoteAndNewLine + newlineLen);
								nextDelim = input.indexOf(delim, cursor);	// because we may have skipped the nextDelim in the quoted field
								quoteSearch = input.indexOf(quoteChar, cursor);	// we search for first quote in next line

								if (stepIsFunction)
								{
									doStep();
									if (aborted)
										return returnable();
								}

								if (preview && data.length >= preview)
									return returnable(true);

								break;
							}


							// Checks for valid closing quotes are complete (escaped quotes or quote followed by EOF/delimiter/newline) -- assume these quotes are part of an invalid text string
							errors.push({
								type: 'Quotes',
								code: 'InvalidQuotes',
								message: 'Trailing quote on quoted field is malformed',
								row: data.length,	// row has yet to be inserted
								index: cursor
							});

							quoteSearch++;
							continue;

						}

						continue;
					}

					// Comment found at start of new line
					if (comments && row.length === 0 && input.substring(cursor, cursor + commentsLen) === comments)
					{
						if (nextNewline === -1)	// Comment ends at EOF
							return returnable();
						cursor = nextNewline + newlineLen;
						nextNewline = input.indexOf(newline, cursor);
						nextDelim = input.indexOf(delim, cursor);
						continue;
					}

					// Next delimiter comes before next newline, so we've reached end of field
					if (nextDelim !== -1 && (nextDelim < nextNewline || nextNewline === -1))
					{
						row.push(input.substring(cursor, nextDelim));
						cursor = nextDelim + delimLen;
						// we look for next delimiter char
						nextDelim = input.indexOf(delim, cursor);
						continue;
					}

					// End of row
					if (nextNewline !== -1)
					{
						row.push(input.substring(cursor, nextNewline));
						saveRow(nextNewline + newlineLen);

						if (stepIsFunction)
						{
							doStep();
							if (aborted)
								return returnable();
						}

						if (preview && data.length >= preview)
							return returnable(true);

						continue;
					}

					break;
				}

				return finish();


				function pushRow(row)
				{
					data.push(row);
					lastCursor = cursor;
				}

				/**
	             * checks if there are extra spaces after closing quote and given index without any text
	             * if Yes, returns the number of spaces
	             */
				function extraSpaces(index) {
					var spaceLength = 0;
					if (index !== -1) {
						var textBetweenClosingQuoteAndIndex = input.substring(quoteSearch + 1, index);
						if (textBetweenClosingQuoteAndIndex && textBetweenClosingQuoteAndIndex.trim() === '') {
							spaceLength = textBetweenClosingQuoteAndIndex.length;
						}
					}
					return spaceLength;
				}

				/**
				 * Appends the remaining input from cursor to the end into
				 * row, saves the row, calls step, and returns the results.
				 */
				function finish(value)
				{
					if (ignoreLastRow)
						return returnable();
					if (typeof value === 'undefined')
						value = input.substring(cursor);
					row.push(value);
					cursor = inputLen;	// important in case parsing is paused
					pushRow(row);
					if (stepIsFunction)
						doStep();
					return returnable();
				}

				/**
				 * Appends the current row to the results. It sets the cursor
				 * to newCursor and finds the nextNewline. The caller should
				 * take care to execute user's step function and check for
				 * preview and end parsing if necessary.
				 */
				function saveRow(newCursor)
				{
					cursor = newCursor;
					pushRow(row);
					row = [];
					nextNewline = input.indexOf(newline, cursor);
				}

				/** Returns an object with the results, errors, and meta. */
				function returnable(stopped)
				{
					if (config.header && !baseIndex && data.length && !headerParsed)
					{
						const result = data[0];
						const headerCount = Object.create(null); // To track the count of each base header
						const usedHeaders = new Set(result); // To track used headers and avoid duplicates
						let duplicateHeaders = false;

						for (let i = 0; i < result.length; i++) {
							let header = result[i];
							if (isFunction(config.transformHeader))
								header = config.transformHeader(header, i);

							if (!headerCount[header]) {
								headerCount[header] = 1;
								result[i] = header;
							} else {
								let newHeader;
								let suffixCount = headerCount[header];

								// Find a unique new header
								do {
									newHeader = `${header}_${suffixCount}`;
									suffixCount++;
								} while (usedHeaders.has(newHeader));

								usedHeaders.add(newHeader); // Mark this new Header as used
								result[i] = newHeader;
								headerCount[header]++;
								duplicateHeaders = true;
								if (renamedHeaders === null) {
									renamedHeaders = {};
								}
								renamedHeaders[newHeader] = header;
							}

							usedHeaders.add(header); // Ensure the original header is marked as used
						}
						if (duplicateHeaders) {
							console.warn('Duplicate headers found and renamed.');
						}
						headerParsed = true;
					}
					return {
						data: data,
						errors: errors,
						meta: {
							delimiter: delim,
							linebreak: newline,
							aborted: aborted,
							truncated: !!stopped,
							cursor: lastCursor + (baseIndex || 0),
							renamedHeaders: renamedHeaders
						}
					};
				}

				/** Executes the user's step function and resets data & errors. */
				function doStep()
				{
					step(returnable());
					data = [];
					errors = [];
				}
			};

			/** Sets the abort flag */
			this.abort = function()
			{
				aborted = true;
			};

			/** Gets the cursor position */
			this.getCharIndex = function()
			{
				return cursor;
			};
		}


		function newWorker()
		{
			if (!Papa.WORKERS_SUPPORTED)
				return false;

			var workerUrl = getWorkerBlob();
			var w = new global.Worker(workerUrl);
			w.onmessage = mainThreadReceivedMessage;
			w.id = workerIdCounter++;
			workers[w.id] = w;
			return w;
		}

		/** Callback when main thread receives a message */
		function mainThreadReceivedMessage(e)
		{
			var msg = e.data;
			var worker = workers[msg.workerId];
			var aborted = false;

			if (msg.error)
				worker.userError(msg.error, msg.file);
			else if (msg.results && msg.results.data)
			{
				var abort = function() {
					aborted = true;
					completeWorker(msg.workerId, { data: [], errors: [], meta: { aborted: true } });
				};

				var handle = {
					abort: abort,
					pause: notImplemented,
					resume: notImplemented
				};

				if (isFunction(worker.userStep))
				{
					for (var i = 0; i < msg.results.data.length; i++)
					{
						worker.userStep({
							data: msg.results.data[i],
							errors: msg.results.errors,
							meta: msg.results.meta
						}, handle);
						if (aborted)
							break;
					}
					delete msg.results;	// free memory ASAP
				}
				else if (isFunction(worker.userChunk))
				{
					worker.userChunk(msg.results, handle, msg.file);
					delete msg.results;
				}
			}

			if (msg.finished && !aborted)
				completeWorker(msg.workerId, msg.results);
		}

		function completeWorker(workerId, results) {
			var worker = workers[workerId];
			if (isFunction(worker.userComplete))
				worker.userComplete(results);
			worker.terminate();
			delete workers[workerId];
		}

		function notImplemented() {
			throw new Error('Not implemented.');
		}

		/** Callback when worker thread receives a message */
		function workerThreadReceivedMessage(e)
		{
			var msg = e.data;

			if (typeof Papa.WORKER_ID === 'undefined' && msg)
				Papa.WORKER_ID = msg.workerId;

			if (typeof msg.input === 'string')
			{
				global.postMessage({
					workerId: Papa.WORKER_ID,
					results: Papa.parse(msg.input, msg.config),
					finished: true
				});
			}
			else if ((global.File && msg.input instanceof File) || msg.input instanceof Object)	// thank you, Safari (see issue #106)
			{
				var results = Papa.parse(msg.input, msg.config);
				if (results)
					global.postMessage({
						workerId: Papa.WORKER_ID,
						results: results,
						finished: true
					});
			}
		}

		/** Makes a deep copy of an array or object (mostly) */
		function copy(obj)
		{
			if (typeof obj !== 'object' || obj === null)
				return obj;
			var cpy = Array.isArray(obj) ? [] : {};
			for (var key in obj)
				cpy[key] = copy(obj[key]);
			return cpy;
		}

		function bindFunction(f, self)
		{
			return function() { f.apply(self, arguments); };
		}
		function isFunction(func)
		{
			return typeof func === 'function';
		}

		return Papa;
	})); 
} (papaparse));

var papaparseExports = papaparse.exports;
var Papa = /*@__PURE__*/_commonjsHelpers.getDefaultExportFromCjs(papaparseExports);

var isValidEmail = function isValidEmail(email) {
  return yup.string().email().isValidSync(email);
};
var createEmailOptions = function createEmailOptions() {
  var emails = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
  return emails.map(function (email) {
    return {
      label: email,
      value: email,
      valid: isValidEmail(email)
    };
  });
};
var parseCsvEmails = function parseCsvEmails(file, onSuccess) {
  Papa.parse(file, {
    header: true,
    skipEmptyLines: true,
    transformHeader: function transformHeader(h) {
      return h.toLowerCase().replace(/\W/g, "");
    },
    complete: function complete(results) {
      var _results$meta$fields;
      var isEmailFieldPresent = (_results$meta$fields = results.meta.fields) === null || _results$meta$fields === void 0 ? void 0 : _results$meta$fields.includes("email");
      if (isEmailFieldPresent) {
        var emails = results.data.filter(ramda.prop("email")).map(function (item) {
          return item.email.trim();
        });
        onSuccess(createEmailOptions(emails));
      } else {
        Toastr.error(i18next.t("neetoMolecules.sendToFields.errors.invalidCsv"));
      }
    }
  });
};

function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
var SendToFields = function SendToFields(_ref) {
  var emailInputProps = _ref.emailInputProps,
    ccInputProps = _ref.ccInputProps,
    bccInputProps = _ref.bccInputProps,
    _ref$showUploadCsvBut = _ref.showUploadCsvButton,
    showUploadCsvButton = _ref$showUploadCsvBut === void 0 ? false : _ref$showUploadCsvBut,
    _ref$showCcBccButton = _ref.showCcBccButton,
    showCcBccButton = _ref$showCcBccButton === void 0 ? false : _ref$showCcBccButton,
    _ref$showCcField = _ref.showCcField,
    showCcField = _ref$showCcField === void 0 ? false : _ref$showCcField,
    _ref$showBccField = _ref.showBccField,
    showBccField = _ref$showBccField === void 0 ? false : _ref$showBccField,
    _ref$showSendToField = _ref.showSendToField,
    showSendToField = _ref$showSendToField === void 0 ? true : _ref$showSendToField;
  var _useState = React.useState(false),
    _useState2 = _slicedToArray(_useState, 2),
    isBulkUploadPaneOpen = _useState2[0],
    setIsBulkUploadPaneOpen = _useState2[1];
  var sendToFieldRef = React.useRef();
  var _useFormikContext = formik.useFormikContext(),
    _useFormikContext$val = _useFormikContext.values,
    showCopyEmails = _useFormikContext$val.showCopyEmails,
    existingSendToEmails = _useFormikContext$val[emailInputProps.name || "sendTo"],
    setFieldValue = _useFormikContext.setFieldValue;
  var _useTranslation = reactI18next.useTranslation(),
    t = _useTranslation.t;
  var handleCSVFile = function handleCSVFile(file) {
    try {
      var _sendToFieldRef$curre;
      var onSuccess = function onSuccess(values) {
        return setFieldValue(emailInputProps.name || "sendTo", [].concat(_toConsumableArray(existingSendToEmails), _toConsumableArray(values)));
      };
      parseCsvEmails(file, onSuccess);
      setIsBulkUploadPaneOpen(false);
      (_sendToFieldRef$curre = sendToFieldRef.current) === null || _sendToFieldRef$curre === void 0 || _sendToFieldRef$curre.focus();
    } catch (error) {
      Toastr.error(error);
    }
  };
  var handelCcBccButtonClick = function handelCcBccButtonClick(e) {
    e.stopPropagation();
    setFieldValue("showCopyEmails", !showCopyEmails);
  };
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
    className: "relative w-full flex-col gap-2",
    "data-testid": "send-to-text-field",
    children: [showUploadCsvButton && /*#__PURE__*/jsxRuntime.jsx(Button, {
      className: "absolute right-1 top-0",
      "data-cy": "bulk-upload-button",
      "data-testid": "bulk-upload-button",
      icon: Upload,
      label: t("neetoMolecules.shareViaLink.bulkUpload"),
      size: "small",
      style: "link",
      onClick: function onClick() {
        return setIsBulkUploadPaneOpen(true);
      }
    }), showSendToField && /*#__PURE__*/jsxRuntime.jsx(MultiEmailInput, _objectSpread(_objectSpread({
      name: "sendTo",
      ref: sendToFieldRef
    }, emailInputProps), {}, {
      suffix: showCcBccButton && /*#__PURE__*/jsxRuntime.jsx(Button, {
        "data-cy": "cc-bcc-button",
        "data-testid": "cc-bcc-button",
        label: t("neetoMolecules.emailForm.labels.ccBcc"),
        size: "small",
        style: "link",
        onClick: handelCcBccButtonClick
      })
    })), (showCopyEmails || showCcField || showBccField) && /*#__PURE__*/jsxRuntime.jsxs("div", {
      className: "mt-5 flex w-full flex-col gap-6",
      children: [(showCopyEmails || showCcField) && /*#__PURE__*/jsxRuntime.jsx(MultiEmailInput, _objectSpread({
        name: "sendToBcc"
      }, ccInputProps)), (showCopyEmails || showBccField) && /*#__PURE__*/jsxRuntime.jsx(MultiEmailInput, _objectSpread({
        name: "sendToCc"
      }, bccInputProps))]
    }), /*#__PURE__*/jsxRuntime.jsx(BulkUploadPane, {
      fileSize: CSV_FILE_SIZE_IN_KB,
      handleFileSubmit: handleCSVFile,
      isOpen: isBulkUploadPaneOpen,
      onClose: function onClose() {
        return setIsBulkUploadPaneOpen(false);
      }
    })]
  });
};

module.exports = SendToFields;
//# sourceMappingURL=SendToFields.js.map
