(function (global, factory) {
	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
	typeof define === 'function' && define.amd ? define(['exports'], factory) :
	(global = global || self, factory(global.immer = {}));
}(this, (function (exports) { 'use strict';

	var _ref;

	// Should be no imports here!
	// Some things that should be evaluated before all else...
	// We only want to know if non-polyfilled symbols are available
	var hasSymbol = typeof Symbol !== "undefined" && typeof
	/*#__PURE__*/
	Symbol("x") === "symbol";
	var hasMap = typeof Map !== "undefined";
	var hasSet = typeof Set !== "undefined";
	var hasProxies = typeof Proxy !== "undefined" && typeof Proxy.revocable !== "undefined" && typeof Reflect !== "undefined";
	/**
	 * The sentinel value returned by producers to replace the draft with undefined.
	 */

	var NOTHING = hasSymbol ?
	/*#__PURE__*/
	Symbol.for("immer-nothing") : (_ref = {}, _ref["immer-nothing"] = true, _ref);
	/**
	 * To let Immer treat your class instances as plain immutable objects
	 * (albeit with a custom prototype), you must define either an instance property
	 * or a static property on each of your custom classes.
	 *
	 * Otherwise, your class instance will never be drafted, which means it won't be
	 * safe to mutate in a produce callback.
	 */

	var DRAFTABLE = hasSymbol ?
	/*#__PURE__*/
	Symbol.for("immer-draftable") : "__$immer_draftable";
	var DRAFT_STATE = hasSymbol ?
	/*#__PURE__*/
	Symbol.for("immer-state") : "__$immer_state"; // Even a polyfilled Symbol might provide Symbol.iterator

	var iteratorSymbol = typeof Symbol != "undefined" && Symbol.iterator || "@@iterator";

	var errors = {
	  0: "Illegal state",
	  1: "Immer drafts cannot have computed properties",
	  2: "This object has been frozen and should not be mutated",
	  3: function _(data) {
	    return "Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? " + data;
	  },
	  4: "An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.",
	  5: "Immer forbids circular references",
	  6: "The first or second argument to `produce` must be a function",
	  7: "The third argument to `produce` must be a function or undefined",
	  8: "First argument to `createDraft` must be a plain object, an array, or an immerable object",
	  9: "First argument to `finishDraft` must be a draft returned by `createDraft`",
	  10: "The given draft is already finalized",
	  11: "Object.defineProperty() cannot be used on an Immer draft",
	  12: "Object.setPrototypeOf() cannot be used on an Immer draft",
	  13: "Immer only supports deleting array indices",
	  14: "Immer only supports setting array indices and the 'length' property",
	  15: function _(path) {
	    return "Cannot apply patch, path doesn't resolve: " + path;
	  },
	  16: 'Sets cannot have "replace" patches.',
	  17: function _(op) {
	    return "Unsupported patch operation: " + op;
	  },
	  18: function _(plugin) {
	    return "The plugin for '" + plugin + "' has not been loaded into Immer. To enable the plugin, import and call `enable" + plugin + "()` when initializing your application.";
	  },
	  20: "Cannot use proxies if Proxy, Proxy.revocable or Reflect are not available",
	  21: function _(thing) {
	    return "produce can only be called on things that are draftable: plain objects, arrays, Map, Set or classes that are marked with '[immerable]: true'. Got '" + thing + "'";
	  },
	  22: function _(thing) {
	    return "'current' expects a draft, got: " + thing;
	  },
	  23: function _(thing) {
	    return "'original' expects a draft, got: " + thing;
	  },
	  24: "Patching reserved attributes like __proto__, prototype and constructor is not allowed"
	};
	function die(error) {
	  for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
	    args[_key - 1] = arguments[_key];
	  }

	  {
	    var e = errors[error];
	    var msg = !e ? "unknown error nr: " + error : typeof e === "function" ? e.apply(null, args) : e;
	    throw new Error("[Immer] " + msg);
	  }
	}

	/** Returns true if the given value is an Immer draft */

	/*#__PURE__*/

	function isDraft(value) {
	  return !!value && !!value[DRAFT_STATE];
	}
	/** Returns true if the given value can be drafted by Immer */

	/*#__PURE__*/

	function isDraftable(value) {
	  var _value$constructor;

	  if (!value) return false;
	  return isPlainObject(value) || Array.isArray(value) || !!value[DRAFTABLE] || !!((_value$constructor = value.constructor) === null || _value$constructor === void 0 ? void 0 : _value$constructor[DRAFTABLE]) || isMap(value) || isSet(value);
	}
	var objectCtorString =
	/*#__PURE__*/
	Object.prototype.constructor.toString();
	/*#__PURE__*/

	function isPlainObject(value) {
	  if (!value || typeof value !== "object") return false;
	  var proto = Object.getPrototypeOf(value);

	  if (proto === null) {
	    return true;
	  }

	  var Ctor = Object.hasOwnProperty.call(proto, "constructor") && proto.constructor;
	  if (Ctor === Object) return true;
	  return typeof Ctor == "function" && Function.toString.call(Ctor) === objectCtorString;
	}
	function original(value) {
	  if (!isDraft(value)) die(23, value);
	  return value[DRAFT_STATE].base_;
	}
	/*#__PURE__*/

	var ownKeys = typeof Reflect !== "undefined" && Reflect.ownKeys ? Reflect.ownKeys : typeof Object.getOwnPropertySymbols !== "undefined" ? function (obj) {
	  return Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertySymbols(obj));
	} :
	/* istanbul ignore next */
	Object.getOwnPropertyNames;
	var getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors || function getOwnPropertyDescriptors(target) {
	  // Polyfill needed for Hermes and IE, see https://github.com/facebook/hermes/issues/274
	  var res = {};
	  ownKeys(target).forEach(function (key) {
	    res[key] = Object.getOwnPropertyDescriptor(target, key);
	  });
	  return res;
	};
	function each(obj, iter, enumerableOnly) {
	  if (enumerableOnly === void 0) {
	    enumerableOnly = false;
	  }

	  if (getArchtype(obj) === 0
	  /* Object */
	  ) {
	      (enumerableOnly ? Object.keys : ownKeys)(obj).forEach(function (key) {
	        if (!enumerableOnly || typeof key !== "symbol") iter(key, obj[key], obj);
	      });
	    } else {
	    obj.forEach(function (entry, index) {
	      return iter(index, entry, obj);
	    });
	  }
	}
	/*#__PURE__*/

	function getArchtype(thing) {
	  /* istanbul ignore next */
	  var state = thing[DRAFT_STATE];
	  return state ? state.type_ > 3 ? state.type_ - 4 // cause Object and Array map back from 4 and 5
	  : state.type_ // others are the same
	  : Array.isArray(thing) ? 1
	  /* Array */
	  : isMap(thing) ? 2
	  /* Map */
	  : isSet(thing) ? 3
	  /* Set */
	  : 0
	  /* Object */
	  ;
	}
	/*#__PURE__*/

	function has(thing, prop) {
	  return getArchtype(thing) === 2
	  /* Map */
	  ? thing.has(prop) : Object.prototype.hasOwnProperty.call(thing, prop);
	}
	/*#__PURE__*/

	function get(thing, prop) {
	  // @ts-ignore
	  return getArchtype(thing) === 2
	  /* Map */
	  ? thing.get(prop) : thing[prop];
	}
	/*#__PURE__*/

	function set(thing, propOrOldValue, value) {
	  var t = getArchtype(thing);
	  if (t === 2
	  /* Map */
	  ) thing.set(propOrOldValue, value);else if (t === 3
	  /* Set */
	  ) {
	      thing.delete(propOrOldValue);
	      thing.add(value);
	    } else thing[propOrOldValue] = value;
	}
	/*#__PURE__*/

	function is(x, y) {
	  // From: https://github.com/facebook/fbjs/blob/c69904a511b900266935168223063dd8772dfc40/packages/fbjs/src/core/shallowEqual.js
	  if (x === y) {
	    return x !== 0 || 1 / x === 1 / y;
	  } else {
	    return x !== x && y !== y;
	  }
	}
	/*#__PURE__*/

	function isMap(target) {
	  return hasMap && target instanceof Map;
	}
	/*#__PURE__*/

	function isSet(target) {
	  return hasSet && target instanceof Set;
	}
	/*#__PURE__*/

	function latest(state) {
	  return state.copy_ || state.base_;
	}
	/*#__PURE__*/

	function shallowCopy(base) {
	  if (Array.isArray(base)) return Array.prototype.slice.call(base);
	  var descriptors = getOwnPropertyDescriptors(base);
	  delete descriptors[DRAFT_STATE];
	  var keys = ownKeys(descriptors);

	  for (var i = 0; i < keys.length; i++) {
	    var key = keys[i];
	    var desc = descriptors[key];

	    if (desc.writable === false) {
	      desc.writable = true;
	      desc.configurable = true;
	    } // like object.assign, we will read any _own_, get/set accessors. This helps in dealing
	    // with libraries that trap values, like mobx or vue
	    // unlike object.assign, non-enumerables will be copied as well


	    if (desc.get || desc.set) descriptors[key] = {
	      configurable: true,
	      writable: true,
	      enumerable: desc.enumerable,
	      value: base[key]
	    };
	  }

	  return Object.create(Object.getPrototypeOf(base), descriptors);
	}
	function freeze(obj, deep) {
	  if (deep === void 0) {
	    deep = false;
	  }

	  if (isFrozen(obj) || isDraft(obj) || !isDraftable(obj)) return obj;

	  if (getArchtype(obj) > 1
	  /* Map or Set */
	  ) {
	      obj.set = obj.add = obj.clear = obj.delete = dontMutateFrozenCollections;
	    }

	  Object.freeze(obj);
	  if (deep) each(obj, function (key, value) {
	    return freeze(value, true);
	  }, true);
	  return obj;
	}

	function dontMutateFrozenCollections() {
	  die(2);
	}

	function isFrozen(obj) {
	  if (obj == null || typeof obj !== "object") return true; // See #600, IE dies on non-objects in Object.isFrozen

	  return Object.isFrozen(obj);
	}

	/** Plugin utilities */

	var plugins = {};
	function getPlugin(pluginKey) {
	  var plugin = plugins[pluginKey];

	  if (!plugin) {
	    die(18, pluginKey);
	  } // @ts-ignore


	  return plugin;
	}
	function loadPlugin(pluginKey, implementation) {
	  if (!plugins[pluginKey]) plugins[pluginKey] = implementation;
	}

	var currentScope;
	function getCurrentScope() {
	  if ( !currentScope) die(0);
	  return currentScope;
	}

	function createScope(parent_, immer_) {
	  return {
	    drafts_: [],
	    parent_: parent_,
	    immer_: immer_,
	    // Whenever the modified draft contains a draft from another scope, we
	    // need to prevent auto-freezing so the unowned draft can be finalized.
	    canAutoFreeze_: true,
	    unfinalizedDrafts_: 0
	  };
	}

	function usePatchesInScope(scope, patchListener) {
	  if (patchListener) {
	    getPlugin("Patches"); // assert we have the plugin

	    scope.patches_ = [];
	    scope.inversePatches_ = [];
	    scope.patchListener_ = patchListener;
	  }
	}
	function revokeScope(scope) {
	  leaveScope(scope);
	  scope.drafts_.forEach(revokeDraft); // @ts-ignore

	  scope.drafts_ = null;
	}
	function leaveScope(scope) {
	  if (scope === currentScope) {
	    currentScope = scope.parent_;
	  }
	}
	function enterScope(immer) {
	  return currentScope = createScope(currentScope, immer);
	}

	function revokeDraft(draft) {
	  var state = draft[DRAFT_STATE];
	  if (state.type_ === 0
	  /* ProxyObject */
	  || state.type_ === 1
	  /* ProxyArray */
	  ) state.revoke_();else state.revoked_ = true;
	}

	function processResult(result, scope) {
	  scope.unfinalizedDrafts_ = scope.drafts_.length;
	  var baseDraft = scope.drafts_[0];
	  var isReplaced = result !== undefined && result !== baseDraft;
	  if (!scope.immer_.useProxies_) getPlugin("ES5").willFinalizeES5_(scope, result, isReplaced);

	  if (isReplaced) {
	    if (baseDraft[DRAFT_STATE].modified_) {
	      revokeScope(scope);
	      die(4);
	    }

	    if (isDraftable(result)) {
	      // Finalize the result in case it contains (or is) a subset of the draft.
	      result = finalize(scope, result);
	      if (!scope.parent_) maybeFreeze(scope, result);
	    }

	    if (scope.patches_) {
	      getPlugin("Patches").generateReplacementPatches_(baseDraft[DRAFT_STATE].base_, result, scope.patches_, scope.inversePatches_);
	    }
	  } else {
	    // Finalize the base draft.
	    result = finalize(scope, baseDraft, []);
	  }

	  revokeScope(scope);

	  if (scope.patches_) {
	    scope.patchListener_(scope.patches_, scope.inversePatches_);
	  }

	  return result !== NOTHING ? result : undefined;
	}

	function finalize(rootScope, value, path) {
	  // Don't recurse in tho recursive data structures
	  if (isFrozen(value)) return value;
	  var state = value[DRAFT_STATE]; // A plain object, might need freezing, might contain drafts

	  if (!state) {
	    each(value, function (key, childValue) {
	      return finalizeProperty(rootScope, state, value, key, childValue, path);
	    }, true // See #590, don't recurse into non-enumerable of non drafted objects
	    );
	    return value;
	  } // Never finalize drafts owned by another scope.


	  if (state.scope_ !== rootScope) return value; // Unmodified draft, return the (frozen) original

	  if (!state.modified_) {
	    maybeFreeze(rootScope, state.base_, true);
	    return state.base_;
	  } // Not finalized yet, let's do that now


	  if (!state.finalized_) {
	    state.finalized_ = true;
	    state.scope_.unfinalizedDrafts_--;
	    var result = // For ES5, create a good copy from the draft first, with added keys and without deleted keys.
	    state.type_ === 4
	    /* ES5Object */
	    || state.type_ === 5
	    /* ES5Array */
	    ? state.copy_ = shallowCopy(state.draft_) : state.copy_; // Finalize all children of the copy
	    // For sets we clone before iterating, otherwise we can get in endless loop due to modifying during iteration, see #628
	    // Although the original test case doesn't seem valid anyway, so if this in the way we can turn the next line
	    // back to each(result, ....)

	    each(state.type_ === 3
	    /* Set */
	    ? new Set(result) : result, function (key, childValue) {
	      return finalizeProperty(rootScope, state, result, key, childValue, path);
	    }); // everything inside is frozen, we can freeze here

	    maybeFreeze(rootScope, result, false); // first time finalizing, let's create those patches

	    if (path && rootScope.patches_) {
	      getPlugin("Patches").generatePatches_(state, path, rootScope.patches_, rootScope.inversePatches_);
	    }
	  }

	  return state.copy_;
	}

	function finalizeProperty(rootScope, parentState, targetObject, prop, childValue, rootPath) {
	  if ( childValue === targetObject) die(5);

	  if (isDraft(childValue)) {
	    var path = rootPath && parentState && parentState.type_ !== 3
	    /* Set */
	    && // Set objects are atomic since they have no keys.
	    !has(parentState.assigned_, prop) // Skip deep patches for assigned keys.
	    ? rootPath.concat(prop) : undefined; // Drafts owned by `scope` are finalized here.

	    var res = finalize(rootScope, childValue, path);
	    set(targetObject, prop, res); // Drafts from another scope must prevented to be frozen
	    // if we got a draft back from finalize, we're in a nested produce and shouldn't freeze

	    if (isDraft(res)) {
	      rootScope.canAutoFreeze_ = false;
	    } else return;
	  } // Search new objects for unfinalized drafts. Frozen objects should never contain drafts.


	  if (isDraftable(childValue) && !isFrozen(childValue)) {
	    if (!rootScope.immer_.autoFreeze_ && rootScope.unfinalizedDrafts_ < 1) {
	      // optimization: if an object is not a draft, and we don't have to
	      // deepfreeze everything, and we are sure that no drafts are left in the remaining object
	      // cause we saw and finalized all drafts already; we can stop visiting the rest of the tree.
	      // This benefits especially adding large data tree's without further processing.
	      // See add-data.js perf test
	      return;
	    }

	    finalize(rootScope, childValue); // immer deep freezes plain objects, so if there is no parent state, we freeze as well

	    if (!parentState || !parentState.scope_.parent_) maybeFreeze(rootScope, childValue);
	  }
	}

	function maybeFreeze(scope, value, deep) {
	  if (deep === void 0) {
	    deep = false;
	  }

	  if (scope.immer_.autoFreeze_ && scope.canAutoFreeze_) {
	    freeze(value, deep);
	  }
	}

	/**
	 * Returns a new draft of the `base` object.
	 *
	 * The second argument is the parent draft-state (used internally).
	 */

	function createProxyProxy(base, parent) {
	  var isArray = Array.isArray(base);
	  var state = {
	    type_: isArray ? 1
	    /* ProxyArray */
	    : 0
	    /* ProxyObject */
	    ,
	    // Track which produce call this is associated with.
	    scope_: parent ? parent.scope_ : getCurrentScope(),
	    // True for both shallow and deep changes.
	    modified_: false,
	    // Used during finalization.
	    finalized_: false,
	    // Track which properties have been assigned (true) or deleted (false).
	    assigned_: {},
	    // The parent draft state.
	    parent_: parent,
	    // The base state.
	    base_: base,
	    // The base proxy.
	    draft_: null,
	    // The base copy with any updated values.
	    copy_: null,
	    // Called by the `produce` function.
	    revoke_: null,
	    isManual_: false
	  }; // the traps must target something, a bit like the 'real' base.
	  // but also, we need to be able to determine from the target what the relevant state is
	  // (to avoid creating traps per instance to capture the state in closure,
	  // and to avoid creating weird hidden properties as well)
	  // So the trick is to use 'state' as the actual 'target'! (and make sure we intercept everything)
	  // Note that in the case of an array, we put the state in an array to have better Reflect defaults ootb

	  var target = state;
	  var traps = objectTraps;

	  if (isArray) {
	    target = [state];
	    traps = arrayTraps;
	  }

	  var _Proxy$revocable = Proxy.revocable(target, traps),
	      revoke = _Proxy$revocable.revoke,
	      proxy = _Proxy$revocable.proxy;

	  state.draft_ = proxy;
	  state.revoke_ = revoke;
	  return proxy;
	}
	/**
	 * Object drafts
	 */

	var objectTraps = {
	  get: function get(state, prop) {
	    if (prop === DRAFT_STATE) return state;
	    var source = latest(state);

	    if (!has(source, prop)) {
	      // non-existing or non-own property...
	      return readPropFromProto(state, source, prop);
	    }

	    var value = source[prop];

	    if (state.finalized_ || !isDraftable(value)) {
	      return value;
	    } // Check for existing draft in modified state.
	    // Assigned values are never drafted. This catches any drafts we created, too.


	    if (value === peek(state.base_, prop)) {
	      prepareCopy(state);
	      return state.copy_[prop] = createProxy(state.scope_.immer_, value, state);
	    }

	    return value;
	  },
	  has: function has(state, prop) {
	    return prop in latest(state);
	  },
	  ownKeys: function ownKeys(state) {
	    return Reflect.ownKeys(latest(state));
	  },
	  set: function set(state, prop
	  /* strictly not, but helps TS */
	  , value) {
	    var desc = getDescriptorFromProto(latest(state), prop);

	    if (desc === null || desc === void 0 ? void 0 : desc.set) {
	      // special case: if this write is captured by a setter, we have
	      // to trigger it with the correct context
	      desc.set.call(state.draft_, value);
	      return true;
	    }

	    if (!state.modified_) {
	      // the last check is because we need to be able to distinguish setting a non-existing to undefined (which is a change)
	      // from setting an existing property with value undefined to undefined (which is not a change)
	      var current = peek(latest(state), prop); // special case, if we assigning the original value to a draft, we can ignore the assignment

	      var currentState = current === null || current === void 0 ? void 0 : current[DRAFT_STATE];

	      if (currentState && currentState.base_ === value) {
	        state.copy_[prop] = value;
	        state.assigned_[prop] = false;
	        return true;
	      }

	      if (is(value, current) && (value !== undefined || has(state.base_, prop))) return true;
	      prepareCopy(state);
	      markChanged(state);
	    }

	    if (state.copy_[prop] === value && // special case: NaN
	    typeof value !== "number" && ( // special case: handle new props with value 'undefined'
	    value !== undefined || prop in state.copy_)) return true; // @ts-ignore

	    state.copy_[prop] = value;
	    state.assigned_[prop] = true;
	    return true;
	  },
	  deleteProperty: function deleteProperty(state, prop) {
	    // The `undefined` check is a fast path for pre-existing keys.
	    if (peek(state.base_, prop) !== undefined || prop in state.base_) {
	      state.assigned_[prop] = false;
	      prepareCopy(state);
	      markChanged(state);
	    } else {
	      // if an originally not assigned property was deleted
	      delete state.assigned_[prop];
	    } // @ts-ignore


	    if (state.copy_) delete state.copy_[prop];
	    return true;
	  },
	  // Note: We never coerce `desc.value` into an Immer draft, because we can't make
	  // the same guarantee in ES5 mode.
	  getOwnPropertyDescriptor: function getOwnPropertyDescriptor(state, prop) {
	    var owner = latest(state);
	    var desc = Reflect.getOwnPropertyDescriptor(owner, prop);
	    if (!desc) return desc;
	    return {
	      writable: true,
	      configurable: state.type_ !== 1
	      /* ProxyArray */
	      || prop !== "length",
	      enumerable: desc.enumerable,
	      value: owner[prop]
	    };
	  },
	  defineProperty: function defineProperty() {
	    die(11);
	  },
	  getPrototypeOf: function getPrototypeOf(state) {
	    return Object.getPrototypeOf(state.base_);
	  },
	  setPrototypeOf: function setPrototypeOf() {
	    die(12);
	  }
	};
	/**
	 * Array drafts
	 */

	var arrayTraps = {};
	each(objectTraps, function (key, fn) {
	  // @ts-ignore
	  arrayTraps[key] = function () {
	    arguments[0] = arguments[0][0];
	    return fn.apply(this, arguments);
	  };
	});

	arrayTraps.deleteProperty = function (state, prop) {
	  if ( isNaN(parseInt(prop))) die(13); // @ts-ignore

	  return arrayTraps.set.call(this, state, prop, undefined);
	};

	arrayTraps.set = function (state, prop, value) {
	  if ( prop !== "length" && isNaN(parseInt(prop))) die(14);
	  return objectTraps.set.call(this, state[0], prop, value, state[0]);
	}; // Access a property without creating an Immer draft.


	function peek(draft, prop) {
	  var state = draft[DRAFT_STATE];
	  var source = state ? latest(state) : draft;
	  return source[prop];
	}

	function readPropFromProto(state, source, prop) {
	  var _desc$get;

	  var desc = getDescriptorFromProto(source, prop);
	  return desc ? "value" in desc ? desc.value : // This is a very special case, if the prop is a getter defined by the
	  // prototype, we should invoke it with the draft as context!
	  (_desc$get = desc.get) === null || _desc$get === void 0 ? void 0 : _desc$get.call(state.draft_) : undefined;
	}

	function getDescriptorFromProto(source, prop) {
	  // 'in' checks proto!
	  if (!(prop in source)) return undefined;
	  var proto = Object.getPrototypeOf(source);

	  while (proto) {
	    var desc = Object.getOwnPropertyDescriptor(proto, prop);
	    if (desc) return desc;
	    proto = Object.getPrototypeOf(proto);
	  }

	  return undefined;
	}

	function markChanged(state) {
	  if (!state.modified_) {
	    state.modified_ = true;

	    if (state.parent_) {
	      markChanged(state.parent_);
	    }
	  }
	}
	function prepareCopy(state) {
	  if (!state.copy_) {
	    state.copy_ = shallowCopy(state.base_);
	  }
	}

	var Immer =
	/*#__PURE__*/
	function () {
	  function Immer(config) {
	    var _this = this;

	    this.useProxies_ = hasProxies;
	    this.autoFreeze_ = true;
	    /**
	     * The `produce` function takes a value and a "recipe function" (whose
	     * return value often depends on the base state). The recipe function is
	     * free to mutate its first argument however it wants. All mutations are
	     * only ever applied to a __copy__ of the base state.
	     *
	     * Pass only a function to create a "curried producer" which relieves you
	     * from passing the recipe function every time.
	     *
	     * Only plain objects and arrays are made mutable. All other objects are
	     * considered uncopyable.
	     *
	     * Note: This function is __bound__ to its `Immer` instance.
	     *
	     * @param {any} base - the initial state
	     * @param {Function} producer - function that receives a proxy of the base state as first argument and which can be freely modified
	     * @param {Function} patchListener - optional function that will be called with all the patches produced here
	     * @returns {any} a new state, or the initial state if nothing was modified
	     */

	    this.produce = function (base, recipe, patchListener) {
	      // curried invocation
	      if (typeof base === "function" && typeof recipe !== "function") {
	        var defaultBase = recipe;
	        recipe = base;
	        var self = _this;
	        return function curriedProduce(base) {
	          var _this2 = this;

	          if (base === void 0) {
	            base = defaultBase;
	          }

	          for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
	            args[_key - 1] = arguments[_key];
	          }

	          return self.produce(base, function (draft) {
	            var _recipe;

	            return (_recipe = recipe).call.apply(_recipe, [_this2, draft].concat(args));
	          }); // prettier-ignore
	        };
	      }

	      if (typeof recipe !== "function") die(6);
	      if (patchListener !== undefined && typeof patchListener !== "function") die(7);
	      var result; // Only plain objects, arrays, and "immerable classes" are drafted.

	      if (isDraftable(base)) {
	        var scope = enterScope(_this);
	        var proxy = createProxy(_this, base, undefined);
	        var hasError = true;

	        try {
	          result = recipe(proxy);
	          hasError = false;
	        } finally {
	          // finally instead of catch + rethrow better preserves original stack
	          if (hasError) revokeScope(scope);else leaveScope(scope);
	        }

	        if (typeof Promise !== "undefined" && result instanceof Promise) {
	          return result.then(function (result) {
	            usePatchesInScope(scope, patchListener);
	            return processResult(result, scope);
	          }, function (error) {
	            revokeScope(scope);
	            throw error;
	          });
	        }

	        usePatchesInScope(scope, patchListener);
	        return processResult(result, scope);
	      } else if (!base || typeof base !== "object") {
	        result = recipe(base);
	        if (result === undefined) result = base;
	        if (result === NOTHING) result = undefined;
	        if (_this.autoFreeze_) freeze(result, true);

	        if (patchListener) {
	          var p = [];
	          var ip = [];
	          getPlugin("Patches").generateReplacementPatches_(base, result, p, ip);
	          patchListener(p, ip);
	        }

	        return result;
	      } else die(21, base);
	    };

	    this.produceWithPatches = function (base, recipe) {
	      // curried invocation
	      if (typeof base === "function") {
	        return function (state) {
	          for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
	            args[_key2 - 1] = arguments[_key2];
	          }

	          return _this.produceWithPatches(state, function (draft) {
	            return base.apply(void 0, [draft].concat(args));
	          });
	        };
	      }

	      var patches, inversePatches;

	      var result = _this.produce(base, recipe, function (p, ip) {
	        patches = p;
	        inversePatches = ip;
	      });

	      if (typeof Promise !== "undefined" && result instanceof Promise) {
	        return result.then(function (nextState) {
	          return [nextState, patches, inversePatches];
	        });
	      }

	      return [result, patches, inversePatches];
	    };

	    if (typeof (config === null || config === void 0 ? void 0 : config.useProxies) === "boolean") this.setUseProxies(config.useProxies);
	    if (typeof (config === null || config === void 0 ? void 0 : config.autoFreeze) === "boolean") this.setAutoFreeze(config.autoFreeze);
	  }

	  var _proto = Immer.prototype;

	  _proto.createDraft = function createDraft(base) {
	    if (!isDraftable(base)) die(8);
	    if (isDraft(base)) base = current(base);
	    var scope = enterScope(this);
	    var proxy = createProxy(this, base, undefined);
	    proxy[DRAFT_STATE].isManual_ = true;
	    leaveScope(scope);
	    return proxy;
	  };

	  _proto.finishDraft = function finishDraft(draft, patchListener) {
	    var state = draft && draft[DRAFT_STATE];

	    {
	      if (!state || !state.isManual_) die(9);
	      if (state.finalized_) die(10);
	    }

	    var scope = state.scope_;
	    usePatchesInScope(scope, patchListener);
	    return processResult(undefined, scope);
	  }
	  /**
	   * Pass true to automatically freeze all copies created by Immer.
	   *
	   * By default, auto-freezing is enabled.
	   */
	  ;

	  _proto.setAutoFreeze = function setAutoFreeze(value) {
	    this.autoFreeze_ = value;
	  }
	  /**
	   * Pass true to use the ES2015 `Proxy` class when creating drafts, which is
	   * always faster than using ES5 proxies.
	   *
	   * By default, feature detection is used, so calling this is rarely necessary.
	   */
	  ;

	  _proto.setUseProxies = function setUseProxies(value) {
	    if (value && !hasProxies) {
	      die(20);
	    }

	    this.useProxies_ = value;
	  };

	  _proto.applyPatches = function applyPatches(base, patches) {
	    // If a patch replaces the entire state, take that replacement as base
	    // before applying patches
	    var i;

	    for (i = patches.length - 1; i >= 0; i--) {
	      var patch = patches[i];

	      if (patch.path.length === 0 && patch.op === "replace") {
	        base = patch.value;
	        break;
	      }
	    } // If there was a patch that replaced the entire state, start from the
	    // patch after that.


	    if (i > -1) {
	      patches = patches.slice(i + 1);
	    }

	    var applyPatchesImpl = getPlugin("Patches").applyPatches_;

	    if (isDraft(base)) {
	      // N.B: never hits if some patch a replacement, patches are never drafts
	      return applyPatchesImpl(base, patches);
	    } // Otherwise, produce a copy of the base state.


	    return this.produce(base, function (draft) {
	      return applyPatchesImpl(draft, patches);
	    });
	  };

	  return Immer;
	}();
	function createProxy(immer, value, parent) {
	  // precondition: createProxy should be guarded by isDraftable, so we know we can safely draft
	  var draft = isMap(value) ? getPlugin("MapSet").proxyMap_(value, parent) : isSet(value) ? getPlugin("MapSet").proxySet_(value, parent) : immer.useProxies_ ? createProxyProxy(value, parent) : getPlugin("ES5").createES5Proxy_(value, parent);
	  var scope = parent ? parent.scope_ : getCurrentScope();
	  scope.drafts_.push(draft);
	  return draft;
	}

	function current(value) {
	  if (!isDraft(value)) die(22, value);
	  return currentImpl(value);
	}

	function currentImpl(value) {
	  if (!isDraftable(value)) return value;
	  var state = value[DRAFT_STATE];
	  var copy;
	  var archType = getArchtype(value);

	  if (state) {
	    if (!state.modified_ && (state.type_ < 4 || !getPlugin("ES5").hasChanges_(state))) return state.base_; // Optimization: avoid generating new drafts during copying

	    state.finalized_ = true;
	    copy = copyHelper(value, archType);
	    state.finalized_ = false;
	  } else {
	    copy = copyHelper(value, archType);
	  }

	  each(copy, function (key, childValue) {
	    if (state && get(state.base_, key) === childValue) return; // no need to copy or search in something that didn't change

	    set(copy, key, currentImpl(childValue));
	  }); // In the future, we might consider freezing here, based on the current settings

	  return archType === 3
	  /* Set */
	  ? new Set(copy) : copy;
	}

	function copyHelper(value, archType) {
	  // creates a shallow copy, even if it is a map or set
	  switch (archType) {
	    case 2
	    /* Map */
	    :
	      return new Map(value);

	    case 3
	    /* Set */
	    :
	      // Set will be cloned as array temporarily, so that we can replace individual items
	      return Array.from(value);
	  }

	  return shallowCopy(value);
	}

	function enableES5() {
	  function willFinalizeES5_(scope, result, isReplaced) {
	    if (!isReplaced) {
	      if (scope.patches_) {
	        markChangesRecursively(scope.drafts_[0]);
	      } // This is faster when we don't care about which attributes changed.


	      markChangesSweep(scope.drafts_);
	    } // When a child draft is returned, look for changes.
	    else if (isDraft(result) && result[DRAFT_STATE].scope_ === scope) {
	        markChangesSweep(scope.drafts_);
	      }
	  }

	  function createES5Draft(isArray, base) {
	    if (isArray) {
	      var draft = new Array(base.length);

	      for (var i = 0; i < base.length; i++) {
	        Object.defineProperty(draft, "" + i, proxyProperty(i, true));
	      }

	      return draft;
	    } else {
	      var _descriptors = getOwnPropertyDescriptors(base);

	      delete _descriptors[DRAFT_STATE];
	      var keys = ownKeys(_descriptors);

	      for (var _i = 0; _i < keys.length; _i++) {
	        var key = keys[_i];
	        _descriptors[key] = proxyProperty(key, isArray || !!_descriptors[key].enumerable);
	      }

	      return Object.create(Object.getPrototypeOf(base), _descriptors);
	    }
	  }

	  function createES5Proxy_(base, parent) {
	    var isArray = Array.isArray(base);
	    var draft = createES5Draft(isArray, base);
	    var state = {
	      type_: isArray ? 5
	      /* ES5Array */
	      : 4
	      /* ES5Object */
	      ,
	      scope_: parent ? parent.scope_ : getCurrentScope(),
	      modified_: false,
	      finalized_: false,
	      assigned_: {},
	      parent_: parent,
	      // base is the object we are drafting
	      base_: base,
	      // draft is the draft object itself, that traps all reads and reads from either the base (if unmodified) or copy (if modified)
	      draft_: draft,
	      copy_: null,
	      revoked_: false,
	      isManual_: false
	    };
	    Object.defineProperty(draft, DRAFT_STATE, {
	      value: state,
	      // enumerable: false <- the default
	      writable: true
	    });
	    return draft;
	  } // property descriptors are recycled to make sure we don't create a get and set closure per property,
	  // but share them all instead


	  var descriptors = {};

	  function proxyProperty(prop, enumerable) {
	    var desc = descriptors[prop];

	    if (desc) {
	      desc.enumerable = enumerable;
	    } else {
	      descriptors[prop] = desc = {
	        configurable: true,
	        enumerable: enumerable,
	        get: function get() {
	          var state = this[DRAFT_STATE];
	          assertUnrevoked(state); // @ts-ignore

	          return objectTraps.get(state, prop);
	        },
	        set: function set(value) {
	          var state = this[DRAFT_STATE];
	          assertUnrevoked(state); // @ts-ignore

	          objectTraps.set(state, prop, value);
	        }
	      };
	    }

	    return desc;
	  } // This looks expensive, but only proxies are visited, and only objects without known changes are scanned.


	  function markChangesSweep(drafts) {
	    // The natural order of drafts in the `scope` array is based on when they
	    // were accessed. By processing drafts in reverse natural order, we have a
	    // better chance of processing leaf nodes first. When a leaf node is known to
	    // have changed, we can avoid any traversal of its ancestor nodes.
	    for (var i = drafts.length - 1; i >= 0; i--) {
	      var state = drafts[i][DRAFT_STATE];

	      if (!state.modified_) {
	        switch (state.type_) {
	          case 5
	          /* ES5Array */
	          :
	            if (hasArrayChanges(state)) markChanged(state);
	            break;

	          case 4
	          /* ES5Object */
	          :
	            if (hasObjectChanges(state)) markChanged(state);
	            break;
	        }
	      }
	    }
	  }

	  function markChangesRecursively(object) {
	    if (!object || typeof object !== "object") return;
	    var state = object[DRAFT_STATE];
	    if (!state) return;
	    var base_ = state.base_,
	        draft_ = state.draft_,
	        assigned_ = state.assigned_,
	        type_ = state.type_;

	    if (type_ === 4
	    /* ES5Object */
	    ) {
	        // Look for added keys.
	        // probably there is a faster way to detect changes, as sweep + recurse seems to do some
	        // unnecessary work.
	        // also: probably we can store the information we detect here, to speed up tree finalization!
	        each(draft_, function (key) {
	          if (key === DRAFT_STATE) return; // The `undefined` check is a fast path for pre-existing keys.

	          if (base_[key] === undefined && !has(base_, key)) {
	            assigned_[key] = true;
	            markChanged(state);
	          } else if (!assigned_[key]) {
	            // Only untouched properties trigger recursion.
	            markChangesRecursively(draft_[key]);
	          }
	        }); // Look for removed keys.

	        each(base_, function (key) {
	          // The `undefined` check is a fast path for pre-existing keys.
	          if (draft_[key] === undefined && !has(draft_, key)) {
	            assigned_[key] = false;
	            markChanged(state);
	          }
	        });
	      } else if (type_ === 5
	    /* ES5Array */
	    ) {
	        if (hasArrayChanges(state)) {
	          markChanged(state);
	          assigned_.length = true;
	        }

	        if (draft_.length < base_.length) {
	          for (var i = draft_.length; i < base_.length; i++) {
	            assigned_[i] = false;
	          }
	        } else {
	          for (var _i2 = base_.length; _i2 < draft_.length; _i2++) {
	            assigned_[_i2] = true;
	          }
	        } // Minimum count is enough, the other parts has been processed.


	        var min = Math.min(draft_.length, base_.length);

	        for (var _i3 = 0; _i3 < min; _i3++) {
	          // Only untouched indices trigger recursion.
	          if (!draft_.hasOwnProperty(_i3)) {
	            assigned_[_i3] = true;
	          }

	          if (assigned_[_i3] === undefined) markChangesRecursively(draft_[_i3]);
	        }
	      }
	  }

	  function hasObjectChanges(state) {
	    var base_ = state.base_,
	        draft_ = state.draft_; // Search for added keys and changed keys. Start at the back, because
	    // non-numeric keys are ordered by time of definition on the object.

	    var keys = ownKeys(draft_);

	    for (var i = keys.length - 1; i >= 0; i--) {
	      var key = keys[i];
	      if (key === DRAFT_STATE) continue;
	      var baseValue = base_[key]; // The `undefined` check is a fast path for pre-existing keys.

	      if (baseValue === undefined && !has(base_, key)) {
	        return true;
	      } // Once a base key is deleted, future changes go undetected, because its
	      // descriptor is erased. This branch detects any missed changes.
	      else {
	          var value = draft_[key];

	          var _state = value && value[DRAFT_STATE];

	          if (_state ? _state.base_ !== baseValue : !is(value, baseValue)) {
	            return true;
	          }
	        }
	    } // At this point, no keys were added or changed.
	    // Compare key count to determine if keys were deleted.


	    var baseIsDraft = !!base_[DRAFT_STATE];
	    return keys.length !== ownKeys(base_).length + (baseIsDraft ? 0 : 1); // + 1 to correct for DRAFT_STATE
	  }

	  function hasArrayChanges(state) {
	    var draft_ = state.draft_;
	    if (draft_.length !== state.base_.length) return true; // See #116
	    // If we first shorten the length, our array interceptors will be removed.
	    // If after that new items are added, result in the same original length,
	    // those last items will have no intercepting property.
	    // So if there is no own descriptor on the last position, we know that items were removed and added
	    // N.B.: splice, unshift, etc only shift values around, but not prop descriptors, so we only have to check
	    // the last one
	    // last descriptor can be not a trap, if the array was extended

	    var descriptor = Object.getOwnPropertyDescriptor(draft_, draft_.length - 1); // descriptor can be null, but only for newly created sparse arrays, eg. new Array(10)

	    if (descriptor && !descriptor.get) return true; // if we miss a property, it has been deleted, so array probobaly changed

	    for (var i = 0; i < draft_.length; i++) {
	      if (!draft_.hasOwnProperty(i)) return true;
	    } // For all other cases, we don't have to compare, as they would have been picked up by the index setters


	    return false;
	  }

	  function hasChanges_(state) {
	    return state.type_ === 4
	    /* ES5Object */
	    ? hasObjectChanges(state) : hasArrayChanges(state);
	  }

	  function assertUnrevoked(state
	  /*ES5State | MapState | SetState*/
	  ) {
	    if (state.revoked_) die(3, JSON.stringify(latest(state)));
	  }

	  loadPlugin("ES5", {
	    createES5Proxy_: createES5Proxy_,
	    willFinalizeES5_: willFinalizeES5_,
	    hasChanges_: hasChanges_
	  });
	}

	function enablePatches() {
	  var REPLACE = "replace";
	  var ADD = "add";
	  var REMOVE = "remove";

	  function generatePatches_(state, basePath, patches, inversePatches) {
	    switch (state.type_) {
	      case 0
	      /* ProxyObject */
	      :
	      case 4
	      /* ES5Object */
	      :
	      case 2
	      /* Map */
	      :
	        return generatePatchesFromAssigned(state, basePath, patches, inversePatches);

	      case 5
	      /* ES5Array */
	      :
	      case 1
	      /* ProxyArray */
	      :
	        return generateArrayPatches(state, basePath, patches, inversePatches);

	      case 3
	      /* Set */
	      :
	        return generateSetPatches(state, basePath, patches, inversePatches);
	    }
	  }

	  function generateArrayPatches(state, basePath, patches, inversePatches) {
	    var base_ = state.base_,
	        assigned_ = state.assigned_;
	    var copy_ = state.copy_; // Reduce complexity by ensuring `base` is never longer.

	    if (copy_.length < base_.length) {
	      var _ref = [copy_, base_];
	      base_ = _ref[0];
	      copy_ = _ref[1];
	      var _ref2 = [inversePatches, patches];
	      patches = _ref2[0];
	      inversePatches = _ref2[1];
	    } // Process replaced indices.


	    for (var i = 0; i < base_.length; i++) {
	      if (assigned_[i] && copy_[i] !== base_[i]) {
	        var path = basePath.concat([i]);
	        patches.push({
	          op: REPLACE,
	          path: path,
	          // Need to maybe clone it, as it can in fact be the original value
	          // due to the base/copy inversion at the start of this function
	          value: clonePatchValueIfNeeded(copy_[i])
	        });
	        inversePatches.push({
	          op: REPLACE,
	          path: path,
	          value: clonePatchValueIfNeeded(base_[i])
	        });
	      }
	    } // Process added indices.


	    for (var _i = base_.length; _i < copy_.length; _i++) {
	      var _path = basePath.concat([_i]);

	      patches.push({
	        op: ADD,
	        path: _path,
	        // Need to maybe clone it, as it can in fact be the original value
	        // due to the base/copy inversion at the start of this function
	        value: clonePatchValueIfNeeded(copy_[_i])
	      });
	    }

	    if (base_.length < copy_.length) {
	      inversePatches.push({
	        op: REPLACE,
	        path: basePath.concat(["length"]),
	        value: base_.length
	      });
	    }
	  } // This is used for both Map objects and normal objects.


	  function generatePatchesFromAssigned(state, basePath, patches, inversePatches) {
	    var base_ = state.base_,
	        copy_ = state.copy_;
	    each(state.assigned_, function (key, assignedValue) {
	      var origValue = get(base_, key);
	      var value = get(copy_, key);
	      var op = !assignedValue ? REMOVE : has(base_, key) ? REPLACE : ADD;
	      if (origValue === value && op === REPLACE) return;
	      var path = basePath.concat(key);
	      patches.push(op === REMOVE ? {
	        op: op,
	        path: path
	      } : {
	        op: op,
	        path: path,
	        value: value
	      });
	      inversePatches.push(op === ADD ? {
	        op: REMOVE,
	        path: path
	      } : op === REMOVE ? {
	        op: ADD,
	        path: path,
	        value: clonePatchValueIfNeeded(origValue)
	      } : {
	        op: REPLACE,
	        path: path,
	        value: clonePatchValueIfNeeded(origValue)
	      });
	    });
	  }

	  function generateSetPatches(state, basePath, patches, inversePatches) {
	    var base_ = state.base_,
	        copy_ = state.copy_;
	    var i = 0;
	    base_.forEach(function (value) {
	      if (!copy_.has(value)) {
	        var path = basePath.concat([i]);
	        patches.push({
	          op: REMOVE,
	          path: path,
	          value: value
	        });
	        inversePatches.unshift({
	          op: ADD,
	          path: path,
	          value: value
	        });
	      }

	      i++;
	    });
	    i = 0;
	    copy_.forEach(function (value) {
	      if (!base_.has(value)) {
	        var path = basePath.concat([i]);
	        patches.push({
	          op: ADD,
	          path: path,
	          value: value
	        });
	        inversePatches.unshift({
	          op: REMOVE,
	          path: path,
	          value: value
	        });
	      }

	      i++;
	    });
	  }

	  function generateReplacementPatches_(baseValue, replacement, patches, inversePatches) {
	    patches.push({
	      op: REPLACE,
	      path: [],
	      value: replacement === NOTHING ? undefined : replacement
	    });
	    inversePatches.push({
	      op: REPLACE,
	      path: [],
	      value: baseValue
	    });
	  }

	  function applyPatches_(draft, patches) {
	    patches.forEach(function (patch) {
	      var path = patch.path,
	          op = patch.op;
	      var base = draft;

	      for (var i = 0; i < path.length - 1; i++) {
	        var parentType = getArchtype(base);
	        var p = "" + path[i]; // See #738, avoid prototype pollution

	        if ((parentType === 0
	        /* Object */
	        || parentType === 1
	        /* Array */
	        ) && (p === "__proto__" || p === "constructor")) die(24);
	        if (typeof base === "function" && p === "prototype") die(24);
	        base = get(base, p);
	        if (typeof base !== "object") die(15, path.join("/"));
	      }

	      var type = getArchtype(base);
	      var value = deepClonePatchValue(patch.value); // used to clone patch to ensure original patch is not modified, see #411

	      var key = path[path.length - 1];

	      switch (op) {
	        case REPLACE:
	          switch (type) {
	            case 2
	            /* Map */
	            :
	              return base.set(key, value);

	            /* istanbul ignore next */

	            case 3
	            /* Set */
	            :
	              die(16);

	            default:
	              // if value is an object, then it's assigned by reference
	              // in the following add or remove ops, the value field inside the patch will also be modifyed
	              // so we use value from the cloned patch
	              // @ts-ignore
	              return base[key] = value;
	          }

	        case ADD:
	          switch (type) {
	            case 1
	            /* Array */
	            :
	              return key === "-" ? base.push(value) : base.splice(key, 0, value);

	            case 2
	            /* Map */
	            :
	              return base.set(key, value);

	            case 3
	            /* Set */
	            :
	              return base.add(value);

	            default:
	              return base[key] = value;
	          }

	        case REMOVE:
	          switch (type) {
	            case 1
	            /* Array */
	            :
	              return base.splice(key, 1);

	            case 2
	            /* Map */
	            :
	              return base.delete(key);

	            case 3
	            /* Set */
	            :
	              return base.delete(patch.value);

	            default:
	              return delete base[key];
	          }

	        default:
	          die(17, op);
	      }
	    });
	    return draft;
	  }

	  function deepClonePatchValue(obj) {
	    if (!isDraftable(obj)) return obj;
	    if (Array.isArray(obj)) return obj.map(deepClonePatchValue);
	    if (isMap(obj)) return new Map(Array.from(obj.entries()).map(function (_ref3) {
	      var k = _ref3[0],
	          v = _ref3[1];
	      return [k, deepClonePatchValue(v)];
	    }));
	    if (isSet(obj)) return new Set(Array.from(obj).map(deepClonePatchValue));
	    var cloned = Object.create(Object.getPrototypeOf(obj));

	    for (var key in obj) {
	      cloned[key] = deepClonePatchValue(obj[key]);
	    }

	    if (has(obj, DRAFTABLE)) cloned[DRAFTABLE] = obj[DRAFTABLE];
	    return cloned;
	  }

	  function clonePatchValueIfNeeded(obj) {
	    if (isDraft(obj)) {
	      return deepClonePatchValue(obj);
	    } else return obj;
	  }

	  loadPlugin("Patches", {
	    applyPatches_: applyPatches_,
	    generatePatches_: generatePatches_,
	    generateReplacementPatches_: generateReplacementPatches_
	  });
	}

	// types only!
	function enableMapSet() {
	  /* istanbul ignore next */
	  var _extendStatics = function extendStatics(d, b) {
	    _extendStatics = Object.setPrototypeOf || {
	      __proto__: []
	    } instanceof Array && function (d, b) {
	      d.__proto__ = b;
	    } || function (d, b) {
	      for (var p in b) {
	        if (b.hasOwnProperty(p)) d[p] = b[p];
	      }
	    };

	    return _extendStatics(d, b);
	  }; // Ugly hack to resolve #502 and inherit built in Map / Set


	  function __extends(d, b) {
	    _extendStatics(d, b);

	    function __() {
	      this.constructor = d;
	    }

	    d.prototype = ( // @ts-ignore
	    __.prototype = b.prototype, new __());
	  }

	  var DraftMap = function (_super) {
	    __extends(DraftMap, _super); // Create class manually, cause #502


	    function DraftMap(target, parent) {
	      this[DRAFT_STATE] = {
	        type_: 2
	        /* Map */
	        ,
	        parent_: parent,
	        scope_: parent ? parent.scope_ : getCurrentScope(),
	        modified_: false,
	        finalized_: false,
	        copy_: undefined,
	        assigned_: undefined,
	        base_: target,
	        draft_: this,
	        isManual_: false,
	        revoked_: false
	      };
	      return this;
	    }

	    var p = DraftMap.prototype;
	    Object.defineProperty(p, "size", {
	      get: function get() {
	        return latest(this[DRAFT_STATE]).size;
	      } // enumerable: false,
	      // configurable: true

	    });

	    p.has = function (key) {
	      return latest(this[DRAFT_STATE]).has(key);
	    };

	    p.set = function (key, value) {
	      var state = this[DRAFT_STATE];
	      assertUnrevoked(state);

	      if (!latest(state).has(key) || latest(state).get(key) !== value) {
	        prepareMapCopy(state);
	        markChanged(state);
	        state.assigned_.set(key, true);
	        state.copy_.set(key, value);
	        state.assigned_.set(key, true);
	      }

	      return this;
	    };

	    p.delete = function (key) {
	      if (!this.has(key)) {
	        return false;
	      }

	      var state = this[DRAFT_STATE];
	      assertUnrevoked(state);
	      prepareMapCopy(state);
	      markChanged(state);

	      if (state.base_.has(key)) {
	        state.assigned_.set(key, false);
	      } else {
	        state.assigned_.delete(key);
	      }

	      state.copy_.delete(key);
	      return true;
	    };

	    p.clear = function () {
	      var state = this[DRAFT_STATE];
	      assertUnrevoked(state);

	      if (latest(state).size) {
	        prepareMapCopy(state);
	        markChanged(state);
	        state.assigned_ = new Map();
	        each(state.base_, function (key) {
	          state.assigned_.set(key, false);
	        });
	        state.copy_.clear();
	      }
	    };

	    p.forEach = function (cb, thisArg) {
	      var _this = this;

	      var state = this[DRAFT_STATE];
	      latest(state).forEach(function (_value, key, _map) {
	        cb.call(thisArg, _this.get(key), key, _this);
	      });
	    };

	    p.get = function (key) {
	      var state = this[DRAFT_STATE];
	      assertUnrevoked(state);
	      var value = latest(state).get(key);

	      if (state.finalized_ || !isDraftable(value)) {
	        return value;
	      }

	      if (value !== state.base_.get(key)) {
	        return value; // either already drafted or reassigned
	      } // despite what it looks, this creates a draft only once, see above condition


	      var draft = createProxy(state.scope_.immer_, value, state);
	      prepareMapCopy(state);
	      state.copy_.set(key, draft);
	      return draft;
	    };

	    p.keys = function () {
	      return latest(this[DRAFT_STATE]).keys();
	    };

	    p.values = function () {
	      var _this2 = this,
	          _ref;

	      var iterator = this.keys();
	      return _ref = {}, _ref[iteratorSymbol] = function () {
	        return _this2.values();
	      }, _ref.next = function next() {
	        var r = iterator.next();
	        /* istanbul ignore next */

	        if (r.done) return r;

	        var value = _this2.get(r.value);

	        return {
	          done: false,
	          value: value
	        };
	      }, _ref;
	    };

	    p.entries = function () {
	      var _this3 = this,
	          _ref2;

	      var iterator = this.keys();
	      return _ref2 = {}, _ref2[iteratorSymbol] = function () {
	        return _this3.entries();
	      }, _ref2.next = function next() {
	        var r = iterator.next();
	        /* istanbul ignore next */

	        if (r.done) return r;

	        var value = _this3.get(r.value);

	        return {
	          done: false,
	          value: [r.value, value]
	        };
	      }, _ref2;
	    };

	    p[iteratorSymbol] = function () {
	      return this.entries();
	    };

	    return DraftMap;
	  }(Map);

	  function proxyMap_(target, parent) {
	    // @ts-ignore
	    return new DraftMap(target, parent);
	  }

	  function prepareMapCopy(state) {
	    if (!state.copy_) {
	      state.assigned_ = new Map();
	      state.copy_ = new Map(state.base_);
	    }
	  }

	  var DraftSet = function (_super) {
	    __extends(DraftSet, _super); // Create class manually, cause #502


	    function DraftSet(target, parent) {
	      this[DRAFT_STATE] = {
	        type_: 3
	        /* Set */
	        ,
	        parent_: parent,
	        scope_: parent ? parent.scope_ : getCurrentScope(),
	        modified_: false,
	        finalized_: false,
	        copy_: undefined,
	        base_: target,
	        draft_: this,
	        drafts_: new Map(),
	        revoked_: false,
	        isManual_: false
	      };
	      return this;
	    }

	    var p = DraftSet.prototype;
	    Object.defineProperty(p, "size", {
	      get: function get() {
	        return latest(this[DRAFT_STATE]).size;
	      } // enumerable: true,

	    });

	    p.has = function (value) {
	      var state = this[DRAFT_STATE];
	      assertUnrevoked(state); // bit of trickery here, to be able to recognize both the value, and the draft of its value

	      if (!state.copy_) {
	        return state.base_.has(value);
	      }

	      if (state.copy_.has(value)) return true;
	      if (state.drafts_.has(value) && state.copy_.has(state.drafts_.get(value))) return true;
	      return false;
	    };

	    p.add = function (value) {
	      var state = this[DRAFT_STATE];
	      assertUnrevoked(state);

	      if (!this.has(value)) {
	        prepareSetCopy(state);
	        markChanged(state);
	        state.copy_.add(value);
	      }

	      return this;
	    };

	    p.delete = function (value) {
	      if (!this.has(value)) {
	        return false;
	      }

	      var state = this[DRAFT_STATE];
	      assertUnrevoked(state);
	      prepareSetCopy(state);
	      markChanged(state);
	      return state.copy_.delete(value) || (state.drafts_.has(value) ? state.copy_.delete(state.drafts_.get(value)) :
	      /* istanbul ignore next */
	      false);
	    };

	    p.clear = function () {
	      var state = this[DRAFT_STATE];
	      assertUnrevoked(state);

	      if (latest(state).size) {
	        prepareSetCopy(state);
	        markChanged(state);
	        state.copy_.clear();
	      }
	    };

	    p.values = function () {
	      var state = this[DRAFT_STATE];
	      assertUnrevoked(state);
	      prepareSetCopy(state);
	      return state.copy_.values();
	    };

	    p.entries = function entries() {
	      var state = this[DRAFT_STATE];
	      assertUnrevoked(state);
	      prepareSetCopy(state);
	      return state.copy_.entries();
	    };

	    p.keys = function () {
	      return this.values();
	    };

	    p[iteratorSymbol] = function () {
	      return this.values();
	    };

	    p.forEach = function forEach(cb, thisArg) {
	      var iterator = this.values();
	      var result = iterator.next();

	      while (!result.done) {
	        cb.call(thisArg, result.value, result.value, this);
	        result = iterator.next();
	      }
	    };

	    return DraftSet;
	  }(Set);

	  function proxySet_(target, parent) {
	    // @ts-ignore
	    return new DraftSet(target, parent);
	  }

	  function prepareSetCopy(state) {
	    if (!state.copy_) {
	      // create drafts for all entries to preserve insertion order
	      state.copy_ = new Set();
	      state.base_.forEach(function (value) {
	        if (isDraftable(value)) {
	          var draft = createProxy(state.scope_.immer_, value, state);
	          state.drafts_.set(value, draft);
	          state.copy_.add(draft);
	        } else {
	          state.copy_.add(value);
	        }
	      });
	    }
	  }

	  function assertUnrevoked(state
	  /*ES5State | MapState | SetState*/
	  ) {
	    if (state.revoked_) die(3, JSON.stringify(latest(state)));
	  }

	  loadPlugin("MapSet", {
	    proxyMap_: proxyMap_,
	    proxySet_: proxySet_
	  });
	}

	function enableAllPlugins() {
	  enableES5();
	  enableMapSet();
	  enablePatches();
	}

	var immer =
	/*#__PURE__*/
	new Immer();
	/**
	 * The `produce` function takes a value and a "recipe function" (whose
	 * return value often depends on the base state). The recipe function is
	 * free to mutate its first argument however it wants. All mutations are
	 * only ever applied to a __copy__ of the base state.
	 *
	 * Pass only a function to create a "curried producer" which relieves you
	 * from passing the recipe function every time.
	 *
	 * Only plain objects and arrays are made mutable. All other objects are
	 * considered uncopyable.
	 *
	 * Note: This function is __bound__ to its `Immer` instance.
	 *
	 * @param {any} base - the initial state
	 * @param {Function} producer - function that receives a proxy of the base state as first argument and which can be freely modified
	 * @param {Function} patchListener - optional function that will be called with all the patches produced here
	 * @returns {any} a new state, or the initial state if nothing was modified
	 */

	var produce = immer.produce;
	/**
	 * Like `produce`, but `produceWithPatches` always returns a tuple
	 * [nextState, patches, inversePatches] (instead of just the next state)
	 */

	var produceWithPatches =
	/*#__PURE__*/
	immer.produceWithPatches.bind(immer);
	/**
	 * Pass true to automatically freeze all copies created by Immer.
	 *
	 * Always freeze by default, even in production mode
	 */

	var setAutoFreeze =
	/*#__PURE__*/
	immer.setAutoFreeze.bind(immer);
	/**
	 * Pass true to use the ES2015 `Proxy` class when creating drafts, which is
	 * always faster than using ES5 proxies.
	 *
	 * By default, feature detection is used, so calling this is rarely necessary.
	 */

	var setUseProxies =
	/*#__PURE__*/
	immer.setUseProxies.bind(immer);
	/**
	 * Apply an array of Immer patches to the first argument.
	 *
	 * This function is a producer, which means copy-on-write is in effect.
	 */

	var applyPatches =
	/*#__PURE__*/
	immer.applyPatches.bind(immer);
	/**
	 * Create an Immer draft from the given base state, which may be a draft itself.
	 * The draft can be modified until you finalize it with the `finishDraft` function.
	 */

	var createDraft =
	/*#__PURE__*/
	immer.createDraft.bind(immer);
	/**
	 * Finalize an Immer draft from a `createDraft` call, returning the base state
	 * (if no changes were made) or a modified copy. The draft must *not* be
	 * mutated afterwards.
	 *
	 * Pass a function as the 2nd argument to generate Immer patches based on the
	 * changes that were made.
	 */

	var finishDraft =
	/*#__PURE__*/
	immer.finishDraft.bind(immer);
	/**
	 * This function is actually a no-op, but can be used to cast an immutable type
	 * to an draft type and make TypeScript happy
	 *
	 * @param value
	 */

	function castDraft(value) {
	  return value;
	}
	/**
	 * This function is actually a no-op, but can be used to cast a mutable type
	 * to an immutable type and make TypeScript happy
	 * @param value
	 */

	function castImmutable(value) {
	  return value;
	}

	exports.Immer = Immer;
	exports.applyPatches = applyPatches;
	exports.castDraft = castDraft;
	exports.castImmutable = castImmutable;
	exports.createDraft = createDraft;
	exports.current = current;
	exports.default = produce;
	exports.enableAllPlugins = enableAllPlugins;
	exports.enableES5 = enableES5;
	exports.enableMapSet = enableMapSet;
	exports.enablePatches = enablePatches;
	exports.finishDraft = finishDraft;
	exports.freeze = freeze;
	exports.immerable = DRAFTABLE;
	exports.isDraft = isDraft;
	exports.isDraftable = isDraftable;
	exports.nothing = NOTHING;
	exports.original = original;
	exports.produce = produce;
	exports.produceWithPatches = produceWithPatches;
	exports.setAutoFreeze = setAutoFreeze;
	exports.setUseProxies = setUseProxies;

	Object.defineProperty(exports, '__esModule', { value: true });

})));
//# sourceMappingURL=immer.umd.development.js.map
