(function () {
	'use strict';

	function getDefaultExportFromCjs (x) {
		return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
	}

	function createCommonjsModule(fn) {
	  var module = { exports: {} };
		return fn(module, module.exports), module.exports;
	}

	var constants = createCommonjsModule(function (module, exports) {

	  Object.defineProperty(exports, "__esModule", {
	    value: true
	  });
	  exports.DATA_CLONE_ERROR = exports.MESSAGE = exports.REJECTED = exports.FULFILLED = exports.REPLY = exports.CALL = exports.HANDSHAKE_REPLY = exports.HANDSHAKE = void 0;
	  const HANDSHAKE = 'handshake';
	  exports.HANDSHAKE = HANDSHAKE;
	  const HANDSHAKE_REPLY = 'handshake-reply';
	  exports.HANDSHAKE_REPLY = HANDSHAKE_REPLY;
	  const CALL = 'call';
	  exports.CALL = CALL;
	  const REPLY = 'reply';
	  exports.REPLY = REPLY;
	  const FULFILLED = 'fulfilled';
	  exports.FULFILLED = FULFILLED;
	  const REJECTED = 'rejected';
	  exports.REJECTED = REJECTED;
	  const MESSAGE = 'message';
	  exports.MESSAGE = MESSAGE;
	  const DATA_CLONE_ERROR = 'DataCloneError';
	  exports.DATA_CLONE_ERROR = DATA_CLONE_ERROR;
	});

	var errorCodes = createCommonjsModule(function (module, exports) {

	  Object.defineProperty(exports, "__esModule", {
	    value: true
	  });
	  exports.ERR_NO_IFRAME_SRC = exports.ERR_NOT_IN_IFRAME = exports.ERR_CONNECTION_TIMEOUT = exports.ERR_CONNECTION_DESTROYED = void 0;
	  const ERR_CONNECTION_DESTROYED = 'ConnectionDestroyed';
	  exports.ERR_CONNECTION_DESTROYED = ERR_CONNECTION_DESTROYED;
	  const ERR_CONNECTION_TIMEOUT = 'ConnectionTimeout';
	  exports.ERR_CONNECTION_TIMEOUT = ERR_CONNECTION_TIMEOUT;
	  const ERR_NOT_IN_IFRAME = 'NotInIframe';
	  exports.ERR_NOT_IN_IFRAME = ERR_NOT_IN_IFRAME;
	  const ERR_NO_IFRAME_SRC = 'NoIframeSrc';
	  exports.ERR_NO_IFRAME_SRC = ERR_NO_IFRAME_SRC;
	});

	var createDestructor = createCommonjsModule(function (module, exports) {

	  Object.defineProperty(exports, "__esModule", {
	    value: true
	  });
	  exports.default = void 0;

	  var _default = () => {
	    const callbacks = [];
	    let destroyed = false;
	    return {
	      destroy() {
	        destroyed = true;
	        callbacks.forEach(callback => {
	          callback();
	        });
	      },

	      onDestroy(callback) {
	        destroyed ? callback() : callbacks.push(callback);
	      }

	    };
	  };

	  exports.default = _default;
	  module.exports = exports.default;
	});

	var errorSerialization = createCommonjsModule(function (module, exports) {

	  Object.defineProperty(exports, "__esModule", {
	    value: true
	  });
	  exports.deserializeError = exports.serializeError = void 0;
	  /**
	   * Converts an error object into a plain object.
	   * @param {Error} Error object.
	   * @returns {Object}
	   */

	  const serializeError = _ref => {
	    let name = _ref.name,
	        message = _ref.message,
	        stack = _ref.stack;
	    return {
	      name,
	      message,
	      stack
	    };
	  };
	  /**
	   * Converts a plain object into an error object.
	   * @param {Object} Object with error properties.
	   * @returns {Error}
	   */


	  exports.serializeError = serializeError;

	  const deserializeError = obj => {
	    const deserializedError = new Error();
	    Object.keys(obj).forEach(key => deserializedError[key] = obj[key]);
	    return deserializedError;
	  };

	  exports.deserializeError = deserializeError;
	});

	var connectCallReceiver = createCommonjsModule(function (module, exports) {

	  Object.defineProperty(exports, "__esModule", {
	    value: true
	  });
	  exports.default = void 0;
	  /**
	   * Listens for "call" messages coming from the remote, executes the corresponding method, and
	   * responds with the return value.
	   * @param {Object} info Information about the local and remote windows.
	   * @param {Object} methods The keys are the names of the methods that can be called by the remote
	   * while the values are the method functions.
	   * @param {Promise} destructionPromise A promise resolved when destroy() is called on the penpal
	   * connection.
	   * @returns {Function} A function that may be called to disconnect the receiver.
	   */

	  var _default = (info, methods, log) => {
	    const localName = info.localName,
	          local = info.local,
	          remote = info.remote,
	          originForSending = info.originForSending,
	          originForReceiving = info.originForReceiving;
	    let destroyed = false;
	    log(`${localName}: Connecting call receiver`);

	    const handleMessageEvent = event => {
	      if (event.source !== remote || event.data.penpal !== constants.CALL) {
	        return;
	      }

	      if (event.origin !== originForReceiving) {
	        log(`${localName} received message from origin ${event.origin} which did not match expected origin ${originForReceiving}`);
	        return;
	      }

	      const _event$data = event.data,
	            methodName = _event$data.methodName,
	            args = _event$data.args,
	            id = _event$data.id;
	      log(`${localName}: Received ${methodName}() call`);

	      const createPromiseHandler = resolution => {
	        return returnValue => {
	          log(`${localName}: Sending ${methodName}() reply`);

	          if (destroyed) {
	            // It's possible to throw an error here, but it would need to be thrown asynchronously
	            // and would only be catchable using window.onerror. This is because the consumer
	            // is merely returning a value from their method and not calling any function
	            // that they could wrap in a try-catch. Even if the consumer were to catch the error,
	            // the value of doing so is questionable. Instead, we'll just log a message.
	            log(`${localName}: Unable to send ${methodName}() reply due to destroyed connection`);
	            return;
	          }

	          const message = {
	            penpal: constants.REPLY,
	            id,
	            resolution,
	            returnValue
	          };

	          if (resolution === constants.REJECTED && returnValue instanceof Error) {
	            message.returnValue = (0, errorSerialization.serializeError)(returnValue);
	            message.returnValueIsError = true;
	          }

	          try {
	            remote.postMessage(message, originForSending);
	          } catch (err) {
	            // If a consumer attempts to send an object that's not cloneable (e.g., window),
	            // we want to ensure the receiver's promise gets rejected.
	            if (err.name === constants.DATA_CLONE_ERROR) {
	              remote.postMessage({
	                penpal: constants.REPLY,
	                id,
	                resolution: constants.REJECTED,
	                returnValue: (0, errorSerialization.serializeError)(err),
	                returnValueIsError: true
	              }, originForSending);
	            }

	            throw err;
	          }
	        };
	      };

	      new Promise(resolve => resolve(methods[methodName].apply(methods, args))).then(createPromiseHandler(constants.FULFILLED), createPromiseHandler(constants.REJECTED));
	    };

	    local.addEventListener(constants.MESSAGE, handleMessageEvent);
	    return () => {
	      destroyed = true;
	      local.removeEventListener(constants.MESSAGE, handleMessageEvent);
	    };
	  };

	  exports.default = _default;
	  module.exports = exports.default;
	});

	var generateId = createCommonjsModule(function (module, exports) {

	  Object.defineProperty(exports, "__esModule", {
	    value: true
	  });
	  exports.default = void 0;
	  let id = 0;
	  /**
	   * @return {number} A unique ID (not universally unique)
	   */

	  var _default = () => ++id;

	  exports.default = _default;
	  module.exports = exports.default;
	});

	var connectCallSender = createCommonjsModule(function (module, exports) {

	  Object.defineProperty(exports, "__esModule", {
	    value: true
	  });
	  exports.default = void 0;

	  var _generateId = _interopRequireDefault(generateId);

	  function _interopRequireDefault(obj) {
	    return obj && obj.__esModule ? obj : {
	      default: obj
	    };
	  }
	  /**
	   * Augments an object with methods that match those defined by the remote. When these methods are
	   * called, a "call" message will be sent to the remote, the remote's corresponding method will be
	   * executed, and the method's return value will be returned via a message.
	   * @param {Object} callSender Sender object that should be augmented with methods.
	   * @param {Object} info Information about the local and remote windows.
	   * @param {Array} methodNames Names of methods available to be called on the remote.
	   * @param {Promise} destructionPromise A promise resolved when destroy() is called on the penpal
	   * connection.
	   * @returns {Object} The call sender object with methods that may be called.
	   */


	  var _default = (callSender, info, methodNames, destroyConnection, log) => {
	    const localName = info.localName,
	          local = info.local,
	          remote = info.remote,
	          originForSending = info.originForSending,
	          originForReceiving = info.originForReceiving;
	    let destroyed = false;
	    log(`${localName}: Connecting call sender`);

	    const createMethodProxy = methodName => {
	      return function () {
	        for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
	          args[_key] = arguments[_key];
	        }

	        log(`${localName}: Sending ${methodName}() call`); // This handles the case where the iframe has been removed from the DOM
	        // (and therefore its window closed), the consumer has not yet
	        // called destroy(), and the user calls a method exposed by
	        // the remote. We detect the iframe has been removed and force
	        // a destroy() immediately so that the consumer sees the error saying
	        // the connection has been destroyed. We wrap this check in a try catch
	        // because Edge throws an "Object expected" error when accessing
	        // contentWindow.closed on a contentWindow from an iframe that's been
	        // removed from the DOM.

	        let iframeRemoved;

	        try {
	          if (remote.closed) {
	            iframeRemoved = true;
	          }
	        } catch (e) {
	          iframeRemoved = true;
	        }

	        if (iframeRemoved) {
	          destroyConnection();
	        }

	        if (destroyed) {
	          const error = new Error(`Unable to send ${methodName}() call due ` + `to destroyed connection`);
	          error.code = errorCodes.ERR_CONNECTION_DESTROYED;
	          throw error;
	        }

	        return new Promise((resolve, reject) => {
	          const id = (0, _generateId.default)();

	          const handleMessageEvent = event => {
	            if (event.source !== remote || event.data.penpal !== constants.REPLY || event.data.id !== id) {
	              return;
	            }

	            if (event.origin !== originForReceiving) {
	              log(`${localName} received message from origin ${event.origin} which did not match expected origin ${originForReceiving}`);
	              return;
	            }

	            log(`${localName}: Received ${methodName}() reply`);
	            local.removeEventListener(constants.MESSAGE, handleMessageEvent);
	            let returnValue = event.data.returnValue;

	            if (event.data.returnValueIsError) {
	              returnValue = (0, errorSerialization.deserializeError)(returnValue);
	            }

	            (event.data.resolution === constants.FULFILLED ? resolve : reject)(returnValue);
	          };

	          local.addEventListener(constants.MESSAGE, handleMessageEvent);
	          remote.postMessage({
	            penpal: constants.CALL,
	            id,
	            methodName,
	            args
	          }, originForSending);
	        });
	      };
	    };

	    methodNames.reduce((api, methodName) => {
	      api[methodName] = createMethodProxy(methodName);
	      return api;
	    }, callSender);
	    return () => {
	      destroyed = true;
	    };
	  };

	  exports.default = _default;
	  module.exports = exports.default;
	});

	var createLogger = createCommonjsModule(function (module, exports) {

	  Object.defineProperty(exports, "__esModule", {
	    value: true
	  });
	  exports.default = void 0;

	  var _default = debug => {
	    return function () {
	      if (debug) {
	        for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
	          args[_key] = arguments[_key];
	        }

	        console.log('[Penpal]', ...args); // eslint-disable-line no-console
	      }
	    };
	  };

	  exports.default = _default;
	  module.exports = exports.default;
	});

	var connectToParent = createCommonjsModule(function (module, exports) {

	  Object.defineProperty(exports, "__esModule", {
	    value: true
	  });
	  exports.default = void 0;

	  var _createDestructor2 = _interopRequireDefault(createDestructor);

	  var _connectCallReceiver = _interopRequireDefault(connectCallReceiver);

	  var _connectCallSender = _interopRequireDefault(connectCallSender);

	  var _createLogger = _interopRequireDefault(createLogger);

	  function _interopRequireDefault(obj) {
	    return obj && obj.__esModule ? obj : {
	      default: obj
	    };
	  }
	  /**
	   * @typedef {Object} Parent
	   * @property {Promise} promise A promise which will be resolved once a connection has
	   * been established.
	   * @property {Function} destroy A method that, when called, will disconnect any
	   * messaging channels. You may call this even before a connection has been established.
	   */

	  /**
	   * Attempts to establish communication with the parent window.
	   * @param {Object} options
	   * @param {string} [options.parentOrigin=*] Valid parent origin used to restrict communication.
	   * @param {Object} [options.methods={}] Methods that may be called by the parent window.
	   * @param {Number} [options.timeout] The amount of time, in milliseconds, Penpal should wait
	   * for the parent to respond before rejecting the connection promise.
	   * @return {Parent}
	   */


	  var _default = function _default() {
	    let _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
	        _ref$parentOrigin = _ref.parentOrigin,
	        parentOrigin = _ref$parentOrigin === void 0 ? '*' : _ref$parentOrigin,
	        _ref$methods = _ref.methods,
	        methods = _ref$methods === void 0 ? {} : _ref$methods,
	        timeout = _ref.timeout,
	        debug = _ref.debug;

	    const log = (0, _createLogger.default)(debug);

	    if (window === window.top) {
	      const error = new Error('connectToParent() must be called within an iframe');
	      error.code = errorCodes.ERR_NOT_IN_IFRAME;
	      throw error;
	    }

	    const _createDestructor = (0, _createDestructor2.default)(),
	          destroy = _createDestructor.destroy,
	          onDestroy = _createDestructor.onDestroy;

	    const child = window;
	    const parent = child.parent;
	    const promise = new Promise((resolveConnectionPromise, reject) => {
	      let connectionTimeoutId;

	      if (timeout !== undefined) {
	        connectionTimeoutId = setTimeout(() => {
	          const error = new Error(`Connection to parent timed out after ${timeout}ms`);
	          error.code = errorCodes.ERR_CONNECTION_TIMEOUT;
	          reject(error);
	          destroy();
	        }, timeout);
	      }

	      const handleMessageEvent = event => {
	        // Under niche scenarios, we get into this function after
	        // the iframe has been removed from the DOM. In Edge, this
	        // results in "Object expected" errors being thrown when we
	        // try to access properties on window (global properties).
	        // For this reason, we try to access a global up front (clearTimeout)
	        // and if it fails we can assume the iframe has been removed
	        // and we ignore the message event.
	        try {
	          clearTimeout();
	        } catch (e) {
	          return;
	        }

	        if (event.source !== parent || event.data.penpal !== constants.HANDSHAKE_REPLY) {
	          return;
	        }

	        if (parentOrigin !== '*' && parentOrigin !== event.origin) {
	          log(`Child received handshake reply from origin ${event.origin} which did not match expected origin ${parentOrigin}`);
	          return;
	        }

	        log('Child: Received handshake reply');
	        child.removeEventListener(constants.MESSAGE, handleMessageEvent);
	        const info = {
	          localName: 'Child',
	          local: child,
	          remote: parent,
	          originForSending: event.origin === 'null' ? '*' : event.origin,
	          originForReceiving: event.origin
	        };
	        const callSender = {};
	        const destroyCallReceiver = (0, _connectCallReceiver.default)(info, methods, log);
	        onDestroy(destroyCallReceiver);
	        const destroyCallSender = (0, _connectCallSender.default)(callSender, info, event.data.methodNames, destroy, log);
	        onDestroy(destroyCallSender);
	        clearTimeout(connectionTimeoutId);
	        resolveConnectionPromise(callSender);
	      };

	      child.addEventListener(constants.MESSAGE, handleMessageEvent);
	      onDestroy(() => {
	        child.removeEventListener(constants.MESSAGE, handleMessageEvent);
	        const error = new Error('Connection destroyed');
	        error.code = errorCodes.ERR_CONNECTION_DESTROYED;
	        reject(error);
	      });
	      log('Child: Sending handshake');
	      parent.postMessage({
	        penpal: constants.HANDSHAKE,
	        methodNames: Object.keys(methods)
	      }, parentOrigin);
	    });
	    return {
	      promise,
	      destroy
	    };
	  };

	  exports.default = _default;
	  module.exports = exports.default;
	});
	var connectToParent$1 = /*@__PURE__*/getDefaultExportFromCjs(connectToParent);

	/***************************************************************************************
	 * (c) 2017 Adobe. All rights reserved.
	 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
	 * you may not use this file except in compliance with the License. You may obtain a copy
	 * of the License at http://www.apache.org/licenses/LICENSE-2.0
	 *
	 * Unless required by applicable law or agreed to in writing, software distributed under
	 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
	 * OF ANY KIND, either express or implied. See the License for the specific language
	 * governing permissions and limitations under the License.
	 ****************************************************************************************/

	/**
	 * Creates a style block, adds CSS to it, then adds the block to the page.
	 * @param {string} The CSS to be applied to the page.
	 */
	var addStylesToPage = (css => {
	  const styleTag = document.createElement('style');
	  styleTag.appendChild(document.createTextNode(css));
	  document.head.appendChild(styleTag);
	});

	/***************************************************************************************
	 * (c) 2017 Adobe. All rights reserved.
	 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
	 * you may not use this file except in compliance with the License. You may obtain a copy
	 * of the License at http://www.apache.org/licenses/LICENSE-2.0
	 *
	 * Unless required by applicable law or agreed to in writing, software distributed under
	 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
	 * OF ANY KIND, either express or implied. See the License for the specific language
	 * governing permissions and limitations under the License.
	 ****************************************************************************************/
	const STYLES = `
  html, body {
    background-color: transparent !important;
  }
`;
	addStylesToPage(STYLES);
	let extensionViewMethods = {};
	let connectionPromise;

	const getExtensionViewMethod = methodName => {
	  const method = extensionViewMethods[methodName];

	  if (method) {
	    return method.bind(extensionViewMethods);
	  } else {
	    throw new Error(`Unable to call ${methodName} on the extension. The extension must register a ${methodName} function using extensionBridge.register().`);
	  }
	};

	const init = (...args) => {
	  getExtensionViewMethod('init')(...args);
	};

	const validate = (...args) => {
	  return Promise.resolve(getExtensionViewMethod('validate')(...args)).then(result => {
	    if (typeof result !== 'boolean') {
	      throw new Error(`The extension attempted to return a non-boolean value from validate: ${result}`);
	    }

	    return result;
	  });
	};

	const getSettings = function (...args) {
	  return Promise.resolve(getExtensionViewMethod('getSettings')(...args)).then(result => {
	    if (typeof result !== 'object') {
	      throw new Error('The extension attempted to return a non-object value from getSettings: ' + result);
	    }

	    return result;
	  });
	};

	const wrapOpenSharedViewMethod = (methodName, sharedViewName) => (...args) => {
	  let callback;

	  if (typeof args[0] === 'function') {
	    callback = args.shift(); // Deprecated April 10, 2018. 30+ extensions were using a callback at the time.

	    console.warn('Passing a callback to extensionBridge.' + methodName + '() has been deprecated. ' + 'The method now returns a promise that should be used instead.');
	  }

	  return connectionPromise.then(parent => {
	    if (parent[methodName]) {
	      return parent[methodName](...args);
	    } else {
	      throw new Error(`An error occurred while opening ${sharedViewName}. The shared view is unavailable.`);
	    }
	  }).then(result => {
	    if (callback) {
	      callback(result);
	    }

	    return result;
	  });
	};

	connectionPromise = connectToParent$1({
	  methods: {
	    init,
	    validate,
	    getSettings
	  }
	}).promise;
	const extensionBridge = {
	  openCodeEditor: wrapOpenSharedViewMethod('openCodeEditor', 'code editor'),
	  openDataElementSelector: wrapOpenSharedViewMethod('openDataElementSelector', 'data element selector'),
	  openRegexTester: wrapOpenSharedViewMethod('openRegexTester', 'regex tester'),

	  register(methods) {
	    extensionViewMethods = { ...methods
	    };
	    connectionPromise.then(parent => parent.extensionRegistered());
	  }

	};
	window.addEventListener('focus', () => {
	  connectionPromise.then(parent => parent.markAsDirty());
	});

	const executeQueuedCall = call => {
	  // Not all of the extension bridge methods return promises. Rather than do a switch where we
	  // only handle promises coming from certain methods here, we'll just always convert the return
	  // value to a promise and them consistently.
	  Promise.resolve(extensionBridge[call.methodName](...call.args)).then(call.resolve, call.reject);
	};

	const callQueue = window.extensionBridge._callQueue;

	while (callQueue.length) {
	  executeQueuedCall(callQueue.shift());
	}

	callQueue.push = executeQueuedCall;

}());
