<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[41604] trunk/src/wp-includes: TinyMCE: update to 4.6.7, changelog: https://www.tinymce.com/docs/changelog/#version467september182017.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/41604">41604</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/41604","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>azaozz</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2017-09-26 21:14:28 +0000 (Tue, 26 Sep 2017)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>TinyMCE: update to 4.6.7, changelog: https://www.tinymce.com/docs/changelog/#version467september182017.

Fixes <a href="https://core.trac.wordpress.org/ticket/41996">#41996</a> <a href="https://core.trac.wordpress.org/ticket/40956">#40956</a></pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesjstinymcepluginsimagepluginjs">trunk/src/wp-includes/js/tinymce/plugins/image/plugin.js</a></li>
<li><a href="#trunksrcwpincludesjstinymcepluginsimagepluginminjs">trunk/src/wp-includes/js/tinymce/plugins/image/plugin.min.js</a></li>
<li><a href="#trunksrcwpincludesjstinymcepluginslinkpluginjs">trunk/src/wp-includes/js/tinymce/plugins/link/plugin.js</a></li>
<li><a href="#trunksrcwpincludesjstinymcepluginslinkpluginminjs">trunk/src/wp-includes/js/tinymce/plugins/link/plugin.min.js</a></li>
<li><a href="#trunksrcwpincludesjstinymcepluginslistspluginjs">trunk/src/wp-includes/js/tinymce/plugins/lists/plugin.js</a></li>
<li><a href="#trunksrcwpincludesjstinymcepluginslistspluginminjs">trunk/src/wp-includes/js/tinymce/plugins/lists/plugin.min.js</a></li>
<li><a href="#trunksrcwpincludesjstinymcepluginspastepluginjs">trunk/src/wp-includes/js/tinymce/plugins/paste/plugin.js</a></li>
<li><a href="#trunksrcwpincludesjstinymcepluginspastepluginminjs">trunk/src/wp-includes/js/tinymce/plugins/paste/plugin.min.js</a></li>
<li><a href="#trunksrcwpincludesjstinymceskinslightgraycontentinlinemincss">trunk/src/wp-includes/js/tinymce/skins/lightgray/content.inline.min.css</a></li>
<li><a href="#trunksrcwpincludesjstinymceskinslightgraycontentmincss">trunk/src/wp-includes/js/tinymce/skins/lightgray/content.min.css</a></li>
<li><a href="#trunksrcwpincludesjstinymceskinslightgrayskinmincss">trunk/src/wp-includes/js/tinymce/skins/lightgray/skin.min.css</a></li>
<li><a href="#trunksrcwpincludesjstinymceskinswordpresswpcontentcss">trunk/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css</a></li>
<li><a href="#trunksrcwpincludesjstinymcethemesinlitethemejs">trunk/src/wp-includes/js/tinymce/themes/inlite/theme.js</a></li>
<li><a href="#trunksrcwpincludesjstinymcethemesinlitethememinjs">trunk/src/wp-includes/js/tinymce/themes/inlite/theme.min.js</a></li>
<li><a href="#trunksrcwpincludesjstinymcetiny_mce_popupjs">trunk/src/wp-includes/js/tinymce/tiny_mce_popup.js</a></li>
<li><a href="#trunksrcwpincludesjstinymcetinymcejs">trunk/src/wp-includes/js/tinymce/tinymce.js</a></li>
<li><a href="#trunksrcwpincludesjstinymcetinymceminjs">trunk/src/wp-includes/js/tinymce/tinymce.min.js</a></li>
<li><a href="#trunksrcwpincludesjstinymceutilsmctabsjs">trunk/src/wp-includes/js/tinymce/utils/mctabs.js</a></li>
<li><a href="#trunksrcwpincludesversionphp">trunk/src/wp-includes/version.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpincludesjstinymcepluginsimagepluginjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/tinymce/plugins/image/plugin.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/tinymce/plugins/image/plugin.js  2017-09-26 20:32:46 UTC (rev 41603)
+++ trunk/src/wp-includes/js/tinymce/plugins/image/plugin.js    2017-09-26 21:14:28 UTC (rev 41604)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -81,7 +81,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">   define(id, [], function () { return ref; });
</span><span class="cx" style="display: block; padding: 0 10px"> };
</span><span class="cx" style="display: block; padding: 0 10px"> /*jsc
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-["tinymce.plugins.image.Plugin","tinymce.core.Env","tinymce.core.PluginManager","tinymce.core.util.JSON","tinymce.core.util.Tools","tinymce.core.util.XHR","global!tinymce.util.Tools.resolve"]
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+["tinymce.plugins.image.Plugin","tinymce.core.PluginManager","tinymce.core.util.Tools","tinymce.plugins.image.ui.Dialog","global!tinymce.util.Tools.resolve","global!document","global!Math","global!RegExp","tinymce.core.Env","tinymce.core.ui.Factory","tinymce.core.util.JSON","tinymce.core.util.XHR","tinymce.plugins.image.core.Uploader","tinymce.plugins.image.core.Utils","tinymce.core.util.Promise"]
</ins><span class="cx" style="display: block; padding: 0 10px"> jsc*/
</span><span class="cx" style="display: block; padding: 0 10px"> defineGlobal("global!tinymce.util.Tools.resolve", tinymce.util.Tools.resolve);
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -95,6 +95,49 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.PluginManager',
+  [
+    'global!tinymce.util.Tools.resolve'
+  ],
+  function (resolve) {
+    return resolve('tinymce.PluginManager');
+  }
+);
+
+/**
+ * ResolveGlobal.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.util.Tools',
+  [
+    'global!tinymce.util.Tools.resolve'
+  ],
+  function (resolve) {
+    return resolve('tinymce.util.Tools');
+  }
+);
+
+defineGlobal("global!document", document);
+defineGlobal("global!Math", Math);
+defineGlobal("global!RegExp", RegExp);
+/**
+ * ResolveGlobal.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
</ins><span class="cx" style="display: block; padding: 0 10px">   'tinymce.core.Env',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><span class="cx" style="display: block; padding: 0 10px">     'global!tinymce.util.Tools.resolve'
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -115,12 +158,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.PluginManager',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.ui.Factory',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><span class="cx" style="display: block; padding: 0 10px">     'global!tinymce.util.Tools.resolve'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><span class="cx" style="display: block; padding: 0 10px">   function (resolve) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return resolve('tinymce.PluginManager');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return resolve('tinymce.ui.Factory');
</ins><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -155,12 +198,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.util.Tools',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.util.XHR',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><span class="cx" style="display: block; padding: 0 10px">     'global!tinymce.util.Tools.resolve'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><span class="cx" style="display: block; padding: 0 10px">   function (resolve) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return resolve('tinymce.util.Tools');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return resolve('tinymce.util.XHR');
</ins><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -175,17 +218,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.util.XHR',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.util.Promise',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><span class="cx" style="display: block; padding: 0 10px">     'global!tinymce.util.Tools.resolve'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><span class="cx" style="display: block; padding: 0 10px">   function (resolve) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return resolve('tinymce.util.XHR');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return resolve('tinymce.util.Promise');
</ins><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Plugin.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Uploader.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -195,97 +238,330 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * This class contains all core logic for the image plugin.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * This is basically cut down version of tinymce.core.file.Uploader, which we could use directly
+ * if it wasn't marked as private.
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @class tinymce.image.Plugin
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @class tinymce.image.core.Uploader
</ins><span class="cx" style="display: block; padding: 0 10px">  * @private
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.plugins.image.Plugin',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.plugins.image.core.Uploader',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.Env',
-    'tinymce.core.PluginManager',
-    'tinymce.core.util.JSON',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.util.Promise',
</ins><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.Tools',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.util.XHR'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'global!document'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Env, PluginManager, JSON, Tools, XHR) {
-    PluginManager.add('image', function (editor) {
-      function getImageSize(url, callback) {
-        var img = document.createElement('img');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Promise, Tools, document) {
+    return function (settings) {
+      var noop = function () {};
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function done(width, height) {
-          if (img.parentNode) {
-            img.parentNode.removeChild(img);
-          }
-
-          callback({ width: width, height: height });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function pathJoin(path1, path2) {
+        if (path1) {
+          return path1.replace(/\/$/, '') + '/' + path2.replace(/^\//, '');
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        img.onload = function () {
-          done(Math.max(img.width, img.clientWidth), Math.max(img.height, img.clientHeight));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return path2;
+      }
+
+      function defaultHandler(blobInfo, success, failure, progress) {
+        var xhr, formData;
+
+        xhr = new XMLHttpRequest();
+        xhr.open('POST', settings.url);
+        xhr.withCredentials = settings.credentials;
+
+        xhr.upload.onprogress = function (e) {
+          progress(e.loaded / e.total * 100);
</ins><span class="cx" style="display: block; padding: 0 10px">         };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        img.onerror = function () {
-          done();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        xhr.onerror = function () {
+          failure("Image upload failed due to a XHR Transport error. Code: " + xhr.status);
</ins><span class="cx" style="display: block; padding: 0 10px">         };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var style = img.style;
-        style.visibility = 'hidden';
-        style.position = 'fixed';
-        style.bottom = style.left = 0;
-        style.width = style.height = 'auto';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        xhr.onload = function () {
+          var json;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        document.body.appendChild(img);
-        img.src = url;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (xhr.status < 200 || xhr.status >= 300) {
+            failure("HTTP Error: " + xhr.status);
+            return;
+          }
+
+          json = JSON.parse(xhr.responseText);
+
+          if (!json || typeof json.location != "string") {
+            failure("Invalid JSON: " + xhr.responseText);
+            return;
+          }
+
+          success(pathJoin(settings.basePath, json.location));
+        };
+
+        formData = new FormData();
+        formData.append('file', blobInfo.blob(), blobInfo.filename());
+
+        xhr.send(formData);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function buildListItems(inputList, itemCallback, startItems) {
-        function appendItems(values, output) {
-          output = output || [];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function uploadBlob(blobInfo, handler) {
+        return new Promise(function (resolve, reject) {
+          try {
+            handler(blobInfo, resolve, reject, noop);
+          } catch (ex) {
+            reject(ex.message);
+          }
+        });
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          Tools.each(values, function (item) {
-            var menuItem = { text: item.text || item.title };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function isDefaultHandler(handler) {
+        return handler === defaultHandler;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (item.menu) {
-              menuItem.menu = appendItems(item.menu);
-            } else {
-              menuItem.value = item.value;
-              itemCallback(menuItem);
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function upload(blobInfo) {
+        return (!settings.url && isDefaultHandler(settings.handler)) ? Promise.reject("Upload url missng from the settings.") : uploadBlob(blobInfo, settings.handler);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            output.push(menuItem);
-          });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      settings = Tools.extend({
+        credentials: false,
+        handler: defaultHandler
+      }, settings);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return output;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return {
+        upload: upload
+      };
+    };
+  }
+);
+/**
+ * Utils.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * @class tinymce.image.core.Utils
+ * @private
+ */
+define(
+  'tinymce.plugins.image.core.Utils',
+  [
+    'tinymce.core.util.Tools',
+    'global!Math',
+    'global!document'
+  ],
+  function (Tools, Math, document) {
+
+    var getImageSize = function (url, callback) {
+      var img = document.createElement('img');
+
+      function done(width, height) {
+        if (img.parentNode) {
+          img.parentNode.removeChild(img);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return appendItems(inputList, startItems || []);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        callback({ width: width, height: height });
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function createImageList(callback) {
-        return function () {
-          var imageList = editor.settings.image_list;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      img.onload = function () {
+        done(Math.max(img.width, img.clientWidth), Math.max(img.height, img.clientHeight));
+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (typeof imageList == "string") {
-            XHR.send({
-              url: imageList,
-              success: function (text) {
-                callback(JSON.parse(text));
-              }
-            });
-          } else if (typeof imageList == "function") {
-            imageList(callback);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      img.onerror = function () {
+        done();
+      };
+
+      var style = img.style;
+      style.visibility = 'hidden';
+      style.position = 'fixed';
+      style.bottom = style.left = 0;
+      style.width = style.height = 'auto';
+
+      document.body.appendChild(img);
+      img.src = url;
+    };
+
+
+    var buildListItems = function (inputList, itemCallback, startItems) {
+      function appendItems(values, output) {
+        output = output || [];
+
+        Tools.each(values, function (item) {
+          var menuItem = { text: item.text || item.title };
+
+          if (item.menu) {
+            menuItem.menu = appendItems(item.menu);
</ins><span class="cx" style="display: block; padding: 0 10px">           } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            callback(imageList);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            menuItem.value = item.value;
+            itemCallback(menuItem);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+          output.push(menuItem);
+        });
+
+        return output;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return appendItems(inputList, startItems || []);
+    };
+
+    var removePixelSuffix = function (value) {
+      if (value) {
+        value = value.replace(/px$/, '');
+      }
+      return value;
+    };
+
+    var addPixelSuffix = function (value) {
+      if (value.length > 0 && /^[0-9]+$/.test(value)) {
+        value += 'px';
+      }
+      return value;
+    };
+
+    var mergeMargins = function (css) {
+      if (css.margin) {
+
+        var splitMargin = css.margin.split(" ");
+
+        switch (splitMargin.length) {
+          case 1: //margin: toprightbottomleft;
+            css['margin-top'] = css['margin-top'] || splitMargin[0];
+            css['margin-right'] = css['margin-right'] || splitMargin[0];
+            css['margin-bottom'] = css['margin-bottom'] || splitMargin[0];
+            css['margin-left'] = css['margin-left'] || splitMargin[0];
+            break;
+          case 2: //margin: topbottom rightleft;
+            css['margin-top'] = css['margin-top'] || splitMargin[0];
+            css['margin-right'] = css['margin-right'] || splitMargin[1];
+            css['margin-bottom'] = css['margin-bottom'] || splitMargin[0];
+            css['margin-left'] = css['margin-left'] || splitMargin[1];
+            break;
+          case 3: //margin: top rightleft bottom;
+            css['margin-top'] = css['margin-top'] || splitMargin[0];
+            css['margin-right'] = css['margin-right'] || splitMargin[1];
+            css['margin-bottom'] = css['margin-bottom'] || splitMargin[2];
+            css['margin-left'] = css['margin-left'] || splitMargin[1];
+            break;
+          case 4: //margin: top right bottom left;
+            css['margin-top'] = css['margin-top'] || splitMargin[0];
+            css['margin-right'] = css['margin-right'] || splitMargin[1];
+            css['margin-bottom'] = css['margin-bottom'] || splitMargin[2];
+            css['margin-left'] = css['margin-left'] || splitMargin[3];
+        }
+        delete css.margin;
+      }
+      return css;
+    };
+
+    return {
+      getImageSize: getImageSize,
+      buildListItems: buildListItems,
+      removePixelSuffix: removePixelSuffix,
+      addPixelSuffix: addPixelSuffix,
+      mergeMargins: mergeMargins
+    };
+  }
+);
+
+/**
+ * Dialog.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * @class tinymce.image.ui.Dialog
+ * @private
+ */
+define(
+  'tinymce.plugins.image.ui.Dialog',
+  [
+    'global!document',
+    'global!Math',
+    'global!RegExp',
+    'tinymce.core.Env',
+    'tinymce.core.ui.Factory',
+    'tinymce.core.util.JSON',
+    'tinymce.core.util.Tools',
+    'tinymce.core.util.XHR',
+    'tinymce.plugins.image.core.Uploader',
+    'tinymce.plugins.image.core.Utils'
+  ],
+  function (document, Math, RegExp, Env, Factory, JSON, Tools, XHR, Uploader, Utils) {
+
+    return function (editor) {
+      function createImageList(callback) {
+        var imageList = editor.settings.image_list;
+
+        if (typeof imageList == "string") {
+          XHR.send({
+            url: imageList,
+            success: function (text) {
+              callback(JSON.parse(text));
+            }
+          });
+        } else if (typeof imageList == "function") {
+          imageList(callback);
+        } else {
+          callback(imageList);
+        }
+      }
+
</ins><span class="cx" style="display: block; padding: 0 10px">       function showDialog(imageList) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var win, data = {}, dom = editor.dom, imgElm, figureElm;
-        var width, height, imageListCtrl, classListCtrl, imageDimensions = editor.settings.image_dimensions !== false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var win, data = {}, imgElm, figureElm, dom = editor.dom, settings = editor.settings;
+        var width, height, imageListCtrl, classListCtrl, imageDimensions = settings.image_dimensions !== false;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+        function onFileInput() {
+          var Throbber = Factory.get('Throbber');
+          var throbber = new Throbber(win.getEl());
+          var file = this.value();
+
+          var uploader = new Uploader({
+            url: settings.images_upload_url,
+            basePath: settings.images_upload_base_path,
+            credentials: settings.images_upload_credentials,
+            handler: settings.images_upload_handler
+          });
+
+          // we do not need to add this to editors blobCache, so we fake bare minimum
+          var blobInfo = editor.editorUpload.blobCache.create({
+            blob: file,
+            name: file.name ? file.name.replace(/\.[^\.]+$/, '') : null, // strip extension
+            base64: 'data:image/fake;base64,=' // without this create() will throw exception
+          });
+
+          var finalize = function () {
+            throbber.hide();
+            URL.revokeObjectURL(blobInfo.blobUri()); // in theory we could fake blobUri too, but until it's legitimate, we have too revoke it manually
+          };
+
+          throbber.show();
+
+          return uploader.upload(blobInfo).then(function (url) {
+            var src = win.find('#src');
+            src.value(url);
+            win.find('tabpanel')[0].activateTab(0); // switch to General tab
+            src.fire('change'); // this will invoke onSrcChange (and any other handlers, if any).
+            finalize();
+            return url;
+          }, function (err) {
+            editor.windowManager.alert(err);
+            finalize();
+          });
+        }
+
+        function isTextBlock(node) {
+          return editor.schema.getTextBlockElements()[node.nodeName];
+        }
+
</ins><span class="cx" style="display: block; padding: 0 10px">         function recalcSize() {
</span><span class="cx" style="display: block; padding: 0 10px">           var widthCtrl, heightCtrl, newWidth, newHeight;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -319,33 +595,91 @@
</span><span class="cx" style="display: block; padding: 0 10px">           height = newHeight;
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function onSubmitForm() {
-          var figureElm, oldImg;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        function updateStyle() {
+          if (!editor.settings.image_advtab) {
+            return;
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          function waitLoad(imgElm) {
-            function selectImage() {
-              imgElm.onload = imgElm.onerror = null;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          var data = win.toJSON(),
+            css = dom.parseStyle(data.style);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              if (editor.selection) {
-                editor.selection.select(imgElm);
-                editor.nodeChanged();
-              }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          css = Utils.mergeMargins(css);
+
+          if (data.vspace) {
+            css['margin-top'] = css['margin-bottom'] = Utils.addPixelSuffix(data.vspace);
+          }
+          if (data.hspace) {
+            css['margin-left'] = css['margin-right'] = Utils.addPixelSuffix(data.hspace);
+          }
+          if (data.border) {
+            css['border-width'] = Utils.addPixelSuffix(data.border);
+          }
+
+          win.find('#style').value(dom.serializeStyle(dom.parseStyle(dom.serializeStyle(css))));
+        }
+
+        function updateVSpaceHSpaceBorder() {
+          if (!editor.settings.image_advtab) {
+            return;
+          }
+
+          var data = win.toJSON(),
+            css = dom.parseStyle(data.style);
+
+          win.find('#vspace').value("");
+          win.find('#hspace').value("");
+
+          css = Utils.mergeMargins(css);
+
+          //Move opposite equal margins to vspace/hspace field
+          if ((css['margin-top'] && css['margin-bottom']) || (css['margin-right'] && css['margin-left'])) {
+            if (css['margin-top'] === css['margin-bottom']) {
+              win.find('#vspace').value(Utils.removePixelSuffix(css['margin-top']));
+            } else {
+              win.find('#vspace').value('');
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            if (css['margin-right'] === css['margin-left']) {
+              win.find('#hspace').value(Utils.removePixelSuffix(css['margin-right']));
+            } else {
+              win.find('#hspace').value('');
+            }
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            imgElm.onload = function () {
-              if (!data.width && !data.height && imageDimensions) {
-                dom.setAttribs(imgElm, {
-                  width: imgElm.clientWidth,
-                  height: imgElm.clientHeight
-                });
-              }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          //Move border-width
+          if (css['border-width']) {
+            win.find('#border').value(Utils.removePixelSuffix(css['border-width']));
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              selectImage();
-            };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          win.find('#style').value(dom.serializeStyle(dom.parseStyle(dom.serializeStyle(css))));
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            imgElm.onerror = selectImage;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        function waitLoad(imgElm) {
+          function selectImage() {
+            imgElm.onload = imgElm.onerror = null;
+
+            if (editor.selection) {
+              editor.selection.select(imgElm);
+              editor.nodeChanged();
+            }
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          imgElm.onload = function () {
+            if (!data.width && !data.height && imageDimensions) {
+              dom.setAttribs(imgElm, {
+                width: imgElm.clientWidth,
+                height: imgElm.clientHeight
+              });
+            }
+
+            selectImage();
+          };
+
+          imgElm.onerror = selectImage;
+        }
+
+        function onSubmitForm() {
+          var figureElm, oldImg;
+
</ins><span class="cx" style="display: block; padding: 0 10px">           updateStyle();
</span><span class="cx" style="display: block; padding: 0 10px">           recalcSize();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -387,9 +721,15 @@
</span><span class="cx" style="display: block; padding: 0 10px">           editor.undoManager.transact(function () {
</span><span class="cx" style="display: block; padding: 0 10px">             if (!data.src) {
</span><span class="cx" style="display: block; padding: 0 10px">               if (imgElm) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                dom.remove(imgElm);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                var elm = dom.is(imgElm.parentNode, 'figure.image') ? imgElm.parentNode : imgElm;
+                dom.remove(elm);
</ins><span class="cx" style="display: block; padding: 0 10px">                 editor.focus();
</span><span class="cx" style="display: block; padding: 0 10px">                 editor.nodeChanged();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+                if (dom.isEmpty(editor.getBody())) {
+                  editor.setContent('');
+                  editor.selection.setCursorLocation();
+                }
</ins><span class="cx" style="display: block; padding: 0 10px">               }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">               return;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -414,19 +754,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">             if (data.caption === false) {
</span><span class="cx" style="display: block; padding: 0 10px">               if (dom.is(imgElm.parentNode, 'figure.image')) {
</span><span class="cx" style="display: block; padding: 0 10px">                 figureElm = imgElm.parentNode;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                dom.setAttrib(imgElm, 'contenteditable', null);
</ins><span class="cx" style="display: block; padding: 0 10px">                 dom.insertAfter(imgElm, figureElm);
</span><span class="cx" style="display: block; padding: 0 10px">                 dom.remove(figureElm);
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                editor.selection.select(imgElm);
+                editor.nodeChanged();
</ins><span class="cx" style="display: block; padding: 0 10px">               }
</span><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            function isTextBlock(node) {
-              return editor.schema.getTextBlockElements()[node.nodeName];
-            }
-
</del><span class="cx" style="display: block; padding: 0 10px">             if (data.caption === true) {
</span><span class="cx" style="display: block; padding: 0 10px">               if (!dom.is(imgElm.parentNode, 'figure.image')) {
</span><span class="cx" style="display: block; padding: 0 10px">                 oldImg = imgElm;
</span><span class="cx" style="display: block; padding: 0 10px">                 imgElm = imgElm.cloneNode(true);
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                imgElm.contentEditable = true;
</ins><span class="cx" style="display: block; padding: 0 10px">                 figureElm = dom.create('figure', { 'class': 'image' });
</span><span class="cx" style="display: block; padding: 0 10px">                 figureElm.appendChild(imgElm);
</span><span class="cx" style="display: block; padding: 0 10px">                 figureElm.appendChild(dom.create('figcaption', { contentEditable: true }, 'Caption'));
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -449,15 +789,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">           });
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function removePixelSuffix(value) {
-          if (value) {
-            value = value.replace(/px$/, '');
-          }
-
-          return value;
-        }
-
-        function srcChange(e) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        function onSrcChange(e) {
</ins><span class="cx" style="display: block; padding: 0 10px">           var srcURL, prependURL, absoluteURLPattern, meta = e.meta || {};
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">           if (imageListCtrl) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -480,7 +812,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">             this.value(srcURL);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            getImageSize(editor.documentBaseURI.toAbsolute(this.value()), function (data) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            Utils.getImageSize(editor.documentBaseURI.toAbsolute(this.value()), function (data) {
</ins><span class="cx" style="display: block; padding: 0 10px">               if (data.width && data.height && imageDimensions) {
</span><span class="cx" style="display: block; padding: 0 10px">                 width = data.width;
</span><span class="cx" style="display: block; padding: 0 10px">                 height = data.height;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -528,7 +860,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">           imageListCtrl = {
</span><span class="cx" style="display: block; padding: 0 10px">             type: 'listbox',
</span><span class="cx" style="display: block; padding: 0 10px">             label: 'Image list',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            values: buildListItems(
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            values: Utils.buildListItems(
</ins><span class="cx" style="display: block; padding: 0 10px">               imageList,
</span><span class="cx" style="display: block; padding: 0 10px">               function (item) {
</span><span class="cx" style="display: block; padding: 0 10px">                 item.value = editor.convertURL(item.value || item.url, 'src');
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -557,7 +889,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">             name: 'class',
</span><span class="cx" style="display: block; padding: 0 10px">             type: 'listbox',
</span><span class="cx" style="display: block; padding: 0 10px">             label: 'Class',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            values: buildListItems(
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            values: Utils.buildListItems(
</ins><span class="cx" style="display: block; padding: 0 10px">               editor.settings.image_class_list,
</span><span class="cx" style="display: block; padding: 0 10px">               function (item) {
</span><span class="cx" style="display: block; padding: 0 10px">                 if (item.value) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -578,7 +910,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">             filetype: 'image',
</span><span class="cx" style="display: block; padding: 0 10px">             label: 'Source',
</span><span class="cx" style="display: block; padding: 0 10px">             autofocus: true,
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            onchange: srcChange,
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            onchange: onSrcChange,
</ins><span class="cx" style="display: block; padding: 0 10px">             onbeforecall: onBeforeCall
</span><span class="cx" style="display: block; padding: 0 10px">           },
</span><span class="cx" style="display: block; padding: 0 10px">           imageListCtrl
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -615,122 +947,105 @@
</span><span class="cx" style="display: block; padding: 0 10px">           generalFormItems.push({ name: 'caption', type: 'checkbox', label: 'Caption' });
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function mergeMargins(css) {
-          if (css.margin) {
-
-            var splitMargin = css.margin.split(" ");
-
-            switch (splitMargin.length) {
-              case 1: //margin: toprightbottomleft;
-                css['margin-top'] = css['margin-top'] || splitMargin[0];
-                css['margin-right'] = css['margin-right'] || splitMargin[0];
-                css['margin-bottom'] = css['margin-bottom'] || splitMargin[0];
-                css['margin-left'] = css['margin-left'] || splitMargin[0];
-                break;
-              case 2: //margin: topbottom rightleft;
-                css['margin-top'] = css['margin-top'] || splitMargin[0];
-                css['margin-right'] = css['margin-right'] || splitMargin[1];
-                css['margin-bottom'] = css['margin-bottom'] || splitMargin[0];
-                css['margin-left'] = css['margin-left'] || splitMargin[1];
-                break;
-              case 3: //margin: top rightleft bottom;
-                css['margin-top'] = css['margin-top'] || splitMargin[0];
-                css['margin-right'] = css['margin-right'] || splitMargin[1];
-                css['margin-bottom'] = css['margin-bottom'] || splitMargin[2];
-                css['margin-left'] = css['margin-left'] || splitMargin[1];
-                break;
-              case 4: //margin: top right bottom left;
-                css['margin-top'] = css['margin-top'] || splitMargin[0];
-                css['margin-right'] = css['margin-right'] || splitMargin[1];
-                css['margin-bottom'] = css['margin-bottom'] || splitMargin[2];
-                css['margin-left'] = css['margin-left'] || splitMargin[3];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (editor.settings.image_advtab || editor.settings.images_upload_url) {
+          var body = [
+            {
+              title: 'General',
+              type: 'form',
+              items: generalFormItems
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            delete css.margin;
-          }
-          return css;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          ];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function updateStyle() {
-          function addPixelSuffix(value) {
-            if (value.length > 0 && /^[0-9]+$/.test(value)) {
-              value += 'px';
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (editor.settings.image_advtab) {
+            // Parse styles from img
+            if (imgElm) {
+              if (imgElm.style.marginLeft && imgElm.style.marginRight && imgElm.style.marginLeft === imgElm.style.marginRight) {
+                data.hspace = Utils.removePixelSuffix(imgElm.style.marginLeft);
+              }
+              if (imgElm.style.marginTop && imgElm.style.marginBottom && imgElm.style.marginTop === imgElm.style.marginBottom) {
+                data.vspace = Utils.removePixelSuffix(imgElm.style.marginTop);
+              }
+              if (imgElm.style.borderWidth) {
+                data.border = Utils.removePixelSuffix(imgElm.style.borderWidth);
+              }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            return value;
-          }
-
-          if (!editor.settings.image_advtab) {
-            return;
-          }
-
-          var data = win.toJSON(),
-            css = dom.parseStyle(data.style);
-
-          css = mergeMargins(css);
-
-          if (data.vspace) {
-            css['margin-top'] = css['margin-bottom'] = addPixelSuffix(data.vspace);
-          }
-          if (data.hspace) {
-            css['margin-left'] = css['margin-right'] = addPixelSuffix(data.hspace);
-          }
-          if (data.border) {
-            css['border-width'] = addPixelSuffix(data.border);
-          }
-
-          win.find('#style').value(dom.serializeStyle(dom.parseStyle(dom.serializeStyle(css))));
-        }
-
-        function updateVSpaceHSpaceBorder() {
-          if (!editor.settings.image_advtab) {
-            return;
-          }
-
-          var data = win.toJSON(),
-            css = dom.parseStyle(data.style);
-
-          win.find('#vspace').value("");
-          win.find('#hspace').value("");
-
-          css = mergeMargins(css);
-
-          //Move opposite equal margins to vspace/hspace field
-          if ((css['margin-top'] && css['margin-bottom']) || (css['margin-right'] && css['margin-left'])) {
-            if (css['margin-top'] === css['margin-bottom']) {
-              win.find('#vspace').value(removePixelSuffix(css['margin-top']));
-            } else {
-              win.find('#vspace').value('');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              data.style = editor.dom.serializeStyle(editor.dom.parseStyle(editor.dom.getAttrib(imgElm, 'style')));
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (css['margin-right'] === css['margin-left']) {
-              win.find('#hspace').value(removePixelSuffix(css['margin-right']));
-            } else {
-              win.find('#hspace').value('');
-            }
-          }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          //Move border-width
-          if (css['border-width']) {
-            win.find('#border').value(removePixelSuffix(css['border-width']));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            body.push({
+              title: 'Advanced',
+              type: 'form',
+              pack: 'start',
+              items: [
+                {
+                  label: 'Style',
+                  name: 'style',
+                  type: 'textbox',
+                  onchange: updateVSpaceHSpaceBorder
+                },
+                {
+                  type: 'form',
+                  layout: 'grid',
+                  packV: 'start',
+                  columns: 2,
+                  padding: 0,
+                  alignH: ['left', 'right'],
+                  defaults: {
+                    type: 'textbox',
+                    maxWidth: 50,
+                    onchange: updateStyle
+                  },
+                  items: [
+                    { label: 'Vertical space', name: 'vspace' },
+                    { label: 'Horizontal space', name: 'hspace' },
+                    { label: 'Border', name: 'border' }
+                  ]
+                }
+              ]
+            });
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          win.find('#style').value(dom.serializeStyle(dom.parseStyle(dom.serializeStyle(css))));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (editor.settings.images_upload_url) {
+            var acceptExts = '.jpg,.jpeg,.png,.gif';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            var uploadTab = {
+              title: 'Upload',
+              type: 'form',
+              layout: 'flex',
+              direction: 'column',
+              align: 'stretch',
+              padding: '20 20 20 20',
+              items: [
+                {
+                  type: 'container',
+                  layout: 'flex',
+                  direction: 'column',
+                  align: 'center',
+                  spacing: 10,
+                  items: [
+                    {
+                      text: "Browse for an image",
+                      type: 'browsebutton',
+                      accept: acceptExts,
+                      onchange: onFileInput
+                    },
+                    {
+                      text: 'OR',
+                      type: 'label'
+                    }
+                  ]
+                },
+                {
+                  text: "Drop an image here",
+                  type: 'dropzone',
+                  accept: acceptExts,
+                  height: 100,
+                  onchange: onFileInput
+                }
+              ]
+            };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (editor.settings.image_advtab) {
-          // Parse styles from img
-          if (imgElm) {
-            if (imgElm.style.marginLeft && imgElm.style.marginRight && imgElm.style.marginLeft === imgElm.style.marginRight) {
-              data.hspace = removePixelSuffix(imgElm.style.marginLeft);
-            }
-            if (imgElm.style.marginTop && imgElm.style.marginBottom && imgElm.style.marginTop === imgElm.style.marginBottom) {
-              data.vspace = removePixelSuffix(imgElm.style.marginTop);
-            }
-            if (imgElm.style.borderWidth) {
-              data.border = removePixelSuffix(imgElm.style.borderWidth);
-            }
-
-            data.style = editor.dom.serializeStyle(editor.dom.parseStyle(editor.dom.getAttrib(imgElm, 'style')));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            body.push(uploadTab);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">           // Advanced dialog shows general+advanced tabs
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -738,45 +1053,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">             title: 'Insert/edit image',
</span><span class="cx" style="display: block; padding: 0 10px">             data: data,
</span><span class="cx" style="display: block; padding: 0 10px">             bodyType: 'tabpanel',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            body: [
-              {
-                title: 'General',
-                type: 'form',
-                items: generalFormItems
-              },
-
-              {
-                title: 'Advanced',
-                type: 'form',
-                pack: 'start',
-                items: [
-                  {
-                    label: 'Style',
-                    name: 'style',
-                    type: 'textbox',
-                    onchange: updateVSpaceHSpaceBorder
-                  },
-                  {
-                    type: 'form',
-                    layout: 'grid',
-                    packV: 'start',
-                    columns: 2,
-                    padding: 0,
-                    alignH: ['left', 'right'],
-                    defaults: {
-                      type: 'textbox',
-                      maxWidth: 50,
-                      onchange: updateStyle
-                    },
-                    items: [
-                      { label: 'Vertical space', name: 'vspace' },
-                      { label: 'Horizontal space', name: 'hspace' },
-                      { label: 'Border', name: 'border' }
-                    ]
-                  }
-                ]
-              }
-            ],
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            body: body,
</ins><span class="cx" style="display: block; padding: 0 10px">             onSubmit: onSubmitForm
</span><span class="cx" style="display: block; padding: 0 10px">           });
</span><span class="cx" style="display: block; padding: 0 10px">         } else {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -790,6 +1067,43 @@
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function open() {
+        createImageList(showDialog);
+      }
+
+      return {
+        open: open
+      };
+    };
+  }
+);
+
+/**
+ * Plugin.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This class contains all core logic for the image plugin.
+ *
+ * @class tinymce.image.Plugin
+ * @private
+ */
+define(
+  'tinymce.plugins.image.Plugin',
+  [
+    'tinymce.core.PluginManager',
+    'tinymce.core.util.Tools',
+    'tinymce.plugins.image.ui.Dialog'
+  ],
+  function (PluginManager, Tools, Dialog) {
+    PluginManager.add('image', function (editor) {
+
</ins><span class="cx" style="display: block; padding: 0 10px">       editor.on('preInit', function () {
</span><span class="cx" style="display: block; padding: 0 10px">         function hasImageClass(node) {
</span><span class="cx" style="display: block; padding: 0 10px">           var className = node.attr('class');
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -810,6 +1124,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">               if (hasImageClass(node)) {
</span><span class="cx" style="display: block; padding: 0 10px">                 node.attr('contenteditable', state ? 'false' : null);
</span><span class="cx" style="display: block; padding: 0 10px">                 Tools.each(node.getAll('figcaption'), toggleContentEditable);
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                Tools.each(node.getAll('img'), toggleContentEditable);
</ins><span class="cx" style="display: block; padding: 0 10px">               }
</span><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px">           };
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -822,19 +1137,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">       editor.addButton('image', {
</span><span class="cx" style="display: block; padding: 0 10px">         icon: 'image',
</span><span class="cx" style="display: block; padding: 0 10px">         tooltip: 'Insert/edit image',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        onclick: createImageList(showDialog),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        onclick: Dialog(editor).open,
</ins><span class="cx" style="display: block; padding: 0 10px">         stateSelector: 'img:not([data-mce-object],[data-mce-placeholder]),figure.image'
</span><span class="cx" style="display: block; padding: 0 10px">       });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       editor.addMenuItem('image', {
</span><span class="cx" style="display: block; padding: 0 10px">         icon: 'image',
</span><span class="cx" style="display: block; padding: 0 10px">         text: 'Image',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        onclick: createImageList(showDialog),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        onclick: Dialog(editor).open,
</ins><span class="cx" style="display: block; padding: 0 10px">         context: 'insert',
</span><span class="cx" style="display: block; padding: 0 10px">         prependToContext: true
</span><span class="cx" style="display: block; padding: 0 10px">       });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      editor.addCommand('mceImage', createImageList(showDialog));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      editor.addCommand('mceImage', Dialog(editor).open);
</ins><span class="cx" style="display: block; padding: 0 10px">     });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     return function () { };
</span></span></pre></div>
<a id="trunksrcwpincludesjstinymcepluginsimagepluginminjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/tinymce/plugins/image/plugin.min.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/tinymce/plugins/image/plugin.min.js      2017-09-26 20:32:46 UTC (rev 41603)
+++ trunk/src/wp-includes/js/tinymce/plugins/image/plugin.min.js        2017-09-26 21:14:28 UTC (rev 41604)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1 +1 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("6",tinymce.util.Tools.resolve),g("1",[&q
 uot;6"],function(a){return a("tinymce.Env")}),g("2",["6"],function(a){return a("tinymce.PluginManager")}),g("3",["6"],function(a){return a("tinymce.util.JSON")}),g("4",["6"],function(a){return a("tinymce.util.Tools")}),g("5",["6"],function(a){return a("tinymce.util.XHR")}),g("0",["1","2","3","4","5"],function(a,b,c,d,e){return b.add("image",function(b){function f(a,b){function c(a,c){d.parentNode&&d.parentNode.removeChild(d),b({width:a,height:c})}var d=document.createElement("img");d.onload=function(){c(Math.max(d.width,d.clientWidth),Math.max(d.height,d.clientHeight))},d.onerror=function(){c()};var e=d.style;e.visibility="hidden",e.position="fixed",e.bottom=e.left=0,e.width=e.height="auto",document.body.appendChild(d),d.src=a}functio
 n g(a,b,c){function e(a,c){return c=c||[],d.each(a,function(a){var d={text:a.text||a.title};a.menu?d.menu=e(a.menu):(d.value=a.value,b(d)),c.push(d)}),c}return e(a,c||[])}function h(a){return function(){var d=b.settings.image_list;"string"==typeof d?e.send({url:d,success:function(b){a(c.parse(b))}}):"function"==typeof d?d(a):a(d)}}function i(c){function e(){var a,b,c,d;a=o.find("#width")[0],b=o.find("#height")[0],a&&b&&(c=a.value(),d=b.value(),o.find("#constrain")[0].checked()&&r&&s&&c&&d&&(r!=c?(d=Math.round(c/r*d),isNaN(d)||b.value(d)):(c=Math.round(d/s*c),isNaN(c)||a.value(c))),r=c,s=d)}function h(){function a(a){function c(){a.onload=a.onerror=null,b.selection&&(b.selection.select(a),b.nodeChanged())}a.onload=function(){v.width||v.height||!x||w.setAttribs(a,{width:a.clientWidth,height:a.clientHeight}),c()},a.onerror=c}var c,f;m(),e(),v=d.extend(v,o.toJSON()),v.alt||(
 v.alt=""),v.title||(v.title=""),""===v.width&&(v.width=null),""===v.height&&(v.height=null),v.style||(v.style=null),v={src:v.src,alt:v.alt,title:v.title,width:v.width,height:v.height,style:v.style,caption:v.caption,"class":v["class"]},b.undoManager.transact(function(){function d(a){return b.schema.getTextBlockElements()[a.nodeName]}if(!v.src)return void(p&&(w.remove(p),b.focus(),b.nodeChanged()));if(""===v.title&&(v.title=null),p?w.setAttribs(p,v):(v.id="__mcenew",b.focus(),b.selection.setContent(w.createHTML("img",v)),p=w.get("__mcenew"),w.setAttrib(p,"id",null)),b.editorUpload.uploadImagesAuto(),v.caption===!1&&w.is(p.parentNode,"figure.image")&&(c=p.parentNode,w.insertAfter(p,c),w.remove(c)),v.caption!==!0)a(p);else if(!w.is(p.parentNode,"figure.image")){f=p,p=p.cloneNode(!0),c=w.create("figure"
 ,{"class":"image"}),c.appendChild(p),c.appendChild(w.create("figcaption",{contentEditable:!0},"Caption")),c.contentEditable=!1;var e=w.getParent(f,d);e?w.split(e,f,c):w.replace(c,f),b.selection.select(c)}})}function i(a){return a&&(a=a.replace(/px$/,"")),a}function j(a){var c,e,g,h=a.meta||{};t&&t.value(b.convertURL(this.value(),"src")),d.each(h,function(a,b){o.find("#"+b).value(a)}),h.width||h.height||(c=b.convertURL(this.value(),"src"),e=b.settings.image_prepend_url,g=new RegExp("^(?:[a-z]+:)?//","i"),e&&!g.test(c)&&c.substring(0,e.length)!==e&&(c=e+c),this.value(c),f(b.documentBaseURI.toAbsolute(this.value()),function(a){a.width&&a.height&&x&&(r=a.width,s=a.height,o.find("#width").value(r),o.find("#height").value(s))}))}function k(a){a.meta=o.toJSON()}function l(a){if(a.margin){var b=a.margin.split(
 " ");switch(b.length){case 1:a["margin-top"]=a["margin-top"]||b[0],a["margin-right"]=a["margin-right"]||b[0],a["margin-bottom"]=a["margin-bottom"]||b[0],a["margin-left"]=a["margin-left"]||b[0];break;case 2:a["margin-top"]=a["margin-top"]||b[0],a["margin-right"]=a["margin-right"]||b[1],a["margin-bottom"]=a["margin-bottom"]||b[0],a["margin-left"]=a["margin-left"]||b[1];break;case 3:a["margin-top"]=a["margin-top"]||b[0],a["margin-right"]=a["margin-right"]||b[1],a["margin-bottom"]=a["margin-bottom"]||b[2],a["margin-left"]=a["margin-left"]||b[1];break;case 4:a["margin-top"]=a["margin-top"]||b[0],a["margin-right"]=a["margin-right"]||b[1],a["margin-bottom"]=a["margin-bottom"]||b[2],a[&
 quot;margin-left"]=a["margin-left"]||b[3]}delete a.margin}return a}function m(){function a(a){return a.length>0&&/^[0-9]+$/.test(a)&&(a+="px"),a}if(b.settings.image_advtab){var c=o.toJSON(),d=w.parseStyle(c.style);d=l(d),c.vspace&&(d["margin-top"]=d["margin-bottom"]=a(c.vspace)),c.hspace&&(d["margin-left"]=d["margin-right"]=a(c.hspace)),c.border&&(d["border-width"]=a(c.border)),o.find("#style").value(w.serializeStyle(w.parseStyle(w.serializeStyle(d))))}}function n(){if(b.settings.image_advtab){var a=o.toJSON(),c=w.parseStyle(a.style);o.find("#vspace").value(""),o.find("#hspace").value(""),c=l(c),(c["margin-top"]&&c["margin-bottom"]||c["margin-right"]&&c["margin-left"])&&(c["margin-top"]===c["margin-bottom"]?o.find("#vspace").
 value(i(c["margin-top"])):o.find("#vspace").value(""),c["margin-right"]===c["margin-left"]?o.find("#hspace").value(i(c["margin-right"])):o.find("#hspace").value("")),c["border-width"]&&o.find("#border").value(i(c["border-width"])),o.find("#style").value(w.serializeStyle(w.parseStyle(w.serializeStyle(c))))}}var o,p,q,r,s,t,u,v={},w=b.dom,x=b.settings.image_dimensions!==!1;p=b.selection.getNode(),q=w.getParent(p,"figure.image"),q&&(p=w.select("img",q)[0]),p&&("IMG"!=p.nodeName||p.getAttribute("data-mce-object")||p.getAttribute("data-mce-placeholder"))&&(p=null),p&&(r=w.getAttrib(p,"width"),s=w.getAttrib(p,"height"),v={src:w.getAttrib(p,"src"),alt:w.getAttrib(p,"alt"),title:w.getAttrib(p,"title"),"class":w.getA
 ttrib(p,"class"),width:r,height:s,caption:!!q}),c&&(t={type:"listbox",label:"Image list",values:g(c,function(a){a.value=b.convertURL(a.value||a.url,"src")},[{text:"None",value:""}]),value:v.src&&b.convertURL(v.src,"src"),onselect:function(a){var b=o.find("#alt");(!b.value()||a.lastControl&&b.value()==a.lastControl.text())&&b.value(a.control.text()),o.find("#src").value(a.control.value()).fire("change")},onPostRender:function(){t=this}}),b.settings.image_class_list&&(u={name:"class",type:"listbox",label:"Class",values:g(b.settings.image_class_list,function(a){a.value&&(a.textStyle=function(){return b.formatter.getCssText({inline:"img",classes:[a.value]})})})});var y=[{name:"src",type:"filepicker",filetype:"image",label:"Source",autofocus:!0,onchange:j,onbefore
 call:k},t];b.settings.image_description!==!1&&y.push({name:"alt",type:"textbox",label:"Image description"}),b.settings.image_title&&y.push({name:"title",type:"textbox",label:"Image Title"}),x&&y.push({type:"container",label:"Dimensions",layout:"flex",direction:"row",align:"center",spacing:5,items:[{name:"width",type:"textbox",maxLength:5,size:3,onchange:e,ariaLabel:"Width"},{type:"label",text:"x"},{name:"height",type:"textbox",maxLength:5,size:3,onchange:e,ariaLabel:"Height"},{name:"constrain",type:"checkbox",checked:!0,text:"Constrain proportions"}]}),y.push(u),b.settings.image_caption&&a.ceFalse&&y.push({name:"caption",type:"checkbox",label:"Caption"}),b.settings.image_advtab?(p&&(p.style
 .marginLeft&&p.style.marginRight&&p.style.marginLeft===p.style.marginRight&&(v.hspace=i(p.style.marginLeft)),p.style.marginTop&&p.style.marginBottom&&p.style.marginTop===p.style.marginBottom&&(v.vspace=i(p.style.marginTop)),p.style.borderWidth&&(v.border=i(p.style.borderWidth)),v.style=b.dom.serializeStyle(b.dom.parseStyle(b.dom.getAttrib(p,"style")))),o=b.windowManager.open({title:"Insert/edit image",data:v,bodyType:"tabpanel",body:[{title:"General",type:"form",items:y},{title:"Advanced",type:"form",pack:"start",items:[{label:"Style",name:"style",type:"textbox",onchange:n},{type:"form",layout:"grid",packV:"start",columns:2,padding:0,alignH:["left","right"],defaults:{type:"textbox",maxWidth:50,onchange:m},items:[{label:"Vertical space",name:"vspa
 ce"},{label:"Horizontal space",name:"hspace"},{label:"Border",name:"border"}]}]}],onSubmit:h})):o=b.windowManager.open({title:"Insert/edit image",data:v,body:y,onSubmit:h})}b.on("preInit",function(){function a(a){var b=a.attr("class");return b&&/\bimage\b/.test(b)}function c(b){return function(c){function e(a){a.attr("contenteditable",b?"true":null)}for(var f,g=c.length;g--;)f=c[g],a(f)&&(f.attr("contenteditable",b?"false":null),d.each(f.getAll("figcaption"),e))}}b.parser.addNodeFilter("figure",c(!0)),b.serializer.addNodeFilter("figure",c(!1))}),b.addButton("image",{icon:"image",tooltip:"Insert/edit image",onclick:h(i),stateSelector:"img:not([data-mce-object],[data-mce-placeholder]),figure.image"}),b.addMenuItem("image",{icon:"image",text:"Image",onclick:h
 (i),context:"insert",prependToContext:!0}),b.addCommand("mceImage",h(i))}),function(){}}),d("0")()}();
</del><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("4",tinymce.util.Tools.resolve),g("1",[&q
 uot;4"],function(a){return a("tinymce.PluginManager")}),g("2",["4"],function(a){return a("tinymce.util.Tools")}),h("5",document),h("6",Math),h("7",RegExp),g("8",["4"],function(a){return a("tinymce.Env")}),g("9",["4"],function(a){return a("tinymce.ui.Factory")}),g("a",["4"],function(a){return a("tinymce.util.JSON")}),g("b",["4"],function(a){return a("tinymce.util.XHR")}),g("e",["4"],function(a){return a("tinymce.util.Promise")}),g("c",["e","2","5"],function(a,b,c){return function(c){function d(a,b){return a?a.replace(/\/$/,"")+"/"+b.replace(/^\//,""):b}function e(a,b,e,f){var g,h;g=new XMLHttpRequest,g.open("POST",c.url),g.withCredentials=c.credentials,g.upload.onprogress=function(a){
 f(a.loaded/a.total*100)},g.onerror=function(){e("Image upload failed due to a XHR Transport error. Code: "+g.status)},g.onload=function(){var a;return g.status<200||g.status>=300?void e("HTTP Error: "+g.status):(a=JSON.parse(g.responseText),a&&"string"==typeof a.location?void b(d(c.basePath,a.location)):void e("Invalid JSON: "+g.responseText))},h=new FormData,h.append("file",a.blob(),a.filename()),g.send(h)}function f(b,c){return new a(function(a,d){try{c(b,a,d,i)}catch(a){d(a.message)}})}function g(a){return a===e}function h(b){return!c.url&&g(c.handler)?a.reject("Upload url missng from the settings."):f(b,c.handler)}var i=function(){};return c=b.extend({credentials:!1,handler:e},c),{upload:h}}}),g("d",["2","6","5"],function(a,b,c){var d=function(a,d){function e(a,b){f.parentNode&&f.parentNode.removeChild(f),d({width:a,height:b})}var f=c.createElement(&q
 uot;img");f.onload=function(){e(b.max(f.width,f.clientWidth),b.max(f.height,f.clientHeight))},f.onerror=function(){e()};var g=f.style;g.visibility="hidden",g.position="fixed",g.bottom=g.left=0,g.width=g.height="auto",c.body.appendChild(f),f.src=a},e=function(b,c,d){function e(b,d){return d=d||[],a.each(b,function(a){var b={text:a.text||a.title};a.menu?b.menu=e(a.menu):(b.value=a.value,c(b)),d.push(b)}),d}return e(b,d||[])},f=function(a){return a&&(a=a.replace(/px$/,"")),a},g=function(a){return a.length>0&&/^[0-9]+$/.test(a)&&(a+="px"),a},h=function(a){if(a.margin){var b=a.margin.split(" ");switch(b.length){case 1:a["margin-top"]=a["margin-top"]||b[0],a["margin-right"]=a["margin-right"]||b[0],a["margin-bottom"]=a["margin-bottom"]||b[0],a["margin-left"]=a["margin-left"]||b[0];break;case 2:a["margin-top"]=a
 ["margin-top"]||b[0],a["margin-right"]=a["margin-right"]||b[1],a["margin-bottom"]=a["margin-bottom"]||b[0],a["margin-left"]=a["margin-left"]||b[1];break;case 3:a["margin-top"]=a["margin-top"]||b[0],a["margin-right"]=a["margin-right"]||b[1],a["margin-bottom"]=a["margin-bottom"]||b[2],a["margin-left"]=a["margin-left"]||b[1];break;case 4:a["margin-top"]=a["margin-top"]||b[0],a["margin-right"]=a["margin-right"]||b[1],a["margin-bottom"]=a["margin-bottom"]||b[2],a["margin-left"]=a["margin-left"]||b[3]}delete a.margin}return a};return{getImageSize:d,buildListItems:e,removePixelSuffix:f,addPixelSuffix:g,mergeMargins:h}}),g("3",["5","6","7","8","9","a","2","b","c",&qu
 ot;d"],function(a,b,c,d,e,f,g,h,i,j){return function(a){function k(b){var c=a.settings.image_list;"string"==typeof c?h.send({url:c,success:function(a){b(f.parse(a))}}):"function"==typeof c?c(b):b(c)}function l(f){function h(){var b=e.get("Throbber"),c=new b(s.getEl()),d=this.value(),f=new i({url:B.images_upload_url,basePath:B.images_upload_base_path,credentials:B.images_upload_credentials,handler:B.images_upload_handler}),g=a.editorUpload.blobCache.create({blob:d,name:d.name?d.name.replace(/\.[^\.]+$/,""):null,base64:"data:image/fake;base64,="}),h=function(){c.hide(),URL.revokeObjectURL(g.blobUri())};return c.show(),f.upload(g).then(function(a){var b=s.find("#src");return b.value(a),s.find("tabpanel")[0].activateTab(0),b.fire("change"),h(),a},function(b){a.windowManager.alert(b),h()})}function k(b){return a.schema.getTextBlockElements()[b.nodeName]}function l(){var a,c,d,e;a=s.find("#width&quot
 ;)[0],c=s.find("#height")[0],a&&c&&(d=a.value(),e=c.value(),s.find("#constrain")[0].checked()&&v&&w&&d&&e&&(v!=d?(e=b.round(d/v*e),isNaN(e)||c.value(e)):(d=b.round(e/w*d),isNaN(d)||a.value(d))),v=d,w=e)}function m(){if(a.settings.image_advtab){var b=s.toJSON(),c=A.parseStyle(b.style);c=j.mergeMargins(c),b.vspace&&(c["margin-top"]=c["margin-bottom"]=j.addPixelSuffix(b.vspace)),b.hspace&&(c["margin-left"]=c["margin-right"]=j.addPixelSuffix(b.hspace)),b.border&&(c["border-width"]=j.addPixelSuffix(b.border)),s.find("#style").value(A.serializeStyle(A.parseStyle(A.serializeStyle(c))))}}function n(){if(a.settings.image_advtab){var b=s.toJSON(),c=A.parseStyle(b.style);s.find("#vspace").value(""),s.find("#hspace").value(""),c=j.mergeMargins(c),(c["margin-top"]&&c["margin-b
 ottom"]||c["margin-right"]&&c["margin-left"])&&(c["margin-top"]===c["margin-bottom"]?s.find("#vspace").value(j.removePixelSuffix(c["margin-top"])):s.find("#vspace").value(""),c["margin-right"]===c["margin-left"]?s.find("#hspace").value(j.removePixelSuffix(c["margin-right"])):s.find("#hspace").value("")),c["border-width"]&&s.find("#border").value(j.removePixelSuffix(c["border-width"])),s.find("#style").value(A.serializeStyle(A.parseStyle(A.serializeStyle(c))))}}function o(b){function c(){b.onload=b.onerror=null,a.selection&&(a.selection.select(b),a.nodeChanged())}b.onload=function(){z.width||z.height||!C||A.setAttribs(b,{width:b.clientWidth,height:b.clientHeight}),c()},b.onerror=c}function p(){var b,c;m(),l(),z=g.extend(z,s.toJSON()),z.alt||(z.alt=""),z.title||
 (z.title=""),""===z.width&&(z.width=null),""===z.height&&(z.height=null),z.style||(z.style=null),z={src:z.src,alt:z.alt,title:z.title,width:z.width,height:z.height,style:z.style,caption:z.caption,"class":z["class"]},a.undoManager.transact(function(){if(z.src){if(""===z.title&&(z.title=null),t?A.setAttribs(t,z):(z.id="__mcenew",a.focus(),a.selection.setContent(A.createHTML("img",z)),t=A.get("__mcenew"),A.setAttrib(t,"id",null)),a.editorUpload.uploadImagesAuto(),z.caption===!1&&A.is(t.parentNode,"figure.image")&&(b=t.parentNode,A.setAttrib(t,"contenteditable",null),A.insertAfter(t,b),A.remove(b),a.selection.select(t),a.nodeChanged()),z.caption!==!0)o(t);else if(!A.is(t.parentNode,"figure.image")){c=t,t=t.cloneNode(!0),t.contentEditable=!0,b=A.create("figure",{"class":"image"}),b.appendChi
 ld(t),b.appendChild(A.create("figcaption",{contentEditable:!0},"Caption")),b.contentEditable=!1;var d=A.getParent(c,k);d?A.split(d,c,b):A.replace(b,c),a.selection.select(b)}}else if(t){var e=A.is(t.parentNode,"figure.image")?t.parentNode:t;A.remove(e),a.focus(),a.nodeChanged(),A.isEmpty(a.getBody())&&(a.setContent(""),a.selection.setCursorLocation())}})}function q(b){var d,e,f,h=b.meta||{};x&&x.value(a.convertURL(this.value(),"src")),g.each(h,function(a,b){s.find("#"+b).value(a)}),h.width||h.height||(d=a.convertURL(this.value(),"src"),e=a.settings.image_prepend_url,f=new c("^(?:[a-z]+:)?//","i"),e&&!f.test(d)&&d.substring(0,e.length)!==e&&(d=e+d),this.value(d),j.getImageSize(a.documentBaseURI.toAbsolute(this.value()),function(a){a.width&&a.height&&C&&(v=a.width,w=a.height,s.find("#width").value(v),s.find("#height&quo
 t;).value(w))}))}function r(a){a.meta=s.toJSON()}var s,t,u,v,w,x,y,z={},A=a.dom,B=a.settings,C=B.image_dimensions!==!1;t=a.selection.getNode(),u=A.getParent(t,"figure.image"),u&&(t=A.select("img",u)[0]),t&&("IMG"!=t.nodeName||t.getAttribute("data-mce-object")||t.getAttribute("data-mce-placeholder"))&&(t=null),t&&(v=A.getAttrib(t,"width"),w=A.getAttrib(t,"height"),z={src:A.getAttrib(t,"src"),alt:A.getAttrib(t,"alt"),title:A.getAttrib(t,"title"),"class":A.getAttrib(t,"class"),width:v,height:w,caption:!!u}),f&&(x={type:"listbox",label:"Image list",values:j.buildListItems(f,function(b){b.value=a.convertURL(b.value||b.url,"src")},[{text:"None",value:""}]),value:z.src&&a.convertURL(z.src,"src"),onselect:function(a){var b=s.find("#alt");(!b.value()||a.last
 Control&&b.value()==a.lastControl.text())&&b.value(a.control.text()),s.find("#src").value(a.control.value()).fire("change")},onPostRender:function(){x=this}}),a.settings.image_class_list&&(y={name:"class",type:"listbox",label:"Class",values:j.buildListItems(a.settings.image_class_list,function(b){b.value&&(b.textStyle=function(){return a.formatter.getCssText({inline:"img",classes:[b.value]})})})});var D=[{name:"src",type:"filepicker",filetype:"image",label:"Source",autofocus:!0,onchange:q,onbeforecall:r},x];if(a.settings.image_description!==!1&&D.push({name:"alt",type:"textbox",label:"Image description"}),a.settings.image_title&&D.push({name:"title",type:"textbox",label:"Image Title"}),C&&D.push({type:"container",label:"Dimensions",layout:"flex&q
 uot;,direction:"row",align:"center",spacing:5,items:[{name:"width",type:"textbox",maxLength:5,size:3,onchange:l,ariaLabel:"Width"},{type:"label",text:"x"},{name:"height",type:"textbox",maxLength:5,size:3,onchange:l,ariaLabel:"Height"},{name:"constrain",type:"checkbox",checked:!0,text:"Constrain proportions"}]}),D.push(y),a.settings.image_caption&&d.ceFalse&&D.push({name:"caption",type:"checkbox",label:"Caption"}),a.settings.image_advtab||a.settings.images_upload_url){var E=[{title:"General",type:"form",items:D}];if(a.settings.image_advtab&&(t&&(t.style.marginLeft&&t.style.marginRight&&t.style.marginLeft===t.style.marginRight&&(z.hspace=j.removePixelSuffix(t.style.marginLeft)),t.style.marginTop&&t.style.marginBottom&&t.style.marginTop==
 =t.style.marginBottom&&(z.vspace=j.removePixelSuffix(t.style.marginTop)),t.style.borderWidth&&(z.border=j.removePixelSuffix(t.style.borderWidth)),z.style=a.dom.serializeStyle(a.dom.parseStyle(a.dom.getAttrib(t,"style")))),E.push({title:"Advanced",type:"form",pack:"start",items:[{label:"Style",name:"style",type:"textbox",onchange:n},{type:"form",layout:"grid",packV:"start",columns:2,padding:0,alignH:["left","right"],defaults:{type:"textbox",maxWidth:50,onchange:m},items:[{label:"Vertical space",name:"vspace"},{label:"Horizontal space",name:"hspace"},{label:"Border",name:"border"}]}]})),a.settings.images_upload_url){var F=".jpg,.jpeg,.png,.gif",G={title:"Upload",type:"form",layout:"flex",direction:"column",align:"stretch",p
 adding:"20 20 20 20",items:[{type:"container",layout:"flex",direction:"column",align:"center",spacing:10,items:[{text:"Browse for an image",type:"browsebutton",accept:F,onchange:h},{text:"OR",type:"label"}]},{text:"Drop an image here",type:"dropzone",accept:F,height:100,onchange:h}]};E.push(G)}s=a.windowManager.open({title:"Insert/edit image",data:z,bodyType:"tabpanel",body:E,onSubmit:p})}else s=a.windowManager.open({title:"Insert/edit image",data:z,body:D,onSubmit:p})}function m(){k(l)}return{open:m}}}),g("0",["1","2","3"],function(a,b,c){return a.add("image",function(a){a.on("preInit",function(){function c(a){var b=a.attr("class");return b&&/\bimage\b/.test(b)}function d(a){return function(d){function e(b){b.attr("contenteditable",a?"true":null)}f
 or(var f,g=d.length;g--;)f=d[g],c(f)&&(f.attr("contenteditable",a?"false":null),b.each(f.getAll("figcaption"),e),b.each(f.getAll("img"),e))}}a.parser.addNodeFilter("figure",d(!0)),a.serializer.addNodeFilter("figure",d(!1))}),a.addButton("image",{icon:"image",tooltip:"Insert/edit image",onclick:c(a).open,stateSelector:"img:not([data-mce-object],[data-mce-placeholder]),figure.image"}),a.addMenuItem("image",{icon:"image",text:"Image",onclick:c(a).open,context:"insert",prependToContext:!0}),a.addCommand("mceImage",c(a).open)}),function(){}}),d("0")()}();
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span></span></pre></div>
<a id="trunksrcwpincludesjstinymcepluginslinkpluginjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/tinymce/plugins/link/plugin.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/tinymce/plugins/link/plugin.js   2017-09-26 20:32:46 UTC (rev 41603)
+++ trunk/src/wp-includes/js/tinymce/plugins/link/plugin.js     2017-09-26 21:14:28 UTC (rev 41604)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -286,22 +286,26 @@
</span><span class="cx" style="display: block; padding: 0 10px">   function (Tools, Settings, RegExp) {
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var toggleTargetRules = function (rel, isUnsafe) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var rules = 'noopener';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var rules = ['noopener'];
+      var newRel = rel ? rel.split(/\s+/) : [];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var toString = function (rel) {
+        return Tools.trim(rel.sort().join(' '));
+      };
+
</ins><span class="cx" style="display: block; padding: 0 10px">       var addTargetRules = function (rel) {
</span><span class="cx" style="display: block; padding: 0 10px">         rel = removeTargetRules(rel);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return rel ? [rel, rules].join(' ') : rules;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return rel.length ? rel.concat(rules) : rules;
</ins><span class="cx" style="display: block; padding: 0 10px">       };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       var removeTargetRules = function (rel) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var regExp = new RegExp('(' + rules.replace(' ', '|') + ')', 'g');
-        if (rel) {
-          rel = Tools.trim(rel.replace(regExp, ''));
-        }
-        return rel ? rel : null;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return rel.filter(function (val) {
+          return Tools.inArray(rules, val) === -1;
+        });
</ins><span class="cx" style="display: block; padding: 0 10px">       };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return isUnsafe ? addTargetRules(rel) : removeTargetRules(rel);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      newRel = isUnsafe ? addTargetRules(newRel) : removeTargetRules(newRel);
+      return newRel.length ? toString(newRel) : null;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -365,7 +369,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">             title: data.title ? data.title : null
</span><span class="cx" style="display: block; padding: 0 10px">           };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (Settings.allowUnsafeLinkTarget(editor.settings) === false) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (!Settings.hasRelList(editor.settings) && Settings.allowUnsafeLinkTarget(editor.settings) === false) {
</ins><span class="cx" style="display: block; padding: 0 10px">             linkAttrs.rel = toggleTargetRules(linkAttrs.rel, linkAttrs.target == '_blank');
</span><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -447,7 +451,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">       hasLinks: hasLinks,
</span><span class="cx" style="display: block; padding: 0 10px">       isOnlyTextSelected: isOnlyTextSelected,
</span><span class="cx" style="display: block; padding: 0 10px">       getAnchorElement: getAnchorElement,
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      getAnchorText: getAnchorText
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      getAnchorText: getAnchorText,
+      toggleTargetRules: toggleTargetRules
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -691,7 +696,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">           name: 'rel',
</span><span class="cx" style="display: block; padding: 0 10px">           type: 'listbox',
</span><span class="cx" style="display: block; padding: 0 10px">           label: 'Rel',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          values: buildListItems(Settings.getRelList(editor.settings))
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          values: buildListItems(
+            Settings.getRelList(editor.settings),
+            function (item) {
+              if (Settings.allowUnsafeLinkTarget(editor.settings) === false) {
+                item.value = Utils.toggleTargetRules(item.value, data.target === '_blank');
+              }
+            }
+          )
</ins><span class="cx" style="display: block; padding: 0 10px">         };
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunksrcwpincludesjstinymcepluginslinkpluginminjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/tinymce/plugins/link/plugin.min.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/tinymce/plugins/link/plugin.min.js       2017-09-26 20:32:46 UTC (rev 41603)
+++ trunk/src/wp-includes/js/tinymce/plugins/link/plugin.min.js 2017-09-26 21:14:28 UTC (rev 41604)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1 +1 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("4",tinymce.util.Tools.resolve),g("1",[&q
 uot;4"],function(a){return a("tinymce.PluginManager")}),g("5",["4"],function(a){return a("tinymce.util.VK")}),g("a",["4"],function(a){return a("tinymce.util.Delay")}),g("b",["4"],function(a){return a("tinymce.util.Tools")}),g("c",["4"],function(a){return a("tinymce.util.XHR")}),g("9",[],function(){var a=function(a){return"boolean"==typeof a.link_assume_external_targets&&a.link_assume_external_targets},b=function(a){return"boolean"==typeof a.link_context_toolbar&&a.link_context_toolbar},c=function(a){return a.link_list},d=function(a){return"string"==typeof a.default_link_target},e=function(a){return a.default_link_target},f=function(a){return a.target_list},g=function(a,b){a.settings.target_list=b},h=function(a){return f(a)!==!1},i=function(a){return a.rel_list},j=function(a){return void 0!==i(a)
 },k=function(a){return a.link_class_list},l=function(a){return void 0!==k(a)},m=function(a){return a.link_title!==!1},n=function(a){return"boolean"==typeof a.allow_unsafe_link_target&&a.allow_unsafe_link_target};return{assumeExternalTargets:a,hasContextToolbar:b,getLinkList:c,hasDefaultLinkTarget:d,getDefaultLinkTarget:e,getTargetList:f,setTargetList:g,shouldShowTargetList:h,getRelList:i,hasRelList:j,getLinkClassList:k,hasLinkClassList:l,shouldShowLinkTitle:m,allowUnsafeLinkTarget:n}}),h("d",RegExp),g("8",["b","9","d"],function(a,b,c){var d=function(b,d){var e="noopener",f=function(a){return a=g(a),a?[a,e].join(" "):e},g=function(b){var d=new c("("+e.replace(" ","|")+")","g");return b&&(b=a.trim(b.replace(d,""))),b?b:null};return d?f(b):g(b)},e=function(a){return a.replace(/\uFEFF/g,"")},f=function(a,b){return b=b||a.se
 lection.getStart(),k(b)?a.dom.select("a[href]",b)[0]:a.dom.getParent(b,"a[href]")},g=function(a,b){var c=b?b.innerText||b.textContent:a.getContent({format:"text"});return e(c)},h=function(a){return a&&"A"===a.nodeName&&a.href},i=function(b){return a.grep(b,h).length>0},j=function(a){return!(/</.test(a)&&(!/^<a [^>]+>[^<]+<\/a>$/.test(a)||a.indexOf("href=")==-1))},k=function(a){return a&&"FIGURE"===a.nodeName&&/\bimage\b/i.test(a.className)},l=function(a,c){return function(e){a.undoManager.transact(function(){var g=a.selection.getNode(),h=f(a,g),i={href:e.href,target:e.target?e.target:null,rel:e.rel?e.rel:null,"class":e["class"]?e["class"]:null,title:e.title?e.title:null};b.allowUnsafeLinkTarget(a.settings)===!1&&(i.rel=d(i.rel,"_blank"==i.target)),e.href===c.href&&(c.attach(),c={}),h?(a.focus(),e.hasOwnPro
 perty("text")&&("innerText"in h?h.innerText=e.text:h.textContent=e.text),a.dom.setAttribs(h,i),a.selection.select(h),a.undoManager.add()):k(g)?o(a,g,i):e.hasOwnProperty("text")?a.insertContent(a.dom.createHTML("a",i,a.dom.encode(e.text))):a.execCommand("mceInsertLink",!1,i)})}},m=function(a){return function(){a.undoManager.transact(function(){var b=a.selection.getNode();k(b)?n(a,b):a.execCommand("unlink")})}},n=function(a,b){var c,d;d=a.dom.select("img",b)[0],d&&(c=a.dom.getParents(d,"a[href]",b)[0],c&&(c.parentNode.insertBefore(d,c),a.dom.remove(c)))},o=function(a,b,c){var d,e;e=a.dom.select("img",b)[0],e&&(d=a.dom.create("a",c),e.parentNode.insertBefore(d,e),d.appendChild(e))};return{link:l,unlink:m,isLink:h,hasLinks:i,isOnlyTextSelected:j,getAnchorElement:f,getAnchorText:g}}),g("6",["a","b","c","8",&q
 uot;9"],function(a,b,c,d,e){var f={},g=function(a,b){var d=e.getLinkList(a.settings);"string"==typeof d?c.send({url:d,success:function(c){b(a,JSON.parse(c))}}):"function"==typeof d?d(function(c){b(a,c)}):b(a,d)},h=function(a,c,d){var e=function(a,d){return d=d||[],b.each(a,function(a){var b={text:a.text||a.title};a.menu?b.menu=e(a.menu):(b.value=a.value,c&&c(b)),d.push(b)}),d};return e(a,d||[])},i=function(b,c,d){var e=b.selection.getRng();a.setEditorTimeout(b,function(){b.windowManager.confirm(c,function(a){b.selection.setRng(e),d(a)})})},j=function(a,c){var g,j,k,l,m,n,o,p,q,r,s,t={},u=a.selection,v=a.dom,w=function(a){var b=k.find("#text");(!b.value()||a.lastControl&&b.value()==a.lastControl.text())&&b.value(a.control.text()),k.find("#href").value(a.control.value())},x=function(c){var d=[];if(b.each(a.dom.select("a:not([href])"),function(a){var b=a.name||a.id;b&&d.push({text:b,value:"#&quo
 t;+b,selected:c.indexOf("#"+b)!=-1})}),d.length)return d.unshift({text:"None",value:""}),{name:"anchor",type:"listbox",label:"Anchors",values:d,onselect:w}},y=function(){j||!l||t.text||this.parent().parent().find("#text")[0].value(this.value())},z=function(c){var d=c.meta||{};n&&n.value(a.convertURL(this.value(),"href")),b.each(c.meta,function(a,b){var c=k.find("#"+b);"text"===b?0===j.length&&(c.value(a),t.text=a):c.value(a)}),d.attach&&(f={href:this.value(),attach:d.attach}),d.text||y.call(this)},A=function(a){a.meta=k.toJSON()};l=d.isOnlyTextSelected(u.getContent()),g=d.getAnchorElement(a),t.text=j=d.getAnchorText(a.selection,g),t.href=g?v.getAttrib(g,"href"):"",g?t.target=v.getAttrib(g,"target"):e.hasDefaultLinkTarget(a.settings)&&(t.target=e.getDefaultLinkTarget(a.settings)),(s=v.getAttrib(g,"rel"))&&(
 t.rel=s),(s=v.getAttrib(g,"class"))&&(t["class"]=s),(s=v.getAttrib(g,"title"))&&(t.title=s),l&&(m={name:"text",type:"textbox",size:40,label:"Text to display",onchange:function(){t.text=this.value()}}),c&&(n={type:"listbox",label:"Link list",values:h(c,function(b){b.value=a.convertURL(b.value||b.url,"href")},[{text:"None",value:""}]),onselect:w,value:a.convertURL(t.href,"href"),onPostRender:function(){n=this}}),e.shouldShowTargetList(a.settings)&&(void 0===e.getTargetList(a.settings)&&e.setTargetList(a,[{text:"None",value:""},{text:"New window",value:"_blank"}]),p={name:"target",type:"listbox",label:"Target",values:h(e.getTargetList(a.settings))}),e.hasRelList(a.settings)&&(o={name:"rel",type:"listbox",label:"Rel&quot
 ;,values:h(e.getRelList(a.settings))}),e.hasLinkClassList(a.settings)&&(q={name:"class",type:"listbox",label:"Class",values:h(e.getLinkClassList(a.settings),function(b){b.value&&(b.textStyle=function(){return a.formatter.getCssText({inline:"a",classes:[b.value]})})})}),e.shouldShowLinkTitle(a.settings)&&(r={name:"title",type:"textbox",label:"Title",value:t.title}),k=a.windowManager.open({title:"Insert link",data:t,body:[{name:"href",type:"filepicker",filetype:"file",size:40,autofocus:!0,label:"Url",onchange:z,onkeyup:y,onbeforecall:A},m,r,x(t.href),n,o,p,q],onSubmit:function(c){var g=e.assumeExternalTargets(a.settings),h=d.link(a,f),k=d.unlink(a),m=b.extend({},t,c.data),n=m.href;return n?(l&&m.text!==j||delete m.text,n.indexOf("@")>0&&n.indexOf("//")==-1&&n.indexOf("mailto:")==-1?void 
 i(a,"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?",function(a){a&&(m.href="mailto:"+n),h(m)}):g===!0&&!/^\w+:/i.test(n)||g===!1&&/^\s*www[\.|\d\.]/i.test(n)?void i(a,"The URL you entered seems to be an external link. Do you want to add the required http:// prefix?",function(a){a&&(m.href="http://"+n),h(m)}):void h(m)):void k()}})},k=function(a){g(a,j)};return{open:k}}),g("e",["4"],function(a){return a("tinymce.dom.DOMUtils")}),g("f",["4"],function(a){return a("tinymce.Env")}),g("7",["e","f"],function(a,b){var c=function(a,b){document.body.appendChild(a),a.dispatchEvent(b),document.body.removeChild(a)},d=function(d){if(!b.ie||b.ie>10){var e=document.createElement("a");e.target="_blank",e.href=d,e.rel="noreferrer noopener";var f=document.cre
 ateEvent("MouseEvents");f.initMouseEvent("click",!0,!0,window,0,0,0,0,0,!1,!1,!1,!1,0,null),c(e,f)}else{var g=window.open("","_blank");if(g){g.opener=null;var h=g.document;h.open(),h.write('<meta http-equiv="refresh" content="0; url='+a.DOM.encode(d)+'">'),h.close()}}};return{open:d}}),g("2",["5","6","7","8","9"],function(a,b,c,d,e){var f=function(a,b){return a.dom.getParent(b,"a[href]")},g=function(a){return f(a,a.selection.getStart())},h=function(a){var b=a.getAttribute("data-mce-href");return b?b:a.getAttribute("href")},i=function(a){var b=a.plugins.contextmenu;return!!b&&b.isContextMenuVisible()},j=function(a){return a.altKey===!0&&a.shiftKey===!1&&a.ctrlKey===!1&&a.metaKey===!1},k=function(a,b){if(b){var d=h(b);if(/^#/.test(d)){var e=a.$(d);e.length&&a.selection.scrollIntoView(e[0],!0)
 }else c.open(b.href)}},l=function(a){return function(){b.open(a)}},m=function(a){return function(){k(a,g(a))}},n=function(a){return function(b){var c,f,g;return!!(e.hasContextToolbar(a.settings)&&!i(a)&&d.isLink(b)&&(c=a.selection,f=c.getRng(),g=f.startContainer,3==g.nodeType&&c.isCollapsed()&&f.startOffset>0&&f.startOffset<g.data.length))}},o=function(b){b.on("click",function(c){var d=f(b,c.target);d&&a.metaKeyPressed(c)&&(c.preventDefault(),k(b,d))}),b.on("keydown",function(a){var c=g(b);c&&13===a.keyCode&&j(a)&&(a.preventDefault(),k(b,c))})},p=function(a){return function(){var b=this;a.on("nodechange",function(c){b.active(!a.readonly&&!!d.getAnchorElement(a,c.element))})}},q=function(a){return function(){var b=this,c=function(a){d.hasLinks(a.parents)?b.show():b.hide()};d.hasLinks(a.dom.getParents(a.selection.getStart()))||b.hide(),a.on("nodechan
 ge",c),b.on("remove",function(){a.off("nodechange",c)})}};return{openDialog:l,gotoSelectedLink:m,leftClickedOnAHref:n,setupGotoLinks:o,toggleActiveState:p,toggleViewLinkState:q}}),g("3",["2","8"],function(a,b){var c=function(c){c.addButton("link",{icon:"link",tooltip:"Insert/edit link",shortcut:"Meta+K",onclick:a.openDialog(c),onpostrender:a.toggleActiveState(c)}),c.addButton("unlink",{icon:"unlink",tooltip:"Remove link",onclick:b.unlink(c),onpostrender:a.toggleActiveState(c)}),c.addContextToolbar&&c.addButton("openlink",{icon:"newtab",tooltip:"Open link",onclick:a.gotoSelectedLink(c)})},d=function(b){b.addMenuItem("openlink",{text:"Open link",icon:"newtab",onclick:a.gotoSelectedLink(b),onPostRender:a.toggleViewLinkState(b),prependToContext:!0}),b.addMenuItem("link",{icon:"link&
 quot;,text:"Link",shortcut:"Meta+K",onclick:a.openDialog(b),stateSelector:"a[href]",context:"insert",prependToContext:!0})},e=function(b){b.addContextToolbar&&b.addContextToolbar(a.leftClickedOnAHref(b),"openlink | link unlink")};return{setupButtons:c,setupMenuItems:d,setupContextToolbars:e}}),g("0",["1","2","3"],function(a,b,c){return a.add("link",function(a){c.setupButtons(a),c.setupMenuItems(a),c.setupContextToolbars(a),b.setupGotoLinks(a),a.addShortcut("Meta+K","",b.openDialog(a)),a.addCommand("mceLink",b.openDialog(a))}),function(){}}),d("0")()}();
</del><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("4",tinymce.util.Tools.resolve),g("1",[&q
 uot;4"],function(a){return a("tinymce.PluginManager")}),g("5",["4"],function(a){return a("tinymce.util.VK")}),g("a",["4"],function(a){return a("tinymce.util.Delay")}),g("b",["4"],function(a){return a("tinymce.util.Tools")}),g("c",["4"],function(a){return a("tinymce.util.XHR")}),g("9",[],function(){var a=function(a){return"boolean"==typeof a.link_assume_external_targets&&a.link_assume_external_targets},b=function(a){return"boolean"==typeof a.link_context_toolbar&&a.link_context_toolbar},c=function(a){return a.link_list},d=function(a){return"string"==typeof a.default_link_target},e=function(a){return a.default_link_target},f=function(a){return a.target_list},g=function(a,b){a.settings.target_list=b},h=function(a){return f(a)!==!1},i=function(a){return a.rel_list},j=function(a){return void 0!==i(a)
 },k=function(a){return a.link_class_list},l=function(a){return void 0!==k(a)},m=function(a){return a.link_title!==!1},n=function(a){return"boolean"==typeof a.allow_unsafe_link_target&&a.allow_unsafe_link_target};return{assumeExternalTargets:a,hasContextToolbar:b,getLinkList:c,hasDefaultLinkTarget:d,getDefaultLinkTarget:e,getTargetList:f,setTargetList:g,shouldShowTargetList:h,getRelList:i,hasRelList:j,getLinkClassList:k,hasLinkClassList:l,shouldShowLinkTitle:m,allowUnsafeLinkTarget:n}}),h("d",RegExp),g("8",["b","9","d"],function(a,b,c){var d=function(b,c){var d=["noopener"],e=b?b.split(/\s+/):[],f=function(b){return a.trim(b.sort().join(" "))},g=function(a){return a=h(a),a.length?a.concat(d):d},h=function(b){return b.filter(function(b){return a.inArray(d,b)===-1})};return e=c?g(e):h(e),e.length?f(e):null},e=function(a){return a.replace(/\uFEFF/g,"")},f=function(a,b){return b=b||a.selecti
 on.getStart(),k(b)?a.dom.select("a[href]",b)[0]:a.dom.getParent(b,"a[href]")},g=function(a,b){var c=b?b.innerText||b.textContent:a.getContent({format:"text"});return e(c)},h=function(a){return a&&"A"===a.nodeName&&a.href},i=function(b){return a.grep(b,h).length>0},j=function(a){return!(/</.test(a)&&(!/^<a [^>]+>[^<]+<\/a>$/.test(a)||a.indexOf("href=")==-1))},k=function(a){return a&&"FIGURE"===a.nodeName&&/\bimage\b/i.test(a.className)},l=function(a,c){return function(e){a.undoManager.transact(function(){var g=a.selection.getNode(),h=f(a,g),i={href:e.href,target:e.target?e.target:null,rel:e.rel?e.rel:null,"class":e["class"]?e["class"]:null,title:e.title?e.title:null};b.hasRelList(a.settings)||b.allowUnsafeLinkTarget(a.settings)!==!1||(i.rel=d(i.rel,"_blank"==i.target)),e.href===c.href&&(c.attach(),c={}),h?(a.focus(
 ),e.hasOwnProperty("text")&&("innerText"in h?h.innerText=e.text:h.textContent=e.text),a.dom.setAttribs(h,i),a.selection.select(h),a.undoManager.add()):k(g)?o(a,g,i):e.hasOwnProperty("text")?a.insertContent(a.dom.createHTML("a",i,a.dom.encode(e.text))):a.execCommand("mceInsertLink",!1,i)})}},m=function(a){return function(){a.undoManager.transact(function(){var b=a.selection.getNode();k(b)?n(a,b):a.execCommand("unlink")})}},n=function(a,b){var c,d;d=a.dom.select("img",b)[0],d&&(c=a.dom.getParents(d,"a[href]",b)[0],c&&(c.parentNode.insertBefore(d,c),a.dom.remove(c)))},o=function(a,b,c){var d,e;e=a.dom.select("img",b)[0],e&&(d=a.dom.create("a",c),e.parentNode.insertBefore(d,e),d.appendChild(e))};return{link:l,unlink:m,isLink:h,hasLinks:i,isOnlyTextSelected:j,getAnchorElement:f,getAnchorText:g,toggleTargetRules:d}}),g("6",["a","b&quo
 t;,"c","8","9"],function(a,b,c,d,e){var f={},g=function(a,b){var d=e.getLinkList(a.settings);"string"==typeof d?c.send({url:d,success:function(c){b(a,JSON.parse(c))}}):"function"==typeof d?d(function(c){b(a,c)}):b(a,d)},h=function(a,c,d){var e=function(a,d){return d=d||[],b.each(a,function(a){var b={text:a.text||a.title};a.menu?b.menu=e(a.menu):(b.value=a.value,c&&c(b)),d.push(b)}),d};return e(a,d||[])},i=function(b,c,d){var e=b.selection.getRng();a.setEditorTimeout(b,function(){b.windowManager.confirm(c,function(a){b.selection.setRng(e),d(a)})})},j=function(a,c){var g,j,k,l,m,n,o,p,q,r,s,t={},u=a.selection,v=a.dom,w=function(a){var b=k.find("#text");(!b.value()||a.lastControl&&b.value()==a.lastControl.text())&&b.value(a.control.text()),k.find("#href").value(a.control.value())},x=function(c){var d=[];if(b.each(a.dom.select("a:not([href])"),function(a){var b=a.name||a.id;b&&amp
 ;d.push({text:b,value:"#"+b,selected:c.indexOf("#"+b)!=-1})}),d.length)return d.unshift({text:"None",value:""}),{name:"anchor",type:"listbox",label:"Anchors",values:d,onselect:w}},y=function(){j||!l||t.text||this.parent().parent().find("#text")[0].value(this.value())},z=function(c){var d=c.meta||{};n&&n.value(a.convertURL(this.value(),"href")),b.each(c.meta,function(a,b){var c=k.find("#"+b);"text"===b?0===j.length&&(c.value(a),t.text=a):c.value(a)}),d.attach&&(f={href:this.value(),attach:d.attach}),d.text||y.call(this)},A=function(a){a.meta=k.toJSON()};l=d.isOnlyTextSelected(u.getContent()),g=d.getAnchorElement(a),t.text=j=d.getAnchorText(a.selection,g),t.href=g?v.getAttrib(g,"href"):"",g?t.target=v.getAttrib(g,"target"):e.hasDefaultLinkTarget(a.settings)&&(t.target=e.getDefaultLinkTarget(a.settings)),(s=v.getAttr
 ib(g,"rel"))&&(t.rel=s),(s=v.getAttrib(g,"class"))&&(t["class"]=s),(s=v.getAttrib(g,"title"))&&(t.title=s),l&&(m={name:"text",type:"textbox",size:40,label:"Text to display",onchange:function(){t.text=this.value()}}),c&&(n={type:"listbox",label:"Link list",values:h(c,function(b){b.value=a.convertURL(b.value||b.url,"href")},[{text:"None",value:""}]),onselect:w,value:a.convertURL(t.href,"href"),onPostRender:function(){n=this}}),e.shouldShowTargetList(a.settings)&&(void 0===e.getTargetList(a.settings)&&e.setTargetList(a,[{text:"None",value:""},{text:"New window",value:"_blank"}]),p={name:"target",type:"listbox",label:"Target",values:h(e.getTargetList(a.settings))}),e.hasRelList(a.settings)&&(o={name:"rel",type:"l
 istbox",label:"Rel",values:h(e.getRelList(a.settings),function(b){e.allowUnsafeLinkTarget(a.settings)===!1&&(b.value=d.toggleTargetRules(b.value,"_blank"===t.target))})}),e.hasLinkClassList(a.settings)&&(q={name:"class",type:"listbox",label:"Class",values:h(e.getLinkClassList(a.settings),function(b){b.value&&(b.textStyle=function(){return a.formatter.getCssText({inline:"a",classes:[b.value]})})})}),e.shouldShowLinkTitle(a.settings)&&(r={name:"title",type:"textbox",label:"Title",value:t.title}),k=a.windowManager.open({title:"Insert link",data:t,body:[{name:"href",type:"filepicker",filetype:"file",size:40,autofocus:!0,label:"Url",onchange:z,onkeyup:y,onbeforecall:A},m,r,x(t.href),n,o,p,q],onSubmit:function(c){var g=e.assumeExternalTargets(a.settings),h=d.link(a,f),k=d.unlink(a),m=b.extend({},t,c.data),n=m.href;
 return n?(l&&m.text!==j||delete m.text,n.indexOf("@")>0&&n.indexOf("//")==-1&&n.indexOf("mailto:")==-1?void i(a,"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?",function(a){a&&(m.href="mailto:"+n),h(m)}):g===!0&&!/^\w+:/i.test(n)||g===!1&&/^\s*www[\.|\d\.]/i.test(n)?void i(a,"The URL you entered seems to be an external link. Do you want to add the required http:// prefix?",function(a){a&&(m.href="http://"+n),h(m)}):void h(m)):void k()}})},k=function(a){g(a,j)};return{open:k}}),g("e",["4"],function(a){return a("tinymce.dom.DOMUtils")}),g("f",["4"],function(a){return a("tinymce.Env")}),g("7",["e","f"],function(a,b){var c=function(a,b){document.body.appendChild(a),a.dispatchEvent(b),document.body.removeChild(a)},d=functi
 on(d){if(!b.ie||b.ie>10){var e=document.createElement("a");e.target="_blank",e.href=d,e.rel="noreferrer noopener";var f=document.createEvent("MouseEvents");f.initMouseEvent("click",!0,!0,window,0,0,0,0,0,!1,!1,!1,!1,0,null),c(e,f)}else{var g=window.open("","_blank");if(g){g.opener=null;var h=g.document;h.open(),h.write('<meta http-equiv="refresh" content="0; url='+a.DOM.encode(d)+'">'),h.close()}}};return{open:d}}),g("2",["5","6","7","8","9"],function(a,b,c,d,e){var f=function(a,b){return a.dom.getParent(b,"a[href]")},g=function(a){return f(a,a.selection.getStart())},h=function(a){var b=a.getAttribute("data-mce-href");return b?b:a.getAttribute("href")},i=function(a){var b=a.plugins.contextmenu;return!!b&&b.isContextMenuVisible()},j=function(a){return a.altKey===!0&&a.shiftKey===!1&
 amp;&a.ctrlKey===!1&&a.metaKey===!1},k=function(a,b){if(b){var d=h(b);if(/^#/.test(d)){var e=a.$(d);e.length&&a.selection.scrollIntoView(e[0],!0)}else c.open(b.href)}},l=function(a){return function(){b.open(a)}},m=function(a){return function(){k(a,g(a))}},n=function(a){return function(b){var c,f,g;return!!(e.hasContextToolbar(a.settings)&&!i(a)&&d.isLink(b)&&(c=a.selection,f=c.getRng(),g=f.startContainer,3==g.nodeType&&c.isCollapsed()&&f.startOffset>0&&f.startOffset<g.data.length))}},o=function(b){b.on("click",function(c){var d=f(b,c.target);d&&a.metaKeyPressed(c)&&(c.preventDefault(),k(b,d))}),b.on("keydown",function(a){var c=g(b);c&&13===a.keyCode&&j(a)&&(a.preventDefault(),k(b,c))})},p=function(a){return function(){var b=this;a.on("nodechange",function(c){b.active(!a.readonly&&!!d.getAnchorElement(a,c.element))})}},q=function(a){r
 eturn function(){var b=this,c=function(a){d.hasLinks(a.parents)?b.show():b.hide()};d.hasLinks(a.dom.getParents(a.selection.getStart()))||b.hide(),a.on("nodechange",c),b.on("remove",function(){a.off("nodechange",c)})}};return{openDialog:l,gotoSelectedLink:m,leftClickedOnAHref:n,setupGotoLinks:o,toggleActiveState:p,toggleViewLinkState:q}}),g("3",["2","8"],function(a,b){var c=function(c){c.addButton("link",{icon:"link",tooltip:"Insert/edit link",shortcut:"Meta+K",onclick:a.openDialog(c),onpostrender:a.toggleActiveState(c)}),c.addButton("unlink",{icon:"unlink",tooltip:"Remove link",onclick:b.unlink(c),onpostrender:a.toggleActiveState(c)}),c.addContextToolbar&&c.addButton("openlink",{icon:"newtab",tooltip:"Open link",onclick:a.gotoSelectedLink(c)})},d=function(b){b.addMenuItem("openlink",{text:"Open link&quo
 t;,icon:"newtab",onclick:a.gotoSelectedLink(b),onPostRender:a.toggleViewLinkState(b),prependToContext:!0}),b.addMenuItem("link",{icon:"link",text:"Link",shortcut:"Meta+K",onclick:a.openDialog(b),stateSelector:"a[href]",context:"insert",prependToContext:!0})},e=function(b){b.addContextToolbar&&b.addContextToolbar(a.leftClickedOnAHref(b),"openlink | link unlink")};return{setupButtons:c,setupMenuItems:d,setupContextToolbars:e}}),g("0",["1","2","3"],function(a,b,c){return a.add("link",function(a){c.setupButtons(a),c.setupMenuItems(a),c.setupContextToolbars(a),b.setupGotoLinks(a),a.addShortcut("Meta+K","",b.openDialog(a)),a.addCommand("mceLink",b.openDialog(a))}),function(){}}),d("0")()}();
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span></span></pre></div>
<a id="trunksrcwpincludesjstinymcepluginslistspluginjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/tinymce/plugins/lists/plugin.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/tinymce/plugins/lists/plugin.js  2017-09-26 20:32:46 UTC (rev 41603)
+++ trunk/src/wp-includes/js/tinymce/plugins/lists/plugin.js    2017-09-26 21:14:28 UTC (rev 41604)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -81,7 +81,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">   define(id, [], function () { return ref; });
</span><span class="cx" style="display: block; padding: 0 10px"> };
</span><span class="cx" style="display: block; padding: 0 10px"> /*jsc
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-["tinymce.plugins.lists.Plugin","tinymce.core.PluginManager","tinymce.core.util.Tools","tinymce.core.util.VK","tinymce.plugins.lists.actions.Indent","tinymce.plugins.lists.actions.Outdent","tinymce.plugins.lists.actions.ToggleList","tinymce.plugins.lists.core.Delete","tinymce.plugins.lists.core.NodeType","global!tinymce.util.Tools.resolve","tinymce.core.dom.DOMUtils","tinymce.plugins.lists.core.Bookmark","tinymce.plugins.lists.core.Selection","tinymce.plugins.lists.core.NormalizeLists","tinymce.plugins.lists.core.SplitList","tinymce.plugins.lists.core.TextBlock","tinymce.core.dom.BookmarkManager","tinymce.core.dom.RangeUtils","tinymce.core.dom.TreeWalker","tinymce.plugins.lists.core.Range",&
 quot;tinymce.core.Env"]
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+["tinymce.plugins.lists.Plugin","tinymce.core.PluginManager","tinymce.core.util.Tools","tinymce.core.util.VK","tinymce.plugins.lists.actions.Indent","tinymce.plugins.lists.actions.Outdent","tinymce.plugins.lists.actions.ToggleList","tinymce.plugins.lists.core.Delete","tinymce.plugins.lists.core.NodeType","tinymce.plugins.lists.core.Selection","global!tinymce.util.Tools.resolve","tinymce.core.dom.DOMUtils","tinymce.plugins.lists.core.Bookmark","tinymce.core.dom.DomQuery","tinymce.plugins.lists.core.NormalizeLists","tinymce.plugins.lists.core.SplitList","tinymce.plugins.lists.core.TextBlock","tinymce.core.dom.BookmarkManager","tinymce.core.dom.RangeUtils","tinymce.core.dom.TreeWalker","tin
 ymce.plugins.lists.core.Range","tinymce.core.Env"]
</ins><span class="cx" style="display: block; padding: 0 10px"> jsc*/
</span><span class="cx" style="display: block; padding: 0 10px"> defineGlobal("global!tinymce.util.Tools.resolve", tinymce.util.Tools.resolve);
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -207,6 +207,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">       return node && !!editor.schema.getTextBlockElements()[node.nodeName];
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isBlock = function (node, blockElements) {
+      return node && node.nodeName in blockElements;
+    };
+
</ins><span class="cx" style="display: block; padding: 0 10px">     var isBogusBr = function (dom, node) {
</span><span class="cx" style="display: block; padding: 0 10px">       if (!isBr(node)) {
</span><span class="cx" style="display: block; padding: 0 10px">         return false;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -241,6 +245,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">       isFirstChild: isFirstChild,
</span><span class="cx" style="display: block; padding: 0 10px">       isLastChild: isLastChild,
</span><span class="cx" style="display: block; padding: 0 10px">       isTextBlock: isTextBlock,
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      isBlock: isBlock,
</ins><span class="cx" style="display: block; padding: 0 10px">       isBogusBr: isBogusBr,
</span><span class="cx" style="display: block; padding: 0 10px">       isEmpty: isEmpty,
</span><span class="cx" style="display: block; padding: 0 10px">       isChildOfBody: isChildOfBody
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -452,6 +457,26 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * ResolveGlobal.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.dom.DomQuery',
+  [
+    'global!tinymce.util.Tools.resolve'
+  ],
+  function (resolve) {
+    return resolve('tinymce.dom.DomQuery');
+  }
+);
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * Selection.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -464,17 +489,42 @@
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><span class="cx" style="display: block; padding: 0 10px">   'tinymce.plugins.lists.core.Selection',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.dom.DomQuery',
</ins><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.Tools',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.plugins.lists.core.NodeType'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Tools, NodeType) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (DomQuery, Tools, NodeType) {
+    var getParentList = function (editor) {
+      return editor.dom.getParent(editor.selection.getStart(true), 'OL,UL,DL');
+    };
+
+    var getSelectedSubLists = function (editor) {
+      var parentList = getParentList(editor);
+      return Tools.grep(editor.selection.getSelectedBlocks(), function (elm) {
+        return NodeType.isListNode(elm) && parentList !== elm;
+      });
+    };
+
+    var findParentListItemsNodes = function (editor, elms) {
+      var listItemsElms = Tools.map(elms, function (elm) {
+        var parentLi = editor.dom.getParent(elm, 'li,dd,dt', editor.getBody());
+
+        return parentLi ? parentLi : elm;
+      });
+
+      return DomQuery.unique(listItemsElms);
+    };
+
</ins><span class="cx" style="display: block; padding: 0 10px">     var getSelectedListItems = function (editor) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return Tools.grep(editor.selection.getSelectedBlocks(), function (block) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var selectedBlocks = editor.selection.getSelectedBlocks();
+      return Tools.grep(findParentListItemsNodes(editor, selectedBlocks), function (block) {
</ins><span class="cx" style="display: block; padding: 0 10px">         return NodeType.isListItemNode(block);
</span><span class="cx" style="display: block; padding: 0 10px">       });
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     return {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      getParentList: getParentList,
+      getSelectedSubLists: getSelectedSubLists,
</ins><span class="cx" style="display: block; padding: 0 10px">       getSelectedListItems: getSelectedListItems
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -682,9 +732,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">   'tinymce.plugins.lists.core.TextBlock',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.dom.DOMUtils',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.Env'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.Env',
+    'tinymce.plugins.lists.core.NodeType'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (DOMUtils, Env) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (DOMUtils, Env, NodeType) {
</ins><span class="cx" style="display: block; padding: 0 10px">     var DOM = DOMUtils.DOM;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var createNewTextBlock = function (editor, contentNode, blockName) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -702,7 +753,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">           DOM.setAttribs(textBlock, editor.settings.forced_root_block_attrs);
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        fragment.appendChild(textBlock);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (!NodeType.isBlock(contentNode.firstChild, blockElements)) {
+          fragment.appendChild(textBlock);
+        }
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       if (contentNode) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -713,7 +766,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">             hasContentNode = true;
</span><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (blockElements[nodeName]) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (NodeType.isBlock(node, blockElements)) {
</ins><span class="cx" style="display: block; padding: 0 10px">             fragment.appendChild(node);
</span><span class="cx" style="display: block; padding: 0 10px">             textBlock = null;
</span><span class="cx" style="display: block; padding: 0 10px">           } else {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1230,17 +1283,40 @@
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var toggleList = function (editor, listName, detail) {
-      var parentList = editor.dom.getParent(editor.selection.getStart(), 'OL,UL,DL');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var updateList = function (dom, list, listName, detail) {
+      if (list.nodeName !== listName) {
+        var newList = dom.rename(list, listName);
+        updateListWithDetails(dom, newList, detail);
+      } else {
+        updateListWithDetails(dom, list, detail);
+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      detail = detail ? detail : {};
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var toggleMultipleLists = function (editor, parentList, lists, listName, detail) {
+      if (parentList.nodeName === listName && !hasListStyleDetail(detail)) {
+        removeList(editor, listName);
+      } else {
+        var bookmark = Bookmark.createBookmark(editor.selection.getRng(true));
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        Tools.each([parentList].concat(lists), function (elm) {
+          updateList(editor.dom, elm, listName, detail);
+        });
+
+        editor.selection.setRng(Bookmark.resolveBookmark(bookmark));
+      }
+    };
+
+    var hasListStyleDetail = function (detail) {
+      return 'list-style-type' in detail;
+    };
+
+    var toggleSingleList = function (editor, parentList, listName, detail) {
</ins><span class="cx" style="display: block; padding: 0 10px">       if (parentList === editor.getBody()) {
</span><span class="cx" style="display: block; padding: 0 10px">         return;
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       if (parentList) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (parentList.nodeName === listName) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (parentList.nodeName === listName && !hasListStyleDetail(detail)) {
</ins><span class="cx" style="display: block; padding: 0 10px">           removeList(editor, listName);
</span><span class="cx" style="display: block; padding: 0 10px">         } else {
</span><span class="cx" style="display: block; padding: 0 10px">           var bookmark = Bookmark.createBookmark(editor.selection.getRng(true));
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1253,6 +1329,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var toggleList = function (editor, listName, detail) {
+      var parentList = Selection.getParentList(editor);
+      var selectedSubLists = Selection.getSelectedSubLists(editor);
+
+      detail = detail ? detail : {};
+
+      if (parentList && selectedSubLists.length > 0) {
+        toggleMultipleLists(editor, parentList, selectedSubLists, listName, detail);
+      } else {
+        toggleSingleList(editor, parentList, listName, detail);
+      }
+    };
+
</ins><span class="cx" style="display: block; padding: 0 10px">     return {
</span><span class="cx" style="display: block; padding: 0 10px">       toggleList: toggleList,
</span><span class="cx" style="display: block; padding: 0 10px">       removeList: removeList,
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1343,6 +1432,30 @@
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var hasOnlyOneBlockChild = function (dom, elm) {
+      var childNodes = elm.childNodes;
+      return childNodes.length === 1 && !NodeType.isListNode(childNodes[0]) && dom.isBlock(childNodes[0]);
+    };
+
+    var unwrapSingleBlockChild = function (dom, elm) {
+      if (hasOnlyOneBlockChild(dom, elm)) {
+        dom.remove(elm.firstChild, true);
+      }
+    };
+
+    var moveChildren = function (dom, fromElm, toElm) {
+      var node, targetElm;
+
+      targetElm = hasOnlyOneBlockChild(dom, toElm) ? toElm.firstChild : toElm;
+      unwrapSingleBlockChild(dom, fromElm);
+
+      if (!NodeType.isEmpty(dom, fromElm, true)) {
+        while ((node = fromElm.firstChild)) {
+          targetElm.appendChild(node);
+        }
+      }
+    };
+
</ins><span class="cx" style="display: block; padding: 0 10px">     var mergeLiElements = function (dom, fromElm, toElm) {
</span><span class="cx" style="display: block; padding: 0 10px">       var node, listNode, ul = fromElm.parentNode;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1369,11 +1482,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         dom.$(toElm).empty();
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (!NodeType.isEmpty(dom, fromElm, true)) {
-        while ((node = fromElm.firstChild)) {
-          toElm.appendChild(node);
-        }
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      moveChildren(dom, fromElm, toElm);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       if (listNode) {
</span><span class="cx" style="display: block; padding: 0 10px">         toElm.appendChild(listNode);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1386,6 +1495,30 @@
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var mergeIntoEmptyLi = function (editor, fromLi, toLi) {
+      editor.dom.$(toLi).empty();
+      mergeLiElements(editor.dom, fromLi, toLi);
+      editor.selection.setCursorLocation(toLi);
+    };
+
+    var mergeForward = function (editor, rng, fromLi, toLi) {
+      var dom = editor.dom;
+
+      if (dom.isEmpty(toLi)) {
+        mergeIntoEmptyLi(editor, fromLi, toLi);
+      } else {
+        var bookmark = Bookmark.createBookmark(rng);
+        mergeLiElements(dom, fromLi, toLi);
+        editor.selection.setRng(Bookmark.resolveBookmark(bookmark));
+      }
+    };
+
+    var mergeBackward = function (editor, rng, fromLi, toLi) {
+      var bookmark = Bookmark.createBookmark(rng);
+      mergeLiElements(editor.dom, fromLi, toLi);
+      editor.selection.setRng(Bookmark.resolveBookmark(bookmark));
+    };
+
</ins><span class="cx" style="display: block; padding: 0 10px">     var backspaceDeleteFromListToListCaret = function (editor, isForward) {
</span><span class="cx" style="display: block; padding: 0 10px">       var dom = editor.dom, selection = editor.selection;
</span><span class="cx" style="display: block; padding: 0 10px">       var li = dom.getParent(selection.getStart(), 'LI'), ul, rng, otherLi;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1400,16 +1533,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">         otherLi = dom.getParent(findNextCaretContainer(editor, rng, isForward), 'LI');
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">         if (otherLi && otherLi !== li) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          var bookmark = Bookmark.createBookmark(rng);
-
</del><span class="cx" style="display: block; padding: 0 10px">           if (isForward) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            mergeLiElements(dom, otherLi, li);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            mergeForward(editor, rng, otherLi, li);
</ins><span class="cx" style="display: block; padding: 0 10px">           } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            mergeLiElements(dom, li, otherLi);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            mergeBackward(editor, rng, li, otherLi);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          editor.selection.setRng(Bookmark.resolveBookmark(bookmark));
-
</del><span class="cx" style="display: block; padding: 0 10px">           return true;
</span><span class="cx" style="display: block; padding: 0 10px">         } else if (!otherLi) {
</span><span class="cx" style="display: block; padding: 0 10px">           if (!isForward && ToggleList.removeList(editor, ul.nodeName)) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1421,6 +1550,15 @@
</span><span class="cx" style="display: block; padding: 0 10px">       return false;
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var removeBlock = function (dom, block) {
+      var parentBlock = dom.getParent(block.parentNode, dom.isBlock);
+
+      dom.remove(block);
+      if (parentBlock && dom.isEmpty(parentBlock)) {
+        dom.remove(parentBlock);
+      }
+    };
+
</ins><span class="cx" style="display: block; padding: 0 10px">     var backspaceDeleteIntoListCaret = function (editor, isForward) {
</span><span class="cx" style="display: block; padding: 0 10px">       var dom = editor.dom;
</span><span class="cx" style="display: block; padding: 0 10px">       var block = dom.getParent(editor.selection.getStart(), dom.isBlock);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1431,7 +1569,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">         if (otherLi) {
</span><span class="cx" style="display: block; padding: 0 10px">           editor.undoManager.transact(function () {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            dom.remove(block);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            removeBlock(dom, block);
</ins><span class="cx" style="display: block; padding: 0 10px">             ToggleList.mergeWithAdjacentLists(dom, otherLi.parentNode);
</span><span class="cx" style="display: block; padding: 0 10px">             editor.selection.select(otherLi, true);
</span><span class="cx" style="display: block; padding: 0 10px">             editor.selection.collapse(isForward);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1509,9 +1647,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.plugins.lists.actions.Outdent',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.plugins.lists.actions.ToggleList',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.plugins.lists.core.Delete',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.plugins.lists.core.NodeType'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.plugins.lists.core.NodeType',
+    'tinymce.plugins.lists.core.Selection'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (PluginManager, Tools, VK, Indent, Outdent, ToggleList, Delete, NodeType) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (PluginManager, Tools, VK, Indent, Outdent, ToggleList, Delete, NodeType, Selection) {
</ins><span class="cx" style="display: block; padding: 0 10px">     var queryListCommandState = function (editor, listName) {
</span><span class="cx" style="display: block; padding: 0 10px">       return function () {
</span><span class="cx" style="display: block; padding: 0 10px">         var parentList = editor.dom.getParent(editor.selection.getStart(), 'UL,OL,DL');
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1617,15 +1756,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">           var ctrl = e.control;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">           editor.on('nodechange', function () {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            var blocks = editor.selection.getSelectedBlocks();
-            var disable = false;
-
-            for (var i = 0, l = blocks.length; !disable && i < l; i++) {
-              var tag = blocks[i].nodeName;
-
-              disable = (tag === 'LI' && NodeType.isFirstChild(blocks[i]) || tag === 'UL' || tag === 'OL' || tag === 'DD');
-            }
-
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            var listItemBlocks = Selection.getSelectedListItems(editor);
+            var disable = listItemBlocks.length > 0 && NodeType.isFirstChild(listItemBlocks[0]);
</ins><span class="cx" style="display: block; padding: 0 10px">             ctrl.disabled(disable);
</span><span class="cx" style="display: block; padding: 0 10px">           });
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span></span></pre></div>
<a id="trunksrcwpincludesjstinymcepluginslistspluginminjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/tinymce/plugins/lists/plugin.min.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/tinymce/plugins/lists/plugin.min.js      2017-09-26 20:32:46 UTC (rev 41603)
+++ trunk/src/wp-includes/js/tinymce/plugins/lists/plugin.min.js        2017-09-26 21:14:28 UTC (rev 41604)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1 +1 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("9",tinymce.util.Tools.resolve),g("1",[&q
 uot;9"],function(a){return a("tinymce.PluginManager")}),g("2",["9"],function(a){return a("tinymce.util.Tools")}),g("3",["9"],function(a){return a("tinymce.util.VK")}),g("a",["9"],function(a){return a("tinymce.dom.DOMUtils")}),g("8",[],function(){var a=function(a){return a&&3===a.nodeType},b=function(a){return a&&/^(OL|UL|DL)$/.test(a.nodeName)},c=function(a){return a&&/^(LI|DT|DD)$/.test(a.nodeName)},d=function(a){return a&&"BR"===a.nodeName},e=function(a){return a.parentNode.firstChild===a},f=function(a){return a.parentNode.lastChild===a},g=function(a,b){return b&&!!a.schema.getTextBlockElements()[b.nodeName]},h=function(a,b){return!!d(b)&&!(!a.isBlock(b.nextSibling)||d(b.previousSibling))},i=function(a,b,c){var d=a.isEmpty(b);return!(c&&a.select("span[data-mce-type=bookmark]",b).length>0)&a
 mp;&d},j=function(a,b){return a.isChildOf(b,a.getRoot())};return{isTextNode:a,isListNode:b,isListItemNode:c,isBr:d,isFirstChild:e,isLastChild:f,isTextBlock:g,isBogusBr:h,isEmpty:i,isChildOfBody:j}}),g("h",["9"],function(a){return a("tinymce.dom.RangeUtils")}),g("j",["h","8"],function(a,b){var c=function(c,d){var e=a.getNode(c,d);if(b.isListItemNode(c)&&b.isTextNode(e)){var f=d>=c.childNodes.length?e.data.length:0;return{container:e,offset:f}}return{container:c,offset:d}},d=function(a){var b=a.cloneRange(),d=c(a.startContainer,a.startOffset);b.setStart(d.container,d.offset);var e=c(a.endContainer,a.endOffset);return b.setEnd(e.container,e.offset),b};return{getNormalizedEndPoint:c,normalizeRange:d}}),g("b",["a","8","j"],function(a,b,c){var d=a.DOM,e=function(a){var b={},c=function(c){var e,f,g;f=a[c?"startContainer":"endContainer"],g=a[c?"startOff
 set":"endOffset"],1===f.nodeType&&(e=d.create("span",{"data-mce-type":"bookmark"}),f.hasChildNodes()?(g=Math.min(g,f.childNodes.length-1),c?f.insertBefore(e,f.childNodes[g]):d.insertAfter(e,f.childNodes[g])):f.appendChild(e),f=e,g=0),b[c?"startContainer":"endContainer"]=f,b[c?"startOffset":"endOffset"]=g};return c(!0),a.collapsed||c(),b},f=function(a){function b(b){var c,e,f,g=function(a){for(var b=a.parentNode.firstChild,c=0;b;){if(b===a)return c;1===b.nodeType&&"bookmark"===b.getAttribute("data-mce-type")||c++,b=b.nextSibling}return-1};c=f=a[b?"startContainer":"endContainer"],e=a[b?"startOffset":"endOffset"],c&&(1===c.nodeType&&(e=g(c),c=c.parentNode,d.remove(f)),a[b?"startContainer":"endContainer"]=c,a[b?"startOffset":"endOffset"]=e)}b(!0),b();var e=d.createRng();ret
 urn e.setStart(a.startContainer,a.startOffset),a.endContainer&&e.setEnd(a.endContainer,a.endOffset),c.normalizeRange(e)};return{createBookmark:e,resolveBookmark:f}}),g("c",["2","8"],function(a,b){var c=function(c){return a.grep(c.selection.getSelectedBlocks(),function(a){return b.isListItemNode(a)})};return{getSelectedListItems:c}}),g("4",["a","b","8","c"],function(a,b,c,d){var e=a.DOM,f=function(a,b){var d;if(c.isListNode(a)){for(;d=a.firstChild;)b.appendChild(d);e.remove(a)}},g=function(a){var b,d,g;return"DT"===a.nodeName?(e.rename(a,"DD"),!0):(b=a.previousSibling,b&&c.isListNode(b)?(b.appendChild(a),!0):b&&"LI"===b.nodeName&&c.isListNode(b.lastChild)?(b.lastChild.appendChild(a),f(a.lastChild,b.lastChild),!0):(b=a.nextSibling,b&&c.isListNode(b)?(b.insertBefore(a,b.firstChild),!0):(b=a.previousSibling,!(!b||"LI"!==b.nodeNam
 e)&&(d=e.create(a.parentNode.nodeName),g=e.getStyle(a.parentNode,"listStyleType"),g&&e.setStyle(d,"listStyleType",g),b.appendChild(d),d.appendChild(a),f(a.lastChild,d),!0))))},h=function(a){var c=d.getSelectedListItems(a);if(c.length){for(var e=b.createBookmark(a.selection.getRng(!0)),f=0;f<c.length&&(g(c[f])||0!==f);f++);return a.selection.setRng(b.resolveBookmark(e)),a.nodeChanged(),!0}};return{indentSelection:h}}),g("d",["a","2","8"],function(a,b,c){var d=a.DOM,e=function(a,b){var e,f=b.parentNode;"LI"===f.nodeName&&f.firstChild===b&&(e=f.previousSibling,e&&"LI"===e.nodeName?(e.appendChild(b),c.isEmpty(a,f)&&d.remove(f)):d.setStyle(f,"listStyleType","none")),c.isListNode(f)&&(e=f.previousSibling,e&&"LI"===e.nodeName&&e.appendChild(b))},f=function(a,c){b.each(b.grep(a.select("ol,ul&quot
 ;,c)),function(b){e(a,b)})};return{normalizeList:e,normalizeLists:f}}),g("k",["9"],function(a){return a("tinymce.Env")}),g("f",["a","k"],function(a,b){var c=a.DOM,d=function(a,d,e){var f,g,h,i=c.createFragment(),j=a.schema.getBlockElements();if(a.settings.forced_root_block&&(e=e||a.settings.forced_root_block),e&&(g=c.create(e),g.tagName===a.settings.forced_root_block&&c.setAttribs(g,a.settings.forced_root_block_attrs),i.appendChild(g)),d)for(;f=d.firstChild;){var k=f.nodeName;h||"SPAN"===k&&"bookmark"===f.getAttribute("data-mce-type")||(h=!0),j[k]?(i.appendChild(f),g=null):e?(g||(g=c.create(e),i.appendChild(g)),g.appendChild(f)):i.appendChild(f)}return a.settings.forced_root_block?h||b.ie&&!(b.ie>10)||g.appendChild(c.create("br",{"data-mce-bogus":"1"})):i.appendChild(c.create("br")),i};return{createNewTextBlock:d
 }}),g("e",["a","8","f","2"],function(a,b,c,d){var e=a.DOM,f=function(a,f,g,h){var i,j,k,l,m=function(a){d.each(k,function(b){a.parentNode.insertBefore(b,g.parentNode)}),e.remove(a)};for(k=e.select('span[data-mce-type="bookmark"]',f),h=h||c.createNewTextBlock(a,g),i=e.createRng(),i.setStartAfter(g),i.setEndAfter(f),j=i.extractContents(),l=j.firstChild;l;l=l.firstChild)if("LI"===l.nodeName&&a.dom.isEmpty(l)){e.remove(l);break}a.dom.isEmpty(j)||e.insertAfter(j,f),e.insertAfter(h,f),b.isEmpty(a.dom,g.parentNode)&&m(g.parentNode),e.remove(g),b.isEmpty(a.dom,f)&&e.remove(f)};return{splitList:f}}),g("5",["a","b","8","d","c","e","f"],function(a,b,c,d,e,f,g){var h=a.DOM,i=function(a,b){c.isEmpty(a,b)&&h.remove(b)},j=function(a,b){var e,j=b.parentNode,k=j.parentNode;return j===a.getBody()||("DD"===b.node
 Name?(h.rename(b,"DT"),!0):c.isFirstChild(b)&&c.isLastChild(b)?("LI"===k.nodeName?(h.insertAfter(b,k),i(a.dom,k),h.remove(j)):c.isListNode(k)?h.remove(j,!0):(k.insertBefore(g.createNewTextBlock(a,b),j),h.remove(j)),!0):c.isFirstChild(b)?("LI"===k.nodeName?(h.insertAfter(b,k),b.appendChild(j),i(a.dom,k)):c.isListNode(k)?k.insertBefore(b,j):(k.insertBefore(g.createNewTextBlock(a,b),j),h.remove(b)),!0):c.isLastChild(b)?("LI"===k.nodeName?h.insertAfter(b,k):c.isListNode(k)?h.insertAfter(b,j):(h.insertAfter(g.createNewTextBlock(a,b),j),h.remove(b)),!0):("LI"===k.nodeName?(j=k,e=g.createNewTextBlock(a,b,"LI")):e=c.isListNode(k)?g.createNewTextBlock(a,b,"LI"):g.createNewTextBlock(a,b),f.splitList(a,j,b,e),d.normalizeLists(a.dom,j.parentNode),!0))},k=function(a){var c=e.getSelectedListItems(a);if(c.length){var d,f,g=b.createBookmark(a.selection.getRng(!0)),h=a.getBody();for(d=c.length;d--;)for(var i=c[d].parentNod
 e;i&&i!==h;){for(f=c.length;f--;)if(c[f]===i){c.splice(d,1);break}i=i.parentNode}for(d=0;d<c.length&&(j(a,c[d])||0!==d);d++);return a.selection.setRng(b.resolveBookmark(g)),a.nodeChanged(),!0}};return{outdent:j,outdentSelection:k}}),g("g",["9"],function(a){return a("tinymce.dom.BookmarkManager")}),g("6",["g","2","5","b","8","d","c","e"],function(a,b,c,d,e,f,g,h){var i=function(a,b,c){var d=c["list-style-type"]?c["list-style-type"]:null;a.setStyle(b,"list-style-type",d)},j=function(a,c){b.each(c,function(b,c){a.setAttribute(c,b)})},k=function(a,c,d){j(c,d["list-attributes"]),b.each(a.select("li",c),function(a){j(a,d["list-item-attributes"])})},l=function(a,b,c){i(a,b,c),k(a,b,c)},m=function(a,b,c){var d,f,g=a.getBody();for(d=b[c?"startContainer":"endContainer"],f=b[c?&
 quot;startOffset":"endOffset"],1===d.nodeType&&(d=d.childNodes[Math.min(f,d.childNodes.length-1)]||d);d.parentNode!==g;){if(e.isTextBlock(a,d))return d;if(/^(TD|TH)$/.test(d.parentNode.nodeName))return d;d=d.parentNode}return d},n=function(c,d){for(var f,g=[],h=c.getBody(),i=c.dom,j=m(c,d,!0),k=m(c,d,!1),l=[],n=j;n&&(l.push(n),n!==k);n=n.nextSibling);return b.each(l,function(b){if(e.isTextBlock(c,b))return g.push(b),void(f=null);if(i.isBlock(b)||e.isBr(b))return e.isBr(b)&&i.remove(b),void(f=null);var d=b.nextSibling;return a.isBookmarkNode(b)&&(e.isTextBlock(c,d)||!d&&b.parentNode===h)?void(f=null):(f||(f=i.create("p"),b.parentNode.insertBefore(f,b),g.push(f)),void f.appendChild(b))}),g},o=function(a,c,f){var g,h=a.selection.getRng(!0),i="LI",j=a.dom;f=f?f:{},"false"!==j.getContentEditable(a.selection.getNode())&&(c=c.toUpperCase(),"DL"===c&&(i="DT"),g=d.createBo
 okmark(h),b.each(n(a,h),function(b){var d,g,h=function(a){var b=j.getStyle(a,"list-style-type"),c=f?f["list-style-type"]:"";return c=null===c?"":c,b===c};g=b.previousSibling,g&&e.isListNode(g)&&g.nodeName===c&&h(g)?(d=g,b=j.rename(b,i),g.appendChild(b)):(d=j.create(c),b.parentNode.insertBefore(d,b),d.appendChild(b),b=j.rename(b,i)),l(j,d,f),u(a.dom,d)}),a.selection.setRng(d.resolveBookmark(g)))},p=function(a){var i=d.createBookmark(a.selection.getRng(!0)),j=a.getBody(),k=g.getSelectedListItems(a),l=b.grep(k,function(b){return a.dom.isEmpty(b)});k=b.grep(k,function(b){return!a.dom.isEmpty(b)}),b.each(l,function(b){if(e.isEmpty(a.dom,b))return void c.outdent(a,b)}),b.each(k,function(b){var c,d;if(b.parentNode!==a.getBody()){for(c=b;c&&c!==j;c=c.parentNode)e.isListNode(c)&&(d=c);h.splitList(a,d,b),f.normalizeLists(a.dom,d.parentNode)}}),a.selection.setRng(d.resolveBookmark(i))},q=function(a,b){return a&
 &b&&e.isListNode(a)&&a.nodeName===b.nodeName},r=function(a,b,c){var d=a.getStyle(b,"list-style-type",!0),e=a.getStyle(c,"list-style-type",!0);return d===e},s=function(a,b){return a.className===b.className},t=function(a,b,c){return q(b,c)&&r(a,b,c)&&s(b,c)},u=function(a,b){var c,d;if(c=b.nextSibling,t(a,b,c)){for(;d=c.firstChild;)b.appendChild(d);a.remove(c)}if(c=b.previousSibling,t(a,b,c)){for(;d=c.lastChild;)b.insertBefore(d,b.firstChild);a.remove(c)}},v=function(a,b,c){var e=a.dom.getParent(a.selection.getStart(),"OL,UL,DL");if(c=c?c:{},e!==a.getBody())if(e)if(e.nodeName===b)p(a,b);else{var f=d.createBookmark(a.selection.getRng(!0));l(a.dom,e,c),u(a.dom,a.dom.rename(e,b)),a.selection.setRng(d.resolveBookmark(f))}else o(a,b,c)};return{toggleList:v,removeList:p,mergeWithAdjacentLists:u}}),g("i",["9"],function(a){return a("tinymce.dom.TreeWalker")}),g("7",["h","i&q
 uot;,"3","6","b","8","d","j","c"],function(a,b,c,d,e,f,g,h,i){var j=function(c,d,e){var g,h,i=d.startContainer,j=d.startOffset;if(3===i.nodeType&&(e?j<i.data.length:j>0))return i;for(g=c.schema.getNonEmptyElements(),1===i.nodeType&&(i=a.getNode(i,j)),h=new b(i,c.getBody()),e&&f.isBogusBr(c.dom,i)&&h.next();i=h[e?"next":"prev2"]();){if("LI"===i.nodeName&&!i.hasChildNodes())return i;if(g[i.nodeName])return i;if(3===i.nodeType&&i.data.length>0)return i}},k=function(a,b,c){var d,e,g=b.parentNode;if(f.isChildOfBody(a,b)&&f.isChildOfBody(a,c)){if(f.isListNode(c.lastChild)&&(e=c.lastChild),g===c.lastChild&&f.isBr(g.previousSibling)&&a.remove(g.previousSibling),d=c.lastChild,d&&f.isBr(d)&&b.hasChildNodes()&&a.remove(d),f.isEmpty(a,c,!0)&&a.$(c).empty(),!f.isEmpty(a,b,!0))fo
 r(;d=b.firstChild;)c.appendChild(d);e&&c.appendChild(e),a.remove(b),f.isEmpty(a,g)&&g!==a.getRoot()&&a.remove(g)}},l=function(a,b){var c,g,i,l=a.dom,m=a.selection,n=l.getParent(m.getStart(),"LI");if(n){if(c=n.parentNode,c===a.getBody()&&f.isEmpty(l,c))return!0;if(g=h.normalizeRange(m.getRng(!0)),i=l.getParent(j(a,g,b),"LI"),i&&i!==n){var o=e.createBookmark(g);return b?k(l,i,n):k(l,n,i),a.selection.setRng(e.resolveBookmark(o)),!0}if(!i&&!b&&d.removeList(a,c.nodeName))return!0}return!1},m=function(a,b){var c=a.dom,e=c.getParent(a.selection.getStart(),c.isBlock);if(e&&c.isEmpty(e)){var f=h.normalizeRange(a.selection.getRng(!0)),g=c.getParent(j(a,f,b),"LI");if(g)return a.undoManager.transact(function(){c.remove(e),d.mergeWithAdjacentLists(c,g.parentNode),a.selection.select(g,!0),a.selection.collapse(b)}),!0}return!1},n=function(a,b){return l(a,b)||m(a,b)},o=function(a){var b=a.dom.getParent(a.s
 election.getStart(),"LI,DT,DD");return!!(b||i.getSelectedListItems(a).length>0)&&(a.undoManager.transact(function(){a.execCommand("Delete"),g.normalizeLists(a.dom,a.getBody())}),!0)},p=function(a,b){return a.selection.isCollapsed()?n(a,b):o(a)},q=function(a){a.on("keydown",function(b){b.keyCode===c.BACKSPACE?p(a,!1)&&b.preventDefault():b.keyCode===c.DELETE&&p(a,!0)&&b.preventDefault()})};return{setup:q,backspaceDelete:p}}),g("0",["1","2","3","4","5","6","7","8"],function(a,b,c,d,e,f,g,h){var i=function(a,b){return function(){var c=a.dom.getParent(a.selection.getStart(),"UL,OL,DL");return c&&c.nodeName===b}},j=function(a){a.on("BeforeExecCommand",function(b){var c,f=b.command.toLowerCase();if("indent"===f?d.indentSelection(a)&&(c=!0):"outdent"===f&&e.outdentSelection(a
 )&&(c=!0),c)return a.fire("ExecCommand",{command:b.command}),b.preventDefault(),!0}),a.addCommand("InsertUnorderedList",function(b,c){f.toggleList(a,"UL",c)}),a.addCommand("InsertOrderedList",function(b,c){f.toggleList(a,"OL",c)}),a.addCommand("InsertDefinitionList",function(b,c){f.toggleList(a,"DL",c)})},k=function(a){a.addQueryStateHandler("InsertUnorderedList",i(a,"UL")),a.addQueryStateHandler("InsertOrderedList",i(a,"OL")),a.addQueryStateHandler("InsertDefinitionList",i(a,"DL"))},l=function(a){a.on("keydown",function(b){9!==b.keyCode||c.metaKeyPressed(b)||a.dom.getParent(a.selection.getStart(),"LI,DT,DD")&&(b.preventDefault(),b.shiftKey?e.outdentSelection(a):d.indentSelection(a))})},m=function(a){var c=function(c){return function(){var d=this;a.on("NodeChange",function(a){var e=b.grep(a.parents,h.isListNod
 e);d.active(e.length>0&&e[0].nodeName===c)})}},d=function(a,c){var d=a.settings.plugins?a.settings.plugins:"";return b.inArray(d.split(/[ ,]/),c)!==-1};d(a,"advlist")||(a.addButton("numlist",{title:"Numbered list",cmd:"InsertOrderedList",onPostRender:c("OL")}),a.addButton("bullist",{title:"Bullet list",cmd:"InsertUnorderedList",onPostRender:c("UL")})),a.addButton("indent",{icon:"indent",title:"Increase indent",cmd:"Indent",onPostRender:function(b){var c=b.control;a.on("nodechange",function(){for(var b=a.selection.getSelectedBlocks(),d=!1,e=0,f=b.length;!d&&e<f;e++){var g=b[e].nodeName;d="LI"===g&&h.isFirstChild(b[e])||"UL"===g||"OL"===g||"DD"===g}c.disabled(d)})}})};return a.add("lists",function(a){return m(a),g.setup(a),a.on("init",function(){j(a
 ),k(a),a.getParam("lists_indent_on_tab",!0)&&l(a)}),{backspaceDelete:function(b){g.backspaceDelete(a,b)}}}),function(){}}),d("0")()}();
</del><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("a",tinymce.util.Tools.resolve),g("1",[&q
 uot;a"],function(a){return a("tinymce.PluginManager")}),g("2",["a"],function(a){return a("tinymce.util.Tools")}),g("3",["a"],function(a){return a("tinymce.util.VK")}),g("b",["a"],function(a){return a("tinymce.dom.DOMUtils")}),g("8",[],function(){var a=function(a){return a&&3===a.nodeType},b=function(a){return a&&/^(OL|UL|DL)$/.test(a.nodeName)},c=function(a){return a&&/^(LI|DT|DD)$/.test(a.nodeName)},d=function(a){return a&&"BR"===a.nodeName},e=function(a){return a.parentNode.firstChild===a},f=function(a){return a.parentNode.lastChild===a},g=function(a,b){return b&&!!a.schema.getTextBlockElements()[b.nodeName]},h=function(a,b){return a&&a.nodeName in b},i=function(a,b){return!!d(b)&&!(!a.isBlock(b.nextSibling)||d(b.previousSibling))},j=function(a,b,c){var d=a.isEmpty(b);return!(c&&a.select("s
 pan[data-mce-type=bookmark]",b).length>0)&&d},k=function(a,b){return a.isChildOf(b,a.getRoot())};return{isTextNode:a,isListNode:b,isListItemNode:c,isBr:d,isFirstChild:e,isLastChild:f,isTextBlock:g,isBlock:h,isBogusBr:i,isEmpty:j,isChildOfBody:k}}),g("i",["a"],function(a){return a("tinymce.dom.RangeUtils")}),g("k",["i","8"],function(a,b){var c=function(c,d){var e=a.getNode(c,d);if(b.isListItemNode(c)&&b.isTextNode(e)){var f=d>=c.childNodes.length?e.data.length:0;return{container:e,offset:f}}return{container:c,offset:d}},d=function(a){var b=a.cloneRange(),d=c(a.startContainer,a.startOffset);b.setStart(d.container,d.offset);var e=c(a.endContainer,a.endOffset);return b.setEnd(e.container,e.offset),b};return{getNormalizedEndPoint:c,normalizeRange:d}}),g("c",["b","8","k"],function(a,b,c){var d=a.DOM,e=function(a){var b={},c=function(c){var e,f,g;f=a[c?"startC
 ontainer":"endContainer"],g=a[c?"startOffset":"endOffset"],1===f.nodeType&&(e=d.create("span",{"data-mce-type":"bookmark"}),f.hasChildNodes()?(g=Math.min(g,f.childNodes.length-1),c?f.insertBefore(e,f.childNodes[g]):d.insertAfter(e,f.childNodes[g])):f.appendChild(e),f=e,g=0),b[c?"startContainer":"endContainer"]=f,b[c?"startOffset":"endOffset"]=g};return c(!0),a.collapsed||c(),b},f=function(a){function b(b){var c,e,f,g=function(a){for(var b=a.parentNode.firstChild,c=0;b;){if(b===a)return c;1===b.nodeType&&"bookmark"===b.getAttribute("data-mce-type")||c++,b=b.nextSibling}return-1};c=f=a[b?"startContainer":"endContainer"],e=a[b?"startOffset":"endOffset"],c&&(1===c.nodeType&&(e=g(c),c=c.parentNode,d.remove(f)),a[b?"startContainer":"endContainer"]=c,a[b?"startOffset&quot
 ;:"endOffset"]=e)}b(!0),b();var e=d.createRng();return e.setStart(a.startContainer,a.startOffset),a.endContainer&&e.setEnd(a.endContainer,a.endOffset),c.normalizeRange(e)};return{createBookmark:e,resolveBookmark:f}}),g("d",["a"],function(a){return a("tinymce.dom.DomQuery")}),g("9",["d","2","8"],function(a,b,c){var d=function(a){return a.dom.getParent(a.selection.getStart(!0),"OL,UL,DL")},e=function(a){var e=d(a);return b.grep(a.selection.getSelectedBlocks(),function(a){return c.isListNode(a)&&e!==a})},f=function(c,d){var e=b.map(d,function(a){var b=c.dom.getParent(a,"li,dd,dt",c.getBody());return b?b:a});return a.unique(e)},g=function(a){var d=a.selection.getSelectedBlocks();return b.grep(f(a,d),function(a){return c.isListItemNode(a)})};return{getParentList:d,getSelectedSubLists:e,getSelectedListItems:g}}),g("4",["b","c","8",&quo
 t;9"],function(a,b,c,d){var e=a.DOM,f=function(a,b){var d;if(c.isListNode(a)){for(;d=a.firstChild;)b.appendChild(d);e.remove(a)}},g=function(a){var b,d,g;return"DT"===a.nodeName?(e.rename(a,"DD"),!0):(b=a.previousSibling,b&&c.isListNode(b)?(b.appendChild(a),!0):b&&"LI"===b.nodeName&&c.isListNode(b.lastChild)?(b.lastChild.appendChild(a),f(a.lastChild,b.lastChild),!0):(b=a.nextSibling,b&&c.isListNode(b)?(b.insertBefore(a,b.firstChild),!0):(b=a.previousSibling,!(!b||"LI"!==b.nodeName)&&(d=e.create(a.parentNode.nodeName),g=e.getStyle(a.parentNode,"listStyleType"),g&&e.setStyle(d,"listStyleType",g),b.appendChild(d),d.appendChild(a),f(a.lastChild,d),!0))))},h=function(a){var c=d.getSelectedListItems(a);if(c.length){for(var e=b.createBookmark(a.selection.getRng(!0)),f=0;f<c.length&&(g(c[f])||0!==f);f++);return a.selection.setRng(b.resolveBookmark(e)),a.nodeChanged(),!
 0}};return{indentSelection:h}}),g("e",["b","2","8"],function(a,b,c){var d=a.DOM,e=function(a,b){var e,f=b.parentNode;"LI"===f.nodeName&&f.firstChild===b&&(e=f.previousSibling,e&&"LI"===e.nodeName?(e.appendChild(b),c.isEmpty(a,f)&&d.remove(f)):d.setStyle(f,"listStyleType","none")),c.isListNode(f)&&(e=f.previousSibling,e&&"LI"===e.nodeName&&e.appendChild(b))},f=function(a,c){b.each(b.grep(a.select("ol,ul",c)),function(b){e(a,b)})};return{normalizeList:e,normalizeLists:f}}),g("l",["a"],function(a){return a("tinymce.Env")}),g("g",["b","l","8"],function(a,b,c){var d=a.DOM,e=function(a,e,f){var g,h,i,j=d.createFragment(),k=a.schema.getBlockElements();if(a.settings.forced_root_block&&(f=f||a.settings.forced_root_block),f&&(h=d.create(f),h.tagName===a.s
 ettings.forced_root_block&&d.setAttribs(h,a.settings.forced_root_block_attrs),c.isBlock(e.firstChild,k)||j.appendChild(h)),e)for(;g=e.firstChild;){var l=g.nodeName;i||"SPAN"===l&&"bookmark"===g.getAttribute("data-mce-type")||(i=!0),c.isBlock(g,k)?(j.appendChild(g),h=null):f?(h||(h=d.create(f),j.appendChild(h)),h.appendChild(g)):j.appendChild(g)}return a.settings.forced_root_block?i||b.ie&&!(b.ie>10)||h.appendChild(d.create("br",{"data-mce-bogus":"1"})):j.appendChild(d.create("br")),j};return{createNewTextBlock:e}}),g("f",["b","8","g","2"],function(a,b,c,d){var e=a.DOM,f=function(a,f,g,h){var i,j,k,l,m=function(a){d.each(k,function(b){a.parentNode.insertBefore(b,g.parentNode)}),e.remove(a)};for(k=e.select('span[data-mce-type="bookmark"]',f),h=h||c.createNewTextBlock(a,g),i=e.createRng(),i.setStartAfter(g),i.setEndAfter(f),j=i.ext
 ractContents(),l=j.firstChild;l;l=l.firstChild)if("LI"===l.nodeName&&a.dom.isEmpty(l)){e.remove(l);break}a.dom.isEmpty(j)||e.insertAfter(j,f),e.insertAfter(h,f),b.isEmpty(a.dom,g.parentNode)&&m(g.parentNode),e.remove(g),b.isEmpty(a.dom,f)&&e.remove(f)};return{splitList:f}}),g("5",["b","c","8","e","9","f","g"],function(a,b,c,d,e,f,g){var h=a.DOM,i=function(a,b){c.isEmpty(a,b)&&h.remove(b)},j=function(a,b){var e,j=b.parentNode,k=j.parentNode;return j===a.getBody()||("DD"===b.nodeName?(h.rename(b,"DT"),!0):c.isFirstChild(b)&&c.isLastChild(b)?("LI"===k.nodeName?(h.insertAfter(b,k),i(a.dom,k),h.remove(j)):c.isListNode(k)?h.remove(j,!0):(k.insertBefore(g.createNewTextBlock(a,b),j),h.remove(j)),!0):c.isFirstChild(b)?("LI"===k.nodeName?(h.insertAfter(b,k),b.appendChild(j),i(a.dom,k)):c.isListNode(k)?k.insertBefore(b,j):(k.i
 nsertBefore(g.createNewTextBlock(a,b),j),h.remove(b)),!0):c.isLastChild(b)?("LI"===k.nodeName?h.insertAfter(b,k):c.isListNode(k)?h.insertAfter(b,j):(h.insertAfter(g.createNewTextBlock(a,b),j),h.remove(b)),!0):("LI"===k.nodeName?(j=k,e=g.createNewTextBlock(a,b,"LI")):e=c.isListNode(k)?g.createNewTextBlock(a,b,"LI"):g.createNewTextBlock(a,b),f.splitList(a,j,b,e),d.normalizeLists(a.dom,j.parentNode),!0))},k=function(a){var c=e.getSelectedListItems(a);if(c.length){var d,f,g=b.createBookmark(a.selection.getRng(!0)),h=a.getBody();for(d=c.length;d--;)for(var i=c[d].parentNode;i&&i!==h;){for(f=c.length;f--;)if(c[f]===i){c.splice(d,1);break}i=i.parentNode}for(d=0;d<c.length&&(j(a,c[d])||0!==d);d++);return a.selection.setRng(b.resolveBookmark(g)),a.nodeChanged(),!0}};return{outdent:j,outdentSelection:k}}),g("h",["a"],function(a){return a("tinymce.dom.BookmarkManager")}),g("6",["h",&quo
 t;2","5","c","8","e","9","f"],function(a,b,c,d,e,f,g,h){var i=function(a,b,c){var d=c["list-style-type"]?c["list-style-type"]:null;a.setStyle(b,"list-style-type",d)},j=function(a,c){b.each(c,function(b,c){a.setAttribute(c,b)})},k=function(a,c,d){j(c,d["list-attributes"]),b.each(a.select("li",c),function(a){j(a,d["list-item-attributes"])})},l=function(a,b,c){i(a,b,c),k(a,b,c)},m=function(a,b,c){var d,f,g=a.getBody();for(d=b[c?"startContainer":"endContainer"],f=b[c?"startOffset":"endOffset"],1===d.nodeType&&(d=d.childNodes[Math.min(f,d.childNodes.length-1)]||d);d.parentNode!==g;){if(e.isTextBlock(a,d))return d;if(/^(TD|TH)$/.test(d.parentNode.nodeName))return d;d=d.parentNode}return d},n=function(c,d){for(var f,g=[],h=c.getBody(),i=c.dom,j=m(c,d,!0),k=m(c,d,!1),l=[],n=j;n&&(l.push(n),n!==k);n=n.nextSibling)
 ;return b.each(l,function(b){if(e.isTextBlock(c,b))return g.push(b),void(f=null);if(i.isBlock(b)||e.isBr(b))return e.isBr(b)&&i.remove(b),void(f=null);var d=b.nextSibling;return a.isBookmarkNode(b)&&(e.isTextBlock(c,d)||!d&&b.parentNode===h)?void(f=null):(f||(f=i.create("p"),b.parentNode.insertBefore(f,b),g.push(f)),void f.appendChild(b))}),g},o=function(a,c,f){var g,h=a.selection.getRng(!0),i="LI",j=a.dom;f=f?f:{},"false"!==j.getContentEditable(a.selection.getNode())&&(c=c.toUpperCase(),"DL"===c&&(i="DT"),g=d.createBookmark(h),b.each(n(a,h),function(b){var d,g,h=function(a){var b=j.getStyle(a,"list-style-type"),c=f?f["list-style-type"]:"";return c=null===c?"":c,b===c};g=b.previousSibling,g&&e.isListNode(g)&&g.nodeName===c&&h(g)?(d=g,b=j.rename(b,i),g.appendChild(b)):(d=j.create(c),b.parentNode.insertBefore(d,b),d.appendChild(b),b=
 j.rename(b,i)),l(j,d,f),u(a.dom,d)}),a.selection.setRng(d.resolveBookmark(g)))},p=function(a){var i=d.createBookmark(a.selection.getRng(!0)),j=a.getBody(),k=g.getSelectedListItems(a),l=b.grep(k,function(b){return a.dom.isEmpty(b)});k=b.grep(k,function(b){return!a.dom.isEmpty(b)}),b.each(l,function(b){if(e.isEmpty(a.dom,b))return void c.outdent(a,b)}),b.each(k,function(b){var c,d;if(b.parentNode!==a.getBody()){for(c=b;c&&c!==j;c=c.parentNode)e.isListNode(c)&&(d=c);h.splitList(a,d,b),f.normalizeLists(a.dom,d.parentNode)}}),a.selection.setRng(d.resolveBookmark(i))},q=function(a,b){return a&&b&&e.isListNode(a)&&a.nodeName===b.nodeName},r=function(a,b,c){var d=a.getStyle(b,"list-style-type",!0),e=a.getStyle(c,"list-style-type",!0);return d===e},s=function(a,b){return a.className===b.className},t=function(a,b,c){return q(b,c)&&r(a,b,c)&&s(b,c)},u=function(a,b){var c,d;if(c=b.nextSibling,t(a,b,c)){for(;d=c.firstChi
 ld;)b.appendChild(d);a.remove(c)}if(c=b.previousSibling,t(a,b,c)){for(;d=c.lastChild;)b.insertBefore(d,b.firstChild);a.remove(c)}},v=function(a,b,c,d){if(b.nodeName!==c){var e=a.rename(b,c);l(a,e,d)}else l(a,b,d)},w=function(a,c,e,f,g){if(c.nodeName!==f||x(g)){var h=d.createBookmark(a.selection.getRng(!0));b.each([c].concat(e),function(b){v(a.dom,b,f,g)}),a.selection.setRng(d.resolveBookmark(h))}else p(a,f)},x=function(a){return"list-style-type"in a},y=function(a,b,c,e){if(b!==a.getBody())if(b)if(b.nodeName!==c||x(e)){var f=d.createBookmark(a.selection.getRng(!0));l(a.dom,b,e),u(a.dom,a.dom.rename(b,c)),a.selection.setRng(d.resolveBookmark(f))}else p(a,c);else o(a,c,e)},z=function(a,b,c){var d=g.getParentList(a),e=g.getSelectedSubLists(a);c=c?c:{},d&&e.length>0?w(a,d,e,b,c):y(a,d,b,c)};return{toggleList:z,removeList:p,mergeWithAdjacentLists:u}}),g("j",["a"],function(a){return a("tinymce.dom.TreeWalker")}),g("7",["i&qu
 ot;,"j","3","6","c","8","e","k","9"],function(a,b,c,d,e,f,g,h,i){var j=function(c,d,e){var g,h,i=d.startContainer,j=d.startOffset;if(3===i.nodeType&&(e?j<i.data.length:j>0))return i;for(g=c.schema.getNonEmptyElements(),1===i.nodeType&&(i=a.getNode(i,j)),h=new b(i,c.getBody()),e&&f.isBogusBr(c.dom,i)&&h.next();i=h[e?"next":"prev2"]();){if("LI"===i.nodeName&&!i.hasChildNodes())return i;if(g[i.nodeName])return i;if(3===i.nodeType&&i.data.length>0)return i}},k=function(a,b){var c=b.childNodes;return 1===c.length&&!f.isListNode(c[0])&&a.isBlock(c[0])},l=function(a,b){k(a,b)&&a.remove(b.firstChild,!0)},m=function(a,b,c){var d,e;if(e=k(a,c)?c.firstChild:c,l(a,b),!f.isEmpty(a,b,!0))for(;d=b.firstChild;)e.appendChild(d)},n=function(a,b,c){var d,e,g=b.parentNode;f.isChildOfBody(a,b)&&f.isChildOfBo
 dy(a,c)&&(f.isListNode(c.lastChild)&&(e=c.lastChild),g===c.lastChild&&f.isBr(g.previousSibling)&&a.remove(g.previousSibling),d=c.lastChild,d&&f.isBr(d)&&b.hasChildNodes()&&a.remove(d),f.isEmpty(a,c,!0)&&a.$(c).empty(),m(a,b,c),e&&c.appendChild(e),a.remove(b),f.isEmpty(a,g)&&g!==a.getRoot()&&a.remove(g))},o=function(a,b,c){a.dom.$(c).empty(),n(a.dom,b,c),a.selection.setCursorLocation(c)},p=function(a,b,c,d){var f=a.dom;if(f.isEmpty(d))o(a,c,d);else{var g=e.createBookmark(b);n(f,c,d),a.selection.setRng(e.resolveBookmark(g))}},q=function(a,b,c,d){var f=e.createBookmark(b);n(a.dom,c,d),a.selection.setRng(e.resolveBookmark(f))},r=function(a,b){var c,e,g,i=a.dom,k=a.selection,l=i.getParent(k.getStart(),"LI");if(l){if(c=l.parentNode,c===a.getBody()&&f.isEmpty(i,c))return!0;if(e=h.normalizeRange(k.getRng(!0)),g=i.getParent(j(a,e,b),"LI"),g&&g!==l)return b?p(a,e,g,l):q(
 a,e,l,g),!0;if(!g&&!b&&d.removeList(a,c.nodeName))return!0}return!1},s=function(a,b){var c=a.getParent(b.parentNode,a.isBlock);a.remove(b),c&&a.isEmpty(c)&&a.remove(c)},t=function(a,b){var c=a.dom,e=c.getParent(a.selection.getStart(),c.isBlock);if(e&&c.isEmpty(e)){var f=h.normalizeRange(a.selection.getRng(!0)),g=c.getParent(j(a,f,b),"LI");if(g)return a.undoManager.transact(function(){s(c,e),d.mergeWithAdjacentLists(c,g.parentNode),a.selection.select(g,!0),a.selection.collapse(b)}),!0}return!1},u=function(a,b){return r(a,b)||t(a,b)},v=function(a){var b=a.dom.getParent(a.selection.getStart(),"LI,DT,DD");return!!(b||i.getSelectedListItems(a).length>0)&&(a.undoManager.transact(function(){a.execCommand("Delete"),g.normalizeLists(a.dom,a.getBody())}),!0)},w=function(a,b){return a.selection.isCollapsed()?u(a,b):v(a)},x=function(a){a.on("keydown",function(b){b.keyCode===c.BACKSPACE?w(a,!1)&&b.
 preventDefault():b.keyCode===c.DELETE&&w(a,!0)&&b.preventDefault()})};return{setup:x,backspaceDelete:w}}),g("0",["1","2","3","4","5","6","7","8","9"],function(a,b,c,d,e,f,g,h,i){var j=function(a,b){return function(){var c=a.dom.getParent(a.selection.getStart(),"UL,OL,DL");return c&&c.nodeName===b}},k=function(a){a.on("BeforeExecCommand",function(b){var c,f=b.command.toLowerCase();if("indent"===f?d.indentSelection(a)&&(c=!0):"outdent"===f&&e.outdentSelection(a)&&(c=!0),c)return a.fire("ExecCommand",{command:b.command}),b.preventDefault(),!0}),a.addCommand("InsertUnorderedList",function(b,c){f.toggleList(a,"UL",c)}),a.addCommand("InsertOrderedList",function(b,c){f.toggleList(a,"OL",c)}),a.addCommand("InsertDefinitionList",function(b,c){f.tog
 gleList(a,"DL",c)})},l=function(a){a.addQueryStateHandler("InsertUnorderedList",j(a,"UL")),a.addQueryStateHandler("InsertOrderedList",j(a,"OL")),a.addQueryStateHandler("InsertDefinitionList",j(a,"DL"))},m=function(a){a.on("keydown",function(b){9!==b.keyCode||c.metaKeyPressed(b)||a.dom.getParent(a.selection.getStart(),"LI,DT,DD")&&(b.preventDefault(),b.shiftKey?e.outdentSelection(a):d.indentSelection(a))})},n=function(a){var c=function(c){return function(){var d=this;a.on("NodeChange",function(a){var e=b.grep(a.parents,h.isListNode);d.active(e.length>0&&e[0].nodeName===c)})}},d=function(a,c){var d=a.settings.plugins?a.settings.plugins:"";return b.inArray(d.split(/[ ,]/),c)!==-1};d(a,"advlist")||(a.addButton("numlist",{title:"Numbered list",cmd:"InsertOrderedList",onPostRender:c("OL")}),a.addButton("bull
 ist",{title:"Bullet list",cmd:"InsertUnorderedList",onPostRender:c("UL")})),a.addButton("indent",{icon:"indent",title:"Increase indent",cmd:"Indent",onPostRender:function(b){var c=b.control;a.on("nodechange",function(){var b=i.getSelectedListItems(a),d=b.length>0&&h.isFirstChild(b[0]);c.disabled(d)})}})};return a.add("lists",function(a){return n(a),g.setup(a),a.on("init",function(){k(a),l(a),a.getParam("lists_indent_on_tab",!0)&&m(a)}),{backspaceDelete:function(b){g.backspaceDelete(a,b)}}}),function(){}}),d("0")()}();
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span></span></pre></div>
<a id="trunksrcwpincludesjstinymcepluginspastepluginjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/tinymce/plugins/paste/plugin.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/tinymce/plugins/paste/plugin.js  2017-09-26 20:32:46 UTC (rev 41603)
+++ trunk/src/wp-includes/js/tinymce/plugins/paste/plugin.js    2017-09-26 21:14:28 UTC (rev 41604)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -81,7 +81,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">   define(id, [], function () { return ref; });
</span><span class="cx" style="display: block; padding: 0 10px"> };
</span><span class="cx" style="display: block; padding: 0 10px"> /*jsc
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-["tinymce.plugins.paste.Plugin","tinymce.core.PluginManager","tinymce.plugins.paste.core.Clipboard","tinymce.plugins.paste.core.CutCopy","tinymce.plugins.paste.core.Quirks","tinymce.plugins.paste.core.WordFilter","global!tinymce.util.Tools.resolve","tinymce.core.dom.RangeUtils","tinymce.core.Env","tinymce.core.util.Delay","tinymce.core.util.Tools","tinymce.core.util.VK","tinymce.plugins.paste.core.InternalHtml","tinymce.plugins.paste.core.Utils","tinymce.plugins.paste.core.Newlines","tinymce.plugins.paste.core.SmartPaste","tinymce.core.html.DomParser","tinymce.core.html.Schema","tinymce.core.html.Serializer","tinymce.core.html.Node","tinymce.core.html.Entities"]
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+["tinymce.plugins.paste.Plugin","tinymce.core.PluginManager","tinymce.plugins.paste.api.Events","tinymce.plugins.paste.core.Clipboard","tinymce.plugins.paste.core.CutCopy","tinymce.plugins.paste.core.Quirks","global!tinymce.util.Tools.resolve","tinymce.core.dom.RangeUtils","tinymce.core.Env","tinymce.core.util.Delay","tinymce.core.util.Tools","tinymce.core.util.VK","tinymce.plugins.paste.core.InternalHtml","tinymce.plugins.paste.core.Newlines","tinymce.plugins.paste.core.PasteBin","tinymce.plugins.paste.core.ProcessFilters","tinymce.plugins.paste.core.SmartPaste","tinymce.plugins.paste.core.Utils","tinymce.plugins.paste.core.WordFilter","tinymce.core.html.Entities","tinymce.core.html.Dom
 Parser","tinymce.core.html.Schema","tinymce.core.html.Serializer","tinymce.core.html.Node"]
</ins><span class="cx" style="display: block; padding: 0 10px"> jsc*/
</span><span class="cx" style="display: block; padding: 0 10px"> defineGlobal("global!tinymce.util.Tools.resolve", tinymce.util.Tools.resolve);
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -105,6 +105,41 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Events.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.plugins.paste.api.Events',
+  [
+  ],
+  function () {
+    var firePastePreProcess = function (editor, html, internal, isWordHtml) {
+      return editor.fire('PastePreProcess', { content: html, internal: internal, wordContent: isWordHtml });
+    };
+
+    var firePastePostProcess = function (editor, node, internal, isWordHtml) {
+      return editor.fire('PastePostProcess', { node: node, internal: internal, wordContent: isWordHtml });
+    };
+
+    var firePastePlainTextToggle = function (editor, state) {
+      return editor.fire('PastePlainTextToggle', { state: state });
+    };
+
+    return {
+      firePastePreProcess: firePastePreProcess,
+      firePastePostProcess: firePastePostProcess,
+      firePastePlainTextToggle: firePastePlainTextToggle
+    };
+  }
+);
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * ResolveGlobal.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -255,6 +290,360 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.html.Entities',
+  [
+    'global!tinymce.util.Tools.resolve'
+  ],
+  function (resolve) {
+    return resolve('tinymce.html.Entities');
+  }
+);
+
+/**
+ * Newlines.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * Newlines class contains utilities to convert newlines (\n or \r\n) tp BRs or to a combination of the specified block element and BRs
+ *
+ * @class tinymce.Newlines
+ * @private
+ */
+define(
+  'tinymce.plugins.paste.core.Newlines',
+  [
+    'tinymce.core.util.Tools',
+    'tinymce.core.html.Entities'
+  ],
+  function (Tools, Entities) {
+
+    var isPlainText = function (text) {
+      // so basically any tag that is not one of the "p, div, span, br", or is one of them, but is followed
+      // by some additional characters qualifies the text as not a plain text (having some HTML tags)
+      // <span style="white-space:pre"> and <br /> are added as separate exceptions to the rule
+      return !/<(?:\/?(?!(?:div|p|br|span)>)\w+|(?:(?!(?:span style="white-space:\s?pre;?">)|br\s?\/>))\w+\s[^>]+)>/i.test(text);
+    };
+
+
+    var toBRs = function (text) {
+      return text.replace(/\r?\n/g, '<br>');
+    };
+
+
+    var openContainer = function (rootTag, rootAttrs) {
+      var key, attrs = [];
+      var tag = '<' + rootTag;
+
+      if (typeof rootAttrs === 'object') {
+        for (key in rootAttrs) {
+          if (rootAttrs.hasOwnProperty(key)) {
+            attrs.push(key + '="' + Entities.encodeAllRaw(rootAttrs[key]) + '"');
+          }
+        }
+
+        if (attrs.length) {
+          tag += ' ' + attrs.join(' ');
+        }
+      }
+      return tag + '>';
+    };
+
+
+    var toBlockElements = function (text, rootTag, rootAttrs) {
+      var blocks = text.split(/\n\n/);
+      var tagOpen = openContainer(rootTag, rootAttrs);
+      var tagClose = '</' + rootTag + '>';
+
+      var paragraphs = Tools.map(blocks, function (p) {
+        return p.split(/\n/).join('<br />');
+      });
+
+      var stitch = function (p) {
+        return tagOpen + p + tagClose;
+      };
+
+      return paragraphs.length === 1 ? paragraphs[0] : Tools.map(paragraphs, stitch).join('');
+    };
+
+
+    var convert = function (text, rootTag, rootAttrs) {
+      return rootTag ? toBlockElements(text, rootTag, rootAttrs) : toBRs(text);
+    };
+
+
+    return {
+      isPlainText: isPlainText,
+      convert: convert,
+      toBRs: toBRs,
+      toBlockElements: toBlockElements
+    };
+  }
+);
+/**
+ * PasteBin.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * @class tinymce.pasteplugin.PasteBin
+ * @private
+ */
+define(
+  'tinymce.plugins.paste.core.PasteBin',
+  [
+    'tinymce.core.util.Tools',
+    'tinymce.core.Env'
+  ],
+  function (Tools, Env) {
+    return function (editor) {
+      var lastRng;
+      var pasteBinDefaultContent = '%MCEPASTEBIN%';
+
+      /**
+       * Creates a paste bin element as close as possible to the current caret location and places the focus inside that element
+       * so that when the real paste event occurs the contents gets inserted into this element
+       * instead of the current editor selection element.
+       */
+      var create = function () {
+        var dom = editor.dom, body = editor.getBody();
+        var viewport = editor.dom.getViewPort(editor.getWin()), scrollTop = viewport.y, top = 20;
+        var pasteBinElm;
+        var scrollContainer;
+
+        lastRng = editor.selection.getRng();
+
+        if (editor.inline) {
+          scrollContainer = editor.selection.getScrollContainer();
+
+          // Can't always rely on scrollTop returning a useful value.
+          // It returns 0 if the browser doesn't support scrollTop for the element or is non-scrollable
+          if (scrollContainer && scrollContainer.scrollTop > 0) {
+            scrollTop = scrollContainer.scrollTop;
+          }
+        }
+
+        /**
+         * Returns the rect of the current caret if the caret is in an empty block before a
+         * BR we insert a temporary invisible character that we get the rect this way we always get a proper rect.
+         *
+         * TODO: This might be useful in core.
+         */
+        function getCaretRect(rng) {
+          var rects, textNode, node, container = rng.startContainer;
+
+          rects = rng.getClientRects();
+          if (rects.length) {
+            return rects[0];
+          }
+
+          if (!rng.collapsed || container.nodeType != 1) {
+            return;
+          }
+
+          node = container.childNodes[lastRng.startOffset];
+
+          // Skip empty whitespace nodes
+          while (node && node.nodeType == 3 && !node.data.length) {
+            node = node.nextSibling;
+          }
+
+          if (!node) {
+            return;
+          }
+
+          // Check if the location is |<br>
+          // TODO: Might need to expand this to say |<table>
+          if (node.tagName == 'BR') {
+            textNode = dom.doc.createTextNode('\uFEFF');
+            node.parentNode.insertBefore(textNode, node);
+
+            rng = dom.createRng();
+            rng.setStartBefore(textNode);
+            rng.setEndAfter(textNode);
+
+            rects = rng.getClientRects();
+            dom.remove(textNode);
+          }
+
+          if (rects.length) {
+            return rects[0];
+          }
+        }
+
+        // Calculate top cordinate this is needed to avoid scrolling to top of document
+        // We want the paste bin to be as close to the caret as possible to avoid scrolling
+        if (lastRng.getClientRects) {
+          var rect = getCaretRect(lastRng);
+
+          if (rect) {
+            // Client rects gets us closes to the actual
+            // caret location in for example a wrapped paragraph block
+            top = scrollTop + (rect.top - dom.getPos(body).y);
+          } else {
+            top = scrollTop;
+
+            // Check if we can find a closer location by checking the range element
+            var container = lastRng.startContainer;
+            if (container) {
+              if (container.nodeType == 3 && container.parentNode != body) {
+                container = container.parentNode;
+              }
+
+              if (container.nodeType == 1) {
+                top = dom.getPos(container, scrollContainer || body).y;
+              }
+            }
+          }
+        }
+
+        // Create a pastebin
+        pasteBinElm = editor.dom.add(editor.getBody(), 'div', {
+          id: "mcepastebin",
+          contentEditable: true,
+          "data-mce-bogus": "all",
+          style: 'position: absolute; top: ' + top + 'px; width: 10px; height: 10px; overflow: hidden; opacity: 0'
+        }, pasteBinDefaultContent);
+
+        // Move paste bin out of sight since the controlSelection rect gets displayed otherwise on IE and Gecko
+        if (Env.ie || Env.gecko) {
+          dom.setStyle(pasteBinElm, 'left', dom.getStyle(body, 'direction', true) == 'rtl' ? 0xFFFF : -0xFFFF);
+        }
+
+        // Prevent focus events from bubbeling fixed FocusManager issues
+        dom.bind(pasteBinElm, 'beforedeactivate focusin focusout', function (e) {
+          e.stopPropagation();
+        });
+
+        pasteBinElm.focus();
+        editor.selection.select(pasteBinElm, true);
+      };
+
+      /**
+       * Removes the paste bin if it exists.
+       */
+      var remove = function () {
+        if (getEl()) {
+          var pasteBinClone;
+
+          // WebKit/Blink might clone the div so
+          // lets make sure we remove all clones
+          // TODO: Man o man is this ugly. WebKit is the new IE! Remove this if they ever fix it!
+          while ((pasteBinClone = editor.dom.get('mcepastebin'))) {
+            editor.dom.remove(pasteBinClone);
+            editor.dom.unbind(pasteBinClone);
+          }
+
+          if (lastRng) {
+            editor.selection.setRng(lastRng);
+          }
+        }
+
+        lastRng = null;
+      };
+
+
+      var getEl = function () {
+        return editor.dom.get('mcepastebin');
+      };
+
+      /**
+       * Returns the contents of the paste bin as a HTML string.
+       *
+       * @return {String} Get the contents of the paste bin.
+       */
+      var getHtml = function () {
+        var pasteBinElm, pasteBinClones, i, dirtyWrappers, cleanWrapper;
+
+        // Since WebKit/Chrome might clone the paste bin when pasting
+        // for example: <img style="float: right"> we need to check if any of them contains some useful html.
+        // TODO: Man o man is this ugly. WebKit is the new IE! Remove this if they ever fix it!
+
+        var copyAndRemove = function (toElm, fromElm) {
+          toElm.appendChild(fromElm);
+          editor.dom.remove(fromElm, true); // remove, but keep children
+        };
+
+        // find only top level elements (there might be more nested inside them as well, see TINY-1162)
+        pasteBinClones = Tools.grep(editor.getBody().childNodes, function (elm) {
+          return elm.id === 'mcepastebin';
+        });
+        pasteBinElm = pasteBinClones.shift();
+
+        // if clones were found, move their content into the first bin
+        Tools.each(pasteBinClones, function (pasteBinClone) {
+          copyAndRemove(pasteBinElm, pasteBinClone);
+        });
+
+        // TINY-1162: when copying plain text (from notepad for example) WebKit clones
+        // paste bin (with styles and attributes) and uses it as a default  wrapper for
+        // the chunks of the content, here we cycle over the whole paste bin and replace
+        // those wrappers with a basic div
+        dirtyWrappers = editor.dom.select('div[id=mcepastebin]', pasteBinElm);
+        for (i = dirtyWrappers.length - 1; i >= 0; i--) {
+          cleanWrapper = editor.dom.create('div');
+          pasteBinElm.insertBefore(cleanWrapper, dirtyWrappers[i]);
+          copyAndRemove(cleanWrapper, dirtyWrappers[i]);
+        }
+
+        return pasteBinElm ? pasteBinElm.innerHTML : '';
+      };
+
+
+      var getLastRng = function () {
+        return lastRng;
+      };
+
+
+      var isDefaultContent = function (content) {
+        return content === pasteBinDefaultContent;
+      };
+
+
+      var isPasteBin = function (elm) {
+        return elm && elm.id === 'mcepastebin';
+      };
+
+
+      var isDefault = function () {
+        var pasteBinElm = getEl();
+        return isPasteBin(pasteBinElm) && isDefaultContent(pasteBinElm.innerHTML);
+      };
+
+      return {
+        create: create,
+        remove: remove,
+        getEl: getEl,
+        getHtml: getHtml,
+        getLastRng: getLastRng,
+        isDefault: isDefault,
+        isDefaultContent: isDefaultContent
+      };
+    };
+  }
+);
+
+/**
+ * ResolveGlobal.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
</ins><span class="cx" style="display: block; padding: 0 10px">   'tinymce.core.html.DomParser',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><span class="cx" style="display: block; padding: 0 10px">     'global!tinymce.util.Tools.resolve'
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -285,6 +674,46 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * ResolveGlobal.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.html.Serializer',
+  [
+    'global!tinymce.util.Tools.resolve'
+  ],
+  function (resolve) {
+    return resolve('tinymce.html.Serializer');
+  }
+);
+
+/**
+ * ResolveGlobal.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.html.Node',
+  [
+    'global!tinymce.util.Tools.resolve'
+  ],
+  function (resolve) {
+    return resolve('tinymce.html.Node');
+  }
+);
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * Utils.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -435,7 +864,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * CutCopy.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * WordFilter.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -444,234 +873,547 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Contributing: http://www.tinymce.com/contributing
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/**
+ * This class parses word HTML into proper TinyMCE markup.
+ *
+ * @class tinymce.pasteplugin.WordFilter
+ * @private
+ */
</ins><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.plugins.paste.core.CutCopy',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.plugins.paste.core.WordFilter',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.Env',
-    'tinymce.plugins.paste.core.InternalHtml',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.util.Tools',
+    'tinymce.core.html.DomParser',
+    'tinymce.core.html.Schema',
+    'tinymce.core.html.Serializer',
+    'tinymce.core.html.Node',
</ins><span class="cx" style="display: block; padding: 0 10px">     'tinymce.plugins.paste.core.Utils'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Env, InternalHtml, Utils) {
-    var noop = function () {
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Tools, DomParser, Schema, Serializer, Node, Utils) {
+    /**
+     * Checks if the specified content is from any of the following sources: MS Word/Office 365/Google docs.
+     */
+    function isWordContent(content) {
+      return (
+        (/<font face="Times New Roman"|class="?Mso|style="[^"]*\bmso-|style='[^'']*\bmso-|w:WordDocument/i).test(content) ||
+        (/class="OutlineElement/).test(content) ||
+        (/id="?docs\-internal\-guid\-/.test(content))
+      );
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var hasWorkingClipboardApi = function (clipboardData) {
-      // iOS supports the clipboardData API but it doesn't do anything for cut operations
-      // Edge 15 has a broken HTML Clipboard API see https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/11780845/
-      return Env.iOS === false && clipboardData !== undefined && typeof clipboardData.setData === 'function' && Utils.isMsEdge() !== true;
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    /**
+     * Checks if the specified text starts with "1. " or "a. " etc.
+     */
+    function isNumericList(text) {
+      var found, patterns;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var setHtml5Clipboard = function (clipboardData, html, text) {
-      if (hasWorkingClipboardApi(clipboardData)) {
-        try {
-          clipboardData.clearData();
-          clipboardData.setData('text/html', html);
-          clipboardData.setData('text/plain', text);
-          clipboardData.setData(InternalHtml.internalHtmlMime(), html);
-          return true;
-        } catch (e) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      patterns = [
+        /^[IVXLMCD]{1,2}\.[ \u00a0]/,  // Roman upper case
+        /^[ivxlmcd]{1,2}\.[ \u00a0]/,  // Roman lower case
+        /^[a-z]{1,2}[\.\)][ \u00a0]/,  // Alphabetical a-z
+        /^[A-Z]{1,2}[\.\)][ \u00a0]/,  // Alphabetical A-Z
+        /^[0-9]+\.[ \u00a0]/,          // Numeric lists
+        /^[\u3007\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d]+\.[ \u00a0]/, // Japanese
+        /^[\u58f1\u5f10\u53c2\u56db\u4f0d\u516d\u4e03\u516b\u4e5d\u62fe]+\.[ \u00a0]/  // Chinese
+      ];
+
+      text = text.replace(/^[\u00a0 ]+/, '');
+
+      Tools.each(patterns, function (pattern) {
+        if (pattern.test(text)) {
+          found = true;
</ins><span class="cx" style="display: block; padding: 0 10px">           return false;
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      } else {
-        return false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      });
+
+      return found;
+    }
+
+    function isBulletList(text) {
+      return /^[\s\u00a0]*[\u2022\u00b7\u00a7\u25CF]\s*/.test(text);
+    }
+
+    /**
+     * Converts fake bullet and numbered lists to real semantic OL/UL.
+     *
+     * @param {tinymce.html.Node} node Root node to convert children of.
+     */
+    function convertFakeListsToProperLists(node) {
+      var currentListNode, prevListNode, lastLevel = 1;
+
+      function getText(node) {
+        var txt = '';
+
+        if (node.type === 3) {
+          return node.value;
+        }
+
+        if ((node = node.firstChild)) {
+          do {
+            txt += getText(node);
+          } while ((node = node.next));
+        }
+
+        return txt;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var setClipboardData = function (evt, data, fallback, done) {
-      if (setHtml5Clipboard(evt.clipboardData, data.html, data.text)) {
-        evt.preventDefault();
-        done();
-      } else {
-        fallback(data.html, done);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function trimListStart(node, regExp) {
+        if (node.type === 3) {
+          if (regExp.test(node.value)) {
+            node.value = node.value.replace(regExp, '');
+            return false;
+          }
+        }
+
+        if ((node = node.firstChild)) {
+          do {
+            if (!trimListStart(node, regExp)) {
+              return false;
+            }
+          } while ((node = node.next));
+        }
+
+        return true;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var fallback = function (editor) {
-      return function (html, done) {
-        var markedHtml = InternalHtml.mark(html);
-        var outer = editor.dom.create('div', { contenteditable: "false" });
-        var inner = editor.dom.create('div', { contenteditable: "true" }, markedHtml);
-        editor.dom.setStyles(outer, {
-          position: 'fixed',
-          left: '-3000px',
-          width: '1000px',
-          overflow: 'hidden'
-        });
-        outer.appendChild(inner);
-        editor.dom.add(editor.getBody(), outer);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function removeIgnoredNodes(node) {
+        if (node._listIgnore) {
+          node.remove();
+          return;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var range = editor.selection.getRng();
-        inner.focus();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if ((node = node.firstChild)) {
+          do {
+            removeIgnoredNodes(node);
+          } while ((node = node.next));
+        }
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var offscreenRange = editor.dom.createRng();
-        offscreenRange.selectNodeContents(inner);
-        editor.selection.setRng(offscreenRange);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function convertParagraphToLi(paragraphNode, listName, start) {
+        var level = paragraphNode._listLevel || lastLevel;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        setTimeout(function () {
-          outer.parentNode.removeChild(outer);
-          editor.selection.setRng(range);
-          done();
-        }, 0);
-      };
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Handle list nesting
+        if (level != lastLevel) {
+          if (level < lastLevel) {
+            // Move to parent list
+            if (currentListNode) {
+              currentListNode = currentListNode.parent.parent;
+            }
+          } else {
+            // Create new list
+            prevListNode = currentListNode;
+            currentListNode = null;
+          }
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var getData = function (editor) {
-      return {
-        html: editor.selection.getContent({ contextual: true }),
-        text: editor.selection.getContent({ format: 'text' })
-      };
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (!currentListNode || currentListNode.name != listName) {
+          prevListNode = prevListNode || currentListNode;
+          currentListNode = new Node(listName, 1);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var cut = function (editor) {
-      return function (evt) {
-        if (editor.selection.isCollapsed() === false) {
-          setClipboardData(evt, getData(editor), fallback(editor), function () {
-            editor.execCommand('Delete');
-          });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (start > 1) {
+            currentListNode.attr('start', '' + start);
+          }
+
+          paragraphNode.wrap(currentListNode);
+        } else {
+          currentListNode.append(paragraphNode);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      };
-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var copy = function (editor) {
-      return function (evt) {
-        if (editor.selection.isCollapsed() === false) {
-          setClipboardData(evt, getData(editor), fallback(editor), noop);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        paragraphNode.name = 'li';
+
+        // Append list to previous list if it exists
+        if (level > lastLevel && prevListNode) {
+          prevListNode.lastChild.append(currentListNode);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      };
-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var register = function (editor) {
-      editor.on('cut', cut(editor));
-      editor.on('copy', copy(editor));
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        lastLevel = level;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return {
-      register: register
-    };
-  }
-);
-/**
- * ResolveGlobal.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Remove start of list item "1. " or "&middot; " etc
+        removeIgnoredNodes(paragraphNode);
+        trimListStart(paragraphNode, /^\u00a0+/);
+        trimListStart(paragraphNode, /^\s*([\u2022\u00b7\u00a7\u25CF]|\w+\.)/);
+        trimListStart(paragraphNode, /^\u00a0+/);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-define(
-  'tinymce.core.html.Entities',
-  [
-    'global!tinymce.util.Tools.resolve'
-  ],
-  function (resolve) {
-    return resolve('tinymce.html.Entities');
-  }
-);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Build a list of all root level elements before we start
+      // altering them in the loop below.
+      var elements = [], child = node.firstChild;
+      while (typeof child !== 'undefined' && child !== null) {
+        elements.push(child);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * Newlines.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        child = child.walk();
+        if (child !== null) {
+          while (typeof child !== 'undefined' && child.parent !== node) {
+            child = child.walk();
+          }
+        }
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * Newlines class contains utilities to convert newlines (\n or \r\n) tp BRs or to a combination of the specified block element and BRs
- *
- * @class tinymce.Newlines
- * @private
- */
-define(
-  'tinymce.plugins.paste.core.Newlines',
-  [
-    'tinymce.core.html.Entities'
-  ],
-  function (Entities) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      for (var i = 0; i < elements.length; i++) {
+        node = elements[i];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var isPlainText = function (text) {
-      // so basically any tag that is not one of the "p, div, br", or is one of them, but is followed
-      // by some additional characters qualifies the text as not a plain text (having some HTML tags)
-      return !/<(?:(?!\/?(?:div|p|br))[^>]*|(?:div|p|br)\s+\w[^>]+)>/.test(text);
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (node.name == 'p' && node.firstChild) {
+          // Find first text node in paragraph
+          var nodeText = getText(node);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Detect unordered lists look for bullets
+          if (isBulletList(nodeText)) {
+            convertParagraphToLi(node, 'ul');
+            continue;
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var toBRs = function (text) {
-      return text.replace(/\r?\n/g, '<br>');
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Detect ordered lists 1., a. or ixv.
+          if (isNumericList(nodeText)) {
+            // Parse OL start number
+            var matches = /([0-9]+)\./.exec(nodeText);
+            var start = 1;
+            if (matches) {
+              start = parseInt(matches[1], 10);
+            }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            convertParagraphToLi(node, 'ol', start);
+            continue;
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var openContainer = function (rootTag, rootAttrs) {
-      var key, attrs = [];
-      var tag = '<' + rootTag;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Convert paragraphs marked as lists but doesn't look like anything
+          if (node._listLevel) {
+            convertParagraphToLi(node, 'ul', 1);
+            continue;
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (typeof rootAttrs === 'object') {
-        for (key in rootAttrs) {
-          if (rootAttrs.hasOwnProperty(key)) {
-            attrs.push(key + '="' + Entities.encodeAllRaw(rootAttrs[key]) + '"');
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          currentListNode = null;
+        } else {
+          // If the root level element isn't a p tag which can be
+          // processed by convertParagraphToLi, it interrupts the
+          // lists, causing a new list to start instead of having
+          // elements from the next list inserted above this tag.
+          prevListNode = currentListNode;
+          currentListNode = null;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (attrs.length) {
-          tag += ' ' + attrs.join(' ');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function filterStyles(editor, validStyles, node, styleValue) {
+      var outputStyles = {}, matches, styles = editor.dom.parseStyle(styleValue);
+
+      Tools.each(styles, function (value, name) {
+        // Convert various MS styles to W3C styles
+        switch (name) {
+          case 'mso-list':
+            // Parse out list indent level for lists
+            matches = /\w+ \w+([0-9]+)/i.exec(styleValue);
+            if (matches) {
+              node._listLevel = parseInt(matches[1], 10);
+            }
+
+            // Remove these nodes <span style="mso-list:Ignore">o</span>
+            // Since the span gets removed we mark the text node and the span
+            if (/Ignore/i.test(value) && node.firstChild) {
+              node._listIgnore = true;
+              node.firstChild._listIgnore = true;
+            }
+
+            break;
+
+          case "horiz-align":
+            name = "text-align";
+            break;
+
+          case "vert-align":
+            name = "vertical-align";
+            break;
+
+          case "font-color":
+          case "mso-foreground":
+            name = "color";
+            break;
+
+          case "mso-background":
+          case "mso-highlight":
+            name = "background";
+            break;
+
+          case "font-weight":
+          case "font-style":
+            if (value != "normal") {
+              outputStyles[name] = value;
+            }
+            return;
+
+          case "mso-element":
+            // Remove track changes code
+            if (/^(comment|comment-list)$/i.test(value)) {
+              node.remove();
+              return;
+            }
+
+            break;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+        if (name.indexOf('mso-comment') === 0) {
+          node.remove();
+          return;
+        }
+
+        // Never allow mso- prefixed names
+        if (name.indexOf('mso-') === 0) {
+          return;
+        }
+
+        // Output only valid styles
+        if (editor.settings.paste_retain_style_properties == "all" || (validStyles && validStyles[name])) {
+          outputStyles[name] = value;
+        }
+      });
+
+      // Convert bold style to "b" element
+      if (/(bold)/i.test(outputStyles["font-weight"])) {
+        delete outputStyles["font-weight"];
+        node.wrap(new Node("b", 1));
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return tag + '>';
-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Convert italic style to "i" element
+      if (/(italic)/i.test(outputStyles["font-style"])) {
+        delete outputStyles["font-style"];
+        node.wrap(new Node("i", 1));
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var toBlockElements = function (text, rootTag, rootAttrs) {
-      var pieces = text.split(/\r?\n/);
-      var i = 0, len = pieces.length;
-      var stack = [];
-      var blocks = [];
-      var tagOpen = openContainer(rootTag, rootAttrs);
-      var tagClose = '</' + rootTag + '>';
-      var isLast, newlineFollows, isSingleNewline;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Serialize the styles and see if there is something left to keep
+      outputStyles = editor.dom.serializeStyle(outputStyles, node.name);
+      if (outputStyles) {
+        return outputStyles;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // if single-line text then nothing to do
-      if (pieces.length === 1) {
-        return text;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return null;
+    }
+
+    var filterWordContent = function (editor, content) {
+      var retainStyleProperties, validStyles;
+
+      retainStyleProperties = editor.settings.paste_retain_style_properties;
+      if (retainStyleProperties) {
+        validStyles = Tools.makeMap(retainStyleProperties.split(/[, ]/));
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      for (; i < len; i++) {
-        isLast = i === len - 1;
-        newlineFollows = !isLast && !pieces[i + 1];
-        isSingleNewline = !pieces[i] && !stack.length;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Remove basic Word junk
+      content = Utils.filter(content, [
+        // Remove apple new line markers
+        /<br class="?Apple-interchange-newline"?>/gi,
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        stack.push(pieces[i] ? pieces[i] : '&nbsp;');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Remove google docs internal guid markers
+        /<b[^>]+id="?docs-internal-[^>]*>/gi,
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (isLast || newlineFollows || isSingleNewline) {
-          blocks.push(stack.join('<br>'));
-          stack = [];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Word comments like conditional comments etc
+        /<!--[\s\S]+?-->/gi,
+
+        // Remove comments, scripts (e.g., msoShowComment), XML tag, VML content,
+        // MS Office namespaced tags, and a few other tags
+        /<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|img|meta|link|style|\w:\w+)(?=[\s\/>]))[^>]*>/gi,
+
+        // Convert <s> into <strike> for line-though
+        [/<(\/?)s>/gi, "<$1strike>"],
+
+        // Replace nsbp entites to char since it's easier to handle
+        [/&nbsp;/gi, "\u00a0"],
+
+        // Convert <span style="mso-spacerun:yes">___</span> to string of alternating
+        // breaking/non-breaking spaces of same length
+        [/<span\s+style\s*=\s*"\s*mso-spacerun\s*:\s*yes\s*;?\s*"\s*>([\s\u00a0]*)<\/span>/gi,
+          function (str, spaces) {
+            return (spaces.length > 0) ?
+              spaces.replace(/./, " ").slice(Math.floor(spaces.length / 2)).split("").join("\u00a0") : "";
+          }
+        ]
+      ]);
+
+      var validElements = editor.settings.paste_word_valid_elements;
+      if (!validElements) {
+        validElements = (
+          '-strong/b,-em/i,-u,-span,-p,-ol,-ul,-li,-h1,-h2,-h3,-h4,-h5,-h6,' +
+          '-p/div,-a[href|name],sub,sup,strike,br,del,table[width],tr,' +
+          'td[colspan|rowspan|width],th[colspan|rowspan|width],thead,tfoot,tbody'
+        );
+      }
+
+      // Setup strict schema
+      var schema = new Schema({
+        valid_elements: validElements,
+        valid_children: '-li[p]'
+      });
+
+      // Add style/class attribute to all element rules since the user might have removed them from
+      // paste_word_valid_elements config option and we need to check them for properties
+      Tools.each(schema.elements, function (rule) {
+        /*eslint dot-notation:0*/
+        if (!rule.attributes["class"]) {
+          rule.attributes["class"] = {};
+          rule.attributesOrder.push("class");
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (newlineFollows) {
-          i++; // extra progress for extra newline
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (!rule.attributes.style) {
+          rule.attributes.style = {};
+          rule.attributesOrder.push("style");
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      });
+
+      // Parse HTML into DOM structure
+      var domParser = new DomParser({}, schema);
+
+      // Filter styles to remove "mso" specific styles and convert some of them
+      domParser.addAttributeFilter('style', function (nodes) {
+        var i = nodes.length, node;
+
+        while (i--) {
+          node = nodes[i];
+          node.attr('style', filterStyles(editor, validStyles, node, node.attr('style')));
+
+          // Remove pointess spans
+          if (node.name == 'span' && node.parent && !node.attributes.length) {
+            node.unwrap();
+          }
+        }
+      });
+
+      // Check the class attribute for comments or del items and remove those
+      domParser.addAttributeFilter('class', function (nodes) {
+        var i = nodes.length, node, className;
+
+        while (i--) {
+          node = nodes[i];
+
+          className = node.attr('class');
+          if (/^(MsoCommentReference|MsoCommentText|msoDel)$/i.test(className)) {
+            node.remove();
+          }
+
+          node.attr('class', null);
+        }
+      });
+
+      // Remove all del elements since we don't want the track changes code in the editor
+      domParser.addNodeFilter('del', function (nodes) {
+        var i = nodes.length;
+
+        while (i--) {
+          nodes[i].remove();
+        }
+      });
+
+      // Keep some of the links and anchors
+      domParser.addNodeFilter('a', function (nodes) {
+        var i = nodes.length, node, href, name;
+
+        while (i--) {
+          node = nodes[i];
+          href = node.attr('href');
+          name = node.attr('name');
+
+          if (href && href.indexOf('#_msocom_') != -1) {
+            node.remove();
+            continue;
+          }
+
+          if (href && href.indexOf('file://') === 0) {
+            href = href.split('#')[1];
+            if (href) {
+              href = '#' + href;
+            }
+          }
+
+          if (!href && !name) {
+            node.unwrap();
+          } else {
+            // Remove all named anchors that aren't specific to TOC, Footnotes or Endnotes
+            if (name && !/^_?(?:toc|edn|ftn)/i.test(name)) {
+              node.unwrap();
+              continue;
+            }
+
+            node.attr({
+              href: href,
+              name: name
+            });
+          }
+        }
+      });
+
+      // Parse into DOM structure
+      var rootNode = domParser.parse(content);
+
+      // Process DOM
+      if (editor.settings.paste_convert_word_fake_lists !== false) {
+        convertFakeListsToProperLists(rootNode);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return blocks.length === 1 ? blocks[0] : tagOpen + blocks.join(tagClose + tagOpen) + tagClose;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Serialize DOM back to HTML
+      content = new Serializer({
+        validate: editor.settings.validate
+      }, schema).serialize(rootNode);
+
+      return content;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var preProcess = function (editor, content) {
+      return editor.settings.paste_enable_default_filters === false ? content : filterWordContent(editor, content);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var convert = function (text, rootTag, rootAttrs) {
-      return rootTag ? toBlockElements(text, rootTag, rootAttrs) : toBRs(text);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return {
+      preProcess: preProcess,
+      isWordContent: isWordContent
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  }
+);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/**
+ * ProcessFilters.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+define(
+  'tinymce.plugins.paste.core.ProcessFilters',
+  [
+    'tinymce.plugins.paste.api.Events',
+    'tinymce.plugins.paste.core.WordFilter'
+  ],
+  function (Events, WordFilter) {
+    var processResult = function (content, cancelled) {
+      return { content: content, cancelled: cancelled };
+    };
+
+    var postProcessFilter = function (editor, html, internal, isWordHtml) {
+      var tempBody = editor.dom.create('div', { style: 'display:none' }, html);
+      var postProcessArgs = Events.firePastePostProcess(editor, tempBody, internal, isWordHtml);
+      return processResult(postProcessArgs.node.innerHTML, postProcessArgs.isDefaultPrevented());
+    };
+
+    var filterContent = function (editor, content, internal, isWordHtml) {
+      var preProcessArgs = Events.firePastePreProcess(editor, content, internal, isWordHtml);
+
+      if (editor.hasEventListeners('PastePostProcess') && !preProcessArgs.isDefaultPrevented()) {
+        return postProcessFilter(editor, preProcessArgs.content, internal, isWordHtml);
+      } else {
+        return processResult(preProcessArgs.content, preProcessArgs.isDefaultPrevented());
+      }
+    };
+
+    var process = function (editor, html, internal) {
+      var isWordHtml = WordFilter.isWordContent(html);
+      var content = isWordHtml ? WordFilter.preProcess(editor, html) : html;
+
+      return filterContent(editor, content, internal, isWordHtml);
+    };
+
</ins><span class="cx" style="display: block; padding: 0 10px">     return {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      isPlainText: isPlainText,
-      convert: convert,
-      toBRs: toBRs,
-      toBlockElements: toBlockElements
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      process: process
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px">  * SmartPaste.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -804,16 +1546,18 @@
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.Delay',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.Tools',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.VK',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.plugins.paste.core.CutCopy',
</del><span class="cx" style="display: block; padding: 0 10px">     'tinymce.plugins.paste.core.InternalHtml',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.plugins.paste.core.Newlines',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.plugins.paste.core.PasteBin',
+    'tinymce.plugins.paste.core.ProcessFilters',
</ins><span class="cx" style="display: block; padding: 0 10px">     'tinymce.plugins.paste.core.SmartPaste',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.plugins.paste.core.Utils'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (RangeUtils, Env, Delay, Tools, VK, CutCopy, InternalHtml, Newlines, SmartPaste, Utils) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (RangeUtils, Env, Delay, Tools, VK, InternalHtml, Newlines, PasteBin, ProcessFilters, SmartPaste, Utils) {
</ins><span class="cx" style="display: block; padding: 0 10px">     return function (editor) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var self = this, pasteBinElm, lastRng, keyboardPasteTimeStamp = 0, draggingInternally = false;
-      var pasteBinDefaultContent = '%MCEPASTEBIN%', keyboardPastePlainTextState;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var self = this, keyboardPasteTimeStamp = 0, draggingInternally = false;
+      var pasteBin = new PasteBin(editor);
+      var keyboardPastePlainTextState;
</ins><span class="cx" style="display: block; padding: 0 10px">       var mceInternalUrlPrefix = 'data:text/mce-internal,';
</span><span class="cx" style="display: block; padding: 0 10px">       var uniqueId = Utils.createIdGenerator("mceclip");
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -826,30 +1570,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">        * @param {Boolean?} internalFlag Optional true/false flag if the contents is internal or external.
</span><span class="cx" style="display: block; padding: 0 10px">        */
</span><span class="cx" style="display: block; padding: 0 10px">       function pasteHtml(html, internalFlag) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var args, dom = editor.dom, internal;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var internal = internalFlag ? internalFlag : InternalHtml.isMarked(html);
+        var args = ProcessFilters.process(editor, InternalHtml.unmark(html), internal);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        internal = internalFlag || InternalHtml.isMarked(html);
-        html = InternalHtml.unmark(html);
-
-        args = editor.fire('BeforePastePreProcess', { content: html, internal: internal }); // Internal event used by Quirks
-        args = editor.fire('PastePreProcess', args);
-        html = args.content;
-
-        if (!args.isDefaultPrevented()) {
-          // User has bound PastePostProcess events then we need to pass it through a DOM node
-          // This is not ideal but we don't want to let the browser mess up the HTML for example
-          // some browsers add &nbsp; to P tags etc
-          if (editor.hasEventListeners('PastePostProcess') && !args.isDefaultPrevented()) {
-            // We need to attach the element to the DOM so Sizzle selectors work on the contents
-            var tempBody = dom.add(editor.getBody(), 'div', { style: 'display:none' }, html);
-            args = editor.fire('PastePostProcess', { node: tempBody, internal: internal });
-            dom.remove(tempBody);
-            html = args.node.innerHTML;
-          }
-
-          if (!args.isDefaultPrevented()) {
-            SmartPaste.insertContent(editor, html);
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (args.cancelled === false) {
+          SmartPaste.insertContent(editor, args.content);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -866,178 +1591,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">         pasteHtml(text, false);
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Creates a paste bin element as close as possible to the current caret location and places the focus inside that element
-       * so that when the real paste event occurs the contents gets inserted into this element
-       * instead of the current editor selection element.
-       */
-      function createPasteBin() {
-        var dom = editor.dom, body = editor.getBody();
-        var viewport = editor.dom.getViewPort(editor.getWin()), scrollTop = viewport.y, top = 20;
-        var scrollContainer;
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        lastRng = editor.selection.getRng();
-
-        if (editor.inline) {
-          scrollContainer = editor.selection.getScrollContainer();
-
-          // Can't always rely on scrollTop returning a useful value.
-          // It returns 0 if the browser doesn't support scrollTop for the element or is non-scrollable
-          if (scrollContainer && scrollContainer.scrollTop > 0) {
-            scrollTop = scrollContainer.scrollTop;
-          }
-        }
-
-        /**
-         * Returns the rect of the current caret if the caret is in an empty block before a
-         * BR we insert a temporary invisible character that we get the rect this way we always get a proper rect.
-         *
-         * TODO: This might be useful in core.
-         */
-        function getCaretRect(rng) {
-          var rects, textNode, node, container = rng.startContainer;
-
-          rects = rng.getClientRects();
-          if (rects.length) {
-            return rects[0];
-          }
-
-          if (!rng.collapsed || container.nodeType != 1) {
-            return;
-          }
-
-          node = container.childNodes[lastRng.startOffset];
-
-          // Skip empty whitespace nodes
-          while (node && node.nodeType == 3 && !node.data.length) {
-            node = node.nextSibling;
-          }
-
-          if (!node) {
-            return;
-          }
-
-          // Check if the location is |<br>
-          // TODO: Might need to expand this to say |<table>
-          if (node.tagName == 'BR') {
-            textNode = dom.doc.createTextNode('\uFEFF');
-            node.parentNode.insertBefore(textNode, node);
-
-            rng = dom.createRng();
-            rng.setStartBefore(textNode);
-            rng.setEndAfter(textNode);
-
-            rects = rng.getClientRects();
-            dom.remove(textNode);
-          }
-
-          if (rects.length) {
-            return rects[0];
-          }
-        }
-
-        // Calculate top cordinate this is needed to avoid scrolling to top of document
-        // We want the paste bin to be as close to the caret as possible to avoid scrolling
-        if (lastRng.getClientRects) {
-          var rect = getCaretRect(lastRng);
-
-          if (rect) {
-            // Client rects gets us closes to the actual
-            // caret location in for example a wrapped paragraph block
-            top = scrollTop + (rect.top - dom.getPos(body).y);
-          } else {
-            top = scrollTop;
-
-            // Check if we can find a closer location by checking the range element
-            var container = lastRng.startContainer;
-            if (container) {
-              if (container.nodeType == 3 && container.parentNode != body) {
-                container = container.parentNode;
-              }
-
-              if (container.nodeType == 1) {
-                top = dom.getPos(container, scrollContainer || body).y;
-              }
-            }
-          }
-        }
-
-        // Create a pastebin
-        pasteBinElm = dom.add(editor.getBody(), 'div', {
-          id: "mcepastebin",
-          contentEditable: true,
-          "data-mce-bogus": "all",
-          style: 'position: absolute; top: ' + top + 'px;' +
-          'width: 10px; height: 10px; overflow: hidden; opacity: 0'
-        }, pasteBinDefaultContent);
-
-        // Move paste bin out of sight since the controlSelection rect gets displayed otherwise on IE and Gecko
-        if (Env.ie || Env.gecko) {
-          dom.setStyle(pasteBinElm, 'left', dom.getStyle(body, 'direction', true) == 'rtl' ? 0xFFFF : -0xFFFF);
-        }
-
-        // Prevent focus events from bubbeling fixed FocusManager issues
-        dom.bind(pasteBinElm, 'beforedeactivate focusin focusout', function (e) {
-          e.stopPropagation();
-        });
-
-        pasteBinElm.focus();
-        editor.selection.select(pasteBinElm, true);
-      }
-
</del><span class="cx" style="display: block; padding: 0 10px">       /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * Removes the paste bin if it exists.
-       */
-      function removePasteBin() {
-        if (pasteBinElm) {
-          var pasteBinClone;
-
-          // WebKit/Blink might clone the div so
-          // lets make sure we remove all clones
-          // TODO: Man o man is this ugly. WebKit is the new IE! Remove this if they ever fix it!
-          while ((pasteBinClone = editor.dom.get('mcepastebin'))) {
-            editor.dom.remove(pasteBinClone);
-            editor.dom.unbind(pasteBinClone);
-          }
-
-          if (lastRng) {
-            editor.selection.setRng(lastRng);
-          }
-        }
-
-        pasteBinElm = lastRng = null;
-      }
-
-      /**
-       * Returns the contents of the paste bin as a HTML string.
-       *
-       * @return {String} Get the contents of the paste bin.
-       */
-      function getPasteBinHtml() {
-        var html = '', pasteBinClones, i, clone, cloneHtml;
-
-        // Since WebKit/Chrome might clone the paste bin when pasting
-        // for example: <img style="float: right"> we need to check if any of them contains some useful html.
-        // TODO: Man o man is this ugly. WebKit is the new IE! Remove this if they ever fix it!
-        pasteBinClones = editor.dom.select('div[id=mcepastebin]');
-        for (i = 0; i < pasteBinClones.length; i++) {
-          clone = pasteBinClones[i];
-
-          // Pasting plain text produces pastebins in pastebinds makes sence right!?
-          if (clone.firstChild && clone.firstChild.id == 'mcepastebin') {
-            clone = clone.firstChild;
-          }
-
-          cloneHtml = clone.innerHTML;
-          if (html != pasteBinDefaultContent) {
-            html += cloneHtml;
-          }
-        }
-
-        return html;
-      }
-
-      /**
</del><span class="cx" style="display: block; padding: 0 10px">        * Gets various content types out of a datatransfer object.
</span><span class="cx" style="display: block; padding: 0 10px">        *
</span><span class="cx" style="display: block; padding: 0 10px">        * @param {DataTransfer} dataTransfer Event fired on paste.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1060,7 +1615,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">           if (dataTransfer.types) {
</span><span class="cx" style="display: block; padding: 0 10px">             for (var i = 0; i < dataTransfer.types.length; i++) {
</span><span class="cx" style="display: block; padding: 0 10px">               var contentType = dataTransfer.types[i];
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              items[contentType] = dataTransfer.getData(contentType);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              try { // IE11 throws exception when contentType is Files (type is present but data cannot be retrieved via getData())
+                items[contentType] = dataTransfer.getData(contentType);
+              } catch (ex) {
+                items[contentType] = ""; // useless in general, but for consistency across browsers
+              }
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1101,6 +1660,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">         return settings.images_dataimg_filter ? settings.images_dataimg_filter(imgElm) : true;
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function extractFilename(str) {
+        var m = str.match(/([\s\S]+?)\.(?:jpeg|jpg|png|gif)$/i);
+        return m ? editor.dom.encode(m[1]) : null;
+      }
+
</ins><span class="cx" style="display: block; padding: 0 10px">       function pasteImage(rng, reader, blob) {
</span><span class="cx" style="display: block; padding: 0 10px">         if (rng) {
</span><span class="cx" style="display: block; padding: 0 10px">           editor.selection.setRng(rng);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1109,8 +1673,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">         var dataUri = reader.result;
</span><span class="cx" style="display: block; padding: 0 10px">         var base64 = getBase64FromUri(dataUri);
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var id = uniqueId();
+        var name = editor.settings.images_reuse_filename && blob.name ? extractFilename(blob.name) : id;
+        var img = new Image();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var img = new Image();
</del><span class="cx" style="display: block; padding: 0 10px">         img.src = dataUri;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">         // TODO: Move the bulk of the cache logic to EditorUpload
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1123,7 +1689,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">           });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">           if (!existingBlobInfo) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            blobInfo = blobCache.create(uniqueId(), blob, base64);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            blobInfo = blobCache.create(id, blob, base64, name);
</ins><span class="cx" style="display: block; padding: 0 10px">             blobCache.add(blobInfo);
</span><span class="cx" style="display: block; padding: 0 10px">           } else {
</span><span class="cx" style="display: block; padding: 0 10px">             blobInfo = existingBlobInfo;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1203,7 +1769,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">           function removePasteBinOnKeyUp(e) {
</span><span class="cx" style="display: block; padding: 0 10px">             // Ctrl+V or Shift+Insert
</span><span class="cx" style="display: block; padding: 0 10px">             if (isKeyboardPasteEvent(e) && !e.isDefaultPrevented()) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              removePasteBin();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              pasteBin.remove();
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1230,8 +1796,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">               return;
</span><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            removePasteBin();
-            createPasteBin();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            pasteBin.remove();
+            pasteBin.create();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">             // Remove pastebin if we get a keyup and no paste event
</span><span class="cx" style="display: block; padding: 0 10px">             // For example pasting a file in IE 11 will not produce a paste event
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1249,35 +1815,28 @@
</span><span class="cx" style="display: block; padding: 0 10px">           if (hasContentType(clipboardContent, 'text/html')) {
</span><span class="cx" style="display: block; padding: 0 10px">             content = clipboardContent['text/html'];
</span><span class="cx" style="display: block; padding: 0 10px">           } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            content = getPasteBinHtml();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            content = pasteBin.getHtml();
+            internal = internal ? internal : InternalHtml.isMarked(content);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">             // If paste bin is empty try using plain text mode
</span><span class="cx" style="display: block; padding: 0 10px">             // since that is better than nothing right
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (content == pasteBinDefaultContent) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            if (pasteBin.isDefaultContent(content)) {
</ins><span class="cx" style="display: block; padding: 0 10px">               plainTextMode = true;
</span><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">           content = Utils.trimHtml(content);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // WebKit has a nice bug where it clones the paste bin if you paste from for example notepad
-          // so we need to force plain text mode in this case
-          if (pasteBinElm && pasteBinElm.firstChild && pasteBinElm.firstChild.id === 'mcepastebin') {
-            plainTextMode = true;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          pasteBin.remove();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          removePasteBin();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          isPlainTextHtml = (internal === false && Newlines.isPlainText(content));
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          isPlainTextHtml = internal === false && Newlines.isPlainText(content);
-
</del><span class="cx" style="display: block; padding: 0 10px">           // If we got nothing from clipboard API and pastebin or the content is a plain text (with only
</span><span class="cx" style="display: block; padding: 0 10px">           // some BRs, Ps or DIVs as newlines) then we fallback to plain/text
</span><span class="cx" style="display: block; padding: 0 10px">           if (!content.length || isPlainTextHtml) {
</span><span class="cx" style="display: block; padding: 0 10px">             plainTextMode = true;
</span><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-
</del><span class="cx" style="display: block; padding: 0 10px">           // Grab plain text from Clipboard API or convert existing HTML to plain text
</span><span class="cx" style="display: block; padding: 0 10px">           if (plainTextMode) {
</span><span class="cx" style="display: block; padding: 0 10px">             // Use plain text contents from Clipboard API unless the HTML contains paragraphs then
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1291,7 +1850,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">           // If the content is the paste bin default HTML then it was
</span><span class="cx" style="display: block; padding: 0 10px">           // impossible to get the cliboard data out.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (content == pasteBinDefaultContent) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (pasteBin.isDefaultContent(content)) {
</ins><span class="cx" style="display: block; padding: 0 10px">             if (!isKeyBoardPaste) {
</span><span class="cx" style="display: block; padding: 0 10px">               editor.windowManager.alert('Please use Ctrl+V/Cmd+V keyboard shortcuts to paste contents.');
</span><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1307,7 +1866,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">         var getLastRng = function () {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return lastRng || editor.selection.getRng();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          return pasteBin.getLastRng() || editor.selection.getRng();
</ins><span class="cx" style="display: block; padding: 0 10px">         };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">         editor.on('paste', function (e) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1323,12 +1882,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">           keyboardPastePlainTextState = false;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">           if (e.isDefaultPrevented() || isBrokenAndroidClipboardEvent(e)) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            removePasteBin();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            pasteBin.remove();
</ins><span class="cx" style="display: block; padding: 0 10px">             return;
</span><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">           if (!hasHtmlOrText(clipboardContent) && pasteImageData(e, getLastRng())) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            removePasteBin();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            pasteBin.remove();
</ins><span class="cx" style="display: block; padding: 0 10px">             return;
</span><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1339,19 +1898,25 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">           // Try IE only method if paste isn't a keyboard paste
</span><span class="cx" style="display: block; padding: 0 10px">           if (Env.ie && (!isKeyBoardPaste || e.ieFake) && !hasContentType(clipboardContent, 'text/html')) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            createPasteBin();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            pasteBin.create();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            editor.dom.bind(pasteBinElm, 'paste', function (e) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            editor.dom.bind(pasteBin.getEl(), 'paste', function (e) {
</ins><span class="cx" style="display: block; padding: 0 10px">               e.stopPropagation();
</span><span class="cx" style="display: block; padding: 0 10px">             });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">             editor.getDoc().execCommand('Paste', false, null);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            clipboardContent["text/html"] = getPasteBinHtml();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            clipboardContent["text/html"] = pasteBin.getHtml();
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">           // If clipboard API has HTML then use that directly
</span><span class="cx" style="display: block; padding: 0 10px">           if (hasContentType(clipboardContent, 'text/html')) {
</span><span class="cx" style="display: block; padding: 0 10px">             e.preventDefault();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+            // if clipboard lacks internal mime type, inspect html for internal markings
+            if (!internal) {
+              internal = InternalHtml.isMarked(clipboardContent['text/html']);
+            }
+
</ins><span class="cx" style="display: block; padding: 0 10px">             insertClipboardContent(clipboardContent, isKeyBoardPaste, plainTextMode, internal);
</span><span class="cx" style="display: block; padding: 0 10px">           } else {
</span><span class="cx" style="display: block; padding: 0 10px">             Delay.setEditorTimeout(editor, function () {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1473,7 +2038,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * ResolveGlobal.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * CutCopy.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1483,540 +2048,118 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.html.Serializer',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.plugins.paste.core.CutCopy',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'global!tinymce.util.Tools.resolve'
-  ],
-  function (resolve) {
-    return resolve('tinymce.html.Serializer');
-  }
-);
-
-/**
- * ResolveGlobal.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-define(
-  'tinymce.core.html.Node',
-  [
-    'global!tinymce.util.Tools.resolve'
-  ],
-  function (resolve) {
-    return resolve('tinymce.html.Node');
-  }
-);
-
-/**
- * WordFilter.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * This class parses word HTML into proper TinyMCE markup.
- *
- * @class tinymce.pasteplugin.WordFilter
- * @private
- */
-define(
-  'tinymce.plugins.paste.core.WordFilter',
-  [
-    'tinymce.core.util.Tools',
-    'tinymce.core.html.DomParser',
-    'tinymce.core.html.Schema',
-    'tinymce.core.html.Serializer',
-    'tinymce.core.html.Node',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.Env',
+    'tinymce.plugins.paste.core.InternalHtml',
</ins><span class="cx" style="display: block; padding: 0 10px">     'tinymce.plugins.paste.core.Utils'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Tools, DomParser, Schema, Serializer, Node, Utils) {
-    /**
-     * Checks if the specified content is from any of the following sources: MS Word/Office 365/Google docs.
-     */
-    function isWordContent(content) {
-      return (
-        (/<font face="Times New Roman"|class="?Mso|style="[^"]*\bmso-|style='[^'']*\bmso-|w:WordDocument/i).test(content) ||
-        (/class="OutlineElement/).test(content) ||
-        (/id="?docs\-internal\-guid\-/.test(content))
-      );
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Env, InternalHtml, Utils) {
+    var noop = function () {
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    /**
-     * Checks if the specified text starts with "1. " or "a. " etc.
-     */
-    function isNumericList(text) {
-      var found, patterns;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var hasWorkingClipboardApi = function (clipboardData) {
+      // iOS supports the clipboardData API but it doesn't do anything for cut operations
+      // Edge 15 has a broken HTML Clipboard API see https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/11780845/
+      return Env.iOS === false && clipboardData !== undefined && typeof clipboardData.setData === 'function' && Utils.isMsEdge() !== true;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      patterns = [
-        /^[IVXLMCD]{1,2}\.[ \u00a0]/,  // Roman upper case
-        /^[ivxlmcd]{1,2}\.[ \u00a0]/,  // Roman lower case
-        /^[a-z]{1,2}[\.\)][ \u00a0]/,  // Alphabetical a-z
-        /^[A-Z]{1,2}[\.\)][ \u00a0]/,  // Alphabetical A-Z
-        /^[0-9]+\.[ \u00a0]/,          // Numeric lists
-        /^[\u3007\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d]+\.[ \u00a0]/, // Japanese
-        /^[\u58f1\u5f10\u53c2\u56db\u4f0d\u516d\u4e03\u516b\u4e5d\u62fe]+\.[ \u00a0]/  // Chinese
-      ];
-
-      text = text.replace(/^[\u00a0 ]+/, '');
-
-      Tools.each(patterns, function (pattern) {
-        if (pattern.test(text)) {
-          found = true;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var setHtml5Clipboard = function (clipboardData, html, text) {
+      if (hasWorkingClipboardApi(clipboardData)) {
+        try {
+          clipboardData.clearData();
+          clipboardData.setData('text/html', html);
+          clipboardData.setData('text/plain', text);
+          clipboardData.setData(InternalHtml.internalHtmlMime(), html);
+          return true;
+        } catch (e) {
</ins><span class="cx" style="display: block; padding: 0 10px">           return false;
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      } else {
+        return false;
+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return found;
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var setClipboardData = function (evt, data, fallback, done) {
+      if (setHtml5Clipboard(evt.clipboardData, data.html, data.text)) {
+        evt.preventDefault();
+        done();
+      } else {
+        fallback(data.html, done);
+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function isBulletList(text) {
-      return /^[\s\u00a0]*[\u2022\u00b7\u00a7\u25CF]\s*/.test(text);
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var fallback = function (editor) {
+      return function (html, done) {
+        var markedHtml = InternalHtml.mark(html);
+        var outer = editor.dom.create('div', {
+          contenteditable: "false",
+          "data-mce-bogus": "all"
+        });
+        var inner = editor.dom.create('div', { contenteditable: "true" }, markedHtml);
+        editor.dom.setStyles(outer, {
+          position: 'fixed',
+          left: '-3000px',
+          width: '1000px',
+          overflow: 'hidden'
+        });
+        outer.appendChild(inner);
+        editor.dom.add(editor.getBody(), outer);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function WordFilter(editor) {
-      var settings = editor.settings;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var range = editor.selection.getRng();
+        inner.focus();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      editor.on('BeforePastePreProcess', function (e) {
-        var content = e.content, retainStyleProperties, validStyles;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var offscreenRange = editor.dom.createRng();
+        offscreenRange.selectNodeContents(inner);
+        editor.selection.setRng(offscreenRange);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Remove google docs internal guid markers
-        content = content.replace(/<b[^>]+id="?docs-internal-[^>]*>/gi, '');
-        content = content.replace(/<br class="?Apple-interchange-newline"?>/gi, '');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        setTimeout(function () {
+          outer.parentNode.removeChild(outer);
+          editor.selection.setRng(range);
+          done();
+        }, 0);
+      };
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        retainStyleProperties = settings.paste_retain_style_properties;
-        if (retainStyleProperties) {
-          validStyles = Tools.makeMap(retainStyleProperties.split(/[, ]/));
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var getData = function (editor) {
+      return {
+        html: editor.selection.getContent({ contextual: true }),
+        text: editor.selection.getContent({ format: 'text' })
+      };
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        /**
-         * Converts fake bullet and numbered lists to real semantic OL/UL.
-         *
-         * @param {tinymce.html.Node} node Root node to convert children of.
-         */
-        function convertFakeListsToProperLists(node) {
-          var currentListNode, prevListNode, lastLevel = 1;
-
-          function getText(node) {
-            var txt = '';
-
-            if (node.type === 3) {
-              return node.value;
-            }
-
-            if ((node = node.firstChild)) {
-              do {
-                txt += getText(node);
-              } while ((node = node.next));
-            }
-
-            return txt;
-          }
-
-          function trimListStart(node, regExp) {
-            if (node.type === 3) {
-              if (regExp.test(node.value)) {
-                node.value = node.value.replace(regExp, '');
-                return false;
-              }
-            }
-
-            if ((node = node.firstChild)) {
-              do {
-                if (!trimListStart(node, regExp)) {
-                  return false;
-                }
-              } while ((node = node.next));
-            }
-
-            return true;
-          }
-
-          function removeIgnoredNodes(node) {
-            if (node._listIgnore) {
-              node.remove();
-              return;
-            }
-
-            if ((node = node.firstChild)) {
-              do {
-                removeIgnoredNodes(node);
-              } while ((node = node.next));
-            }
-          }
-
-          function convertParagraphToLi(paragraphNode, listName, start) {
-            var level = paragraphNode._listLevel || lastLevel;
-
-            // Handle list nesting
-            if (level != lastLevel) {
-              if (level < lastLevel) {
-                // Move to parent list
-                if (currentListNode) {
-                  currentListNode = currentListNode.parent.parent;
-                }
-              } else {
-                // Create new list
-                prevListNode = currentListNode;
-                currentListNode = null;
-              }
-            }
-
-            if (!currentListNode || currentListNode.name != listName) {
-              prevListNode = prevListNode || currentListNode;
-              currentListNode = new Node(listName, 1);
-
-              if (start > 1) {
-                currentListNode.attr('start', '' + start);
-              }
-
-              paragraphNode.wrap(currentListNode);
-            } else {
-              currentListNode.append(paragraphNode);
-            }
-
-            paragraphNode.name = 'li';
-
-            // Append list to previous list if it exists
-            if (level > lastLevel && prevListNode) {
-              prevListNode.lastChild.append(currentListNode);
-            }
-
-            lastLevel = level;
-
-            // Remove start of list item "1. " or "&middot; " etc
-            removeIgnoredNodes(paragraphNode);
-            trimListStart(paragraphNode, /^\u00a0+/);
-            trimListStart(paragraphNode, /^\s*([\u2022\u00b7\u00a7\u25CF]|\w+\.)/);
-            trimListStart(paragraphNode, /^\u00a0+/);
-          }
-
-          // Build a list of all root level elements before we start
-          // altering them in the loop below.
-          var elements = [], child = node.firstChild;
-          while (typeof child !== 'undefined' && child !== null) {
-            elements.push(child);
-
-            child = child.walk();
-            if (child !== null) {
-              while (typeof child !== 'undefined' && child.parent !== node) {
-                child = child.walk();
-              }
-            }
-          }
-
-          for (var i = 0; i < elements.length; i++) {
-            node = elements[i];
-
-            if (node.name == 'p' && node.firstChild) {
-              // Find first text node in paragraph
-              var nodeText = getText(node);
-
-              // Detect unordered lists look for bullets
-              if (isBulletList(nodeText)) {
-                convertParagraphToLi(node, 'ul');
-                continue;
-              }
-
-              // Detect ordered lists 1., a. or ixv.
-              if (isNumericList(nodeText)) {
-                // Parse OL start number
-                var matches = /([0-9]+)\./.exec(nodeText);
-                var start = 1;
-                if (matches) {
-                  start = parseInt(matches[1], 10);
-                }
-
-                convertParagraphToLi(node, 'ol', start);
-                continue;
-              }
-
-              // Convert paragraphs marked as lists but doesn't look like anything
-              if (node._listLevel) {
-                convertParagraphToLi(node, 'ul', 1);
-                continue;
-              }
-
-              currentListNode = null;
-            } else {
-              // If the root level element isn't a p tag which can be
-              // processed by convertParagraphToLi, it interrupts the
-              // lists, causing a new list to start instead of having
-              // elements from the next list inserted above this tag.
-              prevListNode = currentListNode;
-              currentListNode = null;
-            }
-          }
-        }
-
-        function filterStyles(node, styleValue) {
-          var outputStyles = {}, matches, styles = editor.dom.parseStyle(styleValue);
-
-          Tools.each(styles, function (value, name) {
-            // Convert various MS styles to W3C styles
-            switch (name) {
-              case 'mso-list':
-                // Parse out list indent level for lists
-                matches = /\w+ \w+([0-9]+)/i.exec(styleValue);
-                if (matches) {
-                  node._listLevel = parseInt(matches[1], 10);
-                }
-
-                // Remove these nodes <span style="mso-list:Ignore">o</span>
-                // Since the span gets removed we mark the text node and the span
-                if (/Ignore/i.test(value) && node.firstChild) {
-                  node._listIgnore = true;
-                  node.firstChild._listIgnore = true;
-                }
-
-                break;
-
-              case "horiz-align":
-                name = "text-align";
-                break;
-
-              case "vert-align":
-                name = "vertical-align";
-                break;
-
-              case "font-color":
-              case "mso-foreground":
-                name = "color";
-                break;
-
-              case "mso-background":
-              case "mso-highlight":
-                name = "background";
-                break;
-
-              case "font-weight":
-              case "font-style":
-                if (value != "normal") {
-                  outputStyles[name] = value;
-                }
-                return;
-
-              case "mso-element":
-                // Remove track changes code
-                if (/^(comment|comment-list)$/i.test(value)) {
-                  node.remove();
-                  return;
-                }
-
-                break;
-            }
-
-            if (name.indexOf('mso-comment') === 0) {
-              node.remove();
-              return;
-            }
-
-            // Never allow mso- prefixed names
-            if (name.indexOf('mso-') === 0) {
-              return;
-            }
-
-            // Output only valid styles
-            if (retainStyleProperties == "all" || (validStyles && validStyles[name])) {
-              outputStyles[name] = value;
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var cut = function (editor) {
+      return function (evt) {
+        if (editor.selection.isCollapsed() === false) {
+          setClipboardData(evt, getData(editor), fallback(editor), function () {
+            // Chrome fails to execCommand from another execCommand with this message:
+            // "We don't execute document.execCommand() this time, because it is called recursively.""
+            setTimeout(function () { // detach
+              editor.execCommand('Delete');
+            }, 0);
</ins><span class="cx" style="display: block; padding: 0 10px">           });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-          // Convert bold style to "b" element
-          if (/(bold)/i.test(outputStyles["font-weight"])) {
-            delete outputStyles["font-weight"];
-            node.wrap(new Node("b", 1));
-          }
-
-          // Convert italic style to "i" element
-          if (/(italic)/i.test(outputStyles["font-style"])) {
-            delete outputStyles["font-style"];
-            node.wrap(new Node("i", 1));
-          }
-
-          // Serialize the styles and see if there is something left to keep
-          outputStyles = editor.dom.serializeStyle(outputStyles, node.name);
-          if (outputStyles) {
-            return outputStyles;
-          }
-
-          return null;
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      };
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (settings.paste_enable_default_filters === false) {
-          return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var copy = function (editor) {
+      return function (evt) {
+        if (editor.selection.isCollapsed() === false) {
+          setClipboardData(evt, getData(editor), fallback(editor), noop);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      };
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Detect is the contents is Word junk HTML
-        if (isWordContent(e.content)) {
-          e.wordContent = true; // Mark it for other processors
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var register = function (editor) {
+      editor.on('cut', cut(editor));
+      editor.on('copy', copy(editor));
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Remove basic Word junk
-          content = Utils.filter(content, [
-            // Word comments like conditional comments etc
-            /<!--[\s\S]+?-->/gi,
-
-            // Remove comments, scripts (e.g., msoShowComment), XML tag, VML content,
-            // MS Office namespaced tags, and a few other tags
-            /<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|img|meta|link|style|\w:\w+)(?=[\s\/>]))[^>]*>/gi,
-
-            // Convert <s> into <strike> for line-though
-            [/<(\/?)s>/gi, "<$1strike>"],
-
-            // Replace nsbp entites to char since it's easier to handle
-            [/&nbsp;/gi, "\u00a0"],
-
-            // Convert <span style="mso-spacerun:yes">___</span> to string of alternating
-            // breaking/non-breaking spaces of same length
-            [/<span\s+style\s*=\s*"\s*mso-spacerun\s*:\s*yes\s*;?\s*"\s*>([\s\u00a0]*)<\/span>/gi,
-              function (str, spaces) {
-                return (spaces.length > 0) ?
-                  spaces.replace(/./, " ").slice(Math.floor(spaces.length / 2)).split("").join("\u00a0") : "";
-              }
-            ]
-          ]);
-
-          var validElements = settings.paste_word_valid_elements;
-          if (!validElements) {
-            validElements = (
-              '-strong/b,-em/i,-u,-span,-p,-ol,-ul,-li,-h1,-h2,-h3,-h4,-h5,-h6,' +
-              '-p/div,-a[href|name],sub,sup,strike,br,del,table[width],tr,' +
-              'td[colspan|rowspan|width],th[colspan|rowspan|width],thead,tfoot,tbody'
-            );
-          }
-
-          // Setup strict schema
-          var schema = new Schema({
-            valid_elements: validElements,
-            valid_children: '-li[p]'
-          });
-
-          // Add style/class attribute to all element rules since the user might have removed them from
-          // paste_word_valid_elements config option and we need to check them for properties
-          Tools.each(schema.elements, function (rule) {
-            /*eslint dot-notation:0*/
-            if (!rule.attributes["class"]) {
-              rule.attributes["class"] = {};
-              rule.attributesOrder.push("class");
-            }
-
-            if (!rule.attributes.style) {
-              rule.attributes.style = {};
-              rule.attributesOrder.push("style");
-            }
-          });
-
-          // Parse HTML into DOM structure
-          var domParser = new DomParser({}, schema);
-
-          // Filter styles to remove "mso" specific styles and convert some of them
-          domParser.addAttributeFilter('style', function (nodes) {
-            var i = nodes.length, node;
-
-            while (i--) {
-              node = nodes[i];
-              node.attr('style', filterStyles(node, node.attr('style')));
-
-              // Remove pointess spans
-              if (node.name == 'span' && node.parent && !node.attributes.length) {
-                node.unwrap();
-              }
-            }
-          });
-
-          // Check the class attribute for comments or del items and remove those
-          domParser.addAttributeFilter('class', function (nodes) {
-            var i = nodes.length, node, className;
-
-            while (i--) {
-              node = nodes[i];
-
-              className = node.attr('class');
-              if (/^(MsoCommentReference|MsoCommentText|msoDel)$/i.test(className)) {
-                node.remove();
-              }
-
-              node.attr('class', null);
-            }
-          });
-
-          // Remove all del elements since we don't want the track changes code in the editor
-          domParser.addNodeFilter('del', function (nodes) {
-            var i = nodes.length;
-
-            while (i--) {
-              nodes[i].remove();
-            }
-          });
-
-          // Keep some of the links and anchors
-          domParser.addNodeFilter('a', function (nodes) {
-            var i = nodes.length, node, href, name;
-
-            while (i--) {
-              node = nodes[i];
-              href = node.attr('href');
-              name = node.attr('name');
-
-              if (href && href.indexOf('#_msocom_') != -1) {
-                node.remove();
-                continue;
-              }
-
-              if (href && href.indexOf('file://') === 0) {
-                href = href.split('#')[1];
-                if (href) {
-                  href = '#' + href;
-                }
-              }
-
-              if (!href && !name) {
-                node.unwrap();
-              } else {
-                // Remove all named anchors that aren't specific to TOC, Footnotes or Endnotes
-                if (name && !/^_?(?:toc|edn|ftn)/i.test(name)) {
-                  node.unwrap();
-                  continue;
-                }
-
-                node.attr({
-                  href: href,
-                  name: name
-                });
-              }
-            }
-          });
-
-          // Parse into DOM structure
-          var rootNode = domParser.parse(content);
-
-          // Process DOM
-          if (settings.paste_convert_word_fake_lists !== false) {
-            convertFakeListsToProperLists(rootNode);
-          }
-
-          // Serialize DOM back to HTML
-          e.content = new Serializer({
-            validate: settings.validate
-          }, schema).serialize(rootNode);
-        }
-      });
-    }
-
-    WordFilter.isWordContent = isWordContent;
-
-    return WordFilter;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return {
+      register: register
+    };
</ins><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px">  * Quirks.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2044,154 +2187,152 @@
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.plugins.paste.core.Utils'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><span class="cx" style="display: block; padding: 0 10px">   function (Env, Tools, WordFilter, Utils) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    "use strict";
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function addPreProcessFilter(editor, filterFunc) {
+      editor.on('PastePreProcess', function (e) {
+        e.content = filterFunc(editor, e.content, e.internal, e.wordContent);
+      });
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return function (editor) {
-      function addPreProcessFilter(filterFunc) {
-        editor.on('BeforePastePreProcess', function (e) {
-          e.content = filterFunc(e.content);
-        });
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function addPostProcessFilter(editor, filterFunc) {
+      editor.on('PastePostProcess', function (e) {
+        filterFunc(editor, e.node);
+      });
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function addPostProcessFilter(filterFunc) {
-        editor.on('PastePostProcess', function (e) {
-          filterFunc(e.node);
-        });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    /**
+     * Removes BR elements after block elements. IE9 has a nasty bug where it puts a BR element after each
+     * block element when pasting from word. This removes those elements.
+     *
+     * This:
+     *  <p>a</p><br><p>b</p>
+     *
+     * Becomes:
+     *  <p>a</p><p>b</p>
+     */
+    function removeExplorerBrElementsAfterBlocks(editor, html) {
+      // Only filter word specific content
+      if (!WordFilter.isWordContent(html)) {
+        return html;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Removes BR elements after block elements. IE9 has a nasty bug where it puts a BR element after each
-       * block element when pasting from word. This removes those elements.
-       *
-       * This:
-       *  <p>a</p><br><p>b</p>
-       *
-       * Becomes:
-       *  <p>a</p><p>b</p>
-       */
-      function removeExplorerBrElementsAfterBlocks(html) {
-        // Only filter word specific content
-        if (!WordFilter.isWordContent(html)) {
-          return html;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Produce block regexp based on the block elements in schema
+      var blockElements = [];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Produce block regexp based on the block elements in schema
-        var blockElements = [];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      Tools.each(editor.schema.getBlockElements(), function (block, blockName) {
+        blockElements.push(blockName);
+      });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        Tools.each(editor.schema.getBlockElements(), function (block, blockName) {
-          blockElements.push(blockName);
-        });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var explorerBlocksRegExp = new RegExp(
+        '(?:<br>&nbsp;[\\s\\r\\n]+|<br>)*(<\\/?(' + blockElements.join('|') + ')[^>]*>)(?:<br>&nbsp;[\\s\\r\\n]+|<br>)*',
+        'g'
+      );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var explorerBlocksRegExp = new RegExp(
-          '(?:<br>&nbsp;[\\s\\r\\n]+|<br>)*(<\\/?(' + blockElements.join('|') + ')[^>]*>)(?:<br>&nbsp;[\\s\\r\\n]+|<br>)*',
-          'g'
-        );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Remove BR:s from: <BLOCK>X</BLOCK><BR>
+      html = Utils.filter(html, [
+        [explorerBlocksRegExp, '$1']
+      ]);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Remove BR:s from: <BLOCK>X</BLOCK><BR>
-        html = Utils.filter(html, [
-          [explorerBlocksRegExp, '$1']
-        ]);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // IE9 also adds an extra BR element for each soft-linefeed and it also adds a BR for each word wrap break
+      html = Utils.filter(html, [
+        [/<br><br>/g, '<BR><BR>'], // Replace multiple BR elements with uppercase BR to keep them intact
+        [/<br>/g, ' '],            // Replace single br elements with space since they are word wrap BR:s
+        [/<BR><BR>/g, '<br>']      // Replace back the double brs but into a single BR
+      ]);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // IE9 also adds an extra BR element for each soft-linefeed and it also adds a BR for each word wrap break
-        html = Utils.filter(html, [
-          [/<br><br>/g, '<BR><BR>'], // Replace multiple BR elements with uppercase BR to keep them intact
-          [/<br>/g, ' '],            // Replace single br elements with space since they are word wrap BR:s
-          [/<BR><BR>/g, '<br>']      // Replace back the double brs but into a single BR
-        ]);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return html;
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return html;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    /**
+     * WebKit has a nasty bug where the all computed styles gets added to style attributes when copy/pasting contents.
+     * This fix solves that by simply removing the whole style attribute.
+     *
+     * The paste_webkit_styles option can be set to specify what to keep:
+     *  paste_webkit_styles: "none" // Keep no styles
+     *  paste_webkit_styles: "all", // Keep all of them
+     *  paste_webkit_styles: "font-weight color" // Keep specific ones
+     */
+    function removeWebKitStyles(editor, content, internal, isWordHtml) {
+      // WordFilter has already processed styles at this point and internal doesn't need any processing
+      if (isWordHtml || internal) {
+        return content;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * WebKit has a nasty bug where the all computed styles gets added to style attributes when copy/pasting contents.
-       * This fix solves that by simply removing the whole style attribute.
-       *
-       * The paste_webkit_styles option can be set to specify what to keep:
-       *  paste_webkit_styles: "none" // Keep no styles
-       *  paste_webkit_styles: "all", // Keep all of them
-       *  paste_webkit_styles: "font-weight color" // Keep specific ones
-       *
-       * @param {String} content Content that needs to be processed.
-       * @return {String} Processed contents.
-       */
-      function removeWebKitStyles(content) {
-        // Passthrough all styles from Word and let the WordFilter handle that junk
-        if (WordFilter.isWordContent(content)) {
-          return content;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Filter away styles that isn't matching the target node
+      var webKitStyles = editor.settings.paste_webkit_styles;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Filter away styles that isn't matching the target node
-        var webKitStyles = editor.settings.paste_webkit_styles;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (editor.settings.paste_remove_styles_if_webkit === false || webKitStyles == "all") {
+        return content;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (editor.settings.paste_remove_styles_if_webkit === false || webKitStyles == "all") {
-          return content;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (webKitStyles) {
+        webKitStyles = webKitStyles.split(/[, ]/);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (webKitStyles) {
-          webKitStyles = webKitStyles.split(/[, ]/);
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Keep specific styles that doesn't match the current node computed style
+      if (webKitStyles) {
+        var dom = editor.dom, node = editor.selection.getNode();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Keep specific styles that doesn't match the current node computed style
-        if (webKitStyles) {
-          var dom = editor.dom, node = editor.selection.getNode();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, function (all, before, value, after) {
+          var inputStyles = dom.parseStyle(dom.decode(value), 'span');
+          var outputStyles = {};
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, function (all, before, value, after) {
-            var inputStyles = dom.parseStyle(dom.decode(value), 'span');
-            var outputStyles = {};
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (webKitStyles === "none") {
+            return before + after;
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (webKitStyles === "none") {
-              return before + after;
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          for (var i = 0; i < webKitStyles.length; i++) {
+            var inputValue = inputStyles[webKitStyles[i]], currentValue = dom.getStyle(node, webKitStyles[i], true);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            for (var i = 0; i < webKitStyles.length; i++) {
-              var inputValue = inputStyles[webKitStyles[i]], currentValue = dom.getStyle(node, webKitStyles[i], true);
-
-              if (/color/.test(webKitStyles[i])) {
-                inputValue = dom.toHex(inputValue);
-                currentValue = dom.toHex(currentValue);
-              }
-
-              if (currentValue != inputValue) {
-                outputStyles[webKitStyles[i]] = inputValue;
-              }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            if (/color/.test(webKitStyles[i])) {
+              inputValue = dom.toHex(inputValue);
+              currentValue = dom.toHex(currentValue);
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            outputStyles = dom.serializeStyle(outputStyles, 'span');
-            if (outputStyles) {
-              return before + ' style="' + outputStyles + '"' + after;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            if (currentValue != inputValue) {
+              outputStyles[webKitStyles[i]] = inputValue;
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            return before + after;
-          });
-        } else {
-          // Remove all external styles
-          content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, '$1$3');
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          outputStyles = dom.serializeStyle(outputStyles, 'span');
+          if (outputStyles) {
+            return before + ' style="' + outputStyles + '"' + after;
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Keep internal styles
-        content = content.replace(/(<[^>]+) data-mce-style="([^"]+)"([^>]*>)/gi, function (all, before, value, after) {
-          return before + ' style="' + value + '"' + after;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          return before + after;
</ins><span class="cx" style="display: block; padding: 0 10px">         });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-        return content;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      } else {
+        // Remove all external styles
+        content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, '$1$3');
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function removeUnderlineAndFontInAnchor(root) {
-        editor.$('a', root).find('font,u').each(function (i, node) {
-          editor.dom.remove(node, true);
-        });
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Keep internal styles
+      content = content.replace(/(<[^>]+) data-mce-style="([^"]+)"([^>]*>)/gi, function (all, before, value, after) {
+        return before + ' style="' + value + '"' + after;
+      });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Sniff browsers and apply fixes since we can't feature detect
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return content;
+    }
+
+    function removeUnderlineAndFontInAnchor(editor, root) {
+      editor.$('a', root).find('font,u').each(function (i, node) {
+        editor.dom.remove(node, true);
+      });
+    }
+
+    var setup = function (editor) {
</ins><span class="cx" style="display: block; padding: 0 10px">       if (Env.webkit) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        addPreProcessFilter(removeWebKitStyles);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        addPreProcessFilter(editor, removeWebKitStyles);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       if (Env.ie) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        addPreProcessFilter(removeExplorerBrElementsAfterBlocks);
-        addPostProcessFilter(removeUnderlineAndFontInAnchor);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        addPreProcessFilter(editor, removeExplorerBrElementsAfterBlocks);
+        addPostProcessFilter(editor, removeUnderlineAndFontInAnchor);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+    return {
+      setup: setup
+    };
</ins><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2214,12 +2355,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">   'tinymce.plugins.paste.Plugin',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.PluginManager',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.plugins.paste.api.Events',
</ins><span class="cx" style="display: block; padding: 0 10px">     'tinymce.plugins.paste.core.Clipboard',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.plugins.paste.core.CutCopy',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.plugins.paste.core.Quirks',
-    'tinymce.plugins.paste.core.WordFilter'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.plugins.paste.core.Quirks'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (PluginManager, Clipboard, CutCopy, Quirks, WordFilter) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (PluginManager, Events, Clipboard, CutCopy, Quirks) {
</ins><span class="cx" style="display: block; padding: 0 10px">     var userIsInformed;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     PluginManager.add('paste', function (editor) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2232,10 +2373,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">       function togglePlainTextPaste() {
</span><span class="cx" style="display: block; padding: 0 10px">         if (clipboard.pasteFormat == "text") {
</span><span class="cx" style="display: block; padding: 0 10px">           clipboard.pasteFormat = "html";
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          editor.fire('PastePlainTextToggle', { state: false });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          Events.firePastePlainTextToggle(editor, false);
</ins><span class="cx" style="display: block; padding: 0 10px">         } else {
</span><span class="cx" style="display: block; padding: 0 10px">           clipboard.pasteFormat = "text";
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          editor.fire('PastePlainTextToggle', { state: true });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          Events.firePastePlainTextToggle(editor, true);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">           if (!isUserInformedAboutPlainText()) {
</span><span class="cx" style="display: block; padding: 0 10px">             var message = editor.translate('Paste is now in plain text mode. Contents will now ' +
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2273,8 +2414,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       self.clipboard = clipboard = new Clipboard(editor);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      self.quirks = new Quirks(editor);
-      self.wordFilter = new WordFilter(editor);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      self.quirks = Quirks.setup(editor);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       if (editor.settings.paste_as_text) {
</span><span class="cx" style="display: block; padding: 0 10px">         self.clipboard.pasteFormat = "text";
</span></span></pre></div>
<a id="trunksrcwpincludesjstinymcepluginspastepluginminjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/tinymce/plugins/paste/plugin.min.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/tinymce/plugins/paste/plugin.min.js      2017-09-26 20:32:46 UTC (rev 41603)
+++ trunk/src/wp-includes/js/tinymce/plugins/paste/plugin.min.js        2017-09-26 21:14:28 UTC (rev 41604)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1 +1 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("6",tinymce.util.Tools.resolve),g("1",[&q
 uot;6"],function(a){return a("tinymce.PluginManager")}),g("7",["6"],function(a){return a("tinymce.dom.RangeUtils")}),g("8",["6"],function(a){return a("tinymce.Env")}),g("9",["6"],function(a){return a("tinymce.util.Delay")}),g("a",["6"],function(a){return a("tinymce.util.Tools")}),g("b",["6"],function(a){return a("tinymce.util.VK")}),g("c",[],function(){var a="x-tinymce/html",b="<!-- "+a+" -->",c=function(a){return b+a},d=function(a){return a.replace(b,"")},e=function(a){return a.indexOf(b)!==-1};return{mark:c,unmark:d,isMarked:e,internalHtmlMime:function(){return a}}}),g("g",["6"],function(a){return a("tinymce.html.DomParser")}),g("h",["6"],function(a){return a("tinymce.html.Schema")}),g("d",[&quo
 t;a","g","h"],function(a,b,c){function d(b,c){return a.each(c,function(a){b=a.constructor==RegExp?b.replace(a,""):b.replace(a[0],a[1])}),b}function e(e){function f(a){var b=a.name,c=a;if("br"===b)return void(i+="\n");if(j[b]&&(i+=" "),k[b])return void(i+=" ");if(3==a.type&&(i+=a.value),!a.shortEnded&&(a=a.firstChild))do f(a);while(a=a.next);l[b]&&c.next&&(i+="\n","p"==b&&(i+="\n"))}var g=new c,h=new b({},g),i="",j=g.getShortEndedElements(),k=a.makeMap("script noscript style textarea video audio iframe object"," "),l=g.getBlockElements();return e=d(e,[/<!\[[^\]]+\]>/g]),f(h.parse(e)),i}function f(a){function b(a,b,c){return b||c?"\xa0":" "}return a=d(a,[/^[\s\S]*<body[^>]*>\s*|\s*<\/body[^>]*>[\s\S]*$/gi,/<!--StartFragment-->|<!--EndFragment-->/g,[/
 ( ?)<span class="Apple-converted-space">\u00a0<\/span>( ?)/g,b],/<br class="Apple-interchange-newline">/g,/<br>$/i])}function g(a){var b=0;return function(){return a+b++}}var h=function(){return navigator.userAgent.indexOf(" Edge/")!==-1};return{filter:d,innerText:e,trimHtml:f,createIdGenerator:g,isMsEdge:h}}),g("3",["8","c","d"],function(a,b,c){var d=function(){},e=function(b){return a.iOS===!1&&void 0!==b&&"function"==typeof b.setData&&c.isMsEdge()!==!0},f=function(a,c,d){if(!e(a))return!1;try{return a.clearData(),a.setData("text/html",c),a.setData("text/plain",d),a.setData(b.internalHtmlMime(),c),!0}catch(a){return!1}},g=function(a,b,c,d){f(a.clipboardData,b.html,b.text)?(a.preventDefault(),d()):c(b.html,d)},h=function(a){return function(c,d){var e=b.mark(c),f=a.dom.create("div",{contenteditable:"false"}),g=a.dom.c
 reate("div",{contenteditable:"true"},e);a.dom.setStyles(f,{position:"fixed",left:"-3000px",width:"1000px",overflow:"hidden"}),f.appendChild(g),a.dom.add(a.getBody(),f);var h=a.selection.getRng();g.focus();var i=a.dom.createRng();i.selectNodeContents(g),a.selection.setRng(i),setTimeout(function(){f.parentNode.removeChild(f),a.selection.setRng(h),d()},0)}},i=function(a){return{html:a.selection.getContent({contextual:!0}),text:a.selection.getContent({format:"text"})}},j=function(a){return function(b){a.selection.isCollapsed()===!1&&g(b,i(a),h(a),function(){a.execCommand("Delete")})}},k=function(a){return function(b){a.selection.isCollapsed()===!1&&g(b,i(a),h(a),d)}},l=function(a){a.on("cut",j(a)),a.on("copy",k(a))};return{register:l}}),g("k",["6"],function(a){return a("tinymce.html.Entities")}),g("e",["k"],function(a){var 
 b=function(a){return!/<(?:(?!\/?(?:div|p|br))[^>]*|(?:div|p|br)\s+\w[^>]+)>/.test(a)},c=function(a){return a.replace(/\r?\n/g,"<br>")},d=function(b,c){var d,e=[],f="<"+b;if("object"==typeof c){for(d in c)c.hasOwnProperty(d)&&e.push(d+'="'+a.encodeAllRaw(c[d])+'"');e.length&&(f+=" "+e.join(" "))}return f+">"},e=function(a,b,c){var e,f,g,h=a.split(/\r?\n/),i=0,j=h.length,k=[],l=[],m=d(b,c),n="</"+b+">";if(1===h.length)return a;for(;i<j;i++)e=i===j-1,f=!e&&!h[i+1],g=!h[i]&&!k.length,k.push(h[i]?h[i]:"&nbsp;"),(e||f||g)&&(l.push(k.join("<br>")),k=[]),f&&i++;return 1===l.length?l[0]:m+l.join(n+m)+n},f=function(a,b,d){return b?e(a,b,d):c(a)};return{isPlainText:b,convert:f,toBRs:c,toBlockElements:e}}),g("f",["a"],function(a){var b=function(a){return/^https?:\/\/[\w\?\-\/+=
 .&%@~#]+$/i.test(a)},c=function(a){return b(a)&&/.(gif|jpe?g|png)$/.test(a)},d=function(a,b,c){return a.undoManager.extra(function(){c(a,b)},function(){a.insertContent('<img src="'+b+'">')}),!0},e=function(a,b,c){return a.undoManager.extra(function(){c(a,b)},function(){a.execCommand("mceInsertLink",!1,b)}),!0},f=function(a,c,d){return!(a.selection.isCollapsed()!==!1||!b(c))&&e(a,c,d)},g=function(a,b,e){return!!c(b)&&d(a,b,e)},h=function(a,b){return a.insertContent(b,{merge:a.settings.paste_merge_formats!==!1,paste:!0}),!0},i=function(b,c){a.each([f,g,h],function(a){return a(b,c,h)!==!0})},j=function(a,b){a.settings.smart_paste===!1?h(a,b):i(a,b)};return{isImageUrl:c,isAbsoluteUrl:b,insertContent:j}}),g("2",["7","8","9","a","b","3","c","e","f","d"],function(a,b,c,d,e,f,g,h,i,j){return function(f){function k(a,b){var c,d,e=
 f.dom;if(d=b||g.isMarked(a),a=g.unmark(a),c=f.fire("BeforePastePreProcess",{content:a,internal:d}),c=f.fire("PastePreProcess",c),a=c.content,!c.isDefaultPrevented()){if(f.hasEventListeners("PastePostProcess")&&!c.isDefaultPrevented()){var h=e.add(f.getBody(),"div",{style:"display:none"},a);c=f.fire("PastePostProcess",{node:h,internal:d}),e.remove(h),a=c.node.innerHTML}c.isDefaultPrevented()||i.insertContent(f,a)}}function l(a){a=f.dom.encode(a).replace(/\r\n/g,"\n"),a=h.convert(a,f.settings.forced_root_block,f.settings.forced_root_block_attrs),k(a,!1)}function m(){function a(a){var b,c,e,f=a.startContainer;if(b=a.getClientRects(),b.length)return b[0];if(a.collapsed&&1==f.nodeType){for(e=f.childNodes[C.startOffset];e&&3==e.nodeType&&!e.data.length;)e=e.nextSibling;if(e)return"BR"==e.tagName&&(c=d.doc.createTextNode("\ufeff"),e.parentNode.insertBefore(c,e),
 a=d.createRng(),a.setStartBefore(c),a.setEndAfter(c),b=a.getClientRects(),d.remove(c)),b.length?b[0]:void 0}}var c,d=f.dom,e=f.getBody(),g=f.dom.getViewPort(f.getWin()),h=g.y,i=20;if(C=f.selection.getRng(),f.inline&&(c=f.selection.getScrollContainer(),c&&c.scrollTop>0&&(h=c.scrollTop)),C.getClientRects){var j=a(C);if(j)i=h+(j.top-d.getPos(e).y);else{i=h;var k=C.startContainer;k&&(3==k.nodeType&&k.parentNode!=e&&(k=k.parentNode),1==k.nodeType&&(i=d.getPos(k,c||e).y))}}B=d.add(f.getBody(),"div",{id:"mcepastebin",contentEditable:!0,"data-mce-bogus":"all",style:"position: absolute; top: "+i+"px;width: 10px; height: 10px; overflow: hidden; opacity: 0"},H),(b.ie||b.gecko)&&d.setStyle(B,"left","rtl"==d.getStyle(e,"direction",!0)?65535:-65535),d.bind(B,"beforedeactivate focusin focusout",function(a){a.stopPropagation()}),B.foc
 us(),f.selection.select(B,!0)}function n(){if(B){for(var a;a=f.dom.get("mcepastebin");)f.dom.remove(a),f.dom.unbind(a);C&&f.selection.setRng(C)}B=C=null}function o(){var a,b,c,d,e="";for(a=f.dom.select("div[id=mcepastebin]"),b=0;b<a.length;b++)c=a[b],c.firstChild&&"mcepastebin"==c.firstChild.id&&(c=c.firstChild),d=c.innerHTML,e!=H&&(e+=d);return e}function p(a){var b={};if(a){if(a.getData){var c=a.getData("Text");c&&c.length>0&&c.indexOf(I)==-1&&(b["text/plain"]=c)}if(a.types)for(var d=0;d<a.types.length;d++){var e=a.types[d];b[e]=a.getData(e)}}return b}function q(a){var b=p(a.clipboardData||f.getDoc().dataTransfer);return j.isMsEdge()?d.extend(b,{"text/html":""}):b}function r(a){return y(a,"text/html")||y(a,"text/plain")}function s(a){var b;return b=a.indexOf(","),b!==-1?a.substr(b+1):null}function t(a,b){retu
 rn!a.images_dataimg_filter||a.images_dataimg_filter(b)}function u(a,b,c){a&&(f.selection.setRng(a),a=null);var d=b.result,e=s(d),g=new Image;if(g.src=d,t(f.settings,g)){var h,i,j=f.editorUpload.blobCache;i=j.findFirst(function(a){return a.base64()===e}),i?h=i:(h=j.create(J(),c,e),j.add(h)),k('<img src="'+h.blobUri()+'">',!1)}else k('<img src="'+d+'">',!1)}function v(a,b){function c(c){var d,e,f,g=!1;if(c)for(d=0;d<c.length;d++)if(e=c[d],/^image\/(jpeg|png|gif|bmp)$/.test(e.type)){var h=e.getAsFile?e.getAsFile():e;f=new FileReader,f.onload=u.bind(null,b,f,h),f.readAsDataURL(h),a.preventDefault(),g=!0}return g}var d=a.clipboardData||a.dataTransfer;if(f.settings.paste_data_images&&d)return c(d.items)||c(d.files)}function w(a){var b=a.clipboardData;return navigator.userAgent.indexOf("Android")!=-1&&b&&b.items&&0===b.items.length}function x(b){return a.getCaretRangeFromPoint(b.clientX,b.clientY,f.getDoc(
 ))}function y(a,b){return b in a&&a[b].length>0}function z(a){return e.metaKeyPressed(a)&&86==a.keyCode||a.shiftKey&&45==a.keyCode}function A(){function a(a,b,c,d){var e,g;return y(a,"text/html")?e=a["text/html"]:(e=o(),e==H&&(c=!0)),e=j.trimHtml(e),B&&B.firstChild&&"mcepastebin"===B.firstChild.id&&(c=!0),n(),g=d===!1&&h.isPlainText(e),e.length&&!g||(c=!0),c&&(e=y(a,"text/plain")&&g?a["text/plain"]:j.innerText(e)),e==H?void(b||f.windowManager.alert("Please use Ctrl+V/Cmd+V keyboard shortcuts to paste contents.")):void(c?l(e):k(e,d))}function d(a){var b=a["text/plain"];return!!b&&0===b.indexOf("file://")}f.on("keydown",function(a){function c(a){z(a)&&!a.isDefaultPrevented()&&n()}if(z(a)&&!a.isDefaultPrevented()){if(D=a.shiftKey&&86==a.keyCode,D&&b.webkit&
 &navigator.userAgent.indexOf("Version/")!=-1)return;if(a.stopImmediatePropagation(),F=(new Date).getTime(),b.ie&&D)return a.preventDefault(),void f.fire("paste",{ieFake:!0});n(),m(),f.once("keyup",c),f.once("paste",function(){f.off("keyup",c)})}});var e=function(){return C||f.selection.getRng()};f.on("paste",function(d){var h=(new Date).getTime(),i=q(d),j=(new Date).getTime()-h,k=(new Date).getTime()-F-j<1e3,l="text"==E.pasteFormat||D,p=y(i,g.internalHtmlMime());return D=!1,d.isDefaultPrevented()||w(d)?void n():!r(i)&&v(d,e())?void n():(k||d.preventDefault(),!b.ie||k&&!d.ieFake||y(i,"text/html")||(m(),f.dom.bind(B,"paste",function(a){a.stopPropagation()}),f.getDoc().execCommand("Paste",!1,null),i["text/html"]=o()),void(y(i,"text/html")?(d.preventDefault(),a(i,k,l,p)):c.setEditorTimeout(f,function(){a(i,k,l,p)},0)))}),f.on("dragst
 art dragend",function(a){G="dragstart"==a.type}),f.on("drop",function(a){var b,e;if(e=x(a),!a.isDefaultPrevented()&&!G){b=p(a.dataTransfer);var h=y(b,g.internalHtmlMime());if((r(b)&&!d(b)||!v(a,e))&&e&&f.settings.paste_filter_drop!==!1){var i=b["mce-internal"]||b["text/html"]||b["text/plain"];i&&(a.preventDefault(),c.setEditorTimeout(f,function(){f.undoManager.transact(function(){b["mce-internal"]&&f.execCommand("Delete"),f.selection.setRng(e),i=j.trimHtml(i),b["text/html"]?k(i,h):l(i)})}))}}}),f.on("dragover dragend",function(a){f.settings.paste_data_images&&a.preventDefault()})}var B,C,D,E=this,F=0,G=!1,H="%MCEPASTEBIN%",I="data:text/mce-internal,",J=j.createIdGenerator("mceclip");E.pasteHtml=k,E.pasteText=l,E.pasteImageData=v,f.on("preInit",function(){A(),f.parser.addNodeFilter("img&quot
 ;,function(a,c,d){function e(a){return a.data&&a.data.paste===!0}function g(a){a.attr("data-mce-object")||k===b.transparentSrc||a.remove()}function h(a){return 0===a.indexOf("webkit-fake-url")}function i(a){return 0===a.indexOf("data:")}if(!f.settings.paste_data_images&&e(d))for(var j=a.length;j--;){var k=a[j].attributes.map.src;k&&(h(k)?g(a[j]):!f.settings.allow_html_data_urls&&i(k)&&g(a[j]))}})})}}),g("i",["6"],function(a){return a("tinymce.html.Serializer")}),g("j",["6"],function(a){return a("tinymce.html.Node")}),g("5",["a","g","h","i","j","d"],function(a,b,c,d,e,f){function g(a){return/<font face="Times New Roman"|class="?Mso|style="[^"]*\bmso-|style='[^'']*\bmso-|w:WordDocument/i.test(a)||/class="OutlineElement/.test(a)||/id="?docs\-internal\-
 guid\-/.test(a)}function h(b){var c,d;return d=[/^[IVXLMCD]{1,2}\.[ \u00a0]/,/^[ivxlmcd]{1,2}\.[ \u00a0]/,/^[a-z]{1,2}[\.\)][ \u00a0]/,/^[A-Z]{1,2}[\.\)][ \u00a0]/,/^[0-9]+\.[ \u00a0]/,/^[\u3007\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d]+\.[ \u00a0]/,/^[\u58f1\u5f10\u53c2\u56db\u4f0d\u516d\u4e03\u516b\u4e5d\u62fe]+\.[ \u00a0]/],b=b.replace(/^[\u00a0 ]+/,""),a.each(d,function(a){if(a.test(b))return c=!0,!1}),c}function i(a){return/^[\s\u00a0]*[\u2022\u00b7\u00a7\u25CF]\s*/.test(a)}function j(j){var k=j.settings;j.on("BeforePastePreProcess",function(l){function m(a){function b(a){var c="";if(3===a.type)return a.value;if(a=a.firstChild)do c+=b(a);while(a=a.next);return c}function c(a,b){if(3===a.type&&b.test(a.value))return a.value=a.value.replace(b,""),!1;if(a=a.firstChild)do if(!c(a,b))return!1;while(a=a.next);return!0}function d(a){if(a._listIgnore)return void a.remove();if(a=a.firstChild)do d(a);while(a=a.next)}function f(
 a,b,f){var h=a._listLevel||k;h!=k&&(h<k?g&&(g=g.parent.parent):(j=g,g=null)),g&&g.name==b?g.append(a):(j=j||g,g=new e(b,1),f>1&&g.attr("start",""+f),a.wrap(g)),a.name="li",h>k&&j&&j.lastChild.append(g),k=h,d(a),c(a,/^\u00a0+/),c(a,/^\s*([\u2022\u00b7\u00a7\u25CF]|\w+\.)/),c(a,/^\u00a0+/)}for(var g,j,k=1,l=[],m=a.firstChild;"undefined"!=typeof m&&null!==m;)if(l.push(m),m=m.walk(),null!==m)for(;"undefined"!=typeof m&&m.parent!==a;)m=m.walk();for(var n=0;n<l.length;n++)if(a=l[n],"p"==a.name&&a.firstChild){var o=b(a);if(i(o)){f(a,"ul");continue}if(h(o)){var p=/([0-9]+)\./.exec(o),q=1;p&&(q=parseInt(p[1],10)),f(a,"ol",q);continue}if(a._listLevel){f(a,"ul",1);continue}g=null}else j=g,g=null}function n(b,c){var d,f={},g=j.dom.parseStyle(c);return a.each(g,function(a,e){switch(e){case"mso-list":d=/\w+ 
 \w+([0-9]+)/i.exec(c),d&&(b._listLevel=parseInt(d[1],10)),/Ignore/i.test(a)&&b.firstChild&&(b._listIgnore=!0,b.firstChild._listIgnore=!0);break;case"horiz-align":e="text-align";break;case"vert-align":e="vertical-align";break;case"font-color":case"mso-foreground":e="color";break;case"mso-background":case"mso-highlight":e="background";break;case"font-weight":case"font-style":return void("normal"!=a&&(f[e]=a));case"mso-element":if(/^(comment|comment-list)$/i.test(a))return void b.remove()}return 0===e.indexOf("mso-comment")?void b.remove():void(0!==e.indexOf("mso-")&&("all"==o||p&&p[e])&&(f[e]=a))}),/(bold)/i.test(f["font-weight"])&&(delete f["font-weight"],b.wrap(new e("b",1))),/(italic)/i.test(f["font-style"])&
 &(delete f["font-style"],b.wrap(new e("i",1))),f=j.dom.serializeStyle(f,b.name),f?f:null}var o,p,q=l.content;if(q=q.replace(/<b[^>]+id="?docs-internal-[^>]*>/gi,""),q=q.replace(/<br class="?Apple-interchange-newline"?>/gi,""),o=k.paste_retain_style_properties,o&&(p=a.makeMap(o.split(/[, ]/))),k.paste_enable_default_filters!==!1&&g(l.content)){l.wordContent=!0,q=f.filter(q,[/<!--[\s\S]+?-->/gi,/<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|img|meta|link|style|\w:\w+)(?=[\s\/>]))[^>]*>/gi,[/<(\/?)s>/gi,"<$1strike>"],[/&nbsp;/gi,"\xa0"],[/<span\s+style\s*=\s*"\s*mso-spacerun\s*:\s*yes\s*;?\s*"\s*>([\s\u00a0]*)<\/span>/gi,function(a,b){return b.length>0?b.replace(/./," ").slice(Math.floor(b.length/2)).split("").join("\xa0"):""}]]);var r=k.paste_word_valid_el
 ements;r||(r="-strong/b,-em/i,-u,-span,-p,-ol,-ul,-li,-h1,-h2,-h3,-h4,-h5,-h6,-p/div,-a[href|name],sub,sup,strike,br,del,table[width],tr,td[colspan|rowspan|width],th[colspan|rowspan|width],thead,tfoot,tbody");var s=new c({valid_elements:r,valid_children:"-li[p]"});a.each(s.elements,function(a){a.attributes["class"]||(a.attributes["class"]={},a.attributesOrder.push("class")),a.attributes.style||(a.attributes.style={},a.attributesOrder.push("style"))});var t=new b({},s);t.addAttributeFilter("style",function(a){for(var b,c=a.length;c--;)b=a[c],b.attr("style",n(b,b.attr("style"))),"span"==b.name&&b.parent&&!b.attributes.length&&b.unwrap()}),t.addAttributeFilter("class",function(a){for(var b,c,d=a.length;d--;)b=a[d],c=b.attr("class"),/^(MsoCommentReference|MsoCommentText|msoDel)$/i.test(c)&&b.remove(),b.attr("class",null)}),t.ad
 dNodeFilter("del",function(a){for(var b=a.length;b--;)a[b].remove()}),t.addNodeFilter("a",function(a){for(var b,c,d,e=a.length;e--;)if(b=a[e],c=b.attr("href"),d=b.attr("name"),c&&c.indexOf("#_msocom_")!=-1)b.remove();else if(c&&0===c.indexOf("file://")&&(c=c.split("#")[1],c&&(c="#"+c)),c||d){if(d&&!/^_?(?:toc|edn|ftn)/i.test(d)){b.unwrap();continue}b.attr({href:c,name:d})}else b.unwrap()});var u=t.parse(q);k.paste_convert_word_fake_lists!==!1&&m(u),l.content=new d({validate:k.validate},s).serialize(u)}})}return j.isWordContent=g,j}),g("4",["8","a","5","d"],function(a,b,c,d){"use strict";return function(e){function f(a){e.on("BeforePastePreProcess",function(b){b.content=a(b.content)})}function g(a){e.on("PastePostProcess",function(b){a(b.node)})}function h(a){if(!c.isWordContent(
 a))return a;var f=[];b.each(e.schema.getBlockElements(),function(a,b){f.push(b)});var g=new RegExp("(?:<br>&nbsp;[\\s\\r\\n]+|<br>)*(<\\/?("+f.join("|")+")[^>]*>)(?:<br>&nbsp;[\\s\\r\\n]+|<br>)*","g");return a=d.filter(a,[[g,"$1"]]),a=d.filter(a,[[/<br><br>/g,"<BR><BR>"],[/<br>/g," "],[/<BR><BR>/g,"<br>"]])}function i(a){if(c.isWordContent(a))return a;var b=e.settings.paste_webkit_styles;if(e.settings.paste_remove_styles_if_webkit===!1||"all"==b)return a;if(b&&(b=b.split(/[, ]/)),b){var d=e.dom,f=e.selection.getNode();a=a.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi,function(a,c,e,g){var h=d.parseStyle(d.decode(e),"span"),i={};if("none"===b)return c+g;for(var j=0;j<b.length;j++){var k=h[b[j]],l=d.getStyle(f,b[j],!0);/color/.test(b[j])&&(k=d.t
 oHex(k),l=d.toHex(l)),l!=k&&(i[b[j]]=k)}return i=d.serializeStyle(i,"span"),i?c+' style="'+i+'"'+g:c+g})}else a=a.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi,"$1$3");return a=a.replace(/(<[^>]+) data-mce-style="([^"]+)"([^>]*>)/gi,function(a,b,c,d){return b+' style="'+c+'"'+d})}function j(a){e.$("a",a).find("font,u").each(function(a,b){e.dom.remove(b,!0)})}a.webkit&&f(i),a.ie&&(f(h),g(j))}}),g("0",["1","2","3","4","5"],function(a,b,c,d,e){var f;return a.add("paste",function(g){function h(){return f||g.settings.paste_plaintext_inform===!1}function i(){if("text"==k.pasteFormat)k.pasteFormat="html",g.fire("PastePlainTextToggle",{state:!1});else if(k.pasteFormat="text",g.fire("PastePlainTextToggle",{state:!0}),!h()){var a=g.translat
 e("Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.");g.notificationManager.open({text:a,type:"info"}),f=!0}g.focus()}function j(){var a=this;a.active("text"===k.pasteFormat),g.on("PastePlainTextToggle",function(b){a.active(b.state)})}var k,l=this,m=g.settings;return/(^|[ ,])powerpaste([, ]|$)/.test(m.plugins)&&a.get("powerpaste")?void("undefined"!=typeof console&&console.log&&console.log("PowerPaste is incompatible with Paste plugin! Remove 'paste' from the 'plugins' option.")):(l.clipboard=k=new b(g),l.quirks=new d(g),l.wordFilter=new e(g),g.settings.paste_as_text&&(l.clipboard.pasteFormat="text"),m.paste_preprocess&&g.on("PastePreProcess",function(a){m.paste_preprocess.call(l,l,a)}),m.paste_postprocess&&g.on("PastePostProcess",function(a){m.paste_postprocess.call(l,l,a)}),g.a
 ddCommand("mceInsertClipboardContent",function(a,b){b.content&&l.clipboard.pasteHtml(b.content,b.internal),b.text&&l.clipboard.pasteText(b.text)}),g.settings.paste_block_drop&&g.on("dragend dragover draggesture dragdrop drop drag",function(a){a.preventDefault(),a.stopPropagation()}),g.settings.paste_data_images||g.on("drop",function(a){var b=a.dataTransfer;b&&b.files&&b.files.length>0&&a.preventDefault()}),g.addCommand("mceTogglePlainTextPaste",i),g.addButton("pastetext",{icon:"pastetext",tooltip:"Paste as text",onclick:i,onPostRender:j}),g.addMenuItem("pastetext",{text:"Paste as text",selectable:!0,active:k.pasteFormat,onclick:i,onPostRender:j}),void c.register(g))}),function(){}}),d("0")()}();
</del><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("6",tinymce.util.Tools.resolve),g("1",[&q
 uot;6"],function(a){return a("tinymce.PluginManager")}),g("2",[],function(){var a=function(a,b,c,d){return a.fire("PastePreProcess",{content:b,internal:c,wordContent:d})},b=function(a,b,c,d){return a.fire("PastePostProcess",{node:b,internal:c,wordContent:d})},c=function(a,b){return a.fire("PastePlainTextToggle",{state:b})};return{firePastePreProcess:a,firePastePostProcess:b,firePastePlainTextToggle:c}}),g("7",["6"],function(a){return a("tinymce.dom.RangeUtils")}),g("8",["6"],function(a){return a("tinymce.Env")}),g("9",["6"],function(a){return a("tinymce.util.Delay")}),g("a",["6"],function(a){return a("tinymce.util.Tools")}),g("b",["6"],function(a){return a("tinymce.util.VK")}),g("c",[],function(){var a="x-tinymce/html",b="<!-- "+a+" -->&quot
 ;,c=function(a){return b+a},d=function(a){return a.replace(b,"")},e=function(a){return a.indexOf(b)!==-1};return{mark:c,unmark:d,isMarked:e,internalHtmlMime:function(){return a}}}),g("j",["6"],function(a){return a("tinymce.html.Entities")}),g("d",["a","j"],function(a,b){var c=function(a){return!/<(?:\/?(?!(?:div|p|br|span)>)\w+|(?:(?!(?:span style="white-space:\s?pre;?">)|br\s?\/>))\w+\s[^>]+)>/i.test(a)},d=function(a){return a.replace(/\r?\n/g,"<br>")},e=function(a,c){var d,e=[],f="<"+a;if("object"==typeof c){for(d in c)c.hasOwnProperty(d)&&e.push(d+'="'+b.encodeAllRaw(c[d])+'"');e.length&&(f+=" "+e.join(" "))}return f+">"},f=function(b,c,d){var f=b.split(/\n\n/),g=e(c,d),h="</"+c+">",i=a.map(f,function(a){return a.split(/\n/).join("<br />")}),j=fu
 nction(a){return g+a+h};return 1===i.length?i[0]:a.map(i,j).join("")},g=function(a,b,c){return b?f(a,b,c):d(a)};return{isPlainText:c,convert:g,toBRs:d,toBlockElements:f}}),g("e",["a","8"],function(a,b){return function(c){var d,e="%MCEPASTEBIN%",f=function(){function a(a){var b,c,e,f=a.startContainer;if(b=a.getClientRects(),b.length)return b[0];if(a.collapsed&&1==f.nodeType){for(e=f.childNodes[d.startOffset];e&&3==e.nodeType&&!e.data.length;)e=e.nextSibling;if(e)return"BR"==e.tagName&&(c=h.doc.createTextNode("\ufeff"),e.parentNode.insertBefore(c,e),a=h.createRng(),a.setStartBefore(c),a.setEndAfter(c),b=a.getClientRects(),h.remove(c)),b.length?b[0]:void 0}}var f,g,h=c.dom,i=c.getBody(),j=c.dom.getViewPort(c.getWin()),k=j.y,l=20;if(d=c.selection.getRng(),c.inline&&(g=c.selection.getScrollContainer(),g&&g.scrollTop>0&&(k=g.scrollTop)),d.getClientRects){var m=a
 (d);if(m)l=k+(m.top-h.getPos(i).y);else{l=k;var n=d.startContainer;n&&(3==n.nodeType&&n.parentNode!=i&&(n=n.parentNode),1==n.nodeType&&(l=h.getPos(n,g||i).y))}}f=c.dom.add(c.getBody(),"div",{id:"mcepastebin",contentEditable:!0,"data-mce-bogus":"all",style:"position: absolute; top: "+l+"px; width: 10px; height: 10px; overflow: hidden; opacity: 0"},e),(b.ie||b.gecko)&&h.setStyle(f,"left","rtl"==h.getStyle(i,"direction",!0)?65535:-65535),h.bind(f,"beforedeactivate focusin focusout",function(a){a.stopPropagation()}),f.focus(),c.selection.select(f,!0)},g=function(){if(h()){for(var a;a=c.dom.get("mcepastebin");)c.dom.remove(a),c.dom.unbind(a);d&&c.selection.setRng(d)}d=null},h=function(){return c.dom.get("mcepastebin")},i=function(){var b,d,e,f,g,h=function(a,b){a.appendChild(b),c.dom.remove(b,!0)};for(d=a.grep(c.getBody().
 childNodes,function(a){return"mcepastebin"===a.id}),b=d.shift(),a.each(d,function(a){h(b,a)}),f=c.dom.select("div[id=mcepastebin]",b),e=f.length-1;e>=0;e--)g=c.dom.create("div"),b.insertBefore(g,f[e]),h(g,f[e]);return b?b.innerHTML:""},j=function(){return d},k=function(a){return a===e},l=function(a){return a&&"mcepastebin"===a.id},m=function(){var a=h();return l(a)&&k(a.innerHTML)};return{create:f,remove:g,getEl:h,getHtml:i,getLastRng:j,isDefault:m,isDefaultContent:k}}}),g("k",["6"],function(a){return a("tinymce.html.DomParser")}),g("l",["6"],function(a){return a("tinymce.html.Schema")}),g("m",["6"],function(a){return a("tinymce.html.Serializer")}),g("n",["6"],function(a){return a("tinymce.html.Node")}),g("h",["a","k","l"],function(a,b,c){function d(b,c){ret
 urn a.each(c,function(a){b=a.constructor==RegExp?b.replace(a,""):b.replace(a[0],a[1])}),b}function e(e){function f(a){var b=a.name,c=a;if("br"===b)return void(i+="\n");if(j[b]&&(i+=" "),k[b])return void(i+=" ");if(3==a.type&&(i+=a.value),!a.shortEnded&&(a=a.firstChild))do f(a);while(a=a.next);l[b]&&c.next&&(i+="\n","p"==b&&(i+="\n"))}var g=new c,h=new b({},g),i="",j=g.getShortEndedElements(),k=a.makeMap("script noscript style textarea video audio iframe object"," "),l=g.getBlockElements();return e=d(e,[/<!\[[^\]]+\]>/g]),f(h.parse(e)),i}function f(a){function b(a,b,c){return b||c?"\xa0":" "}return a=d(a,[/^[\s\S]*<body[^>]*>\s*|\s*<\/body[^>]*>[\s\S]*$/gi,/<!--StartFragment-->|<!--EndFragment-->/g,[/( ?)<span class="Apple-converted-space">\u00a0<\/span&g
 t;( ?)/g,b],/<br class="Apple-interchange-newline">/g,/<br>$/i])}function g(a){var b=0;return function(){return a+b++}}var h=function(){return navigator.userAgent.indexOf(" Edge/")!==-1};return{filter:d,innerText:e,trimHtml:f,createIdGenerator:g,isMsEdge:h}}),g("i",["a","k","l","m","n","h"],function(a,b,c,d,e,f){function g(a){return/<font face="Times New Roman"|class="?Mso|style="[^"]*\bmso-|style='[^'']*\bmso-|w:WordDocument/i.test(a)||/class="OutlineElement/.test(a)||/id="?docs\-internal\-guid\-/.test(a)}function h(b){var c,d;return d=[/^[IVXLMCD]{1,2}\.[ \u00a0]/,/^[ivxlmcd]{1,2}\.[ \u00a0]/,/^[a-z]{1,2}[\.\)][ \u00a0]/,/^[A-Z]{1,2}[\.\)][ \u00a0]/,/^[0-9]+\.[ \u00a0]/,/^[\u3007\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d]+\.[ \u00a0]/,/^[\u58f1\u5f10\u53c2\u56db\u4f0d\u516d\u4e03\u516b\u4e5d\u62fe]+\.[ \u00a0]/],b=b.replace(/^[\u00
 a0 ]+/,""),a.each(d,function(a){if(a.test(b))return c=!0,!1}),c}function i(a){return/^[\s\u00a0]*[\u2022\u00b7\u00a7\u25CF]\s*/.test(a)}function j(a){function b(a){var c="";if(3===a.type)return a.value;if(a=a.firstChild)do c+=b(a);while(a=a.next);return c}function c(a,b){if(3===a.type&&b.test(a.value))return a.value=a.value.replace(b,""),!1;if(a=a.firstChild)do if(!c(a,b))return!1;while(a=a.next);return!0}function d(a){if(a._listIgnore)return void a.remove();if(a=a.firstChild)do d(a);while(a=a.next)}function f(a,b,f){var h=a._listLevel||k;h!=k&&(h<k?g&&(g=g.parent.parent):(j=g,g=null)),g&&g.name==b?g.append(a):(j=j||g,g=new e(b,1),f>1&&g.attr("start",""+f),a.wrap(g)),a.name="li",h>k&&j&&j.lastChild.append(g),k=h,d(a),c(a,/^\u00a0+/),c(a,/^\s*([\u2022\u00b7\u00a7\u25CF]|\w+\.)/),c(a,/^\u00a0+/)}for(var g,j,k=1,l=[],m=a.firstChild;"undefined"!=typeof m
 &&null!==m;)if(l.push(m),m=m.walk(),null!==m)for(;"undefined"!=typeof m&&m.parent!==a;)m=m.walk();for(var n=0;n<l.length;n++)if(a=l[n],"p"==a.name&&a.firstChild){var o=b(a);if(i(o)){f(a,"ul");continue}if(h(o)){var p=/([0-9]+)\./.exec(o),q=1;p&&(q=parseInt(p[1],10)),f(a,"ol",q);continue}if(a._listLevel){f(a,"ul",1);continue}g=null}else j=g,g=null}function k(b,c,d,f){var g,h={},i=b.dom.parseStyle(f);return a.each(i,function(a,e){switch(e){case"mso-list":g=/\w+ \w+([0-9]+)/i.exec(f),g&&(d._listLevel=parseInt(g[1],10)),/Ignore/i.test(a)&&d.firstChild&&(d._listIgnore=!0,d.firstChild._listIgnore=!0);break;case"horiz-align":e="text-align";break;case"vert-align":e="vertical-align";break;case"font-color":case"mso-foreground":e="color";break;case"mso-background":case"mso-highlight":e=&qu
 ot;background";break;case"font-weight":case"font-style":return void("normal"!=a&&(h[e]=a));case"mso-element":if(/^(comment|comment-list)$/i.test(a))return void d.remove()}return 0===e.indexOf("mso-comment")?void d.remove():void(0!==e.indexOf("mso-")&&("all"==b.settings.paste_retain_style_properties||c&&c[e])&&(h[e]=a))}),/(bold)/i.test(h["font-weight"])&&(delete h["font-weight"],d.wrap(new e("b",1))),/(italic)/i.test(h["font-style"])&&(delete h["font-style"],d.wrap(new e("i",1))),h=b.dom.serializeStyle(h,d.name),h?h:null}var l=function(e,g){var h,i;h=e.settings.paste_retain_style_properties,h&&(i=a.makeMap(h.split(/[, ]/))),g=f.filter(g,[/<br class="?Apple-interchange-newline"?>/gi,/<b[^>]+id="?docs-internal-[^>]*>/gi,/<!--[\s\S]+?-->/gi,/<(!|script[^&gt
 ;]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|img|meta|link|style|\w:\w+)(?=[\s\/>]))[^>]*>/gi,[/<(\/?)s>/gi,"<$1strike>"],[/&nbsp;/gi,"\xa0"],[/<span\s+style\s*=\s*"\s*mso-spacerun\s*:\s*yes\s*;?\s*"\s*>([\s\u00a0]*)<\/span>/gi,function(a,b){return b.length>0?b.replace(/./," ").slice(Math.floor(b.length/2)).split("").join("\xa0"):""}]]);var l=e.settings.paste_word_valid_elements;l||(l="-strong/b,-em/i,-u,-span,-p,-ol,-ul,-li,-h1,-h2,-h3,-h4,-h5,-h6,-p/div,-a[href|name],sub,sup,strike,br,del,table[width],tr,td[colspan|rowspan|width],th[colspan|rowspan|width],thead,tfoot,tbody");var m=new c({valid_elements:l,valid_children:"-li[p]"});a.each(m.elements,function(a){a.attributes["class"]||(a.attributes["class"]={},a.attributesOrder.push("class")),a.attributes.style||(a.attributes.style={},a.attributesOrder.push("style&
 quot;))});var n=new b({},m);n.addAttributeFilter("style",function(a){for(var b,c=a.length;c--;)b=a[c],b.attr("style",k(e,i,b,b.attr("style"))),"span"==b.name&&b.parent&&!b.attributes.length&&b.unwrap()}),n.addAttributeFilter("class",function(a){for(var b,c,d=a.length;d--;)b=a[d],c=b.attr("class"),/^(MsoCommentReference|MsoCommentText|msoDel)$/i.test(c)&&b.remove(),b.attr("class",null)}),n.addNodeFilter("del",function(a){for(var b=a.length;b--;)a[b].remove()}),n.addNodeFilter("a",function(a){for(var b,c,d,e=a.length;e--;)if(b=a[e],c=b.attr("href"),d=b.attr("name"),c&&c.indexOf("#_msocom_")!=-1)b.remove();else if(c&&0===c.indexOf("file://")&&(c=c.split("#")[1],c&&(c="#"+c)),c||d){if(d&&!/^_?(?:toc|edn|ftn)/i.test(d)){b.unwrap();continue}b.attr({href:c,name:d})}else b
 .unwrap()});var o=n.parse(g);return e.settings.paste_convert_word_fake_lists!==!1&&j(o),g=new d({validate:e.settings.validate},m).serialize(o)},m=function(a,b){return a.settings.paste_enable_default_filters===!1?b:l(a,b)};return{preProcess:m,isWordContent:g}}),g("f",["2","i"],function(a,b){var c=function(a,b){return{content:a,cancelled:b}},d=function(b,d,e,f){var g=b.dom.create("div",{style:"display:none"},d),h=a.firePastePostProcess(b,g,e,f);return c(h.node.innerHTML,h.isDefaultPrevented())},e=function(b,e,f,g){var h=a.firePastePreProcess(b,e,f,g);return b.hasEventListeners("PastePostProcess")&&!h.isDefaultPrevented()?d(b,h.content,f,g):c(h.content,h.isDefaultPrevented())},f=function(a,c,d){var f=b.isWordContent(c),g=f?b.preProcess(a,c):c;return e(a,g,d,f)};return{process:f}}),g("g",["a"],function(a){var b=function(a){return/^https?:\/\/[\w\?\-\/+=.&%@~#]+$/i.test(a)},c=function(a){r
 eturn b(a)&&/.(gif|jpe?g|png)$/.test(a)},d=function(a,b,c){return a.undoManager.extra(function(){c(a,b)},function(){a.insertContent('<img src="'+b+'">')}),!0},e=function(a,b,c){return a.undoManager.extra(function(){c(a,b)},function(){a.execCommand("mceInsertLink",!1,b)}),!0},f=function(a,c,d){return!(a.selection.isCollapsed()!==!1||!b(c))&&e(a,c,d)},g=function(a,b,e){return!!c(b)&&d(a,b,e)},h=function(a,b){return a.insertContent(b,{merge:a.settings.paste_merge_formats!==!1,paste:!0}),!0},i=function(b,c){a.each([f,g,h],function(a){return a(b,c,h)!==!0})},j=function(a,b){a.settings.smart_paste===!1?h(a,b):i(a,b)};return{isImageUrl:c,isAbsoluteUrl:b,insertContent:j}}),g("3",["7","8","9","a","b","c","d","e","f","g","h"],function(a,b,c,d,e,f,g,h,i,j,k){return function(l){function m(a,b){var c=b?b:f.isMarked(a),d=i.proces
 s(l,f.unmark(a),c);d.cancelled===!1&&j.insertContent(l,d.content)}function n(a){a=l.dom.encode(a).replace(/\r\n/g,"\n"),a=g.convert(a,l.settings.forced_root_block,l.settings.forced_root_block_attrs),m(a,!1)}function o(a){var b={};if(a){if(a.getData){var c=a.getData("Text");c&&c.length>0&&c.indexOf(G)==-1&&(b["text/plain"]=c)}if(a.types)for(var d=0;d<a.types.length;d++){var e=a.types[d];try{b[e]=a.getData(e)}catch(a){b[e]=""}}}return b}function p(a){var b=o(a.clipboardData||l.getDoc().dataTransfer);return k.isMsEdge()?d.extend(b,{"text/html":""}):b}function q(a){return y(a,"text/html")||y(a,"text/plain")}function r(a){var b;return b=a.indexOf(","),b!==-1?a.substr(b+1):null}function s(a,b){return!a.images_dataimg_filter||a.images_dataimg_filter(b)}function t(a){var b=a.match(/([\s\S]+?)\.(?:jpeg|jpg|png|gif)$/i);return b?l.dom.encode(b[1]):null}function u(a,b
 ,c){a&&(l.selection.setRng(a),a=null);var d=b.result,e=r(d),f=H(),g=l.settings.images_reuse_filename&&c.name?t(c.name):f,h=new Image;if(h.src=d,s(l.settings,h)){var i,j,k=l.editorUpload.blobCache;j=k.findFirst(function(a){return a.base64()===e}),j?i=j:(i=k.create(f,c,e,g),k.add(i)),m('<img src="'+i.blobUri()+'">',!1)}else m('<img src="'+d+'">',!1)}function v(a,b){function c(c){var d,e,f,g=!1;if(c)for(d=0;d<c.length;d++)if(e=c[d],/^image\/(jpeg|png|gif|bmp)$/.test(e.type)){var h=e.getAsFile?e.getAsFile():e;f=new FileReader,f.onload=u.bind(null,b,f,h),f.readAsDataURL(h),a.preventDefault(),g=!0}return g}var d=a.clipboardData||a.dataTransfer;if(l.settings.paste_data_images&&d)return c(d.items)||c(d.files)}function w(a){var b=a.clipboardData;return navigator.userAgent.indexOf("Android")!=-1&&b&&b.items&&0===b.items.length}function x(b){return a.getCaretRangeFromPoint(b.clientX,b.clientY,l.getDoc(
 ))}function y(a,b){return b in a&&a[b].length>0}function z(a){return e.metaKeyPressed(a)&&86==a.keyCode||a.shiftKey&&45==a.keyCode}function A(){function a(a,b,c,d){var e,h;return y(a,"text/html")?e=a["text/html"]:(e=F.getHtml(),d=d?d:f.isMarked(e),F.isDefaultContent(e)&&(c=!0)),e=k.trimHtml(e),F.remove(),h=d===!1&&g.isPlainText(e),e.length&&!h||(c=!0),c&&(e=y(a,"text/plain")&&h?a["text/plain"]:k.innerText(e)),F.isDefaultContent(e)?void(b||l.windowManager.alert("Please use Ctrl+V/Cmd+V keyboard shortcuts to paste contents.")):void(c?n(e):m(e,d))}function d(a){var b=a["text/plain"];return!!b&&0===b.indexOf("file://")}l.on("keydown",function(a){function c(a){z(a)&&!a.isDefaultPrevented()&&F.remove()}if(z(a)&&!a.isDefaultPrevented()){if(B=a.shiftKey&&86==a.keyCode,B&&b.webkit&&navigator.
 userAgent.indexOf("Version/")!=-1)return;if(a.stopImmediatePropagation(),D=(new Date).getTime(),b.ie&&B)return a.preventDefault(),void l.fire("paste",{ieFake:!0});F.remove(),F.create(),l.once("keyup",c),l.once("paste",function(){l.off("keyup",c)})}});var e=function(){return F.getLastRng()||l.selection.getRng()};l.on("paste",function(d){var g=(new Date).getTime(),h=p(d),i=(new Date).getTime()-g,j=(new Date).getTime()-D-i<1e3,k="text"==C.pasteFormat||B,m=y(h,f.internalHtmlMime());return B=!1,d.isDefaultPrevented()||w(d)?void F.remove():!q(h)&&v(d,e())?void F.remove():(j||d.preventDefault(),!b.ie||j&&!d.ieFake||y(h,"text/html")||(F.create(),l.dom.bind(F.getEl(),"paste",function(a){a.stopPropagation()}),l.getDoc().execCommand("Paste",!1,null),h["text/html"]=F.getHtml()),void(y(h,"text/html")?(d.preventDefault(),m||(m=f.isMarked(h["text/h
 tml"])),a(h,j,k,m)):c.setEditorTimeout(l,function(){a(h,j,k,m)},0)))}),l.on("dragstart dragend",function(a){E="dragstart"==a.type}),l.on("drop",function(a){var b,e;if(e=x(a),!a.isDefaultPrevented()&&!E){b=o(a.dataTransfer);var g=y(b,f.internalHtmlMime());if((q(b)&&!d(b)||!v(a,e))&&e&&l.settings.paste_filter_drop!==!1){var h=b["mce-internal"]||b["text/html"]||b["text/plain"];h&&(a.preventDefault(),c.setEditorTimeout(l,function(){l.undoManager.transact(function(){b["mce-internal"]&&l.execCommand("Delete"),l.selection.setRng(e),h=k.trimHtml(h),b["text/html"]?m(h,g):n(h)})}))}}}),l.on("dragover dragend",function(a){l.settings.paste_data_images&&a.preventDefault()})}var B,C=this,D=0,E=!1,F=new h(l),G="data:text/mce-internal,",H=k.createIdGenerator("mceclip");C.pasteHtml=m,C.pasteText=n,C.pasteImageData=v,l.on(
 "preInit",function(){A(),l.parser.addNodeFilter("img",function(a,c,d){function e(a){return a.data&&a.data.paste===!0}function f(a){a.attr("data-mce-object")||j===b.transparentSrc||a.remove()}function g(a){return 0===a.indexOf("webkit-fake-url")}function h(a){return 0===a.indexOf("data:")}if(!l.settings.paste_data_images&&e(d))for(var i=a.length;i--;){var j=a[i].attributes.map.src;j&&(g(j)?f(a[i]):!l.settings.allow_html_data_urls&&h(j)&&f(a[i]))}})})}}),g("4",["8","c","h"],function(a,b,c){var d=function(){},e=function(b){return a.iOS===!1&&void 0!==b&&"function"==typeof b.setData&&c.isMsEdge()!==!0},f=function(a,c,d){if(!e(a))return!1;try{return a.clearData(),a.setData("text/html",c),a.setData("text/plain",d),a.setData(b.internalHtmlMime(),c),!0}catch(a){return!1}},g=function(a,b,c,d){f(a.clipboardData,
 b.html,b.text)?(a.preventDefault(),d()):c(b.html,d)},h=function(a){return function(c,d){var e=b.mark(c),f=a.dom.create("div",{contenteditable:"false","data-mce-bogus":"all"}),g=a.dom.create("div",{contenteditable:"true"},e);a.dom.setStyles(f,{position:"fixed",left:"-3000px",width:"1000px",overflow:"hidden"}),f.appendChild(g),a.dom.add(a.getBody(),f);var h=a.selection.getRng();g.focus();var i=a.dom.createRng();i.selectNodeContents(g),a.selection.setRng(i),setTimeout(function(){f.parentNode.removeChild(f),a.selection.setRng(h),d()},0)}},i=function(a){return{html:a.selection.getContent({contextual:!0}),text:a.selection.getContent({format:"text"})}},j=function(a){return function(b){a.selection.isCollapsed()===!1&&g(b,i(a),h(a),function(){setTimeout(function(){a.execCommand("Delete")},0)})}},k=function(a){return function(b){a.selection.isCollapsed()===!1&&am
 p;g(b,i(a),h(a),d)}},l=function(a){a.on("cut",j(a)),a.on("copy",k(a))};return{register:l}}),g("5",["8","a","i","h"],function(a,b,c,d){function e(a,b){a.on("PastePreProcess",function(c){c.content=b(a,c.content,c.internal,c.wordContent)})}function f(a,b){a.on("PastePostProcess",function(c){b(a,c.node)})}function g(a,e){if(!c.isWordContent(e))return e;var f=[];b.each(a.schema.getBlockElements(),function(a,b){f.push(b)});var g=new RegExp("(?:<br>&nbsp;[\\s\\r\\n]+|<br>)*(<\\/?("+f.join("|")+")[^>]*>)(?:<br>&nbsp;[\\s\\r\\n]+|<br>)*","g");return e=d.filter(e,[[g,"$1"]]),e=d.filter(e,[[/<br><br>/g,"<BR><BR>"],[/<br>/g," "],[/<BR><BR>/g,"<br>"]])}function h(a,b,c,d){if(d||c)return b;var e=a.settings.paste_webkit_styles;if(a.settings.pa
 ste_remove_styles_if_webkit===!1||"all"==e)return b;if(e&&(e=e.split(/[, ]/)),e){var f=a.dom,g=a.selection.getNode();b=b.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi,function(a,b,c,d){var h=f.parseStyle(f.decode(c),"span"),i={};if("none"===e)return b+d;for(var j=0;j<e.length;j++){var k=h[e[j]],l=f.getStyle(g,e[j],!0);/color/.test(e[j])&&(k=f.toHex(k),l=f.toHex(l)),l!=k&&(i[e[j]]=k)}return i=f.serializeStyle(i,"span"),i?b+' style="'+i+'"'+d:b+d})}else b=b.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi,"$1$3");return b=b.replace(/(<[^>]+) data-mce-style="([^"]+)"([^>]*>)/gi,function(a,b,c,d){return b+' style="'+c+'"'+d})}function i(a,b){a.$("a",b).find("font,u").each(function(b,c){a.dom.remove(c,!0)})}var j=function(b){a.webkit&&e(b,h),a.ie&&(e(b,g),f(b,i))};return{setup:j}}),
 g("0",["1","2","3","4","5"],function(a,b,c,d,e){var f;return a.add("paste",function(g){function h(){return f||g.settings.paste_plaintext_inform===!1}function i(){if("text"==k.pasteFormat)k.pasteFormat="html",b.firePastePlainTextToggle(g,!1);else if(k.pasteFormat="text",b.firePastePlainTextToggle(g,!0),!h()){var a=g.translate("Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.");g.notificationManager.open({text:a,type:"info"}),f=!0}g.focus()}function j(){var a=this;a.active("text"===k.pasteFormat),g.on("PastePlainTextToggle",function(b){a.active(b.state)})}var k,l=this,m=g.settings;return/(^|[ ,])powerpaste([, ]|$)/.test(m.plugins)&&a.get("powerpaste")?void("undefined"!=typeof console&&console.log&&console.log("PowerPaste is incompatible wit
 h Paste plugin! Remove 'paste' from the 'plugins' option.")):(l.clipboard=k=new c(g),l.quirks=e.setup(g),g.settings.paste_as_text&&(l.clipboard.pasteFormat="text"),m.paste_preprocess&&g.on("PastePreProcess",function(a){m.paste_preprocess.call(l,l,a)}),m.paste_postprocess&&g.on("PastePostProcess",function(a){m.paste_postprocess.call(l,l,a)}),g.addCommand("mceInsertClipboardContent",function(a,b){b.content&&l.clipboard.pasteHtml(b.content,b.internal),b.text&&l.clipboard.pasteText(b.text)}),g.settings.paste_block_drop&&g.on("dragend dragover draggesture dragdrop drop drag",function(a){a.preventDefault(),a.stopPropagation()}),g.settings.paste_data_images||g.on("drop",function(a){var b=a.dataTransfer;b&&b.files&&b.files.length>0&&a.preventDefault()}),g.addCommand("mceTogglePlainTextPaste",i),g.addButton("pastetext",{icon:"pas
 tetext",tooltip:"Paste as text",onclick:i,onPostRender:j}),g.addMenuItem("pastetext",{text:"Paste as text",selectable:!0,active:k.pasteFormat,onclick:i,onPostRender:j}),void d.register(g))}),function(){}}),d("0")()}();
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span></span></pre></div>
<a id="trunksrcwpincludesjstinymceskinslightgraycontentinlinemincss"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/tinymce/skins/lightgray/content.inline.min.css</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/tinymce/skins/lightgray/content.inline.min.css   2017-09-26 20:32:46 UTC (rev 41603)
+++ trunk/src/wp-includes/js/tinymce/skins/lightgray/content.inline.min.css     2017-09-26 21:14:28 UTC (rev 41604)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1 +1 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-.mce-content-body .mce-reset{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:black;font-family:Arial;font-size:11px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;line-height:normal;font-weight:normal;text-align:left;-webkit-tap-highlight-color:transparent;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr;max-width:none}.mce-object{border:1px dotted #3A3A3A;background:#D5D5D5 url(img/object.gif) no-repeat center}.mce-preview-object{display:inline-block;position:relative;margin:0 2px 0 2px;line-height:0;border:1px solid gray}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-preview-object .mce-shim{position:absolute;top:0;left:0;width:100%;height:100%;background:url(data:image/gif;base64,R0lGODlhAQABAI
 AAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}figure.align-left{float:left}figure.align-right{float:right}figure.image.align-center{display:table;margin-left:auto;margin-right:auto}figure.image{display:inline-block;border:1px solid gray;margin:0 2px 0 1px;background:#f5f2f0}figure.image img{margin:8px 8px 0 8px}figure.image figcaption{margin:6px 8px 6px 8px;text-align:center}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc li{list-style-type:none}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px;page-break-before:always}@media print{.mce-pagebreak{border:0}}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px !important;height:9px !important;border:1px dotted #3A3A3A;background:#D5D5D5 url(img/anchor.gif) no-repeat center}.mce-nbsp,.mce-shy{background:#AAA}.mce
 -shy::after{content:'-'}.mce-match-marker{background:#AAA;color:#fff}.mce-match-marker-selected{background:#3399ff;color:#fff}.mce-spellchecker-word{border-bottom:2px solid #F00;cursor:default}.mce-spellchecker-grammar{border-bottom:2px solid #008000;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td[data-mce-selected],th[data-mce-selected]{background-color:#3399ff !important}.mce-edit-focus{outline:1px dotted #333}.mce-resize-bar-dragging{background-color:blue;opacity:.25;filter:alpha(opacity=25);zoom:1}.mce-content-body p,.mce-content-body div,.mce-content-body h1,.mce-content-body h2,.mce-content-body h3,.mce-content-body h4,.mce-content-body h5,.mce-content-body h6{line-height:1.2em}.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus{outline:2px solid #2d8ac7}.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover{outline:2px solid #7ACAFF}.mce-content-body *[contentEditable
 =false][data-mce-selected]{outline:2px solid #2d8ac7}.mce-content-body a[data-mce-selected],.mce-content-body code[data-mce-selected]{background:#bfe6ff}.mce-content-body hr{cursor:default}
</del><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+.word-wrap{word-wrap:break-word;-ms-word-break:break-all;word-break:break-all;word-break:break-word;-ms-hyphens:auto;-moz-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}.mce-content-body .mce-reset{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:black;font-family:Arial;font-size:11px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;line-height:normal;font-weight:normal;text-align:left;-webkit-tap-highlight-color:transparent;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr;max-width:none}.mce-object{border:1px dotted #3A3A3A;background:#D5D5D5 url(img/object.gif) no-repeat center}.mce-preview-object{display:inline-block;position:relative;margin:0 2px 0 2px;line-height:0;border:1px solid gray}.mce-preview-object[data-mce-selected=&quo
 t;2"] .mce-shim{display:none}.mce-preview-object .mce-shim{position:absolute;top:0;left:0;width:100%;height:100%;background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}figure.align-left{float:left}figure.align-right{float:right}figure.image.align-center{display:table;margin-left:auto;margin-right:auto}figure.image{display:inline-block;border:1px solid gray;margin:0 2px 0 1px;background:#f5f2f0}figure.image img{margin:8px 8px 0 8px}figure.image figcaption{margin:6px 8px 6px 8px;text-align:center}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc li{list-style-type:none}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px;page-break-before:always}@media print{.mce-pagebreak{border:0}}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-
 only;width:9px !important;height:9px !important;border:1px dotted #3A3A3A;background:#D5D5D5 url(img/anchor.gif) no-repeat center}.mce-nbsp,.mce-shy{background:#AAA}.mce-shy::after{content:'-'}.mce-match-marker{background:#AAA;color:#fff}.mce-match-marker-selected{background:#3399ff;color:#fff}.mce-spellchecker-word{border-bottom:2px solid #F00;cursor:default}.mce-spellchecker-grammar{border-bottom:2px solid #008000;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td[data-mce-selected],th[data-mce-selected]{background-color:#3399ff !important}.mce-edit-focus{outline:1px dotted #333}.mce-resize-bar-dragging{background-color:blue;opacity:.25;filter:alpha(opacity=25);zoom:1}.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus{outline:2px solid #2d8ac7}.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover{outline:2px solid #7ACAFF}.mce-content-body *[contentEditable=false][data-mce-
 selected]{outline:2px solid #2d8ac7}.mce-content-body a[data-mce-selected],.mce-content-body code[data-mce-selected],.mce-content-body b[data-mce-selected],.mce-content-body i[data-mce-selected],.mce-content-body em[data-mce-selected],.mce-content-body strong[data-mce-selected],.mce-content-body sup[data-mce-selected],.mce-content-body sub[data-mce-selected]{background:#bfe6ff}.mce-content-body hr{cursor:default}.mce-content-body{line-height:1.3}
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span></span></pre></div>
<a id="trunksrcwpincludesjstinymceskinslightgraycontentmincss"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/tinymce/skins/lightgray/content.min.css</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/tinymce/skins/lightgray/content.min.css  2017-09-26 20:32:46 UTC (rev 41603)
+++ trunk/src/wp-includes/js/tinymce/skins/lightgray/content.min.css    2017-09-26 21:14:28 UTC (rev 41604)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1 +1 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-body{background-color:#FFFFFF;color:#000000;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:14px;scrollbar-3dlight-color:#F0F0EE;scrollbar-arrow-color:#676662;scrollbar-base-color:#F0F0EE;scrollbar-darkshadow-color:#DDDDDD;scrollbar-face-color:#E0E0DD;scrollbar-highlight-color:#F0F0EE;scrollbar-shadow-color:#F0F0EE;scrollbar-track-color:#F5F5F5}td,th{font-family:Verdana,Arial,Helvetica,sans-serif;font-size:14px}.mce-content-body .mce-reset{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:black;font-family:Arial;font-size:11px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;line-height:normal;font-weight:normal;text-align:left;-webkit-tap-highlight-color:transparent;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr;max-width:
 none}.mce-object{border:1px dotted #3A3A3A;background:#D5D5D5 url(img/object.gif) no-repeat center}.mce-preview-object{display:inline-block;position:relative;margin:0 2px 0 2px;line-height:0;border:1px solid gray}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-preview-object .mce-shim{position:absolute;top:0;left:0;width:100%;height:100%;background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}figure.align-left{float:left}figure.align-right{float:right}figure.image.align-center{display:table;margin-left:auto;margin-right:auto}figure.image{display:inline-block;border:1px solid gray;margin:0 2px 0 1px;background:#f5f2f0}figure.image img{margin:8px 8px 0 8px}figure.image figcaption{margin:6px 8px 6px 8px;text-align:center}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc li{list-style-type:none}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:1
 5px;page-break-before:always}@media print{.mce-pagebreak{border:0}}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px !important;height:9px !important;border:1px dotted #3A3A3A;background:#D5D5D5 url(img/anchor.gif) no-repeat center}.mce-nbsp,.mce-shy{background:#AAA}.mce-shy::after{content:'-'}.mce-match-marker{background:#AAA;color:#fff}.mce-match-marker-selected{background:#3399ff;color:#fff}.mce-spellchecker-word{border-bottom:2px solid #F00;cursor:default}.mce-spellchecker-grammar{border-bottom:2px solid #008000;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td[data-mce-selected],th[data-mce-selected]{background-color:#3399ff !important}.mce-edit-focus{outline:1px dotted #333}.mce-resize-bar-dragging{background-color:blue;opacity:.25;filter:alpha(opacity=25);zo
 om:1}.mce-content-body p,.mce-content-body div,.mce-content-body h1,.mce-content-body h2,.mce-content-body h3,.mce-content-body h4,.mce-content-body h5,.mce-content-body h6{line-height:1.2em}.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus{outline:2px solid #2d8ac7}.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover{outline:2px solid #7ACAFF}.mce-content-body *[contentEditable=false][data-mce-selected]{outline:2px solid #2d8ac7}.mce-content-body a[data-mce-selected],.mce-content-body code[data-mce-selected]{background:#bfe6ff}.mce-content-body hr{cursor:default}
</del><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+body{background-color:#FFFFFF;color:#000000;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:14px;line-height:1.3;scrollbar-3dlight-color:#F0F0EE;scrollbar-arrow-color:#676662;scrollbar-base-color:#F0F0EE;scrollbar-darkshadow-color:#DDDDDD;scrollbar-face-color:#E0E0DD;scrollbar-highlight-color:#F0F0EE;scrollbar-shadow-color:#F0F0EE;scrollbar-track-color:#F5F5F5}td,th{font-family:Verdana,Arial,Helvetica,sans-serif;font-size:14px}.word-wrap{word-wrap:break-word;-ms-word-break:break-all;word-break:break-all;word-break:break-word;-ms-hyphens:auto;-moz-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}.mce-content-body .mce-reset{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:black;font-family:Arial;font-size:11px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;line-height:nor
 mal;font-weight:normal;text-align:left;-webkit-tap-highlight-color:transparent;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr;max-width:none}.mce-object{border:1px dotted #3A3A3A;background:#D5D5D5 url(img/object.gif) no-repeat center}.mce-preview-object{display:inline-block;position:relative;margin:0 2px 0 2px;line-height:0;border:1px solid gray}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-preview-object .mce-shim{position:absolute;top:0;left:0;width:100%;height:100%;background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}figure.align-left{float:left}figure.align-right{float:right}figure.image.align-center{display:table;margin-left:auto;margin-right:auto}figure.image{display:inline-block;border:1px solid gray;margin:0 2px 0 1px;background:#f5f2f0}figure.image img{margin:8px 8px 0 8px}figure.image figcaption{margin:6px 8px 6px 8px;text-align:center}.mce-toc{bor
 der:1px solid gray}.mce-toc h2{margin:4px}.mce-toc li{list-style-type:none}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px;page-break-before:always}@media print{.mce-pagebreak{border:0}}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px !important;height:9px !important;border:1px dotted #3A3A3A;background:#D5D5D5 url(img/anchor.gif) no-repeat center}.mce-nbsp,.mce-shy{background:#AAA}.mce-shy::after{content:'-'}.mce-match-marker{background:#AAA;color:#fff}.mce-match-marker-selected{background:#3399ff;color:#fff}.mce-spellchecker-word{border-bottom:2px solid #F00;cursor:default}.mce-spellchecker-grammar{border-bottom:2px solid #008000;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td[data-mce-selected]
 ,th[data-mce-selected]{background-color:#3399ff !important}.mce-edit-focus{outline:1px dotted #333}.mce-resize-bar-dragging{background-color:blue;opacity:.25;filter:alpha(opacity=25);zoom:1}.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus{outline:2px solid #2d8ac7}.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover{outline:2px solid #7ACAFF}.mce-content-body *[contentEditable=false][data-mce-selected]{outline:2px solid #2d8ac7}.mce-content-body a[data-mce-selected],.mce-content-body code[data-mce-selected],.mce-content-body b[data-mce-selected],.mce-content-body i[data-mce-selected],.mce-content-body em[data-mce-selected],.mce-content-body strong[data-mce-selected],.mce-content-body sup[data-mce-selected],.mce-content-body sub[data-mce-selected]{background:#bfe6ff}.mce-content-body hr{cursor:default}
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span></span></pre></div>
<a id="trunksrcwpincludesjstinymceskinslightgrayskinmincss"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/tinymce/skins/lightgray/skin.min.css</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/tinymce/skins/lightgray/skin.min.css     2017-09-26 20:32:46 UTC (rev 41603)
+++ trunk/src/wp-includes/js/tinymce/skins/lightgray/skin.min.css       2017-09-26 21:14:28 UTC (rev 41604)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1 +1 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-.mce-container,.mce-container *,.mce-widget,.mce-widget *,.mce-reset{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:#333;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;-webkit-tap-highlight-color:transparent;line-height:normal;font-weight:normal;text-align:left;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr;max-width:none}.mce-widget button{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.mce-container *[unselectable]{-moz-user-select:none;-webkit-user-select:none;-o-user-select:none;user-select:none}.mce-fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.mce-fade.mce-in{opacity:1}.m
 ce-tinymce{visibility:inherit !important;position:relative}.mce-fullscreen{border:0;padding:0;margin:0;overflow:hidden;height:100%;z-index:100}div.mce-fullscreen{position:fixed;top:0;left:0;width:100%;height:auto}.mce-tinymce{display:block}.mce-wordcount{position:absolute;top:0;right:0;padding:8px}div.mce-edit-area{background:#FFF;filter:none}.mce-statusbar{position:relative}.mce-statusbar .mce-container-body{position:relative}.mce-fullscreen .mce-resizehandle{display:none}.mce-charmap{border-collapse:collapse}.mce-charmap td{cursor:default;border:1px solid rgba(0,0,0,0.2);width:20px;height:20px;line-height:20px;text-align:center;vertical-align:middle;padding:2px}.mce-charmap td div{text-align:center}.mce-charmap td:hover{background:#D9D9D9}.mce-grid td.mce-grid-cell div{border:1px solid #d6d6d6;width:15px;height:15px;margin:0;cursor:pointer}.mce-grid td.mce-grid-cell div:focus{border-color:#3498db}.mce-grid td.mce-grid-cell div[disabled]{cursor:not-allowed}.mce-grid{border-spacing:
 2px;border-collapse:separate}.mce-grid a{display:block;border:1px solid transparent}.mce-grid a:hover,.mce-grid a:focus{border-color:#3498db}.mce-grid-border{margin:0 4px 0 4px}.mce-grid-border a{border-color:#d6d6d6;width:13px;height:13px}.mce-grid-border a:hover,.mce-grid-border a.mce-active{border-color:#3498db;background:#3498db}.mce-text-center{text-align:center}div.mce-tinymce-inline{width:100%}.mce-colorbtn-trans div{text-align:center;vertical-align:middle;font-weight:bold;font-size:20px;line-height:16px;color:#707070}.mce-monospace{font-family:"Courier New",Courier,monospace}.mce-toolbar-grp{padding:2px 0}.mce-toolbar-grp .mce-flow-layout-item{margin-bottom:0}.mce-rtl .mce-wordcount{left:0;right:auto}.mce-container b{font-weight:bold}.mce-container p{margin-bottom:5px}.mce-container a{cursor:pointer;color:#2980b9}.mce-container a:hover{text-decoration:underline}.mce-container ul{margin-left:15px}.mce-container .mce-table-striped{border-collapse:collapse;margin:10px
 }.mce-container .mce-table-striped thead>tr{background-color:#fafafa}.mce-container .mce-table-striped thead>tr th{font-weight:bold}.mce-container .mce-table-striped td,.mce-container .mce-table-striped th{padding:5px}.mce-container .mce-table-striped tr:nth-child(even){background-color:#fafafa}.mce-container .mce-table-striped tbody>tr:hover{background-color:#e1e1e1}.mce-branding-powered-by{background-color:#f0f0f0;position:absolute;right:0;bottom:0;width:91px;height:9px;margin-right:-1px;margin-bottom:-1px;border:1px solid #c5c5c5;border-width:1px 1px 0 1px;padding:6px 6px 0 6px;background-image:url('data:image/gif;base64,R0lGODlhXwAJAIABAIiIiAAAACH5BAEKAAEALAAAAABfAAkAAAJxhBGpy+2PUnzqGNpmPNJqDIZSJY4m+KXLF3At2V6xPFfuvMF6J6fINTnhTr9XcaRC6pKvFYlZjDIszaXRSA3ijlXo9AlWindaldSJthJ55XAz6+ZWbVCOdojP77p8J8vlUSI4SHEnaEiYqOhARdhIWAAAOw');background-repeat:no-repeat;background-position:center center}.mce-croprect-container{position:absolute;top:0;left:0}.mce-croprect-handle{position:
 absolute;top:0;left:0;width:20px;height:20px;border:2px solid white}.mce-croprect-handle-nw{border-width:2px 0 0 2px;margin:-2px 0 0 -2px;cursor:nw-resize;top:100px;left:100px}.mce-croprect-handle-ne{border-width:2px 2px 0 0;margin:-2px 0 0 -20px;cursor:ne-resize;top:100px;left:200px}.mce-croprect-handle-sw{border-width:0 0 2px 2px;margin:-20px 2px 0 -2px;cursor:sw-resize;top:200px;left:100px}.mce-croprect-handle-se{border-width:0 2px 2px 0;margin:-20px 0 0 -20px;cursor:se-resize;top:200px;left:200px}.mce-croprect-handle-move{position:absolute;cursor:move;border:0}.mce-croprect-block{opacity:.3;filter:alpha(opacity=30);zoom:1;position:absolute;background:black}.mce-croprect-handle:focus{border-color:#3498db}.mce-croprect-handle-move:focus{outline:1px solid #3498db}.mce-imagepanel{overflow:auto;background:black}.mce-imagepanel-bg{position:absolute;background:url('data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==')}.mce-imagepanel img{p
 osition:absolute}.mce-imagetool.mce-btn .mce-ico{display:block;width:20px;height:20px;text-align:center;line-height:20px;font-size:20px;padding:5px}.mce-arrow-up{margin-top:12px}.mce-arrow-down{margin-top:-12px}.mce-arrow:before,.mce-arrow:after{position:absolute;left:50%;display:block;width:0;height:0;border-style:solid;border-color:transparent;content:""}.mce-arrow.mce-arrow-up:before{top:-9px;border-bottom-color:rgba(0,0,0,0.2);border-width:0 9px 9px;margin-left:-9px}.mce-arrow.mce-arrow-down:before{bottom:-9px;border-top-color:rgba(0,0,0,0.2);border-width:9px 9px 0;margin-left:-9px}.mce-arrow.mce-arrow-up:after{top:-8px;border-bottom-color:#f0f0f0;border-width:0 8px 8px;margin-left:-8px}.mce-arrow.mce-arrow-down:after{bottom:-8px;border-top-color:#f0f0f0;border-width:8px 8px 0;margin-left:-8px}.mce-arrow.mce-arrow-left:before,.mce-arrow.mce-arrow-left:after{margin:0}.mce-arrow.mce-arrow-left:before{left:8px}.mce-arrow.mce-arrow-left:after{left:9px}.mce-arrow.mce-arrow-
 right:before,.mce-arrow.mce-arrow-right:after{left:auto;margin:0}.mce-arrow.mce-arrow-right:before{right:8px}.mce-arrow.mce-arrow-right:after{right:9px}.mce-arrow.mce-arrow-center.mce-arrow.mce-arrow-left:before{left:-9px;top:50%;border-right-color:rgba(0,0,0,0.2);border-width:9px 9px 9px 0;margin-top:-9px}.mce-arrow.mce-arrow-center.mce-arrow.mce-arrow-left:after{left:-8px;top:50%;border-right-color:#f0f0f0;border-width:8px 8px 8px 0;margin-top:-8px}.mce-arrow.mce-arrow-center.mce-arrow.mce-arrow-left{margin-left:12px}.mce-arrow.mce-arrow-center.mce-arrow.mce-arrow-right:before{right:-9px;top:50%;border-left-color:rgba(0,0,0,0.2);border-width:9px 0 9px 9px;margin-top:-9px}.mce-arrow.mce-arrow-center.mce-arrow.mce-arrow-right:after{right:-8px;top:50%;border-left-color:#f0f0f0;border-width:8px 0 8px 8px;margin-top:-8px}.mce-arrow.mce-arrow-center.mce-arrow.mce-arrow-right{margin-left:-14px}.mce-edit-aria-container>.mce-container-body{display:flex}.mce-edit-aria-container>.mce-c
 ontainer-body .mce-edit-area{flex:1}.mce-edit-aria-container>.mce-container-body .mce-sidebar>.mce-container-body{display:flex;align-items:stretch;height:100%}.mce-edit-aria-container>.mce-container-body .mce-sidebar-panel{min-width:250px;max-width:250px;position:relative}.mce-edit-aria-container>.mce-container-body .mce-sidebar-panel>.mce-container-body{position:absolute;width:100%;height:100%;overflow:auto;top:0;left:0}.mce-sidebar-toolbar{border:0 solid rgba(0,0,0,0.2);border-left-width:1px}.mce-sidebar-toolbar .mce-btn.mce-active,.mce-sidebar-toolbar .mce-btn.mce-active:hover{border:1px solid transparent;border-color:transparent;background-color:#2d8ac7}.mce-sidebar-toolbar .mce-btn.mce-active button,.mce-sidebar-toolbar .mce-btn.mce-active:hover button,.mce-sidebar-toolbar .mce-btn.mce-active button i,.mce-sidebar-toolbar .mce-btn.mce-active:hover button i{color:#fff;text-shadow:1px 1px none}.mce-sidebar-panel{border:0 solid rgba(0,0,0,0.2);border-left-width:1px}
 .mce-container,.mce-container-body{display:block}.mce-autoscroll{overflow:hidden}.mce-scrollbar{position:absolute;width:7px;height:100%;top:2px;right:2px;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-scrollbar-h{top:auto;right:auto;left:2px;bottom:2px;width:100%;height:7px}.mce-scrollbar-thumb{position:absolute;background-color:#000;border:1px solid #888;border-color:rgba(85,85,85,0.6);width:5px;height:100%}.mce-scrollbar-h .mce-scrollbar-thumb{width:100%;height:5px}.mce-scrollbar:hover,.mce-scrollbar.mce-active{background-color:#AAA;opacity:.6;filter:alpha(opacity=60);zoom:1}.mce-scroll{position:relative}.mce-panel{border:0 solid #cacaca;border:0 solid rgba(0,0,0,0.2);background-color:#f0f0f0}.mce-floatpanel{position:absolute}.mce-floatpanel.mce-fixed{position:fixed}.mce-floatpanel .mce-arrow,.mce-floatpanel .mce-arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.mce-floatpanel .mce-arrow{border-width:11px}.mce-floatpanel .mc
 e-arrow:after{border-width:10px;content:""}.mce-floatpanel.mce-popover{filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;top:0;left:0;background:#FFF;border:1px solid rgba(0,0,0,0.2);border:1px solid rgba(0,0,0,0.25)}.mce-floatpanel.mce-popover.mce-bottom{margin-top:10px;*margin-top:0}.mce-floatpanel.mce-popover.mce-bottom>.mce-arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:rgba(0,0,0,0.2);border-bottom-color:rgba(0,0,0,0.25);top:-11px}.mce-floatpanel.mce-popover.mce-bottom>.mce-arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#FFF}.mce-floatpanel.mce-popover.mce-bottom.mce-start{margin-left:-22px}.mce-floatpanel.mce-popover.mce-bottom.mce-start>.mce-arrow{left:20px}.mce-floatpanel.mce-popover.mce-bottom.mce-end{margin-left:22px}.mce-floatpanel.mce-popover.mce-bottom.mce-end>.mce-arrow{right:10px;left:auto}.mce-fullscreen{border:0;padding:0;margin:0;overflow:hidden;heig
 ht:100%}div.mce-fullscreen{position:fixed;top:0;left:0}#mce-modal-block{opacity:0;filter:alpha(opacity=0);zoom:1;position:fixed;left:0;top:0;width:100%;height:100%;background:#000}#mce-modal-block.mce-in{opacity:.3;filter:alpha(opacity=30);zoom:1}.mce-window-move{cursor:move}.mce-window{filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;background:#FFF;position:fixed;top:0;left:0;opacity:0;transform:scale(.1);transition:transform 100ms ease-in,opacity 150ms ease-in}.mce-window.mce-in{transform:scale(1);opacity:1}.mce-window-head{padding:9px 15px;border-bottom:1px solid #c5c5c5;position:relative}.mce-window-head .mce-close{position:absolute;right:0;top:0;height:38px;width:38px;text-align:center;cursor:pointer}.mce-window-head .mce-close i{color:#858585}.mce-close:hover i{color:#adadad}.mce-window-head .mce-title{line-height:20px;font-size:20px;font-weight:bold;text-rendering:optimizelegibility;padding-right:20px}.mce-window .mce-container-body{d
 isplay:block}.mce-foot{display:block;background-color:#FFF;border-top:1px solid #c5c5c5}.mce-window-head .mce-dragh{position:absolute;top:0;left:0;cursor:move;width:90%;height:100%}.mce-window iframe{width:100%;height:100%}.mce-window-body .mce-listbox{border-color:#ccc}.mce-rtl .mce-window-head .mce-close{position:absolute;right:auto;left:15px}.mce-rtl .mce-window-head .mce-dragh{left:auto;right:0}.mce-rtl .mce-window-head .mce-title{direction:rtl;text-align:right}.mce-tooltip{position:absolute;padding:5px;opacity:.8;filter:alpha(opacity=80);zoom:1}.mce-tooltip-inner{font-size:11px;background-color:#000;color:white;max-width:200px;padding:5px 8px 4px 8px;text-align:center;white-space:normal}.mce-tooltip-arrow{position:absolute;width:0;height:0;line-height:0;border:5px dashed #000}.mce-tooltip-arrow-n{border-bottom-color:#000}.mce-tooltip-arrow-s{border-top-color:#000}.mce-tooltip-arrow-e{border-left-color:#000}.mce-tooltip-arrow-w{border-right-color:#000}.mce-tooltip-nw,.mce-toolti
 p-sw{margin-left:-14px}.mce-tooltip-ne,.mce-tooltip-se{margin-left:14px}.mce-tooltip-n .mce-tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-nw .mce-tooltip-arrow{top:0;left:10px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-ne .mce-tooltip-arrow{top:0;right:10px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-s .mce-tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-style:solid;border-bottom:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-sw .mce-tooltip-arrow{bottom:0;left:10px;border-top-style:solid;border-bottom:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-se .mce-tooltip-arrow{bottom:0;right:10px;border-top-style:solid;border-bottom:none;border-left-color:tra
 nsparent;border-right-color:transparent}.mce-tooltip-e .mce-tooltip-arrow{right:0;top:50%;margin-top:-5px;border-left-style:solid;border-right:none;border-top-color:transparent;border-bottom-color:transparent}.mce-tooltip-w .mce-tooltip-arrow{left:0;top:50%;margin-top:-5px;border-right-style:solid;border-left:none;border-top-color:transparent;border-bottom-color:transparent}.mce-progress{display:inline-block;position:relative;height:20px}.mce-progress .mce-bar-container{display:inline-block;width:100px;height:100%;margin-right:8px;border:1px solid #ccc;overflow:hidden}.mce-progress .mce-text{display:inline-block;margin-top:auto;margin-bottom:auto;font-size:14px;width:40px;color:#333}.mce-bar{display:block;width:0;height:100%;background-color:#d7d7d7;-webkit-transition:width .2s ease;transition:width .2s ease}.mce-notification{position:absolute;background-color:#F0F0F0;padding:5px;margin-top:5px;border-width:1px;border-style:solid;border-color:#CCCCCC;transition:transform 100ms ease-
 in,opacity 150ms ease-in;opacity:0}.mce-notification.mce-in{opacity:1}.mce-notification-success{background-color:#dff0d8;border-color:#d6e9c6}.mce-notification-info{background-color:#d9edf7;border-color:#779ECB}.mce-notification-warning{background-color:#fcf8e3;border-color:#faebcc}.mce-notification-error{background-color:#f2dede;border-color:#ebccd1}.mce-notification.mce-has-close{padding-right:15px}.mce-notification .mce-ico{margin-top:5px}.mce-notification-inner{display:inline-block;font-size:14px;margin:5px 8px 4px 8px;text-align:center;white-space:normal;color:#31708f}.mce-notification-inner a{text-decoration:underline;cursor:pointer}.mce-notification .mce-progress{margin-right:8px}.mce-notification .mce-progress .mce-text{margin-top:5px}.mce-notification *,.mce-notification .mce-progress .mce-text{color:#333333}.mce-notification .mce-progress .mce-bar-container{border-color:#CCCCCC}.mce-notification .mce-progress .mce-bar-container .mce-bar{background-color:#333333}.mce-notifi
 cation-success *,.mce-notification-success .mce-progress .mce-text{color:#3c763d}.mce-notification-success .mce-progress .mce-bar-container{border-color:#d6e9c6}.mce-notification-success .mce-progress .mce-bar-container .mce-bar{background-color:#3c763d}.mce-notification-info *,.mce-notification-info .mce-progress .mce-text{color:#31708f}.mce-notification-info .mce-progress .mce-bar-container{border-color:#779ECB}.mce-notification-info .mce-progress .mce-bar-container .mce-bar{background-color:#31708f}.mce-notification-warning *,.mce-notification-warning .mce-progress .mce-text{color:#8a6d3b}.mce-notification-warning .mce-progress .mce-bar-container{border-color:#faebcc}.mce-notification-warning .mce-progress .mce-bar-container .mce-bar{background-color:#8a6d3b}.mce-notification-error *,.mce-notification-error .mce-progress .mce-text{color:#a94442}.mce-notification-error .mce-progress .mce-bar-container{border-color:#ebccd1}.mce-notification-error .mce-progress .mce-bar-container .m
 ce-bar{background-color:#a94442}.mce-notification .mce-close{position:absolute;top:6px;right:8px;font-size:20px;font-weight:bold;line-height:20px;color:#858585;cursor:pointer;height:20px;overflow:hidden}.mce-abs-layout{position:relative}body .mce-abs-layout-item,.mce-abs-end{position:absolute}.mce-abs-end{width:1px;height:1px}.mce-container-body.mce-abs-layout{overflow:hidden}.mce-btn{border:1px solid #b1b1b1;border-color:transparent transparent transparent transparent;position:relative;text-shadow:0 1px 1px rgba(255,255,255,0.75);display:inline-block;*display:inline;*zoom:1;background-color:#f0f0f0}.mce-btn:hover,.mce-btn:focus{color:#333;background-color:#e3e3e3;border-color:#ccc}.mce-btn.mce-disabled button,.mce-btn.mce-disabled:hover button{cursor:default;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-btn.mce-active,.mce-btn.mce-active:hover{background-color:#dbdbdb;border-color:#ccc}.mce-btn:active{background-color:#e0e0e0;border-color:#ccc}.mce-btn button{padding:4px 8px;font
 -size:14px;line-height:20px;*line-height:16px;cursor:pointer;color:#333;text-align:center;overflow:visible;-webkit-appearance:none}.mce-btn button::-moz-focus-inner{border:0;padding:0}.mce-btn i{text-shadow:1px 1px none}.mce-primary.mce-btn-has-text{min-width:50px}.mce-primary{color:#fff;border:1px solid transparent;border-color:transparent;background-color:#2d8ac7}.mce-primary:hover,.mce-primary:focus{background-color:#257cb6;border-color:transparent}.mce-primary.mce-disabled button,.mce-primary.mce-disabled:hover button{cursor:default;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-primary.mce-active,.mce-primary.mce-active:hover,.mce-primary:not(.mce-disabled):active{background-color:#206ea1}.mce-primary button,.mce-primary button i{color:#fff;text-shadow:1px 1px none}.mce-btn .mce-txt{font-size:inherit;line-height:inherit;color:inherit}.mce-btn-large button{padding:9px 14px;font-size:16px;line-height:normal}.mce-btn-large i{margin-top:2px}.mce-btn-small button{padding:1px 5px;fo
 nt-size:12px;*padding-bottom:2px}.mce-btn-small i{line-height:20px;vertical-align:top;*line-height:18px}.mce-btn .mce-caret{margin-top:8px;margin-left:0}.mce-btn-small .mce-caret{margin-top:8px;margin-left:0}.mce-caret{display:inline-block;*display:inline;*zoom:1;width:0;height:0;vertical-align:top;border-top:4px solid #333;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.mce-disabled .mce-caret{border-top-color:#aaa}.mce-caret.mce-up{border-bottom:4px solid #333;border-top:0}.mce-btn-flat{border:0;background:transparent;filter:none}.mce-btn-flat:hover,.mce-btn-flat.mce-active,.mce-btn-flat:focus,.mce-btn-flat:active{border:0;background:#e6e6e6;filter:none}.mce-btn-has-text .mce-ico{padding-right:5px}.mce-rtl .mce-btn button{direction:rtl}.mce-btn-group .mce-btn{border-width:1px;margin:0;margin-left:2px}.mce-btn-group:not(:first-child){border-left:1px solid #d9d9d9;padding-left:3px;margin-left:3px}.mce-btn-group .mce-first{margin-left:0}.mce
 -btn-group .mce-btn.mce-flow-layout-item{margin:0}.mce-rtl .mce-btn-group .mce-btn{margin-left:0;margin-right:2px}.mce-rtl .mce-btn-group .mce-first{margin-right:0}.mce-rtl .mce-btn-group:not(:first-child){border-left:none;border-right:1px solid #d9d9d9;padding-right:4px;margin-right:4px}.mce-checkbox{cursor:pointer}i.mce-i-checkbox{margin:0 3px 0 0;border:1px solid #c5c5c5;background-color:#f0f0f0;text-indent:-10em;*font-size:0;*line-height:0;*text-indent:0;overflow:hidden}.mce-checked i.mce-i-checkbox{color:#333;font-size:16px;line-height:16px;text-indent:0}.mce-checkbox:focus i.mce-i-checkbox,.mce-checkbox.mce-focus i.mce-i-checkbox{border:1px solid rgba(82,168,236,0.8)}.mce-checkbox.mce-disabled .mce-label,.mce-checkbox.mce-disabled i.mce-i-checkbox{color:#acacac}.mce-checkbox .mce-label{vertical-align:middle}.mce-rtl .mce-checkbox{direction:rtl;text-align:right}.mce-rtl i.mce-i-checkbox{margin:0 0 0 3px}.mce-combobox{position:relative;display:inline-block;*display:inline;*zoom:
 1;*height:32px}.mce-combobox input{border:1px solid #c5c5c5;border-right-color:#c5c5c5;height:28px}.mce-combobox.mce-disabled input{color:#adadad}.mce-combobox .mce-btn{border:1px solid #c5c5c5;border-left:0;margin:0}.mce-combobox button{padding-right:8px;padding-left:8px}.mce-combobox.mce-disabled .mce-btn button{cursor:default;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-combobox .mce-status{position:absolute;right:2px;top:50%;line-height:16px;margin-top:-8px;font-size:12px;width:15px;height:15px;text-align:center;cursor:pointer}.mce-combobox.mce-has-status input{padding-right:20px}.mce-combobox.mce-has-open .mce-status{right:37px}.mce-combobox .mce-status.mce-i-warning{color:#c09853}.mce-combobox .mce-status.mce-i-checkmark{color:#468847}.mce-menu.mce-combobox-menu{border-top:0;margin-top:0;max-height:200px}.mce-menu.mce-combobox-menu .mce-menu-item{padding:4px 6px 4px 4px;font-size:11px}.mce-menu.mce-combobox-menu .mce-menu-item-sep{padding:0}.mce-menu.mce-combobox-menu .mce-
 text{font-size:11px}.mce-menu.mce-combobox-menu .mce-menu-item-link,.mce-menu.mce-combobox-menu .mce-menu-item-link b{font-size:11px}.mce-menu.mce-combobox-menu .mce-text b{font-size:11px}.mce-colorbox i{border:1px solid #c5c5c5;width:14px;height:14px}.mce-colorbutton .mce-ico{position:relative}.mce-colorbutton-grid{margin:4px}.mce-colorbutton button{padding-right:6px;padding-left:6px}.mce-colorbutton .mce-preview{padding-right:3px;display:block;position:absolute;left:50%;top:50%;margin-left:-17px;margin-top:7px;background:gray;width:13px;height:2px;overflow:hidden}.mce-colorbutton.mce-btn-small .mce-preview{margin-left:-16px;padding-right:0;width:16px}.mce-colorbutton .mce-open{padding-left:4px;padding-right:4px;border-left:1px solid transparent}.mce-colorbutton:hover .mce-open{border-color:#ccc}.mce-colorbutton.mce-btn-small .mce-open{padding:0 3px 0 3px}.mce-rtl .mce-colorbutton{direction:rtl}.mce-rtl .mce-colorbutton .mce-preview{margin-left:0;padding-right:0;padding-left:3px}.m
 ce-rtl .mce-colorbutton.mce-btn-small .mce-preview{margin-left:0;padding-right:0;padding-left:2px}.mce-rtl .mce-colorbutton .mce-open{padding-left:4px;padding-right:4px;border-left:0}.mce-colorpicker{position:relative;width:250px;height:220px}.mce-colorpicker-sv{position:absolute;top:0;left:0;width:90%;height:100%;border:1px solid #c5c5c5;cursor:crosshair;overflow:hidden}.mce-colorpicker-h-chunk{width:100%}.mce-colorpicker-overlay1,.mce-colorpicker-overlay2{width:100%;height:100%;position:absolute;top:0;left:0}.mce-colorpicker-overlay1{filter:progid:DXImageTransform.Microsoft.gradient(GradientType=1, startColorstr='#ffffff', endColorstr='#00ffffff');-ms-filter:"progid:DXImageTransform.Microsoft.gradient(GradientType=1,startColorstr='#ffffff', endColorstr='#00ffffff')";background:linear-gradient(to right, #fff, rgba(255,255,255,0))}.mce-colorpicker-overlay2{filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#00000000', endColorstr='#000000');-m
 s-filter:"progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#00000000', endColorstr='#000000')";background:linear-gradient(to bottom, rgba(0,0,0,0), #000)}.mce-colorpicker-selector1{background:none;position:absolute;width:12px;height:12px;margin:-8px 0 0 -8px;border:1px solid black;border-radius:50%}.mce-colorpicker-selector2{position:absolute;width:10px;height:10px;border:1px solid white;border-radius:50%}.mce-colorpicker-h{position:absolute;top:0;right:0;width:6.5%;height:100%;border:1px solid #c5c5c5;cursor:crosshair}.mce-colorpicker-h-marker{margin-top:-4px;position:absolute;top:0;left:-1px;width:100%;border:1px solid #333;background:#fff;height:4px;z-index:100}.mce-path{display:inline-block;*display:inline;*zoom:1;padding:8px;white-space:normal}.mce-path .mce-txt{display:inline-block;padding-right:3px}.mce-path .mce-path-body{display:inline-block}.mce-path-item{display:inline-block;*display:inline;*zoom:1;cursor:pointer;color:#333}.mce-path-item
 :hover{text-decoration:underline}.mce-path-item:focus{background:#666;color:#fff}.mce-path .mce-divider{display:inline}.mce-disabled .mce-path-item{color:#aaa}.mce-rtl .mce-path{direction:rtl}.mce-fieldset{border:0 solid #9E9E9E}.mce-fieldset>.mce-container-body{margin-top:-15px}.mce-fieldset-title{margin-left:5px;padding:0 5px 0 5px}.mce-fit-layout{display:inline-block;*display:inline;*zoom:1}.mce-fit-layout-item{position:absolute}.mce-flow-layout-item{display:inline-block;*display:inline;*zoom:1}.mce-flow-layout-item{margin:2px 0 2px 2px}.mce-flow-layout-item.mce-last{margin-right:2px}.mce-flow-layout{white-space:normal}.mce-tinymce-inline .mce-flow-layout{white-space:nowrap}.mce-rtl .mce-flow-layout{text-align:right;direction:rtl}.mce-rtl .mce-flow-layout-item{margin:2px 2px 2px 0}.mce-rtl .mce-flow-layout-item.mce-last{margin-left:2px}.mce-iframe{border:0 solid rgba(0,0,0,0.2);width:100%;height:100%}.mce-infobox{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 1
 px rgba(255,255,255,0.75);overflow:hidden;border:1px solid red}.mce-infobox div{display:block;margin:5px}.mce-infobox div button{position:absolute;top:50%;right:4px;cursor:pointer;margin-top:-8px;display:none}.mce-infobox div button:focus{outline:2px solid #ccc}.mce-infobox.mce-has-help div{margin-right:25px}.mce-infobox.mce-has-help button{display:block}.mce-infobox.mce-success{background:#dff0d8;border-color:#d6e9c6}.mce-infobox.mce-success div{color:#3c763d}.mce-infobox.mce-warning{background:#fcf8e3;border-color:#faebcc}.mce-infobox.mce-warning div{color:#8a6d3b}.mce-infobox.mce-error{background:#f2dede;border-color:#ebccd1}.mce-infobox.mce-error div{color:#a94442}.mce-rtl .mce-infobox div{text-align:right;direction:rtl}.mce-label{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 1px rgba(255,255,255,0.75);overflow:hidden}.mce-label.mce-autoscroll{overflow:auto}.mce-label.mce-disabled{color:#aaa}.mce-label.mce-multiline{white-space:pre-wrap}.mce-label.mce-success{co
 lor:#468847}.mce-label.mce-warning{color:#c09853}.mce-label.mce-error{color:#b94a48}.mce-rtl .mce-label{text-align:right;direction:rtl}.mce-menubar .mce-menubtn{border-color:transparent;background:transparent;filter:none}.mce-menubar .mce-menubtn button{color:#333}.mce-menubar{border:1px solid rgba(217,217,217,0.52)}.mce-menubar .mce-menubtn button span{color:#333}.mce-menubar .mce-caret{border-top-color:#333}.mce-menubar .mce-menubtn:hover,.mce-menubar .mce-menubtn.mce-active,.mce-menubar .mce-menubtn:focus{border-color:#ccc;background:#fff;filter:none}.mce-menubtn button{color:#333}.mce-menubtn.mce-btn-small span{font-size:12px}.mce-menubtn.mce-fixed-width span{display:inline-block;overflow-x:hidden;text-overflow:ellipsis;width:90px}.mce-menubtn.mce-fixed-width.mce-btn-small span{width:70px}.mce-menubtn .mce-caret{*margin-top:6px}.mce-rtl .mce-menubtn button{direction:rtl;text-align:right}.mce-menu-item{display:block;padding:6px 15px 6px 12px;clear:both;font-weight:normal;line-hei
 ght:20px;color:#333;white-space:nowrap;cursor:pointer;line-height:normal;border-left:4px solid transparent;margin-bottom:1px}.mce-menu-item .mce-ico,.mce-menu-item .mce-text{color:#333}.mce-menu-item.mce-disabled .mce-text,.mce-menu-item.mce-disabled .mce-ico{color:#adadad}.mce-menu-item:hover .mce-text,.mce-menu-item.mce-selected .mce-text,.mce-menu-item:focus .mce-text{color:white}.mce-menu-item:hover .mce-ico,.mce-menu-item.mce-selected .mce-ico,.mce-menu-item:focus .mce-ico{color:white}.mce-menu-item.mce-disabled:hover{background:#CCC}.mce-menu-shortcut{display:inline-block;color:#adadad}.mce-menu-shortcut{display:inline-block;*display:inline;*zoom:1;padding:0 15px 0 20px}.mce-menu-item:hover .mce-menu-shortcut,.mce-menu-item.mce-selected .mce-menu-shortcut,.mce-menu-item:focus .mce-menu-shortcut{color:white}.mce-menu-item .mce-caret{margin-top:4px;*margin-top:3px;margin-right:6px;border-top:4px solid transparent;border-bottom:4px solid transparent;border-left:4px solid #333}.mc
 e-menu-item.mce-selected .mce-caret,.mce-menu-item:focus .mce-caret,.mce-menu-item:hover .mce-caret{border-left-color:white}.mce-menu-align .mce-menu-shortcut{*margin-top:-2px}.mce-menu-align .mce-menu-shortcut,.mce-menu-align .mce-caret{position:absolute;right:0}.mce-menu-item.mce-active i{visibility:visible}.mce-menu-item-normal.mce-active{background-color:#3498db}.mce-menu-item-preview.mce-active{border-left:5px solid #aaa}.mce-menu-item-normal.mce-active .mce-text{color:white}.mce-menu-item-normal.mce-active:hover .mce-text,.mce-menu-item-normal.mce-active:hover .mce-ico{color:white}.mce-menu-item-normal.mce-active:focus .mce-text,.mce-menu-item-normal.mce-active:focus .mce-ico{color:white}.mce-menu-item:hover,.mce-menu-item.mce-selected,.mce-menu-item:focus{text-decoration:none;color:white;background-color:#2d8ac7}.mce-menu-item-link{color:#093;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mce-menu-item-link b{color:#093}.mce-menu-item-ellipsis{display:block;text-o
 verflow:ellipsis;white-space:nowrap;overflow:hidden}.mce-menu-item:hover *,.mce-menu-item.mce-selected *,.mce-menu-item:focus *{color:white}div.mce-menu .mce-menu-item-sep,.mce-menu-item-sep:hover{border:0;padding:0;height:1px;margin:9px 1px;overflow:hidden;background:transparent;border-bottom:1px solid rgba(0,0,0,0.1);cursor:default;filter:none}div.mce-menu .mce-menu-item b{font-weight:bold}.mce-menu-item-indent-1{padding-left:20px}.mce-menu-item-indent-2{padding-left:35px}.mce-menu-item-indent-2{padding-left:35px}.mce-menu-item-indent-3{padding-left:40px}.mce-menu-item-indent-4{padding-left:45px}.mce-menu-item-indent-5{padding-left:50px}.mce-menu-item-indent-6{padding-left:55px}.mce-menu.mce-rtl{direction:rtl}.mce-rtl .mce-menu-item{text-align:right;direction:rtl;padding:6px 12px 6px 15px}.mce-menu-align.mce-rtl .mce-menu-shortcut,.mce-menu-align.mce-rtl .mce-caret{right:auto;left:0}.mce-rtl .mce-menu-item .mce-caret{margin-left:6px;margin-right:0;border-right:4px solid #333;borde
 r-left:0}.mce-rtl .mce-menu-item.mce-selected .mce-caret,.mce-rtl .mce-menu-item:focus .mce-caret,.mce-rtl .mce-menu-item:hover .mce-caret{border-left-color:transparent;border-right-color:white}.mce-throbber{position:absolute;top:0;left:0;width:100%;height:100%;opacity:.6;filter:alpha(opacity=60);zoom:1;background:#fff url('img/loader.gif') no-repeat center center}.mce-throbber-inline{position:static;height:50px}.mce-menu .mce-throbber-inline{height:25px;background-size:contain}.mce-menu{position:absolute;left:0;top:0;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;z-index:1000;padding:5px 0 5px 0;margin:-1px 0 0;min-width:160px;background:#fff;border:1px solid #989898;border:1px solid rgba(0,0,0,0.2);z-index:1002;max-height:400px;overflow:auto;overflow-x:hidden}.mce-menu i{display:none}.mce-menu-has-icons i{display:inline-block;*display:inline}.mce-menu-sub-tr-tl{margin:-6px 0 0 -1px}.mce-menu-sub-br-bl{margin:6px 0 0 -1px}.mce-menu-sub-tl-
 tr{margin:-6px 0 0 1px}.mce-menu-sub-bl-br{margin:6px 0 0 1px}.mce-listbox button{text-align:left;padding-right:20px;position:relative}.mce-listbox .mce-caret{position:absolute;margin-top:-2px;right:8px;top:50%}.mce-rtl .mce-listbox .mce-caret{right:auto;left:8px}.mce-rtl .mce-listbox button{padding-right:10px;padding-left:20px}.mce-container-body .mce-resizehandle{position:absolute;right:0;bottom:0;width:16px;height:16px;visibility:visible;cursor:s-resize;margin:0}.mce-container-body .mce-resizehandle-both{cursor:se-resize}i.mce-i-resize{color:#333}.mce-selectbox{background:#fff;border:1px solid #c5c5c5}.mce-slider{border:1px solid #AAA;background:#EEE;width:100px;height:10px;position:relative;display:block}.mce-slider.mce-vertical{width:10px;height:100px}.mce-slider-handle{border:1px solid #BBB;background:#DDD;display:block;width:13px;height:13px;position:absolute;top:0;left:0;margin-left:-1px;margin-top:-2px}.mce-slider-handle:focus{background:#BBB}.mce-spacer{visibility:hidden}.
 mce-splitbtn .mce-open{border-left:1px solid transparent}.mce-splitbtn:hover .mce-open{border-left-color:#ccc}.mce-splitbtn button{padding-right:6px;padding-left:6px}.mce-splitbtn .mce-open{padding-right:4px;padding-left:4px}.mce-splitbtn .mce-open.mce-active{background-color:#dbdbdb;outline:1px solid #ccc}.mce-splitbtn.mce-btn-small .mce-open{padding:0 3px 0 3px}.mce-rtl .mce-splitbtn{direction:rtl;text-align:right}.mce-rtl .mce-splitbtn button{padding-right:4px;padding-left:4px}.mce-rtl .mce-splitbtn .mce-open{border-left:0}.mce-stack-layout-item{display:block}.mce-tabs{display:block;border-bottom:1px solid #c5c5c5}.mce-tabs,.mce-tabs+.mce-container-body{background:#FFF}.mce-tab{display:inline-block;*display:inline;*zoom:1;border:1px solid #c5c5c5;border-width:0 1px 0 0;background:#ffffff;padding:8px;text-shadow:0 1px 1px rgba(255,255,255,0.75);height:13px;cursor:pointer}.mce-tab:hover{background:#FDFDFD}.mce-tab.mce-active{background:#FDFDFD;border-bottom-color:transparent;margin
 -bottom:-1px;height:14px}.mce-rtl .mce-tabs{text-align:right;direction:rtl}.mce-rtl .mce-tab{border-width:0 0 0 1px}.mce-textbox{background:#fff;border:1px solid #c5c5c5;display:inline-block;-webkit-transition:border linear .2s, box-shadow linear .2s;transition:border linear .2s, box-shadow linear .2s;height:28px;resize:none;padding:0 4px 0 4px;white-space:pre-wrap;*white-space:pre;color:#333}.mce-textbox:focus,.mce-textbox.mce-focus{border-color:#3498db}.mce-placeholder .mce-textbox{color:#aaa}.mce-textbox.mce-multiline{padding:4px;height:auto}.mce-textbox.mce-disabled{color:#adadad}.mce-rtl .mce-textbox{text-align:right;direction:rtl}@font-face{font-family:'tinymce';src:url('fonts/tinymce.eot');src:url('fonts/tinymce.eot?#iefix') format('embedded-opentype'),url('fonts/tinymce.woff') format('woff'),url('fonts/tinymce.ttf') format('truetype'),url('fonts/tinymce.svg#tinymce') format('svg');font-weight:normal;font-style:normal}@font-face{font-family:'tinymce-small';src:url('fonts/tiny
 mce-small.eot');src:url('fonts/tinymce-small.eot?#iefix') format('embedded-opentype'),url('fonts/tinymce-small.woff') format('woff'),url('fonts/tinymce-small.ttf') format('truetype'),url('fonts/tinymce-small.svg#tinymce') format('svg');font-weight:normal;font-style:normal}.mce-ico{font-family:'tinymce',Arial;font-style:normal;font-weight:normal;font-variant:normal;font-size:16px;line-height:16px;speak:none;vertical-align:text-top;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;display:inline-block;background:transparent center center;background-size:cover;width:16px;height:16px;color:#333}.mce-btn-small .mce-ico{font-family:'tinymce-small',Arial}.mce-i-save:before{content:"\e000"}.mce-i-newdocument:before{content:"\e001"}.mce-i-fullpage:before{content:"\e002"}.mce-i-alignleft:before{content:"\e003"}.mce-i-aligncenter:before{content:"\e004"}.mce-i-alignright:before{content:"\e005"}.mce-i-alignjustify:bef
 ore{content:"\e006"}.mce-i-alignnone:before{content:"\e003"}.mce-i-cut:before{content:"\e007"}.mce-i-paste:before{content:"\e008"}.mce-i-searchreplace:before{content:"\e009"}.mce-i-bullist:before{content:"\e00a"}.mce-i-numlist:before{content:"\e00b"}.mce-i-indent:before{content:"\e00c"}.mce-i-outdent:before{content:"\e00d"}.mce-i-blockquote:before{content:"\e00e"}.mce-i-undo:before{content:"\e00f"}.mce-i-redo:before{content:"\e010"}.mce-i-link:before{content:"\e011"}.mce-i-unlink:before{content:"\e012"}.mce-i-anchor:before{content:"\e013"}.mce-i-image:before{content:"\e014"}.mce-i-media:before{content:"\e015"}.mce-i-help:before{content:"\e016"}.mce-i-code:before{content:"\e017"}.mce-i-insertdatetime:before{content:"\e018"}.mce-i-preview:before{content:"\e019"}.mce-i-forecolor:
 before{content:"\e01a"}.mce-i-backcolor:before{content:"\e01a"}.mce-i-table:before{content:"\e01b"}.mce-i-hr:before{content:"\e01c"}.mce-i-removeformat:before{content:"\e01d"}.mce-i-subscript:before{content:"\e01e"}.mce-i-superscript:before{content:"\e01f"}.mce-i-charmap:before{content:"\e020"}.mce-i-emoticons:before{content:"\e021"}.mce-i-print:before{content:"\e022"}.mce-i-fullscreen:before{content:"\e023"}.mce-i-spellchecker:before{content:"\e024"}.mce-i-nonbreaking:before{content:"\e025"}.mce-i-template:before{content:"\e026"}.mce-i-pagebreak:before{content:"\e027"}.mce-i-restoredraft:before{content:"\e028"}.mce-i-bold:before{content:"\e02a"}.mce-i-italic:before{content:"\e02b"}.mce-i-underline:before{content:"\e02c"}.mce-i-strikethrough:before{content:"\e02d"}.mce-i-visualchars:bef
 ore{content:"\e02e"}.mce-i-visualblocks:before{content:"\e02e"}.mce-i-ltr:before{content:"\e02f"}.mce-i-rtl:before{content:"\e030"}.mce-i-copy:before{content:"\e031"}.mce-i-resize:before{content:"\e032"}.mce-i-browse:before{content:"\e034"}.mce-i-pastetext:before{content:"\e035"}.mce-i-rotateleft:before{content:"\eaa8"}.mce-i-rotateright:before{content:"\eaa9"}.mce-i-crop:before{content:"\ee78"}.mce-i-editimage:before{content:"\e915"}.mce-i-options:before{content:"\ec6a"}.mce-i-flipv:before{content:"\eaaa"}.mce-i-fliph:before{content:"\eaac"}.mce-i-zoomin:before{content:"\eb35"}.mce-i-zoomout:before{content:"\eb36"}.mce-i-sun:before{content:"\eccc"}.mce-i-moon:before{content:"\eccd"}.mce-i-arrowleft:before{content:"\edc0"}.mce-i-arrowright:before{content:"\e93c"}.mce-i-drop:be
 fore{content:"\e935"}.mce-i-contrast:before{content:"\ecd4"}.mce-i-sharpen:before{content:"\eba7"}.mce-i-resize2:before{content:"\edf9"}.mce-i-orientation:before{content:"\e601"}.mce-i-invert:before{content:"\e602"}.mce-i-gamma:before{content:"\e600"}.mce-i-remove:before{content:"\ed6a"}.mce-i-tablerowprops:before{content:"\e604"}.mce-i-tablecellprops:before{content:"\e605"}.mce-i-table2:before{content:"\e606"}.mce-i-tablemergecells:before{content:"\e607"}.mce-i-tableinsertcolbefore:before{content:"\e608"}.mce-i-tableinsertcolafter:before{content:"\e609"}.mce-i-tableinsertrowbefore:before{content:"\e60a"}.mce-i-tableinsertrowafter:before{content:"\e60b"}.mce-i-tablesplitcells:before{content:"\e60d"}.mce-i-tabledelete:before{content:"\e60e"}.mce-i-tableleftheader:before{content:"\e62a"}.mce-i-tabl
 etopheader:before{content:"\e62b"}.mce-i-tabledeleterow:before{content:"\e800"}.mce-i-tabledeletecol:before{content:"\e801"}.mce-i-codesample:before{content:"\e603"}.mce-i-fill:before{content:"\e902"}.mce-i-borderwidth:before{content:"\e903"}.mce-i-line:before{content:"\e904"}.mce-i-count:before{content:"\e905"}.mce-i-translate:before{content:"\e907"}.mce-i-drag:before{content:"\e908"}.mce-i-home:before{content:"\e90b"}.mce-i-upload:before{content:"\e914"}.mce-i-bubble:before{content:"\e91c"}.mce-i-user:before{content:"\e91d"}.mce-i-lock:before{content:"\e926"}.mce-i-unlock:before{content:"\e927"}.mce-i-settings:before{content:"\e928"}.mce-i-remove2:before{content:"\e92a"}.mce-i-menu:before{content:"\e92d"}.mce-i-warning:before{content:"\e930"}.mce-i-question:before{content:"\e931&
 quot;}.mce-i-pluscircle:before{content:"\e932"}.mce-i-info:before{content:"\e933"}.mce-i-notice:before{content:"\e934"}.mce-i-arrowup:before{content:"\e93b"}.mce-i-arrowdown:before{content:"\e93d"}.mce-i-arrowup2:before{content:"\e93f"}.mce-i-arrowdown2:before{content:"\e940"}.mce-i-menu2:before{content:"\e941"}.mce-i-newtab:before{content:"\e961"}.mce-i-a11y:before{content:"\e900"}.mce-i-plus:before{content:"\e93a"}.mce-i-insert:before{content:"\e93a"}.mce-i-minus:before{content:"\e939"}.mce-i-books:before{content:"\e911"}.mce-i-reload:before{content:"\e906"}.mce-i-toc:before{content:"\e901"}.mce-i-checkmark:before{content:"\e033"}.mce-i-checkbox:before,.mce-i-selected:before{content:"\e033"}.mce-i-insert{font-size:14px}.mce-i-selected{visibility:hidden}i.mce-i-backcolor{text-shadow:none;background:#BBB}
</del><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+.mce-container,.mce-container *,.mce-widget,.mce-widget *,.mce-reset{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:#333;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;-webkit-tap-highlight-color:transparent;line-height:normal;font-weight:normal;text-align:left;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr;max-width:none}.mce-widget button{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.mce-container *[unselectable]{-moz-user-select:none;-webkit-user-select:none;-o-user-select:none;user-select:none}.word-wrap{word-wrap:break-word;-ms-word-break:break-all;word-break:break-all;word-break:break-word;-ms-hyphens:auto;-m
 oz-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}.mce-fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.mce-fade.mce-in{opacity:1}.mce-tinymce{visibility:inherit !important;position:relative}.mce-fullscreen{border:0;padding:0;margin:0;overflow:hidden;height:100%;z-index:100}div.mce-fullscreen{position:fixed;top:0;left:0;width:100%;height:auto}.mce-tinymce{display:block}.mce-wordcount{position:absolute;top:0;right:0;padding:8px}div.mce-edit-area{background:#FFF;filter:none}.mce-statusbar{position:relative}.mce-statusbar .mce-container-body{position:relative}.mce-fullscreen .mce-resizehandle{display:none}.mce-charmap{border-collapse:collapse}.mce-charmap td{cursor:default;border:1px solid rgba(0,0,0,0.2);width:20px;height:20px;line-height:20px;text-align:center;vertical-align:middle;padding:2px}.mce-charmap td div{text-align:center}.mce-charmap td:hover{background:#D9D9D9}.mce-grid td.mce-grid-cell div{border:1px solid #d6d6d6;width:15px;height:15p
 x;margin:0;cursor:pointer}.mce-grid td.mce-grid-cell div:focus{border-color:#3498db}.mce-grid td.mce-grid-cell div[disabled]{cursor:not-allowed}.mce-grid{border-spacing:2px;border-collapse:separate}.mce-grid a{display:block;border:1px solid transparent}.mce-grid a:hover,.mce-grid a:focus{border-color:#3498db}.mce-grid-border{margin:0 4px 0 4px}.mce-grid-border a{border-color:#d6d6d6;width:13px;height:13px}.mce-grid-border a:hover,.mce-grid-border a.mce-active{border-color:#3498db;background:#3498db}.mce-text-center{text-align:center}div.mce-tinymce-inline{width:100%}.mce-colorbtn-trans div{text-align:center;vertical-align:middle;font-weight:bold;font-size:20px;line-height:16px;color:#707070}.mce-monospace{font-family:"Courier New",Courier,monospace}.mce-toolbar-grp{padding:2px 0}.mce-toolbar-grp .mce-flow-layout-item{margin-bottom:0}.mce-rtl .mce-wordcount{left:0;right:auto}.mce-container b{font-weight:bold}.mce-container p{margin-bottom:5px}.mce-container a{cursor:pointer
 ;color:#2980b9}.mce-container a:hover{text-decoration:underline}.mce-container ul{margin-left:15px}.mce-container .mce-table-striped{border-collapse:collapse;margin:10px}.mce-container .mce-table-striped thead>tr{background-color:#fafafa}.mce-container .mce-table-striped thead>tr th{font-weight:bold}.mce-container .mce-table-striped td,.mce-container .mce-table-striped th{padding:5px}.mce-container .mce-table-striped tr:nth-child(even){background-color:#fafafa}.mce-container .mce-table-striped tbody>tr:hover{background-color:#e1e1e1}.mce-branding-powered-by{background-color:#f0f0f0;position:absolute;right:0;bottom:0;width:91px;height:9px;margin-right:-1px;margin-bottom:-1px;border:1px solid #c5c5c5;border-width:1px 1px 0 1px;padding:6px 6px 0 6px;background-image:url('data:image/gif;base64,R0lGODlhXwAJAIABAIiIiAAAACH5BAEKAAEALAAAAABfAAkAAAJxhBGpy+2PUnzqGNpmPNJqDIZSJY4m+KXLF3At2V6xPFfuvMF6J6fINTnhTr9XcaRC6pKvFYlZjDIszaXRSA3ijlXo9AlWindaldSJthJ55XAz6+ZWbVCOdojP77p8J8vlUSI4SHE
 naEiYqOhARdhIWAAAOw');background-repeat:no-repeat;background-position:center center}.mce-croprect-container{position:absolute;top:0;left:0}.mce-croprect-handle{position:absolute;top:0;left:0;width:20px;height:20px;border:2px solid white}.mce-croprect-handle-nw{border-width:2px 0 0 2px;margin:-2px 0 0 -2px;cursor:nw-resize;top:100px;left:100px}.mce-croprect-handle-ne{border-width:2px 2px 0 0;margin:-2px 0 0 -20px;cursor:ne-resize;top:100px;left:200px}.mce-croprect-handle-sw{border-width:0 0 2px 2px;margin:-20px 2px 0 -2px;cursor:sw-resize;top:200px;left:100px}.mce-croprect-handle-se{border-width:0 2px 2px 0;margin:-20px 0 0 -20px;cursor:se-resize;top:200px;left:200px}.mce-croprect-handle-move{position:absolute;cursor:move;border:0}.mce-croprect-block{opacity:.3;filter:alpha(opacity=30);zoom:1;position:absolute;background:black}.mce-croprect-handle:focus{border-color:#3498db}.mce-croprect-handle-move:focus{outline:1px solid #3498db}.mce-imagepanel{overflow:auto;background:black}.mce-i
 magepanel-bg{position:absolute;background:url('data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==')}.mce-imagepanel img{position:absolute}.mce-imagetool.mce-btn .mce-ico{display:block;width:20px;height:20px;text-align:center;line-height:20px;font-size:20px;padding:5px}.mce-arrow-up{margin-top:12px}.mce-arrow-down{margin-top:-12px}.mce-arrow:before,.mce-arrow:after{position:absolute;left:50%;display:block;width:0;height:0;border-style:solid;border-color:transparent;content:""}.mce-arrow.mce-arrow-up:before{top:-9px;border-bottom-color:rgba(0,0,0,0.2);border-width:0 9px 9px;margin-left:-9px}.mce-arrow.mce-arrow-down:before{bottom:-9px;border-top-color:rgba(0,0,0,0.2);border-width:9px 9px 0;margin-left:-9px}.mce-arrow.mce-arrow-up:after{top:-8px;border-bottom-color:#f0f0f0;border-width:0 8px 8px;margin-left:-8px}.mce-arrow.mce-arrow-down:after{bottom:-8px;border-top-color:#f0f0f0;border-width:8px 8px 0;margin-left:-8px}.mce-arro
 w.mce-arrow-left:before,.mce-arrow.mce-arrow-left:after{margin:0}.mce-arrow.mce-arrow-left:before{left:8px}.mce-arrow.mce-arrow-left:after{left:9px}.mce-arrow.mce-arrow-right:before,.mce-arrow.mce-arrow-right:after{left:auto;margin:0}.mce-arrow.mce-arrow-right:before{right:8px}.mce-arrow.mce-arrow-right:after{right:9px}.mce-arrow.mce-arrow-center.mce-arrow.mce-arrow-left:before{left:-9px;top:50%;border-right-color:rgba(0,0,0,0.2);border-width:9px 9px 9px 0;margin-top:-9px}.mce-arrow.mce-arrow-center.mce-arrow.mce-arrow-left:after{left:-8px;top:50%;border-right-color:#f0f0f0;border-width:8px 8px 8px 0;margin-top:-8px}.mce-arrow.mce-arrow-center.mce-arrow.mce-arrow-left{margin-left:12px}.mce-arrow.mce-arrow-center.mce-arrow.mce-arrow-right:before{right:-9px;top:50%;border-left-color:rgba(0,0,0,0.2);border-width:9px 0 9px 9px;margin-top:-9px}.mce-arrow.mce-arrow-center.mce-arrow.mce-arrow-right:after{right:-8px;top:50%;border-left-color:#f0f0f0;border-width:8px 0 8px 8px;margin-top:-8p
 x}.mce-arrow.mce-arrow-center.mce-arrow.mce-arrow-right{margin-left:-14px}.mce-edit-aria-container>.mce-container-body{display:flex}.mce-edit-aria-container>.mce-container-body .mce-edit-area{flex:1}.mce-edit-aria-container>.mce-container-body .mce-sidebar>.mce-container-body{display:flex;align-items:stretch;height:100%}.mce-edit-aria-container>.mce-container-body .mce-sidebar-panel{min-width:250px;max-width:250px;position:relative}.mce-edit-aria-container>.mce-container-body .mce-sidebar-panel>.mce-container-body{position:absolute;width:100%;height:100%;overflow:auto;top:0;left:0}.mce-sidebar-toolbar{border:0 solid rgba(0,0,0,0.2);border-left-width:1px}.mce-sidebar-toolbar .mce-btn.mce-active,.mce-sidebar-toolbar .mce-btn.mce-active:hover{border:1px solid transparent;border-color:transparent;background-color:#2d8ac7}.mce-sidebar-toolbar .mce-btn.mce-active button,.mce-sidebar-toolbar .mce-btn.mce-active:hover button,.mce-sidebar-toolbar .mce-btn.mce-active butt
 on i,.mce-sidebar-toolbar .mce-btn.mce-active:hover button i{color:#fff;text-shadow:1px 1px none}.mce-sidebar-panel{border:0 solid rgba(0,0,0,0.2);border-left-width:1px}.mce-container,.mce-container-body{display:block}.mce-autoscroll{overflow:hidden}.mce-scrollbar{position:absolute;width:7px;height:100%;top:2px;right:2px;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-scrollbar-h{top:auto;right:auto;left:2px;bottom:2px;width:100%;height:7px}.mce-scrollbar-thumb{position:absolute;background-color:#000;border:1px solid #888;border-color:rgba(85,85,85,0.6);width:5px;height:100%}.mce-scrollbar-h .mce-scrollbar-thumb{width:100%;height:5px}.mce-scrollbar:hover,.mce-scrollbar.mce-active{background-color:#AAA;opacity:.6;filter:alpha(opacity=60);zoom:1}.mce-scroll{position:relative}.mce-panel{border:0 solid #cacaca;border:0 solid rgba(0,0,0,0.2);background-color:#f0f0f0}.mce-floatpanel{position:absolute}.mce-floatpanel.mce-fixed{position:fixed}.mce-floatpanel .mce-arrow,.mce-floatpanel .mce-
 arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.mce-floatpanel .mce-arrow{border-width:11px}.mce-floatpanel .mce-arrow:after{border-width:10px;content:""}.mce-floatpanel.mce-popover{filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;top:0;left:0;background:#FFF;border:1px solid rgba(0,0,0,0.2);border:1px solid rgba(0,0,0,0.25)}.mce-floatpanel.mce-popover.mce-bottom{margin-top:10px;*margin-top:0}.mce-floatpanel.mce-popover.mce-bottom>.mce-arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:rgba(0,0,0,0.2);border-bottom-color:rgba(0,0,0,0.25);top:-11px}.mce-floatpanel.mce-popover.mce-bottom>.mce-arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#FFF}.mce-floatpanel.mce-popover.mce-bottom.mce-start{margin-left:-22px}.mce-floatpanel.mce-popover.mce-bottom.mce-start>.mce-arrow{left:20px}.mce-floatpanel.mce-popover.mce-bottom.mc
 e-end{margin-left:22px}.mce-floatpanel.mce-popover.mce-bottom.mce-end>.mce-arrow{right:10px;left:auto}.mce-fullscreen{border:0;padding:0;margin:0;overflow:hidden;height:100%}div.mce-fullscreen{position:fixed;top:0;left:0}#mce-modal-block{opacity:0;filter:alpha(opacity=0);zoom:1;position:fixed;left:0;top:0;width:100%;height:100%;background:#000}#mce-modal-block.mce-in{opacity:.3;filter:alpha(opacity=30);zoom:1}.mce-window-move{cursor:move}.mce-window{filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;background:#FFF;position:fixed;top:0;left:0;opacity:0;transform:scale(.1);transition:transform 100ms ease-in,opacity 150ms ease-in}.mce-window.mce-in{transform:scale(1);opacity:1}.mce-window-head{padding:9px 15px;border-bottom:1px solid #c5c5c5;position:relative}.mce-window-head .mce-close{position:absolute;right:0;top:0;height:38px;width:38px;text-align:center;cursor:pointer}.mce-window-head .mce-close i{color:#858585}.mce-close:hover i{color:#a
 dadad}.mce-window-head .mce-title{line-height:20px;font-size:20px;font-weight:bold;text-rendering:optimizelegibility;padding-right:20px}.mce-window .mce-container-body{display:block}.mce-foot{display:block;background-color:#FFF;border-top:1px solid #c5c5c5}.mce-window-head .mce-dragh{position:absolute;top:0;left:0;cursor:move;width:90%;height:100%}.mce-window iframe{width:100%;height:100%}.mce-window-body .mce-listbox{border-color:#ccc}.mce-rtl .mce-window-head .mce-close{position:absolute;right:auto;left:15px}.mce-rtl .mce-window-head .mce-dragh{left:auto;right:0}.mce-rtl .mce-window-head .mce-title{direction:rtl;text-align:right}.mce-tooltip{position:absolute;padding:5px;opacity:.8;filter:alpha(opacity=80);zoom:1}.mce-tooltip-inner{font-size:11px;background-color:#000;color:white;max-width:200px;padding:5px 8px 4px 8px;text-align:center;white-space:normal}.mce-tooltip-arrow{position:absolute;width:0;height:0;line-height:0;border:5px dashed #000}.mce-tooltip-arrow-n{border-bottom-c
 olor:#000}.mce-tooltip-arrow-s{border-top-color:#000}.mce-tooltip-arrow-e{border-left-color:#000}.mce-tooltip-arrow-w{border-right-color:#000}.mce-tooltip-nw,.mce-tooltip-sw{margin-left:-14px}.mce-tooltip-ne,.mce-tooltip-se{margin-left:14px}.mce-tooltip-n .mce-tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-nw .mce-tooltip-arrow{top:0;left:10px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-ne .mce-tooltip-arrow{top:0;right:10px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-s .mce-tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-style:solid;border-bottom:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-sw .mce-tooltip-arrow{bottom:0;left:10px;border-top-style:solid;border-bottom:none;border-lef
 t-color:transparent;border-right-color:transparent}.mce-tooltip-se .mce-tooltip-arrow{bottom:0;right:10px;border-top-style:solid;border-bottom:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-e .mce-tooltip-arrow{right:0;top:50%;margin-top:-5px;border-left-style:solid;border-right:none;border-top-color:transparent;border-bottom-color:transparent}.mce-tooltip-w .mce-tooltip-arrow{left:0;top:50%;margin-top:-5px;border-right-style:solid;border-left:none;border-top-color:transparent;border-bottom-color:transparent}.mce-progress{display:inline-block;position:relative;height:20px}.mce-progress .mce-bar-container{display:inline-block;width:100px;height:100%;margin-right:8px;border:1px solid #ccc;overflow:hidden}.mce-progress .mce-text{display:inline-block;margin-top:auto;margin-bottom:auto;font-size:14px;width:40px;color:#333}.mce-bar{display:block;width:0;height:100%;background-color:#d7d7d7;-webkit-transition:width .2s ease;transition:width .2s ease}.mce-not
 ification{position:absolute;background-color:#F0F0F0;padding:5px;margin-top:5px;border-width:1px;border-style:solid;border-color:#CCCCCC;transition:transform 100ms ease-in,opacity 150ms ease-in;opacity:0;box-sizing:border-box}.mce-notification.mce-in{opacity:1}.mce-notification-success{background-color:#dff0d8;border-color:#d6e9c6}.mce-notification-info{background-color:#d9edf7;border-color:#779ECB}.mce-notification-warning{background-color:#fcf8e3;border-color:#faebcc}.mce-notification-error{background-color:#f2dede;border-color:#ebccd1}.mce-notification.mce-has-close{padding-right:15px}.mce-notification .mce-ico{margin-top:5px}.mce-notification-inner{word-wrap:break-word;-ms-word-break:break-all;word-break:break-all;word-break:break-word;-ms-hyphens:auto;-moz-hyphens:auto;-webkit-hyphens:auto;hyphens:auto;display:inline-block;font-size:14px;margin:5px 8px 4px 8px;text-align:center;white-space:normal;color:#31708f}.mce-notification-inner a{text-decoration:underline;cursor:pointer}.
 mce-notification .mce-progress{margin-right:8px}.mce-notification .mce-progress .mce-text{margin-top:5px}.mce-notification *,.mce-notification .mce-progress .mce-text{color:#333333}.mce-notification .mce-progress .mce-bar-container{border-color:#CCCCCC}.mce-notification .mce-progress .mce-bar-container .mce-bar{background-color:#333333}.mce-notification-success *,.mce-notification-success .mce-progress .mce-text{color:#3c763d}.mce-notification-success .mce-progress .mce-bar-container{border-color:#d6e9c6}.mce-notification-success .mce-progress .mce-bar-container .mce-bar{background-color:#3c763d}.mce-notification-info *,.mce-notification-info .mce-progress .mce-text{color:#31708f}.mce-notification-info .mce-progress .mce-bar-container{border-color:#779ECB}.mce-notification-info .mce-progress .mce-bar-container .mce-bar{background-color:#31708f}.mce-notification-warning *,.mce-notification-warning .mce-progress .mce-text{color:#8a6d3b}.mce-notification-warning .mce-progress .mce-bar-
 container{border-color:#faebcc}.mce-notification-warning .mce-progress .mce-bar-container .mce-bar{background-color:#8a6d3b}.mce-notification-error *,.mce-notification-error .mce-progress .mce-text{color:#a94442}.mce-notification-error .mce-progress .mce-bar-container{border-color:#ebccd1}.mce-notification-error .mce-progress .mce-bar-container .mce-bar{background-color:#a94442}.mce-notification .mce-close{position:absolute;top:6px;right:8px;font-size:20px;font-weight:bold;line-height:20px;color:#858585;cursor:pointer;height:20px;overflow:hidden}.mce-abs-layout{position:relative}body .mce-abs-layout-item,.mce-abs-end{position:absolute}.mce-abs-end{width:1px;height:1px}.mce-container-body.mce-abs-layout{overflow:hidden}.mce-btn{border:1px solid #b1b1b1;border-color:transparent transparent transparent transparent;position:relative;text-shadow:0 1px 1px rgba(255,255,255,0.75);display:inline-block;*display:inline;*zoom:1;background-color:#f0f0f0}.mce-btn:hover,.mce-btn:focus{color:#333;
 background-color:#e3e3e3;border-color:#ccc}.mce-btn.mce-disabled button,.mce-btn.mce-disabled:hover button{cursor:default;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-btn.mce-active,.mce-btn.mce-active:hover{background-color:#dbdbdb;border-color:#ccc}.mce-btn:active{background-color:#e0e0e0;border-color:#ccc}.mce-btn button{padding:4px 8px;font-size:14px;line-height:20px;*line-height:16px;cursor:pointer;color:#333;text-align:center;overflow:visible;-webkit-appearance:none}.mce-btn button::-moz-focus-inner{border:0;padding:0}.mce-btn i{text-shadow:1px 1px none}.mce-primary.mce-btn-has-text{min-width:50px}.mce-primary{color:#fff;border:1px solid transparent;border-color:transparent;background-color:#2d8ac7}.mce-primary:hover,.mce-primary:focus{background-color:#257cb6;border-color:transparent}.mce-primary.mce-disabled button,.mce-primary.mce-disabled:hover button{cursor:default;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-primary.mce-active,.mce-primary.mce-active:hover,.mce-pri
 mary:not(.mce-disabled):active{background-color:#206ea1}.mce-primary button,.mce-primary button i{color:#fff;text-shadow:1px 1px none}.mce-btn .mce-txt{font-size:inherit;line-height:inherit;color:inherit}.mce-btn-large button{padding:9px 14px;font-size:16px;line-height:normal}.mce-btn-large i{margin-top:2px}.mce-btn-small button{padding:1px 5px;font-size:12px;*padding-bottom:2px}.mce-btn-small i{line-height:20px;vertical-align:top;*line-height:18px}.mce-btn .mce-caret{margin-top:8px;margin-left:0}.mce-btn-small .mce-caret{margin-top:8px;margin-left:0}.mce-caret{display:inline-block;*display:inline;*zoom:1;width:0;height:0;vertical-align:top;border-top:4px solid #333;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.mce-disabled .mce-caret{border-top-color:#aaa}.mce-caret.mce-up{border-bottom:4px solid #333;border-top:0}.mce-btn-flat{border:0;background:transparent;filter:none}.mce-btn-flat:hover,.mce-btn-flat.mce-active,.mce-btn-flat:focus,.m
 ce-btn-flat:active{border:0;background:#e6e6e6;filter:none}.mce-btn-has-text .mce-ico{padding-right:5px}.mce-rtl .mce-btn button{direction:rtl}.mce-btn-group .mce-btn{border-width:1px;margin:0;margin-left:2px}.mce-btn-group:not(:first-child){border-left:1px solid #d9d9d9;padding-left:3px;margin-left:3px}.mce-btn-group .mce-first{margin-left:0}.mce-btn-group .mce-btn.mce-flow-layout-item{margin:0}.mce-rtl .mce-btn-group .mce-btn{margin-left:0;margin-right:2px}.mce-rtl .mce-btn-group .mce-first{margin-right:0}.mce-rtl .mce-btn-group:not(:first-child){border-left:none;border-right:1px solid #d9d9d9;padding-right:4px;margin-right:4px}.mce-checkbox{cursor:pointer}i.mce-i-checkbox{margin:0 3px 0 0;border:1px solid #c5c5c5;background-color:#f0f0f0;text-indent:-10em;*font-size:0;*line-height:0;*text-indent:0;overflow:hidden}.mce-checked i.mce-i-checkbox{color:#333;font-size:16px;line-height:16px;text-indent:0}.mce-checkbox:focus i.mce-i-checkbox,.mce-checkbox.mce-focus i.mce-i-checkbox{bord
 er:1px solid rgba(82,168,236,0.8)}.mce-checkbox.mce-disabled .mce-label,.mce-checkbox.mce-disabled i.mce-i-checkbox{color:#acacac}.mce-checkbox .mce-label{vertical-align:middle}.mce-rtl .mce-checkbox{direction:rtl;text-align:right}.mce-rtl i.mce-i-checkbox{margin:0 0 0 3px}.mce-combobox{position:relative;display:inline-block;*display:inline;*zoom:1;*height:32px}.mce-combobox input{border:1px solid #c5c5c5;border-right-color:#c5c5c5;height:28px}.mce-combobox.mce-disabled input{color:#adadad}.mce-combobox .mce-btn{border:1px solid #c5c5c5;border-left:0;margin:0}.mce-combobox button{padding-right:8px;padding-left:8px}.mce-combobox.mce-disabled .mce-btn button{cursor:default;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-combobox .mce-status{position:absolute;right:2px;top:50%;line-height:16px;margin-top:-8px;font-size:12px;width:15px;height:15px;text-align:center;cursor:pointer}.mce-combobox.mce-has-status input{padding-right:20px}.mce-combobox.mce-has-open .mce-status{right:37px}.mce
 -combobox .mce-status.mce-i-warning{color:#c09853}.mce-combobox .mce-status.mce-i-checkmark{color:#468847}.mce-menu.mce-combobox-menu{border-top:0;margin-top:0;max-height:200px}.mce-menu.mce-combobox-menu .mce-menu-item{padding:4px 6px 4px 4px;font-size:11px}.mce-menu.mce-combobox-menu .mce-menu-item-sep{padding:0}.mce-menu.mce-combobox-menu .mce-text{font-size:11px}.mce-menu.mce-combobox-menu .mce-menu-item-link,.mce-menu.mce-combobox-menu .mce-menu-item-link b{font-size:11px}.mce-menu.mce-combobox-menu .mce-text b{font-size:11px}.mce-colorbox i{border:1px solid #c5c5c5;width:14px;height:14px}.mce-colorbutton .mce-ico{position:relative}.mce-colorbutton-grid{margin:4px}.mce-colorbutton button{padding-right:6px;padding-left:6px}.mce-colorbutton .mce-preview{padding-right:3px;display:block;position:absolute;left:50%;top:50%;margin-left:-17px;margin-top:7px;background:gray;width:13px;height:2px;overflow:hidden}.mce-colorbutton.mce-btn-small .mce-preview{margin-left:-16px;padding-right:
 0;width:16px}.mce-colorbutton .mce-open{padding-left:4px;padding-right:4px;border-left:1px solid transparent}.mce-colorbutton:hover .mce-open{border-color:#ccc}.mce-colorbutton.mce-btn-small .mce-open{padding:0 3px 0 3px}.mce-rtl .mce-colorbutton{direction:rtl}.mce-rtl .mce-colorbutton .mce-preview{margin-left:0;padding-right:0;padding-left:3px}.mce-rtl .mce-colorbutton.mce-btn-small .mce-preview{margin-left:0;padding-right:0;padding-left:2px}.mce-rtl .mce-colorbutton .mce-open{padding-left:4px;padding-right:4px;border-left:0}.mce-colorpicker{position:relative;width:250px;height:220px}.mce-colorpicker-sv{position:absolute;top:0;left:0;width:90%;height:100%;border:1px solid #c5c5c5;cursor:crosshair;overflow:hidden}.mce-colorpicker-h-chunk{width:100%}.mce-colorpicker-overlay1,.mce-colorpicker-overlay2{width:100%;height:100%;position:absolute;top:0;left:0}.mce-colorpicker-overlay1{filter:progid:DXImageTransform.Microsoft.gradient(GradientType=1, startColorstr='#ffffff', endColorstr='#0
 0ffffff');-ms-filter:"progid:DXImageTransform.Microsoft.gradient(GradientType=1,startColorstr='#ffffff', endColorstr='#00ffffff')";background:linear-gradient(to right, #fff, rgba(255,255,255,0))}.mce-colorpicker-overlay2{filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#00000000', endColorstr='#000000');-ms-filter:"progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#00000000', endColorstr='#000000')";background:linear-gradient(to bottom, rgba(0,0,0,0), #000)}.mce-colorpicker-selector1{background:none;position:absolute;width:12px;height:12px;margin:-8px 0 0 -8px;border:1px solid black;border-radius:50%}.mce-colorpicker-selector2{position:absolute;width:10px;height:10px;border:1px solid white;border-radius:50%}.mce-colorpicker-h{position:absolute;top:0;right:0;width:6.5%;height:100%;border:1px solid #c5c5c5;cursor:crosshair}.mce-colorpicker-h-marker{margin-top:-4px;position:absolute;top:0;left:-1px;width:100%;bo
 rder:1px solid #333;background:#fff;height:4px;z-index:100}.mce-path{display:inline-block;*display:inline;*zoom:1;padding:8px;white-space:normal}.mce-path .mce-txt{display:inline-block;padding-right:3px}.mce-path .mce-path-body{display:inline-block}.mce-path-item{display:inline-block;*display:inline;*zoom:1;cursor:pointer;color:#333}.mce-path-item:hover{text-decoration:underline}.mce-path-item:focus{background:#666;color:#fff}.mce-path .mce-divider{display:inline}.mce-disabled .mce-path-item{color:#aaa}.mce-rtl .mce-path{direction:rtl}.mce-fieldset{border:0 solid #9E9E9E}.mce-fieldset>.mce-container-body{margin-top:-15px}.mce-fieldset-title{margin-left:5px;padding:0 5px 0 5px}.mce-fit-layout{display:inline-block;*display:inline;*zoom:1}.mce-fit-layout-item{position:absolute}.mce-flow-layout-item{display:inline-block;*display:inline;*zoom:1}.mce-flow-layout-item{margin:2px 0 2px 2px}.mce-flow-layout-item.mce-last{margin-right:2px}.mce-flow-layout{white-space:normal}.mce-tinymce-in
 line .mce-flow-layout{white-space:nowrap}.mce-rtl .mce-flow-layout{text-align:right;direction:rtl}.mce-rtl .mce-flow-layout-item{margin:2px 2px 2px 0}.mce-rtl .mce-flow-layout-item.mce-last{margin-left:2px}.mce-iframe{border:0 solid rgba(0,0,0,0.2);width:100%;height:100%}.mce-infobox{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 1px rgba(255,255,255,0.75);overflow:hidden;border:1px solid red}.mce-infobox div{display:block;margin:5px}.mce-infobox div button{position:absolute;top:50%;right:4px;cursor:pointer;margin-top:-8px;display:none}.mce-infobox div button:focus{outline:2px solid #ccc}.mce-infobox.mce-has-help div{margin-right:25px}.mce-infobox.mce-has-help button{display:block}.mce-infobox.mce-success{background:#dff0d8;border-color:#d6e9c6}.mce-infobox.mce-success div{color:#3c763d}.mce-infobox.mce-warning{background:#fcf8e3;border-color:#faebcc}.mce-infobox.mce-warning div{color:#8a6d3b}.mce-infobox.mce-error{background:#f2dede;border-color:#ebccd1}.mce-infobox
 .mce-error div{color:#a94442}.mce-rtl .mce-infobox div{text-align:right;direction:rtl}.mce-label{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 1px rgba(255,255,255,0.75);overflow:hidden}.mce-label.mce-autoscroll{overflow:auto}.mce-label.mce-disabled{color:#aaa}.mce-label.mce-multiline{white-space:pre-wrap}.mce-label.mce-success{color:#468847}.mce-label.mce-warning{color:#c09853}.mce-label.mce-error{color:#b94a48}.mce-rtl .mce-label{text-align:right;direction:rtl}.mce-menubar .mce-menubtn{border-color:transparent;background:transparent;filter:none}.mce-menubar .mce-menubtn button{color:#333}.mce-menubar{border:1px solid rgba(217,217,217,0.52)}.mce-menubar .mce-menubtn button span{color:#333}.mce-menubar .mce-caret{border-top-color:#333}.mce-menubar .mce-menubtn:hover,.mce-menubar .mce-menubtn.mce-active,.mce-menubar .mce-menubtn:focus{border-color:#ccc;background:#fff;filter:none}.mce-menubtn button{color:#333}.mce-menubtn.mce-btn-small span{font-size:12px}.mce-menub
 tn.mce-fixed-width span{display:inline-block;overflow-x:hidden;text-overflow:ellipsis;width:90px}.mce-menubtn.mce-fixed-width.mce-btn-small span{width:70px}.mce-menubtn .mce-caret{*margin-top:6px}.mce-rtl .mce-menubtn button{direction:rtl;text-align:right}.mce-menu-item{display:block;padding:6px 15px 6px 12px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap;cursor:pointer;line-height:normal;border-left:4px solid transparent;margin-bottom:1px}.mce-menu-item .mce-ico,.mce-menu-item .mce-text{color:#333}.mce-menu-item.mce-disabled .mce-text,.mce-menu-item.mce-disabled .mce-ico{color:#adadad}.mce-menu-item:hover .mce-text,.mce-menu-item.mce-selected .mce-text,.mce-menu-item:focus .mce-text{color:white}.mce-menu-item:hover .mce-ico,.mce-menu-item.mce-selected .mce-ico,.mce-menu-item:focus .mce-ico{color:white}.mce-menu-item.mce-disabled:hover{background:#CCC}.mce-menu-shortcut{display:inline-block;color:#adadad}.mce-menu-shortcut{display:inline-block;*display:
 inline;*zoom:1;padding:0 15px 0 20px}.mce-menu-item:hover .mce-menu-shortcut,.mce-menu-item.mce-selected .mce-menu-shortcut,.mce-menu-item:focus .mce-menu-shortcut{color:white}.mce-menu-item .mce-caret{margin-top:4px;*margin-top:3px;margin-right:6px;border-top:4px solid transparent;border-bottom:4px solid transparent;border-left:4px solid #333}.mce-menu-item.mce-selected .mce-caret,.mce-menu-item:focus .mce-caret,.mce-menu-item:hover .mce-caret{border-left-color:white}.mce-menu-align .mce-menu-shortcut{*margin-top:-2px}.mce-menu-align .mce-menu-shortcut,.mce-menu-align .mce-caret{position:absolute;right:0}.mce-menu-item.mce-active i{visibility:visible}.mce-menu-item-normal.mce-active{background-color:#3498db}.mce-menu-item-preview.mce-active{border-left:5px solid #aaa}.mce-menu-item-normal.mce-active .mce-text{color:white}.mce-menu-item-normal.mce-active:hover .mce-text,.mce-menu-item-normal.mce-active:hover .mce-ico{color:white}.mce-menu-item-normal.mce-active:focus .mce-text,.mce-
 menu-item-normal.mce-active:focus .mce-ico{color:white}.mce-menu-item:hover,.mce-menu-item.mce-selected,.mce-menu-item:focus{text-decoration:none;color:white;background-color:#2d8ac7}.mce-menu-item-link{color:#093;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mce-menu-item-link b{color:#093}.mce-menu-item-ellipsis{display:block;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.mce-menu-item:hover *,.mce-menu-item.mce-selected *,.mce-menu-item:focus *{color:white}div.mce-menu .mce-menu-item-sep,.mce-menu-item-sep:hover{border:0;padding:0;height:1px;margin:9px 1px;overflow:hidden;background:transparent;border-bottom:1px solid rgba(0,0,0,0.1);cursor:default;filter:none}div.mce-menu .mce-menu-item b{font-weight:bold}.mce-menu-item-indent-1{padding-left:20px}.mce-menu-item-indent-2{padding-left:35px}.mce-menu-item-indent-2{padding-left:35px}.mce-menu-item-indent-3{padding-left:40px}.mce-menu-item-indent-4{padding-left:45px}.mce-menu-item-indent-5{padding-left:50px}.
 mce-menu-item-indent-6{padding-left:55px}.mce-menu.mce-rtl{direction:rtl}.mce-rtl .mce-menu-item{text-align:right;direction:rtl;padding:6px 12px 6px 15px}.mce-menu-align.mce-rtl .mce-menu-shortcut,.mce-menu-align.mce-rtl .mce-caret{right:auto;left:0}.mce-rtl .mce-menu-item .mce-caret{margin-left:6px;margin-right:0;border-right:4px solid #333;border-left:0}.mce-rtl .mce-menu-item.mce-selected .mce-caret,.mce-rtl .mce-menu-item:focus .mce-caret,.mce-rtl .mce-menu-item:hover .mce-caret{border-left-color:transparent;border-right-color:white}.mce-throbber{position:absolute;top:0;left:0;width:100%;height:100%;opacity:.6;filter:alpha(opacity=60);zoom:1;background:#fff url('img/loader.gif') no-repeat center center}.mce-throbber-inline{position:static;height:50px}.mce-menu .mce-throbber-inline{height:25px;background-size:contain}.mce-menu{position:absolute;left:0;top:0;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;z-index:1000;padding:5px 0 5px 0;m
 argin:-1px 0 0;min-width:160px;background:#fff;border:1px solid #989898;border:1px solid rgba(0,0,0,0.2);z-index:1002;max-height:400px;overflow:auto;overflow-x:hidden}.mce-menu i{display:none}.mce-menu-has-icons i{display:inline-block;*display:inline}.mce-menu-sub-tr-tl{margin:-6px 0 0 -1px}.mce-menu-sub-br-bl{margin:6px 0 0 -1px}.mce-menu-sub-tl-tr{margin:-6px 0 0 1px}.mce-menu-sub-bl-br{margin:6px 0 0 1px}.mce-listbox button{text-align:left;padding-right:20px;position:relative}.mce-listbox .mce-caret{position:absolute;margin-top:-2px;right:8px;top:50%}.mce-rtl .mce-listbox .mce-caret{right:auto;left:8px}.mce-rtl .mce-listbox button{padding-right:10px;padding-left:20px}.mce-container-body .mce-resizehandle{position:absolute;right:0;bottom:0;width:16px;height:16px;visibility:visible;cursor:s-resize;margin:0}.mce-container-body .mce-resizehandle-both{cursor:se-resize}i.mce-i-resize{color:#333}.mce-selectbox{background:#fff;border:1px solid #c5c5c5}.mce-slider{border:1px solid #AAA;ba
 ckground:#EEE;width:100px;height:10px;position:relative;display:block}.mce-slider.mce-vertical{width:10px;height:100px}.mce-slider-handle{border:1px solid #BBB;background:#DDD;display:block;width:13px;height:13px;position:absolute;top:0;left:0;margin-left:-1px;margin-top:-2px}.mce-slider-handle:focus{background:#BBB}.mce-spacer{visibility:hidden}.mce-splitbtn .mce-open{border-left:1px solid transparent}.mce-splitbtn:hover .mce-open{border-left-color:#ccc}.mce-splitbtn button{padding-right:6px;padding-left:6px}.mce-splitbtn .mce-open{padding-right:4px;padding-left:4px}.mce-splitbtn .mce-open.mce-active{background-color:#dbdbdb;outline:1px solid #ccc}.mce-splitbtn.mce-btn-small .mce-open{padding:0 3px 0 3px}.mce-rtl .mce-splitbtn{direction:rtl;text-align:right}.mce-rtl .mce-splitbtn button{padding-right:4px;padding-left:4px}.mce-rtl .mce-splitbtn .mce-open{border-left:0}.mce-stack-layout-item{display:block}.mce-tabs{display:block;border-bottom:1px solid #c5c5c5}.mce-tabs,.mce-tabs+.mc
 e-container-body{background:#FFF}.mce-tab{display:inline-block;*display:inline;*zoom:1;border:1px solid #c5c5c5;border-width:0 1px 0 0;background:#ffffff;padding:8px;text-shadow:0 1px 1px rgba(255,255,255,0.75);height:13px;cursor:pointer}.mce-tab:hover{background:#FDFDFD}.mce-tab.mce-active{background:#FDFDFD;border-bottom-color:transparent;margin-bottom:-1px;height:14px}.mce-rtl .mce-tabs{text-align:right;direction:rtl}.mce-rtl .mce-tab{border-width:0 0 0 1px}.mce-textbox{background:#fff;border:1px solid #c5c5c5;display:inline-block;-webkit-transition:border linear .2s, box-shadow linear .2s;transition:border linear .2s, box-shadow linear .2s;height:28px;resize:none;padding:0 4px 0 4px;white-space:pre-wrap;*white-space:pre;color:#333}.mce-textbox:focus,.mce-textbox.mce-focus{border-color:#3498db}.mce-placeholder .mce-textbox{color:#aaa}.mce-textbox.mce-multiline{padding:4px;height:auto}.mce-textbox.mce-disabled{color:#adadad}.mce-rtl .mce-textbox{text-align:right;direction:rtl}.mce
 -dropzone{border:3px dashed gray;text-align:center}.mce-dropzone span{color:gray;text-transform:uppercase;font-family:Verdana;display:inline-block;vertical-align:middle}.mce-dropzone:after{content:"";height:100%;display:inline-block;vertical-align:middle}.mce-dropzone.mce-disabled{opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-dropzone.mce-disabled.mce-dragenter{cursor:not-allowed}.mce-browsebutton{position:relative;overflow:hidden}.mce-browsebutton button{position:relative;z-index:1}.mce-browsebutton input{opacity:0;filter:alpha(opacity=0);zoom:1;position:absolute;top:0;left:0;width:100%;height:100%;z-index:0}@font-face{font-family:'tinymce';src:url('fonts/tinymce.eot');src:url('fonts/tinymce.eot?#iefix') format('embedded-opentype'),url('fonts/tinymce.woff') format('woff'),url('fonts/tinymce.ttf') format('truetype'),url('fonts/tinymce.svg#tinymce') format('svg');font-weight:normal;font-style:normal}@font-face{font-family:'tinymce-small';src:url('fonts/tinymce-small.eot')
 ;src:url('fonts/tinymce-small.eot?#iefix') format('embedded-opentype'),url('fonts/tinymce-small.woff') format('woff'),url('fonts/tinymce-small.ttf') format('truetype'),url('fonts/tinymce-small.svg#tinymce') format('svg');font-weight:normal;font-style:normal}.mce-ico{font-family:'tinymce',Arial;font-style:normal;font-weight:normal;font-variant:normal;font-size:16px;line-height:16px;speak:none;vertical-align:text-top;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;display:inline-block;background:transparent center center;background-size:cover;width:16px;height:16px;color:#333}.mce-btn-small .mce-ico{font-family:'tinymce-small',Arial}.mce-i-save:before{content:"\e000"}.mce-i-newdocument:before{content:"\e001"}.mce-i-fullpage:before{content:"\e002"}.mce-i-alignleft:before{content:"\e003"}.mce-i-aligncenter:before{content:"\e004"}.mce-i-alignright:before{content:"\e005"}.mce-i-alignjustify:before{content:&qu
 ot;\e006"}.mce-i-alignnone:before{content:"\e003"}.mce-i-cut:before{content:"\e007"}.mce-i-paste:before{content:"\e008"}.mce-i-searchreplace:before{content:"\e009"}.mce-i-bullist:before{content:"\e00a"}.mce-i-numlist:before{content:"\e00b"}.mce-i-indent:before{content:"\e00c"}.mce-i-outdent:before{content:"\e00d"}.mce-i-blockquote:before{content:"\e00e"}.mce-i-undo:before{content:"\e00f"}.mce-i-redo:before{content:"\e010"}.mce-i-link:before{content:"\e011"}.mce-i-unlink:before{content:"\e012"}.mce-i-anchor:before{content:"\e013"}.mce-i-image:before{content:"\e014"}.mce-i-media:before{content:"\e015"}.mce-i-help:before{content:"\e016"}.mce-i-code:before{content:"\e017"}.mce-i-insertdatetime:before{content:"\e018"}.mce-i-preview:before{content:"\e019"}.mce-i-forecolor:before{content:
 "\e01a"}.mce-i-backcolor:before{content:"\e01a"}.mce-i-table:before{content:"\e01b"}.mce-i-hr:before{content:"\e01c"}.mce-i-removeformat:before{content:"\e01d"}.mce-i-subscript:before{content:"\e01e"}.mce-i-superscript:before{content:"\e01f"}.mce-i-charmap:before{content:"\e020"}.mce-i-emoticons:before{content:"\e021"}.mce-i-print:before{content:"\e022"}.mce-i-fullscreen:before{content:"\e023"}.mce-i-spellchecker:before{content:"\e024"}.mce-i-nonbreaking:before{content:"\e025"}.mce-i-template:before{content:"\e026"}.mce-i-pagebreak:before{content:"\e027"}.mce-i-restoredraft:before{content:"\e028"}.mce-i-bold:before{content:"\e02a"}.mce-i-italic:before{content:"\e02b"}.mce-i-underline:before{content:"\e02c"}.mce-i-strikethrough:before{content:"\e02d"}.mce-i-visualchars:before{content:&qu
 ot;\e02e"}.mce-i-visualblocks:before{content:"\e02e"}.mce-i-ltr:before{content:"\e02f"}.mce-i-rtl:before{content:"\e030"}.mce-i-copy:before{content:"\e031"}.mce-i-resize:before{content:"\e032"}.mce-i-browse:before{content:"\e034"}.mce-i-pastetext:before{content:"\e035"}.mce-i-rotateleft:before{content:"\eaa8"}.mce-i-rotateright:before{content:"\eaa9"}.mce-i-crop:before{content:"\ee78"}.mce-i-editimage:before{content:"\e915"}.mce-i-options:before{content:"\ec6a"}.mce-i-flipv:before{content:"\eaaa"}.mce-i-fliph:before{content:"\eaac"}.mce-i-zoomin:before{content:"\eb35"}.mce-i-zoomout:before{content:"\eb36"}.mce-i-sun:before{content:"\eccc"}.mce-i-moon:before{content:"\eccd"}.mce-i-arrowleft:before{content:"\edc0"}.mce-i-arrowright:before{content:"\e93c"}.mce-i-drop:before{content:&q
 uot;\e935"}.mce-i-contrast:before{content:"\ecd4"}.mce-i-sharpen:before{content:"\eba7"}.mce-i-resize2:before{content:"\edf9"}.mce-i-orientation:before{content:"\e601"}.mce-i-invert:before{content:"\e602"}.mce-i-gamma:before{content:"\e600"}.mce-i-remove:before{content:"\ed6a"}.mce-i-tablerowprops:before{content:"\e604"}.mce-i-tablecellprops:before{content:"\e605"}.mce-i-table2:before{content:"\e606"}.mce-i-tablemergecells:before{content:"\e607"}.mce-i-tableinsertcolbefore:before{content:"\e608"}.mce-i-tableinsertcolafter:before{content:"\e609"}.mce-i-tableinsertrowbefore:before{content:"\e60a"}.mce-i-tableinsertrowafter:before{content:"\e60b"}.mce-i-tablesplitcells:before{content:"\e60d"}.mce-i-tabledelete:before{content:"\e60e"}.mce-i-tableleftheader:before{content:"\e62a"}.mce-i-tabletopheader:befo
 re{content:"\e62b"}.mce-i-tabledeleterow:before{content:"\e800"}.mce-i-tabledeletecol:before{content:"\e801"}.mce-i-codesample:before{content:"\e603"}.mce-i-fill:before{content:"\e902"}.mce-i-borderwidth:before{content:"\e903"}.mce-i-line:before{content:"\e904"}.mce-i-count:before{content:"\e905"}.mce-i-translate:before{content:"\e907"}.mce-i-drag:before{content:"\e908"}.mce-i-home:before{content:"\e90b"}.mce-i-upload:before{content:"\e914"}.mce-i-bubble:before{content:"\e91c"}.mce-i-user:before{content:"\e91d"}.mce-i-lock:before{content:"\e926"}.mce-i-unlock:before{content:"\e927"}.mce-i-settings:before{content:"\e928"}.mce-i-remove2:before{content:"\e92a"}.mce-i-menu:before{content:"\e92d"}.mce-i-warning:before{content:"\e930"}.mce-i-question:before{content:"\e931"}.mce-i-pl
 uscircle:before{content:"\e932"}.mce-i-info:before{content:"\e933"}.mce-i-notice:before{content:"\e934"}.mce-i-arrowup:before{content:"\e93b"}.mce-i-arrowdown:before{content:"\e93d"}.mce-i-arrowup2:before{content:"\e93f"}.mce-i-arrowdown2:before{content:"\e940"}.mce-i-menu2:before{content:"\e941"}.mce-i-newtab:before{content:"\e961"}.mce-i-a11y:before{content:"\e900"}.mce-i-plus:before{content:"\e93a"}.mce-i-insert:before{content:"\e93a"}.mce-i-minus:before{content:"\e939"}.mce-i-books:before{content:"\e911"}.mce-i-reload:before{content:"\e906"}.mce-i-toc:before{content:"\e901"}.mce-i-checkmark:before{content:"\e033"}.mce-i-checkbox:before,.mce-i-selected:before{content:"\e033"}.mce-i-insert{font-size:14px}.mce-i-selected{visibility:hidden}i.mce-i-backcolor{text-shadow:none;background:#BBB}
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span></span></pre></div>
<a id="trunksrcwpincludesjstinymceskinswordpresswpcontentcss"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css   2017-09-26 20:32:46 UTC (rev 41603)
+++ trunk/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css     2017-09-26 21:14:28 UTC (rev 41604)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -21,18 +21,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">        word-wrap: break-word; /* Old syntax */
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/* Changed in 4.6.0, see https://core.trac.wordpress.org/ticket/40743 */
-.mce-content-body p,
-.mce-content-body div,
-.mce-content-body h1,
-.mce-content-body h2,
-.mce-content-body h3,
-.mce-content-body h4,
-.mce-content-body h5,
-.mce-content-body h6 {
-    line-height: inherit;
-}
-
</del><span class="cx" style="display: block; padding: 0 10px"> body.rtl {
</span><span class="cx" style="display: block; padding: 0 10px">        font-family: Tahoma, "Times New Roman", "Bitstream Charter", Times, serif;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="trunksrcwpincludesjstinymcethemesinlitethemejs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/tinymce/themes/inlite/theme.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/tinymce/themes/inlite/theme.js   2017-09-26 20:32:46 UTC (rev 41603)
+++ trunk/src/wp-includes/js/tinymce/themes/inlite/theme.js     2017-09-26 21:14:28 UTC (rev 41604)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -81,7 +81,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">   define(id, [], function () { return ref; });
</span><span class="cx" style="display: block; padding: 0 10px"> };
</span><span class="cx" style="display: block; padding: 0 10px"> /*jsc
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-["tinymce.themes.inlite.Theme","tinymce.core.ThemeManager","tinymce.core.ui.Api","tinymce.core.util.Delay","tinymce.themes.inlite.alien.Arr","tinymce.themes.inlite.alien.EditorSettings","tinymce.themes.inlite.core.ElementMatcher","tinymce.themes.inlite.core.Matcher","tinymce.themes.inlite.core.PredicateId","tinymce.themes.inlite.core.SelectionMatcher","tinymce.themes.inlite.core.SkinLoader","tinymce.themes.inlite.ui.Buttons","tinymce.themes.inlite.ui.Panel","global!tinymce.util.Tools.resolve","tinymce.themes.inlite.alien.Type","tinymce.themes.inlite.core.Measure","tinymce.core.util.Tools","tinymce.core.EditorManager","tinymce.core.dom.DOMUtils","tinymce.core.ui.Factory","tinymce.themes.
 inlite.ui.Toolbar","tinymce.themes.inlite.ui.Forms","tinymce.themes.inlite.core.Layout","tinymce.themes.inlite.file.Conversions","tinymce.themes.inlite.file.Picker","tinymce.themes.inlite.core.Actions","tinymce.core.geom.Rect","tinymce.themes.inlite.core.Convert","tinymce.core.util.Promise","tinymce.themes.inlite.alien.Uuid","tinymce.themes.inlite.alien.Unlink","tinymce.themes.inlite.core.UrlType","tinymce.themes.inlite.alien.Bookmark","tinymce.core.dom.TreeWalker","tinymce.core.dom.RangeUtils"]
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+["tinymce.themes.inlite.Theme","tinymce.core.ThemeManager","tinymce.core.ui.Api","tinymce.core.util.Delay","tinymce.themes.inlite.alien.Arr","tinymce.themes.inlite.alien.EditorSettings","tinymce.themes.inlite.core.ElementMatcher","tinymce.themes.inlite.core.Matcher","tinymce.themes.inlite.core.PredicateId","tinymce.themes.inlite.core.SelectionMatcher","tinymce.themes.inlite.core.SkinLoader","tinymce.themes.inlite.ui.Buttons","tinymce.themes.inlite.ui.Panel","global!tinymce.util.Tools.resolve","tinymce.themes.inlite.alien.Type","tinymce.themes.inlite.core.Measure","tinymce.core.util.Tools","tinymce.core.EditorManager","tinymce.core.dom.DOMUtils","tinymce.core.ui.Factory","tinymce.themes.i
 nlite.ui.Toolbar","tinymce.themes.inlite.ui.Forms","tinymce.themes.inlite.core.Layout","tinymce.themes.inlite.file.Conversions","tinymce.themes.inlite.file.Picker","tinymce.themes.inlite.core.Actions","tinymce.themes.inlite.core.Convert","tinymce.core.util.Promise","tinymce.themes.inlite.alien.Uuid","tinymce.themes.inlite.alien.Unlink","tinymce.themes.inlite.core.UrlType","tinymce.core.geom.Rect","tinymce.themes.inlite.alien.Bookmark","tinymce.core.dom.TreeWalker","tinymce.core.dom.RangeUtils"]
</ins><span class="cx" style="display: block; padding: 0 10px"> jsc*/
</span><span class="cx" style="display: block; padding: 0 10px"> defineGlobal("global!tinymce.util.Tools.resolve", tinymce.util.Tools.resolve);
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -360,26 +360,6 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * ResolveGlobal.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-define(
-  'tinymce.core.geom.Rect',
-  [
-    'global!tinymce.util.Tools.resolve'
-  ],
-  function (resolve) {
-    return resolve('tinymce.geom.Rect');
-  }
-);
-
-/**
</del><span class="cx" style="display: block; padding: 0 10px">  * Convert.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -435,10 +415,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">   'tinymce.themes.inlite.core.Measure',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.dom.DOMUtils',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.geom.Rect',
</del><span class="cx" style="display: block; padding: 0 10px">     'tinymce.themes.inlite.core.Convert'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (DOMUtils, Rect, Convert) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (DOMUtils, Convert) {
</ins><span class="cx" style="display: block; padding: 0 10px">     var toAbsolute = function (rect) {
</span><span class="cx" style="display: block; padding: 0 10px">       var vp = DOMUtils.DOM.getViewPort();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1469,6 +1448,26 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * ResolveGlobal.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.geom.Rect',
+  [
+    'global!tinymce.util.Tools.resolve'
+  ],
+  function (resolve) {
+    return resolve('tinymce.geom.Rect');
+  }
+);
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * Layout.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1499,18 +1498,26 @@
</span><span class="cx" style="display: block; padding: 0 10px">     var calcByPositions = function (testPositions1, testPositions2, targetRect, contentAreaRect, panelRect) {
</span><span class="cx" style="display: block; padding: 0 10px">       var relPos, relRect, outputPanelRect;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      relPos = Rect.findBestRelativePosition(panelRect, targetRect, contentAreaRect, testPositions1);
-      targetRect = Rect.clamp(targetRect, contentAreaRect);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var paddedContentRect = {
+        x: contentAreaRect.x,
+        y: contentAreaRect.y,
+        w: contentAreaRect.w + (contentAreaRect.w < (panelRect.w + targetRect.w) ? panelRect.w : 0),
+        h: contentAreaRect.h + (contentAreaRect.h < (panelRect.h + targetRect.h) ? panelRect.h : 0)
+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      relPos = Rect.findBestRelativePosition(panelRect, targetRect, paddedContentRect, testPositions1);
+      targetRect = Rect.clamp(targetRect, paddedContentRect);
+
</ins><span class="cx" style="display: block; padding: 0 10px">       if (relPos) {
</span><span class="cx" style="display: block; padding: 0 10px">         relRect = Rect.relativePosition(panelRect, targetRect, relPos);
</span><span class="cx" style="display: block; padding: 0 10px">         outputPanelRect = moveTo(panelRect, relRect);
</span><span class="cx" style="display: block; padding: 0 10px">         return result(outputPanelRect, relPos);
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      targetRect = Rect.intersect(contentAreaRect, targetRect);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      targetRect = Rect.intersect(paddedContentRect, targetRect);
</ins><span class="cx" style="display: block; padding: 0 10px">       if (targetRect) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        relPos = Rect.findBestRelativePosition(panelRect, targetRect, contentAreaRect, testPositions2);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        relPos = Rect.findBestRelativePosition(panelRect, targetRect, paddedContentRect, testPositions2);
+
</ins><span class="cx" style="display: block; padding: 0 10px">         if (relPos) {
</span><span class="cx" style="display: block; padding: 0 10px">           relRect = Rect.relativePosition(panelRect, targetRect, relPos);
</span><span class="cx" style="display: block; padding: 0 10px">           outputPanelRect = moveTo(panelRect, relRect);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1536,8 +1543,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var calc = function (targetRect, contentAreaRect, panelRect) {
</span><span class="cx" style="display: block; padding: 0 10px">       return calcByPositions(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        ['tc-bc', 'bc-tc', 'tl-bl', 'bl-tl', 'tr-br', 'br-tr'],
-        ['bc-tc', 'bl-tl', 'br-tr'],
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        ['tc-bc', 'bc-tc', 'tl-bl', 'bl-tl', 'tr-br', 'br-tr', 'cr-cl', 'cl-cr'],
+        ['bc-tc', 'bl-tl', 'br-tr', 'cr-cl'],
</ins><span class="cx" style="display: block; padding: 0 10px">         targetRect,
</span><span class="cx" style="display: block; padding: 0 10px">         contentAreaRect,
</span><span class="cx" style="display: block; padding: 0 10px">         panelRect
</span></span></pre></div>
<a id="trunksrcwpincludesjstinymcethemesinlitethememinjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/tinymce/themes/inlite/theme.min.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/tinymce/themes/inlite/theme.min.js       2017-09-26 20:32:46 UTC (rev 41603)
+++ trunk/src/wp-includes/js/tinymce/themes/inlite/theme.min.js 2017-09-26 21:14:28 UTC (rev 41604)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1 +1 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("d",tinymce.util.Tools.resolve),g("1",[&q
 uot;d"],function(a){return a("tinymce.ThemeManager")}),g("2",["d"],function(a){return a("tinymce.ui.Api")}),g("3",["d"],function(a){return a("tinymce.util.Delay")}),g("4",[],function(){var a=function(b){return b.reduce(function(b,c){return Array.isArray(c)?b.concat(a(c)):b.concat(c)},[])};return{flatten:a}}),g("e",[],function(){var a=function(a){return function(b){return typeof b===a}},b=function(a){return Array.isArray(a)},c=function(a){return null===a},d=function(a){return function(d){return!c(d)&&!b(d)&&a(d)}};return{isString:a("string"),isNumber:a("number"),isBoolean:a("boolean"),isFunction:a("function"),isObject:d(a("object")),isNull:c,isArray:b}}),g("5",["e"],function(a){var b=function(a,b){if(b(a))return!0;throw new Error("Default value doesn't match requested type.")},c=function(a){retur
 n function(c,d,e){var f=c.settings;return b(e,a),d in f&&a(f[d])?f[d]:e}},d=function(a,b){return a.split(b).filter(function(a){return a.length>0})},e=function(b,c){var e=function(a){return"string"==typeof a?d(a,/[ ,]/):a},f=function(a,b){return a===!1?[]:b};return a.isArray(b)?b:a.isString(b)?e(b):a.isBoolean(b)?f(b,c):c},f=function(a){return function(c,d,f){var g=d in c.settings?c.settings[d]:f;return b(f,a),e(g,f)}};return{getStringOr:c(a.isString),getBoolOr:c(a.isBoolean),getNumberOr:c(a.isNumber),getHandlerOr:c(a.isFunction),getToolbarItemsOr:f(a.isArray)}}),g("7",[],function(){var a=function(a,b){return{id:a,rect:b}},b=function(a,b){for(var c=0;c<b.length;c++){var d=b[c],e=d(a);if(e)return e}return null};return{match:b,result:a}}),g("i",["d"],function(a){return a("tinymce.dom.DOMUtils")}),g("q",["d"],function(a){return a("tinymce.geom.Rect")}),g("r",[],function(){var a=functi
 on(a){return{x:a.left,y:a.top,w:a.width,h:a.height}},b=function(a){return{left:a.x,top:a.y,width:a.w,height:a.h,right:a.x+a.w,bottom:a.y+a.h}};return{fromClientRect:a,toClientRect:b}}),g("f",["i","q","r"],function(a,b,c){var d=function(b){var c=a.DOM.getViewPort();return{x:b.x+c.x,y:b.y+c.y,w:b.w,h:b.h}},e=function(a){var b=a.getBoundingClientRect();return d({x:b.left,y:b.top,w:Math.max(a.clientWidth,a.offsetWidth),h:Math.max(a.clientHeight,a.offsetHeight)})},f=function(a,b){return e(b)},g=function(a){return e(a.getElement().ownerDocument.body)},h=function(a){return e(a.getContentAreaContainer()||a.getBody())},i=function(a){var b=a.selection.getBoundingClientRect();return b?d(c.fromClientRect(b)):null};return{getElementRect:f,getPageAreaRect:g,getContentAreaRect:h,getSelectionRect:i}}),g("6",["7","f"],function(a,b){var c=function(c,d){return function(e){for(var f=0;f<d.length;f++)if(d[f].predicate(c))return a.r
 esult(d[f].id,b.getElementRect(e,c));return null}},d=function(c,d){return function(e){for(var f=0;f<c.length;f++)for(var g=0;g<d.length;g++)if(d[g].predicate(c[f]))return a.result(d[g].id,b.getElementRect(e,c[f]));return null}};return{element:c,parent:d}}),g("g",["d"],function(a){return a("tinymce.util.Tools")}),g("8",["g"],function(a){var b=function(a,b){return{id:a,predicate:b}},c=function(c){return a.map(c,function(a){return b(a.id,a.predicate)})};return{create:b,fromContextToolbars:c}}),g("9",["7","f"],function(a,b){var c=function(c){return function(d){return d.selection.isCollapsed()?null:a.result(c,b.getSelectionRect(d))}},d=function(c,d){return function(e){var f,g=e.schema.getTextBlockElements();for(f=0;f<c.length;f++)if("TABLE"===c[f].nodeName)return null;for(f=0;f<c.length;f++)if(c[f].nodeName in g)return e.dom.isEmpty(c[f])?a.result(d,b.getSelectionRect(e)):null;return nul
 l}};return{textSelection:c,emptyTextBlock:d}}),g("h",["d"],function(a){return a("tinymce.EditorManager")}),g("a",["h","i"],function(a,b){var c=function(a,b){var c=function(){a._skinLoaded=!0,a.fire("SkinLoaded"),b()};a.initialized?c():a.on("init",c)},d=function(b){var c=a.baseURL+"/skins/";return b?c+b:c+"lightgray"},e=function(a,b){return a.documentBaseURI.toAbsolute(b)},f=function(a,f){var g=a.settings,h=g.skin_url?e(a,g.skin_url):d(g.skin),i=function(){c(a,f)};b.DOM.styleSheetLoader.load(h+"/skin.min.css",i),a.contentCSS.push(h+"/content.inline.min.css")};return{load:f}}),g("j",["d"],function(a){return a("tinymce.ui.Factory")}),g("k",["g","j","e"],function(a,b,c){var d=function(a,b){var c=function(a,b){return{selector:a,handler:b}},d=function(a){b.active(a)},e=function(a){b.disabled(a)};return
  b.settings.stateSelector?c(b.settings.stateSelector,d):b.settings.disabledStateSelector?c(b.settings.disabledStateSelector,e):null},e=function(a,b,c){return function(){var e=d(b,c);null!==e&&a.selection.selectorChanged(e.selector,e.handler)}},f=function(a){return c.isArray(a)?a:c.isString(a)?a.split(/[ ,]/):[]},g=function(c,d,g){var h,i=[];if(g)return a.each(f(g),function(a){var d;"|"==a?h=null:c.buttons[a]&&(h||(h={type:"buttongroup",items:[]},i.push(h)),d=a,a=c.buttons[d],"function"==typeof a&&(a=a()),a.type=a.type||"button",a=b.create(a),a.on("postRender",e(c,d,a)),h.items.push(a))}),b.create({type:"toolbar",layout:"flow",name:d,items:i})};return{create:g}}),g("s",["d"],function(a){return a("tinymce.util.Promise")}),g("t",[],function(){var a=0,b=function(){var a=function(){return Math.round(4294967295*Math.random()).toString(36)};return"s&quo
 t;+Date.now().toString(36)+a()+a()+a()},c=function(c){return c+a++ +b()};return{uuid:c}}),g("w",[],function(){var a=function(a,b){function c(c){var e,f,g;f=b[c?"startContainer":"endContainer"],g=b[c?"startOffset":"endOffset"],1==f.nodeType&&(e=a.create("span",{"data-mce-type":"bookmark"}),f.hasChildNodes()?(g=Math.min(g,f.childNodes.length-1),c?f.insertBefore(e,f.childNodes[g]):a.insertAfter(e,f.childNodes[g])):f.appendChild(e),f=e,g=0),d[c?"startContainer":"endContainer"]=f,d[c?"startOffset":"endOffset"]=g}var d={};return c(!0),b.collapsed||c(),d},b=function(a,b){function c(c){function d(a){for(var b=a.parentNode.firstChild,c=0;b;){if(b==a)return c;1==b.nodeType&&"bookmark"==b.getAttribute("data-mce-type")||c++,b=b.nextSibling}return-1}var e,f,g;e=g=b[c?"startContainer":"endContainer"],f=b[c?"startOffset
 ":"endOffset"],e&&(1==e.nodeType&&(f=d(e),e=e.parentNode,a.remove(g)),b[c?"startContainer":"endContainer"]=e,b[c?"startOffset":"endOffset"]=f)}c(!0),c();var d=a.createRng();return d.setStart(b.startContainer,b.startOffset),b.endContainer&&d.setEnd(b.endContainer,b.endOffset),d};return{create:a,resolve:b}}),g("x",["d"],function(a){return a("tinymce.dom.TreeWalker")}),g("y",["d"],function(a){return a("tinymce.dom.RangeUtils")}),g("u",["w","g","x","y"],function(a,b,c,d){var e=function(a,b,d){var e,f,g=[];for(e=new c(b,a),f=b;f&&(1===f.nodeType&&g.push(f),f!==d);f=e.next());return g},f=function(c,d){var e,f,g;f=c.dom,g=c.selection,e=a.create(f,g.getRng()),b.each(d,function(a){c.dom.remove(a,!0)}),g.setRng(a.resolve(f,e))},g=function(a){return"A"===a.nodeName&&a.hasAtt
 ribute("href")},h=function(a,b){var c=a.getParent(b,g);return c?c:b},i=function(a){var c,f,i,j,k,l,m;return k=a.selection,l=a.dom,m=k.getRng(),c=h(l,d.getNode(m.startContainer,m.startOffset)),f=d.getNode(m.endContainer,m.endOffset),i=a.getBody(),j=b.grep(e(i,c,f),g)},j=function(a){f(a,i(a))};return{unlinkSelection:j}}),g("p",["t","u"],function(a,b){var c=function(a,b){var c,d,e;for(e='<table data-mce-id="mce" style="width: 100%">',e+="<tbody>",d=0;d<b;d++){for(e+="<tr>",c=0;c<a;c++)e+="<td><br></td>";e+="</tr>"}return e+="</tbody>",e+="</table>"},d=function(a){var b=a.dom.select("*[data-mce-id]");return b[0]},e=function(a,b,e){a.undoManager.transact(function(){var f,g;a.insertContent(c(b,e)),f=d(a),f.removeAttribute("data-mce-id"),g=a.dom.select("td,th",f),a.selection.setCurso
 rLocation(g[0],0)})},f=function(a,b){a.execCommand("FormatBlock",!1,b)},g=function(b,c,d){var e,f;e=b.editorUpload.blobCache,f=e.create(a.uuid("mceu"),d,c),e.add(f),b.insertContent(b.dom.createHTML("img",{src:f.blobUri()}))},h=function(a){a.selection.collapse(!1)},i=function(a){a.focus(),b.unlinkSelection(a),h(a)},j=function(a,b,c){a.focus(),a.dom.setAttrib(b,"href",c),h(a)},k=function(a,b){a.execCommand("mceInsertLink",!1,{href:b}),h(a)},l=function(a,b){var c=a.dom.getParent(a.selection.getStart(),"a[href]");c?j(a,c,b):k(a,b)},m=function(a,b){0===b.trim().length?i(a):l(a,b)};return{insertTable:e,formatBlock:f,insertBlob:g,createLink:m,unlink:i}}),g("v",[],function(){var a=function(a){return/^www\.|\.(com|org|edu|gov|uk|net|ca|de|jp|fr|au|us|ru|ch|it|nl|se|no|es|mil)$/i.test(a.trim())},b=function(a){return/^https?:\/\//.test(a.trim())};return{isDomainLike:a,isAbsolute:b}}),g("l",["g","j&qu
 ot;,"s","p","v"],function(a,b,c,d,e){var f=function(a){a.find("textbox").eq(0).each(function(a){a.focus()})},g=function(c,d){var e=b.create(a.extend({type:"form",layout:"flex",direction:"row",padding:5,name:c,spacing:3},d));return e.on("show",function(){f(e)}),e},h=function(a,b){return b?a.show():a.hide()},i=function(a,b){return new c(function(c){a.windowManager.confirm("The URL you entered seems to be an external link. Do you want to add the required http:// prefix?",function(a){var d=a===!0?"http://"+b:b;c(d)})})},j=function(a,b){return!e.isAbsolute(b)&&e.isDomainLike(b)?i(a,b):c.resolve(b)},k=function(a,b){var c={},e=function(){a.focus(),d.unlink(a),b()},f=function(a){var b=a.meta;b&&b.attach&&(c={href:this.value(),attach:b.attach})},i=function(b){if(b.control===this){var c,d="";c=a.dom.getParent(a.selection.getStart(),"a[href]"),c&&a
 mp;(d=a.dom.getAttrib(c,"href")),this.fromJSON({linkurl:d}),h(this.find("#unlink"),c),this.find("#linkurl")[0].focus()}};return g("quicklink",{items:[{type:"button",name:"unlink",icon:"unlink",onclick:e,tooltip:"Remove link"},{type:"filepicker",name:"linkurl",placeholder:"Paste or type a link",filetype:"file",onchange:f},{type:"button",icon:"checkmark",subtype:"primary",tooltip:"Ok",onclick:"submit"}],onshow:i,onsubmit:function(e){j(a,e.data.linkurl).then(function(e){a.undoManager.transact(function(){e===c.href&&(c.attach(),c={}),d.createLink(a,e)}),b()})}})};return{createQuickLinkForm:k}}),g("m",["q","r"],function(a,b){var c=function(a,b){return{rect:a,position:b}},d=function(a,b){return{x:b.x,y:b.y,w:a.w,h:a.h}},e=function(b,e,f,g,h){var i,j,k;return i=a.findBestRelativePositi
 on(h,f,g,b),f=a.clamp(f,g),i?(j=a.relativePosition(h,f,i),k=d(h,j),c(k,i)):(f=a.intersect(g,f),f?(i=a.findBestRelativePosition(h,f,g,e))?(j=a.relativePosition(h,f,i),k=d(h,j),c(k,i)):(k=d(h,f),c(k,i)):null)},f=function(a,b,c){return e(["cr-cl","cl-cr"],["bc-tc","bl-tl","br-tr"],a,b,c)},g=function(a,b,c){return e(["tc-bc","bc-tc","tl-bl","bl-tl","tr-br","br-tr"],["bc-tc","bl-tl","br-tr"],a,b,c)},h=function(a,c,d,e){var f;return"function"==typeof a?(f=a({elementRect:b.toClientRect(c),contentAreaRect:b.toClientRect(d),panelRect:b.toClientRect(e)}),b.fromClientRect(f)):e},i=function(a){return a.panelRect};return{calcInsert:f,calc:g,userConstrain:h,defaultHandler:i}}),g("c",["g","j","i","k","l","f","m","5"],function(a,b,c,d,e,f,g,h){return function(){v
 ar i,j,k=["bold","italic","|","quicklink","h2","h3","blockquote"],l=["quickimage","quicktable"],m=function(b,c){return a.map(c,function(a){return d.create(b,a.id,a.items)})},n=function(a){return h.getToolbarItemsOr(a,"selection_toolbar",k)},o=function(a){return h.getToolbarItemsOr(a,"insert_toolbar",l)},p=function(a){return a.items().length>0},q=function(c,f){var g=m(c,f).concat([d.create(c,"text",n(c)),d.create(c,"insert",o(c)),e.createQuickLinkForm(c,B)]);return b.create({type:"floatpanel",role:"dialog",classes:"tinymce tinymce-inline arrow",ariaLabel:"Inline toolbar",layout:"flex",direction:"column",align:"stretch",autohide:!1,autofix:!0,fixed:!0,border:1,items:a.grep(g,p),oncancel:function(){c.focus()}})},r=function(a){a&&a.show()},s=function(a,b){a.moveTo(b.x,b.y)},t=fun
 ction(b,c){c=c?c.substr(0,2):"",a.each({t:"down",b:"up",c:"center"},function(a,d){b.classes.toggle("arrow-"+a,d===c.substr(0,1))}),"cr"===c?(b.classes.toggle("arrow-left",!0),b.classes.toggle("arrow-right",!1)):"cl"===c?(b.classes.toggle("arrow-left",!0),b.classes.toggle("arrow-right",!0)):a.each({l:"left",r:"right"},function(a,d){b.classes.toggle("arrow-"+a,d===c.substr(1,1))})},u=function(a,b){var c=a.items().filter("#"+b);return c.length>0&&(c[0].show(),a.reflow(),!0)},v=function(a,b,d,e){var i,k,l,m;return m=h.getHandlerOr(d,"inline_toolbar_position_handler",g.defaultHandler),i=f.getContentAreaRect(d),k=c.DOM.getRect(a.getEl()),l="insert"===b?g.calcInsert(e,i,k):g.calc(e,i,k),!!l&&(k=l.rect,j=e,s(a,g.userConstrain(m,e,i,k)),t(a,l.position),!0)},w=function(a,b,c,d){return r(a),a.items().hide(),
 u(a,b)?void(v(a,b,c,d)===!1&&B(a)):void B(a)},x=function(){return i.items().filter("form:visible").length>0},y=function(a,b){if(i){if(i.items().hide(),!u(i,b))return void B(i);var d,e,k,l;r(i),i.items().hide(),u(i,b),l=h.getHandlerOr(a,"inline_toolbar_position_handler",g.defaultHandler),d=f.getContentAreaRect(a),e=c.DOM.getRect(i.getEl()),k=g.calc(j,d,e),k&&(e=k.rect,s(i,g.userConstrain(l,j,d,e)),t(i,k.position))}},z=function(a,b,c,d){i||(i=q(a,d),i.renderTo(document.body).reflow().moveTo(c.x,c.y),a.nodeChanged()),w(i,b,a,c)},A=function(a,b,c){i&&v(i,b,a,c)},B=function(){i&&i.hide()},C=function(){i&&i.find("toolbar:visible").eq(0).each(function(a){a.focus(!0)})},D=function(){i&&(i.remove(),i=null)},E=function(){return i&&i.visible()&&x()};return{show:z,showForm:y,reposition:A,inForm:E,hide:B,focus:C,remove:D}}}),g("n",["s"],function(a){var b=function(b){return new a(f
 unction(a){var c=new FileReader;c.onloadend=function(){a(c.result.split(",")[1])},c.readAsDataURL(b)})};return{blobToBase64:b}}),g("o",["s"],function(a){var b=function(){return new a(function(a){var b;b=document.createElement("input"),b.type="file",b.style.position="fixed",b.style.left=0,b.style.top=0,b.style.opacity=.001,document.body.appendChild(b),b.onchange=function(b){a(Array.prototype.slice.call(b.target.files))},b.click(),b.parentNode.removeChild(b)})};return{pickFile:b}}),g("b",["c","n","o","p"],function(a,b,c,d){var e=function(a){for(var b=function(b){return function(){d.formatBlock(a,b)}},c=1;c<6;c++){var e="h"+c;a.addButton(e,{text:e.toUpperCase(),tooltip:"Heading "+c,stateSelector:e,onclick:b(e),onPostRender:function(){var a=this.getEl().firstChild.firstChild;a.style.fontWeight="bold"}})}},f=function(a,f){a.addButton("quickli
 nk",{icon:"link",tooltip:"Insert/Edit link",stateSelector:"a[href]",onclick:function(){f.showForm(a,"quicklink")}}),a.addButton("quickimage",{icon:"image",tooltip:"Insert image",onclick:function(){c.pickFile().then(function(c){var e=c[0];b.blobToBase64(e).then(function(b){d.insertBlob(a,b,e)})})}}),a.addButton("quicktable",{icon:"table",tooltip:"Insert table",onclick:function(){f.hide(),d.insertTable(a,2,2)}}),e(a)};return{addToEditor:f}}),g("0",["1","2","3","4","5","6","7","8","9","a","b","c"],function(a,b,c,d,e,f,g,h,i,j,k,l){var m=function(a){var b=a.selection.getNode(),c=a.dom.getParents(b);return c},n=function(a,b,c,d){var e=function(c){return a.dom.is(c,b)};return{predicate:e,id:c,items:d}},o=function(a){var b=a.contextToolbars;return d.flatten([
 b?b:[],n(a,"img","image","alignleft aligncenter alignright")])},p=function(a,b){var c,d,e;return d=m(a),e=h.fromContextToolbars(b),c=g.match(a,[f.element(d[0],e),i.textSelection("text"),i.emptyTextBlock(d,"insert"),f.parent(d,e)]),c&&c.rect?c:null},q=function(a,b){var c=function(){var c=o(a),d=p(a,c);d?b.show(a,d.id,d.rect,c):b.hide()};return function(){a.removed||c()}},r=function(a,b){return function(){var c=o(a),d=p(a,c);d&&b.reposition(a,d.id,d.rect)}},s=function(a,b,c){return function(){a.removed||b.inForm()||c()}},t=function(a,b){var d=c.throttle(q(a,b),0),e=c.throttle(s(a,b,q(a,b)),0);a.on("blur hide ObjectResizeStart",b.hide),a.on("click",d),a.on("nodeChange mouseup",e),a.on("ResizeEditor keyup",d),a.on("ResizeWindow",r(a,b)),a.on("remove",b.remove),a.shortcuts.add("Alt+F10","",b.focus)},u=function(a,b){a.shortcuts.remove("meta
 +k"),a.shortcuts.add("meta+k","",function(){var c=o(a),d=d=g.match(a,[i.textSelection("quicklink")]);d&&b.show(a,d.id,d.rect,c)})},v=function(a,b){return j.load(a,function(){t(a,b),u(a,b)}),{}},w=function(a){throw new Error(a)};return a.add("inlite",function(a){var b=new l;k.addToEditor(a,b);var c=function(){return a.inline?v(a,b):w("inlite theme only supports inline mode.")};return{renderUI:c}}),b.appendTo(window.tinymce?window.tinymce:{}),function(){}}),d("0")()}();
</del><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("d",tinymce.util.Tools.resolve),g("1",[&q
 uot;d"],function(a){return a("tinymce.ThemeManager")}),g("2",["d"],function(a){return a("tinymce.ui.Api")}),g("3",["d"],function(a){return a("tinymce.util.Delay")}),g("4",[],function(){var a=function(b){return b.reduce(function(b,c){return Array.isArray(c)?b.concat(a(c)):b.concat(c)},[])};return{flatten:a}}),g("e",[],function(){var a=function(a){return function(b){return typeof b===a}},b=function(a){return Array.isArray(a)},c=function(a){return null===a},d=function(a){return function(d){return!c(d)&&!b(d)&&a(d)}};return{isString:a("string"),isNumber:a("number"),isBoolean:a("boolean"),isFunction:a("function"),isObject:d(a("object")),isNull:c,isArray:b}}),g("5",["e"],function(a){var b=function(a,b){if(b(a))return!0;throw new Error("Default value doesn't match requested type.")},c=function(a){retur
 n function(c,d,e){var f=c.settings;return b(e,a),d in f&&a(f[d])?f[d]:e}},d=function(a,b){return a.split(b).filter(function(a){return a.length>0})},e=function(b,c){var e=function(a){return"string"==typeof a?d(a,/[ ,]/):a},f=function(a,b){return a===!1?[]:b};return a.isArray(b)?b:a.isString(b)?e(b):a.isBoolean(b)?f(b,c):c},f=function(a){return function(c,d,f){var g=d in c.settings?c.settings[d]:f;return b(f,a),e(g,f)}};return{getStringOr:c(a.isString),getBoolOr:c(a.isBoolean),getNumberOr:c(a.isNumber),getHandlerOr:c(a.isFunction),getToolbarItemsOr:f(a.isArray)}}),g("7",[],function(){var a=function(a,b){return{id:a,rect:b}},b=function(a,b){for(var c=0;c<b.length;c++){var d=b[c],e=d(a);if(e)return e}return null};return{match:b,result:a}}),g("i",["d"],function(a){return a("tinymce.dom.DOMUtils")}),g("q",[],function(){var a=function(a){return{x:a.left,y:a.top,w:a.width,h:a.height}},b=function(a){return{left:a.x,top
 :a.y,width:a.w,height:a.h,right:a.x+a.w,bottom:a.y+a.h}};return{fromClientRect:a,toClientRect:b}}),g("f",["i","q"],function(a,b){var c=function(b){var c=a.DOM.getViewPort();return{x:b.x+c.x,y:b.y+c.y,w:b.w,h:b.h}},d=function(a){var b=a.getBoundingClientRect();return c({x:b.left,y:b.top,w:Math.max(a.clientWidth,a.offsetWidth),h:Math.max(a.clientHeight,a.offsetHeight)})},e=function(a,b){return d(b)},f=function(a){return d(a.getElement().ownerDocument.body)},g=function(a){return d(a.getContentAreaContainer()||a.getBody())},h=function(a){var d=a.selection.getBoundingClientRect();return d?c(b.fromClientRect(d)):null};return{getElementRect:e,getPageAreaRect:f,getContentAreaRect:g,getSelectionRect:h}}),g("6",["7","f"],function(a,b){var c=function(c,d){return function(e){for(var f=0;f<d.length;f++)if(d[f].predicate(c))return a.result(d[f].id,b.getElementRect(e,c));return null}},d=function(c,d){return function(e){for(var f=0;f&lt
 ;c.length;f++)for(var g=0;g<d.length;g++)if(d[g].predicate(c[f]))return a.result(d[g].id,b.getElementRect(e,c[f]));return null}};return{element:c,parent:d}}),g("g",["d"],function(a){return a("tinymce.util.Tools")}),g("8",["g"],function(a){var b=function(a,b){return{id:a,predicate:b}},c=function(c){return a.map(c,function(a){return b(a.id,a.predicate)})};return{create:b,fromContextToolbars:c}}),g("9",["7","f"],function(a,b){var c=function(c){return function(d){return d.selection.isCollapsed()?null:a.result(c,b.getSelectionRect(d))}},d=function(c,d){return function(e){var f,g=e.schema.getTextBlockElements();for(f=0;f<c.length;f++)if("TABLE"===c[f].nodeName)return null;for(f=0;f<c.length;f++)if(c[f].nodeName in g)return e.dom.isEmpty(c[f])?a.result(d,b.getSelectionRect(e)):null;return null}};return{textSelection:c,emptyTextBlock:d}}),g("h",["d"],function(a){return a(&q
 uot;tinymce.EditorManager")}),g("a",["h","i"],function(a,b){var c=function(a,b){var c=function(){a._skinLoaded=!0,a.fire("SkinLoaded"),b()};a.initialized?c():a.on("init",c)},d=function(b){var c=a.baseURL+"/skins/";return b?c+b:c+"lightgray"},e=function(a,b){return a.documentBaseURI.toAbsolute(b)},f=function(a,f){var g=a.settings,h=g.skin_url?e(a,g.skin_url):d(g.skin),i=function(){c(a,f)};b.DOM.styleSheetLoader.load(h+"/skin.min.css",i),a.contentCSS.push(h+"/content.inline.min.css")};return{load:f}}),g("j",["d"],function(a){return a("tinymce.ui.Factory")}),g("k",["g","j","e"],function(a,b,c){var d=function(a,b){var c=function(a,b){return{selector:a,handler:b}},d=function(a){b.active(a)},e=function(a){b.disabled(a)};return b.settings.stateSelector?c(b.settings.stateSelector,d):b.settings.disabledStateSelector?c(b.settings.
 disabledStateSelector,e):null},e=function(a,b,c){return function(){var e=d(b,c);null!==e&&a.selection.selectorChanged(e.selector,e.handler)}},f=function(a){return c.isArray(a)?a:c.isString(a)?a.split(/[ ,]/):[]},g=function(c,d,g){var h,i=[];if(g)return a.each(f(g),function(a){var d;"|"==a?h=null:c.buttons[a]&&(h||(h={type:"buttongroup",items:[]},i.push(h)),d=a,a=c.buttons[d],"function"==typeof a&&(a=a()),a.type=a.type||"button",a=b.create(a),a.on("postRender",e(c,d,a)),h.items.push(a))}),b.create({type:"toolbar",layout:"flow",name:d,items:i})};return{create:g}}),g("r",["d"],function(a){return a("tinymce.util.Promise")}),g("s",[],function(){var a=0,b=function(){var a=function(){return Math.round(4294967295*Math.random()).toString(36)};return"s"+Date.now().toString(36)+a()+a()+a()},c=function(c){return c+a++ +b()};return{uuid:c}}),g("w&qu
 ot;,[],function(){var a=function(a,b){function c(c){var e,f,g;f=b[c?"startContainer":"endContainer"],g=b[c?"startOffset":"endOffset"],1==f.nodeType&&(e=a.create("span",{"data-mce-type":"bookmark"}),f.hasChildNodes()?(g=Math.min(g,f.childNodes.length-1),c?f.insertBefore(e,f.childNodes[g]):a.insertAfter(e,f.childNodes[g])):f.appendChild(e),f=e,g=0),d[c?"startContainer":"endContainer"]=f,d[c?"startOffset":"endOffset"]=g}var d={};return c(!0),b.collapsed||c(),d},b=function(a,b){function c(c){function d(a){for(var b=a.parentNode.firstChild,c=0;b;){if(b==a)return c;1==b.nodeType&&"bookmark"==b.getAttribute("data-mce-type")||c++,b=b.nextSibling}return-1}var e,f,g;e=g=b[c?"startContainer":"endContainer"],f=b[c?"startOffset":"endOffset"],e&&(1==e.nodeType&&(f=d(e),e=e.parentNode,a.remove(g)),b
 [c?"startContainer":"endContainer"]=e,b[c?"startOffset":"endOffset"]=f)}c(!0),c();var d=a.createRng();return d.setStart(b.startContainer,b.startOffset),b.endContainer&&d.setEnd(b.endContainer,b.endOffset),d};return{create:a,resolve:b}}),g("x",["d"],function(a){return a("tinymce.dom.TreeWalker")}),g("y",["d"],function(a){return a("tinymce.dom.RangeUtils")}),g("t",["w","g","x","y"],function(a,b,c,d){var e=function(a,b,d){var e,f,g=[];for(e=new c(b,a),f=b;f&&(1===f.nodeType&&g.push(f),f!==d);f=e.next());return g},f=function(c,d){var e,f,g;f=c.dom,g=c.selection,e=a.create(f,g.getRng()),b.each(d,function(a){c.dom.remove(a,!0)}),g.setRng(a.resolve(f,e))},g=function(a){return"A"===a.nodeName&&a.hasAttribute("href")},h=function(a,b){var c=a.getParent(b,g);return c?c:b},i=function(a){var c,f,i
 ,j,k,l,m;return k=a.selection,l=a.dom,m=k.getRng(),c=h(l,d.getNode(m.startContainer,m.startOffset)),f=d.getNode(m.endContainer,m.endOffset),i=a.getBody(),j=b.grep(e(i,c,f),g)},j=function(a){f(a,i(a))};return{unlinkSelection:j}}),g("p",["s","t"],function(a,b){var c=function(a,b){var c,d,e;for(e='<table data-mce-id="mce" style="width: 100%">',e+="<tbody>",d=0;d<b;d++){for(e+="<tr>",c=0;c<a;c++)e+="<td><br></td>";e+="</tr>"}return e+="</tbody>",e+="</table>"},d=function(a){var b=a.dom.select("*[data-mce-id]");return b[0]},e=function(a,b,e){a.undoManager.transact(function(){var f,g;a.insertContent(c(b,e)),f=d(a),f.removeAttribute("data-mce-id"),g=a.dom.select("td,th",f),a.selection.setCursorLocation(g[0],0)})},f=function(a,b){a.execCommand("FormatBlock",!1,b)},g=function(b,c,d){va
 r e,f;e=b.editorUpload.blobCache,f=e.create(a.uuid("mceu"),d,c),e.add(f),b.insertContent(b.dom.createHTML("img",{src:f.blobUri()}))},h=function(a){a.selection.collapse(!1)},i=function(a){a.focus(),b.unlinkSelection(a),h(a)},j=function(a,b,c){a.focus(),a.dom.setAttrib(b,"href",c),h(a)},k=function(a,b){a.execCommand("mceInsertLink",!1,{href:b}),h(a)},l=function(a,b){var c=a.dom.getParent(a.selection.getStart(),"a[href]");c?j(a,c,b):k(a,b)},m=function(a,b){0===b.trim().length?i(a):l(a,b)};return{insertTable:e,formatBlock:f,insertBlob:g,createLink:m,unlink:i}}),g("u",[],function(){var a=function(a){return/^www\.|\.(com|org|edu|gov|uk|net|ca|de|jp|fr|au|us|ru|ch|it|nl|se|no|es|mil)$/i.test(a.trim())},b=function(a){return/^https?:\/\//.test(a.trim())};return{isDomainLike:a,isAbsolute:b}}),g("l",["g","j","r","p","u"],function(a,b,c,d,e){var f=function(a){a.find("text
 box").eq(0).each(function(a){a.focus()})},g=function(c,d){var e=b.create(a.extend({type:"form",layout:"flex",direction:"row",padding:5,name:c,spacing:3},d));return e.on("show",function(){f(e)}),e},h=function(a,b){return b?a.show():a.hide()},i=function(a,b){return new c(function(c){a.windowManager.confirm("The URL you entered seems to be an external link. Do you want to add the required http:// prefix?",function(a){var d=a===!0?"http://"+b:b;c(d)})})},j=function(a,b){return!e.isAbsolute(b)&&e.isDomainLike(b)?i(a,b):c.resolve(b)},k=function(a,b){var c={},e=function(){a.focus(),d.unlink(a),b()},f=function(a){var b=a.meta;b&&b.attach&&(c={href:this.value(),attach:b.attach})},i=function(b){if(b.control===this){var c,d="";c=a.dom.getParent(a.selection.getStart(),"a[href]"),c&&(d=a.dom.getAttrib(c,"href")),this.fromJSON({linkurl:d}),h(this.find("#unlink")
 ,c),this.find("#linkurl")[0].focus()}};return g("quicklink",{items:[{type:"button",name:"unlink",icon:"unlink",onclick:e,tooltip:"Remove link"},{type:"filepicker",name:"linkurl",placeholder:"Paste or type a link",filetype:"file",onchange:f},{type:"button",icon:"checkmark",subtype:"primary",tooltip:"Ok",onclick:"submit"}],onshow:i,onsubmit:function(e){j(a,e.data.linkurl).then(function(e){a.undoManager.transact(function(){e===c.href&&(c.attach(),c={}),d.createLink(a,e)}),b()})}})};return{createQuickLinkForm:k}}),g("v",["d"],function(a){return a("tinymce.geom.Rect")}),g("m",["v","q"],function(a,b){var c=function(a,b){return{rect:a,position:b}},d=function(a,b){return{x:b.x,y:b.y,w:a.w,h:a.h}},e=function(b,e,f,g,h){var i,j,k,l={x:g.x,y:g.y,w:g.w+(g.w<h.w+f.w?h.w:0),h:g.h
 +(g.h<h.h+f.h?h.h:0)};return i=a.findBestRelativePosition(h,f,l,b),f=a.clamp(f,l),i?(j=a.relativePosition(h,f,i),k=d(h,j),c(k,i)):(f=a.intersect(l,f),f?(i=a.findBestRelativePosition(h,f,l,e))?(j=a.relativePosition(h,f,i),k=d(h,j),c(k,i)):(k=d(h,f),c(k,i)):null)},f=function(a,b,c){return e(["cr-cl","cl-cr"],["bc-tc","bl-tl","br-tr"],a,b,c)},g=function(a,b,c){return e(["tc-bc","bc-tc","tl-bl","bl-tl","tr-br","br-tr","cr-cl","cl-cr"],["bc-tc","bl-tl","br-tr","cr-cl"],a,b,c)},h=function(a,c,d,e){var f;return"function"==typeof a?(f=a({elementRect:b.toClientRect(c),contentAreaRect:b.toClientRect(d),panelRect:b.toClientRect(e)}),b.fromClientRect(f)):e},i=function(a){return a.panelRect};return{calcInsert:f,calc:g,userConstrain:h,defaultHandler:i}}),g("c",["g","j","i",&quo
 t;k","l","f","m","5"],function(a,b,c,d,e,f,g,h){return function(){var i,j,k=["bold","italic","|","quicklink","h2","h3","blockquote"],l=["quickimage","quicktable"],m=function(b,c){return a.map(c,function(a){return d.create(b,a.id,a.items)})},n=function(a){return h.getToolbarItemsOr(a,"selection_toolbar",k)},o=function(a){return h.getToolbarItemsOr(a,"insert_toolbar",l)},p=function(a){return a.items().length>0},q=function(c,f){var g=m(c,f).concat([d.create(c,"text",n(c)),d.create(c,"insert",o(c)),e.createQuickLinkForm(c,B)]);return b.create({type:"floatpanel",role:"dialog",classes:"tinymce tinymce-inline arrow",ariaLabel:"Inline toolbar",layout:"flex",direction:"column",align:"stretch",autohide:!1,autofix:!0,fixed:!0,border:1,items:a.grep(g,
 p),oncancel:function(){c.focus()}})},r=function(a){a&&a.show()},s=function(a,b){a.moveTo(b.x,b.y)},t=function(b,c){c=c?c.substr(0,2):"",a.each({t:"down",b:"up",c:"center"},function(a,d){b.classes.toggle("arrow-"+a,d===c.substr(0,1))}),"cr"===c?(b.classes.toggle("arrow-left",!0),b.classes.toggle("arrow-right",!1)):"cl"===c?(b.classes.toggle("arrow-left",!0),b.classes.toggle("arrow-right",!0)):a.each({l:"left",r:"right"},function(a,d){b.classes.toggle("arrow-"+a,d===c.substr(1,1))})},u=function(a,b){var c=a.items().filter("#"+b);return c.length>0&&(c[0].show(),a.reflow(),!0)},v=function(a,b,d,e){var i,k,l,m;return m=h.getHandlerOr(d,"inline_toolbar_position_handler",g.defaultHandler),i=f.getContentAreaRect(d),k=c.DOM.getRect(a.getEl()),l="insert"===b?g.calcInsert(e,i,k):g.calc(e,i,k),!!l&&(k
 =l.rect,j=e,s(a,g.userConstrain(m,e,i,k)),t(a,l.position),!0)},w=function(a,b,c,d){return r(a),a.items().hide(),u(a,b)?void(v(a,b,c,d)===!1&&B(a)):void B(a)},x=function(){return i.items().filter("form:visible").length>0},y=function(a,b){if(i){if(i.items().hide(),!u(i,b))return void B(i);var d,e,k,l;r(i),i.items().hide(),u(i,b),l=h.getHandlerOr(a,"inline_toolbar_position_handler",g.defaultHandler),d=f.getContentAreaRect(a),e=c.DOM.getRect(i.getEl()),k=g.calc(j,d,e),k&&(e=k.rect,s(i,g.userConstrain(l,j,d,e)),t(i,k.position))}},z=function(a,b,c,d){i||(i=q(a,d),i.renderTo(document.body).reflow().moveTo(c.x,c.y),a.nodeChanged()),w(i,b,a,c)},A=function(a,b,c){i&&v(i,b,a,c)},B=function(){i&&i.hide()},C=function(){i&&i.find("toolbar:visible").eq(0).each(function(a){a.focus(!0)})},D=function(){i&&(i.remove(),i=null)},E=function(){return i&&i.visible()&&x()};return{show:z,showForm:y,reposition:A,i
 nForm:E,hide:B,focus:C,remove:D}}}),g("n",["r"],function(a){var b=function(b){return new a(function(a){var c=new FileReader;c.onloadend=function(){a(c.result.split(",")[1])},c.readAsDataURL(b)})};return{blobToBase64:b}}),g("o",["r"],function(a){var b=function(){return new a(function(a){var b;b=document.createElement("input"),b.type="file",b.style.position="fixed",b.style.left=0,b.style.top=0,b.style.opacity=.001,document.body.appendChild(b),b.onchange=function(b){a(Array.prototype.slice.call(b.target.files))},b.click(),b.parentNode.removeChild(b)})};return{pickFile:b}}),g("b",["c","n","o","p"],function(a,b,c,d){var e=function(a){for(var b=function(b){return function(){d.formatBlock(a,b)}},c=1;c<6;c++){var e="h"+c;a.addButton(e,{text:e.toUpperCase(),tooltip:"Heading "+c,stateSelector:e,onclick:b(e),onPostRender:function(){var a=this.
 getEl().firstChild.firstChild;a.style.fontWeight="bold"}})}},f=function(a,f){a.addButton("quicklink",{icon:"link",tooltip:"Insert/Edit link",stateSelector:"a[href]",onclick:function(){f.showForm(a,"quicklink")}}),a.addButton("quickimage",{icon:"image",tooltip:"Insert image",onclick:function(){c.pickFile().then(function(c){var e=c[0];b.blobToBase64(e).then(function(b){d.insertBlob(a,b,e)})})}}),a.addButton("quicktable",{icon:"table",tooltip:"Insert table",onclick:function(){f.hide(),d.insertTable(a,2,2)}}),e(a)};return{addToEditor:f}}),g("0",["1","2","3","4","5","6","7","8","9","a","b","c"],function(a,b,c,d,e,f,g,h,i,j,k,l){var m=function(a){var b=a.selection.getNode(),c=a.dom.getParents(b);return c},n=function(a,b,c,d){var e=function(c){
 return a.dom.is(c,b)};return{predicate:e,id:c,items:d}},o=function(a){var b=a.contextToolbars;return d.flatten([b?b:[],n(a,"img","image","alignleft aligncenter alignright")])},p=function(a,b){var c,d,e;return d=m(a),e=h.fromContextToolbars(b),c=g.match(a,[f.element(d[0],e),i.textSelection("text"),i.emptyTextBlock(d,"insert"),f.parent(d,e)]),c&&c.rect?c:null},q=function(a,b){var c=function(){var c=o(a),d=p(a,c);d?b.show(a,d.id,d.rect,c):b.hide()};return function(){a.removed||c()}},r=function(a,b){return function(){var c=o(a),d=p(a,c);d&&b.reposition(a,d.id,d.rect)}},s=function(a,b,c){return function(){a.removed||b.inForm()||c()}},t=function(a,b){var d=c.throttle(q(a,b),0),e=c.throttle(s(a,b,q(a,b)),0);a.on("blur hide ObjectResizeStart",b.hide),a.on("click",d),a.on("nodeChange mouseup",e),a.on("ResizeEditor keyup",d),a.on("ResizeWindow",r(a,b)),a.on("remove",b.
 remove),a.shortcuts.add("Alt+F10","",b.focus)},u=function(a,b){a.shortcuts.remove("meta+k"),a.shortcuts.add("meta+k","",function(){var c=o(a),d=d=g.match(a,[i.textSelection("quicklink")]);d&&b.show(a,d.id,d.rect,c)})},v=function(a,b){return j.load(a,function(){t(a,b),u(a,b)}),{}},w=function(a){throw new Error(a)};return a.add("inlite",function(a){var b=new l;k.addToEditor(a,b);var c=function(){return a.inline?v(a,b):w("inlite theme only supports inline mode.")};return{renderUI:c}}),b.appendTo(window.tinymce?window.tinymce:{}),function(){}}),d("0")()}();
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span></span></pre></div>
<a id="trunksrcwpincludesjstinymcetiny_mce_popupjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/tinymce/tiny_mce_popup.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/tinymce/tiny_mce_popup.js        2017-09-26 20:32:46 UTC (rev 41603)
+++ trunk/src/wp-includes/js/tinymce/tiny_mce_popup.js  2017-09-26 21:14:28 UTC (rev 41604)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -53,7 +53,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Setup local DOM
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    self.dom = self.editor.windowManager.createInstance('tinymce.plugins.dom.DOMUtils', document, {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    self.dom = self.editor.windowManager.createInstance('tinymce.dom.DOMUtils', document, {
</ins><span class="cx" style="display: block; padding: 0 10px">       ownEvents: true,
</span><span class="cx" style="display: block; padding: 0 10px">       proxy: tinyMCEPopup._eventProxy
</span><span class="cx" style="display: block; padding: 0 10px">     });
</span></span></pre></div>
<a id="trunksrcwpincludesjstinymcetinymcejs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/tinymce/tinymce.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/tinymce/tinymce.js       2017-09-26 20:32:46 UTC (rev 41603)
+++ trunk/src/wp-includes/js/tinymce/tinymce.js 2017-09-26 21:14:28 UTC (rev 41604)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,4 +1,4 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-// 4.6.3 (2017-05-30)
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+// 4.6.7 (2017-09-18)
</ins><span class="cx" style="display: block; padding: 0 10px"> (function () {
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> var defs = {}; // id -> {dependencies, definition, instance (possibly undefined)}
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -82,223 +82,97 @@
</span><span class="cx" style="display: block; padding: 0 10px">   define(id, [], function () { return ref; });
</span><span class="cx" style="display: block; padding: 0 10px"> };
</span><span class="cx" style="display: block; padding: 0 10px"> /*jsc
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-["tinymce.core.api.Main","tinymce.core.api.Tinymce","tinymce.core.Register","tinymce.core.geom.Rect","tinymce.core.util.Promise","tinymce.core.util.Delay","tinymce.core.Env","tinymce.core.dom.EventUtils","tinymce.core.dom.Sizzle","tinymce.core.util.Tools","tinymce.core.dom.DomQuery","tinymce.core.html.Styles","tinymce.core.dom.TreeWalker","tinymce.core.html.Entities","tinymce.core.dom.DOMUtils","tinymce.core.dom.ScriptLoader","tinymce.core.AddOnManager","tinymce.core.dom.RangeUtils","tinymce.core.html.Node","tinymce.core.html.Schema","tinymce.core.html.SaxParser","tinymce.core.html.DomParser","tinymce.core.html.Writer","tinymce.core.html.Serializer",&q
 uot;tinymce.core.dom.Serializer","tinymce.core.util.VK","tinymce.core.dom.ControlSelection","tinymce.core.dom.BookmarkManager","tinymce.core.dom.Selection","tinymce.core.Formatter","tinymce.core.UndoManager","tinymce.core.EditorCommands","tinymce.core.util.URI","tinymce.core.util.Class","tinymce.core.util.EventDispatcher","tinymce.core.util.Observable","tinymce.core.WindowManager","tinymce.core.NotificationManager","tinymce.core.EditorObservable","tinymce.core.Shortcuts","tinymce.core.Editor","tinymce.core.util.I18n","tinymce.core.FocusManager","tinymce.core.EditorManager","tinymce.core.util.XHR","tinymce.core.util.JSON","tinymce.core.util.JSONRequest","tinymce.core.util.JSONP","tinymce.core.util.LocalStorage","tinymce.core.api.Compat&qu
 ot;,"tinymce.core.util.Color","tinymce.core.ui.Api","tinymce.core.util.Arr","tinymce.core.dom.Range","tinymce.core.dom.StyleSheetLoader","tinymce.core.dom.NodeType","tinymce.core.caret.CaretContainer","tinymce.core.text.Zwsp","tinymce.core.caret.CaretBookmark","tinymce.core.caret.CaretPosition","tinymce.core.dom.ScrollIntoView","tinymce.core.dom.TridentSelection","tinymce.core.selection.FragmentReader","tinymce.core.dom.ElementUtils","tinymce.core.util.Fun","tinymce.core.fmt.Preview","tinymce.core.fmt.Hooks","tinymce.core.undo.Levels","tinymce.core.delete.DeleteCommands","tinymce.core.InsertContent","global!document","tinymce.core.ui.Window","tinymce.core.ui.MessageBox","tinymce.core.ui.Notification","tinymce.core.init.Render","tiny
 mce.core.Mode","tinymce.core.ui.Sidebar","tinymce.core.util.Uuid","tinymce.core.ErrorReporter","tinymce.core.LegacyInput","tinymce.core.ui.Selector","tinymce.core.ui.Collection","tinymce.core.ui.ReflowQueue","tinymce.core.ui.Control","tinymce.core.ui.Factory","tinymce.core.ui.KeyboardNavigation","tinymce.core.ui.Container","tinymce.core.ui.DragHelper","tinymce.core.ui.Scrollable","tinymce.core.ui.Panel","tinymce.core.ui.Movable","tinymce.core.ui.Resizable","tinymce.core.ui.FloatPanel","tinymce.core.ui.Tooltip","tinymce.core.ui.Widget","tinymce.core.ui.Progress","tinymce.core.ui.Layout","tinymce.core.ui.AbsoluteLayout","tinymce.core.ui.Button","tinymce.core.ui.ButtonGroup","tinymce.core.ui.Checkbox","tinymce.core.ui.ComboBox&quo
 t;,"tinymce.core.ui.ColorBox","tinymce.core.ui.PanelButton","tinymce.core.ui.ColorButton","tinymce.core.ui.ColorPicker","tinymce.core.ui.Path","tinymce.core.ui.ElementPath","tinymce.core.ui.FormItem","tinymce.core.ui.Form","tinymce.core.ui.FieldSet","tinymce.core.ui.FilePicker","tinymce.core.ui.FitLayout","tinymce.core.ui.FlexLayout","tinymce.core.ui.FlowLayout","tinymce.core.ui.FormatControls","tinymce.core.ui.GridLayout","tinymce.core.ui.Iframe","tinymce.core.ui.InfoBox","tinymce.core.ui.Label","tinymce.core.ui.Toolbar","tinymce.core.ui.MenuBar","tinymce.core.ui.MenuButton","tinymce.core.ui.MenuItem","tinymce.core.ui.Throbber","tinymce.core.ui.Menu","tinymce.core.ui.ListBox","tinymce.core.ui.Radio","tinymce.core.ui.Resiz
 eHandle","tinymce.core.ui.SelectBox","tinymce.core.ui.Slider","tinymce.core.ui.Spacer","tinymce.core.ui.SplitButton","tinymce.core.ui.StackLayout","tinymce.core.ui.TabPanel","tinymce.core.ui.TextBox","ephox.katamari.api.Arr","ephox.katamari.api.Fun","ephox.katamari.api.Future","ephox.katamari.api.Futures","ephox.katamari.api.Result","tinymce.core.caret.CaretCandidate","tinymce.core.geom.ClientRect","tinymce.core.text.ExtendingChar","ephox.sugar.api.dom.Insert","ephox.sugar.api.dom.Replication","ephox.sugar.api.node.Element","ephox.sugar.api.node.Fragment","ephox.sugar.api.node.Node","tinymce.core.dom.ElementType","tinymce.core.dom.Parents","tinymce.core.selection.SelectionUtils","tinymce.core.undo.Fragments","tinymce.core.delete.BlockBou
 ndaryDelete","tinymce.core.delete.BlockRangeDelete","tinymce.core.delete.CefDelete","tinymce.core.delete.InlineBoundaryDelete","tinymce.core.caret.CaretWalker","tinymce.core.dom.RangeNormalizer","tinymce.core.InsertList","tinymce.core.data.ObservableObject","tinymce.core.ui.DomUtils","tinymce.core.ui.BoxUtils","tinymce.core.ui.ClassList","global!window","tinymce.core.init.Init","tinymce.core.PluginManager","tinymce.core.ThemeManager","tinymce.core.content.LinkTargets","tinymce.core.fmt.FontInfo","ephox.katamari.api.Option","global!Array","global!Error","global!String","ephox.katamari.api.LazyValue","ephox.katamari.async.Bounce","ephox.katamari.async.AsyncValues","ephox.sugar.api.search.Traverse","ephox.sugar.api.properties.Attr",&qu
 ot;global!console","ephox.sugar.api.dom.InsertAll","ephox.sugar.api.dom.Remove","ephox.sugar.api.node.NodeTypes","ephox.sugar.api.dom.Compare","ephox.katamari.api.Options","tinymce.core.undo.Diff","tinymce.core.delete.BlockBoundary","tinymce.core.delete.MergeBlocks","tinymce.core.delete.DeleteUtils","tinymce.core.caret.CaretUtils","tinymce.core.delete.CefDeleteAction","tinymce.core.delete.DeleteElement","tinymce.core.caret.CaretFinder","tinymce.core.keyboard.BoundaryCaret","tinymce.core.keyboard.BoundaryLocation","tinymce.core.keyboard.BoundarySelection","tinymce.core.keyboard.InlineUtils","tinymce.core.data.Binding","tinymce.core.init.InitContentBody","global!Object","global!setTimeout","ephox.katamari.api.Type","ephox.katamari.api.Struct","ephox
 .sugar.alien.Recurse","ephox.sand.api.Node","ephox.sand.api.PlatformDetection","ephox.sugar.api.search.Selectors","ephox.katamari.api.Obj","ephox.sugar.api.search.PredicateFind","tinymce.core.dom.Empty","ephox.katamari.api.Adt","tinymce.core.text.Bidi","tinymce.core.caret.CaretContainerInline","tinymce.core.caret.CaretContainerRemove","tinymce.core.util.LazyEvaluator","ephox.katamari.api.Cell","tinymce.core.caret.CaretContainerInput","tinymce.core.EditorUpload","tinymce.core.ForceBlocks","tinymce.core.keyboard.KeyboardOverrides","tinymce.core.NodeChange","tinymce.core.SelectionOverrides","tinymce.core.util.Quirks","ephox.katamari.data.Immutable","ephox.katamari.data.MixedBag","ephox.sand.util.Global","ephox.katamari.api.Thunk","ephox.sand.core.Pla
 tformDetection","global!navigator","ephox.sugar.api.node.Body","ephox.sugar.impl.ClosestOrAncestor","ephox.sugar.api.search.SelectorExists","tinymce.core.file.Uploader","tinymce.core.file.ImageScanner","tinymce.core.file.BlobCache","tinymce.core.file.UploadStatus","tinymce.core.keyboard.ArrowKeys","tinymce.core.keyboard.DeleteBackspaceKeys","tinymce.core.keyboard.EnterKey","tinymce.core.keyboard.SpaceKey","tinymce.core.caret.FakeCaret","tinymce.core.caret.LineUtils","tinymce.core.DragDropOverrides","tinymce.core.keyboard.CefUtils","tinymce.core.dom.NodePath","ephox.katamari.util.BagUtils","ephox.katamari.api.Resolve","ephox.sand.core.Browser","ephox.sand.core.OperatingSystem","ephox.sand.detect.DeviceType","ephox.sand.detect.UaString","ephox.sand.
 info.PlatformInfo","ephox.sugar.api.search.SelectorFind","tinymce.core.file.Conversions","global!URL","tinymce.core.keyboard.CefNavigation","tinymce.core.keyboard.MatchKeys","tinymce.core.keyboard.InsertSpace","tinymce.core.dom.Dimensions","tinymce.core.dom.MousePosition","ephox.katamari.api.Global","ephox.sand.detect.Version","ephox.katamari.api.Strings","tinymce.core.caret.LineWalker","ephox.katamari.api.Merger","global!Number","ephox.katamari.str.StrAppend","ephox.katamari.str.StringParts"]
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+["tinymce.core.api.Main","ephox.katamari.api.Fun","tinymce.core.api.Tinymce","global!Array","global!Error","tinymce.core.AddOnManager","tinymce.core.api.Formatter","tinymce.core.api.NotificationManager","tinymce.core.api.WindowManager","tinymce.core.dom.BookmarkManager","tinymce.core.dom.ControlSelection","tinymce.core.dom.DomQuery","tinymce.core.dom.DOMUtils","tinymce.core.dom.EventUtils","tinymce.core.dom.RangeUtils","tinymce.core.dom.ScriptLoader","tinymce.core.dom.Selection","tinymce.core.dom.Serializer","tinymce.core.dom.Sizzle","tinymce.core.dom.TreeWalker","tinymce.core.Editor","tinymce.core.EditorCommands","tinymce.core.EditorManager","tinymce.core.E
 ditorObservable","tinymce.core.Env","tinymce.core.FocusManager","tinymce.core.geom.Rect","tinymce.core.html.DomParser","tinymce.core.html.Entities","tinymce.core.html.Node","tinymce.core.html.SaxParser","tinymce.core.html.Schema","tinymce.core.html.Serializer","tinymce.core.html.Styles","tinymce.core.html.Writer","tinymce.core.Shortcuts","tinymce.core.ui.Api","tinymce.core.UndoManager","tinymce.core.util.Class","tinymce.core.util.Color","tinymce.core.util.Delay","tinymce.core.util.EventDispatcher","tinymce.core.util.I18n","tinymce.core.util.JSON","tinymce.core.util.JSONP","tinymce.core.util.JSONRequest","tinymce.core.util.LocalStorage","tinymce.core.util.Observable","tinymce.core.util.Promise","tinymce.core.util.Tools",&qu
 ot;tinymce.core.util.URI","tinymce.core.util.VK","tinymce.core.util.XHR","tinymce.core.util.Arr","tinymce.core.dom.Range","tinymce.core.dom.StyleSheetLoader","ephox.katamari.api.Cell","tinymce.core.fmt.ApplyFormat","tinymce.core.fmt.FormatChanged","tinymce.core.fmt.FormatRegistry","tinymce.core.fmt.MatchFormat","tinymce.core.fmt.Preview","tinymce.core.fmt.RemoveFormat","tinymce.core.fmt.ToggleFormat","tinymce.core.keyboard.FormatShortcuts","ephox.katamari.api.Arr","ephox.katamari.api.Option","tinymce.core.EditorView","tinymce.core.ui.NotificationManagerImpl","tinymce.core.ui.WindowManagerImpl","tinymce.core.caret.CaretBookmark","tinymce.core.caret.CaretContainer","tinymce.core.caret.CaretPosition","tinymce.core.dom.NodeType","tinymce.core.text.Zws
 p","ephox.sugar.api.node.Element","ephox.sugar.api.search.Selectors","tinymce.core.dom.RangePoint","ephox.sugar.api.dom.Compare","tinymce.core.dom.ScrollIntoView","tinymce.core.dom.TridentSelection","tinymce.core.selection.FragmentReader","tinymce.core.selection.MultiRange","tinymce.core.delete.DeleteCommands","tinymce.core.InsertContent","tinymce.core.EditorFocus","tinymce.core.EditorSettings","tinymce.core.init.Render","tinymce.core.Mode","tinymce.core.ui.Sidebar","global!document","tinymce.core.util.Uuid","ephox.katamari.api.Type","tinymce.core.ErrorReporter","tinymce.core.LegacyInput","tinymce.core.ui.Selector","tinymce.core.ui.Collection","tinymce.core.ui.ReflowQueue","tinymce.core.ui.Control","tinymce.core.ui.Factory","ti
 nymce.core.ui.KeyboardNavigation","tinymce.core.ui.Container","tinymce.core.ui.DragHelper","tinymce.core.ui.Scrollable","tinymce.core.ui.Panel","tinymce.core.ui.Movable","tinymce.core.ui.Resizable","tinymce.core.ui.FloatPanel","tinymce.core.ui.Window","tinymce.core.ui.MessageBox","tinymce.core.ui.Tooltip","tinymce.core.ui.Widget","tinymce.core.ui.Progress","tinymce.core.ui.Notification","tinymce.core.ui.Layout","tinymce.core.ui.AbsoluteLayout","tinymce.core.ui.Button","tinymce.core.ui.ButtonGroup","tinymce.core.ui.Checkbox","tinymce.core.ui.ComboBox","tinymce.core.ui.ColorBox","tinymce.core.ui.PanelButton","tinymce.core.ui.ColorButton","tinymce.core.ui.ColorPicker","tinymce.core.ui.Path","tinymce.core.ui.ElementPath","tinymce.c
 ore.ui.FormItem","tinymce.core.ui.Form","tinymce.core.ui.FieldSet","tinymce.core.ui.FilePicker","tinymce.core.ui.FitLayout","tinymce.core.ui.FlexLayout","tinymce.core.ui.FlowLayout","tinymce.core.ui.FormatControls","tinymce.core.ui.GridLayout","tinymce.core.ui.Iframe","tinymce.core.ui.InfoBox","tinymce.core.ui.Label","tinymce.core.ui.Toolbar","tinymce.core.ui.MenuBar","tinymce.core.ui.MenuButton","tinymce.core.ui.MenuItem","tinymce.core.ui.Throbber","tinymce.core.ui.Menu","tinymce.core.ui.ListBox","tinymce.core.ui.Radio","tinymce.core.ui.ResizeHandle","tinymce.core.ui.SelectBox","tinymce.core.ui.Slider","tinymce.core.ui.Spacer","tinymce.core.ui.SplitButton","tinymce.core.ui.StackLayout","tinymce.core.ui.TabPanel","tin
 ymce.core.ui.TextBox","tinymce.core.ui.DropZone","tinymce.core.ui.BrowseButton","tinymce.core.undo.Levels","global!Object","global!String","ephox.katamari.api.Future","ephox.katamari.api.Futures","ephox.katamari.api.Result","tinymce.core.util.Fun","tinymce.core.caret.CaretCandidate","tinymce.core.geom.ClientRect","tinymce.core.text.ExtendingChar","tinymce.core.dom.RangeNormalizer","tinymce.core.fmt.CaretFormat","tinymce.core.fmt.ExpandRange","tinymce.core.fmt.FormatUtils","tinymce.core.fmt.Hooks","tinymce.core.fmt.MergeFormats","tinymce.core.fmt.DefaultFormats","ephox.sand.api.Node","ephox.sand.api.PlatformDetection","global!console","ephox.sugar.api.node.NodeTypes","ephox.sugar.api.properties.Css","ephox.sugar.api.search.Traverse",
 "tinymce.core.ui.DomUtils","tinymce.core.data.ObservableObject","tinymce.core.ui.BoxUtils","tinymce.core.ui.ClassList","ephox.sugar.api.dom.Insert","ephox.sugar.api.dom.Replication","ephox.sugar.api.node.Fragment","ephox.sugar.api.node.Node","ephox.sugar.api.search.SelectorFind","tinymce.core.dom.ElementType","tinymce.core.dom.Parents","tinymce.core.selection.SelectionUtils","tinymce.core.selection.SimpleTableModel","tinymce.core.selection.TableCellSelection","tinymce.core.delete.BlockBoundaryDelete","tinymce.core.delete.BlockRangeDelete","tinymce.core.delete.CefDelete","tinymce.core.delete.DeleteUtils","tinymce.core.delete.InlineBoundaryDelete","tinymce.core.delete.TableDelete","tinymce.core.caret.CaretWalker","tinymce.core.dom.ElementUtils","tinymce.core.dom.P
 addingBr","tinymce.core.InsertList","tinymce.core.caret.CaretFinder","ephox.katamari.api.Obj","ephox.katamari.api.Strings","ephox.katamari.api.Struct","global!window","tinymce.core.init.Init","tinymce.core.PluginManager","tinymce.core.ThemeManager","tinymce.core.content.LinkTargets","tinymce.core.fmt.FontInfo","global!RegExp","tinymce.core.undo.Fragments","ephox.katamari.api.LazyValue","ephox.katamari.async.Bounce","ephox.katamari.async.AsyncValues","tinymce.core.caret.CaretUtils","ephox.katamari.data.Immutable","ephox.katamari.data.MixedBag","ephox.sugar.alien.Recurse","ephox.sand.util.Global","ephox.katamari.api.Thunk","ephox.sand.core.PlatformDetection","global!navigator","ephox.sugar.api.dom.Remove","ephox.sugar.api.node.Te
 xt","ephox.sugar.api.search.SelectorFilter","ephox.sugar.api.properties.Attr","ephox.sugar.api.node.Body","ephox.sugar.impl.Style","ephox.katamari.str.StrAppend","ephox.katamari.str.StringParts","tinymce.core.data.Binding","ephox.sugar.api.dom.InsertAll","ephox.sugar.api.search.PredicateFind","ephox.sugar.impl.ClosestOrAncestor","ephox.katamari.api.Options","tinymce.core.delete.BlockBoundary","tinymce.core.delete.MergeBlocks","tinymce.core.delete.CefDeleteAction","tinymce.core.delete.DeleteElement","tinymce.core.keyboard.BoundaryCaret","tinymce.core.keyboard.BoundaryLocation","tinymce.core.keyboard.BoundarySelection","tinymce.core.keyboard.InlineUtils","tinymce.core.delete.TableDeleteAction","tinymce.core.init.InitContentBody","tinymce.core.undo.Diff","glob
 al!setTimeout","ephox.katamari.util.BagUtils","ephox.katamari.api.Resolve","ephox.sand.core.Browser","ephox.sand.core.OperatingSystem","ephox.sand.detect.DeviceType","ephox.sand.detect.UaString","ephox.sand.info.PlatformInfo","ephox.sugar.impl.NodeValue","ephox.sugar.api.search.PredicateFilter","tinymce.core.dom.Empty","ephox.katamari.api.Adt","tinymce.core.caret.CaretContainerInline","tinymce.core.caret.CaretContainerRemove","tinymce.core.text.Bidi","tinymce.core.util.LazyEvaluator","tinymce.core.caret.CaretContainerInput","tinymce.core.EditorUpload","tinymce.core.ForceBlocks","tinymce.core.keyboard.KeyboardOverrides","tinymce.core.NodeChange","tinymce.core.SelectionOverrides","tinymce.core.util.Quirks","ephox.katamari.api.Global","ephox.sand.det
 ect.Version","ephox.sugar.api.search.SelectorExists","tinymce.core.file.Uploader","tinymce.core.file.ImageScanner","tinymce.core.file.BlobCache","tinymce.core.file.UploadStatus","tinymce.core.keyboard.ArrowKeys","tinymce.core.keyboard.DeleteBackspaceKeys","tinymce.core.keyboard.EnterKey","tinymce.core.keyboard.SpaceKey","tinymce.core.DragDropOverrides","tinymce.core.caret.FakeCaret","tinymce.core.caret.LineUtils","tinymce.core.keyboard.CefUtils","tinymce.core.dom.NodePath","global!Number","tinymce.core.file.Conversions","ephox.sand.api.URL","tinymce.core.keyboard.CefNavigation","tinymce.core.keyboard.MatchKeys","tinymce.core.keyboard.InsertNewLine","tinymce.core.keyboard.InsertSpace","tinymce.core.dom.MousePosition","tinymce.core.dom.Dimensions","
 ephox.sand.api.Window","tinymce.core.caret.LineWalker","ephox.katamari.api.Merger"]
</ins><span class="cx" style="display: block; padding: 0 10px"> jsc*/
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * Rect.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+defineGlobal("global!Array", Array);
+defineGlobal("global!Error", Error);
+define(
+  'ephox.katamari.api.Fun',
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * Contains various tools for rect/position calculation.
- *
- * @class tinymce.geom.Rect
- */
-define(
-  'tinymce.core.geom.Rect',
</del><span class="cx" style="display: block; padding: 0 10px">   [
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'global!Array',
+    'global!Error'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function () {
-    "use strict";
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var min = Math.min, max = Math.max, round = Math.round;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Array, Error) {
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    /**
-     * Returns the rect positioned based on the relative position name
-     * to the target rect.
-     *
-     * @method relativePosition
-     * @param {Rect} rect Source rect to modify into a new rect.
-     * @param {Rect} targetRect Rect to move relative to based on the rel option.
-     * @param {String} rel Relative position. For example: tr-bl.
-     */
-    function relativePosition(rect, targetRect, rel) {
-      var x, y, w, h, targetW, targetH;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var noop = function () { };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      x = targetRect.x;
-      y = targetRect.y;
-      w = rect.w;
-      h = rect.h;
-      targetW = targetRect.w;
-      targetH = targetRect.h;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var compose = function (fa, fb) {
+      return function () {
+        return fa(fb.apply(null, arguments));
+      };
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      rel = (rel || '').split('');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var constant = function (value) {
+      return function () {
+        return value;
+      };
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (rel[0] === 'b') {
-        y += targetH;
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var identity = function (x) {
+      return x;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (rel[1] === 'r') {
-        x += targetW;
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var tripleEquals = function(a, b) {
+      return a === b;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (rel[0] === 'c') {
-        y += round(targetH / 2);
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Don't use array slice(arguments), makes the whole function unoptimisable on Chrome
+    var curry = function (f) {
+      // equivalent to arguments.slice(1)
+      // starting at 1 because 0 is the f, makes things tricky.
+      // Pay attention to what variable is where, and the -1 magic.
+      // thankfully, we have tests for this.
+      var args = new Array(arguments.length - 1);
+      for (var i = 1; i < arguments.length; i++) args[i-1] = arguments[i];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (rel[1] === 'c') {
-        x += round(targetW / 2);
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return function () {
+        var newArgs = new Array(arguments.length);
+        for (var j = 0; j < newArgs.length; j++) newArgs[j] = arguments[j];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (rel[3] === 'b') {
-        y -= h;
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var all = args.concat(newArgs);
+        return f.apply(null, all);
+      };
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (rel[4] === 'r') {
-        x -= w;
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var not = function (f) {
+      return function () {
+        return !f.apply(null, arguments);
+      };
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (rel[3] === 'c') {
-        y -= round(h / 2);
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var die = function (msg) {
+      return function () {
+        throw new Error(msg);
+      };
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (rel[4] === 'c') {
-        x -= round(w / 2);
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var apply = function (f) {
+      return f();
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return create(x, y, w, h);
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var call = function(f) {
+      f();
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    /**
-     * Tests various positions to get the most suitable one.
-     *
-     * @method findBestRelativePosition
-     * @param {Rect} rect Rect to use as source.
-     * @param {Rect} targetRect Rect to move relative to.
-     * @param {Rect} constrainRect Rect to constrain within.
-     * @param {Array} rels Array of relative positions to test against.
-     */
-    function findBestRelativePosition(rect, targetRect, constrainRect, rels) {
-      var pos, i;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var never = constant(false);
+    var always = constant(true);
+    
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      for (i = 0; i < rels.length; i++) {
-        pos = relativePosition(rect, targetRect, rels[i]);
-
-        if (pos.x >= constrainRect.x && pos.x + pos.w <= constrainRect.w + constrainRect.x &&
-          pos.y >= constrainRect.y && pos.y + pos.h <= constrainRect.h + constrainRect.y) {
-          return rels[i];
-        }
-      }
-
-      return null;
-    }
-
-    /**
-     * Inflates the rect in all directions.
-     *
-     * @method inflate
-     * @param {Rect} rect Rect to expand.
-     * @param {Number} w Relative width to expand by.
-     * @param {Number} h Relative height to expand by.
-     * @return {Rect} New expanded rect.
-     */
-    function inflate(rect, w, h) {
-      return create(rect.x - w, rect.y - h, rect.w + w * 2, rect.h + h * 2);
-    }
-
-    /**
-     * Returns the intersection of the specified rectangles.
-     *
-     * @method intersect
-     * @param {Rect} rect The first rectangle to compare.
-     * @param {Rect} cropRect The second rectangle to compare.
-     * @return {Rect} The intersection of the two rectangles or null if they don't intersect.
-     */
-    function intersect(rect, cropRect) {
-      var x1, y1, x2, y2;
-
-      x1 = max(rect.x, cropRect.x);
-      y1 = max(rect.y, cropRect.y);
-      x2 = min(rect.x + rect.w, cropRect.x + cropRect.w);
-      y2 = min(rect.y + rect.h, cropRect.y + cropRect.h);
-
-      if (x2 - x1 < 0 || y2 - y1 < 0) {
-        return null;
-      }
-
-      return create(x1, y1, x2 - x1, y2 - y1);
-    }
-
-    /**
-     * Returns a rect clamped within the specified clamp rect. This forces the
-     * rect to be inside the clamp rect.
-     *
-     * @method clamp
-     * @param {Rect} rect Rectangle to force within clamp rect.
-     * @param {Rect} clampRect Rectable to force within.
-     * @param {Boolean} fixedSize True/false if size should be fixed.
-     * @return {Rect} Clamped rect.
-     */
-    function clamp(rect, clampRect, fixedSize) {
-      var underflowX1, underflowY1, overflowX2, overflowY2,
-        x1, y1, x2, y2, cx2, cy2;
-
-      x1 = rect.x;
-      y1 = rect.y;
-      x2 = rect.x + rect.w;
-      y2 = rect.y + rect.h;
-      cx2 = clampRect.x + clampRect.w;
-      cy2 = clampRect.y + clampRect.h;
-
-      underflowX1 = max(0, clampRect.x - x1);
-      underflowY1 = max(0, clampRect.y - y1);
-      overflowX2 = max(0, x2 - cx2);
-      overflowY2 = max(0, y2 - cy2);
-
-      x1 += underflowX1;
-      y1 += underflowY1;
-
-      if (fixedSize) {
-        x2 += underflowX1;
-        y2 += underflowY1;
-        x1 -= overflowX2;
-        y1 -= overflowY2;
-      }
-
-      x2 -= overflowX2;
-      y2 -= overflowY2;
-
-      return create(x1, y1, x2 - x1, y2 - y1);
-    }
-
-    /**
-     * Creates a new rectangle object.
-     *
-     * @method create
-     * @param {Number} x Rectangle x location.
-     * @param {Number} y Rectangle y location.
-     * @param {Number} w Rectangle width.
-     * @param {Number} h Rectangle height.
-     * @return {Rect} New rectangle object.
-     */
-    function create(x, y, w, h) {
-      return { x: x, y: y, w: w, h: h };
-    }
-
-    /**
-     * Creates a new rectangle object form a clientRects object.
-     *
-     * @method fromClientRect
-     * @param {ClientRect} clientRect DOM ClientRect object.
-     * @return {Rect} New rectangle object.
-     */
-    function fromClientRect(clientRect) {
-      return create(clientRect.left, clientRect.top, clientRect.width, clientRect.height);
-    }
-
</del><span class="cx" style="display: block; padding: 0 10px">     return {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      inflate: inflate,
-      relativePosition: relativePosition,
-      findBestRelativePosition: findBestRelativePosition,
-      intersect: intersect,
-      clamp: clamp,
-      create: create,
-      fromClientRect: fromClientRect
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      noop: noop,
+      compose: compose,
+      constant: constant,
+      identity: identity,
+      tripleEquals: tripleEquals,
+      curry: curry,
+      not: not,
+      die: die,
+      apply: apply,
+      call: call,
+      never: never,
+      always: always
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1525,6 +1399,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Contributing: http://www.tinymce.com/contributing
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @ignore-file
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ *
+ * Forked changes:
+ * - Disabled all assertions since they are only used for non supported browsers and cause dom repaints see #TINY-1141
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /*jshint bitwise:false, expr:true, noempty:false, sub:true, eqnull:true, latedef:false, maxlen:255 */
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1858,7 +1735,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">      * Support testing using an element
</span><span class="cx" style="display: block; padding: 0 10px">      * @param {Function} fn Passed the created div and expects a boolean result
</span><span class="cx" style="display: block; padding: 0 10px">      */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function assert(fn) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    /*function assert(fn) {
</ins><span class="cx" style="display: block; padding: 0 10px">       var div = document.createElement("div");
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       try {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1873,7 +1750,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         // release memory in IE
</span><span class="cx" style="display: block; padding: 0 10px">         div = null;
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    }*/
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     /**
</span><span class="cx" style="display: block; padding: 0 10px">      * Adds the same handler for all of the specified attrs
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2041,19 +1918,13 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // Support: IE<8
</span><span class="cx" style="display: block; padding: 0 10px">       // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      support.attributes = assert(function (div) {
-        div.className = "i";
-        return !div.getAttribute("className");
-      });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      support.attributes = true;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       /* getElement(s)By*
</span><span class="cx" style="display: block; padding: 0 10px">       ---------------------------------------------------------------------- */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // Check if getElementsByTagName("*") returns only elements
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      support.getElementsByTagName = assert(function (div) {
-        div.appendChild(doc.createComment(""));
-        return !div.getElementsByTagName("*").length;
-      });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      support.getElementsByTagName = true;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // Support: IE<9
</span><span class="cx" style="display: block; padding: 0 10px">       support.getElementsByClassName = rnative.test(doc.getElementsByClassName);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2062,13 +1933,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">       // Check if getElementById returns elements by name
</span><span class="cx" style="display: block; padding: 0 10px">       // The broken getElementById methods don't pick up programatically-set names,
</span><span class="cx" style="display: block; padding: 0 10px">       // so use a roundabout getElementsByName test
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      support.getById = assert(function (div) {
-        docElem.appendChild(div).id = expando;
-        return !doc.getElementsByName || !doc.getElementsByName(expando).length;
-      });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      support.getById = true;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // ID find and filter
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (support.getById) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      /*if (support.getById) {*/
</ins><span class="cx" style="display: block; padding: 0 10px">         Expr.find["ID"] = function (id, context) {
</span><span class="cx" style="display: block; padding: 0 10px">           if (typeof context.getElementById !== strundefined && documentIsHTML) {
</span><span class="cx" style="display: block; padding: 0 10px">             var m = context.getElementById(id);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2083,7 +1951,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">             return elem.getAttribute("id") === attrId;
</span><span class="cx" style="display: block; padding: 0 10px">           };
</span><span class="cx" style="display: block; padding: 0 10px">         };
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      } else {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      /*} else {
</ins><span class="cx" style="display: block; padding: 0 10px">         // Support: IE6/7
</span><span class="cx" style="display: block; padding: 0 10px">         // getElementById is not reliable as a find shortcut
</span><span class="cx" style="display: block; padding: 0 10px">         delete Expr.find["ID"];
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2095,7 +1963,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">             return node && node.value === attrId;
</span><span class="cx" style="display: block; padding: 0 10px">           };
</span><span class="cx" style="display: block; padding: 0 10px">         };
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }*/
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // Tag
</span><span class="cx" style="display: block; padding: 0 10px">       Expr.find["TAG"] = support.getElementsByTagName ?
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2145,6 +2013,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">       // See http://bugs.jquery.com/ticket/13378
</span><span class="cx" style="display: block; padding: 0 10px">       rbuggyQSA = [];
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      /*
</ins><span class="cx" style="display: block; padding: 0 10px">       if ((support.qsa = rnative.test(doc.querySelectorAll))) {
</span><span class="cx" style="display: block; padding: 0 10px">         // Build QSA regex
</span><span class="cx" style="display: block; padding: 0 10px">         // Regex strategy adopted from Diego Perini
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2202,7 +2071,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">           rbuggyQSA.push(",.*:");
</span><span class="cx" style="display: block; padding: 0 10px">         });
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      */
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      support.disconnectedMatch = true;
+
+      /*
</ins><span class="cx" style="display: block; padding: 0 10px">       if ((support.matchesSelector = rnative.test((matches = docElem.matches ||
</span><span class="cx" style="display: block; padding: 0 10px">         docElem.webkitMatchesSelector ||
</span><span class="cx" style="display: block; padding: 0 10px">         docElem.mozMatchesSelector ||
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2220,6 +2093,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">           rbuggyMatches.push("!=", pseudos);
</span><span class="cx" style="display: block; padding: 0 10px">         });
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      */
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       rbuggyQSA = rbuggyQSA.length && new RegExp(rbuggyQSA.join("|"));
</span><span class="cx" style="display: block; padding: 0 10px">       rbuggyMatches = rbuggyMatches.length && new RegExp(rbuggyMatches.join("|"));
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -3515,16 +3389,12 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
</span><span class="cx" style="display: block; padding: 0 10px">     // Detached nodes confoundingly follow *each other*
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    support.sortDetached = assert(function (div1) {
-      // Should return 1, but returns 4 (following)
-      return div1.compareDocumentPosition(document.createElement("div")) & 1;
-    }
-    );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    support.sortDetached = true;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Support: IE<8
</span><span class="cx" style="display: block; padding: 0 10px">     // Prevent attribute/property "interpolation"
</span><span class="cx" style="display: block; padding: 0 10px">     // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    if (!assert(function (div) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    /*if (!assert(function (div) {
</ins><span class="cx" style="display: block; padding: 0 10px">       div.innerHTML = "<a href='#'></a>";
</span><span class="cx" style="display: block; padding: 0 10px">       return div.firstChild.getAttribute("href") === "#";
</span><span class="cx" style="display: block; padding: 0 10px">     })) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -3533,11 +3403,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">           return elem.getAttribute(name, name.toLowerCase() === "type" ? 1 : 2);
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">       });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    }*/
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Support: IE<9
</span><span class="cx" style="display: block; padding: 0 10px">     // Use defaultValue in place of getAttribute("value")
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    if (!support.attributes || !assert(function (div) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    /*if (!support.attributes || !assert(function (div) {
</ins><span class="cx" style="display: block; padding: 0 10px">       div.innerHTML = "<input/>";
</span><span class="cx" style="display: block; padding: 0 10px">       div.firstChild.setAttribute("value", "");
</span><span class="cx" style="display: block; padding: 0 10px">       return div.firstChild.getAttribute("value") === "";
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -3547,11 +3417,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">           return elem.defaultValue;
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">       });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    }*/
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Support: IE<9
</span><span class="cx" style="display: block; padding: 0 10px">     // Use getAttributeNode to fetch booleans when getAttribute lies
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    if (!assert(function (div) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    /*if (!assert(function (div) {
</ins><span class="cx" style="display: block; padding: 0 10px">       return div.getAttribute("disabled") == null;
</span><span class="cx" style="display: block; padding: 0 10px">     })) {
</span><span class="cx" style="display: block; padding: 0 10px">       addHandle(booleans, function (elem, name, isXML) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -3563,7 +3433,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">               null;
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">       });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    }*/
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // EXPOSE
</span><span class="cx" style="display: block; padding: 0 10px">     return Sizzle;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -5775,803 +5645,6 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Styles.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * This class is used to parse CSS styles it also compresses styles to reduce the output size.
- *
- * @example
- * var Styles = new tinymce.html.Styles({
- *    url_converter: function(url) {
- *       return url;
- *    }
- * });
- *
- * styles = Styles.parse('border: 1px solid red');
- * styles.color = 'red';
- *
- * console.log(new tinymce.html.StyleSerializer().serialize(styles));
- *
- * @class tinymce.html.Styles
- * @version 3.4
- */
-define(
-  'tinymce.core.html.Styles',
-  [
-  ],
-  function () {
-    return function (settings, schema) {
-      /*jshint maxlen:255 */
-      /*eslint max-len:0 */
-      var rgbRegExp = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi,
-        urlOrStrRegExp = /(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi,
-        styleRegExp = /\s*([^:]+):\s*([^;]+);?/g,
-        trimRightRegExp = /\s+$/,
-        i, encodingLookup = {}, encodingItems, validStyles, invalidStyles, invisibleChar = '\uFEFF';
-
-      settings = settings || {};
-
-      if (schema) {
-        validStyles = schema.getValidStyles();
-        invalidStyles = schema.getInvalidStyles();
-      }
-
-      encodingItems = ('\\" \\\' \\; \\: ; : ' + invisibleChar).split(' ');
-      for (i = 0; i < encodingItems.length; i++) {
-        encodingLookup[encodingItems[i]] = invisibleChar + i;
-        encodingLookup[invisibleChar + i] = encodingItems[i];
-      }
-
-      function toHex(match, r, g, b) {
-        function hex(val) {
-          val = parseInt(val, 10).toString(16);
-
-          return val.length > 1 ? val : '0' + val; // 0 -> 00
-        }
-
-        return '#' + hex(r) + hex(g) + hex(b);
-      }
-
-      return {
-        /**
-         * Parses the specified RGB color value and returns a hex version of that color.
-         *
-         * @method toHex
-         * @param {String} color RGB string value like rgb(1,2,3)
-         * @return {String} Hex version of that RGB value like #FF00FF.
-         */
-        toHex: function (color) {
-          return color.replace(rgbRegExp, toHex);
-        },
-
-        /**
-         * Parses the specified style value into an object collection. This parser will also
-         * merge and remove any redundant items that browsers might have added. It will also convert non hex
-         * colors to hex values. Urls inside the styles will also be converted to absolute/relative based on settings.
-         *
-         * @method parse
-         * @param {String} css Style value to parse for example: border:1px solid red;.
-         * @return {Object} Object representation of that style like {border: '1px solid red'}
-         */
-        parse: function (css) {
-          var styles = {}, matches, name, value, isEncoded, urlConverter = settings.url_converter;
-          var urlConverterScope = settings.url_converter_scope || this;
-
-          function compress(prefix, suffix, noJoin) {
-            var top, right, bottom, left;
-
-            top = styles[prefix + '-top' + suffix];
-            if (!top) {
-              return;
-            }
-
-            right = styles[prefix + '-right' + suffix];
-            if (!right) {
-              return;
-            }
-
-            bottom = styles[prefix + '-bottom' + suffix];
-            if (!bottom) {
-              return;
-            }
-
-            left = styles[prefix + '-left' + suffix];
-            if (!left) {
-              return;
-            }
-
-            var box = [top, right, bottom, left];
-            i = box.length - 1;
-            while (i--) {
-              if (box[i] !== box[i + 1]) {
-                break;
-              }
-            }
-
-            if (i > -1 && noJoin) {
-              return;
-            }
-
-            styles[prefix + suffix] = i == -1 ? box[0] : box.join(' ');
-            delete styles[prefix + '-top' + suffix];
-            delete styles[prefix + '-right' + suffix];
-            delete styles[prefix + '-bottom' + suffix];
-            delete styles[prefix + '-left' + suffix];
-          }
-
-          /**
-           * Checks if the specific style can be compressed in other words if all border-width are equal.
-           */
-          function canCompress(key) {
-            var value = styles[key], i;
-
-            if (!value) {
-              return;
-            }
-
-            value = value.split(' ');
-            i = value.length;
-            while (i--) {
-              if (value[i] !== value[0]) {
-                return false;
-              }
-            }
-
-            styles[key] = value[0];
-
-            return true;
-          }
-
-          /**
-           * Compresses multiple styles into one style.
-           */
-          function compress2(target, a, b, c) {
-            if (!canCompress(a)) {
-              return;
-            }
-
-            if (!canCompress(b)) {
-              return;
-            }
-
-            if (!canCompress(c)) {
-              return;
-            }
-
-            // Compress
-            styles[target] = styles[a] + ' ' + styles[b] + ' ' + styles[c];
-            delete styles[a];
-            delete styles[b];
-            delete styles[c];
-          }
-
-          // Encodes the specified string by replacing all \" \' ; : with _<num>
-          function encode(str) {
-            isEncoded = true;
-
-            return encodingLookup[str];
-          }
-
-          // Decodes the specified string by replacing all _<num> with it's original value \" \' etc
-          // It will also decode the \" \' if keepSlashes is set to fale or omitted
-          function decode(str, keepSlashes) {
-            if (isEncoded) {
-              str = str.replace(/\uFEFF[0-9]/g, function (str) {
-                return encodingLookup[str];
-              });
-            }
-
-            if (!keepSlashes) {
-              str = str.replace(/\\([\'\";:])/g, "$1");
-            }
-
-            return str;
-          }
-
-          function decodeSingleHexSequence(escSeq) {
-            return String.fromCharCode(parseInt(escSeq.slice(1), 16));
-          }
-
-          function decodeHexSequences(value) {
-            return value.replace(/\\[0-9a-f]+/gi, decodeSingleHexSequence);
-          }
-
-          function processUrl(match, url, url2, url3, str, str2) {
-            str = str || str2;
-
-            if (str) {
-              str = decode(str);
-
-              // Force strings into single quote format
-              return "'" + str.replace(/\'/g, "\\'") + "'";
-            }
-
-            url = decode(url || url2 || url3);
-
-            if (!settings.allow_script_urls) {
-              var scriptUrl = url.replace(/[\s\r\n]+/g, '');
-
-              if (/(java|vb)script:/i.test(scriptUrl)) {
-                return "";
-              }
-
-              if (!settings.allow_svg_data_urls && /^data:image\/svg/i.test(scriptUrl)) {
-                return "";
-              }
-            }
-
-            // Convert the URL to relative/absolute depending on config
-            if (urlConverter) {
-              url = urlConverter.call(urlConverterScope, url, 'style');
-            }
-
-            // Output new URL format
-            return "url('" + url.replace(/\'/g, "\\'") + "')";
-          }
-
-          if (css) {
-            css = css.replace(/[\u0000-\u001F]/g, '');
-
-            // Encode \" \' % and ; and : inside strings so they don't interfere with the style parsing
-            css = css.replace(/\\[\"\';:\uFEFF]/g, encode).replace(/\"[^\"]+\"|\'[^\']+\'/g, function (str) {
-              return str.replace(/[;:]/g, encode);
-            });
-
-            // Parse styles
-            while ((matches = styleRegExp.exec(css))) {
-              styleRegExp.lastIndex = matches.index + matches[0].length;
-              name = matches[1].replace(trimRightRegExp, '').toLowerCase();
-              value = matches[2].replace(trimRightRegExp, '');
-
-              if (name && value) {
-                // Decode escaped sequences like \65 -> e
-                name = decodeHexSequences(name);
-                value = decodeHexSequences(value);
-
-                // Skip properties with double quotes and sequences like \" \' in their names
-                // See 'mXSS Attacks: Attacking well-secured Web-Applications by using innerHTML Mutations'
-                // https://cure53.de/fp170.pdf
-                if (name.indexOf(invisibleChar) !== -1 || name.indexOf('"') !== -1) {
-                  continue;
-                }
-
-                // Don't allow behavior name or expression/comments within the values
-                if (!settings.allow_script_urls && (name == "behavior" || /expression\s*\(|\/\*|\*\//.test(value))) {
-                  continue;
-                }
-
-                // Opera will produce 700 instead of bold in their style values
-                if (name === 'font-weight' && value === '700') {
-                  value = 'bold';
-                } else if (name === 'color' || name === 'background-color') { // Lowercase colors like RED
-                  value = value.toLowerCase();
-                }
-
-                // Convert RGB colors to HEX
-                value = value.replace(rgbRegExp, toHex);
-
-                // Convert URLs and force them into url('value') format
-                value = value.replace(urlOrStrRegExp, processUrl);
-                styles[name] = isEncoded ? decode(value, true) : value;
-              }
-            }
-            // Compress the styles to reduce it's size for example IE will expand styles
-            compress("border", "", true);
-            compress("border", "-width");
-            compress("border", "-color");
-            compress("border", "-style");
-            compress("padding", "");
-            compress("margin", "");
-            compress2('border', 'border-width', 'border-style', 'border-color');
-
-            // Remove pointless border, IE produces these
-            if (styles.border === 'medium none') {
-              delete styles.border;
-            }
-
-            // IE 11 will produce a border-image: none when getting the style attribute from <p style="border: 1px solid red"></p>
-            // So let us assume it shouldn't be there
-            if (styles['border-image'] === 'none') {
-              delete styles['border-image'];
-            }
-          }
-
-          return styles;
-        },
-
-        /**
-         * Serializes the specified style object into a string.
-         *
-         * @method serialize
-         * @param {Object} styles Object to serialize as string for example: {border: '1px solid red'}
-         * @param {String} elementName Optional element name, if specified only the styles that matches the schema will be serialized.
-         * @return {String} String representation of the style object for example: border: 1px solid red.
-         */
-        serialize: function (styles, elementName) {
-          var css = '', name, value;
-
-          function serializeStyles(name) {
-            var styleList, i, l, value;
-
-            styleList = validStyles[name];
-            if (styleList) {
-              for (i = 0, l = styleList.length; i < l; i++) {
-                name = styleList[i];
-                value = styles[name];
-
-                if (value) {
-                  css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
-                }
-              }
-            }
-          }
-
-          function isValid(name, elementName) {
-            var styleMap;
-
-            styleMap = invalidStyles['*'];
-            if (styleMap && styleMap[name]) {
-              return false;
-            }
-
-            styleMap = invalidStyles[elementName];
-            if (styleMap && styleMap[name]) {
-              return false;
-            }
-
-            return true;
-          }
-
-          // Serialize styles according to schema
-          if (elementName && validStyles) {
-            // Serialize global styles and element specific styles
-            serializeStyles('*');
-            serializeStyles(elementName);
-          } else {
-            // Output the styles in the order they are inside the object
-            for (name in styles) {
-              value = styles[name];
-
-              if (value && (!invalidStyles || isValid(name, elementName))) {
-                css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
-              }
-            }
-          }
-
-          return css;
-        }
-      };
-    };
-  }
-);
-
-/**
- * TreeWalker.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * TreeWalker class enables you to walk the DOM in a linear manner.
- *
- * @class tinymce.dom.TreeWalker
- * @example
- * var walker = new tinymce.dom.TreeWalker(startNode);
- *
- * do {
- *     console.log(walker.current());
- * } while (walker.next());
- */
-define(
-  'tinymce.core.dom.TreeWalker',
-  [
-  ],
-  function () {
-    /**
-     * Constructs a new TreeWalker instance.
-     *
-     * @constructor
-     * @method TreeWalker
-     * @param {Node} startNode Node to start walking from.
-     * @param {node} rootNode Optional root node to never walk out of.
-     */
-    return function (startNode, rootNode) {
-      var node = startNode;
-
-      function findSibling(node, startName, siblingName, shallow) {
-        var sibling, parent;
-
-        if (node) {
-          // Walk into nodes if it has a start
-          if (!shallow && node[startName]) {
-            return node[startName];
-          }
-
-          // Return the sibling if it has one
-          if (node != rootNode) {
-            sibling = node[siblingName];
-            if (sibling) {
-              return sibling;
-            }
-
-            // Walk up the parents to look for siblings
-            for (parent = node.parentNode; parent && parent != rootNode; parent = parent.parentNode) {
-              sibling = parent[siblingName];
-              if (sibling) {
-                return sibling;
-              }
-            }
-          }
-        }
-      }
-
-      function findPreviousNode(node, startName, siblingName, shallow) {
-        var sibling, parent, child;
-
-        if (node) {
-          sibling = node[siblingName];
-          if (rootNode && sibling === rootNode) {
-            return;
-          }
-
-          if (sibling) {
-            if (!shallow) {
-              // Walk up the parents to look for siblings
-              for (child = sibling[startName]; child; child = child[startName]) {
-                if (!child[startName]) {
-                  return child;
-                }
-              }
-            }
-
-            return sibling;
-          }
-
-          parent = node.parentNode;
-          if (parent && parent !== rootNode) {
-            return parent;
-          }
-        }
-      }
-
-      /**
-       * Returns the current node.
-       *
-       * @method current
-       * @return {Node} Current node where the walker is.
-       */
-      this.current = function () {
-        return node;
-      };
-
-      /**
-       * Walks to the next node in tree.
-       *
-       * @method next
-       * @return {Node} Current node where the walker is after moving to the next node.
-       */
-      this.next = function (shallow) {
-        node = findSibling(node, 'firstChild', 'nextSibling', shallow);
-        return node;
-      };
-
-      /**
-       * Walks to the previous node in tree.
-       *
-       * @method prev
-       * @return {Node} Current node where the walker is after moving to the previous node.
-       */
-      this.prev = function (shallow) {
-        node = findSibling(node, 'lastChild', 'previousSibling', shallow);
-        return node;
-      };
-
-      this.prev2 = function (shallow) {
-        node = findPreviousNode(node, 'lastChild', 'previousSibling', shallow);
-        return node;
-      };
-    };
-  }
-);
-
-/**
- * Entities.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/*jshint bitwise:false */
-/*eslint no-bitwise:0 */
-
-/**
- * Entity encoder class.
- *
- * @class tinymce.html.Entities
- * @static
- * @version 3.4
- */
-define(
-  'tinymce.core.html.Entities',
-  [
-    "tinymce.core.util.Tools"
-  ],
-  function (Tools) {
-    var makeMap = Tools.makeMap;
-
-    var namedEntities, baseEntities, reverseEntities,
-      attrsCharsRegExp = /[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
-      textCharsRegExp = /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
-      rawCharsRegExp = /[<>&\"\']/g,
-      entityRegExp = /&#([a-z0-9]+);?|&([a-z0-9]+);/gi,
-      asciiMap = {
-        128: "\u20AC", 130: "\u201A", 131: "\u0192", 132: "\u201E", 133: "\u2026", 134: "\u2020",
-        135: "\u2021", 136: "\u02C6", 137: "\u2030", 138: "\u0160", 139: "\u2039", 140: "\u0152",
-        142: "\u017D", 145: "\u2018", 146: "\u2019", 147: "\u201C", 148: "\u201D", 149: "\u2022",
-        150: "\u2013", 151: "\u2014", 152: "\u02DC", 153: "\u2122", 154: "\u0161", 155: "\u203A",
-        156: "\u0153", 158: "\u017E", 159: "\u0178"
-      };
-
-    // Raw entities
-    baseEntities = {
-      '\"': '&quot;', // Needs to be escaped since the YUI compressor would otherwise break the code
-      "'": '&#39;',
-      '<': '&lt;',
-      '>': '&gt;',
-      '&': '&amp;',
-      '\u0060': '&#96;'
-    };
-
-    // Reverse lookup table for raw entities
-    reverseEntities = {
-      '&lt;': '<',
-      '&gt;': '>',
-      '&amp;': '&',
-      '&quot;': '"',
-      '&apos;': "'"
-    };
-
-    // Decodes text by using the browser
-    function nativeDecode(text) {
-      var elm;
-
-      elm = document.createElement("div");
-      elm.innerHTML = text;
-
-      return elm.textContent || elm.innerText || text;
-    }
-
-    // Build a two way lookup table for the entities
-    function buildEntitiesLookup(items, radix) {
-      var i, chr, entity, lookup = {};
-
-      if (items) {
-        items = items.split(',');
-        radix = radix || 10;
-
-        // Build entities lookup table
-        for (i = 0; i < items.length; i += 2) {
-          chr = String.fromCharCode(parseInt(items[i], radix));
-
-          // Only add non base entities
-          if (!baseEntities[chr]) {
-            entity = '&' + items[i + 1] + ';';
-            lookup[chr] = entity;
-            lookup[entity] = chr;
-          }
-        }
-
-        return lookup;
-      }
-    }
-
-    // Unpack entities lookup where the numbers are in radix 32 to reduce the size
-    namedEntities = buildEntitiesLookup(
-      '50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,' +
-      '5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,' +
-      '5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,' +
-      '5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,' +
-      '68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,' +
-      '6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,' +
-      '6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,' +
-      '75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,' +
-      '7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,' +
-      '7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,' +
-      'sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,' +
-      'st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,' +
-      't9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,' +
-      'tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,' +
-      'u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,' +
-      '81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,' +
-      '8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,' +
-      '8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,' +
-      '8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,' +
-      '8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,' +
-      'nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,' +
-      'rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,' +
-      'Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,' +
-      '80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,' +
-      '811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro', 32);
-
-    var Entities = {
-      /**
-       * Encodes the specified string using raw entities. This means only the required XML base entities will be encoded.
-       *
-       * @method encodeRaw
-       * @param {String} text Text to encode.
-       * @param {Boolean} attr Optional flag to specify if the text is attribute contents.
-       * @return {String} Entity encoded text.
-       */
-      encodeRaw: function (text, attr) {
-        return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function (chr) {
-          return baseEntities[chr] || chr;
-        });
-      },
-
-      /**
-       * Encoded the specified text with both the attributes and text entities. This function will produce larger text contents
-       * since it doesn't know if the context is within a attribute or text node. This was added for compatibility
-       * and is exposed as the DOMUtils.encode function.
-       *
-       * @method encodeAllRaw
-       * @param {String} text Text to encode.
-       * @return {String} Entity encoded text.
-       */
-      encodeAllRaw: function (text) {
-        return ('' + text).replace(rawCharsRegExp, function (chr) {
-          return baseEntities[chr] || chr;
-        });
-      },
-
-      /**
-       * Encodes the specified string using numeric entities. The core entities will be
-       * encoded as named ones but all non lower ascii characters will be encoded into numeric entities.
-       *
-       * @method encodeNumeric
-       * @param {String} text Text to encode.
-       * @param {Boolean} attr Optional flag to specify if the text is attribute contents.
-       * @return {String} Entity encoded text.
-       */
-      encodeNumeric: function (text, attr) {
-        return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function (chr) {
-          // Multi byte sequence convert it to a single entity
-          if (chr.length > 1) {
-            return '&#' + (((chr.charCodeAt(0) - 0xD800) * 0x400) + (chr.charCodeAt(1) - 0xDC00) + 0x10000) + ';';
-          }
-
-          return baseEntities[chr] || '&#' + chr.charCodeAt(0) + ';';
-        });
-      },
-
-      /**
-       * Encodes the specified string using named entities. The core entities will be encoded
-       * as named ones but all non lower ascii characters will be encoded into named entities.
-       *
-       * @method encodeNamed
-       * @param {String} text Text to encode.
-       * @param {Boolean} attr Optional flag to specify if the text is attribute contents.
-       * @param {Object} entities Optional parameter with entities to use.
-       * @return {String} Entity encoded text.
-       */
-      encodeNamed: function (text, attr, entities) {
-        entities = entities || namedEntities;
-
-        return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function (chr) {
-          return baseEntities[chr] || entities[chr] || chr;
-        });
-      },
-
-      /**
-       * Returns an encode function based on the name(s) and it's optional entities.
-       *
-       * @method getEncodeFunc
-       * @param {String} name Comma separated list of encoders for example named,numeric.
-       * @param {String} entities Optional parameter with entities to use instead of the built in set.
-       * @return {function} Encode function to be used.
-       */
-      getEncodeFunc: function (name, entities) {
-        entities = buildEntitiesLookup(entities) || namedEntities;
-
-        function encodeNamedAndNumeric(text, attr) {
-          return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function (chr) {
-            if (baseEntities[chr] !== undefined) {
-              return baseEntities[chr];
-            }
-
-            if (entities[chr] !== undefined) {
-              return entities[chr];
-            }
-
-            // Convert multi-byte sequences to a single entity.
-            if (chr.length > 1) {
-              return '&#' + (((chr.charCodeAt(0) - 0xD800) * 0x400) + (chr.charCodeAt(1) - 0xDC00) + 0x10000) + ';';
-            }
-
-            return '&#' + chr.charCodeAt(0) + ';';
-          });
-        }
-
-        function encodeCustomNamed(text, attr) {
-          return Entities.encodeNamed(text, attr, entities);
-        }
-
-        // Replace + with , to be compatible with previous TinyMCE versions
-        name = makeMap(name.replace(/\+/g, ','));
-
-        // Named and numeric encoder
-        if (name.named && name.numeric) {
-          return encodeNamedAndNumeric;
-        }
-
-        // Named encoder
-        if (name.named) {
-          // Custom names
-          if (entities) {
-            return encodeCustomNamed;
-          }
-
-          return Entities.encodeNamed;
-        }
-
-        // Numeric
-        if (name.numeric) {
-          return Entities.encodeNumeric;
-        }
-
-        // Raw encoder
-        return Entities.encodeRaw;
-      },
-
-      /**
-       * Decodes the specified string, this will replace entities with raw UTF characters.
-       *
-       * @method decode
-       * @param {String} text Text to entity decode.
-       * @return {String} Entity decoded string.
-       */
-      decode: function (text) {
-        return text.replace(entityRegExp, function (all, numeric) {
-          if (numeric) {
-            if (numeric.charAt(0).toLowerCase() === 'x') {
-              numeric = parseInt(numeric.substr(1), 16);
-            } else {
-              numeric = parseInt(numeric, 10);
-            }
-
-            // Support upper UTF
-            if (numeric > 0xFFFF) {
-              numeric -= 0x10000;
-
-              return String.fromCharCode(0xD800 + (numeric >> 10), 0xDC00 + (numeric & 0x3FF));
-            }
-
-            return asciiMap[numeric] || String.fromCharCode(numeric);
-          }
-
-          return reverseEntities[all] || namedEntities[all] || nativeDecode(all);
-        });
-      }
-    };
-
-    return Entities;
-  }
-);
-
-/**
</del><span class="cx" style="display: block; padding: 0 10px">  * Range.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -7361,99 +6434,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-defineGlobal("global!Array", Array);
-defineGlobal("global!Error", Error);
-define(
-  'ephox.katamari.api.Fun',
-
-  [
-    'global!Array',
-    'global!Error'
-  ],
-
-  function (Array, Error) {
-
-    var noop = function () { };
-
-    var compose = function (fa, fb) {
-      return function () {
-        return fa(fb.apply(null, arguments));
-      };
-    };
-
-    var constant = function (value) {
-      return function () {
-        return value;
-      };
-    };
-
-    var identity = function (x) {
-      return x;
-    };
-
-    var tripleEquals = function(a, b) {
-      return a === b;
-    };
-
-    // Don't use array slice(arguments), makes the whole function unoptimisable on Chrome
-    var curry = function (f) {
-      // equivalent to arguments.slice(1)
-      // starting at 1 because 0 is the f, makes things tricky.
-      // Pay attention to what variable is where, and the -1 magic.
-      // thankfully, we have tests for this.
-      var args = new Array(arguments.length - 1);
-      for (var i = 1; i < arguments.length; i++) args[i-1] = arguments[i];
-
-      return function () {
-        var newArgs = new Array(arguments.length);
-        for (var j = 0; j < newArgs.length; j++) newArgs[j] = arguments[j];
-
-        var all = args.concat(newArgs);
-        return f.apply(null, all);
-      };
-    };
-
-    var not = function (f) {
-      return function () {
-        return !f.apply(null, arguments);
-      };
-    };
-
-    var die = function (msg) {
-      return function () {
-        throw new Error(msg);
-      };
-    };
-
-    var apply = function (f) {
-      return f();
-    };
-
-    var call = function(f) {
-      f();
-    };
-
-    var never = constant(false);
-    var always = constant(true);
-    
-
-    return {
-      noop: noop,
-      compose: compose,
-      constant: constant,
-      identity: identity,
-      tripleEquals: tripleEquals,
-      curry: curry,
-      not: not,
-      die: die,
-      apply: apply,
-      call: call,
-      never: never,
-      always: always
-    };
-  }
-);
-
</del><span class="cx" style="display: block; padding: 0 10px"> defineGlobal("global!Object", Object);
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><span class="cx" style="display: block; padding: 0 10px">   'ephox.katamari.api.Option',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -8567,6 +7547,425 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * TreeWalker.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * TreeWalker class enables you to walk the DOM in a linear manner.
+ *
+ * @class tinymce.dom.TreeWalker
+ * @example
+ * var walker = new tinymce.dom.TreeWalker(startNode);
+ *
+ * do {
+ *     console.log(walker.current());
+ * } while (walker.next());
+ */
+define(
+  'tinymce.core.dom.TreeWalker',
+  [
+  ],
+  function () {
+    /**
+     * Constructs a new TreeWalker instance.
+     *
+     * @constructor
+     * @method TreeWalker
+     * @param {Node} startNode Node to start walking from.
+     * @param {node} rootNode Optional root node to never walk out of.
+     */
+    return function (startNode, rootNode) {
+      var node = startNode;
+
+      function findSibling(node, startName, siblingName, shallow) {
+        var sibling, parent;
+
+        if (node) {
+          // Walk into nodes if it has a start
+          if (!shallow && node[startName]) {
+            return node[startName];
+          }
+
+          // Return the sibling if it has one
+          if (node != rootNode) {
+            sibling = node[siblingName];
+            if (sibling) {
+              return sibling;
+            }
+
+            // Walk up the parents to look for siblings
+            for (parent = node.parentNode; parent && parent != rootNode; parent = parent.parentNode) {
+              sibling = parent[siblingName];
+              if (sibling) {
+                return sibling;
+              }
+            }
+          }
+        }
+      }
+
+      function findPreviousNode(node, startName, siblingName, shallow) {
+        var sibling, parent, child;
+
+        if (node) {
+          sibling = node[siblingName];
+          if (rootNode && sibling === rootNode) {
+            return;
+          }
+
+          if (sibling) {
+            if (!shallow) {
+              // Walk up the parents to look for siblings
+              for (child = sibling[startName]; child; child = child[startName]) {
+                if (!child[startName]) {
+                  return child;
+                }
+              }
+            }
+
+            return sibling;
+          }
+
+          parent = node.parentNode;
+          if (parent && parent !== rootNode) {
+            return parent;
+          }
+        }
+      }
+
+      /**
+       * Returns the current node.
+       *
+       * @method current
+       * @return {Node} Current node where the walker is.
+       */
+      this.current = function () {
+        return node;
+      };
+
+      /**
+       * Walks to the next node in tree.
+       *
+       * @method next
+       * @return {Node} Current node where the walker is after moving to the next node.
+       */
+      this.next = function (shallow) {
+        node = findSibling(node, 'firstChild', 'nextSibling', shallow);
+        return node;
+      };
+
+      /**
+       * Walks to the previous node in tree.
+       *
+       * @method prev
+       * @return {Node} Current node where the walker is after moving to the previous node.
+       */
+      this.prev = function (shallow) {
+        node = findSibling(node, 'lastChild', 'previousSibling', shallow);
+        return node;
+      };
+
+      this.prev2 = function (shallow) {
+        node = findPreviousNode(node, 'lastChild', 'previousSibling', shallow);
+        return node;
+      };
+    };
+  }
+);
+
+/**
+ * Entities.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/*jshint bitwise:false */
+/*eslint no-bitwise:0 */
+
+/**
+ * Entity encoder class.
+ *
+ * @class tinymce.html.Entities
+ * @static
+ * @version 3.4
+ */
+define(
+  'tinymce.core.html.Entities',
+  [
+    "tinymce.core.util.Tools"
+  ],
+  function (Tools) {
+    var makeMap = Tools.makeMap;
+
+    var namedEntities, baseEntities, reverseEntities,
+      attrsCharsRegExp = /[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
+      textCharsRegExp = /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
+      rawCharsRegExp = /[<>&\"\']/g,
+      entityRegExp = /&#([a-z0-9]+);?|&([a-z0-9]+);/gi,
+      asciiMap = {
+        128: "\u20AC", 130: "\u201A", 131: "\u0192", 132: "\u201E", 133: "\u2026", 134: "\u2020",
+        135: "\u2021", 136: "\u02C6", 137: "\u2030", 138: "\u0160", 139: "\u2039", 140: "\u0152",
+        142: "\u017D", 145: "\u2018", 146: "\u2019", 147: "\u201C", 148: "\u201D", 149: "\u2022",
+        150: "\u2013", 151: "\u2014", 152: "\u02DC", 153: "\u2122", 154: "\u0161", 155: "\u203A",
+        156: "\u0153", 158: "\u017E", 159: "\u0178"
+      };
+
+    // Raw entities
+    baseEntities = {
+      '\"': '&quot;', // Needs to be escaped since the YUI compressor would otherwise break the code
+      "'": '&#39;',
+      '<': '&lt;',
+      '>': '&gt;',
+      '&': '&amp;',
+      '\u0060': '&#96;'
+    };
+
+    // Reverse lookup table for raw entities
+    reverseEntities = {
+      '&lt;': '<',
+      '&gt;': '>',
+      '&amp;': '&',
+      '&quot;': '"',
+      '&apos;': "'"
+    };
+
+    // Decodes text by using the browser
+    function nativeDecode(text) {
+      var elm;
+
+      elm = document.createElement("div");
+      elm.innerHTML = text;
+
+      return elm.textContent || elm.innerText || text;
+    }
+
+    // Build a two way lookup table for the entities
+    function buildEntitiesLookup(items, radix) {
+      var i, chr, entity, lookup = {};
+
+      if (items) {
+        items = items.split(',');
+        radix = radix || 10;
+
+        // Build entities lookup table
+        for (i = 0; i < items.length; i += 2) {
+          chr = String.fromCharCode(parseInt(items[i], radix));
+
+          // Only add non base entities
+          if (!baseEntities[chr]) {
+            entity = '&' + items[i + 1] + ';';
+            lookup[chr] = entity;
+            lookup[entity] = chr;
+          }
+        }
+
+        return lookup;
+      }
+    }
+
+    // Unpack entities lookup where the numbers are in radix 32 to reduce the size
+    namedEntities = buildEntitiesLookup(
+      '50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,' +
+      '5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,' +
+      '5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,' +
+      '5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,' +
+      '68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,' +
+      '6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,' +
+      '6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,' +
+      '75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,' +
+      '7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,' +
+      '7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,' +
+      'sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,' +
+      'st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,' +
+      't9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,' +
+      'tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,' +
+      'u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,' +
+      '81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,' +
+      '8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,' +
+      '8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,' +
+      '8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,' +
+      '8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,' +
+      'nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,' +
+      'rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,' +
+      'Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,' +
+      '80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,' +
+      '811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro', 32);
+
+    var Entities = {
+      /**
+       * Encodes the specified string using raw entities. This means only the required XML base entities will be encoded.
+       *
+       * @method encodeRaw
+       * @param {String} text Text to encode.
+       * @param {Boolean} attr Optional flag to specify if the text is attribute contents.
+       * @return {String} Entity encoded text.
+       */
+      encodeRaw: function (text, attr) {
+        return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function (chr) {
+          return baseEntities[chr] || chr;
+        });
+      },
+
+      /**
+       * Encoded the specified text with both the attributes and text entities. This function will produce larger text contents
+       * since it doesn't know if the context is within a attribute or text node. This was added for compatibility
+       * and is exposed as the DOMUtils.encode function.
+       *
+       * @method encodeAllRaw
+       * @param {String} text Text to encode.
+       * @return {String} Entity encoded text.
+       */
+      encodeAllRaw: function (text) {
+        return ('' + text).replace(rawCharsRegExp, function (chr) {
+          return baseEntities[chr] || chr;
+        });
+      },
+
+      /**
+       * Encodes the specified string using numeric entities. The core entities will be
+       * encoded as named ones but all non lower ascii characters will be encoded into numeric entities.
+       *
+       * @method encodeNumeric
+       * @param {String} text Text to encode.
+       * @param {Boolean} attr Optional flag to specify if the text is attribute contents.
+       * @return {String} Entity encoded text.
+       */
+      encodeNumeric: function (text, attr) {
+        return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function (chr) {
+          // Multi byte sequence convert it to a single entity
+          if (chr.length > 1) {
+            return '&#' + (((chr.charCodeAt(0) - 0xD800) * 0x400) + (chr.charCodeAt(1) - 0xDC00) + 0x10000) + ';';
+          }
+
+          return baseEntities[chr] || '&#' + chr.charCodeAt(0) + ';';
+        });
+      },
+
+      /**
+       * Encodes the specified string using named entities. The core entities will be encoded
+       * as named ones but all non lower ascii characters will be encoded into named entities.
+       *
+       * @method encodeNamed
+       * @param {String} text Text to encode.
+       * @param {Boolean} attr Optional flag to specify if the text is attribute contents.
+       * @param {Object} entities Optional parameter with entities to use.
+       * @return {String} Entity encoded text.
+       */
+      encodeNamed: function (text, attr, entities) {
+        entities = entities || namedEntities;
+
+        return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function (chr) {
+          return baseEntities[chr] || entities[chr] || chr;
+        });
+      },
+
+      /**
+       * Returns an encode function based on the name(s) and it's optional entities.
+       *
+       * @method getEncodeFunc
+       * @param {String} name Comma separated list of encoders for example named,numeric.
+       * @param {String} entities Optional parameter with entities to use instead of the built in set.
+       * @return {function} Encode function to be used.
+       */
+      getEncodeFunc: function (name, entities) {
+        entities = buildEntitiesLookup(entities) || namedEntities;
+
+        function encodeNamedAndNumeric(text, attr) {
+          return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function (chr) {
+            if (baseEntities[chr] !== undefined) {
+              return baseEntities[chr];
+            }
+
+            if (entities[chr] !== undefined) {
+              return entities[chr];
+            }
+
+            // Convert multi-byte sequences to a single entity.
+            if (chr.length > 1) {
+              return '&#' + (((chr.charCodeAt(0) - 0xD800) * 0x400) + (chr.charCodeAt(1) - 0xDC00) + 0x10000) + ';';
+            }
+
+            return '&#' + chr.charCodeAt(0) + ';';
+          });
+        }
+
+        function encodeCustomNamed(text, attr) {
+          return Entities.encodeNamed(text, attr, entities);
+        }
+
+        // Replace + with , to be compatible with previous TinyMCE versions
+        name = makeMap(name.replace(/\+/g, ','));
+
+        // Named and numeric encoder
+        if (name.named && name.numeric) {
+          return encodeNamedAndNumeric;
+        }
+
+        // Named encoder
+        if (name.named) {
+          // Custom names
+          if (entities) {
+            return encodeCustomNamed;
+          }
+
+          return Entities.encodeNamed;
+        }
+
+        // Numeric
+        if (name.numeric) {
+          return Entities.encodeNumeric;
+        }
+
+        // Raw encoder
+        return Entities.encodeRaw;
+      },
+
+      /**
+       * Decodes the specified string, this will replace entities with raw UTF characters.
+       *
+       * @method decode
+       * @param {String} text Text to entity decode.
+       * @return {String} Entity decoded string.
+       */
+      decode: function (text) {
+        return text.replace(entityRegExp, function (all, numeric) {
+          if (numeric) {
+            if (numeric.charAt(0).toLowerCase() === 'x') {
+              numeric = parseInt(numeric.substr(1), 16);
+            } else {
+              numeric = parseInt(numeric, 10);
+            }
+
+            // Support upper UTF
+            if (numeric > 0xFFFF) {
+              numeric -= 0x10000;
+
+              return String.fromCharCode(0xD800 + (numeric >> 10), 0xDC00 + (numeric & 0x3FF));
+            }
+
+            return asciiMap[numeric] || String.fromCharCode(numeric);
+          }
+
+          return reverseEntities[all] || namedEntities[all] || nativeDecode(all);
+        });
+      }
+    };
+
+    return Entities;
+  }
+);
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * Schema.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -8973,7 +8372,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">       textInlineElementsMap = createLookupTable('text_inline_elements', 'span strong b em i font strike u var cite ' +
</span><span class="cx" style="display: block; padding: 0 10px">         'dfn code mark q sup sub samp');
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      each((settings.special || 'script noscript style textarea').split(' '), function (name) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      each((settings.special || 'script noscript noframes noembed title style textarea xmp').split(' '), function (name) {
</ins><span class="cx" style="display: block; padding: 0 10px">         specialElements[name] = new RegExp('<\/' + name + '[^>]*>', 'gi');
</span><span class="cx" style="display: block; padding: 0 10px">       });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -9597,6 +8996,384 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Styles.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This class is used to parse CSS styles it also compresses styles to reduce the output size.
+ *
+ * @example
+ * var Styles = new tinymce.html.Styles({
+ *    url_converter: function(url) {
+ *       return url;
+ *    }
+ * });
+ *
+ * styles = Styles.parse('border: 1px solid red');
+ * styles.color = 'red';
+ *
+ * console.log(new tinymce.html.StyleSerializer().serialize(styles));
+ *
+ * @class tinymce.html.Styles
+ * @version 3.4
+ */
+define(
+  'tinymce.core.html.Styles',
+  [
+  ],
+  function () {
+    return function (settings, schema) {
+      /*jshint maxlen:255 */
+      /*eslint max-len:0 */
+      var rgbRegExp = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi,
+        urlOrStrRegExp = /(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi,
+        styleRegExp = /\s*([^:]+):\s*([^;]+);?/g,
+        trimRightRegExp = /\s+$/,
+        i, encodingLookup = {}, encodingItems, validStyles, invalidStyles, invisibleChar = '\uFEFF';
+
+      settings = settings || {};
+
+      if (schema) {
+        validStyles = schema.getValidStyles();
+        invalidStyles = schema.getInvalidStyles();
+      }
+
+      encodingItems = ('\\" \\\' \\; \\: ; : ' + invisibleChar).split(' ');
+      for (i = 0; i < encodingItems.length; i++) {
+        encodingLookup[encodingItems[i]] = invisibleChar + i;
+        encodingLookup[invisibleChar + i] = encodingItems[i];
+      }
+
+      function toHex(match, r, g, b) {
+        function hex(val) {
+          val = parseInt(val, 10).toString(16);
+
+          return val.length > 1 ? val : '0' + val; // 0 -> 00
+        }
+
+        return '#' + hex(r) + hex(g) + hex(b);
+      }
+
+      return {
+        /**
+         * Parses the specified RGB color value and returns a hex version of that color.
+         *
+         * @method toHex
+         * @param {String} color RGB string value like rgb(1,2,3)
+         * @return {String} Hex version of that RGB value like #FF00FF.
+         */
+        toHex: function (color) {
+          return color.replace(rgbRegExp, toHex);
+        },
+
+        /**
+         * Parses the specified style value into an object collection. This parser will also
+         * merge and remove any redundant items that browsers might have added. It will also convert non hex
+         * colors to hex values. Urls inside the styles will also be converted to absolute/relative based on settings.
+         *
+         * @method parse
+         * @param {String} css Style value to parse for example: border:1px solid red;.
+         * @return {Object} Object representation of that style like {border: '1px solid red'}
+         */
+        parse: function (css) {
+          var styles = {}, matches, name, value, isEncoded, urlConverter = settings.url_converter;
+          var urlConverterScope = settings.url_converter_scope || this;
+
+          function compress(prefix, suffix, noJoin) {
+            var top, right, bottom, left;
+
+            top = styles[prefix + '-top' + suffix];
+            if (!top) {
+              return;
+            }
+
+            right = styles[prefix + '-right' + suffix];
+            if (!right) {
+              return;
+            }
+
+            bottom = styles[prefix + '-bottom' + suffix];
+            if (!bottom) {
+              return;
+            }
+
+            left = styles[prefix + '-left' + suffix];
+            if (!left) {
+              return;
+            }
+
+            var box = [top, right, bottom, left];
+            i = box.length - 1;
+            while (i--) {
+              if (box[i] !== box[i + 1]) {
+                break;
+              }
+            }
+
+            if (i > -1 && noJoin) {
+              return;
+            }
+
+            styles[prefix + suffix] = i == -1 ? box[0] : box.join(' ');
+            delete styles[prefix + '-top' + suffix];
+            delete styles[prefix + '-right' + suffix];
+            delete styles[prefix + '-bottom' + suffix];
+            delete styles[prefix + '-left' + suffix];
+          }
+
+          /**
+           * Checks if the specific style can be compressed in other words if all border-width are equal.
+           */
+          function canCompress(key) {
+            var value = styles[key], i;
+
+            if (!value) {
+              return;
+            }
+
+            value = value.split(' ');
+            i = value.length;
+            while (i--) {
+              if (value[i] !== value[0]) {
+                return false;
+              }
+            }
+
+            styles[key] = value[0];
+
+            return true;
+          }
+
+          /**
+           * Compresses multiple styles into one style.
+           */
+          function compress2(target, a, b, c) {
+            if (!canCompress(a)) {
+              return;
+            }
+
+            if (!canCompress(b)) {
+              return;
+            }
+
+            if (!canCompress(c)) {
+              return;
+            }
+
+            // Compress
+            styles[target] = styles[a] + ' ' + styles[b] + ' ' + styles[c];
+            delete styles[a];
+            delete styles[b];
+            delete styles[c];
+          }
+
+          // Encodes the specified string by replacing all \" \' ; : with _<num>
+          function encode(str) {
+            isEncoded = true;
+
+            return encodingLookup[str];
+          }
+
+          // Decodes the specified string by replacing all _<num> with it's original value \" \' etc
+          // It will also decode the \" \' if keepSlashes is set to fale or omitted
+          function decode(str, keepSlashes) {
+            if (isEncoded) {
+              str = str.replace(/\uFEFF[0-9]/g, function (str) {
+                return encodingLookup[str];
+              });
+            }
+
+            if (!keepSlashes) {
+              str = str.replace(/\\([\'\";:])/g, "$1");
+            }
+
+            return str;
+          }
+
+          function decodeSingleHexSequence(escSeq) {
+            return String.fromCharCode(parseInt(escSeq.slice(1), 16));
+          }
+
+          function decodeHexSequences(value) {
+            return value.replace(/\\[0-9a-f]+/gi, decodeSingleHexSequence);
+          }
+
+          function processUrl(match, url, url2, url3, str, str2) {
+            str = str || str2;
+
+            if (str) {
+              str = decode(str);
+
+              // Force strings into single quote format
+              return "'" + str.replace(/\'/g, "\\'") + "'";
+            }
+
+            url = decode(url || url2 || url3);
+
+            if (!settings.allow_script_urls) {
+              var scriptUrl = url.replace(/[\s\r\n]+/g, '');
+
+              if (/(java|vb)script:/i.test(scriptUrl)) {
+                return "";
+              }
+
+              if (!settings.allow_svg_data_urls && /^data:image\/svg/i.test(scriptUrl)) {
+                return "";
+              }
+            }
+
+            // Convert the URL to relative/absolute depending on config
+            if (urlConverter) {
+              url = urlConverter.call(urlConverterScope, url, 'style');
+            }
+
+            // Output new URL format
+            return "url('" + url.replace(/\'/g, "\\'") + "')";
+          }
+
+          if (css) {
+            css = css.replace(/[\u0000-\u001F]/g, '');
+
+            // Encode \" \' % and ; and : inside strings so they don't interfere with the style parsing
+            css = css.replace(/\\[\"\';:\uFEFF]/g, encode).replace(/\"[^\"]+\"|\'[^\']+\'/g, function (str) {
+              return str.replace(/[;:]/g, encode);
+            });
+
+            // Parse styles
+            while ((matches = styleRegExp.exec(css))) {
+              styleRegExp.lastIndex = matches.index + matches[0].length;
+              name = matches[1].replace(trimRightRegExp, '').toLowerCase();
+              value = matches[2].replace(trimRightRegExp, '');
+
+              if (name && value) {
+                // Decode escaped sequences like \65 -> e
+                name = decodeHexSequences(name);
+                value = decodeHexSequences(value);
+
+                // Skip properties with double quotes and sequences like \" \' in their names
+                // See 'mXSS Attacks: Attacking well-secured Web-Applications by using innerHTML Mutations'
+                // https://cure53.de/fp170.pdf
+                if (name.indexOf(invisibleChar) !== -1 || name.indexOf('"') !== -1) {
+                  continue;
+                }
+
+                // Don't allow behavior name or expression/comments within the values
+                if (!settings.allow_script_urls && (name == "behavior" || /expression\s*\(|\/\*|\*\//.test(value))) {
+                  continue;
+                }
+
+                // Opera will produce 700 instead of bold in their style values
+                if (name === 'font-weight' && value === '700') {
+                  value = 'bold';
+                } else if (name === 'color' || name === 'background-color') { // Lowercase colors like RED
+                  value = value.toLowerCase();
+                }
+
+                // Convert RGB colors to HEX
+                value = value.replace(rgbRegExp, toHex);
+
+                // Convert URLs and force them into url('value') format
+                value = value.replace(urlOrStrRegExp, processUrl);
+                styles[name] = isEncoded ? decode(value, true) : value;
+              }
+            }
+            // Compress the styles to reduce it's size for example IE will expand styles
+            compress("border", "", true);
+            compress("border", "-width");
+            compress("border", "-color");
+            compress("border", "-style");
+            compress("padding", "");
+            compress("margin", "");
+            compress2('border', 'border-width', 'border-style', 'border-color');
+
+            // Remove pointless border, IE produces these
+            if (styles.border === 'medium none') {
+              delete styles.border;
+            }
+
+            // IE 11 will produce a border-image: none when getting the style attribute from <p style="border: 1px solid red"></p>
+            // So let us assume it shouldn't be there
+            if (styles['border-image'] === 'none') {
+              delete styles['border-image'];
+            }
+          }
+
+          return styles;
+        },
+
+        /**
+         * Serializes the specified style object into a string.
+         *
+         * @method serialize
+         * @param {Object} styles Object to serialize as string for example: {border: '1px solid red'}
+         * @param {String} elementName Optional element name, if specified only the styles that matches the schema will be serialized.
+         * @return {String} String representation of the style object for example: border: 1px solid red.
+         */
+        serialize: function (styles, elementName) {
+          var css = '', name, value;
+
+          function serializeStyles(name) {
+            var styleList, i, l, value;
+
+            styleList = validStyles[name];
+            if (styleList) {
+              for (i = 0, l = styleList.length; i < l; i++) {
+                name = styleList[i];
+                value = styles[name];
+
+                if (value) {
+                  css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
+                }
+              }
+            }
+          }
+
+          function isValid(name, elementName) {
+            var styleMap;
+
+            styleMap = invalidStyles['*'];
+            if (styleMap && styleMap[name]) {
+              return false;
+            }
+
+            styleMap = invalidStyles[elementName];
+            if (styleMap && styleMap[name]) {
+              return false;
+            }
+
+            return true;
+          }
+
+          // Serialize styles according to schema
+          if (elementName && validStyles) {
+            // Serialize global styles and element specific styles
+            serializeStyles('*');
+            serializeStyles(elementName);
+          } else {
+            // Output the styles in the order they are inside the object
+            for (name in styles) {
+              value = styles[name];
+
+              if (value && (!invalidStyles || isValid(name, elementName))) {
+                css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
+              }
+            }
+          }
+
+          return css;
+        }
+      };
+    };
+  }
+);
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * DOMUtils.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -12049,6 +11826,39 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * });
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+define(
+  'ephox.katamari.api.Cell',
+
+  [
+  ],
+
+  function () {
+    var Cell = function (initial) {
+      var value = initial;
+
+      var get = function () {
+        return value;
+      };
+
+      var set = function (v) {
+        value = v;
+      };
+
+      var clone = function () {
+        return Cell(get());
+      };
+
+      return {
+        get: get,
+        set: set,
+        clone: clone
+      };
+    };
+
+    return Cell;
+  }
+);
+
</ins><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px">  * NodeType.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -12172,6 +11982,102 @@
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Fun.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * Functional utility class.
+ *
+ * @private
+ * @class tinymce.util.Fun
+ */
+define(
+  'tinymce.core.util.Fun',
+  [
+  ],
+  function () {
+    var slice = [].slice;
+
+    function constant(value) {
+      return function () {
+        return value;
+      };
+    }
+
+    function negate(predicate) {
+      return function (x) {
+        return !predicate(x);
+      };
+    }
+
+    function compose(f, g) {
+      return function (x) {
+        return f(g(x));
+      };
+    }
+
+    function or() {
+      var args = slice.call(arguments);
+
+      return function (x) {
+        for (var i = 0; i < args.length; i++) {
+          if (args[i](x)) {
+            return true;
+          }
+        }
+
+        return false;
+      };
+    }
+
+    function and() {
+      var args = slice.call(arguments);
+
+      return function (x) {
+        for (var i = 0; i < args.length; i++) {
+          if (!args[i](x)) {
+            return false;
+          }
+        }
+
+        return true;
+      };
+    }
+
+    function curry(fn) {
+      var args = slice.call(arguments);
+
+      if (args.length - 1 >= fn.length) {
+        return fn.apply(this, args.slice(1));
+      }
+
+      return function () {
+        var tempArgs = args.concat([].slice.call(arguments));
+        return curry.apply(this, tempArgs);
+      };
+    }
+
+    function noop() {
+    }
+
+    return {
+      constant: constant,
+      negate: negate,
+      and: and,
+      or: or,
+      curry: curry,
+      compose: compose,
+      noop: noop
+    };
+  }
+);
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * Zwsp.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -12879,13 +12785,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">                     break;
</span><span class="cx" style="display: block; padding: 0 10px">                   }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                  // Found a BR/IMG element that we can place the caret before
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                  // Found a BR/IMG/PRE element that we can place the caret before
</ins><span class="cx" style="display: block; padding: 0 10px">                   if (nonEmptyElementsMap[node.nodeName.toLowerCase()] && !isTableCell(node)) {
</span><span class="cx" style="display: block; padding: 0 10px">                     offset = dom.nodeIndex(node);
</span><span class="cx" style="display: block; padding: 0 10px">                     container = node.parentNode;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                    // Put caret after image when moving the end point
-                    if (node.nodeName == "IMG" && !directionLeft) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                    // Put caret after image and pre tag when moving the end point
+                    if ((node.nodeName === "IMG" || node.nodeName === "PRE") && !directionLeft) {
</ins><span class="cx" style="display: block; padding: 0 10px">                       offset++;
</span><span class="cx" style="display: block; padding: 0 10px">                     }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -13080,7 +12986,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     RangeUtils.getNode = function (container, offset) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (container.nodeType == 1 && container.hasChildNodes()) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (container.nodeType === 1 && container.hasChildNodes()) {
</ins><span class="cx" style="display: block; padding: 0 10px">         if (offset >= container.childNodes.length) {
</span><span class="cx" style="display: block; padding: 0 10px">           offset = container.childNodes.length - 1;
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -13096,3558 +13002,6 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Node.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * This class is a minimalistic implementation of a DOM like node used by the DomParser class.
- *
- * @example
- * var node = new tinymce.html.Node('strong', 1);
- * someRoot.append(node);
- *
- * @class tinymce.html.Node
- * @version 3.4
- */
-define(
-  'tinymce.core.html.Node',
-  [
-  ],
-  function () {
-    var whiteSpaceRegExp = /^[ \t\r\n]*$/;
-    var typeLookup = {
-      '#text': 3,
-      '#comment': 8,
-      '#cdata': 4,
-      '#pi': 7,
-      '#doctype': 10,
-      '#document-fragment': 11
-    };
-
-    // Walks the tree left/right
-    function walk(node, rootNode, prev) {
-      var sibling, parent, startName = prev ? 'lastChild' : 'firstChild', siblingName = prev ? 'prev' : 'next';
-
-      // Walk into nodes if it has a start
-      if (node[startName]) {
-        return node[startName];
-      }
-
-      // Return the sibling if it has one
-      if (node !== rootNode) {
-        sibling = node[siblingName];
-
-        if (sibling) {
-          return sibling;
-        }
-
-        // Walk up the parents to look for siblings
-        for (parent = node.parent; parent && parent !== rootNode; parent = parent.parent) {
-          sibling = parent[siblingName];
-
-          if (sibling) {
-            return sibling;
-          }
-        }
-      }
-    }
-
-    /**
-     * Constructs a new Node instance.
-     *
-     * @constructor
-     * @method Node
-     * @param {String} name Name of the node type.
-     * @param {Number} type Numeric type representing the node.
-     */
-    function Node(name, type) {
-      this.name = name;
-      this.type = type;
-
-      if (type === 1) {
-        this.attributes = [];
-        this.attributes.map = {};
-      }
-    }
-
-    Node.prototype = {
-      /**
-       * Replaces the current node with the specified one.
-       *
-       * @example
-       * someNode.replace(someNewNode);
-       *
-       * @method replace
-       * @param {tinymce.html.Node} node Node to replace the current node with.
-       * @return {tinymce.html.Node} The old node that got replaced.
-       */
-      replace: function (node) {
-        var self = this;
-
-        if (node.parent) {
-          node.remove();
-        }
-
-        self.insert(node, self);
-        self.remove();
-
-        return self;
-      },
-
-      /**
-       * Gets/sets or removes an attribute by name.
-       *
-       * @example
-       * someNode.attr("name", "value"); // Sets an attribute
-       * console.log(someNode.attr("name")); // Gets an attribute
-       * someNode.attr("name", null); // Removes an attribute
-       *
-       * @method attr
-       * @param {String} name Attribute name to set or get.
-       * @param {String} value Optional value to set.
-       * @return {String/tinymce.html.Node} String or undefined on a get operation or the current node on a set operation.
-       */
-      attr: function (name, value) {
-        var self = this, attrs, i, undef;
-
-        if (typeof name !== "string") {
-          for (i in name) {
-            self.attr(i, name[i]);
-          }
-
-          return self;
-        }
-
-        if ((attrs = self.attributes)) {
-          if (value !== undef) {
-            // Remove attribute
-            if (value === null) {
-              if (name in attrs.map) {
-                delete attrs.map[name];
-
-                i = attrs.length;
-                while (i--) {
-                  if (attrs[i].name === name) {
-                    attrs = attrs.splice(i, 1);
-                    return self;
-                  }
-                }
-              }
-
-              return self;
-            }
-
-            // Set attribute
-            if (name in attrs.map) {
-              // Set attribute
-              i = attrs.length;
-              while (i--) {
-                if (attrs[i].name === name) {
-                  attrs[i].value = value;
-                  break;
-                }
-              }
-            } else {
-              attrs.push({ name: name, value: value });
-            }
-
-            attrs.map[name] = value;
-
-            return self;
-          }
-
-          return attrs.map[name];
-        }
-      },
-
-      /**
-       * Does a shallow clones the node into a new node. It will also exclude id attributes since
-       * there should only be one id per document.
-       *
-       * @example
-       * var clonedNode = node.clone();
-       *
-       * @method clone
-       * @return {tinymce.html.Node} New copy of the original node.
-       */
-      clone: function () {
-        var self = this, clone = new Node(self.name, self.type), i, l, selfAttrs, selfAttr, cloneAttrs;
-
-        // Clone element attributes
-        if ((selfAttrs = self.attributes)) {
-          cloneAttrs = [];
-          cloneAttrs.map = {};
-
-          for (i = 0, l = selfAttrs.length; i < l; i++) {
-            selfAttr = selfAttrs[i];
-
-            // Clone everything except id
-            if (selfAttr.name !== 'id') {
-              cloneAttrs[cloneAttrs.length] = { name: selfAttr.name, value: selfAttr.value };
-              cloneAttrs.map[selfAttr.name] = selfAttr.value;
-            }
-          }
-
-          clone.attributes = cloneAttrs;
-        }
-
-        clone.value = self.value;
-        clone.shortEnded = self.shortEnded;
-
-        return clone;
-      },
-
-      /**
-       * Wraps the node in in another node.
-       *
-       * @example
-       * node.wrap(wrapperNode);
-       *
-       * @method wrap
-       */
-      wrap: function (wrapper) {
-        var self = this;
-
-        self.parent.insert(wrapper, self);
-        wrapper.append(self);
-
-        return self;
-      },
-
-      /**
-       * Unwraps the node in other words it removes the node but keeps the children.
-       *
-       * @example
-       * node.unwrap();
-       *
-       * @method unwrap
-       */
-      unwrap: function () {
-        var self = this, node, next;
-
-        for (node = self.firstChild; node;) {
-          next = node.next;
-          self.insert(node, self, true);
-          node = next;
-        }
-
-        self.remove();
-      },
-
-      /**
-       * Removes the node from it's parent.
-       *
-       * @example
-       * node.remove();
-       *
-       * @method remove
-       * @return {tinymce.html.Node} Current node that got removed.
-       */
-      remove: function () {
-        var self = this, parent = self.parent, next = self.next, prev = self.prev;
-
-        if (parent) {
-          if (parent.firstChild === self) {
-            parent.firstChild = next;
-
-            if (next) {
-              next.prev = null;
-            }
-          } else {
-            prev.next = next;
-          }
-
-          if (parent.lastChild === self) {
-            parent.lastChild = prev;
-
-            if (prev) {
-              prev.next = null;
-            }
-          } else {
-            next.prev = prev;
-          }
-
-          self.parent = self.next = self.prev = null;
-        }
-
-        return self;
-      },
-
-      /**
-       * Appends a new node as a child of the current node.
-       *
-       * @example
-       * node.append(someNode);
-       *
-       * @method append
-       * @param {tinymce.html.Node} node Node to append as a child of the current one.
-       * @return {tinymce.html.Node} The node that got appended.
-       */
-      append: function (node) {
-        var self = this, last;
-
-        if (node.parent) {
-          node.remove();
-        }
-
-        last = self.lastChild;
-        if (last) {
-          last.next = node;
-          node.prev = last;
-          self.lastChild = node;
-        } else {
-          self.lastChild = self.firstChild = node;
-        }
-
-        node.parent = self;
-
-        return node;
-      },
-
-      /**
-       * Inserts a node at a specific position as a child of the current node.
-       *
-       * @example
-       * parentNode.insert(newChildNode, oldChildNode);
-       *
-       * @method insert
-       * @param {tinymce.html.Node} node Node to insert as a child of the current node.
-       * @param {tinymce.html.Node} refNode Reference node to set node before/after.
-       * @param {Boolean} before Optional state to insert the node before the reference node.
-       * @return {tinymce.html.Node} The node that got inserted.
-       */
-      insert: function (node, refNode, before) {
-        var parent;
-
-        if (node.parent) {
-          node.remove();
-        }
-
-        parent = refNode.parent || this;
-
-        if (before) {
-          if (refNode === parent.firstChild) {
-            parent.firstChild = node;
-          } else {
-            refNode.prev.next = node;
-          }
-
-          node.prev = refNode.prev;
-          node.next = refNode;
-          refNode.prev = node;
-        } else {
-          if (refNode === parent.lastChild) {
-            parent.lastChild = node;
-          } else {
-            refNode.next.prev = node;
-          }
-
-          node.next = refNode.next;
-          node.prev = refNode;
-          refNode.next = node;
-        }
-
-        node.parent = parent;
-
-        return node;
-      },
-
-      /**
-       * Get all children by name.
-       *
-       * @method getAll
-       * @param {String} name Name of the child nodes to collect.
-       * @return {Array} Array with child nodes matchin the specified name.
-       */
-      getAll: function (name) {
-        var self = this, node, collection = [];
-
-        for (node = self.firstChild; node; node = walk(node, self)) {
-          if (node.name === name) {
-            collection.push(node);
-          }
-        }
-
-        return collection;
-      },
-
-      /**
-       * Removes all children of the current node.
-       *
-       * @method empty
-       * @return {tinymce.html.Node} The current node that got cleared.
-       */
-      empty: function () {
-        var self = this, nodes, i, node;
-
-        // Remove all children
-        if (self.firstChild) {
-          nodes = [];
-
-          // Collect the children
-          for (node = self.firstChild; node; node = walk(node, self)) {
-            nodes.push(node);
-          }
-
-          // Remove the children
-          i = nodes.length;
-          while (i--) {
-            node = nodes[i];
-            node.parent = node.firstChild = node.lastChild = node.next = node.prev = null;
-          }
-        }
-
-        self.firstChild = self.lastChild = null;
-
-        return self;
-      },
-
-      /**
-       * Returns true/false if the node is to be considered empty or not.
-       *
-       * @example
-       * node.isEmpty({img: true});
-       * @method isEmpty
-       * @param {Object} elements Name/value object with elements that are automatically treated as non empty elements.
-       * @param {Object} whitespace Name/value object with elements that are automatically treated whitespace preservables.
-       * @return {Boolean} true/false if the node is empty or not.
-       */
-      isEmpty: function (elements, whitespace) {
-        var self = this, node = self.firstChild, i, name;
-
-        whitespace = whitespace || {};
-
-        if (node) {
-          do {
-            if (node.type === 1) {
-              // Ignore bogus elements
-              if (node.attributes.map['data-mce-bogus']) {
-                continue;
-              }
-
-              // Keep empty elements like <img />
-              if (elements[node.name]) {
-                return false;
-              }
-
-              // Keep bookmark nodes and name attribute like <a name="1"></a>
-              i = node.attributes.length;
-              while (i--) {
-                name = node.attributes[i].name;
-                if (name === "name" || name.indexOf('data-mce-bookmark') === 0) {
-                  return false;
-                }
-              }
-            }
-
-            // Keep comments
-            if (node.type === 8) {
-              return false;
-            }
-
-            // Keep non whitespace text nodes
-            if (node.type === 3 && !whiteSpaceRegExp.test(node.value)) {
-              return false;
-            }
-
-            // Keep whitespace preserve elements
-            if (node.type === 3 && node.parent && whitespace[node.parent.name] && whiteSpaceRegExp.test(node.value)) {
-              return false;
-            }
-          } while ((node = walk(node, self)));
-        }
-
-        return true;
-      },
-
-      /**
-       * Walks to the next or previous node and returns that node or null if it wasn't found.
-       *
-       * @method walk
-       * @param {Boolean} prev Optional previous node state defaults to false.
-       * @return {tinymce.html.Node} Node that is next to or previous of the current node.
-       */
-      walk: function (prev) {
-        return walk(this, null, prev);
-      }
-    };
-
-    /**
-     * Creates a node of a specific type.
-     *
-     * @static
-     * @method create
-     * @param {String} name Name of the node type to create for example "b" or "#text".
-     * @param {Object} attrs Name/value collection of attributes that will be applied to elements.
-     */
-    Node.create = function (name, attrs) {
-      var node, attrName;
-
-      // Create node
-      node = new Node(name, typeLookup[name] || 1);
-
-      // Add attributes if needed
-      if (attrs) {
-        for (attrName in attrs) {
-          node.attr(attrName, attrs[attrName]);
-        }
-      }
-
-      return node;
-    };
-
-    return Node;
-  }
-);
-
-/**
- * SaxParser.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/*eslint max-depth:[2, 9] */
-
-/**
- * This class parses HTML code using pure JavaScript and executes various events for each item it finds. It will
- * always execute the events in the right order for tag soup code like <b><p></b></p>. It will also remove elements
- * and attributes that doesn't fit the schema if the validate setting is enabled.
- *
- * @example
- * var parser = new tinymce.html.SaxParser({
- *     validate: true,
- *
- *     comment: function(text) {
- *         console.log('Comment:', text);
- *     },
- *
- *     cdata: function(text) {
- *         console.log('CDATA:', text);
- *     },
- *
- *     text: function(text, raw) {
- *         console.log('Text:', text, 'Raw:', raw);
- *     },
- *
- *     start: function(name, attrs, empty) {
- *         console.log('Start:', name, attrs, empty);
- *     },
- *
- *     end: function(name) {
- *         console.log('End:', name);
- *     },
- *
- *     pi: function(name, text) {
- *         console.log('PI:', name, text);
- *     },
- *
- *     doctype: function(text) {
- *         console.log('DocType:', text);
- *     }
- * }, schema);
- * @class tinymce.html.SaxParser
- * @version 3.4
- */
-define(
-  'tinymce.core.html.SaxParser',
-  [
-    "tinymce.core.html.Schema",
-    "tinymce.core.html.Entities",
-    "tinymce.core.util.Tools"
-  ],
-  function (Schema, Entities, Tools) {
-    var each = Tools.each;
-
-    var isValidPrefixAttrName = function (name) {
-      return name.indexOf('data-') === 0 || name.indexOf('aria-') === 0;
-    };
-
-    /**
-     * Returns the index of the end tag for a specific start tag. This can be
-     * used to skip all children of a parent element from being processed.
-     *
-     * @private
-     * @method findEndTag
-     * @param {tinymce.html.Schema} schema Schema instance to use to match short ended elements.
-     * @param {String} html HTML string to find the end tag in.
-     * @param {Number} startIndex Indext to start searching at should be after the start tag.
-     * @return {Number} Index of the end tag.
-     */
-    function findEndTag(schema, html, startIndex) {
-      var count = 1, index, matches, tokenRegExp, shortEndedElements;
-
-      shortEndedElements = schema.getShortEndedElements();
-      tokenRegExp = /<([!?\/])?([A-Za-z0-9\-_\:\.]+)((?:\s+[^"\'>]+(?:(?:"[^"]*")|(?:\'[^\']*\')|[^>]*))*|\/|\s+)>/g;
-      tokenRegExp.lastIndex = index = startIndex;
-
-      while ((matches = tokenRegExp.exec(html))) {
-        index = tokenRegExp.lastIndex;
-
-        if (matches[1] === '/') { // End element
-          count--;
-        } else if (!matches[1]) { // Start element
-          if (matches[2] in shortEndedElements) {
-            continue;
-          }
-
-          count++;
-        }
-
-        if (count === 0) {
-          break;
-        }
-      }
-
-      return index;
-    }
-
-    /**
-     * Constructs a new SaxParser instance.
-     *
-     * @constructor
-     * @method SaxParser
-     * @param {Object} settings Name/value collection of settings. comment, cdata, text, start and end are callbacks.
-     * @param {tinymce.html.Schema} schema HTML Schema class to use when parsing.
-     */
-    function SaxParser(settings, schema) {
-      var self = this;
-
-      function noop() { }
-
-      settings = settings || {};
-      self.schema = schema = schema || new Schema();
-
-      if (settings.fix_self_closing !== false) {
-        settings.fix_self_closing = true;
-      }
-
-      // Add handler functions from settings and setup default handlers
-      each('comment cdata text start end pi doctype'.split(' '), function (name) {
-        if (name) {
-          self[name] = settings[name] || noop;
-        }
-      });
-
-      /**
-       * Parses the specified HTML string and executes the callbacks for each item it finds.
-       *
-       * @example
-       * new SaxParser({...}).parse('<b>text</b>');
-       * @method parse
-       * @param {String} html Html string to sax parse.
-       */
-      self.parse = function (html) {
-        var self = this, matches, index = 0, value, endRegExp, stack = [], attrList, i, text, name;
-        var isInternalElement, removeInternalElements, shortEndedElements, fillAttrsMap, isShortEnded;
-        var validate, elementRule, isValidElement, attr, attribsValue, validAttributesMap, validAttributePatterns;
-        var attributesRequired, attributesDefault, attributesForced, processHtml;
-        var anyAttributesRequired, selfClosing, tokenRegExp, attrRegExp, specialElements, attrValue, idCount = 0;
-        var decode = Entities.decode, fixSelfClosing, filteredUrlAttrs = Tools.makeMap('src,href,data,background,formaction,poster');
-        var scriptUriRegExp = /((java|vb)script|mhtml):/i, dataUriRegExp = /^data:/i;
-
-        function processEndTag(name) {
-          var pos, i;
-
-          // Find position of parent of the same type
-          pos = stack.length;
-          while (pos--) {
-            if (stack[pos].name === name) {
-              break;
-            }
-          }
-
-          // Found parent
-          if (pos >= 0) {
-            // Close all the open elements
-            for (i = stack.length - 1; i >= pos; i--) {
-              name = stack[i];
-
-              if (name.valid) {
-                self.end(name.name);
-              }
-            }
-
-            // Remove the open elements from the stack
-            stack.length = pos;
-          }
-        }
-
-        function parseAttribute(match, name, value, val2, val3) {
-          var attrRule, i, trimRegExp = /[\s\u0000-\u001F]+/g;
-
-          name = name.toLowerCase();
-          value = name in fillAttrsMap ? name : decode(value || val2 || val3 || ''); // Handle boolean attribute than value attribute
-
-          // Validate name and value pass through all data- attributes
-          if (validate && !isInternalElement && isValidPrefixAttrName(name) === false) {
-            attrRule = validAttributesMap[name];
-
-            // Find rule by pattern matching
-            if (!attrRule && validAttributePatterns) {
-              i = validAttributePatterns.length;
-              while (i--) {
-                attrRule = validAttributePatterns[i];
-                if (attrRule.pattern.test(name)) {
-                  break;
-                }
-              }
-
-              // No rule matched
-              if (i === -1) {
-                attrRule = null;
-              }
-            }
-
-            // No attribute rule found
-            if (!attrRule) {
-              return;
-            }
-
-            // Validate value
-            if (attrRule.validValues && !(value in attrRule.validValues)) {
-              return;
-            }
-          }
-
-          // Block any javascript: urls or non image data uris
-          if (filteredUrlAttrs[name] && !settings.allow_script_urls) {
-            var uri = value.replace(trimRegExp, '');
-
-            try {
-              // Might throw malformed URI sequence
-              uri = decodeURIComponent(uri);
-            } catch (ex) {
-              // Fallback to non UTF-8 decoder
-              uri = unescape(uri);
-            }
-
-            if (scriptUriRegExp.test(uri)) {
-              return;
-            }
-
-            if (!settings.allow_html_data_urls && dataUriRegExp.test(uri) && !/^data:image\//i.test(uri)) {
-              return;
-            }
-          }
-
-          // Add attribute to list and map
-          attrList.map[name] = value;
-          attrList.push({
-            name: name,
-            value: value
-          });
-        }
-
-        // Precompile RegExps and map objects
-        tokenRegExp = new RegExp('<(?:' +
-          '(?:!--([\\w\\W]*?)-->)|' + // Comment
-          '(?:!\\[CDATA\\[([\\w\\W]*?)\\]\\]>)|' + // CDATA
-          '(?:!DOCTYPE([\\w\\W]*?)>)|' + // DOCTYPE
-          '(?:\\?([^\\s\\/<>]+) ?([\\w\\W]*?)[?/]>)|' + // PI
-          '(?:\\/([A-Za-z][A-Za-z0-9\\-_\\:\\.]*)>)|' + // End element
-          '(?:([A-Za-z][A-Za-z0-9\\-_\\:\\.]*)((?:\\s+[^"\'>]+(?:(?:"[^"]*")|(?:\'[^\']*\')|[^>]*))*|\\/|\\s+)>)' + // Start element
-          ')', 'g');
-
-        attrRegExp = /([\w:\-]+)(?:\s*=\s*(?:(?:\"((?:[^\"])*)\")|(?:\'((?:[^\'])*)\')|([^>\s]+)))?/g;
-
-        // Setup lookup tables for empty elements and boolean attributes
-        shortEndedElements = schema.getShortEndedElements();
-        selfClosing = settings.self_closing_elements || schema.getSelfClosingElements();
-        fillAttrsMap = schema.getBoolAttrs();
-        validate = settings.validate;
-        removeInternalElements = settings.remove_internals;
-        fixSelfClosing = settings.fix_self_closing;
-        specialElements = schema.getSpecialElements();
-        processHtml = html + '>';
-
-        while ((matches = tokenRegExp.exec(processHtml))) { // Adds and extra '>' to keep regexps from doing catastrofic backtracking on malformed html
-          // Text
-          if (index < matches.index) {
-            self.text(decode(html.substr(index, matches.index - index)));
-          }
-
-          if ((value = matches[6])) { // End element
-            value = value.toLowerCase();
-
-            // IE will add a ":" in front of elements it doesn't understand like custom elements or HTML5 elements
-            if (value.charAt(0) === ':') {
-              value = value.substr(1);
-            }
-
-            processEndTag(value);
-          } else if ((value = matches[7])) { // Start element
-            // Did we consume the extra character then treat it as text
-            // This handles the case with html like this: "text a<b text"
-            if (matches.index + matches[0].length > html.length) {
-              self.text(decode(html.substr(matches.index)));
-              index = matches.index + matches[0].length;
-              continue;
-            }
-
-            value = value.toLowerCase();
-
-            // IE will add a ":" in front of elements it doesn't understand like custom elements or HTML5 elements
-            if (value.charAt(0) === ':') {
-              value = value.substr(1);
-            }
-
-            isShortEnded = value in shortEndedElements;
-
-            // Is self closing tag for example an <li> after an open <li>
-            if (fixSelfClosing && selfClosing[value] && stack.length > 0 && stack[stack.length - 1].name === value) {
-              processEndTag(value);
-            }
-
-            // Validate element
-            if (!validate || (elementRule = schema.getElementRule(value))) {
-              isValidElement = true;
-
-              // Grab attributes map and patters when validation is enabled
-              if (validate) {
-                validAttributesMap = elementRule.attributes;
-                validAttributePatterns = elementRule.attributePatterns;
-              }
-
-              // Parse attributes
-              if ((attribsValue = matches[8])) {
-                isInternalElement = attribsValue.indexOf('data-mce-type') !== -1; // Check if the element is an internal element
-
-                // If the element has internal attributes then remove it if we are told to do so
-                if (isInternalElement && removeInternalElements) {
-                  isValidElement = false;
-                }
-
-                attrList = [];
-                attrList.map = {};
-
-                attribsValue.replace(attrRegExp, parseAttribute);
-              } else {
-                attrList = [];
-                attrList.map = {};
-              }
-
-              // Process attributes if validation is enabled
-              if (validate && !isInternalElement) {
-                attributesRequired = elementRule.attributesRequired;
-                attributesDefault = elementRule.attributesDefault;
-                attributesForced = elementRule.attributesForced;
-                anyAttributesRequired = elementRule.removeEmptyAttrs;
-
-                // Check if any attribute exists
-                if (anyAttributesRequired && !attrList.length) {
-                  isValidElement = false;
-                }
-
-                // Handle forced attributes
-                if (attributesForced) {
-                  i = attributesForced.length;
-                  while (i--) {
-                    attr = attributesForced[i];
-                    name = attr.name;
-                    attrValue = attr.value;
-
-                    if (attrValue === '{$uid}') {
-                      attrValue = 'mce_' + idCount++;
-                    }
-
-                    attrList.map[name] = attrValue;
-                    attrList.push({ name: name, value: attrValue });
-                  }
-                }
-
-                // Handle default attributes
-                if (attributesDefault) {
-                  i = attributesDefault.length;
-                  while (i--) {
-                    attr = attributesDefault[i];
-                    name = attr.name;
-
-                    if (!(name in attrList.map)) {
-                      attrValue = attr.value;
-
-                      if (attrValue === '{$uid}') {
-                        attrValue = 'mce_' + idCount++;
-                      }
-
-                      attrList.map[name] = attrValue;
-                      attrList.push({ name: name, value: attrValue });
-                    }
-                  }
-                }
-
-                // Handle required attributes
-                if (attributesRequired) {
-                  i = attributesRequired.length;
-                  while (i--) {
-                    if (attributesRequired[i] in attrList.map) {
-                      break;
-                    }
-                  }
-
-                  // None of the required attributes where found
-                  if (i === -1) {
-                    isValidElement = false;
-                  }
-                }
-
-                // Invalidate element if it's marked as bogus
-                if ((attr = attrList.map['data-mce-bogus'])) {
-                  if (attr === 'all') {
-                    index = findEndTag(schema, html, tokenRegExp.lastIndex);
-                    tokenRegExp.lastIndex = index;
-                    continue;
-                  }
-
-                  isValidElement = false;
-                }
-              }
-
-              if (isValidElement) {
-                self.start(value, attrList, isShortEnded);
-              }
-            } else {
-              isValidElement = false;
-            }
-
-            // Treat script, noscript and style a bit different since they may include code that looks like elements
-            if ((endRegExp = specialElements[value])) {
-              endRegExp.lastIndex = index = matches.index + matches[0].length;
-
-              if ((matches = endRegExp.exec(html))) {
-                if (isValidElement) {
-                  text = html.substr(index, matches.index - index);
-                }
-
-                index = matches.index + matches[0].length;
-              } else {
-                text = html.substr(index);
-                index = html.length;
-              }
-
-              if (isValidElement) {
-                if (text.length > 0) {
-                  self.text(text, true);
-                }
-
-                self.end(value);
-              }
-
-              tokenRegExp.lastIndex = index;
-              continue;
-            }
-
-            // Push value on to stack
-            if (!isShortEnded) {
-              if (!attribsValue || attribsValue.indexOf('/') != attribsValue.length - 1) {
-                stack.push({ name: value, valid: isValidElement });
-              } else if (isValidElement) {
-                self.end(value);
-              }
-            }
-          } else if ((value = matches[1])) { // Comment
-            // Padd comment value to avoid browsers from parsing invalid comments as HTML
-            if (value.charAt(0) === '>') {
-              value = ' ' + value;
-            }
-
-            if (!settings.allow_conditional_comments && value.substr(0, 3).toLowerCase() === '[if') {
-              value = ' ' + value;
-            }
-
-            self.comment(value);
-          } else if ((value = matches[2])) { // CDATA
-            self.cdata(value);
-          } else if ((value = matches[3])) { // DOCTYPE
-            self.doctype(value);
-          } else if ((value = matches[4])) { // PI
-            self.pi(value, matches[5]);
-          }
-
-          index = matches.index + matches[0].length;
-        }
-
-        // Text
-        if (index < html.length) {
-          self.text(decode(html.substr(index)));
-        }
-
-        // Close any open elements
-        for (i = stack.length - 1; i >= 0; i--) {
-          value = stack[i];
-
-          if (value.valid) {
-            self.end(value.name);
-          }
-        }
-      };
-    }
-
-    SaxParser.findEndTag = findEndTag;
-
-    return SaxParser;
-  }
-);
-/**
- * DomParser.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * This class parses HTML code into a DOM like structure of nodes it will remove redundant whitespace and make
- * sure that the node tree is valid according to the specified schema.
- * So for example: <p>a<p>b</p>c</p> will become <p>a</p><p>b</p><p>c</p>
- *
- * @example
- * var parser = new tinymce.html.DomParser({validate: true}, schema);
- * var rootNode = parser.parse('<h1>content</h1>');
- *
- * @class tinymce.html.DomParser
- * @version 3.4
- */
-define(
-  'tinymce.core.html.DomParser',
-  [
-    "tinymce.core.html.Node",
-    "tinymce.core.html.Schema",
-    "tinymce.core.html.SaxParser",
-    "tinymce.core.util.Tools"
-  ],
-  function (Node, Schema, SaxParser, Tools) {
-    var makeMap = Tools.makeMap, each = Tools.each, explode = Tools.explode, extend = Tools.extend;
-
-    var paddEmptyNode = function (settings, node) {
-      if (settings.padd_empty_with_br) {
-        node.empty().append(new Node('br', '1')).shortEnded = true;
-      } else {
-        node.empty().append(new Node('#text', '3')).value = '\u00a0';
-      }
-    };
-
-    var hasOnlyChild = function (node, name) {
-      return node && node.firstChild === node.lastChild && node.firstChild.name === name;
-    };
-
-    /**
-     * Constructs a new DomParser instance.
-     *
-     * @constructor
-     * @method DomParser
-     * @param {Object} settings Name/value collection of settings. comment, cdata, text, start and end are callbacks.
-     * @param {tinymce.html.Schema} schema HTML Schema class to use when parsing.
-     */
-    return function (settings, schema) {
-      var self = this, nodeFilters = {}, attributeFilters = [], matchedNodes = {}, matchedAttributes = {};
-
-      settings = settings || {};
-      settings.validate = "validate" in settings ? settings.validate : true;
-      settings.root_name = settings.root_name || 'body';
-      self.schema = schema = schema || new Schema();
-
-      function fixInvalidChildren(nodes) {
-        var ni, node, parent, parents, newParent, currentNode, tempNode, childNode, i;
-        var nonEmptyElements, whitespaceElements, nonSplitableElements, textBlockElements, specialElements, sibling, nextNode;
-
-        nonSplitableElements = makeMap('tr,td,th,tbody,thead,tfoot,table');
-        nonEmptyElements = schema.getNonEmptyElements();
-        whitespaceElements = schema.getWhiteSpaceElements();
-        textBlockElements = schema.getTextBlockElements();
-        specialElements = schema.getSpecialElements();
-
-        for (ni = 0; ni < nodes.length; ni++) {
-          node = nodes[ni];
-
-          // Already removed or fixed
-          if (!node.parent || node.fixed) {
-            continue;
-          }
-
-          // If the invalid element is a text block and the text block is within a parent LI element
-          // Then unwrap the first text block and convert other sibling text blocks to LI elements similar to Word/Open Office
-          if (textBlockElements[node.name] && node.parent.name == 'li') {
-            // Move sibling text blocks after LI element
-            sibling = node.next;
-            while (sibling) {
-              if (textBlockElements[sibling.name]) {
-                sibling.name = 'li';
-                sibling.fixed = true;
-                node.parent.insert(sibling, node.parent);
-              } else {
-                break;
-              }
-
-              sibling = sibling.next;
-            }
-
-            // Unwrap current text block
-            node.unwrap(node);
-            continue;
-          }
-
-          // Get list of all parent nodes until we find a valid parent to stick the child into
-          parents = [node];
-          for (parent = node.parent; parent && !schema.isValidChild(parent.name, node.name) &&
-            !nonSplitableElements[parent.name]; parent = parent.parent) {
-            parents.push(parent);
-          }
-
-          // Found a suitable parent
-          if (parent && parents.length > 1) {
-            // Reverse the array since it makes looping easier
-            parents.reverse();
-
-            // Clone the related parent and insert that after the moved node
-            newParent = currentNode = self.filterNode(parents[0].clone());
-
-            // Start cloning and moving children on the left side of the target node
-            for (i = 0; i < parents.length - 1; i++) {
-              if (schema.isValidChild(currentNode.name, parents[i].name)) {
-                tempNode = self.filterNode(parents[i].clone());
-                currentNode.append(tempNode);
-              } else {
-                tempNode = currentNode;
-              }
-
-              for (childNode = parents[i].firstChild; childNode && childNode != parents[i + 1];) {
-                nextNode = childNode.next;
-                tempNode.append(childNode);
-                childNode = nextNode;
-              }
-
-              currentNode = tempNode;
-            }
-
-            if (!newParent.isEmpty(nonEmptyElements, whitespaceElements)) {
-              parent.insert(newParent, parents[0], true);
-              parent.insert(node, newParent);
-            } else {
-              parent.insert(node, parents[0], true);
-            }
-
-            // Check if the element is empty by looking through it's contents and special treatment for <p><br /></p>
-            parent = parents[0];
-            if (parent.isEmpty(nonEmptyElements, whitespaceElements) || hasOnlyChild(parent, 'br')) {
-              parent.empty().remove();
-            }
-          } else if (node.parent) {
-            // If it's an LI try to find a UL/OL for it or wrap it
-            if (node.name === 'li') {
-              sibling = node.prev;
-              if (sibling && (sibling.name === 'ul' || sibling.name === 'ul')) {
-                sibling.append(node);
-                continue;
-              }
-
-              sibling = node.next;
-              if (sibling && (sibling.name === 'ul' || sibling.name === 'ul')) {
-                sibling.insert(node, sibling.firstChild, true);
-                continue;
-              }
-
-              node.wrap(self.filterNode(new Node('ul', 1)));
-              continue;
-            }
-
-            // Try wrapping the element in a DIV
-            if (schema.isValidChild(node.parent.name, 'div') && schema.isValidChild('div', node.name)) {
-              node.wrap(self.filterNode(new Node('div', 1)));
-            } else {
-              // We failed wrapping it, then remove or unwrap it
-              if (specialElements[node.name]) {
-                node.empty().remove();
-              } else {
-                node.unwrap();
-              }
-            }
-          }
-        }
-      }
-
-      /**
-       * Runs the specified node though the element and attributes filters.
-       *
-       * @method filterNode
-       * @param {tinymce.html.Node} Node the node to run filters on.
-       * @return {tinymce.html.Node} The passed in node.
-       */
-      self.filterNode = function (node) {
-        var i, name, list;
-
-        // Run element filters
-        if (name in nodeFilters) {
-          list = matchedNodes[name];
-
-          if (list) {
-            list.push(node);
-          } else {
-            matchedNodes[name] = [node];
-          }
-        }
-
-        // Run attribute filters
-        i = attributeFilters.length;
-        while (i--) {
-          name = attributeFilters[i].name;
-
-          if (name in node.attributes.map) {
-            list = matchedAttributes[name];
-
-            if (list) {
-              list.push(node);
-            } else {
-              matchedAttributes[name] = [node];
-            }
-          }
-        }
-
-        return node;
-      };
-
-      /**
-       * Adds a node filter function to the parser, the parser will collect the specified nodes by name
-       * and then execute the callback ones it has finished parsing the document.
-       *
-       * @example
-       * parser.addNodeFilter('p,h1', function(nodes, name) {
-       *  for (var i = 0; i < nodes.length; i++) {
-       *   console.log(nodes[i].name);
-       *  }
-       * });
-       * @method addNodeFilter
-       * @method {String} name Comma separated list of nodes to collect.
-       * @param {function} callback Callback function to execute once it has collected nodes.
-       */
-      self.addNodeFilter = function (name, callback) {
-        each(explode(name), function (name) {
-          var list = nodeFilters[name];
-
-          if (!list) {
-            nodeFilters[name] = list = [];
-          }
-
-          list.push(callback);
-        });
-      };
-
-      /**
-       * Adds a attribute filter function to the parser, the parser will collect nodes that has the specified attributes
-       * and then execute the callback ones it has finished parsing the document.
-       *
-       * @example
-       * parser.addAttributeFilter('src,href', function(nodes, name) {
-       *  for (var i = 0; i < nodes.length; i++) {
-       *   console.log(nodes[i].name);
-       *  }
-       * });
-       * @method addAttributeFilter
-       * @method {String} name Comma separated list of nodes to collect.
-       * @param {function} callback Callback function to execute once it has collected nodes.
-       */
-      self.addAttributeFilter = function (name, callback) {
-        each(explode(name), function (name) {
-          var i;
-
-          for (i = 0; i < attributeFilters.length; i++) {
-            if (attributeFilters[i].name === name) {
-              attributeFilters[i].callbacks.push(callback);
-              return;
-            }
-          }
-
-          attributeFilters.push({ name: name, callbacks: [callback] });
-        });
-      };
-
-      /**
-       * Parses the specified HTML string into a DOM like node tree and returns the result.
-       *
-       * @example
-       * var rootNode = new DomParser({...}).parse('<b>text</b>');
-       * @method parse
-       * @param {String} html Html string to sax parse.
-       * @param {Object} args Optional args object that gets passed to all filter functions.
-       * @return {tinymce.html.Node} Root node containing the tree.
-       */
-      self.parse = function (html, args) {
-        var parser, rootNode, node, nodes, i, l, fi, fl, list, name, validate;
-        var blockElements, startWhiteSpaceRegExp, invalidChildren = [], isInWhiteSpacePreservedElement;
-        var endWhiteSpaceRegExp, allWhiteSpaceRegExp, isAllWhiteSpaceRegExp, whiteSpaceElements;
-        var children, nonEmptyElements, rootBlockName;
-
-        args = args || {};
-        matchedNodes = {};
-        matchedAttributes = {};
-        blockElements = extend(makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements());
-        nonEmptyElements = schema.getNonEmptyElements();
-        children = schema.children;
-        validate = settings.validate;
-        rootBlockName = "forced_root_block" in args ? args.forced_root_block : settings.forced_root_block;
-
-        whiteSpaceElements = schema.getWhiteSpaceElements();
-        startWhiteSpaceRegExp = /^[ \t\r\n]+/;
-        endWhiteSpaceRegExp = /[ \t\r\n]+$/;
-        allWhiteSpaceRegExp = /[ \t\r\n]+/g;
-        isAllWhiteSpaceRegExp = /^[ \t\r\n]+$/;
-
-        function addRootBlocks() {
-          var node = rootNode.firstChild, next, rootBlockNode;
-
-          // Removes whitespace at beginning and end of block so:
-          // <p> x </p> -> <p>x</p>
-          function trim(rootBlockNode) {
-            if (rootBlockNode) {
-              node = rootBlockNode.firstChild;
-              if (node && node.type == 3) {
-                node.value = node.value.replace(startWhiteSpaceRegExp, '');
-              }
-
-              node = rootBlockNode.lastChild;
-              if (node && node.type == 3) {
-                node.value = node.value.replace(endWhiteSpaceRegExp, '');
-              }
-            }
-          }
-
-          // Check if rootBlock is valid within rootNode for example if P is valid in H1 if H1 is the contentEditabe root
-          if (!schema.isValidChild(rootNode.name, rootBlockName.toLowerCase())) {
-            return;
-          }
-
-          while (node) {
-            next = node.next;
-
-            if (node.type == 3 || (node.type == 1 && node.name !== 'p' &&
-              !blockElements[node.name] && !node.attr('data-mce-type'))) {
-              if (!rootBlockNode) {
-                // Create a new root block element
-                rootBlockNode = createNode(rootBlockName, 1);
-                rootBlockNode.attr(settings.forced_root_block_attrs);
-                rootNode.insert(rootBlockNode, node);
-                rootBlockNode.append(node);
-              } else {
-                rootBlockNode.append(node);
-              }
-            } else {
-              trim(rootBlockNode);
-              rootBlockNode = null;
-            }
-
-            node = next;
-          }
-
-          trim(rootBlockNode);
-        }
-
-        function createNode(name, type) {
-          var node = new Node(name, type), list;
-
-          if (name in nodeFilters) {
-            list = matchedNodes[name];
-
-            if (list) {
-              list.push(node);
-            } else {
-              matchedNodes[name] = [node];
-            }
-          }
-
-          return node;
-        }
-
-        function removeWhitespaceBefore(node) {
-          var textNode, textNodeNext, textVal, sibling, blockElements = schema.getBlockElements();
-
-          for (textNode = node.prev; textNode && textNode.type === 3;) {
-            textVal = textNode.value.replace(endWhiteSpaceRegExp, '');
-
-            // Found a text node with non whitespace then trim that and break
-            if (textVal.length > 0) {
-              textNode.value = textVal;
-              return;
-            }
-
-            textNodeNext = textNode.next;
-
-            // Fix for bug #7543 where bogus nodes would produce empty
-            // text nodes and these would be removed if a nested list was before it
-            if (textNodeNext) {
-              if (textNodeNext.type == 3 && textNodeNext.value.length) {
-                textNode = textNode.prev;
-                continue;
-              }
-
-              if (!blockElements[textNodeNext.name] && textNodeNext.name != 'script' && textNodeNext.name != 'style') {
-                textNode = textNode.prev;
-                continue;
-              }
-            }
-
-            sibling = textNode.prev;
-            textNode.remove();
-            textNode = sibling;
-          }
-        }
-
-        function cloneAndExcludeBlocks(input) {
-          var name, output = {};
-
-          for (name in input) {
-            if (name !== 'li' && name != 'p') {
-              output[name] = input[name];
-            }
-          }
-
-          return output;
-        }
-
-        parser = new SaxParser({
-          validate: validate,
-          allow_script_urls: settings.allow_script_urls,
-          allow_conditional_comments: settings.allow_conditional_comments,
-
-          // Exclude P and LI from DOM parsing since it's treated better by the DOM parser
-          self_closing_elements: cloneAndExcludeBlocks(schema.getSelfClosingElements()),
-
-          cdata: function (text) {
-            node.append(createNode('#cdata', 4)).value = text;
-          },
-
-          text: function (text, raw) {
-            var textNode;
-
-            // Trim all redundant whitespace on non white space elements
-            if (!isInWhiteSpacePreservedElement) {
-              text = text.replace(allWhiteSpaceRegExp, ' ');
-
-              if (node.lastChild && blockElements[node.lastChild.name]) {
-                text = text.replace(startWhiteSpaceRegExp, '');
-              }
-            }
-
-            // Do we need to create the node
-            if (text.length !== 0) {
-              textNode = createNode('#text', 3);
-              textNode.raw = !!raw;
-              node.append(textNode).value = text;
-            }
-          },
-
-          comment: function (text) {
-            node.append(createNode('#comment', 8)).value = text;
-          },
-
-          pi: function (name, text) {
-            node.append(createNode(name, 7)).value = text;
-            removeWhitespaceBefore(node);
-          },
-
-          doctype: function (text) {
-            var newNode;
-
-            newNode = node.append(createNode('#doctype', 10));
-            newNode.value = text;
-            removeWhitespaceBefore(node);
-          },
-
-          start: function (name, attrs, empty) {
-            var newNode, attrFiltersLen, elementRule, attrName, parent;
-
-            elementRule = validate ? schema.getElementRule(name) : {};
-            if (elementRule) {
-              newNode = createNode(elementRule.outputName || name, 1);
-              newNode.attributes = attrs;
-              newNode.shortEnded = empty;
-
-              node.append(newNode);
-
-              // Check if node is valid child of the parent node is the child is
-              // unknown we don't collect it since it's probably a custom element
-              parent = children[node.name];
-              if (parent && children[newNode.name] && !parent[newNode.name]) {
-                invalidChildren.push(newNode);
-              }
-
-              attrFiltersLen = attributeFilters.length;
-              while (attrFiltersLen--) {
-                attrName = attributeFilters[attrFiltersLen].name;
-
-                if (attrName in attrs.map) {
-                  list = matchedAttributes[attrName];
-
-                  if (list) {
-                    list.push(newNode);
-                  } else {
-                    matchedAttributes[attrName] = [newNode];
-                  }
-                }
-              }
-
-              // Trim whitespace before block
-              if (blockElements[name]) {
-                removeWhitespaceBefore(newNode);
-              }
-
-              // Change current node if the element wasn't empty i.e not <br /> or <img />
-              if (!empty) {
-                node = newNode;
-              }
-
-              // Check if we are inside a whitespace preserved element
-              if (!isInWhiteSpacePreservedElement && whiteSpaceElements[name]) {
-                isInWhiteSpacePreservedElement = true;
-              }
-            }
-          },
-
-          end: function (name) {
-            var textNode, elementRule, text, sibling, tempNode;
-
-            elementRule = validate ? schema.getElementRule(name) : {};
-            if (elementRule) {
-              if (blockElements[name]) {
-                if (!isInWhiteSpacePreservedElement) {
-                  // Trim whitespace of the first node in a block
-                  textNode = node.firstChild;
-                  if (textNode && textNode.type === 3) {
-                    text = textNode.value.replace(startWhiteSpaceRegExp, '');
-
-                    // Any characters left after trim or should we remove it
-                    if (text.length > 0) {
-                      textNode.value = text;
-                      textNode = textNode.next;
-                    } else {
-                      sibling = textNode.next;
-                      textNode.remove();
-                      textNode = sibling;
-
-                      // Remove any pure whitespace siblings
-                      while (textNode && textNode.type === 3) {
-                        text = textNode.value;
-                        sibling = textNode.next;
-
-                        if (text.length === 0 || isAllWhiteSpaceRegExp.test(text)) {
-                          textNode.remove();
-                          textNode = sibling;
-                        }
-
-                        textNode = sibling;
-                      }
-                    }
-                  }
-
-                  // Trim whitespace of the last node in a block
-                  textNode = node.lastChild;
-                  if (textNode && textNode.type === 3) {
-                    text = textNode.value.replace(endWhiteSpaceRegExp, '');
-
-                    // Any characters left after trim or should we remove it
-                    if (text.length > 0) {
-                      textNode.value = text;
-                      textNode = textNode.prev;
-                    } else {
-                      sibling = textNode.prev;
-                      textNode.remove();
-                      textNode = sibling;
-
-                      // Remove any pure whitespace siblings
-                      while (textNode && textNode.type === 3) {
-                        text = textNode.value;
-                        sibling = textNode.prev;
-
-                        if (text.length === 0 || isAllWhiteSpaceRegExp.test(text)) {
-                          textNode.remove();
-                          textNode = sibling;
-                        }
-
-                        textNode = sibling;
-                      }
-                    }
-                  }
-                }
-
-                // Trim start white space
-                // Removed due to: #5424
-                /*textNode = node.prev;
-                if (textNode && textNode.type === 3) {
-                  text = textNode.value.replace(startWhiteSpaceRegExp, '');
-
-                  if (text.length > 0)
-                    textNode.value = text;
-                  else
-                    textNode.remove();
-                }*/
-              }
-
-              // Check if we exited a whitespace preserved element
-              if (isInWhiteSpacePreservedElement && whiteSpaceElements[name]) {
-                isInWhiteSpacePreservedElement = false;
-              }
-
-              // Handle empty nodes
-              if (elementRule.removeEmpty || elementRule.paddEmpty) {
-                if (node.isEmpty(nonEmptyElements, whiteSpaceElements)) {
-                  if (elementRule.paddEmpty) {
-                    paddEmptyNode(settings, node);
-                  } else {
-                    // Leave nodes that have a name like <a name="name">
-                    if (!node.attributes.map.name && !node.attributes.map.id) {
-                      tempNode = node.parent;
-
-                      if (blockElements[node.name]) {
-                        node.empty().remove();
-                      } else {
-                        node.unwrap();
-                      }
-
-                      node = tempNode;
-                      return;
-                    }
-                  }
-                }
-              }
-
-              node = node.parent;
-            }
-          }
-        }, schema);
-
-        rootNode = node = new Node(args.context || settings.root_name, 11);
-
-        parser.parse(html);
-
-        // Fix invalid children or report invalid children in a contextual parsing
-        if (validate && invalidChildren.length) {
-          if (!args.context) {
-            fixInvalidChildren(invalidChildren);
-          } else {
-            args.invalid = true;
-          }
-        }
-
-        // Wrap nodes in the root into block elements if the root is body
-        if (rootBlockName && (rootNode.name == 'body' || args.isRootContent)) {
-          addRootBlocks();
-        }
-
-        // Run filters only when the contents is valid
-        if (!args.invalid) {
-          // Run node filters
-          for (name in matchedNodes) {
-            list = nodeFilters[name];
-            nodes = matchedNodes[name];
-
-            // Remove already removed children
-            fi = nodes.length;
-            while (fi--) {
-              if (!nodes[fi].parent) {
-                nodes.splice(fi, 1);
-              }
-            }
-
-            for (i = 0, l = list.length; i < l; i++) {
-              list[i](nodes, name, args);
-            }
-          }
-
-          // Run attribute filters
-          for (i = 0, l = attributeFilters.length; i < l; i++) {
-            list = attributeFilters[i];
-
-            if (list.name in matchedAttributes) {
-              nodes = matchedAttributes[list.name];
-
-              // Remove already removed children
-              fi = nodes.length;
-              while (fi--) {
-                if (!nodes[fi].parent) {
-                  nodes.splice(fi, 1);
-                }
-              }
-
-              for (fi = 0, fl = list.callbacks.length; fi < fl; fi++) {
-                list.callbacks[fi](nodes, list.name, args);
-              }
-            }
-          }
-        }
-
-        return rootNode;
-      };
-
-      // Remove <br> at end of block elements Gecko and WebKit injects BR elements to
-      // make it possible to place the caret inside empty blocks. This logic tries to remove
-      // these elements and keep br elements that where intended to be there intact
-      if (settings.remove_trailing_brs) {
-        self.addNodeFilter('br', function (nodes) {
-          var i, l = nodes.length, node, blockElements = extend({}, schema.getBlockElements());
-          var nonEmptyElements = schema.getNonEmptyElements(), parent, lastParent, prev, prevName;
-          var whiteSpaceElements = schema.getNonEmptyElements();
-          var elementRule, textNode;
-
-          // Remove brs from body element as well
-          blockElements.body = 1;
-
-          // Must loop forwards since it will otherwise remove all brs in <p>a<br><br><br></p>
-          for (i = 0; i < l; i++) {
-            node = nodes[i];
-            parent = node.parent;
-
-            if (blockElements[node.parent.name] && node === parent.lastChild) {
-              // Loop all nodes to the left of the current node and check for other BR elements
-              // excluding bookmarks since they are invisible
-              prev = node.prev;
-              while (prev) {
-                prevName = prev.name;
-
-                // Ignore bookmarks
-                if (prevName !== "span" || prev.attr('data-mce-type') !== 'bookmark') {
-                  // Found a non BR element
-                  if (prevName !== "br") {
-                    break;
-                  }
-
-                  // Found another br it's a <br><br> structure then don't remove anything
-                  if (prevName === 'br') {
-                    node = null;
-                    break;
-                  }
-                }
-
-                prev = prev.prev;
-              }
-
-              if (node) {
-                node.remove();
-
-                // Is the parent to be considered empty after we removed the BR
-                if (parent.isEmpty(nonEmptyElements, whiteSpaceElements)) {
-                  elementRule = schema.getElementRule(parent.name);
-
-                  // Remove or padd the element depending on schema rule
-                  if (elementRule) {
-                    if (elementRule.removeEmpty) {
-                      parent.remove();
-                    } else if (elementRule.paddEmpty) {
-                      paddEmptyNode(settings, parent);
-                    }
-                  }
-                }
-              }
-            } else {
-              // Replaces BR elements inside inline elements like <p><b><i><br></i></b></p>
-              // so they become <p><b><i>&nbsp;</i></b></p>
-              lastParent = node;
-              while (parent && parent.firstChild === lastParent && parent.lastChild === lastParent) {
-                lastParent = parent;
-
-                if (blockElements[parent.name]) {
-                  break;
-                }
-
-                parent = parent.parent;
-              }
-
-              if (lastParent === parent && settings.padd_empty_with_br !== true) {
-                textNode = new Node('#text', 3);
-                textNode.value = '\u00a0';
-                node.replace(textNode);
-              }
-            }
-          }
-        });
-      }
-
-      if (!settings.allow_unsafe_link_target) {
-        self.addAttributeFilter('href', function (nodes) {
-          var i = nodes.length, node;
-
-          var appendRel = function (rel) {
-            var parts = rel.split(' ').filter(function (p) {
-              return p.length > 0;
-            });
-            return parts.concat(['noopener']).join(' ');
-          };
-
-          var addNoOpener = function (rel) {
-            var newRel = rel ? Tools.trim(rel) : '';
-            if (!/\b(noopener)\b/g.test(newRel)) {
-              return appendRel(newRel);
-            } else {
-              return newRel;
-            }
-          };
-
-          while (i--) {
-            node = nodes[i];
-            if (node.name === 'a' && node.attr('target') === '_blank') {
-              node.attr('rel', addNoOpener(node.attr('rel')));
-            }
-          }
-        });
-      }
-
-      // Force anchor names closed, unless the setting "allow_html_in_named_anchor" is explicitly included.
-      if (!settings.allow_html_in_named_anchor) {
-        self.addAttributeFilter('id,name', function (nodes) {
-          var i = nodes.length, sibling, prevSibling, parent, node;
-
-          while (i--) {
-            node = nodes[i];
-            if (node.name === 'a' && node.firstChild && !node.attr('href')) {
-              parent = node.parent;
-
-              // Move children after current node
-              sibling = node.lastChild;
-              do {
-                prevSibling = sibling.prev;
-                parent.insert(sibling, node);
-                sibling = prevSibling;
-              } while (sibling);
-            }
-          }
-        });
-      }
-
-      if (settings.fix_list_elements) {
-        self.addNodeFilter('ul,ol', function (nodes) {
-          var i = nodes.length, node, parentNode;
-
-          while (i--) {
-            node = nodes[i];
-            parentNode = node.parent;
-
-            if (parentNode.name === 'ul' || parentNode.name === 'ol') {
-              if (node.prev && node.prev.name === 'li') {
-                node.prev.append(node);
-              } else {
-                var li = new Node('li', 1);
-                li.attr('style', 'list-style-type: none');
-                node.wrap(li);
-              }
-            }
-          }
-        });
-      }
-
-      if (settings.validate && schema.getValidClasses()) {
-        self.addAttributeFilter('class', function (nodes) {
-          var i = nodes.length, node, classList, ci, className, classValue;
-          var validClasses = schema.getValidClasses(), validClassesMap, valid;
-
-          while (i--) {
-            node = nodes[i];
-            classList = node.attr('class').split(' ');
-            classValue = '';
-
-            for (ci = 0; ci < classList.length; ci++) {
-              className = classList[ci];
-              valid = false;
-
-              validClassesMap = validClasses['*'];
-              if (validClassesMap && validClassesMap[className]) {
-                valid = true;
-              }
-
-              validClassesMap = validClasses[node.name];
-              if (!valid && validClassesMap && validClassesMap[className]) {
-                valid = true;
-              }
-
-              if (valid) {
-                if (classValue) {
-                  classValue += ' ';
-                }
-
-                classValue += className;
-              }
-            }
-
-            if (!classValue.length) {
-              classValue = null;
-            }
-
-            node.attr('class', classValue);
-          }
-        });
-      }
-    };
-  }
-);
-
-/**
- * Writer.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * This class is used to write HTML tags out it can be used with the Serializer or the SaxParser.
- *
- * @class tinymce.html.Writer
- * @example
- * var writer = new tinymce.html.Writer({indent: true});
- * var parser = new tinymce.html.SaxParser(writer).parse('<p><br></p>');
- * console.log(writer.getContent());
- *
- * @class tinymce.html.Writer
- * @version 3.4
- */
-define(
-  'tinymce.core.html.Writer',
-  [
-    "tinymce.core.html.Entities",
-    "tinymce.core.util.Tools"
-  ],
-  function (Entities, Tools) {
-    var makeMap = Tools.makeMap;
-
-    /**
-     * Constructs a new Writer instance.
-     *
-     * @constructor
-     * @method Writer
-     * @param {Object} settings Name/value settings object.
-     */
-    return function (settings) {
-      var html = [], indent, indentBefore, indentAfter, encode, htmlOutput;
-
-      settings = settings || {};
-      indent = settings.indent;
-      indentBefore = makeMap(settings.indent_before || '');
-      indentAfter = makeMap(settings.indent_after || '');
-      encode = Entities.getEncodeFunc(settings.entity_encoding || 'raw', settings.entities);
-      htmlOutput = settings.element_format == "html";
-
-      return {
-        /**
-         * Writes the a start element such as <p id="a">.
-         *
-         * @method start
-         * @param {String} name Name of the element.
-         * @param {Array} attrs Optional attribute array or undefined if it hasn't any.
-         * @param {Boolean} empty Optional empty state if the tag should end like <br />.
-         */
-        start: function (name, attrs, empty) {
-          var i, l, attr, value;
-
-          if (indent && indentBefore[name] && html.length > 0) {
-            value = html[html.length - 1];
-
-            if (value.length > 0 && value !== '\n') {
-              html.push('\n');
-            }
-          }
-
-          html.push('<', name);
-
-          if (attrs) {
-            for (i = 0, l = attrs.length; i < l; i++) {
-              attr = attrs[i];
-              html.push(' ', attr.name, '="', encode(attr.value, true), '"');
-            }
-          }
-
-          if (!empty || htmlOutput) {
-            html[html.length] = '>';
-          } else {
-            html[html.length] = ' />';
-          }
-
-          if (empty && indent && indentAfter[name] && html.length > 0) {
-            value = html[html.length - 1];
-
-            if (value.length > 0 && value !== '\n') {
-              html.push('\n');
-            }
-          }
-        },
-
-        /**
-         * Writes the a end element such as </p>.
-         *
-         * @method end
-         * @param {String} name Name of the element.
-         */
-        end: function (name) {
-          var value;
-
-          /*if (indent && indentBefore[name] && html.length > 0) {
-            value = html[html.length - 1];
-
-            if (value.length > 0 && value !== '\n')
-              html.push('\n');
-          }*/
-
-          html.push('</', name, '>');
-
-          if (indent && indentAfter[name] && html.length > 0) {
-            value = html[html.length - 1];
-
-            if (value.length > 0 && value !== '\n') {
-              html.push('\n');
-            }
-          }
-        },
-
-        /**
-         * Writes a text node.
-         *
-         * @method text
-         * @param {String} text String to write out.
-         * @param {Boolean} raw Optional raw state if true the contents wont get encoded.
-         */
-        text: function (text, raw) {
-          if (text.length > 0) {
-            html[html.length] = raw ? text : encode(text);
-          }
-        },
-
-        /**
-         * Writes a cdata node such as <![CDATA[data]]>.
-         *
-         * @method cdata
-         * @param {String} text String to write out inside the cdata.
-         */
-        cdata: function (text) {
-          html.push('<![CDATA[', text, ']]>');
-        },
-
-        /**
-         * Writes a comment node such as <!-- Comment -->.
-         *
-         * @method cdata
-         * @param {String} text String to write out inside the comment.
-         */
-        comment: function (text) {
-          html.push('<!--', text, '-->');
-        },
-
-        /**
-         * Writes a PI node such as <?xml attr="value" ?>.
-         *
-         * @method pi
-         * @param {String} name Name of the pi.
-         * @param {String} text String to write out inside the pi.
-         */
-        pi: function (name, text) {
-          if (text) {
-            html.push('<?', name, ' ', encode(text), '?>');
-          } else {
-            html.push('<?', name, '?>');
-          }
-
-          if (indent) {
-            html.push('\n');
-          }
-        },
-
-        /**
-         * Writes a doctype node such as <!DOCTYPE data>.
-         *
-         * @method doctype
-         * @param {String} text String to write out inside the doctype.
-         */
-        doctype: function (text) {
-          html.push('<!DOCTYPE', text, '>', indent ? '\n' : '');
-        },
-
-        /**
-         * Resets the internal buffer if one wants to reuse the writer.
-         *
-         * @method reset
-         */
-        reset: function () {
-          html.length = 0;
-        },
-
-        /**
-         * Returns the contents that got serialized.
-         *
-         * @method getContent
-         * @return {String} HTML contents that got written down.
-         */
-        getContent: function () {
-          return html.join('').replace(/\n$/, '');
-        }
-      };
-    };
-  }
-);
-/**
- * Serializer.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * This class is used to serialize down the DOM tree into a string using a Writer instance.
- *
- *
- * @example
- * new tinymce.html.Serializer().serialize(new tinymce.html.DomParser().parse('<p>text</p>'));
- * @class tinymce.html.Serializer
- * @version 3.4
- */
-define(
-  'tinymce.core.html.Serializer',
-  [
-    "tinymce.core.html.Writer",
-    "tinymce.core.html.Schema"
-  ],
-  function (Writer, Schema) {
-    /**
-     * Constructs a new Serializer instance.
-     *
-     * @constructor
-     * @method Serializer
-     * @param {Object} settings Name/value settings object.
-     * @param {tinymce.html.Schema} schema Schema instance to use.
-     */
-    return function (settings, schema) {
-      var self = this, writer = new Writer(settings);
-
-      settings = settings || {};
-      settings.validate = "validate" in settings ? settings.validate : true;
-
-      self.schema = schema = schema || new Schema();
-      self.writer = writer;
-
-      /**
-       * Serializes the specified node into a string.
-       *
-       * @example
-       * new tinymce.html.Serializer().serialize(new tinymce.html.DomParser().parse('<p>text</p>'));
-       * @method serialize
-       * @param {tinymce.html.Node} node Node instance to serialize.
-       * @return {String} String with HTML based on DOM tree.
-       */
-      self.serialize = function (node) {
-        var handlers, validate;
-
-        validate = settings.validate;
-
-        handlers = {
-          // #text
-          3: function (node) {
-            writer.text(node.value, node.raw);
-          },
-
-          // #comment
-          8: function (node) {
-            writer.comment(node.value);
-          },
-
-          // Processing instruction
-          7: function (node) {
-            writer.pi(node.name, node.value);
-          },
-
-          // Doctype
-          10: function (node) {
-            writer.doctype(node.value);
-          },
-
-          // CDATA
-          4: function (node) {
-            writer.cdata(node.value);
-          },
-
-          // Document fragment
-          11: function (node) {
-            if ((node = node.firstChild)) {
-              do {
-                walk(node);
-              } while ((node = node.next));
-            }
-          }
-        };
-
-        writer.reset();
-
-        function walk(node) {
-          var handler = handlers[node.type], name, isEmpty, attrs, attrName, attrValue, sortedAttrs, i, l, elementRule;
-
-          if (!handler) {
-            name = node.name;
-            isEmpty = node.shortEnded;
-            attrs = node.attributes;
-
-            // Sort attributes
-            if (validate && attrs && attrs.length > 1) {
-              sortedAttrs = [];
-              sortedAttrs.map = {};
-
-              elementRule = schema.getElementRule(node.name);
-              if (elementRule) {
-                for (i = 0, l = elementRule.attributesOrder.length; i < l; i++) {
-                  attrName = elementRule.attributesOrder[i];
-
-                  if (attrName in attrs.map) {
-                    attrValue = attrs.map[attrName];
-                    sortedAttrs.map[attrName] = attrValue;
-                    sortedAttrs.push({ name: attrName, value: attrValue });
-                  }
-                }
-
-                for (i = 0, l = attrs.length; i < l; i++) {
-                  attrName = attrs[i].name;
-
-                  if (!(attrName in sortedAttrs.map)) {
-                    attrValue = attrs.map[attrName];
-                    sortedAttrs.map[attrName] = attrValue;
-                    sortedAttrs.push({ name: attrName, value: attrValue });
-                  }
-                }
-
-                attrs = sortedAttrs;
-              }
-            }
-
-            writer.start(node.name, attrs, isEmpty);
-
-            if (!isEmpty) {
-              if ((node = node.firstChild)) {
-                do {
-                  walk(node);
-                } while ((node = node.next));
-              }
-
-              writer.end(name);
-            }
-          } else {
-            handler(node);
-          }
-        }
-
-        // Serialize element and treat all non elements as fragments
-        if (node.type == 1 && !settings.inner) {
-          walk(node);
-        } else {
-          handlers[11](node);
-        }
-
-        return writer.getContent();
-      };
-    };
-  }
-);
-
-/**
- * Serializer.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * This class is used to serialize DOM trees into a string. Consult the TinyMCE Wiki API for
- * more details and examples on how to use this class.
- *
- * @class tinymce.dom.Serializer
- */
-define(
-  'tinymce.core.dom.Serializer',
-  [
-    "tinymce.core.dom.DOMUtils",
-    "tinymce.core.html.DomParser",
-    "tinymce.core.html.SaxParser",
-    "tinymce.core.html.Entities",
-    "tinymce.core.html.Serializer",
-    "tinymce.core.html.Node",
-    "tinymce.core.html.Schema",
-    "tinymce.core.Env",
-    "tinymce.core.util.Tools",
-    "tinymce.core.text.Zwsp"
-  ],
-  function (DOMUtils, DomParser, SaxParser, Entities, Serializer, Node, Schema, Env, Tools, Zwsp) {
-    var each = Tools.each, trim = Tools.trim;
-    var DOM = DOMUtils.DOM;
-
-    /**
-     * IE 11 has a fantastic bug where it will produce two trailing BR elements to iframe bodies when
-     * the iframe is hidden by display: none on a parent container. The DOM is actually out of sync
-     * with innerHTML in this case. It's like IE adds shadow DOM BR elements that appears on innerHTML
-     * but not as the lastChild of the body. So this fix simply removes the last two
-     * BR elements at the end of the document.
-     *
-     * Example of what happens: <body>text</body> becomes <body>text<br><br></body>
-     */
-    function trimTrailingBr(rootNode) {
-      var brNode1, brNode2;
-
-      function isBr(node) {
-        return node && node.name === 'br';
-      }
-
-      brNode1 = rootNode.lastChild;
-      if (isBr(brNode1)) {
-        brNode2 = brNode1.prev;
-
-        if (isBr(brNode2)) {
-          brNode1.remove();
-          brNode2.remove();
-        }
-      }
-    }
-
-    /**
-     * Constructs a new DOM serializer class.
-     *
-     * @constructor
-     * @method Serializer
-     * @param {Object} settings Serializer settings object.
-     * @param {tinymce.Editor} editor Optional editor to bind events to and get schema/dom from.
-     */
-    return function (settings, editor) {
-      var dom, schema, htmlParser, tempAttrs = ["data-mce-selected"];
-
-      if (editor) {
-        dom = editor.dom;
-        schema = editor.schema;
-      }
-
-      function trimHtml(html) {
-        var trimContentRegExp = new RegExp([
-          '<span[^>]+data-mce-bogus[^>]+>[\u200B\uFEFF]+<\\/span>', // Trim bogus spans like caret containers
-          '\\s?(' + tempAttrs.join('|') + ')="[^"]+"' // Trim temporaty data-mce prefixed attributes like data-mce-selected
-        ].join('|'), 'gi');
-
-        html = Zwsp.trim(html.replace(trimContentRegExp, ''));
-
-        return html;
-      }
-
-      function trimContent(html) {
-        var content = html;
-        var bogusAllRegExp = /<(\w+) [^>]*data-mce-bogus="all"[^>]*>/g;
-        var endTagIndex, index, matchLength, matches, shortEndedElements, schema = editor.schema;
-
-        content = trimHtml(content);
-        shortEndedElements = schema.getShortEndedElements();
-
-        // Remove all bogus elements marked with "all"
-        while ((matches = bogusAllRegExp.exec(content))) {
-          index = bogusAllRegExp.lastIndex;
-          matchLength = matches[0].length;
-
-          if (shortEndedElements[matches[1]]) {
-            endTagIndex = index;
-          } else {
-            endTagIndex = SaxParser.findEndTag(schema, content, index);
-          }
-
-          content = content.substring(0, index - matchLength) + content.substring(endTagIndex);
-          bogusAllRegExp.lastIndex = index - matchLength;
-        }
-
-        return content;
-      }
-
-      /**
-       * Returns a trimmed version of the editor contents to be used for the undo level. This
-       * will remove any data-mce-bogus="all" marked elements since these are used for UI it will also
-       * remove the data-mce-selected attributes used for selection of objects and caret containers.
-       * It will keep all data-mce-bogus="1" elements since these can be used to place the caret etc and will
-       * be removed by the serialization logic when you save.
-       *
-       * @private
-       * @return {String} HTML contents of the editor excluding some internal bogus elements.
-       */
-      function getTrimmedContent() {
-        return trimContent(editor.getBody().innerHTML);
-      }
-
-      function addTempAttr(name) {
-        if (Tools.inArray(tempAttrs, name) === -1) {
-          htmlParser.addAttributeFilter(name, function (nodes, name) {
-            var i = nodes.length;
-
-            while (i--) {
-              nodes[i].attr(name, null);
-            }
-          });
-
-          tempAttrs.push(name);
-        }
-      }
-
-      // Default DOM and Schema if they are undefined
-      dom = dom || DOM;
-      schema = schema || new Schema(settings);
-      settings.entity_encoding = settings.entity_encoding || 'named';
-      settings.remove_trailing_brs = "remove_trailing_brs" in settings ? settings.remove_trailing_brs : true;
-
-      htmlParser = new DomParser(settings, schema);
-
-      // Convert tabindex back to elements when serializing contents
-      htmlParser.addAttributeFilter('data-mce-tabindex', function (nodes, name) {
-        var i = nodes.length, node;
-
-        while (i--) {
-          node = nodes[i];
-          node.attr('tabindex', node.attributes.map['data-mce-tabindex']);
-          node.attr(name, null);
-        }
-      });
-
-      // Convert move data-mce-src, data-mce-href and data-mce-style into nodes or process them if needed
-      htmlParser.addAttributeFilter('src,href,style', function (nodes, name) {
-        var i = nodes.length, node, value, internalName = 'data-mce-' + name;
-        var urlConverter = settings.url_converter, urlConverterScope = settings.url_converter_scope, undef;
-
-        while (i--) {
-          node = nodes[i];
-
-          value = node.attributes.map[internalName];
-          if (value !== undef) {
-            // Set external name to internal value and remove internal
-            node.attr(name, value.length > 0 ? value : null);
-            node.attr(internalName, null);
-          } else {
-            // No internal attribute found then convert the value we have in the DOM
-            value = node.attributes.map[name];
-
-            if (name === "style") {
-              value = dom.serializeStyle(dom.parseStyle(value), node.name);
-            } else if (urlConverter) {
-              value = urlConverter.call(urlConverterScope, value, name, node.name);
-            }
-
-            node.attr(name, value.length > 0 ? value : null);
-          }
-        }
-      });
-
-      // Remove internal classes mceItem<..> or mceSelected
-      htmlParser.addAttributeFilter('class', function (nodes) {
-        var i = nodes.length, node, value;
-
-        while (i--) {
-          node = nodes[i];
-          value = node.attr('class');
-
-          if (value) {
-            value = node.attr('class').replace(/(?:^|\s)mce-item-\w+(?!\S)/g, '');
-            node.attr('class', value.length > 0 ? value : null);
-          }
-        }
-      });
-
-      // Remove bookmark elements
-      htmlParser.addAttributeFilter('data-mce-type', function (nodes, name, args) {
-        var i = nodes.length, node;
-
-        while (i--) {
-          node = nodes[i];
-
-          if (node.attributes.map['data-mce-type'] === 'bookmark' && !args.cleanup) {
-            node.remove();
-          }
-        }
-      });
-
-      htmlParser.addNodeFilter('noscript', function (nodes) {
-        var i = nodes.length, node;
-
-        while (i--) {
-          node = nodes[i].firstChild;
-
-          if (node) {
-            node.value = Entities.decode(node.value);
-          }
-        }
-      });
-
-      // Force script into CDATA sections and remove the mce- prefix also add comments around styles
-      htmlParser.addNodeFilter('script,style', function (nodes, name) {
-        var i = nodes.length, node, value, type;
-
-        function trim(value) {
-          /*jshint maxlen:255 */
-          /*eslint max-len:0 */
-          return value.replace(/(<!--\[CDATA\[|\]\]-->)/g, '\n')
-            .replace(/^[\r\n]*|[\r\n]*$/g, '')
-            .replace(/^\s*((<!--)?(\s*\/\/)?\s*<!\[CDATA\[|(<!--\s*)?\/\*\s*<!\[CDATA\[\s*\*\/|(\/\/)?\s*<!--|\/\*\s*<!--\s*\*\/)\s*[\r\n]*/gi, '')
-            .replace(/\s*(\/\*\s*\]\]>\s*\*\/(-->)?|\s*\/\/\s*\]\]>(-->)?|\/\/\s*(-->)?|\]\]>|\/\*\s*-->\s*\*\/|\s*-->\s*)\s*$/g, '');
-        }
-
-        while (i--) {
-          node = nodes[i];
-          value = node.firstChild ? node.firstChild.value : '';
-
-          if (name === "script") {
-            // Remove mce- prefix from script elements and remove default type since the user specified
-            // a script element without type attribute
-            type = node.attr('type');
-            if (type) {
-              node.attr('type', type == 'mce-no/type' ? null : type.replace(/^mce\-/, ''));
-            }
-
-            if (value.length > 0) {
-              node.firstChild.value = '// <![CDATA[\n' + trim(value) + '\n// ]]>';
-            }
-          } else {
-            if (value.length > 0) {
-              node.firstChild.value = '<!--\n' + trim(value) + '\n-->';
-            }
-          }
-        }
-      });
-
-      // Convert comments to cdata and handle protected comments
-      htmlParser.addNodeFilter('#comment', function (nodes) {
-        var i = nodes.length, node;
-
-        while (i--) {
-          node = nodes[i];
-
-          if (node.value.indexOf('[CDATA[') === 0) {
-            node.name = '#cdata';
-            node.type = 4;
-            node.value = node.value.replace(/^\[CDATA\[|\]\]$/g, '');
-          } else if (node.value.indexOf('mce:protected ') === 0) {
-            node.name = "#text";
-            node.type = 3;
-            node.raw = true;
-            node.value = unescape(node.value).substr(14);
-          }
-        }
-      });
-
-      htmlParser.addNodeFilter('xml:namespace,input', function (nodes, name) {
-        var i = nodes.length, node;
-
-        while (i--) {
-          node = nodes[i];
-          if (node.type === 7) {
-            node.remove();
-          } else if (node.type === 1) {
-            if (name === "input" && !("type" in node.attributes.map)) {
-              node.attr('type', 'text');
-            }
-          }
-        }
-      });
-
-      // Remove internal data attributes
-      htmlParser.addAttributeFilter(
-        'data-mce-src,data-mce-href,data-mce-style,' +
-        'data-mce-selected,data-mce-expando,' +
-        'data-mce-type,data-mce-resize',
-
-        function (nodes, name) {
-          var i = nodes.length;
-
-          while (i--) {
-            nodes[i].attr(name, null);
-          }
-        }
-      );
-
-      // Return public methods
-      return {
-        /**
-         * Schema instance that was used to when the Serializer was constructed.
-         *
-         * @field {tinymce.html.Schema} schema
-         */
-        schema: schema,
-
-        /**
-         * Adds a node filter function to the parser used by the serializer, the parser will collect the specified nodes by name
-         * and then execute the callback ones it has finished parsing the document.
-         *
-         * @example
-         * parser.addNodeFilter('p,h1', function(nodes, name) {
-         *  for (var i = 0; i < nodes.length; i++) {
-         *   console.log(nodes[i].name);
-         *  }
-         * });
-         * @method addNodeFilter
-         * @method {String} name Comma separated list of nodes to collect.
-         * @param {function} callback Callback function to execute once it has collected nodes.
-         */
-        addNodeFilter: htmlParser.addNodeFilter,
-
-        /**
-         * Adds a attribute filter function to the parser used by the serializer, the parser will
-         * collect nodes that has the specified attributes
-         * and then execute the callback ones it has finished parsing the document.
-         *
-         * @example
-         * parser.addAttributeFilter('src,href', function(nodes, name) {
-         *  for (var i = 0; i < nodes.length; i++) {
-         *   console.log(nodes[i].name);
-         *  }
-         * });
-         * @method addAttributeFilter
-         * @method {String} name Comma separated list of nodes to collect.
-         * @param {function} callback Callback function to execute once it has collected nodes.
-         */
-        addAttributeFilter: htmlParser.addAttributeFilter,
-
-        /**
-         * Serializes the specified browser DOM node into a HTML string.
-         *
-         * @method serialize
-         * @param {DOMNode} node DOM node to serialize.
-         * @param {Object} args Arguments option that gets passed to event handlers.
-         */
-        serialize: function (node, args) {
-          var self = this, impl, doc, oldDoc, htmlSerializer, content, rootNode;
-
-          // Explorer won't clone contents of script and style and the
-          // selected index of select elements are cleared on a clone operation.
-          if (Env.ie && dom.select('script,style,select,map').length > 0) {
-            content = node.innerHTML;
-            node = node.cloneNode(false);
-            dom.setHTML(node, content);
-          } else {
-            node = node.cloneNode(true);
-          }
-
-          // Nodes needs to be attached to something in WebKit/Opera
-          // This fix will make DOM ranges and make Sizzle happy!
-          impl = document.implementation;
-          if (impl.createHTMLDocument) {
-            // Create an empty HTML document
-            doc = impl.createHTMLDocument("");
-
-            // Add the element or it's children if it's a body element to the new document
-            each(node.nodeName == 'BODY' ? node.childNodes : [node], function (node) {
-              doc.body.appendChild(doc.importNode(node, true));
-            });
-
-            // Grab first child or body element for serialization
-            if (node.nodeName != 'BODY') {
-              node = doc.body.firstChild;
-            } else {
-              node = doc.body;
-            }
-
-            // set the new document in DOMUtils so createElement etc works
-            oldDoc = dom.doc;
-            dom.doc = doc;
-          }
-
-          args = args || {};
-          args.format = args.format || 'html';
-
-          // Don't wrap content if we want selected html
-          if (args.selection) {
-            args.forced_root_block = '';
-          }
-
-          // Pre process
-          if (!args.no_events) {
-            args.node = node;
-            self.onPreProcess(args);
-          }
-
-          // Parse HTML
-          rootNode = htmlParser.parse(trim(args.getInner ? node.innerHTML : dom.getOuterHTML(node)), args);
-          trimTrailingBr(rootNode);
-
-          // Serialize HTML
-          htmlSerializer = new Serializer(settings, schema);
-          args.content = htmlSerializer.serialize(rootNode);
-
-          // Replace all BOM characters for now until we can find a better solution
-          if (!args.cleanup) {
-            args.content = Zwsp.trim(args.content);
-            args.content = args.content.replace(/\uFEFF/g, '');
-          }
-
-          // Post process
-          if (!args.no_events) {
-            self.onPostProcess(args);
-          }
-
-          // Restore the old document if it was changed
-          if (oldDoc) {
-            dom.doc = oldDoc;
-          }
-
-          args.node = null;
-
-          return args.content;
-        },
-
-        /**
-         * Adds valid elements rules to the serializers schema instance this enables you to specify things
-         * like what elements should be outputted and what attributes specific elements might have.
-         * Consult the Wiki for more details on this format.
-         *
-         * @method addRules
-         * @param {String} rules Valid elements rules string to add to schema.
-         */
-        addRules: function (rules) {
-          schema.addValidElements(rules);
-        },
-
-        /**
-         * Sets the valid elements rules to the serializers schema instance this enables you to specify things
-         * like what elements should be outputted and what attributes specific elements might have.
-         * Consult the Wiki for more details on this format.
-         *
-         * @method setRules
-         * @param {String} rules Valid elements rules string.
-         */
-        setRules: function (rules) {
-          schema.setValidElements(rules);
-        },
-
-        onPreProcess: function (args) {
-          if (editor) {
-            editor.fire('PreProcess', args);
-          }
-        },
-
-        onPostProcess: function (args) {
-          if (editor) {
-            editor.fire('PostProcess', args);
-          }
-        },
-
-        /**
-         * Adds a temporary internal attribute these attributes will get removed on undo and
-         * when getting contents out of the editor.
-         *
-         * @method addTempAttr
-         * @param {String} name string
-         */
-        addTempAttr: addTempAttr,
-
-        // Internal
-        trimHtml: trimHtml,
-        getTrimmedContent: getTrimmedContent,
-        trimContent: trimContent
-      };
-    };
-  }
-);
-
-/**
- * VK.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * This file exposes a set of the common KeyCodes for use. Please grow it as needed.
- */
-define(
-  'tinymce.core.util.VK',
-  [
-    "tinymce.core.Env"
-  ],
-  function (Env) {
-    return {
-      BACKSPACE: 8,
-      DELETE: 46,
-      DOWN: 40,
-      ENTER: 13,
-      LEFT: 37,
-      RIGHT: 39,
-      SPACEBAR: 32,
-      TAB: 9,
-      UP: 38,
-
-      modifierPressed: function (e) {
-        return e.shiftKey || e.ctrlKey || e.altKey || this.metaKeyPressed(e);
-      },
-
-      metaKeyPressed: function (e) {
-        // Check if ctrl or meta key is pressed. Edge case for AltGr on Windows where it produces ctrlKey+altKey states
-        return (Env.mac ? e.metaKey : e.ctrlKey && !e.altKey);
-      }
-    };
-  }
-);
-
-/**
- * ControlSelection.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * This class handles control selection of elements. Controls are elements
- * that can be resized and needs to be selected as a whole. It adds custom resize handles
- * to all browser engines that support properly disabling the built in resize logic.
- *
- * @class tinymce.dom.ControlSelection
- */
-define(
-  'tinymce.core.dom.ControlSelection',
-  [
-    "tinymce.core.util.VK",
-    "tinymce.core.util.Tools",
-    "tinymce.core.util.Delay",
-    "tinymce.core.Env",
-    "tinymce.core.dom.NodeType"
-  ],
-  function (VK, Tools, Delay, Env, NodeType) {
-    var isContentEditableFalse = NodeType.isContentEditableFalse;
-    var isContentEditableTrue = NodeType.isContentEditableTrue;
-
-    function getContentEditableRoot(root, node) {
-      while (node && node != root) {
-        if (isContentEditableTrue(node) || isContentEditableFalse(node)) {
-          return node;
-        }
-
-        node = node.parentNode;
-      }
-
-      return null;
-    }
-
-    return function (selection, editor) {
-      var dom = editor.dom, each = Tools.each;
-      var selectedElm, selectedElmGhost, resizeHelper, resizeHandles, selectedHandle, lastMouseDownEvent;
-      var startX, startY, selectedElmX, selectedElmY, startW, startH, ratio, resizeStarted;
-      var width, height, editableDoc = editor.getDoc(), rootDocument = document, isIE = Env.ie && Env.ie < 11;
-      var abs = Math.abs, round = Math.round, rootElement = editor.getBody(), startScrollWidth, startScrollHeight;
-
-      // Details about each resize handle how to scale etc
-      resizeHandles = {
-        // Name: x multiplier, y multiplier, delta size x, delta size y
-        /*n: [0.5, 0, 0, -1],
-        e: [1, 0.5, 1, 0],
-        s: [0.5, 1, 0, 1],
-        w: [0, 0.5, -1, 0],*/
-        nw: [0, 0, -1, -1],
-        ne: [1, 0, 1, -1],
-        se: [1, 1, 1, 1],
-        sw: [0, 1, -1, 1]
-      };
-
-      // Add CSS for resize handles, cloned element and selected
-      var rootClass = '.mce-content-body';
-      editor.contentStyles.push(
-        rootClass + ' div.mce-resizehandle {' +
-        'position: absolute;' +
-        'border: 1px solid black;' +
-        'box-sizing: box-sizing;' +
-        'background: #FFF;' +
-        'width: 7px;' +
-        'height: 7px;' +
-        'z-index: 10000' +
-        '}' +
-        rootClass + ' .mce-resizehandle:hover {' +
-        'background: #000' +
-        '}' +
-        rootClass + ' img[data-mce-selected],' + rootClass + ' hr[data-mce-selected] {' +
-        'outline: 1px solid black;' +
-        'resize: none' + // Have been talks about implementing this in browsers
-        '}' +
-        rootClass + ' .mce-clonedresizable {' +
-        'position: absolute;' +
-        (Env.gecko ? '' : 'outline: 1px dashed black;') + // Gecko produces trails while resizing
-        'opacity: .5;' +
-        'filter: alpha(opacity=50);' +
-        'z-index: 10000' +
-        '}' +
-        rootClass + ' .mce-resize-helper {' +
-        'background: #555;' +
-        'background: rgba(0,0,0,0.75);' +
-        'border-radius: 3px;' +
-        'border: 1px;' +
-        'color: white;' +
-        'display: none;' +
-        'font-family: sans-serif;' +
-        'font-size: 12px;' +
-        'white-space: nowrap;' +
-        'line-height: 14px;' +
-        'margin: 5px 10px;' +
-        'padding: 5px;' +
-        'position: absolute;' +
-        'z-index: 10001' +
-        '}'
-      );
-
-      function isResizable(elm) {
-        var selector = editor.settings.object_resizing;
-
-        if (selector === false || Env.iOS) {
-          return false;
-        }
-
-        if (typeof selector != 'string') {
-          selector = 'table,img,div';
-        }
-
-        if (elm.getAttribute('data-mce-resize') === 'false') {
-          return false;
-        }
-
-        if (elm == editor.getBody()) {
-          return false;
-        }
-
-        return editor.dom.is(elm, selector);
-      }
-
-      function resizeGhostElement(e) {
-        var deltaX, deltaY, proportional;
-        var resizeHelperX, resizeHelperY;
-
-        // Calc new width/height
-        deltaX = e.screenX - startX;
-        deltaY = e.screenY - startY;
-
-        // Calc new size
-        width = deltaX * selectedHandle[2] + startW;
-        height = deltaY * selectedHandle[3] + startH;
-
-        // Never scale down lower than 5 pixels
-        width = width < 5 ? 5 : width;
-        height = height < 5 ? 5 : height;
-
-        if (selectedElm.nodeName == "IMG" && editor.settings.resize_img_proportional !== false) {
-          proportional = !VK.modifierPressed(e);
-        } else {
-          proportional = VK.modifierPressed(e) || (selectedElm.nodeName == "IMG" && selectedHandle[2] * selectedHandle[3] !== 0);
-        }
-
-        // Constrain proportions
-        if (proportional) {
-          if (abs(deltaX) > abs(deltaY)) {
-            height = round(width * ratio);
-            width = round(height / ratio);
-          } else {
-            width = round(height / ratio);
-            height = round(width * ratio);
-          }
-        }
-
-        // Update ghost size
-        dom.setStyles(selectedElmGhost, {
-          width: width,
-          height: height
-        });
-
-        // Update resize helper position
-        resizeHelperX = selectedHandle.startPos.x + deltaX;
-        resizeHelperY = selectedHandle.startPos.y + deltaY;
-        resizeHelperX = resizeHelperX > 0 ? resizeHelperX : 0;
-        resizeHelperY = resizeHelperY > 0 ? resizeHelperY : 0;
-
-        dom.setStyles(resizeHelper, {
-          left: resizeHelperX,
-          top: resizeHelperY,
-          display: 'block'
-        });
-
-        resizeHelper.innerHTML = width + ' &times; ' + height;
-
-        // Update ghost X position if needed
-        if (selectedHandle[2] < 0 && selectedElmGhost.clientWidth <= width) {
-          dom.setStyle(selectedElmGhost, 'left', selectedElmX + (startW - width));
-        }
-
-        // Update ghost Y position if needed
-        if (selectedHandle[3] < 0 && selectedElmGhost.clientHeight <= height) {
-          dom.setStyle(selectedElmGhost, 'top', selectedElmY + (startH - height));
-        }
-
-        // Calculate how must overflow we got
-        deltaX = rootElement.scrollWidth - startScrollWidth;
-        deltaY = rootElement.scrollHeight - startScrollHeight;
-
-        // Re-position the resize helper based on the overflow
-        if (deltaX + deltaY !== 0) {
-          dom.setStyles(resizeHelper, {
-            left: resizeHelperX - deltaX,
-            top: resizeHelperY - deltaY
-          });
-        }
-
-        if (!resizeStarted) {
-          editor.fire('ObjectResizeStart', { target: selectedElm, width: startW, height: startH });
-          resizeStarted = true;
-        }
-      }
-
-      function endGhostResize() {
-        resizeStarted = false;
-
-        function setSizeProp(name, value) {
-          if (value) {
-            // Resize by using style or attribute
-            if (selectedElm.style[name] || !editor.schema.isValid(selectedElm.nodeName.toLowerCase(), name)) {
-              dom.setStyle(selectedElm, name, value);
-            } else {
-              dom.setAttrib(selectedElm, name, value);
-            }
-          }
-        }
-
-        // Set width/height properties
-        setSizeProp('width', width);
-        setSizeProp('height', height);
-
-        dom.unbind(editableDoc, 'mousemove', resizeGhostElement);
-        dom.unbind(editableDoc, 'mouseup', endGhostResize);
-
-        if (rootDocument != editableDoc) {
-          dom.unbind(rootDocument, 'mousemove', resizeGhostElement);
-          dom.unbind(rootDocument, 'mouseup', endGhostResize);
-        }
-
-        // Remove ghost/helper and update resize handle positions
-        dom.remove(selectedElmGhost);
-        dom.remove(resizeHelper);
-
-        if (!isIE || selectedElm.nodeName == "TABLE") {
-          showResizeRect(selectedElm);
-        }
-
-        editor.fire('ObjectResized', { target: selectedElm, width: width, height: height });
-        dom.setAttrib(selectedElm, 'style', dom.getAttrib(selectedElm, 'style'));
-        editor.nodeChanged();
-      }
-
-      function showResizeRect(targetElm, mouseDownHandleName, mouseDownEvent) {
-        var position, targetWidth, targetHeight, e, rect;
-
-        hideResizeRect();
-        unbindResizeHandleEvents();
-
-        // Get position and size of target
-        position = dom.getPos(targetElm, rootElement);
-        selectedElmX = position.x;
-        selectedElmY = position.y;
-        rect = targetElm.getBoundingClientRect(); // Fix for Gecko offsetHeight for table with caption
-        targetWidth = rect.width || (rect.right - rect.left);
-        targetHeight = rect.height || (rect.bottom - rect.top);
-
-        // Reset width/height if user selects a new image/table
-        if (selectedElm != targetElm) {
-          detachResizeStartListener();
-          selectedElm = targetElm;
-          width = height = 0;
-        }
-
-        // Makes it possible to disable resizing
-        e = editor.fire('ObjectSelected', { target: targetElm });
-
-        if (isResizable(targetElm) && !e.isDefaultPrevented()) {
-          each(resizeHandles, function (handle, name) {
-            var handleElm;
-
-            function startDrag(e) {
-              startX = e.screenX;
-              startY = e.screenY;
-              startW = selectedElm.clientWidth;
-              startH = selectedElm.clientHeight;
-              ratio = startH / startW;
-              selectedHandle = handle;
-
-              handle.startPos = {
-                x: targetWidth * handle[0] + selectedElmX,
-                y: targetHeight * handle[1] + selectedElmY
-              };
-
-              startScrollWidth = rootElement.scrollWidth;
-              startScrollHeight = rootElement.scrollHeight;
-
-              selectedElmGhost = selectedElm.cloneNode(true);
-              dom.addClass(selectedElmGhost, 'mce-clonedresizable');
-              dom.setAttrib(selectedElmGhost, 'data-mce-bogus', 'all');
-              selectedElmGhost.contentEditable = false; // Hides IE move layer cursor
-              selectedElmGhost.unSelectabe = true;
-              dom.setStyles(selectedElmGhost, {
-                left: selectedElmX,
-                top: selectedElmY,
-                margin: 0
-              });
-
-              selectedElmGhost.removeAttribute('data-mce-selected');
-              rootElement.appendChild(selectedElmGhost);
-
-              dom.bind(editableDoc, 'mousemove', resizeGhostElement);
-              dom.bind(editableDoc, 'mouseup', endGhostResize);
-
-              if (rootDocument != editableDoc) {
-                dom.bind(rootDocument, 'mousemove', resizeGhostElement);
-                dom.bind(rootDocument, 'mouseup', endGhostResize);
-              }
-
-              resizeHelper = dom.add(rootElement, 'div', {
-                'class': 'mce-resize-helper',
-                'data-mce-bogus': 'all'
-              }, startW + ' &times; ' + startH);
-            }
-
-            if (mouseDownHandleName) {
-              // Drag started by IE native resizestart
-              if (name == mouseDownHandleName) {
-                startDrag(mouseDownEvent);
-              }
-
-              return;
-            }
-
-            // Get existing or render resize handle
-            handleElm = dom.get('mceResizeHandle' + name);
-            if (handleElm) {
-              dom.remove(handleElm);
-            }
-
-            handleElm = dom.add(rootElement, 'div', {
-              id: 'mceResizeHandle' + name,
-              'data-mce-bogus': 'all',
-              'class': 'mce-resizehandle',
-              unselectable: true,
-              style: 'cursor:' + name + '-resize; margin:0; padding:0'
-            });
-
-            // Hides IE move layer cursor
-            // If we set it on Chrome we get this wounderful bug: #6725
-            if (Env.ie) {
-              handleElm.contentEditable = false;
-            }
-
-            dom.bind(handleElm, 'mousedown', function (e) {
-              e.stopImmediatePropagation();
-              e.preventDefault();
-              startDrag(e);
-            });
-
-            handle.elm = handleElm;
-
-            // Position element
-            dom.setStyles(handleElm, {
-              left: (targetWidth * handle[0] + selectedElmX) - (handleElm.offsetWidth / 2),
-              top: (targetHeight * handle[1] + selectedElmY) - (handleElm.offsetHeight / 2)
-            });
-          });
-        } else {
-          hideResizeRect();
-        }
-
-        selectedElm.setAttribute('data-mce-selected', '1');
-      }
-
-      function hideResizeRect() {
-        var name, handleElm;
-
-        unbindResizeHandleEvents();
-
-        if (selectedElm) {
-          selectedElm.removeAttribute('data-mce-selected');
-        }
-
-        for (name in resizeHandles) {
-          handleElm = dom.get('mceResizeHandle' + name);
-          if (handleElm) {
-            dom.unbind(handleElm);
-            dom.remove(handleElm);
-          }
-        }
-      }
-
-      function updateResizeRect(e) {
-        var startElm, controlElm;
-
-        function isChildOrEqual(node, parent) {
-          if (node) {
-            do {
-              if (node === parent) {
-                return true;
-              }
-            } while ((node = node.parentNode));
-          }
-        }
-
-        // Ignore all events while resizing or if the editor instance was removed
-        if (resizeStarted || editor.removed) {
-          return;
-        }
-
-        // Remove data-mce-selected from all elements since they might have been copied using Ctrl+c/v
-        each(dom.select('img[data-mce-selected],hr[data-mce-selected]'), function (img) {
-          img.removeAttribute('data-mce-selected');
-        });
-
-        controlElm = e.type == 'mousedown' ? e.target : selection.getNode();
-        controlElm = dom.$(controlElm).closest(isIE ? 'table' : 'table,img,hr')[0];
-
-        if (isChildOrEqual(controlElm, rootElement)) {
-          disableGeckoResize();
-          startElm = selection.getStart(true);
-
-          if (isChildOrEqual(startElm, controlElm) && isChildOrEqual(selection.getEnd(true), controlElm)) {
-            if (!isIE || (controlElm != startElm && startElm.nodeName !== 'IMG')) {
-              showResizeRect(controlElm);
-              return;
-            }
-          }
-        }
-
-        hideResizeRect();
-      }
-
-      function attachEvent(elm, name, func) {
-        if (elm && elm.attachEvent) {
-          elm.attachEvent('on' + name, func);
-        }
-      }
-
-      function detachEvent(elm, name, func) {
-        if (elm && elm.detachEvent) {
-          elm.detachEvent('on' + name, func);
-        }
-      }
-
-      function resizeNativeStart(e) {
-        var target = e.srcElement, pos, name, corner, cornerX, cornerY, relativeX, relativeY;
-
-        pos = target.getBoundingClientRect();
-        relativeX = lastMouseDownEvent.clientX - pos.left;
-        relativeY = lastMouseDownEvent.clientY - pos.top;
-
-        // Figure out what corner we are draging on
-        for (name in resizeHandles) {
-          corner = resizeHandles[name];
-
-          cornerX = target.offsetWidth * corner[0];
-          cornerY = target.offsetHeight * corner[1];
-
-          if (abs(cornerX - relativeX) < 8 && abs(cornerY - relativeY) < 8) {
-            selectedHandle = corner;
-            break;
-          }
-        }
-
-        // Remove native selection and let the magic begin
-        resizeStarted = true;
-        editor.fire('ObjectResizeStart', {
-          target: selectedElm,
-          width: selectedElm.clientWidth,
-          height: selectedElm.clientHeight
-        });
-        editor.getDoc().selection.empty();
-        showResizeRect(target, name, lastMouseDownEvent);
-      }
-
-      function preventDefault(e) {
-        if (e.preventDefault) {
-          e.preventDefault();
-        } else {
-          e.returnValue = false; // IE
-        }
-      }
-
-      function isWithinContentEditableFalse(elm) {
-        return isContentEditableFalse(getContentEditableRoot(editor.getBody(), elm));
-      }
-
-      function nativeControlSelect(e) {
-        var target = e.srcElement;
-
-        if (isWithinContentEditableFalse(target)) {
-          preventDefault(e);
-          return;
-        }
-
-        if (target != selectedElm) {
-          editor.fire('ObjectSelected', { target: target });
-          detachResizeStartListener();
-
-          if (target.id.indexOf('mceResizeHandle') === 0) {
-            e.returnValue = false;
-            return;
-          }
-
-          if (target.nodeName == 'IMG' || target.nodeName == 'TABLE') {
-            hideResizeRect();
-            selectedElm = target;
-            attachEvent(target, 'resizestart', resizeNativeStart);
-          }
-        }
-      }
-
-      function detachResizeStartListener() {
-        detachEvent(selectedElm, 'resizestart', resizeNativeStart);
-      }
-
-      function unbindResizeHandleEvents() {
-        for (var name in resizeHandles) {
-          var handle = resizeHandles[name];
-
-          if (handle.elm) {
-            dom.unbind(handle.elm);
-            delete handle.elm;
-          }
-        }
-      }
-
-      function disableGeckoResize() {
-        try {
-          // Disable object resizing on Gecko
-          editor.getDoc().execCommand('enableObjectResizing', false, false);
-        } catch (ex) {
-          // Ignore
-        }
-      }
-
-      function controlSelect(elm) {
-        var ctrlRng;
-
-        if (!isIE) {
-          return;
-        }
-
-        ctrlRng = editableDoc.body.createControlRange();
-
-        try {
-          ctrlRng.addElement(elm);
-          ctrlRng.select();
-          return true;
-        } catch (ex) {
-          // Ignore since the element can't be control selected for example a P tag
-        }
-      }
-
-      editor.on('init', function () {
-        if (isIE) {
-          // Hide the resize rect on resize and reselect the image
-          editor.on('ObjectResized', function (e) {
-            if (e.target.nodeName != 'TABLE') {
-              hideResizeRect();
-              controlSelect(e.target);
-            }
-          });
-
-          attachEvent(rootElement, 'controlselect', nativeControlSelect);
-
-          editor.on('mousedown', function (e) {
-            lastMouseDownEvent = e;
-          });
-        } else {
-          disableGeckoResize();
-
-          // Sniff sniff, hard to feature detect this stuff
-          if (Env.ie >= 11) {
-            // Needs to be mousedown for drag/drop to work on IE 11
-            // Needs to be click on Edge to properly select images
-            editor.on('mousedown click', function (e) {
-              var target = e.target, nodeName = target.nodeName;
-
-              if (!resizeStarted && /^(TABLE|IMG|HR)$/.test(nodeName) && !isWithinContentEditableFalse(target)) {
-                editor.selection.select(target, nodeName == 'TABLE');
-
-                // Only fire once since nodeChange is expensive
-                if (e.type == 'mousedown') {
-                  editor.nodeChanged();
-                }
-              }
-            });
-
-            editor.dom.bind(rootElement, 'mscontrolselect', function (e) {
-              function delayedSelect(node) {
-                Delay.setEditorTimeout(editor, function () {
-                  editor.selection.select(node);
-                });
-              }
-
-              if (isWithinContentEditableFalse(e.target)) {
-                e.preventDefault();
-                delayedSelect(e.target);
-                return;
-              }
-
-              if (/^(TABLE|IMG|HR)$/.test(e.target.nodeName)) {
-                e.preventDefault();
-
-                // This moves the selection from being a control selection to a text like selection like in WebKit #6753
-                // TODO: Fix this the day IE works like other browsers without this nasty native ugly control selections.
-                if (e.target.tagName == 'IMG') {
-                  delayedSelect(e.target);
-                }
-              }
-            });
-          }
-        }
-
-        var throttledUpdateResizeRect = Delay.throttle(function (e) {
-          if (!editor.composing) {
-            updateResizeRect(e);
-          }
-        });
-
-        editor.on('nodechange ResizeEditor ResizeWindow drop', throttledUpdateResizeRect);
-
-        // Update resize rect while typing in a table
-        editor.on('keyup compositionend', function (e) {
-          // Don't update the resize rect while composing since it blows away the IME see: #2710
-          if (selectedElm && selectedElm.nodeName == "TABLE") {
-            throttledUpdateResizeRect(e);
-          }
-        });
-
-        editor.on('hide blur', hideResizeRect);
-
-        // Hide rect on focusout since it would float on top of windows otherwise
-        //editor.on('focusout', hideResizeRect);
-      });
-
-      editor.on('remove', unbindResizeHandleEvents);
-
-      function destroy() {
-        selectedElm = selectedElmGhost = null;
-
-        if (isIE) {
-          detachResizeStartListener();
-          detachEvent(rootElement, 'controlselect', nativeControlSelect);
-        }
-      }
-
-      return {
-        isResizable: isResizable,
-        showResizeRect: showResizeRect,
-        hideResizeRect: hideResizeRect,
-        updateResizeRect: updateResizeRect,
-        controlSelect: controlSelect,
-        destroy: destroy
-      };
-    };
-  }
-);
-
-/**
- * Fun.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * Functional utility class.
- *
- * @private
- * @class tinymce.util.Fun
- */
-define(
-  'tinymce.core.util.Fun',
-  [
-  ],
-  function () {
-    var slice = [].slice;
-
-    function constant(value) {
-      return function () {
-        return value;
-      };
-    }
-
-    function negate(predicate) {
-      return function (x) {
-        return !predicate(x);
-      };
-    }
-
-    function compose(f, g) {
-      return function (x) {
-        return f(g(x));
-      };
-    }
-
-    function or() {
-      var args = slice.call(arguments);
-
-      return function (x) {
-        for (var i = 0; i < args.length; i++) {
-          if (args[i](x)) {
-            return true;
-          }
-        }
-
-        return false;
-      };
-    }
-
-    function and() {
-      var args = slice.call(arguments);
-
-      return function (x) {
-        for (var i = 0; i < args.length; i++) {
-          if (!args[i](x)) {
-            return false;
-          }
-        }
-
-        return true;
-      };
-    }
-
-    function curry(fn) {
-      var args = slice.call(arguments);
-
-      if (args.length - 1 >= fn.length) {
-        return fn.apply(this, args.slice(1));
-      }
-
-      return function () {
-        var tempArgs = args.concat([].slice.call(arguments));
-        return curry.apply(this, tempArgs);
-      };
-    }
-
-    function noop() {
-    }
-
-    return {
-      constant: constant,
-      negate: negate,
-      and: and,
-      or: or,
-      curry: curry,
-      compose: compose,
-      noop: noop
-    };
-  }
-);
-/**
</del><span class="cx" style="display: block; padding: 0 10px">  * CaretCandidate.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -17648,6 +14002,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">       return trimmedOffset;
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var trimEmptyTextNode = function (node) {
+      if (NodeType.isText(node) && node.data.length === 0) {
+        node.parentNode.removeChild(node);
+      }
+    };
+
</ins><span class="cx" style="display: block; padding: 0 10px">     /**
</span><span class="cx" style="display: block; padding: 0 10px">      * Constructs a new BookmarkManager instance for a specific selection instance.
</span><span class="cx" style="display: block; padding: 0 10px">      *
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -17875,12 +14235,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">           // Insert end marker
</span><span class="cx" style="display: block; padding: 0 10px">           if (!collapsed) {
</span><span class="cx" style="display: block; padding: 0 10px">             rng2.collapse(false);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            rng2.insertNode(dom.create('span', { 'data-mce-type': "bookmark", id: id + '_end', style: styles }, chr));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            var endBookmarkNode = dom.create('span', { 'data-mce-type': "bookmark", id: id + '_end', style: styles }, chr);
+            rng2.insertNode(endBookmarkNode);
+            trimEmptyTextNode(endBookmarkNode.nextSibling);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">           rng = normalizeTableCellSelection(rng);
</span><span class="cx" style="display: block; padding: 0 10px">           rng.collapse(true);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          rng.insertNode(dom.create('span', { 'data-mce-type': "bookmark", id: id + '_start', style: styles }, chr));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          var startBookmarkNode = dom.create('span', { 'data-mce-type': "bookmark", id: id + '_start', style: styles }, chr);
+          rng.insertNode(startBookmarkNode);
+          trimEmptyTextNode(startBookmarkNode.previousSibling);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">         selection.moveToBookmark({ id: id, keep: 1 });
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -18082,7 +14446,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * ScrollIntoView.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * CaretUtils.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -18091,586 +14455,784 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Contributing: http://www.tinymce.com/contributing
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/**
+ * Utility functions shared by the caret logic.
+ *
+ * @private
+ * @class tinymce.caret.CaretUtils
+ */
</ins><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.dom.ScrollIntoView',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.caret.CaretUtils',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.dom.NodeType'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    "tinymce.core.util.Fun",
+    "tinymce.core.dom.TreeWalker",
+    "tinymce.core.dom.NodeType",
+    "tinymce.core.caret.CaretPosition",
+    "tinymce.core.caret.CaretContainer",
+    "tinymce.core.caret.CaretCandidate"
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (NodeType) {
-    var getPos = function (elm) {
-      var x = 0, y = 0;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Fun, TreeWalker, NodeType, CaretPosition, CaretContainer, CaretCandidate) {
+    var isContentEditableTrue = NodeType.isContentEditableTrue,
+      isContentEditableFalse = NodeType.isContentEditableFalse,
+      isBlockLike = NodeType.matchStyleValues('display', 'block table table-cell table-caption list-item'),
+      isCaretContainer = CaretContainer.isCaretContainer,
+      isCaretContainerBlock = CaretContainer.isCaretContainerBlock,
+      curry = Fun.curry,
+      isElement = NodeType.isElement,
+      isCaretCandidate = CaretCandidate.isCaretCandidate;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var offsetParent = elm;
-      while (offsetParent && offsetParent.nodeType) {
-        x += offsetParent.offsetLeft || 0;
-        y += offsetParent.offsetTop || 0;
-        offsetParent = offsetParent.offsetParent;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function isForwards(direction) {
+      return direction > 0;
+    }
+
+    function isBackwards(direction) {
+      return direction < 0;
+    }
+
+    function skipCaretContainers(walk, shallow) {
+      var node;
+
+      while ((node = walk(shallow))) {
+        if (!isCaretContainerBlock(node)) {
+          return node;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return { x: x, y: y };
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return null;
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var fireScrollIntoViewEvent = function (editor, elm, alignToTop) {
-      var scrollEvent = { elm: elm, alignToTop: alignToTop };
-      editor.fire('scrollIntoView', scrollEvent);
-      return scrollEvent.isDefaultPrevented();
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function findNode(node, direction, predicateFn, rootNode, shallow) {
+      var walker = new TreeWalker(node, rootNode);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var scrollIntoView = function (editor, elm, alignToTop) {
-      var y, viewPort, dom = editor.dom, root = dom.getRoot(), viewPortY, viewPortH, offsetY = 0;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (isBackwards(direction)) {
+        if (isContentEditableFalse(node) || isCaretContainerBlock(node)) {
+          node = skipCaretContainers(walker.prev, true);
+          if (predicateFn(node)) {
+            return node;
+          }
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (fireScrollIntoViewEvent(editor, elm, alignToTop)) {
-        return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        while ((node = skipCaretContainers(walker.prev, shallow))) {
+          if (predicateFn(node)) {
+            return node;
+          }
+        }
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (!NodeType.isElement(elm)) {
-        return;
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (isForwards(direction)) {
+        if (isContentEditableFalse(node) || isCaretContainerBlock(node)) {
+          node = skipCaretContainers(walker.next, true);
+          if (predicateFn(node)) {
+            return node;
+          }
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (alignToTop === false) {
-        offsetY = elm.offsetHeight;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        while ((node = skipCaretContainers(walker.next, shallow))) {
+          if (predicateFn(node)) {
+            return node;
+          }
+        }
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (root.nodeName !== 'BODY') {
-        var scrollContainer = editor.selection.getScrollContainer();
-        if (scrollContainer) {
-          y = getPos(elm).y - getPos(scrollContainer).y + offsetY;
-          viewPortH = scrollContainer.clientHeight;
-          viewPortY = scrollContainer.scrollTop;
-          if (y < viewPortY || y + 25 > viewPortY + viewPortH) {
-            scrollContainer.scrollTop = y < viewPortY ? y : y - viewPortH + 25;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return null;
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function getEditingHost(node, rootNode) {
+      for (node = node.parentNode; node && node != rootNode; node = node.parentNode) {
+        if (isContentEditableTrue(node)) {
+          return node;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      viewPort = dom.getViewPort(editor.getWin());
-      y = dom.getPos(elm).y + offsetY;
-      viewPortY = viewPort.y;
-      viewPortH = viewPort.h;
-      if (y < viewPort.y || y + 25 > viewPortY + viewPortH) {
-        editor.getWin().scrollTo(0, y < viewPortY ? y : y - viewPortH + 25);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return rootNode;
+    }
+
+    function getParentBlock(node, rootNode) {
+      while (node && node != rootNode) {
+        if (isBlockLike(node)) {
+          return node;
+        }
+
+        node = node.parentNode;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return {
-      scrollIntoView: scrollIntoView
-    };
-  }
-);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return null;
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * TridentSelection.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function isInSameBlock(caretPosition1, caretPosition2, rootNode) {
+      return getParentBlock(caretPosition1.container(), rootNode) == getParentBlock(caretPosition2.container(), rootNode);
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * Selection class for old explorer versions. This one fakes the
- * native selection object available on modern browsers.
- *
- * @private
- * @class tinymce.dom.TridentSelection
- */
-define(
-  'tinymce.core.dom.TridentSelection',
-  [
-  ],
-  function () {
-    function Selection(selection) {
-      var self = this, dom = selection.dom, FALSE = false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function isInSameEditingHost(caretPosition1, caretPosition2, rootNode) {
+      return getEditingHost(caretPosition1.container(), rootNode) == getEditingHost(caretPosition2.container(), rootNode);
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function getPosition(rng, start) {
-        var checkRng, startIndex = 0, endIndex, inside,
-          children, child, offset, index, position = -1, parent;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function getChildNodeAtRelativeOffset(relativeOffset, caretPosition) {
+      var container, offset;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Setup test range, collapse it and get the parent
-        checkRng = rng.duplicate();
-        checkRng.collapse(start);
-        parent = checkRng.parentElement();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (!caretPosition) {
+        return null;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Check if the selection is within the right document
-        if (parent.ownerDocument !== selection.dom.doc) {
-          return;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      container = caretPosition.container();
+      offset = caretPosition.offset();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // IE will report non editable elements as it's parent so look for an editable one
-        while (parent.contentEditable === "false") {
-          parent = parent.parentNode;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (!isElement(container)) {
+        return null;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // If parent doesn't have any children then return that we are inside the element
-        if (!parent.hasChildNodes()) {
-          return { node: parent, inside: 1 };
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return container.childNodes[offset + relativeOffset];
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Setup node list and endIndex
-        children = parent.children;
-        endIndex = children.length - 1;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function beforeAfter(before, node) {
+      var range = node.ownerDocument.createRange();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Perform a binary search for the position
-        while (startIndex <= endIndex) {
-          index = Math.floor((startIndex + endIndex) / 2);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (before) {
+        range.setStartBefore(node);
+        range.setEndBefore(node);
+      } else {
+        range.setStartAfter(node);
+        range.setEndAfter(node);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Move selection to node and compare the ranges
-          child = children[index];
-          checkRng.moveToElementText(child);
-          position = checkRng.compareEndPoints(start ? 'StartToStart' : 'EndToEnd', rng);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return range;
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Before/after or an exact match
-          if (position > 0) {
-            endIndex = index - 1;
-          } else if (position < 0) {
-            startIndex = index + 1;
-          } else {
-            return { node: child };
-          }
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function isNodesInSameBlock(rootNode, node1, node2) {
+      return getParentBlock(node1, rootNode) == getParentBlock(node2, rootNode);
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Check if child position is before or we didn't find a position
-        if (position < 0) {
-          // No element child was found use the parent element and the offset inside that
-          if (!child) {
-            checkRng.moveToElementText(parent);
-            checkRng.collapse(true);
-            child = parent;
-            inside = true;
-          } else {
-            checkRng.collapse(false);
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function lean(left, rootNode, node) {
+      var sibling, siblingName;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Walk character by character in text node until we hit the selected range endpoint,
-          // hit the end of document or parent isn't the right one
-          // We need to walk char by char since rng.text or rng.htmlText will trim line endings
-          offset = 0;
-          while (checkRng.compareEndPoints(start ? 'StartToStart' : 'StartToEnd', rng) !== 0) {
-            if (checkRng.move('character', 1) === 0 || parent != checkRng.parentElement()) {
-              break;
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (left) {
+        siblingName = 'previousSibling';
+      } else {
+        siblingName = 'nextSibling';
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            offset++;
-          }
-        } else {
-          // Child position is after the selection endpoint
-          checkRng.collapse(true);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      while (node && node != rootNode) {
+        sibling = node[siblingName];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Walk character by character in text node until we hit the selected range endpoint, hit
-          // the end of document or parent isn't the right one
-          offset = 0;
-          while (checkRng.compareEndPoints(start ? 'StartToStart' : 'StartToEnd', rng) !== 0) {
-            if (checkRng.move('character', -1) === 0 || parent != checkRng.parentElement()) {
-              break;
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (isCaretContainer(sibling)) {
+          sibling = sibling[siblingName];
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            offset++;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (isContentEditableFalse(sibling)) {
+          if (isNodesInSameBlock(rootNode, sibling, node)) {
+            return sibling;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+          break;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return { node: child, position: position, offset: offset, inside: inside };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (isCaretCandidate(sibling)) {
+          break;
+        }
+
+        node = node.parentNode;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Returns a W3C DOM compatible range object by using the IE Range API
-      function getRange() {
-        var ieRange = selection.getRng(), domRange = dom.createRng(), element, collapsed, tmpRange, element2, bookmark;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return null;
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // If selection is outside the current document just return an empty range
-        element = ieRange.item ? ieRange.item(0) : ieRange.parentElement();
-        if (element.ownerDocument != dom.doc) {
-          return domRange;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var before = curry(beforeAfter, true);
+    var after = curry(beforeAfter, false);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        collapsed = selection.isCollapsed();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function normalizeRange(direction, rootNode, range) {
+      var node, container, offset, location;
+      var leanLeft = curry(lean, true, rootNode);
+      var leanRight = curry(lean, false, rootNode);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Handle control selection
-        if (ieRange.item) {
-          domRange.setStart(element.parentNode, dom.nodeIndex(element));
-          domRange.setEnd(domRange.startContainer, domRange.startOffset + 1);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      container = range.startContainer;
+      offset = range.startOffset;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return domRange;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (CaretContainer.isCaretContainerBlock(container)) {
+        if (!isElement(container)) {
+          container = container.parentNode;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function findEndPoint(start) {
-          var endPoint = getPosition(ieRange, start), container, offset, textNodeOffset = 0, sibling, undef, nodeValue;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        location = container.getAttribute('data-mce-caret');
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          container = endPoint.node;
-          offset = endPoint.offset;
-
-          if (endPoint.inside && !container.hasChildNodes()) {
-            domRange[start ? 'setStart' : 'setEnd'](container, 0);
-            return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (location == 'before') {
+          node = container.nextSibling;
+          if (isContentEditableFalse(node)) {
+            return before(node);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (offset === undef) {
-            domRange[start ? 'setStartBefore' : 'setEndAfter'](container);
-            return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (location == 'after') {
+          node = container.previousSibling;
+          if (isContentEditableFalse(node)) {
+            return after(node);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        }
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (endPoint.position < 0) {
-            sibling = endPoint.inside ? container.firstChild : container.nextSibling;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (!range.collapsed) {
+        return range;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (!sibling) {
-              domRange[start ? 'setStartAfter' : 'setEndAfter'](container);
-              return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (NodeType.isText(container)) {
+        if (isCaretContainer(container)) {
+          if (direction === 1) {
+            node = leanRight(container);
+            if (node) {
+              return before(node);
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (!offset) {
-              if (sibling.nodeType == 3) {
-                domRange[start ? 'setStart' : 'setEnd'](sibling, 0);
-              } else {
-                domRange[start ? 'setStartBefore' : 'setEndBefore'](sibling);
-              }
-
-              return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            node = leanLeft(container);
+            if (node) {
+              return after(node);
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // Find the text node and offset
-            while (sibling) {
-              if (sibling.nodeType == 3) {
-                nodeValue = sibling.nodeValue;
-                textNodeOffset += nodeValue.length;
-
-                // We are at or passed the position we where looking for
-                if (textNodeOffset >= offset) {
-                  container = sibling;
-                  textNodeOffset -= offset;
-                  textNodeOffset = nodeValue.length - textNodeOffset;
-                  break;
-                }
-              }
-
-              sibling = sibling.nextSibling;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (direction === -1) {
+            node = leanLeft(container);
+            if (node) {
+              return after(node);
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          } else {
-            // Find the text node and offset
-            sibling = container.previousSibling;
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (!sibling) {
-              return domRange[start ? 'setStartBefore' : 'setEndBefore'](container);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            node = leanRight(container);
+            if (node) {
+              return before(node);
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // If there isn't any text to loop then use the first position
-            if (!offset) {
-              if (container.nodeType == 3) {
-                domRange[start ? 'setStart' : 'setEnd'](sibling, container.nodeValue.length);
-              } else {
-                domRange[start ? 'setStartAfter' : 'setEndAfter'](sibling);
-              }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          return range;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (CaretContainer.endsWithCaretContainer(container) && offset >= container.data.length - 1) {
+          if (direction === 1) {
+            node = leanRight(container);
+            if (node) {
+              return before(node);
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            while (sibling) {
-              if (sibling.nodeType == 3) {
-                textNodeOffset += sibling.nodeValue.length;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          return range;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                // We are at or passed the position we where looking for
-                if (textNodeOffset >= offset) {
-                  container = sibling;
-                  textNodeOffset -= offset;
-                  break;
-                }
-              }
-
-              sibling = sibling.previousSibling;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (CaretContainer.startsWithCaretContainer(container) && offset <= 1) {
+          if (direction === -1) {
+            node = leanLeft(container);
+            if (node) {
+              return after(node);
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          domRange[start ? 'setStart' : 'setEnd'](container, textNodeOffset);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          return range;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        try {
-          // Find start point
-          findEndPoint(true);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (offset === container.data.length) {
+          node = leanRight(container);
+          if (node) {
+            return before(node);
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Find end point if needed
-          if (!collapsed) {
-            findEndPoint();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          return range;
+        }
+
+        if (offset === 0) {
+          node = leanLeft(container);
+          if (node) {
+            return after(node);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        } catch (ex) {
-          // IE has a nasty bug where text nodes might throw "invalid argument" when you
-          // access the nodeValue or other properties of text nodes. This seems to happen when
-          // text nodes are split into two nodes by a delete/backspace call.
-          // So let us detect and try to fix it.
-          if (ex.number == -2147024809) {
-            // Get the current selection
-            bookmark = self.getBookmark(2);
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // Get start element
-            tmpRange = ieRange.duplicate();
-            tmpRange.collapse(true);
-            element = tmpRange.parentElement();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          return range;
+        }
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // Get end element
-            if (!collapsed) {
-              tmpRange = ieRange.duplicate();
-              tmpRange.collapse(false);
-              element2 = tmpRange.parentElement();
-              element2.innerHTML = element2.innerHTML;
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return range;
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // Remove the broken elements
-            element.innerHTML = element.innerHTML;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function isNextToContentEditableFalse(relativeOffset, caretPosition) {
+      return isContentEditableFalse(getChildNodeAtRelativeOffset(relativeOffset, caretPosition));
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // Restore the selection
-            self.moveToBookmark(bookmark);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return {
+      isForwards: isForwards,
+      isBackwards: isBackwards,
+      findNode: findNode,
+      getEditingHost: getEditingHost,
+      getParentBlock: getParentBlock,
+      isInSameBlock: isInSameBlock,
+      isInSameEditingHost: isInSameEditingHost,
+      isBeforeContentEditableFalse: curry(isNextToContentEditableFalse, 0),
+      isAfterContentEditableFalse: curry(isNextToContentEditableFalse, -1),
+      normalizeRange: normalizeRange
+    };
+  }
+);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // Since the range has moved we need to re-get it
-            ieRange = selection.getRng();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/**
+ * CaretWalker.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // Find start point
-            findEndPoint(true);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/**
+ * This module contains logic for moving around a virtual caret in logical order within a DOM element.
+ *
+ * It ignores the most obvious invalid caret locations such as within a script element or within a
+ * contentEditable=false element but it will return locations that isn't possible to render visually.
+ *
+ * @private
+ * @class tinymce.caret.CaretWalker
+ * @example
+ * var caretWalker = new CaretWalker(rootElm);
+ *
+ * var prevLogicalCaretPosition = caretWalker.prev(CaretPosition.fromRangeStart(range));
+ * var nextLogicalCaretPosition = caretWalker.next(CaretPosition.fromRangeEnd(range));
+ */
+define(
+  'tinymce.core.caret.CaretWalker',
+  [
+    "tinymce.core.dom.NodeType",
+    "tinymce.core.caret.CaretCandidate",
+    "tinymce.core.caret.CaretPosition",
+    "tinymce.core.caret.CaretUtils",
+    "tinymce.core.util.Arr",
+    "tinymce.core.util.Fun"
+  ],
+  function (NodeType, CaretCandidate, CaretPosition, CaretUtils, Arr, Fun) {
+    var isContentEditableFalse = NodeType.isContentEditableFalse,
+      isText = NodeType.isText,
+      isElement = NodeType.isElement,
+      isBr = NodeType.isBr,
+      isForwards = CaretUtils.isForwards,
+      isBackwards = CaretUtils.isBackwards,
+      isCaretCandidate = CaretCandidate.isCaretCandidate,
+      isAtomic = CaretCandidate.isAtomic,
+      isEditableCaretCandidate = CaretCandidate.isEditableCaretCandidate;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // Find end point if needed
-            if (!collapsed) {
-              findEndPoint();
-            }
-          } else {
-            throw ex; // Throw other errors
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function getParents(node, rootNode) {
+      var parents = [];
+
+      while (node && node != rootNode) {
+        parents.push(node);
+        node = node.parentNode;
+      }
+
+      return parents;
+    }
+
+    function nodeAtIndex(container, offset) {
+      if (container.hasChildNodes() && offset < container.childNodes.length) {
+        return container.childNodes[offset];
+      }
+
+      return null;
+    }
+
+    function getCaretCandidatePosition(direction, node) {
+      if (isForwards(direction)) {
+        if (isCaretCandidate(node.previousSibling) && !isText(node.previousSibling)) {
+          return CaretPosition.before(node);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return domRange;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (isText(node)) {
+          return CaretPosition(node, 0);
+        }
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      this.getBookmark = function (type) {
-        var rng = selection.getRng(), bookmark = {};
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (isBackwards(direction)) {
+        if (isCaretCandidate(node.nextSibling) && !isText(node.nextSibling)) {
+          return CaretPosition.after(node);
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function getIndexes(node) {
-          var parent, root, children, i, indexes = [];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (isText(node)) {
+          return CaretPosition(node, node.data.length);
+        }
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          parent = node.parentNode;
-          root = dom.getRoot().parentNode;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (isBackwards(direction)) {
+        if (isBr(node)) {
+          return CaretPosition.before(node);
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          while (parent != root && parent.nodeType !== 9) {
-            children = parent.children;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return CaretPosition.after(node);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            i = children.length;
-            while (i--) {
-              if (node === children[i]) {
-                indexes.push(i);
-                break;
-              }
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return CaretPosition.before(node);
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            node = parent;
-            parent = parent.parentNode;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Jumps over BR elements <p>|<br></p><p>a</p> -> <p><br></p><p>|a</p>
+    function isBrBeforeBlock(node, rootNode) {
+      var next;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return indexes;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (!NodeType.isBr(node)) {
+        return false;
+      }
+
+      next = findCaretPosition(1, CaretPosition.after(node), rootNode);
+      if (!next) {
+        return false;
+      }
+
+      return !CaretUtils.isInSameBlock(CaretPosition.before(node), CaretPosition.before(next), rootNode);
+    }
+
+    function findCaretPosition(direction, startCaretPosition, rootNode) {
+      var container, offset, node, nextNode, innerNode,
+        rootContentEditableFalseElm, caretPosition;
+
+      if (!isElement(rootNode) || !startCaretPosition) {
+        return null;
+      }
+
+      if (startCaretPosition.isEqual(CaretPosition.after(rootNode)) && rootNode.lastChild) {
+        caretPosition = CaretPosition.after(rootNode.lastChild);
+        if (isBackwards(direction) && isCaretCandidate(rootNode.lastChild) && isElement(rootNode.lastChild)) {
+          return isBr(rootNode.lastChild) ? CaretPosition.before(rootNode.lastChild) : caretPosition;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      } else {
+        caretPosition = startCaretPosition;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function getBookmarkEndPoint(start) {
-          var position;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      container = caretPosition.container();
+      offset = caretPosition.offset();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          position = getPosition(rng, start);
-          if (position) {
-            return {
-              position: position.position,
-              offset: position.offset,
-              indexes: getIndexes(position.node),
-              inside: position.inside
-            };
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (isText(container)) {
+        if (isBackwards(direction) && offset > 0) {
+          return CaretPosition(container, --offset);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Non ubstructive bookmark
-        if (type === 2) {
-          // Handle text selection
-          if (!rng.item) {
-            bookmark.start = getBookmarkEndPoint(true);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (isForwards(direction) && offset < container.length) {
+          return CaretPosition(container, ++offset);
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (!selection.isCollapsed()) {
-              bookmark.end = getBookmarkEndPoint();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        node = container;
+      } else {
+        if (isBackwards(direction) && offset > 0) {
+          nextNode = nodeAtIndex(container, offset - 1);
+          if (isCaretCandidate(nextNode)) {
+            if (!isAtomic(nextNode)) {
+              innerNode = CaretUtils.findNode(nextNode, direction, isEditableCaretCandidate, nextNode);
+              if (innerNode) {
+                if (isText(innerNode)) {
+                  return CaretPosition(innerNode, innerNode.data.length);
+                }
+
+                return CaretPosition.after(innerNode);
+              }
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          } else {
-            bookmark.start = { ctrl: true, indexes: getIndexes(rng.item(0)) };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+            if (isText(nextNode)) {
+              return CaretPosition(nextNode, nextNode.data.length);
+            }
+
+            return CaretPosition.before(nextNode);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return bookmark;
-      };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (isForwards(direction) && offset < container.childNodes.length) {
+          nextNode = nodeAtIndex(container, offset);
+          if (isCaretCandidate(nextNode)) {
+            if (isBrBeforeBlock(nextNode, rootNode)) {
+              return findCaretPosition(direction, CaretPosition.after(nextNode), rootNode);
+            }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      this.moveToBookmark = function (bookmark) {
-        var rng, body = dom.doc.body;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            if (!isAtomic(nextNode)) {
+              innerNode = CaretUtils.findNode(nextNode, direction, isEditableCaretCandidate, nextNode);
+              if (innerNode) {
+                if (isText(innerNode)) {
+                  return CaretPosition(innerNode, 0);
+                }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function resolveIndexes(indexes) {
-          var node, i, idx, children;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                return CaretPosition.before(innerNode);
+              }
+            }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          node = dom.getRoot();
-          for (i = indexes.length - 1; i >= 0; i--) {
-            children = node.children;
-            idx = indexes[i];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            if (isText(nextNode)) {
+              return CaretPosition(nextNode, 0);
+            }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (idx <= children.length - 1) {
-              node = children[idx];
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            return CaretPosition.after(nextNode);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return node;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        node = caretPosition.getNode();
+      }
+
+      if ((isForwards(direction) && caretPosition.isAtEnd()) || (isBackwards(direction) && caretPosition.isAtStart())) {
+        node = CaretUtils.findNode(node, direction, Fun.constant(true), rootNode, true);
+        if (isEditableCaretCandidate(node)) {
+          return getCaretCandidatePosition(direction, node);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function setBookmarkEndPoint(start) {
-          var endPoint = bookmark[start ? 'start' : 'end'], moveLeft, moveRng, undef, offset;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      nextNode = CaretUtils.findNode(node, direction, isEditableCaretCandidate, rootNode);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (endPoint) {
-            moveLeft = endPoint.position > 0;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      rootContentEditableFalseElm = Arr.last(Arr.filter(getParents(container, rootNode), isContentEditableFalse));
+      if (rootContentEditableFalseElm && (!nextNode || !rootContentEditableFalseElm.contains(nextNode))) {
+        if (isForwards(direction)) {
+          caretPosition = CaretPosition.after(rootContentEditableFalseElm);
+        } else {
+          caretPosition = CaretPosition.before(rootContentEditableFalseElm);
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            moveRng = body.createTextRange();
-            moveRng.moveToElementText(resolveIndexes(endPoint.indexes));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return caretPosition;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            offset = endPoint.offset;
-            if (offset !== undef) {
-              moveRng.collapse(endPoint.inside || moveLeft);
-              moveRng.moveStart('character', moveLeft ? -offset : offset);
-            } else {
-              moveRng.collapse(start);
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (nextNode) {
+        return getCaretCandidatePosition(direction, nextNode);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            rng.setEndPoint(start ? 'StartToStart' : 'EndToStart', moveRng);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return null;
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (start) {
-              rng.collapse(true);
-            }
-          }
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return function (rootNode) {
+      return {
+        /**
+         * Returns the next logical caret position from the specificed input
+         * caretPoisiton or null if there isn't any more positions left for example
+         * at the end specified root element.
+         *
+         * @method next
+         * @param {tinymce.caret.CaretPosition} caretPosition Caret position to start from.
+         * @return {tinymce.caret.CaretPosition} CaretPosition or null if no position was found.
+         */
+        next: function (caretPosition) {
+          return findCaretPosition(1, caretPosition, rootNode);
+        },
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (bookmark.start) {
-          if (bookmark.start.ctrl) {
-            rng = body.createControlRange();
-            rng.addElement(resolveIndexes(bookmark.start.indexes));
-            rng.select();
-          } else {
-            rng = body.createTextRange();
-            setBookmarkEndPoint(true);
-            setBookmarkEndPoint();
-            rng.select();
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+         * Returns the previous logical caret position from the specificed input
+         * caretPoisiton or null if there isn't any more positions left for example
+         * at the end specified root element.
+         *
+         * @method prev
+         * @param {tinymce.caret.CaretPosition} caretPosition Caret position to start from.
+         * @return {tinymce.caret.CaretPosition} CaretPosition or null if no position was found.
+         */
+        prev: function (caretPosition) {
+          return findCaretPosition(-1, caretPosition, rootNode);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">       };
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    };
+  }
+);
+/**
+ * CaretFinder.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      this.addRange = function (rng) {
-        var ieRng, ctrlRng, startContainer, startOffset, endContainer, endOffset, sibling,
-          doc = selection.dom.doc, body = doc.body, nativeRng, ctrlElm;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+define(
+  'tinymce.core.caret.CaretFinder',
+  [
+    'ephox.katamari.api.Fun',
+    'ephox.katamari.api.Option',
+    'tinymce.core.caret.CaretCandidate',
+    'tinymce.core.caret.CaretPosition',
+    'tinymce.core.caret.CaretUtils',
+    'tinymce.core.caret.CaretWalker',
+    'tinymce.core.dom.NodeType'
+  ],
+  function (Fun, Option, CaretCandidate, CaretPosition, CaretUtils, CaretWalker, NodeType) {
+    var walkToPositionIn = function (forward, rootNode, startNode) {
+      var position = forward ? CaretPosition.before(startNode) : CaretPosition.after(startNode);
+      return fromPosition(forward, rootNode, position);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function setEndPoint(start) {
-          var container, offset, marker, tmpRng, nodes;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var afterElement = function (node) {
+      return NodeType.isBr(node) ? CaretPosition.before(node) : CaretPosition.after(node);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          marker = dom.create('a');
-          container = start ? startContainer : endContainer;
-          offset = start ? startOffset : endOffset;
-          tmpRng = ieRng.duplicate();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isBeforeOrStart = function (position) {
+      if (CaretPosition.isTextPosition(position)) {
+        return position.offset() === 0;
+      } else {
+        return CaretCandidate.isCaretCandidate(position.getNode());
+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (container == doc || container == doc.documentElement) {
-            container = body;
-            offset = 0;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isAfterOrEnd = function (position) {
+      if (CaretPosition.isTextPosition(position)) {
+        return position.offset() === position.container().data.length;
+      } else {
+        return CaretCandidate.isCaretCandidate(position.getNode(true));
+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (container.nodeType == 3) {
-            container.parentNode.insertBefore(marker, container);
-            tmpRng.moveToElementText(marker);
-            tmpRng.moveStart('character', offset);
-            dom.remove(marker);
-            ieRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', tmpRng);
-          } else {
-            nodes = container.childNodes;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isBeforeAfterSameElement = function (from, to) {
+      return !CaretPosition.isTextPosition(from) && !CaretPosition.isTextPosition(to) && from.getNode() === to.getNode(true);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (nodes.length) {
-              if (offset >= nodes.length) {
-                dom.insertAfter(marker, nodes[nodes.length - 1]);
-              } else {
-                container.insertBefore(marker, nodes[offset]);
-              }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isAtBr = function (position) {
+      return !CaretPosition.isTextPosition(position) && NodeType.isBr(position.getNode());
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              tmpRng.moveToElementText(marker);
-            } else if (container.canHaveHTML) {
-              // Empty node selection for example <div>|</div>
-              // Setting innerHTML with a span marker then remove that marker seems to keep empty block elements open
-              container.innerHTML = '<span>&#xFEFF;</span>';
-              marker = container.firstChild;
-              tmpRng.moveToElementText(marker);
-              tmpRng.collapse(FALSE); // Collapse false works better than true for some odd reason
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var shouldSkipPosition = function (forward, from, to) {
+      if (forward) {
+        return !isBeforeAfterSameElement(from, to) && !isAtBr(from) && isAfterOrEnd(from) && isBeforeOrStart(to);
+      } else {
+        return !isBeforeAfterSameElement(to, from) && isBeforeOrStart(from) && isAfterOrEnd(to);
+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            ieRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', tmpRng);
-            dom.remove(marker);
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Finds: <p>a|<b>b</b></p> -> <p>a<b>|b</b></p>
+    var fromPosition = function (forward, rootNode, position) {
+      var walker = new CaretWalker(rootNode);
+      return Option.from(forward ? walker.next(position) : walker.prev(position));
+    };
+
+    // Finds: <p>a|<b>b</b></p> -> <p>a<b>b|</b></p>
+    var navigate = function (forward, rootNode, from) {
+      return fromPosition(forward, rootNode, from).bind(function (to) {
+        if (CaretUtils.isInSameBlock(from, to, rootNode) && shouldSkipPosition(forward, from, to)) {
+          return fromPosition(forward, rootNode, to);
+        } else {
+          return Option.some(to);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      });
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Setup some shorter versions
-        startContainer = rng.startContainer;
-        startOffset = rng.startOffset;
-        endContainer = rng.endContainer;
-        endOffset = rng.endOffset;
-        ieRng = body.createTextRange();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var positionIn = function (forward, element) {
+      var startNode = forward ? element.firstChild : element.lastChild;
+      if (NodeType.isText(startNode)) {
+        return Option.some(new CaretPosition(startNode, forward ? 0 : startNode.data.length));
+      } else if (startNode) {
+        if (CaretCandidate.isCaretCandidate(startNode)) {
+          return Option.some(forward ? CaretPosition.before(startNode) : afterElement(startNode));
+        } else {
+          return walkToPositionIn(forward, element, startNode);
+        }
+      } else {
+        return Option.none();
+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // If single element selection then try making a control selection out of it
-        if (startContainer == endContainer && startContainer.nodeType == 1) {
-          // Trick to place the caret inside an empty block element like <p></p>
-          if (startOffset == endOffset && !startContainer.hasChildNodes()) {
-            if (startContainer.canHaveHTML) {
-              // Check if previous sibling is an empty block if it is then we need to render it
-              // IE would otherwise move the caret into the sibling instead of the empty startContainer see: #5236
-              // Example this: <p></p><p>|</p> would become this: <p>|</p><p></p>
-              sibling = startContainer.previousSibling;
-              if (sibling && !sibling.hasChildNodes() && dom.isBlock(sibling)) {
-                sibling.innerHTML = '&#xFEFF;';
-              } else {
-                sibling = null;
-              }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return {
+      fromPosition: fromPosition,
+      nextPosition: Fun.curry(fromPosition, true),
+      prevPosition: Fun.curry(fromPosition, false),
+      navigate: navigate,
+      positionIn: positionIn,
+      firstPositionIn: Fun.curry(positionIn, true),
+      lastPositionIn: Fun.curry(positionIn, false)
+    };
+  }
+);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              startContainer.innerHTML = '<span>&#xFEFF;</span><span>&#xFEFF;</span>';
-              ieRng.moveToElementText(startContainer.lastChild);
-              ieRng.select();
-              dom.doc.selection.clear();
-              startContainer.innerHTML = '';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/**
+ * RangeNormalizer.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              if (sibling) {
-                sibling.innerHTML = '';
-              }
-              return;
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+define(
+  'tinymce.core.dom.RangeNormalizer',
+  [
+    'tinymce.core.caret.CaretFinder',
+    'tinymce.core.caret.CaretPosition',
+    'tinymce.core.caret.CaretUtils'
+  ],
+  function (CaretFinder, CaretPosition, CaretUtils) {
+    var createRange = function (sc, so, ec, eo) {
+      var rng = document.createRange();
+      rng.setStart(sc, so);
+      rng.setEnd(ec, eo);
+      return rng;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            startOffset = dom.nodeIndex(startContainer);
-            startContainer = startContainer.parentNode;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // If you triple click a paragraph in this case:
+    //   <blockquote><p>a</p></blockquote><p>b</p>
+    // It would become this range in webkit:
+    //   <blockquote><p>[a</p></blockquote><p>]b</p>
+    // We would want it to be:
+    //   <blockquote><p>[a]</p></blockquote><p>b</p>
+    // Since it would otherwise produces spans out of thin air on insertContent for example.
+    var normalizeBlockSelectionRange = function (rng) {
+      var startPos = CaretPosition.fromRangeStart(rng);
+      var endPos = CaretPosition.fromRangeEnd(rng);
+      var rootNode = rng.commonAncestorContainer;
+
+      return CaretFinder.fromPosition(false, rootNode, endPos)
+        .map(function (newEndPos) {
+          if (!CaretUtils.isInSameBlock(startPos, endPos, rootNode) && CaretUtils.isInSameBlock(startPos, newEndPos, rootNode)) {
+            return createRange(startPos.container(), startPos.offset(), newEndPos.container(), newEndPos.offset());
+          } else {
+            return rng;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        }).getOr(rng);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (startOffset == endOffset - 1) {
-            try {
-              ctrlElm = startContainer.childNodes[startOffset];
-              ctrlRng = body.createControlRange();
-              ctrlRng.addElement(ctrlElm);
-              ctrlRng.select();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var normalizeBlockSelection = function (rng) {
+      return rng.collapsed ? rng : normalizeBlockSelectionRange(rng);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              // Check if the range produced is on the correct element and is a control range
-              // On IE 8 it will select the parent contentEditable container if you select an inner element see: #5398
-              nativeRng = selection.getRng();
-              if (nativeRng.item && ctrlElm === nativeRng.item(0)) {
-                return;
-              }
-            } catch (ex) {
-              // Ignore
-            }
-          }
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var normalize = function (rng) {
+      return normalizeBlockSelection(rng);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Set start/end point of selection
-        setEndPoint(true);
-        setEndPoint();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return {
+      normalize: normalize
+    };
+  }
+);
+define("global!console", [], function () { if (typeof console === "undefined") console = { log: function () {} }; return console; });
+defineGlobal("global!document", document);
+define(
+  'ephox.sugar.api.node.Element',
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Select the new range and scroll it into view
-        ieRng.select();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  [
+    'ephox.katamari.api.Fun',
+    'global!Error',
+    'global!console',
+    'global!document'
+  ],
+
+  function (Fun, Error, console, document) {
+    var fromHtml = function (html, scope) {
+      var doc = scope || document;
+      var div = doc.createElement('div');
+      div.innerHTML = html;
+      if (!div.hasChildNodes() || div.childNodes.length > 1) {
+        console.error('HTML does not have a single root node', html);
+        throw 'HTML must have a single root node';
+      }
+      return fromDom(div.childNodes[0]);
+    };
+
+    var fromTag = function (tag, scope) {
+      var doc = scope || document;
+      var node = doc.createElement(tag);
+      return fromDom(node);
+    };
+
+    var fromText = function (text, scope) {
+      var doc = scope || document;
+      var node = doc.createTextNode(text);
+      return fromDom(node);
+    };
+
+    var fromDom = function (node) {
+      if (node === null || node === undefined) throw new Error('Node cannot be null or undefined');
+      return {
+        dom: Fun.constant(node)
</ins><span class="cx" style="display: block; padding: 0 10px">       };
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Expose range method
-      this.getRangeAt = getRange;
-    }
-
-    return Selection;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return {
+      fromHtml: fromHtml,
+      fromTag: fromTag,
+      fromText: fromText,
+      fromDom: fromDom
+    };
</ins><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -19787,59 +16349,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-define("global!console", [], function () { if (typeof console === "undefined") console = { log: function () {} }; return console; });
-defineGlobal("global!document", document);
</del><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'ephox.sugar.api.node.Element',
-
-  [
-    'ephox.katamari.api.Fun',
-    'global!Error',
-    'global!console',
-    'global!document'
-  ],
-
-  function (Fun, Error, console, document) {
-    var fromHtml = function (html, scope) {
-      var doc = scope || document;
-      var div = doc.createElement('div');
-      div.innerHTML = html;
-      if (!div.hasChildNodes() || div.childNodes.length > 1) {
-        console.error('HTML does not have a single root node', html);
-        throw 'HTML must have a single root node';
-      }
-      return fromDom(div.childNodes[0]);
-    };
-
-    var fromTag = function (tag, scope) {
-      var doc = scope || document;
-      var node = doc.createElement(tag);
-      return fromDom(node);
-    };
-
-    var fromText = function (text, scope) {
-      var doc = scope || document;
-      var node = doc.createTextNode(text);
-      return fromDom(node);
-    };
-
-    var fromDom = function (node) {
-      if (node === null || node === undefined) throw new Error('Node cannot be null or undefined');
-      return {
-        dom: Fun.constant(node)
-      };
-    };
-
-    return {
-      fromHtml: fromHtml,
-      fromTag: fromTag,
-      fromText: fromText,
-      fromDom: fromDom
-    };
-  }
-);
-
-define(
</del><span class="cx" style="display: block; padding: 0 10px">   'ephox.sugar.api.node.NodeTypes',
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -20208,151 +16718,6 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'ephox.sugar.api.node.Node',
-
-  [
-    'ephox.sugar.api.node.NodeTypes'
-  ],
-
-  function (NodeTypes) {
-    var name = function (element) {
-      var r = element.dom().nodeName;
-      return r.toLowerCase();
-    };
-
-    var type = function (element) {
-      return element.dom().nodeType;
-    };
-
-    var value = function (element) {
-      return element.dom().nodeValue;
-    };
-
-    var isType = function (t) {
-      return function (element) {
-        return type(element) === t;
-      };
-    };
-
-    var isComment = function (element) {
-      return type(element) === NodeTypes.COMMENT || name(element) === '#comment';
-    };
-
-    var isElement = isType(NodeTypes.ELEMENT);
-    var isText = isType(NodeTypes.TEXT);
-    var isDocument = isType(NodeTypes.DOCUMENT);
-
-    return {
-      name: name,
-      type: type,
-      value: value,
-      isElement: isElement,
-      isText: isText,
-      isDocument: isDocument,
-      isComment: isComment
-    };
-  }
-);
-
-define(
-  'ephox.sugar.api.properties.Attr',
-
-  [
-    'ephox.katamari.api.Type',
-    'ephox.katamari.api.Arr',
-    'ephox.katamari.api.Obj',
-    'ephox.sugar.api.node.Node',
-    'global!Error',
-    'global!console'
-  ],
-
-  /*
-   * Direct attribute manipulation has been around since IE8, but
-   * was apparently unstable until IE10.
-   */
-  function (Type, Arr, Obj, Node, Error, console) {
-    var rawSet = function (dom, key, value) {
-      /*
-       * JQuery coerced everything to a string, and silently did nothing on text node/null/undefined.
-       *
-       * We fail on those invalid cases, only allowing numbers and booleans.
-       */
-      if (Type.isString(value) || Type.isBoolean(value) || Type.isNumber(value)) {
-        dom.setAttribute(key, value + '');
-      } else {
-        console.error('Invalid call to Attr.set. Key ', key, ':: Value ', value, ':: Element ', dom);
-        throw new Error('Attribute value was not simple');
-      }
-    };
-
-    var set = function (element, key, value) {
-      rawSet(element.dom(), key, value);
-    };
-
-    var setAll = function (element, attrs) {
-      var dom = element.dom();
-      Obj.each(attrs, function (v, k) {
-        rawSet(dom, k, v);
-      });
-    };
-
-    var get = function (element, key) {
-      var v = element.dom().getAttribute(key);
-
-      // undefined is the more appropriate value for JS, and this matches JQuery
-      return v === null ? undefined : v;
-    };
-
-    var has = function (element, key) {
-      var dom = element.dom();
-
-      // return false for non-element nodes, no point in throwing an error
-      return dom && dom.hasAttribute ? dom.hasAttribute(key) : false;
-    };
-
-    var remove = function (element, key) {
-      element.dom().removeAttribute(key);
-    };
-
-    var hasNone = function (element) {
-      var attrs = element.dom().attributes;
-      return attrs === undefined || attrs === null || attrs.length === 0;
-    };
-
-    var clone = function (element) {
-      return Arr.foldl(element.dom().attributes, function (acc, attr) {
-        acc[attr.name] = attr.value;
-        return acc;
-      }, {});
-    };
-
-    var transferOne = function (source, destination, attr) {
-      // NOTE: We don't want to clobber any existing attributes
-      if (has(source, attr) && !has(destination, attr)) set(destination, attr, get(source, attr));        
-    };
-
-    // Transfer attributes(attrs) from source to destination, unless they are already present
-    var transfer = function (source, destination, attrs) {
-      if (!Node.isElement(source) || !Node.isElement(destination)) return;
-      Arr.each(attrs, function (attr) {
-        transferOne(source, destination, attr);
-      });
-    };
-
-    return {
-      clone: clone,
-      set: set,
-      setAll: setAll,
-      get: get,
-      has: has,
-      remove: remove,
-      hasNone: hasNone,
-      transfer: transfer
-    };
-  }
-);
-
-define(
</del><span class="cx" style="display: block; padding: 0 10px">   'ephox.sugar.api.dom.InsertAll',
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -20440,104 +16805,278 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'ephox.sugar.api.dom.Replication',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'ephox.sugar.api.node.Node',
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'ephox.sugar.api.properties.Attr',
-    'ephox.sugar.api.node.Element',
-    'ephox.sugar.api.dom.Insert',
-    'ephox.sugar.api.dom.InsertAll',
-    'ephox.sugar.api.dom.Remove',
-    'ephox.sugar.api.search.Traverse'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.sugar.api.node.NodeTypes'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Attr, Element, Insert, InsertAll, Remove, Traverse) {
-    var clone = function (original, deep) {
-      return Element.fromDom(original.dom().cloneNode(deep));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (NodeTypes) {
+    var name = function (element) {
+      var r = element.dom().nodeName;
+      return r.toLowerCase();
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    /** Shallow clone - just the tag, no children */
-    var shallow = function (original) {
-      return clone(original, false);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var type = function (element) {
+      return element.dom().nodeType;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    /** Deep clone - everything copied including children */
-    var deep = function (original) {
-      return clone(original, true);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var value = function (element) {
+      return element.dom().nodeValue;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    /** Shallow clone, with a new tag */
-    var shallowAs = function (original, tag) {
-      var nu = Element.fromTag(tag);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isType = function (t) {
+      return function (element) {
+        return type(element) === t;
+      };
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var attributes = Attr.clone(original);
-      Attr.setAll(nu, attributes);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isComment = function (element) {
+      return type(element) === NodeTypes.COMMENT || name(element) === '#comment';
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return nu;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isElement = isType(NodeTypes.ELEMENT);
+    var isText = isType(NodeTypes.TEXT);
+    var isDocument = isType(NodeTypes.DOCUMENT);
+
+    return {
+      name: name,
+      type: type,
+      value: value,
+      isElement: isElement,
+      isText: isText,
+      isDocument: isDocument,
+      isComment: isComment
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  }
+);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    /** Deep clone, with a new tag */
-    var copy = function (original, tag) {
-      var nu = shallowAs(original, tag);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+define(
+  'ephox.sugar.impl.NodeValue',
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // NOTE
-      // previously this used serialisation:
-      // nu.dom().innerHTML = original.dom().innerHTML;
-      //
-      // Clone should be equivalent (and faster), but if TD <-> TH toggle breaks, put it back.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  [
+    'ephox.sand.api.PlatformDetection',
+    'ephox.katamari.api.Option',
+    'global!Error'
+  ],
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var cloneChildren = Traverse.children(deep(original));
-      InsertAll.append(nu, cloneChildren);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (PlatformDetection, Option, Error) {
+    return function (is, name) {
+      var get = function (element) {
+        if (!is(element)) throw new Error('Can only get ' + name + ' value of a ' + name + ' node');
+        return getOption(element).getOr('');
+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return nu;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var getOptionIE10 = function (element) {
+        // Prevent IE10 from throwing exception when setting parent innerHTML clobbers (TBIO-451).
+        try {
+          return getOptionSafe(element);
+        } catch (e) {
+          return Option.none();
+        }
+      };
+
+      var getOptionSafe = function (element) {
+        return is(element) ? Option.from(element.dom().nodeValue) : Option.none();
+      };
+
+      var browser = PlatformDetection.detect().browser;
+      var getOption = browser.isIE() && browser.version.major === 10 ? getOptionIE10 : getOptionSafe;
+
+      var set = function (element, value) {
+        if (!is(element)) throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node');
+        element.dom().nodeValue = value;
+      };
+
+      return {
+        get: get,
+        getOption: getOption,
+        set: set
+      };
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  }
+);
+define(
+  'ephox.sugar.api.node.Text',
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    /** Change the tag name, but keep all children */
-    var mutate = function (original, tag) {
-      var nu = shallowAs(original, tag);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  [
+    'ephox.sugar.api.node.Node',
+    'ephox.sugar.impl.NodeValue'
+  ],
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      Insert.before(original, nu);
-      var children = Traverse.children(original);
-      InsertAll.append(nu, children);
-      Remove.remove(original);
-      return nu;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Node, NodeValue) {
+    var api = NodeValue(Node.isText, 'text');
+
+    var get = function (element) {
+      return api.get(element);
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var getOption = function (element) {
+      return api.getOption(element);
+    };
+
+    var set = function (element, value) {
+      api.set(element, value);
+    };
+
</ins><span class="cx" style="display: block; padding: 0 10px">     return {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      shallow: shallow,
-      shallowAs: shallowAs,
-      deep: deep,
-      copy: copy,
-      mutate: mutate
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      get: get,
+      getOption: getOption,
+      set: set
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'ephox.sugar.api.node.Fragment',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'ephox.sugar.api.node.Body',
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'ephox.katamari.api.Arr',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.katamari.api.Thunk',
</ins><span class="cx" style="display: block; padding: 0 10px">     'ephox.sugar.api.node.Element',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.sugar.api.node.Node',
</ins><span class="cx" style="display: block; padding: 0 10px">     'global!document'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Arr, Element, document) {
-    var fromElements = function (elements, scope) {
-      var doc = scope || document;
-      var fragment = doc.createDocumentFragment();
-      Arr.each(elements, function (element) {
-        fragment.appendChild(element.dom());
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Thunk, Element, Node, document) {
+
+    // Node.contains() is very, very, very good performance
+    // http://jsperf.com/closest-vs-contains/5
+    var inBody = function (element) {
+      // Technically this is only required on IE, where contains() returns false for text nodes.
+      // But it's cheap enough to run everywhere and Sugar doesn't have platform detection (yet).
+      var dom = Node.isText(element) ? element.dom().parentNode : element.dom();
+
+      // use ownerDocument.body to ensure this works inside iframes.
+      // Normally contains is bad because an element "contains" itself, but here we want that.
+      return dom !== undefined && dom !== null && dom.ownerDocument.body.contains(dom);
+    };
+
+    var body = Thunk.cached(function() {
+      return getBody(Element.fromDom(document));
+    });
+
+    var getBody = function (doc) {
+      var body = doc.dom().body;
+      if (body === null || body === undefined) throw 'Body is not available yet';
+      return Element.fromDom(body);
+    };
+
+    return {
+      body: body,
+      getBody: getBody,
+      inBody: inBody
+    };
+  }
+);
+
+define(
+  'ephox.sugar.api.search.PredicateFilter',
+
+  [
+    'ephox.katamari.api.Arr',
+    'ephox.sugar.api.node.Body',
+    'ephox.sugar.api.search.Traverse'
+  ],
+
+  function (Arr, Body, Traverse) {
+    // maybe TraverseWith, similar to traverse but with a predicate?
+
+    var all = function (predicate) {
+      return descendants(Body.body(), predicate);
+    };
+
+    var ancestors = function (scope, predicate, isRoot) {
+      return Arr.filter(Traverse.parents(scope, isRoot), predicate);
+    };
+
+    var siblings = function (scope, predicate) {
+      return Arr.filter(Traverse.siblings(scope), predicate);
+    };
+
+    var children = function (scope, predicate) {
+      return Arr.filter(Traverse.children(scope), predicate);
+    };
+
+    var descendants = function (scope, predicate) {
+      var result = [];
+
+      // Recurse.toArray() might help here
+      Arr.each(Traverse.children(scope), function (x) {
+        if (predicate(x)) {
+          result = result.concat([ x ]);
+        }
+        result = result.concat(descendants(x, predicate));
</ins><span class="cx" style="display: block; padding: 0 10px">       });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return Element.fromDom(fragment);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return result;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     return {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      fromElements: fromElements
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      all: all,
+      ancestors: ancestors,
+      siblings: siblings,
+      children: children,
+      descendants: descendants
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+define(
+  'ephox.sugar.api.search.SelectorFilter',
+
+  [
+    'ephox.sugar.api.search.PredicateFilter',
+    'ephox.sugar.api.search.Selectors'
+  ],
+
+  function (PredicateFilter, Selectors) {
+    var all = function (selector) {
+      return Selectors.all(selector);
+    };
+
+    // For all of the following:
+    //
+    // jQuery does siblings of firstChild. IE9+ supports scope.dom().children (similar to Traverse.children but elements only).
+    // Traverse should also do this (but probably not by default).
+    //
+
+    var ancestors = function (scope, selector, isRoot) {
+      // It may surprise you to learn this is exactly what JQuery does
+      // TODO: Avoid all this wrapping and unwrapping
+      return PredicateFilter.ancestors(scope, function (e) {
+        return Selectors.is(e, selector);
+      }, isRoot);
+    };
+
+    var siblings = function (scope, selector) {
+      // It may surprise you to learn this is exactly what JQuery does
+      // TODO: Avoid all the wrapping and unwrapping
+      return PredicateFilter.siblings(scope, function (e) {
+        return Selectors.is(e, selector);
+      });
+    };
+
+    var children = function (scope, selector) {
+      // It may surprise you to learn this is exactly what JQuery does
+      // TODO: Avoid all the wrapping and unwrapping
+      return PredicateFilter.children(scope, function (e) {
+        return Selectors.is(e, selector);
+      });
+    };
+
+    var descendants = function (scope, selector) {
+      return Selectors.all(selector, scope);
+    };
+
+    return {
+      all: all,
+      ancestors: ancestors,
+      siblings: siblings,
+      children: children,
+      descendants: descendants
+    };
+  }
+);
+
</ins><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px">  * ElementType.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -20571,6 +17110,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">     ];
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var tableCells = ['td', 'th'];
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var tableSections = ['thead', 'tbody', 'tfoot'];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var textBlocks = [
</span><span class="cx" style="display: block; padding: 0 10px">       'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'div', 'address', 'pre', 'form',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -20579,6 +17119,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">     ];
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var headings = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var listItems = ['li', 'dd', 'dt'];
+    var lists = ['ul', 'ol', 'dl'];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var lazyLookup = function (items) {
</span><span class="cx" style="display: block; padding: 0 10px">       var lookup;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -20596,19 +17138,27 @@
</span><span class="cx" style="display: block; padding: 0 10px">       return Node.isElement(node) && !isBlock(node);
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isBr = function (node) {
+      return Node.isElement(node) && Node.name(node) === 'br';
+    };
+
</ins><span class="cx" style="display: block; padding: 0 10px">     return {
</span><span class="cx" style="display: block; padding: 0 10px">       isBlock: isBlock,
</span><span class="cx" style="display: block; padding: 0 10px">       isInline: isInline,
</span><span class="cx" style="display: block; padding: 0 10px">       isHeading: isHeading,
</span><span class="cx" style="display: block; padding: 0 10px">       isTextBlock: lazyLookup(textBlocks),
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      isList: lazyLookup(lists),
+      isListItem: lazyLookup(listItems),
</ins><span class="cx" style="display: block; padding: 0 10px">       isVoid: lazyLookup(voids),
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      isTableCell: lazyLookup(tableCells)
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      isTableSection: lazyLookup(tableSections),
+      isTableCell: lazyLookup(tableCells),
+      isBr: isBr
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Parents.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * PaddingBr.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -20618,101 +17168,71 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.dom.Parents',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.dom.PaddingBr',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'ephox.katamari.api.Fun',
-    'ephox.sugar.api.dom.Compare',
-    'ephox.sugar.api.search.Traverse'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.katamari.api.Arr',
+    'ephox.sugar.api.dom.Insert',
+    'ephox.sugar.api.dom.Remove',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.node.Node',
+    'ephox.sugar.api.node.Text',
+    'ephox.sugar.api.search.SelectorFilter',
+    'ephox.sugar.api.search.Traverse',
+    'tinymce.core.dom.ElementType'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Fun, Compare, Traverse) {
-    var dropLast = function (xs) {
-      return xs.slice(0, -1);
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Arr, Insert, Remove, Element, Node, Text, SelectorFilter, Traverse, ElementType) {
+    var getLastChildren = function (elm) {
+      var children = [], rawNode = elm.dom();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var parentsUntil = function (startNode, rootElm, predicate) {
-      if (Compare.contains(rootElm, startNode)) {
-        return dropLast(Traverse.parents(startNode, function (elm) {
-          return predicate(elm) || Compare.eq(elm, rootElm);
-        }));
-      } else {
-        return [];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      while (rawNode) {
+        children.push(Element.fromDom(rawNode));
+        rawNode = rawNode.lastChild;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var parents = function (startNode, rootElm) {
-      return parentsUntil(startNode, rootElm, Fun.constant(false));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return children;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var parentsAndSelf = function (startNode, rootElm) {
-      return [startNode].concat(parents(startNode, rootElm));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var removeTrailingBr = function (elm) {
+      var allBrs = SelectorFilter.descendants(elm, 'br');
+      var brs = Arr.filter(getLastChildren(elm).slice(-1), ElementType.isBr);
+      if (allBrs.length === brs.length) {
+        Arr.each(brs, Remove.remove);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return {
-      parentsUntil: parentsUntil,
-      parents: parents,
-      parentsAndSelf: parentsAndSelf
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var fillWithPaddingBr = function (elm) {
+      Remove.empty(elm);
+      Insert.append(elm, Element.fromHtml('<br data-mce-bogus="1">'));
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  }
-);
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-define(
-  'ephox.katamari.api.Options',
-
-  [
-    'ephox.katamari.api.Option'
-  ],
-
-  function (Option) {
-    /** cat :: [Option a] -> [a] */
-    var cat = function (arr) {
-      var r = [];
-      var push = function (x) {
-        r.push(x);
-      };
-      for (var i = 0; i < arr.length; i++) {
-        arr[i].each(push);
-      }
-      return r;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isPaddingContents = function (elm) {
+      return Node.isText(elm) ? Text.get(elm) === '\u00a0' : ElementType.isBr(elm);
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    /** findMap :: ([a], (a, Int -> Option b)) -> Option b */
-    var findMap = function (arr, f) {
-      for (var i = 0; i < arr.length; i++) {
-        var r = f(arr[i], i);
-        if (r.isSome()) {
-          return r;
-        }
-      }
-      return Option.none();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isPaddedElement = function (elm) {
+      return Arr.filter(Traverse.children(elm), isPaddingContents).length === 1;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    /**
-     * if all elements in arr are 'some', their inner values are passed as arguments to f
-     * f must have arity arr.length
-    */
-    var liftN = function(arr, f) {
-      var r = [];
-      for (var i = 0; i < arr.length; i++) {
-        var x = arr[i];
-        if (x.isSome()) {
-          r.push(x.getOrDie());
-        } else {
-          return Option.none();
-        }
-      }
-      return Option.some(f.apply(null, r));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var trimBlockTrailingBr = function (elm) {
+      Traverse.lastChild(elm).each(function (lastChild) {
+        Traverse.prevSibling(lastChild).each(function (lastChildPrevSibling) {
+          if (ElementType.isBlock(elm) && ElementType.isBr(lastChild) && ElementType.isBlock(lastChildPrevSibling)) {
+            Remove.remove(lastChild);
+          }
+        });
+      });
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     return {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      cat: cat,
-      findMap: findMap,
-      liftN: liftN
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      removeTrailingBr: removeTrailingBr,
+      fillWithPaddingBr: fillWithPaddingBr,
+      isPaddedElement: isPaddedElement,
+      trimBlockTrailingBr: trimBlockTrailingBr
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * SelectionUtils.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * FormatUtils.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -20722,155 +17242,187 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.selection.SelectionUtils',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.fmt.FormatUtils',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'ephox.katamari.api.Arr',
-    'ephox.katamari.api.Fun',
-    'ephox.katamari.api.Option',
-    'ephox.katamari.api.Options',
-    'ephox.sugar.api.dom.Compare',
-    'ephox.sugar.api.node.Element',
-    'ephox.sugar.api.node.Node',
-    'ephox.sugar.api.search.Traverse',
-    'tinymce.core.dom.NodeType'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.dom.TreeWalker'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Arr, Fun, Option, Options, Compare, Element, Node, Traverse, NodeType) {
-    var getStartNode = function (rng) {
-      var sc = rng.startContainer, so = rng.startOffset;
-      if (NodeType.isText(sc)) {
-        return so === 0 ? Option.some(Element.fromDom(sc)) : Option.none();
-      } else {
-        return Option.from(sc.childNodes[so]).map(Element.fromDom);
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (TreeWalker) {
+    var isInlineBlock = function (node) {
+      return node && /^(IMG)$/.test(node.nodeName);
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var getEndNode = function (rng) {
-      var ec = rng.endContainer, eo = rng.endOffset;
-      if (NodeType.isText(ec)) {
-        return eo === ec.data.length ? Option.some(Element.fromDom(ec)) : Option.none();
-      } else {
-        return Option.from(ec.childNodes[eo - 1]).map(Element.fromDom);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var moveStart = function (dom, selection, rng) {
+      var container = rng.startContainer,
+        offset = rng.startOffset,
+        walker, node, nodes;
+
+      if (rng.startContainer === rng.endContainer) {
+        if (isInlineBlock(rng.startContainer.childNodes[rng.startOffset])) {
+          return;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var getFirstChildren = function (node) {
-      return Traverse.firstChild(node).fold(
-        Fun.constant([node]),
-        function (child) {
-          return [node].concat(getFirstChildren(child));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Convert text node into index if possible
+      if (container.nodeType === 3 && offset >= container.nodeValue.length) {
+        // Get the parent container location and walk from there
+        offset = dom.nodeIndex(container);
+        container = container.parentNode;
+      }
+
+      // Move startContainer/startOffset in to a suitable node
+      if (container.nodeType === 1) {
+        nodes = container.childNodes;
+        if (offset < nodes.length) {
+          container = nodes[offset];
+          walker = new TreeWalker(container, dom.getParent(container, dom.isBlock));
+        } else {
+          container = nodes[nodes.length - 1];
+          walker = new TreeWalker(container, dom.getParent(container, dom.isBlock));
+          walker.next(true);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+        for (node = walker.current(); node; node = walker.next()) {
+          if (node.nodeType === 3 && !isWhiteSpaceNode(node)) {
+            rng.setStart(node, 0);
+            selection.setRng(rng);
+
+            return;
+          }
+        }
+      }
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var getLastChildren = function (node) {
-      return Traverse.lastChild(node).fold(
-        Fun.constant([node]),
-        function (child) {
-          if (Node.name(child) === 'br') {
-            return Traverse.prevSibling(child).map(function (sibling) {
-              return [node].concat(getLastChildren(sibling));
-            }).getOr([]);
-          } else {
-            return [node].concat(getLastChildren(child));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    /**
+     * Returns the next/previous non whitespace node.
+     *
+     * @private
+     * @param {Node} node Node to start at.
+     * @param {boolean} next (Optional) Include next or previous node defaults to previous.
+     * @param {boolean} inc (Optional) Include the current node in checking. Defaults to false.
+     * @return {Node} Next or previous node or undefined if it wasn't found.
+     */
+    var getNonWhiteSpaceSibling = function (node, next, inc) {
+      if (node) {
+        next = next ? 'nextSibling' : 'previousSibling';
+
+        for (node = inc ? node : node[next]; node; node = node[next]) {
+          if (node.nodeType === 1 || !isWhiteSpaceNode(node)) {
+            return node;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var hasAllContentsSelected = function (elm, rng) {
-      return Options.liftN([getStartNode(rng), getEndNode(rng)], function (startNode, endNode) {
-        var start = Arr.find(getFirstChildren(elm), Fun.curry(Compare.eq, startNode));
-        var end = Arr.find(getLastChildren(elm), Fun.curry(Compare.eq, endNode));
-        return start.isSome() && end.isSome();
-      }).getOr(false);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isTextBlock = function (editor, name) {
+      if (name.nodeType) {
+        name = name.nodeName;
+      }
+
+      return !!editor.schema.getTextBlockElements()[name.toLowerCase()];
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return {
-      hasAllContentsSelected: hasAllContentsSelected
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isValid = function (ed, parent, child) {
+      return ed.schema.isValidChild(parent, child);
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  }
-);
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * FragmentReader.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isWhiteSpaceNode = function (node) {
+      return node && node.nodeType === 3 && /^([\t \r\n]+|)$/.test(node.nodeValue);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-define(
-  'tinymce.core.selection.FragmentReader',
-  [
-    'ephox.katamari.api.Arr',
-    'ephox.katamari.api.Fun',
-    'ephox.sugar.api.dom.Insert',
-    'ephox.sugar.api.dom.Replication',
-    'ephox.sugar.api.node.Element',
-    'ephox.sugar.api.node.Fragment',
-    'ephox.sugar.api.node.Node',
-    'tinymce.core.dom.ElementType',
-    'tinymce.core.dom.Parents',
-    'tinymce.core.selection.SelectionUtils'
-  ],
-  function (Arr, Fun, Insert, Replication, Element, Fragment, Node, ElementType, Parents, SelectionUtils) {
-    var findParentListContainer = function (parents) {
-      return Arr.find(parents, function (elm) {
-        return Node.name(elm) === 'ul' || Node.name(elm) === 'ol';
-      });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    /**
+     * Replaces variables in the value. The variable format is %var.
+     *
+     * @private
+     * @param {String} value Value to replace variables in.
+     * @param {Object} vars Name/value array with variables to replace.
+     * @return {String} New value with replaced variables.
+     */
+    var replaceVars = function (value, vars) {
+      if (typeof value !== "string") {
+        value = value(vars);
+      } else if (vars) {
+        value = value.replace(/%(\w+)/g, function (str, name) {
+          return vars[name] || str;
+        });
+      }
+
+      return value;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var getFullySelectedListWrappers = function (parents, rng) {
-      return Arr.find(parents, function (elm) {
-        return Node.name(elm) === 'li' && SelectionUtils.hasAllContentsSelected(elm, rng);
-      }).fold(
-        Fun.constant([]),
-        function (li) {
-          return findParentListContainer(parents).map(function (listCont) {
-            return [
-              Element.fromTag('li'),
-              Element.fromTag(Node.name(listCont))
-            ];
-          }).getOr([]);
-        }
-      );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    /**
+     * Compares two string/nodes regardless of their case.
+     *
+     * @private
+     * @param {String/Node} str1 Node or string to compare.
+     * @param {String/Node} str2 Node or string to compare.
+     * @return {boolean} True/false if they match.
+     */
+    var isEq = function (str1, str2) {
+      str1 = str1 || '';
+      str2 = str2 || '';
+
+      str1 = '' + (str1.nodeName || str1);
+      str2 = '' + (str2.nodeName || str2);
+
+      return str1.toLowerCase() === str2.toLowerCase();
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var wrap = function (innerElm, elms) {
-      var wrapped = Arr.foldl(elms, function (acc, elm) {
-        Insert.append(elm, acc);
-        return elm;
-      }, innerElm);
-      return elms.length > 0 ? Fragment.fromElements([wrapped]) : wrapped;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var normalizeStyleValue = function (dom, value, name) {
+      // Force the format to hex
+      if (name === 'color' || name === 'backgroundColor') {
+        value = dom.toHex(value);
+      }
+
+      // Opera will return bold as 700
+      if (name === 'fontWeight' && value === 700) {
+        value = 'bold';
+      }
+
+      // Normalize fontFamily so "'Font name', Font" becomes: "Font name,Font"
+      if (name === 'fontFamily') {
+        value = value.replace(/[\'\"]/g, '').replace(/,\s+/g, ',');
+      }
+
+      return '' + value;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var getWrapElements = function (rootNode, rng) {
-      var parents = Parents.parentsAndSelf(Element.fromDom(rng.commonAncestorContainer), Element.fromDom(rootNode));
-      var wrapElements = Arr.filter(parents, function (elm) {
-        return ElementType.isInline(elm) || ElementType.isHeading(elm);
-      });
-      var fullWrappers = getFullySelectedListWrappers(parents, rng);
-      return Arr.map(wrapElements.concat(fullWrappers), Replication.shallow);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var getStyle = function (dom, node, name) {
+      return normalizeStyleValue(dom, dom.getStyle(node, name), name);
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var getFragmentFromRange = function (rootNode, rng) {
-      return wrap(Element.fromDom(rng.cloneContents()), getWrapElements(rootNode, rng));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var getTextDecoration = function (dom, node) {
+      var decoration;
+
+      dom.getParent(node, function (n) {
+        decoration = dom.getStyle(n, 'text-decoration');
+        return decoration && decoration !== 'none';
+      });
+
+      return decoration;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var read = function (rootNode, rng) {
-      return rng.collapsed ? Fragment.fromElements([]) : getFragmentFromRange(rootNode, rng);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var getParents = function (dom, node, selector) {
+      return dom.getParents(node, selector, dom.getRoot());
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     return {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      read: read
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      isInlineBlock: isInlineBlock,
+      moveStart: moveStart,
+      getNonWhiteSpaceSibling: getNonWhiteSpaceSibling,
+      isTextBlock: isTextBlock,
+      isValid: isValid,
+      isWhiteSpaceNode: isWhiteSpaceNode,
+      replaceVars: replaceVars,
+      isEq: isEq,
+      normalizeStyleValue: normalizeStyleValue,
+      getStyle: getStyle,
+      getTextDecoration: getTextDecoration,
+      getParents: getParents
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Selection.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * ExpandRange.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -20879,1010 +17431,602 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Contributing: http://www.tinymce.com/contributing
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * This class handles text and control selection it's an crossbrowser utility class.
- * Consult the TinyMCE Wiki API for more details and examples on how to use this class.
- *
- * @class tinymce.dom.Selection
- * @example
- * // Getting the currently selected node for the active editor
- * alert(tinymce.activeEditor.selection.getNode().nodeName);
- */
</del><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.dom.Selection',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.fmt.ExpandRange',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.caret.CaretPosition',
</del><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.dom.BookmarkManager',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.dom.ControlSelection',
-    'tinymce.core.dom.NodeType',
-    'tinymce.core.dom.RangeUtils',
-    'tinymce.core.dom.ScrollIntoView',
</del><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.dom.TreeWalker',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.dom.TridentSelection',
-    'tinymce.core.Env',
-    'tinymce.core.selection.FragmentReader',
-    'tinymce.core.text.Zwsp',
-    'tinymce.core.util.Tools'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.fmt.FormatUtils'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (CaretPosition, BookmarkManager, ControlSelection, NodeType, RangeUtils, ScrollIntoView, TreeWalker, TridentSelection, Env, FragmentReader, Zwsp, Tools) {
-    var each = Tools.each, trim = Tools.trim;
-    var isIE = Env.ie;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (BookmarkManager, TreeWalker, FormatUtils) {
+    var isBookmarkNode = BookmarkManager.isBookmarkNode;
+    var getParents = FormatUtils.getParents, isWhiteSpaceNode = FormatUtils.isWhiteSpaceNode, isTextBlock = FormatUtils.isTextBlock;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var isValidRange = function (rng) {
-      if (!rng) {
-        return false;
-      } else if (rng.select) { // Native IE range still produced by placeCaretAt
-        return true;
-      } else {
-        var sc = rng.startContainer, ec = rng.endContainer;
-        return !!(sc && sc.parentNode && ec && ec.parentNode);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // This function walks down the tree to find the leaf at the selection.
+      // The offset is also returned as if node initially a leaf, the offset may be in the middle of the text node.
+    var findLeaf = function (node, offset) {
+      if (typeof offset === 'undefined') {
+        offset = node.nodeType === 3 ? node.length : node.childNodes.length;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    /**
-     * Constructs a new selection instance.
-     *
-     * @constructor
-     * @method Selection
-     * @param {tinymce.dom.DOMUtils} dom DOMUtils object reference.
-     * @param {Window} win Window to bind the selection object to.
-     * @param {tinymce.Editor} editor Editor instance of the selection.
-     * @param {tinymce.dom.Serializer} serializer DOM serialization class to use for getContent.
-     */
-    function Selection(dom, win, serializer, editor) {
-      var self = this;
-
-      self.dom = dom;
-      self.win = win;
-      self.serializer = serializer;
-      self.editor = editor;
-      self.bookmarkManager = new BookmarkManager(self);
-      self.controlSelection = new ControlSelection(self, editor);
-
-      // No W3C Range support
-      if (!self.win.getSelection) {
-        self.tridentSel = new TridentSelection(self);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      while (node && node.hasChildNodes()) {
+        node = node.childNodes[offset];
+        if (node) {
+          offset = node.nodeType === 3 ? node.length : node.childNodes.length;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return { node: node, offset: offset };
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    Selection.prototype = {
-      /**
-       * Move the selection cursor range to the specified node and offset.
-       * If there is no node specified it will move it to the first suitable location within the body.
-       *
-       * @method setCursorLocation
-       * @param {Node} node Optional node to put the cursor in.
-       * @param {Number} offset Optional offset from the start of the node to put the cursor at.
-       */
-      setCursorLocation: function (node, offset) {
-        var self = this, rng = self.dom.createRng();
-
-        if (!node) {
-          self._moveEndPoint(rng, self.editor.getBody(), true);
-          self.setRng(rng);
-        } else {
-          rng.setStart(node, offset);
-          rng.setEnd(node, offset);
-          self.setRng(rng);
-          self.collapse(false);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var excludeTrailingWhitespace = function (endContainer, endOffset) {
+      // Avoid applying formatting to a trailing space,
+      // but remove formatting from trailing space
+      var leaf = findLeaf(endContainer, endOffset);
+      if (leaf.node) {
+        while (leaf.node && leaf.offset === 0 && leaf.node.previousSibling) {
+          leaf = findLeaf(leaf.node.previousSibling);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      },
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Returns the selected contents using the DOM serializer passed in to this class.
-       *
-       * @method getContent
-       * @param {Object} args Optional settings class with for example output format text or html.
-       * @return {String} Selected contents in for example HTML format.
-       * @example
-       * // Alerts the currently selected contents
-       * alert(tinymce.activeEditor.selection.getContent());
-       *
-       * // Alerts the currently selected contents as plain text
-       * alert(tinymce.activeEditor.selection.getContent({format: 'text'}));
-       */
-      getContent: function (args) {
-        var self = this, rng = self.getRng(), tmpElm = self.dom.create("body");
-        var se = self.getSel(), whiteSpaceBefore, whiteSpaceAfter, fragment;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (leaf.node && leaf.offset > 0 && leaf.node.nodeType === 3 &&
+            leaf.node.nodeValue.charAt(leaf.offset - 1) === ' ') {
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        args = args || {};
-        whiteSpaceBefore = whiteSpaceAfter = '';
-        args.get = true;
-        args.format = args.format || 'html';
-        args.selection = true;
-        self.editor.fire('BeforeGetContent', args);
-
-        if (args.format === 'text') {
-          return self.isCollapsed() ? '' : Zwsp.trim(rng.text || (se.toString ? se.toString() : ''));
-        }
-
-        if (rng.cloneContents) {
-          fragment = args.contextual ? FragmentReader.read(self.editor.getBody(), rng).dom() : rng.cloneContents();
-          if (fragment) {
-            tmpElm.appendChild(fragment);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (leaf.offset > 1) {
+            endContainer = leaf.node;
+            endContainer.splitText(leaf.offset - 1);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        } else if (rng.item !== undefined || rng.htmlText !== undefined) {
-          // IE will produce invalid markup if elements are present that
-          // it doesn't understand like custom elements or HTML5 elements.
-          // Adding a BR in front of the contents and then remoiving it seems to fix it though.
-          tmpElm.innerHTML = '<br>' + (rng.item ? rng.item(0).outerHTML : rng.htmlText);
-          tmpElm.removeChild(tmpElm.firstChild);
-        } else {
-          tmpElm.innerHTML = rng.toString();
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Keep whitespace before and after
-        if (/^\s/.test(tmpElm.innerHTML)) {
-          whiteSpaceBefore = ' ';
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return endContainer;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (/\s+$/.test(tmpElm.innerHTML)) {
-          whiteSpaceAfter = ' ';
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isBogusBr = function (node) {
+      return node.nodeName === "BR" && node.getAttribute('data-mce-bogus') && !node.nextSibling;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        args.getInner = true;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var expandRng = function (editor, rng, format, remove) {
+      var lastIdx, endPoint,
+        startContainer = rng.startContainer,
+        startOffset = rng.startOffset,
+        endContainer = rng.endContainer,
+        endOffset = rng.endOffset,
+        dom = editor.dom;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        args.content = self.isCollapsed() ? '' : whiteSpaceBefore + self.serializer.serialize(tmpElm, args) + whiteSpaceAfter;
-        self.editor.fire('GetContent', args);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // This function walks up the tree if there is no siblings before/after the node
+      var findParentContainer = function (start) {
+        var container, parent, sibling, siblingName, root;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return args.content;
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        container = parent = start ? startContainer : endContainer;
+        siblingName = start ? 'previousSibling' : 'nextSibling';
+        root = dom.getRoot();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Sets the current selection to the specified content. If any contents is selected it will be replaced
-       * with the contents passed in to this function. If there is no selection the contents will be inserted
-       * where the caret is placed in the editor/page.
-       *
-       * @method setContent
-       * @param {String} content HTML contents to set could also be other formats depending on settings.
-       * @param {Object} args Optional settings object with for example data format.
-       * @example
-       * // Inserts some HTML contents at the current selection
-       * tinymce.activeEditor.selection.setContent('<strong>Some contents</strong>');
-       */
-      setContent: function (content, args) {
-        var self = this, rng = self.getRng(), caretNode, doc = self.win.document, frag, temp;
-
-        args = args || { format: 'html' };
-        args.set = true;
-        args.selection = true;
-        args.content = content;
-
-        // Dispatch before set content event
-        if (!args.no_events) {
-          self.editor.fire('BeforeSetContent', args);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // If it's a text node and the offset is inside the text
+        if (container.nodeType === 3 && !isWhiteSpaceNode(container)) {
+          if (start ? startOffset > 0 : endOffset < container.nodeValue.length) {
+            return container;
+          }
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        content = args.content;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /*eslint no-constant-condition:0 */
+        while (true) {
+          // Stop expanding on block elements
+          if (!format[0].block_expand && dom.isBlock(parent)) {
+            return parent;
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (rng.insertNode) {
-          // Make caret marker since insertNode places the caret in the beginning of text after insert
-          content += '<span id="__caret">_</span>';
-
-          // Delete and insert new node
-          if (rng.startContainer == doc && rng.endContainer == doc) {
-            // WebKit will fail if the body is empty since the range is then invalid and it can't insert contents
-            doc.body.innerHTML = content;
-          } else {
-            rng.deleteContents();
-
-            if (doc.body.childNodes.length === 0) {
-              doc.body.innerHTML = content;
-            } else {
-              // createContextualFragment doesn't exists in IE 9 DOMRanges
-              if (rng.createContextualFragment) {
-                rng.insertNode(rng.createContextualFragment(content));
-              } else {
-                // Fake createContextualFragment call in IE 9
-                frag = doc.createDocumentFragment();
-                temp = doc.createElement('div');
-
-                frag.appendChild(temp);
-                temp.outerHTML = content;
-
-                rng.insertNode(frag);
-              }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Walk left/right
+          for (sibling = parent[siblingName]; sibling; sibling = sibling[siblingName]) {
+            if (!isBookmarkNode(sibling) && !isWhiteSpaceNode(sibling) && !isBogusBr(sibling)) {
+              return parent;
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Move to caret marker
-          caretNode = self.dom.get('__caret');
-
-          // Make sure we wrap it compleatly, Opera fails with a simple select call
-          rng = doc.createRange();
-          rng.setStartBefore(caretNode);
-          rng.setEndBefore(caretNode);
-          self.setRng(rng);
-
-          // Remove the caret position
-          self.dom.remove('__caret');
-
-          try {
-            self.setRng(rng);
-          } catch (ex) {
-            // Might fail on Opera for some odd reason
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Check if we can move up are we at root level or body level
+          if (parent === root || parent.parentNode === root) {
+            container = parent;
+            break;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        } else {
-          if (rng.item) {
-            // Delete content and get caret text selection
-            doc.execCommand('Delete', false, null);
-            rng = self.getRng();
-          }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Explorer removes spaces from the beginning of pasted contents
-          if (/^\s+/.test(content)) {
-            rng.pasteHTML('<span id="__mce_tmp">_</span>' + content);
-            self.dom.remove('__mce_tmp');
-          } else {
-            rng.pasteHTML(content);
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          parent = parent.parentNode;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Dispatch set content event
-        if (!args.no_events) {
-          self.editor.fire('SetContent', args);
-        }
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return container;
+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Returns the start element of a selection range. If the start is in a text
-       * node the parent element will be returned.
-       *
-       * @method getStart
-       * @param {Boolean} real Optional state to get the real parent when the selection is collapsed not the closest element.
-       * @return {Element} Start element of selection range.
-       */
-      getStart: function (real) {
-        var self = this, rng = self.getRng(), startElement, parentElement, checkRng, node;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // If index based start position then resolve it
+      if (startContainer.nodeType === 1 && startContainer.hasChildNodes()) {
+        lastIdx = startContainer.childNodes.length - 1;
+        startContainer = startContainer.childNodes[startOffset > lastIdx ? lastIdx : startOffset];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (rng.duplicate || rng.item) {
-          // Control selection, return first item
-          if (rng.item) {
-            return rng.item(0);
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (startContainer.nodeType === 3) {
+          startOffset = 0;
+        }
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Get start element
-          checkRng = rng.duplicate();
-          checkRng.collapse(1);
-          startElement = checkRng.parentElement();
-          if (startElement.ownerDocument !== self.dom.doc) {
-            startElement = self.dom.getRoot();
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // If index based end position then resolve it
+      if (endContainer.nodeType === 1 && endContainer.hasChildNodes()) {
+        lastIdx = endContainer.childNodes.length - 1;
+        endContainer = endContainer.childNodes[endOffset > lastIdx ? lastIdx : endOffset - 1];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Check if range parent is inside the start element, then return the inner parent element
-          // This will fix issues when a single element is selected, IE would otherwise return the wrong start element
-          parentElement = node = rng.parentElement();
-          while ((node = node.parentNode)) {
-            if (node == startElement) {
-              startElement = parentElement;
-              break;
-            }
-          }
-
-          return startElement;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (endContainer.nodeType === 3) {
+          endOffset = endContainer.nodeValue.length;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        startElement = rng.startContainer;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Expands the node to the closes contentEditable false element if it exists
+      var findParentContentEditable = function (node) {
+        var parent = node;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (startElement.nodeType == 1 && startElement.hasChildNodes()) {
-          if (!real || !rng.collapsed) {
-            startElement = startElement.childNodes[Math.min(startElement.childNodes.length - 1, rng.startOffset)];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        while (parent) {
+          if (parent.nodeType === 1 && dom.getContentEditable(parent)) {
+            return dom.getContentEditable(parent) === "false" ? parent : node;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (startElement && startElement.nodeType == 3) {
-          return startElement.parentNode;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          parent = parent.parentNode;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return startElement;
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return node;
+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Returns the end element of a selection range. If the end is in a text
-       * node the parent element will be returned.
-       *
-       * @method getEnd
-       * @param {Boolean} real Optional state to get the real parent when the selection is collapsed not the closest element.
-       * @return {Element} End element of selection range.
-       */
-      getEnd: function (real) {
-        var self = this, rng = self.getRng(), endElement, endOffset;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var findWordEndPoint = function (container, offset, start) {
+        var walker, node, pos, lastTextNode;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (rng.duplicate || rng.item) {
-          if (rng.item) {
-            return rng.item(0);
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var findSpace = function (node, offset) {
+          var pos, pos2, str = node.nodeValue;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          rng = rng.duplicate();
-          rng.collapse(0);
-          endElement = rng.parentElement();
-          if (endElement.ownerDocument !== self.dom.doc) {
-            endElement = self.dom.getRoot();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (typeof offset === "undefined") {
+            offset = start ? str.length : 0;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (endElement && endElement.nodeName == 'BODY') {
-            return endElement.lastChild || endElement;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (start) {
+            pos = str.lastIndexOf(' ', offset);
+            pos2 = str.lastIndexOf('\u00a0', offset);
+            pos = pos > pos2 ? pos : pos2;
+
+            // Include the space on remove to avoid tag soup
+            if (pos !== -1 && !remove) {
+              pos++;
+            }
+          } else {
+            pos = str.indexOf(' ', offset);
+            pos2 = str.indexOf('\u00a0', offset);
+            pos = pos !== -1 && (pos2 === -1 || pos < pos2) ? pos : pos2;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return endElement;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          return pos;
+        };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        endElement = rng.endContainer;
-        endOffset = rng.endOffset;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (container.nodeType === 3) {
+          pos = findSpace(container, offset);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (endElement.nodeType == 1 && endElement.hasChildNodes()) {
-          if (!real || !rng.collapsed) {
-            endElement = endElement.childNodes[endOffset > 0 ? endOffset - 1 : endOffset];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (pos !== -1) {
+            return { container: container, offset: pos };
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (endElement && endElement.nodeType == 3) {
-          return endElement.parentNode;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          lastTextNode = container;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return endElement;
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Walk the nodes inside the block
+        walker = new TreeWalker(container, dom.getParent(container, dom.isBlock) || editor.getBody());
+        while ((node = walker[start ? 'prev' : 'next']())) {
+          if (node.nodeType === 3) {
+            lastTextNode = node;
+            pos = findSpace(node);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Returns a bookmark location for the current selection. This bookmark object
-       * can then be used to restore the selection after some content modification to the document.
-       *
-       * @method getBookmark
-       * @param {Number} type Optional state if the bookmark should be simple or not. Default is complex.
-       * @param {Boolean} normalized Optional state that enables you to get a position that it would be after normalization.
-       * @return {Object} Bookmark object, use moveToBookmark with this object to restore the selection.
-       * @example
-       * // Stores a bookmark of the current selection
-       * var bm = tinymce.activeEditor.selection.getBookmark();
-       *
-       * tinymce.activeEditor.setContent(tinymce.activeEditor.getContent() + 'Some new content');
-       *
-       * // Restore the selection bookmark
-       * tinymce.activeEditor.selection.moveToBookmark(bm);
-       */
-      getBookmark: function (type, normalized) {
-        return this.bookmarkManager.getBookmark(type, normalized);
-      },
-
-      /**
-       * Restores the selection to the specified bookmark.
-       *
-       * @method moveToBookmark
-       * @param {Object} bookmark Bookmark to restore selection from.
-       * @return {Boolean} true/false if it was successful or not.
-       * @example
-       * // Stores a bookmark of the current selection
-       * var bm = tinymce.activeEditor.selection.getBookmark();
-       *
-       * tinymce.activeEditor.setContent(tinymce.activeEditor.getContent() + 'Some new content');
-       *
-       * // Restore the selection bookmark
-       * tinymce.activeEditor.selection.moveToBookmark(bm);
-       */
-      moveToBookmark: function (bookmark) {
-        return this.bookmarkManager.moveToBookmark(bookmark);
-      },
-
-      /**
-       * Selects the specified element. This will place the start and end of the selection range around the element.
-       *
-       * @method select
-       * @param {Element} node HTML DOM element to select.
-       * @param {Boolean} content Optional bool state if the contents should be selected or not on non IE browser.
-       * @return {Element} Selected element the same element as the one that got passed in.
-       * @example
-       * // Select the first paragraph in the active editor
-       * tinymce.activeEditor.selection.select(tinymce.activeEditor.dom.select('p')[0]);
-       */
-      select: function (node, content) {
-        var self = this, dom = self.dom, rng = dom.createRng(), idx;
-
-        // Clear stored range set by FocusManager
-        self.lastFocusBookmark = null;
-
-        if (node) {
-          if (!content && self.controlSelection.controlSelect(node)) {
-            return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            if (pos !== -1) {
+              return { container: node, offset: pos };
+            }
+          } else if (dom.isBlock(node)) {
+            break;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          idx = dom.nodeIndex(node);
-          rng.setStart(node.parentNode, idx);
-          rng.setEnd(node.parentNode, idx + 1);
-
-          // Find first/last text node or BR element
-          if (content) {
-            self._moveEndPoint(rng, node, true);
-            self._moveEndPoint(rng, node);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (lastTextNode) {
+          if (start) {
+            offset = 0;
+          } else {
+            offset = lastTextNode.length;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          self.setRng(rng);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          return { container: lastTextNode, offset: offset };
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return node;
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var findSelectorEndPoint = function (container, siblingName) {
+        var parents, i, y, curFormat;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Returns true/false if the selection range is collapsed or not. Collapsed means if it's a caret or a larger selection.
-       *
-       * @method isCollapsed
-       * @return {Boolean} true/false state if the selection range is collapsed or not.
-       * Collapsed means if it's a caret or a larger selection.
-       */
-      isCollapsed: function () {
-        var self = this, rng = self.getRng(), sel = self.getSel();
-
-        if (!rng || rng.item) {
-          return false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (container.nodeType === 3 && container.nodeValue.length === 0 && container[siblingName]) {
+          container = container[siblingName];
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (rng.compareEndPoints) {
-          return rng.compareEndPoints('StartToEnd', rng) === 0;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        parents = getParents(dom, container);
+        for (i = 0; i < parents.length; i++) {
+          for (y = 0; y < format.length; y++) {
+            curFormat = format[y];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return !sel || rng.collapsed;
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // If collapsed state is set then skip formats that doesn't match that
+            if ("collapsed" in curFormat && curFormat.collapsed !== rng.collapsed) {
+              continue;
+            }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Collapse the selection to start or end of range.
-       *
-       * @method collapse
-       * @param {Boolean} toStart Optional boolean state if to collapse to end or not. Defaults to false.
-       */
-      collapse: function (toStart) {
-        var self = this, rng = self.getRng(), node;
-
-        // Control range on IE
-        if (rng.item) {
-          node = rng.item(0);
-          rng = self.win.document.body.createTextRange();
-          rng.moveToElementText(node);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            if (dom.is(parents[i], curFormat.selector)) {
+              return parents[i];
+            }
+          }
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        rng.collapse(!!toStart);
-        self.setRng(rng);
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return container;
+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Returns the browsers internal selection object.
-       *
-       * @method getSel
-       * @return {Selection} Internal browser selection object.
-       */
-      getSel: function () {
-        var win = this.win;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var findBlockEndPoint = function (container, siblingName) {
+        var node, root = dom.getRoot();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return win.getSelection ? win.getSelection() : win.document.selection;
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Expand to block of similar type
+        if (!format[0].wrapper) {
+          node = dom.getParent(container, format[0].block, root);
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Returns the browsers internal range object.
-       *
-       * @method getRng
-       * @param {Boolean} w3c Forces a compatible W3C range on IE.
-       * @return {Range} Internal browser range object.
-       * @see http://www.quirksmode.org/dom/range_intro.html
-       * @see http://www.dotvoid.com/2001/03/using-the-range-object-in-mozilla/
-       */
-      getRng: function (w3c) {
-        var self = this, selection, rng, elm, doc, ieRng, evt;
-
-        function tryCompareBoundaryPoints(how, sourceRange, destinationRange) {
-          try {
-            return sourceRange.compareBoundaryPoints(how, destinationRange);
-          } catch (ex) {
-            // Gecko throws wrong document exception if the range points
-            // to nodes that where removed from the dom #6690
-            // Browsers should mutate existing DOMRange instances so that they always point
-            // to something in the document this is not the case in Gecko works fine in IE/WebKit/Blink
-            // For performance reasons just return -1
-            return -1;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Expand to first wrappable block element or any block element
+        if (!node) {
+          var scopeRoot = dom.getParent(container, 'LI,TD,TH');
+          node = dom.getParent(container.nodeType === 3 ? container.parentNode : container, function (node) {
+            // Fixes #6183 where it would expand to editable parent element in inline mode
+            return node !== root && isTextBlock(editor, node);
+          }, scopeRoot);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (!self.win) {
-          return null;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Exclude inner lists from wrapping
+        if (node && format[0].wrapper) {
+          node = getParents(dom, node, 'ul,ol').reverse()[0] || node;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        doc = self.win.document;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Didn't find a block element look for first/last wrappable element
+        if (!node) {
+          node = container;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (typeof doc === 'undefined' || doc === null) {
-          return null;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          while (node[siblingName] && !dom.isBlock(node[siblingName])) {
+            node = node[siblingName];
+
+            // Break on BR but include it will be removed later on
+            // we can't remove it now since we need to check if it can be wrapped
+            if (FormatUtils.isEq(node, 'br')) {
+              break;
+            }
+          }
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Use last rng passed from FocusManager if it's available this enables
-        // calls to editor.selection.getStart() to work when caret focus is lost on IE
-        if (!w3c && self.lastFocusBookmark) {
-          var bookmark = self.lastFocusBookmark;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return node || container;
+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Convert bookmark to range IE 11 fix
-          if (bookmark.startContainer) {
-            rng = doc.createRange();
-            rng.setStart(bookmark.startContainer, bookmark.startOffset);
-            rng.setEnd(bookmark.endContainer, bookmark.endOffset);
-          } else {
-            rng = bookmark;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Expand to closest contentEditable element
+      startContainer = findParentContentEditable(startContainer);
+      endContainer = findParentContentEditable(endContainer);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return rng;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Exclude bookmark nodes if possible
+      if (isBookmarkNode(startContainer.parentNode) || isBookmarkNode(startContainer)) {
+        startContainer = isBookmarkNode(startContainer) ? startContainer : startContainer.parentNode;
+        startContainer = startContainer.nextSibling || startContainer;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Found tridentSel object then we need to use that one
-        if (w3c && self.tridentSel) {
-          return self.tridentSel.getRangeAt(0);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (startContainer.nodeType === 3) {
+          startOffset = 0;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        try {
-          if ((selection = self.getSel())) {
-            if (selection.rangeCount > 0) {
-              rng = selection.getRangeAt(0);
-            } else {
-              rng = selection.createRange ? selection.createRange() : doc.createRange();
-            }
-          }
-        } catch (ex) {
-          // IE throws unspecified error here if TinyMCE is placed in a frame/iframe
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (isBookmarkNode(endContainer.parentNode) || isBookmarkNode(endContainer)) {
+        endContainer = isBookmarkNode(endContainer) ? endContainer : endContainer.parentNode;
+        endContainer = endContainer.previousSibling || endContainer;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        evt = self.editor.fire('GetSelectionRange', { range: rng });
-        if (evt.range !== rng) {
-          return evt.range;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (endContainer.nodeType === 3) {
+          endOffset = endContainer.length;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // We have W3C ranges and it's IE then fake control selection since IE9 doesn't handle that correctly yet
-        // IE 11 doesn't support the selection object so we check for that as well
-        if (isIE && rng && rng.setStart && doc.selection) {
-          try {
-            // IE will sometimes throw an exception here
-            ieRng = doc.selection.createRange();
-          } catch (ex) {
-            // Ignore
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (format[0].inline) {
+        if (rng.collapsed) {
+          // Expand left to closest word boundary
+          endPoint = findWordEndPoint(startContainer, startOffset, true);
+          if (endPoint) {
+            startContainer = endPoint.container;
+            startOffset = endPoint.offset;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (ieRng && ieRng.item) {
-            elm = ieRng.item(0);
-            rng = doc.createRange();
-            rng.setStartBefore(elm);
-            rng.setEndAfter(elm);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Expand right to closest word boundary
+          endPoint = findWordEndPoint(endContainer, endOffset);
+          if (endPoint) {
+            endContainer = endPoint.container;
+            endOffset = endPoint.offset;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // No range found then create an empty one
-        // This can occur when the editor is placed in a hidden container element on Gecko
-        // Or on IE when there was an exception
-        if (!rng) {
-          rng = doc.createRange ? doc.createRange() : doc.body.createTextRange();
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        endContainer = remove ? endContainer : excludeTrailingWhitespace(endContainer, endOffset);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // If range is at start of document then move it to start of body
-        if (rng.setStart && rng.startContainer.nodeType === 9 && rng.collapsed) {
-          elm = self.dom.getRoot();
-          rng.setStart(elm, 0);
-          rng.setEnd(elm, 0);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Move start/end point up the tree if the leaves are sharp and if we are in different containers
+      // Example * becomes !: !<p><b><i>*text</i><i>text*</i></b></p>!
+      // This will reduce the number of wrapper elements that needs to be created
+      // Move start point up the tree
+      if (format[0].inline || format[0].block_expand) {
+        if (!format[0].inline || (startContainer.nodeType !== 3 || startOffset === 0)) {
+          startContainer = findParentContainer(true);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (self.selectedRange && self.explicitRange) {
-          if (tryCompareBoundaryPoints(rng.START_TO_START, rng, self.selectedRange) === 0 &&
-            tryCompareBoundaryPoints(rng.END_TO_END, rng, self.selectedRange) === 0) {
-            // Safari, Opera and Chrome only ever select text which causes the range to change.
-            // This lets us use the originally set range if the selection hasn't been changed by the user.
-            rng = self.explicitRange;
-          } else {
-            self.selectedRange = null;
-            self.explicitRange = null;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (!format[0].inline || (endContainer.nodeType !== 3 || endOffset === endContainer.nodeValue.length)) {
+          endContainer = findParentContainer();
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return rng;
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Expand start/end container to matching selector
+      if (format[0].selector && format[0].expand !== false && !format[0].inline) {
+        // Find new startContainer/endContainer if there is better one
+        startContainer = findSelectorEndPoint(startContainer, 'previousSibling');
+        endContainer = findSelectorEndPoint(endContainer, 'nextSibling');
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Changes the selection to the specified DOM range.
-       *
-       * @method setRng
-       * @param {Range} rng Range to select.
-       * @param {Boolean} forward Optional boolean if the selection is forwards or backwards.
-       */
-      setRng: function (rng, forward) {
-        var self = this, sel, node, evt;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Expand start/end container to matching block element or text node
+      if (format[0].block || format[0].selector) {
+        // Find new startContainer/endContainer if there is better one
+        startContainer = findBlockEndPoint(startContainer, 'previousSibling');
+        endContainer = findBlockEndPoint(endContainer, 'nextSibling');
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (!isValidRange(rng)) {
-          return;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Non block element then try to expand up the leaf
+        if (format[0].block) {
+          if (!dom.isBlock(startContainer)) {
+            startContainer = findParentContainer(true);
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Is IE specific range
-        if (rng.select) {
-          self.explicitRange = null;
-
-          try {
-            rng.select();
-          } catch (ex) {
-            // Needed for some odd IE bug #1843306
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (!dom.isBlock(endContainer)) {
+            endContainer = findParentContainer();
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-          return;
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (!self.tridentSel) {
-          sel = self.getSel();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Setup index for startContainer
+      if (startContainer.nodeType === 1) {
+        startOffset = dom.nodeIndex(startContainer);
+        startContainer = startContainer.parentNode;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          evt = self.editor.fire('SetSelectionRange', { range: rng, forward: forward });
-          rng = evt.range;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Setup index for endContainer
+      if (endContainer.nodeType === 1) {
+        endOffset = dom.nodeIndex(endContainer) + 1;
+        endContainer = endContainer.parentNode;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (sel) {
-            self.explicitRange = rng;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Return new range like object
+      return {
+        startContainer: startContainer,
+        startOffset: startOffset,
+        endContainer: endContainer,
+        endOffset: endOffset
+      };
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            try {
-              sel.removeAllRanges();
-              sel.addRange(rng);
-            } catch (ex) {
-              // IE might throw errors here if the editor is within a hidden container and selection is changed
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return {
+      expandRng: expandRng
+    };
+  }
+);
+/**
+ * MatchFormat.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // Forward is set to false and we have an extend function
-            if (forward === false && sel.extend) {
-              sel.collapse(rng.endContainer, rng.endOffset);
-              sel.extend(rng.startContainer, rng.startOffset);
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+define(
+  'tinymce.core.fmt.MatchFormat',
+  [
+    'tinymce.core.fmt.FormatUtils'
+  ],
+  function (FormatUtils) {
+    var isEq = FormatUtils.isEq;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // adding range isn't always successful so we need to check range count otherwise an exception can occur
-            self.selectedRange = sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var matchesUnInheritedFormatSelector = function (ed, node, name) {
+      var formatList = ed.formatter.get(name);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // WebKit egde case selecting images works better using setBaseAndExtent when the image is floated
-          if (!rng.collapsed && rng.startContainer === rng.endContainer && sel.setBaseAndExtent && !Env.ie) {
-            if (rng.endOffset - rng.startOffset < 2) {
-              if (rng.startContainer.hasChildNodes()) {
-                node = rng.startContainer.childNodes[rng.startOffset];
-                if (node && node.tagName === 'IMG') {
-                  sel.setBaseAndExtent(
-                    rng.startContainer,
-                    rng.startOffset,
-                    rng.endContainer,
-                    rng.endOffset
-                  );
-
-                  // Since the setBaseAndExtent is fixed in more recent Blink versions we
-                  // need to detect if it's doing the wrong thing and falling back to the
-                  // crazy incorrect behavior api call since that seems to be the only way
-                  // to get it to work on Safari WebKit as of 2017-02-23
-                  if (sel.anchorNode !== rng.startContainer || sel.focusNode !== rng.endContainer) {
-                    sel.setBaseAndExtent(node, 0, node, 1);
-                  }
-                }
-              }
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (formatList) {
+        for (var i = 0; i < formatList.length; i++) {
+          if (formatList[i].inherit === false && ed.dom.is(node, formatList[i].selector)) {
+            return true;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-          self.editor.fire('AfterSetSelectionRange', { range: rng, forward: forward });
-        } else {
-          // Is W3C Range fake range on IE
-          if (rng.cloneRange) {
-            try {
-              self.tridentSel.addRange(rng);
-            } catch (ex) {
-              //IE9 throws an error here if called before selection is placed in the editor
-            }
-          }
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Sets the current selection to the specified DOM element.
-       *
-       * @method setNode
-       * @param {Element} elm Element to set as the contents of the selection.
-       * @return {Element} Returns the element that got passed in.
-       * @example
-       * // Inserts a DOM node at current selection/caret location
-       * tinymce.activeEditor.selection.setNode(tinymce.activeEditor.dom.create('img', {src: 'some.gif', title: 'some title'}));
-       */
-      setNode: function (elm) {
-        var self = this;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return false;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        self.setContent(self.dom.getOuterHTML(elm));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var matchParents = function (editor, node, name, vars) {
+      var root = editor.dom.getRoot();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return elm;
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (node === root) {
+        return false;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Returns the currently selected element or the common ancestor element for both start and end of the selection.
-       *
-       * @method getNode
-       * @return {Element} Currently selected element or common ancestor element.
-       * @example
-       * // Alerts the currently selected elements node name
-       * alert(tinymce.activeEditor.selection.getNode().nodeName);
-       */
-      getNode: function () {
-        var self = this, rng = self.getRng(), elm;
-        var startContainer, endContainer, startOffset, endOffset, root = self.dom.getRoot();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Find first node with similar format settings
+      node = editor.dom.getParent(node, function (node) {
+        if (matchesUnInheritedFormatSelector(editor, node, name)) {
+          return true;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function skipEmptyTextNodes(node, forwards) {
-          var orig = node;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return node.parentNode === root || !!matchNode(editor, node, name, vars, true);
+      });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          while (node && node.nodeType === 3 && node.length === 0) {
-            node = forwards ? node.nextSibling : node.previousSibling;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Do an exact check on the similar format element
+      return matchNode(editor, node, name, vars);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return node || orig;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var matchName = function (dom, node, format) {
+      // Check for inline match
+      if (isEq(node, format.inline)) {
+        return true;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Range maybe lost after the editor is made visible again
-        if (!rng) {
-          return root;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Check for block match
+      if (isEq(node, format.block)) {
+        return true;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        startContainer = rng.startContainer;
-        endContainer = rng.endContainer;
-        startOffset = rng.startOffset;
-        endOffset = rng.endOffset;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Check for selector match
+      if (format.selector) {
+        return node.nodeType === 1 && dom.is(node, format.selector);
+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (rng.setStart) {
-          elm = rng.commonAncestorContainer;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var matchItems = function (dom, node, format, itemName, similar, vars) {
+      var key, value, items = format[itemName], i;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Handle selection a image or other control like element such as anchors
-          if (!rng.collapsed) {
-            if (startContainer == endContainer) {
-              if (endOffset - startOffset < 2) {
-                if (startContainer.hasChildNodes()) {
-                  elm = startContainer.childNodes[startOffset];
-                }
-              }
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Custom match
+      if (format.onmatch) {
+        return format.onmatch(node, format, itemName);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // If the anchor node is a element instead of a text node then return this element
-            //if (tinymce.isWebKit && sel.anchorNode && sel.anchorNode.nodeType == 1)
-            // return sel.anchorNode.childNodes[sel.anchorOffset];
-
-            // Handle cases where the selection is immediately wrapped around a node and return that node instead of it's parent.
-            // This happens when you double click an underlined word in FireFox.
-            if (startContainer.nodeType === 3 && endContainer.nodeType === 3) {
-              if (startContainer.length === startOffset) {
-                startContainer = skipEmptyTextNodes(startContainer.nextSibling, true);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Check all items
+      if (items) {
+        // Non indexed object
+        if (typeof items.length === 'undefined') {
+          for (key in items) {
+            if (items.hasOwnProperty(key)) {
+              if (itemName === 'attributes') {
+                value = dom.getAttrib(node, key);
</ins><span class="cx" style="display: block; padding: 0 10px">               } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                startContainer = startContainer.parentNode;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                value = FormatUtils.getStyle(dom, node, key);
</ins><span class="cx" style="display: block; padding: 0 10px">               }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              if (endOffset === 0) {
-                endContainer = skipEmptyTextNodes(endContainer.previousSibling, false);
-              } else {
-                endContainer = endContainer.parentNode;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              if (similar && !value && !format.exact) {
+                return;
</ins><span class="cx" style="display: block; padding: 0 10px">               }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              if (startContainer && startContainer === endContainer) {
-                return startContainer;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              if ((!similar || format.exact) && !isEq(value, FormatUtils.normalizeStyleValue(dom, FormatUtils.replaceVars(items[key], vars), key))) {
+                return;
</ins><span class="cx" style="display: block; padding: 0 10px">               }
</span><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-          if (elm && elm.nodeType == 3) {
-            return elm.parentNode;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        } else {
+          // Only one match needed for indexed arrays
+          for (i = 0; i < items.length; i++) {
+            if (itemName === 'attributes' ? dom.getAttrib(node, items[i]) : FormatUtils.getStyle(dom, node, items[i])) {
+              return format;
+            }
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-          return elm;
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        elm = rng.item ? rng.item(0) : rng.parentElement();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return format;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // IE 7 might return elements outside the iframe
-        if (elm.ownerDocument !== self.win.document) {
-          elm = root;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var matchNode = function (ed, node, name, vars, similar) {
+      var formatList = ed.formatter.get(name), format, i, x, classes, dom = ed.dom;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return elm;
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (formatList && node) {
+        // Check each format in list
+        for (i = 0; i < formatList.length; i++) {
+          format = formatList[i];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      getSelectedBlocks: function (startElm, endElm) {
-        var self = this, dom = self.dom, node, root, selectedBlocks = [];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Name name, attributes, styles and classes
+          if (matchName(ed.dom, node, format) && matchItems(dom, node, format, 'attributes', similar, vars) && matchItems(dom, node, format, 'styles', similar, vars)) {
+            // Match classes
+            if ((classes = format.classes)) {
+              for (x = 0; x < classes.length; x++) {
+                if (!ed.dom.hasClass(node, classes[x])) {
+                  return;
+                }
+              }
+            }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        root = dom.getRoot();
-        startElm = dom.getParent(startElm || self.getStart(), dom.isBlock);
-        endElm = dom.getParent(endElm || self.getEnd(), dom.isBlock);
-
-        if (startElm && startElm != root) {
-          selectedBlocks.push(startElm);
-        }
-
-        if (startElm && endElm && startElm != endElm) {
-          node = startElm;
-
-          var walker = new TreeWalker(startElm, root);
-          while ((node = walker.next()) && node != endElm) {
-            if (dom.isBlock(node)) {
-              selectedBlocks.push(node);
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            return format;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (endElm && startElm != endElm && endElm != root) {
-          selectedBlocks.push(endElm);
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var match = function (editor, name, vars, node) {
+      var startNode;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return selectedBlocks;
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Check specified node
+      if (node) {
+        return matchParents(editor, node, name, vars);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      isForward: function () {
-        var dom = this.dom, sel = this.getSel(), anchorRange, focusRange;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Check selected node
+      node = editor.selection.getNode();
+      if (matchParents(editor, node, name, vars)) {
+        return true;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // No support for selection direction then always return true
-        if (!sel || !sel.anchorNode || !sel.focusNode) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Check start node if it's different
+      startNode = editor.selection.getStart();
+      if (startNode !== node) {
+        if (matchParents(editor, startNode, name, vars)) {
</ins><span class="cx" style="display: block; padding: 0 10px">           return true;
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        anchorRange = dom.createRng();
-        anchorRange.setStart(sel.anchorNode, sel.anchorOffset);
-        anchorRange.collapse(true);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return false;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        focusRange = dom.createRng();
-        focusRange.setStart(sel.focusNode, sel.focusOffset);
-        focusRange.collapse(true);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var matchAll = function (editor, names, vars) {
+      var startElement, matchedFormatNames = [], checkedMap = {};
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return anchorRange.compareBoundaryPoints(anchorRange.START_TO_START, focusRange) <= 0;
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Check start of selection for formats
+      startElement = editor.selection.getStart();
+      editor.dom.getParent(startElement, function (node) {
+        var i, name;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      normalize: function () {
-        var self = this, rng = self.getRng();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        for (i = 0; i < names.length; i++) {
+          name = names[i];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (Env.range && new RangeUtils(self.dom).normalize(rng)) {
-          self.setRng(rng, self.isForward());
-        }
-
-        return rng;
-      },
-
-      /**
-       * Executes callback when the current selection starts/stops matching the specified selector. The current
-       * state will be passed to the callback as it's first argument.
-       *
-       * @method selectorChanged
-       * @param {String} selector CSS selector to check for.
-       * @param {function} callback Callback with state and args when the selector is matches or not.
-       */
-      selectorChanged: function (selector, callback) {
-        var self = this, currentSelectors;
-
-        if (!self.selectorChangedData) {
-          self.selectorChangedData = {};
-          currentSelectors = {};
-
-          self.editor.on('NodeChange', function (e) {
-            var node = e.element, dom = self.dom, parents = dom.getParents(node, null, dom.getRoot()), matchedSelectors = {};
-
-            // Check for new matching selectors
-            each(self.selectorChangedData, function (callbacks, selector) {
-              each(parents, function (node) {
-                if (dom.is(node, selector)) {
-                  if (!currentSelectors[selector]) {
-                    // Execute callbacks
-                    each(callbacks, function (callback) {
-                      callback(true, { node: node, selector: selector, parents: parents });
-                    });
-
-                    currentSelectors[selector] = callbacks;
-                  }
-
-                  matchedSelectors[selector] = callbacks;
-                  return false;
-                }
-              });
-            });
-
-            // Check if current selectors still match
-            each(currentSelectors, function (callbacks, selector) {
-              if (!matchedSelectors[selector]) {
-                delete currentSelectors[selector];
-
-                each(callbacks, function (callback) {
-                  callback(false, { node: node, selector: selector, parents: parents });
-                });
-              }
-            });
-          });
-        }
-
-        // Add selector listeners
-        if (!self.selectorChangedData[selector]) {
-          self.selectorChangedData[selector] = [];
-        }
-
-        self.selectorChangedData[selector].push(callback);
-
-        return self;
-      },
-
-      getScrollContainer: function () {
-        var scrollContainer, node = this.dom.getRoot();
-
-        while (node && node.nodeName != 'BODY') {
-          if (node.scrollHeight > node.clientHeight) {
-            scrollContainer = node;
-            break;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (!checkedMap[name] && matchNode(editor, node, name, vars)) {
+            checkedMap[name] = true;
+            matchedFormatNames.push(name);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-          node = node.parentNode;
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }, editor.dom.getRoot());
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return scrollContainer;
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return matchedFormatNames;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      scrollIntoView: function (elm, alignToTop) {
-        ScrollIntoView.scrollIntoView(this.editor, elm, alignToTop);
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var canApply = function (editor, name) {
+      var formatList = editor.formatter.get(name), startNode, parents, i, x, selector, dom = editor.dom;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      placeCaretAt: function (clientX, clientY) {
-        this.setRng(RangeUtils.getCaretRangeFromPoint(clientX, clientY, this.editor.getDoc()));
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (formatList) {
+        startNode = editor.selection.getStart();
+        parents = FormatUtils.getParents(dom, startNode);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      _moveEndPoint: function (rng, node, start) {
-        var root = node, walker = new TreeWalker(node, root);
-        var nonEmptyElementsMap = this.dom.schema.getNonEmptyElements();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        for (x = formatList.length - 1; x >= 0; x--) {
+          selector = formatList[x].selector;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        do {
-          // Text node
-          if (node.nodeType == 3 && trim(node.nodeValue).length !== 0) {
-            if (start) {
-              rng.setStart(node, 0);
-            } else {
-              rng.setEnd(node, node.nodeValue.length);
-            }
-
-            return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Format is not selector based then always return TRUE
+          // Is it has a defaultBlock then it's likely it can be applied for example align on a non block element line
+          if (!selector || formatList[x].defaultBlock) {
+            return true;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // BR/IMG/INPUT elements but not table cells
-          if (nonEmptyElementsMap[node.nodeName] && !/^(TD|TH)$/.test(node.nodeName)) {
-            if (start) {
-              rng.setStartBefore(node);
-            } else {
-              if (node.nodeName == 'BR') {
-                rng.setEndBefore(node);
-              } else {
-                rng.setEndAfter(node);
-              }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          for (i = parents.length - 1; i >= 0; i--) {
+            if (dom.is(parents[i], selector)) {
+              return true;
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-            return;
</del><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-          // Found empty text block old IE can place the selection inside those
-          if (Env.ie && Env.ie < 11 && this.dom.isBlock(node) && this.dom.isEmpty(node)) {
-            if (start) {
-              rng.setStart(node, 0);
-            } else {
-              rng.setEnd(node, 0);
-            }
-
-            return;
-          }
-        } while ((node = (start ? walker.next() : walker.prev())));
-
-        // Failed to find any text node or other suitable location then move to the root of body
-        if (root.nodeName == 'BODY') {
-          if (start) {
-            rng.setStart(root, 0);
-          } else {
-            rng.setEnd(root, root.childNodes.length);
-          }
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      getBoundingClientRect: function () {
-        var rng = this.getRng();
-        return rng.collapsed ? CaretPosition.fromRangeStart(rng).getClientRects()[0] : rng.getBoundingClientRect();
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return false;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      destroy: function () {
-        this.win = null;
-        this.controlSelection.destroy();
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return {
+      matchNode: matchNode,
+      matchName: matchName,
+      match: match,
+      matchAll: matchAll,
+      canApply: canApply,
+      matchesUnInheritedFormatSelector: matchesUnInheritedFormatSelector
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-    return Selection;
</del><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * ElementUtils.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * CaretFormat.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -21891,467 +18035,379 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Contributing: http://www.tinymce.com/contributing
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * Utility class for various element specific functions.
- *
- * @private
- * @class tinymce.dom.ElementUtils
- */
</del><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.dom.ElementUtils',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.fmt.CaretFormat',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    "tinymce.core.dom.BookmarkManager",
-    "tinymce.core.util.Tools"
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.katamari.api.Arr',
+    'ephox.sugar.api.node.Element',
+    'tinymce.core.dom.PaddingBr',
+    'tinymce.core.dom.RangeUtils',
+    'tinymce.core.dom.TreeWalker',
+    'tinymce.core.fmt.ExpandRange',
+    'tinymce.core.fmt.FormatUtils',
+    'tinymce.core.fmt.MatchFormat',
+    'tinymce.core.text.Zwsp',
+    'tinymce.core.util.Fun',
+    'tinymce.core.util.Tools'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (BookmarkManager, Tools) {
-    var each = Tools.each;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Arr, Element, PaddingBr, RangeUtils, TreeWalker, ExpandRange, FormatUtils, MatchFormat, Zwsp, Fun, Tools) {
+    var ZWSP = Zwsp.ZWSP, CARET_ID = '_mce_caret', DEBUG = false;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function ElementUtils(dom) {
-      /**
-       * Compares two nodes and checks if it's attributes and styles matches.
-       * This doesn't compare classes as items since their order is significant.
-       *
-       * @method compare
-       * @param {Node} node1 First node to compare with.
-       * @param {Node} node2 Second node to compare with.
-       * @return {boolean} True/false if the nodes are the same or not.
-       */
-      this.compare = function (node1, node2) {
-        // Not the same name
-        if (node1.nodeName != node2.nodeName) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isCaretNode = function (node) {
+      return node.nodeType === 1 && node.id === CARET_ID;
+    };
+
+    var isCaretContainerEmpty = function (node, nodes) {
+      while (node) {
+        if ((node.nodeType === 3 && node.nodeValue !== ZWSP) || node.childNodes.length > 1) {
</ins><span class="cx" style="display: block; padding: 0 10px">           return false;
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        /**
-         * Returns all the nodes attributes excluding internal ones, styles and classes.
-         *
-         * @private
-         * @param {Node} node Node to get attributes from.
-         * @return {Object} Name/value object with attributes and attribute values.
-         */
-        function getAttribs(node) {
-          var attribs = {};
-
-          each(dom.getAttribs(node), function (attr) {
-            var name = attr.nodeName.toLowerCase();
-
-            // Don't compare internal attributes or style
-            if (name.indexOf('_') !== 0 && name !== 'style' && name.indexOf('data-') !== 0) {
-              attribs[name] = dom.getAttrib(node, name);
-            }
-          });
-
-          return attribs;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Collect nodes
+        if (nodes && node.nodeType === 1) {
+          nodes.push(node);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        /**
-         * Compares two objects checks if it's key + value exists in the other one.
-         *
-         * @private
-         * @param {Object} obj1 First object to compare.
-         * @param {Object} obj2 Second object to compare.
-         * @return {boolean} True/false if the objects matches or not.
-         */
-        function compareObjects(obj1, obj2) {
-          var value, name;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        node = node.firstChild;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          for (name in obj1) {
-            // Obj1 has item obj2 doesn't have
-            if (obj1.hasOwnProperty(name)) {
-              value = obj2[name];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return true;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              // Obj2 doesn't have obj1 item
-              if (typeof value == "undefined") {
-                return false;
-              }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var findFirstTextNode = function (node) {
+      var walker;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              // Obj2 item has a different value
-              if (obj1[name] != value) {
-                return false;
-              }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (node) {
+        walker = new TreeWalker(node, node);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              // Delete similar value
-              delete obj2[name];
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        for (node = walker.current(); node; node = walker.next()) {
+          if (node.nodeType === 3) {
+            return node;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-          // Check if obj 2 has something obj 1 doesn't have
-          for (name in obj2) {
-            // Obj2 has item obj1 doesn't have
-            if (obj2.hasOwnProperty(name)) {
-              return false;
-            }
-          }
-
-          return true;
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Attribs are not the same
-        if (!compareObjects(getAttribs(node1), getAttribs(node2))) {
-          return false;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return null;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Styles are not the same
-        if (!compareObjects(dom.parseStyle(dom.getAttrib(node1, 'style')), dom.parseStyle(dom.getAttrib(node2, 'style')))) {
-          return false;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var createCaretContainer = function (dom, fill) {
+      var caretContainer = dom.create('span', { id: CARET_ID, 'data-mce-bogus': '1', style: DEBUG ? 'color:red' : '' });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return !BookmarkManager.isBookmarkNode(node1) && !BookmarkManager.isBookmarkNode(node2);
-      };
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (fill) {
+        caretContainer.appendChild(dom.doc.createTextNode(ZWSP));
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return ElementUtils;
-  }
-);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return caretContainer;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * Preview.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var getParentCaretContainer = function (node) {
+      while (node) {
+        if (node.id === CARET_ID) {
+          return node;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * Internal class for generating previews styles for formats.
- *
- * Example:
- *  Preview.getCssText(editor, 'bold');
- *
- * @private
- * @class tinymce.fmt.Preview
- */
-define(
-  'tinymce.core.fmt.Preview',
-  [
-    "tinymce.core.dom.DOMUtils",
-    "tinymce.core.util.Tools",
-    "tinymce.core.html.Schema"
-  ],
-  function (DOMUtils, Tools, Schema) {
-    var each = Tools.each;
-    var dom = DOMUtils.DOM;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        node = node.parentNode;
+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function parsedSelectorToHtml(ancestry, editor) {
-      var elm, item, fragment;
-      var schema = editor && editor.schema || new Schema({});
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Checks if the parent caret container node isn't empty if that is the case it
+    // will remove the bogus state on all children that isn't empty
+    var unmarkBogusCaretParents = function (dom, selection) {
+      var caretContainer;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function decorate(elm, item) {
-        if (item.classes.length) {
-          dom.addClass(elm, item.classes.join(' '));
-        }
-        dom.setAttribs(elm, item.attrs);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      caretContainer = getParentCaretContainer(selection.getStart());
+      if (caretContainer && !dom.isEmpty(caretContainer)) {
+        Tools.walk(caretContainer, function (node) {
+          if (node.nodeType === 1 && node.id !== CARET_ID && !dom.isEmpty(node)) {
+            dom.setAttrib(node, 'data-mce-bogus', null);
+          }
+        }, 'childNodes');
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function createElement(sItem) {
-        var elm;
-
-        item = typeof sItem === 'string' ? {
-          name: sItem,
-          classes: [],
-          attrs: {}
-        } : sItem;
-
-        elm = dom.create(item.name);
-        decorate(elm, item);
-        return elm;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var trimZwspFromCaretContainer = function (caretContainerNode) {
+      var textNode = findFirstTextNode(caretContainerNode);
+      if (textNode && textNode.nodeValue.charAt(0) === ZWSP) {
+        textNode.deleteData(0, 1);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function getRequiredParent(elm, candidate) {
-        var name = typeof elm !== 'string' ? elm.nodeName.toLowerCase() : elm;
-        var elmRule = schema.getElementRule(name);
-        var parentsRequired = elmRule && elmRule.parentsRequired;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return textNode;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (parentsRequired && parentsRequired.length) {
-          return candidate && Tools.inArray(parentsRequired, candidate) !== -1 ? candidate : parentsRequired[0];
-        } else {
-          return false;
-        }
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var removeCaretContainerNode = function (dom, selection, node, moveCaret) {
+      var rng, block, textNode;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function wrapInHtml(elm, ancestry, siblings) {
-        var parent, parentCandidate, parentRequired;
-        var ancestor = ancestry.length > 0 && ancestry[0];
-        var ancestorName = ancestor && ancestor.name;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      rng = selection.getRng(true);
+      block = dom.getParent(node, dom.isBlock);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        parentRequired = getRequiredParent(elm, ancestorName);
-
-        if (parentRequired) {
-          if (ancestorName == parentRequired) {
-            parentCandidate = ancestry[0];
-            ancestry = ancestry.slice(1);
-          } else {
-            parentCandidate = parentRequired;
-          }
-        } else if (ancestor) {
-          parentCandidate = ancestry[0];
-          ancestry = ancestry.slice(1);
-        } else if (!siblings) {
-          return elm;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (isCaretContainerEmpty(node)) {
+        if (moveCaret !== false) {
+          rng.setStartBefore(node);
+          rng.setEndBefore(node);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (parentCandidate) {
-          parent = createElement(parentCandidate);
-          parent.appendChild(elm);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        dom.remove(node);
+      } else {
+        textNode = trimZwspFromCaretContainer(node);
+        if (rng.startContainer === textNode && rng.startOffset > 0) {
+          rng.setStart(textNode, rng.startOffset - 1);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (siblings) {
-          if (!parent) {
-            // if no more ancestry, wrap in generic div
-            parent = dom.create('div');
-            parent.appendChild(elm);
-          }
-
-          Tools.each(siblings, function (sibling) {
-            var siblingElm = createElement(sibling);
-            parent.insertBefore(siblingElm, elm);
-          });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (rng.endContainer === textNode && rng.endOffset > 0) {
+          rng.setEnd(textNode, rng.endOffset - 1);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return wrapInHtml(parent, ancestry, parentCandidate && parentCandidate.siblings);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        dom.remove(node, true);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (ancestry && ancestry.length) {
-        item = ancestry[0];
-        elm = createElement(item);
-        fragment = dom.create('div');
-        fragment.appendChild(wrapInHtml(elm, ancestry.slice(1), item.siblings));
-        return fragment;
-      } else {
-        return '';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (block && dom.isEmpty(block)) {
+        PaddingBr.fillWithPaddingBr(Element.fromDom(block));
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      selection.setRng(rng);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function selectorToHtml(selector, editor) {
-      return parsedSelectorToHtml(parseSelector(selector), editor);
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Removes the caret container for the specified node or all on the current document
+    var removeCaretContainer = function (dom, selection, node, moveCaret) {
+      if (!node) {
+        node = getParentCaretContainer(selection.getStart());
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (!node) {
+          while ((node = dom.get(CARET_ID))) {
+            removeCaretContainerNode(dom, selection, node, false);
+          }
+        }
+      } else {
+        removeCaretContainerNode(dom, selection, node, moveCaret);
+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function parseSelectorItem(item) {
-      var tagName;
-      var obj = {
-        classes: [],
-        attrs: {}
-      };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var insertCaretContainerNode = function (editor, caretContainer, formatNode) {
+      var dom = editor.dom, block = dom.getParent(formatNode, Fun.curry(FormatUtils.isTextBlock, editor));
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      item = obj.selector = Tools.trim(item);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (block && dom.isEmpty(block)) {
+        // Replace formatNode with caretContainer when removing format from empty block like <p><b>|</b></p>
+        formatNode.parentNode.replaceChild(caretContainer, formatNode);
+      } else {
+        PaddingBr.removeTrailingBr(Element.fromDom(formatNode));
+        if (dom.isEmpty(formatNode)) {
+          formatNode.parentNode.replaceChild(caretContainer, formatNode);
+        } else {
+          dom.insertAfter(caretContainer, formatNode);
+        }
+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (item !== '*') {
-        // matching IDs, CLASSes, ATTRIBUTES and PSEUDOs
-        tagName = item.replace(/(?:([#\.]|::?)([\w\-]+)|(\[)([^\]]+)\]?)/g, function ($0, $1, $2, $3, $4) {
-          switch ($1) {
-            case '#':
-              obj.attrs.id = $2;
-              break;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var appendNode = function (parentNode, node) {
+      parentNode.appendChild(node);
+      return node;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            case '.':
-              obj.classes.push($2);
-              break;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var insertFormatNodesIntoCaretContainer = function (formatNodes, caretContainer) {
+      var innerMostFormatNode = Arr.foldr(formatNodes, function (parentNode, formatNode) {
+        return appendNode(parentNode, formatNode.cloneNode(false));
+      }, caretContainer);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            case ':':
-              if (Tools.inArray('checked disabled enabled read-only required'.split(' '), $2) !== -1) {
-                obj.attrs[$2] = $2;
-              }
-              break;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return appendNode(innerMostFormatNode, innerMostFormatNode.ownerDocument.createTextNode(ZWSP));
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // atribute matched
-          if ($3 == '[') {
-            var m = $4.match(/([\w\-]+)(?:\=\"([^\"]+))?/);
-            if (m) {
-              obj.attrs[m[1]] = m[2];
-            }
-          }
-
-          return '';
-        });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var setupCaretEvents = function (editor) {
+      if (!editor._hasCaretEvents) {
+        bindEvents(editor);
+        editor._hasCaretEvents = true;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      obj.name = tagName || 'div';
-      return obj;
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var applyCaretFormat = function (editor, name, vars) {
+      var rng, caretContainer, textNode, offset, bookmark, container, text;
+      var dom = editor.dom, selection = editor.selection;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      setupCaretEvents(editor);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function parseSelector(selector) {
-      if (!selector || typeof selector !== 'string') {
-        return [];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      rng = selection.getRng(true);
+      offset = rng.startOffset;
+      container = rng.startContainer;
+      text = container.nodeValue;
+
+      caretContainer = getParentCaretContainer(selection.getStart());
+      if (caretContainer) {
+        textNode = findFirstTextNode(caretContainer);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // take into account only first one
-      selector = selector.split(/\s*,\s*/)[0];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Expand to word if caret is in the middle of a text node and the char before/after is a alpha numeric character
+      var wordcharRegex = /[^\s\u00a0\u00ad\u200b\ufeff]/;
+      if (text && offset > 0 && offset < text.length &&
+        wordcharRegex.test(text.charAt(offset)) && wordcharRegex.test(text.charAt(offset - 1))) {
+        // Get bookmark of caret position
+        bookmark = selection.getBookmark();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // tighten
-      selector = selector.replace(/\s*(~\+|~|\+|>)\s*/g, '$1');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Collapse bookmark range (WebKit)
+        rng.collapse(true);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // split either on > or on space, but not the one inside brackets
-      return Tools.map(selector.split(/(?:>|\s+(?![^\[\]]+\]))/), function (item) {
-        // process each sibling selector separately
-        var siblings = Tools.map(item.split(/(?:~\+|~|\+)/), parseSelectorItem);
-        var obj = siblings.pop(); // the last one is our real target
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Expand the range to the closest word and split it at those points
+        rng = ExpandRange.expandRng(editor, rng, editor.formatter.get(name));
+        rng = new RangeUtils(dom).split(rng);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (siblings.length) {
-          obj.siblings = siblings;
-        }
-        return obj;
-      }).reverse();
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Apply the format to the range
+        editor.formatter.apply(name, vars, rng);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Move selection back to caret position
+        selection.moveToBookmark(bookmark);
+      } else {
+        if (!caretContainer || textNode.nodeValue !== ZWSP) {
+          caretContainer = createCaretContainer(dom, true);
+          textNode = caretContainer.firstChild;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function getCssText(editor, format) {
-      var name, previewFrag, previewElm, items;
-      var previewCss = '', parentFontSize, previewStyles;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          rng.insertNode(caretContainer);
+          offset = 1;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      previewStyles = editor.settings.preview_styles;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          editor.formatter.apply(name, vars, caretContainer);
+        } else {
+          editor.formatter.apply(name, vars, caretContainer);
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // No preview forced
-      if (previewStyles === false) {
-        return '';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Move selection to text node
+        selection.setCursorLocation(textNode, offset);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Default preview
-      if (typeof previewStyles !== 'string') {
-        previewStyles = 'font-family font-size font-weight font-style text-decoration ' +
-          'text-transform color background-color border border-radius outline text-shadow';
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var removeCaretFormat = function (editor, name, vars, similar) {
+      var dom = editor.dom, selection = editor.selection;
+      var rng = selection.getRng(true), container, offset, bookmark;
+      var hasContentAfter, node, formatNode, parents = [], caretContainer;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Removes any variables since these can't be previewed
-      function removeVars(val) {
-        return val.replace(/%(\w+)/g, '');
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      setupCaretEvents(editor);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Create block/inline element to use for preview
-      if (typeof format == "string") {
-        format = editor.formatter.get(format);
-        if (!format) {
-          return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      container = rng.startContainer;
+      offset = rng.startOffset;
+      node = container;
+
+      if (container.nodeType === 3) {
+        if (offset !== container.nodeValue.length) {
+          hasContentAfter = true;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        format = format[0];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        node = node.parentNode;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Format specific preview override
-      // TODO: This should probably be further reduced by the previewStyles option
-      if ('preview' in format) {
-        previewStyles = format.preview;
-        if (previewStyles === false) {
-          return '';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      while (node) {
+        if (MatchFormat.matchNode(editor, node, name, vars, similar)) {
+          formatNode = node;
+          break;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      name = format.block || format.inline || 'span';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (node.nextSibling) {
+          hasContentAfter = true;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      items = parseSelector(format.selector);
-      if (items.length) {
-        if (!items[0].name) { // e.g. something like ul > .someClass was provided
-          items[0].name = name;
-        }
-        name = format.selector;
-        previewFrag = parsedSelectorToHtml(items, editor);
-      } else {
-        previewFrag = parsedSelectorToHtml([name], editor);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        parents.push(node);
+        node = node.parentNode;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      previewElm = dom.select(name, previewFrag)[0] || previewFrag.firstChild;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Node doesn't have the specified format
+      if (!formatNode) {
+        return;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Add format styles to preview element
-      each(format.styles, function (value, name) {
-        value = removeVars(value);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Is there contents after the caret then remove the format on the element
+      if (hasContentAfter) {
+        bookmark = selection.getBookmark();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (value) {
-          dom.setStyle(previewElm, name, value);
-        }
-      });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Collapse bookmark range (WebKit)
+        rng.collapse(true);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Add attributes to preview element
-      each(format.attributes, function (value, name) {
-        value = removeVars(value);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Expand the range to the closest word and split it at those points
+        rng = ExpandRange.expandRng(editor, rng, editor.formatter.get(name), true);
+        rng = new RangeUtils(dom).split(rng);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (value) {
-          dom.setAttrib(previewElm, name, value);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        editor.formatter.remove(name, vars, rng);
+        selection.moveToBookmark(bookmark);
+      } else {
+        caretContainer = getParentCaretContainer(formatNode);
+        var newCaretContainer = createCaretContainer(dom, false);
+        var caretNode = insertFormatNodesIntoCaretContainer(parents, newCaretContainer);
+
+        if (caretContainer) {
+          insertCaretContainerNode(editor, newCaretContainer, caretContainer);
+        } else {
+          insertCaretContainerNode(editor, newCaretContainer, formatNode);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      });
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Add classes to preview element
-      each(format.classes, function (value) {
-        value = removeVars(value);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        removeCaretContainerNode(dom, selection, caretContainer, false);
+        selection.setCursorLocation(caretNode, 1);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (!dom.hasClass(previewElm, value)) {
-          dom.addClass(previewElm, value);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (dom.isEmpty(formatNode)) {
+          dom.remove(formatNode);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      editor.fire('PreviewFormats');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var bindEvents = function (editor) {
+      var dom = editor.dom, selection = editor.selection;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Add the previewElm outside the visual area
-      dom.setStyles(previewFrag, { position: 'absolute', left: -0xFFFF });
-      editor.getBody().appendChild(previewFrag);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (!editor._hasCaretEvents) {
+        var markCaretContainersBogus, disableCaretContainer;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Get parent container font size so we can compute px values out of em/% for older IE:s
-      parentFontSize = dom.getStyle(editor.getBody(), 'fontSize', true);
-      parentFontSize = /px$/.test(parentFontSize) ? parseInt(parentFontSize, 10) : 0;
-
-      each(previewStyles.split(' '), function (name) {
-        var value = dom.getStyle(previewElm, name, true);
-
-        // If background is transparent then check if the body has a background color we can use
-        if (name == 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) {
-          value = dom.getStyle(editor.getBody(), name, true);
-
-          // Ignore white since it's the default color, not the nicest fix
-          // TODO: Fix this by detecting runtime style
-          if (dom.toHex(value).toLowerCase() == '#ffffff') {
-            return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        editor.on('BeforeGetContent', function (e) {
+          if (markCaretContainersBogus && e.format !== 'raw') {
+            markCaretContainersBogus();
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (name == 'color') {
-          // Ignore black since it's the default color, not the nicest fix
-          // TODO: Fix this by detecting runtime style
-          if (dom.toHex(value).toLowerCase() == '#000000') {
-            return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        editor.on('mouseup keydown', function (e) {
+          if (disableCaretContainer) {
+            disableCaretContainer(e);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Old IE won't calculate the font size so we need to do that manually
-        if (name == 'font-size') {
-          if (/em|%$/.test(value)) {
-            if (parentFontSize === 0) {
-              return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Mark current caret container elements as bogus when getting the contents so we don't end up with empty elements
+        markCaretContainersBogus = function () {
+          var nodes = [], i;
+
+          if (isCaretContainerEmpty(getParentCaretContainer(selection.getStart()), nodes)) {
+            // Mark children
+            i = nodes.length;
+            while (i--) {
+              dom.setAttrib(nodes[i], 'data-mce-bogus', '1');
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-            // Convert font size from em/% to px
-            value = parseFloat(value, 10) / (/%$/.test(value) ? 100 : 1);
-            value = (value * parentFontSize) + 'px';
</del><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (name == "border" && value) {
-          previewCss += 'padding:0 2px;';
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        disableCaretContainer = function (e) {
+          var keyCode = e.keyCode;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        previewCss += name + ':' + value + ';';
-      });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          removeCaretContainer(dom, selection, null, false);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      editor.fire('AfterPreviewFormats');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Remove caret container if it's empty
+          if (keyCode === 8 && selection.isCollapsed() && selection.getStart().innerHTML === ZWSP) {
+            removeCaretContainer(dom, selection, getParentCaretContainer(selection.getStart()));
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      //previewCss += 'line-height:normal';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Remove caret container on keydown and it's left/right arrow keys
+          if (keyCode === 37 || keyCode === 39) {
+            removeCaretContainer(dom, selection, getParentCaretContainer(selection.getStart()));
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      dom.remove(previewFrag);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          unmarkBogusCaretParents(dom, selection);
+        };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return previewCss;
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Remove bogus state if they got filled by contents using editor.selection.setContent
+        editor.on('SetContent', function (e) {
+          if (e.selection) {
+            unmarkBogusCaretParents(dom, selection);
+          }
+        });
+        editor._hasCaretEvents = true;
+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     return {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      getCssText: getCssText,
-      parseSelector: parseSelector,
-      selectorToHtml: selectorToHtml
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      applyCaretFormat: applyCaretFormat,
+      removeCaretFormat: removeCaretFormat,
+      isCaretNode: isCaretNode
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px">  * Hooks.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -22398,7 +18454,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">       var rng = editor.selection.getRng(), isPre, blocks;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       function hasPreSibling(pre) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return isPre(pre.previousSibling) && Arr.indexOf(blocks, pre.previousSibling) != -1;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return isPre(pre.previousSibling) && Arr.indexOf(blocks, pre.previousSibling) !== -1;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       function joinPre(pre1, pre2) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -22424,7 +18480,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Formatter.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * ElementUtils.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -22434,2578 +18490,667 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Text formatter engine class. This class is used to apply formats like bold, italic, font size
- * etc to the current selection or specific nodes. This engine was built to replace the browser's
- * default formatting logic for execCommand due to its inconsistent and buggy behavior.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Utility class for various element specific functions.
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @class tinymce.Formatter
- * @example
- *  tinymce.activeEditor.formatter.register('mycustomformat', {
- *    inline: 'span',
- *    styles: {color: '#ff0000'}
- *  });
- *
- *  tinymce.activeEditor.formatter.apply('mycustomformat');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @private
+ * @class tinymce.dom.ElementUtils
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.Formatter',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.dom.ElementUtils',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    "tinymce.core.dom.TreeWalker",
-    "tinymce.core.dom.RangeUtils",
</del><span class="cx" style="display: block; padding: 0 10px">     "tinymce.core.dom.BookmarkManager",
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    "tinymce.core.dom.ElementUtils",
-    "tinymce.core.dom.NodeType",
-    "tinymce.core.util.Fun",
-    "tinymce.core.util.Tools",
-    "tinymce.core.fmt.Preview",
-    "tinymce.core.fmt.Hooks"
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    "tinymce.core.util.Tools"
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (TreeWalker, RangeUtils, BookmarkManager, ElementUtils, NodeType, Fun, Tools, Preview, Hooks) {
-    /**
-     * Constructs a new formatter instance.
-     *
-     * @constructor Formatter
-     * @param {tinymce.Editor} ed Editor instance to construct the formatter engine to.
-     */
-    return function (ed) {
-      var formats = {},
-        dom = ed.dom,
-        selection = ed.selection,
-        rangeUtils = new RangeUtils(dom),
-        isValid = ed.schema.isValidChild,
-        isBlock = dom.isBlock,
-        forcedRootBlock = ed.settings.forced_root_block,
-        nodeIndex = dom.nodeIndex,
-        INVISIBLE_CHAR = '\uFEFF',
-        MCE_ATTR_RE = /^(src|href|style)$/,
-        FALSE = false,
-        TRUE = true,
-        formatChangeData,
-        undef,
-        getContentEditable = dom.getContentEditable,
-        disableCaretContainer,
-        markCaretContainersBogus,
-        isBookmarkNode = BookmarkManager.isBookmarkNode;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (BookmarkManager, Tools) {
+    var each = Tools.each;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var each = Tools.each,
-        grep = Tools.grep,
-        walk = Tools.walk,
-        extend = Tools.extend;
-
-      function isTextBlock(name) {
-        if (name.nodeType) {
-          name = name.nodeName;
-        }
-
-        return !!ed.schema.getTextBlockElements()[name.toLowerCase()];
-      }
-
-      function isTableCell(node) {
-        return /^(TH|TD)$/.test(node.nodeName);
-      }
-
-      function isInlineBlock(node) {
-        return node && /^(IMG)$/.test(node.nodeName);
-      }
-
-      function getParents(node, selector) {
-        return dom.getParents(node, selector, dom.getRoot());
-      }
-
-      function isCaretNode(node) {
-        return node.nodeType === 1 && node.id === '_mce_caret';
-      }
-
-      function defaultFormats() {
-        register({
-          valigntop: [
-            { selector: 'td,th', styles: { 'verticalAlign': 'top' } }
-          ],
-
-          valignmiddle: [
-            { selector: 'td,th', styles: { 'verticalAlign': 'middle' } }
-          ],
-
-          valignbottom: [
-            { selector: 'td,th', styles: { 'verticalAlign': 'bottom' } }
-          ],
-
-          alignleft: [
-            {
-              selector: 'figure.image',
-              collapsed: false,
-              classes: 'align-left',
-              ceFalseOverride: true,
-              preview: 'font-family font-size'
-            },
-            {
-              selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li',
-              styles: {
-                textAlign: 'left'
-              },
-              inherit: false,
-              preview: false,
-              defaultBlock: 'div'
-            },
-            { selector: 'img,table', collapsed: false, styles: { 'float': 'left' }, preview: 'font-family font-size' }
-          ],
-
-          aligncenter: [
-            {
-              selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li',
-              styles: {
-                textAlign: 'center'
-              },
-              inherit: false,
-              preview: false,
-              defaultBlock: 'div'
-            },
-            {
-              selector: 'figure.image',
-              collapsed: false,
-              classes: 'align-center',
-              ceFalseOverride: true,
-              preview: 'font-family font-size'
-            },
-            {
-              selector: 'img',
-              collapsed: false,
-              styles: {
-                display: 'block',
-                marginLeft: 'auto',
-                marginRight: 'auto'
-              },
-              preview: false
-            },
-            {
-              selector: 'table',
-              collapsed: false,
-              styles: {
-                marginLeft: 'auto',
-                marginRight: 'auto'
-              },
-              preview: 'font-family font-size'
-            }
-          ],
-
-          alignright: [
-            {
-              selector: 'figure.image',
-              collapsed: false,
-              classes: 'align-right',
-              ceFalseOverride: true,
-              preview: 'font-family font-size'
-            },
-            {
-              selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li',
-              styles: {
-                textAlign: 'right'
-              },
-              inherit: false,
-              preview: 'font-family font-size',
-              defaultBlock: 'div'
-            },
-            {
-              selector: 'img,table',
-              collapsed: false,
-              styles: {
-                'float': 'right'
-              },
-              preview: 'font-family font-size'
-            }
-          ],
-
-          alignjustify: [
-            {
-              selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li',
-              styles: {
-                textAlign: 'justify'
-              },
-              inherit: false,
-              defaultBlock: 'div',
-              preview: 'font-family font-size'
-            }
-          ],
-
-          bold: [
-            { inline: 'strong', remove: 'all' },
-            { inline: 'span', styles: { fontWeight: 'bold' } },
-            { inline: 'b', remove: 'all' }
-          ],
-
-          italic: [
-            { inline: 'em', remove: 'all' },
-            { inline: 'span', styles: { fontStyle: 'italic' } },
-            { inline: 'i', remove: 'all' }
-          ],
-
-          underline: [
-            { inline: 'span', styles: { textDecoration: 'underline' }, exact: true },
-            { inline: 'u', remove: 'all' }
-          ],
-
-          strikethrough: [
-            { inline: 'span', styles: { textDecoration: 'line-through' }, exact: true },
-            { inline: 'strike', remove: 'all' }
-          ],
-
-          forecolor: { inline: 'span', styles: { color: '%value' }, links: true, remove_similar: true, clear_child_styles: true },
-          hilitecolor: { inline: 'span', styles: { backgroundColor: '%value' }, links: true, remove_similar: true, clear_child_styles: true },
-          fontname: { inline: 'span', styles: { fontFamily: '%value' }, clear_child_styles: true },
-          fontsize: { inline: 'span', styles: { fontSize: '%value' }, clear_child_styles: true },
-          fontsize_class: { inline: 'span', attributes: { 'class': '%value' } },
-          blockquote: { block: 'blockquote', wrapper: 1, remove: 'all' },
-          subscript: { inline: 'sub' },
-          superscript: { inline: 'sup' },
-          code: { inline: 'code' },
-
-          link: {
-            inline: 'a', selector: 'a', remove: 'all', split: true, deep: true,
-            onmatch: function () {
-              return true;
-            },
-
-            onformat: function (elm, fmt, vars) {
-              each(vars, function (value, key) {
-                dom.setAttrib(elm, key, value);
-              });
-            }
-          },
-
-          removeformat: [
-            {
-              selector: 'b,strong,em,i,font,u,strike,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins',
-              remove: 'all',
-              split: true,
-              expand: false,
-              block_expand: true,
-              deep: true
-            },
-            { selector: 'span', attributes: ['style', 'class'], remove: 'empty', split: true, expand: false, deep: true },
-            { selector: '*', attributes: ['style', 'class'], split: false, expand: false, deep: true }
-          ]
-        });
-
-        // Register default block formats
-        each('p h1 h2 h3 h4 h5 h6 div address pre div dt dd samp'.split(/\s/), function (name) {
-          register(name, { block: name, remove: 'all' });
-        });
-
-        // Register user defined formats
-        register(ed.settings.formats);
-      }
-
-      var clearChildStyles = function (format, node) {
-        if (format.clear_child_styles) {
-          each(dom.select('*', node), function (node) {
-            each(format.styles, function (value, name) {
-              dom.setStyle(node, name, '');
-            });
-          });
-        }
-      };
-
-      function addKeyboardShortcuts() {
-        // Add some inline shortcuts
-        ed.addShortcut('meta+b', 'bold_desc', 'Bold');
-        ed.addShortcut('meta+i', 'italic_desc', 'Italic');
-        ed.addShortcut('meta+u', 'underline_desc', 'Underline');
-
-        // BlockFormat shortcuts keys
-        for (var i = 1; i <= 6; i++) {
-          ed.addShortcut('access+' + i, '', ['FormatBlock', false, 'h' + i]);
-        }
-
-        ed.addShortcut('access+7', '', ['FormatBlock', false, 'p']);
-        ed.addShortcut('access+8', '', ['FormatBlock', false, 'div']);
-        ed.addShortcut('access+9', '', ['FormatBlock', false, 'address']);
-      }
-
-      // Public functions
-
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function ElementUtils(dom) {
</ins><span class="cx" style="display: block; padding: 0 10px">       /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * Returns the format by name or all formats if no name is specified.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * Compares two nodes and checks if it's attributes and styles matches.
+       * This doesn't compare classes as items since their order is significant.
</ins><span class="cx" style="display: block; padding: 0 10px">        *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * @method get
-       * @param {String} name Optional name to retrieve by.
-       * @return {Array/Object} Array/Object with all registered formats or a specific format.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * @method compare
+       * @param {Node} node1 First node to compare with.
+       * @param {Node} node2 Second node to compare with.
+       * @return {boolean} True/false if the nodes are the same or not.
</ins><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function get(name) {
-        return name ? formats[name] : formats;
-      }
-
-      /**
-       * Registers a specific format by name.
-       *
-       * @method register
-       * @param {Object/String} name Name of the format for example "bold".
-       * @param {Object/Array} format Optional format object or array of format variants
-       * can only be omitted if the first arg is an object.
-       */
-      function register(name, format) {
-        if (name) {
-          if (typeof name !== 'string') {
-            each(name, function (format, name) {
-              register(name, format);
-            });
-          } else {
-            // Force format into array and add it to internal collection
-            format = format.length ? format : [format];
-
-            each(format, function (format) {
-              // Set deep to false by default on selector formats this to avoid removing
-              // alignment on images inside paragraphs when alignment is changed on paragraphs
-              if (format.deep === undef) {
-                format.deep = !format.selector;
-              }
-
-              // Default to true
-              if (format.split === undef) {
-                format.split = !format.selector || format.inline;
-              }
-
-              // Default to true
-              if (format.remove === undef && format.selector && !format.inline) {
-                format.remove = 'none';
-              }
-
-              // Mark format as a mixed format inline + block level
-              if (format.selector && format.inline) {
-                format.mixed = true;
-                format.block_expand = true;
-              }
-
-              // Split classes if needed
-              if (typeof format.classes === 'string') {
-                format.classes = format.classes.split(/\s+/);
-              }
-            });
-
-            formats[name] = format;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      this.compare = function (node1, node2) {
+        // Not the same name
+        if (node1.nodeName != node2.nodeName) {
+          return false;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Unregister a specific format by name.
-       *
-       * @method unregister
-       * @param {String} name Name of the format for example "bold".
-       */
-      function unregister(name) {
-        if (name && formats[name]) {
-          delete formats[name];
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+         * Returns all the nodes attributes excluding internal ones, styles and classes.
+         *
+         * @private
+         * @param {Node} node Node to get attributes from.
+         * @return {Object} Name/value object with attributes and attribute values.
+         */
+        function getAttribs(node) {
+          var attribs = {};
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return formats;
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          each(dom.getAttribs(node), function (attr) {
+            var name = attr.nodeName.toLowerCase();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function matchesUnInheritedFormatSelector(node, name) {
-        var formatList = get(name);
-
-        if (formatList) {
-          for (var i = 0; i < formatList.length; i++) {
-            if (formatList[i].inherit === false && dom.is(node, formatList[i].selector)) {
-              return true;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // Don't compare internal attributes or style
+            if (name.indexOf('_') !== 0 && name !== 'style' && name.indexOf('data-') !== 0) {
+              attribs[name] = dom.getAttrib(node, name);
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          }
-        }
-
-        return false;
-      }
-
-      function getTextDecoration(node) {
-        var decoration;
-
-        ed.dom.getParent(node, function (n) {
-          decoration = ed.dom.getStyle(n, 'text-decoration');
-          return decoration && decoration !== 'none';
-        });
-
-        return decoration;
-      }
-
-      function processUnderlineAndColor(node) {
-        var textDecoration;
-        if (node.nodeType === 1 && node.parentNode && node.parentNode.nodeType === 1) {
-          textDecoration = getTextDecoration(node.parentNode);
-          if (ed.dom.getStyle(node, 'color') && textDecoration) {
-            ed.dom.setStyle(node, 'text-decoration', textDecoration);
-          } else if (ed.dom.getStyle(node, 'text-decoration') === textDecoration) {
-            ed.dom.setStyle(node, 'text-decoration', null);
-          }
-        }
-      }
-
-      /**
-       * Applies the specified format to the current selection or specified node.
-       *
-       * @method apply
-       * @param {String} name Name of format to apply.
-       * @param {Object} vars Optional list of variables to replace within format before applying it.
-       * @param {Node} node Optional node to apply the format to defaults to current selection.
-       */
-      function apply(name, vars, node) {
-        var formatList = get(name), format = formatList[0], bookmark, rng, isCollapsed = !node && selection.isCollapsed();
-
-        function setElementFormat(elm, fmt) {
-          fmt = fmt || format;
-
-          if (elm) {
-            if (fmt.onformat) {
-              fmt.onformat(elm, fmt, vars, node);
-            }
-
-            each(fmt.styles, function (value, name) {
-              dom.setStyle(elm, name, replaceVars(value, vars));
-            });
-
-            // Needed for the WebKit span spam bug
-            // TODO: Remove this once WebKit/Blink fixes this
-            if (fmt.styles) {
-              var styleVal = dom.getAttrib(elm, 'style');
-
-              if (styleVal) {
-                elm.setAttribute('data-mce-style', styleVal);
-              }
-            }
-
-            each(fmt.attributes, function (value, name) {
-              dom.setAttrib(elm, name, replaceVars(value, vars));
-            });
-
-            each(fmt.classes, function (value) {
-              value = replaceVars(value, vars);
-
-              if (!dom.hasClass(elm, value)) {
-                dom.addClass(elm, value);
-              }
-            });
-          }
-        }
-
-        function applyNodeStyle(formatList, node) {
-          var found = false;
-
-          if (!format.selector) {
-            return false;
-          }
-
-          // Look for matching formats
-          each(formatList, function (format) {
-            // Check collapsed state if it exists
-            if ('collapsed' in format && format.collapsed !== isCollapsed) {
-              return;
-            }
-
-            if (dom.is(node, format.selector) && !isCaretNode(node)) {
-              setElementFormat(node, format);
-              found = true;
-              return false;
-            }
</del><span class="cx" style="display: block; padding: 0 10px">           });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return found;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          return attribs;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // This converts: <p>[a</p><p>]b</p> -> <p>[a]</p><p>b</p>
-        function adjustSelectionToVisibleSelection() {
-          function findSelectionEnd(start, end) {
-            var walker = new TreeWalker(end);
-            for (node = walker.prev2(); node; node = walker.prev2()) {
-              if (node.nodeType == 3 && node.data.length > 0) {
-                return node;
-              }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+         * Compares two objects checks if it's key + value exists in the other one.
+         *
+         * @private
+         * @param {Object} obj1 First object to compare.
+         * @param {Object} obj2 Second object to compare.
+         * @return {boolean} True/false if the objects matches or not.
+         */
+        function compareObjects(obj1, obj2) {
+          var value, name;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              if (node.childNodes.length > 1 || node == start || node.tagName == 'BR') {
-                return node;
-              }
-            }
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          for (name in obj1) {
+            // Obj1 has item obj2 doesn't have
+            if (obj1.hasOwnProperty(name)) {
+              value = obj2[name];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Adjust selection so that a end container with a end offset of zero is not included in the selection
-          // as this isn't visible to the user.
-          var rng = ed.selection.getRng();
-          var start = rng.startContainer;
-          var end = rng.endContainer;
-
-          if (start != end && rng.endOffset === 0) {
-            var newEnd = findSelectionEnd(start, end);
-            var endOffset = newEnd.nodeType == 3 ? newEnd.data.length : newEnd.childNodes.length;
-
-            rng.setEnd(newEnd, endOffset);
-          }
-
-          return rng;
-        }
-
-        function applyRngStyle(rng, bookmark, nodeSpecific) {
-          var newWrappers = [], wrapName, wrapElm, contentEditable = true;
-
-          // Setup wrapper element
-          wrapName = format.inline || format.block;
-          wrapElm = dom.create(wrapName);
-          setElementFormat(wrapElm);
-
-          rangeUtils.walk(rng, function (nodes) {
-            var currentWrapElm;
-
-            /**
-             * Process a list of nodes wrap them.
-             */
-            function process(node) {
-              var nodeName, parentName, hasContentEditableState, lastContentEditable;
-
-              lastContentEditable = contentEditable;
-              nodeName = node.nodeName.toLowerCase();
-              parentName = node.parentNode.nodeName.toLowerCase();
-
-              // Node has a contentEditable value
-              if (node.nodeType === 1 && getContentEditable(node)) {
-                lastContentEditable = contentEditable;
-                contentEditable = getContentEditable(node) === "true";
-                hasContentEditableState = true; // We don't want to wrap the container only it's children
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              // Obj2 doesn't have obj1 item
+              if (typeof value == "undefined") {
+                return false;
</ins><span class="cx" style="display: block; padding: 0 10px">               }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              // Stop wrapping on br elements
-              if (isEq(nodeName, 'br')) {
-                currentWrapElm = 0;
-
-                // Remove any br elements when we wrap things
-                if (format.block) {
-                  dom.remove(node);
-                }
-
-                return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              // Obj2 item has a different value
+              if (obj1[name] != value) {
+                return false;
</ins><span class="cx" style="display: block; padding: 0 10px">               }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              // If node is wrapper type
-              if (format.wrapper && matchNode(node, name, vars)) {
-                currentWrapElm = 0;
-                return;
-              }
-
-              // Can we rename the block
-              // TODO: Break this if up, too complex
-              if (contentEditable && !hasContentEditableState && format.block &&
-                !format.wrapper && isTextBlock(nodeName) && isValid(parentName, wrapName)) {
-                node = dom.rename(node, wrapName);
-                setElementFormat(node);
-                newWrappers.push(node);
-                currentWrapElm = 0;
-                return;
-              }
-
-              // Handle selector patterns
-              if (format.selector) {
-                var found = applyNodeStyle(formatList, node);
-
-                // Continue processing if a selector match wasn't found and a inline element is defined
-                if (!format.inline || found) {
-                  currentWrapElm = 0;
-                  return;
-                }
-              }
-
-              // Is it valid to wrap this item
-              // TODO: Break this if up, too complex
-              if (contentEditable && !hasContentEditableState && isValid(wrapName, nodeName) && isValid(parentName, wrapName) &&
-                !(!nodeSpecific && node.nodeType === 3 &&
-                  node.nodeValue.length === 1 &&
-                  node.nodeValue.charCodeAt(0) === 65279) &&
-                !isCaretNode(node) &&
-                (!format.inline || !isBlock(node))) {
-                // Start wrapping
-                if (!currentWrapElm) {
-                  // Wrap the node
-                  currentWrapElm = dom.clone(wrapElm, FALSE);
-                  node.parentNode.insertBefore(currentWrapElm, node);
-                  newWrappers.push(currentWrapElm);
-                }
-
-                currentWrapElm.appendChild(node);
-              } else {
-                // Start a new wrapper for possible children
-                currentWrapElm = 0;
-
-                each(grep(node.childNodes), process);
-
-                if (hasContentEditableState) {
-                  contentEditable = lastContentEditable; // Restore last contentEditable state from stack
-                }
-
-                // End the last wrapper
-                currentWrapElm = 0;
-              }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              // Delete similar value
+              delete obj2[name];
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-            // Process siblings from range
-            each(nodes, process);
-          });
-
-          // Apply formats to links as well to get the color of the underline to change as well
-          if (format.links === true) {
-            each(newWrappers, function (node) {
-              function process(node) {
-                if (node.nodeName === 'A') {
-                  setElementFormat(node, format);
-                }
-
-                each(grep(node.childNodes), process);
-              }
-
-              process(node);
-            });
</del><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Cleanup
-          each(newWrappers, function (node) {
-            var childCount;
-
-            function getChildCount(node) {
-              var count = 0;
-
-              each(node.childNodes, function (node) {
-                if (!isWhiteSpaceNode(node) && !isBookmarkNode(node)) {
-                  count++;
-                }
-              });
-
-              return count;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Check if obj 2 has something obj 1 doesn't have
+          for (name in obj2) {
+            // Obj2 has item obj1 doesn't have
+            if (obj2.hasOwnProperty(name)) {
+              return false;
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-            function getChildElementNode(root) {
-              var child = false;
-              each(root.childNodes, function (node) {
-                if (isElementNode(node)) {
-                  child = node;
-                  return false; // break loop
-                }
-              });
-              return child;
-            }
-
-            function matchNestedWrapper(node, filter) {
-              do {
-                if (getChildCount(node) !== 1) {
-                  break;
-                }
-
-                node = getChildElementNode(node);
-                if (!node) {
-                  break;
-                } else if (filter(node)) {
-                  return node;
-                }
-              } while (node);
-
-              return null;
-            }
-
-            function mergeStyles(node) {
-              var child, clone;
-
-              child = getChildElementNode(node);
-
-              // If child was found and of the same type as the current node
-              if (child && !isBookmarkNode(child) && matchName(child, format)) {
-                clone = dom.clone(child, FALSE);
-                setElementFormat(clone);
-
-                dom.replace(clone, node, TRUE);
-                dom.remove(child, 1);
-              }
-
-              return clone || node;
-            }
-
-            childCount = getChildCount(node);
-
-            // Remove empty nodes but only if there is multiple wrappers and they are not block
-            // elements so never remove single <h1></h1> since that would remove the
-            // current empty block element where the caret is at
-            if ((newWrappers.length > 1 || !isBlock(node)) && childCount === 0) {
-              dom.remove(node, 1);
-              return;
-            }
-
-            if (format.inline || format.wrapper) {
-              // Merges the current node with it's children of similar type to reduce the number of elements
-              if (!format.exact && childCount === 1) {
-                node = mergeStyles(node);
-              }
-
-              // Remove/merge children
-              each(formatList, function (format) {
-                // Merge all children of similar type will move styles from child to parent
-                // this: <span style="color:red"><b><span style="color:red; font-size:10px">text</span></b></span>
-                // will become: <span style="color:red"><b><span style="font-size:10px">text</span></b></span>
-                each(dom.select(format.inline, node), function (child) {
-                  if (!isElementNode(child)) {
-                    return;
-                  }
-
-                  removeFormat(format, vars, child, format.exact ? child : null);
-                });
-
-                clearChildStyles(format, node);
-              });
-
-              // Remove format if direct parent already has the same format
-              if (matchNode(node.parentNode, name, vars)) {
-                if (removeFormat(format, vars, node)) {
-                  node = 0;
-                }
-              }
-
-              // Remove format if any ancestor already has the same format
-              if (format.merge_with_parents) {
-                dom.getParent(node.parentNode, function (parent) {
-                  if (matchNode(parent, name, vars)) {
-                    if (removeFormat(format, vars, node)) {
-                      node = 0;
-                    }
-                    return TRUE;
-                  }
-                });
-              }
-
-              // fontSize defines the line height for the whole branch of nested style wrappers,
-              // therefore it should be set on the outermost wrapper
-              if (node && !isBlock(node) && !getStyle(node, 'fontSize')) {
-                var styleNode = matchNestedWrapper(node, hasStyle('fontSize'));
-                if (styleNode) {
-                  apply('fontsize', { value: getStyle(styleNode, 'fontSize') }, node);
-                }
-              }
-
-              // Merge next and previous siblings if they are similar <b>text</b><b>text</b> becomes <b>texttext</b>
-              if (node && format.merge_siblings !== false) {
-                node = mergeSiblings(getNonWhiteSpaceSibling(node), node);
-                node = mergeSiblings(node, getNonWhiteSpaceSibling(node, TRUE));
-              }
-            }
-          });
-        }
-
-        if (getContentEditable(selection.getNode()) === "false") {
-          node = selection.getNode();
-          for (var i = 0, l = formatList.length; i < l; i++) {
-            if (formatList[i].ceFalseOverride && dom.is(node, formatList[i].selector)) {
-              setElementFormat(node, formatList[i]);
-              return;
-            }
</del><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          return true;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (format) {
-          if (node) {
-            if (node.nodeType) {
-              if (!applyNodeStyle(formatList, node)) {
-                rng = dom.createRng();
-                rng.setStartBefore(node);
-                rng.setEndAfter(node);
-                applyRngStyle(expandRng(rng, formatList), null, true);
-              }
-            } else {
-              applyRngStyle(node, null, true);
-            }
-          } else {
-            if (!isCollapsed || !format.inline || dom.select('td[data-mce-selected],th[data-mce-selected]').length) {
-              // Obtain selection node before selection is unselected by applyRngStyle()
-              var curSelNode = ed.selection.getNode();
-
-              // If the formats have a default block and we can't find a parent block then
-              // start wrapping it with a DIV this is for forced_root_blocks: false
-              // It's kind of a hack but people should be using the default block type P since all desktop editors work that way
-              if (!forcedRootBlock && formatList[0].defaultBlock && !dom.getParent(curSelNode, dom.isBlock)) {
-                apply(formatList[0].defaultBlock);
-              }
-
-              // Apply formatting to selection
-              ed.selection.setRng(adjustSelectionToVisibleSelection());
-              bookmark = selection.getBookmark();
-              applyRngStyle(expandRng(selection.getRng(TRUE), formatList), bookmark);
-
-              if (format.styles) {
-                // Colored nodes should be underlined so that the color of the underline matches the text color.
-                if (format.styles.color || format.styles.textDecoration) {
-                  walk(curSelNode, processUnderlineAndColor, 'childNodes');
-                  processUnderlineAndColor(curSelNode);
-                }
-
-                // nodes with font-size should have their own background color as well to fit the line-height (see TINY-882)
-                if (format.styles.backgroundColor) {
-                  processChildElements(curSelNode,
-                    hasStyle('fontSize'),
-                    applyStyle('backgroundColor', replaceVars(format.styles.backgroundColor, vars))
-                  );
-                }
-              }
-
-              selection.moveToBookmark(bookmark);
-              moveStart(selection.getRng(TRUE));
-              ed.nodeChanged();
-            } else {
-              performCaretAction('apply', name, vars);
-            }
-          }
-
-          Hooks.postProcess(name, ed);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Attribs are not the same
+        if (!compareObjects(getAttribs(node1), getAttribs(node2))) {
+          return false;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Removes the specified format from the current selection or specified node.
-       *
-       * @method remove
-       * @param {String} name Name of format to remove.
-       * @param {Object} vars Optional list of variables to replace within format before removing it.
-       * @param {Node/Range} node Optional node or DOM range to remove the format from defaults to current selection.
-       */
-      function remove(name, vars, node, similar) {
-        var formatList = get(name), format = formatList[0], bookmark, rng, contentEditable = true;
-
-        // Merges the styles for each node
-        function process(node) {
-          var children, i, l, lastContentEditable, hasContentEditableState;
-
-          // Node has a contentEditable value
-          if (node.nodeType === 1 && getContentEditable(node)) {
-            lastContentEditable = contentEditable;
-            contentEditable = getContentEditable(node) === "true";
-            hasContentEditableState = true; // We don't want to wrap the container only it's children
-          }
-
-          // Grab the children first since the nodelist might be changed
-          children = grep(node.childNodes);
-
-          // Process current node
-          if (contentEditable && !hasContentEditableState) {
-            for (i = 0, l = formatList.length; i < l; i++) {
-              if (removeFormat(formatList[i], vars, node, node)) {
-                break;
-              }
-            }
-          }
-
-          // Process the children
-          if (format.deep) {
-            if (children.length) {
-              for (i = 0, l = children.length; i < l; i++) {
-                process(children[i]);
-              }
-
-              if (hasContentEditableState) {
-                contentEditable = lastContentEditable; // Restore last contentEditable state from stack
-              }
-            }
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Styles are not the same
+        if (!compareObjects(dom.parseStyle(dom.getAttrib(node1, 'style')), dom.parseStyle(dom.getAttrib(node2, 'style')))) {
+          return false;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function findFormatRoot(container) {
-          var formatRoot;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return !BookmarkManager.isBookmarkNode(node1) && !BookmarkManager.isBookmarkNode(node2);
+      };
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Find format root
-          each(getParents(container.parentNode).reverse(), function (parent) {
-            var format;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return ElementUtils;
+  }
+);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // Find format root element
-            if (!formatRoot && parent.id != '_start' && parent.id != '_end') {
-              // Is the node matching the format we are looking for
-              format = matchNode(parent, name, vars, similar);
-              if (format && format.split !== false) {
-                formatRoot = parent;
-              }
-            }
-          });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/**
+ * RemoveFormat.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return formatRoot;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+define(
+  'tinymce.core.fmt.RemoveFormat',
+  [
+    'ephox.katamari.api.Fun',
+    'tinymce.core.dom.BookmarkManager',
+    'tinymce.core.dom.RangeUtils',
+    'tinymce.core.dom.TreeWalker',
+    'tinymce.core.fmt.CaretFormat',
+    'tinymce.core.fmt.ExpandRange',
+    'tinymce.core.fmt.FormatUtils',
+    'tinymce.core.fmt.MatchFormat',
+    'tinymce.core.util.Tools'
+  ],
+  function (Fun, BookmarkManager, RangeUtils, TreeWalker, CaretFormat, ExpandRange, FormatUtils, MatchFormat, Tools) {
+    var MCE_ATTR_RE = /^(src|href|style)$/;
+    var each = Tools.each;
+    var isEq = FormatUtils.isEq;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function wrapAndSplit(formatRoot, container, target, split) {
-          var parent, clone, lastClone, firstClone, i, formatRootParent;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isTableCell = function (node) {
+      return /^(TH|TD)$/.test(node.nodeName);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Format root found then clone formats and split it
-          if (formatRoot) {
-            formatRootParent = formatRoot.parentNode;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var getContainer = function (ed, rng, start) {
+      var container, offset, lastIdx;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            for (parent = container.parentNode; parent && parent != formatRootParent; parent = parent.parentNode) {
-              clone = dom.clone(parent, FALSE);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      container = rng[start ? 'startContainer' : 'endContainer'];
+      offset = rng[start ? 'startOffset' : 'endOffset'];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              for (i = 0; i < formatList.length; i++) {
-                if (removeFormat(formatList[i], vars, clone, clone)) {
-                  clone = 0;
-                  break;
-                }
-              }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (container.nodeType === 1) {
+        lastIdx = container.childNodes.length - 1;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              // Build wrapper node
-              if (clone) {
-                if (lastClone) {
-                  clone.appendChild(lastClone);
-                }
-
-                if (!firstClone) {
-                  firstClone = clone;
-                }
-
-                lastClone = clone;
-              }
-            }
-
-            // Never split block elements if the format is mixed
-            if (split && (!format.mixed || !isBlock(formatRoot))) {
-              container = dom.split(formatRoot, container);
-            }
-
-            // Wrap container in cloned formats
-            if (lastClone) {
-              target.parentNode.insertBefore(lastClone, target);
-              firstClone.appendChild(target);
-            }
-          }
-
-          return container;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (!start && offset) {
+          offset--;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function splitToFormatRoot(container) {
-          return wrapAndSplit(findFormatRoot(container), container, container, true);
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        container = container.childNodes[offset > lastIdx ? lastIdx : offset];
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function unwrap(start) {
-          var node = dom.get(start ? '_start' : '_end'),
-            out = node[start ? 'firstChild' : 'lastChild'];
-
-          // If the end is placed within the start the result will be removed
-          // So this checks if the out node is a bookmark node if it is it
-          // checks for another more suitable node
-          if (isBookmarkNode(out)) {
-            out = out[start ? 'firstChild' : 'lastChild'];
-          }
-
-          // Since dom.remove removes empty text nodes then we need to try to find a better node
-          if (out.nodeType == 3 && out.data.length === 0) {
-            out = start ? node.previousSibling || node.nextSibling : node.nextSibling || node.previousSibling;
-          }
-
-          dom.remove(node, true);
-
-          return out;
-        }
-
-        function removeRngStyle(rng) {
-          var startContainer, endContainer;
-          var commonAncestorContainer = rng.commonAncestorContainer;
-
-          rng = expandRng(rng, formatList, TRUE);
-
-          if (format.split) {
-            startContainer = getContainer(rng, TRUE);
-            endContainer = getContainer(rng);
-
-            if (startContainer != endContainer) {
-              // WebKit will render the table incorrectly if we wrap a TH or TD in a SPAN
-              // so let's see if we can use the first child instead
-              // This will happen if you triple click a table cell and use remove formatting
-              if (/^(TR|TH|TD)$/.test(startContainer.nodeName) && startContainer.firstChild) {
-                if (startContainer.nodeName == "TR") {
-                  startContainer = startContainer.firstChild.firstChild || startContainer;
-                } else {
-                  startContainer = startContainer.firstChild || startContainer;
-                }
-              }
-
-              // Try to adjust endContainer as well if cells on the same row were selected - bug #6410
-              if (commonAncestorContainer &&
-                /^T(HEAD|BODY|FOOT|R)$/.test(commonAncestorContainer.nodeName) &&
-                isTableCell(endContainer) && endContainer.firstChild) {
-                endContainer = endContainer.firstChild || endContainer;
-              }
-
-              if (dom.isChildOf(startContainer, endContainer) && !isBlock(endContainer) &&
-                !isTableCell(startContainer) && !isTableCell(endContainer)) {
-                startContainer = wrap(startContainer, 'span', { id: '_start', 'data-mce-type': 'bookmark' });
-                splitToFormatRoot(startContainer);
-                startContainer = unwrap(TRUE);
-                return;
-              }
-
-              // Wrap start/end nodes in span element since these might be cloned/moved
-              startContainer = wrap(startContainer, 'span', { id: '_start', 'data-mce-type': 'bookmark' });
-              endContainer = wrap(endContainer, 'span', { id: '_end', 'data-mce-type': 'bookmark' });
-
-              // Split start/end
-              splitToFormatRoot(startContainer);
-              splitToFormatRoot(endContainer);
-
-              // Unwrap start/end to get real elements again
-              startContainer = unwrap(TRUE);
-              endContainer = unwrap();
-            } else {
-              startContainer = endContainer = splitToFormatRoot(startContainer);
-            }
-
-            // Update range positions since they might have changed after the split operations
-            rng.startContainer = startContainer.parentNode ? startContainer.parentNode : startContainer;
-            rng.startOffset = nodeIndex(startContainer);
-            rng.endContainer = endContainer.parentNode ? endContainer.parentNode : endContainer;
-            rng.endOffset = nodeIndex(endContainer) + 1;
-          }
-
-          // Remove items between start/end
-          rangeUtils.walk(rng, function (nodes) {
-            each(nodes, function (node) {
-              process(node);
-
-              // Remove parent span if it only contains text-decoration: underline, yet a parent node is also underlined.
-              if (node.nodeType === 1 && ed.dom.getStyle(node, 'text-decoration') === 'underline' &&
-                node.parentNode && getTextDecoration(node.parentNode) === 'underline') {
-                removeFormat({
-                  'deep': false,
-                  'exact': true,
-                  'inline': 'span',
-                  'styles': {
-                    'textDecoration': 'underline'
-                  }
-                }, null, node);
-              }
-            });
-          });
-        }
-
-        // Handle node
-        if (node) {
-          if (node.nodeType) {
-            rng = dom.createRng();
-            rng.setStartBefore(node);
-            rng.setEndAfter(node);
-            removeRngStyle(rng);
-          } else {
-            removeRngStyle(node);
-          }
-
-          return;
-        }
-
-        if (getContentEditable(selection.getNode()) === "false") {
-          node = selection.getNode();
-          for (var i = 0, l = formatList.length; i < l; i++) {
-            if (formatList[i].ceFalseOverride) {
-              if (removeFormat(formatList[i], vars, node, node)) {
-                break;
-              }
-            }
-          }
-
-          return;
-        }
-
-        if (!selection.isCollapsed() || !format.inline || dom.select('td[data-mce-selected],th[data-mce-selected]').length) {
-          bookmark = selection.getBookmark();
-          removeRngStyle(selection.getRng(TRUE));
-          selection.moveToBookmark(bookmark);
-
-          // Check if start element still has formatting then we are at: "<b>text|</b>text"
-          // and need to move the start into the next text node
-          if (format.inline && match(name, vars, selection.getStart())) {
-            moveStart(selection.getRng(true));
-          }
-
-          ed.nodeChanged();
-        } else {
-          performCaretAction('remove', name, vars, similar);
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // If start text node is excluded then walk to the next node
+      if (container.nodeType === 3 && start && offset >= container.nodeValue.length) {
+        container = new TreeWalker(container, ed.getBody()).next() || container;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Toggles the specified format on/off.
-       *
-       * @method toggle
-       * @param {String} name Name of format to apply/remove.
-       * @param {Object} vars Optional list of variables to replace within format before applying/removing it.
-       * @param {Node} node Optional node to apply the format to or remove from. Defaults to current selection.
-       */
-      function toggle(name, vars, node) {
-        var fmt = get(name);
-
-        if (match(name, vars, node) && (!('toggle' in fmt[0]) || fmt[0].toggle)) {
-          remove(name, vars, node);
-        } else {
-          apply(name, vars, node);
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // If end text node is excluded then walk to the previous node
+      if (container.nodeType === 3 && !start && offset === 0) {
+        container = new TreeWalker(container, ed.getBody()).prev() || container;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Return true/false if the specified node has the specified format.
-       *
-       * @method matchNode
-       * @param {Node} node Node to check the format on.
-       * @param {String} name Format name to check.
-       * @param {Object} vars Optional list of variables to replace before checking it.
-       * @param {Boolean} similar Match format that has similar properties.
-       * @return {Object} Returns the format object it matches or undefined if it doesn't match.
-       */
-      function matchNode(node, name, vars, similar) {
-        var formatList = get(name), format, i, classes;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return container;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function matchItems(node, format, itemName) {
-          var key, value, items = format[itemName], i;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var wrap = function (dom, node, name, attrs) {
+      var wrapper = dom.create(name, attrs);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Custom match
-          if (format.onmatch) {
-            return format.onmatch(node, format, itemName);
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      node.parentNode.insertBefore(wrapper, node);
+      wrapper.appendChild(node);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Check all items
-          if (items) {
-            // Non indexed object
-            if (items.length === undef) {
-              for (key in items) {
-                if (items.hasOwnProperty(key)) {
-                  if (itemName === 'attributes') {
-                    value = dom.getAttrib(node, key);
-                  } else {
-                    value = getStyle(node, key);
-                  }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return wrapper;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                  if (similar && !value && !format.exact) {
-                    return;
-                  }
-
-                  if ((!similar || format.exact) && !isEq(value, normalizeStyleValue(replaceVars(items[key], vars), key))) {
-                    return;
-                  }
-                }
-              }
-            } else {
-              // Only one match needed for indexed arrays
-              for (i = 0; i < items.length; i++) {
-                if (itemName === 'attributes' ? dom.getAttrib(node, items[i]) : getStyle(node, items[i])) {
-                  return format;
-                }
-              }
-            }
-          }
-
-          return format;
-        }
-
-        if (formatList && node) {
-          // Check each format in list
-          for (i = 0; i < formatList.length; i++) {
-            format = formatList[i];
-
-            // Name name, attributes, styles and classes
-            if (matchName(node, format) && matchItems(node, format, 'attributes') && matchItems(node, format, 'styles')) {
-              // Match classes
-              if ((classes = format.classes)) {
-                for (i = 0; i < classes.length; i++) {
-                  if (!dom.hasClass(node, classes[i])) {
-                    return;
-                  }
-                }
-              }
-
-              return format;
-            }
-          }
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    /**
+     * Checks if the specified nodes name matches the format inline/block or selector.
+     *
+     * @private
+     * @param {Node} node Node to match against the specified format.
+     * @param {Object} format Format object o match with.
+     * @return {boolean} true/false if the format matches.
+     */
+    var matchName = function (dom, node, format) {
+      // Check for inline match
+      if (isEq(node, format.inline)) {
+        return true;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Matches the current selection or specified node against the specified format name.
-       *
-       * @method match
-       * @param {String} name Name of format to match.
-       * @param {Object} vars Optional list of variables to replace before checking it.
-       * @param {Node} node Optional node to check.
-       * @return {boolean} true/false if the specified selection/node matches the format.
-       */
-      function match(name, vars, node) {
-        var startNode;
-
-        function matchParents(node) {
-          var root = dom.getRoot();
-
-          if (node === root) {
-            return false;
-          }
-
-          // Find first node with similar format settings
-          node = dom.getParent(node, function (node) {
-            if (matchesUnInheritedFormatSelector(node, name)) {
-              return true;
-            }
-
-            return node.parentNode === root || !!matchNode(node, name, vars, true);
-          });
-
-          // Do an exact check on the similar format element
-          return matchNode(node, name, vars);
-        }
-
-        // Check specified node
-        if (node) {
-          return matchParents(node);
-        }
-
-        // Check selected node
-        node = selection.getNode();
-        if (matchParents(node)) {
-          return TRUE;
-        }
-
-        // Check start node if it's different
-        startNode = selection.getStart();
-        if (startNode != node) {
-          if (matchParents(startNode)) {
-            return TRUE;
-          }
-        }
-
-        return FALSE;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Check for block match
+      if (isEq(node, format.block)) {
+        return true;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Matches the current selection against the array of formats and returns a new array with matching formats.
-       *
-       * @method matchAll
-       * @param {Array} names Name of format to match.
-       * @param {Object} vars Optional list of variables to replace before checking it.
-       * @return {Array} Array with matched formats.
-       */
-      function matchAll(names, vars) {
-        var startElement, matchedFormatNames = [], checkedMap = {};
-
-        // Check start of selection for formats
-        startElement = selection.getStart();
-        dom.getParent(startElement, function (node) {
-          var i, name;
-
-          for (i = 0; i < names.length; i++) {
-            name = names[i];
-
-            if (!checkedMap[name] && matchNode(node, name, vars)) {
-              checkedMap[name] = true;
-              matchedFormatNames.push(name);
-            }
-          }
-        }, dom.getRoot());
-
-        return matchedFormatNames;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Check for selector match
+      if (format.selector) {
+        return node.nodeType === 1 && dom.is(node, format.selector);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Returns true/false if the specified format can be applied to the current selection or not. It
-       * will currently only check the state for selector formats, it returns true on all other format types.
-       *
-       * @method canApply
-       * @param {String} name Name of format to check.
-       * @return {boolean} true/false if the specified format can be applied to the current selection/node.
-       */
-      function canApply(name) {
-        var formatList = get(name), startNode, parents, i, x, selector;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isColorFormatAndAnchor = function (node, format) {
+      return format.links && node.tagName === 'A';
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (formatList) {
-          startNode = selection.getStart();
-          parents = getParents(startNode);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var find = function (dom, node, next, inc) {
+      node = FormatUtils.getNonWhiteSpaceSibling(node, next, inc);
+      return !node || (node.nodeName === 'BR' || dom.isBlock(node));
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          for (x = formatList.length - 1; x >= 0; x--) {
-            selector = formatList[x].selector;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    /**
+     * Removes the node and wrap it's children in paragraphs before doing so or
+     * appends BR elements to the beginning/end of the block element if forcedRootBlocks is disabled.
+     *
+     * If the div in the node below gets removed:
+     *  text<div>text</div>text
+     *
+     * Output becomes:
+     *  text<div><br />text<br /></div>text
+     *
+     * So when the div is removed the result is:
+     *  text<br />text<br />text
+     *
+     * @private
+     * @param {Node} node Node to remove + apply BR/P elements to.
+     * @param {Object} format Format rule.
+     * @return {Node} Input node.
+     */
+    var removeNode = function (ed, node, format) {
+      var parentNode = node.parentNode, rootBlockElm;
+      var dom = ed.dom, forcedRootBlock = ed.settings.forced_root_block;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // Format is not selector based then always return TRUE
-            // Is it has a defaultBlock then it's likely it can be applied for example align on a non block element line
-            if (!selector || formatList[x].defaultBlock) {
-              return TRUE;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (format.block) {
+        if (!forcedRootBlock) {
+          // Append BR elements if needed before we remove the block
+          if (dom.isBlock(node) && !dom.isBlock(parentNode)) {
+            if (!find(dom, node, false) && !find(dom, node.firstChild, true, 1)) {
+              node.insertBefore(dom.create('br'), node.firstChild);
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            for (i = parents.length - 1; i >= 0; i--) {
-              if (dom.is(parents[i], selector)) {
-                return TRUE;
-              }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            if (!find(dom, node, true) && !find(dom, node.lastChild, false, 1)) {
+              node.appendChild(dom.create('br'));
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        }
-
-        return FALSE;
-      }
-
-      /**
-       * Executes the specified callback when the current selection matches the formats or not.
-       *
-       * @method formatChanged
-       * @param {String} formats Comma separated list of formats to check for.
-       * @param {function} callback Callback with state and args when the format is changed/toggled on/off.
-       * @param {Boolean} similar True/false state if the match should handle similar or exact formats.
-       */
-      function formatChanged(formats, callback, similar) {
-        var currentFormats;
-
-        // Setup format node change logic
-        if (!formatChangeData) {
-          formatChangeData = {};
-          currentFormats = {};
-
-          ed.on('NodeChange', function (e) {
-            var parents = getParents(e.element), matchedFormats = {};
-
-            // Ignore bogus nodes like the <a> tag created by moveStart()
-            parents = Tools.grep(parents, function (node) {
-              return node.nodeType == 1 && !node.getAttribute('data-mce-bogus');
-            });
-
-            // Check for new formats
-            each(formatChangeData, function (callbacks, format) {
-              each(parents, function (node) {
-                if (matchNode(node, format, {}, callbacks.similar)) {
-                  if (!currentFormats[format]) {
-                    // Execute callbacks
-                    each(callbacks, function (callback) {
-                      callback(true, { node: node, format: format, parents: parents });
-                    });
-
-                    currentFormats[format] = callbacks;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        } else {
+          // Wrap the block in a forcedRootBlock if we are at the root of document
+          if (parentNode === dom.getRoot()) {
+            if (!format.list_block || !isEq(node, format.list_block)) {
+              each(Tools.grep(node.childNodes), function (node) {
+                if (FormatUtils.isValid(ed, forcedRootBlock, node.nodeName.toLowerCase())) {
+                  if (!rootBlockElm) {
+                    rootBlockElm = wrap(dom, node, forcedRootBlock);
+                    dom.setAttribs(rootBlockElm, ed.settings.forced_root_block_attrs);
+                  } else {
+                    rootBlockElm.appendChild(node);
</ins><span class="cx" style="display: block; padding: 0 10px">                   }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-                  matchedFormats[format] = callbacks;
-                  return false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                } else {
+                  rootBlockElm = 0;
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-                if (matchesUnInheritedFormatSelector(node, format)) {
-                  return false;
-                }
</del><span class="cx" style="display: block; padding: 0 10px">               });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            });
-
-            // Check if current formats still match
-            each(currentFormats, function (callbacks, format) {
-              if (!matchedFormats[format]) {
-                delete currentFormats[format];
-
-                each(callbacks, function (callback) {
-                  callback(false, { node: e.element, format: format, parents: parents });
-                });
-              }
-            });
-          });
-        }
-
-        // Add format listeners
-        each(formats.split(','), function (format) {
-          if (!formatChangeData[format]) {
-            formatChangeData[format] = [];
-            formatChangeData[format].similar = similar;
-          }
-
-          formatChangeData[format].push(callback);
-        });
-
-        return this;
-      }
-
-      /**
-       * Returns a preview css text for the specified format.
-       *
-       * @method getCssText
-       * @param {String/Object} format Format to generate preview css text for.
-       * @return {String} Css text for the specified format.
-       * @example
-       * var cssText1 = editor.formatter.getCssText('bold');
-       * var cssText2 = editor.formatter.getCssText({inline: 'b'});
-       */
-      function getCssText(format) {
-        return Preview.getCssText(ed, format);
-      }
-
-      // Expose to public
-      extend(this, {
-        get: get,
-        register: register,
-        unregister: unregister,
-        apply: apply,
-        remove: remove,
-        toggle: toggle,
-        match: match,
-        matchAll: matchAll,
-        matchNode: matchNode,
-        canApply: canApply,
-        formatChanged: formatChanged,
-        getCssText: getCssText
-      });
-
-      // Initialize
-      defaultFormats();
-      addKeyboardShortcuts();
-      ed.on('BeforeGetContent', function (e) {
-        if (markCaretContainersBogus && e.format != 'raw') {
-          markCaretContainersBogus();
-        }
-      });
-      ed.on('mouseup keydown', function (e) {
-        if (disableCaretContainer) {
-          disableCaretContainer(e);
-        }
-      });
-
-      // Private functions
-
-      /**
-       * Checks if the specified nodes name matches the format inline/block or selector.
-       *
-       * @private
-       * @param {Node} node Node to match against the specified format.
-       * @param {Object} format Format object o match with.
-       * @return {boolean} true/false if the format matches.
-       */
-      function matchName(node, format) {
-        // Check for inline match
-        if (isEq(node, format.inline)) {
-          return TRUE;
-        }
-
-        // Check for block match
-        if (isEq(node, format.block)) {
-          return TRUE;
-        }
-
-        // Check for selector match
-        if (format.selector) {
-          return node.nodeType == 1 && dom.is(node, format.selector);
-        }
-      }
-
-      /**
-       * Compares two string/nodes regardless of their case.
-       *
-       * @private
-       * @param {String/Node} str1 Node or string to compare.
-       * @param {String/Node} str2 Node or string to compare.
-       * @return {boolean} True/false if they match.
-       */
-      function isEq(str1, str2) {
-        str1 = str1 || '';
-        str2 = str2 || '';
-
-        str1 = '' + (str1.nodeName || str1);
-        str2 = '' + (str2.nodeName || str2);
-
-        return str1.toLowerCase() == str2.toLowerCase();
-      }
-
-      function processChildElements(node, filter, process) {
-        each(node.childNodes, function (node) {
-          if (isElementNode(node)) {
-            if (filter(node)) {
-              process(node);
</del><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (node.hasChildNodes()) {
-              processChildElements(node, filter, process);
-            }
</del><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        });
-      }
-
-      function isElementNode(node) {
-        return node && node.nodeType === 1 && !isBookmarkNode(node) && !isCaretNode(node) && !NodeType.isBogus(node);
-      }
-
-      function hasStyle(name) {
-        return Fun.curry(function (name, node) {
-          return !!(node && getStyle(node, name));
-        }, name);
-      }
-
-      function applyStyle(name, value) {
-        return Fun.curry(function (name, value, node) {
-          dom.setStyle(node, name, value);
-        }, name, value);
-      }
-
-      /**
-       * Returns the style by name on the specified node. This method modifies the style
-       * contents to make it more easy to match. This will resolve a few browser issues.
-       *
-       * @private
-       * @param {Node} node to get style from.
-       * @param {String} name Style name to get.
-       * @return {String} Style item value.
-       */
-      function getStyle(node, name) {
-        return normalizeStyleValue(dom.getStyle(node, name), name);
-      }
-
-      /**
-       * Normalize style value by name. This method modifies the style contents
-       * to make it more easy to match. This will resolve a few browser issues.
-       *
-       * @private
-       * @param {String} value Value to get style from.
-       * @param {String} name Style name to get.
-       * @return {String} Style item value.
-       */
-      function normalizeStyleValue(value, name) {
-        // Force the format to hex
-        if (name == 'color' || name == 'backgroundColor') {
-          value = dom.toHex(value);
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-        // Opera will return bold as 700
-        if (name == 'fontWeight' && value == 700) {
-          value = 'bold';
-        }
-
-        // Normalize fontFamily so "'Font name', Font" becomes: "Font name,Font"
-        if (name == 'fontFamily') {
-          value = value.replace(/[\'\"]/g, '').replace(/,\s+/g, ',');
-        }
-
-        return '' + value;
</del><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Replaces variables in the value. The variable format is %var.
-       *
-       * @private
-       * @param {String} value Value to replace variables in.
-       * @param {Object} vars Name/value array with variables to replace.
-       * @return {String} New value with replaced variables.
-       */
-      function replaceVars(value, vars) {
-        if (typeof value != "string") {
-          value = value(vars);
-        } else if (vars) {
-          value = value.replace(/%(\w+)/g, function (str, name) {
-            return vars[name] || str;
-          });
-        }
-
-        return value;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Never remove nodes that isn't the specified inline element if a selector is specified too
+      if (format.selector && format.inline && !isEq(format.inline, node)) {
+        return;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function isWhiteSpaceNode(node) {
-        return node && node.nodeType === 3 && /^([\t \r\n]+|)$/.test(node.nodeValue);
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      dom.remove(node, 1);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function wrap(node, name, attrs) {
-        var wrapper = dom.create(name, attrs);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    /**
+     * Removes the specified format for the specified node. It will also remove the node if it doesn't have
+     * any attributes if the format specifies it to do so.
+     *
+     * @private
+     * @param {Object} format Format object with items to remove from node.
+     * @param {Object} vars Name/value object with variables to apply to format.
+     * @param {Node} node Node to remove the format styles on.
+     * @param {Node} compareNode Optional compare node, if specified the styles will be compared to that node.
+     * @return {Boolean} True/false if the node was removed or not.
+     */
+    var removeFormat = function (ed, format, vars, node, compareNode) {
+      var i, attrs, stylesModified, dom = ed.dom;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        node.parentNode.insertBefore(wrapper, node);
-        wrapper.appendChild(node);
-
-        return wrapper;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Check if node matches format
+      if (!matchName(dom, node, format) && !isColorFormatAndAnchor(node, format)) {
+        return false;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Expands the specified range like object to depending on format.
-       *
-       * For example on block formats it will move the start/end position
-       * to the beginning of the current block.
-       *
-       * @private
-       * @param {Object} rng Range like object.
-       * @param {Array} format Array with formats to expand by.
-       * @param {Boolean} remove
-       * @return {Object} Expanded range like object.
-       */
-      function expandRng(rng, format, remove) {
-        var lastIdx, leaf, endPoint,
-          startContainer = rng.startContainer,
-          startOffset = rng.startOffset,
-          endContainer = rng.endContainer,
-          endOffset = rng.endOffset;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Should we compare with format attribs and styles
+      if (format.remove !== 'all') {
+        // Remove styles
+        each(format.styles, function (value, name) {
+          value = FormatUtils.normalizeStyleValue(dom, FormatUtils.replaceVars(value, vars), name);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // This function walks up the tree if there is no siblings before/after the node
-        function findParentContainer(start) {
-          var container, parent, sibling, siblingName, root;
-
-          container = parent = start ? startContainer : endContainer;
-          siblingName = start ? 'previousSibling' : 'nextSibling';
-          root = dom.getRoot();
-
-          function isBogusBr(node) {
-            return node.nodeName == "BR" && node.getAttribute('data-mce-bogus') && !node.nextSibling;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Indexed array
+          if (typeof name === 'number') {
+            name = value;
+            compareNode = 0;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // If it's a text node and the offset is inside the text
-          if (container.nodeType == 3 && !isWhiteSpaceNode(container)) {
-            if (start ? startOffset > 0 : endOffset < container.nodeValue.length) {
-              return container;
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (format.remove_similar || (!compareNode || isEq(FormatUtils.getStyle(dom, compareNode, name), value))) {
+            dom.setStyle(node, name, '');
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          /*eslint no-constant-condition:0 */
-          while (true) {
-            // Stop expanding on block elements
-            if (!format[0].block_expand && isBlock(parent)) {
-              return parent;
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          stylesModified = 1;
+        });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // Walk left/right
-            for (sibling = parent[siblingName]; sibling; sibling = sibling[siblingName]) {
-              if (!isBookmarkNode(sibling) && !isWhiteSpaceNode(sibling) && !isBogusBr(sibling)) {
-                return parent;
-              }
-            }
-
-            // Check if we can move up are we at root level or body level
-            if (parent == root || parent.parentNode == root) {
-              container = parent;
-              break;
-            }
-
-            parent = parent.parentNode;
-          }
-
-          return container;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Remove style attribute if it's empty
+        if (stylesModified && dom.getAttrib(node, 'style') === '') {
+          node.removeAttribute('style');
+          node.removeAttribute('data-mce-style');
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // This function walks down the tree to find the leaf at the selection.
-        // The offset is also returned as if node initially a leaf, the offset may be in the middle of the text node.
-        function findLeaf(node, offset) {
-          if (offset === undef) {
-            offset = node.nodeType === 3 ? node.length : node.childNodes.length;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Remove attributes
+        each(format.attributes, function (value, name) {
+          var valueOut;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          while (node && node.hasChildNodes()) {
-            node = node.childNodes[offset];
-            if (node) {
-              offset = node.nodeType === 3 ? node.length : node.childNodes.length;
-            }
-          }
-          return { node: node, offset: offset };
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          value = FormatUtils.replaceVars(value, vars);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // If index based start position then resolve it
-        if (startContainer.nodeType == 1 && startContainer.hasChildNodes()) {
-          lastIdx = startContainer.childNodes.length - 1;
-          startContainer = startContainer.childNodes[startOffset > lastIdx ? lastIdx : startOffset];
-
-          if (startContainer.nodeType == 3) {
-            startOffset = 0;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Indexed array
+          if (typeof name === 'number') {
+            name = value;
+            compareNode = 0;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // If index based end position then resolve it
-        if (endContainer.nodeType == 1 && endContainer.hasChildNodes()) {
-          lastIdx = endContainer.childNodes.length - 1;
-          endContainer = endContainer.childNodes[endOffset > lastIdx ? lastIdx : endOffset - 1];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (!compareNode || isEq(dom.getAttrib(compareNode, name), value)) {
+            // Keep internal classes
+            if (name === 'class') {
+              value = dom.getAttrib(node, name);
+              if (value) {
+                // Build new class value where everything is removed except the internal prefixed classes
+                valueOut = '';
+                each(value.split(/\s+/), function (cls) {
+                  if (/mce\-\w+/.test(cls)) {
+                    valueOut += (valueOut ? ' ' : '') + cls;
+                  }
+                });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (endContainer.nodeType == 3) {
-            endOffset = endContainer.nodeValue.length;
-          }
-        }
-
-        // Expands the node to the closes contentEditable false element if it exists
-        function findParentContentEditable(node) {
-          var parent = node;
-
-          while (parent) {
-            if (parent.nodeType === 1 && getContentEditable(parent)) {
-              return getContentEditable(parent) === "false" ? parent : node;
-            }
-
-            parent = parent.parentNode;
-          }
-
-          return node;
-        }
-
-        function findWordEndPoint(container, offset, start) {
-          var walker, node, pos, lastTextNode;
-
-          function findSpace(node, offset) {
-            var pos, pos2, str = node.nodeValue;
-
-            if (typeof offset == "undefined") {
-              offset = start ? str.length : 0;
-            }
-
-            if (start) {
-              pos = str.lastIndexOf(' ', offset);
-              pos2 = str.lastIndexOf('\u00a0', offset);
-              pos = pos > pos2 ? pos : pos2;
-
-              // Include the space on remove to avoid tag soup
-              if (pos !== -1 && !remove) {
-                pos++;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                // We got some internal classes left
+                if (valueOut) {
+                  dom.setAttrib(node, name, valueOut);
+                  return;
+                }
</ins><span class="cx" style="display: block; padding: 0 10px">               }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            } else {
-              pos = str.indexOf(' ', offset);
-              pos2 = str.indexOf('\u00a0', offset);
-              pos = pos !== -1 && (pos2 === -1 || pos < pos2) ? pos : pos2;
</del><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            return pos;
-          }
-
-          if (container.nodeType === 3) {
-            pos = findSpace(container, offset);
-
-            if (pos !== -1) {
-              return { container: container, offset: pos };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // IE6 has a bug where the attribute doesn't get removed correctly
+            if (name === "class") {
+              node.removeAttribute('className');
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            lastTextNode = container;
-          }
-
-          // Walk the nodes inside the block
-          walker = new TreeWalker(container, dom.getParent(container, isBlock) || ed.getBody());
-          while ((node = walker[start ? 'prev' : 'next']())) {
-            if (node.nodeType === 3) {
-              lastTextNode = node;
-              pos = findSpace(node);
-
-              if (pos !== -1) {
-                return { container: node, offset: pos };
-              }
-            } else if (isBlock(node)) {
-              break;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // Remove mce prefixed attributes
+            if (MCE_ATTR_RE.test(name)) {
+              node.removeAttribute('data-mce-' + name);
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (lastTextNode) {
-            if (start) {
-              offset = 0;
-            } else {
-              offset = lastTextNode.length;
-            }
-
-            return { container: lastTextNode, offset: offset };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            node.removeAttribute(name);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function findSelectorEndPoint(container, siblingName) {
-          var parents, i, y, curFormat;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Remove classes
+        each(format.classes, function (value) {
+          value = FormatUtils.replaceVars(value, vars);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (container.nodeType == 3 && container.nodeValue.length === 0 && container[siblingName]) {
-            container = container[siblingName];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (!compareNode || dom.hasClass(compareNode, value)) {
+            dom.removeClass(node, value);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          parents = getParents(container);
-          for (i = 0; i < parents.length; i++) {
-            for (y = 0; y < format.length; y++) {
-              curFormat = format[y];
-
-              // If collapsed state is set then skip formats that doesn't match that
-              if ("collapsed" in curFormat && curFormat.collapsed !== rng.collapsed) {
-                continue;
-              }
-
-              if (dom.is(parents[i], curFormat.selector)) {
-                return parents[i];
-              }
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Check for non internal attributes
+        attrs = dom.getAttribs(node);
+        for (i = 0; i < attrs.length; i++) {
+          var attrName = attrs[i].nodeName;
+          if (attrName.indexOf('_') !== 0 && attrName.indexOf('data-') !== 0) {
+            return false;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-          return container;
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function findBlockEndPoint(container, siblingName) {
-          var node, root = dom.getRoot();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Remove the inline child if it's empty for example <b> or <span>
+      if (format.remove !== 'none') {
+        removeNode(ed, node, format);
+        return true;
+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Expand to block of similar type
-          if (!format[0].wrapper) {
-            node = dom.getParent(container, format[0].block, root);
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var findFormatRoot = function (editor, container, name, vars, similar) {
+      var formatRoot;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Expand to first wrappable block element or any block element
-          if (!node) {
-            node = dom.getParent(container.nodeType == 3 ? container.parentNode : container, function (node) {
-              // Fixes #6183 where it would expand to editable parent element in inline mode
-              return node != root && isTextBlock(node);
-            });
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Find format root
+      each(FormatUtils.getParents(editor.dom, container.parentNode).reverse(), function (parent) {
+        var format;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Exclude inner lists from wrapping
-          if (node && format[0].wrapper) {
-            node = getParents(node, 'ul,ol').reverse()[0] || node;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Find format root element
+        if (!formatRoot && parent.id !== '_start' && parent.id !== '_end') {
+          // Is the node matching the format we are looking for
+          format = MatchFormat.matchNode(editor, parent, name, vars, similar);
+          if (format && format.split !== false) {
+            formatRoot = parent;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-          // Didn't find a block element look for first/last wrappable element
-          if (!node) {
-            node = container;
-
-            while (node[siblingName] && !isBlock(node[siblingName])) {
-              node = node[siblingName];
-
-              // Break on BR but include it will be removed later on
-              // we can't remove it now since we need to check if it can be wrapped
-              if (isEq(node, 'br')) {
-                break;
-              }
-            }
-          }
-
-          return node || container;
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Expand to closest contentEditable element
-        startContainer = findParentContentEditable(startContainer);
-        endContainer = findParentContentEditable(endContainer);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return formatRoot;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Exclude bookmark nodes if possible
-        if (isBookmarkNode(startContainer.parentNode) || isBookmarkNode(startContainer)) {
-          startContainer = isBookmarkNode(startContainer) ? startContainer : startContainer.parentNode;
-          startContainer = startContainer.nextSibling || startContainer;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var wrapAndSplit = function (editor, formatList, formatRoot, container, target, split, format, vars) {
+      var parent, clone, lastClone, firstClone, i, formatRootParent, dom = editor.dom;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (startContainer.nodeType == 3) {
-            startOffset = 0;
-          }
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Format root found then clone formats and split it
+      if (formatRoot) {
+        formatRootParent = formatRoot.parentNode;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (isBookmarkNode(endContainer.parentNode) || isBookmarkNode(endContainer)) {
-          endContainer = isBookmarkNode(endContainer) ? endContainer : endContainer.parentNode;
-          endContainer = endContainer.previousSibling || endContainer;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        for (parent = container.parentNode; parent && parent !== formatRootParent; parent = parent.parentNode) {
+          clone = dom.clone(parent, false);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (endContainer.nodeType == 3) {
-            endOffset = endContainer.length;
-          }
-        }
-
-        if (format[0].inline) {
-          if (rng.collapsed) {
-            // Expand left to closest word boundary
-            endPoint = findWordEndPoint(startContainer, startOffset, true);
-            if (endPoint) {
-              startContainer = endPoint.container;
-              startOffset = endPoint.offset;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          for (i = 0; i < formatList.length; i++) {
+            if (removeFormat(editor, formatList[i], vars, clone, clone)) {
+              clone = 0;
+              break;
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-            // Expand right to closest word boundary
-            endPoint = findWordEndPoint(endContainer, endOffset);
-            if (endPoint) {
-              endContainer = endPoint.container;
-              endOffset = endPoint.offset;
-            }
</del><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Avoid applying formatting to a trailing space.
-          leaf = findLeaf(endContainer, endOffset);
-          if (leaf.node) {
-            while (leaf.node && leaf.offset === 0 && leaf.node.previousSibling) {
-              leaf = findLeaf(leaf.node.previousSibling);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Build wrapper node
+          if (clone) {
+            if (lastClone) {
+              clone.appendChild(lastClone);
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (leaf.node && leaf.offset > 0 && leaf.node.nodeType === 3 &&
-              leaf.node.nodeValue.charAt(leaf.offset - 1) === ' ') {
-
-              if (leaf.offset > 1) {
-                endContainer = leaf.node;
-                endContainer.splitText(leaf.offset - 1);
-              }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            if (!firstClone) {
+              firstClone = clone;
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          }
-        }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Move start/end point up the tree if the leaves are sharp and if we are in different containers
-        // Example * becomes !: !<p><b><i>*text</i><i>text*</i></b></p>!
-        // This will reduce the number of wrapper elements that needs to be created
-        // Move start point up the tree
-        if (format[0].inline || format[0].block_expand) {
-          if (!format[0].inline || (startContainer.nodeType != 3 || startOffset === 0)) {
-            startContainer = findParentContainer(true);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            lastClone = clone;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-          if (!format[0].inline || (endContainer.nodeType != 3 || endOffset === endContainer.nodeValue.length)) {
-            endContainer = findParentContainer();
-          }
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Expand start/end container to matching selector
-        if (format[0].selector && format[0].expand !== FALSE && !format[0].inline) {
-          // Find new startContainer/endContainer if there is better one
-          startContainer = findSelectorEndPoint(startContainer, 'previousSibling');
-          endContainer = findSelectorEndPoint(endContainer, 'nextSibling');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Never split block elements if the format is mixed
+        if (split && (!format.mixed || !dom.isBlock(formatRoot))) {
+          container = dom.split(formatRoot, container);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Expand start/end container to matching block element or text node
-        if (format[0].block || format[0].selector) {
-          // Find new startContainer/endContainer if there is better one
-          startContainer = findBlockEndPoint(startContainer, 'previousSibling');
-          endContainer = findBlockEndPoint(endContainer, 'nextSibling');
-
-          // Non block element then try to expand up the leaf
-          if (format[0].block) {
-            if (!isBlock(startContainer)) {
-              startContainer = findParentContainer(true);
-            }
-
-            if (!isBlock(endContainer)) {
-              endContainer = findParentContainer();
-            }
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Wrap container in cloned formats
+        if (lastClone) {
+          target.parentNode.insertBefore(lastClone, target);
+          firstClone.appendChild(target);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-        // Setup index for startContainer
-        if (startContainer.nodeType == 1) {
-          startOffset = nodeIndex(startContainer);
-          startContainer = startContainer.parentNode;
-        }
-
-        // Setup index for endContainer
-        if (endContainer.nodeType == 1) {
-          endOffset = nodeIndex(endContainer) + 1;
-          endContainer = endContainer.parentNode;
-        }
-
-        // Return new range like object
-        return {
-          startContainer: startContainer,
-          startOffset: startOffset,
-          endContainer: endContainer,
-          endOffset: endOffset
-        };
</del><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function isColorFormatAndAnchor(node, format) {
-        return format.links && node.tagName == 'A';
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return container;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Removes the specified format for the specified node. It will also remove the node if it doesn't have
-       * any attributes if the format specifies it to do so.
-       *
-       * @private
-       * @param {Object} format Format object with items to remove from node.
-       * @param {Object} vars Name/value object with variables to apply to format.
-       * @param {Node} node Node to remove the format styles on.
-       * @param {Node} compareNode Optional compare node, if specified the styles will be compared to that node.
-       * @return {Boolean} True/false if the node was removed or not.
-       */
-      function removeFormat(format, vars, node, compareNode) {
-        var i, attrs, stylesModified;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var remove = function (ed, name, vars, node, similar) {
+      var formatList = ed.formatter.get(name), format = formatList[0];
+      var bookmark, rng, contentEditable = true, dom = ed.dom, selection = ed.selection;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Check if node matches format
-        if (!matchName(node, format) && !isColorFormatAndAnchor(node, format)) {
-          return FALSE;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var splitToFormatRoot = function (container) {
+        var formatRoot = findFormatRoot(ed, container, name, vars, similar);
+        return wrapAndSplit(ed, formatList, formatRoot, container, container, true, format, vars);
+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Should we compare with format attribs and styles
-        if (format.remove != 'all') {
-          // Remove styles
-          each(format.styles, function (value, name) {
-            value = normalizeStyleValue(replaceVars(value, vars), name);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Merges the styles for each node
+      var process = function (node) {
+        var children, i, l, lastContentEditable, hasContentEditableState;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // Indexed array
-            if (typeof name === 'number') {
-              name = value;
-              compareNode = 0;
-            }
-
-            if (format.remove_similar || (!compareNode || isEq(getStyle(compareNode, name), value))) {
-              dom.setStyle(node, name, '');
-            }
-
-            stylesModified = 1;
-          });
-
-          // Remove style attribute if it's empty
-          if (stylesModified && dom.getAttrib(node, 'style') === '') {
-            node.removeAttribute('style');
-            node.removeAttribute('data-mce-style');
-          }
-
-          // Remove attributes
-          each(format.attributes, function (value, name) {
-            var valueOut;
-
-            value = replaceVars(value, vars);
-
-            // Indexed array
-            if (typeof name === 'number') {
-              name = value;
-              compareNode = 0;
-            }
-
-            if (!compareNode || isEq(dom.getAttrib(compareNode, name), value)) {
-              // Keep internal classes
-              if (name == 'class') {
-                value = dom.getAttrib(node, name);
-                if (value) {
-                  // Build new class value where everything is removed except the internal prefixed classes
-                  valueOut = '';
-                  each(value.split(/\s+/), function (cls) {
-                    if (/mce\-\w+/.test(cls)) {
-                      valueOut += (valueOut ? ' ' : '') + cls;
-                    }
-                  });
-
-                  // We got some internal classes left
-                  if (valueOut) {
-                    dom.setAttrib(node, name, valueOut);
-                    return;
-                  }
-                }
-              }
-
-              // IE6 has a bug where the attribute doesn't get removed correctly
-              if (name == "class") {
-                node.removeAttribute('className');
-              }
-
-              // Remove mce prefixed attributes
-              if (MCE_ATTR_RE.test(name)) {
-                node.removeAttribute('data-mce-' + name);
-              }
-
-              node.removeAttribute(name);
-            }
-          });
-
-          // Remove classes
-          each(format.classes, function (value) {
-            value = replaceVars(value, vars);
-
-            if (!compareNode || dom.hasClass(compareNode, value)) {
-              dom.removeClass(node, value);
-            }
-          });
-
-          // Check for non internal attributes
-          attrs = dom.getAttribs(node);
-          for (i = 0; i < attrs.length; i++) {
-            var attrName = attrs[i].nodeName;
-            if (attrName.indexOf('_') !== 0 && attrName.indexOf('data-') !== 0) {
-              return FALSE;
-            }
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Node has a contentEditable value
+        if (node.nodeType === 1 && dom.getContentEditable(node)) {
+          lastContentEditable = contentEditable;
+          contentEditable = dom.getContentEditable(node) === "true";
+          hasContentEditableState = true; // We don't want to wrap the container only it's children
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Remove the inline child if it's empty for example <b> or <span>
-        if (format.remove != 'none') {
-          removeNode(node, format);
-          return TRUE;
-        }
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Grab the children first since the nodelist might be changed
+        children = Tools.grep(node.childNodes);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Removes the node and wrap it's children in paragraphs before doing so or
-       * appends BR elements to the beginning/end of the block element if forcedRootBlocks is disabled.
-       *
-       * If the div in the node below gets removed:
-       *  text<div>text</div>text
-       *
-       * Output becomes:
-       *  text<div><br />text<br /></div>text
-       *
-       * So when the div is removed the result is:
-       *  text<br />text<br />text
-       *
-       * @private
-       * @param {Node} node Node to remove + apply BR/P elements to.
-       * @param {Object} format Format rule.
-       * @return {Node} Input node.
-       */
-      function removeNode(node, format) {
-        var parentNode = node.parentNode, rootBlockElm;
-
-        function find(node, next, inc) {
-          node = getNonWhiteSpaceSibling(node, next, inc);
-
-          return !node || (node.nodeName == 'BR' || isBlock(node));
-        }
-
-        if (format.block) {
-          if (!forcedRootBlock) {
-            // Append BR elements if needed before we remove the block
-            if (isBlock(node) && !isBlock(parentNode)) {
-              if (!find(node, FALSE) && !find(node.firstChild, TRUE, 1)) {
-                node.insertBefore(dom.create('br'), node.firstChild);
-              }
-
-              if (!find(node, TRUE) && !find(node.lastChild, FALSE, 1)) {
-                node.appendChild(dom.create('br'));
-              }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Process current node
+        if (contentEditable && !hasContentEditableState) {
+          for (i = 0, l = formatList.length; i < l; i++) {
+            if (removeFormat(ed, formatList[i], vars, node, node)) {
+              break;
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          } else {
-            // Wrap the block in a forcedRootBlock if we are at the root of document
-            if (parentNode == dom.getRoot()) {
-              if (!format.list_block || !isEq(node, format.list_block)) {
-                each(grep(node.childNodes), function (node) {
-                  if (isValid(forcedRootBlock, node.nodeName.toLowerCase())) {
-                    if (!rootBlockElm) {
-                      rootBlockElm = wrap(node, forcedRootBlock);
-                      dom.setAttribs(rootBlockElm, ed.settings.forced_root_block_attrs);
-                    } else {
-                      rootBlockElm.appendChild(node);
-                    }
-                  } else {
-                    rootBlockElm = 0;
-                  }
-                });
-              }
-            }
</del><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Never remove nodes that isn't the specified inline element if a selector is specified too
-        if (format.selector && format.inline && !isEq(format.inline, node)) {
-          return;
-        }
-
-        dom.remove(node, 1);
-      }
-
-      /**
-       * Returns the next/previous non whitespace node.
-       *
-       * @private
-       * @param {Node} node Node to start at.
-       * @param {boolean} next (Optional) Include next or previous node defaults to previous.
-       * @param {boolean} inc (Optional) Include the current node in checking. Defaults to false.
-       * @return {Node} Next or previous node or undefined if it wasn't found.
-       */
-      function getNonWhiteSpaceSibling(node, next, inc) {
-        if (node) {
-          next = next ? 'nextSibling' : 'previousSibling';
-
-          for (node = inc ? node : node[next]; node; node = node[next]) {
-            if (node.nodeType == 1 || !isWhiteSpaceNode(node)) {
-              return node;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Process the children
+        if (format.deep) {
+          if (children.length) {
+            for (i = 0, l = children.length; i < l; i++) {
+              process(children[i]);
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          }
-        }
-      }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Merges the next/previous sibling element if they match.
-       *
-       * @private
-       * @param {Node} prev Previous node to compare/merge.
-       * @param {Node} next Next node to compare/merge.
-       * @return {Node} Next node if we didn't merge and prev node if we did.
-       */
-      function mergeSiblings(prev, next) {
-        var sibling, tmpSibling, elementUtils = new ElementUtils(dom);
-
-        function findElementSibling(node, siblingName) {
-          for (sibling = node; sibling; sibling = sibling[siblingName]) {
-            if (sibling.nodeType == 3 && sibling.nodeValue.length !== 0) {
-              return node;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            if (hasContentEditableState) {
+              contentEditable = lastContentEditable; // Restore last contentEditable state from stack
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-            if (sibling.nodeType == 1 && !isBookmarkNode(sibling)) {
-              return sibling;
-            }
</del><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-          return node;
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Check if next/prev exists and that they are elements
-        if (prev && next) {
-          // If previous sibling is empty then jump over it
-          prev = findElementSibling(prev, 'previousSibling');
-          next = findElementSibling(next, 'nextSibling');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var unwrap = function (start) {
+        var node = dom.get(start ? '_start' : '_end'),
+          out = node[start ? 'firstChild' : 'lastChild'];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Compare next and previous nodes
-          if (elementUtils.compare(prev, next)) {
-            // Append nodes between
-            for (sibling = prev.nextSibling; sibling && sibling != next;) {
-              tmpSibling = sibling;
-              sibling = sibling.nextSibling;
-              prev.appendChild(tmpSibling);
-            }
-
-            // Remove next node
-            dom.remove(next);
-
-            // Move children into prev node
-            each(grep(next.childNodes), function (node) {
-              prev.appendChild(node);
-            });
-
-            return prev;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // If the end is placed within the start the result will be removed
+        // So this checks if the out node is a bookmark node if it is it
+        // checks for another more suitable node
+        if (BookmarkManager.isBookmarkNode(out)) {
+          out = out[start ? 'firstChild' : 'lastChild'];
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return next;
-      }
-
-      function getContainer(rng, start) {
-        var container, offset, lastIdx;
-
-        container = rng[start ? 'startContainer' : 'endContainer'];
-        offset = rng[start ? 'startOffset' : 'endOffset'];
-
-        if (container.nodeType == 1) {
-          lastIdx = container.childNodes.length - 1;
-
-          if (!start && offset) {
-            offset--;
-          }
-
-          container = container.childNodes[offset > lastIdx ? lastIdx : offset];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Since dom.remove removes empty text nodes then we need to try to find a better node
+        if (out.nodeType === 3 && out.data.length === 0) {
+          out = start ? node.previousSibling || node.nextSibling : node.nextSibling || node.previousSibling;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // If start text node is excluded then walk to the next node
-        if (container.nodeType === 3 && start && offset >= container.nodeValue.length) {
-          container = new TreeWalker(container, ed.getBody()).next() || container;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        dom.remove(node, true);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // If end text node is excluded then walk to the previous node
-        if (container.nodeType === 3 && !start && offset === 0) {
-          container = new TreeWalker(container, ed.getBody()).prev() || container;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return out;
+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return container;
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var removeRngStyle = function (rng) {
+        var startContainer, endContainer;
+        var commonAncestorContainer = rng.commonAncestorContainer;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function performCaretAction(type, name, vars, similar) {
-        var caretContainerId = '_mce_caret', debug = ed.settings.caret_debug;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        rng = ExpandRange.expandRng(ed, rng, formatList, true);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Creates a caret container bogus element
-        function createCaretContainer(fill) {
-          var caretContainer = dom.create('span', { id: caretContainerId, 'data-mce-bogus': true, style: debug ? 'color:red' : '' });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (format.split) {
+          startContainer = getContainer(ed, rng, true);
+          endContainer = getContainer(ed, rng);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (fill) {
-            caretContainer.appendChild(ed.getDoc().createTextNode(INVISIBLE_CHAR));
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (startContainer !== endContainer) {
+            // WebKit will render the table incorrectly if we wrap a TH or TD in a SPAN
+            // so let's see if we can use the first child instead
+            // This will happen if you triple click a table cell and use remove formatting
+            if (/^(TR|TH|TD)$/.test(startContainer.nodeName) && startContainer.firstChild) {
+              if (startContainer.nodeName === "TR") {
+                startContainer = startContainer.firstChild.firstChild || startContainer;
+              } else {
+                startContainer = startContainer.firstChild || startContainer;
+              }
+            }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return caretContainer;
-        }
-
-        function isCaretContainerEmpty(node, nodes) {
-          while (node) {
-            if ((node.nodeType === 3 && node.nodeValue !== INVISIBLE_CHAR) || node.childNodes.length > 1) {
-              return false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // Try to adjust endContainer as well if cells on the same row were selected - bug #6410
+            if (commonAncestorContainer &&
+              /^T(HEAD|BODY|FOOT|R)$/.test(commonAncestorContainer.nodeName) &&
+              isTableCell(endContainer) && endContainer.firstChild) {
+              endContainer = endContainer.firstChild || endContainer;
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // Collect nodes
-            if (nodes && node.nodeType === 1) {
-              nodes.push(node);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            if (dom.isChildOf(startContainer, endContainer) && !dom.isBlock(endContainer) &&
+              !isTableCell(startContainer) && !isTableCell(endContainer)) {
+              startContainer = wrap(dom, startContainer, 'span', { id: '_start', 'data-mce-type': 'bookmark' });
+              splitToFormatRoot(startContainer);
+              startContainer = unwrap(true);
+              return;
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            node = node.firstChild;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // Wrap start/end nodes in span element since these might be cloned/moved
+            startContainer = wrap(dom, startContainer, 'span', { id: '_start', 'data-mce-type': 'bookmark' });
+            endContainer = wrap(dom, endContainer, 'span', { id: '_end', 'data-mce-type': 'bookmark' });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return true;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // Split start/end
+            splitToFormatRoot(startContainer);
+            splitToFormatRoot(endContainer);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Returns any parent caret container element
-        function getParentCaretContainer(node) {
-          while (node) {
-            if (node.id === caretContainerId) {
-              return node;
-            }
-
-            node = node.parentNode;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // Unwrap start/end to get real elements again
+            startContainer = unwrap(true);
+            endContainer = unwrap();
+          } else {
+            startContainer = endContainer = splitToFormatRoot(startContainer);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Finds the first text node in the specified node
-        function findFirstTextNode(node) {
-          var walker;
-
-          if (node) {
-            walker = new TreeWalker(node, node);
-
-            for (node = walker.current(); node; node = walker.next()) {
-              if (node.nodeType === 3) {
-                return node;
-              }
-            }
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Update range positions since they might have changed after the split operations
+          rng.startContainer = startContainer.parentNode ? startContainer.parentNode : startContainer;
+          rng.startOffset = dom.nodeIndex(startContainer);
+          rng.endContainer = endContainer.parentNode ? endContainer.parentNode : endContainer;
+          rng.endOffset = dom.nodeIndex(endContainer) + 1;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Removes the caret container for the specified node or all on the current document
-        function removeCaretContainer(node, moveCaret) {
-          var child, rng;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Remove items between start/end
+        new RangeUtils(dom).walk(rng, function (nodes) {
+          each(nodes, function (node) {
+            process(node);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (!node) {
-            node = getParentCaretContainer(selection.getStart());
-
-            if (!node) {
-              while ((node = dom.get(caretContainerId))) {
-                removeCaretContainer(node, false);
-              }
-            }
-          } else {
-            rng = selection.getRng(true);
-
-            if (isCaretContainerEmpty(node)) {
-              if (moveCaret !== false) {
-                rng.setStartBefore(node);
-                rng.setEndBefore(node);
-              }
-
-              dom.remove(node);
-            } else {
-              child = findFirstTextNode(node);
-
-              if (child.nodeValue.charAt(0) === INVISIBLE_CHAR) {
-                child.deleteData(0, 1);
-
-                // Fix for bug #6976
-                if (rng.startContainer == child && rng.startOffset > 0) {
-                  rng.setStart(child, rng.startOffset - 1);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // Remove parent span if it only contains text-decoration: underline, yet a parent node is also underlined.
+            if (node.nodeType === 1 && ed.dom.getStyle(node, 'text-decoration') === 'underline' &&
+              node.parentNode && FormatUtils.getTextDecoration(dom, node.parentNode) === 'underline') {
+              removeFormat(ed, {
+                'deep': false,
+                'exact': true,
+                'inline': 'span',
+                'styles': {
+                  'textDecoration': 'underline'
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-                if (rng.endContainer == child && rng.endOffset > 0) {
-                  rng.setEnd(child, rng.endOffset - 1);
-                }
-              }
-
-              dom.remove(node, 1);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              }, null, node);
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          });
+        });
+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            selection.setRng(rng);
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Handle node
+      if (node) {
+        if (node.nodeType) {
+          rng = dom.createRng();
+          rng.setStartBefore(node);
+          rng.setEndAfter(node);
+          removeRngStyle(rng);
+        } else {
+          removeRngStyle(node);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Applies formatting to the caret position
-        function applyCaretFormat() {
-          var rng, caretContainer, textNode, offset, bookmark, container, text;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          rng = selection.getRng(true);
-          offset = rng.startOffset;
-          container = rng.startContainer;
-          text = container.nodeValue;
-
-          caretContainer = getParentCaretContainer(selection.getStart());
-          if (caretContainer) {
-            textNode = findFirstTextNode(caretContainer);
-          }
-
-          // Expand to word if caret is in the middle of a text node and the char before/after is a alpha numeric character
-          var wordcharRegex = /[^\s\u00a0\u00ad\u200b\ufeff]/;
-          if (text && offset > 0 && offset < text.length &&
-            wordcharRegex.test(text.charAt(offset)) && wordcharRegex.test(text.charAt(offset - 1))) {
-            // Get bookmark of caret position
-            bookmark = selection.getBookmark();
-
-            // Collapse bookmark range (WebKit)
-            rng.collapse(true);
-
-            // Expand the range to the closest word and split it at those points
-            rng = expandRng(rng, get(name));
-            rng = rangeUtils.split(rng);
-
-            // Apply the format to the range
-            apply(name, vars, rng);
-
-            // Move selection back to caret position
-            selection.moveToBookmark(bookmark);
-          } else {
-            if (!caretContainer || textNode.nodeValue !== INVISIBLE_CHAR) {
-              caretContainer = createCaretContainer(true);
-              textNode = caretContainer.firstChild;
-
-              rng.insertNode(caretContainer);
-              offset = 1;
-
-              apply(name, vars, caretContainer);
-            } else {
-              apply(name, vars, caretContainer);
-            }
-
-            // Move selection to text node
-            selection.setCursorLocation(textNode, offset);
-          }
-        }
-
-        function removeCaretFormat() {
-          var rng = selection.getRng(true), container, offset, bookmark,
-            hasContentAfter, node, formatNode, parents = [], i, caretContainer;
-
-          container = rng.startContainer;
-          offset = rng.startOffset;
-          node = container;
-
-          if (container.nodeType == 3) {
-            if (offset != container.nodeValue.length) {
-              hasContentAfter = true;
-            }
-
-            node = node.parentNode;
-          }
-
-          while (node) {
-            if (matchNode(node, name, vars, similar)) {
-              formatNode = node;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (dom.getContentEditable(selection.getNode()) === "false") {
+        node = selection.getNode();
+        for (var i = 0, l = formatList.length; i < l; i++) {
+          if (formatList[i].ceFalseOverride) {
+            if (removeFormat(ed, formatList[i], vars, node, node)) {
</ins><span class="cx" style="display: block; padding: 0 10px">               break;
</span><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-            if (node.nextSibling) {
-              hasContentAfter = true;
-            }
-
-            parents.push(node);
-            node = node.parentNode;
</del><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-          // Node doesn't have the specified format
-          if (!formatNode) {
-            return;
-          }
-
-          // Is there contents after the caret then remove the format on the element
-          if (hasContentAfter) {
-            // Get bookmark of caret position
-            bookmark = selection.getBookmark();
-
-            // Collapse bookmark range (WebKit)
-            rng.collapse(true);
-
-            // Expand the range to the closest word and split it at those points
-            rng = expandRng(rng, get(name), true);
-            rng = rangeUtils.split(rng);
-
-            // Remove the format from the range
-            remove(name, vars, rng);
-
-            // Move selection back to caret position
-            selection.moveToBookmark(bookmark);
-          } else {
-            caretContainer = createCaretContainer();
-
-            node = caretContainer;
-            for (i = parents.length - 1; i >= 0; i--) {
-              node.appendChild(dom.clone(parents[i], false));
-              node = node.firstChild;
-            }
-
-            // Insert invisible character into inner most format element
-            node.appendChild(dom.doc.createTextNode(INVISIBLE_CHAR));
-            node = node.firstChild;
-
-            var block = dom.getParent(formatNode, isTextBlock);
-
-            if (block && dom.isEmpty(block)) {
-              // Replace formatNode with caretContainer when removing format from empty block like <p><b>|</b></p>
-              formatNode.parentNode.replaceChild(caretContainer, formatNode);
-            } else {
-              // Insert caret container after the formatted node
-              dom.insertAfter(caretContainer, formatNode);
-            }
-
-            // Move selection to text node
-            selection.setCursorLocation(node, 1);
-
-            // If the formatNode is empty, we can remove it safely.
-            if (dom.isEmpty(formatNode)) {
-              dom.remove(formatNode);
-            }
-          }
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Checks if the parent caret container node isn't empty if that is the case it
-        // will remove the bogus state on all children that isn't empty
-        function unmarkBogusCaretParents() {
-          var caretContainer;
-
-          caretContainer = getParentCaretContainer(selection.getStart());
-          if (caretContainer && !dom.isEmpty(caretContainer)) {
-            walk(caretContainer, function (node) {
-              if (node.nodeType == 1 && node.id !== caretContainerId && !dom.isEmpty(node)) {
-                dom.setAttrib(node, 'data-mce-bogus', null);
-              }
-            }, 'childNodes');
-          }
-        }
-
-        // Only bind the caret events once
-        if (!ed._hasCaretEvents) {
-          // Mark current caret container elements as bogus when getting the contents so we don't end up with empty elements
-          markCaretContainersBogus = function () {
-            var nodes = [], i;
-
-            if (isCaretContainerEmpty(getParentCaretContainer(selection.getStart()), nodes)) {
-              // Mark children
-              i = nodes.length;
-              while (i--) {
-                dom.setAttrib(nodes[i], 'data-mce-bogus', '1');
-              }
-            }
-          };
-
-          disableCaretContainer = function (e) {
-            var keyCode = e.keyCode;
-
-            removeCaretContainer();
-
-            // Remove caret container if it's empty
-            if (keyCode == 8 && selection.isCollapsed() && selection.getStart().innerHTML == INVISIBLE_CHAR) {
-              removeCaretContainer(getParentCaretContainer(selection.getStart()));
-            }
-
-            // Remove caret container on keydown and it's left/right arrow keys
-            if (keyCode == 37 || keyCode == 39) {
-              removeCaretContainer(getParentCaretContainer(selection.getStart()));
-            }
-
-            unmarkBogusCaretParents();
-          };
-
-          // Remove bogus state if they got filled by contents using editor.selection.setContent
-          ed.on('SetContent', function (e) {
-            if (e.selection) {
-              unmarkBogusCaretParents();
-            }
-          });
-          ed._hasCaretEvents = true;
-        }
-
-        // Do apply or remove caret format
-        if (type == "apply") {
-          applyCaretFormat();
-        } else {
-          removeCaretFormat();
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Moves the start to the first suitable text node.
-       */
-      function moveStart(rng) {
-        var container = rng.startContainer,
-          offset = rng.startOffset,
-          walker, node, nodes;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (!selection.isCollapsed() || !format.inline || dom.select('td[data-mce-selected],th[data-mce-selected]').length) {
+        bookmark = selection.getBookmark();
+        removeRngStyle(selection.getRng(true));
+        selection.moveToBookmark(bookmark);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (rng.startContainer == rng.endContainer) {
-          if (isInlineBlock(rng.startContainer.childNodes[rng.startOffset])) {
-            return;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Check if start element still has formatting then we are at: "<b>text|</b>text"
+        // and need to move the start into the next text node
+        if (format.inline && MatchFormat.match(ed, name, vars, selection.getStart())) {
+          FormatUtils.moveStart(dom, selection, selection.getRng(true));
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Convert text node into index if possible
-        if (container.nodeType == 3 && offset >= container.nodeValue.length) {
-          // Get the parent container location and walk from there
-          offset = nodeIndex(container);
-          container = container.parentNode;
-        }
-
-        // Move startContainer/startOffset in to a suitable node
-        if (container.nodeType == 1) {
-          nodes = container.childNodes;
-          if (offset < nodes.length) {
-            container = nodes[offset];
-            walker = new TreeWalker(container, dom.getParent(container, dom.isBlock));
-          } else {
-            container = nodes[nodes.length - 1];
-            walker = new TreeWalker(container, dom.getParent(container, dom.isBlock));
-            walker.next(true);
-          }
-
-          for (node = walker.current(); node; node = walker.next()) {
-            if (node.nodeType == 3 && !isWhiteSpaceNode(node)) {
-              rng.setStart(node, 0);
-              selection.setRng(rng);
-
-              return;
-            }
-          }
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        ed.nodeChanged();
+      } else {
+        CaretFormat.removeCaretFormat(ed, name, vars, similar);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+    return {
+      removeFormat: removeFormat,
+      remove: remove
+    };
</ins><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Diff.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * MergeFormats.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -25014,342 +19159,222 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Contributing: http://www.tinymce.com/contributing
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * JS Implementation of the O(ND) Difference Algorithm by Eugene W. Myers.
- *
- * @class tinymce.undo.Diff
- * @private
- */
</del><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.undo.Diff',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.fmt.MergeFormats',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.katamari.api.Fun',
+    'tinymce.core.dom.BookmarkManager',
+    'tinymce.core.dom.ElementUtils',
+    'tinymce.core.dom.NodeType',
+    'tinymce.core.fmt.CaretFormat',
+    'tinymce.core.fmt.FormatUtils',
+    'tinymce.core.fmt.MatchFormat',
+    'tinymce.core.fmt.RemoveFormat',
+    'tinymce.core.util.Tools'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function () {
-    var KEEP = 0, INSERT = 1, DELETE = 2;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Fun, BookmarkManager, ElementUtils, NodeType, CaretFormat, FormatUtils, MatchFormat, RemoveFormat, Tools) {
+    var each = Tools.each;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var diff = function (left, right) {
-      var size = left.length + right.length + 2;
-      var vDown = new Array(size);
-      var vUp = new Array(size);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isElementNode = function (node) {
+      return node && node.nodeType === 1 && !BookmarkManager.isBookmarkNode(node) && !CaretFormat.isCaretNode(node) && !NodeType.isBogus(node);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var snake = function (start, end, diag) {
-        return {
-          start: start,
-          end: end,
-          diag: diag
-        };
-      };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var findElementSibling = function (node, siblingName) {
+      var sibling;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var buildScript = function (start1, end1, start2, end2, script) {
-        var middle = getMiddleSnake(start1, end1, start2, end2);
-
-        if (middle === null || middle.start === end1 && middle.diag === end1 - end2 ||
-          middle.end === start1 && middle.diag === start1 - start2) {
-          var i = start1;
-          var j = start2;
-          while (i < end1 || j < end2) {
-            if (i < end1 && j < end2 && left[i] === right[j]) {
-              script.push([KEEP, left[i]]);
-              ++i;
-              ++j;
-            } else {
-              if (end1 - start1 > end2 - start2) {
-                script.push([DELETE, left[i]]);
-                ++i;
-              } else {
-                script.push([INSERT, right[j]]);
-                ++j;
-              }
-            }
-          }
-        } else {
-          buildScript(start1, middle.start, start2, middle.start - middle.diag, script);
-          for (var i2 = middle.start; i2 < middle.end; ++i2) {
-            script.push([KEEP, left[i2]]);
-          }
-          buildScript(middle.end, end1, middle.end - middle.diag, end2, script);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      for (sibling = node; sibling; sibling = sibling[siblingName]) {
+        if (sibling.nodeType === 3 && sibling.nodeValue.length !== 0) {
+          return node;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var buildSnake = function (start, diag, end1, end2) {
-        var end = start;
-        while (end - diag < end2 && end < end1 && left[end] === right[end - diag]) {
-          ++end;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (sibling.nodeType === 1 && !BookmarkManager.isBookmarkNode(sibling)) {
+          return sibling;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return snake(start, end, diag);
-      };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var getMiddleSnake = function (start1, end1, start2, end2) {
-        // Myers Algorithm
-        // Initialisations
-        var m = end1 - start1;
-        var n = end2 - start2;
-        if (m === 0 || n === 0) {
-          return null;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return node;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var delta = m - n;
-        var sum = n + m;
-        var offset = (sum % 2 === 0 ? sum : sum + 1) / 2;
-        vDown[1 + offset] = start1;
-        vUp[1 + offset] = end1 + 1;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var mergeSiblingsNodes = function (dom, prev, next) {
+      var sibling, tmpSibling, elementUtils = new ElementUtils(dom);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        for (var d = 0; d <= offset; ++d) {
-          // Down
-          for (var k = -d; k <= d; k += 2) {
-            // First step
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Check if next/prev exists and that they are elements
+      if (prev && next) {
+        // If previous sibling is empty then jump over it
+        prev = findElementSibling(prev, 'previousSibling');
+        next = findElementSibling(next, 'nextSibling');
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            var i = k + offset;
-            if (k === -d || k != d && vDown[i - 1] < vDown[i + 1]) {
-              vDown[i] = vDown[i + 1];
-            } else {
-              vDown[i] = vDown[i - 1] + 1;
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Compare next and previous nodes
+        if (elementUtils.compare(prev, next)) {
+          // Append nodes between
+          for (sibling = prev.nextSibling; sibling && sibling !== next;) {
+            tmpSibling = sibling;
+            sibling = sibling.nextSibling;
+            prev.appendChild(tmpSibling);
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            var x = vDown[i];
-            var y = x - start1 + start2 - k;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          dom.remove(next);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            while (x < end1 && y < end2 && left[x] === right[y]) {
-              vDown[i] = ++x;
-              ++y;
-            }
-            // Second step
-            if (delta % 2 != 0 && delta - d <= k && k <= delta + d) {
-              if (vUp[i - delta] <= vDown[i]) {
-                return buildSnake(vUp[i - delta], k + start1 - start2, end1, end2);
-              }
-            }
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          Tools.each(Tools.grep(next.childNodes), function (node) {
+            prev.appendChild(node);
+          });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Up
-          for (k = delta - d; k <= delta + d; k += 2) {
-            // First step
-            i = k + offset - delta;
-            if (k === delta - d || k != delta + d && vUp[i + 1] <= vUp[i - 1]) {
-              vUp[i] = vUp[i + 1] - 1;
-            } else {
-              vUp[i] = vUp[i - 1];
-            }
-
-            x = vUp[i] - 1;
-            y = x - start1 + start2 - k;
-            while (x >= start1 && y >= start2 && left[x] === right[y]) {
-              vUp[i] = x--;
-              y--;
-            }
-            // Second step
-            if (delta % 2 === 0 && -d <= k && k <= d) {
-              if (vUp[i] <= vDown[i + delta]) {
-                return buildSnake(vUp[i], k + start1 - start2, end1, end2);
-              }
-            }
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          return prev;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var script = [];
-      buildScript(0, left.length, 0, right.length, script);
-      return script;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return next;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return {
-      KEEP: KEEP,
-      DELETE: DELETE,
-      INSERT: INSERT,
-      diff: diff
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var processChildElements = function (node, filter, process) {
+      each(node.childNodes, function (node) {
+        if (isElementNode(node)) {
+          if (filter(node)) {
+            process(node);
+          }
+          if (node.hasChildNodes()) {
+            processChildElements(node, filter, process);
+          }
+        }
+      });
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  }
-);
-/**
- * Fragments.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * This module reads and applies html fragments from/to dom nodes.
- *
- * @class tinymce.undo.Fragments
- * @private
- */
-define(
-  'tinymce.core.undo.Fragments',
-  [
-    "tinymce.core.util.Arr",
-    "tinymce.core.html.Entities",
-    "tinymce.core.undo.Diff"
-  ],
-  function (Arr, Entities, Diff) {
-    var getOuterHtml = function (elm) {
-      if (elm.nodeType === 1) {
-        return elm.outerHTML;
-      } else if (elm.nodeType === 3) {
-        return Entities.encodeRaw(elm.data, false);
-      } else if (elm.nodeType === 8) {
-        return '<!--' + elm.data + '-->';
-      }
-
-      return '';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var hasStyle = function (dom, name) {
+      return Fun.curry(function (name, node) {
+        return !!(node && FormatUtils.getStyle(dom, node, name));
+      }, name);
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var createFragment = function (html) {
-      var frag, node, container;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var applyStyle = function (dom, name, value) {
+      return Fun.curry(function (name, value, node) {
+        dom.setStyle(node, name, value);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      container = document.createElement("div");
-      frag = document.createDocumentFragment();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (node.getAttribute('style') === '') {
+          node.removeAttribute('style');
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (html) {
-        container.innerHTML = html;
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        unwrapEmptySpan(dom, node);
+      }, name, value);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      while ((node = container.firstChild)) {
-        frag.appendChild(node);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var unwrapEmptySpan = function (dom, node) {
+      if (node.nodeName === 'SPAN' && dom.getAttribs(node).length === 0) {
+        dom.remove(node, true);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-      return frag;
</del><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var insertAt = function (elm, html, index) {
-      var fragment = createFragment(html);
-      if (elm.hasChildNodes() && index < elm.childNodes.length) {
-        var target = elm.childNodes[index];
-        target.parentNode.insertBefore(fragment, target);
-      } else {
-        elm.appendChild(fragment);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var processUnderlineAndColor = function (dom, node) {
+      var textDecoration;
+      if (node.nodeType === 1 && node.parentNode && node.parentNode.nodeType === 1) {
+        textDecoration = FormatUtils.getTextDecoration(dom, node.parentNode);
+        if (dom.getStyle(node, 'color') && textDecoration) {
+          dom.setStyle(node, 'text-decoration', textDecoration);
+        } else if (dom.getStyle(node, 'text-decoration') === textDecoration) {
+          dom.setStyle(node, 'text-decoration', null);
+        }
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var removeAt = function (elm, index) {
-      if (elm.hasChildNodes() && index < elm.childNodes.length) {
-        var target = elm.childNodes[index];
-        target.parentNode.removeChild(target);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var mergeUnderlineAndColor = function (dom, format, vars, node) {
+      // Colored nodes should be underlined so that the color of the underline matches the text color.
+      if (format.styles.color || format.styles.textDecoration) {
+        Tools.walk(node, Fun.curry(processUnderlineAndColor, dom), 'childNodes');
+        processUnderlineAndColor(dom, node);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var applyDiff = function (diff, elm) {
-      var index = 0;
-      Arr.each(diff, function (action) {
-        if (action[0] === Diff.KEEP) {
-          index++;
-        } else if (action[0] === Diff.INSERT) {
-          insertAt(elm, action[1], index);
-          index++;
-        } else if (action[0] === Diff.DELETE) {
-          removeAt(elm, index);
-        }
-      });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var mergeBackgroundColorAndFontSize = function (dom, format, vars, node) {
+      // nodes with font-size should have their own background color as well to fit the line-height (see TINY-882)
+      if (format.styles && format.styles.backgroundColor) {
+        processChildElements(node,
+          hasStyle(dom, 'fontSize'),
+          applyStyle(dom, 'backgroundColor', FormatUtils.replaceVars(format.styles.backgroundColor, vars))
+        );
+      }
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var read = function (elm) {
-      return Arr.filter(Arr.map(elm.childNodes, getOuterHtml), function (item) {
-        return item.length > 0;
-      });
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var mergeSubSup = function (dom, format, vars, node) {
+      // Remove font size on all chilren of a sub/sup and remove the inverse element
+      if (format.inline === 'sub' || format.inline === 'sup') {
+        processChildElements(node,
+          hasStyle(dom, 'fontSize'),
+          applyStyle(dom, 'fontSize', '')
+        );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var write = function (fragments, elm) {
-      var currentFragments = Arr.map(elm.childNodes, getOuterHtml);
-      applyDiff(Diff.diff(currentFragments, fragments), elm);
-      return elm;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        dom.remove(dom.select(format.inline === 'sup' ? 'sub' : 'sup', node), true);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return {
-      read: read,
-      write: write
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var mergeSiblings = function (dom, format, vars, node) {
+      // Merge next and previous siblings if they are similar <b>text</b><b>text</b> becomes <b>texttext</b>
+      if (node && format.merge_siblings !== false) {
+        node = mergeSiblingsNodes(dom, FormatUtils.getNonWhiteSpaceSibling(node), node);
+        node = mergeSiblingsNodes(dom, node, FormatUtils.getNonWhiteSpaceSibling(node, true));
+      }
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  }
-);
-/**
- * Levels.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * This module handles getting/setting undo levels to/from editor instances.
- *
- * @class tinymce.undo.Levels
- * @private
- */
-define(
-  'tinymce.core.undo.Levels',
-  [
-    "tinymce.core.util.Arr",
-    "tinymce.core.undo.Fragments"
-  ],
-  function (Arr, Fragments) {
-    var hasIframes = function (html) {
-      return html.indexOf('</iframe>') !== -1;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var clearChildStyles = function (dom, format, node) {
+      if (format.clear_child_styles) {
+        var selector = format.links ? '*:not(a)' : '*';
+        each(dom.select(selector, node), function (node) {
+          if (isElementNode(node)) {
+            each(format.styles, function (value, name) {
+              dom.setStyle(node, name, '');
+            });
+          }
+        });
+      }
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var createFragmentedLevel = function (fragments) {
-      return {
-        type: 'fragmented',
-        fragments: fragments,
-        content: '',
-        bookmark: null,
-        beforeBookmark: null
-      };
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var mergeWithChildren = function (editor, formatList, vars, node) {
+      // Remove/merge children
+      each(formatList, function (format) {
+        // Merge all children of similar type will move styles from child to parent
+        // this: <span style="color:red"><b><span style="color:red; font-size:10px">text</span></b></span>
+        // will become: <span style="color:red"><b><span style="font-size:10px">text</span></b></span>
+        each(editor.dom.select(format.inline, node), function (child) {
+          if (!isElementNode(child)) {
+            return;
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var createCompleteLevel = function (content) {
-      return {
-        type: 'complete',
-        fragments: null,
-        content: content,
-        bookmark: null,
-        beforeBookmark: null
-      };
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          RemoveFormat.removeFormat(editor, format, vars, child, format.exact ? child : null);
+        });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var createFromEditor = function (editor) {
-      var fragments, content, trimmedFragments;
-
-      fragments = Fragments.read(editor.getBody());
-      trimmedFragments = Arr.map(fragments, function (html) {
-        return editor.serializer.trimContent(html);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        clearChildStyles(editor.dom, format, node);
</ins><span class="cx" style="display: block; padding: 0 10px">       });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      content = trimmedFragments.join('');
-
-      return hasIframes(content) ? createFragmentedLevel(trimmedFragments) : createCompleteLevel(content);
</del><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var applyToEditor = function (editor, level, before) {
-      if (level.type === 'fragmented') {
-        Fragments.write(level.fragments, editor.getBody());
-      } else {
-        editor.setContent(level.content, { format: 'raw' });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var mergeWithParents = function (editor, format, name, vars, node) {
+      // Remove format if direct parent already has the same format
+      if (MatchFormat.matchNode(editor, node.parentNode, name, vars)) {
+        if (RemoveFormat.removeFormat(editor, format, vars, node)) {
+          return;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      editor.selection.moveToBookmark(before ? level.beforeBookmark : level.bookmark);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Remove format if any ancestor already has the same format
+      if (format.merge_with_parents) {
+        editor.dom.getParent(node.parentNode, function (parent) {
+          if (MatchFormat.matchNode(editor, parent, name, vars)) {
+            RemoveFormat.removeFormat(editor, format, vars, node);
+            return true;
+          }
+        });
+      }
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var getLevelContent = function (level) {
-      return level.type === 'fragmented' ? level.fragments.join('') : level.content;
-    };
-
-    var isEq = function (level1, level2) {
-      return getLevelContent(level1) === getLevelContent(level2);
-    };
-
</del><span class="cx" style="display: block; padding: 0 10px">     return {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      createFragmentedLevel: createFragmentedLevel,
-      createCompleteLevel: createCompleteLevel,
-      createFromEditor: createFromEditor,
-      applyToEditor: applyToEditor,
-      isEq: isEq
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      mergeWithChildren: mergeWithChildren,
+      mergeUnderlineAndColor: mergeUnderlineAndColor,
+      mergeBackgroundColorAndFontSize: mergeBackgroundColorAndFontSize,
+      mergeSubSup: mergeSubSup,
+      mergeSiblings: mergeSiblings,
+      mergeWithParents: mergeWithParents
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * UndoManager.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * ApplyFormat.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -25358,856 +19383,357 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Contributing: http://www.tinymce.com/contributing
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * This class handles the undo/redo history levels for the editor. Since the built-in undo/redo has major drawbacks a custom one was needed.
- *
- * @class tinymce.UndoManager
- */
</del><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.UndoManager',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.fmt.ApplyFormat',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    "tinymce.core.util.VK",
-    "tinymce.core.util.Tools",
-    "tinymce.core.undo.Levels"
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.dom.BookmarkManager',
+    'tinymce.core.dom.NodeType',
+    'tinymce.core.dom.RangeNormalizer',
+    'tinymce.core.dom.RangeUtils',
+    'tinymce.core.fmt.CaretFormat',
+    'tinymce.core.fmt.ExpandRange',
+    'tinymce.core.fmt.FormatUtils',
+    'tinymce.core.fmt.Hooks',
+    'tinymce.core.fmt.MatchFormat',
+    'tinymce.core.fmt.MergeFormats',
+    'tinymce.core.util.Tools'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (VK, Tools, Levels) {
-    return function (editor) {
-      var self = this, index = 0, data = [], beforeBookmark, isFirstTypedCharacter, locks = 0;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (BookmarkManager, NodeType, RangeNormalizer, RangeUtils, CaretFormat, ExpandRange, FormatUtils, Hooks, MatchFormat, MergeFormats, Tools) {
+    var each = Tools.each;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var isUnlocked = function () {
-        return locks === 0;
-      };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isElementNode = function (node) {
+      return node && node.nodeType === 1 && !BookmarkManager.isBookmarkNode(node) && !CaretFormat.isCaretNode(node) && !NodeType.isBogus(node);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var setTyping = function (typing) {
-        if (isUnlocked()) {
-          self.typing = typing;
-        }
-      };
-
-      function setDirty(state) {
-        editor.setDirty(state);
-      }
-
-      function addNonTypingUndoLevel(e) {
-        setTyping(false);
-        self.add({}, e);
-      }
-
-      function endTyping() {
-        if (self.typing) {
-          setTyping(false);
-          self.add();
-        }
-      }
-
-      // Add initial undo level when the editor is initialized
-      editor.on('init', function () {
-        self.add();
-      });
-
-      // Get position before an execCommand is processed
-      editor.on('BeforeExecCommand', function (e) {
-        var cmd = e.command;
-
-        if (cmd !== 'Undo' && cmd !== 'Redo' && cmd !== 'mceRepaint') {
-          endTyping();
-          self.beforeChange();
-        }
-      });
-
-      // Add undo level after an execCommand call was made
-      editor.on('ExecCommand', function (e) {
-        var cmd = e.command;
-
-        if (cmd !== 'Undo' && cmd !== 'Redo' && cmd !== 'mceRepaint') {
-          addNonTypingUndoLevel(e);
-        }
-      });
-
-      editor.on('ObjectResizeStart Cut', function () {
-        self.beforeChange();
-      });
-
-      editor.on('SaveContent ObjectResized blur', addNonTypingUndoLevel);
-      editor.on('DragEnd', addNonTypingUndoLevel);
-
-      editor.on('KeyUp', function (e) {
-        var keyCode = e.keyCode;
-
-        // If key is prevented then don't add undo level
-        // This would happen on keyboard shortcuts for example
-        if (e.isDefaultPrevented()) {
-          return;
-        }
-
-        if ((keyCode >= 33 && keyCode <= 36) || (keyCode >= 37 && keyCode <= 40) || keyCode === 45 || e.ctrlKey) {
-          addNonTypingUndoLevel();
-          editor.nodeChanged();
-        }
-
-        if (keyCode === 46 || keyCode === 8) {
-          editor.nodeChanged();
-        }
-
-        // Fire a TypingUndo/Change event on the first character entered
-        if (isFirstTypedCharacter && self.typing && Levels.isEq(Levels.createFromEditor(editor), data[0]) === false) {
-          if (editor.isDirty() === false) {
-            setDirty(true);
-            editor.fire('change', { level: data[0], lastLevel: null });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var processChildElements = function (node, filter, process) {
+      each(node.childNodes, function (node) {
+        if (isElementNode(node)) {
+          if (filter(node)) {
+            process(node);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-          editor.fire('TypingUndo');
-          isFirstTypedCharacter = false;
-          editor.nodeChanged();
-        }
-      });
-
-      editor.on('KeyDown', function (e) {
-        var keyCode = e.keyCode;
-
-        // If key is prevented then don't add undo level
-        // This would happen on keyboard shortcuts for example
-        if (e.isDefaultPrevented()) {
-          return;
-        }
-
-        // Is character position keys left,right,up,down,home,end,pgdown,pgup,enter
-        if ((keyCode >= 33 && keyCode <= 36) || (keyCode >= 37 && keyCode <= 40) || keyCode === 45) {
-          if (self.typing) {
-            addNonTypingUndoLevel(e);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (node.hasChildNodes()) {
+            processChildElements(node, filter, process);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-          return;
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-        // If key isn't Ctrl+Alt/AltGr
-        var modKey = (e.ctrlKey && !e.altKey) || e.metaKey;
-        if ((keyCode < 16 || keyCode > 20) && keyCode !== 224 && keyCode !== 91 && !self.typing && !modKey) {
-          self.beforeChange();
-          setTyping(true);
-          self.add({}, e);
-          isFirstTypedCharacter = true;
-        }
</del><span class="cx" style="display: block; padding: 0 10px">       });
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      editor.on('MouseDown', function (e) {
-        if (self.typing) {
-          addNonTypingUndoLevel(e);
-        }
-      });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var applyFormat = function (ed, name, vars, node) {
+      var formatList = ed.formatter.get(name), format = formatList[0], bookmark, rng, isCollapsed = !node && ed.selection.isCollapsed();
+      var dom = ed.dom, selection = ed.selection;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Add keyboard shortcuts for undo/redo keys
-      editor.addShortcut('meta+z', '', 'Undo');
-      editor.addShortcut('meta+y,meta+shift+z', '', 'Redo');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var setElementFormat = function (elm, fmt) {
+        fmt = fmt || format;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      editor.on('AddUndo Undo Redo ClearUndos', function (e) {
-        if (!e.isDefaultPrevented()) {
-          editor.nodeChanged();
-        }
-      });
-
-      /*eslint consistent-this:0 */
-      self = {
-        // Explode for debugging reasons
-        data: data,
-
-        /**
-         * State if the user is currently typing or not. This will add a typing operation into one undo
-         * level instead of one new level for each keystroke.
-         *
-         * @field {Boolean} typing
-         */
-        typing: false,
-
-        /**
-         * Stores away a bookmark to be used when performing an undo action so that the selection is before
-         * the change has been made.
-         *
-         * @method beforeChange
-         */
-        beforeChange: function () {
-          if (isUnlocked()) {
-            beforeBookmark = editor.selection.getBookmark(2, true);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (elm) {
+          if (fmt.onformat) {
+            fmt.onformat(elm, fmt, vars, node);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        },
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        /**
-         * Adds a new undo level/snapshot to the undo list.
-         *
-         * @method add
-         * @param {Object} level Optional undo level object to add.
-         * @param {DOMEvent} event Optional event responsible for the creation of the undo level.
-         * @return {Object} Undo level that got added or null it a level wasn't needed.
-         */
-        add: function (level, event) {
-          var i, settings = editor.settings, lastLevel, currentLevel;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          each(fmt.styles, function (value, name) {
+            dom.setStyle(elm, name, FormatUtils.replaceVars(value, vars));
+          });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          currentLevel = Levels.createFromEditor(editor);
-          level = level || {};
-          level = Tools.extend(level, currentLevel);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Needed for the WebKit span spam bug
+          // TODO: Remove this once WebKit/Blink fixes this
+          if (fmt.styles) {
+            var styleVal = dom.getAttrib(elm, 'style');
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (isUnlocked() === false || editor.removed) {
-            return null;
-          }
-
-          lastLevel = data[index];
-          if (editor.fire('BeforeAddUndo', { level: level, lastLevel: lastLevel, originalEvent: event }).isDefaultPrevented()) {
-            return null;
-          }
-
-          // Add undo level if needed
-          if (lastLevel && Levels.isEq(lastLevel, level)) {
-            return null;
-          }
-
-          // Set before bookmark on previous level
-          if (data[index]) {
-            data[index].beforeBookmark = beforeBookmark;
-          }
-
-          // Time to compress
-          if (settings.custom_undo_redo_levels) {
-            if (data.length > settings.custom_undo_redo_levels) {
-              for (i = 0; i < data.length - 1; i++) {
-                data[i] = data[i + 1];
-              }
-
-              data.length--;
-              index = data.length;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            if (styleVal) {
+              elm.setAttribute('data-mce-style', styleVal);
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Get a non intrusive normalized bookmark
-          level.bookmark = editor.selection.getBookmark(2, true);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          each(fmt.attributes, function (value, name) {
+            dom.setAttrib(elm, name, FormatUtils.replaceVars(value, vars));
+          });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Crop array if needed
-          if (index < data.length - 1) {
-            data.length = index + 1;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          each(fmt.classes, function (value) {
+            value = FormatUtils.replaceVars(value, vars);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          data.push(level);
-          index = data.length - 1;
-
-          var args = { level: level, lastLevel: lastLevel, originalEvent: event };
-
-          editor.fire('AddUndo', args);
-
-          if (index > 0) {
-            setDirty(true);
-            editor.fire('change', args);
-          }
-
-          return level;
-        },
-
-        /**
-         * Undoes the last action.
-         *
-         * @method undo
-         * @return {Object} Undo level or null if no undo was performed.
-         */
-        undo: function () {
-          var level;
-
-          if (self.typing) {
-            self.add();
-            self.typing = false;
-            setTyping(false);
-          }
-
-          if (index > 0) {
-            level = data[--index];
-            Levels.applyToEditor(editor, level, true);
-            setDirty(true);
-            editor.fire('undo', { level: level });
-          }
-
-          return level;
-        },
-
-        /**
-         * Redoes the last action.
-         *
-         * @method redo
-         * @return {Object} Redo level or null if no redo was performed.
-         */
-        redo: function () {
-          var level;
-
-          if (index < data.length - 1) {
-            level = data[++index];
-            Levels.applyToEditor(editor, level, false);
-            setDirty(true);
-            editor.fire('redo', { level: level });
-          }
-
-          return level;
-        },
-
-        /**
-         * Removes all undo levels.
-         *
-         * @method clear
-         */
-        clear: function () {
-          data = [];
-          index = 0;
-          self.typing = false;
-          self.data = data;
-          editor.fire('ClearUndos');
-        },
-
-        /**
-         * Returns true/false if the undo manager has any undo levels.
-         *
-         * @method hasUndo
-         * @return {Boolean} true/false if the undo manager has any undo levels.
-         */
-        hasUndo: function () {
-          // Has undo levels or typing and content isn't the same as the initial level
-          return index > 0 || (self.typing && data[0] && !Levels.isEq(Levels.createFromEditor(editor), data[0]));
-        },
-
-        /**
-         * Returns true/false if the undo manager has any redo levels.
-         *
-         * @method hasRedo
-         * @return {Boolean} true/false if the undo manager has any redo levels.
-         */
-        hasRedo: function () {
-          return index < data.length - 1 && !self.typing;
-        },
-
-        /**
-         * Executes the specified mutator function as an undo transaction. The selection
-         * before the modification will be stored to the undo stack and if the DOM changes
-         * it will add a new undo level. Any logic within the translation that adds undo levels will
-         * be ignored. So a translation can include calls to execCommand or editor.insertContent.
-         *
-         * @method transact
-         * @param {function} callback Function that gets executed and has dom manipulation logic in it.
-         * @return {Object} Undo level that got added or null it a level wasn't needed.
-         */
-        transact: function (callback) {
-          endTyping();
-          self.beforeChange();
-          self.ignore(callback);
-          return self.add();
-        },
-
-        /**
-         * Executes the specified mutator function as an undo transaction. But without adding an undo level.
-         * Any logic within the translation that adds undo levels will be ignored. So a translation can
-         * include calls to execCommand or editor.insertContent.
-         *
-         * @method ignore
-         * @param {function} callback Function that gets executed and has dom manipulation logic in it.
-         * @return {Object} Undo level that got added or null it a level wasn't needed.
-         */
-        ignore: function (callback) {
-          try {
-            locks++;
-            callback();
-          } finally {
-            locks--;
-          }
-        },
-
-        /**
-         * Adds an extra "hidden" undo level by first applying the first mutation and store that to the undo stack
-         * then roll back that change and do the second mutation on top of the stack. This will produce an extra
-         * undo level that the user doesn't see until they undo.
-         *
-         * @method extra
-         * @param {function} callback1 Function that does mutation but gets stored as a "hidden" extra undo level.
-         * @param {function} callback2 Function that does mutation but gets displayed to the user.
-         */
-        extra: function (callback1, callback2) {
-          var lastLevel, bookmark;
-
-          if (self.transact(callback1)) {
-            bookmark = data[index].bookmark;
-            lastLevel = data[index - 1];
-            Levels.applyToEditor(editor, lastLevel, true);
-
-            if (self.transact(callback2)) {
-              data[index - 1].beforeBookmark = bookmark;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            if (!dom.hasClass(elm, value)) {
+              dom.addClass(elm, value);
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          });
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">       };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return self;
-    };
-  }
-);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var applyNodeStyle = function (formatList, node) {
+        var found = false;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-define(
-  'ephox.sugar.api.node.Body',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (!format.selector) {
+          return false;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  [
-    'ephox.katamari.api.Thunk',
-    'ephox.sugar.api.node.Element',
-    'ephox.sugar.api.node.Node',
-    'global!document'
-  ],
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Look for matching formats
+        each(formatList, function (format) {
+          // Check collapsed state if it exists
+          if ('collapsed' in format && format.collapsed !== isCollapsed) {
+            return;
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Thunk, Element, Node, document) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (dom.is(node, format.selector) && !CaretFormat.isCaretNode(node)) {
+            setElementFormat(node, format);
+            found = true;
+            return false;
+          }
+        });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // Node.contains() is very, very, very good performance
-    // http://jsperf.com/closest-vs-contains/5
-    var inBody = function (element) {
-      // Technically this is only required on IE, where contains() returns false for text nodes.
-      // But it's cheap enough to run everywhere and Sugar doesn't have platform detection (yet).
-      var dom = Node.isText(element) ? element.dom().parentNode : element.dom();
-
-      // use ownerDocument.body to ensure this works inside iframes.
-      // Normally contains is bad because an element "contains" itself, but here we want that.
-      return dom !== undefined && dom !== null && dom.ownerDocument.body.contains(dom);
-    };
-
-    var body = Thunk.cached(function() {
-      return getBody(Element.fromDom(document));
-    });
-
-    var getBody = function (doc) {
-      var body = doc.dom().body;
-      if (body === null || body === undefined) throw 'Body is not available yet';
-      return Element.fromDom(body);
-    };
-
-    return {
-      body: body,
-      getBody: getBody,
-      inBody: inBody
-    };
-  }
-);
-
-define(
-  'ephox.sugar.impl.ClosestOrAncestor',
-
-  [
-    'ephox.katamari.api.Type',
-    'ephox.katamari.api.Option'
-  ],
-
-  function (Type, Option) {
-    return function (is, ancestor, scope, a, isRoot) {
-      return is(scope, a) ?
-              Option.some(scope) :
-              Type.isFunction(isRoot) && isRoot(scope) ?
-                  Option.none() :
-                  ancestor(scope, a, isRoot);
-    };
-  }
-);
-define(
-  'ephox.sugar.api.search.PredicateFind',
-
-  [
-    'ephox.katamari.api.Type',
-    'ephox.katamari.api.Arr',
-    'ephox.katamari.api.Fun',
-    'ephox.katamari.api.Option',
-    'ephox.sugar.api.node.Body',
-    'ephox.sugar.api.dom.Compare',
-    'ephox.sugar.api.node.Element',
-    'ephox.sugar.impl.ClosestOrAncestor'
-  ],
-
-  function (Type, Arr, Fun, Option, Body, Compare, Element, ClosestOrAncestor) {
-    var first = function (predicate) {
-      return descendant(Body.body(), predicate);
-    };
-
-    var ancestor = function (scope, predicate, isRoot) {
-      var element = scope.dom();
-      var stop = Type.isFunction(isRoot) ? isRoot : Fun.constant(false);
-
-      while (element.parentNode) {
-        element = element.parentNode;
-        var el = Element.fromDom(element);
-
-        if (predicate(el)) return Option.some(el);
-        else if (stop(el)) break;
-      }
-      return Option.none();
-    };
-
-    var closest = function (scope, predicate, isRoot) {
-      // This is required to avoid ClosestOrAncestor passing the predicate to itself
-      var is = function (scope) {
-        return predicate(scope);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return found;
</ins><span class="cx" style="display: block; padding: 0 10px">       };
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return ClosestOrAncestor(is, ancestor, scope, predicate, isRoot);
-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var sibling = function (scope, predicate) {
-      var element = scope.dom();
-      if (!element.parentNode) return Option.none();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var applyRngStyle = function (dom, rng, bookmark, nodeSpecific) {
+        var newWrappers = [], wrapName, wrapElm, contentEditable = true;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return child(Element.fromDom(element.parentNode), function (x) {
-        return !Compare.eq(scope, x) && predicate(x);
-      });
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Setup wrapper element
+        wrapName = format.inline || format.block;
+        wrapElm = dom.create(wrapName);
+        setElementFormat(wrapElm);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var child = function (scope, predicate) {
-      var result = Arr.find(scope.dom().childNodes,
-        Fun.compose(predicate, Element.fromDom));
-      return result.map(Element.fromDom);
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        new RangeUtils(dom).walk(rng, function (nodes) {
+          var currentWrapElm;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var descendant = function (scope, predicate) {
-      var descend = function (element) {
-        for (var i = 0; i < element.childNodes.length; i++) {
-          if (predicate(Element.fromDom(element.childNodes[i])))
-            return Option.some(Element.fromDom(element.childNodes[i]));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          /**
+           * Process a list of nodes wrap them.
+           */
+          var process = function (node) {
+            var nodeName, parentName, hasContentEditableState, lastContentEditable;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          var res = descend(element.childNodes[i]);
-          if (res.isSome())
-            return res;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            lastContentEditable = contentEditable;
+            nodeName = node.nodeName.toLowerCase();
+            parentName = node.parentNode.nodeName.toLowerCase();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return Option.none();
-      };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // Node has a contentEditable value
+            if (node.nodeType === 1 && dom.getContentEditable(node)) {
+              lastContentEditable = contentEditable;
+              contentEditable = dom.getContentEditable(node) === "true";
+              hasContentEditableState = true; // We don't want to wrap the container only it's children
+            }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return descend(scope.dom());
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // Stop wrapping on br elements
+            if (FormatUtils.isEq(nodeName, 'br')) {
+              currentWrapElm = 0;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return {
-      first: first,
-      ancestor: ancestor,
-      closest: closest,
-      sibling: sibling,
-      child: child,
-      descendant: descendant
-    };
-  }
-);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              // Remove any br elements when we wrap things
+              if (format.block) {
+                dom.remove(node);
+              }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * CaretUtils.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              return;
+            }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * Utility functions shared by the caret logic.
- *
- * @private
- * @class tinymce.caret.CaretUtils
- */
-define(
-  'tinymce.core.caret.CaretUtils',
-  [
-    "tinymce.core.util.Fun",
-    "tinymce.core.dom.TreeWalker",
-    "tinymce.core.dom.NodeType",
-    "tinymce.core.caret.CaretPosition",
-    "tinymce.core.caret.CaretContainer",
-    "tinymce.core.caret.CaretCandidate"
-  ],
-  function (Fun, TreeWalker, NodeType, CaretPosition, CaretContainer, CaretCandidate) {
-    var isContentEditableTrue = NodeType.isContentEditableTrue,
-      isContentEditableFalse = NodeType.isContentEditableFalse,
-      isBlockLike = NodeType.matchStyleValues('display', 'block table table-cell table-caption list-item'),
-      isCaretContainer = CaretContainer.isCaretContainer,
-      isCaretContainerBlock = CaretContainer.isCaretContainerBlock,
-      curry = Fun.curry,
-      isElement = NodeType.isElement,
-      isCaretCandidate = CaretCandidate.isCaretCandidate;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // If node is wrapper type
+            if (format.wrapper && MatchFormat.matchNode(ed, node, name, vars)) {
+              currentWrapElm = 0;
+              return;
+            }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function isForwards(direction) {
-      return direction > 0;
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // Can we rename the block
+            // TODO: Break this if up, too complex
+            if (contentEditable && !hasContentEditableState && format.block &&
+              !format.wrapper && FormatUtils.isTextBlock(ed, nodeName) && FormatUtils.isValid(ed, parentName, wrapName)) {
+              node = dom.rename(node, wrapName);
+              setElementFormat(node);
+              newWrappers.push(node);
+              currentWrapElm = 0;
+              return;
+            }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function isBackwards(direction) {
-      return direction < 0;
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // Handle selector patterns
+            if (format.selector) {
+              var found = applyNodeStyle(formatList, node);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function skipCaretContainers(walk, shallow) {
-      var node;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              // Continue processing if a selector match wasn't found and a inline element is defined
+              if (!format.inline || found) {
+                currentWrapElm = 0;
+                return;
+              }
+            }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      while ((node = walk(shallow))) {
-        if (!isCaretContainerBlock(node)) {
-          return node;
-        }
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // Is it valid to wrap this item
+            // TODO: Break this if up, too complex
+            if (contentEditable && !hasContentEditableState && FormatUtils.isValid(ed, wrapName, nodeName) && FormatUtils.isValid(ed, parentName, wrapName) &&
+              !(!nodeSpecific && node.nodeType === 3 &&
+                node.nodeValue.length === 1 &&
+                node.nodeValue.charCodeAt(0) === 65279) &&
+              !CaretFormat.isCaretNode(node) &&
+              (!format.inline || !dom.isBlock(node))) {
+              // Start wrapping
+              if (!currentWrapElm) {
+                // Wrap the node
+                currentWrapElm = dom.clone(wrapElm, false);
+                node.parentNode.insertBefore(currentWrapElm, node);
+                newWrappers.push(currentWrapElm);
+              }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return null;
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              currentWrapElm.appendChild(node);
+            } else {
+              // Start a new wrapper for possible children
+              currentWrapElm = 0;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function findNode(node, direction, predicateFn, rootNode, shallow) {
-      var walker = new TreeWalker(node, rootNode);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              each(Tools.grep(node.childNodes), process);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (isBackwards(direction)) {
-        if (isContentEditableFalse(node) || isCaretContainerBlock(node)) {
-          node = skipCaretContainers(walker.prev, true);
-          if (predicateFn(node)) {
-            return node;
-          }
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              if (hasContentEditableState) {
+                contentEditable = lastContentEditable; // Restore last contentEditable state from stack
+              }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        while ((node = skipCaretContainers(walker.prev, shallow))) {
-          if (predicateFn(node)) {
-            return node;
-          }
-        }
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              // End the last wrapper
+              currentWrapElm = 0;
+            }
+          };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (isForwards(direction)) {
-        if (isContentEditableFalse(node) || isCaretContainerBlock(node)) {
-          node = skipCaretContainers(walker.next, true);
-          if (predicateFn(node)) {
-            return node;
-          }
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Process siblings from range
+          each(nodes, process);
+        });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        while ((node = skipCaretContainers(walker.next, shallow))) {
-          if (predicateFn(node)) {
-            return node;
-          }
-        }
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Apply formats to links as well to get the color of the underline to change as well
+        if (format.links === true) {
+          each(newWrappers, function (node) {
+            var process = function (node) {
+              if (node.nodeName === 'A') {
+                setElementFormat(node, format);
+              }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return null;
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              each(Tools.grep(node.childNodes), process);
+            };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function getEditingHost(node, rootNode) {
-      for (node = node.parentNode; node && node != rootNode; node = node.parentNode) {
-        if (isContentEditableTrue(node)) {
-          return node;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            process(node);
+          });
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return rootNode;
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Cleanup
+        each(newWrappers, function (node) {
+          var childCount;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function getParentBlock(node, rootNode) {
-      while (node && node != rootNode) {
-        if (isBlockLike(node)) {
-          return node;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          var getChildCount = function (node) {
+            var count = 0;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        node = node.parentNode;
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            each(node.childNodes, function (node) {
+              if (!FormatUtils.isWhiteSpaceNode(node) && !BookmarkManager.isBookmarkNode(node)) {
+                count++;
+              }
+            });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return null;
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            return count;
+          };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function isInSameBlock(caretPosition1, caretPosition2, rootNode) {
-      return getParentBlock(caretPosition1.container(), rootNode) == getParentBlock(caretPosition2.container(), rootNode);
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          var getChildElementNode = function (root) {
+            var child = false;
+            each(root.childNodes, function (node) {
+              if (isElementNode(node)) {
+                child = node;
+                return false; // break loop
+              }
+            });
+            return child;
+          };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function isInSameEditingHost(caretPosition1, caretPosition2, rootNode) {
-      return getEditingHost(caretPosition1.container(), rootNode) == getEditingHost(caretPosition2.container(), rootNode);
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          var mergeStyles = function (node) {
+            var child, clone;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function getChildNodeAtRelativeOffset(relativeOffset, caretPosition) {
-      var container, offset;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            child = getChildElementNode(node);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (!caretPosition) {
-        return null;
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // If child was found and of the same type as the current node
+            if (child && !BookmarkManager.isBookmarkNode(child) && MatchFormat.matchName(dom, child, format)) {
+              clone = dom.clone(child, false);
+              setElementFormat(clone);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      container = caretPosition.container();
-      offset = caretPosition.offset();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              dom.replace(clone, node, true);
+              dom.remove(child, 1);
+            }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (!isElement(container)) {
-        return null;
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            return clone || node;
+          };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return container.childNodes[offset + relativeOffset];
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          childCount = getChildCount(node);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function beforeAfter(before, node) {
-      var range = node.ownerDocument.createRange();
-
-      if (before) {
-        range.setStartBefore(node);
-        range.setEndBefore(node);
-      } else {
-        range.setStartAfter(node);
-        range.setEndAfter(node);
-      }
-
-      return range;
-    }
-
-    function isNodesInSameBlock(rootNode, node1, node2) {
-      return getParentBlock(node1, rootNode) == getParentBlock(node2, rootNode);
-    }
-
-    function lean(left, rootNode, node) {
-      var sibling, siblingName;
-
-      if (left) {
-        siblingName = 'previousSibling';
-      } else {
-        siblingName = 'nextSibling';
-      }
-
-      while (node && node != rootNode) {
-        sibling = node[siblingName];
-
-        if (isCaretContainer(sibling)) {
-          sibling = sibling[siblingName];
-        }
-
-        if (isContentEditableFalse(sibling)) {
-          if (isNodesInSameBlock(rootNode, sibling, node)) {
-            return sibling;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Remove empty nodes but only if there is multiple wrappers and they are not block
+          // elements so never remove single <h1></h1> since that would remove the
+          // current empty block element where the caret is at
+          if ((newWrappers.length > 1 || !dom.isBlock(node)) && childCount === 0) {
+            dom.remove(node, 1);
+            return;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          break;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (format.inline || format.wrapper) {
+            // Merges the current node with it's children of similar type to reduce the number of elements
+            if (!format.exact && childCount === 1) {
+              node = mergeStyles(node);
+            }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (isCaretCandidate(sibling)) {
-          break;
-        }
-
-        node = node.parentNode;
-      }
-
-      return null;
-    }
-
-    var before = curry(beforeAfter, true);
-    var after = curry(beforeAfter, false);
-
-    function normalizeRange(direction, rootNode, range) {
-      var node, container, offset, location;
-      var leanLeft = curry(lean, true, rootNode);
-      var leanRight = curry(lean, false, rootNode);
-
-      container = range.startContainer;
-      offset = range.startOffset;
-
-      if (CaretContainer.isCaretContainerBlock(container)) {
-        if (!isElement(container)) {
-          container = container.parentNode;
-        }
-
-        location = container.getAttribute('data-mce-caret');
-
-        if (location == 'before') {
-          node = container.nextSibling;
-          if (isContentEditableFalse(node)) {
-            return before(node);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            MergeFormats.mergeWithChildren(ed, formatList, vars, node);
+            MergeFormats.mergeWithParents(ed, format, name, vars, node);
+            MergeFormats.mergeBackgroundColorAndFontSize(dom, format, vars, node);
+            MergeFormats.mergeSubSup(dom, format, vars, node);
+            MergeFormats.mergeSiblings(dom, format, vars, node);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        });
+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (location == 'after') {
-          node = container.previousSibling;
-          if (isContentEditableFalse(node)) {
-            return after(node);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (dom.getContentEditable(selection.getNode()) === "false") {
+        node = selection.getNode();
+        for (var i = 0, l = formatList.length; i < l; i++) {
+          if (formatList[i].ceFalseOverride && dom.is(node, formatList[i].selector)) {
+            setElementFormat(node, formatList[i]);
+            return;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (!range.collapsed) {
-        return range;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (NodeType.isText(container)) {
-        if (isCaretContainer(container)) {
-          if (direction === 1) {
-            node = leanRight(container);
-            if (node) {
-              return before(node);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (format) {
+        if (node) {
+          if (node.nodeType) {
+            if (!applyNodeStyle(formatList, node)) {
+              rng = dom.createRng();
+              rng.setStartBefore(node);
+              rng.setEndAfter(node);
+              applyRngStyle(dom, ExpandRange.expandRng(ed, rng, formatList), null, true);
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-            node = leanLeft(container);
-            if (node) {
-              return after(node);
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          } else {
+            applyRngStyle(dom, node, null, true);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        } else {
+          if (!isCollapsed || !format.inline || dom.select('td[data-mce-selected],th[data-mce-selected]').length) {
+            // Obtain selection node before selection is unselected by applyRngStyle
+            var curSelNode = ed.selection.getNode();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (direction === -1) {
-            node = leanLeft(container);
-            if (node) {
-              return after(node);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // If the formats have a default block and we can't find a parent block then
+            // start wrapping it with a DIV this is for forced_root_blocks: false
+            // It's kind of a hack but people should be using the default block type P since all desktop editors work that way
+            if (!ed.settings.forced_root_block && formatList[0].defaultBlock && !dom.getParent(curSelNode, dom.isBlock)) {
+              applyFormat(ed, formatList[0].defaultBlock);
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            node = leanRight(container);
-            if (node) {
-              return before(node);
-            }
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // Apply formatting to selection
+            ed.selection.setRng(RangeNormalizer.normalize(ed.selection.getRng()));
+            bookmark = selection.getBookmark();
+            applyRngStyle(dom, ExpandRange.expandRng(ed, selection.getRng(true), formatList), bookmark);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return range;
-        }
-
-        if (CaretContainer.endsWithCaretContainer(container) && offset >= container.data.length - 1) {
-          if (direction === 1) {
-            node = leanRight(container);
-            if (node) {
-              return before(node);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            if (format.styles) {
+              MergeFormats.mergeUnderlineAndColor(dom, format, vars, curSelNode);
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return range;
-        }
-
-        if (CaretContainer.startsWithCaretContainer(container) && offset <= 1) {
-          if (direction === -1) {
-            node = leanLeft(container);
-            if (node) {
-              return after(node);
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            selection.moveToBookmark(bookmark);
+            FormatUtils.moveStart(dom, selection, selection.getRng(true));
+            ed.nodeChanged();
+          } else {
+            CaretFormat.applyCaretFormat(ed, name, vars);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-          return range;
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (offset === container.data.length) {
-          node = leanRight(container);
-          if (node) {
-            return before(node);
-          }
-
-          return range;
-        }
-
-        if (offset === 0) {
-          node = leanLeft(container);
-          if (node) {
-            return after(node);
-          }
-
-          return range;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        Hooks.postProcess(name, ed);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return range;
-    }
-
-    function isNextToContentEditableFalse(relativeOffset, caretPosition) {
-      return isContentEditableFalse(getChildNodeAtRelativeOffset(relativeOffset, caretPosition));
-    }
-
</del><span class="cx" style="display: block; padding: 0 10px">     return {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      isForwards: isForwards,
-      isBackwards: isBackwards,
-      findNode: findNode,
-      getEditingHost: getEditingHost,
-      getParentBlock: getParentBlock,
-      isInSameBlock: isInSameBlock,
-      isInSameEditingHost: isInSameEditingHost,
-      isBeforeContentEditableFalse: curry(isNextToContentEditableFalse, 0),
-      isAfterContentEditableFalse: curry(isNextToContentEditableFalse, -1),
-      normalizeRange: normalizeRange
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      applyFormat: applyFormat
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * CaretWalker.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * FormatChanged.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -26216,353 +19742,96 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Contributing: http://www.tinymce.com/contributing
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * This module contains logic for moving around a virtual caret in logical order within a DOM element.
- *
- * It ignores the most obvious invalid caret locations such as within a script element or within a
- * contentEditable=false element but it will return locations that isn't possible to render visually.
- *
- * @private
- * @class tinymce.caret.CaretWalker
- * @example
- * var caretWalker = new CaretWalker(rootElm);
- *
- * var prevLogicalCaretPosition = caretWalker.prev(CaretPosition.fromRangeStart(range));
- * var nextLogicalCaretPosition = caretWalker.next(CaretPosition.fromRangeEnd(range));
- */
</del><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.caret.CaretWalker',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.fmt.FormatChanged',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    "tinymce.core.dom.NodeType",
-    "tinymce.core.caret.CaretCandidate",
-    "tinymce.core.caret.CaretPosition",
-    "tinymce.core.caret.CaretUtils",
-    "tinymce.core.util.Arr",
-    "tinymce.core.util.Fun"
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.katamari.api.Cell',
+    'tinymce.core.fmt.FormatUtils',
+    'tinymce.core.fmt.MatchFormat',
+    'tinymce.core.util.Tools'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (NodeType, CaretCandidate, CaretPosition, CaretUtils, Arr, Fun) {
-    var isContentEditableFalse = NodeType.isContentEditableFalse,
-      isText = NodeType.isText,
-      isElement = NodeType.isElement,
-      isBr = NodeType.isBr,
-      isForwards = CaretUtils.isForwards,
-      isBackwards = CaretUtils.isBackwards,
-      isCaretCandidate = CaretCandidate.isCaretCandidate,
-      isAtomic = CaretCandidate.isAtomic,
-      isEditableCaretCandidate = CaretCandidate.isEditableCaretCandidate;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Cell, FormatUtils, MatchFormat, Tools) {
+    var each = Tools.each;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function getParents(node, rootNode) {
-      var parents = [];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var setup = function (formatChangeData, editor) {
+      var currentFormats = {};
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      while (node && node != rootNode) {
-        parents.push(node);
-        node = node.parentNode;
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      formatChangeData.set({});
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return parents;
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      editor.on('NodeChange', function (e) {
+        var parents = FormatUtils.getParents(editor.dom, e.element), matchedFormats = {};
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function nodeAtIndex(container, offset) {
-      if (container.hasChildNodes() && offset < container.childNodes.length) {
-        return container.childNodes[offset];
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Ignore bogus nodes like the <a> tag created by moveStart()
+        parents = Tools.grep(parents, function (node) {
+          return node.nodeType === 1 && !node.getAttribute('data-mce-bogus');
+        });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return null;
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Check for new formats
+        each(formatChangeData.get(), function (callbacks, format) {
+          each(parents, function (node) {
+            if (editor.formatter.matchNode(node, format, {}, callbacks.similar)) {
+              if (!currentFormats[format]) {
+                // Execute callbacks
+                each(callbacks, function (callback) {
+                  callback(true, { node: node, format: format, parents: parents });
+                });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function getCaretCandidatePosition(direction, node) {
-      if (isForwards(direction)) {
-        if (isCaretCandidate(node.previousSibling) && !isText(node.previousSibling)) {
-          return CaretPosition.before(node);
-        }
-
-        if (isText(node)) {
-          return CaretPosition(node, 0);
-        }
-      }
-
-      if (isBackwards(direction)) {
-        if (isCaretCandidate(node.nextSibling) && !isText(node.nextSibling)) {
-          return CaretPosition.after(node);
-        }
-
-        if (isText(node)) {
-          return CaretPosition(node, node.data.length);
-        }
-      }
-
-      if (isBackwards(direction)) {
-        if (isBr(node)) {
-          return CaretPosition.before(node);
-        }
-
-        return CaretPosition.after(node);
-      }
-
-      return CaretPosition.before(node);
-    }
-
-    // Jumps over BR elements <p>|<br></p><p>a</p> -> <p><br></p><p>|a</p>
-    function isBrBeforeBlock(node, rootNode) {
-      var next;
-
-      if (!NodeType.isBr(node)) {
-        return false;
-      }
-
-      next = findCaretPosition(1, CaretPosition.after(node), rootNode);
-      if (!next) {
-        return false;
-      }
-
-      return !CaretUtils.isInSameBlock(CaretPosition.before(node), CaretPosition.before(next), rootNode);
-    }
-
-    function findCaretPosition(direction, startCaretPosition, rootNode) {
-      var container, offset, node, nextNode, innerNode,
-        rootContentEditableFalseElm, caretPosition;
-
-      if (!isElement(rootNode) || !startCaretPosition) {
-        return null;
-      }
-
-      if (startCaretPosition.isEqual(CaretPosition.after(rootNode)) && rootNode.lastChild) {
-        caretPosition = CaretPosition.after(rootNode.lastChild);
-        if (isBackwards(direction) && isCaretCandidate(rootNode.lastChild) && isElement(rootNode.lastChild)) {
-          return isBr(rootNode.lastChild) ? CaretPosition.before(rootNode.lastChild) : caretPosition;
-        }
-      } else {
-        caretPosition = startCaretPosition;
-      }
-
-      container = caretPosition.container();
-      offset = caretPosition.offset();
-
-      if (isText(container)) {
-        if (isBackwards(direction) && offset > 0) {
-          return CaretPosition(container, --offset);
-        }
-
-        if (isForwards(direction) && offset < container.length) {
-          return CaretPosition(container, ++offset);
-        }
-
-        node = container;
-      } else {
-        if (isBackwards(direction) && offset > 0) {
-          nextNode = nodeAtIndex(container, offset - 1);
-          if (isCaretCandidate(nextNode)) {
-            if (!isAtomic(nextNode)) {
-              innerNode = CaretUtils.findNode(nextNode, direction, isEditableCaretCandidate, nextNode);
-              if (innerNode) {
-                if (isText(innerNode)) {
-                  return CaretPosition(innerNode, innerNode.data.length);
-                }
-
-                return CaretPosition.after(innerNode);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                currentFormats[format] = callbacks;
</ins><span class="cx" style="display: block; padding: 0 10px">               }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (isText(nextNode)) {
-              return CaretPosition(nextNode, nextNode.data.length);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              matchedFormats[format] = callbacks;
+              return false;
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            return CaretPosition.before(nextNode);
-          }
-        }
-
-        if (isForwards(direction) && offset < container.childNodes.length) {
-          nextNode = nodeAtIndex(container, offset);
-          if (isCaretCandidate(nextNode)) {
-            if (isBrBeforeBlock(nextNode, rootNode)) {
-              return findCaretPosition(direction, CaretPosition.after(nextNode), rootNode);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            if (MatchFormat.matchesUnInheritedFormatSelector(editor, node, format)) {
+              return false;
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          });
+        });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (!isAtomic(nextNode)) {
-              innerNode = CaretUtils.findNode(nextNode, direction, isEditableCaretCandidate, nextNode);
-              if (innerNode) {
-                if (isText(innerNode)) {
-                  return CaretPosition(innerNode, 0);
-                }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Check if current formats still match
+        each(currentFormats, function (callbacks, format) {
+          if (!matchedFormats[format]) {
+            delete currentFormats[format];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                return CaretPosition.before(innerNode);
-              }
-            }
-
-            if (isText(nextNode)) {
-              return CaretPosition(nextNode, 0);
-            }
-
-            return CaretPosition.after(nextNode);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            each(callbacks, function (callback) {
+              callback(false, { node: e.element, format: format, parents: parents });
+            });
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        });
+      });
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        node = caretPosition.getNode();
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var addListeners = function (formatChangeData, formats, callback, similar) {
+      var formatChangeItems = formatChangeData.get();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if ((isForwards(direction) && caretPosition.isAtEnd()) || (isBackwards(direction) && caretPosition.isAtStart())) {
-        node = CaretUtils.findNode(node, direction, Fun.constant(true), rootNode, true);
-        if (isEditableCaretCandidate(node)) {
-          return getCaretCandidatePosition(direction, node);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      each(formats.split(','), function (format) {
+        if (!formatChangeItems[format]) {
+          formatChangeItems[format] = [];
+          formatChangeItems[format].similar = similar;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      nextNode = CaretUtils.findNode(node, direction, isEditableCaretCandidate, rootNode);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        formatChangeItems[format].push(callback);
+      });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      rootContentEditableFalseElm = Arr.last(Arr.filter(getParents(container, rootNode), isContentEditableFalse));
-      if (rootContentEditableFalseElm && (!nextNode || !rootContentEditableFalseElm.contains(nextNode))) {
-        if (isForwards(direction)) {
-          caretPosition = CaretPosition.after(rootContentEditableFalseElm);
-        } else {
-          caretPosition = CaretPosition.before(rootContentEditableFalseElm);
-        }
-
-        return caretPosition;
-      }
-
-      if (nextNode) {
-        return getCaretCandidatePosition(direction, nextNode);
-      }
-
-      return null;
-    }
-
-    return function (rootNode) {
-      return {
-        /**
-         * Returns the next logical caret position from the specificed input
-         * caretPoisiton or null if there isn't any more positions left for example
-         * at the end specified root element.
-         *
-         * @method next
-         * @param {tinymce.caret.CaretPosition} caretPosition Caret position to start from.
-         * @return {tinymce.caret.CaretPosition} CaretPosition or null if no position was found.
-         */
-        next: function (caretPosition) {
-          return findCaretPosition(1, caretPosition, rootNode);
-        },
-
-        /**
-         * Returns the previous logical caret position from the specificed input
-         * caretPoisiton or null if there isn't any more positions left for example
-         * at the end specified root element.
-         *
-         * @method prev
-         * @param {tinymce.caret.CaretPosition} caretPosition Caret position to start from.
-         * @return {tinymce.caret.CaretPosition} CaretPosition or null if no position was found.
-         */
-        prev: function (caretPosition) {
-          return findCaretPosition(-1, caretPosition, rootNode);
-        }
-      };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      formatChangeData.set(formatChangeItems);
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  }
-);
-/**
- * CaretFinder.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-define(
-  'tinymce.core.caret.CaretFinder',
-  [
-    'ephox.katamari.api.Fun',
-    'ephox.katamari.api.Option',
-    'tinymce.core.caret.CaretCandidate',
-    'tinymce.core.caret.CaretPosition',
-    'tinymce.core.caret.CaretUtils',
-    'tinymce.core.caret.CaretWalker',
-    'tinymce.core.dom.NodeType'
-  ],
-  function (Fun, Option, CaretCandidate, CaretPosition, CaretUtils, CaretWalker, NodeType) {
-    var walkToPositionIn = function (forward, rootNode, startNode) {
-      var position = forward ? CaretPosition.before(startNode) : CaretPosition.after(startNode);
-      return fromPosition(forward, rootNode, position);
-    };
-
-    var afterElement = function (node) {
-      return NodeType.isBr(node) ? CaretPosition.before(node) : CaretPosition.after(node);
-    };
-
-    var isBeforeOrStart = function (position) {
-      if (CaretPosition.isTextPosition(position)) {
-        return position.offset() === 0;
-      } else {
-        return CaretCandidate.isCaretCandidate(position.getNode());
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var formatChanged = function (editor, formatChangeState, formats, callback, similar) {
+      if (formatChangeState.get() === null) {
+        setup(formatChangeState, editor);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var isAfterOrEnd = function (position) {
-      if (CaretPosition.isTextPosition(position)) {
-        return position.offset() === position.container().data.length;
-      } else {
-        return CaretCandidate.isCaretCandidate(position.getNode(true));
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      addListeners(formatChangeState, formats, callback, similar);
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var isBeforeAfterSameElement = function (from, to) {
-      return !CaretPosition.isTextPosition(from) && !CaretPosition.isTextPosition(to) && from.getNode() === to.getNode(true);
-    };
-
-    var isAtBr = function (position) {
-      return !CaretPosition.isTextPosition(position) && NodeType.isBr(position.getNode());
-    };
-
-    var shouldSkipPosition = function (forward, from, to) {
-      if (forward) {
-        return !isBeforeAfterSameElement(from, to) && !isAtBr(from) && isAfterOrEnd(from) && isBeforeOrStart(to);
-      } else {
-        return !isBeforeAfterSameElement(to, from) && isBeforeOrStart(from) && isAfterOrEnd(to);
-      }
-    };
-
-    // Finds: <p>a|<b>b</b></p> -> <p>a<b>|b</b></p>
-    var fromPosition = function (forward, rootNode, position) {
-      var walker = new CaretWalker(rootNode);
-      return Option.from(forward ? walker.next(position) : walker.prev(position));
-    };
-
-    // Finds: <p>a|<b>b</b></p> -> <p>a<b>b|</b></p>
-    var navigate = function (forward, rootNode, from) {
-      return fromPosition(forward, rootNode, from).bind(function (to) {
-        if (CaretUtils.isInSameBlock(from, to, rootNode) && shouldSkipPosition(forward, from, to)) {
-          return fromPosition(forward, rootNode, to);
-        } else {
-          return Option.some(to);
-        }
-      });
-    };
-
-    var positionIn = function (forward, element) {
-      var startNode = forward ? element.firstChild : element.lastChild;
-      if (NodeType.isText(startNode)) {
-        return Option.some(new CaretPosition(startNode, forward ? 0 : startNode.data.length));
-      } else if (startNode) {
-        if (CaretCandidate.isCaretCandidate(startNode)) {
-          return Option.some(forward ? CaretPosition.before(startNode) : afterElement(startNode));
-        } else {
-          return walkToPositionIn(forward, element, startNode);
-        }
-      } else {
-        return Option.none();
-      }
-    };
-
</del><span class="cx" style="display: block; padding: 0 10px">     return {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      fromPosition: fromPosition,
-      navigate: navigate,
-      positionIn: positionIn
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      formatChanged: formatChanged
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * DeleteUtils.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * DefaultFormats.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -26572,146 +19841,202 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.delete.DeleteUtils',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.fmt.DefaultFormats',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'ephox.katamari.api.Arr',
-    'ephox.katamari.api.Option',
-    'ephox.sugar.api.dom.Compare',
-    'ephox.sugar.api.node.Element',
-    'ephox.sugar.api.node.Node',
-    'ephox.sugar.api.search.PredicateFind'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.util.Tools'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Arr, Option, Compare, Element, Node, PredicateFind) {
-    var toLookup = function (names) {
-      var lookup = Arr.foldl(names, function (acc, name) {
-        acc[name] = true;
-        return acc;
-      }, { });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Tools) {
+    var get = function (dom) {
+      var formats = {
+        valigntop: [
+          { selector: 'td,th', styles: { 'verticalAlign': 'top' } }
+        ],
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return function (elm) {
-        return lookup[Node.name(elm)] === true;
-      };
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        valignmiddle: [
+          { selector: 'td,th', styles: { 'verticalAlign': 'middle' } }
+        ],
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var isTextBlock = toLookup([
-      'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'div', 'address', 'pre', 'form', 'blockquote', 'center',
-      'dir', 'fieldset', 'header', 'footer', 'article', 'section', 'hgroup', 'aside', 'nav', 'figure'
-    ]);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        valignbottom: [
+          { selector: 'td,th', styles: { 'verticalAlign': 'bottom' } }
+        ],
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var isBeforeRoot = function (rootNode) {
-      return function (elm) {
-        return Compare.eq(rootNode, Element.fromDom(elm.dom().parentNode));
-      };
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        alignleft: [
+          {
+            selector: 'figure.image',
+            collapsed: false,
+            classes: 'align-left',
+            ceFalseOverride: true,
+            preview: 'font-family font-size'
+          },
+          {
+            selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li',
+            styles: {
+              textAlign: 'left'
+            },
+            inherit: false,
+            preview: false,
+            defaultBlock: 'div'
+          },
+          {
+            selector: 'img,table',
+            collapsed: false,
+            styles: {
+              'float': 'left'
+            },
+            preview: 'font-family font-size'
+          }
+        ],
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var getParentTextBlock = function (rootNode, elm) {
-      return Compare.contains(rootNode, elm) ? PredicateFind.closest(elm, isTextBlock, isBeforeRoot(rootNode)) : Option.none();
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        aligncenter: [
+          {
+            selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li',
+            styles: {
+              textAlign: 'center'
+            },
+            inherit: false,
+            preview: 'font-family font-size',
+            defaultBlock: 'div'
+          },
+          {
+            selector: 'figure.image',
+            collapsed: false,
+            classes: 'align-center',
+            ceFalseOverride: true,
+            preview: 'font-family font-size'
+          },
+          {
+            selector: 'img',
+            collapsed: false,
+            styles: {
+              display: 'block',
+              marginLeft: 'auto',
+              marginRight: 'auto'
+            },
+            preview: false
+          },
+          {
+            selector: 'table',
+            collapsed: false,
+            styles: {
+              marginLeft: 'auto',
+              marginRight: 'auto'
+            },
+            preview: 'font-family font-size'
+          }
+        ],
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return {
-      getParentTextBlock: getParentTextBlock
-    };
-  }
-);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        alignright: [
+          {
+            selector: 'figure.image',
+            collapsed: false,
+            classes: 'align-right',
+            ceFalseOverride: true,
+            preview: 'font-family font-size'
+          },
+          {
+            selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li',
+            styles: {
+              textAlign: 'right'
+            },
+            inherit: false,
+            preview: 'font-family font-size',
+            defaultBlock: 'div'
+          },
+          {
+            selector: 'img,table',
+            collapsed: false,
+            styles: {
+              'float': 'right'
+            },
+            preview: 'font-family font-size'
+          }
+        ],
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-define(
-  'ephox.sugar.api.search.SelectorFind',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        alignjustify: [
+          {
+            selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li',
+            styles: {
+              textAlign: 'justify'
+            },
+            inherit: false,
+            defaultBlock: 'div',
+            preview: 'font-family font-size'
+          }
+        ],
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  [
-    'ephox.sugar.api.search.PredicateFind',
-    'ephox.sugar.api.search.Selectors',
-    'ephox.sugar.impl.ClosestOrAncestor'
-  ],
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        bold: [
+          { inline: 'strong', remove: 'all' },
+          { inline: 'span', styles: { fontWeight: 'bold' } },
+          { inline: 'b', remove: 'all' }
+        ],
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (PredicateFind, Selectors, ClosestOrAncestor) {
-    // TODO: An internal SelectorFilter module that doesn't Element.fromDom() everything
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        italic: [
+          { inline: 'em', remove: 'all' },
+          { inline: 'span', styles: { fontStyle: 'italic' } },
+          { inline: 'i', remove: 'all' }
+        ],
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var first = function (selector) {
-      return Selectors.one(selector);
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        underline: [
+          { inline: 'span', styles: { textDecoration: 'underline' }, exact: true },
+          { inline: 'u', remove: 'all' }
+        ],
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var ancestor = function (scope, selector, isRoot) {
-      return PredicateFind.ancestor(scope, function (e) {
-        return Selectors.is(e, selector);
-      }, isRoot);
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        strikethrough: [
+          { inline: 'span', styles: { textDecoration: 'line-through' }, exact: true },
+          { inline: 'strike', remove: 'all' }
+        ],
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var sibling = function (scope, selector) {
-      return PredicateFind.sibling(scope, function (e) {
-        return Selectors.is(e, selector);
-      });
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        forecolor: { inline: 'span', styles: { color: '%value' }, links: true, remove_similar: true, clear_child_styles: true },
+        hilitecolor: { inline: 'span', styles: { backgroundColor: '%value' }, links: true, remove_similar: true, clear_child_styles: true },
+        fontname: { inline: 'span', styles: { fontFamily: '%value' }, clear_child_styles: true },
+        fontsize: { inline: 'span', styles: { fontSize: '%value' }, clear_child_styles: true },
+        fontsize_class: { inline: 'span', attributes: { 'class': '%value' } },
+        blockquote: { block: 'blockquote', wrapper: 1, remove: 'all' },
+        subscript: { inline: 'sub' },
+        superscript: { inline: 'sup' },
+        code: { inline: 'code' },
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var child = function (scope, selector) {
-      return PredicateFind.child(scope, function (e) {
-        return Selectors.is(e, selector);
-      });
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        link: {
+          inline: 'a', selector: 'a', remove: 'all', split: true, deep: true,
+          onmatch: function () {
+            return true;
+          },
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var descendant = function (scope, selector) {
-      return Selectors.one(selector, scope);
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          onformat: function (elm, fmt, vars) {
+            Tools.each(vars, function (value, key) {
+              dom.setAttrib(elm, key, value);
+            });
+          }
+        },
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var closest = function (scope, selector, isRoot) {
-      return ClosestOrAncestor(Selectors.is, ancestor, scope, selector, isRoot);
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        removeformat: [
+          {
+            selector: 'b,strong,em,i,font,u,strike,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins',
+            remove: 'all',
+            split: true,
+            expand: false,
+            block_expand: true,
+            deep: true
+          },
+          { selector: 'span', attributes: ['style', 'class'], remove: 'empty', split: true, expand: false, deep: true },
+          { selector: '*', attributes: ['style', 'class'], split: false, expand: false, deep: true }
+        ]
+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return {
-      first: first,
-      ancestor: ancestor,
-      sibling: sibling,
-      child: child,
-      descendant: descendant,
-      closest: closest
-    };
-  }
-);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      Tools.each('p h1 h2 h3 h4 h5 h6 div address pre div dt dd samp'.split(/\s/), function (name) {
+        formats[name] = { block: name, remove: 'all' };
+      });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-define(
-  'ephox.sugar.api.search.SelectorExists',
-
-  [
-    'ephox.sugar.api.search.SelectorFind'
-  ],
-
-  function (SelectorFind) {
-    var any = function (selector) {
-      return SelectorFind.first(selector).isSome();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return formats;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var ancestor = function (scope, selector, isRoot) {
-      return SelectorFind.ancestor(scope, selector, isRoot).isSome();
-    };
-
-    var sibling = function (scope, selector) {
-      return SelectorFind.sibling(scope, selector).isSome();
-    };
-
-    var child = function (scope, selector) {
-      return SelectorFind.child(scope, selector).isSome();
-    };
-
-    var descendant = function (scope, selector) {
-      return SelectorFind.descendant(scope, selector).isSome();
-    };
-
-    var closest = function (scope, selector, isRoot) {
-      return SelectorFind.closest(scope, selector, isRoot).isSome();
-    };
-
</del><span class="cx" style="display: block; padding: 0 10px">     return {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      any: any,
-      ancestor: ancestor,
-      sibling: sibling,
-      child: child,
-      descendant: descendant,
-      closest: closest
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      get: get
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Empty.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * FormatRegistry.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -26721,91 +20046,85 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.dom.Empty',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.fmt.FormatRegistry',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'ephox.katamari.api.Fun',
-    'ephox.sugar.api.dom.Compare',
-    'ephox.sugar.api.node.Element',
-    'ephox.sugar.api.search.SelectorExists',
-    'tinymce.core.caret.CaretCandidate',
-    'tinymce.core.dom.NodeType',
-    'tinymce.core.dom.TreeWalker'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.fmt.DefaultFormats',
+    'tinymce.core.util.Tools'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Fun, Compare, Element, SelectorExists, CaretCandidate, NodeType, TreeWalker) {
-    var hasWhitespacePreserveParent = function (rootNode, node) {
-      var rootElement = Element.fromDom(rootNode);
-      var startNode = Element.fromDom(node);
-      return SelectorExists.ancestor(startNode, 'pre,code', Fun.curry(Compare.eq, rootElement));
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (DefaultFormats, Tools) {
+    return function (editor) {
+      var formats = {};
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var isWhitespace = function (rootNode, node) {
-      return NodeType.isText(node) && /^[ \t\r\n]*$/.test(node.data) && hasWhitespacePreserveParent(rootNode, node) === false;
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var get = function (name) {
+        return name ? formats[name] : formats;
+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var isNamedAnchor = function (node) {
-      return NodeType.isElement(node) && node.nodeName === 'A' && node.hasAttribute('name');
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var register = function (name, format) {
+        if (name) {
+          if (typeof name !== 'string') {
+            Tools.each(name, function (format, name) {
+              register(name, format);
+            });
+          } else {
+            // Force format into array and add it to internal collection
+            format = format.length ? format : [format];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var isContent = function (rootNode, node) {
-      return (CaretCandidate.isCaretCandidate(node) && isWhitespace(rootNode, node) === false) || isNamedAnchor(node) || isBookmark(node);
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            Tools.each(format, function (format) {
+              // Set deep to false by default on selector formats this to avoid removing
+              // alignment on images inside paragraphs when alignment is changed on paragraphs
+              if (typeof format.deep === 'undefined') {
+                format.deep = !format.selector;
+              }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var isBookmark = NodeType.hasAttribute('data-mce-bookmark');
-    var isBogus = NodeType.hasAttribute('data-mce-bogus');
-    var isBogusAll = NodeType.hasAttributeValue('data-mce-bogus', 'all');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              // Default to true
+              if (typeof format.split === 'undefined') {
+                format.split = !format.selector || format.inline;
+              }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var isEmptyNode = function (targetNode) {
-      var walker, node, brCount = 0;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              // Default to true
+              if (typeof format.remove === 'undefined' && format.selector && !format.inline) {
+                format.remove = 'none';
+              }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (isContent(targetNode, targetNode)) {
-        return false;
-      } else {
-        node = targetNode.firstChild;
-        if (!node) {
-          return true;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              // Mark format as a mixed format inline + block level
+              if (format.selector && format.inline) {
+                format.mixed = true;
+                format.block_expand = true;
+              }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        walker = new TreeWalker(node, targetNode);
-        do {
-          if (isBogusAll(node)) {
-            node = walker.next(true);
-            continue;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              // Split classes if needed
+              if (typeof format.classes === 'string') {
+                format.classes = format.classes.split(/\s+/);
+              }
+            });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (isBogus(node)) {
-            node = walker.next();
-            continue;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            formats[name] = format;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        }
+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (NodeType.isBr(node)) {
-            brCount++;
-            node = walker.next();
-            continue;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var unregister = function (name) {
+        if (name && formats[name]) {
+          delete formats[name];
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (isContent(targetNode, node)) {
-            return false;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return formats;
+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          node = walker.next();
-        } while (node);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      register(DefaultFormats.get(editor.dom));
+      register(editor.settings.formats);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return brCount <= 1;
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return {
+        get: get,
+        register: register,
+        unregister: unregister
+      };
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-    var isEmpty = function (elm) {
-      return isEmptyNode(elm.dom());
-    };
-
-    return {
-      isEmpty: isEmpty
-    };
</del><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * BlockBoundary.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Preview.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -26814,923 +20133,346 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Contributing: http://www.tinymce.com/contributing
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-define(
-  'tinymce.core.delete.BlockBoundary',
-  [
-    'ephox.katamari.api.Arr',
-    'ephox.katamari.api.Fun',
-    'ephox.katamari.api.Option',
-    'ephox.katamari.api.Options',
-    'ephox.katamari.api.Struct',
-    'ephox.sugar.api.dom.Compare',
-    'ephox.sugar.api.node.Element',
-    'ephox.sugar.api.node.Node',
-    'ephox.sugar.api.search.PredicateFind',
-    'ephox.sugar.api.search.Traverse',
-    'tinymce.core.caret.CaretFinder',
-    'tinymce.core.caret.CaretPosition',
-    'tinymce.core.delete.DeleteUtils',
-    'tinymce.core.dom.Empty',
-    'tinymce.core.dom.NodeType'
-  ],
-  function (Arr, Fun, Option, Options, Struct, Compare, Element, Node, PredicateFind, Traverse, CaretFinder, CaretPosition, DeleteUtils, Empty, NodeType) {
-    var BlockPosition = Struct.immutable('block', 'position');
-    var BlockBoundary = Struct.immutable('from', 'to');
-
-    var getBlockPosition = function (rootNode, pos) {
-      var rootElm = Element.fromDom(rootNode);
-      var containerElm = Element.fromDom(pos.container());
-      return DeleteUtils.getParentTextBlock(rootElm, containerElm).map(function (block) {
-        return BlockPosition(block, pos);
-      });
-    };
-
-    var isDifferentBlocks = function (blockBoundary) {
-      return Compare.eq(blockBoundary.from().block(), blockBoundary.to().block()) === false;
-    };
-
-    var hasSameParent = function (blockBoundary) {
-      return Traverse.parent(blockBoundary.from().block()).bind(function (parent1) {
-        return Traverse.parent(blockBoundary.to().block()).filter(function (parent2) {
-          return Compare.eq(parent1, parent2);
-        });
-      }).isSome();
-    };
-
-    var isEditable = function (blockBoundary) {
-      return NodeType.isContentEditableFalse(blockBoundary.from().block()) === false && NodeType.isContentEditableFalse(blockBoundary.to().block()) === false;
-    };
-
-    var skipLastBr = function (rootNode, forward, blockPosition) {
-      if (NodeType.isBr(blockPosition.position().getNode()) && Empty.isEmpty(blockPosition.block()) === false) {
-        return CaretFinder.positionIn(false, blockPosition.block().dom()).bind(function (lastPositionInBlock) {
-          if (lastPositionInBlock.isEqual(blockPosition.position())) {
-            return CaretFinder.fromPosition(forward, rootNode, lastPositionInBlock).bind(function (to) {
-              return getBlockPosition(rootNode, to);
-            });
-          } else {
-            return Option.some(blockPosition);
-          }
-        }).getOr(blockPosition);
-      } else {
-        return blockPosition;
-      }
-    };
-
-    var readFromRange = function (rootNode, forward, rng) {
-      var fromBlockPos = getBlockPosition(rootNode, CaretPosition.fromRangeStart(rng));
-      var toBlockPos = fromBlockPos.bind(function (blockPos) {
-        return CaretFinder.fromPosition(forward, rootNode, blockPos.position()).bind(function (to) {
-          return getBlockPosition(rootNode, to).map(function (blockPos) {
-            return skipLastBr(rootNode, forward, blockPos);
-          });
-        });
-      });
-
-      return Options.liftN([fromBlockPos, toBlockPos], BlockBoundary).filter(function (blockBoundary) {
-        return isDifferentBlocks(blockBoundary) && hasSameParent(blockBoundary) && isEditable(blockBoundary);
-      });
-    };
-
-    var read = function (rootNode, forward, rng) {
-      return rng.collapsed ? readFromRange(rootNode, forward, rng) : Option.none();
-    };
-
-    return {
-      read: read
-    };
-  }
-);
-
</del><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * MergeBlocks.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Internal class for generating previews styles for formats.
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Example:
+ *  Preview.getCssText(editor, 'bold');
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @private
+ * @class tinymce.fmt.Preview
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.delete.MergeBlocks',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.fmt.Preview',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'ephox.katamari.api.Arr',
-    'ephox.katamari.api.Option',
-    'ephox.sugar.api.dom.Insert',
-    'ephox.sugar.api.dom.Remove',
-    'ephox.sugar.api.node.Element',
-    'ephox.sugar.api.search.Traverse',
-    'tinymce.core.caret.CaretFinder',
-    'tinymce.core.caret.CaretPosition',
-    'tinymce.core.dom.Empty',
-    'tinymce.core.dom.NodeType'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    "tinymce.core.dom.DOMUtils",
+    "tinymce.core.util.Tools",
+    "tinymce.core.html.Schema"
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Arr, Option, Insert, Remove, Element, Traverse, CaretFinder, CaretPosition, Empty, NodeType) {
-    var mergeBlocksAndReposition = function (forward, fromBlock, toBlock, toPosition) {
-      var children = Traverse.children(fromBlock);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (DOMUtils, Tools, Schema) {
+    var each = Tools.each;
+    var dom = DOMUtils.DOM;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (NodeType.isBr(toPosition.getNode())) {
-        Remove.remove(Element.fromDom(toPosition.getNode()));
-        toPosition = CaretFinder.positionIn(false, toBlock.dom()).getOr(toPosition);
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function parsedSelectorToHtml(ancestry, editor) {
+      var elm, item, fragment;
+      var schema = editor && editor.schema || new Schema({});
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (Empty.isEmpty(fromBlock) === false) {
-        Arr.each(children, function (node) {
-          Insert.append(toBlock, node);
-        });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function decorate(elm, item) {
+        if (item.classes.length) {
+          dom.addClass(elm, item.classes.join(' '));
+        }
+        dom.setAttribs(elm, item.attrs);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (Empty.isEmpty(fromBlock)) {
-        Remove.remove(fromBlock);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function createElement(sItem) {
+        var elm;
+
+        item = typeof sItem === 'string' ? {
+          name: sItem,
+          classes: [],
+          attrs: {}
+        } : sItem;
+
+        elm = dom.create(item.name);
+        decorate(elm, item);
+        return elm;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return children.length > 0 ? Option.from(toPosition) : Option.none();
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function getRequiredParent(elm, candidate) {
+        var name = typeof elm !== 'string' ? elm.nodeName.toLowerCase() : elm;
+        var elmRule = schema.getElementRule(name);
+        var parentsRequired = elmRule && elmRule.parentsRequired;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var mergeBlocks = function (forward, block1, block2) {
-      if (forward) {
-        if (Empty.isEmpty(block1)) {
-          Remove.remove(block1);
-          return CaretFinder.positionIn(true, block2.dom());
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (parentsRequired && parentsRequired.length) {
+          return candidate && Tools.inArray(parentsRequired, candidate) !== -1 ? candidate : parentsRequired[0];
</ins><span class="cx" style="display: block; padding: 0 10px">         } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return CaretFinder.positionIn(false, block1.dom()).bind(function (toPosition) {
-            return mergeBlocksAndReposition(forward, block2, block1, toPosition);
-          });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          return false;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      } else {
-        if (Empty.isEmpty(block2)) {
-          Remove.remove(block2);
-          return CaretFinder.positionIn(true, block1.dom());
-        } else {
-          return CaretFinder.positionIn(false, block2.dom()).bind(function (toPosition) {
-            return mergeBlocksAndReposition(forward, block1, block2, toPosition);
-          });
-        }
</del><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return {
-      mergeBlocks: mergeBlocks
-    };
-  }
-);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function wrapInHtml(elm, ancestry, siblings) {
+        var parent, parentCandidate, parentRequired;
+        var ancestor = ancestry.length > 0 && ancestry[0];
+        var ancestorName = ancestor && ancestor.name;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * BlockBoundaryDelete.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        parentRequired = getRequiredParent(elm, ancestorName);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-define(
-  'tinymce.core.delete.BlockBoundaryDelete',
-  [
-    'tinymce.core.delete.BlockBoundary',
-    'tinymce.core.delete.MergeBlocks'
-  ],
-  function (BlockBoundary, MergeBlocks) {
-    var backspaceDelete = function (editor, forward) {
-      var position;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (parentRequired) {
+          if (ancestorName === parentRequired) {
+            parentCandidate = ancestry[0];
+            ancestry = ancestry.slice(1);
+          } else {
+            parentCandidate = parentRequired;
+          }
+        } else if (ancestor) {
+          parentCandidate = ancestry[0];
+          ancestry = ancestry.slice(1);
+        } else if (!siblings) {
+          return elm;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      position = BlockBoundary.read(editor.getBody(), forward, editor.selection.getRng()).bind(function (blockBoundary) {
-        return MergeBlocks.mergeBlocks(forward, blockBoundary.from().block(), blockBoundary.to().block());
-      });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (parentCandidate) {
+          parent = createElement(parentCandidate);
+          parent.appendChild(elm);
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      position.each(function (pos) {
-        editor.selection.setRng(pos.toRange());
-      });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (siblings) {
+          if (!parent) {
+            // if no more ancestry, wrap in generic div
+            parent = dom.create('div');
+            parent.appendChild(elm);
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return position.isSome();
-    };
-
-    return {
-      backspaceDelete: backspaceDelete
-    };
-  }
-);
-
-/**
- * BlockRangeDelete.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-define(
-  'tinymce.core.delete.BlockRangeDelete',
-  [
-    'ephox.katamari.api.Options',
-    'ephox.sugar.api.dom.Compare',
-    'ephox.sugar.api.node.Element',
-    'tinymce.core.delete.DeleteUtils',
-    'tinymce.core.delete.MergeBlocks'
-  ],
-  function (Options, Compare, Element, DeleteUtils, MergeBlocks) {
-    var deleteRange = function (rootNode, selection) {
-      var rng = selection.getRng();
-
-      return Options.liftN([
-        DeleteUtils.getParentTextBlock(rootNode, Element.fromDom(rng.startContainer)),
-        DeleteUtils.getParentTextBlock(rootNode, Element.fromDom(rng.endContainer))
-      ], function (block1, block2) {
-        if (Compare.eq(block1, block2) === false) {
-          rng.deleteContents();
-
-          MergeBlocks.mergeBlocks(true, block1, block2).each(function (pos) {
-            selection.setRng(pos.toRange());
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          Tools.each(siblings, function (sibling) {
+            var siblingElm = createElement(sibling);
+            parent.insertBefore(siblingElm, elm);
</ins><span class="cx" style="display: block; padding: 0 10px">           });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-          return true;
-        } else {
-          return false;
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      }).getOr(false);
-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var backspaceDelete = function (editor, forward) {
-      var rootNode = Element.fromDom(editor.getBody());
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return wrapInHtml(parent, ancestry, parentCandidate && parentCandidate.siblings);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (editor.selection.isCollapsed() === false) {
-        return deleteRange(rootNode, editor.selection);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (ancestry && ancestry.length) {
+        item = ancestry[0];
+        elm = createElement(item);
+        fragment = dom.create('div');
+        fragment.appendChild(wrapInHtml(elm, ancestry.slice(1), item.siblings));
+        return fragment;
</ins><span class="cx" style="display: block; padding: 0 10px">       } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return '';
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return {
-      backspaceDelete: backspaceDelete
-    };
-  }
-);
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-define(
-  'ephox.katamari.api.Adt',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function selectorToHtml(selector, editor) {
+      return parsedSelectorToHtml(parseSelector(selector), editor);
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  [
-    'ephox.katamari.api.Arr',
-    'ephox.katamari.api.Obj',
-    'ephox.katamari.api.Type',
-    'global!Array',
-    'global!Error',
-    'global!console'
-  ],
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Arr, Obj, Type, Array, Error, console) {
-    /*
-     * Generates a church encoded ADT (https://en.wikipedia.org/wiki/Church_encoding)
-     * For syntax and use, look at the test code.
-     */
-    var generate = function (cases) {
-      // validation
-      if (!Type.isArray(cases)) {
-        throw new Error('cases must be an array');
-      }
-      if (cases.length === 0) {
-        throw new Error('there must be at least one case');
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function parseSelectorItem(item) {
+      var tagName;
+      var obj = {
+        classes: [],
+        attrs: {}
+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var constructors = [ ];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      item = obj.selector = Tools.trim(item);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // adt is mutated to add the individual cases
-      var adt = {};
-      Arr.each(cases, function (acase, count) {
-        var keys = Obj.keys(acase);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (item !== '*') {
+        // matching IDs, CLASSes, ATTRIBUTES and PSEUDOs
+        tagName = item.replace(/(?:([#\.]|::?)([\w\-]+)|(\[)([^\]]+)\]?)/g, function ($0, $1, $2, $3, $4) {
+          switch ($1) {
+            case '#':
+              obj.attrs.id = $2;
+              break;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // validation
-        if (keys.length !== 1) {
-          throw new Error('one and only one name per case');
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            case '.':
+              obj.classes.push($2);
+              break;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var key = keys[0];
-        var value = acase[key];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            case ':':
+              if (Tools.inArray('checked disabled enabled read-only required'.split(' '), $2) !== -1) {
+                obj.attrs[$2] = $2;
+              }
+              break;
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // validation
-        if (adt[key] !== undefined) {
-          throw new Error('duplicate key detected:' + key);
-        } else if (key === 'cata') {
-          throw new Error('cannot have a case named cata (sorry)');
-        } else if (!Type.isArray(value)) {
-          // this implicitly checks if acase is an object
-          throw new Error('case arguments must be an array');
-        }
-
-        constructors.push(key);
-        //
-        // constructor for key
-        //
-        adt[key] = function () {
-          var argLength = arguments.length;
-
-          // validation
-          if (argLength !== value.length) {
-            throw new Error('Wrong number of arguments to case ' + key + '. Expected ' + value.length + ' (' + value + '), got ' + argLength);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // atribute matched
+          if ($3 === '[') {
+            var m = $4.match(/([\w\-]+)(?:\=\"([^\"]+))?/);
+            if (m) {
+              obj.attrs[m[1]] = m[2];
+            }
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Don't use array slice(arguments), makes the whole function unoptimisable on Chrome
-          var args = new Array(argLength);
-          for (var i = 0; i < args.length; i++) args[i] = arguments[i];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          return '';
+        });
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      obj.name = tagName || 'div';
+      return obj;
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          var match = function (branches) {
-            var branchKeys = Obj.keys(branches);
-            if (constructors.length !== branchKeys.length) {
-              throw new Error('Wrong number of arguments to match. Expected: ' + constructors.join(',') + '\nActual: ' + branchKeys.join(','));
-            }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            var allReqd = Arr.forall(constructors, function (reqKey) {
-              return Arr.contains(branchKeys, reqKey);
-            });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function parseSelector(selector) {
+      if (!selector || typeof selector !== 'string') {
+        return [];
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (!allReqd) throw new Error('Not all branches were specified when using match. Specified: ' + branchKeys.join(', ') + '\nRequired: ' + constructors.join(', '));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // take into account only first one
+      selector = selector.split(/\s*,\s*/)[0];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            return branches[key].apply(null, args);
-          };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // tighten
+      selector = selector.replace(/\s*(~\+|~|\+|>)\s*/g, '$1');
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          //
-          // the fold function for key
-          //
-          return {
-            fold: function (/* arguments */) {
-              // runtime validation
-              if (arguments.length !== cases.length) {
-                throw new Error('Wrong number of arguments to fold. Expected ' + cases.length + ', got ' + arguments.length);
-              }
-              var target = arguments[count];
-              return target.apply(null, args);
-            },
-            match: match,
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // split either on > or on space, but not the one inside brackets
+      return Tools.map(selector.split(/(?:>|\s+(?![^\[\]]+\]))/), function (item) {
+        // process each sibling selector separately
+        var siblings = Tools.map(item.split(/(?:~\+|~|\+)/), parseSelectorItem);
+        var obj = siblings.pop(); // the last one is our real target
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // NOTE: Only for debugging.
-            log: function (label) {
-              console.log(label, {
-                constructors: constructors,
-                constructor: key,
-                params: args
-              });
-            }
-          };
-        };
-      });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (siblings.length) {
+          obj.siblings = siblings;
+        }
+        return obj;
+      }).reverse();
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return adt;
-    };
-    return {
-      generate: generate
-    };
-  }
-);
-/**
- * CefDeleteAction.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-define(
-  'tinymce.core.delete.CefDeleteAction',
-  [
-    'ephox.katamari.api.Adt',
-    'ephox.katamari.api.Option',
-    'ephox.sugar.api.node.Element',
-    'tinymce.core.caret.CaretFinder',
-    'tinymce.core.caret.CaretPosition',
-    'tinymce.core.caret.CaretUtils',
-    'tinymce.core.delete.DeleteUtils',
-    'tinymce.core.dom.Empty',
-    'tinymce.core.dom.NodeType'
-  ],
-  function (Adt, Option, Element, CaretFinder, CaretPosition, CaretUtils, DeleteUtils, Empty, NodeType) {
-    var DeleteAction = Adt.generate([
-      { remove: [ 'element' ] },
-      { moveToElement: [ 'element' ] },
-      { moveToPosition: [ 'position' ] }
-    ]);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function getCssText(editor, format) {
+      var name, previewFrag, previewElm, items;
+      var previewCss = '', parentFontSize, previewStyles;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var isAtContentEditableBlockCaret = function (forward, from) {
-      var elm = from.getNode(forward === false);
-      var caretLocation = forward ? 'after' : 'before';
-      return NodeType.isElement(elm) && elm.getAttribute('data-mce-caret') === caretLocation;
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      previewStyles = editor.settings.preview_styles;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var deleteEmptyBlockOrMoveToCef = function (rootNode, forward, from, to) {
-      var toCefElm = to.getNode(forward === false);
-      return DeleteUtils.getParentTextBlock(Element.fromDom(rootNode), Element.fromDom(from.getNode())).map(function (blockElm) {
-        return Empty.isEmpty(blockElm) ? DeleteAction.remove(blockElm.dom()) : DeleteAction.moveToElement(toCefElm);
-      }).orThunk(function () {
-        return Option.some(DeleteAction.moveToElement(toCefElm));
-      });
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // No preview forced
+      if (previewStyles === false) {
+        return '';
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var findCefPosition = function (rootNode, forward, from) {
-      return CaretFinder.fromPosition(forward, rootNode, from).bind(function (to) {
-        if (forward && NodeType.isContentEditableFalse(to.getNode())) {
-          return deleteEmptyBlockOrMoveToCef(rootNode, forward, from, to);
-        } else if (forward === false && NodeType.isContentEditableFalse(to.getNode(true))) {
-          return deleteEmptyBlockOrMoveToCef(rootNode, forward, from, to);
-        } else if (forward && CaretUtils.isAfterContentEditableFalse(from)) {
-          return Option.some(DeleteAction.moveToPosition(to));
-        } else if (forward === false && CaretUtils.isBeforeContentEditableFalse(from)) {
-          return Option.some(DeleteAction.moveToPosition(to));
-        } else {
-          return Option.none();
-        }
-      });
-    };
-
-    var getContentEditableBlockAction = function (forward, elm) {
-      if (forward && NodeType.isContentEditableFalse(elm.nextSibling)) {
-        return Option.some(DeleteAction.moveToElement(elm.nextSibling));
-      } else if (forward === false && NodeType.isContentEditableFalse(elm.previousSibling)) {
-        return Option.some(DeleteAction.moveToElement(elm.previousSibling));
-      } else {
-        return Option.none();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Default preview
+      if (typeof previewStyles !== 'string') {
+        previewStyles = 'font-family font-size font-weight font-style text-decoration ' +
+          'text-transform color background-color border border-radius outline text-shadow';
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var getContentEditableAction = function (rootNode, forward, from) {
-      if (isAtContentEditableBlockCaret(forward, from)) {
-        return getContentEditableBlockAction(forward, from.getNode(forward === false))
-          .fold(
-            function () {
-              return findCefPosition(rootNode, forward, from);
-            },
-            Option.some
-          );
-      } else {
-        return findCefPosition(rootNode, forward, from);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Removes any variables since these can't be previewed
+      function removeVars(val) {
+        return val.replace(/%(\w+)/g, '');
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var read = function (rootNode, forward, rng) {
-      var normalizedRange = CaretUtils.normalizeRange(forward ? 1 : -1, rootNode, rng);
-      var from = CaretPosition.fromRangeStart(normalizedRange);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Create block/inline element to use for preview
+      if (typeof format === "string") {
+        format = editor.formatter.get(format);
+        if (!format) {
+          return;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (forward === false && CaretUtils.isAfterContentEditableFalse(from)) {
-        return Option.some(DeleteAction.remove(from.getNode(true)));
-      } else if (forward && CaretUtils.isBeforeContentEditableFalse(from)) {
-        return Option.some(DeleteAction.remove(from.getNode()));
-      } else {
-        return getContentEditableAction(rootNode, forward, from);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        format = format[0];
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return {
-      read: read
-    };
-  }
-);
-
-/**
- * Bidi.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-define(
-  'tinymce.core.text.Bidi',
-  [
-  ],
-  function () {
-    var strongRtl = /[\u0591-\u07FF\uFB1D-\uFDFF\uFE70-\uFEFC]/;
-
-    var hasStrongRtl = function (text) {
-      return strongRtl.test(text);
-    };
-
-    return {
-      hasStrongRtl: hasStrongRtl
-    };
-  }
-);
-/**
- * InlineUtils.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-define(
-  'tinymce.core.keyboard.InlineUtils',
-  [
-    'ephox.katamari.api.Arr',
-    'ephox.katamari.api.Fun',
-    'ephox.katamari.api.Option',
-    'ephox.katamari.api.Options',
-    'tinymce.core.caret.CaretContainer',
-    'tinymce.core.caret.CaretFinder',
-    'tinymce.core.caret.CaretPosition',
-    'tinymce.core.caret.CaretUtils',
-    'tinymce.core.caret.CaretWalker',
-    'tinymce.core.dom.DOMUtils',
-    'tinymce.core.dom.NodeType',
-    'tinymce.core.text.Bidi'
-  ],
-  function (Arr, Fun, Option, Options, CaretContainer, CaretFinder, CaretPosition, CaretUtils, CaretWalker, DOMUtils, NodeType, Bidi) {
-    var isInlineTarget = function (elm) {
-      return DOMUtils.DOM.is(elm, 'a[href],code');
-    };
-
-    var isRtl = function (element) {
-      return DOMUtils.DOM.getStyle(element, 'direction', true) === 'rtl' || Bidi.hasStrongRtl(element.textContent);
-    };
-
-    var findInlineParents = function (rootNode, pos) {
-      return Arr.filter(DOMUtils.DOM.getParents(pos.container(), '*', rootNode), isInlineTarget);
-    };
-
-    var findInline = function (rootNode, pos) {
-      var parents = findInlineParents(rootNode, pos);
-      return Option.from(parents[0]);
-    };
-
-    var findRootInline = function (rootNode, pos) {
-      var parents = findInlineParents(rootNode, pos);
-      return Option.from(parents[parents.length - 1]);
-    };
-
-    var hasSameParentBlock = function (rootNode, node1, node2) {
-      var block1 = CaretUtils.getParentBlock(node1, rootNode);
-      var block2 = CaretUtils.getParentBlock(node2, rootNode);
-      return block1 && block1 === block2;
-    };
-
-    var isInInline = function (rootNode, pos) {
-      return pos ? findRootInline(rootNode, pos).isSome() : false;
-    };
-
-    var isAtInlineEndPoint = function (rootNode, pos) {
-      return findRootInline(rootNode, pos).map(function (inline) {
-        return findCaretPosition(inline, false, pos).isNone() || findCaretPosition(inline, true, pos).isNone();
-      }).getOr(false);
-    };
-
-    var isAtZwsp = function (pos) {
-      return CaretContainer.isBeforeInline(pos) || CaretContainer.isAfterInline(pos);
-    };
-
-    var findCaretPositionIn = function (node, forward) {
-      return CaretFinder.positionIn(forward, node);
-    };
-
-    var findCaretPosition = function (rootNode, forward, from) {
-      return CaretFinder.fromPosition(forward, rootNode, from);
-    };
-
-    var normalizePosition = function (forward, pos) {
-      var container = pos.container(), offset = pos.offset();
-
-      if (forward) {
-        if (CaretContainer.isCaretContainerInline(container)) {
-          if (NodeType.isText(container.nextSibling)) {
-            return new CaretPosition(container.nextSibling, 0);
-          } else {
-            return CaretPosition.after(container);
-          }
-        } else {
-          return CaretContainer.isBeforeInline(pos) ? new CaretPosition(container, offset + 1) : pos;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Format specific preview override
+      // TODO: This should probably be further reduced by the previewStyles option
+      if ('preview' in format) {
+        previewStyles = format.preview;
+        if (previewStyles === false) {
+          return '';
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      } else {
-        if (CaretContainer.isCaretContainerInline(container)) {
-          if (NodeType.isText(container.previousSibling)) {
-            return new CaretPosition(container.previousSibling, container.previousSibling.data.length);
-          } else {
-            return CaretPosition.before(container);
-          }
-        } else {
-          return CaretContainer.isAfterInline(pos) ? new CaretPosition(container, offset - 1) : pos;
-        }
</del><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var normalizeForwards = Fun.curry(normalizePosition, true);
-    var normalizeBackwards = Fun.curry(normalizePosition, false);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      name = format.block || format.inline || 'span';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return {
-      isInlineTarget: isInlineTarget,
-      findInline: findInline,
-      findRootInline: findRootInline,
-      isInInline: isInInline,
-      isRtl: isRtl,
-      isAtInlineEndPoint: isAtInlineEndPoint,
-      isAtZwsp: isAtZwsp,
-      findCaretPositionIn: findCaretPositionIn,
-      findCaretPosition: findCaretPosition,
-      normalizePosition: normalizePosition,
-      normalizeForwards: normalizeForwards,
-      normalizeBackwards: normalizeBackwards,
-      hasSameParentBlock: hasSameParentBlock
-    };
-  }
-);
-/**
- * DeleteElement.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-define(
-  'tinymce.core.delete.DeleteElement',
-  [
-    'ephox.katamari.api.Fun',
-    'ephox.katamari.api.Option',
-    'ephox.katamari.api.Options',
-    'ephox.sugar.api.dom.Insert',
-    'ephox.sugar.api.dom.Remove',
-    'ephox.sugar.api.node.Element',
-    'ephox.sugar.api.node.Node',
-    'ephox.sugar.api.search.PredicateFind',
-    'ephox.sugar.api.search.Traverse',
-    'tinymce.core.caret.CaretCandidate',
-    'tinymce.core.caret.CaretPosition',
-    'tinymce.core.dom.Empty',
-    'tinymce.core.dom.NodeType',
-    'tinymce.core.keyboard.InlineUtils'
-  ],
-  function (Fun, Option, Options, Insert, Remove, Element, Node, PredicateFind, Traverse, CaretCandidate, CaretPosition, Empty, NodeType, InlineUtils) {
-    var needsReposition = function (pos, elm) {
-      var container = pos.container();
-      var offset = pos.offset();
-      return CaretPosition.isTextPosition(pos) === false && container === elm.parentNode && offset > CaretPosition.before(elm).offset();
-    };
-
-    var reposition = function (elm, pos) {
-      return needsReposition(pos, elm) ? new CaretPosition(pos.container(), pos.offset() - 1) : pos;
-    };
-
-    var beforeOrStartOf = function (node) {
-      return NodeType.isText(node) ? new CaretPosition(node, 0) : CaretPosition.before(node);
-    };
-
-    var afterOrEndOf = function (node) {
-      return NodeType.isText(node) ? new CaretPosition(node, node.data.length) : CaretPosition.after(node);
-    };
-
-    var getPreviousSiblingCaretPosition = function (elm) {
-      if (CaretCandidate.isCaretCandidate(elm.previousSibling)) {
-        return Option.some(afterOrEndOf(elm.previousSibling));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      items = parseSelector(format.selector);
+      if (items.length) {
+        if (!items[0].name) { // e.g. something like ul > .someClass was provided
+          items[0].name = name;
+        }
+        name = format.selector;
+        previewFrag = parsedSelectorToHtml(items, editor);
</ins><span class="cx" style="display: block; padding: 0 10px">       } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return elm.previousSibling ? InlineUtils.findCaretPositionIn(elm.previousSibling, false) : Option.none();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        previewFrag = parsedSelectorToHtml([name], editor);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var getNextSiblingCaretPosition = function (elm) {
-      if (CaretCandidate.isCaretCandidate(elm.nextSibling)) {
-        return Option.some(beforeOrStartOf(elm.nextSibling));
-      } else {
-        return elm.nextSibling ? InlineUtils.findCaretPositionIn(elm.nextSibling, true) : Option.none();
-      }
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      previewElm = dom.select(name, previewFrag)[0] || previewFrag.firstChild;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var findCaretPositionBackwardsFromElm = function (rootElement, elm) {
-      var startPosition = CaretPosition.before(elm.previousSibling ? elm.previousSibling : elm.parentNode);
-      return InlineUtils.findCaretPosition(rootElement, false, startPosition).fold(
-        function () {
-          return InlineUtils.findCaretPosition(rootElement, true, CaretPosition.after(elm));
-        },
-        Option.some
-      );
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Add format styles to preview element
+      each(format.styles, function (value, name) {
+        value = removeVars(value);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var findCaretPositionForwardsFromElm = function (rootElement, elm) {
-      return InlineUtils.findCaretPosition(rootElement, true, CaretPosition.after(elm)).fold(
-        function () {
-          return InlineUtils.findCaretPosition(rootElement, false, CaretPosition.before(elm));
-        },
-        Option.some
-      );
-    };
-
-    var findCaretPositionBackwards = function (rootElement, elm) {
-      return getPreviousSiblingCaretPosition(elm).orThunk(function () {
-        return getNextSiblingCaretPosition(elm);
-      }).orThunk(function () {
-        return findCaretPositionBackwardsFromElm(rootElement, elm);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (value) {
+          dom.setStyle(previewElm, name, value);
+        }
</ins><span class="cx" style="display: block; padding: 0 10px">       });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var findCaretPositionForward = function (rootElement, elm) {
-      return getNextSiblingCaretPosition(elm).orThunk(function () {
-        return getPreviousSiblingCaretPosition(elm);
-      }).orThunk(function () {
-        return findCaretPositionForwardsFromElm(rootElement, elm);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Add attributes to preview element
+      each(format.attributes, function (value, name) {
+        value = removeVars(value);
+
+        if (value) {
+          dom.setAttrib(previewElm, name, value);
+        }
</ins><span class="cx" style="display: block; padding: 0 10px">       });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var findCaretPosition = function (forward, rootElement, elm) {
-      return forward ? findCaretPositionForward(rootElement, elm) : findCaretPositionBackwards(rootElement, elm);
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Add classes to preview element
+      each(format.classes, function (value) {
+        value = removeVars(value);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var findCaretPosOutsideElmAfterDelete = function (forward, rootElement, elm) {
-      return findCaretPosition(forward, rootElement, elm).map(Fun.curry(reposition, elm));
-    };
-
-    var setSelection = function (editor, forward, pos) {
-      pos.fold(
-        function () {
-          editor.focus();
-        },
-        function (pos) {
-          editor.selection.setRng(pos.toRange(), forward);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (!dom.hasClass(previewElm, value)) {
+          dom.addClass(previewElm, value);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      );
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var eqRawNode = function (rawNode) {
-      return function (elm) {
-        return elm.dom() === rawNode;
-      };
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      editor.fire('PreviewFormats');
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var isBlock = function (editor, elm) {
-      return elm && editor.schema.getBlockElements().hasOwnProperty(Node.name(elm));
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Add the previewElm outside the visual area
+      dom.setStyles(previewFrag, { position: 'absolute', left: -0xFFFF });
+      editor.getBody().appendChild(previewFrag);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var paddEmptyBlock = function (elm) {
-      if (Empty.isEmpty(elm)) {
-        var br = Element.fromHtml('<br data-mce-bogus="1">');
-        Remove.empty(elm);
-        Insert.append(elm, br);
-        return Option.some(CaretPosition.before(br.dom()));
-      } else {
-        return Option.none();
-      }
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Get parent container font size so we can compute px values out of em/% for older IE:s
+      parentFontSize = dom.getStyle(editor.getBody(), 'fontSize', true);
+      parentFontSize = /px$/.test(parentFontSize) ? parseInt(parentFontSize, 10) : 0;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // When deleting an element between two text nodes IE 11 doesn't automatically merge the adjacent text nodes
-    var deleteNormalized = function (elm, afterDeletePosOpt) {
-      return Options.liftN([Traverse.prevSibling(elm), Traverse.nextSibling(elm), afterDeletePosOpt], function (prev, next, afterDeletePos) {
-        var offset, prevNode = prev.dom(), nextNode = next.dom();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      each(previewStyles.split(' '), function (name) {
+        var value = dom.getStyle(previewElm, name, true);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (NodeType.isText(prevNode) && NodeType.isText(nextNode)) {
-          offset = prevNode.data.length;
-          prevNode.appendData(nextNode.data);
-          Remove.remove(next);
-          Remove.remove(elm);
-          if (afterDeletePos.container() === nextNode) {
-            return new CaretPosition(prevNode, offset);
-          } else {
-            return afterDeletePos;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // If background is transparent then check if the body has a background color we can use
+        if (name === 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) {
+          value = dom.getStyle(editor.getBody(), name, true);
+
+          // Ignore white since it's the default color, not the nicest fix
+          // TODO: Fix this by detecting runtime style
+          if (dom.toHex(value).toLowerCase() === '#ffffff') {
+            return;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        } else {
-          Remove.remove(elm);
-          return afterDeletePos;
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      }).orThunk(function () {
-        Remove.remove(elm);
-        return afterDeletePosOpt;
-      });
-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var deleteElement = function (editor, forward, elm) {
-      var afterDeletePos = findCaretPosOutsideElmAfterDelete(forward, editor.getBody(), elm.dom());
-      var parentBlock = PredicateFind.ancestor(elm, Fun.curry(isBlock, editor), eqRawNode(editor.getBody()));
-      var normalizedAfterDeletePos = deleteNormalized(elm, afterDeletePos);
-
-      parentBlock.bind(paddEmptyBlock).fold(
-        function () {
-          setSelection(editor, forward, normalizedAfterDeletePos);
-        },
-        function (paddPos) {
-          setSelection(editor, forward, Option.some(paddPos));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (name === 'color') {
+          // Ignore black since it's the default color, not the nicest fix
+          // TODO: Fix this by detecting runtime style
+          if (dom.toHex(value).toLowerCase() === '#000000') {
+            return;
+          }
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      );
-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return {
-      deleteElement: deleteElement
-    };
-  }
-);
-/**
- * CefDelete.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Old IE won't calculate the font size so we need to do that manually
+        if (name === 'font-size') {
+          if (/em|%$/.test(value)) {
+            if (parentFontSize === 0) {
+              return;
+            }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-define(
-  'tinymce.core.delete.CefDelete',
-  [
-    'ephox.sugar.api.node.Element',
-    'tinymce.core.caret.CaretPosition',
-    'tinymce.core.caret.CaretUtils',
-    'tinymce.core.delete.BlockBoundary',
-    'tinymce.core.delete.CefDeleteAction',
-    'tinymce.core.delete.DeleteElement',
-    'tinymce.core.delete.MergeBlocks',
-    'tinymce.core.dom.NodeType'
-  ],
-  function (Element, CaretPosition, CaretUtils, BlockBoundary, CefDeleteAction, DeleteElement, MergeBlocks, NodeType) {
-    var deleteElement = function (editor, forward) {
-      return function (element) {
-        DeleteElement.deleteElement(editor, forward, Element.fromDom(element));
-        return true;
-      };
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // Convert font size from em/% to px
+            value = parseFloat(value, 10) / (/%$/.test(value) ? 100 : 1);
+            value = (value * parentFontSize) + 'px';
+          }
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var moveToElement = function (editor, forward) {
-      return function (element) {
-        var pos = forward ? CaretPosition.before(element) : CaretPosition.after(element);
-        editor.selection.setRng(pos.toRange());
-        return true;
-      };
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (name === "border" && value) {
+          previewCss += 'padding:0 2px;';
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var moveToPosition = function (editor) {
-      return function (pos) {
-        editor.selection.setRng(pos.toRange());
-        return true;
-      };
-    };
-
-    var backspaceDeleteCaret = function (editor, forward) {
-      var result = CefDeleteAction.read(editor.getBody(), forward, editor.selection.getRng()).map(function (deleteAction) {
-        return deleteAction.fold(
-          deleteElement(editor, forward),
-          moveToElement(editor, forward),
-          moveToPosition(editor)
-        );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        previewCss += name + ':' + value + ';';
</ins><span class="cx" style="display: block; padding: 0 10px">       });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return result.getOr(false);
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      editor.fire('AfterPreviewFormats');
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var backspaceDeleteRange = function (editor, forward) {
-      var selectedElement = editor.selection.getNode();
-      if (NodeType.isContentEditableFalse(selectedElement)) {
-        DeleteElement.deleteElement(editor, forward, Element.fromDom(editor.selection.getNode()));
-        return true;
-      } else {
-        return false;
-      }
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      //previewCss += 'line-height:normal';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var getContentEditableRoot = function (root, node) {
-      while (node && node !== root) {
-        if (NodeType.isContentEditableTrue(node) || NodeType.isContentEditableFalse(node)) {
-          return node;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      dom.remove(previewFrag);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        node = node.parentNode;
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return previewCss;
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return null;
-    };
-
-    var paddEmptyElement = function (editor) {
-      var br, ceRoot = getContentEditableRoot(editor.getBody(), editor.selection.getNode());
-
-      if (NodeType.isContentEditableTrue(ceRoot) && editor.dom.isBlock(ceRoot) && editor.dom.isEmpty(ceRoot)) {
-        br = editor.dom.create('br', { "data-mce-bogus": "1" });
-        editor.dom.setHTML(ceRoot, '');
-        ceRoot.appendChild(br);
-        editor.selection.setRng(CaretPosition.before(br).toRange());
-      }
-
-      return true;
-    };
-
-    var backspaceDelete = function (editor, forward) {
-      if (editor.selection.isCollapsed()) {
-        return backspaceDeleteCaret(editor, forward);
-      } else {
-        return backspaceDeleteRange(editor, forward);
-      }
-    };
-
</del><span class="cx" style="display: block; padding: 0 10px">     return {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      backspaceDelete: backspaceDelete,
-      paddEmptyElement: paddEmptyElement
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      getCssText: getCssText,
+      parseSelector: parseSelector,
+      selectorToHtml: selectorToHtml
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * CaretContainerInline.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * ToggleFormat.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -27740,88 +20482,31 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.caret.CaretContainerInline',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.fmt.ToggleFormat',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'ephox.katamari.api.Fun',
-    'tinymce.core.dom.NodeType',
-    'tinymce.core.text.Zwsp'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.fmt.ApplyFormat',
+    'tinymce.core.fmt.MatchFormat',
+    'tinymce.core.fmt.RemoveFormat'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Fun, NodeType, Zwsp) {
-    var isText = NodeType.isText;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (ApplyFormat, MatchFormat, RemoveFormat) {
+    var toggle = function (editor, formats, name, vars, node) {
+      var fmt = formats.get(name);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var startsWithCaretContainer = function (node) {
-      return isText(node) && node.data[0] === Zwsp.ZWSP;
-    };
-
-    var endsWithCaretContainer = function (node) {
-      return isText(node) && node.data[node.data.length - 1] === Zwsp.ZWSP;
-    };
-
-    var createZwsp = function (node) {
-      return node.ownerDocument.createTextNode(Zwsp.ZWSP);
-    };
-
-    var insertBefore = function (node) {
-      if (isText(node.previousSibling)) {
-        if (endsWithCaretContainer(node.previousSibling)) {
-          return node.previousSibling;
-        } else {
-          node.previousSibling.appendData(Zwsp.ZWSP);
-          return node.previousSibling;
-        }
-      } else if (isText(node)) {
-        if (startsWithCaretContainer(node)) {
-          return node;
-        } else {
-          node.insertData(0, Zwsp.ZWSP);
-          return node;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (MatchFormat.match(editor, name, vars, node) && (!('toggle' in fmt[0]) || fmt[0].toggle)) {
+        RemoveFormat.remove(editor, name, vars, node);
</ins><span class="cx" style="display: block; padding: 0 10px">       } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var newNode = createZwsp(node);
-        node.parentNode.insertBefore(newNode, node);
-        return newNode;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        ApplyFormat.applyFormat(editor, name, vars, node);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var insertAfter = function (node) {
-      if (isText(node.nextSibling)) {
-        if (startsWithCaretContainer(node.nextSibling)) {
-          return node.nextSibling;
-        } else {
-          node.nextSibling.insertData(0, Zwsp.ZWSP);
-          return node.nextSibling;
-        }
-      } else if (isText(node)) {
-        if (endsWithCaretContainer(node)) {
-          return node;
-        } else {
-          node.appendData(Zwsp.ZWSP);
-          return node;
-        }
-      } else {
-        var newNode = createZwsp(node);
-        if (node.nextSibling) {
-          node.parentNode.insertBefore(newNode, node.nextSibling);
-        } else {
-          node.parentNode.appendChild(newNode);
-        }
-        return newNode;
-      }
-    };
-
-    var insertInline = function (before, node) {
-      return before ? insertBefore(node) : insertAfter(node);
-    };
-
</del><span class="cx" style="display: block; padding: 0 10px">     return {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      insertInline: insertInline,
-      insertInlineBefore: Fun.curry(insertInline, true),
-      insertInlineAfter: Fun.curry(insertInline, false)
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      toggle: toggle
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * CaretContainerRemove.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * FormatShortcuts.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -27831,191 +20516,34 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.caret.CaretContainerRemove',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.keyboard.FormatShortcuts',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'ephox.katamari.api.Arr',
-    'tinymce.core.caret.CaretContainer',
-    'tinymce.core.caret.CaretPosition',
-    'tinymce.core.dom.NodeType',
-    'tinymce.core.text.Zwsp',
-    'tinymce.core.util.Tools'
</del><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Arr, CaretContainer, CaretPosition, NodeType, Zwsp, Tools) {
-    var isElement = NodeType.isElement;
-    var isText = NodeType.isText;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function () {
+    var setup = function (editor) {
+      // Add some inline shortcuts
+      editor.addShortcut('meta+b', '', 'Bold');
+      editor.addShortcut('meta+i', '', 'Italic');
+      editor.addShortcut('meta+u', '', 'Underline');
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var removeNode = function (node) {
-      var parentNode = node.parentNode;
-      if (parentNode) {
-        parentNode.removeChild(node);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // BlockFormat shortcuts keys
+      for (var i = 1; i <= 6; i++) {
+        editor.addShortcut('access+' + i, '', ['FormatBlock', false, 'h' + i]);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var getNodeValue = function (node) {
-      try {
-        return node.nodeValue;
-      } catch (ex) {
-        // IE sometimes produces "Invalid argument" on nodes
-        return "";
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      editor.addShortcut('access+7', '', ['FormatBlock', false, 'p']);
+      editor.addShortcut('access+8', '', ['FormatBlock', false, 'div']);
+      editor.addShortcut('access+9', '', ['FormatBlock', false, 'address']);
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var setNodeValue = function (node, text) {
-      if (text.length === 0) {
-        removeNode(node);
-      } else {
-        node.nodeValue = text;
-      }
-    };
-
-    var trimCount = function (text) {
-      var trimmedText = Zwsp.trim(text);
-      return { count: text.length - trimmedText.length, text: trimmedText };
-    };
-
-    var removeUnchanged = function (caretContainer, pos) {
-      remove(caretContainer);
-      return pos;
-    };
-
-    var removeTextAndReposition = function (caretContainer, pos) {
-      var before = trimCount(caretContainer.data.substr(0, pos.offset()));
-      var after = trimCount(caretContainer.data.substr(pos.offset()));
-      var text = before.text + after.text;
-
-      if (text.length > 0) {
-        setNodeValue(caretContainer, text);
-        return new CaretPosition(caretContainer, pos.offset() - before.count);
-      } else {
-        return pos;
-      }
-    };
-
-    var removeElementAndReposition = function (caretContainer, pos) {
-      var parentNode = pos.container();
-      var newPosition = Arr.indexOf(parentNode.childNodes, caretContainer).map(function (index) {
-        return index < pos.offset() ? new CaretPosition(parentNode, pos.offset() - 1) : pos;
-      }).getOr(pos);
-      remove(caretContainer);
-      return newPosition;
-    };
-
-    var removeTextCaretContainer = function (caretContainer, pos) {
-      return pos.container() === caretContainer ? removeTextAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
-    };
-
-    var removeElementCaretContainer = function (caretContainer, pos) {
-      return pos.container() === caretContainer.parentNode ? removeElementAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
-    };
-
-    var removeAndReposition = function (container, pos) {
-      return CaretPosition.isTextPosition(pos) ? removeTextCaretContainer(container, pos) : removeElementCaretContainer(container, pos);
-    };
-
-    var remove = function (caretContainerNode) {
-      if (isElement(caretContainerNode) && CaretContainer.isCaretContainer(caretContainerNode)) {
-        if (CaretContainer.hasContent(caretContainerNode)) {
-          caretContainerNode.removeAttribute('data-mce-caret');
-        } else {
-          removeNode(caretContainerNode);
-        }
-      }
-
-      if (isText(caretContainerNode)) {
-        var text = Zwsp.trim(getNodeValue(caretContainerNode));
-        setNodeValue(caretContainerNode, text);
-      }
-    };
-
</del><span class="cx" style="display: block; padding: 0 10px">     return {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      removeAndReposition: removeAndReposition,
-      remove: remove
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      setup: setup
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * BoundaryCaret.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-define(
-  'tinymce.core.keyboard.BoundaryCaret',
-  [
-    'ephox.katamari.api.Option',
-    'tinymce.core.caret.CaretContainer',
-    'tinymce.core.caret.CaretContainerInline',
-    'tinymce.core.caret.CaretContainerRemove',
-    'tinymce.core.caret.CaretPosition',
-    'tinymce.core.dom.NodeType',
-    'tinymce.core.keyboard.InlineUtils'
-  ],
-  function (Option, CaretContainer, CaretContainerInline, CaretContainerRemove, CaretPosition, NodeType, InlineUtils) {
-    var insertInlinePos = function (pos, before) {
-      if (NodeType.isText(pos.container())) {
-        return CaretContainerInline.insertInline(before, pos.container());
-      } else {
-        return CaretContainerInline.insertInline(before, pos.getNode());
-      }
-    };
-
-    var isPosCaretContainer = function (pos, caret) {
-      var caretNode = caret.get();
-      return caretNode && pos.container() === caretNode && CaretContainer.isCaretContainerInline(caretNode);
-    };
-
-    var renderCaret = function (caret, location) {
-      return location.fold(
-        function (element) { // Before
-          CaretContainerRemove.remove(caret.get());
-          var text = CaretContainerInline.insertInlineBefore(element);
-          caret.set(text);
-          return Option.some(new CaretPosition(text, text.length - 1));
-        },
-        function (element) { // Start
-          return InlineUtils.findCaretPositionIn(element, true).map(function (pos) {
-            if (!isPosCaretContainer(pos, caret)) {
-              CaretContainerRemove.remove(caret.get());
-              var text = insertInlinePos(pos, true);
-              caret.set(text);
-              return new CaretPosition(text, 1);
-            } else {
-              return new CaretPosition(caret.get(), 1);
-            }
-          });
-        },
-        function (element) { // End
-          return InlineUtils.findCaretPositionIn(element, false).map(function (pos) {
-            if (!isPosCaretContainer(pos, caret)) {
-              CaretContainerRemove.remove(caret.get());
-              var text = insertInlinePos(pos, false);
-              caret.set(text);
-              return new CaretPosition(text, text.length - 1);
-            } else {
-              return new CaretPosition(caret.get(), caret.get().length - 1);
-            }
-          });
-        },
-        function (element) { // After
-          CaretContainerRemove.remove(caret.get());
-          var text = CaretContainerInline.insertInlineAfter(element);
-          caret.set(text);
-          return Option.some(new CaretPosition(text, 1));
-        }
-      );
-    };
-
-    return {
-      renderCaret: renderCaret
-    };
-  }
-);
</del><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * LazyEvaluator.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Formatter.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -28024,1271 +20552,564 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Contributing: http://www.tinymce.com/contributing
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-define(
-  'tinymce.core.util.LazyEvaluator',
-  [
-    'ephox.katamari.api.Option'
-  ],
-  function (Option) {
-    var evaluateUntil = function (fns, args) {
-      for (var i = 0; i < fns.length; i++) {
-        var result = fns[i].apply(null, args);
-        if (result.isSome()) {
-          return result;
-        }
-      }
-
-      return Option.none();
-    };
-
-    return {
-      evaluateUntil: evaluateUntil
-    };
-  }
-);
</del><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * BoundaryLocation.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Text formatter engine class. This class is used to apply formats like bold, italic, font size
+ * etc to the current selection or specific nodes. This engine was built to replace the browser's
+ * default formatting logic for execCommand due to its inconsistent and buggy behavior.
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @class tinymce.Formatter
+ * @example
+ *  tinymce.activeEditor.formatter.register('mycustomformat', {
+ *    inline: 'span',
+ *    styles: {color: '#ff0000'}
+ *  });
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ *  tinymce.activeEditor.formatter.apply('mycustomformat');
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.keyboard.BoundaryLocation',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.api.Formatter',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'ephox.katamari.api.Adt',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.katamari.api.Cell',
</ins><span class="cx" style="display: block; padding: 0 10px">     'ephox.katamari.api.Fun',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'ephox.katamari.api.Option',
-    'ephox.katamari.api.Options',
-    'tinymce.core.caret.CaretContainer',
-    'tinymce.core.caret.CaretPosition',
-    'tinymce.core.caret.CaretUtils',
-    'tinymce.core.dom.NodeType',
-    'tinymce.core.keyboard.InlineUtils',
-    'tinymce.core.util.LazyEvaluator'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.fmt.ApplyFormat',
+    'tinymce.core.fmt.FormatChanged',
+    'tinymce.core.fmt.FormatRegistry',
+    'tinymce.core.fmt.MatchFormat',
+    'tinymce.core.fmt.Preview',
+    'tinymce.core.fmt.RemoveFormat',
+    'tinymce.core.fmt.ToggleFormat',
+    'tinymce.core.keyboard.FormatShortcuts'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Adt, Fun, Option, Options, CaretContainer, CaretPosition, CaretUtils, NodeType, InlineUtils, LazyEvaluator) {
-    var Location = Adt.generate([
-      { before: [ 'element' ] },
-      { start: [ 'element' ] },
-      { end: [ 'element' ] },
-      { after: [ 'element' ] }
-    ]);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Cell, Fun, ApplyFormat, FormatChanged, FormatRegistry, MatchFormat, Preview, RemoveFormat, ToggleFormat, FormatShortcuts) {
+    /**
+     * Constructs a new formatter instance.
+     *
+     * @constructor Formatter
+     * @param {tinymce.Editor} ed Editor instance to construct the formatter engine to.
+     */
+    return function (editor) {
+      var formats = FormatRegistry(editor);
+      var formatChangeState = Cell(null);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var rescope = function (rootNode, node) {
-      var parentBlock = CaretUtils.getParentBlock(node, rootNode);
-      return parentBlock ? parentBlock : rootNode;
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      FormatShortcuts.setup(editor);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var before = function (rootNode, pos) {
-      var nPos = InlineUtils.normalizeForwards(pos);
-      var scope = rescope(rootNode, nPos.container());
-      return InlineUtils.findRootInline(scope, nPos).fold(
-        function () {
-          return InlineUtils.findCaretPosition(scope, true, nPos)
-            .bind(Fun.curry(InlineUtils.findRootInline, scope))
-            .map(function (inline) {
-              return Location.before(inline);
-            });
-        },
-        Option.none
-      );
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return {
+        /**
+         * Returns the format by name or all formats if no name is specified.
+         *
+         * @method get
+         * @param {String} name Optional name to retrieve by.
+         * @return {Array/Object} Array/Object with all registered formats or a specific format.
+         */
+        get: formats.get,
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var start = function (rootNode, pos) {
-      var nPos = InlineUtils.normalizeBackwards(pos);
-      return InlineUtils.findRootInline(rootNode, nPos).bind(function (inline) {
-        var prevPos = InlineUtils.findCaretPosition(inline, false, nPos);
-        return prevPos.isNone() ? Option.some(Location.start(inline)) : Option.none();
-      });
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+         * Registers a specific format by name.
+         *
+         * @method register
+         * @param {Object/String} name Name of the format for example "bold".
+         * @param {Object/Array} format Optional format object or array of format variants
+         * can only be omitted if the first arg is an object.
+         */
+        register: formats.register,
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var end = function (rootNode, pos) {
-      var nPos = InlineUtils.normalizeForwards(pos);
-      return InlineUtils.findRootInline(rootNode, nPos).bind(function (inline) {
-        var nextPos = InlineUtils.findCaretPosition(inline, true, nPos);
-        return nextPos.isNone() ? Option.some(Location.end(inline)) : Option.none();
-      });
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+         * Unregister a specific format by name.
+         *
+         * @method unregister
+         * @param {String} name Name of the format for example "bold".
+         */
+        unregister: formats.unregister,
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var after = function (rootNode, pos) {
-      var nPos = InlineUtils.normalizeBackwards(pos);
-      var scope = rescope(rootNode, nPos.container());
-      return InlineUtils.findRootInline(scope, nPos).fold(
-        function () {
-          return InlineUtils.findCaretPosition(scope, false, nPos)
-            .bind(Fun.curry(InlineUtils.findRootInline, scope))
-            .map(function (inline) {
-              return Location.after(inline);
-            });
-        },
-        Option.none
-      );
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+         * Applies the specified format to the current selection or specified node.
+         *
+         * @method apply
+         * @param {String} name Name of format to apply.
+         * @param {Object} vars Optional list of variables to replace within format before applying it.
+         * @param {Node} node Optional node to apply the format to defaults to current selection.
+         */
+        apply: Fun.curry(ApplyFormat.applyFormat, editor),
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var isValidLocation = function (location) {
-      return InlineUtils.isRtl(getElement(location)) === false;
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+         * Removes the specified format from the current selection or specified node.
+         *
+         * @method remove
+         * @param {String} name Name of format to remove.
+         * @param {Object} vars Optional list of variables to replace within format before removing it.
+         * @param {Node/Range} node Optional node or DOM range to remove the format from defaults to current selection.
+         */
+        remove: Fun.curry(RemoveFormat.remove, editor),
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var readLocation = function (rootNode, pos) {
-      var location = LazyEvaluator.evaluateUntil([
-        before,
-        start,
-        end,
-        after
-      ], [rootNode, pos]);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+         * Toggles the specified format on/off.
+         *
+         * @method toggle
+         * @param {String} name Name of format to apply/remove.
+         * @param {Object} vars Optional list of variables to replace within format before applying/removing it.
+         * @param {Node} node Optional node to apply the format to or remove from. Defaults to current selection.
+         */
+        toggle: Fun.curry(ToggleFormat.toggle, editor, formats),
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return location.filter(isValidLocation);
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+         * Matches the current selection or specified node against the specified format name.
+         *
+         * @method match
+         * @param {String} name Name of format to match.
+         * @param {Object} vars Optional list of variables to replace before checking it.
+         * @param {Node} node Optional node to check.
+         * @return {boolean} true/false if the specified selection/node matches the format.
+         */
+        match: Fun.curry(MatchFormat.match, editor),
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var getElement = function (location) {
-      return location.fold(
-        Fun.identity, // Before
-        Fun.identity, // Start
-        Fun.identity, // End
-        Fun.identity  // After
-      );
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+         * Matches the current selection against the array of formats and returns a new array with matching formats.
+         *
+         * @method matchAll
+         * @param {Array} names Name of format to match.
+         * @param {Object} vars Optional list of variables to replace before checking it.
+         * @return {Array} Array with matched formats.
+         */
+        matchAll: Fun.curry(MatchFormat.matchAll, editor),
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var getName = function (location) {
-      return location.fold(
-        Fun.constant('before'), // Before
-        Fun.constant('start'),  // Start
-        Fun.constant('end'),    // End
-        Fun.constant('after')   // After
-      );
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+         * Return true/false if the specified node has the specified format.
+         *
+         * @method matchNode
+         * @param {Node} node Node to check the format on.
+         * @param {String} name Format name to check.
+         * @param {Object} vars Optional list of variables to replace before checking it.
+         * @param {Boolean} similar Match format that has similar properties.
+         * @return {Object} Returns the format object it matches or undefined if it doesn't match.
+         */
+        matchNode: Fun.curry(MatchFormat.matchNode, editor),
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var outside = function (location) {
-      return location.fold(
-        Location.before, // Before
-        Location.before, // Start
-        Location.after,  // End
-        Location.after   // After
-      );
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+         * Returns true/false if the specified format can be applied to the current selection or not. It
+         * will currently only check the state for selector formats, it returns true on all other format types.
+         *
+         * @method canApply
+         * @param {String} name Name of format to check.
+         * @return {boolean} true/false if the specified format can be applied to the current selection/node.
+         */
+        canApply: Fun.curry(MatchFormat.canApply, editor),
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var inside = function (location) {
-      return location.fold(
-        Location.start, // Before
-        Location.start, // Start
-        Location.end,   // End
-        Location.end    // After
-      );
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+         * Executes the specified callback when the current selection matches the formats or not.
+         *
+         * @method formatChanged
+         * @param {String} formats Comma separated list of formats to check for.
+         * @param {function} callback Callback with state and args when the format is changed/toggled on/off.
+         * @param {Boolean} similar True/false state if the match should handle similar or exact formats.
+         */
+        formatChanged: Fun.curry(FormatChanged.formatChanged, editor, formatChangeState),
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var isEq = function (location1, location2) {
-      return getName(location1) === getName(location2) && getElement(location1) === getElement(location2);
-    };
-
-    var betweenInlines = function (forward, rootNode, from, to, location) {
-      return Options.liftN([
-        InlineUtils.findRootInline(rootNode, from),
-        InlineUtils.findRootInline(rootNode, to)
-      ], function (fromInline, toInline) {
-        if (fromInline !== toInline && InlineUtils.hasSameParentBlock(rootNode, fromInline, toInline)) {
-          // Force after since some browsers normalize and lean left into the closest inline
-          return Location.after(forward ? fromInline : toInline);
-        } else {
-          return location;
-        }
-      }).getOr(location);
-    };
-
-    var skipNoMovement = function (fromLocation, toLocation) {
-      return fromLocation.fold(
-        Fun.constant(true),
-        function (fromLocation) {
-          return !isEq(fromLocation, toLocation);
-        }
-      );
-    };
-
-    var findLocationTraverse = function (forward, rootNode, fromLocation, pos) {
-      var from = InlineUtils.normalizePosition(forward, pos);
-      var to = InlineUtils.findCaretPosition(rootNode, forward, from).map(Fun.curry(InlineUtils.normalizePosition, forward));
-
-      var location = to.fold(
-        function () {
-          return fromLocation.map(outside);
-        },
-        function (to) {
-          return readLocation(rootNode, to)
-            .map(Fun.curry(betweenInlines, forward, rootNode, from, to))
-            .filter(Fun.curry(skipNoMovement, fromLocation));
-        }
-      );
-
-      return location.filter(isValidLocation);
-    };
-
-    var findLocationSimple = function (forward, location) {
-      if (forward) {
-        return location.fold(
-          Fun.compose(Option.some, Location.start), // Before -> Start
-          Option.none,
-          Fun.compose(Option.some, Location.after), // End -> After
-          Option.none
-        );
-      } else {
-        return location.fold(
-          Option.none,
-          Fun.compose(Option.some, Location.before), // Before <- Start
-          Option.none,
-          Fun.compose(Option.some, Location.end) // End <- After
-        );
-      }
-    };
-
-    var findLocation = function (forward, rootNode, pos) {
-      var from = InlineUtils.normalizePosition(forward, pos);
-      var fromLocation = readLocation(rootNode, from);
-
-      return readLocation(rootNode, from).bind(Fun.curry(findLocationSimple, forward)).orThunk(function () {
-        return findLocationTraverse(forward, rootNode, fromLocation, pos);
-      });
-    };
-
-    return {
-      readLocation: readLocation,
-      prevLocation: Fun.curry(findLocation, false),
-      nextLocation: Fun.curry(findLocation, true),
-      getElement: getElement,
-      outside: outside,
-      inside: inside
-    };
-  }
-);
-define(
-  'ephox.katamari.api.Cell',
-
-  [
-  ],
-
-  function () {
-    var Cell = function (initial) {
-      var value = initial;
-
-      var get = function () {
-        return value;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+         * Returns a preview css text for the specified format.
+         *
+         * @method getCssText
+         * @param {String/Object} format Format to generate preview css text for.
+         * @return {String} Css text for the specified format.
+         * @example
+         * var cssText1 = editor.formatter.getCssText('bold');
+         * var cssText2 = editor.formatter.getCssText({inline: 'b'});
+         */
+        getCssText: Fun.curry(Preview.getCssText, editor)
</ins><span class="cx" style="display: block; padding: 0 10px">       };
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-      var set = function (v) {
-        value = v;
-      };
-
-      var clone = function () {
-        return Cell(get());
-      };
-
-      return {
-        get: get,
-        set: set,
-        clone: clone
-      };
</del><span class="cx" style="display: block; padding: 0 10px">     };
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-    return Cell;
</del><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * BoundarySelection.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+define(
+  'ephox.sugar.api.properties.Attr',
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-define(
-  'tinymce.core.keyboard.BoundarySelection',
</del><span class="cx" style="display: block; padding: 0 10px">   [
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.katamari.api.Type',
</ins><span class="cx" style="display: block; padding: 0 10px">     'ephox.katamari.api.Arr',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'ephox.katamari.api.Cell',
-    'ephox.katamari.api.Fun',
-    'tinymce.core.caret.CaretContainerRemove',
-    'tinymce.core.caret.CaretPosition',
-    'tinymce.core.keyboard.BoundaryCaret',
-    'tinymce.core.keyboard.BoundaryLocation',
-    'tinymce.core.keyboard.InlineUtils'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.katamari.api.Obj',
+    'ephox.sugar.api.node.Node',
+    'global!Error',
+    'global!console'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Arr, Cell, Fun, CaretContainerRemove, CaretPosition, BoundaryCaret, BoundaryLocation, InlineUtils) {
-    var setCaretPosition = function (editor, pos) {
-      var rng = editor.dom.createRng();
-      rng.setStart(pos.container(), pos.offset());
-      rng.setEnd(pos.container(), pos.offset());
-      editor.selection.setRng(rng);
-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var isFeatureEnabled = function (editor) {
-      return editor.settings.inline_boundaries !== false;
-    };
-
-    var setSelected = function (state, elm) {
-      if (state) {
-        elm.setAttribute('data-mce-selected', '1');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  /*
+   * Direct attribute manipulation has been around since IE8, but
+   * was apparently unstable until IE10.
+   */
+  function (Type, Arr, Obj, Node, Error, console) {
+    var rawSet = function (dom, key, value) {
+      /*
+       * JQuery coerced everything to a string, and silently did nothing on text node/null/undefined.
+       *
+       * We fail on those invalid cases, only allowing numbers and booleans.
+       */
+      if (Type.isString(value) || Type.isBoolean(value) || Type.isNumber(value)) {
+        dom.setAttribute(key, value + '');
</ins><span class="cx" style="display: block; padding: 0 10px">       } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        elm.removeAttribute('data-mce-selected', '1');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        console.error('Invalid call to Attr.set. Key ', key, ':: Value ', value, ':: Element ', dom);
+        throw new Error('Attribute value was not simple');
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var renderCaretLocation = function (editor, caret, location) {
-      return BoundaryCaret.renderCaret(caret, location).map(function (pos) {
-        setCaretPosition(editor, pos);
-        return location;
-      });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var set = function (element, key, value) {
+      rawSet(element.dom(), key, value);
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var findLocation = function (editor, caret, forward) {
-      var rootNode = editor.getBody();
-      var from = CaretPosition.fromRangeStart(editor.selection.getRng());
-      var location = forward ? BoundaryLocation.nextLocation(rootNode, from) : BoundaryLocation.prevLocation(rootNode, from);
-      return location.bind(function (location) {
-        return renderCaretLocation(editor, caret, location);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var setAll = function (element, attrs) {
+      var dom = element.dom();
+      Obj.each(attrs, function (v, k) {
+        rawSet(dom, k, v);
</ins><span class="cx" style="display: block; padding: 0 10px">       });
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var toggleInlines = function (dom, elms) {
-      var selectedInlines = dom.select('a[href][data-mce-selected],code[data-mce-selected]');
-      var targetInlines = Arr.filter(elms, InlineUtils.isInlineTarget);
-      Arr.each(Arr.difference(selectedInlines, targetInlines), Fun.curry(setSelected, false));
-      Arr.each(Arr.difference(targetInlines, selectedInlines), Fun.curry(setSelected, true));
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var get = function (element, key) {
+      var v = element.dom().getAttribute(key);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var safeRemoveCaretContainer = function (editor, caret) {
-      if (editor.selection.isCollapsed() && editor.composing !== true && caret.get()) {
-        var pos = CaretPosition.fromRangeStart(editor.selection.getRng());
-        if (CaretPosition.isTextPosition(pos) && InlineUtils.isAtZwsp(pos) === false) {
-          setCaretPosition(editor, CaretContainerRemove.removeAndReposition(caret.get(), pos));
-          caret.set(null);
-        }
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // undefined is the more appropriate value for JS, and this matches JQuery
+      return v === null ? undefined : v;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var renderInsideInlineCaret = function (editor, caret, elms) {
-      if (editor.selection.isCollapsed()) {
-        var inlines = Arr.filter(elms, InlineUtils.isInlineTarget);
-        Arr.each(inlines, function (inline) {
-          var pos = CaretPosition.fromRangeStart(editor.selection.getRng());
-          BoundaryLocation.readLocation(editor.getBody(), pos).bind(function (location) {
-            return renderCaretLocation(editor, caret, location);
-          });
-        });
-      }
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var has = function (element, key) {
+      var dom = element.dom();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var move = function (editor, caret, forward) {
-      return function () {
-        return isFeatureEnabled(editor) ? findLocation(editor, caret, forward).isSome() : false;
-      };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // return false for non-element nodes, no point in throwing an error
+      return dom && dom.hasAttribute ? dom.hasAttribute(key) : false;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var setupSelectedState = function (editor) {
-      var caret = new Cell(null);
-
-      editor.on('NodeChange', function (e) {
-        if (isFeatureEnabled(editor)) {
-          toggleInlines(editor.dom, e.parents);
-          safeRemoveCaretContainer(editor, caret);
-          renderInsideInlineCaret(editor, caret, e.parents);
-        }
-      });
-
-      return caret;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var remove = function (element, key) {
+      element.dom().removeAttribute(key);
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return {
-      move: move,
-      setupSelectedState: setupSelectedState,
-      setCaretPosition: setCaretPosition
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var hasNone = function (element) {
+      var attrs = element.dom().attributes;
+      return attrs === undefined || attrs === null || attrs.length === 0;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  }
-);
-/**
- * InlineBoundaryDelete.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-define(
-  'tinymce.core.delete.InlineBoundaryDelete',
-  [
-    'ephox.katamari.api.Fun',
-    'ephox.katamari.api.Option',
-    'ephox.katamari.api.Options',
-    'ephox.sugar.api.node.Element',
-    'tinymce.core.caret.CaretContainer',
-    'tinymce.core.caret.CaretFinder',
-    'tinymce.core.caret.CaretPosition',
-    'tinymce.core.caret.CaretUtils',
-    'tinymce.core.delete.DeleteElement',
-    'tinymce.core.keyboard.BoundaryCaret',
-    'tinymce.core.keyboard.BoundaryLocation',
-    'tinymce.core.keyboard.BoundarySelection',
-    'tinymce.core.keyboard.InlineUtils'
-  ],
-  function (
-    Fun, Option, Options, Element, CaretContainer, CaretFinder, CaretPosition, CaretUtils, DeleteElement, BoundaryCaret, BoundaryLocation, BoundarySelection,
-    InlineUtils
-  ) {
-    var isFeatureEnabled = function (editor) {
-      return editor.settings.inline_boundaries !== false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var clone = function (element) {
+      return Arr.foldl(element.dom().attributes, function (acc, attr) {
+        acc[attr.name] = attr.value;
+        return acc;
+      }, {});
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var rangeFromPositions = function (from, to) {
-      var range = document.createRange();
-
-      range.setStart(from.container(), from.offset());
-      range.setEnd(to.container(), to.offset());
-
-      return range;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var transferOne = function (source, destination, attr) {
+      // NOTE: We don't want to clobber any existing attributes
+      if (has(source, attr) && !has(destination, attr)) set(destination, attr, get(source, attr));        
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // Checks for delete at <code>|a</code> when there is only one item left except the zwsp caret container nodes
-    var hasOnlyTwoOrLessPositionsLeft = function (elm) {
-      return Options.liftN([
-        InlineUtils.findCaretPositionIn(elm, true),
-        InlineUtils.findCaretPositionIn(elm, false)
-      ], function (firstPos, lastPos) {
-        var normalizedFirstPos = InlineUtils.normalizePosition(true, firstPos);
-        var normalizedLastPos = InlineUtils.normalizePosition(false, lastPos);
-
-        return InlineUtils.findCaretPosition(elm, true, normalizedFirstPos).map(function (pos) {
-          return pos.isEqual(normalizedLastPos);
-        }).getOr(true);
-      }).getOr(true);
-    };
-
-    var setCaretLocation = function (editor, caret) {
-      return function (location) {
-        return BoundaryCaret.renderCaret(caret, location).map(function (pos) {
-          BoundarySelection.setCaretPosition(editor, pos);
-          return true;
-        }).getOr(false);
-      };
-    };
-
-    var deleteFromTo = function (editor, caret, from, to) {
-      var rootNode = editor.getBody();
-
-      editor.undoManager.ignore(function () {
-        editor.selection.setRng(rangeFromPositions(from, to));
-        editor.execCommand('Delete');
-
-        BoundaryLocation.readLocation(rootNode, CaretPosition.fromRangeStart(editor.selection.getRng()))
-          .map(BoundaryLocation.inside)
-          .map(setCaretLocation(editor, caret));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Transfer attributes(attrs) from source to destination, unless they are already present
+    var transfer = function (source, destination, attrs) {
+      if (!Node.isElement(source) || !Node.isElement(destination)) return;
+      Arr.each(attrs, function (attr) {
+        transferOne(source, destination, attr);
</ins><span class="cx" style="display: block; padding: 0 10px">       });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-      editor.nodeChanged();
</del><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var rescope = function (rootNode, node) {
-      var parentBlock = CaretUtils.getParentBlock(node, rootNode);
-      return parentBlock ? parentBlock : rootNode;
-    };
-
-    var backspaceDeleteCollapsed = function (editor, caret, forward, from) {
-      var rootNode = rescope(editor.getBody(), from.container());
-      var fromLocation = BoundaryLocation.readLocation(rootNode, from);
-
-      return fromLocation.bind(function (location) {
-        if (forward) {
-          return location.fold(
-            Fun.constant(Option.some(BoundaryLocation.inside(location))), // Before
-            Option.none, // Start
-            Fun.constant(Option.some(BoundaryLocation.outside(location))), // End
-            Option.none  // After
-          );
-        } else {
-          return location.fold(
-            Option.none, // Before
-            Fun.constant(Option.some(BoundaryLocation.outside(location))), // Start
-            Option.none, // End
-            Fun.constant(Option.some(BoundaryLocation.inside(location)))  // After
-          );
-        }
-      })
-      .map(setCaretLocation(editor, caret))
-      .getOrThunk(function () {
-        var toPosition = CaretFinder.navigate(forward, rootNode, from);
-        var toLocation = toPosition.bind(function (pos) {
-          return BoundaryLocation.readLocation(rootNode, pos);
-        });
-
-        if (fromLocation.isSome() && toLocation.isSome()) {
-          return InlineUtils.findRootInline(rootNode, from).map(function (elm) {
-            if (hasOnlyTwoOrLessPositionsLeft(elm)) {
-              DeleteElement.deleteElement(editor, forward, Element.fromDom(elm));
-              return true;
-            } else {
-              return false;
-            }
-          }).getOr(false);
-        } else {
-          return toLocation.bind(function (_) {
-            return toPosition.map(function (to) {
-              if (forward) {
-                deleteFromTo(editor, caret, from, to);
-              } else {
-                deleteFromTo(editor, caret, to, from);
-              }
-
-              return true;
-            });
-          }).getOr(false);
-        }
-      });
-    };
-
-    var backspaceDelete = function (editor, caret, forward) {
-      if (editor.selection.isCollapsed() && isFeatureEnabled(editor)) {
-        var from = CaretPosition.fromRangeStart(editor.selection.getRng());
-        return backspaceDeleteCollapsed(editor, caret, forward, from);
-      }
-
-      return false;
-    };
-
</del><span class="cx" style="display: block; padding: 0 10px">     return {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      backspaceDelete: backspaceDelete
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      clone: clone,
+      set: set,
+      setAll: setAll,
+      get: get,
+      has: has,
+      remove: remove,
+      hasNone: hasNone,
+      transfer: transfer
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * Commands.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.delete.DeleteCommands',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'ephox.sugar.impl.Style',
+
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.delete.BlockBoundaryDelete',
-    'tinymce.core.delete.BlockRangeDelete',
-    'tinymce.core.delete.CefDelete',
-    'tinymce.core.delete.InlineBoundaryDelete'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (BlockBoundaryDelete, BlockRangeDelete, CefDelete, BoundaryDelete) {
-    var nativeCommand = function (editor, command) {
-      editor.getDoc().execCommand(command, false, null);
-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var paddEmptyBody = function (editor) {
-      var dom = editor.dom;
-
-      // Check if body is empty after the delete call if so then set the contents
-      // to an empty string and move the caret to any block produced by that operation
-      // this fixes the issue with root blocks not being properly produced after a delete call on IE
-      var body = editor.getBody();
-
-      if (dom.isEmpty(body)) {
-        editor.setContent('');
-
-        if (body.firstChild && dom.isBlock(body.firstChild)) {
-          editor.selection.setCursorLocation(body.firstChild, 0);
-        } else {
-          editor.selection.setCursorLocation(body, 0);
-        }
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function () {
+    // some elements, such as mathml, don't have style attributes
+    var isSupported = function (dom) {
+      return dom.style !== undefined;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var deleteCommand = function (editor) {
-      if (CefDelete.backspaceDelete(editor, false)) {
-        return;
-      } else if (BoundaryDelete.backspaceDelete(editor, false)) {
-        return;
-      } else if (BlockBoundaryDelete.backspaceDelete(editor, false)) {
-        return;
-      } else if (BlockRangeDelete.backspaceDelete(editor, false)) {
-        return;
-      } else {
-        nativeCommand(editor, 'Delete');
-        paddEmptyBody(editor);
-      }
-    };
-
-    var forwardDeleteCommand = function (editor) {
-      if (CefDelete.backspaceDelete(editor, true)) {
-        return;
-      } else if (BoundaryDelete.backspaceDelete(editor, true)) {
-        return;
-      } else if (BlockBoundaryDelete.backspaceDelete(editor, true)) {
-        return;
-      } else if (BlockRangeDelete.backspaceDelete(editor, true)) {
-        return;
-      } else {
-        nativeCommand(editor, 'ForwardDelete');
-      }
-    };
-
</del><span class="cx" style="display: block; padding: 0 10px">     return {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      deleteCommand: deleteCommand,
-      forwardDeleteCommand: forwardDeleteCommand
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      isSupported: isSupported
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * RangeNormalizer.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+defineGlobal("global!window", window);
+define(
+  'ephox.sugar.api.properties.Css',
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-define(
-  'tinymce.core.dom.RangeNormalizer',
</del><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.caret.CaretFinder',
-    'tinymce.core.caret.CaretPosition',
-    'tinymce.core.caret.CaretUtils',
-    'tinymce.core.dom.NodeType'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.katamari.api.Type',
+    'ephox.katamari.api.Arr',
+    'ephox.katamari.api.Obj',
+    'ephox.katamari.api.Option',
+    'ephox.sugar.api.properties.Attr',
+    'ephox.sugar.api.node.Body',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.node.Node',
+    'ephox.sugar.impl.Style',
+    'ephox.katamari.api.Strings',
+    'global!Error',
+    'global!console',
+    'global!window'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (CaretFinder, CaretPosition, CaretUtils, NodeType) {
-    var isTextBlock = function (elm) {
-      return NodeType.isElement(elm) && /^(P|H[1-6]|DIV)$/.test(elm.nodeName);
-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var matchEndContainer = function (rng, predicate) {
-      return predicate(rng.endContainer);
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Type, Arr, Obj, Option, Attr, Body, Element, Node, Style, Strings, Error, console, window) {
+    var internalSet = function (dom, property, value) {
+      // This is going to hurt. Apologies.
+      // JQuery coerces numbers to pixels for certain property names, and other times lets numbers through.
+      // we're going to be explicit; strings only.
+      if (!Type.isString(value)) {
+        console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom);
+        throw new Error('CSS value must be a string: ' + value);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var createRange = function (sc, so, ec, eo) {
-      var rng = document.createRange();
-      rng.setStart(sc, so);
-      rng.setEnd(ec, eo);
-      return rng;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // removed: support for dom().style[property] where prop is camel case instead of normal property name
+      if (Style.isSupported(dom)) dom.style.setProperty(property, value);
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // If you tripple click a paragraph in this case:
-    //   <blockquote><p>a</p></blockquote><p>b</p>
-    // It would become this range in webkit:
-    //   <blockquote><p>[a</p></blockquote><p>]b</p>
-    // We would want it to be:
-    //   <blockquote><p>[a]</p></blockquote><p>b</p>
-    // Since it would otherwise produces spans out of thin air on insertContent for example.
-    var normalizeBlockSelection = function (rng) {
-      var startPos = CaretPosition.fromRangeStart(rng);
-      var endPos = CaretPosition.fromRangeEnd(rng);
-      var rootNode = rng.commonAncestorContainer;
-
-      if (rng.collapsed === false && matchEndContainer(rng, isTextBlock) && rng.endOffset === 0) {
-        return CaretFinder.fromPosition(false, rootNode, endPos)
-          .map(function (newEndPos) {
-            if (!CaretUtils.isInSameBlock(startPos, endPos, rootNode) && CaretUtils.isInSameBlock(startPos, newEndPos, rootNode)) {
-              return createRange(startPos.container(), startPos.offset(), newEndPos.container(), newEndPos.offset());
-            } else {
-              return rng;
-            }
-          }).getOr(rng);
-      } else {
-        return rng;
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var internalRemove = function (dom, property) {
+      /*
+       * IE9 and above - MDN doesn't have details, but here's a couple of random internet claims
+       *
+       * http://help.dottoro.com/ljopsjck.php
+       * http://stackoverflow.com/a/7901886/7546
+       */
+      if (Style.isSupported(dom)) dom.style.removeProperty(property);
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var normalize = function (rng) {
-      return normalizeBlockSelection(rng);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var set = function (element, property, value) {
+      var dom = element.dom();
+      internalSet(dom, property, value);
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return {
-      normalize: normalize
-    };
-  }
-);
-/**
- * InsertList.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var setAll = function (element, css) {
+      var dom = element.dom();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * Handles inserts of lists into the editor instance.
- *
- * @class tinymce.InsertList
- * @private
- */
-define(
-  'tinymce.core.InsertList',
-  [
-    "tinymce.core.util.Tools",
-    "tinymce.core.caret.CaretWalker",
-    "tinymce.core.caret.CaretPosition"
-  ],
-  function (Tools, CaretWalker, CaretPosition) {
-    var isListFragment = function (fragment) {
-      var firstChild = fragment.firstChild;
-      var lastChild = fragment.lastChild;
-
-      // Skip meta since it's likely <meta><ul>..</ul>
-      if (firstChild && firstChild.name === 'meta') {
-        firstChild = firstChild.next;
-      }
-
-      // Skip mce_marker since it's likely <ul>..</ul><span id="mce_marker"></span>
-      if (lastChild && lastChild.attr('id') === 'mce_marker') {
-        lastChild = lastChild.prev;
-      }
-
-      if (!firstChild || firstChild !== lastChild) {
-        return false;
-      }
-
-      return firstChild.name === 'ul' || firstChild.name === 'ol';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      Obj.each(css, function (v, k) {
+        internalSet(dom, k, v);
+      });
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var cleanupDomFragment = function (domFragment) {
-      var firstChild = domFragment.firstChild;
-      var lastChild = domFragment.lastChild;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var setOptions = function(element, css) {
+      var dom = element.dom();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // TODO: remove the meta tag from paste logic
-      if (firstChild && firstChild.nodeName === 'META') {
-        firstChild.parentNode.removeChild(firstChild);
-      }
-
-      if (lastChild && lastChild.id === 'mce_marker') {
-        lastChild.parentNode.removeChild(lastChild);
-      }
-
-      return domFragment;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      Obj.each(css, function (v, k) {
+        v.fold(function () {
+          internalRemove(dom, k);
+        }, function (value) {
+          internalSet(dom, k, value);
+        });
+      });
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var toDomFragment = function (dom, serializer, fragment) {
-      var html = serializer.serialize(fragment);
-      var domFragment = dom.createFragment(html);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    /*
+     * NOTE: For certain properties, this returns the "used value" which is subtly different to the "computed value" (despite calling getComputedStyle).
+     * Blame CSS 2.0.
+     *
+     * https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
+     */
+    var get = function (element, property) {
+      var dom = element.dom();
+      /*
+       * IE9 and above per
+       * https://developer.mozilla.org/en/docs/Web/API/window.getComputedStyle
+       *
+       * Not in numerosity, because it doesn't memoize and looking this up dynamically in performance critical code would be horrendous.
+       *
+       * JQuery has some magic here for IE popups, but we don't really need that.
+       * It also uses element.ownerDocument.defaultView to handle iframes but that hasn't been required since FF 3.6.
+       */
+      var styles = window.getComputedStyle(dom);
+      var r = styles.getPropertyValue(property);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return cleanupDomFragment(domFragment);
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // jquery-ism: If r is an empty string, check that the element is not in a document. If it isn't, return the raw value.
+      // Turns out we do this a lot.
+      var v = (r === '' && !Body.inBody(element)) ? getUnsafeProperty(dom, property) : r;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var listItems = function (elm) {
-      return Tools.grep(elm.childNodes, function (child) {
-        return child.nodeName === 'LI';
-      });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // undefined is the more appropriate value for JS. JQuery coerces to an empty string, but screw that!
+      return v === null ? undefined : v;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var isEmpty = function (elm) {
-      return !elm.firstChild;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var getUnsafeProperty = function (dom, property) {
+      // removed: support for dom().style[property] where prop is camel case instead of normal property name
+      // empty string is what the browsers (IE11 and Chrome) return when the propertyValue doesn't exists.
+      return Style.isSupported(dom) ? dom.style.getPropertyValue(property) : '';
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var trimListItems = function (elms) {
-      return elms.length > 0 && isEmpty(elms[elms.length - 1]) ? elms.slice(0, -1) : elms;
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    /*
+     * Gets the raw value from the style attribute. Useful for retrieving "used values" from the DOM:
+     * https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
+     *
+     * Returns NONE if the property isn't set, or the value is an empty string.
+     */
+    var getRaw = function (element, property) {
+      var dom = element.dom();
+      var raw = getUnsafeProperty(dom, property);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var getParentLi = function (dom, node) {
-      var parentBlock = dom.getParent(node, dom.isBlock);
-      return parentBlock && parentBlock.nodeName === 'LI' ? parentBlock : null;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return Option.from(raw).filter(function (r) { return r.length > 0; });
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var isParentBlockLi = function (dom, node) {
-      return !!getParentLi(dom, node);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isValidValue = function (tag, property, value) {
+      var element = Element.fromTag(tag);
+      set(element, property, value);
+      var style = getRaw(element, property);
+      return style.isSome();
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var getSplit = function (parentNode, rng) {
-      var beforeRng = rng.cloneRange();
-      var afterRng = rng.cloneRange();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var remove = function (element, property) {
+      var dom = element.dom();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      beforeRng.setStartBefore(parentNode);
-      afterRng.setEndAfter(parentNode);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      internalRemove(dom, property);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return [
-        beforeRng.cloneContents(),
-        afterRng.cloneContents()
-      ];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (Attr.has(element, 'style') && Strings.trim(Attr.get(element, 'style')) === '') {
+        // No more styles left, remove the style attribute as well
+        Attr.remove(element, 'style');
+      }
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var findFirstIn = function (node, rootNode) {
-      var caretPos = CaretPosition.before(node);
-      var caretWalker = new CaretWalker(rootNode);
-      var newCaretPos = caretWalker.next(caretPos);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var preserve = function (element, f) {
+      var oldStyles = Attr.get(element, 'style');
+      var result = f(element);
+      var restore = oldStyles === undefined ? Attr.remove : Attr.set;
+      restore(element, 'style', oldStyles);
+      return result;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return newCaretPos ? newCaretPos.toRange() : null;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var copy = function (source, target) {
+      var sourceDom = source.dom();
+      var targetDom = target.dom();
+      if (Style.isSupported(sourceDom) && Style.isSupported(targetDom)) {
+        targetDom.style.cssText = sourceDom.style.cssText;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var findLastOf = function (node, rootNode) {
-      var caretPos = CaretPosition.after(node);
-      var caretWalker = new CaretWalker(rootNode);
-      var newCaretPos = caretWalker.prev(caretPos);
-
-      return newCaretPos ? newCaretPos.toRange() : null;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var reflow = function (e) {
+      /* NOTE:
+       * do not rely on this return value.
+       * It's here so the closure compiler doesn't optimise the property access away.
+       */
+      return e.dom().offsetWidth;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var insertMiddle = function (target, elms, rootNode, rng) {
-      var parts = getSplit(target, rng);
-      var parentElm = target.parentNode;
-
-      parentElm.insertBefore(parts[0], target);
-      Tools.each(elms, function (li) {
-        parentElm.insertBefore(li, target);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var transferOne = function (source, destination, style) {
+      getRaw(source, style).each(function (value) {
+        // NOTE: We don't want to clobber any existing inline styles.
+        if (getRaw(destination, style).isNone()) set(destination, style, value);
</ins><span class="cx" style="display: block; padding: 0 10px">       });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      parentElm.insertBefore(parts[1], target);
-      parentElm.removeChild(target);
-
-      return findLastOf(elms[elms.length - 1], rootNode);
</del><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var insertBefore = function (target, elms, rootNode) {
-      var parentElm = target.parentNode;
-
-      Tools.each(elms, function (elm) {
-        parentElm.insertBefore(elm, target);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var transfer = function (source, destination, styles) {
+      if (!Node.isElement(source) || !Node.isElement(destination)) return;
+      Arr.each(styles, function (style) {
+        transferOne(source, destination, style);
</ins><span class="cx" style="display: block; padding: 0 10px">       });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-      return findFirstIn(target, rootNode);
</del><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var insertAfter = function (target, elms, rootNode, dom) {
-      dom.insertAfter(elms.reverse(), target);
-      return findLastOf(elms[0], rootNode);
-    };
-
-    var insertAtCaret = function (serializer, dom, rng, fragment) {
-      var domFragment = toDomFragment(dom, serializer, fragment);
-      var liTarget = getParentLi(dom, rng.startContainer);
-      var liElms = trimListItems(listItems(domFragment.firstChild));
-      var BEGINNING = 1, END = 2;
-      var rootNode = dom.getRoot();
-
-      var isAt = function (location) {
-        var caretPos = CaretPosition.fromRangeStart(rng);
-        var caretWalker = new CaretWalker(dom.getRoot());
-        var newPos = location === BEGINNING ? caretWalker.prev(caretPos) : caretWalker.next(caretPos);
-
-        return newPos ? getParentLi(dom, newPos.getNode()) !== liTarget : true;
-      };
-
-      if (isAt(BEGINNING)) {
-        return insertBefore(liTarget, liElms, rootNode);
-      } else if (isAt(END)) {
-        return insertAfter(liTarget, liElms, rootNode, dom);
-      }
-
-      return insertMiddle(liTarget, liElms, rootNode, rng);
-    };
-
</del><span class="cx" style="display: block; padding: 0 10px">     return {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      isListFragment: isListFragment,
-      insertAtCaret: insertAtCaret,
-      isParentBlockLi: isParentBlockLi,
-      trimListItems: trimListItems,
-      listItems: listItems
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      copy: copy,
+      set: set,
+      preserve: preserve,
+      setAll: setAll,
+      setOptions: setOptions,
+      remove: remove,
+      get: get,
+      getRaw: getRaw,
+      isValidValue: isValidValue,
+      reflow: reflow,
+      transfer: transfer
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * InsertContent.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * EditorView.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * License: http://www.tinymce.com/license
</span><span class="cx" style="display: block; padding: 0 10px">  * Contributing: http://www.tinymce.com/contributing
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * Handles inserts of contents into the editor instance.
- *
- * @class tinymce.InsertContent
- * @private
- */
</del><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.InsertContent',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.EditorView',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.caret.CaretPosition',
-    'tinymce.core.caret.CaretWalker',
-    'tinymce.core.dom.ElementUtils',
-    'tinymce.core.dom.NodeType',
-    'tinymce.core.dom.RangeNormalizer',
-    'tinymce.core.Env',
-    'tinymce.core.html.Serializer',
-    'tinymce.core.InsertList',
-    'tinymce.core.util.Tools'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.katamari.api.Fun',
+    'ephox.katamari.api.Option',
+    'ephox.sugar.api.dom.Compare',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.properties.Css',
+    'ephox.sugar.api.search.Traverse'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (CaretPosition, CaretWalker, ElementUtils, NodeType, RangeNormalizer, Env, Serializer, InsertList, Tools) {
-    var isTableCell = NodeType.matchNodeNames('td th');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Fun, Option, Compare, Element, Css, Traverse) {
+    var getProp = function (propName, elm) {
+      var rawElm = elm.dom();
+      return rawElm[propName];
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var validInsertion = function (editor, value, parentNode) {
-      // Should never insert content into bogus elements, since these can
-      // be resize handles or similar
-      if (parentNode.getAttribute('data-mce-bogus') === 'all') {
-        parentNode.parentNode.insertBefore(editor.dom.createFragment(value), parentNode);
-      } else {
-        // Check if parent is empty or only has one BR element then set the innerHTML of that parent
-        var node = parentNode.firstChild;
-        var node2 = parentNode.lastChild;
-        if (!node || (node === node2 && node.nodeName === 'BR')) {///
-          editor.dom.setHTML(parentNode, value);
-        } else {
-          editor.selection.setContent(value);
-        }
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var getComputedSizeProp = function (propName, elm) {
+      return parseInt(Css.get(elm, propName), 10);
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var insertHtmlAtCaret = function (editor, value, details) {
-      var parser, serializer, parentNode, rootNode, fragment, args;
-      var marker, rng, node, node2, bookmarkHtml, merge;
-      var textInlineElements = editor.schema.getTextInlineElements();
-      var selection = editor.selection, dom = editor.dom;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var getClientWidth = Fun.curry(getProp, 'clientWidth');
+    var getClientHeight = Fun.curry(getProp, 'clientHeight');
+    var getMarginTop = Fun.curry(getComputedSizeProp, 'margin-top');
+    var getMarginLeft = Fun.curry(getComputedSizeProp, 'margin-left');
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function trimOrPaddLeftRight(html) {
-        var rng, container, offset;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var getBoundingClientRect = function (elm) {
+      return elm.dom().getBoundingClientRect();
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        rng = selection.getRng(true);
-        container = rng.startContainer;
-        offset = rng.startOffset;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isInsideElementContentArea = function (bodyElm, clientX, clientY) {
+      var clientWidth = getClientWidth(bodyElm);
+      var clientHeight = getClientHeight(bodyElm);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function hasSiblingText(siblingName) {
-          return container[siblingName] && container[siblingName].nodeType == 3;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return clientX >= 0 && clientY >= 0 && clientX <= clientWidth && clientY <= clientHeight;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (container.nodeType == 3) {
-          if (offset > 0) {
-            html = html.replace(/^&nbsp;/, ' ');
-          } else if (!hasSiblingText('previousSibling')) {
-            html = html.replace(/^ /, '&nbsp;');
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var transpose = function (inline, elm, clientX, clientY) {
+      var clientRect = getBoundingClientRect(elm);
+      var deltaX = inline ? clientRect.left + elm.dom().clientLeft + getMarginLeft(elm) : 0;
+      var deltaY = inline ? clientRect.top + elm.dom().clientTop + getMarginTop(elm) : 0;
+      var x = clientX - deltaX;
+      var y = clientY - deltaY;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (offset < container.length) {
-            html = html.replace(/&nbsp;(<br>|)$/, ' ');
-          } else if (!hasSiblingText('nextSibling')) {
-            html = html.replace(/(&nbsp;| )(<br>|)$/, '&nbsp;');
-          }
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return { x: x, y: y };
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return html;
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Checks if the specified coordinate is within the visual content area excluding the scrollbars
+    var isXYInContentArea = function (editor, clientX, clientY) {
+      var bodyElm = Element.fromDom(editor.getBody());
+      var targetElm = editor.inline ? bodyElm : Traverse.documentElement(bodyElm);
+      var transposedPoint = transpose(editor.inline, targetElm, clientX, clientY);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Removes &nbsp; from a [b] c -> a &nbsp;c -> a c
-      function trimNbspAfterDeleteAndPaddValue() {
-        var rng, container, offset;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return isInsideElementContentArea(targetElm, transposedPoint.x, transposedPoint.y);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        rng = selection.getRng(true);
-        container = rng.startContainer;
-        offset = rng.startOffset;
-
-        if (container.nodeType == 3 && rng.collapsed) {
-          if (container.data[offset] === '\u00a0') {
-            container.deleteData(offset, 1);
-
-            if (!/[\u00a0| ]$/.test(value)) {
-              value += ' ';
-            }
-          } else if (container.data[offset - 1] === '\u00a0') {
-            container.deleteData(offset - 1, 1);
-
-            if (!/[\u00a0| ]$/.test(value)) {
-              value = ' ' + value;
-            }
-          }
-        }
-      }
-
-      function reduceInlineTextElements() {
-        if (merge) {
-          var root = editor.getBody(), elementUtils = new ElementUtils(dom);
-
-          Tools.each(dom.select('*[data-mce-fragment]'), function (node) {
-            for (var testNode = node.parentNode; testNode && testNode != root; testNode = testNode.parentNode) {
-              if (textInlineElements[node.nodeName.toLowerCase()] && elementUtils.compare(testNode, node)) {
-                dom.remove(node, true);
-              }
-            }
-          });
-        }
-      }
-
-      function markFragmentElements(fragment) {
-        var node = fragment;
-
-        while ((node = node.walk())) {
-          if (node.type === 1) {
-            node.attr('data-mce-fragment', '1');
-          }
-        }
-      }
-
-      function umarkFragmentElements(elm) {
-        Tools.each(elm.getElementsByTagName('*'), function (elm) {
-          elm.removeAttribute('data-mce-fragment');
-        });
-      }
-
-      function isPartOfFragment(node) {
-        return !!node.getAttribute('data-mce-fragment');
-      }
-
-      function canHaveChildren(node) {
-        return node && !editor.schema.getShortEndedElements()[node.nodeName];
-      }
-
-      function moveSelectionToMarker(marker) {
-        var parentEditableFalseElm, parentBlock, nextRng;
-
-        function getContentEditableFalseParent(node) {
-          var root = editor.getBody();
-
-          for (; node && node !== root; node = node.parentNode) {
-            if (editor.dom.getContentEditable(node) === 'false') {
-              return node;
-            }
-          }
-
-          return null;
-        }
-
-        if (!marker) {
-          return;
-        }
-
-        selection.scrollIntoView(marker);
-
-        // If marker is in cE=false then move selection to that element instead
-        parentEditableFalseElm = getContentEditableFalseParent(marker);
-        if (parentEditableFalseElm) {
-          dom.remove(marker);
-          selection.select(parentEditableFalseElm);
-          return;
-        }
-
-        // Move selection before marker and remove it
-        rng = dom.createRng();
-
-        // If previous sibling is a text node set the selection to the end of that node
-        node = marker.previousSibling;
-        if (node && node.nodeType == 3) {
-          rng.setStart(node, node.nodeValue.length);
-
-          // TODO: Why can't we normalize on IE
-          if (!Env.ie) {
-            node2 = marker.nextSibling;
-            if (node2 && node2.nodeType == 3) {
-              node.appendData(node2.data);
-              node2.parentNode.removeChild(node2);
-            }
-          }
-        } else {
-          // If the previous sibling isn't a text node or doesn't exist set the selection before the marker node
-          rng.setStartBefore(marker);
-          rng.setEndBefore(marker);
-        }
-
-        function findNextCaretRng(rng) {
-          var caretPos = CaretPosition.fromRangeStart(rng);
-          var caretWalker = new CaretWalker(editor.getBody());
-
-          caretPos = caretWalker.next(caretPos);
-          if (caretPos) {
-            return caretPos.toRange();
-          }
-        }
-
-        // Remove the marker node and set the new range
-        parentBlock = dom.getParent(marker, dom.isBlock);
-        dom.remove(marker);
-
-        if (parentBlock && dom.isEmpty(parentBlock)) {
-          editor.$(parentBlock).empty();
-
-          rng.setStart(parentBlock, 0);
-          rng.setEnd(parentBlock, 0);
-
-          if (!isTableCell(parentBlock) && !isPartOfFragment(parentBlock) && (nextRng = findNextCaretRng(rng))) {
-            rng = nextRng;
-            dom.remove(parentBlock);
-          } else {
-            dom.add(parentBlock, dom.create('br', { 'data-mce-bogus': '1' }));
-          }
-        }
-
-        selection.setRng(rng);
-      }
-
-      // Check for whitespace before/after value
-      if (/^ | $/.test(value)) {
-        value = trimOrPaddLeftRight(value);
-      }
-
-      // Setup parser and serializer
-      parser = editor.parser;
-      merge = details.merge;
-
-      serializer = new Serializer({
-        validate: editor.settings.validate
-      }, editor.schema);
-      bookmarkHtml = '<span id="mce_marker" data-mce-type="bookmark">&#xFEFF;&#x200B;</span>';
-
-      // Run beforeSetContent handlers on the HTML to be inserted
-      args = { content: value, format: 'html', selection: true };
-      editor.fire('BeforeSetContent', args);
-      value = args.content;
-
-      // Add caret at end of contents if it's missing
-      if (value.indexOf('{$caret}') == -1) {
-        value += '{$caret}';
-      }
-
-      // Replace the caret marker with a span bookmark element
-      value = value.replace(/\{\$caret\}/, bookmarkHtml);
-
-      // If selection is at <body>|<p></p> then move it into <body><p>|</p>
-      rng = selection.getRng();
-      var caretElement = rng.startContainer || (rng.parentElement ? rng.parentElement() : null);
-      var body = editor.getBody();
-      if (caretElement === body && selection.isCollapsed()) {
-        if (dom.isBlock(body.firstChild) && canHaveChildren(body.firstChild) && dom.isEmpty(body.firstChild)) {
-          rng = dom.createRng();
-          rng.setStart(body.firstChild, 0);
-          rng.setEnd(body.firstChild, 0);
-          selection.setRng(rng);
-        }
-      }
-
-      // Insert node maker where we will insert the new HTML and get it's parent
-      if (!selection.isCollapsed()) {
-        // Fix for #2595 seems that delete removes one extra character on
-        // WebKit for some odd reason if you double click select a word
-        editor.selection.setRng(RangeNormalizer.normalize(editor.selection.getRng()));
-        editor.getDoc().execCommand('Delete', false, null);
-        trimNbspAfterDeleteAndPaddValue();
-      }
-
-      parentNode = selection.getNode();
-
-      // Parse the fragment within the context of the parent node
-      var parserArgs = { context: parentNode.nodeName.toLowerCase(), data: details.data };
-      fragment = parser.parse(value, parserArgs);
-
-      // Custom handling of lists
-      if (details.paste === true && InsertList.isListFragment(fragment) && InsertList.isParentBlockLi(dom, parentNode)) {
-        rng = InsertList.insertAtCaret(serializer, dom, editor.selection.getRng(true), fragment);
-        editor.selection.setRng(rng);
-        editor.fire('SetContent', args);
-        return;
-      }
-
-      markFragmentElements(fragment);
-
-      // Move the caret to a more suitable location
-      node = fragment.lastChild;
-      if (node.attr('id') == 'mce_marker') {
-        marker = node;
-
-        for (node = node.prev; node; node = node.walk(true)) {
-          if (node.type == 3 || !dom.isBlock(node.name)) {
-            if (editor.schema.isValidChild(node.parent.name, 'span')) {
-              node.parent.insert(marker, node, node.name === 'br');
-            }
-            break;
-          }
-        }
-      }
-
-      editor._selectionOverrides.showBlockCaretContainer(parentNode);
-
-      // If parser says valid we can insert the contents into that parent
-      if (!parserArgs.invalid) {
-        value = serializer.serialize(fragment);
-        validInsertion(editor, value, parentNode);
-      } else {
-        // If the fragment was invalid within that context then we need
-        // to parse and process the parent it's inserted into
-
-        // Insert bookmark node and get the parent
-        selection.setContent(bookmarkHtml);
-        parentNode = selection.getNode();
-        rootNode = editor.getBody();
-
-        // Opera will return the document node when selection is in root
-        if (parentNode.nodeType == 9) {
-          parentNode = node = rootNode;
-        } else {
-          node = parentNode;
-        }
-
-        // Find the ancestor just before the root element
-        while (node !== rootNode) {
-          parentNode = node;
-          node = node.parentNode;
-        }
-
-        // Get the outer/inner HTML depending on if we are in the root and parser and serialize that
-        value = parentNode == rootNode ? rootNode.innerHTML : dom.getOuterHTML(parentNode);
-        value = serializer.serialize(
-          parser.parse(
-            // Need to replace by using a function since $ in the contents would otherwise be a problem
-            value.replace(/<span (id="mce_marker"|id=mce_marker).+?<\/span>/i, function () {
-              return serializer.serialize(fragment);
-            })
-          )
-        );
-
-        // Set the inner/outer HTML depending on if we are in the root or not
-        if (parentNode == rootNode) {
-          dom.setHTML(rootNode, value);
-        } else {
-          dom.setOuterHTML(parentNode, value);
-        }
-      }
-
-      reduceInlineTextElements();
-      moveSelectionToMarker(dom.get('mce_marker'));
-      umarkFragmentElements(editor.getBody());
-      editor.fire('SetContent', args);
-      editor.addVisual();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var fromDomSafe = function (node) {
+      return Option.from(node).map(Element.fromDom);
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var processValue = function (value) {
-      var details;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isEditorAttachedToDom = function (editor) {
+      var rawContainer = editor.inline ? editor.getBody() : editor.getContentAreaContainer();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (typeof value !== 'string') {
-        details = Tools.extend({
-          paste: value.paste,
-          data: {
-            paste: value.paste
-          }
-        }, value);
-
-        return {
-          content: value.content,
-          details: details
-        };
-      }
-
-      return {
-        content: value,
-        details: {}
-      };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return fromDomSafe(rawContainer).map(function (container) {
+        return Compare.contains(Traverse.owner(container), container);
+      }).getOr(false);
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var insertAtCaret = function (editor, value) {
-      var result = processValue(value);
-      insertHtmlAtCaret(editor, result.content, result.details);
-    };
-
</del><span class="cx" style="display: block; padding: 0 10px">     return {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      insertAtCaret: insertAtCaret
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      isXYInContentArea: isXYInContentArea,
+      isEditorAttachedToDom: isEditorAttachedToDom
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * EditorCommands.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * DomUtils.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -29298,1188 +21119,131 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * This class enables you to add custom editor commands and it contains
- * overrides for native browser commands to address various bugs and issues.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Private UI DomUtils proxy.
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @class tinymce.EditorCommands
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @private
+ * @class tinymce.ui.DomUtils
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.EditorCommands',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.ui.DomUtils',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.delete.DeleteCommands',
-    'tinymce.core.dom.NodeType',
-    'tinymce.core.dom.RangeUtils',
-    'tinymce.core.dom.TreeWalker',
-    'tinymce.core.Env',
-    'tinymce.core.InsertContent',
-    'tinymce.core.util.Tools'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    "tinymce.core.Env",
+    "tinymce.core.util.Tools",
+    "tinymce.core.dom.DOMUtils"
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (DeleteCommands, NodeType, RangeUtils, TreeWalker, Env, InsertContent, Tools) {
-    // Added for compression purposes
-    var each = Tools.each, extend = Tools.extend;
-    var map = Tools.map, inArray = Tools.inArray, explode = Tools.explode;
-    var isOldIE = Env.ie && Env.ie < 11;
-    var TRUE = true, FALSE = false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Env, Tools, DOMUtils) {
+    "use strict";
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return function (editor) {
-      var dom, selection, formatter,
-        commands = { state: {}, exec: {}, value: {} },
-        settings = editor.settings,
-        bookmark;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var count = 0;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      editor.on('PreInit', function () {
-        dom = editor.dom;
-        selection = editor.selection;
-        settings = editor.settings;
-        formatter = editor.formatter;
-      });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var funcs = {
+      id: function () {
+        return 'mceu_' + (count++);
+      },
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Executes the specified command.
-       *
-       * @method execCommand
-       * @param {String} command Command to execute.
-       * @param {Boolean} ui Optional user interface state.
-       * @param {Object} value Optional value for command.
-       * @param {Object} args Optional extra arguments to the execCommand.
-       * @return {Boolean} true/false if the command was found or not.
-       */
-      function execCommand(command, ui, value, args) {
-        var func, customCommand, state = 0;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      create: function (name, attrs, children) {
+        var elm = document.createElement(name);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (editor.removed) {
-          return;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        DOMUtils.DOM.setAttribs(elm, attrs);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint)$/.test(command) && (!args || !args.skip_focus)) {
-          editor.focus();
-        }
-
-        args = editor.fire('BeforeExecCommand', { command: command, ui: ui, value: value });
-        if (args.isDefaultPrevented()) {
-          return false;
-        }
-
-        customCommand = command.toLowerCase();
-        if ((func = commands.exec[customCommand])) {
-          func(customCommand, ui, value);
-          editor.fire('ExecCommand', { command: command, ui: ui, value: value });
-          return true;
-        }
-
-        // Plugin commands
-        each(editor.plugins, function (p) {
-          if (p.execCommand && p.execCommand(command, ui, value)) {
-            editor.fire('ExecCommand', { command: command, ui: ui, value: value });
-            state = true;
-            return false;
-          }
-        });
-
-        if (state) {
-          return state;
-        }
-
-        // Theme commands
-        if (editor.theme && editor.theme.execCommand && editor.theme.execCommand(command, ui, value)) {
-          editor.fire('ExecCommand', { command: command, ui: ui, value: value });
-          return true;
-        }
-
-        // Browser commands
-        try {
-          state = editor.getDoc().execCommand(command, ui, value);
-        } catch (ex) {
-          // Ignore old IE errors
-        }
-
-        if (state) {
-          editor.fire('ExecCommand', { command: command, ui: ui, value: value });
-          return true;
-        }
-
-        return false;
-      }
-
-      /**
-       * Queries the current state for a command for example if the current selection is "bold".
-       *
-       * @method queryCommandState
-       * @param {String} command Command to check the state of.
-       * @return {Boolean/Number} true/false if the selected contents is bold or not, -1 if it's not found.
-       */
-      function queryCommandState(command) {
-        var func;
-
-        if (editor.quirks.isHidden() || editor.removed) {
-          return;
-        }
-
-        command = command.toLowerCase();
-        if ((func = commands.state[command])) {
-          return func(command);
-        }
-
-        // Browser commands
-        try {
-          return editor.getDoc().queryCommandState(command);
-        } catch (ex) {
-          // Fails sometimes see bug: 1896577
-        }
-
-        return false;
-      }
-
-      /**
-       * Queries the command value for example the current fontsize.
-       *
-       * @method queryCommandValue
-       * @param {String} command Command to check the value of.
-       * @return {Object} Command value of false if it's not found.
-       */
-      function queryCommandValue(command) {
-        var func;
-
-        if (editor.quirks.isHidden() || editor.removed) {
-          return;
-        }
-
-        command = command.toLowerCase();
-        if ((func = commands.value[command])) {
-          return func(command);
-        }
-
-        // Browser commands
-        try {
-          return editor.getDoc().queryCommandValue(command);
-        } catch (ex) {
-          // Fails sometimes see bug: 1896577
-        }
-      }
-
-      /**
-       * Adds commands to the command collection.
-       *
-       * @method addCommands
-       * @param {Object} commandList Name/value collection with commands to add, the names can also be comma separated.
-       * @param {String} type Optional type to add, defaults to exec. Can be value or state as well.
-       */
-      function addCommands(commandList, type) {
-        type = type || 'exec';
-
-        each(commandList, function (callback, command) {
-          each(command.toLowerCase().split(','), function (command) {
-            commands[type][command] = callback;
-          });
-        });
-      }
-
-      function addCommand(command, callback, scope) {
-        command = command.toLowerCase();
-        commands.exec[command] = function (command, ui, value, args) {
-          return callback.call(scope || editor, ui, value, args);
-        };
-      }
-
-      /**
-       * Returns true/false if the command is supported or not.
-       *
-       * @method queryCommandSupported
-       * @param {String} command Command that we check support for.
-       * @return {Boolean} true/false if the command is supported or not.
-       */
-      function queryCommandSupported(command) {
-        command = command.toLowerCase();
-
-        if (commands.exec[command]) {
-          return true;
-        }
-
-        // Browser commands
-        try {
-          return editor.getDoc().queryCommandSupported(command);
-        } catch (ex) {
-          // Fails sometimes see bug: 1896577
-        }
-
-        return false;
-      }
-
-      function addQueryStateHandler(command, callback, scope) {
-        command = command.toLowerCase();
-        commands.state[command] = function () {
-          return callback.call(scope || editor);
-        };
-      }
-
-      function addQueryValueHandler(command, callback, scope) {
-        command = command.toLowerCase();
-        commands.value[command] = function () {
-          return callback.call(scope || editor);
-        };
-      }
-
-      function hasCustomCommand(command) {
-        command = command.toLowerCase();
-        return !!commands.exec[command];
-      }
-
-      // Expose public methods
-      extend(this, {
-        execCommand: execCommand,
-        queryCommandState: queryCommandState,
-        queryCommandValue: queryCommandValue,
-        queryCommandSupported: queryCommandSupported,
-        addCommands: addCommands,
-        addCommand: addCommand,
-        addQueryStateHandler: addQueryStateHandler,
-        addQueryValueHandler: addQueryValueHandler,
-        hasCustomCommand: hasCustomCommand
-      });
-
-      // Private methods
-
-      function execNativeCommand(command, ui, value) {
-        if (ui === undefined) {
-          ui = FALSE;
-        }
-
-        if (value === undefined) {
-          value = null;
-        }
-
-        return editor.getDoc().execCommand(command, ui, value);
-      }
-
-      function isFormatMatch(name) {
-        return formatter.match(name);
-      }
-
-      function toggleFormat(name, value) {
-        formatter.toggle(name, value ? { value: value } : undefined);
-        editor.nodeChanged();
-      }
-
-      function storeSelection(type) {
-        bookmark = selection.getBookmark(type);
-      }
-
-      function restoreSelection() {
-        selection.moveToBookmark(bookmark);
-      }
-
-      // Add execCommand overrides
-      addCommands({
-        // Ignore these, added for compatibility
-        'mceResetDesignMode,mceBeginUndoLevel': function () { },
-
-        // Add undo manager logic
-        'mceEndUndoLevel,mceAddUndoLevel': function () {
-          editor.undoManager.add();
-        },
-
-        'Cut,Copy,Paste': function (command) {
-          var doc = editor.getDoc(), failed;
-
-          // Try executing the native command
-          try {
-            execNativeCommand(command);
-          } catch (ex) {
-            // Command failed
-            failed = TRUE;
-          }
-
-          // Chrome reports the paste command as supported however older IE:s will return false for cut/paste
-          if (command === 'paste' && !doc.queryCommandEnabled(command)) {
-            failed = true;
-          }
-
-          // Present alert message about clipboard access not being available
-          if (failed || !doc.queryCommandSupported(command)) {
-            var msg = editor.translate(
-              "Your browser doesn't support direct access to the clipboard. " +
-              "Please use the Ctrl+X/C/V keyboard shortcuts instead."
-            );
-
-            if (Env.mac) {
-              msg = msg.replace(/Ctrl\+/g, '\u2318+');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (typeof children === 'string') {
+          elm.innerHTML = children;
+        } else {
+          Tools.each(children, function (child) {
+            if (child.nodeType) {
+              elm.appendChild(child);
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-            editor.notificationManager.open({ text: msg, type: 'error' });
-          }
-        },
-
-        // Override unlink command
-        unlink: function () {
-          if (selection.isCollapsed()) {
-            var elm = editor.dom.getParent(editor.selection.getStart(), 'a');
-            if (elm) {
-              editor.dom.remove(elm, true);
-            }
-
-            return;
-          }
-
-          formatter.remove("link");
-        },
-
-        // Override justify commands to use the text formatter engine
-        'JustifyLeft,JustifyCenter,JustifyRight,JustifyFull,JustifyNone': function (command) {
-          var align = command.substring(7);
-
-          if (align == 'full') {
-            align = 'justify';
-          }
-
-          // Remove all other alignments first
-          each('left,center,right,justify'.split(','), function (name) {
-            if (align != name) {
-              formatter.remove('align' + name);
-            }
</del><span class="cx" style="display: block; padding: 0 10px">           });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-          if (align != 'none') {
-            toggleFormat('align' + align);
-          }
-        },
-
-        // Override list commands to fix WebKit bug
-        'InsertUnorderedList,InsertOrderedList': function (command) {
-          var listElm, listParent;
-
-          execNativeCommand(command);
-
-          // WebKit produces lists within block elements so we need to split them
-          // we will replace the native list creation logic to custom logic later on
-          // TODO: Remove this when the list creation logic is removed
-          listElm = dom.getParent(selection.getNode(), 'ol,ul');
-          if (listElm) {
-            listParent = listElm.parentNode;
-
-            // If list is within a text block then split that block
-            if (/^(H[1-6]|P|ADDRESS|PRE)$/.test(listParent.nodeName)) {
-              storeSelection();
-              dom.split(listParent, listElm);
-              restoreSelection();
-            }
-          }
-        },
-
-        // Override commands to use the text formatter engine
-        'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': function (command) {
-          toggleFormat(command);
-        },
-
-        // Override commands to use the text formatter engine
-        'ForeColor,HiliteColor,FontName': function (command, ui, value) {
-          toggleFormat(command, value);
-        },
-
-        FontSize: function (command, ui, value) {
-          var fontClasses, fontSizes;
-
-          // Convert font size 1-7 to styles
-          if (value >= 1 && value <= 7) {
-            fontSizes = explode(settings.font_size_style_values);
-            fontClasses = explode(settings.font_size_classes);
-
-            if (fontClasses) {
-              value = fontClasses[value - 1] || value;
-            } else {
-              value = fontSizes[value - 1] || value;
-            }
-          }
-
-          toggleFormat(command, value);
-        },
-
-        RemoveFormat: function (command) {
-          formatter.remove(command);
-        },
-
-        mceBlockQuote: function () {
-          toggleFormat('blockquote');
-        },
-
-        FormatBlock: function (command, ui, value) {
-          return toggleFormat(value || 'p');
-        },
-
-        mceCleanup: function () {
-          var bookmark = selection.getBookmark();
-
-          editor.setContent(editor.getContent({ cleanup: TRUE }), { cleanup: TRUE });
-
-          selection.moveToBookmark(bookmark);
-        },
-
-        mceRemoveNode: function (command, ui, value) {
-          var node = value || selection.getNode();
-
-          // Make sure that the body node isn't removed
-          if (node != editor.getBody()) {
-            storeSelection();
-            editor.dom.remove(node, TRUE);
-            restoreSelection();
-          }
-        },
-
-        mceSelectNodeDepth: function (command, ui, value) {
-          var counter = 0;
-
-          dom.getParent(selection.getNode(), function (node) {
-            if (node.nodeType == 1 && counter++ == value) {
-              selection.select(node);
-              return FALSE;
-            }
-          }, editor.getBody());
-        },
-
-        mceSelectNode: function (command, ui, value) {
-          selection.select(value);
-        },
-
-        mceInsertContent: function (command, ui, value) {
-          InsertContent.insertAtCaret(editor, value);
-        },
-
-        mceInsertRawHTML: function (command, ui, value) {
-          selection.setContent('tiny_mce_marker');
-          editor.setContent(
-            editor.getContent().replace(/tiny_mce_marker/g, function () {
-              return value;
-            })
-          );
-        },
-
-        mceToggleFormat: function (command, ui, value) {
-          toggleFormat(value);
-        },
-
-        mceSetContent: function (command, ui, value) {
-          editor.setContent(value);
-        },
-
-        'Indent,Outdent': function (command) {
-          var intentValue, indentUnit, value;
-
-          // Setup indent level
-          intentValue = settings.indentation;
-          indentUnit = /[a-z%]+$/i.exec(intentValue);
-          intentValue = parseInt(intentValue, 10);
-
-          if (!queryCommandState('InsertUnorderedList') && !queryCommandState('InsertOrderedList')) {
-            // If forced_root_blocks is set to false we don't have a block to indent so lets create a div
-            if (!settings.forced_root_block && !dom.getParent(selection.getNode(), dom.isBlock)) {
-              formatter.apply('div');
-            }
-
-            each(selection.getSelectedBlocks(), function (element) {
-              if (dom.getContentEditable(element) === "false") {
-                return;
-              }
-
-              if (element.nodeName !== "LI") {
-                var indentStyleName = editor.getParam('indent_use_margin', false) ? 'margin' : 'padding';
-                indentStyleName = element.nodeName === 'TABLE' ? 'margin' : indentStyleName;
-                indentStyleName += dom.getStyle(element, 'direction', true) == 'rtl' ? 'Right' : 'Left';
-
-                if (command == 'outdent') {
-                  value = Math.max(0, parseInt(element.style[indentStyleName] || 0, 10) - intentValue);
-                  dom.setStyle(element, indentStyleName, value ? value + indentUnit : '');
-                } else {
-                  value = (parseInt(element.style[indentStyleName] || 0, 10) + intentValue) + indentUnit;
-                  dom.setStyle(element, indentStyleName, value);
-                }
-              }
-            });
-          } else {
-            execNativeCommand(command);
-          }
-        },
-
-        mceRepaint: function () {
-        },
-
-        InsertHorizontalRule: function () {
-          editor.execCommand('mceInsertContent', false, '<hr />');
-        },
-
-        mceToggleVisualAid: function () {
-          editor.hasVisual = !editor.hasVisual;
-          editor.addVisual();
-        },
-
-        mceReplaceContent: function (command, ui, value) {
-          editor.execCommand('mceInsertContent', false, value.replace(/\{\$selection\}/g, selection.getContent({ format: 'text' })));
-        },
-
-        mceInsertLink: function (command, ui, value) {
-          var anchor;
-
-          if (typeof value == 'string') {
-            value = { href: value };
-          }
-
-          anchor = dom.getParent(selection.getNode(), 'a');
-
-          // Spaces are never valid in URLs and it's a very common mistake for people to make so we fix it here.
-          value.href = value.href.replace(' ', '%20');
-
-          // Remove existing links if there could be child links or that the href isn't specified
-          if (!anchor || !value.href) {
-            formatter.remove('link');
-          }
-
-          // Apply new link to selection
-          if (value.href) {
-            formatter.apply('link', value, anchor);
-          }
-        },
-
-        selectAll: function () {
-          var root = dom.getRoot(), rng;
-
-          if (selection.getRng().setStart) {
-            var editingHost = dom.getParent(selection.getStart(), NodeType.isContentEditableTrue);
-            if (editingHost) {
-              rng = dom.createRng();
-              rng.selectNodeContents(editingHost);
-              selection.setRng(rng);
-            }
-          } else {
-            // IE will render it's own root level block elements and sometimes
-            // even put font elements in them when the user starts typing. So we need to
-            // move the selection to a more suitable element from this:
-            // <body>|<p></p></body> to this: <body><p>|</p></body>
-            rng = selection.getRng();
-            if (!rng.item) {
-              rng.moveToElementText(root);
-              rng.select();
-            }
-          }
-        },
-
-        "delete": function () {
-          DeleteCommands.deleteCommand(editor);
-        },
-
-        "forwardDelete": function () {
-          DeleteCommands.forwardDeleteCommand(editor);
-        },
-
-        mceNewDocument: function () {
-          editor.setContent('');
-        },
-
-        InsertLineBreak: function (command, ui, value) {
-          // We load the current event in from EnterKey.js when appropriate to heed
-          // certain event-specific variations such as ctrl-enter in a list
-          var evt = value;
-          var brElm, extraBr, marker;
-          var rng = selection.getRng(true);
-          new RangeUtils(dom).normalize(rng);
-
-          var offset = rng.startOffset;
-          var container = rng.startContainer;
-
-          // Resolve node index
-          if (container.nodeType == 1 && container.hasChildNodes()) {
-            var isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
-
-            container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
-            if (isAfterLastNodeInContainer && container.nodeType == 3) {
-              offset = container.nodeValue.length;
-            } else {
-              offset = 0;
-            }
-          }
-
-          var parentBlock = dom.getParent(container, dom.isBlock);
-          var parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : ''; // IE < 9 & HTML5
-          var containerBlock = parentBlock ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
-          var containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : ''; // IE < 9 & HTML5
-
-          // Enter inside block contained within a LI then split or insert before/after LI
-          var isControlKey = evt && evt.ctrlKey;
-          if (containerBlockName == 'LI' && !isControlKey) {
-            parentBlock = containerBlock;
-            parentBlockName = containerBlockName;
-          }
-
-          // Walks the parent block to the right and look for BR elements
-          function hasRightSideContent() {
-            var walker = new TreeWalker(container, parentBlock), node;
-            var nonEmptyElementsMap = editor.schema.getNonEmptyElements();
-
-            while ((node = walker.next())) {
-              if (nonEmptyElementsMap[node.nodeName.toLowerCase()] || node.length > 0) {
-                return true;
-              }
-            }
-          }
-
-          if (container && container.nodeType == 3 && offset >= container.nodeValue.length) {
-            // Insert extra BR element at the end block elements
-            if (!isOldIE && !hasRightSideContent()) {
-              brElm = dom.create('br');
-              rng.insertNode(brElm);
-              rng.setStartAfter(brElm);
-              rng.setEndAfter(brElm);
-              extraBr = true;
-            }
-          }
-
-          brElm = dom.create('br');
-          rng.insertNode(brElm);
-
-          // Rendering modes below IE8 doesn't display BR elements in PRE unless we have a \n before it
-          var documentMode = dom.doc.documentMode;
-          if (isOldIE && parentBlockName == 'PRE' && (!documentMode || documentMode < 8)) {
-            brElm.parentNode.insertBefore(dom.doc.createTextNode('\r'), brElm);
-          }
-
-          // Insert temp marker and scroll to that
-          marker = dom.create('span', {}, '&nbsp;');
-          brElm.parentNode.insertBefore(marker, brElm);
-          selection.scrollIntoView(marker);
-          dom.remove(marker);
-
-          if (!extraBr) {
-            rng.setStartAfter(brElm);
-            rng.setEndAfter(brElm);
-          } else {
-            rng.setStartBefore(brElm);
-            rng.setEndBefore(brElm);
-          }
-
-          selection.setRng(rng);
-          editor.undoManager.add();
-
-          return TRUE;
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      });
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Add queryCommandState overrides
-      addCommands({
-        // Override justify commands
-        'JustifyLeft,JustifyCenter,JustifyRight,JustifyFull': function (command) {
-          var name = 'align' + command.substring(7);
-          var nodes = selection.isCollapsed() ? [dom.getParent(selection.getNode(), dom.isBlock)] : selection.getSelectedBlocks();
-          var matches = map(nodes, function (node) {
-            return !!formatter.matchNode(node, name);
-          });
-          return inArray(matches, TRUE) !== -1;
-        },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return elm;
+      },
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': function (command) {
-          return isFormatMatch(command);
-        },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      createFragment: function (html) {
+        return DOMUtils.DOM.createFragment(html);
+      },
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        mceBlockQuote: function () {
-          return isFormatMatch('blockquote');
-        },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      getWindowSize: function () {
+        return DOMUtils.DOM.getViewPort();
+      },
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        Outdent: function () {
-          var node;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      getSize: function (elm) {
+        var width, height;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (settings.inline_styles) {
-            if ((node = dom.getParent(selection.getStart(), dom.isBlock)) && parseInt(node.style.paddingLeft, 10) > 0) {
-              return TRUE;
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (elm.getBoundingClientRect) {
+          var rect = elm.getBoundingClientRect();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if ((node = dom.getParent(selection.getEnd(), dom.isBlock)) && parseInt(node.style.paddingLeft, 10) > 0) {
-              return TRUE;
-            }
-          }
-
-          return (
-            queryCommandState('InsertUnorderedList') ||
-            queryCommandState('InsertOrderedList') ||
-            (!settings.inline_styles && !!dom.getParent(selection.getNode(), 'BLOCKQUOTE'))
-          );
-        },
-
-        'InsertUnorderedList,InsertOrderedList': function (command) {
-          var list = dom.getParent(selection.getNode(), 'ul,ol');
-
-          return list &&
-            (
-              command === 'insertunorderedlist' && list.tagName === 'UL' ||
-              command === 'insertorderedlist' && list.tagName === 'OL'
-            );
-        }
-      }, 'state');
-
-      // Add queryCommandValue overrides
-      addCommands({
-        'FontSize,FontName': function (command) {
-          var value = 0, parent;
-
-          if ((parent = dom.getParent(selection.getNode(), 'span'))) {
-            if (command == 'fontsize') {
-              value = parent.style.fontSize;
-            } else {
-              value = parent.style.fontFamily.replace(/, /g, ',').replace(/[\'\"]/g, '').toLowerCase();
-            }
-          }
-
-          return value;
-        }
-      }, 'value');
-
-      // Add undo manager logic
-      addCommands({
-        Undo: function () {
-          editor.undoManager.undo();
-        },
-
-        Redo: function () {
-          editor.undoManager.redo();
-        }
-      });
-    };
-  }
-);
-
-/**
- * URI.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * This class handles parsing, modification and serialization of URI/URL strings.
- * @class tinymce.util.URI
- */
-define(
-  'tinymce.core.util.URI',
-  [
-    'global!document',
-    'tinymce.core.util.Tools'
-  ],
-  function (document, Tools) {
-    var each = Tools.each, trim = Tools.trim;
-    var queryParts = "source protocol authority userInfo user password host port relative path directory file query anchor".split(' ');
-    var DEFAULT_PORTS = {
-      'ftp': 21,
-      'http': 80,
-      'https': 443,
-      'mailto': 25
-    };
-
-    /**
-     * Constructs a new URI instance.
-     *
-     * @constructor
-     * @method URI
-     * @param {String} url URI string to parse.
-     * @param {Object} settings Optional settings object.
-     */
-    function URI(url, settings) {
-      var self = this, baseUri, baseUrl;
-
-      url = trim(url);
-      settings = self.settings = settings || {};
-      baseUri = settings.base_uri;
-
-      // Strange app protocol that isn't http/https or local anchor
-      // For example: mailto,skype,tel etc.
-      if (/^([\w\-]+):([^\/]{2})/i.test(url) || /^\s*#/.test(url)) {
-        self.source = url;
-        return;
-      }
-
-      var isProtocolRelative = url.indexOf('//') === 0;
-
-      // Absolute path with no host, fake host and protocol
-      if (url.indexOf('/') === 0 && !isProtocolRelative) {
-        url = (baseUri ? baseUri.protocol || 'http' : 'http') + '://mce_host' + url;
-      }
-
-      // Relative path http:// or protocol relative //path
-      if (!/^[\w\-]*:?\/\//.test(url)) {
-        baseUrl = settings.base_uri ? settings.base_uri.path : new URI(document.location.href).directory;
-        if (settings.base_uri.protocol === "") {
-          url = '//mce_host' + self.toAbsPath(baseUrl, url);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          width = Math.max(rect.width || (rect.right - rect.left), elm.offsetWidth);
+          height = Math.max(rect.height || (rect.bottom - rect.bottom), elm.offsetHeight);
</ins><span class="cx" style="display: block; padding: 0 10px">         } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          url = /([^#?]*)([#?]?.*)/.exec(url);
-          url = ((baseUri && baseUri.protocol) || 'http') + '://mce_host' + self.toAbsPath(baseUrl, url[1]) + url[2];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          width = elm.offsetWidth;
+          height = elm.offsetHeight;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Parse URL (Credits goes to Steave, http://blog.stevenlevithan.com/archives/parseuri)
-      url = url.replace(/@@/g, '(mce_at)'); // Zope 3 workaround, they use @@something
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return { width: width, height: height };
+      },
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /*jshint maxlen: 255 */
-      /*eslint max-len: 0 */
-      url = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(url);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      getPos: function (elm, root) {
+        return DOMUtils.DOM.getPos(elm, root || funcs.getContainer());
+      },
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      each(queryParts, function (v, i) {
-        var part = url[i];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      getContainer: function () {
+        return Env.container ? Env.container : document.body;
+      },
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Zope 3 workaround, they use @@something
-        if (part) {
-          part = part.replace(/\(mce_at\)/g, '@@');
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      getViewPort: function (win) {
+        return DOMUtils.DOM.getViewPort(win);
+      },
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        self[v] = part;
-      });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      get: function (id) {
+        return document.getElementById(id);
+      },
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (baseUri) {
-        if (!self.protocol) {
-          self.protocol = baseUri.protocol;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      addClass: function (elm, cls) {
+        return DOMUtils.DOM.addClass(elm, cls);
+      },
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (!self.userInfo) {
-          self.userInfo = baseUri.userInfo;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      removeClass: function (elm, cls) {
+        return DOMUtils.DOM.removeClass(elm, cls);
+      },
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (!self.port && self.host === 'mce_host') {
-          self.port = baseUri.port;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      hasClass: function (elm, cls) {
+        return DOMUtils.DOM.hasClass(elm, cls);
+      },
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (!self.host || self.host === 'mce_host') {
-          self.host = baseUri.host;
-        }
-
-        self.source = '';
-      }
-
-      if (isProtocolRelative) {
-        self.protocol = '';
-      }
-
-      //t.path = t.path || '/';
-    }
-
-    URI.prototype = {
-      /**
-       * Sets the internal path part of the URI.
-       *
-       * @method setPath
-       * @param {string} path Path string to set.
-       */
-      setPath: function (path) {
-        var self = this;
-
-        path = /^(.*?)\/?(\w+)?$/.exec(path);
-
-        // Update path parts
-        self.path = path[0];
-        self.directory = path[1];
-        self.file = path[2];
-
-        // Rebuild source
-        self.source = '';
-        self.getURI();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      toggleClass: function (elm, cls, state) {
+        return DOMUtils.DOM.toggleClass(elm, cls, state);
</ins><span class="cx" style="display: block; padding: 0 10px">       },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Converts the specified URI into a relative URI based on the current URI instance location.
-       *
-       * @method toRelative
-       * @param {String} uri URI to convert into a relative path/URI.
-       * @return {String} Relative URI from the point specified in the current URI instance.
-       * @example
-       * // Converts an absolute URL to an relative URL url will be somedir/somefile.htm
-       * var url = new tinymce.util.URI('http://www.site.com/dir/').toRelative('http://www.site.com/dir/somedir/somefile.htm');
-       */
-      toRelative: function (uri) {
-        var self = this, output;
-
-        if (uri === "./") {
-          return uri;
-        }
-
-        uri = new URI(uri, { base_uri: self });
-
-        // Not on same domain/port or protocol
-        if ((uri.host != 'mce_host' && self.host != uri.host && uri.host) || self.port != uri.port ||
-          (self.protocol != uri.protocol && uri.protocol !== "")) {
-          return uri.getURI();
-        }
-
-        var tu = self.getURI(), uu = uri.getURI();
-
-        // Allow usage of the base_uri when relative_urls = true
-        if (tu == uu || (tu.charAt(tu.length - 1) == "/" && tu.substr(0, tu.length - 1) == uu)) {
-          return tu;
-        }
-
-        output = self.toRelPath(self.path, uri.path);
-
-        // Add query
-        if (uri.query) {
-          output += '?' + uri.query;
-        }
-
-        // Add anchor
-        if (uri.anchor) {
-          output += '#' + uri.anchor;
-        }
-
-        return output;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      css: function (elm, name, value) {
+        return DOMUtils.DOM.setStyle(elm, name, value);
</ins><span class="cx" style="display: block; padding: 0 10px">       },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Converts the specified URI into a absolute URI based on the current URI instance location.
-       *
-       * @method toAbsolute
-       * @param {String} uri URI to convert into a relative path/URI.
-       * @param {Boolean} noHost No host and protocol prefix.
-       * @return {String} Absolute URI from the point specified in the current URI instance.
-       * @example
-       * // Converts an relative URL to an absolute URL url will be http://www.site.com/dir/somedir/somefile.htm
-       * var url = new tinymce.util.URI('http://www.site.com/dir/').toAbsolute('somedir/somefile.htm');
-       */
-      toAbsolute: function (uri, noHost) {
-        uri = new URI(uri, { base_uri: this });
-
-        return uri.getURI(noHost && this.isSameOrigin(uri));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      getRuntimeStyle: function (elm, name) {
+        return DOMUtils.DOM.getStyle(elm, name, true);
</ins><span class="cx" style="display: block; padding: 0 10px">       },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Determine whether the given URI has the same origin as this URI.  Based on RFC-6454.
-       * Supports default ports for protocols listed in DEFAULT_PORTS.  Unsupported protocols will fail safe: they
-       * won't match, if the port specifications differ.
-       *
-       * @method isSameOrigin
-       * @param {tinymce.util.URI} uri Uri instance to compare.
-       * @returns {Boolean} True if the origins are the same.
-       */
-      isSameOrigin: function (uri) {
-        if (this.host == uri.host && this.protocol == uri.protocol) {
-          if (this.port == uri.port) {
-            return true;
-          }
-
-          var defaultPort = DEFAULT_PORTS[this.protocol];
-          if (defaultPort && ((this.port || defaultPort) == (uri.port || defaultPort))) {
-            return true;
-          }
-        }
-
-        return false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      on: function (target, name, callback, scope) {
+        return DOMUtils.DOM.bind(target, name, callback, scope);
</ins><span class="cx" style="display: block; padding: 0 10px">       },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Converts a absolute path into a relative path.
-       *
-       * @method toRelPath
-       * @param {String} base Base point to convert the path from.
-       * @param {String} path Absolute path to convert into a relative path.
-       */
-      toRelPath: function (base, path) {
-        var items, breakPoint = 0, out = '', i, l;
-
-        // Split the paths
-        base = base.substring(0, base.lastIndexOf('/'));
-        base = base.split('/');
-        items = path.split('/');
-
-        if (base.length >= items.length) {
-          for (i = 0, l = base.length; i < l; i++) {
-            if (i >= items.length || base[i] != items[i]) {
-              breakPoint = i + 1;
-              break;
-            }
-          }
-        }
-
-        if (base.length < items.length) {
-          for (i = 0, l = items.length; i < l; i++) {
-            if (i >= base.length || base[i] != items[i]) {
-              breakPoint = i + 1;
-              break;
-            }
-          }
-        }
-
-        if (breakPoint === 1) {
-          return path;
-        }
-
-        for (i = 0, l = base.length - (breakPoint - 1); i < l; i++) {
-          out += "../";
-        }
-
-        for (i = breakPoint - 1, l = items.length; i < l; i++) {
-          if (i != breakPoint - 1) {
-            out += "/" + items[i];
-          } else {
-            out += items[i];
-          }
-        }
-
-        return out;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      off: function (target, name, callback) {
+        return DOMUtils.DOM.unbind(target, name, callback);
</ins><span class="cx" style="display: block; padding: 0 10px">       },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Converts a relative path into a absolute path.
-       *
-       * @method toAbsPath
-       * @param {String} base Base point to convert the path from.
-       * @param {String} path Relative path to convert into an absolute path.
-       */
-      toAbsPath: function (base, path) {
-        var i, nb = 0, o = [], tr, outPath;
-
-        // Split paths
-        tr = /\/$/.test(path) ? '/' : '';
-        base = base.split('/');
-        path = path.split('/');
-
-        // Remove empty chunks
-        each(base, function (k) {
-          if (k) {
-            o.push(k);
-          }
-        });
-
-        base = o;
-
-        // Merge relURLParts chunks
-        for (i = path.length - 1, o = []; i >= 0; i--) {
-          // Ignore empty or .
-          if (path[i].length === 0 || path[i] === ".") {
-            continue;
-          }
-
-          // Is parent
-          if (path[i] === '..') {
-            nb++;
-            continue;
-          }
-
-          // Move up
-          if (nb > 0) {
-            nb--;
-            continue;
-          }
-
-          o.push(path[i]);
-        }
-
-        i = base.length - nb;
-
-        // If /a/b/c or /
-        if (i <= 0) {
-          outPath = o.reverse().join('/');
-        } else {
-          outPath = base.slice(0, i).join('/') + '/' + o.reverse().join('/');
-        }
-
-        // Add front / if it's needed
-        if (outPath.indexOf('/') !== 0) {
-          outPath = '/' + outPath;
-        }
-
-        // Add traling / if it's needed
-        if (tr && outPath.lastIndexOf('/') !== outPath.length - 1) {
-          outPath += tr;
-        }
-
-        return outPath;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      fire: function (target, name, args) {
+        return DOMUtils.DOM.fire(target, name, args);
</ins><span class="cx" style="display: block; padding: 0 10px">       },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Returns the full URI of the internal structure.
-       *
-       * @method getURI
-       * @param {Boolean} noProtoHost Optional no host and protocol part. Defaults to false.
-       */
-      getURI: function (noProtoHost) {
-        var s, self = this;
-
-        // Rebuild source
-        if (!self.source || noProtoHost) {
-          s = '';
-
-          if (!noProtoHost) {
-            if (self.protocol) {
-              s += self.protocol + '://';
-            } else {
-              s += '//';
-            }
-
-            if (self.userInfo) {
-              s += self.userInfo + '@';
-            }
-
-            if (self.host) {
-              s += self.host;
-            }
-
-            if (self.port) {
-              s += ':' + self.port;
-            }
-          }
-
-          if (self.path) {
-            s += self.path;
-          }
-
-          if (self.query) {
-            s += '?' + self.query;
-          }
-
-          if (self.anchor) {
-            s += '#' + self.anchor;
-          }
-
-          self.source = s;
-        }
-
-        return self.source;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      innerHtml: function (elm, html) {
+        // Workaround for <div> in <p> bug on IE 8 #6178
+        DOMUtils.DOM.setHTML(elm, html);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    URI.parseDataUri = function (uri) {
-      var type, matches;
-
-      uri = decodeURIComponent(uri).split(',');
-
-      matches = /data:([^;]+)/.exec(uri[0]);
-      if (matches) {
-        type = matches[1];
-      }
-
-      return {
-        type: type,
-        data: uri[1]
-      };
-    };
-
-    URI.getDocumentBaseUrl = function (loc) {
-      var baseUrl;
-
-      // Pass applewebdata:// and other non web protocols though
-      if (loc.protocol.indexOf('http') !== 0 && loc.protocol !== 'file:') {
-        baseUrl = loc.href;
-      } else {
-        baseUrl = loc.protocol + '//' + loc.host + loc.pathname;
-      }
-
-      if (/^[^:]+:\/\/\/?[^\/]+\//.test(baseUrl)) {
-        baseUrl = baseUrl.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
-
-        if (!/[\/\\]$/.test(baseUrl)) {
-          baseUrl += '/';
-        }
-      }
-
-      return baseUrl;
-    };
-
-    return URI;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return funcs;
</ins><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px">  * Class.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -30951,6 +21715,90 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Binding.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This class gets dynamically extended to provide a binding between two models. This makes it possible to
+ * sync the state of two properties in two models by a layer of abstraction.
+ *
+ * @private
+ * @class tinymce.data.Binding
+ */
+define(
+  'tinymce.core.data.Binding',
+  [
+  ],
+  function () {
+    /**
+     * Constructs a new bidning.
+     *
+     * @constructor
+     * @method Binding
+     * @param {Object} settings Settings to the binding.
+     */
+    function Binding(settings) {
+      this.create = settings.create;
+    }
+
+    /**
+     * Creates a binding for a property on a model.
+     *
+     * @method create
+     * @param {tinymce.data.ObservableObject} model Model to create binding to.
+     * @param {String} name Name of property to bind.
+     * @return {tinymce.data.Binding} Binding instance.
+     */
+    Binding.create = function (model, name) {
+      return new Binding({
+        create: function (otherModel, otherName) {
+          var bindings;
+
+          function fromSelfToOther(e) {
+            otherModel.set(otherName, e.value);
+          }
+
+          function fromOtherToSelf(e) {
+            model.set(name, e.value);
+          }
+
+          otherModel.on('change:' + otherName, fromOtherToSelf);
+          model.on('change:' + name, fromSelfToOther);
+
+          // Keep track of the bindings
+          bindings = otherModel._bindings;
+
+          if (!bindings) {
+            bindings = otherModel._bindings = [];
+
+            otherModel.on('destroy', function () {
+              var i = bindings.length;
+
+              while (i--) {
+                bindings[i]();
+              }
+            });
+          }
+
+          bindings.push(function () {
+            model.off('change:' + name, fromSelfToOther);
+          });
+
+          return model.get(name);
+        }
+      });
+    };
+
+    return Binding;
+  }
+);
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * Observable.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -31088,90 +21936,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Binding.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * This class gets dynamically extended to provide a binding between two models. This makes it possible to
- * sync the state of two properties in two models by a layer of abstraction.
- *
- * @private
- * @class tinymce.data.Binding
- */
-define(
-  'tinymce.core.data.Binding',
-  [
-  ],
-  function () {
-    /**
-     * Constructs a new bidning.
-     *
-     * @constructor
-     * @method Binding
-     * @param {Object} settings Settings to the binding.
-     */
-    function Binding(settings) {
-      this.create = settings.create;
-    }
-
-    /**
-     * Creates a binding for a property on a model.
-     *
-     * @method create
-     * @param {tinymce.data.ObservableObject} model Model to create binding to.
-     * @param {String} name Name of property to bind.
-     * @return {tinymce.data.Binding} Binding instance.
-     */
-    Binding.create = function (model, name) {
-      return new Binding({
-        create: function (otherModel, otherName) {
-          var bindings;
-
-          function fromSelfToOther(e) {
-            otherModel.set(otherName, e.value);
-          }
-
-          function fromOtherToSelf(e) {
-            model.set(name, e.value);
-          }
-
-          otherModel.on('change:' + otherName, fromOtherToSelf);
-          model.on('change:' + name, fromSelfToOther);
-
-          // Keep track of the bindings
-          bindings = otherModel._bindings;
-
-          if (!bindings) {
-            bindings = otherModel._bindings = [];
-
-            otherModel.on('destroy', function () {
-              var i = bindings.length;
-
-              while (i--) {
-                bindings[i]();
-              }
-            });
-          }
-
-          bindings.push(function () {
-            model.off('change:' + name, fromSelfToOther);
-          });
-
-          return model.get(name);
-        }
-      });
-    };
-
-    return Binding;
-  }
-);
-/**
</del><span class="cx" style="display: block; padding: 0 10px">  * ObservableObject.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -32185,142 +22949,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * DomUtils.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * Private UI DomUtils proxy.
- *
- * @private
- * @class tinymce.ui.DomUtils
- */
-define(
-  'tinymce.core.ui.DomUtils',
-  [
-    "tinymce.core.Env",
-    "tinymce.core.util.Tools",
-    "tinymce.core.dom.DOMUtils"
-  ],
-  function (Env, Tools, DOMUtils) {
-    "use strict";
-
-    var count = 0;
-
-    var funcs = {
-      id: function () {
-        return 'mceu_' + (count++);
-      },
-
-      create: function (name, attrs, children) {
-        var elm = document.createElement(name);
-
-        DOMUtils.DOM.setAttribs(elm, attrs);
-
-        if (typeof children === 'string') {
-          elm.innerHTML = children;
-        } else {
-          Tools.each(children, function (child) {
-            if (child.nodeType) {
-              elm.appendChild(child);
-            }
-          });
-        }
-
-        return elm;
-      },
-
-      createFragment: function (html) {
-        return DOMUtils.DOM.createFragment(html);
-      },
-
-      getWindowSize: function () {
-        return DOMUtils.DOM.getViewPort();
-      },
-
-      getSize: function (elm) {
-        var width, height;
-
-        if (elm.getBoundingClientRect) {
-          var rect = elm.getBoundingClientRect();
-
-          width = Math.max(rect.width || (rect.right - rect.left), elm.offsetWidth);
-          height = Math.max(rect.height || (rect.bottom - rect.bottom), elm.offsetHeight);
-        } else {
-          width = elm.offsetWidth;
-          height = elm.offsetHeight;
-        }
-
-        return { width: width, height: height };
-      },
-
-      getPos: function (elm, root) {
-        return DOMUtils.DOM.getPos(elm, root || funcs.getContainer());
-      },
-
-      getContainer: function () {
-        return Env.container ? Env.container : document.body;
-      },
-
-      getViewPort: function (win) {
-        return DOMUtils.DOM.getViewPort(win);
-      },
-
-      get: function (id) {
-        return document.getElementById(id);
-      },
-
-      addClass: function (elm, cls) {
-        return DOMUtils.DOM.addClass(elm, cls);
-      },
-
-      removeClass: function (elm, cls) {
-        return DOMUtils.DOM.removeClass(elm, cls);
-      },
-
-      hasClass: function (elm, cls) {
-        return DOMUtils.DOM.hasClass(elm, cls);
-      },
-
-      toggleClass: function (elm, cls, state) {
-        return DOMUtils.DOM.toggleClass(elm, cls, state);
-      },
-
-      css: function (elm, name, value) {
-        return DOMUtils.DOM.setStyle(elm, name, value);
-      },
-
-      getRuntimeStyle: function (elm, name) {
-        return DOMUtils.DOM.getStyle(elm, name, true);
-      },
-
-      on: function (target, name, callback, scope) {
-        return DOMUtils.DOM.bind(target, name, callback, scope);
-      },
-
-      off: function (target, name, callback) {
-        return DOMUtils.DOM.unbind(target, name, callback);
-      },
-
-      fire: function (target, name, args) {
-        return DOMUtils.DOM.fire(target, name, args);
-      },
-
-      innerHtml: function (elm, html) {
-        // Workaround for <div> in <p> bug on IE 8 #6178
-        DOMUtils.DOM.setHTML(elm, html);
-      }
-    };
-
-    return funcs;
-  }
-);
-/**
</del><span class="cx" style="display: block; padding: 0 10px">  * BoxUtils.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -33967,6 +24595,949 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Movable.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * Movable mixin. Makes controls movable absolute and relative to other elements.
+ *
+ * @mixin tinymce.ui.Movable
+ */
+define(
+  'tinymce.core.ui.Movable',
+  [
+    "tinymce.core.ui.DomUtils"
+  ],
+  function (DomUtils) {
+    "use strict";
+
+    function calculateRelativePosition(ctrl, targetElm, rel) {
+      var ctrlElm, pos, x, y, selfW, selfH, targetW, targetH, viewport, size;
+
+      viewport = DomUtils.getViewPort();
+
+      // Get pos of target
+      pos = DomUtils.getPos(targetElm);
+      x = pos.x;
+      y = pos.y;
+
+      if (ctrl.state.get('fixed') && DomUtils.getRuntimeStyle(document.body, 'position') == 'static') {
+        x -= viewport.x;
+        y -= viewport.y;
+      }
+
+      // Get size of self
+      ctrlElm = ctrl.getEl();
+      size = DomUtils.getSize(ctrlElm);
+      selfW = size.width;
+      selfH = size.height;
+
+      // Get size of target
+      size = DomUtils.getSize(targetElm);
+      targetW = size.width;
+      targetH = size.height;
+
+      // Parse align string
+      rel = (rel || '').split('');
+
+      // Target corners
+      if (rel[0] === 'b') {
+        y += targetH;
+      }
+
+      if (rel[1] === 'r') {
+        x += targetW;
+      }
+
+      if (rel[0] === 'c') {
+        y += Math.round(targetH / 2);
+      }
+
+      if (rel[1] === 'c') {
+        x += Math.round(targetW / 2);
+      }
+
+      // Self corners
+      if (rel[3] === 'b') {
+        y -= selfH;
+      }
+
+      if (rel[4] === 'r') {
+        x -= selfW;
+      }
+
+      if (rel[3] === 'c') {
+        y -= Math.round(selfH / 2);
+      }
+
+      if (rel[4] === 'c') {
+        x -= Math.round(selfW / 2);
+      }
+
+      return {
+        x: x,
+        y: y,
+        w: selfW,
+        h: selfH
+      };
+    }
+
+    return {
+      /**
+       * Tests various positions to get the most suitable one.
+       *
+       * @method testMoveRel
+       * @param {DOMElement} elm Element to position against.
+       * @param {Array} rels Array with relative positions.
+       * @return {String} Best suitable relative position.
+       */
+      testMoveRel: function (elm, rels) {
+        var viewPortRect = DomUtils.getViewPort();
+
+        for (var i = 0; i < rels.length; i++) {
+          var pos = calculateRelativePosition(this, elm, rels[i]);
+
+          if (this.state.get('fixed')) {
+            if (pos.x > 0 && pos.x + pos.w < viewPortRect.w && pos.y > 0 && pos.y + pos.h < viewPortRect.h) {
+              return rels[i];
+            }
+          } else {
+            if (pos.x > viewPortRect.x && pos.x + pos.w < viewPortRect.w + viewPortRect.x &&
+              pos.y > viewPortRect.y && pos.y + pos.h < viewPortRect.h + viewPortRect.y) {
+              return rels[i];
+            }
+          }
+        }
+
+        return rels[0];
+      },
+
+      /**
+       * Move relative to the specified element.
+       *
+       * @method moveRel
+       * @param {Element} elm Element to move relative to.
+       * @param {String} rel Relative mode. For example: br-tl.
+       * @return {tinymce.ui.Control} Current control instance.
+       */
+      moveRel: function (elm, rel) {
+        if (typeof rel != 'string') {
+          rel = this.testMoveRel(elm, rel);
+        }
+
+        var pos = calculateRelativePosition(this, elm, rel);
+        return this.moveTo(pos.x, pos.y);
+      },
+
+      /**
+       * Move by a relative x, y values.
+       *
+       * @method moveBy
+       * @param {Number} dx Relative x position.
+       * @param {Number} dy Relative y position.
+       * @return {tinymce.ui.Control} Current control instance.
+       */
+      moveBy: function (dx, dy) {
+        var self = this, rect = self.layoutRect();
+
+        self.moveTo(rect.x + dx, rect.y + dy);
+
+        return self;
+      },
+
+      /**
+       * Move to absolute position.
+       *
+       * @method moveTo
+       * @param {Number} x Absolute x position.
+       * @param {Number} y Absolute y position.
+       * @return {tinymce.ui.Control} Current control instance.
+       */
+      moveTo: function (x, y) {
+        var self = this;
+
+        // TODO: Move this to some global class
+        function constrain(value, max, size) {
+          if (value < 0) {
+            return 0;
+          }
+
+          if (value + size > max) {
+            value = max - size;
+            return value < 0 ? 0 : value;
+          }
+
+          return value;
+        }
+
+        if (self.settings.constrainToViewport) {
+          var viewPortRect = DomUtils.getViewPort(window);
+          var layoutRect = self.layoutRect();
+
+          x = constrain(x, viewPortRect.w + viewPortRect.x, layoutRect.w);
+          y = constrain(y, viewPortRect.h + viewPortRect.y, layoutRect.h);
+        }
+
+        if (self.state.get('rendered')) {
+          self.layoutRect({ x: x, y: y }).repaint();
+        } else {
+          self.settings.x = x;
+          self.settings.y = y;
+        }
+
+        self.fire('move', { x: x, y: y });
+
+        return self;
+      }
+    };
+  }
+);
+/**
+ * Tooltip.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * Creates a tooltip instance.
+ *
+ * @-x-less ToolTip.less
+ * @class tinymce.ui.ToolTip
+ * @extends tinymce.ui.Control
+ * @mixes tinymce.ui.Movable
+ */
+define(
+  'tinymce.core.ui.Tooltip',
+  [
+    "tinymce.core.ui.Control",
+    "tinymce.core.ui.Movable"
+  ],
+  function (Control, Movable) {
+    return Control.extend({
+      Mixins: [Movable],
+
+      Defaults: {
+        classes: 'widget tooltip tooltip-n'
+      },
+
+      /**
+       * Renders the control as a HTML string.
+       *
+       * @method renderHtml
+       * @return {String} HTML representing the control.
+       */
+      renderHtml: function () {
+        var self = this, prefix = self.classPrefix;
+
+        return (
+          '<div id="' + self._id + '" class="' + self.classes + '" role="presentation">' +
+          '<div class="' + prefix + 'tooltip-arrow"></div>' +
+          '<div class="' + prefix + 'tooltip-inner">' + self.encode(self.state.get('text')) + '</div>' +
+          '</div>'
+        );
+      },
+
+      bindStates: function () {
+        var self = this;
+
+        self.state.on('change:text', function (e) {
+          self.getEl().lastChild.innerHTML = self.encode(e.value);
+        });
+
+        return self._super();
+      },
+
+      /**
+       * Repaints the control after a layout operation.
+       *
+       * @method repaint
+       */
+      repaint: function () {
+        var self = this, style, rect;
+
+        style = self.getEl().style;
+        rect = self._layoutRect;
+
+        style.left = rect.x + 'px';
+        style.top = rect.y + 'px';
+        style.zIndex = 0xFFFF + 0xFFFF;
+      }
+    });
+  }
+);
+/**
+ * Widget.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * Widget base class a widget is a control that has a tooltip and some basic states.
+ *
+ * @class tinymce.ui.Widget
+ * @extends tinymce.ui.Control
+ */
+define(
+  'tinymce.core.ui.Widget',
+  [
+    "tinymce.core.ui.Control",
+    "tinymce.core.ui.Tooltip"
+  ],
+  function (Control, Tooltip) {
+    "use strict";
+
+    var tooltip;
+
+    var Widget = Control.extend({
+      /**
+       * Constructs a instance with the specified settings.
+       *
+       * @constructor
+       * @param {Object} settings Name/value object with settings.
+       * @setting {String} tooltip Tooltip text to display when hovering.
+       * @setting {Boolean} autofocus True if the control should be focused when rendered.
+       * @setting {String} text Text to display inside widget.
+       */
+      init: function (settings) {
+        var self = this;
+
+        self._super(settings);
+        settings = self.settings;
+        self.canFocus = true;
+
+        if (settings.tooltip && Widget.tooltips !== false) {
+          self.on('mouseenter', function (e) {
+            var tooltip = self.tooltip().moveTo(-0xFFFF);
+
+            if (e.control == self) {
+              var rel = tooltip.text(settings.tooltip).show().testMoveRel(self.getEl(), ['bc-tc', 'bc-tl', 'bc-tr']);
+
+              tooltip.classes.toggle('tooltip-n', rel == 'bc-tc');
+              tooltip.classes.toggle('tooltip-nw', rel == 'bc-tl');
+              tooltip.classes.toggle('tooltip-ne', rel == 'bc-tr');
+
+              tooltip.moveRel(self.getEl(), rel);
+            } else {
+              tooltip.hide();
+            }
+          });
+
+          self.on('mouseleave mousedown click', function () {
+            self.tooltip().hide();
+          });
+        }
+
+        self.aria('label', settings.ariaLabel || settings.tooltip);
+      },
+
+      /**
+       * Returns the current tooltip instance.
+       *
+       * @method tooltip
+       * @return {tinymce.ui.Tooltip} Tooltip instance.
+       */
+      tooltip: function () {
+        if (!tooltip) {
+          tooltip = new Tooltip({ type: 'tooltip' });
+          tooltip.renderTo();
+        }
+
+        return tooltip;
+      },
+
+      /**
+       * Called after the control has been rendered.
+       *
+       * @method postRender
+       */
+      postRender: function () {
+        var self = this, settings = self.settings;
+
+        self._super();
+
+        if (!self.parent() && (settings.width || settings.height)) {
+          self.initLayoutRect();
+          self.repaint();
+        }
+
+        if (settings.autofocus) {
+          self.focus();
+        }
+      },
+
+      bindStates: function () {
+        var self = this;
+
+        function disable(state) {
+          self.aria('disabled', state);
+          self.classes.toggle('disabled', state);
+        }
+
+        function active(state) {
+          self.aria('pressed', state);
+          self.classes.toggle('active', state);
+        }
+
+        self.state.on('change:disabled', function (e) {
+          disable(e.value);
+        });
+
+        self.state.on('change:active', function (e) {
+          active(e.value);
+        });
+
+        if (self.state.get('disabled')) {
+          disable(true);
+        }
+
+        if (self.state.get('active')) {
+          active(true);
+        }
+
+        return self._super();
+      },
+
+      /**
+       * Removes the current control from DOM and from UI collections.
+       *
+       * @method remove
+       * @return {tinymce.ui.Control} Current control instance.
+       */
+      remove: function () {
+        this._super();
+
+        if (tooltip) {
+          tooltip.remove();
+          tooltip = null;
+        }
+      }
+    });
+
+    return Widget;
+  }
+);
+
+/**
+ * Progress.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * Progress control.
+ *
+ * @-x-less Progress.less
+ * @class tinymce.ui.Progress
+ * @extends tinymce.ui.Control
+ */
+define(
+  'tinymce.core.ui.Progress',
+  [
+    "tinymce.core.ui.Widget"
+  ],
+  function (Widget) {
+    "use strict";
+
+    return Widget.extend({
+      Defaults: {
+        value: 0
+      },
+
+      init: function (settings) {
+        var self = this;
+
+        self._super(settings);
+        self.classes.add('progress');
+
+        if (!self.settings.filter) {
+          self.settings.filter = function (value) {
+            return Math.round(value);
+          };
+        }
+      },
+
+      renderHtml: function () {
+        var self = this, id = self._id, prefix = this.classPrefix;
+
+        return (
+          '<div id="' + id + '" class="' + self.classes + '">' +
+          '<div class="' + prefix + 'bar-container">' +
+          '<div class="' + prefix + 'bar"></div>' +
+          '</div>' +
+          '<div class="' + prefix + 'text">0%</div>' +
+          '</div>'
+        );
+      },
+
+      postRender: function () {
+        var self = this;
+
+        self._super();
+        self.value(self.settings.value);
+
+        return self;
+      },
+
+      bindStates: function () {
+        var self = this;
+
+        function setValue(value) {
+          value = self.settings.filter(value);
+          self.getEl().lastChild.innerHTML = value + '%';
+          self.getEl().firstChild.firstChild.style.width = value + '%';
+        }
+
+        self.state.on('change:value', function (e) {
+          setValue(e.value);
+        });
+
+        setValue(self.state.get('value'));
+
+        return self._super();
+      }
+    });
+  }
+);
+/**
+ * Notification.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * Creates a notification instance.
+ *
+ * @-x-less Notification.less
+ * @class tinymce.ui.Notification
+ * @extends tinymce.ui.Container
+ * @mixes tinymce.ui.Movable
+ */
+define(
+  'tinymce.core.ui.Notification',
+  [
+    "tinymce.core.ui.Control",
+    "tinymce.core.ui.Movable",
+    "tinymce.core.ui.Progress",
+    "tinymce.core.util.Delay"
+  ],
+  function (Control, Movable, Progress, Delay) {
+    var updateLiveRegion = function (ctx, text) {
+      ctx.getEl().lastChild.textContent = text + (ctx.progressBar ? ' ' + ctx.progressBar.value() + '%' : '');
+    };
+
+    return Control.extend({
+      Mixins: [Movable],
+
+      Defaults: {
+        classes: 'widget notification'
+      },
+
+      init: function (settings) {
+        var self = this;
+
+        self._super(settings);
+
+        self.maxWidth = settings.maxWidth;
+
+        if (settings.text) {
+          self.text(settings.text);
+        }
+
+        if (settings.icon) {
+          self.icon = settings.icon;
+        }
+
+        if (settings.color) {
+          self.color = settings.color;
+        }
+
+        if (settings.type) {
+          self.classes.add('notification-' + settings.type);
+        }
+
+        if (settings.timeout && (settings.timeout < 0 || settings.timeout > 0) && !settings.closeButton) {
+          self.closeButton = false;
+        } else {
+          self.classes.add('has-close');
+          self.closeButton = true;
+        }
+
+        if (settings.progressBar) {
+          self.progressBar = new Progress();
+        }
+
+        self.on('click', function (e) {
+          if (e.target.className.indexOf(self.classPrefix + 'close') != -1) {
+            self.close();
+          }
+        });
+      },
+
+      /**
+       * Renders the control as a HTML string.
+       *
+       * @method renderHtml
+       * @return {String} HTML representing the control.
+       */
+      renderHtml: function () {
+        var self = this, prefix = self.classPrefix, icon = '', closeButton = '', progressBar = '', notificationStyle = '';
+
+        if (self.icon) {
+          icon = '<i class="' + prefix + 'ico' + ' ' + prefix + 'i-' + self.icon + '"></i>';
+        }
+
+        notificationStyle = ' style="max-width: ' + self.maxWidth + 'px;' + (self.color ? 'background-color: ' + self.color + ';"' : '"');
+
+        if (self.closeButton) {
+          closeButton = '<button type="button" class="' + prefix + 'close" aria-hidden="true">\u00d7</button>';
+        }
+
+        if (self.progressBar) {
+          progressBar = self.progressBar.renderHtml();
+        }
+
+        return (
+          '<div id="' + self._id + '" class="' + self.classes + '"' + notificationStyle + ' role="presentation">' +
+          icon +
+          '<div class="' + prefix + 'notification-inner">' + self.state.get('text') + '</div>' +
+          progressBar +
+          closeButton +
+          '<div style="clip: rect(1px, 1px, 1px, 1px);height: 1px;overflow: hidden;position: absolute;width: 1px;"' +
+          ' aria-live="assertive" aria-relevant="additions" aria-atomic="true"></div>' +
+          '</div>'
+        );
+      },
+
+      postRender: function () {
+        var self = this;
+
+        Delay.setTimeout(function () {
+          self.$el.addClass(self.classPrefix + 'in');
+          updateLiveRegion(self, self.state.get('text'));
+        }, 100);
+
+        return self._super();
+      },
+
+      bindStates: function () {
+        var self = this;
+
+        self.state.on('change:text', function (e) {
+          self.getEl().firstChild.innerHTML = e.value;
+          updateLiveRegion(self, e.value);
+        });
+        if (self.progressBar) {
+          self.progressBar.bindStates();
+          self.progressBar.state.on('change:value', function (e) {
+            updateLiveRegion(self, self.state.get('text'));
+          });
+        }
+        return self._super();
+      },
+
+      close: function () {
+        var self = this;
+
+        if (!self.fire('close').isDefaultPrevented()) {
+          self.remove();
+        }
+
+        return self;
+      },
+
+      /**
+       * Repaints the control after a layout operation.
+       *
+       * @method repaint
+       */
+      repaint: function () {
+        var self = this, style, rect;
+
+        style = self.getEl().style;
+        rect = self._layoutRect;
+
+        style.left = rect.x + 'px';
+        style.top = rect.y + 'px';
+
+        // Hardcoded arbitrary z-value because we want the
+        // notifications under the other windows
+        style.zIndex = 0xFFFF - 1;
+      }
+    });
+  }
+);
+/**
+ * NotificationManagerImpl.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.ui.NotificationManagerImpl',
+  [
+    'ephox.katamari.api.Arr',
+    'tinymce.core.ui.DomUtils',
+    'tinymce.core.ui.Notification',
+    'tinymce.core.util.Tools'
+  ],
+  function (Arr, DomUtils, Notification, Tools) {
+    return function (editor) {
+      var getEditorContainer = function (editor) {
+        return editor.inline ? editor.getElement() : editor.getContentAreaContainer();
+      };
+
+      var getContainerWidth = function () {
+        var container = getEditorContainer(editor);
+        return DomUtils.getSize(container).width;
+      };
+
+      // Since the viewport will change based on the present notifications, we need to move them all to the
+      // top left of the viewport to give an accurate size measurement so we can position them later.
+      var prePositionNotifications = function (notifications) {
+        Arr.each(notifications, function (notification) {
+          notification.moveTo(0, 0);
+        });
+      };
+
+      var positionNotifications = function (notifications) {
+        if (notifications.length > 0) {
+          var firstItem = notifications.slice(0, 1)[0];
+          var container = getEditorContainer(editor);
+          firstItem.moveRel(container, 'tc-tc');
+          Arr.each(notifications, function (notification, index) {
+            if (index > 0) {
+              notification.moveRel(notifications[index - 1].getEl(), 'bc-tc');
+            }
+          });
+        }
+      };
+
+      var reposition = function (notifications) {
+        prePositionNotifications(notifications);
+        positionNotifications(notifications);
+      };
+
+      var open = function (args, closeCallback) {
+        var extendedArgs = Tools.extend(args, { maxWidth: getContainerWidth() });
+        var notif = new Notification(extendedArgs);
+        notif.args = extendedArgs;
+
+        //If we have a timeout value
+        if (extendedArgs.timeout > 0) {
+          notif.timer = setTimeout(function () {
+            notif.close();
+            closeCallback();
+          }, extendedArgs.timeout);
+        }
+
+        notif.on('close', function () {
+          closeCallback();
+        });
+
+        notif.renderTo();
+
+        return notif;
+      };
+
+      var close = function (notification) {
+        notification.close();
+      };
+
+      var getArgs = function (notification) {
+        return notification.args;
+      };
+
+      return {
+        open: open,
+        close: close,
+        reposition: reposition,
+        getArgs: getArgs
+      };
+    };
+  }
+);
+
+/**
+ * NotificationManager.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This class handles the creation of TinyMCE's notifications.
+ *
+ * @class tinymce.NotificationManager
+ * @example
+ * // Opens a new notification of type "error" with text "An error occurred."
+ * tinymce.activeEditor.notificationManager.open({
+ *    text: 'An error occurred.',
+ *    type: 'error'
+ * });
+ */
+define(
+  'tinymce.core.api.NotificationManager',
+  [
+    'ephox.katamari.api.Arr',
+    'ephox.katamari.api.Option',
+    'tinymce.core.EditorView',
+    'tinymce.core.ui.NotificationManagerImpl',
+    'tinymce.core.util.Delay'
+  ],
+  function (Arr, Option, EditorView, NotificationManagerImpl, Delay) {
+    return function (editor) {
+      var notifications = [];
+
+      var getImplementation = function () {
+        var theme = editor.theme;
+        return theme.getNotificationManagerImpl ? theme.getNotificationManagerImpl() : NotificationManagerImpl(editor);
+      };
+
+      var getTopNotification = function () {
+        return Option.from(notifications[0]);
+      };
+
+      var isEqual = function (a, b) {
+        return a.type === b.type && a.text === b.text && !a.progressBar && !a.timeout && !b.progressBar && !b.timeout;
+      };
+
+      var reposition = function () {
+        getImplementation().reposition(notifications);
+      };
+
+      var addNotification = function (notification) {
+        notifications.push(notification);
+      };
+
+      var closeNotification = function (notification) {
+        Arr.findIndex(notifications, function (otherNotification) {
+          return otherNotification === notification;
+        }).each(function (index) {
+          // Mutate here since third party might have stored away the window array
+          // TODO: Consider breaking this api
+          notifications.splice(index, 1);
+        });
+      };
+
+      var open = function (args) {
+        // Never open notification if editor has been removed.
+        if (editor.removed || !EditorView.isEditorAttachedToDom(editor)) {
+          return;
+        }
+
+        return Arr.find(notifications, function (notification) {
+          return isEqual(getImplementation().getArgs(notification), args);
+        }).getOrThunk(function () {
+          editor.editorManager.setActive(editor);
+
+          var notification = getImplementation().open(args, function () {
+            closeNotification(notification);
+            reposition();
+          });
+
+          addNotification(notification);
+          reposition();
+          return notification;
+        });
+      };
+
+      var close = function () {
+        getTopNotification().each(function (notification) {
+          getImplementation().close(notification);
+          closeNotification(notification);
+          reposition();
+        });
+      };
+
+      var getNotifications = function () {
+        return notifications;
+      };
+
+      var registerEvents = function (editor) {
+        editor.on('SkinLoaded', function () {
+          var serviceMessage = editor.settings.service_message;
+
+          if (serviceMessage) {
+            open({
+              text: serviceMessage,
+              type: 'warning',
+              timeout: 0,
+              icon: ''
+            });
+          }
+        });
+
+        editor.on('ResizeEditor ResizeWindow', function () {
+          Delay.requestAnimationFrame(reposition);
+        });
+
+        editor.on('remove', function () {
+          Arr.each(notifications, function (notification) {
+            getImplementation().close(notification);
+          });
+        });
+      };
+
+      registerEvents(editor);
+
+      return {
+        /**
+         * Opens a new notification.
+         *
+         * @method open
+         * @param {Object} args Optional name/value settings collection contains things like timeout/color/message etc.
+         */
+        open: open,
+
+        /**
+         * Closes the top most notification.
+         *
+         * @method close
+         */
+        close: close,
+
+        /**
+         * Returns the currently opened notification objects.
+         *
+         * @method getNotifications
+         * @return {Array} Array of the currently opened notifications.
+         */
+        getNotifications: getNotifications
+      };
+    };
+  }
+);
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * Factory.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -34017,6 +25588,23 @@
</span><span class="cx" style="display: block; padding: 0 10px">       },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * Returns ui control module by name.
+       *
+       * @method get
+       * @param {String} type Type get.
+       * @return {Object} Module or undefined.
+       */
+      get: function (type) {
+        var lctype = type.toLowerCase();
+        var controlType = types.hasOwnProperty(lctype) ? types[lctype] : null;
+        if (controlType === null) {
+          throw new Error("Could not find module for type: " + type);
+        }
+
+        return controlType;
+      },
+
+      /**
</ins><span class="cx" style="display: block; padding: 0 10px">        * Creates a new control instance based on the settings provided. The instance created will be
</span><span class="cx" style="display: block; padding: 0 10px">        * based on the specified type property it can also create whole structures of components out of
</span><span class="cx" style="display: block; padding: 0 10px">        * the specified JSON object.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -35361,210 +26949,6 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Movable.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * Movable mixin. Makes controls movable absolute and relative to other elements.
- *
- * @mixin tinymce.ui.Movable
- */
-define(
-  'tinymce.core.ui.Movable',
-  [
-    "tinymce.core.ui.DomUtils"
-  ],
-  function (DomUtils) {
-    "use strict";
-
-    function calculateRelativePosition(ctrl, targetElm, rel) {
-      var ctrlElm, pos, x, y, selfW, selfH, targetW, targetH, viewport, size;
-
-      viewport = DomUtils.getViewPort();
-
-      // Get pos of target
-      pos = DomUtils.getPos(targetElm);
-      x = pos.x;
-      y = pos.y;
-
-      if (ctrl.state.get('fixed') && DomUtils.getRuntimeStyle(document.body, 'position') == 'static') {
-        x -= viewport.x;
-        y -= viewport.y;
-      }
-
-      // Get size of self
-      ctrlElm = ctrl.getEl();
-      size = DomUtils.getSize(ctrlElm);
-      selfW = size.width;
-      selfH = size.height;
-
-      // Get size of target
-      size = DomUtils.getSize(targetElm);
-      targetW = size.width;
-      targetH = size.height;
-
-      // Parse align string
-      rel = (rel || '').split('');
-
-      // Target corners
-      if (rel[0] === 'b') {
-        y += targetH;
-      }
-
-      if (rel[1] === 'r') {
-        x += targetW;
-      }
-
-      if (rel[0] === 'c') {
-        y += Math.round(targetH / 2);
-      }
-
-      if (rel[1] === 'c') {
-        x += Math.round(targetW / 2);
-      }
-
-      // Self corners
-      if (rel[3] === 'b') {
-        y -= selfH;
-      }
-
-      if (rel[4] === 'r') {
-        x -= selfW;
-      }
-
-      if (rel[3] === 'c') {
-        y -= Math.round(selfH / 2);
-      }
-
-      if (rel[4] === 'c') {
-        x -= Math.round(selfW / 2);
-      }
-
-      return {
-        x: x,
-        y: y,
-        w: selfW,
-        h: selfH
-      };
-    }
-
-    return {
-      /**
-       * Tests various positions to get the most suitable one.
-       *
-       * @method testMoveRel
-       * @param {DOMElement} elm Element to position against.
-       * @param {Array} rels Array with relative positions.
-       * @return {String} Best suitable relative position.
-       */
-      testMoveRel: function (elm, rels) {
-        var viewPortRect = DomUtils.getViewPort();
-
-        for (var i = 0; i < rels.length; i++) {
-          var pos = calculateRelativePosition(this, elm, rels[i]);
-
-          if (this.state.get('fixed')) {
-            if (pos.x > 0 && pos.x + pos.w < viewPortRect.w && pos.y > 0 && pos.y + pos.h < viewPortRect.h) {
-              return rels[i];
-            }
-          } else {
-            if (pos.x > viewPortRect.x && pos.x + pos.w < viewPortRect.w + viewPortRect.x &&
-              pos.y > viewPortRect.y && pos.y + pos.h < viewPortRect.h + viewPortRect.y) {
-              return rels[i];
-            }
-          }
-        }
-
-        return rels[0];
-      },
-
-      /**
-       * Move relative to the specified element.
-       *
-       * @method moveRel
-       * @param {Element} elm Element to move relative to.
-       * @param {String} rel Relative mode. For example: br-tl.
-       * @return {tinymce.ui.Control} Current control instance.
-       */
-      moveRel: function (elm, rel) {
-        if (typeof rel != 'string') {
-          rel = this.testMoveRel(elm, rel);
-        }
-
-        var pos = calculateRelativePosition(this, elm, rel);
-        return this.moveTo(pos.x, pos.y);
-      },
-
-      /**
-       * Move by a relative x, y values.
-       *
-       * @method moveBy
-       * @param {Number} dx Relative x position.
-       * @param {Number} dy Relative y position.
-       * @return {tinymce.ui.Control} Current control instance.
-       */
-      moveBy: function (dx, dy) {
-        var self = this, rect = self.layoutRect();
-
-        self.moveTo(rect.x + dx, rect.y + dy);
-
-        return self;
-      },
-
-      /**
-       * Move to absolute position.
-       *
-       * @method moveTo
-       * @param {Number} x Absolute x position.
-       * @param {Number} y Absolute y position.
-       * @return {tinymce.ui.Control} Current control instance.
-       */
-      moveTo: function (x, y) {
-        var self = this;
-
-        // TODO: Move this to some global class
-        function constrain(value, max, size) {
-          if (value < 0) {
-            return 0;
-          }
-
-          if (value + size > max) {
-            value = max - size;
-            return value < 0 ? 0 : value;
-          }
-
-          return value;
-        }
-
-        if (self.settings.constrainToViewport) {
-          var viewPortRect = DomUtils.getViewPort(window);
-          var layoutRect = self.layoutRect();
-
-          x = constrain(x, viewPortRect.w + viewPortRect.x, layoutRect.w);
-          y = constrain(y, viewPortRect.h + viewPortRect.y, layoutRect.h);
-        }
-
-        if (self.state.get('rendered')) {
-          self.layoutRect({ x: x, y: y }).repaint();
-        } else {
-          self.settings.x = x;
-          self.settings.y = y;
-        }
-
-        self.fire('move', { x: x, y: y });
-
-        return self;
-      }
-    };
-  }
-);
-/**
</del><span class="cx" style="display: block; padding: 0 10px">  * Resizable.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -36747,6 +28131,143 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * WindowManagerImpl.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.ui.WindowManagerImpl',
+  [
+    "tinymce.core.ui.Window",
+    "tinymce.core.ui.MessageBox"
+  ],
+  function (Window, MessageBox) {
+    return function (editor) {
+      var open = function (args, params, closeCallback) {
+        var win;
+
+        args.title = args.title || ' ';
+
+        // Handle URL
+        args.url = args.url || args.file; // Legacy
+        if (args.url) {
+          args.width = parseInt(args.width || 320, 10);
+          args.height = parseInt(args.height || 240, 10);
+        }
+
+        // Handle body
+        if (args.body) {
+          args.items = {
+            defaults: args.defaults,
+            type: args.bodyType || 'form',
+            items: args.body,
+            data: args.data,
+            callbacks: args.commands
+          };
+        }
+
+        if (!args.url && !args.buttons) {
+          args.buttons = [
+            {
+              text: 'Ok', subtype: 'primary', onclick: function () {
+                win.find('form')[0].submit();
+              }
+            },
+
+            {
+              text: 'Cancel', onclick: function () {
+                win.close();
+              }
+            }
+          ];
+        }
+
+        win = new Window(args);
+
+        win.on('close', function () {
+          closeCallback(win);
+        });
+
+        // Handle data
+        if (args.data) {
+          win.on('postRender', function () {
+            this.find('*').each(function (ctrl) {
+              var name = ctrl.name();
+
+              if (name in args.data) {
+                ctrl.value(args.data[name]);
+              }
+            });
+          });
+        }
+
+        // store args and parameters
+        win.features = args || {};
+        win.params = params || {};
+
+        win = win.renderTo().reflow();
+
+        return win;
+      };
+
+      var alert = function (message, choiceCallback, closeCallback) {
+        var win;
+
+        win = MessageBox.alert(message, function () {
+          choiceCallback();
+        });
+
+        win.on('close', function () {
+          closeCallback(win);
+        });
+
+        return win;
+      };
+
+      var confirm = function (message, choiceCallback, closeCallback) {
+        var win;
+
+        win = MessageBox.confirm(message, function (state) {
+          choiceCallback(state);
+        });
+
+        win.on('close', function () {
+          closeCallback(win);
+        });
+
+        return win;
+      };
+
+      var close = function (window) {
+        window.close();
+      };
+
+      var getParams = function (window) {
+        return window.params;
+      };
+
+      var setParams = function (window, params) {
+        window.params = params;
+      };
+
+      return {
+        open: open,
+        alert: alert,
+        confirm: confirm,
+        close: close,
+        getParams: getParams,
+        setParams: setParams
+      };
+    };
+  }
+);
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * WindowManager.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -36775,7 +28296,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * tinymce.activeEditor.windowManager.alert('Hello world!');
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * // Displays an confirm box and an alert message will be displayed depending on what you choose in the confirm
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * tinymce.activeEditor.windowManager.confirm("Do you want to do something", function(s) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * tinymce.activeEditor.windowManager.confirm("Do you want to do something", function(s, ) {
</ins><span class="cx" style="display: block; padding: 0 10px">  *    if (s)
</span><span class="cx" style="display: block; padding: 0 10px">  *       tinymce.activeEditor.windowManager.alert("Ok");
</span><span class="cx" style="display: block; padding: 0 10px">  *    else
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -36783,258 +28304,3405 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * });
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.WindowManager',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.api.WindowManager',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    "tinymce.core.ui.Window",
-    "tinymce.core.ui.MessageBox"
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.katamari.api.Arr',
+    'ephox.katamari.api.Option',
+    'tinymce.core.ui.WindowManagerImpl'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Window, MessageBox) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Arr, Option, WindowManagerImpl) {
</ins><span class="cx" style="display: block; padding: 0 10px">     return function (editor) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var self = this, windows = [];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var windows = [];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function getTopMostWindow() {
-        if (windows.length) {
-          return windows[windows.length - 1];
-        }
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var getImplementation = function () {
+        var theme = editor.theme;
+        return theme.getWindowManagerImpl ? theme.getWindowManagerImpl() : WindowManagerImpl(editor);
+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function fireOpenEvent(win) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var funcBind = function (scope, f) {
+        return function () {
+          return f ? f.apply(scope, arguments) : undefined;
+        };
+      };
+
+      var fireOpenEvent = function (win) {
</ins><span class="cx" style="display: block; padding: 0 10px">         editor.fire('OpenWindow', {
</span><span class="cx" style="display: block; padding: 0 10px">           win: win
</span><span class="cx" style="display: block; padding: 0 10px">         });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function fireCloseEvent(win) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var fireCloseEvent = function (win) {
</ins><span class="cx" style="display: block; padding: 0 10px">         editor.fire('CloseWindow', {
</span><span class="cx" style="display: block; padding: 0 10px">           win: win
</span><span class="cx" style="display: block; padding: 0 10px">         });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      self.windows = windows;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var addWindow = function (win) {
+        windows.push(win);
+        fireOpenEvent(win);
+      };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      editor.on('remove', function () {
-        var i = windows.length;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var closeWindow = function (win) {
+        Arr.findIndex(windows, function (otherWindow) {
+          return otherWindow === win;
+        }).each(function (index) {
+          // Mutate here since third party might have stored away the window array, consider breaking this api
+          windows.splice(index, 1);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        while (i--) {
-          windows[i].close();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          fireCloseEvent(win);
+
+          // Move focus back to editor when the last window is closed
+          if (windows.length === 0) {
+            editor.focus();
+          }
+        });
+      };
+
+      var getTopWindow = function () {
+        return Option.from(windows[0]);
+      };
+
+      var open = function (args, params) {
+        editor.editorManager.setActive(editor);
+
+        // Takes a snapshot in the FocusManager of the selection before focus is lost to dialog
+        if (windows.length === 0) {
+          editor.nodeChanged();
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+        var win = getImplementation().open(args, params, closeWindow);
+        addWindow(win);
+        return win;
+      };
+
+      var alert = function (message, callback, scope) {
+        var win = getImplementation().alert(message, funcBind(scope ? scope : this, callback), closeWindow);
+        addWindow(win);
+      };
+
+      var confirm = function (message, callback, scope) {
+        var win = getImplementation().confirm(message, funcBind(scope ? scope : this, callback), closeWindow);
+        addWindow(win);
+      };
+
+      var close = function () {
+        getTopWindow().each(function (win) {
+          getImplementation().close(win);
+          closeWindow(win);
+        });
+      };
+
+      var getParams = function () {
+        return getTopWindow().map(getImplementation().getParams).getOr(null);
+      };
+
+      var setParams = function (params) {
+        getTopWindow().each(function (win) {
+          getImplementation().setParams(win, params);
+        });
+      };
+
+      var getWindows = function () {
+        return windows;
+      };
+
+      editor.on('remove', function () {
+        Arr.each(windows.slice(0), function (win) {
+          getImplementation().close(win);
+        });
</ins><span class="cx" style="display: block; padding: 0 10px">       });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Opens a new window.
-       *
-       * @method open
-       * @param {Object} args Optional name/value settings collection contains things like width/height/url etc.
-       * @param {Object} params Options like title, file, width, height etc.
-       * @option {String} title Window title.
-       * @option {String} file URL of the file to open in the window.
-       * @option {Number} width Width in pixels.
-       * @option {Number} height Height in pixels.
-       * @option {Boolean} autoScroll Specifies whether the popup window can have scrollbars if required (i.e. content
-       * larger than the popup size specified).
-       */
-      self.open = function (args, params) {
-        var win;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return {
+        // Used by the legacy3x compat layer and possible third party
+        // TODO: Deprecate this, and possible switch to a immutable window array for getWindows
+        windows: windows,
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        editor.editorManager.setActive(editor);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+         * Opens a new window.
+         *
+         * @method open
+         * @param {Object} args Optional name/value settings collection contains things like width/height/url etc.
+         * @param {Object} params Options like title, file, width, height etc.
+         * @option {String} title Window title.
+         * @option {String} file URL of the file to open in the window.
+         * @option {Number} width Width in pixels.
+         * @option {Number} height Height in pixels.
+         * @option {Boolean} autoScroll Specifies whether the popup window can have scrollbars if required (i.e. content
+         * larger than the popup size specified).
+         */
+        open: open,
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        args.title = args.title || ' ';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+         * Creates a alert dialog. Please don't use the blocking behavior of this
+         * native version use the callback method instead then it can be extended.
+         *
+         * @method alert
+         * @param {String} message Text to display in the new alert dialog.
+         * @param {function} callback Callback function to be executed after the user has selected ok.
+         * @param {Object} scope Optional scope to execute the callback in.
+         * @example
+         * // Displays an alert box using the active editors window manager instance
+         * tinymce.activeEditor.windowManager.alert('Hello world!');
+         */
+        alert: alert,
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Handle URL
-        args.url = args.url || args.file; // Legacy
-        if (args.url) {
-          args.width = parseInt(args.width || 320, 10);
-          args.height = parseInt(args.height || 240, 10);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+         * Creates a confirm dialog. Please don't use the blocking behavior of this
+         * native version use the callback method instead then it can be extended.
+         *
+         * @method confirm
+         * @param {String} message Text to display in the new confirm dialog.
+         * @param {function} callback Callback function to be executed after the user has selected ok or cancel.
+         * @param {Object} scope Optional scope to execute the callback in.
+         * @example
+         * // Displays an confirm box and an alert message will be displayed depending on what you choose in the confirm
+         * tinymce.activeEditor.windowManager.confirm("Do you want to do something", function(s) {
+         *    if (s)
+         *       tinymce.activeEditor.windowManager.alert("Ok");
+         *    else
+         *       tinymce.activeEditor.windowManager.alert("Cancel");
+         * });
+         */
+        confirm: confirm,
+
+        /**
+         * Closes the top most window.
+         *
+         * @method close
+         */
+        close: close,
+
+        /**
+         * Returns the params of the last window open call. This can be used in iframe based
+         * dialog to get params passed from the tinymce plugin.
+         *
+         * @example
+         * var dialogArguments = top.tinymce.activeEditor.windowManager.getParams();
+         *
+         * @method getParams
+         * @return {Object} Name/value object with parameters passed from windowManager.open call.
+         */
+        getParams: getParams,
+
+        /**
+         * Sets the params of the last opened window.
+         *
+         * @method setParams
+         * @param {Object} params Params object to set for the last opened window.
+         */
+        setParams: setParams,
+
+        /**
+         * Returns the currently opened window objects.
+         *
+         * @method getWindows
+         * @return {Array} Array of the currently opened windows.
+         */
+        getWindows: getWindows
+      };
+    };
+  }
+);
+
+/**
+ * RangePoint.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.dom.RangePoint',
+  [
+    'ephox.katamari.api.Arr',
+    'tinymce.core.geom.ClientRect'
+  ],
+  function (Arr, ClientRect) {
+    var isXYWithinRange = function (clientX, clientY, range) {
+      if (range.collapsed) {
+        return false;
+      }
+
+      return Arr.foldl(range.getClientRects(), function (state, rect) {
+        return state || ClientRect.containsXY(rect, clientX, clientY);
+      }, false);
+    };
+
+    return {
+      isXYWithinRange: isXYWithinRange
+    };
+  }
+);
+/**
+ * VK.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This file exposes a set of the common KeyCodes for use. Please grow it as needed.
+ */
+define(
+  'tinymce.core.util.VK',
+  [
+    "tinymce.core.Env"
+  ],
+  function (Env) {
+    return {
+      BACKSPACE: 8,
+      DELETE: 46,
+      DOWN: 40,
+      ENTER: 13,
+      LEFT: 37,
+      RIGHT: 39,
+      SPACEBAR: 32,
+      TAB: 9,
+      UP: 38,
+
+      modifierPressed: function (e) {
+        return e.shiftKey || e.ctrlKey || e.altKey || this.metaKeyPressed(e);
+      },
+
+      metaKeyPressed: function (e) {
+        // Check if ctrl or meta key is pressed. Edge case for AltGr on Windows where it produces ctrlKey+altKey states
+        return (Env.mac ? e.metaKey : e.ctrlKey && !e.altKey);
+      }
+    };
+  }
+);
+
+/**
+ * ControlSelection.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This class handles control selection of elements. Controls are elements
+ * that can be resized and needs to be selected as a whole. It adds custom resize handles
+ * to all browser engines that support properly disabling the built in resize logic.
+ *
+ * @class tinymce.dom.ControlSelection
+ */
+define(
+  'tinymce.core.dom.ControlSelection',
+  [
+    'ephox.katamari.api.Fun',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.search.Selectors',
+    'tinymce.core.dom.NodeType',
+    'tinymce.core.dom.RangePoint',
+    'tinymce.core.Env',
+    'tinymce.core.util.Delay',
+    'tinymce.core.util.Tools',
+    'tinymce.core.util.VK'
+  ],
+  function (Fun, Element, Selectors, NodeType, RangePoint, Env, Delay, Tools, VK) {
+    var isContentEditableFalse = NodeType.isContentEditableFalse;
+    var isContentEditableTrue = NodeType.isContentEditableTrue;
+
+    function getContentEditableRoot(root, node) {
+      while (node && node != root) {
+        if (isContentEditableTrue(node) || isContentEditableFalse(node)) {
+          return node;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Handle body
-        if (args.body) {
-          args.items = {
-            defaults: args.defaults,
-            type: args.bodyType || 'form',
-            items: args.body,
-            data: args.data,
-            callbacks: args.commands
-          };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        node = node.parentNode;
+      }
+
+      return null;
+    }
+
+    var isImage = function (elm) {
+      return elm && elm.nodeName === 'IMG';
+    };
+
+    var isEventOnImageOutsideRange = function (evt, range) {
+      return isImage(evt.target) && !RangePoint.isXYWithinRange(evt.clientX, evt.clientY, range);
+    };
+
+    var contextMenuSelectImage = function (editor, evt) {
+      var target = evt.target;
+
+      if (isEventOnImageOutsideRange(evt, editor.selection.getRng()) && !evt.isDefaultPrevented()) {
+        evt.preventDefault();
+        editor.selection.select(target);
+      }
+    };
+
+    return function (selection, editor) {
+      var dom = editor.dom, each = Tools.each;
+      var selectedElm, selectedElmGhost, resizeHelper, resizeHandles, selectedHandle, lastMouseDownEvent;
+      var startX, startY, selectedElmX, selectedElmY, startW, startH, ratio, resizeStarted;
+      var width, height, editableDoc = editor.getDoc(), rootDocument = document, isIE = Env.ie && Env.ie < 11;
+      var abs = Math.abs, round = Math.round, rootElement = editor.getBody(), startScrollWidth, startScrollHeight;
+
+      // Details about each resize handle how to scale etc
+      resizeHandles = {
+        // Name: x multiplier, y multiplier, delta size x, delta size y
+        /*n: [0.5, 0, 0, -1],
+        e: [1, 0.5, 1, 0],
+        s: [0.5, 1, 0, 1],
+        w: [0, 0.5, -1, 0],*/
+        nw: [0, 0, -1, -1],
+        ne: [1, 0, 1, -1],
+        se: [1, 1, 1, 1],
+        sw: [0, 1, -1, 1]
+      };
+
+      // Add CSS for resize handles, cloned element and selected
+      var rootClass = '.mce-content-body';
+      editor.contentStyles.push(
+        rootClass + ' div.mce-resizehandle {' +
+        'position: absolute;' +
+        'border: 1px solid black;' +
+        'box-sizing: box-sizing;' +
+        'background: #FFF;' +
+        'width: 7px;' +
+        'height: 7px;' +
+        'z-index: 10000' +
+        '}' +
+        rootClass + ' .mce-resizehandle:hover {' +
+        'background: #000' +
+        '}' +
+        rootClass + ' img[data-mce-selected],' + rootClass + ' hr[data-mce-selected] {' +
+        'outline: 1px solid black;' +
+        'resize: none' + // Have been talks about implementing this in browsers
+        '}' +
+        rootClass + ' .mce-clonedresizable {' +
+        'position: absolute;' +
+        (Env.gecko ? '' : 'outline: 1px dashed black;') + // Gecko produces trails while resizing
+        'opacity: .5;' +
+        'filter: alpha(opacity=50);' +
+        'z-index: 10000' +
+        '}' +
+        rootClass + ' .mce-resize-helper {' +
+        'background: #555;' +
+        'background: rgba(0,0,0,0.75);' +
+        'border-radius: 3px;' +
+        'border: 1px;' +
+        'color: white;' +
+        'display: none;' +
+        'font-family: sans-serif;' +
+        'font-size: 12px;' +
+        'white-space: nowrap;' +
+        'line-height: 14px;' +
+        'margin: 5px 10px;' +
+        'padding: 5px;' +
+        'position: absolute;' +
+        'z-index: 10001' +
+        '}'
+      );
+
+      function isResizable(elm) {
+        var selector = editor.settings.object_resizing;
+
+        if (selector === false || Env.iOS) {
+          return false;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (!args.url && !args.buttons) {
-          args.buttons = [
-            {
-              text: 'Ok', subtype: 'primary', onclick: function () {
-                win.find('form')[0].submit();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (typeof selector != 'string') {
+          selector = 'table,img,div';
+        }
+
+        if (elm.getAttribute('data-mce-resize') === 'false') {
+          return false;
+        }
+
+        if (elm == editor.getBody()) {
+          return false;
+        }
+
+        return Selectors.is(Element.fromDom(elm), selector);
+      }
+
+      function resizeGhostElement(e) {
+        var deltaX, deltaY, proportional;
+        var resizeHelperX, resizeHelperY;
+
+        // Calc new width/height
+        deltaX = e.screenX - startX;
+        deltaY = e.screenY - startY;
+
+        // Calc new size
+        width = deltaX * selectedHandle[2] + startW;
+        height = deltaY * selectedHandle[3] + startH;
+
+        // Never scale down lower than 5 pixels
+        width = width < 5 ? 5 : width;
+        height = height < 5 ? 5 : height;
+
+        if (selectedElm.nodeName == "IMG" && editor.settings.resize_img_proportional !== false) {
+          proportional = !VK.modifierPressed(e);
+        } else {
+          proportional = VK.modifierPressed(e) || (selectedElm.nodeName == "IMG" && selectedHandle[2] * selectedHandle[3] !== 0);
+        }
+
+        // Constrain proportions
+        if (proportional) {
+          if (abs(deltaX) > abs(deltaY)) {
+            height = round(width * ratio);
+            width = round(height / ratio);
+          } else {
+            width = round(height / ratio);
+            height = round(width * ratio);
+          }
+        }
+
+        // Update ghost size
+        dom.setStyles(selectedElmGhost, {
+          width: width,
+          height: height
+        });
+
+        // Update resize helper position
+        resizeHelperX = selectedHandle.startPos.x + deltaX;
+        resizeHelperY = selectedHandle.startPos.y + deltaY;
+        resizeHelperX = resizeHelperX > 0 ? resizeHelperX : 0;
+        resizeHelperY = resizeHelperY > 0 ? resizeHelperY : 0;
+
+        dom.setStyles(resizeHelper, {
+          left: resizeHelperX,
+          top: resizeHelperY,
+          display: 'block'
+        });
+
+        resizeHelper.innerHTML = width + ' &times; ' + height;
+
+        // Update ghost X position if needed
+        if (selectedHandle[2] < 0 && selectedElmGhost.clientWidth <= width) {
+          dom.setStyle(selectedElmGhost, 'left', selectedElmX + (startW - width));
+        }
+
+        // Update ghost Y position if needed
+        if (selectedHandle[3] < 0 && selectedElmGhost.clientHeight <= height) {
+          dom.setStyle(selectedElmGhost, 'top', selectedElmY + (startH - height));
+        }
+
+        // Calculate how must overflow we got
+        deltaX = rootElement.scrollWidth - startScrollWidth;
+        deltaY = rootElement.scrollHeight - startScrollHeight;
+
+        // Re-position the resize helper based on the overflow
+        if (deltaX + deltaY !== 0) {
+          dom.setStyles(resizeHelper, {
+            left: resizeHelperX - deltaX,
+            top: resizeHelperY - deltaY
+          });
+        }
+
+        if (!resizeStarted) {
+          editor.fire('ObjectResizeStart', { target: selectedElm, width: startW, height: startH });
+          resizeStarted = true;
+        }
+      }
+
+      function endGhostResize() {
+        resizeStarted = false;
+
+        function setSizeProp(name, value) {
+          if (value) {
+            // Resize by using style or attribute
+            if (selectedElm.style[name] || !editor.schema.isValid(selectedElm.nodeName.toLowerCase(), name)) {
+              dom.setStyle(selectedElm, name, value);
+            } else {
+              dom.setAttrib(selectedElm, name, value);
+            }
+          }
+        }
+
+        // Set width/height properties
+        setSizeProp('width', width);
+        setSizeProp('height', height);
+
+        dom.unbind(editableDoc, 'mousemove', resizeGhostElement);
+        dom.unbind(editableDoc, 'mouseup', endGhostResize);
+
+        if (rootDocument != editableDoc) {
+          dom.unbind(rootDocument, 'mousemove', resizeGhostElement);
+          dom.unbind(rootDocument, 'mouseup', endGhostResize);
+        }
+
+        // Remove ghost/helper and update resize handle positions
+        dom.remove(selectedElmGhost);
+        dom.remove(resizeHelper);
+
+        if (!isIE || selectedElm.nodeName == "TABLE") {
+          showResizeRect(selectedElm);
+        }
+
+        editor.fire('ObjectResized', { target: selectedElm, width: width, height: height });
+        dom.setAttrib(selectedElm, 'style', dom.getAttrib(selectedElm, 'style'));
+        editor.nodeChanged();
+      }
+
+      function showResizeRect(targetElm, mouseDownHandleName, mouseDownEvent) {
+        var position, targetWidth, targetHeight, e, rect;
+
+        hideResizeRect();
+        unbindResizeHandleEvents();
+
+        // Get position and size of target
+        position = dom.getPos(targetElm, rootElement);
+        selectedElmX = position.x;
+        selectedElmY = position.y;
+        rect = targetElm.getBoundingClientRect(); // Fix for Gecko offsetHeight for table with caption
+        targetWidth = rect.width || (rect.right - rect.left);
+        targetHeight = rect.height || (rect.bottom - rect.top);
+
+        // Reset width/height if user selects a new image/table
+        if (selectedElm != targetElm) {
+          detachResizeStartListener();
+          selectedElm = targetElm;
+          width = height = 0;
+        }
+
+        // Makes it possible to disable resizing
+        e = editor.fire('ObjectSelected', { target: targetElm });
+
+        if (isResizable(targetElm) && !e.isDefaultPrevented()) {
+          each(resizeHandles, function (handle, name) {
+            var handleElm;
+
+            function startDrag(e) {
+              startX = e.screenX;
+              startY = e.screenY;
+              startW = selectedElm.clientWidth;
+              startH = selectedElm.clientHeight;
+              ratio = startH / startW;
+              selectedHandle = handle;
+
+              handle.startPos = {
+                x: targetWidth * handle[0] + selectedElmX,
+                y: targetHeight * handle[1] + selectedElmY
+              };
+
+              startScrollWidth = rootElement.scrollWidth;
+              startScrollHeight = rootElement.scrollHeight;
+
+              selectedElmGhost = selectedElm.cloneNode(true);
+              dom.addClass(selectedElmGhost, 'mce-clonedresizable');
+              dom.setAttrib(selectedElmGhost, 'data-mce-bogus', 'all');
+              selectedElmGhost.contentEditable = false; // Hides IE move layer cursor
+              selectedElmGhost.unSelectabe = true;
+              dom.setStyles(selectedElmGhost, {
+                left: selectedElmX,
+                top: selectedElmY,
+                margin: 0
+              });
+
+              selectedElmGhost.removeAttribute('data-mce-selected');
+              rootElement.appendChild(selectedElmGhost);
+
+              dom.bind(editableDoc, 'mousemove', resizeGhostElement);
+              dom.bind(editableDoc, 'mouseup', endGhostResize);
+
+              if (rootDocument != editableDoc) {
+                dom.bind(rootDocument, 'mousemove', resizeGhostElement);
+                dom.bind(rootDocument, 'mouseup', endGhostResize);
</ins><span class="cx" style="display: block; padding: 0 10px">               }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            },
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            {
-              text: 'Cancel', onclick: function () {
-                win.close();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              resizeHelper = dom.add(rootElement, 'div', {
+                'class': 'mce-resize-helper',
+                'data-mce-bogus': 'all'
+              }, startW + ' &times; ' + startH);
+            }
+
+            if (mouseDownHandleName) {
+              // Drag started by IE native resizestart
+              if (name == mouseDownHandleName) {
+                startDrag(mouseDownEvent);
</ins><span class="cx" style="display: block; padding: 0 10px">               }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+              return;
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          ];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+            // Get existing or render resize handle
+            handleElm = dom.get('mceResizeHandle' + name);
+            if (handleElm) {
+              dom.remove(handleElm);
+            }
+
+            handleElm = dom.add(rootElement, 'div', {
+              id: 'mceResizeHandle' + name,
+              'data-mce-bogus': 'all',
+              'class': 'mce-resizehandle',
+              unselectable: true,
+              style: 'cursor:' + name + '-resize; margin:0; padding:0'
+            });
+
+            // Hides IE move layer cursor
+            // If we set it on Chrome we get this wounderful bug: #6725
+            if (Env.ie) {
+              handleElm.contentEditable = false;
+            }
+
+            dom.bind(handleElm, 'mousedown', function (e) {
+              e.stopImmediatePropagation();
+              e.preventDefault();
+              startDrag(e);
+            });
+
+            handle.elm = handleElm;
+
+            // Position element
+            dom.setStyles(handleElm, {
+              left: (targetWidth * handle[0] + selectedElmX) - (handleElm.offsetWidth / 2),
+              top: (targetHeight * handle[1] + selectedElmY) - (handleElm.offsetHeight / 2)
+            });
+          });
+        } else {
+          hideResizeRect();
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        win = new Window(args);
-        windows.push(win);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        selectedElm.setAttribute('data-mce-selected', '1');
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        win.on('close', function () {
-          var i = windows.length;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function hideResizeRect() {
+        var name, handleElm;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          while (i--) {
-            if (windows[i] === win) {
-              windows.splice(i, 1);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        unbindResizeHandleEvents();
+
+        if (selectedElm) {
+          selectedElm.removeAttribute('data-mce-selected');
+        }
+
+        for (name in resizeHandles) {
+          handleElm = dom.get('mceResizeHandle' + name);
+          if (handleElm) {
+            dom.unbind(handleElm);
+            dom.remove(handleElm);
+          }
+        }
+      }
+
+      function updateResizeRect(e) {
+        var startElm, controlElm;
+
+        function isChildOrEqual(node, parent) {
+          if (node) {
+            do {
+              if (node === parent) {
+                return true;
+              }
+            } while ((node = node.parentNode));
+          }
+        }
+
+        // Ignore all events while resizing or if the editor instance was removed
+        if (resizeStarted || editor.removed) {
+          return;
+        }
+
+        // Remove data-mce-selected from all elements since they might have been copied using Ctrl+c/v
+        each(dom.select('img[data-mce-selected],hr[data-mce-selected]'), function (img) {
+          img.removeAttribute('data-mce-selected');
+        });
+
+        controlElm = e.type == 'mousedown' ? e.target : selection.getNode();
+        controlElm = dom.$(controlElm).closest(isIE ? 'table' : 'table,img,hr')[0];
+
+        if (isChildOrEqual(controlElm, rootElement)) {
+          disableGeckoResize();
+          startElm = selection.getStart(true);
+
+          if (isChildOrEqual(startElm, controlElm) && isChildOrEqual(selection.getEnd(true), controlElm)) {
+            if (!isIE || (controlElm != startElm && startElm.nodeName !== 'IMG')) {
+              showResizeRect(controlElm);
+              return;
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px">           }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (!windows.length) {
-            editor.focus();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        hideResizeRect();
+      }
+
+      function attachEvent(elm, name, func) {
+        if (elm && elm.attachEvent) {
+          elm.attachEvent('on' + name, func);
+        }
+      }
+
+      function detachEvent(elm, name, func) {
+        if (elm && elm.detachEvent) {
+          elm.detachEvent('on' + name, func);
+        }
+      }
+
+      function resizeNativeStart(e) {
+        var target = e.srcElement, pos, name, corner, cornerX, cornerY, relativeX, relativeY;
+
+        pos = target.getBoundingClientRect();
+        relativeX = lastMouseDownEvent.clientX - pos.left;
+        relativeY = lastMouseDownEvent.clientY - pos.top;
+
+        // Figure out what corner we are draging on
+        for (name in resizeHandles) {
+          corner = resizeHandles[name];
+
+          cornerX = target.offsetWidth * corner[0];
+          cornerY = target.offsetHeight * corner[1];
+
+          if (abs(cornerX - relativeX) < 8 && abs(cornerY - relativeY) < 8) {
+            selectedHandle = corner;
+            break;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          fireCloseEvent(win);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Remove native selection and let the magic begin
+        resizeStarted = true;
+        editor.fire('ObjectResizeStart', {
+          target: selectedElm,
+          width: selectedElm.clientWidth,
+          height: selectedElm.clientHeight
</ins><span class="cx" style="display: block; padding: 0 10px">         });
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        editor.getDoc().selection.empty();
+        showResizeRect(target, name, lastMouseDownEvent);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Handle data
-        if (args.data) {
-          win.on('postRender', function () {
-            this.find('*').each(function (ctrl) {
-              var name = ctrl.name();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function preventDefault(e) {
+        if (e.preventDefault) {
+          e.preventDefault();
+        } else {
+          e.returnValue = false; // IE
+        }
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              if (name in args.data) {
-                ctrl.value(args.data[name]);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function isWithinContentEditableFalse(elm) {
+        return isContentEditableFalse(getContentEditableRoot(editor.getBody(), elm));
+      }
+
+      function nativeControlSelect(e) {
+        var target = e.srcElement;
+
+        if (isWithinContentEditableFalse(target)) {
+          preventDefault(e);
+          return;
+        }
+
+        if (target != selectedElm) {
+          editor.fire('ObjectSelected', { target: target });
+          detachResizeStartListener();
+
+          if (target.id.indexOf('mceResizeHandle') === 0) {
+            e.returnValue = false;
+            return;
+          }
+
+          if (target.nodeName == 'IMG' || target.nodeName == 'TABLE') {
+            hideResizeRect();
+            selectedElm = target;
+            attachEvent(target, 'resizestart', resizeNativeStart);
+          }
+        }
+      }
+
+      function detachResizeStartListener() {
+        detachEvent(selectedElm, 'resizestart', resizeNativeStart);
+      }
+
+      function unbindResizeHandleEvents() {
+        for (var name in resizeHandles) {
+          var handle = resizeHandles[name];
+
+          if (handle.elm) {
+            dom.unbind(handle.elm);
+            delete handle.elm;
+          }
+        }
+      }
+
+      function disableGeckoResize() {
+        try {
+          // Disable object resizing on Gecko
+          editor.getDoc().execCommand('enableObjectResizing', false, false);
+        } catch (ex) {
+          // Ignore
+        }
+      }
+
+      function controlSelect(elm) {
+        var ctrlRng;
+
+        if (!isIE) {
+          return;
+        }
+
+        ctrlRng = editableDoc.body.createControlRange();
+
+        try {
+          ctrlRng.addElement(elm);
+          ctrlRng.select();
+          return true;
+        } catch (ex) {
+          // Ignore since the element can't be control selected for example a P tag
+        }
+      }
+
+      editor.on('init', function () {
+        if (isIE) {
+          // Hide the resize rect on resize and reselect the image
+          editor.on('ObjectResized', function (e) {
+            if (e.target.nodeName != 'TABLE') {
+              hideResizeRect();
+              controlSelect(e.target);
+            }
+          });
+
+          attachEvent(rootElement, 'controlselect', nativeControlSelect);
+
+          editor.on('mousedown', function (e) {
+            lastMouseDownEvent = e;
+          });
+        } else {
+          disableGeckoResize();
+
+          // Sniff sniff, hard to feature detect this stuff
+          if (Env.ie >= 11) {
+            // Needs to be mousedown for drag/drop to work on IE 11
+            // Needs to be click on Edge to properly select images
+            editor.on('mousedown click', function (e) {
+              var target = e.target, nodeName = target.nodeName;
+
+              if (!resizeStarted && /^(TABLE|IMG|HR)$/.test(nodeName) && !isWithinContentEditableFalse(target)) {
+                if (e.button !== 2) {
+                  editor.selection.select(target, nodeName == 'TABLE');
+                }
+
+                // Only fire once since nodeChange is expensive
+                if (e.type == 'mousedown') {
+                  editor.nodeChanged();
+                }
</ins><span class="cx" style="display: block; padding: 0 10px">               }
</span><span class="cx" style="display: block; padding: 0 10px">             });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+            editor.dom.bind(rootElement, 'mscontrolselect', function (e) {
+              function delayedSelect(node) {
+                Delay.setEditorTimeout(editor, function () {
+                  editor.selection.select(node);
+                });
+              }
+
+              if (isWithinContentEditableFalse(e.target)) {
+                e.preventDefault();
+                delayedSelect(e.target);
+                return;
+              }
+
+              if (/^(TABLE|IMG|HR)$/.test(e.target.nodeName)) {
+                e.preventDefault();
+
+                // This moves the selection from being a control selection to a text like selection like in WebKit #6753
+                // TODO: Fix this the day IE works like other browsers without this nasty native ugly control selections.
+                if (e.target.tagName == 'IMG') {
+                  delayedSelect(e.target);
+                }
+              }
+            });
+          }
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // store args and parameters
-        win.features = args || {};
-        win.params = params || {};
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var throttledUpdateResizeRect = Delay.throttle(function (e) {
+          if (!editor.composing) {
+            updateResizeRect(e);
+          }
+        });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Takes a snapshot in the FocusManager of the selection before focus is lost to dialog
-        if (windows.length === 1) {
-          editor.nodeChanged();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        editor.on('nodechange ResizeEditor ResizeWindow drop', throttledUpdateResizeRect);
+
+        // Update resize rect while typing in a table
+        editor.on('keyup compositionend', function (e) {
+          // Don't update the resize rect while composing since it blows away the IME see: #2710
+          if (selectedElm && selectedElm.nodeName == "TABLE") {
+            throttledUpdateResizeRect(e);
+          }
+        });
+
+        editor.on('hide blur', hideResizeRect);
+        editor.on('contextmenu', Fun.curry(contextMenuSelectImage, editor));
+
+        // Hide rect on focusout since it would float on top of windows otherwise
+        //editor.on('focusout', hideResizeRect);
+      });
+
+      editor.on('remove', unbindResizeHandleEvents);
+
+      function destroy() {
+        selectedElm = selectedElmGhost = null;
+
+        if (isIE) {
+          detachResizeStartListener();
+          detachEvent(rootElement, 'controlselect', nativeControlSelect);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        win = win.renderTo().reflow();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return {
+        isResizable: isResizable,
+        showResizeRect: showResizeRect,
+        hideResizeRect: hideResizeRect,
+        updateResizeRect: updateResizeRect,
+        controlSelect: controlSelect,
+        destroy: destroy
+      };
+    };
+  }
+);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        fireOpenEvent(win);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/**
+ * ScrollIntoView.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return win;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+define(
+  'tinymce.core.dom.ScrollIntoView',
+  [
+    'tinymce.core.dom.NodeType'
+  ],
+  function (NodeType) {
+    var getPos = function (elm) {
+      var x = 0, y = 0;
+
+      var offsetParent = elm;
+      while (offsetParent && offsetParent.nodeType) {
+        x += offsetParent.offsetLeft || 0;
+        y += offsetParent.offsetTop || 0;
+        offsetParent = offsetParent.offsetParent;
+      }
+
+      return { x: x, y: y };
+    };
+
+    var fireScrollIntoViewEvent = function (editor, elm, alignToTop) {
+      var scrollEvent = { elm: elm, alignToTop: alignToTop };
+      editor.fire('scrollIntoView', scrollEvent);
+      return scrollEvent.isDefaultPrevented();
+    };
+
+    var scrollIntoView = function (editor, elm, alignToTop) {
+      var y, viewPort, dom = editor.dom, root = dom.getRoot(), viewPortY, viewPortH, offsetY = 0;
+
+      if (fireScrollIntoViewEvent(editor, elm, alignToTop)) {
+        return;
+      }
+
+      if (!NodeType.isElement(elm)) {
+        return;
+      }
+
+      if (alignToTop === false) {
+        offsetY = elm.offsetHeight;
+      }
+
+      if (root.nodeName !== 'BODY') {
+        var scrollContainer = editor.selection.getScrollContainer();
+        if (scrollContainer) {
+          y = getPos(elm).y - getPos(scrollContainer).y + offsetY;
+          viewPortH = scrollContainer.clientHeight;
+          viewPortY = scrollContainer.scrollTop;
+          if (y < viewPortY || y + 25 > viewPortY + viewPortH) {
+            scrollContainer.scrollTop = y < viewPortY ? y : y - viewPortH + 25;
+          }
+
+          return;
+        }
+      }
+
+      viewPort = dom.getViewPort(editor.getWin());
+      y = dom.getPos(elm).y + offsetY;
+      viewPortY = viewPort.y;
+      viewPortH = viewPort.h;
+      if (y < viewPort.y || y + 25 > viewPortY + viewPortH) {
+        editor.getWin().scrollTo(0, y < viewPortY ? y : y - viewPortH + 25);
+      }
+    };
+
+    return {
+      scrollIntoView: scrollIntoView
+    };
+  }
+);
+
+/**
+ * TridentSelection.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * Selection class for old explorer versions. This one fakes the
+ * native selection object available on modern browsers.
+ *
+ * @private
+ * @class tinymce.dom.TridentSelection
+ */
+define(
+  'tinymce.core.dom.TridentSelection',
+  [
+  ],
+  function () {
+    function Selection(selection) {
+      var self = this, dom = selection.dom, FALSE = false;
+
+      function getPosition(rng, start) {
+        var checkRng, startIndex = 0, endIndex, inside,
+          children, child, offset, index, position = -1, parent;
+
+        // Setup test range, collapse it and get the parent
+        checkRng = rng.duplicate();
+        checkRng.collapse(start);
+        parent = checkRng.parentElement();
+
+        // Check if the selection is within the right document
+        if (parent.ownerDocument !== selection.dom.doc) {
+          return;
+        }
+
+        // IE will report non editable elements as it's parent so look for an editable one
+        while (parent.contentEditable === "false") {
+          parent = parent.parentNode;
+        }
+
+        // If parent doesn't have any children then return that we are inside the element
+        if (!parent.hasChildNodes()) {
+          return { node: parent, inside: 1 };
+        }
+
+        // Setup node list and endIndex
+        children = parent.children;
+        endIndex = children.length - 1;
+
+        // Perform a binary search for the position
+        while (startIndex <= endIndex) {
+          index = Math.floor((startIndex + endIndex) / 2);
+
+          // Move selection to node and compare the ranges
+          child = children[index];
+          checkRng.moveToElementText(child);
+          position = checkRng.compareEndPoints(start ? 'StartToStart' : 'EndToEnd', rng);
+
+          // Before/after or an exact match
+          if (position > 0) {
+            endIndex = index - 1;
+          } else if (position < 0) {
+            startIndex = index + 1;
+          } else {
+            return { node: child };
+          }
+        }
+
+        // Check if child position is before or we didn't find a position
+        if (position < 0) {
+          // No element child was found use the parent element and the offset inside that
+          if (!child) {
+            checkRng.moveToElementText(parent);
+            checkRng.collapse(true);
+            child = parent;
+            inside = true;
+          } else {
+            checkRng.collapse(false);
+          }
+
+          // Walk character by character in text node until we hit the selected range endpoint,
+          // hit the end of document or parent isn't the right one
+          // We need to walk char by char since rng.text or rng.htmlText will trim line endings
+          offset = 0;
+          while (checkRng.compareEndPoints(start ? 'StartToStart' : 'StartToEnd', rng) !== 0) {
+            if (checkRng.move('character', 1) === 0 || parent != checkRng.parentElement()) {
+              break;
+            }
+
+            offset++;
+          }
+        } else {
+          // Child position is after the selection endpoint
+          checkRng.collapse(true);
+
+          // Walk character by character in text node until we hit the selected range endpoint, hit
+          // the end of document or parent isn't the right one
+          offset = 0;
+          while (checkRng.compareEndPoints(start ? 'StartToStart' : 'StartToEnd', rng) !== 0) {
+            if (checkRng.move('character', -1) === 0 || parent != checkRng.parentElement()) {
+              break;
+            }
+
+            offset++;
+          }
+        }
+
+        return { node: child, position: position, offset: offset, inside: inside };
+      }
+
+      // Returns a W3C DOM compatible range object by using the IE Range API
+      function getRange() {
+        var ieRange = selection.getRng(), domRange = dom.createRng(), element, collapsed, tmpRange, element2, bookmark;
+
+        // If selection is outside the current document just return an empty range
+        element = ieRange.item ? ieRange.item(0) : ieRange.parentElement();
+        if (element.ownerDocument != dom.doc) {
+          return domRange;
+        }
+
+        collapsed = selection.isCollapsed();
+
+        // Handle control selection
+        if (ieRange.item) {
+          domRange.setStart(element.parentNode, dom.nodeIndex(element));
+          domRange.setEnd(domRange.startContainer, domRange.startOffset + 1);
+
+          return domRange;
+        }
+
+        function findEndPoint(start) {
+          var endPoint = getPosition(ieRange, start), container, offset, textNodeOffset = 0, sibling, undef, nodeValue;
+
+          container = endPoint.node;
+          offset = endPoint.offset;
+
+          if (endPoint.inside && !container.hasChildNodes()) {
+            domRange[start ? 'setStart' : 'setEnd'](container, 0);
+            return;
+          }
+
+          if (offset === undef) {
+            domRange[start ? 'setStartBefore' : 'setEndAfter'](container);
+            return;
+          }
+
+          if (endPoint.position < 0) {
+            sibling = endPoint.inside ? container.firstChild : container.nextSibling;
+
+            if (!sibling) {
+              domRange[start ? 'setStartAfter' : 'setEndAfter'](container);
+              return;
+            }
+
+            if (!offset) {
+              if (sibling.nodeType == 3) {
+                domRange[start ? 'setStart' : 'setEnd'](sibling, 0);
+              } else {
+                domRange[start ? 'setStartBefore' : 'setEndBefore'](sibling);
+              }
+
+              return;
+            }
+
+            // Find the text node and offset
+            while (sibling) {
+              if (sibling.nodeType == 3) {
+                nodeValue = sibling.nodeValue;
+                textNodeOffset += nodeValue.length;
+
+                // We are at or passed the position we where looking for
+                if (textNodeOffset >= offset) {
+                  container = sibling;
+                  textNodeOffset -= offset;
+                  textNodeOffset = nodeValue.length - textNodeOffset;
+                  break;
+                }
+              }
+
+              sibling = sibling.nextSibling;
+            }
+          } else {
+            // Find the text node and offset
+            sibling = container.previousSibling;
+
+            if (!sibling) {
+              return domRange[start ? 'setStartBefore' : 'setEndBefore'](container);
+            }
+
+            // If there isn't any text to loop then use the first position
+            if (!offset) {
+              if (container.nodeType == 3) {
+                domRange[start ? 'setStart' : 'setEnd'](sibling, container.nodeValue.length);
+              } else {
+                domRange[start ? 'setStartAfter' : 'setEndAfter'](sibling);
+              }
+
+              return;
+            }
+
+            while (sibling) {
+              if (sibling.nodeType == 3) {
+                textNodeOffset += sibling.nodeValue.length;
+
+                // We are at or passed the position we where looking for
+                if (textNodeOffset >= offset) {
+                  container = sibling;
+                  textNodeOffset -= offset;
+                  break;
+                }
+              }
+
+              sibling = sibling.previousSibling;
+            }
+          }
+
+          domRange[start ? 'setStart' : 'setEnd'](container, textNodeOffset);
+        }
+
+        try {
+          // Find start point
+          findEndPoint(true);
+
+          // Find end point if needed
+          if (!collapsed) {
+            findEndPoint();
+          }
+        } catch (ex) {
+          // IE has a nasty bug where text nodes might throw "invalid argument" when you
+          // access the nodeValue or other properties of text nodes. This seems to happen when
+          // text nodes are split into two nodes by a delete/backspace call.
+          // So let us detect and try to fix it.
+          if (ex.number == -2147024809) {
+            // Get the current selection
+            bookmark = self.getBookmark(2);
+
+            // Get start element
+            tmpRange = ieRange.duplicate();
+            tmpRange.collapse(true);
+            element = tmpRange.parentElement();
+
+            // Get end element
+            if (!collapsed) {
+              tmpRange = ieRange.duplicate();
+              tmpRange.collapse(false);
+              element2 = tmpRange.parentElement();
+              element2.innerHTML = element2.innerHTML;
+            }
+
+            // Remove the broken elements
+            element.innerHTML = element.innerHTML;
+
+            // Restore the selection
+            self.moveToBookmark(bookmark);
+
+            // Since the range has moved we need to re-get it
+            ieRange = selection.getRng();
+
+            // Find start point
+            findEndPoint(true);
+
+            // Find end point if needed
+            if (!collapsed) {
+              findEndPoint();
+            }
+          } else {
+            throw ex; // Throw other errors
+          }
+        }
+
+        return domRange;
+      }
+
+      this.getBookmark = function (type) {
+        var rng = selection.getRng(), bookmark = {};
+
+        function getIndexes(node) {
+          var parent, root, children, i, indexes = [];
+
+          parent = node.parentNode;
+          root = dom.getRoot().parentNode;
+
+          while (parent != root && parent.nodeType !== 9) {
+            children = parent.children;
+
+            i = children.length;
+            while (i--) {
+              if (node === children[i]) {
+                indexes.push(i);
+                break;
+              }
+            }
+
+            node = parent;
+            parent = parent.parentNode;
+          }
+
+          return indexes;
+        }
+
+        function getBookmarkEndPoint(start) {
+          var position;
+
+          position = getPosition(rng, start);
+          if (position) {
+            return {
+              position: position.position,
+              offset: position.offset,
+              indexes: getIndexes(position.node),
+              inside: position.inside
+            };
+          }
+        }
+
+        // Non ubstructive bookmark
+        if (type === 2) {
+          // Handle text selection
+          if (!rng.item) {
+            bookmark.start = getBookmarkEndPoint(true);
+
+            if (!selection.isCollapsed()) {
+              bookmark.end = getBookmarkEndPoint();
+            }
+          } else {
+            bookmark.start = { ctrl: true, indexes: getIndexes(rng.item(0)) };
+          }
+        }
+
+        return bookmark;
</ins><span class="cx" style="display: block; padding: 0 10px">       };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      this.moveToBookmark = function (bookmark) {
+        var rng, body = dom.doc.body;
+
+        function resolveIndexes(indexes) {
+          var node, i, idx, children;
+
+          node = dom.getRoot();
+          for (i = indexes.length - 1; i >= 0; i--) {
+            children = node.children;
+            idx = indexes[i];
+
+            if (idx <= children.length - 1) {
+              node = children[idx];
+            }
+          }
+
+          return node;
+        }
+
+        function setBookmarkEndPoint(start) {
+          var endPoint = bookmark[start ? 'start' : 'end'], moveLeft, moveRng, undef, offset;
+
+          if (endPoint) {
+            moveLeft = endPoint.position > 0;
+
+            moveRng = body.createTextRange();
+            moveRng.moveToElementText(resolveIndexes(endPoint.indexes));
+
+            offset = endPoint.offset;
+            if (offset !== undef) {
+              moveRng.collapse(endPoint.inside || moveLeft);
+              moveRng.moveStart('character', moveLeft ? -offset : offset);
+            } else {
+              moveRng.collapse(start);
+            }
+
+            rng.setEndPoint(start ? 'StartToStart' : 'EndToStart', moveRng);
+
+            if (start) {
+              rng.collapse(true);
+            }
+          }
+        }
+
+        if (bookmark.start) {
+          if (bookmark.start.ctrl) {
+            rng = body.createControlRange();
+            rng.addElement(resolveIndexes(bookmark.start.indexes));
+            rng.select();
+          } else {
+            rng = body.createTextRange();
+            setBookmarkEndPoint(true);
+            setBookmarkEndPoint();
+            rng.select();
+          }
+        }
+      };
+
+      this.addRange = function (rng) {
+        var ieRng, ctrlRng, startContainer, startOffset, endContainer, endOffset, sibling,
+          doc = selection.dom.doc, body = doc.body, nativeRng, ctrlElm;
+
+        function setEndPoint(start) {
+          var container, offset, marker, tmpRng, nodes;
+
+          marker = dom.create('a');
+          container = start ? startContainer : endContainer;
+          offset = start ? startOffset : endOffset;
+          tmpRng = ieRng.duplicate();
+
+          if (container == doc || container == doc.documentElement) {
+            container = body;
+            offset = 0;
+          }
+
+          if (container.nodeType == 3) {
+            container.parentNode.insertBefore(marker, container);
+            tmpRng.moveToElementText(marker);
+            tmpRng.moveStart('character', offset);
+            dom.remove(marker);
+            ieRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', tmpRng);
+          } else {
+            nodes = container.childNodes;
+
+            if (nodes.length) {
+              if (offset >= nodes.length) {
+                dom.insertAfter(marker, nodes[nodes.length - 1]);
+              } else {
+                container.insertBefore(marker, nodes[offset]);
+              }
+
+              tmpRng.moveToElementText(marker);
+            } else if (container.canHaveHTML) {
+              // Empty node selection for example <div>|</div>
+              // Setting innerHTML with a span marker then remove that marker seems to keep empty block elements open
+              container.innerHTML = '<span>&#xFEFF;</span>';
+              marker = container.firstChild;
+              tmpRng.moveToElementText(marker);
+              tmpRng.collapse(FALSE); // Collapse false works better than true for some odd reason
+            }
+
+            ieRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', tmpRng);
+            dom.remove(marker);
+          }
+        }
+
+        // Setup some shorter versions
+        startContainer = rng.startContainer;
+        startOffset = rng.startOffset;
+        endContainer = rng.endContainer;
+        endOffset = rng.endOffset;
+        ieRng = body.createTextRange();
+
+        // If single element selection then try making a control selection out of it
+        if (startContainer == endContainer && startContainer.nodeType == 1) {
+          // Trick to place the caret inside an empty block element like <p></p>
+          if (startOffset == endOffset && !startContainer.hasChildNodes()) {
+            if (startContainer.canHaveHTML) {
+              // Check if previous sibling is an empty block if it is then we need to render it
+              // IE would otherwise move the caret into the sibling instead of the empty startContainer see: #5236
+              // Example this: <p></p><p>|</p> would become this: <p>|</p><p></p>
+              sibling = startContainer.previousSibling;
+              if (sibling && !sibling.hasChildNodes() && dom.isBlock(sibling)) {
+                sibling.innerHTML = '&#xFEFF;';
+              } else {
+                sibling = null;
+              }
+
+              startContainer.innerHTML = '<span>&#xFEFF;</span><span>&#xFEFF;</span>';
+              ieRng.moveToElementText(startContainer.lastChild);
+              ieRng.select();
+              dom.doc.selection.clear();
+              startContainer.innerHTML = '';
+
+              if (sibling) {
+                sibling.innerHTML = '';
+              }
+              return;
+            }
+
+            startOffset = dom.nodeIndex(startContainer);
+            startContainer = startContainer.parentNode;
+          }
+
+          if (startOffset == endOffset - 1) {
+            try {
+              ctrlElm = startContainer.childNodes[startOffset];
+              ctrlRng = body.createControlRange();
+              ctrlRng.addElement(ctrlElm);
+              ctrlRng.select();
+
+              // Check if the range produced is on the correct element and is a control range
+              // On IE 8 it will select the parent contentEditable container if you select an inner element see: #5398
+              nativeRng = selection.getRng();
+              if (nativeRng.item && ctrlElm === nativeRng.item(0)) {
+                return;
+              }
+            } catch (ex) {
+              // Ignore
+            }
+          }
+        }
+
+        // Set start/end point of selection
+        setEndPoint(true);
+        setEndPoint();
+
+        // Select the new range and scroll it into view
+        ieRng.select();
+      };
+
+      // Expose range method
+      this.getRangeAt = getRange;
+    }
+
+    return Selection;
+  }
+);
+
+define(
+  'ephox.sugar.api.dom.Replication',
+
+  [
+    'ephox.sugar.api.properties.Attr',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.dom.Insert',
+    'ephox.sugar.api.dom.InsertAll',
+    'ephox.sugar.api.dom.Remove',
+    'ephox.sugar.api.search.Traverse'
+  ],
+
+  function (Attr, Element, Insert, InsertAll, Remove, Traverse) {
+    var clone = function (original, deep) {
+      return Element.fromDom(original.dom().cloneNode(deep));
+    };
+
+    /** Shallow clone - just the tag, no children */
+    var shallow = function (original) {
+      return clone(original, false);
+    };
+
+    /** Deep clone - everything copied including children */
+    var deep = function (original) {
+      return clone(original, true);
+    };
+
+    /** Shallow clone, with a new tag */
+    var shallowAs = function (original, tag) {
+      var nu = Element.fromTag(tag);
+
+      var attributes = Attr.clone(original);
+      Attr.setAll(nu, attributes);
+
+      return nu;
+    };
+
+    /** Deep clone, with a new tag */
+    var copy = function (original, tag) {
+      var nu = shallowAs(original, tag);
+
+      // NOTE
+      // previously this used serialisation:
+      // nu.dom().innerHTML = original.dom().innerHTML;
+      //
+      // Clone should be equivalent (and faster), but if TD <-> TH toggle breaks, put it back.
+
+      var cloneChildren = Traverse.children(deep(original));
+      InsertAll.append(nu, cloneChildren);
+
+      return nu;
+    };
+
+    /** Change the tag name, but keep all children */
+    var mutate = function (original, tag) {
+      var nu = shallowAs(original, tag);
+
+      Insert.before(original, nu);
+      var children = Traverse.children(original);
+      InsertAll.append(nu, children);
+      Remove.remove(original);
+      return nu;
+    };
+
+    return {
+      shallow: shallow,
+      shallowAs: shallowAs,
+      deep: deep,
+      copy: copy,
+      mutate: mutate
+    };
+  }
+);
+
+define(
+  'ephox.sugar.api.node.Fragment',
+
+  [
+    'ephox.katamari.api.Arr',
+    'ephox.sugar.api.node.Element',
+    'global!document'
+  ],
+
+  function (Arr, Element, document) {
+    var fromElements = function (elements, scope) {
+      var doc = scope || document;
+      var fragment = doc.createDocumentFragment();
+      Arr.each(elements, function (element) {
+        fragment.appendChild(element.dom());
+      });
+      return Element.fromDom(fragment);
+    };
+
+    return {
+      fromElements: fromElements
+    };
+  }
+);
+
+define(
+  'ephox.sugar.impl.ClosestOrAncestor',
+
+  [
+    'ephox.katamari.api.Type',
+    'ephox.katamari.api.Option'
+  ],
+
+  function (Type, Option) {
+    return function (is, ancestor, scope, a, isRoot) {
+      return is(scope, a) ?
+              Option.some(scope) :
+              Type.isFunction(isRoot) && isRoot(scope) ?
+                  Option.none() :
+                  ancestor(scope, a, isRoot);
+    };
+  }
+);
+define(
+  'ephox.sugar.api.search.PredicateFind',
+
+  [
+    'ephox.katamari.api.Type',
+    'ephox.katamari.api.Arr',
+    'ephox.katamari.api.Fun',
+    'ephox.katamari.api.Option',
+    'ephox.sugar.api.node.Body',
+    'ephox.sugar.api.dom.Compare',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.impl.ClosestOrAncestor'
+  ],
+
+  function (Type, Arr, Fun, Option, Body, Compare, Element, ClosestOrAncestor) {
+    var first = function (predicate) {
+      return descendant(Body.body(), predicate);
+    };
+
+    var ancestor = function (scope, predicate, isRoot) {
+      var element = scope.dom();
+      var stop = Type.isFunction(isRoot) ? isRoot : Fun.constant(false);
+
+      while (element.parentNode) {
+        element = element.parentNode;
+        var el = Element.fromDom(element);
+
+        if (predicate(el)) return Option.some(el);
+        else if (stop(el)) break;
+      }
+      return Option.none();
+    };
+
+    var closest = function (scope, predicate, isRoot) {
+      // This is required to avoid ClosestOrAncestor passing the predicate to itself
+      var is = function (scope) {
+        return predicate(scope);
+      };
+      return ClosestOrAncestor(is, ancestor, scope, predicate, isRoot);
+    };
+
+    var sibling = function (scope, predicate) {
+      var element = scope.dom();
+      if (!element.parentNode) return Option.none();
+
+      return child(Element.fromDom(element.parentNode), function (x) {
+        return !Compare.eq(scope, x) && predicate(x);
+      });
+    };
+
+    var child = function (scope, predicate) {
+      var result = Arr.find(scope.dom().childNodes,
+        Fun.compose(predicate, Element.fromDom));
+      return result.map(Element.fromDom);
+    };
+
+    var descendant = function (scope, predicate) {
+      var descend = function (element) {
+        for (var i = 0; i < element.childNodes.length; i++) {
+          if (predicate(Element.fromDom(element.childNodes[i])))
+            return Option.some(Element.fromDom(element.childNodes[i]));
+
+          var res = descend(element.childNodes[i]);
+          if (res.isSome())
+            return res;
+        }
+
+        return Option.none();
+      };
+
+      return descend(scope.dom());
+    };
+
+    return {
+      first: first,
+      ancestor: ancestor,
+      closest: closest,
+      sibling: sibling,
+      child: child,
+      descendant: descendant
+    };
+  }
+);
+
+define(
+  'ephox.sugar.api.search.SelectorFind',
+
+  [
+    'ephox.sugar.api.search.PredicateFind',
+    'ephox.sugar.api.search.Selectors',
+    'ephox.sugar.impl.ClosestOrAncestor'
+  ],
+
+  function (PredicateFind, Selectors, ClosestOrAncestor) {
+    // TODO: An internal SelectorFilter module that doesn't Element.fromDom() everything
+
+    var first = function (selector) {
+      return Selectors.one(selector);
+    };
+
+    var ancestor = function (scope, selector, isRoot) {
+      return PredicateFind.ancestor(scope, function (e) {
+        return Selectors.is(e, selector);
+      }, isRoot);
+    };
+
+    var sibling = function (scope, selector) {
+      return PredicateFind.sibling(scope, function (e) {
+        return Selectors.is(e, selector);
+      });
+    };
+
+    var child = function (scope, selector) {
+      return PredicateFind.child(scope, function (e) {
+        return Selectors.is(e, selector);
+      });
+    };
+
+    var descendant = function (scope, selector) {
+      return Selectors.one(selector, scope);
+    };
+
+    var closest = function (scope, selector, isRoot) {
+      return ClosestOrAncestor(Selectors.is, ancestor, scope, selector, isRoot);
+    };
+
+    return {
+      first: first,
+      ancestor: ancestor,
+      sibling: sibling,
+      child: child,
+      descendant: descendant,
+      closest: closest
+    };
+  }
+);
+
+/**
+ * Parents.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.dom.Parents',
+  [
+    'ephox.katamari.api.Fun',
+    'ephox.sugar.api.dom.Compare',
+    'ephox.sugar.api.search.Traverse'
+  ],
+  function (Fun, Compare, Traverse) {
+    var dropLast = function (xs) {
+      return xs.slice(0, -1);
+    };
+
+    var parentsUntil = function (startNode, rootElm, predicate) {
+      if (Compare.contains(rootElm, startNode)) {
+        return dropLast(Traverse.parents(startNode, function (elm) {
+          return predicate(elm) || Compare.eq(elm, rootElm);
+        }));
+      } else {
+        return [];
+      }
+    };
+
+    var parents = function (startNode, rootElm) {
+      return parentsUntil(startNode, rootElm, Fun.constant(false));
+    };
+
+    var parentsAndSelf = function (startNode, rootElm) {
+      return [startNode].concat(parents(startNode, rootElm));
+    };
+
+    return {
+      parentsUntil: parentsUntil,
+      parents: parents,
+      parentsAndSelf: parentsAndSelf
+    };
+  }
+);
+
+define(
+  'ephox.katamari.api.Options',
+
+  [
+    'ephox.katamari.api.Option'
+  ],
+
+  function (Option) {
+    /** cat :: [Option a] -> [a] */
+    var cat = function (arr) {
+      var r = [];
+      var push = function (x) {
+        r.push(x);
+      };
+      for (var i = 0; i < arr.length; i++) {
+        arr[i].each(push);
+      }
+      return r;
+    };
+
+    /** findMap :: ([a], (a, Int -> Option b)) -> Option b */
+    var findMap = function (arr, f) {
+      for (var i = 0; i < arr.length; i++) {
+        var r = f(arr[i], i);
+        if (r.isSome()) {
+          return r;
+        }
+      }
+      return Option.none();
+    };
+
+    /**
+     * if all elements in arr are 'some', their inner values are passed as arguments to f
+     * f must have arity arr.length
+    */
+    var liftN = function(arr, f) {
+      var r = [];
+      for (var i = 0; i < arr.length; i++) {
+        var x = arr[i];
+        if (x.isSome()) {
+          r.push(x.getOrDie());
+        } else {
+          return Option.none();
+        }
+      }
+      return Option.some(f.apply(null, r));
+    };
+
+    return {
+      cat: cat,
+      findMap: findMap,
+      liftN: liftN
+    };
+  }
+);
+
+/**
+ * SelectionUtils.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.selection.SelectionUtils',
+  [
+    'ephox.katamari.api.Arr',
+    'ephox.katamari.api.Fun',
+    'ephox.katamari.api.Option',
+    'ephox.katamari.api.Options',
+    'ephox.sugar.api.dom.Compare',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.node.Node',
+    'ephox.sugar.api.search.Traverse',
+    'tinymce.core.dom.NodeType'
+  ],
+  function (Arr, Fun, Option, Options, Compare, Element, Node, Traverse, NodeType) {
+    var getStartNode = function (rng) {
+      var sc = rng.startContainer, so = rng.startOffset;
+      if (NodeType.isText(sc)) {
+        return so === 0 ? Option.some(Element.fromDom(sc)) : Option.none();
+      } else {
+        return Option.from(sc.childNodes[so]).map(Element.fromDom);
+      }
+    };
+
+    var getEndNode = function (rng) {
+      var ec = rng.endContainer, eo = rng.endOffset;
+      if (NodeType.isText(ec)) {
+        return eo === ec.data.length ? Option.some(Element.fromDom(ec)) : Option.none();
+      } else {
+        return Option.from(ec.childNodes[eo - 1]).map(Element.fromDom);
+      }
+    };
+
+    var getFirstChildren = function (node) {
+      return Traverse.firstChild(node).fold(
+        Fun.constant([node]),
+        function (child) {
+          return [node].concat(getFirstChildren(child));
+        }
+      );
+    };
+
+    var getLastChildren = function (node) {
+      return Traverse.lastChild(node).fold(
+        Fun.constant([node]),
+        function (child) {
+          if (Node.name(child) === 'br') {
+            return Traverse.prevSibling(child).map(function (sibling) {
+              return [node].concat(getLastChildren(sibling));
+            }).getOr([]);
+          } else {
+            return [node].concat(getLastChildren(child));
+          }
+        }
+      );
+    };
+
+    var hasAllContentsSelected = function (elm, rng) {
+      return Options.liftN([getStartNode(rng), getEndNode(rng)], function (startNode, endNode) {
+        var start = Arr.find(getFirstChildren(elm), Fun.curry(Compare.eq, startNode));
+        var end = Arr.find(getLastChildren(elm), Fun.curry(Compare.eq, endNode));
+        return start.isSome() && end.isSome();
+      }).getOr(false);
+    };
+
+    return {
+      hasAllContentsSelected: hasAllContentsSelected
+    };
+  }
+);
+
+/**
+ * SimpleTableModel.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.selection.SimpleTableModel',
+  [
+    'ephox.katamari.api.Arr',
+    'ephox.katamari.api.Option',
+    'ephox.katamari.api.Struct',
+    'ephox.sugar.api.dom.Compare',
+    'ephox.sugar.api.dom.Insert',
+    'ephox.sugar.api.dom.InsertAll',
+    'ephox.sugar.api.dom.Replication',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.properties.Attr',
+    'ephox.sugar.api.search.SelectorFilter'
+  ],
+  function (Arr, Option, Struct, Compare, Insert, InsertAll, Replication, Element, Attr, SelectorFilter) {
+    var tableModel = Struct.immutable('element', 'width', 'rows');
+    var tableRow = Struct.immutable('element', 'cells');
+    var cellPosition = Struct.immutable('x', 'y');
+
+    var getSpan = function (td, key) {
+      var value = parseInt(Attr.get(td, key), 10);
+      return isNaN(value) ? 1 : value;
+    };
+
+    var fillout = function (table, x, y, tr, td) {
+      var rowspan = getSpan(td, 'rowspan');
+      var colspan = getSpan(td, 'colspan');
+      var rows = table.rows();
+
+      for (var y2 = y; y2 < y + rowspan; y2++) {
+        if (!rows[y2]) {
+          rows[y2] = tableRow(Replication.deep(tr), []);
+        }
+
+        for (var x2 = x; x2 < x + colspan; x2++) {
+          var cells = rows[y2].cells();
+
+          // not filler td:s are purposely not cloned so that we can
+          // find cells in the model by element object references
+          cells[x2] = y2 == y && x2 == x ? td : Replication.shallow(td);
+        }
+      }
+    };
+
+    var cellExists = function (table, x, y) {
+      var rows = table.rows();
+      var cells = rows[y] ? rows[y].cells() : [];
+      return !!cells[x];
+    };
+
+    var skipCellsX = function (table, x, y) {
+      while (cellExists(table, x, y)) {
+        x++;
+      }
+
+      return x;
+    };
+
+    var getWidth = function (rows) {
+      return Arr.foldl(rows, function (acc, row) {
+        return row.cells().length > acc ? row.cells().length : acc;
+      }, 0);
+    };
+
+    var findElementPos = function (table, element) {
+      var rows = table.rows();
+      for (var y = 0; y < rows.length; y++) {
+        var cells = rows[y].cells();
+        for (var x = 0; x < cells.length; x++) {
+          if (Compare.eq(cells[x], element)) {
+            return Option.some(cellPosition(x, y));
+          }
+        }
+      }
+
+      return Option.none();
+    };
+
+    var extractRows = function (table, sx, sy, ex, ey) {
+      var newRows = [];
+      var rows = table.rows();
+
+      for (var y = sy; y <= ey; y++) {
+        var cells = rows[y].cells();
+        var slice = sx < ex ? cells.slice(sx, ex + 1) : cells.slice(ex, sx + 1);
+        newRows.push(tableRow(rows[y].element(), slice));
+      }
+
+      return newRows;
+    };
+
+    var subTable = function (table, startPos, endPos) {
+      var sx = startPos.x(), sy = startPos.y();
+      var ex = endPos.x(), ey = endPos.y();
+      var newRows = sy < ey ? extractRows(table, sx, sy, ex, ey) : extractRows(table, sx, ey, ex, sy);
+
+      return tableModel(table.element(), getWidth(newRows), newRows);
+    };
+
+    var createDomTable = function (table, rows) {
+      var tableElement = Replication.shallow(table.element());
+      var tableBody = Element.fromTag('tbody');
+
+      InsertAll.append(tableBody, rows);
+      Insert.append(tableElement, tableBody);
+
+      return tableElement;
+    };
+
+    var modelRowsToDomRows = function (table) {
+      return Arr.map(table.rows(), function (row) {
+        var cells = Arr.map(row.cells(), function (cell) {
+          var td = Replication.deep(cell);
+          Attr.remove(td, 'colspan');
+          Attr.remove(td, 'rowspan');
+          return td;
+        });
+
+        var tr = Replication.shallow(row.element());
+        InsertAll.append(tr, cells);
+        return tr;
+      });
+    };
+
+    var fromDom = function (tableElm) {
+      var table = tableModel(Replication.shallow(tableElm), 0, []);
+
+      Arr.each(SelectorFilter.descendants(tableElm, 'tr'), function (tr, y) {
+        Arr.each(SelectorFilter.descendants(tr, 'td,th'), function (td, x) {
+          fillout(table, skipCellsX(table, x, y), y, tr, td);
+        });
+      });
+
+      return tableModel(table.element(), getWidth(table.rows()), table.rows());
+    };
+
+    var toDom = function (table) {
+      return createDomTable(table, modelRowsToDomRows(table));
+    };
+
+    var subsection = function (table, startElement, endElement) {
+      return findElementPos(table, startElement).bind(function (startPos) {
+        return findElementPos(table, endElement).map(function (endPos) {
+          return subTable(table, startPos, endPos);
+        });
+      });
+    };
+
+    return {
+      fromDom: fromDom,
+      toDom: toDom,
+      subsection: subsection
+    };
+  }
+);
+
+/**
+ * MultiRange.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.selection.MultiRange',
+  [
+    'ephox.katamari.api.Arr',
+    'ephox.sugar.api.node.Element',
+    'tinymce.core.dom.RangeUtils'
+  ],
+  function (Arr, Element, RangeUtils) {
+    var getRanges = function (selection) {
+      var ranges = [];
+
+      for (var i = 0; i < selection.rangeCount; i++) {
+        ranges.push(selection.getRangeAt(i));
+      }
+
+      return ranges;
+    };
+
+    var getSelectedNodes = function (ranges) {
+      return Arr.bind(ranges, function (range) {
+        var node = RangeUtils.getSelectedNode(range);
+        return node ? [ Element.fromDom(node) ] : [];
+      });
+    };
+
+    var hasMultipleRanges = function (selection) {
+      return getRanges(selection).length > 1;
+    };
+
+    return {
+      getRanges: getRanges,
+      getSelectedNodes: getSelectedNodes,
+      hasMultipleRanges: hasMultipleRanges
+    };
+  }
+);
+
+/**
+ * TableCellSelection.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.selection.TableCellSelection',
+  [
+    'ephox.katamari.api.Arr',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.search.SelectorFilter',
+    'tinymce.core.dom.ElementType',
+    'tinymce.core.selection.MultiRange'
+  ],
+  function (Arr, Element, SelectorFilter, ElementType, MultiRange) {
+    var getCellsFromRanges = function (ranges) {
+      return Arr.filter(MultiRange.getSelectedNodes(ranges), ElementType.isTableCell);
+    };
+
+    var getCellsFromElement = function (elm) {
+      var selectedCells = SelectorFilter.descendants(elm, 'td[data-mce-selected],th[data-mce-selected]');
+      return selectedCells;
+    };
+
+    var getCellsFromElementOrRanges = function (ranges, element) {
+      var selectedCells = getCellsFromElement(element);
+      var rangeCells = getCellsFromRanges(ranges);
+      return selectedCells.length > 0 ? selectedCells : rangeCells;
+    };
+
+    var getCellsFromEditor = function (editor) {
+      return getCellsFromElementOrRanges(MultiRange.getRanges(editor.selection.getSel()), Element.fromDom(editor.getBody()));
+    };
+
+    return {
+      getCellsFromRanges: getCellsFromRanges,
+      getCellsFromElement: getCellsFromElement,
+      getCellsFromElementOrRanges: getCellsFromElementOrRanges,
+      getCellsFromEditor: getCellsFromEditor
+    };
+  }
+);
+
+/**
+ * FragmentReader.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.selection.FragmentReader',
+  [
+    'ephox.katamari.api.Arr',
+    'ephox.katamari.api.Fun',
+    'ephox.sugar.api.dom.Compare',
+    'ephox.sugar.api.dom.Insert',
+    'ephox.sugar.api.dom.Replication',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.node.Fragment',
+    'ephox.sugar.api.node.Node',
+    'ephox.sugar.api.search.SelectorFind',
+    'ephox.sugar.api.search.Traverse',
+    'tinymce.core.dom.ElementType',
+    'tinymce.core.dom.Parents',
+    'tinymce.core.selection.SelectionUtils',
+    'tinymce.core.selection.SimpleTableModel',
+    'tinymce.core.selection.TableCellSelection'
+  ],
+  function (Arr, Fun, Compare, Insert, Replication, Element, Fragment, Node, SelectorFind, Traverse, ElementType, Parents, SelectionUtils, SimpleTableModel, TableCellSelection) {
+    var findParentListContainer = function (parents) {
+      return Arr.find(parents, function (elm) {
+        return Node.name(elm) === 'ul' || Node.name(elm) === 'ol';
+      });
+    };
+
+    var getFullySelectedListWrappers = function (parents, rng) {
+      return Arr.find(parents, function (elm) {
+        return Node.name(elm) === 'li' && SelectionUtils.hasAllContentsSelected(elm, rng);
+      }).fold(
+        Fun.constant([]),
+        function (li) {
+          return findParentListContainer(parents).map(function (listCont) {
+            return [
+              Element.fromTag('li'),
+              Element.fromTag(Node.name(listCont))
+            ];
+          }).getOr([]);
+        }
+      );
+    };
+
+    var wrap = function (innerElm, elms) {
+      var wrapped = Arr.foldl(elms, function (acc, elm) {
+        Insert.append(elm, acc);
+        return elm;
+      }, innerElm);
+      return elms.length > 0 ? Fragment.fromElements([wrapped]) : wrapped;
+    };
+
+    var directListWrappers = function (commonAnchorContainer) {
+      if (ElementType.isListItem(commonAnchorContainer)) {
+        return Traverse.parent(commonAnchorContainer).filter(ElementType.isList).fold(
+          Fun.constant([]),
+          function (listElm) {
+            return [ commonAnchorContainer, listElm ];
+          }
+        );
+      } else {
+        return ElementType.isList(commonAnchorContainer) ? [ commonAnchorContainer ] : [ ];
+      }
+    };
+
+    var getWrapElements = function (rootNode, rng) {
+      var commonAnchorContainer = Element.fromDom(rng.commonAncestorContainer);
+      var parents = Parents.parentsAndSelf(commonAnchorContainer, rootNode);
+      var wrapElements = Arr.filter(parents, function (elm) {
+        return ElementType.isInline(elm) || ElementType.isHeading(elm);
+      });
+      var listWrappers = getFullySelectedListWrappers(parents, rng);
+      var allWrappers = wrapElements.concat(listWrappers.length ? listWrappers : directListWrappers(commonAnchorContainer));
+      return Arr.map(allWrappers, Replication.shallow);
+    };
+
+    var emptyFragment = function () {
+      return Fragment.fromElements([]);
+    };
+
+    var getFragmentFromRange = function (rootNode, rng) {
+      return wrap(Element.fromDom(rng.cloneContents()), getWrapElements(rootNode, rng));
+    };
+
+    var getParentTable = function (rootElm, cell) {
+      return SelectorFind.ancestor(cell, 'table', Fun.curry(Compare.eq, rootElm));
+    };
+
+    var getTableFragment = function (rootNode, selectedTableCells) {
+      return getParentTable(rootNode, selectedTableCells[0]).bind(function (tableElm) {
+        var firstCell = selectedTableCells[0];
+        var lastCell = selectedTableCells[selectedTableCells.length - 1];
+        var fullTableModel = SimpleTableModel.fromDom(tableElm);
+
+        return SimpleTableModel.subsection(fullTableModel, firstCell, lastCell).map(function (sectionedTableModel) {
+          return Fragment.fromElements([SimpleTableModel.toDom(sectionedTableModel)]);
+        });
+      }).getOrThunk(emptyFragment);
+    };
+
+    var getSelectionFragment = function (rootNode, ranges) {
+      return ranges.length > 0 && ranges[0].collapsed ? emptyFragment() : getFragmentFromRange(rootNode, ranges[0]);
+    };
+
+    var read = function (rootNode, ranges) {
+      var selectedCells = TableCellSelection.getCellsFromElementOrRanges(ranges, rootNode);
+      return selectedCells.length > 0 ? getTableFragment(rootNode, selectedCells) : getSelectionFragment(rootNode, ranges);
+    };
+
+    return {
+      read: read
+    };
+  }
+);
+
+/**
+ * Selection.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This class handles text and control selection it's an crossbrowser utility class.
+ * Consult the TinyMCE Wiki API for more details and examples on how to use this class.
+ *
+ * @class tinymce.dom.Selection
+ * @example
+ * // Getting the currently selected node for the active editor
+ * alert(tinymce.activeEditor.selection.getNode().nodeName);
+ */
+define(
+  'tinymce.core.dom.Selection',
+  [
+    'ephox.katamari.api.Arr',
+    'ephox.sugar.api.dom.Compare',
+    'ephox.sugar.api.node.Element',
+    'tinymce.core.caret.CaretPosition',
+    'tinymce.core.dom.BookmarkManager',
+    'tinymce.core.dom.ControlSelection',
+    'tinymce.core.dom.NodeType',
+    'tinymce.core.dom.RangeUtils',
+    'tinymce.core.dom.ScrollIntoView',
+    'tinymce.core.dom.TreeWalker',
+    'tinymce.core.dom.TridentSelection',
+    'tinymce.core.Env',
+    'tinymce.core.selection.FragmentReader',
+    'tinymce.core.selection.MultiRange',
+    'tinymce.core.text.Zwsp',
+    'tinymce.core.util.Tools'
+  ],
+  function (
+    Arr, Compare, Element, CaretPosition, BookmarkManager, ControlSelection, NodeType, RangeUtils, ScrollIntoView, TreeWalker, TridentSelection, Env, FragmentReader,
+    MultiRange, Zwsp, Tools
+  ) {
+    var each = Tools.each, trim = Tools.trim;
+    var isIE = Env.ie;
+
+    var isAttachedToDom = function (node) {
+      return !!(node && node.ownerDocument) && Compare.contains(Element.fromDom(node.ownerDocument), Element.fromDom(node));
+    };
+
+    var isValidRange = function (rng) {
+      if (!rng) {
+        return false;
+      } else if (rng.select) { // Native IE range still produced by placeCaretAt
+        return true;
+      } else {
+        return isAttachedToDom(rng.startContainer) && isAttachedToDom(rng.endContainer);
+      }
+    };
+
+    var eventProcessRanges = function (editor, ranges) {
+      return Arr.map(ranges, function (range) {
+        var evt = editor.fire('GetSelectionRange', { range: range });
+        return evt.range !== range ? evt.range : range;
+      });
+    };
+
+    /**
+     * Constructs a new selection instance.
+     *
+     * @constructor
+     * @method Selection
+     * @param {tinymce.dom.DOMUtils} dom DOMUtils object reference.
+     * @param {Window} win Window to bind the selection object to.
+     * @param {tinymce.Editor} editor Editor instance of the selection.
+     * @param {tinymce.dom.Serializer} serializer DOM serialization class to use for getContent.
+     */
+    function Selection(dom, win, serializer, editor) {
+      var self = this;
+
+      self.dom = dom;
+      self.win = win;
+      self.serializer = serializer;
+      self.editor = editor;
+      self.bookmarkManager = new BookmarkManager(self);
+      self.controlSelection = new ControlSelection(self, editor);
+
+      // No W3C Range support
+      if (!self.win.getSelection) {
+        self.tridentSel = new TridentSelection(self);
+      }
+    }
+
+    Selection.prototype = {
</ins><span class="cx" style="display: block; padding: 0 10px">       /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * Creates a alert dialog. Please don't use the blocking behavior of this
-       * native version use the callback method instead then it can be extended.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * Move the selection cursor range to the specified node and offset.
+       * If there is no node specified it will move it to the first suitable location within the body.
</ins><span class="cx" style="display: block; padding: 0 10px">        *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * @method alert
-       * @param {String} message Text to display in the new alert dialog.
-       * @param {function} callback Callback function to be executed after the user has selected ok.
-       * @param {Object} scope Optional scope to execute the callback in.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * @method setCursorLocation
+       * @param {Node} node Optional node to put the cursor in.
+       * @param {Number} offset Optional offset from the start of the node to put the cursor at.
+       */
+      setCursorLocation: function (node, offset) {
+        var self = this, rng = self.dom.createRng();
+
+        if (!node) {
+          self._moveEndPoint(rng, self.editor.getBody(), true);
+          self.setRng(rng);
+        } else {
+          rng.setStart(node, offset);
+          rng.setEnd(node, offset);
+          self.setRng(rng);
+          self.collapse(false);
+        }
+      },
+
+      /**
+       * Returns the selected contents using the DOM serializer passed in to this class.
+       *
+       * @method getContent
+       * @param {Object} args Optional settings class with for example output format text or html.
+       * @return {String} Selected contents in for example HTML format.
</ins><span class="cx" style="display: block; padding: 0 10px">        * @example
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * // Displays an alert box using the active editors window manager instance
-       * tinymce.activeEditor.windowManager.alert('Hello world!');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * // Alerts the currently selected contents
+       * alert(tinymce.activeEditor.selection.getContent());
+       *
+       * // Alerts the currently selected contents as plain text
+       * alert(tinymce.activeEditor.selection.getContent({format: 'text'}));
</ins><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      self.alert = function (message, callback, scope) {
-        var win;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      getContent: function (args) {
+        var self = this, rng = self.getRng(), tmpElm = self.dom.create("body");
+        var se = self.getSel(), whiteSpaceBefore, whiteSpaceAfter, fragment;
+        var ranges = eventProcessRanges(self.editor, MultiRange.getRanges(this.getSel()));
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        win = MessageBox.alert(message, function () {
-          if (callback) {
-            callback.call(scope || this);
-          } else {
-            editor.focus();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        args = args || {};
+        whiteSpaceBefore = whiteSpaceAfter = '';
+        args.get = true;
+        args.format = args.format || 'html';
+        args.selection = true;
+        self.editor.fire('BeforeGetContent', args);
+
+        if (args.format === 'text') {
+          return self.isCollapsed() ? '' : Zwsp.trim(rng.text || (se.toString ? se.toString() : ''));
+        }
+
+        if (rng.cloneContents) {
+          fragment = args.contextual ? FragmentReader.read(Element.fromDom(self.editor.getBody()), ranges).dom() : rng.cloneContents();
+          if (fragment) {
+            tmpElm.appendChild(fragment);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        } else if (rng.item !== undefined || rng.htmlText !== undefined) {
+          // IE will produce invalid markup if elements are present that
+          // it doesn't understand like custom elements or HTML5 elements.
+          // Adding a BR in front of the contents and then remoiving it seems to fix it though.
+          tmpElm.innerHTML = '<br>' + (rng.item ? rng.item(0).outerHTML : rng.htmlText);
+          tmpElm.removeChild(tmpElm.firstChild);
+        } else {
+          tmpElm.innerHTML = rng.toString();
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        win.on('close', function () {
-          fireCloseEvent(win);
-        });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Keep whitespace before and after
+        if (/^\s/.test(tmpElm.innerHTML)) {
+          whiteSpaceBefore = ' ';
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        fireOpenEvent(win);
-      };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (/\s+$/.test(tmpElm.innerHTML)) {
+          whiteSpaceAfter = ' ';
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        args.getInner = true;
+
+        args.content = self.isCollapsed() ? '' : whiteSpaceBefore + self.serializer.serialize(tmpElm, args) + whiteSpaceAfter;
+        self.editor.fire('GetContent', args);
+
+        return args.content;
+      },
+
</ins><span class="cx" style="display: block; padding: 0 10px">       /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * Creates a confirm dialog. Please don't use the blocking behavior of this
-       * native version use the callback method instead then it can be extended.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * Sets the current selection to the specified content. If any contents is selected it will be replaced
+       * with the contents passed in to this function. If there is no selection the contents will be inserted
+       * where the caret is placed in the editor/page.
</ins><span class="cx" style="display: block; padding: 0 10px">        *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * @method confirm
-       * @param {String} message Text to display in the new confirm dialog.
-       * @param {function} callback Callback function to be executed after the user has selected ok or cancel.
-       * @param {Object} scope Optional scope to execute the callback in.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * @method setContent
+       * @param {String} content HTML contents to set could also be other formats depending on settings.
+       * @param {Object} args Optional settings object with for example data format.
</ins><span class="cx" style="display: block; padding: 0 10px">        * @example
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * // Displays an confirm box and an alert message will be displayed depending on what you choose in the confirm
-       * tinymce.activeEditor.windowManager.confirm("Do you want to do something", function(s) {
-       *    if (s)
-       *       tinymce.activeEditor.windowManager.alert("Ok");
-       *    else
-       *       tinymce.activeEditor.windowManager.alert("Cancel");
-       * });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * // Inserts some HTML contents at the current selection
+       * tinymce.activeEditor.selection.setContent('<strong>Some contents</strong>');
</ins><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      self.confirm = function (message, callback, scope) {
-        var win;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      setContent: function (content, args) {
+        var self = this, rng = self.getRng(), caretNode, doc = self.win.document, frag, temp;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        win = MessageBox.confirm(message, function (state) {
-          callback.call(scope || this, state);
-        });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        args = args || { format: 'html' };
+        args.set = true;
+        args.selection = true;
+        args.content = content;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        win.on('close', function () {
-          fireCloseEvent(win);
-        });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Dispatch before set content event
+        if (!args.no_events) {
+          self.editor.fire('BeforeSetContent', args);
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        fireOpenEvent(win);
-      };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        content = args.content;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (rng.insertNode) {
+          // Make caret marker since insertNode places the caret in the beginning of text after insert
+          content += '<span id="__caret">_</span>';
+
+          // Delete and insert new node
+          if (rng.startContainer == doc && rng.endContainer == doc) {
+            // WebKit will fail if the body is empty since the range is then invalid and it can't insert contents
+            doc.body.innerHTML = content;
+          } else {
+            rng.deleteContents();
+
+            if (doc.body.childNodes.length === 0) {
+              doc.body.innerHTML = content;
+            } else {
+              // createContextualFragment doesn't exists in IE 9 DOMRanges
+              if (rng.createContextualFragment) {
+                rng.insertNode(rng.createContextualFragment(content));
+              } else {
+                // Fake createContextualFragment call in IE 9
+                frag = doc.createDocumentFragment();
+                temp = doc.createElement('div');
+
+                frag.appendChild(temp);
+                temp.outerHTML = content;
+
+                rng.insertNode(frag);
+              }
+            }
+          }
+
+          // Move to caret marker
+          caretNode = self.dom.get('__caret');
+
+          // Make sure we wrap it compleatly, Opera fails with a simple select call
+          rng = doc.createRange();
+          rng.setStartBefore(caretNode);
+          rng.setEndBefore(caretNode);
+          self.setRng(rng);
+
+          // Remove the caret position
+          self.dom.remove('__caret');
+
+          try {
+            self.setRng(rng);
+          } catch (ex) {
+            // Might fail on Opera for some odd reason
+          }
+        } else {
+          if (rng.item) {
+            // Delete content and get caret text selection
+            doc.execCommand('Delete', false, null);
+            rng = self.getRng();
+          }
+
+          // Explorer removes spaces from the beginning of pasted contents
+          if (/^\s+/.test(content)) {
+            rng.pasteHTML('<span id="__mce_tmp">_</span>' + content);
+            self.dom.remove('__mce_tmp');
+          } else {
+            rng.pasteHTML(content);
+          }
+        }
+
+        // Dispatch set content event
+        if (!args.no_events) {
+          self.editor.fire('SetContent', args);
+        }
+      },
+
</ins><span class="cx" style="display: block; padding: 0 10px">       /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * Closes the top most window.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * Returns the start element of a selection range. If the start is in a text
+       * node the parent element will be returned.
</ins><span class="cx" style="display: block; padding: 0 10px">        *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * @method close
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * @method getStart
+       * @param {Boolean} real Optional state to get the real parent when the selection is collapsed not the closest element.
+       * @return {Element} Start element of selection range.
</ins><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      self.close = function () {
-        if (getTopMostWindow()) {
-          getTopMostWindow().close();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      getStart: function (real) {
+        var self = this, rng = self.getRng(), startElement, parentElement, checkRng, node;
+
+        if (rng.duplicate || rng.item) {
+          // Control selection, return first item
+          if (rng.item) {
+            return rng.item(0);
+          }
+
+          // Get start element
+          checkRng = rng.duplicate();
+          checkRng.collapse(1);
+          startElement = checkRng.parentElement();
+          if (startElement.ownerDocument !== self.dom.doc) {
+            startElement = self.dom.getRoot();
+          }
+
+          // Check if range parent is inside the start element, then return the inner parent element
+          // This will fix issues when a single element is selected, IE would otherwise return the wrong start element
+          parentElement = node = rng.parentElement();
+          while ((node = node.parentNode)) {
+            if (node == startElement) {
+              startElement = parentElement;
+              break;
+            }
+          }
+
+          return startElement;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        startElement = rng.startContainer;
+
+        if (startElement.nodeType == 1 && startElement.hasChildNodes()) {
+          if (!real || !rng.collapsed) {
+            startElement = startElement.childNodes[Math.min(startElement.childNodes.length - 1, rng.startOffset)];
+          }
+        }
+
+        if (startElement && startElement.nodeType == 3) {
+          return startElement.parentNode;
+        }
+
+        return startElement;
+      },
+
</ins><span class="cx" style="display: block; padding: 0 10px">       /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * Returns the params of the last window open call. This can be used in iframe based
-       * dialog to get params passed from the tinymce plugin.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * Returns the end element of a selection range. If the end is in a text
+       * node the parent element will be returned.
</ins><span class="cx" style="display: block; padding: 0 10px">        *
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * @method getEnd
+       * @param {Boolean} real Optional state to get the real parent when the selection is collapsed not the closest element.
+       * @return {Element} End element of selection range.
+       */
+      getEnd: function (real) {
+        var self = this, rng = self.getRng(), endElement, endOffset;
+
+        if (rng.duplicate || rng.item) {
+          if (rng.item) {
+            return rng.item(0);
+          }
+
+          rng = rng.duplicate();
+          rng.collapse(0);
+          endElement = rng.parentElement();
+          if (endElement.ownerDocument !== self.dom.doc) {
+            endElement = self.dom.getRoot();
+          }
+
+          if (endElement && endElement.nodeName == 'BODY') {
+            return endElement.lastChild || endElement;
+          }
+
+          return endElement;
+        }
+
+        endElement = rng.endContainer;
+        endOffset = rng.endOffset;
+
+        if (endElement.nodeType == 1 && endElement.hasChildNodes()) {
+          if (!real || !rng.collapsed) {
+            endElement = endElement.childNodes[endOffset > 0 ? endOffset - 1 : endOffset];
+          }
+        }
+
+        if (endElement && endElement.nodeType == 3) {
+          return endElement.parentNode;
+        }
+
+        return endElement;
+      },
+
+      /**
+       * Returns a bookmark location for the current selection. This bookmark object
+       * can then be used to restore the selection after some content modification to the document.
+       *
+       * @method getBookmark
+       * @param {Number} type Optional state if the bookmark should be simple or not. Default is complex.
+       * @param {Boolean} normalized Optional state that enables you to get a position that it would be after normalization.
+       * @return {Object} Bookmark object, use moveToBookmark with this object to restore the selection.
</ins><span class="cx" style="display: block; padding: 0 10px">        * @example
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * var dialogArguments = top.tinymce.activeEditor.windowManager.getParams();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * // Stores a bookmark of the current selection
+       * var bm = tinymce.activeEditor.selection.getBookmark();
</ins><span class="cx" style="display: block; padding: 0 10px">        *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * @method getParams
-       * @return {Object} Name/value object with parameters passed from windowManager.open call.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * tinymce.activeEditor.setContent(tinymce.activeEditor.getContent() + 'Some new content');
+       *
+       * // Restore the selection bookmark
+       * tinymce.activeEditor.selection.moveToBookmark(bm);
</ins><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      self.getParams = function () {
-        return getTopMostWindow() ? getTopMostWindow().params : null;
-      };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      getBookmark: function (type, normalized) {
+        return this.bookmarkManager.getBookmark(type, normalized);
+      },
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * Sets the params of the last opened window.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * Restores the selection to the specified bookmark.
</ins><span class="cx" style="display: block; padding: 0 10px">        *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * @method setParams
-       * @param {Object} params Params object to set for the last opened window.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * @method moveToBookmark
+       * @param {Object} bookmark Bookmark to restore selection from.
+       * @return {Boolean} true/false if it was successful or not.
+       * @example
+       * // Stores a bookmark of the current selection
+       * var bm = tinymce.activeEditor.selection.getBookmark();
+       *
+       * tinymce.activeEditor.setContent(tinymce.activeEditor.getContent() + 'Some new content');
+       *
+       * // Restore the selection bookmark
+       * tinymce.activeEditor.selection.moveToBookmark(bm);
</ins><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      self.setParams = function (params) {
-        if (getTopMostWindow()) {
-          getTopMostWindow().params = params;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      moveToBookmark: function (bookmark) {
+        return this.bookmarkManager.moveToBookmark(bookmark);
+      },
+
+      /**
+       * Selects the specified element. This will place the start and end of the selection range around the element.
+       *
+       * @method select
+       * @param {Element} node HTML DOM element to select.
+       * @param {Boolean} content Optional bool state if the contents should be selected or not on non IE browser.
+       * @return {Element} Selected element the same element as the one that got passed in.
+       * @example
+       * // Select the first paragraph in the active editor
+       * tinymce.activeEditor.selection.select(tinymce.activeEditor.dom.select('p')[0]);
+       */
+      select: function (node, content) {
+        var self = this, dom = self.dom, rng = dom.createRng(), idx;
+
+        // Clear stored range set by FocusManager
+        self.lastFocusBookmark = null;
+
+        if (node) {
+          if (!content && self.controlSelection.controlSelect(node)) {
+            return;
+          }
+
+          idx = dom.nodeIndex(node);
+          rng.setStart(node.parentNode, idx);
+          rng.setEnd(node.parentNode, idx + 1);
+
+          // Find first/last text node or BR element
+          if (content) {
+            self._moveEndPoint(rng, node, true);
+            self._moveEndPoint(rng, node);
+          }
+
+          self.setRng(rng);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return node;
+      },
+
</ins><span class="cx" style="display: block; padding: 0 10px">       /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * Returns the currently opened window objects.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * Returns true/false if the selection range is collapsed or not. Collapsed means if it's a caret or a larger selection.
</ins><span class="cx" style="display: block; padding: 0 10px">        *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * @method getWindows
-       * @return {Array} Array of the currently opened windows.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * @method isCollapsed
+       * @return {Boolean} true/false state if the selection range is collapsed or not.
+       * Collapsed means if it's a caret or a larger selection.
</ins><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      self.getWindows = function () {
-        return windows;
-      };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      isCollapsed: function () {
+        var self = this, rng = self.getRng(), sel = self.getSel();
+
+        if (!rng || rng.item) {
+          return false;
+        }
+
+        if (rng.compareEndPoints) {
+          return rng.compareEndPoints('StartToEnd', rng) === 0;
+        }
+
+        return !sel || rng.collapsed;
+      },
+
+      /**
+       * Collapse the selection to start or end of range.
+       *
+       * @method collapse
+       * @param {Boolean} toStart Optional boolean state if to collapse to end or not. Defaults to false.
+       */
+      collapse: function (toStart) {
+        var self = this, rng = self.getRng(), node;
+
+        // Control range on IE
+        if (rng.item) {
+          node = rng.item(0);
+          rng = self.win.document.body.createTextRange();
+          rng.moveToElementText(node);
+        }
+
+        rng.collapse(!!toStart);
+        self.setRng(rng);
+      },
+
+      /**
+       * Returns the browsers internal selection object.
+       *
+       * @method getSel
+       * @return {Selection} Internal browser selection object.
+       */
+      getSel: function () {
+        var win = this.win;
+
+        return win.getSelection ? win.getSelection() : win.document.selection;
+      },
+
+      /**
+       * Returns the browsers internal range object.
+       *
+       * @method getRng
+       * @param {Boolean} w3c Forces a compatible W3C range on IE.
+       * @return {Range} Internal browser range object.
+       * @see http://www.quirksmode.org/dom/range_intro.html
+       * @see http://www.dotvoid.com/2001/03/using-the-range-object-in-mozilla/
+       */
+      getRng: function (w3c) {
+        var self = this, selection, rng, elm, doc, ieRng;
+
+        function tryCompareBoundaryPoints(how, sourceRange, destinationRange) {
+          try {
+            return sourceRange.compareBoundaryPoints(how, destinationRange);
+          } catch (ex) {
+            // Gecko throws wrong document exception if the range points
+            // to nodes that where removed from the dom #6690
+            // Browsers should mutate existing DOMRange instances so that they always point
+            // to something in the document this is not the case in Gecko works fine in IE/WebKit/Blink
+            // For performance reasons just return -1
+            return -1;
+          }
+        }
+
+        if (!self.win) {
+          return null;
+        }
+
+        doc = self.win.document;
+
+        if (typeof doc === 'undefined' || doc === null) {
+          return null;
+        }
+
+        // Use last rng passed from FocusManager if it's available this enables
+        // calls to editor.selection.getStart() to work when caret focus is lost on IE
+        if (!w3c && self.lastFocusBookmark) {
+          var bookmark = self.lastFocusBookmark;
+
+          // Convert bookmark to range IE 11 fix
+          if (bookmark.startContainer) {
+            rng = doc.createRange();
+            rng.setStart(bookmark.startContainer, bookmark.startOffset);
+            rng.setEnd(bookmark.endContainer, bookmark.endOffset);
+          } else {
+            rng = bookmark;
+          }
+
+          return rng;
+        }
+
+        // Found tridentSel object then we need to use that one
+        if (w3c && self.tridentSel) {
+          return self.tridentSel.getRangeAt(0);
+        }
+
+        try {
+          if ((selection = self.getSel())) {
+            if (selection.rangeCount > 0) {
+              rng = selection.getRangeAt(0);
+            } else {
+              rng = selection.createRange ? selection.createRange() : doc.createRange();
+            }
+          }
+        } catch (ex) {
+          // IE throws unspecified error here if TinyMCE is placed in a frame/iframe
+        }
+
+        rng = eventProcessRanges(self.editor, [ rng ])[0];
+
+        // We have W3C ranges and it's IE then fake control selection since IE9 doesn't handle that correctly yet
+        // IE 11 doesn't support the selection object so we check for that as well
+        if (isIE && rng && rng.setStart && doc.selection) {
+          try {
+            // IE will sometimes throw an exception here
+            ieRng = doc.selection.createRange();
+          } catch (ex) {
+            // Ignore
+          }
+
+          if (ieRng && ieRng.item) {
+            elm = ieRng.item(0);
+            rng = doc.createRange();
+            rng.setStartBefore(elm);
+            rng.setEndAfter(elm);
+          }
+        }
+
+        // No range found then create an empty one
+        // This can occur when the editor is placed in a hidden container element on Gecko
+        // Or on IE when there was an exception
+        if (!rng) {
+          rng = doc.createRange ? doc.createRange() : doc.body.createTextRange();
+        }
+
+        // If range is at start of document then move it to start of body
+        if (rng.setStart && rng.startContainer.nodeType === 9 && rng.collapsed) {
+          elm = self.dom.getRoot();
+          rng.setStart(elm, 0);
+          rng.setEnd(elm, 0);
+        }
+
+        if (self.selectedRange && self.explicitRange) {
+          if (tryCompareBoundaryPoints(rng.START_TO_START, rng, self.selectedRange) === 0 &&
+            tryCompareBoundaryPoints(rng.END_TO_END, rng, self.selectedRange) === 0) {
+            // Safari, Opera and Chrome only ever select text which causes the range to change.
+            // This lets us use the originally set range if the selection hasn't been changed by the user.
+            rng = self.explicitRange;
+          } else {
+            self.selectedRange = null;
+            self.explicitRange = null;
+          }
+        }
+
+        return rng;
+      },
+
+      /**
+       * Changes the selection to the specified DOM range.
+       *
+       * @method setRng
+       * @param {Range} rng Range to select.
+       * @param {Boolean} forward Optional boolean if the selection is forwards or backwards.
+       */
+      setRng: function (rng, forward) {
+        var self = this, sel, node, evt;
+
+        if (!isValidRange(rng)) {
+          return;
+        }
+
+        // Is IE specific range
+        if (rng.select) {
+          self.explicitRange = null;
+
+          try {
+            rng.select();
+          } catch (ex) {
+            // Needed for some odd IE bug #1843306
+          }
+
+          return;
+        }
+
+        if (!self.tridentSel) {
+          sel = self.getSel();
+
+          evt = self.editor.fire('SetSelectionRange', { range: rng, forward: forward });
+          rng = evt.range;
+
+          if (sel) {
+            self.explicitRange = rng;
+
+            try {
+              sel.removeAllRanges();
+              sel.addRange(rng);
+            } catch (ex) {
+              // IE might throw errors here if the editor is within a hidden container and selection is changed
+            }
+
+            // Forward is set to false and we have an extend function
+            if (forward === false && sel.extend) {
+              sel.collapse(rng.endContainer, rng.endOffset);
+              sel.extend(rng.startContainer, rng.startOffset);
+            }
+
+            // adding range isn't always successful so we need to check range count otherwise an exception can occur
+            self.selectedRange = sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
+          }
+
+          // WebKit egde case selecting images works better using setBaseAndExtent when the image is floated
+          if (!rng.collapsed && rng.startContainer === rng.endContainer && sel.setBaseAndExtent && !Env.ie) {
+            if (rng.endOffset - rng.startOffset < 2) {
+              if (rng.startContainer.hasChildNodes()) {
+                node = rng.startContainer.childNodes[rng.startOffset];
+                if (node && node.tagName === 'IMG') {
+                  sel.setBaseAndExtent(
+                    rng.startContainer,
+                    rng.startOffset,
+                    rng.endContainer,
+                    rng.endOffset
+                  );
+
+                  // Since the setBaseAndExtent is fixed in more recent Blink versions we
+                  // need to detect if it's doing the wrong thing and falling back to the
+                  // crazy incorrect behavior api call since that seems to be the only way
+                  // to get it to work on Safari WebKit as of 2017-02-23
+                  if (sel.anchorNode !== rng.startContainer || sel.focusNode !== rng.endContainer) {
+                    sel.setBaseAndExtent(node, 0, node, 1);
+                  }
+                }
+              }
+            }
+          }
+
+          self.editor.fire('AfterSetSelectionRange', { range: rng, forward: forward });
+        } else {
+          // Is W3C Range fake range on IE
+          if (rng.cloneRange) {
+            try {
+              self.tridentSel.addRange(rng);
+            } catch (ex) {
+              //IE9 throws an error here if called before selection is placed in the editor
+            }
+          }
+        }
+      },
+
+      /**
+       * Sets the current selection to the specified DOM element.
+       *
+       * @method setNode
+       * @param {Element} elm Element to set as the contents of the selection.
+       * @return {Element} Returns the element that got passed in.
+       * @example
+       * // Inserts a DOM node at current selection/caret location
+       * tinymce.activeEditor.selection.setNode(tinymce.activeEditor.dom.create('img', {src: 'some.gif', title: 'some title'}));
+       */
+      setNode: function (elm) {
+        var self = this;
+
+        self.setContent(self.dom.getOuterHTML(elm));
+
+        return elm;
+      },
+
+      /**
+       * Returns the currently selected element or the common ancestor element for both start and end of the selection.
+       *
+       * @method getNode
+       * @return {Element} Currently selected element or common ancestor element.
+       * @example
+       * // Alerts the currently selected elements node name
+       * alert(tinymce.activeEditor.selection.getNode().nodeName);
+       */
+      getNode: function () {
+        var self = this, rng = self.getRng(), elm;
+        var startContainer, endContainer, startOffset, endOffset, root = self.dom.getRoot();
+
+        function skipEmptyTextNodes(node, forwards) {
+          var orig = node;
+
+          while (node && node.nodeType === 3 && node.length === 0) {
+            node = forwards ? node.nextSibling : node.previousSibling;
+          }
+
+          return node || orig;
+        }
+
+        // Range maybe lost after the editor is made visible again
+        if (!rng) {
+          return root;
+        }
+
+        startContainer = rng.startContainer;
+        endContainer = rng.endContainer;
+        startOffset = rng.startOffset;
+        endOffset = rng.endOffset;
+
+        if (rng.setStart) {
+          elm = rng.commonAncestorContainer;
+
+          // Handle selection a image or other control like element such as anchors
+          if (!rng.collapsed) {
+            if (startContainer == endContainer) {
+              if (endOffset - startOffset < 2) {
+                if (startContainer.hasChildNodes()) {
+                  elm = startContainer.childNodes[startOffset];
+                }
+              }
+            }
+
+            // If the anchor node is a element instead of a text node then return this element
+            //if (tinymce.isWebKit && sel.anchorNode && sel.anchorNode.nodeType == 1)
+            // return sel.anchorNode.childNodes[sel.anchorOffset];
+
+            // Handle cases where the selection is immediately wrapped around a node and return that node instead of it's parent.
+            // This happens when you double click an underlined word in FireFox.
+            if (startContainer.nodeType === 3 && endContainer.nodeType === 3) {
+              if (startContainer.length === startOffset) {
+                startContainer = skipEmptyTextNodes(startContainer.nextSibling, true);
+              } else {
+                startContainer = startContainer.parentNode;
+              }
+
+              if (endOffset === 0) {
+                endContainer = skipEmptyTextNodes(endContainer.previousSibling, false);
+              } else {
+                endContainer = endContainer.parentNode;
+              }
+
+              if (startContainer && startContainer === endContainer) {
+                return startContainer;
+              }
+            }
+          }
+
+          if (elm && elm.nodeType == 3) {
+            return elm.parentNode;
+          }
+
+          return elm;
+        }
+
+        elm = rng.item ? rng.item(0) : rng.parentElement();
+
+        // IE 7 might return elements outside the iframe
+        if (elm.ownerDocument !== self.win.document) {
+          elm = root;
+        }
+
+        return elm;
+      },
+
+      getSelectedBlocks: function (startElm, endElm) {
+        var self = this, dom = self.dom, node, root, selectedBlocks = [];
+
+        root = dom.getRoot();
+        startElm = dom.getParent(startElm || self.getStart(), dom.isBlock);
+        endElm = dom.getParent(endElm || self.getEnd(), dom.isBlock);
+
+        if (startElm && startElm != root) {
+          selectedBlocks.push(startElm);
+        }
+
+        if (startElm && endElm && startElm != endElm) {
+          node = startElm;
+
+          var walker = new TreeWalker(startElm, root);
+          while ((node = walker.next()) && node != endElm) {
+            if (dom.isBlock(node)) {
+              selectedBlocks.push(node);
+            }
+          }
+        }
+
+        if (endElm && startElm != endElm && endElm != root) {
+          selectedBlocks.push(endElm);
+        }
+
+        return selectedBlocks;
+      },
+
+      isForward: function () {
+        var dom = this.dom, sel = this.getSel(), anchorRange, focusRange;
+
+        // No support for selection direction then always return true
+        if (!sel || !sel.anchorNode || !sel.focusNode) {
+          return true;
+        }
+
+        anchorRange = dom.createRng();
+        anchorRange.setStart(sel.anchorNode, sel.anchorOffset);
+        anchorRange.collapse(true);
+
+        focusRange = dom.createRng();
+        focusRange.setStart(sel.focusNode, sel.focusOffset);
+        focusRange.collapse(true);
+
+        return anchorRange.compareBoundaryPoints(anchorRange.START_TO_START, focusRange) <= 0;
+      },
+
+      normalize: function () {
+        var self = this, rng = self.getRng();
+
+        if (new RangeUtils(self.dom).normalize(rng) && !MultiRange.hasMultipleRanges(self.getSel())) {
+          self.setRng(rng, self.isForward());
+        }
+
+        return rng;
+      },
+
+      /**
+       * Executes callback when the current selection starts/stops matching the specified selector. The current
+       * state will be passed to the callback as it's first argument.
+       *
+       * @method selectorChanged
+       * @param {String} selector CSS selector to check for.
+       * @param {function} callback Callback with state and args when the selector is matches or not.
+       */
+      selectorChanged: function (selector, callback) {
+        var self = this, currentSelectors;
+
+        if (!self.selectorChangedData) {
+          self.selectorChangedData = {};
+          currentSelectors = {};
+
+          self.editor.on('NodeChange', function (e) {
+            var node = e.element, dom = self.dom, parents = dom.getParents(node, null, dom.getRoot()), matchedSelectors = {};
+
+            // Check for new matching selectors
+            each(self.selectorChangedData, function (callbacks, selector) {
+              each(parents, function (node) {
+                if (dom.is(node, selector)) {
+                  if (!currentSelectors[selector]) {
+                    // Execute callbacks
+                    each(callbacks, function (callback) {
+                      callback(true, { node: node, selector: selector, parents: parents });
+                    });
+
+                    currentSelectors[selector] = callbacks;
+                  }
+
+                  matchedSelectors[selector] = callbacks;
+                  return false;
+                }
+              });
+            });
+
+            // Check if current selectors still match
+            each(currentSelectors, function (callbacks, selector) {
+              if (!matchedSelectors[selector]) {
+                delete currentSelectors[selector];
+
+                each(callbacks, function (callback) {
+                  callback(false, { node: node, selector: selector, parents: parents });
+                });
+              }
+            });
+          });
+        }
+
+        // Add selector listeners
+        if (!self.selectorChangedData[selector]) {
+          self.selectorChangedData[selector] = [];
+        }
+
+        self.selectorChangedData[selector].push(callback);
+
+        return self;
+      },
+
+      getScrollContainer: function () {
+        var scrollContainer, node = this.dom.getRoot();
+
+        while (node && node.nodeName != 'BODY') {
+          if (node.scrollHeight > node.clientHeight) {
+            scrollContainer = node;
+            break;
+          }
+
+          node = node.parentNode;
+        }
+
+        return scrollContainer;
+      },
+
+      scrollIntoView: function (elm, alignToTop) {
+        ScrollIntoView.scrollIntoView(this.editor, elm, alignToTop);
+      },
+
+      placeCaretAt: function (clientX, clientY) {
+        this.setRng(RangeUtils.getCaretRangeFromPoint(clientX, clientY, this.editor.getDoc()));
+      },
+
+      _moveEndPoint: function (rng, node, start) {
+        var root = node, walker = new TreeWalker(node, root);
+        var nonEmptyElementsMap = this.dom.schema.getNonEmptyElements();
+
+        do {
+          // Text node
+          if (node.nodeType == 3 && trim(node.nodeValue).length !== 0) {
+            if (start) {
+              rng.setStart(node, 0);
+            } else {
+              rng.setEnd(node, node.nodeValue.length);
+            }
+
+            return;
+          }
+
+          // BR/IMG/INPUT elements but not table cells
+          if (nonEmptyElementsMap[node.nodeName] && !/^(TD|TH)$/.test(node.nodeName)) {
+            if (start) {
+              rng.setStartBefore(node);
+            } else {
+              if (node.nodeName == 'BR') {
+                rng.setEndBefore(node);
+              } else {
+                rng.setEndAfter(node);
+              }
+            }
+
+            return;
+          }
+
+          // Found empty text block old IE can place the selection inside those
+          if (Env.ie && Env.ie < 11 && this.dom.isBlock(node) && this.dom.isEmpty(node)) {
+            if (start) {
+              rng.setStart(node, 0);
+            } else {
+              rng.setEnd(node, 0);
+            }
+
+            return;
+          }
+        } while ((node = (start ? walker.next() : walker.prev())));
+
+        // Failed to find any text node or other suitable location then move to the root of body
+        if (root.nodeName == 'BODY') {
+          if (start) {
+            rng.setStart(root, 0);
+          } else {
+            rng.setEnd(root, root.childNodes.length);
+          }
+        }
+      },
+
+      getBoundingClientRect: function () {
+        var rng = this.getRng();
+        return rng.collapsed ? CaretPosition.fromRangeStart(rng).getClientRects()[0] : rng.getBoundingClientRect();
+      },
+
+      destroy: function () {
+        this.win = null;
+        this.controlSelection.destroy();
+      }
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+    return Selection;
</ins><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Tooltip.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Node.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -37044,74 +31712,513 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Creates a tooltip instance.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * This class is a minimalistic implementation of a DOM like node used by the DomParser class.
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @-x-less ToolTip.less
- * @class tinymce.ui.ToolTip
- * @extends tinymce.ui.Control
- * @mixes tinymce.ui.Movable
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @example
+ * var node = new tinymce.html.Node('strong', 1);
+ * someRoot.append(node);
+ *
+ * @class tinymce.html.Node
+ * @version 3.4
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.ui.Tooltip',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.html.Node',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    "tinymce.core.ui.Control",
-    "tinymce.core.ui.Movable"
</del><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Control, Movable) {
-    return Control.extend({
-      Mixins: [Movable],
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function () {
+    var whiteSpaceRegExp = /^[ \t\r\n]*$/;
+    var typeLookup = {
+      '#text': 3,
+      '#comment': 8,
+      '#cdata': 4,
+      '#pi': 7,
+      '#doctype': 10,
+      '#document-fragment': 11
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      Defaults: {
-        classes: 'widget tooltip tooltip-n'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Walks the tree left/right
+    function walk(node, rootNode, prev) {
+      var sibling, parent, startName = prev ? 'lastChild' : 'firstChild', siblingName = prev ? 'prev' : 'next';
+
+      // Walk into nodes if it has a start
+      if (node[startName]) {
+        return node[startName];
+      }
+
+      // Return the sibling if it has one
+      if (node !== rootNode) {
+        sibling = node[siblingName];
+
+        if (sibling) {
+          return sibling;
+        }
+
+        // Walk up the parents to look for siblings
+        for (parent = node.parent; parent && parent !== rootNode; parent = parent.parent) {
+          sibling = parent[siblingName];
+
+          if (sibling) {
+            return sibling;
+          }
+        }
+      }
+    }
+
+    /**
+     * Constructs a new Node instance.
+     *
+     * @constructor
+     * @method Node
+     * @param {String} name Name of the node type.
+     * @param {Number} type Numeric type representing the node.
+     */
+    function Node(name, type) {
+      this.name = name;
+      this.type = type;
+
+      if (type === 1) {
+        this.attributes = [];
+        this.attributes.map = {};
+      }
+    }
+
+    Node.prototype = {
+      /**
+       * Replaces the current node with the specified one.
+       *
+       * @example
+       * someNode.replace(someNewNode);
+       *
+       * @method replace
+       * @param {tinymce.html.Node} node Node to replace the current node with.
+       * @return {tinymce.html.Node} The old node that got replaced.
+       */
+      replace: function (node) {
+        var self = this;
+
+        if (node.parent) {
+          node.remove();
+        }
+
+        self.insert(node, self);
+        self.remove();
+
+        return self;
</ins><span class="cx" style="display: block; padding: 0 10px">       },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * Renders the control as a HTML string.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * Gets/sets or removes an attribute by name.
</ins><span class="cx" style="display: block; padding: 0 10px">        *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * @method renderHtml
-       * @return {String} HTML representing the control.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * @example
+       * someNode.attr("name", "value"); // Sets an attribute
+       * console.log(someNode.attr("name")); // Gets an attribute
+       * someNode.attr("name", null); // Removes an attribute
+       *
+       * @method attr
+       * @param {String} name Attribute name to set or get.
+       * @param {String} value Optional value to set.
+       * @return {String/tinymce.html.Node} String or undefined on a get operation or the current node on a set operation.
</ins><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      renderHtml: function () {
-        var self = this, prefix = self.classPrefix;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      attr: function (name, value) {
+        var self = this, attrs, i, undef;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return (
-          '<div id="' + self._id + '" class="' + self.classes + '" role="presentation">' +
-          '<div class="' + prefix + 'tooltip-arrow"></div>' +
-          '<div class="' + prefix + 'tooltip-inner">' + self.encode(self.state.get('text')) + '</div>' +
-          '</div>'
-        );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (typeof name !== "string") {
+          for (i in name) {
+            self.attr(i, name[i]);
+          }
+
+          return self;
+        }
+
+        if ((attrs = self.attributes)) {
+          if (value !== undef) {
+            // Remove attribute
+            if (value === null) {
+              if (name in attrs.map) {
+                delete attrs.map[name];
+
+                i = attrs.length;
+                while (i--) {
+                  if (attrs[i].name === name) {
+                    attrs = attrs.splice(i, 1);
+                    return self;
+                  }
+                }
+              }
+
+              return self;
+            }
+
+            // Set attribute
+            if (name in attrs.map) {
+              // Set attribute
+              i = attrs.length;
+              while (i--) {
+                if (attrs[i].name === name) {
+                  attrs[i].value = value;
+                  break;
+                }
+              }
+            } else {
+              attrs.push({ name: name, value: value });
+            }
+
+            attrs.map[name] = value;
+
+            return self;
+          }
+
+          return attrs.map[name];
+        }
</ins><span class="cx" style="display: block; padding: 0 10px">       },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      bindStates: function () {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      /**
+       * Does a shallow clones the node into a new node. It will also exclude id attributes since
+       * there should only be one id per document.
+       *
+       * @example
+       * var clonedNode = node.clone();
+       *
+       * @method clone
+       * @return {tinymce.html.Node} New copy of the original node.
+       */
+      clone: function () {
+        var self = this, clone = new Node(self.name, self.type), i, l, selfAttrs, selfAttr, cloneAttrs;
+
+        // Clone element attributes
+        if ((selfAttrs = self.attributes)) {
+          cloneAttrs = [];
+          cloneAttrs.map = {};
+
+          for (i = 0, l = selfAttrs.length; i < l; i++) {
+            selfAttr = selfAttrs[i];
+
+            // Clone everything except id
+            if (selfAttr.name !== 'id') {
+              cloneAttrs[cloneAttrs.length] = { name: selfAttr.name, value: selfAttr.value };
+              cloneAttrs.map[selfAttr.name] = selfAttr.value;
+            }
+          }
+
+          clone.attributes = cloneAttrs;
+        }
+
+        clone.value = self.value;
+        clone.shortEnded = self.shortEnded;
+
+        return clone;
+      },
+
+      /**
+       * Wraps the node in in another node.
+       *
+       * @example
+       * node.wrap(wrapperNode);
+       *
+       * @method wrap
+       */
+      wrap: function (wrapper) {
</ins><span class="cx" style="display: block; padding: 0 10px">         var self = this;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        self.state.on('change:text', function (e) {
-          self.getEl().lastChild.innerHTML = self.encode(e.value);
-        });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        self.parent.insert(wrapper, self);
+        wrapper.append(self);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return self._super();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return self;
</ins><span class="cx" style="display: block; padding: 0 10px">       },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * Repaints the control after a layout operation.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * Unwraps the node in other words it removes the node but keeps the children.
</ins><span class="cx" style="display: block; padding: 0 10px">        *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * @method repaint
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * @example
+       * node.unwrap();
+       *
+       * @method unwrap
</ins><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      repaint: function () {
-        var self = this, style, rect;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      unwrap: function () {
+        var self = this, node, next;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        style = self.getEl().style;
-        rect = self._layoutRect;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        for (node = self.firstChild; node;) {
+          next = node.next;
+          self.insert(node, self, true);
+          node = next;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        style.left = rect.x + 'px';
-        style.top = rect.y + 'px';
-        style.zIndex = 0xFFFF + 0xFFFF;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        self.remove();
+      },
+
+      /**
+       * Removes the node from it's parent.
+       *
+       * @example
+       * node.remove();
+       *
+       * @method remove
+       * @return {tinymce.html.Node} Current node that got removed.
+       */
+      remove: function () {
+        var self = this, parent = self.parent, next = self.next, prev = self.prev;
+
+        if (parent) {
+          if (parent.firstChild === self) {
+            parent.firstChild = next;
+
+            if (next) {
+              next.prev = null;
+            }
+          } else {
+            prev.next = next;
+          }
+
+          if (parent.lastChild === self) {
+            parent.lastChild = prev;
+
+            if (prev) {
+              prev.next = null;
+            }
+          } else {
+            next.prev = prev;
+          }
+
+          self.parent = self.next = self.prev = null;
+        }
+
+        return self;
+      },
+
+      /**
+       * Appends a new node as a child of the current node.
+       *
+       * @example
+       * node.append(someNode);
+       *
+       * @method append
+       * @param {tinymce.html.Node} node Node to append as a child of the current one.
+       * @return {tinymce.html.Node} The node that got appended.
+       */
+      append: function (node) {
+        var self = this, last;
+
+        if (node.parent) {
+          node.remove();
+        }
+
+        last = self.lastChild;
+        if (last) {
+          last.next = node;
+          node.prev = last;
+          self.lastChild = node;
+        } else {
+          self.lastChild = self.firstChild = node;
+        }
+
+        node.parent = self;
+
+        return node;
+      },
+
+      /**
+       * Inserts a node at a specific position as a child of the current node.
+       *
+       * @example
+       * parentNode.insert(newChildNode, oldChildNode);
+       *
+       * @method insert
+       * @param {tinymce.html.Node} node Node to insert as a child of the current node.
+       * @param {tinymce.html.Node} refNode Reference node to set node before/after.
+       * @param {Boolean} before Optional state to insert the node before the reference node.
+       * @return {tinymce.html.Node} The node that got inserted.
+       */
+      insert: function (node, refNode, before) {
+        var parent;
+
+        if (node.parent) {
+          node.remove();
+        }
+
+        parent = refNode.parent || this;
+
+        if (before) {
+          if (refNode === parent.firstChild) {
+            parent.firstChild = node;
+          } else {
+            refNode.prev.next = node;
+          }
+
+          node.prev = refNode.prev;
+          node.next = refNode;
+          refNode.prev = node;
+        } else {
+          if (refNode === parent.lastChild) {
+            parent.lastChild = node;
+          } else {
+            refNode.next.prev = node;
+          }
+
+          node.next = refNode.next;
+          node.prev = refNode;
+          refNode.next = node;
+        }
+
+        node.parent = parent;
+
+        return node;
+      },
+
+      /**
+       * Get all children by name.
+       *
+       * @method getAll
+       * @param {String} name Name of the child nodes to collect.
+       * @return {Array} Array with child nodes matchin the specified name.
+       */
+      getAll: function (name) {
+        var self = this, node, collection = [];
+
+        for (node = self.firstChild; node; node = walk(node, self)) {
+          if (node.name === name) {
+            collection.push(node);
+          }
+        }
+
+        return collection;
+      },
+
+      /**
+       * Removes all children of the current node.
+       *
+       * @method empty
+       * @return {tinymce.html.Node} The current node that got cleared.
+       */
+      empty: function () {
+        var self = this, nodes, i, node;
+
+        // Remove all children
+        if (self.firstChild) {
+          nodes = [];
+
+          // Collect the children
+          for (node = self.firstChild; node; node = walk(node, self)) {
+            nodes.push(node);
+          }
+
+          // Remove the children
+          i = nodes.length;
+          while (i--) {
+            node = nodes[i];
+            node.parent = node.firstChild = node.lastChild = node.next = node.prev = null;
+          }
+        }
+
+        self.firstChild = self.lastChild = null;
+
+        return self;
+      },
+
+      /**
+       * Returns true/false if the node is to be considered empty or not.
+       *
+       * @example
+       * node.isEmpty({img: true});
+       * @method isEmpty
+       * @param {Object} elements Name/value object with elements that are automatically treated as non empty elements.
+       * @param {Object} whitespace Name/value object with elements that are automatically treated whitespace preservables.
+       * @param {function} predicate Optional predicate that gets called after the other rules determine that the node is empty. Should return true if the node is a content node.
+       * @return {Boolean} true/false if the node is empty or not.
+       */
+      isEmpty: function (elements, whitespace, predicate) {
+        var self = this, node = self.firstChild, i, name;
+
+        whitespace = whitespace || {};
+
+        if (node) {
+          do {
+            if (node.type === 1) {
+              // Ignore bogus elements
+              if (node.attributes.map['data-mce-bogus']) {
+                continue;
+              }
+
+              // Keep empty elements like <img />
+              if (elements[node.name]) {
+                return false;
+              }
+
+              // Keep bookmark nodes and name attribute like <a name="1"></a>
+              i = node.attributes.length;
+              while (i--) {
+                name = node.attributes[i].name;
+                if (name === "name" || name.indexOf('data-mce-bookmark') === 0) {
+                  return false;
+                }
+              }
+            }
+
+            // Keep comments
+            if (node.type === 8) {
+              return false;
+            }
+
+            // Keep non whitespace text nodes
+            if (node.type === 3 && !whiteSpaceRegExp.test(node.value)) {
+              return false;
+            }
+
+            // Keep whitespace preserve elements
+            if (node.type === 3 && node.parent && whitespace[node.parent.name] && whiteSpaceRegExp.test(node.value)) {
+              return false;
+            }
+
+            // Predicate tells that the node is contents
+            if (predicate && predicate(node)) {
+              return false;
+            }
+          } while ((node = walk(node, self)));
+        }
+
+        return true;
+      },
+
+      /**
+       * Walks to the next or previous node and returns that node or null if it wasn't found.
+       *
+       * @method walk
+       * @param {Boolean} prev Optional previous node state defaults to false.
+       * @return {tinymce.html.Node} Node that is next to or previous of the current node.
+       */
+      walk: function (prev) {
+        return walk(this, null, prev);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    };
+
+    /**
+     * Creates a node of a specific type.
+     *
+     * @static
+     * @method create
+     * @param {String} name Name of the node type to create for example "b" or "#text".
+     * @param {Object} attrs Name/value collection of attributes that will be applied to elements.
+     */
+    Node.create = function (name, attrs) {
+      var node, attrName;
+
+      // Create node
+      node = new Node(name, typeLookup[name] || 1);
+
+      // Add attributes if needed
+      if (attrs) {
+        for (attrName in attrs) {
+          node.attr(attrName, attrs[attrName]);
+        }
+      }
+
+      return node;
+    };
+
+    return Node;
</ins><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Widget.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * SaxParser.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -37120,154 +32227,2259 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Contributing: http://www.tinymce.com/contributing
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/*eslint max-depth:[2, 9] */
+
</ins><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Widget base class a widget is a control that has a tooltip and some basic states.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * This class parses HTML code using pure JavaScript and executes various events for each item it finds. It will
+ * always execute the events in the right order for tag soup code like <b><p></b></p>. It will also remove elements
+ * and attributes that doesn't fit the schema if the validate setting is enabled.
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @class tinymce.ui.Widget
- * @extends tinymce.ui.Control
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @example
+ * var parser = new tinymce.html.SaxParser({
+ *     validate: true,
+ *
+ *     comment: function(text) {
+ *         console.log('Comment:', text);
+ *     },
+ *
+ *     cdata: function(text) {
+ *         console.log('CDATA:', text);
+ *     },
+ *
+ *     text: function(text, raw) {
+ *         console.log('Text:', text, 'Raw:', raw);
+ *     },
+ *
+ *     start: function(name, attrs, empty) {
+ *         console.log('Start:', name, attrs, empty);
+ *     },
+ *
+ *     end: function(name) {
+ *         console.log('End:', name);
+ *     },
+ *
+ *     pi: function(name, text) {
+ *         console.log('PI:', name, text);
+ *     },
+ *
+ *     doctype: function(text) {
+ *         console.log('DocType:', text);
+ *     }
+ * }, schema);
+ * @class tinymce.html.SaxParser
+ * @version 3.4
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.ui.Widget',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.html.SaxParser',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    "tinymce.core.ui.Control",
-    "tinymce.core.ui.Tooltip"
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    "tinymce.core.html.Schema",
+    "tinymce.core.html.Entities",
+    "tinymce.core.util.Tools"
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Control, Tooltip) {
-    "use strict";
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Schema, Entities, Tools) {
+    var each = Tools.each;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var tooltip;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isValidPrefixAttrName = function (name) {
+      return name.indexOf('data-') === 0 || name.indexOf('aria-') === 0;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var Widget = Control.extend({
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var trimComments = function (text) {
+      return text.replace(/<!--|-->/g, '');
+    };
+
+    /**
+     * Returns the index of the end tag for a specific start tag. This can be
+     * used to skip all children of a parent element from being processed.
+     *
+     * @private
+     * @method findEndTag
+     * @param {tinymce.html.Schema} schema Schema instance to use to match short ended elements.
+     * @param {String} html HTML string to find the end tag in.
+     * @param {Number} startIndex Indext to start searching at should be after the start tag.
+     * @return {Number} Index of the end tag.
+     */
+    function findEndTag(schema, html, startIndex) {
+      var count = 1, index, matches, tokenRegExp, shortEndedElements;
+
+      shortEndedElements = schema.getShortEndedElements();
+      tokenRegExp = /<([!?\/])?([A-Za-z0-9\-_\:\.]+)((?:\s+[^"\'>]+(?:(?:"[^"]*")|(?:\'[^\']*\')|[^>]*))*|\/|\s+)>/g;
+      tokenRegExp.lastIndex = index = startIndex;
+
+      while ((matches = tokenRegExp.exec(html))) {
+        index = tokenRegExp.lastIndex;
+
+        if (matches[1] === '/') { // End element
+          count--;
+        } else if (!matches[1]) { // Start element
+          if (matches[2] in shortEndedElements) {
+            continue;
+          }
+
+          count++;
+        }
+
+        if (count === 0) {
+          break;
+        }
+      }
+
+      return index;
+    }
+
+    /**
+     * Constructs a new SaxParser instance.
+     *
+     * @constructor
+     * @method SaxParser
+     * @param {Object} settings Name/value collection of settings. comment, cdata, text, start and end are callbacks.
+     * @param {tinymce.html.Schema} schema HTML Schema class to use when parsing.
+     */
+    function SaxParser(settings, schema) {
+      var self = this;
+
+      function noop() { }
+
+      settings = settings || {};
+      self.schema = schema = schema || new Schema();
+
+      if (settings.fix_self_closing !== false) {
+        settings.fix_self_closing = true;
+      }
+
+      // Add handler functions from settings and setup default handlers
+      each('comment cdata text start end pi doctype'.split(' '), function (name) {
+        if (name) {
+          self[name] = settings[name] || noop;
+        }
+      });
+
</ins><span class="cx" style="display: block; padding: 0 10px">       /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * Constructs a instance with the specified settings.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * Parses the specified HTML string and executes the callbacks for each item it finds.
</ins><span class="cx" style="display: block; padding: 0 10px">        *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * @constructor
-       * @param {Object} settings Name/value object with settings.
-       * @setting {String} tooltip Tooltip text to display when hovering.
-       * @setting {Boolean} autofocus True if the control should be focused when rendered.
-       * @setting {String} text Text to display inside widget.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * @example
+       * new SaxParser({...}).parse('<b>text</b>');
+       * @method parse
+       * @param {String} html Html string to sax parse.
</ins><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      init: function (settings) {
-        var self = this;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      self.parse = function (html) {
+        var self = this, matches, index = 0, value, endRegExp, stack = [], attrList, i, text, name;
+        var isInternalElement, removeInternalElements, shortEndedElements, fillAttrsMap, isShortEnded;
+        var validate, elementRule, isValidElement, attr, attribsValue, validAttributesMap, validAttributePatterns;
+        var attributesRequired, attributesDefault, attributesForced, processHtml;
+        var anyAttributesRequired, selfClosing, tokenRegExp, attrRegExp, specialElements, attrValue, idCount = 0;
+        var decode = Entities.decode, fixSelfClosing, filteredUrlAttrs = Tools.makeMap('src,href,data,background,formaction,poster');
+        var scriptUriRegExp = /((java|vb)script|mhtml):/i, dataUriRegExp = /^data:/i;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        self._super(settings);
-        settings = self.settings;
-        self.canFocus = true;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        function processEndTag(name) {
+          var pos, i;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (settings.tooltip && Widget.tooltips !== false) {
-          self.on('mouseenter', function (e) {
-            var tooltip = self.tooltip().moveTo(-0xFFFF);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Find position of parent of the same type
+          pos = stack.length;
+          while (pos--) {
+            if (stack[pos].name === name) {
+              break;
+            }
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (e.control == self) {
-              var rel = tooltip.text(settings.tooltip).show().testMoveRel(self.getEl(), ['bc-tc', 'bc-tl', 'bc-tr']);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Found parent
+          if (pos >= 0) {
+            // Close all the open elements
+            for (i = stack.length - 1; i >= pos; i--) {
+              name = stack[i];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              tooltip.classes.toggle('tooltip-n', rel == 'bc-tc');
-              tooltip.classes.toggle('tooltip-nw', rel == 'bc-tl');
-              tooltip.classes.toggle('tooltip-ne', rel == 'bc-tr');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              if (name.valid) {
+                self.end(name.name);
+              }
+            }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              tooltip.moveRel(self.getEl(), rel);
-            } else {
-              tooltip.hide();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // Remove the open elements from the stack
+            stack.length = pos;
+          }
+        }
+
+        function parseAttribute(match, name, value, val2, val3) {
+          var attrRule, i, trimRegExp = /[\s\u0000-\u001F]+/g;
+
+          name = name.toLowerCase();
+          value = name in fillAttrsMap ? name : decode(value || val2 || val3 || ''); // Handle boolean attribute than value attribute
+
+          // Validate name and value pass through all data- attributes
+          if (validate && !isInternalElement && isValidPrefixAttrName(name) === false) {
+            attrRule = validAttributesMap[name];
+
+            // Find rule by pattern matching
+            if (!attrRule && validAttributePatterns) {
+              i = validAttributePatterns.length;
+              while (i--) {
+                attrRule = validAttributePatterns[i];
+                if (attrRule.pattern.test(name)) {
+                  break;
+                }
+              }
+
+              // No rule matched
+              if (i === -1) {
+                attrRule = null;
+              }
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          });
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          self.on('mouseleave mousedown click', function () {
-            self.tooltip().hide();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // No attribute rule found
+            if (!attrRule) {
+              return;
+            }
+
+            // Validate value
+            if (attrRule.validValues && !(value in attrRule.validValues)) {
+              return;
+            }
+          }
+
+          // Block any javascript: urls or non image data uris
+          if (filteredUrlAttrs[name] && !settings.allow_script_urls) {
+            var uri = value.replace(trimRegExp, '');
+
+            try {
+              // Might throw malformed URI sequence
+              uri = decodeURIComponent(uri);
+            } catch (ex) {
+              // Fallback to non UTF-8 decoder
+              uri = unescape(uri);
+            }
+
+            if (scriptUriRegExp.test(uri)) {
+              return;
+            }
+
+            if (!settings.allow_html_data_urls && dataUriRegExp.test(uri) && !/^data:image\//i.test(uri)) {
+              return;
+            }
+          }
+
+          // Block data or event attributes on elements marked as internal
+          if (isInternalElement && (name in filteredUrlAttrs || name.indexOf('on') === 0)) {
+            return;
+          }
+
+          // Add attribute to list and map
+          attrList.map[name] = value;
+          attrList.push({
+            name: name,
+            value: value
</ins><span class="cx" style="display: block; padding: 0 10px">           });
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        self.aria('label', settings.ariaLabel || settings.tooltip);
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Precompile RegExps and map objects
+        tokenRegExp = new RegExp('<(?:' +
+          '(?:!--([\\w\\W]*?)-->)|' + // Comment
+          '(?:!\\[CDATA\\[([\\w\\W]*?)\\]\\]>)|' + // CDATA
+          '(?:!DOCTYPE([\\w\\W]*?)>)|' + // DOCTYPE
+          '(?:\\?([^\\s\\/<>]+) ?([\\w\\W]*?)[?/]>)|' + // PI
+          '(?:\\/([A-Za-z][A-Za-z0-9\\-_\\:\\.]*)>)|' + // End element
+          '(?:([A-Za-z][A-Za-z0-9\\-_\\:\\.]*)((?:\\s+[^"\'>]+(?:(?:"[^"]*")|(?:\'[^\']*\')|[^>]*))*|\\/|\\s+)>)' + // Start element
+          ')', 'g');
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        attrRegExp = /([\w:\-]+)(?:\s*=\s*(?:(?:\"((?:[^\"])*)\")|(?:\'((?:[^\'])*)\')|([^>\s]+)))?/g;
+
+        // Setup lookup tables for empty elements and boolean attributes
+        shortEndedElements = schema.getShortEndedElements();
+        selfClosing = settings.self_closing_elements || schema.getSelfClosingElements();
+        fillAttrsMap = schema.getBoolAttrs();
+        validate = settings.validate;
+        removeInternalElements = settings.remove_internals;
+        fixSelfClosing = settings.fix_self_closing;
+        specialElements = schema.getSpecialElements();
+        processHtml = html + '>';
+
+        while ((matches = tokenRegExp.exec(processHtml))) { // Adds and extra '>' to keep regexps from doing catastrofic backtracking on malformed html
+          // Text
+          if (index < matches.index) {
+            self.text(decode(html.substr(index, matches.index - index)));
+          }
+
+          if ((value = matches[6])) { // End element
+            value = value.toLowerCase();
+
+            // IE will add a ":" in front of elements it doesn't understand like custom elements or HTML5 elements
+            if (value.charAt(0) === ':') {
+              value = value.substr(1);
+            }
+
+            processEndTag(value);
+          } else if ((value = matches[7])) { // Start element
+            // Did we consume the extra character then treat it as text
+            // This handles the case with html like this: "text a<b text"
+            if (matches.index + matches[0].length > html.length) {
+              self.text(decode(html.substr(matches.index)));
+              index = matches.index + matches[0].length;
+              continue;
+            }
+
+            value = value.toLowerCase();
+
+            // IE will add a ":" in front of elements it doesn't understand like custom elements or HTML5 elements
+            if (value.charAt(0) === ':') {
+              value = value.substr(1);
+            }
+
+            isShortEnded = value in shortEndedElements;
+
+            // Is self closing tag for example an <li> after an open <li>
+            if (fixSelfClosing && selfClosing[value] && stack.length > 0 && stack[stack.length - 1].name === value) {
+              processEndTag(value);
+            }
+
+            // Validate element
+            if (!validate || (elementRule = schema.getElementRule(value))) {
+              isValidElement = true;
+
+              // Grab attributes map and patters when validation is enabled
+              if (validate) {
+                validAttributesMap = elementRule.attributes;
+                validAttributePatterns = elementRule.attributePatterns;
+              }
+
+              // Parse attributes
+              if ((attribsValue = matches[8])) {
+                isInternalElement = attribsValue.indexOf('data-mce-type') !== -1; // Check if the element is an internal element
+
+                // If the element has internal attributes then remove it if we are told to do so
+                if (isInternalElement && removeInternalElements) {
+                  isValidElement = false;
+                }
+
+                attrList = [];
+                attrList.map = {};
+
+                attribsValue.replace(attrRegExp, parseAttribute);
+              } else {
+                attrList = [];
+                attrList.map = {};
+              }
+
+              // Process attributes if validation is enabled
+              if (validate && !isInternalElement) {
+                attributesRequired = elementRule.attributesRequired;
+                attributesDefault = elementRule.attributesDefault;
+                attributesForced = elementRule.attributesForced;
+                anyAttributesRequired = elementRule.removeEmptyAttrs;
+
+                // Check if any attribute exists
+                if (anyAttributesRequired && !attrList.length) {
+                  isValidElement = false;
+                }
+
+                // Handle forced attributes
+                if (attributesForced) {
+                  i = attributesForced.length;
+                  while (i--) {
+                    attr = attributesForced[i];
+                    name = attr.name;
+                    attrValue = attr.value;
+
+                    if (attrValue === '{$uid}') {
+                      attrValue = 'mce_' + idCount++;
+                    }
+
+                    attrList.map[name] = attrValue;
+                    attrList.push({ name: name, value: attrValue });
+                  }
+                }
+
+                // Handle default attributes
+                if (attributesDefault) {
+                  i = attributesDefault.length;
+                  while (i--) {
+                    attr = attributesDefault[i];
+                    name = attr.name;
+
+                    if (!(name in attrList.map)) {
+                      attrValue = attr.value;
+
+                      if (attrValue === '{$uid}') {
+                        attrValue = 'mce_' + idCount++;
+                      }
+
+                      attrList.map[name] = attrValue;
+                      attrList.push({ name: name, value: attrValue });
+                    }
+                  }
+                }
+
+                // Handle required attributes
+                if (attributesRequired) {
+                  i = attributesRequired.length;
+                  while (i--) {
+                    if (attributesRequired[i] in attrList.map) {
+                      break;
+                    }
+                  }
+
+                  // None of the required attributes where found
+                  if (i === -1) {
+                    isValidElement = false;
+                  }
+                }
+
+                // Invalidate element if it's marked as bogus
+                if ((attr = attrList.map['data-mce-bogus'])) {
+                  if (attr === 'all') {
+                    index = findEndTag(schema, html, tokenRegExp.lastIndex);
+                    tokenRegExp.lastIndex = index;
+                    continue;
+                  }
+
+                  isValidElement = false;
+                }
+              }
+
+              if (isValidElement) {
+                self.start(value, attrList, isShortEnded);
+              }
+            } else {
+              isValidElement = false;
+            }
+
+            // Treat script, noscript and style a bit different since they may include code that looks like elements
+            if ((endRegExp = specialElements[value])) {
+              endRegExp.lastIndex = index = matches.index + matches[0].length;
+
+              if ((matches = endRegExp.exec(html))) {
+                if (isValidElement) {
+                  text = html.substr(index, matches.index - index);
+                }
+
+                index = matches.index + matches[0].length;
+              } else {
+                text = html.substr(index);
+                index = html.length;
+              }
+
+              if (isValidElement) {
+                if (text.length > 0) {
+                  self.text(text, true);
+                }
+
+                self.end(value);
+              }
+
+              tokenRegExp.lastIndex = index;
+              continue;
+            }
+
+            // Push value on to stack
+            if (!isShortEnded) {
+              if (!attribsValue || attribsValue.indexOf('/') != attribsValue.length - 1) {
+                stack.push({ name: value, valid: isValidElement });
+              } else if (isValidElement) {
+                self.end(value);
+              }
+            }
+          } else if ((value = matches[1])) { // Comment
+            // Padd comment value to avoid browsers from parsing invalid comments as HTML
+            if (value.charAt(0) === '>') {
+              value = ' ' + value;
+            }
+
+            if (!settings.allow_conditional_comments && value.substr(0, 3).toLowerCase() === '[if') {
+              value = ' ' + value;
+            }
+
+            self.comment(value);
+          } else if ((value = matches[2])) { // CDATA
+            self.cdata(trimComments(value));
+          } else if ((value = matches[3])) { // DOCTYPE
+            self.doctype(value);
+          } else if ((value = matches[4])) { // PI
+            self.pi(value, matches[5]);
+          }
+
+          index = matches.index + matches[0].length;
+        }
+
+        // Text
+        if (index < html.length) {
+          self.text(decode(html.substr(index)));
+        }
+
+        // Close any open elements
+        for (i = stack.length - 1; i >= 0; i--) {
+          value = stack[i];
+
+          if (value.valid) {
+            self.end(value.name);
+          }
+        }
+      };
+    }
+
+    SaxParser.findEndTag = findEndTag;
+
+    return SaxParser;
+  }
+);
+/**
+ * DomParser.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This class parses HTML code into a DOM like structure of nodes it will remove redundant whitespace and make
+ * sure that the node tree is valid according to the specified schema.
+ * So for example: <p>a<p>b</p>c</p> will become <p>a</p><p>b</p><p>c</p>
+ *
+ * @example
+ * var parser = new tinymce.html.DomParser({validate: true}, schema);
+ * var rootNode = parser.parse('<h1>content</h1>');
+ *
+ * @class tinymce.html.DomParser
+ * @version 3.4
+ */
+define(
+  'tinymce.core.html.DomParser',
+  [
+    "tinymce.core.html.Node",
+    "tinymce.core.html.Schema",
+    "tinymce.core.html.SaxParser",
+    "tinymce.core.util.Tools"
+  ],
+  function (Node, Schema, SaxParser, Tools) {
+    var makeMap = Tools.makeMap, each = Tools.each, explode = Tools.explode, extend = Tools.extend;
+
+    var paddEmptyNode = function (settings, node) {
+      if (settings.padd_empty_with_br) {
+        node.empty().append(new Node('br', '1')).shortEnded = true;
+      } else {
+        node.empty().append(new Node('#text', '3')).value = '\u00a0';
+      }
+    };
+
+    var hasOnlyChild = function (node, name) {
+      return node && node.firstChild === node.lastChild && node.firstChild.name === name;
+    };
+
+    var isPadded = function (schema, node) {
+      var rule = schema.getElementRule(node.name);
+      return rule && rule.paddEmpty;
+    };
+
+    var isEmpty = function (schema, nonEmptyElements, whitespaceElements, node) {
+      return node.isEmpty(nonEmptyElements, whitespaceElements, function (node) {
+        return isPadded(schema, node);
+      });
+    };
+
+    /**
+     * Constructs a new DomParser instance.
+     *
+     * @constructor
+     * @method DomParser
+     * @param {Object} settings Name/value collection of settings. comment, cdata, text, start and end are callbacks.
+     * @param {tinymce.html.Schema} schema HTML Schema class to use when parsing.
+     */
+    return function (settings, schema) {
+      var self = this, nodeFilters = {}, attributeFilters = [], matchedNodes = {}, matchedAttributes = {};
+
+      settings = settings || {};
+      settings.validate = "validate" in settings ? settings.validate : true;
+      settings.root_name = settings.root_name || 'body';
+      self.schema = schema = schema || new Schema();
+
+      function fixInvalidChildren(nodes) {
+        var ni, node, parent, parents, newParent, currentNode, tempNode, childNode, i;
+        var nonEmptyElements, whitespaceElements, nonSplitableElements, textBlockElements, specialElements, sibling, nextNode;
+
+        nonSplitableElements = makeMap('tr,td,th,tbody,thead,tfoot,table');
+        nonEmptyElements = schema.getNonEmptyElements();
+        whitespaceElements = schema.getWhiteSpaceElements();
+        textBlockElements = schema.getTextBlockElements();
+        specialElements = schema.getSpecialElements();
+
+        for (ni = 0; ni < nodes.length; ni++) {
+          node = nodes[ni];
+
+          // Already removed or fixed
+          if (!node.parent || node.fixed) {
+            continue;
+          }
+
+          // If the invalid element is a text block and the text block is within a parent LI element
+          // Then unwrap the first text block and convert other sibling text blocks to LI elements similar to Word/Open Office
+          if (textBlockElements[node.name] && node.parent.name == 'li') {
+            // Move sibling text blocks after LI element
+            sibling = node.next;
+            while (sibling) {
+              if (textBlockElements[sibling.name]) {
+                sibling.name = 'li';
+                sibling.fixed = true;
+                node.parent.insert(sibling, node.parent);
+              } else {
+                break;
+              }
+
+              sibling = sibling.next;
+            }
+
+            // Unwrap current text block
+            node.unwrap(node);
+            continue;
+          }
+
+          // Get list of all parent nodes until we find a valid parent to stick the child into
+          parents = [node];
+          for (parent = node.parent; parent && !schema.isValidChild(parent.name, node.name) &&
+            !nonSplitableElements[parent.name]; parent = parent.parent) {
+            parents.push(parent);
+          }
+
+          // Found a suitable parent
+          if (parent && parents.length > 1) {
+            // Reverse the array since it makes looping easier
+            parents.reverse();
+
+            // Clone the related parent and insert that after the moved node
+            newParent = currentNode = self.filterNode(parents[0].clone());
+
+            // Start cloning and moving children on the left side of the target node
+            for (i = 0; i < parents.length - 1; i++) {
+              if (schema.isValidChild(currentNode.name, parents[i].name)) {
+                tempNode = self.filterNode(parents[i].clone());
+                currentNode.append(tempNode);
+              } else {
+                tempNode = currentNode;
+              }
+
+              for (childNode = parents[i].firstChild; childNode && childNode != parents[i + 1];) {
+                nextNode = childNode.next;
+                tempNode.append(childNode);
+                childNode = nextNode;
+              }
+
+              currentNode = tempNode;
+            }
+
+            if (!isEmpty(schema, nonEmptyElements, whitespaceElements, newParent)) {
+              parent.insert(newParent, parents[0], true);
+              parent.insert(node, newParent);
+            } else {
+              parent.insert(node, parents[0], true);
+            }
+
+            // Check if the element is empty by looking through it's contents and special treatment for <p><br /></p>
+            parent = parents[0];
+            if (isEmpty(schema, nonEmptyElements, whitespaceElements, parent) || hasOnlyChild(parent, 'br')) {
+              parent.empty().remove();
+            }
+          } else if (node.parent) {
+            // If it's an LI try to find a UL/OL for it or wrap it
+            if (node.name === 'li') {
+              sibling = node.prev;
+              if (sibling && (sibling.name === 'ul' || sibling.name === 'ul')) {
+                sibling.append(node);
+                continue;
+              }
+
+              sibling = node.next;
+              if (sibling && (sibling.name === 'ul' || sibling.name === 'ul')) {
+                sibling.insert(node, sibling.firstChild, true);
+                continue;
+              }
+
+              node.wrap(self.filterNode(new Node('ul', 1)));
+              continue;
+            }
+
+            // Try wrapping the element in a DIV
+            if (schema.isValidChild(node.parent.name, 'div') && schema.isValidChild('div', node.name)) {
+              node.wrap(self.filterNode(new Node('div', 1)));
+            } else {
+              // We failed wrapping it, then remove or unwrap it
+              if (specialElements[node.name]) {
+                node.empty().remove();
+              } else {
+                node.unwrap();
+              }
+            }
+          }
+        }
+      }
+
</ins><span class="cx" style="display: block; padding: 0 10px">       /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * Returns the current tooltip instance.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * Runs the specified node though the element and attributes filters.
</ins><span class="cx" style="display: block; padding: 0 10px">        *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * @method tooltip
-       * @return {tinymce.ui.Tooltip} Tooltip instance.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * @method filterNode
+       * @param {tinymce.html.Node} Node the node to run filters on.
+       * @return {tinymce.html.Node} The passed in node.
</ins><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      tooltip: function () {
-        if (!tooltip) {
-          tooltip = new Tooltip({ type: 'tooltip' });
-          tooltip.renderTo();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      self.filterNode = function (node) {
+        var i, name, list;
+
+        // Run element filters
+        if (name in nodeFilters) {
+          list = matchedNodes[name];
+
+          if (list) {
+            list.push(node);
+          } else {
+            matchedNodes[name] = [node];
+          }
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return tooltip;
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Run attribute filters
+        i = attributeFilters.length;
+        while (i--) {
+          name = attributeFilters[i].name;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (name in node.attributes.map) {
+            list = matchedAttributes[name];
+
+            if (list) {
+              list.push(node);
+            } else {
+              matchedAttributes[name] = [node];
+            }
+          }
+        }
+
+        return node;
+      };
+
</ins><span class="cx" style="display: block; padding: 0 10px">       /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * Called after the control has been rendered.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * Adds a node filter function to the parser, the parser will collect the specified nodes by name
+       * and then execute the callback ones it has finished parsing the document.
</ins><span class="cx" style="display: block; padding: 0 10px">        *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * @method postRender
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * @example
+       * parser.addNodeFilter('p,h1', function(nodes, name) {
+       *  for (var i = 0; i < nodes.length; i++) {
+       *   console.log(nodes[i].name);
+       *  }
+       * });
+       * @method addNodeFilter
+       * @method {String} name Comma separated list of nodes to collect.
+       * @param {function} callback Callback function to execute once it has collected nodes.
</ins><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      postRender: function () {
-        var self = this, settings = self.settings;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      self.addNodeFilter = function (name, callback) {
+        each(explode(name), function (name) {
+          var list = nodeFilters[name];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        self._super();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (!list) {
+            nodeFilters[name] = list = [];
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (!self.parent() && (settings.width || settings.height)) {
-          self.initLayoutRect();
-          self.repaint();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          list.push(callback);
+        });
+      };
+
+      /**
+       * Adds a attribute filter function to the parser, the parser will collect nodes that has the specified attributes
+       * and then execute the callback ones it has finished parsing the document.
+       *
+       * @example
+       * parser.addAttributeFilter('src,href', function(nodes, name) {
+       *  for (var i = 0; i < nodes.length; i++) {
+       *   console.log(nodes[i].name);
+       *  }
+       * });
+       * @method addAttributeFilter
+       * @method {String} name Comma separated list of nodes to collect.
+       * @param {function} callback Callback function to execute once it has collected nodes.
+       */
+      self.addAttributeFilter = function (name, callback) {
+        each(explode(name), function (name) {
+          var i;
+
+          for (i = 0; i < attributeFilters.length; i++) {
+            if (attributeFilters[i].name === name) {
+              attributeFilters[i].callbacks.push(callback);
+              return;
+            }
+          }
+
+          attributeFilters.push({ name: name, callbacks: [callback] });
+        });
+      };
+
+      /**
+       * Parses the specified HTML string into a DOM like node tree and returns the result.
+       *
+       * @example
+       * var rootNode = new DomParser({...}).parse('<b>text</b>');
+       * @method parse
+       * @param {String} html Html string to sax parse.
+       * @param {Object} args Optional args object that gets passed to all filter functions.
+       * @return {tinymce.html.Node} Root node containing the tree.
+       */
+      self.parse = function (html, args) {
+        var parser, rootNode, node, nodes, i, l, fi, fl, list, name, validate;
+        var blockElements, startWhiteSpaceRegExp, invalidChildren = [], isInWhiteSpacePreservedElement;
+        var endWhiteSpaceRegExp, allWhiteSpaceRegExp, isAllWhiteSpaceRegExp, whiteSpaceElements;
+        var children, nonEmptyElements, rootBlockName;
+
+        args = args || {};
+        matchedNodes = {};
+        matchedAttributes = {};
+        blockElements = extend(makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements());
+        nonEmptyElements = schema.getNonEmptyElements();
+        children = schema.children;
+        validate = settings.validate;
+        rootBlockName = "forced_root_block" in args ? args.forced_root_block : settings.forced_root_block;
+
+        whiteSpaceElements = schema.getWhiteSpaceElements();
+        startWhiteSpaceRegExp = /^[ \t\r\n]+/;
+        endWhiteSpaceRegExp = /[ \t\r\n]+$/;
+        allWhiteSpaceRegExp = /[ \t\r\n]+/g;
+        isAllWhiteSpaceRegExp = /^[ \t\r\n]+$/;
+
+        function addRootBlocks() {
+          var node = rootNode.firstChild, next, rootBlockNode;
+
+          // Removes whitespace at beginning and end of block so:
+          // <p> x </p> -> <p>x</p>
+          function trim(rootBlockNode) {
+            if (rootBlockNode) {
+              node = rootBlockNode.firstChild;
+              if (node && node.type == 3) {
+                node.value = node.value.replace(startWhiteSpaceRegExp, '');
+              }
+
+              node = rootBlockNode.lastChild;
+              if (node && node.type == 3) {
+                node.value = node.value.replace(endWhiteSpaceRegExp, '');
+              }
+            }
+          }
+
+          // Check if rootBlock is valid within rootNode for example if P is valid in H1 if H1 is the contentEditabe root
+          if (!schema.isValidChild(rootNode.name, rootBlockName.toLowerCase())) {
+            return;
+          }
+
+          while (node) {
+            next = node.next;
+
+            if (node.type == 3 || (node.type == 1 && node.name !== 'p' &&
+              !blockElements[node.name] && !node.attr('data-mce-type'))) {
+              if (!rootBlockNode) {
+                // Create a new root block element
+                rootBlockNode = createNode(rootBlockName, 1);
+                rootBlockNode.attr(settings.forced_root_block_attrs);
+                rootNode.insert(rootBlockNode, node);
+                rootBlockNode.append(node);
+              } else {
+                rootBlockNode.append(node);
+              }
+            } else {
+              trim(rootBlockNode);
+              rootBlockNode = null;
+            }
+
+            node = next;
+          }
+
+          trim(rootBlockNode);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (settings.autofocus) {
-          self.focus();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        function createNode(name, type) {
+          var node = new Node(name, type), list;
+
+          if (name in nodeFilters) {
+            list = matchedNodes[name];
+
+            if (list) {
+              list.push(node);
+            } else {
+              matchedNodes[name] = [node];
+            }
+          }
+
+          return node;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      },
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      bindStates: function () {
-        var self = this;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        function removeWhitespaceBefore(node) {
+          var textNode, textNodeNext, textVal, sibling, blockElements = schema.getBlockElements();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function disable(state) {
-          self.aria('disabled', state);
-          self.classes.toggle('disabled', state);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          for (textNode = node.prev; textNode && textNode.type === 3;) {
+            textVal = textNode.value.replace(endWhiteSpaceRegExp, '');
+
+            // Found a text node with non whitespace then trim that and break
+            if (textVal.length > 0) {
+              textNode.value = textVal;
+              return;
+            }
+
+            textNodeNext = textNode.next;
+
+            // Fix for bug #7543 where bogus nodes would produce empty
+            // text nodes and these would be removed if a nested list was before it
+            if (textNodeNext) {
+              if (textNodeNext.type == 3 && textNodeNext.value.length) {
+                textNode = textNode.prev;
+                continue;
+              }
+
+              if (!blockElements[textNodeNext.name] && textNodeNext.name != 'script' && textNodeNext.name != 'style') {
+                textNode = textNode.prev;
+                continue;
+              }
+            }
+
+            sibling = textNode.prev;
+            textNode.remove();
+            textNode = sibling;
+          }
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function active(state) {
-          self.aria('pressed', state);
-          self.classes.toggle('active', state);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        function cloneAndExcludeBlocks(input) {
+          var name, output = {};
+
+          for (name in input) {
+            if (name !== 'li' && name != 'p') {
+              output[name] = input[name];
+            }
+          }
+
+          return output;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        self.state.on('change:disabled', function (e) {
-          disable(e.value);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        parser = new SaxParser({
+          validate: validate,
+          allow_script_urls: settings.allow_script_urls,
+          allow_conditional_comments: settings.allow_conditional_comments,
+
+          // Exclude P and LI from DOM parsing since it's treated better by the DOM parser
+          self_closing_elements: cloneAndExcludeBlocks(schema.getSelfClosingElements()),
+
+          cdata: function (text) {
+            node.append(createNode('#cdata', 4)).value = text;
+          },
+
+          text: function (text, raw) {
+            var textNode;
+
+            // Trim all redundant whitespace on non white space elements
+            if (!isInWhiteSpacePreservedElement) {
+              text = text.replace(allWhiteSpaceRegExp, ' ');
+
+              if (node.lastChild && blockElements[node.lastChild.name]) {
+                text = text.replace(startWhiteSpaceRegExp, '');
+              }
+            }
+
+            // Do we need to create the node
+            if (text.length !== 0) {
+              textNode = createNode('#text', 3);
+              textNode.raw = !!raw;
+              node.append(textNode).value = text;
+            }
+          },
+
+          comment: function (text) {
+            node.append(createNode('#comment', 8)).value = text;
+          },
+
+          pi: function (name, text) {
+            node.append(createNode(name, 7)).value = text;
+            removeWhitespaceBefore(node);
+          },
+
+          doctype: function (text) {
+            var newNode;
+
+            newNode = node.append(createNode('#doctype', 10));
+            newNode.value = text;
+            removeWhitespaceBefore(node);
+          },
+
+          start: function (name, attrs, empty) {
+            var newNode, attrFiltersLen, elementRule, attrName, parent;
+
+            elementRule = validate ? schema.getElementRule(name) : {};
+            if (elementRule) {
+              newNode = createNode(elementRule.outputName || name, 1);
+              newNode.attributes = attrs;
+              newNode.shortEnded = empty;
+
+              node.append(newNode);
+
+              // Check if node is valid child of the parent node is the child is
+              // unknown we don't collect it since it's probably a custom element
+              parent = children[node.name];
+              if (parent && children[newNode.name] && !parent[newNode.name]) {
+                invalidChildren.push(newNode);
+              }
+
+              attrFiltersLen = attributeFilters.length;
+              while (attrFiltersLen--) {
+                attrName = attributeFilters[attrFiltersLen].name;
+
+                if (attrName in attrs.map) {
+                  list = matchedAttributes[attrName];
+
+                  if (list) {
+                    list.push(newNode);
+                  } else {
+                    matchedAttributes[attrName] = [newNode];
+                  }
+                }
+              }
+
+              // Trim whitespace before block
+              if (blockElements[name]) {
+                removeWhitespaceBefore(newNode);
+              }
+
+              // Change current node if the element wasn't empty i.e not <br /> or <img />
+              if (!empty) {
+                node = newNode;
+              }
+
+              // Check if we are inside a whitespace preserved element
+              if (!isInWhiteSpacePreservedElement && whiteSpaceElements[name]) {
+                isInWhiteSpacePreservedElement = true;
+              }
+            }
+          },
+
+          end: function (name) {
+            var textNode, elementRule, text, sibling, tempNode;
+
+            elementRule = validate ? schema.getElementRule(name) : {};
+            if (elementRule) {
+              if (blockElements[name]) {
+                if (!isInWhiteSpacePreservedElement) {
+                  // Trim whitespace of the first node in a block
+                  textNode = node.firstChild;
+                  if (textNode && textNode.type === 3) {
+                    text = textNode.value.replace(startWhiteSpaceRegExp, '');
+
+                    // Any characters left after trim or should we remove it
+                    if (text.length > 0) {
+                      textNode.value = text;
+                      textNode = textNode.next;
+                    } else {
+                      sibling = textNode.next;
+                      textNode.remove();
+                      textNode = sibling;
+
+                      // Remove any pure whitespace siblings
+                      while (textNode && textNode.type === 3) {
+                        text = textNode.value;
+                        sibling = textNode.next;
+
+                        if (text.length === 0 || isAllWhiteSpaceRegExp.test(text)) {
+                          textNode.remove();
+                          textNode = sibling;
+                        }
+
+                        textNode = sibling;
+                      }
+                    }
+                  }
+
+                  // Trim whitespace of the last node in a block
+                  textNode = node.lastChild;
+                  if (textNode && textNode.type === 3) {
+                    text = textNode.value.replace(endWhiteSpaceRegExp, '');
+
+                    // Any characters left after trim or should we remove it
+                    if (text.length > 0) {
+                      textNode.value = text;
+                      textNode = textNode.prev;
+                    } else {
+                      sibling = textNode.prev;
+                      textNode.remove();
+                      textNode = sibling;
+
+                      // Remove any pure whitespace siblings
+                      while (textNode && textNode.type === 3) {
+                        text = textNode.value;
+                        sibling = textNode.prev;
+
+                        if (text.length === 0 || isAllWhiteSpaceRegExp.test(text)) {
+                          textNode.remove();
+                          textNode = sibling;
+                        }
+
+                        textNode = sibling;
+                      }
+                    }
+                  }
+                }
+
+                // Trim start white space
+                // Removed due to: #5424
+                /*textNode = node.prev;
+                if (textNode && textNode.type === 3) {
+                  text = textNode.value.replace(startWhiteSpaceRegExp, '');
+
+                  if (text.length > 0)
+                    textNode.value = text;
+                  else
+                    textNode.remove();
+                }*/
+              }
+
+              // Check if we exited a whitespace preserved element
+              if (isInWhiteSpacePreservedElement && whiteSpaceElements[name]) {
+                isInWhiteSpacePreservedElement = false;
+              }
+
+              // Handle empty nodes
+              if (elementRule.removeEmpty || elementRule.paddEmpty) {
+                if (isEmpty(schema, nonEmptyElements, whiteSpaceElements, node)) {
+                  if (elementRule.paddEmpty) {
+                    paddEmptyNode(settings, node);
+                  } else {
+                    // Leave nodes that have a name like <a name="name">
+                    if (!node.attributes.map.name && !node.attributes.map.id) {
+                      tempNode = node.parent;
+
+                      if (blockElements[node.name]) {
+                        node.empty().remove();
+                      } else {
+                        node.unwrap();
+                      }
+
+                      node = tempNode;
+                      return;
+                    }
+                  }
+                }
+              }
+
+              node = node.parent;
+            }
+          }
+        }, schema);
+
+        rootNode = node = new Node(args.context || settings.root_name, 11);
+
+        parser.parse(html);
+
+        // Fix invalid children or report invalid children in a contextual parsing
+        if (validate && invalidChildren.length) {
+          if (!args.context) {
+            fixInvalidChildren(invalidChildren);
+          } else {
+            args.invalid = true;
+          }
+        }
+
+        // Wrap nodes in the root into block elements if the root is body
+        if (rootBlockName && (rootNode.name == 'body' || args.isRootContent)) {
+          addRootBlocks();
+        }
+
+        // Run filters only when the contents is valid
+        if (!args.invalid) {
+          // Run node filters
+          for (name in matchedNodes) {
+            list = nodeFilters[name];
+            nodes = matchedNodes[name];
+
+            // Remove already removed children
+            fi = nodes.length;
+            while (fi--) {
+              if (!nodes[fi].parent) {
+                nodes.splice(fi, 1);
+              }
+            }
+
+            for (i = 0, l = list.length; i < l; i++) {
+              list[i](nodes, name, args);
+            }
+          }
+
+          // Run attribute filters
+          for (i = 0, l = attributeFilters.length; i < l; i++) {
+            list = attributeFilters[i];
+
+            if (list.name in matchedAttributes) {
+              nodes = matchedAttributes[list.name];
+
+              // Remove already removed children
+              fi = nodes.length;
+              while (fi--) {
+                if (!nodes[fi].parent) {
+                  nodes.splice(fi, 1);
+                }
+              }
+
+              for (fi = 0, fl = list.callbacks.length; fi < fl; fi++) {
+                list.callbacks[fi](nodes, list.name, args);
+              }
+            }
+          }
+        }
+
+        return rootNode;
+      };
+
+      // Remove <br> at end of block elements Gecko and WebKit injects BR elements to
+      // make it possible to place the caret inside empty blocks. This logic tries to remove
+      // these elements and keep br elements that where intended to be there intact
+      if (settings.remove_trailing_brs) {
+        self.addNodeFilter('br', function (nodes) {
+          var i, l = nodes.length, node, blockElements = extend({}, schema.getBlockElements());
+          var nonEmptyElements = schema.getNonEmptyElements(), parent, lastParent, prev, prevName;
+          var whiteSpaceElements = schema.getNonEmptyElements();
+          var elementRule, textNode;
+
+          // Remove brs from body element as well
+          blockElements.body = 1;
+
+          // Must loop forwards since it will otherwise remove all brs in <p>a<br><br><br></p>
+          for (i = 0; i < l; i++) {
+            node = nodes[i];
+            parent = node.parent;
+
+            if (blockElements[node.parent.name] && node === parent.lastChild) {
+              // Loop all nodes to the left of the current node and check for other BR elements
+              // excluding bookmarks since they are invisible
+              prev = node.prev;
+              while (prev) {
+                prevName = prev.name;
+
+                // Ignore bookmarks
+                if (prevName !== "span" || prev.attr('data-mce-type') !== 'bookmark') {
+                  // Found a non BR element
+                  if (prevName !== "br") {
+                    break;
+                  }
+
+                  // Found another br it's a <br><br> structure then don't remove anything
+                  if (prevName === 'br') {
+                    node = null;
+                    break;
+                  }
+                }
+
+                prev = prev.prev;
+              }
+
+              if (node) {
+                node.remove();
+
+                // Is the parent to be considered empty after we removed the BR
+                if (isEmpty(schema, nonEmptyElements, whiteSpaceElements, parent)) {
+                  elementRule = schema.getElementRule(parent.name);
+
+                  // Remove or padd the element depending on schema rule
+                  if (elementRule) {
+                    if (elementRule.removeEmpty) {
+                      parent.remove();
+                    } else if (elementRule.paddEmpty) {
+                      paddEmptyNode(settings, parent);
+                    }
+                  }
+                }
+              }
+            } else {
+              // Replaces BR elements inside inline elements like <p><b><i><br></i></b></p>
+              // so they become <p><b><i>&nbsp;</i></b></p>
+              lastParent = node;
+              while (parent && parent.firstChild === lastParent && parent.lastChild === lastParent) {
+                lastParent = parent;
+
+                if (blockElements[parent.name]) {
+                  break;
+                }
+
+                parent = parent.parent;
+              }
+
+              if (lastParent === parent && settings.padd_empty_with_br !== true) {
+                textNode = new Node('#text', 3);
+                textNode.value = '\u00a0';
+                node.replace(textNode);
+              }
+            }
+          }
</ins><span class="cx" style="display: block; padding: 0 10px">         });
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        self.state.on('change:active', function (e) {
-          active(e.value);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+      self.addAttributeFilter('href', function (nodes) {
+        var i = nodes.length, node;
+
+        var appendRel = function (rel) {
+          var parts = rel.split(' ').filter(function (p) {
+            return p.length > 0;
+          });
+          return parts.concat(['noopener']).sort().join(' ');
+        };
+
+        var addNoOpener = function (rel) {
+          var newRel = rel ? Tools.trim(rel) : '';
+          if (!/\b(noopener)\b/g.test(newRel)) {
+            return appendRel(newRel);
+          } else {
+            return newRel;
+          }
+        };
+
+        if (!settings.allow_unsafe_link_target) {
+          while (i--) {
+            node = nodes[i];
+            if (node.name === 'a' && node.attr('target') === '_blank') {
+              node.attr('rel', addNoOpener(node.attr('rel')));
+            }
+          }
+        }
+      });
+
+      // Force anchor names closed, unless the setting "allow_html_in_named_anchor" is explicitly included.
+      if (!settings.allow_html_in_named_anchor) {
+        self.addAttributeFilter('id,name', function (nodes) {
+          var i = nodes.length, sibling, prevSibling, parent, node;
+
+          while (i--) {
+            node = nodes[i];
+            if (node.name === 'a' && node.firstChild && !node.attr('href')) {
+              parent = node.parent;
+
+              // Move children after current node
+              sibling = node.lastChild;
+              do {
+                prevSibling = sibling.prev;
+                parent.insert(sibling, node);
+                sibling = prevSibling;
+              } while (sibling);
+            }
+          }
</ins><span class="cx" style="display: block; padding: 0 10px">         });
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (self.state.get('disabled')) {
-          disable(true);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (settings.fix_list_elements) {
+        self.addNodeFilter('ul,ol', function (nodes) {
+          var i = nodes.length, node, parentNode;
+
+          while (i--) {
+            node = nodes[i];
+            parentNode = node.parent;
+
+            if (parentNode.name === 'ul' || parentNode.name === 'ol') {
+              if (node.prev && node.prev.name === 'li') {
+                node.prev.append(node);
+              } else {
+                var li = new Node('li', 1);
+                li.attr('style', 'list-style-type: none');
+                node.wrap(li);
+              }
+            }
+          }
+        });
+      }
+
+      if (settings.validate && schema.getValidClasses()) {
+        self.addAttributeFilter('class', function (nodes) {
+          var i = nodes.length, node, classList, ci, className, classValue;
+          var validClasses = schema.getValidClasses(), validClassesMap, valid;
+
+          while (i--) {
+            node = nodes[i];
+            classList = node.attr('class').split(' ');
+            classValue = '';
+
+            for (ci = 0; ci < classList.length; ci++) {
+              className = classList[ci];
+              valid = false;
+
+              validClassesMap = validClasses['*'];
+              if (validClassesMap && validClassesMap[className]) {
+                valid = true;
+              }
+
+              validClassesMap = validClasses[node.name];
+              if (!valid && validClassesMap && validClassesMap[className]) {
+                valid = true;
+              }
+
+              if (valid) {
+                if (classValue) {
+                  classValue += ' ';
+                }
+
+                classValue += className;
+              }
+            }
+
+            if (!classValue.length) {
+              classValue = null;
+            }
+
+            node.attr('class', classValue);
+          }
+        });
+      }
+    };
+  }
+);
+/**
+ * Writer.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This class is used to write HTML tags out it can be used with the Serializer or the SaxParser.
+ *
+ * @class tinymce.html.Writer
+ * @example
+ * var writer = new tinymce.html.Writer({indent: true});
+ * var parser = new tinymce.html.SaxParser(writer).parse('<p><br></p>');
+ * console.log(writer.getContent());
+ *
+ * @class tinymce.html.Writer
+ * @version 3.4
+ */
+define(
+  'tinymce.core.html.Writer',
+  [
+    "tinymce.core.html.Entities",
+    "tinymce.core.util.Tools"
+  ],
+  function (Entities, Tools) {
+    var makeMap = Tools.makeMap;
+
+    /**
+     * Constructs a new Writer instance.
+     *
+     * @constructor
+     * @method Writer
+     * @param {Object} settings Name/value settings object.
+     */
+    return function (settings) {
+      var html = [], indent, indentBefore, indentAfter, encode, htmlOutput;
+
+      settings = settings || {};
+      indent = settings.indent;
+      indentBefore = makeMap(settings.indent_before || '');
+      indentAfter = makeMap(settings.indent_after || '');
+      encode = Entities.getEncodeFunc(settings.entity_encoding || 'raw', settings.entities);
+      htmlOutput = settings.element_format == "html";
+
+      return {
+        /**
+         * Writes the a start element such as <p id="a">.
+         *
+         * @method start
+         * @param {String} name Name of the element.
+         * @param {Array} attrs Optional attribute array or undefined if it hasn't any.
+         * @param {Boolean} empty Optional empty state if the tag should end like <br />.
+         */
+        start: function (name, attrs, empty) {
+          var i, l, attr, value;
+
+          if (indent && indentBefore[name] && html.length > 0) {
+            value = html[html.length - 1];
+
+            if (value.length > 0 && value !== '\n') {
+              html.push('\n');
+            }
+          }
+
+          html.push('<', name);
+
+          if (attrs) {
+            for (i = 0, l = attrs.length; i < l; i++) {
+              attr = attrs[i];
+              html.push(' ', attr.name, '="', encode(attr.value, true), '"');
+            }
+          }
+
+          if (!empty || htmlOutput) {
+            html[html.length] = '>';
+          } else {
+            html[html.length] = ' />';
+          }
+
+          if (empty && indent && indentAfter[name] && html.length > 0) {
+            value = html[html.length - 1];
+
+            if (value.length > 0 && value !== '\n') {
+              html.push('\n');
+            }
+          }
+        },
+
+        /**
+         * Writes the a end element such as </p>.
+         *
+         * @method end
+         * @param {String} name Name of the element.
+         */
+        end: function (name) {
+          var value;
+
+          /*if (indent && indentBefore[name] && html.length > 0) {
+            value = html[html.length - 1];
+
+            if (value.length > 0 && value !== '\n')
+              html.push('\n');
+          }*/
+
+          html.push('</', name, '>');
+
+          if (indent && indentAfter[name] && html.length > 0) {
+            value = html[html.length - 1];
+
+            if (value.length > 0 && value !== '\n') {
+              html.push('\n');
+            }
+          }
+        },
+
+        /**
+         * Writes a text node.
+         *
+         * @method text
+         * @param {String} text String to write out.
+         * @param {Boolean} raw Optional raw state if true the contents wont get encoded.
+         */
+        text: function (text, raw) {
+          if (text.length > 0) {
+            html[html.length] = raw ? text : encode(text);
+          }
+        },
+
+        /**
+         * Writes a cdata node such as <![CDATA[data]]>.
+         *
+         * @method cdata
+         * @param {String} text String to write out inside the cdata.
+         */
+        cdata: function (text) {
+          html.push('<![CDATA[', text, ']]>');
+        },
+
+        /**
+         * Writes a comment node such as <!-- Comment -->.
+         *
+         * @method cdata
+         * @param {String} text String to write out inside the comment.
+         */
+        comment: function (text) {
+          html.push('<!--', text, '-->');
+        },
+
+        /**
+         * Writes a PI node such as <?xml attr="value" ?>.
+         *
+         * @method pi
+         * @param {String} name Name of the pi.
+         * @param {String} text String to write out inside the pi.
+         */
+        pi: function (name, text) {
+          if (text) {
+            html.push('<?', name, ' ', encode(text), '?>');
+          } else {
+            html.push('<?', name, '?>');
+          }
+
+          if (indent) {
+            html.push('\n');
+          }
+        },
+
+        /**
+         * Writes a doctype node such as <!DOCTYPE data>.
+         *
+         * @method doctype
+         * @param {String} text String to write out inside the doctype.
+         */
+        doctype: function (text) {
+          html.push('<!DOCTYPE', text, '>', indent ? '\n' : '');
+        },
+
+        /**
+         * Resets the internal buffer if one wants to reuse the writer.
+         *
+         * @method reset
+         */
+        reset: function () {
+          html.length = 0;
+        },
+
+        /**
+         * Returns the contents that got serialized.
+         *
+         * @method getContent
+         * @return {String} HTML contents that got written down.
+         */
+        getContent: function () {
+          return html.join('').replace(/\n$/, '');
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      };
+    };
+  }
+);
+/**
+ * Serializer.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (self.state.get('active')) {
-          active(true);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/**
+ * This class is used to serialize down the DOM tree into a string using a Writer instance.
+ *
+ *
+ * @example
+ * new tinymce.html.Serializer().serialize(new tinymce.html.DomParser().parse('<p>text</p>'));
+ * @class tinymce.html.Serializer
+ * @version 3.4
+ */
+define(
+  'tinymce.core.html.Serializer',
+  [
+    "tinymce.core.html.Writer",
+    "tinymce.core.html.Schema"
+  ],
+  function (Writer, Schema) {
+    /**
+     * Constructs a new Serializer instance.
+     *
+     * @constructor
+     * @method Serializer
+     * @param {Object} settings Name/value settings object.
+     * @param {tinymce.html.Schema} schema Schema instance to use.
+     */
+    return function (settings, schema) {
+      var self = this, writer = new Writer(settings);
+
+      settings = settings || {};
+      settings.validate = "validate" in settings ? settings.validate : true;
+
+      self.schema = schema = schema || new Schema();
+      self.writer = writer;
+
+      /**
+       * Serializes the specified node into a string.
+       *
+       * @example
+       * new tinymce.html.Serializer().serialize(new tinymce.html.DomParser().parse('<p>text</p>'));
+       * @method serialize
+       * @param {tinymce.html.Node} node Node instance to serialize.
+       * @return {String} String with HTML based on DOM tree.
+       */
+      self.serialize = function (node) {
+        var handlers, validate;
+
+        validate = settings.validate;
+
+        handlers = {
+          // #text
+          3: function (node) {
+            writer.text(node.value, node.raw);
+          },
+
+          // #comment
+          8: function (node) {
+            writer.comment(node.value);
+          },
+
+          // Processing instruction
+          7: function (node) {
+            writer.pi(node.name, node.value);
+          },
+
+          // Doctype
+          10: function (node) {
+            writer.doctype(node.value);
+          },
+
+          // CDATA
+          4: function (node) {
+            writer.cdata(node.value);
+          },
+
+          // Document fragment
+          11: function (node) {
+            if ((node = node.firstChild)) {
+              do {
+                walk(node);
+              } while ((node = node.next));
+            }
+          }
+        };
+
+        writer.reset();
+
+        function walk(node) {
+          var handler = handlers[node.type], name, isEmpty, attrs, attrName, attrValue, sortedAttrs, i, l, elementRule;
+
+          if (!handler) {
+            name = node.name;
+            isEmpty = node.shortEnded;
+            attrs = node.attributes;
+
+            // Sort attributes
+            if (validate && attrs && attrs.length > 1) {
+              sortedAttrs = [];
+              sortedAttrs.map = {};
+
+              elementRule = schema.getElementRule(node.name);
+              if (elementRule) {
+                for (i = 0, l = elementRule.attributesOrder.length; i < l; i++) {
+                  attrName = elementRule.attributesOrder[i];
+
+                  if (attrName in attrs.map) {
+                    attrValue = attrs.map[attrName];
+                    sortedAttrs.map[attrName] = attrValue;
+                    sortedAttrs.push({ name: attrName, value: attrValue });
+                  }
+                }
+
+                for (i = 0, l = attrs.length; i < l; i++) {
+                  attrName = attrs[i].name;
+
+                  if (!(attrName in sortedAttrs.map)) {
+                    attrValue = attrs.map[attrName];
+                    sortedAttrs.map[attrName] = attrValue;
+                    sortedAttrs.push({ name: attrName, value: attrValue });
+                  }
+                }
+
+                attrs = sortedAttrs;
+              }
+            }
+
+            writer.start(node.name, attrs, isEmpty);
+
+            if (!isEmpty) {
+              if ((node = node.firstChild)) {
+                do {
+                  walk(node);
+                } while ((node = node.next));
+              }
+
+              writer.end(name);
+            }
+          } else {
+            handler(node);
+          }
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return self._super();
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Serialize element and treat all non elements as fragments
+        if (node.type == 1 && !settings.inner) {
+          walk(node);
+        } else {
+          handlers[11](node);
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return writer.getContent();
+      };
+    };
+  }
+);
+
+/**
+ * Serializer.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This class is used to serialize DOM trees into a string. Consult the TinyMCE Wiki API for
+ * more details and examples on how to use this class.
+ *
+ * @class tinymce.dom.Serializer
+ */
+define(
+  'tinymce.core.dom.Serializer',
+  [
+    "tinymce.core.dom.DOMUtils",
+    "tinymce.core.html.DomParser",
+    "tinymce.core.html.SaxParser",
+    "tinymce.core.html.Entities",
+    "tinymce.core.html.Serializer",
+    "tinymce.core.html.Node",
+    "tinymce.core.html.Schema",
+    "tinymce.core.Env",
+    "tinymce.core.util.Tools",
+    "tinymce.core.text.Zwsp"
+  ],
+  function (DOMUtils, DomParser, SaxParser, Entities, Serializer, Node, Schema, Env, Tools, Zwsp) {
+    var each = Tools.each, trim = Tools.trim;
+    var DOM = DOMUtils.DOM;
+
+    /**
+     * IE 11 has a fantastic bug where it will produce two trailing BR elements to iframe bodies when
+     * the iframe is hidden by display: none on a parent container. The DOM is actually out of sync
+     * with innerHTML in this case. It's like IE adds shadow DOM BR elements that appears on innerHTML
+     * but not as the lastChild of the body. So this fix simply removes the last two
+     * BR elements at the end of the document.
+     *
+     * Example of what happens: <body>text</body> becomes <body>text<br><br></body>
+     */
+    function trimTrailingBr(rootNode) {
+      var brNode1, brNode2;
+
+      function isBr(node) {
+        return node && node.name === 'br';
+      }
+
+      brNode1 = rootNode.lastChild;
+      if (isBr(brNode1)) {
+        brNode2 = brNode1.prev;
+
+        if (isBr(brNode2)) {
+          brNode1.remove();
+          brNode2.remove();
+        }
+      }
+    }
+
+    /**
+     * Constructs a new DOM serializer class.
+     *
+     * @constructor
+     * @method Serializer
+     * @param {Object} settings Serializer settings object.
+     * @param {tinymce.Editor} editor Optional editor to bind events to and get schema/dom from.
+     */
+    return function (settings, editor) {
+      var dom, schema, htmlParser, tempAttrs = ["data-mce-selected"];
+
+      if (editor) {
+        dom = editor.dom;
+        schema = editor.schema;
+      }
+
+      function trimHtml(html) {
+        var trimContentRegExp = new RegExp([
+          '<span[^>]+data-mce-bogus[^>]+>[\u200B\uFEFF]+<\\/span>', // Trim bogus spans like caret containers
+          '\\s?(' + tempAttrs.join('|') + ')="[^"]+"' // Trim temporaty data-mce prefixed attributes like data-mce-selected
+        ].join('|'), 'gi');
+
+        html = Zwsp.trim(html.replace(trimContentRegExp, ''));
+
+        return html;
+      }
+
+      function trimContent(html) {
+        var content = html;
+        var bogusAllRegExp = /<(\w+) [^>]*data-mce-bogus="all"[^>]*>/g;
+        var endTagIndex, index, matchLength, matches, shortEndedElements, schema = editor.schema;
+
+        content = trimHtml(content);
+        shortEndedElements = schema.getShortEndedElements();
+
+        // Remove all bogus elements marked with "all"
+        while ((matches = bogusAllRegExp.exec(content))) {
+          index = bogusAllRegExp.lastIndex;
+          matchLength = matches[0].length;
+
+          if (shortEndedElements[matches[1]]) {
+            endTagIndex = index;
+          } else {
+            endTagIndex = SaxParser.findEndTag(schema, content, index);
+          }
+
+          content = content.substring(0, index - matchLength) + content.substring(endTagIndex);
+          bogusAllRegExp.lastIndex = index - matchLength;
+        }
+
+        return content;
+      }
+
</ins><span class="cx" style="display: block; padding: 0 10px">       /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * Removes the current control from DOM and from UI collections.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * Returns a trimmed version of the editor contents to be used for the undo level. This
+       * will remove any data-mce-bogus="all" marked elements since these are used for UI it will also
+       * remove the data-mce-selected attributes used for selection of objects and caret containers.
+       * It will keep all data-mce-bogus="1" elements since these can be used to place the caret etc and will
+       * be removed by the serialization logic when you save.
</ins><span class="cx" style="display: block; padding: 0 10px">        *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * @method remove
-       * @return {tinymce.ui.Control} Current control instance.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * @private
+       * @return {String} HTML contents of the editor excluding some internal bogus elements.
</ins><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      remove: function () {
-        this._super();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function getTrimmedContent() {
+        return trimContent(editor.getBody().innerHTML);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (tooltip) {
-          tooltip.remove();
-          tooltip = null;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function addTempAttr(name) {
+        if (Tools.inArray(tempAttrs, name) === -1) {
+          htmlParser.addAttributeFilter(name, function (nodes, name) {
+            var i = nodes.length;
+
+            while (i--) {
+              nodes[i].attr(name, null);
+            }
+          });
+
+          tempAttrs.push(name);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    });
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return Widget;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Default DOM and Schema if they are undefined
+      dom = dom || DOM;
+      schema = schema || new Schema(settings);
+      settings.entity_encoding = settings.entity_encoding || 'named';
+      settings.remove_trailing_brs = "remove_trailing_brs" in settings ? settings.remove_trailing_brs : true;
+
+      htmlParser = new DomParser(settings, schema);
+
+      // Convert tabindex back to elements when serializing contents
+      htmlParser.addAttributeFilter('data-mce-tabindex', function (nodes, name) {
+        var i = nodes.length, node;
+
+        while (i--) {
+          node = nodes[i];
+          node.attr('tabindex', node.attributes.map['data-mce-tabindex']);
+          node.attr(name, null);
+        }
+      });
+
+      // Convert move data-mce-src, data-mce-href and data-mce-style into nodes or process them if needed
+      htmlParser.addAttributeFilter('src,href,style', function (nodes, name) {
+        var i = nodes.length, node, value, internalName = 'data-mce-' + name;
+        var urlConverter = settings.url_converter, urlConverterScope = settings.url_converter_scope, undef;
+
+        while (i--) {
+          node = nodes[i];
+
+          value = node.attributes.map[internalName];
+          if (value !== undef) {
+            // Set external name to internal value and remove internal
+            node.attr(name, value.length > 0 ? value : null);
+            node.attr(internalName, null);
+          } else {
+            // No internal attribute found then convert the value we have in the DOM
+            value = node.attributes.map[name];
+
+            if (name === "style") {
+              value = dom.serializeStyle(dom.parseStyle(value), node.name);
+            } else if (urlConverter) {
+              value = urlConverter.call(urlConverterScope, value, name, node.name);
+            }
+
+            node.attr(name, value.length > 0 ? value : null);
+          }
+        }
+      });
+
+      // Remove internal classes mceItem<..> or mceSelected
+      htmlParser.addAttributeFilter('class', function (nodes) {
+        var i = nodes.length, node, value;
+
+        while (i--) {
+          node = nodes[i];
+          value = node.attr('class');
+
+          if (value) {
+            value = node.attr('class').replace(/(?:^|\s)mce-item-\w+(?!\S)/g, '');
+            node.attr('class', value.length > 0 ? value : null);
+          }
+        }
+      });
+
+      // Remove bookmark elements
+      htmlParser.addAttributeFilter('data-mce-type', function (nodes, name, args) {
+        var i = nodes.length, node;
+
+        while (i--) {
+          node = nodes[i];
+
+          if (node.attributes.map['data-mce-type'] === 'bookmark' && !args.cleanup) {
+            node.remove();
+          }
+        }
+      });
+
+      htmlParser.addNodeFilter('noscript', function (nodes) {
+        var i = nodes.length, node;
+
+        while (i--) {
+          node = nodes[i].firstChild;
+
+          if (node) {
+            node.value = Entities.decode(node.value);
+          }
+        }
+      });
+
+      // Force script into CDATA sections and remove the mce- prefix also add comments around styles
+      htmlParser.addNodeFilter('script,style', function (nodes, name) {
+        var i = nodes.length, node, value, type;
+
+        function trim(value) {
+          /*jshint maxlen:255 */
+          /*eslint max-len:0 */
+          return value.replace(/(<!--\[CDATA\[|\]\]-->)/g, '\n')
+            .replace(/^[\r\n]*|[\r\n]*$/g, '')
+            .replace(/^\s*((<!--)?(\s*\/\/)?\s*<!\[CDATA\[|(<!--\s*)?\/\*\s*<!\[CDATA\[\s*\*\/|(\/\/)?\s*<!--|\/\*\s*<!--\s*\*\/)\s*[\r\n]*/gi, '')
+            .replace(/\s*(\/\*\s*\]\]>\s*\*\/(-->)?|\s*\/\/\s*\]\]>(-->)?|\/\/\s*(-->)?|\]\]>|\/\*\s*-->\s*\*\/|\s*-->\s*)\s*$/g, '');
+        }
+
+        while (i--) {
+          node = nodes[i];
+          value = node.firstChild ? node.firstChild.value : '';
+
+          if (name === "script") {
+            // Remove mce- prefix from script elements and remove default type since the user specified
+            // a script element without type attribute
+            type = node.attr('type');
+            if (type) {
+              node.attr('type', type == 'mce-no/type' ? null : type.replace(/^mce\-/, ''));
+            }
+
+            if (value.length > 0) {
+              node.firstChild.value = '// <![CDATA[\n' + trim(value) + '\n// ]]>';
+            }
+          } else {
+            if (value.length > 0) {
+              node.firstChild.value = '<!--\n' + trim(value) + '\n-->';
+            }
+          }
+        }
+      });
+
+      // Convert comments to cdata and handle protected comments
+      htmlParser.addNodeFilter('#comment', function (nodes) {
+        var i = nodes.length, node;
+
+        while (i--) {
+          node = nodes[i];
+
+          if (node.value.indexOf('[CDATA[') === 0) {
+            node.name = '#cdata';
+            node.type = 4;
+            node.value = node.value.replace(/^\[CDATA\[|\]\]$/g, '');
+          } else if (node.value.indexOf('mce:protected ') === 0) {
+            node.name = "#text";
+            node.type = 3;
+            node.raw = true;
+            node.value = unescape(node.value).substr(14);
+          }
+        }
+      });
+
+      htmlParser.addNodeFilter('xml:namespace,input', function (nodes, name) {
+        var i = nodes.length, node;
+
+        while (i--) {
+          node = nodes[i];
+          if (node.type === 7) {
+            node.remove();
+          } else if (node.type === 1) {
+            if (name === "input" && !("type" in node.attributes.map)) {
+              node.attr('type', 'text');
+            }
+          }
+        }
+      });
+
+      // Remove internal data attributes
+      htmlParser.addAttributeFilter(
+        'data-mce-src,data-mce-href,data-mce-style,' +
+        'data-mce-selected,data-mce-expando,' +
+        'data-mce-type,data-mce-resize',
+
+        function (nodes, name) {
+          var i = nodes.length;
+
+          while (i--) {
+            nodes[i].attr(name, null);
+          }
+        }
+      );
+
+      // Return public methods
+      return {
+        /**
+         * Schema instance that was used to when the Serializer was constructed.
+         *
+         * @field {tinymce.html.Schema} schema
+         */
+        schema: schema,
+
+        /**
+         * Adds a node filter function to the parser used by the serializer, the parser will collect the specified nodes by name
+         * and then execute the callback ones it has finished parsing the document.
+         *
+         * @example
+         * parser.addNodeFilter('p,h1', function(nodes, name) {
+         *  for (var i = 0; i < nodes.length; i++) {
+         *   console.log(nodes[i].name);
+         *  }
+         * });
+         * @method addNodeFilter
+         * @method {String} name Comma separated list of nodes to collect.
+         * @param {function} callback Callback function to execute once it has collected nodes.
+         */
+        addNodeFilter: htmlParser.addNodeFilter,
+
+        /**
+         * Adds a attribute filter function to the parser used by the serializer, the parser will
+         * collect nodes that has the specified attributes
+         * and then execute the callback ones it has finished parsing the document.
+         *
+         * @example
+         * parser.addAttributeFilter('src,href', function(nodes, name) {
+         *  for (var i = 0; i < nodes.length; i++) {
+         *   console.log(nodes[i].name);
+         *  }
+         * });
+         * @method addAttributeFilter
+         * @method {String} name Comma separated list of nodes to collect.
+         * @param {function} callback Callback function to execute once it has collected nodes.
+         */
+        addAttributeFilter: htmlParser.addAttributeFilter,
+
+        /**
+         * Serializes the specified browser DOM node into a HTML string.
+         *
+         * @method serialize
+         * @param {DOMNode} node DOM node to serialize.
+         * @param {Object} args Arguments option that gets passed to event handlers.
+         */
+        serialize: function (node, args) {
+          var self = this, impl, doc, oldDoc, htmlSerializer, content, rootNode;
+
+          // Explorer won't clone contents of script and style and the
+          // selected index of select elements are cleared on a clone operation.
+          if (Env.ie && dom.select('script,style,select,map').length > 0) {
+            content = node.innerHTML;
+            node = node.cloneNode(false);
+            dom.setHTML(node, content);
+          } else {
+            node = node.cloneNode(true);
+          }
+
+          // Nodes needs to be attached to something in WebKit/Opera
+          // This fix will make DOM ranges and make Sizzle happy!
+          impl = document.implementation;
+          if (impl.createHTMLDocument) {
+            // Create an empty HTML document
+            doc = impl.createHTMLDocument("");
+
+            // Add the element or it's children if it's a body element to the new document
+            each(node.nodeName == 'BODY' ? node.childNodes : [node], function (node) {
+              doc.body.appendChild(doc.importNode(node, true));
+            });
+
+            // Grab first child or body element for serialization
+            if (node.nodeName != 'BODY') {
+              node = doc.body.firstChild;
+            } else {
+              node = doc.body;
+            }
+
+            // set the new document in DOMUtils so createElement etc works
+            oldDoc = dom.doc;
+            dom.doc = doc;
+          }
+
+          args = args || {};
+          args.format = args.format || 'html';
+
+          // Don't wrap content if we want selected html
+          if (args.selection) {
+            args.forced_root_block = '';
+          }
+
+          // Pre process
+          if (!args.no_events) {
+            args.node = node;
+            self.onPreProcess(args);
+          }
+
+          // Parse HTML
+          content = Zwsp.trim(trim(args.getInner ? node.innerHTML : dom.getOuterHTML(node)));
+          rootNode = htmlParser.parse(content, args);
+          trimTrailingBr(rootNode);
+
+          // Serialize HTML
+          htmlSerializer = new Serializer(settings, schema);
+          args.content = htmlSerializer.serialize(rootNode);
+
+          // Post process
+          if (!args.no_events) {
+            self.onPostProcess(args);
+          }
+
+          // Restore the old document if it was changed
+          if (oldDoc) {
+            dom.doc = oldDoc;
+          }
+
+          args.node = null;
+
+          return args.content;
+        },
+
+        /**
+         * Adds valid elements rules to the serializers schema instance this enables you to specify things
+         * like what elements should be outputted and what attributes specific elements might have.
+         * Consult the Wiki for more details on this format.
+         *
+         * @method addRules
+         * @param {String} rules Valid elements rules string to add to schema.
+         */
+        addRules: function (rules) {
+          schema.addValidElements(rules);
+        },
+
+        /**
+         * Sets the valid elements rules to the serializers schema instance this enables you to specify things
+         * like what elements should be outputted and what attributes specific elements might have.
+         * Consult the Wiki for more details on this format.
+         *
+         * @method setRules
+         * @param {String} rules Valid elements rules string.
+         */
+        setRules: function (rules) {
+          schema.setValidElements(rules);
+        },
+
+        onPreProcess: function (args) {
+          if (editor) {
+            editor.fire('PreProcess', args);
+          }
+        },
+
+        onPostProcess: function (args) {
+          if (editor) {
+            editor.fire('PostProcess', args);
+          }
+        },
+
+        /**
+         * Adds a temporary internal attribute these attributes will get removed on undo and
+         * when getting contents out of the editor.
+         *
+         * @method addTempAttr
+         * @param {String} name string
+         */
+        addTempAttr: addTempAttr,
+
+        // Internal
+        trimHtml: trimHtml,
+        getTrimmedContent: getTrimmedContent,
+        trimContent: trimContent
+      };
+    };
</ins><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Progress.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * DeleteUtils.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -37276,83 +34488,414 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Contributing: http://www.tinymce.com/contributing
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+define(
+  'tinymce.core.delete.DeleteUtils',
+  [
+    'ephox.katamari.api.Option',
+    'ephox.sugar.api.dom.Compare',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.search.PredicateFind',
+    'tinymce.core.dom.ElementType'
+  ],
+  function (Option, Compare, Element, PredicateFind, ElementType) {
+    var isBeforeRoot = function (rootNode) {
+      return function (elm) {
+        return Compare.eq(rootNode, Element.fromDom(elm.dom().parentNode));
+      };
+    };
+
+    var getParentBlock = function (rootNode, elm) {
+      return Compare.contains(rootNode, elm) ? PredicateFind.closest(elm, function (element) {
+        return ElementType.isTextBlock(element) || ElementType.isListItem(element);
+      }, isBeforeRoot(rootNode)) : Option.none();
+    };
+
+    var placeCaretInEmptyBody = function (editor) {
+      var body = editor.getBody();
+      var node = body.firstChild && editor.dom.isBlock(body.firstChild) ? body.firstChild : body;
+      editor.selection.setCursorLocation(node, 0);
+    };
+
+    var paddEmptyBody = function (editor) {
+      if (editor.dom.isEmpty(editor.getBody())) {
+        editor.setContent('');
+        placeCaretInEmptyBody(editor);
+      }
+    };
+
+    return {
+      getParentBlock: getParentBlock,
+      paddEmptyBody: paddEmptyBody
+    };
+  }
+);
+
+define(
+  'ephox.sugar.api.search.SelectorExists',
+
+  [
+    'ephox.sugar.api.search.SelectorFind'
+  ],
+
+  function (SelectorFind) {
+    var any = function (selector) {
+      return SelectorFind.first(selector).isSome();
+    };
+
+    var ancestor = function (scope, selector, isRoot) {
+      return SelectorFind.ancestor(scope, selector, isRoot).isSome();
+    };
+
+    var sibling = function (scope, selector) {
+      return SelectorFind.sibling(scope, selector).isSome();
+    };
+
+    var child = function (scope, selector) {
+      return SelectorFind.child(scope, selector).isSome();
+    };
+
+    var descendant = function (scope, selector) {
+      return SelectorFind.descendant(scope, selector).isSome();
+    };
+
+    var closest = function (scope, selector, isRoot) {
+      return SelectorFind.closest(scope, selector, isRoot).isSome();
+    };
+
+    return {
+      any: any,
+      ancestor: ancestor,
+      sibling: sibling,
+      child: child,
+      descendant: descendant,
+      closest: closest
+    };
+  }
+);
+
</ins><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Progress control.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Empty.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @-x-less Progress.less
- * @class tinymce.ui.Progress
- * @extends tinymce.ui.Control
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.ui.Progress',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.dom.Empty',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    "tinymce.core.ui.Widget"
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.katamari.api.Fun',
+    'ephox.sugar.api.dom.Compare',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.search.SelectorExists',
+    'tinymce.core.caret.CaretCandidate',
+    'tinymce.core.dom.NodeType',
+    'tinymce.core.dom.TreeWalker'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Widget) {
-    "use strict";
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Fun, Compare, Element, SelectorExists, CaretCandidate, NodeType, TreeWalker) {
+    var hasWhitespacePreserveParent = function (rootNode, node) {
+      var rootElement = Element.fromDom(rootNode);
+      var startNode = Element.fromDom(node);
+      return SelectorExists.ancestor(startNode, 'pre,code', Fun.curry(Compare.eq, rootElement));
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return Widget.extend({
-      Defaults: {
-        value: 0
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isWhitespace = function (rootNode, node) {
+      return NodeType.isText(node) && /^[ \t\r\n]*$/.test(node.data) && hasWhitespacePreserveParent(rootNode, node) === false;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      init: function (settings) {
-        var self = this;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isNamedAnchor = function (node) {
+      return NodeType.isElement(node) && node.nodeName === 'A' && node.hasAttribute('name');
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        self._super(settings);
-        self.classes.add('progress');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isContent = function (rootNode, node) {
+      return (CaretCandidate.isCaretCandidate(node) && isWhitespace(rootNode, node) === false) || isNamedAnchor(node) || isBookmark(node);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (!self.settings.filter) {
-          self.settings.filter = function (value) {
-            return Math.round(value);
-          };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isBookmark = NodeType.hasAttribute('data-mce-bookmark');
+    var isBogus = NodeType.hasAttribute('data-mce-bogus');
+    var isBogusAll = NodeType.hasAttributeValue('data-mce-bogus', 'all');
+
+    var isEmptyNode = function (targetNode) {
+      var walker, node, brCount = 0;
+
+      if (isContent(targetNode, targetNode)) {
+        return false;
+      } else {
+        node = targetNode.firstChild;
+        if (!node) {
+          return true;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      },
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      renderHtml: function () {
-        var self = this, id = self._id, prefix = this.classPrefix;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        walker = new TreeWalker(node, targetNode);
+        do {
+          if (isBogusAll(node)) {
+            node = walker.next(true);
+            continue;
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return (
-          '<div id="' + id + '" class="' + self.classes + '">' +
-          '<div class="' + prefix + 'bar-container">' +
-          '<div class="' + prefix + 'bar"></div>' +
-          '</div>' +
-          '<div class="' + prefix + 'text">0%</div>' +
-          '</div>'
-        );
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (isBogus(node)) {
+            node = walker.next();
+            continue;
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      postRender: function () {
-        var self = this;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (NodeType.isBr(node)) {
+            brCount++;
+            node = walker.next();
+            continue;
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        self._super();
-        self.value(self.settings.value);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (isContent(targetNode, node)) {
+            return false;
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return self;
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          node = walker.next();
+        } while (node);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      bindStates: function () {
-        var self = this;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return brCount <= 1;
+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function setValue(value) {
-          value = self.settings.filter(value);
-          self.getEl().lastChild.innerHTML = value + '%';
-          self.getEl().firstChild.firstChild.style.width = value + '%';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isEmpty = function (elm) {
+      return isEmptyNode(elm.dom());
+    };
+
+    return {
+      isEmpty: isEmpty
+    };
+  }
+);
+
+/**
+ * BlockBoundary.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.delete.BlockBoundary',
+  [
+    'ephox.katamari.api.Arr',
+    'ephox.katamari.api.Fun',
+    'ephox.katamari.api.Option',
+    'ephox.katamari.api.Options',
+    'ephox.katamari.api.Struct',
+    'ephox.sugar.api.dom.Compare',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.node.Node',
+    'ephox.sugar.api.search.PredicateFind',
+    'ephox.sugar.api.search.Traverse',
+    'tinymce.core.caret.CaretFinder',
+    'tinymce.core.caret.CaretPosition',
+    'tinymce.core.delete.DeleteUtils',
+    'tinymce.core.dom.Empty',
+    'tinymce.core.dom.NodeType'
+  ],
+  function (Arr, Fun, Option, Options, Struct, Compare, Element, Node, PredicateFind, Traverse, CaretFinder, CaretPosition, DeleteUtils, Empty, NodeType) {
+    var BlockPosition = Struct.immutable('block', 'position');
+    var BlockBoundary = Struct.immutable('from', 'to');
+
+    var getBlockPosition = function (rootNode, pos) {
+      var rootElm = Element.fromDom(rootNode);
+      var containerElm = Element.fromDom(pos.container());
+      return DeleteUtils.getParentBlock(rootElm, containerElm).map(function (block) {
+        return BlockPosition(block, pos);
+      });
+    };
+
+    var isDifferentBlocks = function (blockBoundary) {
+      return Compare.eq(blockBoundary.from().block(), blockBoundary.to().block()) === false;
+    };
+
+    var hasSameParent = function (blockBoundary) {
+      return Traverse.parent(blockBoundary.from().block()).bind(function (parent1) {
+        return Traverse.parent(blockBoundary.to().block()).filter(function (parent2) {
+          return Compare.eq(parent1, parent2);
+        });
+      }).isSome();
+    };
+
+    var isEditable = function (blockBoundary) {
+      return NodeType.isContentEditableFalse(blockBoundary.from().block()) === false && NodeType.isContentEditableFalse(blockBoundary.to().block()) === false;
+    };
+
+    var skipLastBr = function (rootNode, forward, blockPosition) {
+      if (NodeType.isBr(blockPosition.position().getNode()) && Empty.isEmpty(blockPosition.block()) === false) {
+        return CaretFinder.positionIn(false, blockPosition.block().dom()).bind(function (lastPositionInBlock) {
+          if (lastPositionInBlock.isEqual(blockPosition.position())) {
+            return CaretFinder.fromPosition(forward, rootNode, lastPositionInBlock).bind(function (to) {
+              return getBlockPosition(rootNode, to);
+            });
+          } else {
+            return Option.some(blockPosition);
+          }
+        }).getOr(blockPosition);
+      } else {
+        return blockPosition;
+      }
+    };
+
+    var readFromRange = function (rootNode, forward, rng) {
+      var fromBlockPos = getBlockPosition(rootNode, CaretPosition.fromRangeStart(rng));
+      var toBlockPos = fromBlockPos.bind(function (blockPos) {
+        return CaretFinder.fromPosition(forward, rootNode, blockPos.position()).bind(function (to) {
+          return getBlockPosition(rootNode, to).map(function (blockPos) {
+            return skipLastBr(rootNode, forward, blockPos);
+          });
+        });
+      });
+
+      return Options.liftN([fromBlockPos, toBlockPos], BlockBoundary).filter(function (blockBoundary) {
+        return isDifferentBlocks(blockBoundary) && hasSameParent(blockBoundary) && isEditable(blockBoundary);
+      });
+    };
+
+    var read = function (rootNode, forward, rng) {
+      return rng.collapsed ? readFromRange(rootNode, forward, rng) : Option.none();
+    };
+
+    return {
+      read: read
+    };
+  }
+);
+
+/**
+ * MergeBlocks.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.delete.MergeBlocks',
+  [
+    'ephox.katamari.api.Arr',
+    'ephox.katamari.api.Option',
+    'ephox.sugar.api.dom.Compare',
+    'ephox.sugar.api.dom.Insert',
+    'ephox.sugar.api.dom.Remove',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.search.Traverse',
+    'tinymce.core.caret.CaretFinder',
+    'tinymce.core.caret.CaretPosition',
+    'tinymce.core.dom.ElementType',
+    'tinymce.core.dom.Empty',
+    'tinymce.core.dom.NodeType',
+    'tinymce.core.dom.Parents'
+  ],
+  function (Arr, Option, Compare, Insert, Remove, Element, Traverse, CaretFinder, CaretPosition, ElementType, Empty, NodeType, Parents) {
+    var getChildrenUntilBlockBoundary = function (block) {
+      var children = Traverse.children(block);
+      return Arr.findIndex(children, ElementType.isBlock).fold(
+        function () {
+          return children;
+        },
+        function (index) {
+          return children.slice(0, index);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      );
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        self.state.on('change:value', function (e) {
-          setValue(e.value);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var extractChildren = function (block) {
+      var children = getChildrenUntilBlockBoundary(block);
+
+      Arr.each(children, function (node) {
+        Remove.remove(node);
+      });
+
+      return children;
+    };
+
+    var trimBr = function (first, block) {
+      CaretFinder.positionIn(first, block.dom()).each(function (position) {
+        var node = position.getNode();
+        if (NodeType.isBr(node)) {
+          Remove.remove(Element.fromDom(node));
+        }
+      });
+    };
+
+    var removeEmptyRoot = function (rootNode, block) {
+      var parents = Parents.parentsAndSelf(block, rootNode);
+      return Arr.find(parents.reverse(), Empty.isEmpty).each(Remove.remove);
+    };
+
+    var findParentInsertPoint = function (toBlock, block) {
+      var parents = Traverse.parents(block, function (elm) {
+        return Compare.eq(elm, toBlock);
+      });
+
+      return Option.from(parents[parents.length - 2]);
+    };
+
+    var getInsertionPoint = function (fromBlock, toBlock) {
+      if (Compare.contains(toBlock, fromBlock)) {
+        return Traverse.parent(fromBlock).bind(function (parent) {
+          return Compare.eq(parent, toBlock) ? Option.some(fromBlock) : findParentInsertPoint(toBlock, fromBlock);
</ins><span class="cx" style="display: block; padding: 0 10px">         });
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      } else {
+        return Option.none();
+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        setValue(self.state.get('value'));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var mergeBlockInto = function (rootNode, fromBlock, toBlock) {
+      if (Empty.isEmpty(toBlock)) {
+        Remove.remove(toBlock);
+        return CaretFinder.firstPositionIn(fromBlock.dom());
+      } else {
+        trimBr(true, fromBlock);
+        trimBr(false, toBlock);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return self._super();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var children = extractChildren(fromBlock);
+
+        return getInsertionPoint(fromBlock, toBlock).fold(
+          function () {
+            removeEmptyRoot(rootNode, fromBlock);
+
+            var position = CaretFinder.lastPositionIn(toBlock.dom());
+
+            Arr.each(children, function (node) {
+              Insert.append(toBlock, node);
+            });
+
+            return position;
+          },
+          function (target) {
+            var position = CaretFinder.prevPosition(toBlock.dom(), CaretPosition.before(target.dom()));
+
+            Arr.each(children, function (node) {
+              Insert.before(target, node);
+            });
+
+            removeEmptyRoot(rootNode, fromBlock);
+
+            return position;
+          }
+        );
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    };
+
+    var mergeBlocks = function (rootNode, forward, block1, block2) {
+      return forward ? mergeBlockInto(rootNode, block2, block1) : mergeBlockInto(rootNode, block1, block2);
+    };
+
+    return {
+      mergeBlocks: mergeBlocks
+    };
</ins><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Notification.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * BlockBoundaryDelete.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -37361,159 +34904,1962 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Contributing: http://www.tinymce.com/contributing
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+define(
+  'tinymce.core.delete.BlockBoundaryDelete',
+  [
+    'ephox.sugar.api.node.Element',
+    'tinymce.core.delete.BlockBoundary',
+    'tinymce.core.delete.MergeBlocks'
+  ],
+  function (Element, BlockBoundary, MergeBlocks) {
+    var backspaceDelete = function (editor, forward) {
+      var position, rootNode = Element.fromDom(editor.getBody());
+
+      position = BlockBoundary.read(rootNode.dom(), forward, editor.selection.getRng()).bind(function (blockBoundary) {
+        return MergeBlocks.mergeBlocks(rootNode, forward, blockBoundary.from().block(), blockBoundary.to().block());
+      });
+
+      position.each(function (pos) {
+        editor.selection.setRng(pos.toRange());
+      });
+
+      return position.isSome();
+    };
+
+    return {
+      backspaceDelete: backspaceDelete
+    };
+  }
+);
+
</ins><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Creates a notification instance.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * BlockRangeDelete.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @-x-less Notification.less
- * @class tinymce.ui.Notification
- * @extends tinymce.ui.Container
- * @mixes tinymce.ui.Movable
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.ui.Notification',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.delete.BlockRangeDelete',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    "tinymce.core.ui.Control",
-    "tinymce.core.ui.Movable",
-    "tinymce.core.ui.Progress",
-    "tinymce.core.util.Delay"
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.katamari.api.Options',
+    'ephox.sugar.api.dom.Compare',
+    'ephox.sugar.api.node.Element',
+    'tinymce.core.caret.CaretFinder',
+    'tinymce.core.caret.CaretPosition',
+    'tinymce.core.delete.DeleteUtils',
+    'tinymce.core.delete.MergeBlocks'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Control, Movable, Progress, Delay) {
-    return Control.extend({
-      Mixins: [Movable],
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Options, Compare, Element, CaretFinder, CaretPosition, DeleteUtils, MergeBlocks) {
+    var deleteRangeMergeBlocks = function (rootNode, selection) {
+      var rng = selection.getRng();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      Defaults: {
-        classes: 'widget notification'
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return Options.liftN([
+        DeleteUtils.getParentBlock(rootNode, Element.fromDom(rng.startContainer)),
+        DeleteUtils.getParentBlock(rootNode, Element.fromDom(rng.endContainer))
+      ], function (block1, block2) {
+        if (Compare.eq(block1, block2) === false) {
+          rng.deleteContents();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      init: function (settings) {
-        var self = this;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          MergeBlocks.mergeBlocks(rootNode, true, block1, block2).each(function (pos) {
+            selection.setRng(pos.toRange());
+          });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        self._super(settings);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          return true;
+        } else {
+          return false;
+        }
+      }).getOr(false);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (settings.text) {
-          self.text(settings.text);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isEverythingSelected = function (rootNode, rng) {
+      var noPrevious = CaretFinder.prevPosition(rootNode.dom(), CaretPosition.fromRangeStart(rng)).isNone();
+      var noNext = CaretFinder.nextPosition(rootNode.dom(), CaretPosition.fromRangeEnd(rng)).isNone();
+      return noPrevious && noNext;
+    };
+
+    var emptyEditor = function (editor) {
+      editor.setContent('');
+      editor.selection.setCursorLocation();
+      return true;
+    };
+
+    var deleteRange = function (editor) {
+      var rootNode = Element.fromDom(editor.getBody());
+      var rng = editor.selection.getRng();
+      return isEverythingSelected(rootNode, rng) ? emptyEditor(editor) : deleteRangeMergeBlocks(rootNode, editor.selection);
+    };
+
+    var backspaceDelete = function (editor, forward) {
+      return editor.selection.isCollapsed() ? false : deleteRange(editor, editor.selection.getRng());
+    };
+
+    return {
+      backspaceDelete: backspaceDelete
+    };
+  }
+);
+
+define(
+  'ephox.katamari.api.Adt',
+
+  [
+    'ephox.katamari.api.Arr',
+    'ephox.katamari.api.Obj',
+    'ephox.katamari.api.Type',
+    'global!Array',
+    'global!Error',
+    'global!console'
+  ],
+
+  function (Arr, Obj, Type, Array, Error, console) {
+    /*
+     * Generates a church encoded ADT (https://en.wikipedia.org/wiki/Church_encoding)
+     * For syntax and use, look at the test code.
+     */
+    var generate = function (cases) {
+      // validation
+      if (!Type.isArray(cases)) {
+        throw new Error('cases must be an array');
+      }
+      if (cases.length === 0) {
+        throw new Error('there must be at least one case');
+      }
+
+      var constructors = [ ];
+
+      // adt is mutated to add the individual cases
+      var adt = {};
+      Arr.each(cases, function (acase, count) {
+        var keys = Obj.keys(acase);
+
+        // validation
+        if (keys.length !== 1) {
+          throw new Error('one and only one name per case');
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (settings.icon) {
-          self.icon = settings.icon;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var key = keys[0];
+        var value = acase[key];
+
+        // validation
+        if (adt[key] !== undefined) {
+          throw new Error('duplicate key detected:' + key);
+        } else if (key === 'cata') {
+          throw new Error('cannot have a case named cata (sorry)');
+        } else if (!Type.isArray(value)) {
+          // this implicitly checks if acase is an object
+          throw new Error('case arguments must be an array');
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (settings.color) {
-          self.color = settings.color;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        constructors.push(key);
+        //
+        // constructor for key
+        //
+        adt[key] = function () {
+          var argLength = arguments.length;
+
+          // validation
+          if (argLength !== value.length) {
+            throw new Error('Wrong number of arguments to case ' + key + '. Expected ' + value.length + ' (' + value + '), got ' + argLength);
+          }
+
+          // Don't use array slice(arguments), makes the whole function unoptimisable on Chrome
+          var args = new Array(argLength);
+          for (var i = 0; i < args.length; i++) args[i] = arguments[i];
+
+
+          var match = function (branches) {
+            var branchKeys = Obj.keys(branches);
+            if (constructors.length !== branchKeys.length) {
+              throw new Error('Wrong number of arguments to match. Expected: ' + constructors.join(',') + '\nActual: ' + branchKeys.join(','));
+            }
+
+            var allReqd = Arr.forall(constructors, function (reqKey) {
+              return Arr.contains(branchKeys, reqKey);
+            });
+
+            if (!allReqd) throw new Error('Not all branches were specified when using match. Specified: ' + branchKeys.join(', ') + '\nRequired: ' + constructors.join(', '));
+
+            return branches[key].apply(null, args);
+          };
+
+          //
+          // the fold function for key
+          //
+          return {
+            fold: function (/* arguments */) {
+              // runtime validation
+              if (arguments.length !== cases.length) {
+                throw new Error('Wrong number of arguments to fold. Expected ' + cases.length + ', got ' + arguments.length);
+              }
+              var target = arguments[count];
+              return target.apply(null, args);
+            },
+            match: match,
+
+            // NOTE: Only for debugging.
+            log: function (label) {
+              console.log(label, {
+                constructors: constructors,
+                constructor: key,
+                params: args
+              });
+            }
+          };
+        };
+      });
+
+      return adt;
+    };
+    return {
+      generate: generate
+    };
+  }
+);
+/**
+ * CefDeleteAction.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.delete.CefDeleteAction',
+  [
+    'ephox.katamari.api.Adt',
+    'ephox.katamari.api.Option',
+    'ephox.sugar.api.node.Element',
+    'tinymce.core.caret.CaretFinder',
+    'tinymce.core.caret.CaretPosition',
+    'tinymce.core.caret.CaretUtils',
+    'tinymce.core.delete.DeleteUtils',
+    'tinymce.core.dom.Empty',
+    'tinymce.core.dom.NodeType'
+  ],
+  function (Adt, Option, Element, CaretFinder, CaretPosition, CaretUtils, DeleteUtils, Empty, NodeType) {
+    var DeleteAction = Adt.generate([
+      { remove: [ 'element' ] },
+      { moveToElement: [ 'element' ] },
+      { moveToPosition: [ 'position' ] }
+    ]);
+
+    var isAtContentEditableBlockCaret = function (forward, from) {
+      var elm = from.getNode(forward === false);
+      var caretLocation = forward ? 'after' : 'before';
+      return NodeType.isElement(elm) && elm.getAttribute('data-mce-caret') === caretLocation;
+    };
+
+    var deleteEmptyBlockOrMoveToCef = function (rootNode, forward, from, to) {
+      var toCefElm = to.getNode(forward === false);
+      return DeleteUtils.getParentBlock(Element.fromDom(rootNode), Element.fromDom(from.getNode())).map(function (blockElm) {
+        return Empty.isEmpty(blockElm) ? DeleteAction.remove(blockElm.dom()) : DeleteAction.moveToElement(toCefElm);
+      }).orThunk(function () {
+        return Option.some(DeleteAction.moveToElement(toCefElm));
+      });
+    };
+
+    var findCefPosition = function (rootNode, forward, from) {
+      return CaretFinder.fromPosition(forward, rootNode, from).bind(function (to) {
+        if (forward && NodeType.isContentEditableFalse(to.getNode())) {
+          return deleteEmptyBlockOrMoveToCef(rootNode, forward, from, to);
+        } else if (forward === false && NodeType.isContentEditableFalse(to.getNode(true))) {
+          return deleteEmptyBlockOrMoveToCef(rootNode, forward, from, to);
+        } else if (forward && CaretUtils.isAfterContentEditableFalse(from)) {
+          return Option.some(DeleteAction.moveToPosition(to));
+        } else if (forward === false && CaretUtils.isBeforeContentEditableFalse(from)) {
+          return Option.some(DeleteAction.moveToPosition(to));
+        } else {
+          return Option.none();
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      });
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (settings.type) {
-          self.classes.add('notification-' + settings.type);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var getContentEditableBlockAction = function (forward, elm) {
+      if (forward && NodeType.isContentEditableFalse(elm.nextSibling)) {
+        return Option.some(DeleteAction.moveToElement(elm.nextSibling));
+      } else if (forward === false && NodeType.isContentEditableFalse(elm.previousSibling)) {
+        return Option.some(DeleteAction.moveToElement(elm.previousSibling));
+      } else {
+        return Option.none();
+      }
+    };
+
+    var getContentEditableAction = function (rootNode, forward, from) {
+      if (isAtContentEditableBlockCaret(forward, from)) {
+        return getContentEditableBlockAction(forward, from.getNode(forward === false))
+          .fold(
+            function () {
+              return findCefPosition(rootNode, forward, from);
+            },
+            Option.some
+          );
+      } else {
+        return findCefPosition(rootNode, forward, from);
+      }
+    };
+
+    var read = function (rootNode, forward, rng) {
+      var normalizedRange = CaretUtils.normalizeRange(forward ? 1 : -1, rootNode, rng);
+      var from = CaretPosition.fromRangeStart(normalizedRange);
+
+      if (forward === false && CaretUtils.isAfterContentEditableFalse(from)) {
+        return Option.some(DeleteAction.remove(from.getNode(true)));
+      } else if (forward && CaretUtils.isBeforeContentEditableFalse(from)) {
+        return Option.some(DeleteAction.remove(from.getNode()));
+      } else {
+        return getContentEditableAction(rootNode, forward, from);
+      }
+    };
+
+    return {
+      read: read
+    };
+  }
+);
+
+/**
+ * DeleteElement.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.delete.DeleteElement',
+  [
+    'ephox.katamari.api.Fun',
+    'ephox.katamari.api.Option',
+    'ephox.katamari.api.Options',
+    'ephox.sugar.api.dom.Insert',
+    'ephox.sugar.api.dom.Remove',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.node.Node',
+    'ephox.sugar.api.search.PredicateFind',
+    'ephox.sugar.api.search.Traverse',
+    'tinymce.core.caret.CaretCandidate',
+    'tinymce.core.caret.CaretFinder',
+    'tinymce.core.caret.CaretPosition',
+    'tinymce.core.dom.Empty',
+    'tinymce.core.dom.NodeType'
+  ],
+  function (Fun, Option, Options, Insert, Remove, Element, Node, PredicateFind, Traverse, CaretCandidate, CaretFinder, CaretPosition, Empty, NodeType) {
+    var needsReposition = function (pos, elm) {
+      var container = pos.container();
+      var offset = pos.offset();
+      return CaretPosition.isTextPosition(pos) === false && container === elm.parentNode && offset > CaretPosition.before(elm).offset();
+    };
+
+    var reposition = function (elm, pos) {
+      return needsReposition(pos, elm) ? new CaretPosition(pos.container(), pos.offset() - 1) : pos;
+    };
+
+    var beforeOrStartOf = function (node) {
+      return NodeType.isText(node) ? new CaretPosition(node, 0) : CaretPosition.before(node);
+    };
+
+    var afterOrEndOf = function (node) {
+      return NodeType.isText(node) ? new CaretPosition(node, node.data.length) : CaretPosition.after(node);
+    };
+
+    var getPreviousSiblingCaretPosition = function (elm) {
+      if (CaretCandidate.isCaretCandidate(elm.previousSibling)) {
+        return Option.some(afterOrEndOf(elm.previousSibling));
+      } else {
+        return elm.previousSibling ? CaretFinder.lastPositionIn(elm.previousSibling) : Option.none();
+      }
+    };
+
+    var getNextSiblingCaretPosition = function (elm) {
+      if (CaretCandidate.isCaretCandidate(elm.nextSibling)) {
+        return Option.some(beforeOrStartOf(elm.nextSibling));
+      } else {
+        return elm.nextSibling ? CaretFinder.firstPositionIn(elm.nextSibling) : Option.none();
+      }
+    };
+
+    var findCaretPositionBackwardsFromElm = function (rootElement, elm) {
+      var startPosition = CaretPosition.before(elm.previousSibling ? elm.previousSibling : elm.parentNode);
+      return CaretFinder.prevPosition(rootElement, startPosition).fold(
+        function () {
+          return CaretFinder.nextPosition(rootElement, CaretPosition.after(elm));
+        },
+        Option.some
+      );
+    };
+
+    var findCaretPositionForwardsFromElm = function (rootElement, elm) {
+      return CaretFinder.nextPosition(rootElement, CaretPosition.after(elm)).fold(
+        function () {
+          return CaretFinder.prevPosition(rootElement, CaretPosition.before(elm));
+        },
+        Option.some
+      );
+    };
+
+    var findCaretPositionBackwards = function (rootElement, elm) {
+      return getPreviousSiblingCaretPosition(elm).orThunk(function () {
+        return getNextSiblingCaretPosition(elm);
+      }).orThunk(function () {
+        return findCaretPositionBackwardsFromElm(rootElement, elm);
+      });
+    };
+
+    var findCaretPositionForward = function (rootElement, elm) {
+      return getNextSiblingCaretPosition(elm).orThunk(function () {
+        return getPreviousSiblingCaretPosition(elm);
+      }).orThunk(function () {
+        return findCaretPositionForwardsFromElm(rootElement, elm);
+      });
+    };
+
+    var findCaretPosition = function (forward, rootElement, elm) {
+      return forward ? findCaretPositionForward(rootElement, elm) : findCaretPositionBackwards(rootElement, elm);
+    };
+
+    var findCaretPosOutsideElmAfterDelete = function (forward, rootElement, elm) {
+      return findCaretPosition(forward, rootElement, elm).map(Fun.curry(reposition, elm));
+    };
+
+    var setSelection = function (editor, forward, pos) {
+      pos.fold(
+        function () {
+          editor.focus();
+        },
+        function (pos) {
+          editor.selection.setRng(pos.toRange(), forward);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      );
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (settings.timeout && (settings.timeout < 0 || settings.timeout > 0) && !settings.closeButton) {
-          self.closeButton = false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var eqRawNode = function (rawNode) {
+      return function (elm) {
+        return elm.dom() === rawNode;
+      };
+    };
+
+    var isBlock = function (editor, elm) {
+      return elm && editor.schema.getBlockElements().hasOwnProperty(Node.name(elm));
+    };
+
+    var paddEmptyBlock = function (elm) {
+      if (Empty.isEmpty(elm)) {
+        var br = Element.fromHtml('<br data-mce-bogus="1">');
+        Remove.empty(elm);
+        Insert.append(elm, br);
+        return Option.some(CaretPosition.before(br.dom()));
+      } else {
+        return Option.none();
+      }
+    };
+
+    // When deleting an element between two text nodes IE 11 doesn't automatically merge the adjacent text nodes
+    var deleteNormalized = function (elm, afterDeletePosOpt) {
+      return Options.liftN([Traverse.prevSibling(elm), Traverse.nextSibling(elm), afterDeletePosOpt], function (prev, next, afterDeletePos) {
+        var offset, prevNode = prev.dom(), nextNode = next.dom();
+
+        if (NodeType.isText(prevNode) && NodeType.isText(nextNode)) {
+          offset = prevNode.data.length;
+          prevNode.appendData(nextNode.data);
+          Remove.remove(next);
+          Remove.remove(elm);
+          if (afterDeletePos.container() === nextNode) {
+            return new CaretPosition(prevNode, offset);
+          } else {
+            return afterDeletePos;
+          }
</ins><span class="cx" style="display: block; padding: 0 10px">         } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          self.classes.add('has-close');
-          self.closeButton = true;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          Remove.remove(elm);
+          return afterDeletePos;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }).orThunk(function () {
+        Remove.remove(elm);
+        return afterDeletePosOpt;
+      });
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (settings.progressBar) {
-          self.progressBar = new Progress();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var deleteElement = function (editor, forward, elm) {
+      var afterDeletePos = findCaretPosOutsideElmAfterDelete(forward, editor.getBody(), elm.dom());
+      var parentBlock = PredicateFind.ancestor(elm, Fun.curry(isBlock, editor), eqRawNode(editor.getBody()));
+      var normalizedAfterDeletePos = deleteNormalized(elm, afterDeletePos);
+
+      parentBlock.bind(paddEmptyBlock).fold(
+        function () {
+          setSelection(editor, forward, normalizedAfterDeletePos);
+        },
+        function (paddPos) {
+          setSelection(editor, forward, Option.some(paddPos));
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      );
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        self.on('click', function (e) {
-          if (e.target.className.indexOf(self.classPrefix + 'close') != -1) {
-            self.close();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return {
+      deleteElement: deleteElement
+    };
+  }
+);
+/**
+ * CefDelete.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.delete.CefDelete',
+  [
+    'ephox.katamari.api.Arr',
+    'ephox.sugar.api.dom.Remove',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.search.SelectorFilter',
+    'tinymce.core.caret.CaretPosition',
+    'tinymce.core.delete.CefDeleteAction',
+    'tinymce.core.delete.DeleteElement',
+    'tinymce.core.delete.DeleteUtils',
+    'tinymce.core.dom.NodeType'
+  ],
+  function (Arr, Remove, Element, SelectorFilter, CaretPosition, CefDeleteAction, DeleteElement, DeleteUtils, NodeType) {
+    var deleteElement = function (editor, forward) {
+      return function (element) {
+        DeleteElement.deleteElement(editor, forward, Element.fromDom(element));
+        return true;
+      };
+    };
+
+    var moveToElement = function (editor, forward) {
+      return function (element) {
+        var pos = forward ? CaretPosition.before(element) : CaretPosition.after(element);
+        editor.selection.setRng(pos.toRange());
+        return true;
+      };
+    };
+
+    var moveToPosition = function (editor) {
+      return function (pos) {
+        editor.selection.setRng(pos.toRange());
+        return true;
+      };
+    };
+
+    var backspaceDeleteCaret = function (editor, forward) {
+      var result = CefDeleteAction.read(editor.getBody(), forward, editor.selection.getRng()).map(function (deleteAction) {
+        return deleteAction.fold(
+          deleteElement(editor, forward),
+          moveToElement(editor, forward),
+          moveToPosition(editor)
+        );
+      });
+
+      return result.getOr(false);
+    };
+
+    var deleteOffscreenSelection = function (rootElement) {
+      Arr.each(SelectorFilter.descendants(rootElement, '.mce-offscreen-selection'), Remove.remove);
+    };
+
+    var backspaceDeleteRange = function (editor, forward) {
+      var selectedElement = editor.selection.getNode();
+      if (NodeType.isContentEditableFalse(selectedElement)) {
+        deleteOffscreenSelection(Element.fromDom(editor.getBody()));
+        DeleteElement.deleteElement(editor, forward, Element.fromDom(editor.selection.getNode()));
+        DeleteUtils.paddEmptyBody(editor);
+        return true;
+      } else {
+        return false;
+      }
+    };
+
+    var getContentEditableRoot = function (root, node) {
+      while (node && node !== root) {
+        if (NodeType.isContentEditableTrue(node) || NodeType.isContentEditableFalse(node)) {
+          return node;
+        }
+
+        node = node.parentNode;
+      }
+
+      return null;
+    };
+
+    var paddEmptyElement = function (editor) {
+      var br, ceRoot = getContentEditableRoot(editor.getBody(), editor.selection.getNode());
+
+      if (NodeType.isContentEditableTrue(ceRoot) && editor.dom.isBlock(ceRoot) && editor.dom.isEmpty(ceRoot)) {
+        br = editor.dom.create('br', { "data-mce-bogus": "1" });
+        editor.dom.setHTML(ceRoot, '');
+        ceRoot.appendChild(br);
+        editor.selection.setRng(CaretPosition.before(br).toRange());
+      }
+
+      return true;
+    };
+
+    var backspaceDelete = function (editor, forward) {
+      if (editor.selection.isCollapsed()) {
+        return backspaceDeleteCaret(editor, forward);
+      } else {
+        return backspaceDeleteRange(editor, forward);
+      }
+    };
+
+    return {
+      backspaceDelete: backspaceDelete,
+      paddEmptyElement: paddEmptyElement
+    };
+  }
+);
+
+/**
+ * CaretContainerInline.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.caret.CaretContainerInline',
+  [
+    'ephox.katamari.api.Fun',
+    'tinymce.core.dom.NodeType',
+    'tinymce.core.text.Zwsp'
+  ],
+  function (Fun, NodeType, Zwsp) {
+    var isText = NodeType.isText;
+
+    var startsWithCaretContainer = function (node) {
+      return isText(node) && node.data[0] === Zwsp.ZWSP;
+    };
+
+    var endsWithCaretContainer = function (node) {
+      return isText(node) && node.data[node.data.length - 1] === Zwsp.ZWSP;
+    };
+
+    var createZwsp = function (node) {
+      return node.ownerDocument.createTextNode(Zwsp.ZWSP);
+    };
+
+    var insertBefore = function (node) {
+      if (isText(node.previousSibling)) {
+        if (endsWithCaretContainer(node.previousSibling)) {
+          return node.previousSibling;
+        } else {
+          node.previousSibling.appendData(Zwsp.ZWSP);
+          return node.previousSibling;
+        }
+      } else if (isText(node)) {
+        if (startsWithCaretContainer(node)) {
+          return node;
+        } else {
+          node.insertData(0, Zwsp.ZWSP);
+          return node;
+        }
+      } else {
+        var newNode = createZwsp(node);
+        node.parentNode.insertBefore(newNode, node);
+        return newNode;
+      }
+    };
+
+    var insertAfter = function (node) {
+      if (isText(node.nextSibling)) {
+        if (startsWithCaretContainer(node.nextSibling)) {
+          return node.nextSibling;
+        } else {
+          node.nextSibling.insertData(0, Zwsp.ZWSP);
+          return node.nextSibling;
+        }
+      } else if (isText(node)) {
+        if (endsWithCaretContainer(node)) {
+          return node;
+        } else {
+          node.appendData(Zwsp.ZWSP);
+          return node;
+        }
+      } else {
+        var newNode = createZwsp(node);
+        if (node.nextSibling) {
+          node.parentNode.insertBefore(newNode, node.nextSibling);
+        } else {
+          node.parentNode.appendChild(newNode);
+        }
+        return newNode;
+      }
+    };
+
+    var insertInline = function (before, node) {
+      return before ? insertBefore(node) : insertAfter(node);
+    };
+
+    return {
+      insertInline: insertInline,
+      insertInlineBefore: Fun.curry(insertInline, true),
+      insertInlineAfter: Fun.curry(insertInline, false)
+    };
+  }
+);
+/**
+ * CaretContainerRemove.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.caret.CaretContainerRemove',
+  [
+    'ephox.katamari.api.Arr',
+    'tinymce.core.caret.CaretContainer',
+    'tinymce.core.caret.CaretPosition',
+    'tinymce.core.dom.NodeType',
+    'tinymce.core.text.Zwsp',
+    'tinymce.core.util.Tools'
+  ],
+  function (Arr, CaretContainer, CaretPosition, NodeType, Zwsp, Tools) {
+    var isElement = NodeType.isElement;
+    var isText = NodeType.isText;
+
+    var removeNode = function (node) {
+      var parentNode = node.parentNode;
+      if (parentNode) {
+        parentNode.removeChild(node);
+      }
+    };
+
+    var getNodeValue = function (node) {
+      try {
+        return node.nodeValue;
+      } catch (ex) {
+        // IE sometimes produces "Invalid argument" on nodes
+        return "";
+      }
+    };
+
+    var setNodeValue = function (node, text) {
+      if (text.length === 0) {
+        removeNode(node);
+      } else {
+        node.nodeValue = text;
+      }
+    };
+
+    var trimCount = function (text) {
+      var trimmedText = Zwsp.trim(text);
+      return { count: text.length - trimmedText.length, text: trimmedText };
+    };
+
+    var removeUnchanged = function (caretContainer, pos) {
+      remove(caretContainer);
+      return pos;
+    };
+
+    var removeTextAndReposition = function (caretContainer, pos) {
+      var before = trimCount(caretContainer.data.substr(0, pos.offset()));
+      var after = trimCount(caretContainer.data.substr(pos.offset()));
+      var text = before.text + after.text;
+
+      if (text.length > 0) {
+        setNodeValue(caretContainer, text);
+        return new CaretPosition(caretContainer, pos.offset() - before.count);
+      } else {
+        return pos;
+      }
+    };
+
+    var removeElementAndReposition = function (caretContainer, pos) {
+      var parentNode = pos.container();
+      var newPosition = Arr.indexOf(parentNode.childNodes, caretContainer).map(function (index) {
+        return index < pos.offset() ? new CaretPosition(parentNode, pos.offset() - 1) : pos;
+      }).getOr(pos);
+      remove(caretContainer);
+      return newPosition;
+    };
+
+    var removeTextCaretContainer = function (caretContainer, pos) {
+      return pos.container() === caretContainer ? removeTextAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
+    };
+
+    var removeElementCaretContainer = function (caretContainer, pos) {
+      return pos.container() === caretContainer.parentNode ? removeElementAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
+    };
+
+    var removeAndReposition = function (container, pos) {
+      return CaretPosition.isTextPosition(pos) ? removeTextCaretContainer(container, pos) : removeElementCaretContainer(container, pos);
+    };
+
+    var remove = function (caretContainerNode) {
+      if (isElement(caretContainerNode) && CaretContainer.isCaretContainer(caretContainerNode)) {
+        if (CaretContainer.hasContent(caretContainerNode)) {
+          caretContainerNode.removeAttribute('data-mce-caret');
+        } else {
+          removeNode(caretContainerNode);
+        }
+      }
+
+      if (isText(caretContainerNode)) {
+        var text = Zwsp.trim(getNodeValue(caretContainerNode));
+        setNodeValue(caretContainerNode, text);
+      }
+    };
+
+    return {
+      removeAndReposition: removeAndReposition,
+      remove: remove
+    };
+  }
+);
+/**
+ * DefaultSettings.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.EditorSettings',
+  [
+    'ephox.katamari.api.Arr',
+    'ephox.katamari.api.Fun',
+    'ephox.katamari.api.Obj',
+    'ephox.katamari.api.Option',
+    'ephox.katamari.api.Strings',
+    'ephox.katamari.api.Struct',
+    'ephox.katamari.api.Type',
+    'ephox.sand.api.PlatformDetection',
+    'tinymce.core.util.Tools'
+  ],
+  function (Arr, Fun, Obj, Option, Strings, Struct, Type, PlatformDetection, Tools) {
+    var sectionResult = Struct.immutable('sections', 'settings');
+    var detection = PlatformDetection.detect();
+    var isTouch = detection.deviceType.isTouch();
+    var mobilePlugins = [ 'lists', 'autolink', 'autosave' ];
+
+    var normalizePlugins = function (plugins) {
+      return Type.isArray(plugins) ? plugins.join(' ') : plugins;
+    };
+
+    var filterMobilePlugins = function (plugins) {
+      var trimmedPlugins = Arr.map(normalizePlugins(plugins).split(' '), Strings.trim);
+      return Arr.filter(trimmedPlugins, Fun.curry(Arr.contains, mobilePlugins)).join(' ');
+    };
+
+    var extractSections = function (keys, settings) {
+      var result = Obj.bifilter(settings, function (value, key) {
+        return Arr.contains(keys, key);
+      });
+
+      return sectionResult(result.t, result.f);
+    };
+
+    var getSection = function (sectionResult, name) {
+      var sections = sectionResult.sections();
+      return sections.hasOwnProperty(name) ? sections[name] : { };
+    };
+
+    var hasSection = function (sectionResult, name) {
+      return sectionResult.sections().hasOwnProperty(name);
+    };
+
+    var getDefaultSettings = function (id, documentBaseUrl, editor) {
+      return {
+        id: id,
+        theme: 'modern',
+        delta_width: 0,
+        delta_height: 0,
+        popup_css: '',
+        plugins: '',
+        document_base_url: documentBaseUrl,
+        add_form_submit_trigger: true,
+        submit_patch: true,
+        add_unload_trigger: true,
+        convert_urls: true,
+        relative_urls: true,
+        remove_script_host: true,
+        object_resizing: true,
+        doctype: '<!DOCTYPE html>',
+        visual: true,
+        font_size_style_values: 'xx-small,x-small,small,medium,large,x-large,xx-large',
+
+        // See: http://www.w3.org/TR/CSS2/fonts.html#propdef-font-size
+        font_size_legacy_values: 'xx-small,small,medium,large,x-large,xx-large,300%',
+        forced_root_block: 'p',
+        hidden_input: true,
+        padd_empty_editor: true,
+        render_ui: true,
+        indentation: '30px',
+        inline_styles: true,
+        convert_fonts_to_spans: true,
+        indent: 'simple',
+        indent_before: 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,' +
+        'tfoot,tbody,tr,section,article,hgroup,aside,figure,figcaption,option,optgroup,datalist',
+        indent_after: 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,' +
+        'tfoot,tbody,tr,section,article,hgroup,aside,figure,figcaption,option,optgroup,datalist',
+        entity_encoding: 'named',
+        url_converter: editor.convertURL,
+        url_converter_scope: editor,
+        ie7_compat: true
+      };
+    };
+
+    var getExternalPlugins = function (overrideSettings, settings) {
+      var userDefinedExternalPlugins = settings.external_plugins ? settings.external_plugins : { };
+
+      if (overrideSettings && overrideSettings.external_plugins) {
+        return Tools.extend({}, overrideSettings.external_plugins, userDefinedExternalPlugins);
+      } else {
+        return userDefinedExternalPlugins;
+      }
+    };
+
+    var combineSettings = function (defaultSettings, defaultOverrideSettings, settings) {
+      var sectionResult = extractSections(['mobile'], settings);
+      var plugins = sectionResult.settings().plugins;
+
+      var extendedSettings = Tools.extend(
+        // Default settings
+        defaultSettings,
+
+        // tinymce.overrideDefaults settings
+        defaultOverrideSettings,
+
+        // User settings
+        sectionResult.settings(),
+
+        // Sections
+        isTouch ? getSection(sectionResult, 'mobile') : { },
+
+        // Forced settings
+        {
+          validate: true,
+          content_editable: sectionResult.settings().inline,
+          external_plugins: getExternalPlugins(defaultOverrideSettings, sectionResult.settings())
+        },
+
+        // TODO: Remove this once we fix each plugin with a mobile version
+        isTouch && plugins && hasSection(sectionResult, 'mobile') ? { plugins: filterMobilePlugins(plugins) } : { }
+      );
+
+      return extendedSettings;
+    };
+
+    var getEditorSettings = function (editor, id, documentBaseUrl, defaultOverrideSettings, settings) {
+      var defaultSettings = getDefaultSettings(id, documentBaseUrl, editor);
+      return combineSettings(defaultSettings, defaultOverrideSettings, settings);
+    };
+
+    var get = function (editor, name) {
+      return Option.from(editor.settings[name]);
+    };
+
+    var getFiltered = function (predicate, editor, name) {
+      return Option.from(editor.settings[name]).filter(predicate);
+    };
+
+    return {
+      getEditorSettings: getEditorSettings,
+      get: get,
+      getString: Fun.curry(getFiltered, Type.isString),
+
+      // TODO: Remove this once we have proper mobile plugins
+      filterMobilePlugins: filterMobilePlugins
+    };
+  }
+);
+
+/**
+ * Bidi.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.text.Bidi',
+  [
+  ],
+  function () {
+    var strongRtl = /[\u0591-\u07FF\uFB1D-\uFDFF\uFE70-\uFEFC]/;
+
+    var hasStrongRtl = function (text) {
+      return strongRtl.test(text);
+    };
+
+    return {
+      hasStrongRtl: hasStrongRtl
+    };
+  }
+);
+/**
+ * InlineUtils.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.keyboard.InlineUtils',
+  [
+    'ephox.katamari.api.Arr',
+    'ephox.katamari.api.Fun',
+    'ephox.katamari.api.Option',
+    'ephox.katamari.api.Options',
+    'ephox.katamari.api.Type',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.search.Selectors',
+    'tinymce.core.caret.CaretContainer',
+    'tinymce.core.caret.CaretFinder',
+    'tinymce.core.caret.CaretPosition',
+    'tinymce.core.caret.CaretUtils',
+    'tinymce.core.caret.CaretWalker',
+    'tinymce.core.dom.DOMUtils',
+    'tinymce.core.dom.NodeType',
+    'tinymce.core.EditorSettings',
+    'tinymce.core.text.Bidi'
+  ],
+  function (
+    Arr, Fun, Option, Options, Type, Element, Selectors, CaretContainer, CaretFinder, CaretPosition, CaretUtils, CaretWalker, DOMUtils, NodeType, EditorSettings,
+    Bidi
+  ) {
+    var isInlineTarget = function (editor, elm) {
+      var selector = EditorSettings.getString(editor, 'inline_boundaries_selector').getOr('a[href],code');
+      return Selectors.is(Element.fromDom(elm), selector);
+    };
+
+    var isRtl = function (element) {
+      return DOMUtils.DOM.getStyle(element, 'direction', true) === 'rtl' || Bidi.hasStrongRtl(element.textContent);
+    };
+
+    var findInlineParents = function (isInlineTarget, rootNode, pos) {
+      return Arr.filter(DOMUtils.DOM.getParents(pos.container(), '*', rootNode), isInlineTarget);
+    };
+
+    var findRootInline = function (isInlineTarget, rootNode, pos) {
+      var parents = findInlineParents(isInlineTarget, rootNode, pos);
+      return Option.from(parents[parents.length - 1]);
+    };
+
+    var hasSameParentBlock = function (rootNode, node1, node2) {
+      var block1 = CaretUtils.getParentBlock(node1, rootNode);
+      var block2 = CaretUtils.getParentBlock(node2, rootNode);
+      return block1 && block1 === block2;
+    };
+
+    var isAtZwsp = function (pos) {
+      return CaretContainer.isBeforeInline(pos) || CaretContainer.isAfterInline(pos);
+    };
+
+    var normalizePosition = function (forward, pos) {
+      var container = pos.container(), offset = pos.offset();
+
+      if (forward) {
+        if (CaretContainer.isCaretContainerInline(container)) {
+          if (NodeType.isText(container.nextSibling)) {
+            return new CaretPosition(container.nextSibling, 0);
+          } else {
+            return CaretPosition.after(container);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        });
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        } else {
+          return CaretContainer.isBeforeInline(pos) ? new CaretPosition(container, offset + 1) : pos;
+        }
+      } else {
+        if (CaretContainer.isCaretContainerInline(container)) {
+          if (NodeType.isText(container.previousSibling)) {
+            return new CaretPosition(container.previousSibling, container.previousSibling.data.length);
+          } else {
+            return CaretPosition.before(container);
+          }
+        } else {
+          return CaretContainer.isAfterInline(pos) ? new CaretPosition(container, offset - 1) : pos;
+        }
+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Renders the control as a HTML string.
-       *
-       * @method renderHtml
-       * @return {String} HTML representing the control.
-       */
-      renderHtml: function () {
-        var self = this, prefix = self.classPrefix, icon = '', closeButton = '', progressBar = '', notificationStyle = '';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var normalizeForwards = Fun.curry(normalizePosition, true);
+    var normalizeBackwards = Fun.curry(normalizePosition, false);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (self.icon) {
-          icon = '<i class="' + prefix + 'ico' + ' ' + prefix + 'i-' + self.icon + '"></i>';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return {
+      isInlineTarget: isInlineTarget,
+      findRootInline: findRootInline,
+      isRtl: isRtl,
+      isAtZwsp: isAtZwsp,
+      normalizePosition: normalizePosition,
+      normalizeForwards: normalizeForwards,
+      normalizeBackwards: normalizeBackwards,
+      hasSameParentBlock: hasSameParentBlock
+    };
+  }
+);
+/**
+ * BoundaryCaret.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.keyboard.BoundaryCaret',
+  [
+    'ephox.katamari.api.Option',
+    'tinymce.core.caret.CaretContainer',
+    'tinymce.core.caret.CaretContainerInline',
+    'tinymce.core.caret.CaretContainerRemove',
+    'tinymce.core.caret.CaretFinder',
+    'tinymce.core.caret.CaretPosition',
+    'tinymce.core.dom.NodeType',
+    'tinymce.core.keyboard.InlineUtils'
+  ],
+  function (Option, CaretContainer, CaretContainerInline, CaretContainerRemove, CaretFinder, CaretPosition, NodeType, InlineUtils) {
+    var insertInlinePos = function (pos, before) {
+      if (NodeType.isText(pos.container())) {
+        return CaretContainerInline.insertInline(before, pos.container());
+      } else {
+        return CaretContainerInline.insertInline(before, pos.getNode());
+      }
+    };
+
+    var isPosCaretContainer = function (pos, caret) {
+      var caretNode = caret.get();
+      return caretNode && pos.container() === caretNode && CaretContainer.isCaretContainerInline(caretNode);
+    };
+
+    var renderCaret = function (caret, location) {
+      return location.fold(
+        function (element) { // Before
+          CaretContainerRemove.remove(caret.get());
+          var text = CaretContainerInline.insertInlineBefore(element);
+          caret.set(text);
+          return Option.some(new CaretPosition(text, text.length - 1));
+        },
+        function (element) { // Start
+          return CaretFinder.firstPositionIn(element).map(function (pos) {
+            if (!isPosCaretContainer(pos, caret)) {
+              CaretContainerRemove.remove(caret.get());
+              var text = insertInlinePos(pos, true);
+              caret.set(text);
+              return new CaretPosition(text, 1);
+            } else {
+              return new CaretPosition(caret.get(), 1);
+            }
+          });
+        },
+        function (element) { // End
+          return CaretFinder.lastPositionIn(element).map(function (pos) {
+            if (!isPosCaretContainer(pos, caret)) {
+              CaretContainerRemove.remove(caret.get());
+              var text = insertInlinePos(pos, false);
+              caret.set(text);
+              return new CaretPosition(text, text.length - 1);
+            } else {
+              return new CaretPosition(caret.get(), caret.get().length - 1);
+            }
+          });
+        },
+        function (element) { // After
+          CaretContainerRemove.remove(caret.get());
+          var text = CaretContainerInline.insertInlineAfter(element);
+          caret.set(text);
+          return Option.some(new CaretPosition(text, 1));
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      );
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (self.color) {
-          notificationStyle = ' style="background-color: ' + self.color + '"';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return {
+      renderCaret: renderCaret
+    };
+  }
+);
+/**
+ * LazyEvaluator.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.util.LazyEvaluator',
+  [
+    'ephox.katamari.api.Option'
+  ],
+  function (Option) {
+    var evaluateUntil = function (fns, args) {
+      for (var i = 0; i < fns.length; i++) {
+        var result = fns[i].apply(null, args);
+        if (result.isSome()) {
+          return result;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (self.closeButton) {
-          closeButton = '<button type="button" class="' + prefix + 'close" aria-hidden="true">\u00d7</button>';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return Option.none();
+    };
+
+    return {
+      evaluateUntil: evaluateUntil
+    };
+  }
+);
+/**
+ * BoundaryLocation.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.keyboard.BoundaryLocation',
+  [
+    'ephox.katamari.api.Adt',
+    'ephox.katamari.api.Fun',
+    'ephox.katamari.api.Option',
+    'ephox.katamari.api.Options',
+    'tinymce.core.caret.CaretContainer',
+    'tinymce.core.caret.CaretFinder',
+    'tinymce.core.caret.CaretPosition',
+    'tinymce.core.caret.CaretUtils',
+    'tinymce.core.dom.NodeType',
+    'tinymce.core.keyboard.InlineUtils',
+    'tinymce.core.util.LazyEvaluator'
+  ],
+  function (Adt, Fun, Option, Options, CaretContainer, CaretFinder, CaretPosition, CaretUtils, NodeType, InlineUtils, LazyEvaluator) {
+    var Location = Adt.generate([
+      { before: [ 'element' ] },
+      { start: [ 'element' ] },
+      { end: [ 'element' ] },
+      { after: [ 'element' ] }
+    ]);
+
+    var rescope = function (rootNode, node) {
+      var parentBlock = CaretUtils.getParentBlock(node, rootNode);
+      return parentBlock ? parentBlock : rootNode;
+    };
+
+    var before = function (isInlineTarget, rootNode, pos) {
+      var nPos = InlineUtils.normalizeForwards(pos);
+      var scope = rescope(rootNode, nPos.container());
+      return InlineUtils.findRootInline(isInlineTarget, scope, nPos).fold(
+        function () {
+          return CaretFinder.nextPosition(scope, nPos)
+            .bind(Fun.curry(InlineUtils.findRootInline, isInlineTarget, scope))
+            .map(function (inline) {
+              return Location.before(inline);
+            });
+        },
+        Option.none
+      );
+    };
+
+    var start = function (isInlineTarget, rootNode, pos) {
+      var nPos = InlineUtils.normalizeBackwards(pos);
+      return InlineUtils.findRootInline(isInlineTarget, rootNode, nPos).bind(function (inline) {
+        var prevPos = CaretFinder.prevPosition(inline, nPos);
+        return prevPos.isNone() ? Option.some(Location.start(inline)) : Option.none();
+      });
+    };
+
+    var end = function (isInlineTarget, rootNode, pos) {
+      var nPos = InlineUtils.normalizeForwards(pos);
+      return InlineUtils.findRootInline(isInlineTarget, rootNode, nPos).bind(function (inline) {
+        var nextPos = CaretFinder.nextPosition(inline, nPos);
+        return nextPos.isNone() ? Option.some(Location.end(inline)) : Option.none();
+      });
+    };
+
+    var after = function (isInlineTarget, rootNode, pos) {
+      var nPos = InlineUtils.normalizeBackwards(pos);
+      var scope = rescope(rootNode, nPos.container());
+      return InlineUtils.findRootInline(isInlineTarget, scope, nPos).fold(
+        function () {
+          return CaretFinder.prevPosition(scope, nPos)
+            .bind(Fun.curry(InlineUtils.findRootInline, isInlineTarget, scope))
+            .map(function (inline) {
+              return Location.after(inline);
+            });
+        },
+        Option.none
+      );
+    };
+
+    var isValidLocation = function (location) {
+      return InlineUtils.isRtl(getElement(location)) === false;
+    };
+
+    var readLocation = function (isInlineTarget, rootNode, pos) {
+      var location = LazyEvaluator.evaluateUntil([
+        before,
+        start,
+        end,
+        after
+      ], [isInlineTarget, rootNode, pos]);
+
+      return location.filter(isValidLocation);
+    };
+
+    var getElement = function (location) {
+      return location.fold(
+        Fun.identity, // Before
+        Fun.identity, // Start
+        Fun.identity, // End
+        Fun.identity  // After
+      );
+    };
+
+    var getName = function (location) {
+      return location.fold(
+        Fun.constant('before'), // Before
+        Fun.constant('start'),  // Start
+        Fun.constant('end'),    // End
+        Fun.constant('after')   // After
+      );
+    };
+
+    var outside = function (location) {
+      return location.fold(
+        Location.before, // Before
+        Location.before, // Start
+        Location.after,  // End
+        Location.after   // After
+      );
+    };
+
+    var inside = function (location) {
+      return location.fold(
+        Location.start, // Before
+        Location.start, // Start
+        Location.end,   // End
+        Location.end    // After
+      );
+    };
+
+    var isEq = function (location1, location2) {
+      return getName(location1) === getName(location2) && getElement(location1) === getElement(location2);
+    };
+
+    var betweenInlines = function (forward, isInlineTarget, rootNode, from, to, location) {
+      return Options.liftN([
+        InlineUtils.findRootInline(isInlineTarget, rootNode, from),
+        InlineUtils.findRootInline(isInlineTarget, rootNode, to)
+      ], function (fromInline, toInline) {
+        if (fromInline !== toInline && InlineUtils.hasSameParentBlock(rootNode, fromInline, toInline)) {
+          // Force after since some browsers normalize and lean left into the closest inline
+          return Location.after(forward ? fromInline : toInline);
+        } else {
+          return location;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }).getOr(location);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (self.progressBar) {
-          progressBar = self.progressBar.renderHtml();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var skipNoMovement = function (fromLocation, toLocation) {
+      return fromLocation.fold(
+        Fun.constant(true),
+        function (fromLocation) {
+          return !isEq(fromLocation, toLocation);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      );
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return (
-          '<div id="' + self._id + '" class="' + self.classes + '"' + notificationStyle + ' role="presentation">' +
-          icon +
-          '<div class="' + prefix + 'notification-inner">' + self.state.get('text') + '</div>' +
-          progressBar +
-          closeButton +
-          '</div>'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var findLocationTraverse = function (forward, isInlineTarget, rootNode, fromLocation, pos) {
+      var from = InlineUtils.normalizePosition(forward, pos);
+      var to = CaretFinder.fromPosition(forward, rootNode, from).map(Fun.curry(InlineUtils.normalizePosition, forward));
+
+      var location = to.fold(
+        function () {
+          return fromLocation.map(outside);
+        },
+        function (to) {
+          return readLocation(isInlineTarget, rootNode, to)
+            .map(Fun.curry(betweenInlines, forward, isInlineTarget, rootNode, from, to))
+            .filter(Fun.curry(skipNoMovement, fromLocation));
+        }
+      );
+
+      return location.filter(isValidLocation);
+    };
+
+    var findLocationSimple = function (forward, location) {
+      if (forward) {
+        return location.fold(
+          Fun.compose(Option.some, Location.start), // Before -> Start
+          Option.none,
+          Fun.compose(Option.some, Location.after), // End -> After
+          Option.none
</ins><span class="cx" style="display: block; padding: 0 10px">         );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      } else {
+        return location.fold(
+          Option.none,
+          Fun.compose(Option.some, Location.before), // Before <- Start
+          Option.none,
+          Fun.compose(Option.some, Location.end) // End <- After
+        );
+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      postRender: function () {
-        var self = this;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var findLocation = function (forward, isInlineTarget, rootNode, pos) {
+      var from = InlineUtils.normalizePosition(forward, pos);
+      var fromLocation = readLocation(isInlineTarget, rootNode, from);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        Delay.setTimeout(function () {
-          self.$el.addClass(self.classPrefix + 'in');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return readLocation(isInlineTarget, rootNode, from).bind(Fun.curry(findLocationSimple, forward)).orThunk(function () {
+        return findLocationTraverse(forward, isInlineTarget, rootNode, fromLocation, pos);
+      });
+    };
+
+    return {
+      readLocation: readLocation,
+      findLocation: findLocation,
+      prevLocation: Fun.curry(findLocation, false),
+      nextLocation: Fun.curry(findLocation, true),
+      getElement: getElement,
+      outside: outside,
+      inside: inside
+    };
+  }
+);
+/**
+ * BoundarySelection.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.keyboard.BoundarySelection',
+  [
+    'ephox.katamari.api.Arr',
+    'ephox.katamari.api.Cell',
+    'ephox.katamari.api.Fun',
+    'tinymce.core.caret.CaretContainerRemove',
+    'tinymce.core.caret.CaretPosition',
+    'tinymce.core.keyboard.BoundaryCaret',
+    'tinymce.core.keyboard.BoundaryLocation',
+    'tinymce.core.keyboard.InlineUtils'
+  ],
+  function (Arr, Cell, Fun, CaretContainerRemove, CaretPosition, BoundaryCaret, BoundaryLocation, InlineUtils) {
+    var setCaretPosition = function (editor, pos) {
+      var rng = editor.dom.createRng();
+      rng.setStart(pos.container(), pos.offset());
+      rng.setEnd(pos.container(), pos.offset());
+      editor.selection.setRng(rng);
+    };
+
+    var isFeatureEnabled = function (editor) {
+      return editor.settings.inline_boundaries !== false;
+    };
+
+    var setSelected = function (state, elm) {
+      if (state) {
+        elm.setAttribute('data-mce-selected', '1');
+      } else {
+        elm.removeAttribute('data-mce-selected', '1');
+      }
+    };
+
+    var renderCaretLocation = function (editor, caret, location) {
+      return BoundaryCaret.renderCaret(caret, location).map(function (pos) {
+        setCaretPosition(editor, pos);
+        return location;
+      });
+    };
+
+    var findLocation = function (editor, caret, forward) {
+      var rootNode = editor.getBody();
+      var from = CaretPosition.fromRangeStart(editor.selection.getRng());
+      var isInlineTarget = Fun.curry(InlineUtils.isInlineTarget, editor);
+      var location = BoundaryLocation.findLocation(forward, isInlineTarget, rootNode, from);
+      return location.bind(function (location) {
+        return renderCaretLocation(editor, caret, location);
+      });
+    };
+
+    var toggleInlines = function (isInlineTarget, dom, elms) {
+      var selectedInlines = Arr.filter(dom.select('*[data-mce-selected]'), isInlineTarget);
+      var targetInlines = Arr.filter(elms, isInlineTarget);
+      Arr.each(Arr.difference(selectedInlines, targetInlines), Fun.curry(setSelected, false));
+      Arr.each(Arr.difference(targetInlines, selectedInlines), Fun.curry(setSelected, true));
+    };
+
+    var safeRemoveCaretContainer = function (editor, caret) {
+      if (editor.selection.isCollapsed() && editor.composing !== true && caret.get()) {
+        var pos = CaretPosition.fromRangeStart(editor.selection.getRng());
+        if (CaretPosition.isTextPosition(pos) && InlineUtils.isAtZwsp(pos) === false) {
+          setCaretPosition(editor, CaretContainerRemove.removeAndReposition(caret.get(), pos));
+          caret.set(null);
+        }
+      }
+    };
+
+    var renderInsideInlineCaret = function (isInlineTarget, editor, caret, elms) {
+      if (editor.selection.isCollapsed()) {
+        var inlines = Arr.filter(elms, isInlineTarget);
+        Arr.each(inlines, function (inline) {
+          var pos = CaretPosition.fromRangeStart(editor.selection.getRng());
+          BoundaryLocation.readLocation(isInlineTarget, editor.getBody(), pos).bind(function (location) {
+            return renderCaretLocation(editor, caret, location);
+          });
</ins><span class="cx" style="display: block; padding: 0 10px">         });
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return self._super();
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var move = function (editor, caret, forward) {
+      return function () {
+        return isFeatureEnabled(editor) ? findLocation(editor, caret, forward).isSome() : false;
+      };
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      bindStates: function () {
-        var self = this;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var setupSelectedState = function (editor) {
+      var caret = new Cell(null);
+      var isInlineTarget = Fun.curry(InlineUtils.isInlineTarget, editor);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        self.state.on('change:text', function (e) {
-          self.getEl().childNodes[1].innerHTML = e.value;
-        });
-        if (self.progressBar) {
-          self.progressBar.bindStates();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      editor.on('NodeChange', function (e) {
+        if (isFeatureEnabled(editor)) {
+          toggleInlines(isInlineTarget, editor.dom, e.parents);
+          safeRemoveCaretContainer(editor, caret);
+          renderInsideInlineCaret(isInlineTarget, editor, caret, e.parents);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return self._super();
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      close: function () {
-        var self = this;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return caret;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (!self.fire('close').isDefaultPrevented()) {
-          self.remove();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return {
+      move: move,
+      setupSelectedState: setupSelectedState,
+      setCaretPosition: setCaretPosition
+    };
+  }
+);
+/**
+ * InlineBoundaryDelete.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.delete.InlineBoundaryDelete',
+  [
+    'ephox.katamari.api.Fun',
+    'ephox.katamari.api.Option',
+    'ephox.katamari.api.Options',
+    'ephox.sugar.api.node.Element',
+    'tinymce.core.caret.CaretContainer',
+    'tinymce.core.caret.CaretFinder',
+    'tinymce.core.caret.CaretPosition',
+    'tinymce.core.caret.CaretUtils',
+    'tinymce.core.delete.DeleteElement',
+    'tinymce.core.keyboard.BoundaryCaret',
+    'tinymce.core.keyboard.BoundaryLocation',
+    'tinymce.core.keyboard.BoundarySelection',
+    'tinymce.core.keyboard.InlineUtils'
+  ],
+  function (
+    Fun, Option, Options, Element, CaretContainer, CaretFinder, CaretPosition, CaretUtils, DeleteElement, BoundaryCaret, BoundaryLocation, BoundarySelection,
+    InlineUtils
+  ) {
+    var isFeatureEnabled = function (editor) {
+      return editor.settings.inline_boundaries !== false;
+    };
+
+    var rangeFromPositions = function (from, to) {
+      var range = document.createRange();
+
+      range.setStart(from.container(), from.offset());
+      range.setEnd(to.container(), to.offset());
+
+      return range;
+    };
+
+    // Checks for delete at <code>|a</code> when there is only one item left except the zwsp caret container nodes
+    var hasOnlyTwoOrLessPositionsLeft = function (elm) {
+      return Options.liftN([
+        CaretFinder.firstPositionIn(elm),
+        CaretFinder.lastPositionIn(elm)
+      ], function (firstPos, lastPos) {
+        var normalizedFirstPos = InlineUtils.normalizePosition(true, firstPos);
+        var normalizedLastPos = InlineUtils.normalizePosition(false, lastPos);
+
+        return CaretFinder.nextPosition(elm, normalizedFirstPos).map(function (pos) {
+          return pos.isEqual(normalizedLastPos);
+        }).getOr(true);
+      }).getOr(true);
+    };
+
+    var setCaretLocation = function (editor, caret) {
+      return function (location) {
+        return BoundaryCaret.renderCaret(caret, location).map(function (pos) {
+          BoundarySelection.setCaretPosition(editor, pos);
+          return true;
+        }).getOr(false);
+      };
+    };
+
+    var deleteFromTo = function (editor, caret, from, to) {
+      var rootNode = editor.getBody();
+      var isInlineTarget = Fun.curry(InlineUtils.isInlineTarget, editor);
+
+      editor.undoManager.ignore(function () {
+        editor.selection.setRng(rangeFromPositions(from, to));
+        editor.execCommand('Delete');
+
+        BoundaryLocation.readLocation(isInlineTarget, rootNode, CaretPosition.fromRangeStart(editor.selection.getRng()))
+          .map(BoundaryLocation.inside)
+          .map(setCaretLocation(editor, caret));
+      });
+
+      editor.nodeChanged();
+    };
+
+    var rescope = function (rootNode, node) {
+      var parentBlock = CaretUtils.getParentBlock(node, rootNode);
+      return parentBlock ? parentBlock : rootNode;
+    };
+
+    var backspaceDeleteCollapsed = function (editor, caret, forward, from) {
+      var rootNode = rescope(editor.getBody(), from.container());
+      var isInlineTarget = Fun.curry(InlineUtils.isInlineTarget, editor);
+      var fromLocation = BoundaryLocation.readLocation(isInlineTarget, rootNode, from);
+
+      return fromLocation.bind(function (location) {
+        if (forward) {
+          return location.fold(
+            Fun.constant(Option.some(BoundaryLocation.inside(location))), // Before
+            Option.none, // Start
+            Fun.constant(Option.some(BoundaryLocation.outside(location))), // End
+            Option.none  // After
+          );
+        } else {
+          return location.fold(
+            Option.none, // Before
+            Fun.constant(Option.some(BoundaryLocation.outside(location))), // Start
+            Option.none, // End
+            Fun.constant(Option.some(BoundaryLocation.inside(location)))  // After
+          );
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      })
+      .map(setCaretLocation(editor, caret))
+      .getOrThunk(function () {
+        var toPosition = CaretFinder.navigate(forward, rootNode, from);
+        var toLocation = toPosition.bind(function (pos) {
+          return BoundaryLocation.readLocation(isInlineTarget, rootNode, pos);
+        });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return self;
-      },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (fromLocation.isSome() && toLocation.isSome()) {
+          return InlineUtils.findRootInline(isInlineTarget, rootNode, from).map(function (elm) {
+            if (hasOnlyTwoOrLessPositionsLeft(elm)) {
+              DeleteElement.deleteElement(editor, forward, Element.fromDom(elm));
+              return true;
+            } else {
+              return false;
+            }
+          }).getOr(false);
+        } else {
+          return toLocation.bind(function (_) {
+            return toPosition.map(function (to) {
+              if (forward) {
+                deleteFromTo(editor, caret, from, to);
+              } else {
+                deleteFromTo(editor, caret, to, from);
+              }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Repaints the control after a layout operation.
-       *
-       * @method repaint
-       */
-      repaint: function () {
-        var self = this, style, rect;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              return true;
+            });
+          }).getOr(false);
+        }
+      });
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        style = self.getEl().style;
-        rect = self._layoutRect;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var backspaceDelete = function (editor, caret, forward) {
+      if (editor.selection.isCollapsed() && isFeatureEnabled(editor)) {
+        var from = CaretPosition.fromRangeStart(editor.selection.getRng());
+        return backspaceDeleteCollapsed(editor, caret, forward, from);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        style.left = rect.x + 'px';
-        style.top = rect.y + 'px';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return false;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Hardcoded arbitrary z-value because we want the
-        // notifications under the other windows
-        style.zIndex = 0xFFFF - 1;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return {
+      backspaceDelete: backspaceDelete
+    };
+  }
+);
+define(
+  'tinymce.core.delete.TableDeleteAction',
+
+  [
+    'ephox.katamari.api.Adt',
+    'ephox.katamari.api.Arr',
+    'ephox.katamari.api.Fun',
+    'ephox.katamari.api.Option',
+    'ephox.katamari.api.Options',
+    'ephox.katamari.api.Struct',
+    'ephox.sugar.api.dom.Compare',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.search.SelectorFilter',
+    'ephox.sugar.api.search.SelectorFind'
+  ],
+
+  function (Adt, Arr, Fun, Option, Options, Struct, Compare, Element, SelectorFilter, SelectorFind) {
+    var tableCellRng = Struct.immutable('start', 'end');
+    var tableSelection = Struct.immutable('rng', 'table', 'cells');
+    var deleteAction = Adt.generate([
+      { removeTable: [ 'element' ] },
+      { emptyCells: [ 'cells' ] }
+    ]);
+
+    var getClosestCell = function (container, isRoot) {
+      return SelectorFind.closest(Element.fromDom(container), 'td,th', isRoot);
+    };
+
+    var getClosestTable = function (cell, isRoot) {
+      return SelectorFind.ancestor(cell, 'table', isRoot);
+    };
+
+    var isExpandedCellRng = function (cellRng) {
+      return Compare.eq(cellRng.start(), cellRng.end()) === false;
+    };
+
+    var getTableFromCellRng = function (cellRng, isRoot) {
+      return getClosestTable(cellRng.start(), isRoot)
+        .bind(function (startParentTable) {
+          return getClosestTable(cellRng.end(), isRoot)
+            .bind(function (endParentTable) {
+              return Compare.eq(startParentTable, endParentTable) ? Option.some(startParentTable) : Option.none();
+            });
+        });
+    };
+
+    var getCellRng = function (rng, isRoot) {
+      return Options.liftN([ // get start and end cell
+        getClosestCell(rng.startContainer, isRoot),
+        getClosestCell(rng.endContainer, isRoot)
+      ], tableCellRng)
+        .filter(isExpandedCellRng);
+    };
+
+    var getTableSelectionFromCellRng = function (cellRng, isRoot) {
+      return getTableFromCellRng(cellRng, isRoot)
+        .bind(function (table) {
+          var cells = SelectorFilter.descendants(table, 'td,th');
+
+          return tableSelection(cellRng, table, cells);
+        });
+    };
+
+    var getTableSelectionFromRng = function (rootNode, rng) {
+      var isRoot = Fun.curry(Compare.eq, rootNode);
+
+      return getCellRng(rng, isRoot)
+        .map(function (cellRng) {
+          return getTableSelectionFromCellRng(cellRng, isRoot);
+        });
+    };
+
+    var getCellIndex = function (cellArray, cell) {
+      return Arr.findIndex(cellArray, function (x) {
+        return Compare.eq(x, cell);
+      });
+    };
+
+    var getSelectedCells = function (tableSelection) {
+      return Options.liftN([
+        getCellIndex(tableSelection.cells(), tableSelection.rng().start()),
+        getCellIndex(tableSelection.cells(), tableSelection.rng().end())
+      ], function (startIndex, endIndex) {
+        return tableSelection.cells().slice(startIndex, endIndex + 1);
+      });
+    };
+
+    var getAction = function (tableSelection) {
+      return getSelectedCells(tableSelection)
+        .bind(function (selected) {
+          var cells = tableSelection.cells();
+
+          return selected.length === cells.length ? deleteAction.removeTable(tableSelection.table()) : deleteAction.emptyCells(selected);
+        });
+    };
+
+    var getActionFromCells = function (cells) {
+      return deleteAction.emptyCells(cells);
+    };
+
+    var getActionFromRange = function (rootNode, rng) {
+      return getTableSelectionFromRng(rootNode, rng)
+        .map(getAction);
+    };
+
+    return {
+      getActionFromRange: getActionFromRange,
+      getActionFromCells: getActionFromCells
+    };
+  }
+);
+
+/**
+ * TableDelete.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.delete.TableDelete',
+  [
+    'ephox.katamari.api.Arr',
+    'ephox.katamari.api.Fun',
+    'ephox.sugar.api.node.Element',
+    'tinymce.core.delete.DeleteElement',
+    'tinymce.core.delete.TableDeleteAction',
+    'tinymce.core.dom.PaddingBr',
+    'tinymce.core.selection.TableCellSelection'
+  ],
+  function (Arr, Fun, Element, DeleteElement, TableDeleteAction, PaddingBr, TableCellSelection) {
+    var emptyCells = function (editor, cells) {
+      Arr.each(cells, PaddingBr.fillWithPaddingBr);
+      editor.selection.setCursorLocation(cells[0].dom(), 0);
+
+      return true;
+    };
+
+    var deleteTableElement = function (editor, table) {
+      DeleteElement.deleteElement(editor, false, table);
+
+      return true;
+    };
+
+    var handleCellRange = function (editor, rootNode, rng) {
+      return TableDeleteAction.getActionFromRange(rootNode, rng)
+        .map(function (action) {
+          return action.fold(
+            Fun.curry(deleteTableElement, editor),
+            Fun.curry(emptyCells, editor)
+          );
+        }).getOr(false);
+    };
+
+    var deleteRange = function (editor) {
+      var rootNode = Element.fromDom(editor.getBody());
+      var rng = editor.selection.getRng();
+      var selectedCells = TableCellSelection.getCellsFromEditor(editor);
+
+      return selectedCells.length !== 0 ? emptyCells(editor, selectedCells) : handleCellRange(editor, rootNode, rng);
+    };
+
+    var backspaceDelete = function (editor) {
+      return editor.selection.isCollapsed() ? false : deleteRange(editor);
+    };
+
+    return {
+      backspaceDelete: backspaceDelete
+    };
+  }
+);
+
+/**
+ * Commands.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.delete.DeleteCommands',
+  [
+    'tinymce.core.delete.BlockBoundaryDelete',
+    'tinymce.core.delete.BlockRangeDelete',
+    'tinymce.core.delete.CefDelete',
+    'tinymce.core.delete.DeleteUtils',
+    'tinymce.core.delete.InlineBoundaryDelete',
+    'tinymce.core.delete.TableDelete'
+  ],
+  function (BlockBoundaryDelete, BlockRangeDelete, CefDelete, DeleteUtils, BoundaryDelete, TableDelete) {
+    var nativeCommand = function (editor, command) {
+      editor.getDoc().execCommand(command, false, null);
+    };
+
+    var deleteCommand = function (editor) {
+      if (CefDelete.backspaceDelete(editor, false)) {
+        return;
+      } else if (BoundaryDelete.backspaceDelete(editor, false)) {
+        return;
+      } else if (BlockBoundaryDelete.backspaceDelete(editor, false)) {
+        return;
+      } else if (TableDelete.backspaceDelete(editor)) {
+        return;
+      } else if (BlockRangeDelete.backspaceDelete(editor, false)) {
+        return;
+      } else {
+        nativeCommand(editor, 'Delete');
+        DeleteUtils.paddEmptyBody(editor);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    };
+
+    var forwardDeleteCommand = function (editor) {
+      if (CefDelete.backspaceDelete(editor, true)) {
+        return;
+      } else if (BoundaryDelete.backspaceDelete(editor, true)) {
+        return;
+      } else if (BlockBoundaryDelete.backspaceDelete(editor, true)) {
+        return;
+      } else if (TableDelete.backspaceDelete(editor)) {
+        return;
+      } else if (BlockRangeDelete.backspaceDelete(editor, true)) {
+        return;
+      } else {
+        nativeCommand(editor, 'ForwardDelete');
+      }
+    };
+
+    return {
+      deleteCommand: deleteCommand,
+      forwardDeleteCommand: forwardDeleteCommand
+    };
</ins><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * NotificationManager.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * InsertList.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -37523,212 +36869,1505 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * This class handles the creation of TinyMCE's notifications.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Handles inserts of lists into the editor instance.
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @class tinymce.NotificationManager
- * @example
- * // Opens a new notification of type "error" with text "An error occurred."
- * tinymce.activeEditor.notificationManager.open({
- *    text: 'An error occurred.',
- *    type: 'error'
- * });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @class tinymce.InsertList
+ * @private
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.NotificationManager',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.InsertList',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    "tinymce.core.ui.Notification",
-    "tinymce.core.util.Delay",
-    "tinymce.core.util.Tools"
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    "tinymce.core.util.Tools",
+    "tinymce.core.caret.CaretWalker",
+    "tinymce.core.caret.CaretPosition"
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Notification, Delay, Tools) {
-    return function (editor) {
-      var self = this, notifications = [];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Tools, CaretWalker, CaretPosition) {
+    var hasOnlyOneChild = function (node) {
+      return node.firstChild && node.firstChild === node.lastChild;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function getLastNotification() {
-        if (notifications.length) {
-          return notifications[notifications.length - 1];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isPaddingNode = function (node) {
+      return node.name === 'br' || node.value === '\u00a0';
+    };
+
+    var isPaddedEmptyBlock = function (schema, node) {
+      var blockElements = schema.getBlockElements();
+      return blockElements[node.name] && hasOnlyOneChild(node) && isPaddingNode(node.firstChild);
+    };
+
+    var isEmptyFragmentElement = function (schema, node) {
+      var nonEmptyElements = schema.getNonEmptyElements();
+      return node && (node.isEmpty(nonEmptyElements) || isPaddedEmptyBlock(schema, node));
+    };
+
+    var isListFragment = function (schema, fragment) {
+      var firstChild = fragment.firstChild;
+      var lastChild = fragment.lastChild;
+
+      // Skip meta since it's likely <meta><ul>..</ul>
+      if (firstChild && firstChild.name === 'meta') {
+        firstChild = firstChild.next;
+      }
+
+      // Skip mce_marker since it's likely <ul>..</ul><span id="mce_marker"></span>
+      if (lastChild && lastChild.attr('id') === 'mce_marker') {
+        lastChild = lastChild.prev;
+      }
+
+      // Skip last child if it's an empty block
+      if (isEmptyFragmentElement(schema, lastChild)) {
+        lastChild = lastChild.prev;
+      }
+
+      if (!firstChild || firstChild !== lastChild) {
+        return false;
+      }
+
+      return firstChild.name === 'ul' || firstChild.name === 'ol';
+    };
+
+    var cleanupDomFragment = function (domFragment) {
+      var firstChild = domFragment.firstChild;
+      var lastChild = domFragment.lastChild;
+
+      // TODO: remove the meta tag from paste logic
+      if (firstChild && firstChild.nodeName === 'META') {
+        firstChild.parentNode.removeChild(firstChild);
+      }
+
+      if (lastChild && lastChild.id === 'mce_marker') {
+        lastChild.parentNode.removeChild(lastChild);
+      }
+
+      return domFragment;
+    };
+
+    var toDomFragment = function (dom, serializer, fragment) {
+      var html = serializer.serialize(fragment);
+      var domFragment = dom.createFragment(html);
+
+      return cleanupDomFragment(domFragment);
+    };
+
+    var listItems = function (elm) {
+      return Tools.grep(elm.childNodes, function (child) {
+        return child.nodeName === 'LI';
+      });
+    };
+
+    var isEmpty = function (elm) {
+      return !elm.firstChild;
+    };
+
+    var trimListItems = function (elms) {
+      return elms.length > 0 && isEmpty(elms[elms.length - 1]) ? elms.slice(0, -1) : elms;
+    };
+
+    var getParentLi = function (dom, node) {
+      var parentBlock = dom.getParent(node, dom.isBlock);
+      return parentBlock && parentBlock.nodeName === 'LI' ? parentBlock : null;
+    };
+
+    var isParentBlockLi = function (dom, node) {
+      return !!getParentLi(dom, node);
+    };
+
+    var getSplit = function (parentNode, rng) {
+      var beforeRng = rng.cloneRange();
+      var afterRng = rng.cloneRange();
+
+      beforeRng.setStartBefore(parentNode);
+      afterRng.setEndAfter(parentNode);
+
+      return [
+        beforeRng.cloneContents(),
+        afterRng.cloneContents()
+      ];
+    };
+
+    var findFirstIn = function (node, rootNode) {
+      var caretPos = CaretPosition.before(node);
+      var caretWalker = new CaretWalker(rootNode);
+      var newCaretPos = caretWalker.next(caretPos);
+
+      return newCaretPos ? newCaretPos.toRange() : null;
+    };
+
+    var findLastOf = function (node, rootNode) {
+      var caretPos = CaretPosition.after(node);
+      var caretWalker = new CaretWalker(rootNode);
+      var newCaretPos = caretWalker.prev(caretPos);
+
+      return newCaretPos ? newCaretPos.toRange() : null;
+    };
+
+    var insertMiddle = function (target, elms, rootNode, rng) {
+      var parts = getSplit(target, rng);
+      var parentElm = target.parentNode;
+
+      parentElm.insertBefore(parts[0], target);
+      Tools.each(elms, function (li) {
+        parentElm.insertBefore(li, target);
+      });
+      parentElm.insertBefore(parts[1], target);
+      parentElm.removeChild(target);
+
+      return findLastOf(elms[elms.length - 1], rootNode);
+    };
+
+    var insertBefore = function (target, elms, rootNode) {
+      var parentElm = target.parentNode;
+
+      Tools.each(elms, function (elm) {
+        parentElm.insertBefore(elm, target);
+      });
+
+      return findFirstIn(target, rootNode);
+    };
+
+    var insertAfter = function (target, elms, rootNode, dom) {
+      dom.insertAfter(elms.reverse(), target);
+      return findLastOf(elms[0], rootNode);
+    };
+
+    var insertAtCaret = function (serializer, dom, rng, fragment) {
+      var domFragment = toDomFragment(dom, serializer, fragment);
+      var liTarget = getParentLi(dom, rng.startContainer);
+      var liElms = trimListItems(listItems(domFragment.firstChild));
+      var BEGINNING = 1, END = 2;
+      var rootNode = dom.getRoot();
+
+      var isAt = function (location) {
+        var caretPos = CaretPosition.fromRangeStart(rng);
+        var caretWalker = new CaretWalker(dom.getRoot());
+        var newPos = location === BEGINNING ? caretWalker.prev(caretPos) : caretWalker.next(caretPos);
+
+        return newPos ? getParentLi(dom, newPos.getNode()) !== liTarget : true;
+      };
+
+      if (isAt(BEGINNING)) {
+        return insertBefore(liTarget, liElms, rootNode);
+      } else if (isAt(END)) {
+        return insertAfter(liTarget, liElms, rootNode, dom);
+      }
+
+      return insertMiddle(liTarget, liElms, rootNode, rng);
+    };
+
+    return {
+      isListFragment: isListFragment,
+      insertAtCaret: insertAtCaret,
+      isParentBlockLi: isParentBlockLi,
+      trimListItems: trimListItems,
+      listItems: listItems
+    };
+  }
+);
+/**
+ * InsertContent.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * Handles inserts of contents into the editor instance.
+ *
+ * @class tinymce.InsertContent
+ * @private
+ */
+define(
+  'tinymce.core.InsertContent',
+  [
+    'ephox.katamari.api.Option',
+    'ephox.sugar.api.node.Element',
+    'tinymce.core.caret.CaretPosition',
+    'tinymce.core.caret.CaretWalker',
+    'tinymce.core.dom.ElementUtils',
+    'tinymce.core.dom.NodeType',
+    'tinymce.core.dom.PaddingBr',
+    'tinymce.core.dom.RangeNormalizer',
+    'tinymce.core.Env',
+    'tinymce.core.html.Serializer',
+    'tinymce.core.InsertList',
+    'tinymce.core.util.Tools'
+  ],
+  function (Option, Element, CaretPosition, CaretWalker, ElementUtils, NodeType, PaddingBr, RangeNormalizer, Env, Serializer, InsertList, Tools) {
+    var isTableCell = NodeType.matchNodeNames('td th');
+
+    var validInsertion = function (editor, value, parentNode) {
+      // Should never insert content into bogus elements, since these can
+      // be resize handles or similar
+      if (parentNode.getAttribute('data-mce-bogus') === 'all') {
+        parentNode.parentNode.insertBefore(editor.dom.createFragment(value), parentNode);
+      } else {
+        // Check if parent is empty or only has one BR element then set the innerHTML of that parent
+        var node = parentNode.firstChild;
+        var node2 = parentNode.lastChild;
+        if (!node || (node === node2 && node.nodeName === 'BR')) {///
+          editor.dom.setHTML(parentNode, value);
+        } else {
+          editor.selection.setContent(value);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      self.notifications = notifications;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var trimBrsFromTableCell = function (dom, elm) {
+      Option.from(dom.getParent(elm, 'td,th')).map(Element.fromDom).each(PaddingBr.trimBlockTrailingBr);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function resizeWindowEvent() {
-        Delay.requestAnimationFrame(function () {
-          prePositionNotifications();
-          positionNotifications();
-        });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var insertHtmlAtCaret = function (editor, value, details) {
+      var parser, serializer, parentNode, rootNode, fragment, args;
+      var marker, rng, node, node2, bookmarkHtml, merge;
+      var textInlineElements = editor.schema.getTextInlineElements();
+      var selection = editor.selection, dom = editor.dom;
+
+      function trimOrPaddLeftRight(html) {
+        var rng, container, offset;
+
+        rng = selection.getRng(true);
+        container = rng.startContainer;
+        offset = rng.startOffset;
+
+        function hasSiblingText(siblingName) {
+          return container[siblingName] && container[siblingName].nodeType == 3;
+        }
+
+        if (container.nodeType == 3) {
+          if (offset > 0) {
+            html = html.replace(/^&nbsp;/, ' ');
+          } else if (!hasSiblingText('previousSibling')) {
+            html = html.replace(/^ /, '&nbsp;');
+          }
+
+          if (offset < container.length) {
+            html = html.replace(/&nbsp;(<br>|)$/, ' ');
+          } else if (!hasSiblingText('nextSibling')) {
+            html = html.replace(/(&nbsp;| )(<br>|)$/, '&nbsp;');
+          }
+        }
+
+        return html;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Since the viewport will change based on the present notifications, we need to move them all to the
-      // top left of the viewport to give an accurate size measurement so we can position them later.
-      function prePositionNotifications() {
-        for (var i = 0; i < notifications.length; i++) {
-          notifications[i].moveTo(0, 0);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Removes &nbsp; from a [b] c -> a &nbsp;c -> a c
+      function trimNbspAfterDeleteAndPaddValue() {
+        var rng, container, offset;
+
+        rng = selection.getRng(true);
+        container = rng.startContainer;
+        offset = rng.startOffset;
+
+        if (container.nodeType == 3 && rng.collapsed) {
+          if (container.data[offset] === '\u00a0') {
+            container.deleteData(offset, 1);
+
+            if (!/[\u00a0| ]$/.test(value)) {
+              value += ' ';
+            }
+          } else if (container.data[offset - 1] === '\u00a0') {
+            container.deleteData(offset - 1, 1);
+
+            if (!/[\u00a0| ]$/.test(value)) {
+              value = ' ' + value;
+            }
+          }
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function positionNotifications() {
-        if (notifications.length > 0) {
-          var firstItem = notifications.slice(0, 1)[0];
-          var container = editor.inline ? editor.getElement() : editor.getContentAreaContainer();
-          firstItem.moveRel(container, 'tc-tc');
-          if (notifications.length > 1) {
-            for (var i = 1; i < notifications.length; i++) {
-              notifications[i].moveRel(notifications[i - 1].getEl(), 'bc-tc');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function reduceInlineTextElements() {
+        if (merge) {
+          var root = editor.getBody(), elementUtils = new ElementUtils(dom);
+
+          Tools.each(dom.select('*[data-mce-fragment]'), function (node) {
+            for (var testNode = node.parentNode; testNode && testNode != root; testNode = testNode.parentNode) {
+              if (textInlineElements[node.nodeName.toLowerCase()] && elementUtils.compare(testNode, node)) {
+                dom.remove(node, true);
+              }
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          });
+        }
+      }
+
+      function markFragmentElements(fragment) {
+        var node = fragment;
+
+        while ((node = node.walk())) {
+          if (node.type === 1) {
+            node.attr('data-mce-fragment', '1');
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      editor.on('remove', function () {
-        var i = notifications.length;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function umarkFragmentElements(elm) {
+        Tools.each(elm.getElementsByTagName('*'), function (elm) {
+          elm.removeAttribute('data-mce-fragment');
+        });
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        while (i--) {
-          notifications[i].close();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function isPartOfFragment(node) {
+        return !!node.getAttribute('data-mce-fragment');
+      }
+
+      function canHaveChildren(node) {
+        return node && !editor.schema.getShortEndedElements()[node.nodeName];
+      }
+
+      function moveSelectionToMarker(marker) {
+        var parentEditableFalseElm, parentBlock, nextRng;
+
+        function getContentEditableFalseParent(node) {
+          var root = editor.getBody();
+
+          for (; node && node !== root; node = node.parentNode) {
+            if (editor.dom.getContentEditable(node) === 'false') {
+              return node;
+            }
+          }
+
+          return null;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      });
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      editor.on('ResizeEditor', positionNotifications);
-      editor.on('ResizeWindow', resizeWindowEvent);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (!marker) {
+          return;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Opens a new notification.
-       *
-       * @method open
-       * @param {Object} args Optional name/value settings collection contains things like timeout/color/message etc.
-       */
-      self.open = function (args) {
-        // Never open notification if editor has been removed.
-        if (editor.removed) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        selection.scrollIntoView(marker);
+
+        // If marker is in cE=false then move selection to that element instead
+        parentEditableFalseElm = getContentEditableFalseParent(marker);
+        if (parentEditableFalseElm) {
+          dom.remove(marker);
+          selection.select(parentEditableFalseElm);
</ins><span class="cx" style="display: block; padding: 0 10px">           return;
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var notif;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Move selection before marker and remove it
+        rng = dom.createRng();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        editor.editorManager.setActive(editor);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // If previous sibling is a text node set the selection to the end of that node
+        node = marker.previousSibling;
+        if (node && node.nodeType == 3) {
+          rng.setStart(node, node.nodeValue.length);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var duplicate = findDuplicateMessage(notifications, args);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // TODO: Why can't we normalize on IE
+          if (!Env.ie) {
+            node2 = marker.nextSibling;
+            if (node2 && node2.nodeType == 3) {
+              node.appendData(node2.data);
+              node2.parentNode.removeChild(node2);
+            }
+          }
+        } else {
+          // If the previous sibling isn't a text node or doesn't exist set the selection before the marker node
+          rng.setStartBefore(marker);
+          rng.setEndBefore(marker);
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (duplicate === null) {
-          notif = new Notification(args);
-          notifications.push(notif);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        function findNextCaretRng(rng) {
+          var caretPos = CaretPosition.fromRangeStart(rng);
+          var caretWalker = new CaretWalker(editor.getBody());
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          //If we have a timeout value
-          if (args.timeout > 0) {
-            notif.timer = setTimeout(function () {
-              notif.close();
-            }, args.timeout);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          caretPos = caretWalker.next(caretPos);
+          if (caretPos) {
+            return caretPos.toRange();
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          notif.on('close', function () {
-            var i = notifications.length;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Remove the marker node and set the new range
+        parentBlock = dom.getParent(marker, dom.isBlock);
+        dom.remove(marker);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (notif.timer) {
-              editor.getWin().clearTimeout(notif.timer);
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (parentBlock && dom.isEmpty(parentBlock)) {
+          editor.$(parentBlock).empty();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            while (i--) {
-              if (notifications[i] === notif) {
-                notifications.splice(i, 1);
-              }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          rng.setStart(parentBlock, 0);
+          rng.setEnd(parentBlock, 0);
+
+          if (!isTableCell(parentBlock) && !isPartOfFragment(parentBlock) && (nextRng = findNextCaretRng(rng))) {
+            rng = nextRng;
+            dom.remove(parentBlock);
+          } else {
+            dom.add(parentBlock, dom.create('br', { 'data-mce-bogus': '1' }));
+          }
+        }
+
+        selection.setRng(rng);
+      }
+
+      // Check for whitespace before/after value
+      if (/^ | $/.test(value)) {
+        value = trimOrPaddLeftRight(value);
+      }
+
+      // Setup parser and serializer
+      parser = editor.parser;
+      merge = details.merge;
+
+      serializer = new Serializer({
+        validate: editor.settings.validate
+      }, editor.schema);
+      bookmarkHtml = '<span id="mce_marker" data-mce-type="bookmark">&#xFEFF;&#x200B;</span>';
+
+      // Run beforeSetContent handlers on the HTML to be inserted
+      args = { content: value, format: 'html', selection: true };
+      editor.fire('BeforeSetContent', args);
+      value = args.content;
+
+      // Add caret at end of contents if it's missing
+      if (value.indexOf('{$caret}') == -1) {
+        value += '{$caret}';
+      }
+
+      // Replace the caret marker with a span bookmark element
+      value = value.replace(/\{\$caret\}/, bookmarkHtml);
+
+      // If selection is at <body>|<p></p> then move it into <body><p>|</p>
+      rng = selection.getRng();
+      var caretElement = rng.startContainer || (rng.parentElement ? rng.parentElement() : null);
+      var body = editor.getBody();
+      if (caretElement === body && selection.isCollapsed()) {
+        if (dom.isBlock(body.firstChild) && canHaveChildren(body.firstChild) && dom.isEmpty(body.firstChild)) {
+          rng = dom.createRng();
+          rng.setStart(body.firstChild, 0);
+          rng.setEnd(body.firstChild, 0);
+          selection.setRng(rng);
+        }
+      }
+
+      // Insert node maker where we will insert the new HTML and get it's parent
+      if (!selection.isCollapsed()) {
+        // Fix for #2595 seems that delete removes one extra character on
+        // WebKit for some odd reason if you double click select a word
+        editor.selection.setRng(RangeNormalizer.normalize(editor.selection.getRng()));
+        editor.getDoc().execCommand('Delete', false, null);
+        trimNbspAfterDeleteAndPaddValue();
+      }
+
+      parentNode = selection.getNode();
+
+      // Parse the fragment within the context of the parent node
+      var parserArgs = { context: parentNode.nodeName.toLowerCase(), data: details.data };
+      fragment = parser.parse(value, parserArgs);
+
+      // Custom handling of lists
+      if (details.paste === true && InsertList.isListFragment(editor.schema, fragment) && InsertList.isParentBlockLi(dom, parentNode)) {
+        rng = InsertList.insertAtCaret(serializer, dom, editor.selection.getRng(true), fragment);
+        editor.selection.setRng(rng);
+        editor.fire('SetContent', args);
+        return;
+      }
+
+      markFragmentElements(fragment);
+
+      // Move the caret to a more suitable location
+      node = fragment.lastChild;
+      if (node.attr('id') == 'mce_marker') {
+        marker = node;
+
+        for (node = node.prev; node; node = node.walk(true)) {
+          if (node.type == 3 || !dom.isBlock(node.name)) {
+            if (editor.schema.isValidChild(node.parent.name, 'span')) {
+              node.parent.insert(marker, node, node.name === 'br');
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            break;
+          }
+        }
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            positionNotifications();
-          });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      editor._selectionOverrides.showBlockCaretContainer(parentNode);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          notif.renderTo();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // If parser says valid we can insert the contents into that parent
+      if (!parserArgs.invalid) {
+        value = serializer.serialize(fragment);
+        validInsertion(editor, value, parentNode);
+      } else {
+        // If the fragment was invalid within that context then we need
+        // to parse and process the parent it's inserted into
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          positionNotifications();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Insert bookmark node and get the parent
+        selection.setContent(bookmarkHtml);
+        parentNode = selection.getNode();
+        rootNode = editor.getBody();
+
+        // Opera will return the document node when selection is in root
+        if (parentNode.nodeType == 9) {
+          parentNode = node = rootNode;
</ins><span class="cx" style="display: block; padding: 0 10px">         } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          notif = duplicate;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          node = parentNode;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return notif;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Find the ancestor just before the root element
+        while (node !== rootNode) {
+          parentNode = node;
+          node = node.parentNode;
+        }
+
+        // Get the outer/inner HTML depending on if we are in the root and parser and serialize that
+        value = parentNode == rootNode ? rootNode.innerHTML : dom.getOuterHTML(parentNode);
+        value = serializer.serialize(
+          parser.parse(
+            // Need to replace by using a function since $ in the contents would otherwise be a problem
+            value.replace(/<span (id="mce_marker"|id=mce_marker).+?<\/span>/i, function () {
+              return serializer.serialize(fragment);
+            })
+          )
+        );
+
+        // Set the inner/outer HTML depending on if we are in the root or not
+        if (parentNode == rootNode) {
+          dom.setHTML(rootNode, value);
+        } else {
+          dom.setOuterHTML(parentNode, value);
+        }
+      }
+
+      reduceInlineTextElements();
+      moveSelectionToMarker(dom.get('mce_marker'));
+      umarkFragmentElements(editor.getBody());
+      trimBrsFromTableCell(editor.dom, editor.selection.getStart());
+
+      editor.fire('SetContent', args);
+      editor.addVisual();
+    };
+
+    var processValue = function (value) {
+      var details;
+
+      if (typeof value !== 'string') {
+        details = Tools.extend({
+          paste: value.paste,
+          data: {
+            paste: value.paste
+          }
+        }, value);
+
+        return {
+          content: value.content,
+          details: details
+        };
+      }
+
+      return {
+        content: value,
+        details: {}
</ins><span class="cx" style="display: block; padding: 0 10px">       };
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var insertAtCaret = function (editor, value) {
+      var result = processValue(value);
+      insertHtmlAtCaret(editor, result.content, result.details);
+    };
+
+    return {
+      insertAtCaret: insertAtCaret
+    };
+  }
+);
+/**
+ * EditorCommands.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This class enables you to add custom editor commands and it contains
+ * overrides for native browser commands to address various bugs and issues.
+ *
+ * @class tinymce.EditorCommands
+ */
+define(
+  'tinymce.core.EditorCommands',
+  [
+    'tinymce.core.delete.DeleteCommands',
+    'tinymce.core.dom.NodeType',
+    'tinymce.core.dom.RangeUtils',
+    'tinymce.core.dom.TreeWalker',
+    'tinymce.core.Env',
+    'tinymce.core.InsertContent',
+    'tinymce.core.util.Tools'
+  ],
+  function (DeleteCommands, NodeType, RangeUtils, TreeWalker, Env, InsertContent, Tools) {
+    // Added for compression purposes
+    var each = Tools.each, extend = Tools.extend;
+    var map = Tools.map, inArray = Tools.inArray, explode = Tools.explode;
+    var isOldIE = Env.ie && Env.ie < 11;
+    var TRUE = true, FALSE = false;
+
+    return function (editor) {
+      var dom, selection, formatter,
+        commands = { state: {}, exec: {}, value: {} },
+        settings = editor.settings,
+        bookmark;
+
+      editor.on('PreInit', function () {
+        dom = editor.dom;
+        selection = editor.selection;
+        settings = editor.settings;
+        formatter = editor.formatter;
+      });
+
</ins><span class="cx" style="display: block; padding: 0 10px">       /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * Closes the top most notification.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * Executes the specified command.
</ins><span class="cx" style="display: block; padding: 0 10px">        *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * @method close
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * @method execCommand
+       * @param {String} command Command to execute.
+       * @param {Boolean} ui Optional user interface state.
+       * @param {Object} value Optional value for command.
+       * @param {Object} args Optional extra arguments to the execCommand.
+       * @return {Boolean} true/false if the command was found or not.
</ins><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      self.close = function () {
-        if (getLastNotification()) {
-          getLastNotification().close();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function execCommand(command, ui, value, args) {
+        var func, customCommand, state = 0;
+
+        if (editor.removed) {
+          return;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint)$/.test(command) && (!args || !args.skip_focus)) {
+          editor.focus();
+        }
+
+        args = editor.fire('BeforeExecCommand', { command: command, ui: ui, value: value });
+        if (args.isDefaultPrevented()) {
+          return false;
+        }
+
+        customCommand = command.toLowerCase();
+        if ((func = commands.exec[customCommand])) {
+          func(customCommand, ui, value);
+          editor.fire('ExecCommand', { command: command, ui: ui, value: value });
+          return true;
+        }
+
+        // Plugin commands
+        each(editor.plugins, function (p) {
+          if (p.execCommand && p.execCommand(command, ui, value)) {
+            editor.fire('ExecCommand', { command: command, ui: ui, value: value });
+            state = true;
+            return false;
+          }
+        });
+
+        if (state) {
+          return state;
+        }
+
+        // Theme commands
+        if (editor.theme && editor.theme.execCommand && editor.theme.execCommand(command, ui, value)) {
+          editor.fire('ExecCommand', { command: command, ui: ui, value: value });
+          return true;
+        }
+
+        // Browser commands
+        try {
+          state = editor.getDoc().execCommand(command, ui, value);
+        } catch (ex) {
+          // Ignore old IE errors
+        }
+
+        if (state) {
+          editor.fire('ExecCommand', { command: command, ui: ui, value: value });
+          return true;
+        }
+
+        return false;
+      }
+
</ins><span class="cx" style="display: block; padding: 0 10px">       /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * Returns the currently opened notification objects.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * Queries the current state for a command for example if the current selection is "bold".
</ins><span class="cx" style="display: block; padding: 0 10px">        *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * @method getNotifications
-       * @return {Array} Array of the currently opened notifications.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * @method queryCommandState
+       * @param {String} command Command to check the state of.
+       * @return {Boolean/Number} true/false if the selected contents is bold or not, -1 if it's not found.
</ins><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      self.getNotifications = function () {
-        return notifications;
-      };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function queryCommandState(command) {
+        var func;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      editor.on('SkinLoaded', function () {
-        var serviceMessage = editor.settings.service_message;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (editor.quirks.isHidden() || editor.removed) {
+          return;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (serviceMessage) {
-          editor.notificationManager.open({
-            text: serviceMessage,
-            type: 'warning',
-            timeout: 0,
-            icon: ''
-          });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        command = command.toLowerCase();
+        if ((func = commands.state[command])) {
+          return func(command);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      });
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Browser commands
+        try {
+          return editor.getDoc().queryCommandState(command);
+        } catch (ex) {
+          // Fails sometimes see bug: 1896577
+        }
+
+        return false;
+      }
+
</ins><span class="cx" style="display: block; padding: 0 10px">       /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * Finds any existing notification with the same properties as the new one.
-       * Returns either the found notification or null.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * Queries the command value for example the current fontsize.
</ins><span class="cx" style="display: block; padding: 0 10px">        *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * @param {Notification[]} notificationArray - Array of current notifications
-       * @param {type: string, } newNotification - New notification object
-       * @returns {?Notification}
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * @method queryCommandValue
+       * @param {String} command Command to check the value of.
+       * @return {Object} Command value of false if it's not found.
</ins><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function findDuplicateMessage(notificationArray, newNotification) {
-        if (!isPlainTextNotification(newNotification)) {
-          return null;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function queryCommandValue(command) {
+        var func;
+
+        if (editor.quirks.isHidden() || editor.removed) {
+          return;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var filteredNotifications = Tools.grep(notificationArray, function (notification) {
-          return isSameNotification(newNotification, notification);
-        });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        command = command.toLowerCase();
+        if ((func = commands.value[command])) {
+          return func(command);
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return filteredNotifications.length === 0 ? null : filteredNotifications[0];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Browser commands
+        try {
+          return editor.getDoc().queryCommandValue(command);
+        } catch (ex) {
+          // Fails sometimes see bug: 1896577
+        }
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * Checks if the passed in args object has the same
-       * type and text properties as the sent in notification.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * Adds commands to the command collection.
</ins><span class="cx" style="display: block; padding: 0 10px">        *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * @param {type: string, text: string} a - New notification args object
-       * @param {Notification} b - Old notification
-       * @returns {boolean}
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * @method addCommands
+       * @param {Object} commandList Name/value collection with commands to add, the names can also be comma separated.
+       * @param {String} type Optional type to add, defaults to exec. Can be value or state as well.
</ins><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function isSameNotification(a, b) {
-        return a.type === b.settings.type && a.text === b.settings.text;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function addCommands(commandList, type) {
+        type = type || 'exec';
+
+        each(commandList, function (callback, command) {
+          each(command.toLowerCase().split(','), function (command) {
+            commands[type][command] = callback;
+          });
+        });
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function addCommand(command, callback, scope) {
+        command = command.toLowerCase();
+        commands.exec[command] = function (command, ui, value, args) {
+          return callback.call(scope || editor, ui, value, args);
+        };
+      }
+
</ins><span class="cx" style="display: block; padding: 0 10px">       /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * Checks that the notification does not have a progressBar
-       * or timeour property.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * Returns true/false if the command is supported or not.
</ins><span class="cx" style="display: block; padding: 0 10px">        *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * @param {Notification} notification - Notification to check
-       * @returns {boolean}
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * @method queryCommandSupported
+       * @param {String} command Command that we check support for.
+       * @return {Boolean} true/false if the command is supported or not.
</ins><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function isPlainTextNotification(notification) {
-        return !notification.progressBar && !notification.timeout;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function queryCommandSupported(command) {
+        command = command.toLowerCase();
+
+        if (commands.exec[command]) {
+          return true;
+        }
+
+        // Browser commands
+        try {
+          return editor.getDoc().queryCommandSupported(command);
+        } catch (ex) {
+          // Fails sometimes see bug: 1896577
+        }
+
+        return false;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      //self.positionNotifications = positionNotifications;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function addQueryStateHandler(command, callback, scope) {
+        command = command.toLowerCase();
+        commands.state[command] = function () {
+          return callback.call(scope || editor);
+        };
+      }
+
+      function addQueryValueHandler(command, callback, scope) {
+        command = command.toLowerCase();
+        commands.value[command] = function () {
+          return callback.call(scope || editor);
+        };
+      }
+
+      function hasCustomCommand(command) {
+        command = command.toLowerCase();
+        return !!commands.exec[command];
+      }
+
+      // Expose public methods
+      extend(this, {
+        execCommand: execCommand,
+        queryCommandState: queryCommandState,
+        queryCommandValue: queryCommandValue,
+        queryCommandSupported: queryCommandSupported,
+        addCommands: addCommands,
+        addCommand: addCommand,
+        addQueryStateHandler: addQueryStateHandler,
+        addQueryValueHandler: addQueryValueHandler,
+        hasCustomCommand: hasCustomCommand
+      });
+
+      // Private methods
+
+      function execNativeCommand(command, ui, value) {
+        if (ui === undefined) {
+          ui = FALSE;
+        }
+
+        if (value === undefined) {
+          value = null;
+        }
+
+        return editor.getDoc().execCommand(command, ui, value);
+      }
+
+      function isFormatMatch(name) {
+        return formatter.match(name);
+      }
+
+      function toggleFormat(name, value) {
+        formatter.toggle(name, value ? { value: value } : undefined);
+        editor.nodeChanged();
+      }
+
+      function storeSelection(type) {
+        bookmark = selection.getBookmark(type);
+      }
+
+      function restoreSelection() {
+        selection.moveToBookmark(bookmark);
+      }
+
+      // Add execCommand overrides
+      addCommands({
+        // Ignore these, added for compatibility
+        'mceResetDesignMode,mceBeginUndoLevel': function () { },
+
+        // Add undo manager logic
+        'mceEndUndoLevel,mceAddUndoLevel': function () {
+          editor.undoManager.add();
+        },
+
+        'Cut,Copy,Paste': function (command) {
+          var doc = editor.getDoc(), failed;
+
+          // Try executing the native command
+          try {
+            execNativeCommand(command);
+          } catch (ex) {
+            // Command failed
+            failed = TRUE;
+          }
+
+          // Chrome reports the paste command as supported however older IE:s will return false for cut/paste
+          if (command === 'paste' && !doc.queryCommandEnabled(command)) {
+            failed = true;
+          }
+
+          // Present alert message about clipboard access not being available
+          if (failed || !doc.queryCommandSupported(command)) {
+            var msg = editor.translate(
+              "Your browser doesn't support direct access to the clipboard. " +
+              "Please use the Ctrl+X/C/V keyboard shortcuts instead."
+            );
+
+            if (Env.mac) {
+              msg = msg.replace(/Ctrl\+/g, '\u2318+');
+            }
+
+            editor.notificationManager.open({ text: msg, type: 'error' });
+          }
+        },
+
+        // Override unlink command
+        unlink: function () {
+          if (selection.isCollapsed()) {
+            var elm = editor.dom.getParent(editor.selection.getStart(), 'a');
+            if (elm) {
+              editor.dom.remove(elm, true);
+            }
+
+            return;
+          }
+
+          formatter.remove("link");
+        },
+
+        // Override justify commands to use the text formatter engine
+        'JustifyLeft,JustifyCenter,JustifyRight,JustifyFull,JustifyNone': function (command) {
+          var align = command.substring(7);
+
+          if (align == 'full') {
+            align = 'justify';
+          }
+
+          // Remove all other alignments first
+          each('left,center,right,justify'.split(','), function (name) {
+            if (align != name) {
+              formatter.remove('align' + name);
+            }
+          });
+
+          if (align != 'none') {
+            toggleFormat('align' + align);
+          }
+        },
+
+        // Override list commands to fix WebKit bug
+        'InsertUnorderedList,InsertOrderedList': function (command) {
+          var listElm, listParent;
+
+          execNativeCommand(command);
+
+          // WebKit produces lists within block elements so we need to split them
+          // we will replace the native list creation logic to custom logic later on
+          // TODO: Remove this when the list creation logic is removed
+          listElm = dom.getParent(selection.getNode(), 'ol,ul');
+          if (listElm) {
+            listParent = listElm.parentNode;
+
+            // If list is within a text block then split that block
+            if (/^(H[1-6]|P|ADDRESS|PRE)$/.test(listParent.nodeName)) {
+              storeSelection();
+              dom.split(listParent, listElm);
+              restoreSelection();
+            }
+          }
+        },
+
+        // Override commands to use the text formatter engine
+        'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': function (command) {
+          toggleFormat(command);
+        },
+
+        // Override commands to use the text formatter engine
+        'ForeColor,HiliteColor,FontName': function (command, ui, value) {
+          toggleFormat(command, value);
+        },
+
+        FontSize: function (command, ui, value) {
+          var fontClasses, fontSizes;
+
+          // Convert font size 1-7 to styles
+          if (value >= 1 && value <= 7) {
+            fontSizes = explode(settings.font_size_style_values);
+            fontClasses = explode(settings.font_size_classes);
+
+            if (fontClasses) {
+              value = fontClasses[value - 1] || value;
+            } else {
+              value = fontSizes[value - 1] || value;
+            }
+          }
+
+          toggleFormat(command, value);
+        },
+
+        RemoveFormat: function (command) {
+          formatter.remove(command);
+        },
+
+        mceBlockQuote: function () {
+          toggleFormat('blockquote');
+        },
+
+        FormatBlock: function (command, ui, value) {
+          return toggleFormat(value || 'p');
+        },
+
+        mceCleanup: function () {
+          var bookmark = selection.getBookmark();
+
+          editor.setContent(editor.getContent({ cleanup: TRUE }), { cleanup: TRUE });
+
+          selection.moveToBookmark(bookmark);
+        },
+
+        mceRemoveNode: function (command, ui, value) {
+          var node = value || selection.getNode();
+
+          // Make sure that the body node isn't removed
+          if (node != editor.getBody()) {
+            storeSelection();
+            editor.dom.remove(node, TRUE);
+            restoreSelection();
+          }
+        },
+
+        mceSelectNodeDepth: function (command, ui, value) {
+          var counter = 0;
+
+          dom.getParent(selection.getNode(), function (node) {
+            if (node.nodeType == 1 && counter++ == value) {
+              selection.select(node);
+              return FALSE;
+            }
+          }, editor.getBody());
+        },
+
+        mceSelectNode: function (command, ui, value) {
+          selection.select(value);
+        },
+
+        mceInsertContent: function (command, ui, value) {
+          InsertContent.insertAtCaret(editor, value);
+        },
+
+        mceInsertRawHTML: function (command, ui, value) {
+          selection.setContent('tiny_mce_marker');
+          editor.setContent(
+            editor.getContent().replace(/tiny_mce_marker/g, function () {
+              return value;
+            })
+          );
+        },
+
+        mceToggleFormat: function (command, ui, value) {
+          toggleFormat(value);
+        },
+
+        mceSetContent: function (command, ui, value) {
+          editor.setContent(value);
+        },
+
+        'Indent,Outdent': function (command) {
+          var intentValue, indentUnit, value;
+
+          // Setup indent level
+          intentValue = settings.indentation;
+          indentUnit = /[a-z%]+$/i.exec(intentValue);
+          intentValue = parseInt(intentValue, 10);
+
+          if (!queryCommandState('InsertUnorderedList') && !queryCommandState('InsertOrderedList')) {
+            // If forced_root_blocks is set to false we don't have a block to indent so lets create a div
+            if (!settings.forced_root_block && !dom.getParent(selection.getNode(), dom.isBlock)) {
+              formatter.apply('div');
+            }
+
+            each(selection.getSelectedBlocks(), function (element) {
+              if (dom.getContentEditable(element) === "false") {
+                return;
+              }
+
+              if (element.nodeName !== "LI") {
+                var indentStyleName = editor.getParam('indent_use_margin', false) ? 'margin' : 'padding';
+                indentStyleName = element.nodeName === 'TABLE' ? 'margin' : indentStyleName;
+                indentStyleName += dom.getStyle(element, 'direction', true) == 'rtl' ? 'Right' : 'Left';
+
+                if (command == 'outdent') {
+                  value = Math.max(0, parseInt(element.style[indentStyleName] || 0, 10) - intentValue);
+                  dom.setStyle(element, indentStyleName, value ? value + indentUnit : '');
+                } else {
+                  value = (parseInt(element.style[indentStyleName] || 0, 10) + intentValue) + indentUnit;
+                  dom.setStyle(element, indentStyleName, value);
+                }
+              }
+            });
+          } else {
+            execNativeCommand(command);
+          }
+        },
+
+        mceRepaint: function () {
+        },
+
+        InsertHorizontalRule: function () {
+          editor.execCommand('mceInsertContent', false, '<hr />');
+        },
+
+        mceToggleVisualAid: function () {
+          editor.hasVisual = !editor.hasVisual;
+          editor.addVisual();
+        },
+
+        mceReplaceContent: function (command, ui, value) {
+          editor.execCommand('mceInsertContent', false, value.replace(/\{\$selection\}/g, selection.getContent({ format: 'text' })));
+        },
+
+        mceInsertLink: function (command, ui, value) {
+          var anchor;
+
+          if (typeof value == 'string') {
+            value = { href: value };
+          }
+
+          anchor = dom.getParent(selection.getNode(), 'a');
+
+          // Spaces are never valid in URLs and it's a very common mistake for people to make so we fix it here.
+          value.href = value.href.replace(' ', '%20');
+
+          // Remove existing links if there could be child links or that the href isn't specified
+          if (!anchor || !value.href) {
+            formatter.remove('link');
+          }
+
+          // Apply new link to selection
+          if (value.href) {
+            formatter.apply('link', value, anchor);
+          }
+        },
+
+        selectAll: function () {
+          var root = dom.getRoot(), rng;
+
+          if (selection.getRng().setStart) {
+            var editingHost = dom.getParent(selection.getStart(), NodeType.isContentEditableTrue);
+            if (editingHost) {
+              rng = dom.createRng();
+              rng.selectNodeContents(editingHost);
+              selection.setRng(rng);
+            }
+          } else {
+            // IE will render it's own root level block elements and sometimes
+            // even put font elements in them when the user starts typing. So we need to
+            // move the selection to a more suitable element from this:
+            // <body>|<p></p></body> to this: <body><p>|</p></body>
+            rng = selection.getRng();
+            if (!rng.item) {
+              rng.moveToElementText(root);
+              rng.select();
+            }
+          }
+        },
+
+        "delete": function () {
+          DeleteCommands.deleteCommand(editor);
+        },
+
+        "forwardDelete": function () {
+          DeleteCommands.forwardDeleteCommand(editor);
+        },
+
+        mceNewDocument: function () {
+          editor.setContent('');
+        },
+
+        InsertLineBreak: function (command, ui, value) {
+          // We load the current event in from EnterKey.js when appropriate to heed
+          // certain event-specific variations such as ctrl-enter in a list
+          var evt = value;
+          var brElm, extraBr, marker;
+          var rng = selection.getRng(true);
+          new RangeUtils(dom).normalize(rng);
+
+          var offset = rng.startOffset;
+          var container = rng.startContainer;
+
+          // Resolve node index
+          if (container.nodeType == 1 && container.hasChildNodes()) {
+            var isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
+
+            container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
+            if (isAfterLastNodeInContainer && container.nodeType == 3) {
+              offset = container.nodeValue.length;
+            } else {
+              offset = 0;
+            }
+          }
+
+          var parentBlock = dom.getParent(container, dom.isBlock);
+          var parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : ''; // IE < 9 & HTML5
+          var containerBlock = parentBlock ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
+          var containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : ''; // IE < 9 & HTML5
+
+          // Enter inside block contained within a LI then split or insert before/after LI
+          var isControlKey = evt && evt.ctrlKey;
+          if (containerBlockName == 'LI' && !isControlKey) {
+            parentBlock = containerBlock;
+            parentBlockName = containerBlockName;
+          }
+
+          // Walks the parent block to the right and look for BR elements
+          function hasRightSideContent() {
+            var walker = new TreeWalker(container, parentBlock), node;
+            var nonEmptyElementsMap = editor.schema.getNonEmptyElements();
+
+            while ((node = walker.next())) {
+              if (nonEmptyElementsMap[node.nodeName.toLowerCase()] || node.length > 0) {
+                return true;
+              }
+            }
+          }
+
+          if (container && container.nodeType == 3 && offset >= container.nodeValue.length) {
+            // Insert extra BR element at the end block elements
+            if (!isOldIE && !hasRightSideContent()) {
+              brElm = dom.create('br');
+              rng.insertNode(brElm);
+              rng.setStartAfter(brElm);
+              rng.setEndAfter(brElm);
+              extraBr = true;
+            }
+          }
+
+          brElm = dom.create('br');
+          rng.insertNode(brElm);
+
+          // Rendering modes below IE8 doesn't display BR elements in PRE unless we have a \n before it
+          var documentMode = dom.doc.documentMode;
+          if (isOldIE && parentBlockName == 'PRE' && (!documentMode || documentMode < 8)) {
+            brElm.parentNode.insertBefore(dom.doc.createTextNode('\r'), brElm);
+          }
+
+          // Insert temp marker and scroll to that
+          marker = dom.create('span', {}, '&nbsp;');
+          brElm.parentNode.insertBefore(marker, brElm);
+          selection.scrollIntoView(marker);
+          dom.remove(marker);
+
+          if (!extraBr) {
+            rng.setStartAfter(brElm);
+            rng.setEndAfter(brElm);
+          } else {
+            rng.setStartBefore(brElm);
+            rng.setEndBefore(brElm);
+          }
+
+          selection.setRng(rng);
+          editor.undoManager.add();
+
+          return TRUE;
+        }
+      });
+
+      // Add queryCommandState overrides
+      addCommands({
+        // Override justify commands
+        'JustifyLeft,JustifyCenter,JustifyRight,JustifyFull': function (command) {
+          var name = 'align' + command.substring(7);
+          var nodes = selection.isCollapsed() ? [dom.getParent(selection.getNode(), dom.isBlock)] : selection.getSelectedBlocks();
+          var matches = map(nodes, function (node) {
+            return !!formatter.matchNode(node, name);
+          });
+          return inArray(matches, TRUE) !== -1;
+        },
+
+        'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': function (command) {
+          return isFormatMatch(command);
+        },
+
+        mceBlockQuote: function () {
+          return isFormatMatch('blockquote');
+        },
+
+        Outdent: function () {
+          var node;
+
+          if (settings.inline_styles) {
+            if ((node = dom.getParent(selection.getStart(), dom.isBlock)) && parseInt(node.style.paddingLeft, 10) > 0) {
+              return TRUE;
+            }
+
+            if ((node = dom.getParent(selection.getEnd(), dom.isBlock)) && parseInt(node.style.paddingLeft, 10) > 0) {
+              return TRUE;
+            }
+          }
+
+          return (
+            queryCommandState('InsertUnorderedList') ||
+            queryCommandState('InsertOrderedList') ||
+            (!settings.inline_styles && !!dom.getParent(selection.getNode(), 'BLOCKQUOTE'))
+          );
+        },
+
+        'InsertUnorderedList,InsertOrderedList': function (command) {
+          var list = dom.getParent(selection.getNode(), 'ul,ol');
+
+          return list &&
+            (
+              command === 'insertunorderedlist' && list.tagName === 'UL' ||
+              command === 'insertorderedlist' && list.tagName === 'OL'
+            );
+        }
+      }, 'state');
+
+      // Add queryCommandValue overrides
+      addCommands({
+        'FontSize,FontName': function (command) {
+          var value = 0, parent;
+
+          if ((parent = dom.getParent(selection.getNode(), 'span'))) {
+            if (command == 'fontsize') {
+              value = parent.style.fontSize;
+            } else {
+              value = parent.style.fontFamily.replace(/, /g, ',').replace(/[\'\"]/g, '').toLowerCase();
+            }
+          }
+
+          return value;
+        }
+      }, 'value');
+
+      // Add undo manager logic
+      addCommands({
+        Undo: function () {
+          editor.undoManager.undo();
+        },
+
+        Redo: function () {
+          editor.undoManager.redo();
+        }
+      });
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * EditorFocus.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.EditorFocus',
+  [
+    'ephox.katamari.api.Option',
+    'ephox.sugar.api.dom.Compare',
+    'ephox.sugar.api.node.Element',
+    'tinymce.core.caret.CaretFinder',
+    'tinymce.core.dom.ElementType',
+    'tinymce.core.dom.RangeUtils',
+    'tinymce.core.Env'
+  ],
+  function (Option, Compare, Element, CaretFinder, ElementType, RangeUtils, Env) {
+    var getContentEditableHost = function (editor, node) {
+      return editor.dom.getParent(node, function (node) {
+        return editor.dom.getContentEditable(node) === "true";
+      });
+    };
+
+    var getCollapsedNode = function (rng) {
+      return rng.collapsed ? Option.from(RangeUtils.getNode(rng.startContainer, rng.startOffset)).map(Element.fromDom) : Option.none();
+    };
+
+    var getFocusInElement = function (root, rng) {
+      return getCollapsedNode(rng).bind(function (node) {
+        if (ElementType.isTableSection(node)) {
+          return Option.some(node);
+        } else if (Compare.contains(root, node) === false) {
+          return Option.some(root);
+        } else {
+          return Option.none();
+        }
+      });
+    };
+
+    var normalizeSelection = function (editor, rng) {
+      getFocusInElement(Element.fromDom(editor.getBody()), rng).bind(function (elm) {
+        return CaretFinder.firstPositionIn(elm.dom());
+      }).fold(
+        function () {
+          editor.selection.normalize();
+        },
+        function (caretPos) {
+          editor.selection.setRng(caretPos.toRange());
+        }
+      );
+    };
+
+    var focusBody = function (body) {
+      if (body.setActive) {
+        // IE 11 sometimes throws "Invalid function" then fallback to focus
+        // setActive is better since it doesn't scroll to the element being focused
+        try {
+          body.setActive();
+        } catch (ex) {
+          body.focus();
+        }
+      } else {
+        body.focus();
+      }
+    };
+
+    var focusEditor = function (editor) {
+      var selection = editor.selection, contentEditable = editor.settings.content_editable, rng;
+      var controlElm, doc = editor.getDoc(), body = editor.getBody(), contentEditableHost;
+
+      // Get selected control element
+      rng = selection.getRng();
+      if (rng.item) {
+        controlElm = rng.item(0);
+      }
+
+      editor.quirks.refreshContentEditable();
+
+      // Move focus to contentEditable=true child if needed
+      contentEditableHost = getContentEditableHost(editor, selection.getNode());
+      if (editor.$.contains(body, contentEditableHost)) {
+        focusBody(contentEditableHost);
+        normalizeSelection(editor, rng);
+        activateEditor(editor);
+        return;
+      }
+
+      // Focus the window iframe
+      if (!contentEditable) {
+        // WebKit needs this call to fire focusin event properly see #5948
+        // But Opera pre Blink engine will produce an empty selection so skip Opera
+        if (!Env.opera) {
+          focusBody(body);
+        }
+
+        editor.getWin().focus();
+      }
+
+      // Focus the body as well since it's contentEditable
+      if (Env.gecko || contentEditable) {
+        // Restore previous selection before focus to prevent Chrome from
+        // jumping to the top of the document in long inline editors
+        if (contentEditable && document.activeElement !== body) {
+          editor.selection.setRng(editor.lastRng);
+        }
+
+        focusBody(body);
+        normalizeSelection(editor, rng);
+      }
+
+      // Restore selected control element
+      // This is needed when for example an image is selected within a
+      // layer a call to focus will then remove the control selection
+      if (controlElm && controlElm.ownerDocument === doc) {
+        rng = doc.body.createControlRange();
+        rng.addElement(controlElm);
+        rng.select();
+      }
+
+      activateEditor(editor);
+    };
+
+    var activateEditor = function (editor) {
+      editor.editorManager.setActive(editor);
+    };
+
+    var focus = function (editor, skipFocus) {
+      if (editor.removed) {
+        return;
+      }
+
+      skipFocus ? activateEditor(editor) : focusEditor(editor);
+    };
+
+    return {
+      focus: focus
+    };
+  }
+);
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * EditorObservable.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -37835,7 +38474,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">         delegate = function (e) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          var target = e.target, editors = editor.editorManager.editors, i = editors.length;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          var target = e.target, editors = editor.editorManager.get(), i = editors.length;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">           while (i--) {
</span><span class="cx" style="display: block; padding: 0 10px">             var body = editors[i].getBody();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -37940,228 +38579,6 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Shortcuts.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * Contains all logic for handling of keyboard shortcuts.
- *
- * @class tinymce.Shortcuts
- * @example
- * editor.shortcuts.add('ctrl+a', function() {});
- * editor.shortcuts.add('meta+a', function() {}); // "meta" maps to Command on Mac and Ctrl on PC
- * editor.shortcuts.add('ctrl+alt+a', function() {});
- * editor.shortcuts.add('access+a', function() {}); // "access" maps to ctrl+alt on Mac and shift+alt on PC
- */
-define(
-  'tinymce.core.Shortcuts',
-  [
-    "tinymce.core.util.Tools",
-    "tinymce.core.Env"
-  ],
-  function (Tools, Env) {
-    var each = Tools.each, explode = Tools.explode;
-
-    var keyCodeLookup = {
-      "f9": 120,
-      "f10": 121,
-      "f11": 122
-    };
-
-    var modifierNames = Tools.makeMap('alt,ctrl,shift,meta,access');
-
-    return function (editor) {
-      var self = this, shortcuts = {}, pendingPatterns = [];
-
-      function parseShortcut(pattern) {
-        var id, key, shortcut = {};
-
-        // Parse modifiers and keys ctrl+alt+b for example
-        each(explode(pattern, '+'), function (value) {
-          if (value in modifierNames) {
-            shortcut[value] = true;
-          } else {
-            // Allow numeric keycodes like ctrl+219 for ctrl+[
-            if (/^[0-9]{2,}$/.test(value)) {
-              shortcut.keyCode = parseInt(value, 10);
-            } else {
-              shortcut.charCode = value.charCodeAt(0);
-              shortcut.keyCode = keyCodeLookup[value] || value.toUpperCase().charCodeAt(0);
-            }
-          }
-        });
-
-        // Generate unique id for modifier combination and set default state for unused modifiers
-        id = [shortcut.keyCode];
-        for (key in modifierNames) {
-          if (shortcut[key]) {
-            id.push(key);
-          } else {
-            shortcut[key] = false;
-          }
-        }
-        shortcut.id = id.join(',');
-
-        // Handle special access modifier differently depending on Mac/Win
-        if (shortcut.access) {
-          shortcut.alt = true;
-
-          if (Env.mac) {
-            shortcut.ctrl = true;
-          } else {
-            shortcut.shift = true;
-          }
-        }
-
-        // Handle special meta modifier differently depending on Mac/Win
-        if (shortcut.meta) {
-          if (Env.mac) {
-            shortcut.meta = true;
-          } else {
-            shortcut.ctrl = true;
-            shortcut.meta = false;
-          }
-        }
-
-        return shortcut;
-      }
-
-      function createShortcut(pattern, desc, cmdFunc, scope) {
-        var shortcuts;
-
-        shortcuts = Tools.map(explode(pattern, '>'), parseShortcut);
-        shortcuts[shortcuts.length - 1] = Tools.extend(shortcuts[shortcuts.length - 1], {
-          func: cmdFunc,
-          scope: scope || editor
-        });
-
-        return Tools.extend(shortcuts[0], {
-          desc: editor.translate(desc),
-          subpatterns: shortcuts.slice(1)
-        });
-      }
-
-      function hasModifier(e) {
-        return e.altKey || e.ctrlKey || e.metaKey;
-      }
-
-      function isFunctionKey(e) {
-        return e.type === "keydown" && e.keyCode >= 112 && e.keyCode <= 123;
-      }
-
-      function matchShortcut(e, shortcut) {
-        if (!shortcut) {
-          return false;
-        }
-
-        if (shortcut.ctrl != e.ctrlKey || shortcut.meta != e.metaKey) {
-          return false;
-        }
-
-        if (shortcut.alt != e.altKey || shortcut.shift != e.shiftKey) {
-          return false;
-        }
-
-        if (e.keyCode == shortcut.keyCode || (e.charCode && e.charCode == shortcut.charCode)) {
-          e.preventDefault();
-          return true;
-        }
-
-        return false;
-      }
-
-      function executeShortcutAction(shortcut) {
-        return shortcut.func ? shortcut.func.call(shortcut.scope) : null;
-      }
-
-      editor.on('keyup keypress keydown', function (e) {
-        if ((hasModifier(e) || isFunctionKey(e)) && !e.isDefaultPrevented()) {
-          each(shortcuts, function (shortcut) {
-            if (matchShortcut(e, shortcut)) {
-              pendingPatterns = shortcut.subpatterns.slice(0);
-
-              if (e.type == "keydown") {
-                executeShortcutAction(shortcut);
-              }
-
-              return true;
-            }
-          });
-
-          if (matchShortcut(e, pendingPatterns[0])) {
-            if (pendingPatterns.length === 1) {
-              if (e.type == "keydown") {
-                executeShortcutAction(pendingPatterns[0]);
-              }
-            }
-
-            pendingPatterns.shift();
-          }
-        }
-      });
-
-      /**
-       * Adds a keyboard shortcut for some command or function.
-       *
-       * @method add
-       * @param {String} pattern Shortcut pattern. Like for example: ctrl+alt+o.
-       * @param {String} desc Text description for the command.
-       * @param {String/Function} cmdFunc Command name string or function to execute when the key is pressed.
-       * @param {Object} scope Optional scope to execute the function in.
-       * @return {Boolean} true/false state if the shortcut was added or not.
-       */
-      self.add = function (pattern, desc, cmdFunc, scope) {
-        var cmd;
-
-        cmd = cmdFunc;
-
-        if (typeof cmdFunc === 'string') {
-          cmdFunc = function () {
-            editor.execCommand(cmd, false, null);
-          };
-        } else if (Tools.isArray(cmd)) {
-          cmdFunc = function () {
-            editor.execCommand(cmd[0], cmd[1], cmd[2]);
-          };
-        }
-
-        each(explode(Tools.trim(pattern.toLowerCase())), function (pattern) {
-          var shortcut = createShortcut(pattern, desc, cmdFunc, scope);
-          shortcuts[shortcut.id] = shortcut;
-        });
-
-        return true;
-      };
-
-      /**
-       * Remove a keyboard shortcut by pattern.
-       *
-       * @method remove
-       * @param {String} pattern Shortcut pattern. Like for example: ctrl+alt+o.
-       * @return {Boolean} true/false state if the shortcut was removed or not.
-       */
-      self.remove = function (pattern) {
-        var shortcut = createShortcut(pattern);
-
-        if (shortcuts[shortcut.id]) {
-          delete shortcuts[shortcut.id];
-          return true;
-        }
-
-        return false;
-      };
-    };
-  }
-);
-
-defineGlobal("global!window", window);
-/**
</del><span class="cx" style="display: block; padding: 0 10px">  * ErrorReporter.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -38180,7 +38597,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><span class="cx" style="display: block; padding: 0 10px">   'tinymce.core.ErrorReporter',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    "tinymce.core.AddOnManager"
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.AddOnManager'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><span class="cx" style="display: block; padding: 0 10px">   function (AddOnManager) {
</span><span class="cx" style="display: block; padding: 0 10px">     var PluginManager = AddOnManager.PluginManager;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -38228,10 +38645,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">       displayError(editor, pluginUrlToMessage(editor, url));
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var contentCssError = function (editor, urls) {
-      displayError(editor, 'Failed to load content css: ' + urls[0]);
-    };
-
</del><span class="cx" style="display: block; padding: 0 10px">     var initError = function (message) {
</span><span class="cx" style="display: block; padding: 0 10px">       var console = window.console;
</span><span class="cx" style="display: block; padding: 0 10px">       if (console && !window.test) { // Skip test env
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -38247,7 +38660,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">       pluginLoadError: pluginLoadError,
</span><span class="cx" style="display: block; padding: 0 10px">       uploadError: uploadError,
</span><span class="cx" style="display: block; padding: 0 10px">       displayError: displayError,
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      contentCssError: contentCssError,
</del><span class="cx" style="display: block; padding: 0 10px">       initError: initError
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -38269,11 +38681,15 @@
</span><span class="cx" style="display: block; padding: 0 10px">   'tinymce.core.caret.CaretContainerInput',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><span class="cx" style="display: block; padding: 0 10px">     'ephox.katamari.api.Fun',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.search.SelectorFind',
</ins><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.caret.CaretContainer'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Fun, CaretContainer) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Fun, Element, SelectorFind, CaretContainer) {
</ins><span class="cx" style="display: block; padding: 0 10px">     var findBlockCaretContainer = function (editor) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return editor.dom.select('*[data-mce-caret]')[0];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return SelectorFind.descendant(Element.fromDom(editor.getBody()), '*[data-mce-caret]').fold(Fun.constant(null), function (elm) {
+        return elm.dom();
+      });
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var removeIeControlRect = function (editor) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -38524,6 +38940,45 @@
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+define(
+  'ephox.sand.api.Window',
+
+  [
+    'ephox.sand.util.Global'
+  ],
+
+  function (Global) {
+    /******************************************************************************************
+     * BIG BIG WARNING: Don't put anything other than top-level window functions in here.
+     *
+     * Objects that are technically available as window.X should be in their own module X (e.g. Blob, FileReader, URL).
+     ******************************************************************************************
+     */
+
+    /*
+     * IE10 and above per
+     * https://developer.mozilla.org/en/docs/Web/API/window.requestAnimationFrame
+     */
+    var requestAnimationFrame = function (callback) {
+      var f = Global.getOrDie('requestAnimationFrame');
+      f(callback);
+    };
+
+    /*
+     * IE10 and above per
+     * https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64.atob
+     */
+    var atob = function (base64) {
+      var f = Global.getOrDie('atob');
+      return f(base64);
+    };
+
+    return {
+      atob: atob,
+      requestAnimationFrame: requestAnimationFrame
+    };
+  }
+);
</ins><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px">  * Conversions.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -38543,9 +38998,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><span class="cx" style="display: block; padding: 0 10px">   'tinymce.core.file.Conversions',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    "tinymce.core.util.Promise"
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.sand.api.Window',
+    'tinymce.core.util.Promise'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Promise) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Window, Promise) {
</ins><span class="cx" style="display: block; padding: 0 10px">     function blobUriToBlob(url) {
</span><span class="cx" style="display: block; padding: 0 10px">       return new Promise(function (resolve, reject) {
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -38603,7 +39059,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">         // Might throw error if data isn't proper base64
</span><span class="cx" style="display: block; padding: 0 10px">         try {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          str = atob(uri.data);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          str = Window.atob(uri.data);
</ins><span class="cx" style="display: block; padding: 0 10px">         } catch (e) {
</span><span class="cx" style="display: block; padding: 0 10px">           resolve(new Blob([]));
</span><span class="cx" style="display: block; padding: 0 10px">           return;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -38825,6 +39281,40 @@
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+define(
+  'ephox.sand.api.URL',
+
+  [
+    'ephox.sand.util.Global'
+  ],
+
+  function (Global) {
+    /*
+     * IE10 and above per
+     * https://developer.mozilla.org/en-US/docs/Web/API/URL.createObjectURL
+     *
+     * Also Safari 6.1+
+     * Safari 6.0 has 'webkitURL' instead, but doesn't support flexbox so we
+     * aren't supporting it anyway
+     */
+    var url = function () {
+      return Global.getOrDie('URL');
+    };
+
+    var createObjectURL = function (blob) {
+      return url().createObjectURL(blob);
+    };
+
+    var revokeObjectURL = function (u) {
+      url().revokeObjectURL(u);
+    };
+
+    return {
+      createObjectURL: createObjectURL,
+      revokeObjectURL: revokeObjectURL
+    };
+  }
+);
</ins><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px">  * Uuid.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -38867,7 +39357,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-defineGlobal("global!URL", URL);
</del><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px">  * BlobCache.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -38887,12 +39376,12 @@
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><span class="cx" style="display: block; padding: 0 10px">   'tinymce.core.file.BlobCache',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.sand.api.URL',
</ins><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.Arr',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.Fun',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.util.Uuid',
-    'global!URL'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.util.Uuid'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Arr, Fun, Uuid, URL) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (URL, Arr, Fun, Uuid) {
</ins><span class="cx" style="display: block; padding: 0 10px">     return function () {
</span><span class="cx" style="display: block; padding: 0 10px">       var cache = [], constant = Fun.constant;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -39263,7 +39752,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">           var blobInfo = blobCache.getByUri(blobUri);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">           if (!blobInfo) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            blobInfo = Arr.reduce(editor.editorManager.editors, function (result, editor) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            blobInfo = Arr.reduce(editor.editorManager.get(), function (result, editor) {
</ins><span class="cx" style="display: block; padding: 0 10px">               return result || editor.editorUpload && editor.editorUpload.blobCache.getByUri(blobUri);
</span><span class="cx" style="display: block; padding: 0 10px">             }, null);
</span><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -40317,9 +40806,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">       };
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var execute = function (patterns, evt) {
+      return Arr.find(match(patterns, evt), function (pattern) {
+        return pattern.action();
+      });
+    };
+
</ins><span class="cx" style="display: block; padding: 0 10px">     return {
</span><span class="cx" style="display: block; padding: 0 10px">       match: match,
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      action: action
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      action: action,
+      execute: execute
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -40336,27 +40832,21 @@
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><span class="cx" style="display: block; padding: 0 10px">   'tinymce.core.keyboard.ArrowKeys',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'ephox.katamari.api.Arr',
-    'ephox.katamari.api.Cell',
</del><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.keyboard.BoundarySelection',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.keyboard.CefNavigation',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.keyboard.MatchKeys',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.VK'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Arr, Cell, BoundarySelection, CefNavigation, MatchKeys, VK) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (BoundarySelection, CefNavigation, MatchKeys, VK) {
</ins><span class="cx" style="display: block; padding: 0 10px">     var executeKeydownOverride = function (editor, caret, evt) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var matches = MatchKeys.match([
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      MatchKeys.execute([
</ins><span class="cx" style="display: block; padding: 0 10px">         { keyCode: VK.RIGHT, action: CefNavigation.moveH(editor, true) },
</span><span class="cx" style="display: block; padding: 0 10px">         { keyCode: VK.LEFT, action: CefNavigation.moveH(editor, false) },
</span><span class="cx" style="display: block; padding: 0 10px">         { keyCode: VK.UP, action: CefNavigation.moveV(editor, false) },
</span><span class="cx" style="display: block; padding: 0 10px">         { keyCode: VK.DOWN, action: CefNavigation.moveV(editor, true) },
</span><span class="cx" style="display: block; padding: 0 10px">         { keyCode: VK.RIGHT, action: BoundarySelection.move(editor, caret, true) },
</span><span class="cx" style="display: block; padding: 0 10px">         { keyCode: VK.LEFT, action: BoundarySelection.move(editor, caret, false) }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      ], evt);
-
-      Arr.find(matches, function (pattern) {
-        return pattern.action();
-      }).each(function (_) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      ], evt).each(function (_) {
</ins><span class="cx" style="display: block; padding: 0 10px">         evt.preventDefault();
</span><span class="cx" style="display: block; padding: 0 10px">       });
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -40388,7 +40878,6 @@
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><span class="cx" style="display: block; padding: 0 10px">   'tinymce.core.keyboard.DeleteBackspaceKeys',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'ephox.katamari.api.Arr',
</del><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.delete.BlockBoundaryDelete',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.delete.BlockRangeDelete',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.delete.CefDelete',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -40396,9 +40885,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.keyboard.MatchKeys',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.VK'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Arr, BlockBoundaryDelete, BlockRangeDelete, CefDelete, InlineBoundaryDelete, MatchKeys, VK) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (BlockBoundaryDelete, BlockRangeDelete, CefDelete, InlineBoundaryDelete, MatchKeys, VK) {
</ins><span class="cx" style="display: block; padding: 0 10px">     var executeKeydownOverride = function (editor, caret, evt) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var matches = MatchKeys.match([
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      MatchKeys.execute([
</ins><span class="cx" style="display: block; padding: 0 10px">         { keyCode: VK.BACKSPACE, action: MatchKeys.action(CefDelete.backspaceDelete, editor, false) },
</span><span class="cx" style="display: block; padding: 0 10px">         { keyCode: VK.DELETE, action: MatchKeys.action(CefDelete.backspaceDelete, editor, true) },
</span><span class="cx" style="display: block; padding: 0 10px">         { keyCode: VK.BACKSPACE, action: MatchKeys.action(InlineBoundaryDelete.backspaceDelete, editor, caret, false) },
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -40407,24 +40896,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">         { keyCode: VK.DELETE, action: MatchKeys.action(BlockRangeDelete.backspaceDelete, editor, true) },
</span><span class="cx" style="display: block; padding: 0 10px">         { keyCode: VK.BACKSPACE, action: MatchKeys.action(BlockBoundaryDelete.backspaceDelete, editor, false) },
</span><span class="cx" style="display: block; padding: 0 10px">         { keyCode: VK.DELETE, action: MatchKeys.action(BlockBoundaryDelete.backspaceDelete, editor, true) }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      ], evt);
-
-      Arr.find(matches, function (pattern) {
-        return pattern.action();
-      }).each(function (_) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      ], evt).each(function (_) {
</ins><span class="cx" style="display: block; padding: 0 10px">         evt.preventDefault();
</span><span class="cx" style="display: block; padding: 0 10px">       });
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var executeKeyupOverride = function (editor, evt) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var matches = MatchKeys.match([
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      MatchKeys.execute([
</ins><span class="cx" style="display: block; padding: 0 10px">         { keyCode: VK.BACKSPACE, action: MatchKeys.action(CefDelete.paddEmptyElement, editor) },
</span><span class="cx" style="display: block; padding: 0 10px">         { keyCode: VK.DELETE, action: MatchKeys.action(CefDelete.paddEmptyElement, editor) }
</span><span class="cx" style="display: block; padding: 0 10px">       ], evt);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-      Arr.find(matches, function (pattern) {
-        return pattern.action();
-      });
</del><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var setup = function (editor, caret) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -40448,7 +40929,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * EnterKey.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * InsertNewLine.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -40457,23 +40938,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Contributing: http://www.tinymce.com/contributing
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/**
- * Contains logic for handling the enter key to split/generate block elements.
- */
</del><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.keyboard.EnterKey',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.keyboard.InsertNewLine',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.caret.CaretContainer',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.dom.NodeType',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.dom.RangeUtils',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.dom.TreeWalker',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.Env',
</del><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.text.Zwsp',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.Tools'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (CaretContainer, NodeType, RangeUtils, TreeWalker, Env, Zwsp, Tools) {
-    var isIE = Env.ie && Env.ie < 11;
-
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (CaretContainer, NodeType, RangeUtils, TreeWalker, Zwsp, Tools) {
</ins><span class="cx" style="display: block; padding: 0 10px">     var isEmptyAnchor = function (elm) {
</span><span class="cx" style="display: block; padding: 0 10px">       return elm && elm.nodeName === "A" && Tools.trim(Zwsp.trim(elm.innerText || elm.textContent)).length === 0;
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -40482,15 +40957,30 @@
</span><span class="cx" style="display: block; padding: 0 10px">       return node && /^(TD|TH|CAPTION)$/.test(node.nodeName);
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var hasFirstChild = function (elm, name) {
+      return elm.firstChild && elm.firstChild.nodeName == name;
+    };
+
+    var hasParent = function (elm, parentName) {
+      return elm && elm.parentNode && elm.parentNode.nodeName === parentName;
+    };
+
</ins><span class="cx" style="display: block; padding: 0 10px">     var emptyBlock = function (elm) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // BR is needed in empty blocks on non IE browsers
-      elm.innerHTML = !isIE ? '<br data-mce-bogus="1">' : '';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      elm.innerHTML = '<br data-mce-bogus="1">';
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var containerAndSiblingName = function (container, nodeName) {
</span><span class="cx" style="display: block; padding: 0 10px">       return container.nodeName === nodeName || (container.previousSibling && container.previousSibling.nodeName === nodeName);
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isListBlock = function (elm) {
+      return elm && /^(OL|UL|LI)$/.test(elm.nodeName);
+    };
+
+    var isNestedList = function (elm) {
+      return isListBlock(elm) && isListBlock(elm.parentNode);
+    };
+
</ins><span class="cx" style="display: block; padding: 0 10px">     // Returns true if the block can be split into two blocks or not
</span><span class="cx" style="display: block; padding: 0 10px">     var canSplitBlock = function (dom, node) {
</span><span class="cx" style="display: block; padding: 0 10px">       return node &&
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -40500,19 +40990,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">         dom.getContentEditable(node) !== "true";
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // Renders empty block on IE
-    var renderBlockOnIE = function (dom, selection, block) {
-      var oldRng;
-
-      if (dom.isBlock(block)) {
-        oldRng = selection.getRng();
-        block.appendChild(dom.create('span', null, '\u00a0'));
-        selection.select(block);
-        block.lastChild.outerHTML = '';
-        selection.setRng(oldRng);
-      }
-    };
-
</del><span class="cx" style="display: block; padding: 0 10px">     // Remove the first empty inline element of the block so this: <p><b><em></em></b>x</p> becomes this: <p>x</p>
</span><span class="cx" style="display: block; padding: 0 10px">     var trimInlineElementsOnLeftSideOfBlock = function (dom, nonEmptyElementsMap, block) {
</span><span class="cx" style="display: block; padding: 0 10px">       var node = block, firstChilds = [], i;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -40572,605 +41049,597 @@
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var setup = function (editor) {
-      var dom = editor.dom, selection = editor.selection, settings = editor.settings;
-      var undoManager = editor.undoManager, schema = editor.schema, nonEmptyElementsMap = schema.getNonEmptyElements(),
-        moveCaretBeforeOnEnterElementsMap = schema.getMoveCaretBeforeOnEnterElements();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Inserts a BR element if the forced_root_block option is set to false or empty string
+    var insertBr = function (editor, evt) {
+      editor.execCommand("InsertLineBreak", false, evt);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function handleEnterKey(evt) {
-        var rng, tmpRng, editableRoot, container, offset, parentBlock, documentMode, shiftKey,
-          newBlock, fragment, containerBlock, parentBlockName, containerBlockName, newBlockName, isAfterLastNodeInContainer;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Trims any linebreaks at the beginning of node user for example when pressing enter in a PRE element
+    var trimLeadingLineBreaks = function (node) {
+      do {
+        if (node.nodeType === 3) {
+          node.nodeValue = node.nodeValue.replace(/^[\r\n]+/, '');
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Moves the caret to a suitable position within the root for example in the first non
-        // pure whitespace text node or before an image
-        function moveToCaretPosition(root) {
-          var walker, node, rng, lastNode = root, tempElm;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        node = node.firstChild;
+      } while (node);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (!root) {
-            return;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var getEditableRoot = function (dom, node) {
+      var root = dom.getRoot(), parent, editableRoot;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Old IE versions doesn't properly render blocks with br elements in them
-          // For example <p><br></p> wont be rendered correctly in a contentEditable area
-          // until you remove the br producing <p></p>
-          if (Env.ie && Env.ie < 9 && parentBlock && parentBlock.firstChild) {
-            if (parentBlock.firstChild == parentBlock.lastChild && parentBlock.firstChild.tagName == 'BR') {
-              dom.remove(parentBlock.firstChild);
-            }
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Get all parents until we hit a non editable parent or the root
+      parent = node;
+      while (parent !== root && dom.getContentEditable(parent) !== "false") {
+        if (dom.getContentEditable(parent) === "true") {
+          editableRoot = parent;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (/^(LI|DT|DD)$/.test(root.nodeName)) {
-            var firstChild = firstNonWhiteSpaceNodeSibling(root.firstChild);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        parent = parent.parentNode;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (firstChild && /^(UL|OL|DL)$/.test(firstChild.nodeName)) {
-              root.insertBefore(dom.doc.createTextNode('\u00a0'), root.firstChild);
-            }
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return parent !== root ? editableRoot : root;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          rng = dom.createRng();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var setForcedBlockAttrs = function (editor, node) {
+      var forcedRootBlockName = editor.settings.forced_root_block;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Normalize whitespace to remove empty text nodes. Fix for: #6904
-          // Gecko will be able to place the caret in empty text nodes but it won't render propery
-          // Older IE versions will sometimes crash so for now ignore all IE versions
-          if (!Env.ie) {
-            root.normalize();
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (forcedRootBlockName && forcedRootBlockName.toLowerCase() === node.tagName.toLowerCase()) {
+        editor.dom.setAttribs(node, editor.settings.forced_root_block_attrs);
+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (root.hasChildNodes()) {
-            walker = new TreeWalker(root, root);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Wraps any text nodes or inline elements in the specified forced root block name
+    var wrapSelfAndSiblingsInDefaultBlock = function (editor, newBlockName, rng, container, offset) {
+      var newBlock, parentBlock, startNode, node, next, rootBlockName, blockName = newBlockName || 'P';
+      var dom = editor.dom, editableRoot = getEditableRoot(dom, container);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            while ((node = walker.current())) {
-              if (node.nodeType == 3) {
-                rng.setStart(node, 0);
-                rng.setEnd(node, 0);
-                break;
-              }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Not in a block element or in a table cell or caption
+      parentBlock = dom.getParent(container, dom.isBlock);
+      if (!parentBlock || !canSplitBlock(dom, parentBlock)) {
+        parentBlock = parentBlock || editableRoot;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              if (moveCaretBeforeOnEnterElementsMap[node.nodeName.toLowerCase()]) {
-                rng.setStartBefore(node);
-                rng.setEndBefore(node);
-                break;
-              }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (parentBlock == editor.getBody() || isTableCell(parentBlock)) {
+          rootBlockName = parentBlock.nodeName.toLowerCase();
+        } else {
+          rootBlockName = parentBlock.parentNode.nodeName.toLowerCase();
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              lastNode = node;
-              node = walker.next();
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (!parentBlock.hasChildNodes()) {
+          newBlock = dom.create(blockName);
+          setForcedBlockAttrs(editor, newBlock);
+          parentBlock.appendChild(newBlock);
+          rng.setStart(newBlock, 0);
+          rng.setEnd(newBlock, 0);
+          return newBlock;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (!node) {
-              rng.setStart(lastNode, 0);
-              rng.setEnd(lastNode, 0);
-            }
-          } else {
-            if (root.nodeName == 'BR') {
-              if (root.nextSibling && dom.isBlock(root.nextSibling)) {
-                // Trick on older IE versions to render the caret before the BR between two lists
-                if (!documentMode || documentMode < 9) {
-                  tempElm = dom.create('br');
-                  root.parentNode.insertBefore(tempElm, root);
-                }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Find parent that is the first child of parentBlock
+        node = container;
+        while (node.parentNode != parentBlock) {
+          node = node.parentNode;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                rng.setStartBefore(root);
-                rng.setEndBefore(root);
-              } else {
-                rng.setStartAfter(root);
-                rng.setEndAfter(root);
-              }
-            } else {
-              rng.setStart(root, 0);
-              rng.setEnd(root, 0);
-            }
-          }
-
-          selection.setRng(rng);
-
-          // Remove tempElm created for old IE:s
-          dom.remove(tempElm);
-          selection.scrollIntoView(root);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Loop left to find start node start wrapping at
+        while (node && !dom.isBlock(node)) {
+          startNode = node;
+          node = node.previousSibling;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function setForcedBlockAttrs(node) {
-          var forcedRootBlockName = settings.forced_root_block;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (startNode && editor.schema.isValidChild(rootBlockName, blockName.toLowerCase())) {
+          newBlock = dom.create(blockName);
+          setForcedBlockAttrs(editor, newBlock);
+          startNode.parentNode.insertBefore(newBlock, startNode);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (forcedRootBlockName && forcedRootBlockName.toLowerCase() === node.tagName.toLowerCase()) {
-            dom.setAttribs(node, settings.forced_root_block_attrs);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          // Start wrapping until we hit a block
+          node = startNode;
+          while (node && !dom.isBlock(node)) {
+            next = node.nextSibling;
+            newBlock.appendChild(node);
+            node = next;
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+          // Restore range to it's past location
+          rng.setStart(container, offset);
+          rng.setEnd(container, offset);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Creates a new block element by cloning the current one or creating a new one if the name is specified
-        // This function will also copy any text formatting from the parent block and add it to the new one
-        function createNewBlock(name) {
-          var node = container, block, clonedNode, caretNode, textInlineElements = schema.getTextInlineElements();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return container;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (name || parentBlockName == "TABLE" || parentBlockName == "HR") {
-            block = dom.create(name || newBlockName);
-            setForcedBlockAttrs(block);
-          } else {
-            block = parentBlock.cloneNode(false);
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Adds a BR at the end of blocks that only contains an IMG or INPUT since
+    // these might be floated and then they won't expand the block
+    var addBrToBlockIfNeeded = function (dom, block) {
+      var lastChild;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          caretNode = block;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // IE will render the blocks correctly other browsers needs a BR
+      block.normalize(); // Remove empty text nodes that got left behind by the extract
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (settings.keep_styles === false) {
-            dom.setAttrib(block, 'style', null); // wipe out any styles that came over with the block
-            dom.setAttrib(block, 'class', null);
-          } else {
-            // Clone any parent styles
-            do {
-              if (textInlineElements[node.nodeName]) {
-                // Never clone a caret containers
-                if (node.id == '_mce_caret') {
-                  continue;
-                }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Check if the block is empty or contains a floated last child
+      lastChild = block.lastChild;
+      if (!lastChild || (/^(left|right)$/gi.test(dom.getStyle(lastChild, 'float', true)))) {
+        dom.add(block, 'br');
+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                clonedNode = node.cloneNode(false);
-                dom.setAttrib(clonedNode, 'id', ''); // Remove ID since it needs to be document unique
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var getContainerBlock = function (containerBlock) {
+      var containerBlockParent = containerBlock.parentNode;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if (block.hasChildNodes()) {
-                  clonedNode.appendChild(block.firstChild);
-                  block.appendChild(clonedNode);
-                } else {
-                  caretNode = clonedNode;
-                  block.appendChild(clonedNode);
-                }
-              }
-            } while ((node = node.parentNode) && node != editableRoot);
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (/^(LI|DT|DD)$/.test(containerBlockParent.nodeName)) {
+        return containerBlockParent;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // BR is needed in empty blocks on non IE browsers
-          if (!isIE) {
-            caretNode.innerHTML = '<br data-mce-bogus="1">';
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return containerBlock;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return block;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isFirstOrLastLi = function (containerBlock, parentBlock, first) {
+      var node = containerBlock[first ? 'firstChild' : 'lastChild'];
+
+      // Find first/last element since there might be whitespace there
+      while (node) {
+        if (node.nodeType == 1) {
+          break;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Returns true/false if the caret is at the start/end of the parent block element
-        function isCaretAtStartOrEndOfBlock(start) {
-          var walker, node, name, normalizedOffset;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        node = node[first ? 'nextSibling' : 'previousSibling'];
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          normalizedOffset = normalizeZwspOffset(start, container, offset);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return node === parentBlock;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Caret is in the middle of a text node like "a|b"
-          if (container.nodeType == 3 && (start ? normalizedOffset > 0 : normalizedOffset < container.nodeValue.length)) {
-            return false;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var insert = function (editor, evt) {
+      var tmpRng, editableRoot, container, offset, parentBlock, shiftKey;
+      var newBlock, fragment, containerBlock, parentBlockName, containerBlockName, newBlockName, isAfterLastNodeInContainer;
+      var dom = editor.dom, selection = editor.selection, settings = editor.settings;
+      var schema = editor.schema, nonEmptyElementsMap = schema.getNonEmptyElements();
+      var rng = editor.selection.getRng();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // If after the last element in block node edge case for #5091
-          if (container.parentNode == parentBlock && isAfterLastNodeInContainer && !start) {
-            return true;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Moves the caret to a suitable position within the root for example in the first non
+      // pure whitespace text node or before an image
+      function moveToCaretPosition(root) {
+        var walker, node, rng, lastNode = root, tempElm;
+        var moveCaretBeforeOnEnterElementsMap = schema.getMoveCaretBeforeOnEnterElements();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // If the caret if before the first element in parentBlock
-          if (start && container.nodeType == 1 && container == parentBlock.firstChild) {
-            return true;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (!root) {
+          return;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Caret can be before/after a table or a hr
-          if (containerAndSiblingName(container, 'TABLE') || containerAndSiblingName(container, 'HR')) {
-            return (isAfterLastNodeInContainer && !start) || (!isAfterLastNodeInContainer && start);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (/^(LI|DT|DD)$/.test(root.nodeName)) {
+          var firstChild = firstNonWhiteSpaceNodeSibling(root.firstChild);
+
+          if (firstChild && /^(UL|OL|DL)$/.test(firstChild.nodeName)) {
+            root.insertBefore(dom.doc.createTextNode('\u00a0'), root.firstChild);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Walk the DOM and look for text nodes or non empty elements
-          walker = new TreeWalker(container, parentBlock);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        rng = dom.createRng();
+        root.normalize();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // If caret is in beginning or end of a text block then jump to the next/previous node
-          if (container.nodeType == 3) {
-            if (start && normalizedOffset === 0) {
-              walker.prev();
-            } else if (!start && normalizedOffset == container.nodeValue.length) {
-              walker.next();
-            }
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (root.hasChildNodes()) {
+          walker = new TreeWalker(root, root);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">           while ((node = walker.current())) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (node.nodeType === 1) {
-              // Ignore bogus elements
-              if (!node.getAttribute('data-mce-bogus')) {
-                // Keep empty elements like <img /> <input /> but not trailing br:s like <p>text|<br></p>
-                name = node.nodeName.toLowerCase();
-                if (nonEmptyElementsMap[name] && name !== 'br') {
-                  return false;
-                }
-              }
-            } else if (node.nodeType === 3 && !/^[ \t\r\n]*$/.test(node.nodeValue)) {
-              return false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            if (node.nodeType == 3) {
+              rng.setStart(node, 0);
+              rng.setEnd(node, 0);
+              break;
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (start) {
-              walker.prev();
-            } else {
-              walker.next();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            if (moveCaretBeforeOnEnterElementsMap[node.nodeName.toLowerCase()]) {
+              rng.setStartBefore(node);
+              rng.setEndBefore(node);
+              break;
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+            lastNode = node;
+            node = walker.next();
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return true;
-        }
-
-        // Wraps any text nodes or inline elements in the specified forced root block name
-        function wrapSelfAndSiblingsInDefaultBlock(container, offset) {
-          var newBlock, parentBlock, startNode, node, next, rootBlockName, blockName = newBlockName || 'P';
-
-          // Not in a block element or in a table cell or caption
-          parentBlock = dom.getParent(container, dom.isBlock);
-          if (!parentBlock || !canSplitBlock(dom, parentBlock)) {
-            parentBlock = parentBlock || editableRoot;
-
-            if (parentBlock == editor.getBody() || isTableCell(parentBlock)) {
-              rootBlockName = parentBlock.nodeName.toLowerCase();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (!node) {
+            rng.setStart(lastNode, 0);
+            rng.setEnd(lastNode, 0);
+          }
+        } else {
+          if (root.nodeName == 'BR') {
+            if (root.nextSibling && dom.isBlock(root.nextSibling)) {
+              rng.setStartBefore(root);
+              rng.setEndBefore(root);
</ins><span class="cx" style="display: block; padding: 0 10px">             } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              rootBlockName = parentBlock.parentNode.nodeName.toLowerCase();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              rng.setStartAfter(root);
+              rng.setEndAfter(root);
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          } else {
+            rng.setStart(root, 0);
+            rng.setEnd(root, 0);
+          }
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (!parentBlock.hasChildNodes()) {
-              newBlock = dom.create(blockName);
-              setForcedBlockAttrs(newBlock);
-              parentBlock.appendChild(newBlock);
-              rng.setStart(newBlock, 0);
-              rng.setEnd(newBlock, 0);
-              return newBlock;
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        selection.setRng(rng);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // Find parent that is the first child of parentBlock
-            node = container;
-            while (node.parentNode != parentBlock) {
-              node = node.parentNode;
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Remove tempElm created for old IE:s
+        dom.remove(tempElm);
+        selection.scrollIntoView(root);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // Loop left to find start node start wrapping at
-            while (node && !dom.isBlock(node)) {
-              startNode = node;
-              node = node.previousSibling;
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Creates a new block element by cloning the current one or creating a new one if the name is specified
+      // This function will also copy any text formatting from the parent block and add it to the new one
+      function createNewBlock(name) {
+        var node = container, block, clonedNode, caretNode, textInlineElements = schema.getTextInlineElements();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (startNode && schema.isValidChild(rootBlockName, blockName.toLowerCase())) {
-              newBlock = dom.create(blockName);
-              setForcedBlockAttrs(newBlock);
-              startNode.parentNode.insertBefore(newBlock, startNode);
-
-              // Start wrapping until we hit a block
-              node = startNode;
-              while (node && !dom.isBlock(node)) {
-                next = node.nextSibling;
-                newBlock.appendChild(node);
-                node = next;
-              }
-
-              // Restore range to it's past location
-              rng.setStart(container, offset);
-              rng.setEnd(container, offset);
-            }
-          }
-
-          return container;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (name || parentBlockName == "TABLE" || parentBlockName == "HR") {
+          block = dom.create(name || newBlockName);
+          setForcedBlockAttrs(editor, block);
+        } else {
+          block = parentBlock.cloneNode(false);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Inserts a block or br before/after or in the middle of a split list of the LI is empty
-        function handleEmptyListItem() {
-          function isFirstOrLastLi(first) {
-            var node = containerBlock[first ? 'firstChild' : 'lastChild'];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        caretNode = block;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // Find first/last element since there might be whitespace there
-            while (node) {
-              if (node.nodeType == 1) {
-                break;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (settings.keep_styles === false) {
+          dom.setAttrib(block, 'style', null); // wipe out any styles that came over with the block
+          dom.setAttrib(block, 'class', null);
+        } else {
+          // Clone any parent styles
+          do {
+            if (textInlineElements[node.nodeName]) {
+              // Never clone a caret containers
+              if (node.id == '_mce_caret') {
+                continue;
</ins><span class="cx" style="display: block; padding: 0 10px">               }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              node = node[first ? 'nextSibling' : 'previousSibling'];
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              clonedNode = node.cloneNode(false);
+              dom.setAttrib(clonedNode, 'id', ''); // Remove ID since it needs to be document unique
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            return node === parentBlock;
-          }
-
-          function getContainerBlock() {
-            var containerBlockParent = containerBlock.parentNode;
-
-            if (/^(LI|DT|DD)$/.test(containerBlockParent.nodeName)) {
-              return containerBlockParent;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              if (block.hasChildNodes()) {
+                clonedNode.appendChild(block.firstChild);
+                block.appendChild(clonedNode);
+              } else {
+                caretNode = clonedNode;
+                block.appendChild(clonedNode);
+              }
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          } while ((node = node.parentNode) && node != editableRoot);
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            return containerBlock;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        emptyBlock(caretNode);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (containerBlock == editor.getBody()) {
-            return;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return block;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Check if we are in an nested list
-          var containerBlockParentName = containerBlock.parentNode.nodeName;
-          if (/^(OL|UL|LI)$/.test(containerBlockParentName)) {
-            newBlockName = 'LI';
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Returns true/false if the caret is at the start/end of the parent block element
+      function isCaretAtStartOrEndOfBlock(start) {
+        var walker, node, name, normalizedOffset;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          newBlock = newBlockName ? createNewBlock(newBlockName) : dom.create('BR');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        normalizedOffset = normalizeZwspOffset(start, container, offset);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (isFirstOrLastLi(true) && isFirstOrLastLi()) {
-            if (containerBlockParentName == 'LI') {
-              // Nested list is inside a LI
-              dom.insertAfter(newBlock, getContainerBlock());
-            } else {
-              // Is first and last list item then replace the OL/UL with a text block
-              dom.replace(newBlock, containerBlock);
-            }
-          } else if (isFirstOrLastLi(true)) {
-            if (containerBlockParentName == 'LI') {
-              // List nested in an LI then move the list to a new sibling LI
-              dom.insertAfter(newBlock, getContainerBlock());
-              newBlock.appendChild(dom.doc.createTextNode(' ')); // Needed for IE so the caret can be placed
-              newBlock.appendChild(containerBlock);
-            } else {
-              // First LI in list then remove LI and add text block before list
-              containerBlock.parentNode.insertBefore(newBlock, containerBlock);
-            }
-          } else if (isFirstOrLastLi()) {
-            // Last LI in list then remove LI and add text block after list
-            dom.insertAfter(newBlock, getContainerBlock());
-            renderBlockOnIE(dom, selection, newBlock);
-          } else {
-            // Middle LI in list the split the list and insert a text block in the middle
-            // Extract after fragment and insert it after the current block
-            containerBlock = getContainerBlock();
-            tmpRng = rng.cloneRange();
-            tmpRng.setStartAfter(parentBlock);
-            tmpRng.setEndAfter(containerBlock);
-            fragment = tmpRng.extractContents();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Caret is in the middle of a text node like "a|b"
+        if (container.nodeType == 3 && (start ? normalizedOffset > 0 : normalizedOffset < container.nodeValue.length)) {
+          return false;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (newBlockName == 'LI' && fragment.firstChild.nodeName == 'LI') {
-              newBlock = fragment.firstChild;
-              dom.insertAfter(fragment, containerBlock);
-            } else {
-              dom.insertAfter(fragment, containerBlock);
-              dom.insertAfter(newBlock, containerBlock);
-            }
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // If after the last element in block node edge case for #5091
+        if (container.parentNode == parentBlock && isAfterLastNodeInContainer && !start) {
+          return true;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          dom.remove(parentBlock);
-          moveToCaretPosition(newBlock);
-          undoManager.add();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // If the caret if before the first element in parentBlock
+        if (start && container.nodeType == 1 && container == parentBlock.firstChild) {
+          return true;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Inserts a BR element if the forced_root_block option is set to false or empty string
-        function insertBr() {
-          editor.execCommand("InsertLineBreak", false, evt);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Caret can be before/after a table or a hr
+        if (containerAndSiblingName(container, 'TABLE') || containerAndSiblingName(container, 'HR')) {
+          return (isAfterLastNodeInContainer && !start) || (!isAfterLastNodeInContainer && start);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Trims any linebreaks at the beginning of node user for example when pressing enter in a PRE element
-        function trimLeadingLineBreaks(node) {
-          do {
-            if (node.nodeType === 3) {
-              node.nodeValue = node.nodeValue.replace(/^[\r\n]+/, '');
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Walk the DOM and look for text nodes or non empty elements
+        walker = new TreeWalker(container, parentBlock);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            node = node.firstChild;
-          } while (node);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // If caret is in beginning or end of a text block then jump to the next/previous node
+        if (container.nodeType == 3) {
+          if (start && normalizedOffset === 0) {
+            walker.prev();
+          } else if (!start && normalizedOffset == container.nodeValue.length) {
+            walker.next();
+          }
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function getEditableRoot(node) {
-          var root = dom.getRoot(), parent, editableRoot;
-
-          // Get all parents until we hit a non editable parent or the root
-          parent = node;
-          while (parent !== root && dom.getContentEditable(parent) !== "false") {
-            if (dom.getContentEditable(parent) === "true") {
-              editableRoot = parent;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        while ((node = walker.current())) {
+          if (node.nodeType === 1) {
+            // Ignore bogus elements
+            if (!node.getAttribute('data-mce-bogus')) {
+              // Keep empty elements like <img /> <input /> but not trailing br:s like <p>text|<br></p>
+              name = node.nodeName.toLowerCase();
+              if (nonEmptyElementsMap[name] && name !== 'br') {
+                return false;
+              }
</ins><span class="cx" style="display: block; padding: 0 10px">             }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          } else if (node.nodeType === 3 && !/^[ \t\r\n]*$/.test(node.nodeValue)) {
+            return false;
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            parent = parent.parentNode;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (start) {
+            walker.prev();
+          } else {
+            walker.next();
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-          return parent !== root ? editableRoot : root;
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Adds a BR at the end of blocks that only contains an IMG or INPUT since
-        // these might be floated and then they won't expand the block
-        function addBrToBlockIfNeeded(block) {
-          var lastChild;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return true;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // IE will render the blocks correctly other browsers needs a BR
-          if (!isIE) {
-            block.normalize(); // Remove empty text nodes that got left behind by the extract
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Inserts a block or br before/after or in the middle of a split list of the LI is empty
+      function handleEmptyListItem() {
+        if (containerBlock == editor.getBody()) {
+          return;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            // Check if the block is empty or contains a floated last child
-            lastChild = block.lastChild;
-            if (!lastChild || (/^(left|right)$/gi.test(dom.getStyle(lastChild, 'float', true)))) {
-              dom.add(block, 'br');
-            }
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (isNestedList(containerBlock)) {
+          newBlockName = 'LI';
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function insertNewBlockAfter() {
-          // If the caret is at the end of a header we produce a P tag after it similar to Word unless we are in a hgroup
-          if (/^(H[1-6]|PRE|FIGURE)$/.test(parentBlockName) && containerBlockName != 'HGROUP') {
-            newBlock = createNewBlock(newBlockName);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        newBlock = newBlockName ? createNewBlock(newBlockName) : dom.create('BR');
+
+        if (isFirstOrLastLi(containerBlock, parentBlock, true) && isFirstOrLastLi(containerBlock, parentBlock, false)) {
+          if (hasParent(containerBlock, 'LI')) {
+            // Nested list is inside a LI
+            dom.insertAfter(newBlock, getContainerBlock(containerBlock));
</ins><span class="cx" style="display: block; padding: 0 10px">           } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            newBlock = createNewBlock();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // Is first and last list item then replace the OL/UL with a text block
+            dom.replace(newBlock, containerBlock);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        } else if (isFirstOrLastLi(containerBlock, parentBlock, true)) {
+          if (hasParent(containerBlock, 'LI')) {
+            // List nested in an LI then move the list to a new sibling LI
+            dom.insertAfter(newBlock, getContainerBlock(containerBlock));
+            newBlock.appendChild(dom.doc.createTextNode(' ')); // Needed for IE so the caret can be placed
+            newBlock.appendChild(containerBlock);
+          } else {
+            // First LI in list then remove LI and add text block before list
+            containerBlock.parentNode.insertBefore(newBlock, containerBlock);
+          }
+        } else if (isFirstOrLastLi(containerBlock, parentBlock, false)) {
+          // Last LI in list then remove LI and add text block after list
+          dom.insertAfter(newBlock, getContainerBlock(containerBlock));
+        } else {
+          // Middle LI in list the split the list and insert a text block in the middle
+          // Extract after fragment and insert it after the current block
+          containerBlock = getContainerBlock(containerBlock);
+          tmpRng = rng.cloneRange();
+          tmpRng.setStartAfter(parentBlock);
+          tmpRng.setEndAfter(containerBlock);
+          fragment = tmpRng.extractContents();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Split the current container block element if enter is pressed inside an empty inner block element
-          if (settings.end_container_on_empty_block && canSplitBlock(dom, containerBlock) && dom.isEmpty(parentBlock)) {
-            // Split container block for example a BLOCKQUOTE at the current blockParent location for example a P
-            newBlock = dom.split(containerBlock, parentBlock);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (newBlockName === 'LI' && hasFirstChild(fragment, 'LI')) {
+            newBlock = fragment.firstChild;
+            dom.insertAfter(fragment, containerBlock);
</ins><span class="cx" style="display: block; padding: 0 10px">           } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            dom.insertAfter(newBlock, parentBlock);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            dom.insertAfter(fragment, containerBlock);
+            dom.insertAfter(newBlock, containerBlock);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-          moveToCaretPosition(newBlock);
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        rng = selection.getRng(true);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        dom.remove(parentBlock);
+        moveToCaretPosition(newBlock);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Event is blocked by some other handler for example the lists plugin
-        if (evt.isDefaultPrevented()) {
-          return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      function insertNewBlockAfter() {
+        // If the caret is at the end of a header we produce a P tag after it similar to Word unless we are in a hgroup
+        if (/^(H[1-6]|PRE|FIGURE)$/.test(parentBlockName) && containerBlockName != 'HGROUP') {
+          newBlock = createNewBlock(newBlockName);
+        } else {
+          newBlock = createNewBlock();
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Delete any selected contents
-        if (!rng.collapsed) {
-          editor.execCommand('Delete');
-          return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Split the current container block element if enter is pressed inside an empty inner block element
+        if (settings.end_container_on_empty_block && canSplitBlock(dom, containerBlock) && dom.isEmpty(parentBlock)) {
+          // Split container block for example a BLOCKQUOTE at the current blockParent location for example a P
+          newBlock = dom.split(containerBlock, parentBlock);
+        } else {
+          dom.insertAfter(newBlock, parentBlock);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Setup range items and newBlockName
-        new RangeUtils(dom).normalize(rng);
-        container = rng.startContainer;
-        offset = rng.startOffset;
-        newBlockName = (settings.force_p_newlines ? 'p' : '') || settings.forced_root_block;
-        newBlockName = newBlockName ? newBlockName.toUpperCase() : '';
-        documentMode = dom.doc.documentMode;
-        shiftKey = evt.shiftKey;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        moveToCaretPosition(newBlock);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Resolve node index
-        if (container.nodeType == 1 && container.hasChildNodes()) {
-          isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Setup range items and newBlockName
+      new RangeUtils(dom).normalize(rng);
+      container = rng.startContainer;
+      offset = rng.startOffset;
+      newBlockName = (settings.force_p_newlines ? 'p' : '') || settings.forced_root_block;
+      newBlockName = newBlockName ? newBlockName.toUpperCase() : '';
+      shiftKey = evt.shiftKey;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
-          if (isAfterLastNodeInContainer && container.nodeType == 3) {
-            offset = container.nodeValue.length;
-          } else {
-            offset = 0;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Resolve node index
+      if (container.nodeType == 1 && container.hasChildNodes()) {
+        isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
+
+        container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
+        if (isAfterLastNodeInContainer && container.nodeType == 3) {
+          offset = container.nodeValue.length;
+        } else {
+          offset = 0;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Get editable root node, normally the body element but sometimes a div or span
-        editableRoot = getEditableRoot(container);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Get editable root node, normally the body element but sometimes a div or span
+      editableRoot = getEditableRoot(dom, container);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // If there is no editable root then enter is done inside a contentEditable false element
-        if (!editableRoot) {
-          return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // If there is no editable root then enter is done inside a contentEditable false element
+      if (!editableRoot) {
+        return;
+      }
+
+      // If editable root isn't block nor the root of the editor
+      if (!dom.isBlock(editableRoot) && editableRoot != dom.getRoot()) {
+        if (!newBlockName || shiftKey) {
+          insertBr(editor, evt);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        undoManager.beforeChange();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // If editable root isn't block nor the root of the editor
-        if (!dom.isBlock(editableRoot) && editableRoot != dom.getRoot()) {
-          if (!newBlockName || shiftKey) {
-            insertBr();
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Wrap the current node and it's sibling in a default block if it's needed.
+      // for example this <td>text|<b>text2</b></td> will become this <td><p>text|<b>text2</p></b></td>
+      // This won't happen if root blocks are disabled or the shiftKey is pressed
+      if ((newBlockName && !shiftKey) || (!newBlockName && shiftKey)) {
+        container = wrapSelfAndSiblingsInDefaultBlock(editor, newBlockName, rng, container, offset);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Find parent block and setup empty block paddings
+      parentBlock = dom.getParent(container, dom.isBlock);
+      containerBlock = parentBlock ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Wrap the current node and it's sibling in a default block if it's needed.
-        // for example this <td>text|<b>text2</b></td> will become this <td><p>text|<b>text2</p></b></td>
-        // This won't happen if root blocks are disabled or the shiftKey is pressed
-        if ((newBlockName && !shiftKey) || (!newBlockName && shiftKey)) {
-          container = wrapSelfAndSiblingsInDefaultBlock(container, offset);
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Setup block names
+      parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : ''; // IE < 9 & HTML5
+      containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : ''; // IE < 9 & HTML5
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Find parent block and setup empty block paddings
-        parentBlock = dom.getParent(container, dom.isBlock);
-        containerBlock = parentBlock ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Enter inside block contained within a LI then split or insert before/after LI
+      if (containerBlockName == 'LI' && !evt.ctrlKey) {
+        parentBlock = containerBlock;
+        containerBlock = containerBlock.parentNode;
+        parentBlockName = containerBlockName;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Setup block names
-        parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : ''; // IE < 9 & HTML5
-        containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : ''; // IE < 9 & HTML5
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Handle enter in list item
+      if (/^(LI|DT|DD)$/.test(parentBlockName)) {
+        if (!newBlockName && shiftKey) {
+          insertBr(editor, evt);
+          return;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Enter inside block contained within a LI then split or insert before/after LI
-        if (containerBlockName == 'LI' && !evt.ctrlKey) {
-          parentBlock = containerBlock;
-          parentBlockName = containerBlockName;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Handle enter inside an empty list item
+        if (dom.isEmpty(parentBlock)) {
+          handleEmptyListItem();
+          return;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (editor.undoManager.typing) {
-          editor.undoManager.typing = false;
-          editor.undoManager.add();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Don't split PRE tags but insert a BR instead easier when writing code samples etc
+      if (parentBlockName == 'PRE' && settings.br_in_pre !== false) {
+        if (!shiftKey) {
+          insertBr(editor, evt);
+          return;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      } else {
+        // If no root block is configured then insert a BR by default or if the shiftKey is pressed
+        if ((!newBlockName && !shiftKey && parentBlockName != 'LI') || (newBlockName && shiftKey)) {
+          insertBr(editor, evt);
+          return;
+        }
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Handle enter in list item
-        if (/^(LI|DT|DD)$/.test(parentBlockName)) {
-          if (!newBlockName && shiftKey) {
-            insertBr();
-            return;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // If parent block is root then never insert new blocks
+      if (newBlockName && parentBlock === editor.getBody()) {
+        return;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Handle enter inside an empty list item
-          if (dom.isEmpty(parentBlock)) {
-            handleEmptyListItem();
-            return;
-          }
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Default block name if it's not configured
+      newBlockName = newBlockName || 'P';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Don't split PRE tags but insert a BR instead easier when writing code samples etc
-        if (parentBlockName == 'PRE' && settings.br_in_pre !== false) {
-          if (!shiftKey) {
-            insertBr();
-            return;
-          }
-        } else {
-          // If no root block is configured then insert a BR by default or if the shiftKey is pressed
-          if ((!newBlockName && !shiftKey && parentBlockName != 'LI') || (newBlockName && shiftKey)) {
-            insertBr();
-            return;
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Insert new block before/after the parent block depending on caret location
+      if (CaretContainer.isCaretContainerBlock(parentBlock)) {
+        newBlock = CaretContainer.showCaretContainerBlock(parentBlock);
+        if (dom.isEmpty(parentBlock)) {
+          emptyBlock(parentBlock);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        moveToCaretPosition(newBlock);
+      } else if (isCaretAtStartOrEndOfBlock()) {
+        insertNewBlockAfter();
+      } else if (isCaretAtStartOrEndOfBlock(true)) {
+        // Insert new block before
+        newBlock = parentBlock.parentNode.insertBefore(createNewBlock(), parentBlock);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // If parent block is root then never insert new blocks
-        if (newBlockName && parentBlock === editor.getBody()) {
-          return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Adjust caret position if HR
+        containerAndSiblingName(parentBlock, 'HR') ? moveToCaretPosition(newBlock) : moveToCaretPosition(parentBlock);
+      } else {
+        // Extract after fragment and insert it after the current block
+        tmpRng = includeZwspInRange(rng).cloneRange();
+        tmpRng.setEndAfter(parentBlock);
+        fragment = tmpRng.extractContents();
+        trimLeadingLineBreaks(fragment);
+        newBlock = fragment.firstChild;
+        dom.insertAfter(fragment, parentBlock);
+        trimInlineElementsOnLeftSideOfBlock(dom, nonEmptyElementsMap, newBlock);
+        addBrToBlockIfNeeded(dom, parentBlock);
+
+        if (dom.isEmpty(parentBlock)) {
+          emptyBlock(parentBlock);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Default block name if it's not configured
-        newBlockName = newBlockName || 'P';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        newBlock.normalize();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Insert new block before/after the parent block depending on caret location
-        if (CaretContainer.isCaretContainerBlock(parentBlock)) {
-          newBlock = CaretContainer.showCaretContainerBlock(parentBlock);
-          if (dom.isEmpty(parentBlock)) {
-            emptyBlock(parentBlock);
-          }
-          moveToCaretPosition(newBlock);
-        } else if (isCaretAtStartOrEndOfBlock()) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // New block might become empty if it's <p><b>a |</b></p>
+        if (dom.isEmpty(newBlock)) {
+          dom.remove(newBlock);
</ins><span class="cx" style="display: block; padding: 0 10px">           insertNewBlockAfter();
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        } else if (isCaretAtStartOrEndOfBlock(true)) {
-          // Insert new block before
-          newBlock = parentBlock.parentNode.insertBefore(createNewBlock(), parentBlock);
-          renderBlockOnIE(dom, selection, newBlock);
-
-          // Adjust caret position if HR
-          containerAndSiblingName(parentBlock, 'HR') ? moveToCaretPosition(newBlock) : moveToCaretPosition(parentBlock);
</del><span class="cx" style="display: block; padding: 0 10px">         } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // Extract after fragment and insert it after the current block
-          tmpRng = includeZwspInRange(rng).cloneRange();
-          tmpRng.setEndAfter(parentBlock);
-          fragment = tmpRng.extractContents();
-          trimLeadingLineBreaks(fragment);
-          newBlock = fragment.firstChild;
-          dom.insertAfter(fragment, parentBlock);
-          trimInlineElementsOnLeftSideOfBlock(dom, nonEmptyElementsMap, newBlock);
-          addBrToBlockIfNeeded(parentBlock);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          moveToCaretPosition(newBlock);
+        }
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (dom.isEmpty(parentBlock)) {
-            emptyBlock(parentBlock);
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      dom.setAttrib(newBlock, 'id', ''); // Remove ID since it needs to be document unique
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          newBlock.normalize();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Allow custom handling of new blocks
+      editor.fire('NewBlock', { newBlock: newBlock });
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          // New block might become empty if it's <p><b>a |</b></p>
-          if (dom.isEmpty(newBlock)) {
-            dom.remove(newBlock);
-            insertNewBlockAfter();
-          } else {
-            moveToCaretPosition(newBlock);
-          }
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return {
+      insert: insert
+    };
+  }
+);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        dom.setAttrib(newBlock, 'id', ''); // Remove ID since it needs to be document unique
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/**
+ * EnterKey.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Allow custom handling of new blocks
-        editor.fire('NewBlock', { newBlock: newBlock });
-
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+define(
+  'tinymce.core.keyboard.EnterKey',
+  [
+    'tinymce.core.keyboard.InsertNewLine',
+    'tinymce.core.util.VK'
+  ],
+  function (InsertNewLine, VK) {
+    var endTypingLevel = function (undoManager) {
+      if (undoManager.typing) {
</ins><span class="cx" style="display: block; padding: 0 10px">         undoManager.typing = false;
</span><span class="cx" style="display: block; padding: 0 10px">         undoManager.add();
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      editor.on('keydown', function (evt) {
-        if (evt.keyCode == 13) {
-          if (handleEnterKey(evt) !== false) {
-            evt.preventDefault();
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var handleEnterKeyEvent = function (editor, event) {
+      if (event.isDefaultPrevented()) {
+        return;
+      }
+
+      event.preventDefault();
+
+      endTypingLevel(editor.undoManager);
+      editor.undoManager.transact(function () {
+        if (editor.selection.isCollapsed() === false) {
+          editor.execCommand('Delete');
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+        InsertNewLine.insert(editor, event);
</ins><span class="cx" style="display: block; padding: 0 10px">       });
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var setup = function (editor) {
+      editor.on('keydown', function (event) {
+        if (event.keyCode === VK.ENTER) {
+          handleEnterKeyEvent(editor, event);
+        }
+      });
+    };
+
</ins><span class="cx" style="display: block; padding: 0 10px">     return {
</span><span class="cx" style="display: block; padding: 0 10px">       setup: setup
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -41193,9 +41662,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">     'ephox.katamari.api.Fun',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.caret.CaretPosition',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.dom.NodeType',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.keyboard.BoundaryLocation'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.keyboard.BoundaryLocation',
+    'tinymce.core.keyboard.InlineUtils'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Fun, CaretPosition, NodeType, BoundaryLocation) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Fun, CaretPosition, NodeType, BoundaryLocation, InlineUtils) {
</ins><span class="cx" style="display: block; padding: 0 10px">     var isValidInsertPoint = function (location, caretPosition) {
</span><span class="cx" style="display: block; padding: 0 10px">       return isAtStartOrEnd(location) && NodeType.isText(caretPosition.container());
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -41218,8 +41688,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var insertAtCaret = function (editor) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var isInlineTarget = Fun.curry(InlineUtils.isInlineTarget, editor);
</ins><span class="cx" style="display: block; padding: 0 10px">       var caretPosition = CaretPosition.fromRangeStart(editor.selection.getRng());
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var boundaryLocation = BoundaryLocation.readLocation(editor.getBody(), caretPosition);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var boundaryLocation = BoundaryLocation.readLocation(isInlineTarget, editor.getBody(), caretPosition);
</ins><span class="cx" style="display: block; padding: 0 10px">       return boundaryLocation.map(Fun.curry(insertAtLocation, editor, caretPosition)).getOr(false);
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -41255,20 +41726,15 @@
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><span class="cx" style="display: block; padding: 0 10px">   'tinymce.core.keyboard.SpaceKey',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'ephox.katamari.api.Arr',
</del><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.keyboard.InsertSpace',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.keyboard.MatchKeys',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.VK'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Arr, InsertSpace, MatchKeys, VK) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (InsertSpace, MatchKeys, VK) {
</ins><span class="cx" style="display: block; padding: 0 10px">     var executeKeydownOverride = function (editor, evt) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var matches = MatchKeys.match([
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      MatchKeys.execute([
</ins><span class="cx" style="display: block; padding: 0 10px">         { keyCode: VK.SPACEBAR, action: MatchKeys.action(InsertSpace.insertAtSelection, editor) }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      ], evt);
-
-      Arr.find(matches, function (pattern) {
-        return pattern.action();
-      }).each(function (_) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      ], evt).each(function (_) {
</ins><span class="cx" style="display: block; padding: 0 10px">         evt.preventDefault();
</span><span class="cx" style="display: block; padding: 0 10px">       });
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -41411,9 +41877,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">       editor.on('SelectionChange', function () {
</span><span class="cx" style="display: block; padding: 0 10px">         var startElm = editor.selection.getStart(true);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // When focusout from after cef element to other input element the startelm can be undefined.
</ins><span class="cx" style="display: block; padding: 0 10px">         // IE 8 will fire a selectionchange event with an incorrect selection
</span><span class="cx" style="display: block; padding: 0 10px">         // when focusing out of table cells. Click inside cell -> toolbar = Invalid SelectionChange event
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (!Env.range && editor.selection.isCollapsed()) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (!startElm || (!Env.range && editor.selection.isCollapsed())) {
</ins><span class="cx" style="display: block; padding: 0 10px">           return;
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -41480,210 +41947,6 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * FakeCaret.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * This module contains logic for rendering a fake visual caret.
- *
- * @private
- * @class tinymce.caret.FakeCaret
- */
-define(
-  'tinymce.core.caret.FakeCaret',
-  [
-    'tinymce.core.caret.CaretContainer',
-    'tinymce.core.caret.CaretContainerRemove',
-    'tinymce.core.caret.CaretPosition',
-    'tinymce.core.dom.DomQuery',
-    'tinymce.core.dom.NodeType',
-    'tinymce.core.dom.RangeUtils',
-    'tinymce.core.geom.ClientRect',
-    'tinymce.core.util.Delay'
-  ],
-  function (CaretContainer, CaretContainerRemove, CaretPosition, DomQuery, NodeType, RangeUtils, ClientRect, Delay) {
-    var isContentEditableFalse = NodeType.isContentEditableFalse;
-
-    var isTableCell = function (node) {
-      return node && /^(TD|TH)$/i.test(node.nodeName);
-    };
-
-    return function (rootNode, isBlock) {
-      var cursorInterval, $lastVisualCaret, caretContainerNode;
-
-      function getAbsoluteClientRect(node, before) {
-        var clientRect = ClientRect.collapse(node.getBoundingClientRect(), before),
-          docElm, scrollX, scrollY, margin, rootRect;
-
-        if (rootNode.tagName == 'BODY') {
-          docElm = rootNode.ownerDocument.documentElement;
-          scrollX = rootNode.scrollLeft || docElm.scrollLeft;
-          scrollY = rootNode.scrollTop || docElm.scrollTop;
-        } else {
-          rootRect = rootNode.getBoundingClientRect();
-          scrollX = rootNode.scrollLeft - rootRect.left;
-          scrollY = rootNode.scrollTop - rootRect.top;
-        }
-
-        clientRect.left += scrollX;
-        clientRect.right += scrollX;
-        clientRect.top += scrollY;
-        clientRect.bottom += scrollY;
-        clientRect.width = 1;
-
-        margin = node.offsetWidth - node.clientWidth;
-
-        if (margin > 0) {
-          if (before) {
-            margin *= -1;
-          }
-
-          clientRect.left += margin;
-          clientRect.right += margin;
-        }
-
-        return clientRect;
-      }
-
-      function trimInlineCaretContainers() {
-        var contentEditableFalseNodes, node, sibling, i, data;
-
-        contentEditableFalseNodes = DomQuery('*[contentEditable=false]', rootNode);
-        for (i = 0; i < contentEditableFalseNodes.length; i++) {
-          node = contentEditableFalseNodes[i];
-
-          sibling = node.previousSibling;
-          if (CaretContainer.endsWithCaretContainer(sibling)) {
-            data = sibling.data;
-
-            if (data.length == 1) {
-              sibling.parentNode.removeChild(sibling);
-            } else {
-              sibling.deleteData(data.length - 1, 1);
-            }
-          }
-
-          sibling = node.nextSibling;
-          if (CaretContainer.startsWithCaretContainer(sibling)) {
-            data = sibling.data;
-
-            if (data.length == 1) {
-              sibling.parentNode.removeChild(sibling);
-            } else {
-              sibling.deleteData(0, 1);
-            }
-          }
-        }
-
-        return null;
-      }
-
-      function show(before, node) {
-        var clientRect, rng;
-
-        hide();
-
-        if (isTableCell(node)) {
-          return null;
-        }
-
-        if (isBlock(node)) {
-          caretContainerNode = CaretContainer.insertBlock('p', node, before);
-          clientRect = getAbsoluteClientRect(node, before);
-          DomQuery(caretContainerNode).css('top', clientRect.top);
-
-          $lastVisualCaret = DomQuery('<div class="mce-visual-caret" data-mce-bogus="all"></div>').css(clientRect).appendTo(rootNode);
-
-          if (before) {
-            $lastVisualCaret.addClass('mce-visual-caret-before');
-          }
-
-          startBlink();
-
-          rng = node.ownerDocument.createRange();
-          rng.setStart(caretContainerNode, 0);
-          rng.setEnd(caretContainerNode, 0);
-        } else {
-          caretContainerNode = CaretContainer.insertInline(node, before);
-          rng = node.ownerDocument.createRange();
-
-          if (isContentEditableFalse(caretContainerNode.nextSibling)) {
-            rng.setStart(caretContainerNode, 0);
-            rng.setEnd(caretContainerNode, 0);
-          } else {
-            rng.setStart(caretContainerNode, 1);
-            rng.setEnd(caretContainerNode, 1);
-          }
-
-          return rng;
-        }
-
-        return rng;
-      }
-
-      function hide() {
-        trimInlineCaretContainers();
-
-        if (caretContainerNode) {
-          CaretContainerRemove.remove(caretContainerNode);
-          caretContainerNode = null;
-        }
-
-        if ($lastVisualCaret) {
-          $lastVisualCaret.remove();
-          $lastVisualCaret = null;
-        }
-
-        clearInterval(cursorInterval);
-      }
-
-      function startBlink() {
-        cursorInterval = Delay.setInterval(function () {
-          DomQuery('div.mce-visual-caret', rootNode).toggleClass('mce-visual-caret-hidden');
-        }, 500);
-      }
-
-      function destroy() {
-        Delay.clearInterval(cursorInterval);
-      }
-
-      function getCss() {
-        return (
-          '.mce-visual-caret {' +
-          'position: absolute;' +
-          'background-color: black;' +
-          'background-color: currentcolor;' +
-          '}' +
-          '.mce-visual-caret-hidden {' +
-          'display: none;' +
-          '}' +
-          '*[data-mce-caret] {' +
-          'position: absolute;' +
-          'left: -1000px;' +
-          'right: auto;' +
-          'top: 0;' +
-          'margin: 0;' +
-          'padding: 0;' +
-          '}'
-        );
-      }
-
-      return {
-        show: show,
-        hide: hide,
-        getCss: getCss,
-        destroy: destroy
-      };
-    };
-  }
-);
-/**
</del><span class="cx" style="display: block; padding: 0 10px">  * MousePosition.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -42054,6 +42317,210 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * FakeCaret.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This module contains logic for rendering a fake visual caret.
+ *
+ * @private
+ * @class tinymce.caret.FakeCaret
+ */
+define(
+  'tinymce.core.caret.FakeCaret',
+  [
+    'tinymce.core.caret.CaretContainer',
+    'tinymce.core.caret.CaretContainerRemove',
+    'tinymce.core.caret.CaretPosition',
+    'tinymce.core.dom.DomQuery',
+    'tinymce.core.dom.NodeType',
+    'tinymce.core.dom.RangeUtils',
+    'tinymce.core.geom.ClientRect',
+    'tinymce.core.util.Delay'
+  ],
+  function (CaretContainer, CaretContainerRemove, CaretPosition, DomQuery, NodeType, RangeUtils, ClientRect, Delay) {
+    var isContentEditableFalse = NodeType.isContentEditableFalse;
+
+    var isTableCell = function (node) {
+      return node && /^(TD|TH)$/i.test(node.nodeName);
+    };
+
+    return function (rootNode, isBlock) {
+      var cursorInterval, $lastVisualCaret, caretContainerNode;
+
+      function getAbsoluteClientRect(node, before) {
+        var clientRect = ClientRect.collapse(node.getBoundingClientRect(), before),
+          docElm, scrollX, scrollY, margin, rootRect;
+
+        if (rootNode.tagName == 'BODY') {
+          docElm = rootNode.ownerDocument.documentElement;
+          scrollX = rootNode.scrollLeft || docElm.scrollLeft;
+          scrollY = rootNode.scrollTop || docElm.scrollTop;
+        } else {
+          rootRect = rootNode.getBoundingClientRect();
+          scrollX = rootNode.scrollLeft - rootRect.left;
+          scrollY = rootNode.scrollTop - rootRect.top;
+        }
+
+        clientRect.left += scrollX;
+        clientRect.right += scrollX;
+        clientRect.top += scrollY;
+        clientRect.bottom += scrollY;
+        clientRect.width = 1;
+
+        margin = node.offsetWidth - node.clientWidth;
+
+        if (margin > 0) {
+          if (before) {
+            margin *= -1;
+          }
+
+          clientRect.left += margin;
+          clientRect.right += margin;
+        }
+
+        return clientRect;
+      }
+
+      function trimInlineCaretContainers() {
+        var contentEditableFalseNodes, node, sibling, i, data;
+
+        contentEditableFalseNodes = DomQuery('*[contentEditable=false]', rootNode);
+        for (i = 0; i < contentEditableFalseNodes.length; i++) {
+          node = contentEditableFalseNodes[i];
+
+          sibling = node.previousSibling;
+          if (CaretContainer.endsWithCaretContainer(sibling)) {
+            data = sibling.data;
+
+            if (data.length == 1) {
+              sibling.parentNode.removeChild(sibling);
+            } else {
+              sibling.deleteData(data.length - 1, 1);
+            }
+          }
+
+          sibling = node.nextSibling;
+          if (CaretContainer.startsWithCaretContainer(sibling)) {
+            data = sibling.data;
+
+            if (data.length == 1) {
+              sibling.parentNode.removeChild(sibling);
+            } else {
+              sibling.deleteData(0, 1);
+            }
+          }
+        }
+
+        return null;
+      }
+
+      function show(before, node) {
+        var clientRect, rng;
+
+        hide();
+
+        if (isTableCell(node)) {
+          return null;
+        }
+
+        if (isBlock(node)) {
+          caretContainerNode = CaretContainer.insertBlock('p', node, before);
+          clientRect = getAbsoluteClientRect(node, before);
+          DomQuery(caretContainerNode).css('top', clientRect.top);
+
+          $lastVisualCaret = DomQuery('<div class="mce-visual-caret" data-mce-bogus="all"></div>').css(clientRect).appendTo(rootNode);
+
+          if (before) {
+            $lastVisualCaret.addClass('mce-visual-caret-before');
+          }
+
+          startBlink();
+
+          rng = node.ownerDocument.createRange();
+          rng.setStart(caretContainerNode, 0);
+          rng.setEnd(caretContainerNode, 0);
+        } else {
+          caretContainerNode = CaretContainer.insertInline(node, before);
+          rng = node.ownerDocument.createRange();
+
+          if (isContentEditableFalse(caretContainerNode.nextSibling)) {
+            rng.setStart(caretContainerNode, 0);
+            rng.setEnd(caretContainerNode, 0);
+          } else {
+            rng.setStart(caretContainerNode, 1);
+            rng.setEnd(caretContainerNode, 1);
+          }
+
+          return rng;
+        }
+
+        return rng;
+      }
+
+      function hide() {
+        trimInlineCaretContainers();
+
+        if (caretContainerNode) {
+          CaretContainerRemove.remove(caretContainerNode);
+          caretContainerNode = null;
+        }
+
+        if ($lastVisualCaret) {
+          $lastVisualCaret.remove();
+          $lastVisualCaret = null;
+        }
+
+        clearInterval(cursorInterval);
+      }
+
+      function startBlink() {
+        cursorInterval = Delay.setInterval(function () {
+          DomQuery('div.mce-visual-caret', rootNode).toggleClass('mce-visual-caret-hidden');
+        }, 500);
+      }
+
+      function destroy() {
+        Delay.clearInterval(cursorInterval);
+      }
+
+      function getCss() {
+        return (
+          '.mce-visual-caret {' +
+          'position: absolute;' +
+          'background-color: black;' +
+          'background-color: currentcolor;' +
+          '}' +
+          '.mce-visual-caret-hidden {' +
+          'display: none;' +
+          '}' +
+          '*[data-mce-caret] {' +
+          'position: absolute;' +
+          'left: -1000px;' +
+          'right: auto;' +
+          'top: 0;' +
+          'margin: 0;' +
+          'padding: 0;' +
+          '}'
+        );
+      }
+
+      return {
+        show: show,
+        hide: hide,
+        getCss: getCss,
+        destroy: destroy
+      };
+    };
+  }
+);
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * SelectionOverrides.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -42079,23 +42546,32 @@
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><span class="cx" style="display: block; padding: 0 10px">   'tinymce.core.SelectionOverrides',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.katamari.api.Arr',
+    'ephox.sugar.api.dom.Remove',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.properties.Attr',
+    'ephox.sugar.api.search.SelectorFilter',
+    'ephox.sugar.api.search.SelectorFind',
+    'tinymce.core.DragDropOverrides',
+    'tinymce.core.EditorView',
+    'tinymce.core.Env',
</ins><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.caret.CaretContainer',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.caret.CaretPosition',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.caret.CaretUtils',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.caret.CaretWalker',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.caret.FakeCaret',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.caret.LineUtils',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.dom.ElementType',
</ins><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.dom.NodeType',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.DragDropOverrides',
-    'tinymce.core.Env',
-    'tinymce.core.geom.ClientRect',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.dom.RangePoint',
</ins><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.keyboard.CefUtils',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.util.Arr',
</del><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.Delay',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.util.Fun',
</del><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.VK'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (CaretContainer, CaretPosition, CaretUtils, CaretWalker, FakeCaret, LineUtils, NodeType, DragDropOverrides, Env, ClientRect, CefUtils, Arr, Delay, Fun, VK) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (
+    Arr, Remove, Element, Attr, SelectorFilter, SelectorFind, DragDropOverrides, EditorView, Env, CaretContainer, CaretPosition, CaretUtils, CaretWalker, FakeCaret,
+    LineUtils, ElementType, NodeType, RangePoint, CefUtils, Delay, VK
+  ) {
</ins><span class="cx" style="display: block; padding: 0 10px">     var isContentEditableTrue = NodeType.isContentEditableTrue,
</span><span class="cx" style="display: block; padding: 0 10px">       isContentEditableFalse = NodeType.isContentEditableFalse,
</span><span class="cx" style="display: block; padding: 0 10px">       isAfterContentEditableFalse = CaretUtils.isAfterContentEditableFalse,
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -42186,22 +42662,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">           return null;
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function isXYWithinRange(clientX, clientY, range) {
-          if (range.collapsed) {
-            return false;
-          }
-
-          return Arr.reduce(range.getClientRects(), function (state, rect) {
-            return state || ClientRect.containsXY(rect, clientX, clientY);
-          }, false);
-        }
-
</del><span class="cx" style="display: block; padding: 0 10px">         // Some browsers (Chrome) lets you place the caret after a cE=false
</span><span class="cx" style="display: block; padding: 0 10px">         // Make sure we render the caret container in this case
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        editor.on('mouseup', function () {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        editor.on('mouseup', function (e) {
</ins><span class="cx" style="display: block; padding: 0 10px">           var range = getRange();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (range.collapsed) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (range.collapsed && EditorView.isXYInContentArea(editor, e.clientX, e.clientY)) {
</ins><span class="cx" style="display: block; padding: 0 10px">             setRange(CefUtils.renderCaretAtRange(editor, range));
</span><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px">         });
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -42288,6 +42754,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">         editor.on('mousedown', function (e) {
</span><span class="cx" style="display: block; padding: 0 10px">           var contentEditableRoot;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (EditorView.isXYInContentArea(editor, e.clientX, e.clientY) === false) {
+            return;
+          }
+
</ins><span class="cx" style="display: block; padding: 0 10px">           contentEditableRoot = getContentEditableRoot(e.target);
</span><span class="cx" style="display: block; padding: 0 10px">           if (contentEditableRoot) {
</span><span class="cx" style="display: block; padding: 0 10px">             if (isContentEditableFalse(contentEditableRoot)) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -42297,8 +42767,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">               removeContentEditableSelection();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">               // Check that we're not attempting a shift + click select within a contenteditable='true' element
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-              if (!(isContentEditableTrue(contentEditableRoot) && e.shiftKey) && !isXYWithinRange(e.clientX, e.clientY, editor.selection.getRng())) {
-                editor.selection.placeCaretAt(e.clientX, e.clientY);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+              if (!(isContentEditableTrue(contentEditableRoot) && e.shiftKey) && !RangePoint.isXYWithinRange(e.clientX, e.clientY, editor.selection.getRng())) {
+                ElementType.isVoid(Element.fromDom(e.target)) ? editor.selection.select(e.target) : editor.selection.placeCaretAt(e.clientX, e.clientY);
</ins><span class="cx" style="display: block; padding: 0 10px">               }
</span><span class="cx" style="display: block; padding: 0 10px">             }
</span><span class="cx" style="display: block; padding: 0 10px">           } else {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -42490,8 +42960,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">           return null;
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        $realSelectionContainer = SelectorFind.descendant(Element.fromDom(editor.getBody()), '#' + realSelectionId).fold(
+          function () {
+            return $([]);
+          },
+          function (elm) {
+            return $([elm.dom()]);
+          }
+        );
+
</ins><span class="cx" style="display: block; padding: 0 10px">         targetClone = e.targetClone;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        $realSelectionContainer = $('#' + realSelectionId);
</del><span class="cx" style="display: block; padding: 0 10px">         if ($realSelectionContainer.length === 0) {
</span><span class="cx" style="display: block; padding: 0 10px">           $realSelectionContainer = $(
</span><span class="cx" style="display: block; padding: 0 10px">             '<div data-mce-bogus="all" class="mce-offscreen-selection"></div>'
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -42524,7 +43002,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">         sel.removeAllRanges();
</span><span class="cx" style="display: block; padding: 0 10px">         sel.addRange(range);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        editor.$('*[data-mce-selected]').removeAttr('data-mce-selected');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        Arr.each(SelectorFilter.descendants(Element.fromDom(editor.getBody()), '*[data-mce-selected]'), function (elm) {
+          Attr.remove(elm, 'data-mce-selected');
+        });
+
</ins><span class="cx" style="display: block; padding: 0 10px">         node.setAttribute('data-mce-selected', 1);
</span><span class="cx" style="display: block; padding: 0 10px">         selectedContentEditableNode = node;
</span><span class="cx" style="display: block; padding: 0 10px">         hideFakeCaret();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -42535,7 +43016,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">       function removeContentEditableSelection() {
</span><span class="cx" style="display: block; padding: 0 10px">         if (selectedContentEditableNode) {
</span><span class="cx" style="display: block; padding: 0 10px">           selectedContentEditableNode.removeAttribute('data-mce-selected');
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          editor.$('#' + realSelectionId).remove();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          SelectorFind.descendant(Element.fromDom(editor.getBody()), '#' + realSelectionId).each(Remove.remove);
</ins><span class="cx" style="display: block; padding: 0 10px">           selectedContentEditableNode = null;
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -42567,6 +43048,744 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Diff.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * JS Implementation of the O(ND) Difference Algorithm by Eugene W. Myers.
+ *
+ * @class tinymce.undo.Diff
+ * @private
+ */
+define(
+  'tinymce.core.undo.Diff',
+  [
+  ],
+  function () {
+    var KEEP = 0, INSERT = 1, DELETE = 2;
+
+    var diff = function (left, right) {
+      var size = left.length + right.length + 2;
+      var vDown = new Array(size);
+      var vUp = new Array(size);
+
+      var snake = function (start, end, diag) {
+        return {
+          start: start,
+          end: end,
+          diag: diag
+        };
+      };
+
+      var buildScript = function (start1, end1, start2, end2, script) {
+        var middle = getMiddleSnake(start1, end1, start2, end2);
+
+        if (middle === null || middle.start === end1 && middle.diag === end1 - end2 ||
+          middle.end === start1 && middle.diag === start1 - start2) {
+          var i = start1;
+          var j = start2;
+          while (i < end1 || j < end2) {
+            if (i < end1 && j < end2 && left[i] === right[j]) {
+              script.push([KEEP, left[i]]);
+              ++i;
+              ++j;
+            } else {
+              if (end1 - start1 > end2 - start2) {
+                script.push([DELETE, left[i]]);
+                ++i;
+              } else {
+                script.push([INSERT, right[j]]);
+                ++j;
+              }
+            }
+          }
+        } else {
+          buildScript(start1, middle.start, start2, middle.start - middle.diag, script);
+          for (var i2 = middle.start; i2 < middle.end; ++i2) {
+            script.push([KEEP, left[i2]]);
+          }
+          buildScript(middle.end, end1, middle.end - middle.diag, end2, script);
+        }
+      };
+
+      var buildSnake = function (start, diag, end1, end2) {
+        var end = start;
+        while (end - diag < end2 && end < end1 && left[end] === right[end - diag]) {
+          ++end;
+        }
+        return snake(start, end, diag);
+      };
+
+      var getMiddleSnake = function (start1, end1, start2, end2) {
+        // Myers Algorithm
+        // Initialisations
+        var m = end1 - start1;
+        var n = end2 - start2;
+        if (m === 0 || n === 0) {
+          return null;
+        }
+
+        var delta = m - n;
+        var sum = n + m;
+        var offset = (sum % 2 === 0 ? sum : sum + 1) / 2;
+        vDown[1 + offset] = start1;
+        vUp[1 + offset] = end1 + 1;
+
+        for (var d = 0; d <= offset; ++d) {
+          // Down
+          for (var k = -d; k <= d; k += 2) {
+            // First step
+
+            var i = k + offset;
+            if (k === -d || k != d && vDown[i - 1] < vDown[i + 1]) {
+              vDown[i] = vDown[i + 1];
+            } else {
+              vDown[i] = vDown[i - 1] + 1;
+            }
+
+            var x = vDown[i];
+            var y = x - start1 + start2 - k;
+
+            while (x < end1 && y < end2 && left[x] === right[y]) {
+              vDown[i] = ++x;
+              ++y;
+            }
+            // Second step
+            if (delta % 2 != 0 && delta - d <= k && k <= delta + d) {
+              if (vUp[i - delta] <= vDown[i]) {
+                return buildSnake(vUp[i - delta], k + start1 - start2, end1, end2);
+              }
+            }
+          }
+
+          // Up
+          for (k = delta - d; k <= delta + d; k += 2) {
+            // First step
+            i = k + offset - delta;
+            if (k === delta - d || k != delta + d && vUp[i + 1] <= vUp[i - 1]) {
+              vUp[i] = vUp[i + 1] - 1;
+            } else {
+              vUp[i] = vUp[i - 1];
+            }
+
+            x = vUp[i] - 1;
+            y = x - start1 + start2 - k;
+            while (x >= start1 && y >= start2 && left[x] === right[y]) {
+              vUp[i] = x--;
+              y--;
+            }
+            // Second step
+            if (delta % 2 === 0 && -d <= k && k <= d) {
+              if (vUp[i] <= vDown[i + delta]) {
+                return buildSnake(vUp[i], k + start1 - start2, end1, end2);
+              }
+            }
+          }
+        }
+      };
+
+      var script = [];
+      buildScript(0, left.length, 0, right.length, script);
+      return script;
+    };
+
+    return {
+      KEEP: KEEP,
+      DELETE: DELETE,
+      INSERT: INSERT,
+      diff: diff
+    };
+  }
+);
+/**
+ * Fragments.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This module reads and applies html fragments from/to dom nodes.
+ *
+ * @class tinymce.undo.Fragments
+ * @private
+ */
+define(
+  'tinymce.core.undo.Fragments',
+  [
+    "tinymce.core.util.Arr",
+    "tinymce.core.html.Entities",
+    "tinymce.core.undo.Diff"
+  ],
+  function (Arr, Entities, Diff) {
+    var getOuterHtml = function (elm) {
+      if (elm.nodeType === 1) {
+        return elm.outerHTML;
+      } else if (elm.nodeType === 3) {
+        return Entities.encodeRaw(elm.data, false);
+      } else if (elm.nodeType === 8) {
+        return '<!--' + elm.data + '-->';
+      }
+
+      return '';
+    };
+
+    var createFragment = function (html) {
+      var frag, node, container;
+
+      container = document.createElement("div");
+      frag = document.createDocumentFragment();
+
+      if (html) {
+        container.innerHTML = html;
+      }
+
+      while ((node = container.firstChild)) {
+        frag.appendChild(node);
+      }
+
+      return frag;
+    };
+
+    var insertAt = function (elm, html, index) {
+      var fragment = createFragment(html);
+      if (elm.hasChildNodes() && index < elm.childNodes.length) {
+        var target = elm.childNodes[index];
+        target.parentNode.insertBefore(fragment, target);
+      } else {
+        elm.appendChild(fragment);
+      }
+    };
+
+    var removeAt = function (elm, index) {
+      if (elm.hasChildNodes() && index < elm.childNodes.length) {
+        var target = elm.childNodes[index];
+        target.parentNode.removeChild(target);
+      }
+    };
+
+    var applyDiff = function (diff, elm) {
+      var index = 0;
+      Arr.each(diff, function (action) {
+        if (action[0] === Diff.KEEP) {
+          index++;
+        } else if (action[0] === Diff.INSERT) {
+          insertAt(elm, action[1], index);
+          index++;
+        } else if (action[0] === Diff.DELETE) {
+          removeAt(elm, index);
+        }
+      });
+    };
+
+    var read = function (elm) {
+      return Arr.filter(Arr.map(elm.childNodes, getOuterHtml), function (item) {
+        return item.length > 0;
+      });
+    };
+
+    var write = function (fragments, elm) {
+      var currentFragments = Arr.map(elm.childNodes, getOuterHtml);
+      applyDiff(Diff.diff(currentFragments, fragments), elm);
+      return elm;
+    };
+
+    return {
+      read: read,
+      write: write
+    };
+  }
+);
+/**
+ * Levels.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This module handles getting/setting undo levels to/from editor instances.
+ *
+ * @class tinymce.undo.Levels
+ * @private
+ */
+define(
+  'tinymce.core.undo.Levels',
+  [
+    "tinymce.core.util.Arr",
+    "tinymce.core.undo.Fragments"
+  ],
+  function (Arr, Fragments) {
+    var hasIframes = function (html) {
+      return html.indexOf('</iframe>') !== -1;
+    };
+
+    var createFragmentedLevel = function (fragments) {
+      return {
+        type: 'fragmented',
+        fragments: fragments,
+        content: '',
+        bookmark: null,
+        beforeBookmark: null
+      };
+    };
+
+    var createCompleteLevel = function (content) {
+      return {
+        type: 'complete',
+        fragments: null,
+        content: content,
+        bookmark: null,
+        beforeBookmark: null
+      };
+    };
+
+    var createFromEditor = function (editor) {
+      var fragments, content, trimmedFragments;
+
+      fragments = Fragments.read(editor.getBody());
+      trimmedFragments = Arr.map(fragments, function (html) {
+        return editor.serializer.trimContent(html);
+      });
+      content = trimmedFragments.join('');
+
+      return hasIframes(content) ? createFragmentedLevel(trimmedFragments) : createCompleteLevel(content);
+    };
+
+    var applyToEditor = function (editor, level, before) {
+      if (level.type === 'fragmented') {
+        Fragments.write(level.fragments, editor.getBody());
+      } else {
+        editor.setContent(level.content, { format: 'raw' });
+      }
+
+      editor.selection.moveToBookmark(before ? level.beforeBookmark : level.bookmark);
+    };
+
+    var getLevelContent = function (level) {
+      return level.type === 'fragmented' ? level.fragments.join('') : level.content;
+    };
+
+    var isEq = function (level1, level2) {
+      return !!level1 && !!level2 && getLevelContent(level1) === getLevelContent(level2);
+    };
+
+    return {
+      createFragmentedLevel: createFragmentedLevel,
+      createCompleteLevel: createCompleteLevel,
+      createFromEditor: createFromEditor,
+      applyToEditor: applyToEditor,
+      isEq: isEq
+    };
+  }
+);
+/**
+ * UndoManager.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This class handles the undo/redo history levels for the editor. Since the built-in undo/redo has major drawbacks a custom one was needed.
+ *
+ * @class tinymce.UndoManager
+ */
+define(
+  'tinymce.core.UndoManager',
+  [
+    "tinymce.core.util.VK",
+    "tinymce.core.util.Tools",
+    "tinymce.core.undo.Levels"
+  ],
+  function (VK, Tools, Levels) {
+    return function (editor) {
+      var self = this, index = 0, data = [], beforeBookmark, isFirstTypedCharacter, locks = 0;
+
+      var isUnlocked = function () {
+        return locks === 0;
+      };
+
+      var setTyping = function (typing) {
+        if (isUnlocked()) {
+          self.typing = typing;
+        }
+      };
+
+      function setDirty(state) {
+        editor.setDirty(state);
+      }
+
+      function addNonTypingUndoLevel(e) {
+        setTyping(false);
+        self.add({}, e);
+      }
+
+      function endTyping() {
+        if (self.typing) {
+          setTyping(false);
+          self.add();
+        }
+      }
+
+      // Add initial undo level when the editor is initialized
+      editor.on('init', function () {
+        self.add();
+      });
+
+      // Get position before an execCommand is processed
+      editor.on('BeforeExecCommand', function (e) {
+        var cmd = e.command;
+
+        if (cmd !== 'Undo' && cmd !== 'Redo' && cmd !== 'mceRepaint') {
+          endTyping();
+          self.beforeChange();
+        }
+      });
+
+      // Add undo level after an execCommand call was made
+      editor.on('ExecCommand', function (e) {
+        var cmd = e.command;
+
+        if (cmd !== 'Undo' && cmd !== 'Redo' && cmd !== 'mceRepaint') {
+          addNonTypingUndoLevel(e);
+        }
+      });
+
+      editor.on('ObjectResizeStart Cut', function () {
+        self.beforeChange();
+      });
+
+      editor.on('SaveContent ObjectResized blur', addNonTypingUndoLevel);
+      editor.on('DragEnd', addNonTypingUndoLevel);
+
+      editor.on('KeyUp', function (e) {
+        var keyCode = e.keyCode;
+
+        // If key is prevented then don't add undo level
+        // This would happen on keyboard shortcuts for example
+        if (e.isDefaultPrevented()) {
+          return;
+        }
+
+        if ((keyCode >= 33 && keyCode <= 36) || (keyCode >= 37 && keyCode <= 40) || keyCode === 45 || e.ctrlKey) {
+          addNonTypingUndoLevel();
+          editor.nodeChanged();
+        }
+
+        if (keyCode === 46 || keyCode === 8) {
+          editor.nodeChanged();
+        }
+
+        // Fire a TypingUndo/Change event on the first character entered
+        if (isFirstTypedCharacter && self.typing && Levels.isEq(Levels.createFromEditor(editor), data[0]) === false) {
+          if (editor.isDirty() === false) {
+            setDirty(true);
+            editor.fire('change', { level: data[0], lastLevel: null });
+          }
+
+          editor.fire('TypingUndo');
+          isFirstTypedCharacter = false;
+          editor.nodeChanged();
+        }
+      });
+
+      editor.on('KeyDown', function (e) {
+        var keyCode = e.keyCode;
+
+        // If key is prevented then don't add undo level
+        // This would happen on keyboard shortcuts for example
+        if (e.isDefaultPrevented()) {
+          return;
+        }
+
+        // Is character position keys left,right,up,down,home,end,pgdown,pgup,enter
+        if ((keyCode >= 33 && keyCode <= 36) || (keyCode >= 37 && keyCode <= 40) || keyCode === 45) {
+          if (self.typing) {
+            addNonTypingUndoLevel(e);
+          }
+
+          return;
+        }
+
+        // If key isn't Ctrl+Alt/AltGr
+        var modKey = (e.ctrlKey && !e.altKey) || e.metaKey;
+        if ((keyCode < 16 || keyCode > 20) && keyCode !== 224 && keyCode !== 91 && !self.typing && !modKey) {
+          self.beforeChange();
+          setTyping(true);
+          self.add({}, e);
+          isFirstTypedCharacter = true;
+        }
+      });
+
+      editor.on('MouseDown', function (e) {
+        if (self.typing) {
+          addNonTypingUndoLevel(e);
+        }
+      });
+
+      // Add keyboard shortcuts for undo/redo keys
+      editor.addShortcut('meta+z', '', 'Undo');
+      editor.addShortcut('meta+y,meta+shift+z', '', 'Redo');
+
+      editor.on('AddUndo Undo Redo ClearUndos', function (e) {
+        if (!e.isDefaultPrevented()) {
+          editor.nodeChanged();
+        }
+      });
+
+      /*eslint consistent-this:0 */
+      self = {
+        // Explode for debugging reasons
+        data: data,
+
+        /**
+         * State if the user is currently typing or not. This will add a typing operation into one undo
+         * level instead of one new level for each keystroke.
+         *
+         * @field {Boolean} typing
+         */
+        typing: false,
+
+        /**
+         * Stores away a bookmark to be used when performing an undo action so that the selection is before
+         * the change has been made.
+         *
+         * @method beforeChange
+         */
+        beforeChange: function () {
+          if (isUnlocked()) {
+            beforeBookmark = editor.selection.getBookmark(2, true);
+          }
+        },
+
+        /**
+         * Adds a new undo level/snapshot to the undo list.
+         *
+         * @method add
+         * @param {Object} level Optional undo level object to add.
+         * @param {DOMEvent} event Optional event responsible for the creation of the undo level.
+         * @return {Object} Undo level that got added or null it a level wasn't needed.
+         */
+        add: function (level, event) {
+          var i, settings = editor.settings, lastLevel, currentLevel;
+
+          currentLevel = Levels.createFromEditor(editor);
+          level = level || {};
+          level = Tools.extend(level, currentLevel);
+
+          if (isUnlocked() === false || editor.removed) {
+            return null;
+          }
+
+          lastLevel = data[index];
+          if (editor.fire('BeforeAddUndo', { level: level, lastLevel: lastLevel, originalEvent: event }).isDefaultPrevented()) {
+            return null;
+          }
+
+          // Add undo level if needed
+          if (lastLevel && Levels.isEq(lastLevel, level)) {
+            return null;
+          }
+
+          // Set before bookmark on previous level
+          if (data[index]) {
+            data[index].beforeBookmark = beforeBookmark;
+          }
+
+          // Time to compress
+          if (settings.custom_undo_redo_levels) {
+            if (data.length > settings.custom_undo_redo_levels) {
+              for (i = 0; i < data.length - 1; i++) {
+                data[i] = data[i + 1];
+              }
+
+              data.length--;
+              index = data.length;
+            }
+          }
+
+          // Get a non intrusive normalized bookmark
+          level.bookmark = editor.selection.getBookmark(2, true);
+
+          // Crop array if needed
+          if (index < data.length - 1) {
+            data.length = index + 1;
+          }
+
+          data.push(level);
+          index = data.length - 1;
+
+          var args = { level: level, lastLevel: lastLevel, originalEvent: event };
+
+          editor.fire('AddUndo', args);
+
+          if (index > 0) {
+            setDirty(true);
+            editor.fire('change', args);
+          }
+
+          return level;
+        },
+
+        /**
+         * Undoes the last action.
+         *
+         * @method undo
+         * @return {Object} Undo level or null if no undo was performed.
+         */
+        undo: function () {
+          var level;
+
+          if (self.typing) {
+            self.add();
+            self.typing = false;
+            setTyping(false);
+          }
+
+          if (index > 0) {
+            level = data[--index];
+            Levels.applyToEditor(editor, level, true);
+            setDirty(true);
+            editor.fire('undo', { level: level });
+          }
+
+          return level;
+        },
+
+        /**
+         * Redoes the last action.
+         *
+         * @method redo
+         * @return {Object} Redo level or null if no redo was performed.
+         */
+        redo: function () {
+          var level;
+
+          if (index < data.length - 1) {
+            level = data[++index];
+            Levels.applyToEditor(editor, level, false);
+            setDirty(true);
+            editor.fire('redo', { level: level });
+          }
+
+          return level;
+        },
+
+        /**
+         * Removes all undo levels.
+         *
+         * @method clear
+         */
+        clear: function () {
+          data = [];
+          index = 0;
+          self.typing = false;
+          self.data = data;
+          editor.fire('ClearUndos');
+        },
+
+        /**
+         * Returns true/false if the undo manager has any undo levels.
+         *
+         * @method hasUndo
+         * @return {Boolean} true/false if the undo manager has any undo levels.
+         */
+        hasUndo: function () {
+          // Has undo levels or typing and content isn't the same as the initial level
+          return index > 0 || (self.typing && data[0] && !Levels.isEq(Levels.createFromEditor(editor), data[0]));
+        },
+
+        /**
+         * Returns true/false if the undo manager has any redo levels.
+         *
+         * @method hasRedo
+         * @return {Boolean} true/false if the undo manager has any redo levels.
+         */
+        hasRedo: function () {
+          return index < data.length - 1 && !self.typing;
+        },
+
+        /**
+         * Executes the specified mutator function as an undo transaction. The selection
+         * before the modification will be stored to the undo stack and if the DOM changes
+         * it will add a new undo level. Any logic within the translation that adds undo levels will
+         * be ignored. So a translation can include calls to execCommand or editor.insertContent.
+         *
+         * @method transact
+         * @param {function} callback Function that gets executed and has dom manipulation logic in it.
+         * @return {Object} Undo level that got added or null it a level wasn't needed.
+         */
+        transact: function (callback) {
+          endTyping();
+          self.beforeChange();
+          self.ignore(callback);
+          return self.add();
+        },
+
+        /**
+         * Executes the specified mutator function as an undo transaction. But without adding an undo level.
+         * Any logic within the translation that adds undo levels will be ignored. So a translation can
+         * include calls to execCommand or editor.insertContent.
+         *
+         * @method ignore
+         * @param {function} callback Function that gets executed and has dom manipulation logic in it.
+         * @return {Object} Undo level that got added or null it a level wasn't needed.
+         */
+        ignore: function (callback) {
+          try {
+            locks++;
+            callback();
+          } finally {
+            locks--;
+          }
+        },
+
+        /**
+         * Adds an extra "hidden" undo level by first applying the first mutation and store that to the undo stack
+         * then roll back that change and do the second mutation on top of the stack. This will produce an extra
+         * undo level that the user doesn't see until they undo.
+         *
+         * @method extra
+         * @param {function} callback1 Function that does mutation but gets stored as a "hidden" extra undo level.
+         * @param {function} callback2 Function that does mutation but gets displayed to the user.
+         */
+        extra: function (callback1, callback2) {
+          var lastLevel, bookmark;
+
+          if (self.transact(callback1)) {
+            bookmark = data[index].bookmark;
+            lastLevel = data[index - 1];
+            Levels.applyToEditor(editor, lastLevel, true);
+
+            if (self.transact(callback2)) {
+              data[index - 1].beforeBookmark = bookmark;
+            }
+          }
+        }
+      };
+
+      return self;
+    };
+  }
+);
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * NodePath.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -43430,7 +44649,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">         // Normalize selection for example <b>a</b><i>|a</i> becomes <b>a|</b><i>a</i> except for Ctrl+A since it selects everything
</span><span class="cx" style="display: block; padding: 0 10px">         editor.on('keyup focusin mouseup', function (e) {
</span><span class="cx" style="display: block; padding: 0 10px">           if (e.keyCode != 65 || !VK.metaKeyPressed(e)) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            selection.normalize();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // We can't normalize on non collapsed ranges on keyboard events since that would cause
+            // issues with moving the selection over empty paragraphs. See #TINY-1130
+            if (e.type !== 'keyup' || editor.selection.isCollapsed()) {
+              selection.normalize();
+            }
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px">         }, true);
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -43670,50 +44893,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">         return (!sel || !sel.rangeCount || sel.rangeCount === 0);
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**
-       * Properly empties the editor if all contents is selected and deleted this to
-       * prevent empty paragraphs from being produced at beginning/end of contents.
-       */
-      function emptyEditorOnDeleteEverything() {
-        function isEverythingSelected(editor) {
-          var caretWalker = new CaretWalker(editor.getBody());
-          var rng = editor.selection.getRng();
-          var startCaretPos = CaretPosition.fromRangeStart(rng);
-          var endCaretPos = CaretPosition.fromRangeEnd(rng);
-          var prev = caretWalker.prev(startCaretPos);
-          var next = caretWalker.next(endCaretPos);
-
-          return !editor.selection.isCollapsed() &&
-            (!prev || (prev.isAtStart() && startCaretPos.isEqual(prev))) &&
-            (!next || (next.isAtEnd() && startCaretPos.isEqual(next)));
-        }
-
-        // Type over case delete and insert this won't cover typeover with a IME but at least it covers the common case
-        editor.on('keypress', function (e) {
-          if (!isDefaultPrevented(e) && !selection.isCollapsed() && e.charCode > 31 && !VK.metaKeyPressed(e)) {
-            if (isEverythingSelected(editor)) {
-              e.preventDefault();
-              editor.setContent(String.fromCharCode(e.charCode));
-              editor.selection.select(editor.getBody(), true);
-              editor.selection.collapse(false);
-              editor.nodeChanged();
-            }
-          }
-        });
-
-        editor.on('keydown', function (e) {
-          var keyCode = e.keyCode;
-
-          if (!isDefaultPrevented(e) && (keyCode == DELETE || keyCode == BACKSPACE)) {
-            if (isEverythingSelected(editor)) {
-              e.preventDefault();
-              editor.setContent('');
-              editor.nodeChanged();
-            }
-          }
-        });
-      }
-
</del><span class="cx" style="display: block; padding: 0 10px">       // All browsers
</span><span class="cx" style="display: block; padding: 0 10px">       removeBlockQuoteOnBackSpace();
</span><span class="cx" style="display: block; padding: 0 10px">       emptyEditorWhenDeleting();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -43726,7 +44905,6 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // WebKit
</span><span class="cx" style="display: block; padding: 0 10px">       if (isWebKit) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        emptyEditorOnDeleteEverything();
</del><span class="cx" style="display: block; padding: 0 10px">         inputMethodFocus();
</span><span class="cx" style="display: block; padding: 0 10px">         selectControlElements();
</span><span class="cx" style="display: block; padding: 0 10px">         setDefaultBlockType();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -43771,7 +44949,6 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // Gecko
</span><span class="cx" style="display: block; padding: 0 10px">       if (isGecko) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        emptyEditorOnDeleteEverything();
</del><span class="cx" style="display: block; padding: 0 10px">         removeHrOnBackspace();
</span><span class="cx" style="display: block; padding: 0 10px">         focusBody();
</span><span class="cx" style="display: block; padding: 0 10px">         removeStylesWhenDeletingAcrossBlockElements();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -43803,8 +44980,12 @@
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><span class="cx" style="display: block; padding: 0 10px">   'tinymce.core.init.InitContentBody',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.sugar.api.dom.Insert',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.properties.Attr',
</ins><span class="cx" style="display: block; padding: 0 10px">     'global!document',
</span><span class="cx" style="display: block; padding: 0 10px">     'global!window',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.api.Formatter',
</ins><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.caret.CaretContainerInput',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.dom.DOMUtils',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.dom.Selection',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -43812,7 +44993,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.EditorUpload',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.ErrorReporter',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.ForceBlocks',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.Formatter',
</del><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.html.DomParser',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.html.Node',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.html.Schema',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -43825,11 +45005,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.Tools'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><span class="cx" style="display: block; padding: 0 10px">   function (
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    document, window, CaretContainerInput, DOMUtils, Selection, Serializer, EditorUpload, ErrorReporter, ForceBlocks, Formatter, DomParser, Node, Schema, KeyboardOverrides,
-    NodeChange, SelectionOverrides, UndoManager, Delay, Quirks, Tools
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    Insert, Element, Attr, document, window, Formatter, CaretContainerInput, DOMUtils, Selection, Serializer, EditorUpload, ErrorReporter, ForceBlocks, DomParser,
+    Node, Schema, KeyboardOverrides, NodeChange, SelectionOverrides, UndoManager, Delay, Quirks, Tools
</ins><span class="cx" style="display: block; padding: 0 10px">   ) {
</span><span class="cx" style="display: block; padding: 0 10px">     var DOM = DOMUtils.DOM;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var appendStyle = function (editor, text) {
+      var head = Element.fromDom(editor.getDoc().head);
+      var tag = Element.fromTag('style');
+      Attr.set(tag, 'type', 'text/css');
+      Insert.append(tag, Element.fromText(text));
+      Insert.append(head, tag);
+    };
+
</ins><span class="cx" style="display: block; padding: 0 10px">     var createParser = function (editor) {
</span><span class="cx" style="display: block; padding: 0 10px">       var parser = new DomParser(editor.settings, editor.schema);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -43935,6 +45123,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">       autoFocus(editor);
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var getStyleSheetLoader = function (editor) {
+      return editor.inline ? DOM.styleSheetLoader : editor.dom.styleSheetLoader;
+    };
+
</ins><span class="cx" style="display: block; padding: 0 10px">     var initContentBody = function (editor, skipWrite) {
</span><span class="cx" style="display: block; padding: 0 10px">       var settings = editor.settings, targetElm = editor.getElement(), doc = editor.getDoc(), body, contentCssText;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -44072,16 +45264,20 @@
</span><span class="cx" style="display: block; padding: 0 10px">         editor.dom.addStyle(contentCssText);
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      editor.dom.styleSheetLoader.loadAll(
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      getStyleSheetLoader(editor).loadAll(
</ins><span class="cx" style="display: block; padding: 0 10px">         editor.contentCSS,
</span><span class="cx" style="display: block; padding: 0 10px">         function (_) {
</span><span class="cx" style="display: block; padding: 0 10px">           initEditor(editor);
</span><span class="cx" style="display: block; padding: 0 10px">         },
</span><span class="cx" style="display: block; padding: 0 10px">         function (urls) {
</span><span class="cx" style="display: block; padding: 0 10px">           initEditor(editor);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          ErrorReporter.contentCssError(editor, urls);
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">       );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+      // Append specified content CSS last
+      if (settings.content_style) {
+        appendStyle(editor, settings.content_style);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     return {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -44181,11 +45377,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var trimLegacyPrefix = function (name) {
+      // Themes and plugins can be prefixed with - to prevent them from being lazy loaded
+      return name.replace(/^\-/, '');
+    };
+
</ins><span class="cx" style="display: block; padding: 0 10px">     var initPlugins = function (editor) {
</span><span class="cx" style="display: block; padding: 0 10px">       var initializedPlugins = [];
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      Tools.each(editor.settings.plugins.replace(/\-/g, '').split(/[ ,]/), function (name) {
-        initPlugin(editor, initializedPlugins, name);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      Tools.each(editor.settings.plugins.split(/[ ,]/), function (name) {
+        initPlugin(editor, initializedPlugins, trimLegacyPrefix(name));
</ins><span class="cx" style="display: block; padding: 0 10px">       });
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -44194,7 +45395,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       if (settings.theme) {
</span><span class="cx" style="display: block; padding: 0 10px">         if (typeof settings.theme != "function") {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          settings.theme = settings.theme.replace(/-/, '');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          settings.theme = trimLegacyPrefix(settings.theme);
+
</ins><span class="cx" style="display: block; padding: 0 10px">           Theme = ThemeManager.get(settings.theme);
</span><span class="cx" style="display: block; padding: 0 10px">           editor.theme = new Theme(editor, ThemeManager.urls[settings.theme]);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -44379,11 +45581,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">         });
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Load specified content CSS last
-      if (settings.content_style) {
-        editor.contentStyles.push(settings.content_style);
-      }
-
</del><span class="cx" style="display: block; padding: 0 10px">       // Content editable mode ends here
</span><span class="cx" style="display: block; padding: 0 10px">       if (settings.content_editable) {
</span><span class="cx" style="display: block; padding: 0 10px">         return InitContentBody.initContentBody(editor);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -44424,19 +45621,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">   'tinymce.core.init.Render',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><span class="cx" style="display: block; padding: 0 10px">     'global!window',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.api.NotificationManager',
+    'tinymce.core.api.WindowManager',
</ins><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.dom.DOMUtils',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.dom.EventUtils',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.dom.ScriptLoader',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.Env',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.ErrorReporter',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.init.Init',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.NotificationManager',
</del><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.PluginManager',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.ThemeManager',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.util.Tools',
-    'tinymce.core.WindowManager'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.util.Tools'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (window, DOMUtils, EventUtils, ScriptLoader, Env, ErrorReporter, Init, NotificationManager, PluginManager, ThemeManager, Tools, WindowManager) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (window, NotificationManager, WindowManager, DOMUtils, EventUtils, ScriptLoader, Env, ErrorReporter, Init, PluginManager, ThemeManager, Tools) {
</ins><span class="cx" style="display: block; padding: 0 10px">     var DOM = DOMUtils.DOM;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var loadScripts = function (editor, suffix) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -44715,6 +45912,227 @@
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Shortcuts.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * Contains logic for handling keyboard shortcuts.
+ *
+ * @class tinymce.Shortcuts
+ * @example
+ * editor.shortcuts.add('ctrl+a', "description of the shortcut", function() {});
+ * editor.shortcuts.add('meta+a', "description of the shortcut", function() {}); // "meta" maps to Command on Mac and Ctrl on PC
+ * editor.shortcuts.add('ctrl+alt+a', "description of the shortcut", function() {});
+ * editor.shortcuts.add('access+a', "description of the shortcut", function() {}); // "access" maps to ctrl+alt on Mac and shift+alt on PC
+ */
+define(
+  'tinymce.core.Shortcuts',
+  [
+    'tinymce.core.util.Tools',
+    'tinymce.core.Env'
+  ],
+  function (Tools, Env) {
+    var each = Tools.each, explode = Tools.explode;
+
+    var keyCodeLookup = {
+      "f9": 120,
+      "f10": 121,
+      "f11": 122
+    };
+
+    var modifierNames = Tools.makeMap('alt,ctrl,shift,meta,access');
+
+    return function (editor) {
+      var self = this, shortcuts = {}, pendingPatterns = [];
+
+      function parseShortcut(pattern) {
+        var id, key, shortcut = {};
+
+        // Parse modifiers and keys ctrl+alt+b for example
+        each(explode(pattern, '+'), function (value) {
+          if (value in modifierNames) {
+            shortcut[value] = true;
+          } else {
+            // Allow numeric keycodes like ctrl+219 for ctrl+[
+            if (/^[0-9]{2,}$/.test(value)) {
+              shortcut.keyCode = parseInt(value, 10);
+            } else {
+              shortcut.charCode = value.charCodeAt(0);
+              shortcut.keyCode = keyCodeLookup[value] || value.toUpperCase().charCodeAt(0);
+            }
+          }
+        });
+
+        // Generate unique id for modifier combination and set default state for unused modifiers
+        id = [shortcut.keyCode];
+        for (key in modifierNames) {
+          if (shortcut[key]) {
+            id.push(key);
+          } else {
+            shortcut[key] = false;
+          }
+        }
+        shortcut.id = id.join(',');
+
+        // Handle special access modifier differently depending on Mac/Win
+        if (shortcut.access) {
+          shortcut.alt = true;
+
+          if (Env.mac) {
+            shortcut.ctrl = true;
+          } else {
+            shortcut.shift = true;
+          }
+        }
+
+        // Handle special meta modifier differently depending on Mac/Win
+        if (shortcut.meta) {
+          if (Env.mac) {
+            shortcut.meta = true;
+          } else {
+            shortcut.ctrl = true;
+            shortcut.meta = false;
+          }
+        }
+
+        return shortcut;
+      }
+
+      function createShortcut(pattern, desc, cmdFunc, scope) {
+        var shortcuts;
+
+        shortcuts = Tools.map(explode(pattern, '>'), parseShortcut);
+        shortcuts[shortcuts.length - 1] = Tools.extend(shortcuts[shortcuts.length - 1], {
+          func: cmdFunc,
+          scope: scope || editor
+        });
+
+        return Tools.extend(shortcuts[0], {
+          desc: editor.translate(desc),
+          subpatterns: shortcuts.slice(1)
+        });
+      }
+
+      function hasModifier(e) {
+        return e.altKey || e.ctrlKey || e.metaKey;
+      }
+
+      function isFunctionKey(e) {
+        return e.type === "keydown" && e.keyCode >= 112 && e.keyCode <= 123;
+      }
+
+      function matchShortcut(e, shortcut) {
+        if (!shortcut) {
+          return false;
+        }
+
+        if (shortcut.ctrl != e.ctrlKey || shortcut.meta != e.metaKey) {
+          return false;
+        }
+
+        if (shortcut.alt != e.altKey || shortcut.shift != e.shiftKey) {
+          return false;
+        }
+
+        if (e.keyCode == shortcut.keyCode || (e.charCode && e.charCode == shortcut.charCode)) {
+          e.preventDefault();
+          return true;
+        }
+
+        return false;
+      }
+
+      function executeShortcutAction(shortcut) {
+        return shortcut.func ? shortcut.func.call(shortcut.scope) : null;
+      }
+
+      editor.on('keyup keypress keydown', function (e) {
+        if ((hasModifier(e) || isFunctionKey(e)) && !e.isDefaultPrevented()) {
+          each(shortcuts, function (shortcut) {
+            if (matchShortcut(e, shortcut)) {
+              pendingPatterns = shortcut.subpatterns.slice(0);
+
+              if (e.type == "keydown") {
+                executeShortcutAction(shortcut);
+              }
+
+              return true;
+            }
+          });
+
+          if (matchShortcut(e, pendingPatterns[0])) {
+            if (pendingPatterns.length === 1) {
+              if (e.type == "keydown") {
+                executeShortcutAction(pendingPatterns[0]);
+              }
+            }
+
+            pendingPatterns.shift();
+          }
+        }
+      });
+
+      /**
+       * Adds a keyboard shortcut for some command or function.
+       *
+       * @method add
+       * @param {String} pattern Shortcut pattern. Like for example: ctrl+alt+o.
+       * @param {String} desc Text description for the command.
+       * @param {String/Function} cmdFunc Command name string or function to execute when the key is pressed.
+       * @param {Object} scope Optional scope to execute the function in.
+       * @return {Boolean} true/false state if the shortcut was added or not.
+       */
+      self.add = function (pattern, desc, cmdFunc, scope) {
+        var cmd;
+
+        cmd = cmdFunc;
+
+        if (typeof cmdFunc === 'string') {
+          cmdFunc = function () {
+            editor.execCommand(cmd, false, null);
+          };
+        } else if (Tools.isArray(cmd)) {
+          cmdFunc = function () {
+            editor.execCommand(cmd[0], cmd[1], cmd[2]);
+          };
+        }
+
+        each(explode(Tools.trim(pattern.toLowerCase())), function (pattern) {
+          var shortcut = createShortcut(pattern, desc, cmdFunc, scope);
+          shortcuts[shortcut.id] = shortcut;
+        });
+
+        return true;
+      };
+
+      /**
+       * Remove a keyboard shortcut by pattern.
+       *
+       * @method remove
+       * @param {String} pattern Shortcut pattern. Like for example: ctrl+alt+o.
+       * @return {Boolean} true/false state if the shortcut was removed or not.
+       */
+      self.remove = function (pattern) {
+        var shortcut = createShortcut(pattern);
+
+        if (shortcuts[shortcut.id]) {
+          delete shortcuts[shortcut.id];
+          return true;
+        }
+
+        return false;
+      };
+    };
+  }
+);
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * Sidebar.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -44749,6 +46167,444 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * URI.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This class handles parsing, modification and serialization of URI/URL strings.
+ * @class tinymce.util.URI
+ */
+define(
+  'tinymce.core.util.URI',
+  [
+    'global!document',
+    'tinymce.core.util.Tools'
+  ],
+  function (document, Tools) {
+    var each = Tools.each, trim = Tools.trim;
+    var queryParts = "source protocol authority userInfo user password host port relative path directory file query anchor".split(' ');
+    var DEFAULT_PORTS = {
+      'ftp': 21,
+      'http': 80,
+      'https': 443,
+      'mailto': 25
+    };
+
+    /**
+     * Constructs a new URI instance.
+     *
+     * @constructor
+     * @method URI
+     * @param {String} url URI string to parse.
+     * @param {Object} settings Optional settings object.
+     */
+    function URI(url, settings) {
+      var self = this, baseUri, baseUrl;
+
+      url = trim(url);
+      settings = self.settings = settings || {};
+      baseUri = settings.base_uri;
+
+      // Strange app protocol that isn't http/https or local anchor
+      // For example: mailto,skype,tel etc.
+      if (/^([\w\-]+):([^\/]{2})/i.test(url) || /^\s*#/.test(url)) {
+        self.source = url;
+        return;
+      }
+
+      var isProtocolRelative = url.indexOf('//') === 0;
+
+      // Absolute path with no host, fake host and protocol
+      if (url.indexOf('/') === 0 && !isProtocolRelative) {
+        url = (baseUri ? baseUri.protocol || 'http' : 'http') + '://mce_host' + url;
+      }
+
+      // Relative path http:// or protocol relative //path
+      if (!/^[\w\-]*:?\/\//.test(url)) {
+        baseUrl = settings.base_uri ? settings.base_uri.path : new URI(document.location.href).directory;
+        if (settings.base_uri.protocol === "") {
+          url = '//mce_host' + self.toAbsPath(baseUrl, url);
+        } else {
+          url = /([^#?]*)([#?]?.*)/.exec(url);
+          url = ((baseUri && baseUri.protocol) || 'http') + '://mce_host' + self.toAbsPath(baseUrl, url[1]) + url[2];
+        }
+      }
+
+      // Parse URL (Credits goes to Steave, http://blog.stevenlevithan.com/archives/parseuri)
+      url = url.replace(/@@/g, '(mce_at)'); // Zope 3 workaround, they use @@something
+
+      /*jshint maxlen: 255 */
+      /*eslint max-len: 0 */
+      url = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(url);
+
+      each(queryParts, function (v, i) {
+        var part = url[i];
+
+        // Zope 3 workaround, they use @@something
+        if (part) {
+          part = part.replace(/\(mce_at\)/g, '@@');
+        }
+
+        self[v] = part;
+      });
+
+      if (baseUri) {
+        if (!self.protocol) {
+          self.protocol = baseUri.protocol;
+        }
+
+        if (!self.userInfo) {
+          self.userInfo = baseUri.userInfo;
+        }
+
+        if (!self.port && self.host === 'mce_host') {
+          self.port = baseUri.port;
+        }
+
+        if (!self.host || self.host === 'mce_host') {
+          self.host = baseUri.host;
+        }
+
+        self.source = '';
+      }
+
+      if (isProtocolRelative) {
+        self.protocol = '';
+      }
+
+      //t.path = t.path || '/';
+    }
+
+    URI.prototype = {
+      /**
+       * Sets the internal path part of the URI.
+       *
+       * @method setPath
+       * @param {string} path Path string to set.
+       */
+      setPath: function (path) {
+        var self = this;
+
+        path = /^(.*?)\/?(\w+)?$/.exec(path);
+
+        // Update path parts
+        self.path = path[0];
+        self.directory = path[1];
+        self.file = path[2];
+
+        // Rebuild source
+        self.source = '';
+        self.getURI();
+      },
+
+      /**
+       * Converts the specified URI into a relative URI based on the current URI instance location.
+       *
+       * @method toRelative
+       * @param {String} uri URI to convert into a relative path/URI.
+       * @return {String} Relative URI from the point specified in the current URI instance.
+       * @example
+       * // Converts an absolute URL to an relative URL url will be somedir/somefile.htm
+       * var url = new tinymce.util.URI('http://www.site.com/dir/').toRelative('http://www.site.com/dir/somedir/somefile.htm');
+       */
+      toRelative: function (uri) {
+        var self = this, output;
+
+        if (uri === "./") {
+          return uri;
+        }
+
+        uri = new URI(uri, { base_uri: self });
+
+        // Not on same domain/port or protocol
+        if ((uri.host != 'mce_host' && self.host != uri.host && uri.host) || self.port != uri.port ||
+          (self.protocol != uri.protocol && uri.protocol !== "")) {
+          return uri.getURI();
+        }
+
+        var tu = self.getURI(), uu = uri.getURI();
+
+        // Allow usage of the base_uri when relative_urls = true
+        if (tu == uu || (tu.charAt(tu.length - 1) == "/" && tu.substr(0, tu.length - 1) == uu)) {
+          return tu;
+        }
+
+        output = self.toRelPath(self.path, uri.path);
+
+        // Add query
+        if (uri.query) {
+          output += '?' + uri.query;
+        }
+
+        // Add anchor
+        if (uri.anchor) {
+          output += '#' + uri.anchor;
+        }
+
+        return output;
+      },
+
+      /**
+       * Converts the specified URI into a absolute URI based on the current URI instance location.
+       *
+       * @method toAbsolute
+       * @param {String} uri URI to convert into a relative path/URI.
+       * @param {Boolean} noHost No host and protocol prefix.
+       * @return {String} Absolute URI from the point specified in the current URI instance.
+       * @example
+       * // Converts an relative URL to an absolute URL url will be http://www.site.com/dir/somedir/somefile.htm
+       * var url = new tinymce.util.URI('http://www.site.com/dir/').toAbsolute('somedir/somefile.htm');
+       */
+      toAbsolute: function (uri, noHost) {
+        uri = new URI(uri, { base_uri: this });
+
+        return uri.getURI(noHost && this.isSameOrigin(uri));
+      },
+
+      /**
+       * Determine whether the given URI has the same origin as this URI.  Based on RFC-6454.
+       * Supports default ports for protocols listed in DEFAULT_PORTS.  Unsupported protocols will fail safe: they
+       * won't match, if the port specifications differ.
+       *
+       * @method isSameOrigin
+       * @param {tinymce.util.URI} uri Uri instance to compare.
+       * @returns {Boolean} True if the origins are the same.
+       */
+      isSameOrigin: function (uri) {
+        if (this.host == uri.host && this.protocol == uri.protocol) {
+          if (this.port == uri.port) {
+            return true;
+          }
+
+          var defaultPort = DEFAULT_PORTS[this.protocol];
+          if (defaultPort && ((this.port || defaultPort) == (uri.port || defaultPort))) {
+            return true;
+          }
+        }
+
+        return false;
+      },
+
+      /**
+       * Converts a absolute path into a relative path.
+       *
+       * @method toRelPath
+       * @param {String} base Base point to convert the path from.
+       * @param {String} path Absolute path to convert into a relative path.
+       */
+      toRelPath: function (base, path) {
+        var items, breakPoint = 0, out = '', i, l;
+
+        // Split the paths
+        base = base.substring(0, base.lastIndexOf('/'));
+        base = base.split('/');
+        items = path.split('/');
+
+        if (base.length >= items.length) {
+          for (i = 0, l = base.length; i < l; i++) {
+            if (i >= items.length || base[i] != items[i]) {
+              breakPoint = i + 1;
+              break;
+            }
+          }
+        }
+
+        if (base.length < items.length) {
+          for (i = 0, l = items.length; i < l; i++) {
+            if (i >= base.length || base[i] != items[i]) {
+              breakPoint = i + 1;
+              break;
+            }
+          }
+        }
+
+        if (breakPoint === 1) {
+          return path;
+        }
+
+        for (i = 0, l = base.length - (breakPoint - 1); i < l; i++) {
+          out += "../";
+        }
+
+        for (i = breakPoint - 1, l = items.length; i < l; i++) {
+          if (i != breakPoint - 1) {
+            out += "/" + items[i];
+          } else {
+            out += items[i];
+          }
+        }
+
+        return out;
+      },
+
+      /**
+       * Converts a relative path into a absolute path.
+       *
+       * @method toAbsPath
+       * @param {String} base Base point to convert the path from.
+       * @param {String} path Relative path to convert into an absolute path.
+       */
+      toAbsPath: function (base, path) {
+        var i, nb = 0, o = [], tr, outPath;
+
+        // Split paths
+        tr = /\/$/.test(path) ? '/' : '';
+        base = base.split('/');
+        path = path.split('/');
+
+        // Remove empty chunks
+        each(base, function (k) {
+          if (k) {
+            o.push(k);
+          }
+        });
+
+        base = o;
+
+        // Merge relURLParts chunks
+        for (i = path.length - 1, o = []; i >= 0; i--) {
+          // Ignore empty or .
+          if (path[i].length === 0 || path[i] === ".") {
+            continue;
+          }
+
+          // Is parent
+          if (path[i] === '..') {
+            nb++;
+            continue;
+          }
+
+          // Move up
+          if (nb > 0) {
+            nb--;
+            continue;
+          }
+
+          o.push(path[i]);
+        }
+
+        i = base.length - nb;
+
+        // If /a/b/c or /
+        if (i <= 0) {
+          outPath = o.reverse().join('/');
+        } else {
+          outPath = base.slice(0, i).join('/') + '/' + o.reverse().join('/');
+        }
+
+        // Add front / if it's needed
+        if (outPath.indexOf('/') !== 0) {
+          outPath = '/' + outPath;
+        }
+
+        // Add traling / if it's needed
+        if (tr && outPath.lastIndexOf('/') !== outPath.length - 1) {
+          outPath += tr;
+        }
+
+        return outPath;
+      },
+
+      /**
+       * Returns the full URI of the internal structure.
+       *
+       * @method getURI
+       * @param {Boolean} noProtoHost Optional no host and protocol part. Defaults to false.
+       */
+      getURI: function (noProtoHost) {
+        var s, self = this;
+
+        // Rebuild source
+        if (!self.source || noProtoHost) {
+          s = '';
+
+          if (!noProtoHost) {
+            if (self.protocol) {
+              s += self.protocol + '://';
+            } else {
+              s += '//';
+            }
+
+            if (self.userInfo) {
+              s += self.userInfo + '@';
+            }
+
+            if (self.host) {
+              s += self.host;
+            }
+
+            if (self.port) {
+              s += ':' + self.port;
+            }
+          }
+
+          if (self.path) {
+            s += self.path;
+          }
+
+          if (self.query) {
+            s += '?' + self.query;
+          }
+
+          if (self.anchor) {
+            s += '#' + self.anchor;
+          }
+
+          self.source = s;
+        }
+
+        return self.source;
+      }
+    };
+
+    URI.parseDataUri = function (uri) {
+      var type, matches;
+
+      uri = decodeURIComponent(uri).split(',');
+
+      matches = /data:([^;]+)/.exec(uri[0]);
+      if (matches) {
+        type = matches[1];
+      }
+
+      return {
+        type: type,
+        data: uri[1]
+      };
+    };
+
+    URI.getDocumentBaseUrl = function (loc) {
+      var baseUrl;
+
+      // Pass applewebdata:// and other non web protocols though
+      if (loc.protocol.indexOf('http') !== 0 && loc.protocol !== 'file:') {
+        baseUrl = loc.href;
+      } else {
+        baseUrl = loc.protocol + '//' + loc.host + loc.pathname;
+      }
+
+      if (/^[^:]+:\/\/\/?[^\/]+\//.test(baseUrl)) {
+        baseUrl = baseUrl.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
+
+        if (!/[\/\\]$/.test(baseUrl)) {
+          baseUrl += '/';
+        }
+      }
+
+      return baseUrl;
+    };
+
+    return URI;
+  }
+);
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * Editor.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -44792,7 +46648,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.dom.DomQuery',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.dom.DOMUtils',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.EditorCommands',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.EditorFocus',
</ins><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.EditorObservable',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.EditorSettings',
</ins><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.Env',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.html.Serializer',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.init.Render',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -44804,14 +46662,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.Uuid'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><span class="cx" style="display: block; padding: 0 10px">   function (
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    AddOnManager, DomQuery, DOMUtils, EditorCommands, EditorObservable, Env, Serializer, Render, Mode,
-    Shortcuts, Sidebar, Tools, URI, Uuid
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    AddOnManager, DomQuery, DOMUtils, EditorCommands, EditorFocus, EditorObservable, EditorSettings, Env, Serializer, Render, Mode, Shortcuts, Sidebar, Tools,
+    URI, Uuid
</ins><span class="cx" style="display: block; padding: 0 10px">   ) {
</span><span class="cx" style="display: block; padding: 0 10px">     // Shorten these names
</span><span class="cx" style="display: block; padding: 0 10px">     var DOM = DOMUtils.DOM;
</span><span class="cx" style="display: block; padding: 0 10px">     var extend = Tools.extend, each = Tools.each;
</span><span class="cx" style="display: block; padding: 0 10px">     var trim = Tools.trim, resolve = Tools.resolve;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var isGecko = Env.gecko, ie = Env.ie;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var ie = Env.ie;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     /**
</span><span class="cx" style="display: block; padding: 0 10px">      * Include Editor API docs.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -44829,11 +46687,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">      * @param {tinymce.EditorManager} editorManager EditorManager instance.
</span><span class="cx" style="display: block; padding: 0 10px">      */
</span><span class="cx" style="display: block; padding: 0 10px">     function Editor(id, settings, editorManager) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var self = this, documentBaseUrl, baseUri, defaultSettings;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var self = this, documentBaseUrl, baseUri;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       documentBaseUrl = self.documentBaseUrl = editorManager.documentBaseURL;
</span><span class="cx" style="display: block; padding: 0 10px">       baseUri = editorManager.baseURI;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      defaultSettings = editorManager.defaultSettings;
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       /**
</span><span class="cx" style="display: block; padding: 0 10px">        * Name/value collection with editor settings.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -44844,52 +46701,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">        * // Get the value of the theme setting
</span><span class="cx" style="display: block; padding: 0 10px">        * tinymce.activeEditor.windowManager.alert("You are using the " + tinymce.activeEditor.settings.theme + " theme");
</span><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      settings = extend({
-        id: id,
-        theme: 'modern',
-        delta_width: 0,
-        delta_height: 0,
-        popup_css: '',
-        plugins: '',
-        document_base_url: documentBaseUrl,
-        add_form_submit_trigger: true,
-        submit_patch: true,
-        add_unload_trigger: true,
-        convert_urls: true,
-        relative_urls: true,
-        remove_script_host: true,
-        object_resizing: true,
-        doctype: '<!DOCTYPE html>',
-        visual: true,
-        font_size_style_values: 'xx-small,x-small,small,medium,large,x-large,xx-large',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      settings = EditorSettings.getEditorSettings(self, id, documentBaseUrl, editorManager.defaultSettings, settings);
+      self.settings = settings;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // See: http://www.w3.org/TR/CSS2/fonts.html#propdef-font-size
-        font_size_legacy_values: 'xx-small,small,medium,large,x-large,xx-large,300%',
-        forced_root_block: 'p',
-        hidden_input: true,
-        padd_empty_editor: true,
-        render_ui: true,
-        indentation: '30px',
-        inline_styles: true,
-        convert_fonts_to_spans: true,
-        indent: 'simple',
-        indent_before: 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,' +
-        'tfoot,tbody,tr,section,article,hgroup,aside,figure,figcaption,option,optgroup,datalist',
-        indent_after: 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,' +
-        'tfoot,tbody,tr,section,article,hgroup,aside,figure,figcaption,option,optgroup,datalist',
-        validate: true,
-        entity_encoding: 'named',
-        url_converter: self.convertURL,
-        url_converter_scope: self,
-        ie7_compat: true
-      }, defaultSettings, settings);
-
-      // Merge external_plugins
-      if (defaultSettings && defaultSettings.external_plugins && settings.external_plugins) {
-        settings.external_plugins = extend({}, defaultSettings.external_plugins, settings.external_plugins);
-      }
-
-      self.settings = settings;
</del><span class="cx" style="display: block; padding: 0 10px">       AddOnManager.language = settings.language || 'en';
</span><span class="cx" style="display: block; padding: 0 10px">       AddOnManager.languageLoad = settings.language_load;
</span><span class="cx" style="display: block; padding: 0 10px">       AddOnManager.baseURL = editorManager.baseURL;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -44900,7 +46714,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        * @property id
</span><span class="cx" style="display: block; padding: 0 10px">        * @type String
</span><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      self.id = settings.id = id;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      self.id = id;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       /**
</span><span class="cx" style="display: block; padding: 0 10px">        * State to force the editor to return false on a isDirty call.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -44934,7 +46748,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        * // Get absolute URL from the location of document_base_url
</span><span class="cx" style="display: block; padding: 0 10px">        * tinymce.activeEditor.documentBaseURI.toAbsolute('somefile.htm');
</span><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      self.documentBaseURI = new URI(settings.document_base_url || documentBaseUrl, {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      self.documentBaseURI = new URI(settings.document_base_url, {
</ins><span class="cx" style="display: block; padding: 0 10px">         base_uri: baseUri
</span><span class="cx" style="display: block; padding: 0 10px">       });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -44975,7 +46789,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">       self.suffix = editorManager.suffix;
</span><span class="cx" style="display: block; padding: 0 10px">       self.editorManager = editorManager;
</span><span class="cx" style="display: block; padding: 0 10px">       self.inline = settings.inline;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      self.settings.content_editable = self.inline;
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       if (settings.cache_suffix) {
</span><span class="cx" style="display: block; padding: 0 10px">         Env.cacheSuffix = settings.cache_suffix.replace(/^[\?\&]+/, '');
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -45024,78 +46837,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        * @param {Boolean} skipFocus Skip DOM focus. Just set is as the active editor.
</span><span class="cx" style="display: block; padding: 0 10px">        */
</span><span class="cx" style="display: block; padding: 0 10px">       focus: function (skipFocus) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var self = this, selection = self.selection, contentEditable = self.settings.content_editable, rng;
-        var controlElm, doc = self.getDoc(), body = self.getBody(), contentEditableHost;
-
-        function getContentEditableHost(node) {
-          return self.dom.getParent(node, function (node) {
-            return self.dom.getContentEditable(node) === "true";
-          });
-        }
-
-        if (self.removed) {
-          return;
-        }
-
-        if (!skipFocus) {
-          // Get selected control element
-          rng = selection.getRng();
-          if (rng.item) {
-            controlElm = rng.item(0);
-          }
-
-          self.quirks.refreshContentEditable();
-
-          // Move focus to contentEditable=true child if needed
-          contentEditableHost = getContentEditableHost(selection.getNode());
-          if (self.$.contains(body, contentEditableHost)) {
-            contentEditableHost.focus();
-            selection.normalize();
-            self.editorManager.setActive(self);
-            return;
-          }
-
-          // Focus the window iframe
-          if (!contentEditable) {
-            // WebKit needs this call to fire focusin event properly see #5948
-            // But Opera pre Blink engine will produce an empty selection so skip Opera
-            if (!Env.opera) {
-              self.getBody().focus();
-            }
-
-            self.getWin().focus();
-          }
-
-          // Focus the body as well since it's contentEditable
-          if (isGecko || contentEditable) {
-            // Check for setActive since it doesn't scroll to the element
-            if (body.setActive) {
-              // IE 11 sometimes throws "Invalid function" then fallback to focus
-              try {
-                body.setActive();
-              } catch (ex) {
-                body.focus();
-              }
-            } else {
-              body.focus();
-            }
-
-            if (contentEditable) {
-              selection.normalize();
-            }
-          }
-
-          // Restore selected control element
-          // This is needed when for example an image is selected within a
-          // layer a call to focus will then remove the control selection
-          if (controlElm && controlElm.ownerDocument == doc) {
-            rng = doc.body.createControlRange();
-            rng.addElement(controlElm);
-            rng.select();
-          }
-        }
-
-        self.editorManager.setActive(self);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        EditorFocus.focus(this, skipFocus);
</ins><span class="cx" style="display: block; padding: 0 10px">       },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -45139,16 +46881,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">        * @return {String} Translated string.
</span><span class="cx" style="display: block; padding: 0 10px">        */
</span><span class="cx" style="display: block; padding: 0 10px">       translate: function (text) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var lang = this.settings.language || 'en', i18n = this.editorManager.i18n;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (text && Tools.is(text, 'string')) {
+          var lang = this.settings.language || 'en', i18n = this.editorManager.i18n;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (!text) {
-          return '';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          text = i18n.data[lang + '.' + text] || text.replace(/\{\#([^\}]+)\}/g, function (a, b) {
+            return i18n.data[lang + '.' + b] || '{#' + b + '}';
+          });
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        text = i18n.data[lang + '.' + text] || text.replace(/\{\#([^\}]+)\}/g, function (a, b) {
-          return i18n.data[lang + '.' + b] || '{#' + b + '}';
-        });
-
</del><span class="cx" style="display: block; padding: 0 10px">         return this.editorManager.translate(text);
</span><span class="cx" style="display: block; padding: 0 10px">       },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -46188,150 +47928,6 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * I18n.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * I18n class that handles translation of TinyMCE UI.
- * Uses po style with csharp style parameters.
- *
- * @class tinymce.util.I18n
- */
-define(
-  'tinymce.core.util.I18n',
-  [
-    "tinymce.core.util.Tools"
-  ],
-  function (Tools) {
-    "use strict";
-
-    var data = {}, code = "en";
-
-    return {
-      /**
-       * Sets the current language code.
-       *
-       * @method setCode
-       * @param {String} newCode Current language code.
-       */
-      setCode: function (newCode) {
-        if (newCode) {
-          code = newCode;
-          this.rtl = this.data[newCode] ? this.data[newCode]._dir === 'rtl' : false;
-        }
-      },
-
-      /**
-       * Returns the current language code.
-       *
-       * @method getCode
-       * @return {String} Current language code.
-       */
-      getCode: function () {
-        return code;
-      },
-
-      /**
-       * Property gets set to true if a RTL language pack was loaded.
-       *
-       * @property rtl
-       * @type Boolean
-       */
-      rtl: false,
-
-      /**
-       * Adds translations for a specific language code.
-       *
-       * @method add
-       * @param {String} code Language code like sv_SE.
-       * @param {Array} items Name/value array with English en_US to sv_SE.
-       */
-      add: function (code, items) {
-        var langData = data[code];
-
-        if (!langData) {
-          data[code] = langData = {};
-        }
-
-        for (var name in items) {
-          langData[name] = items[name];
-        }
-
-        this.setCode(code);
-      },
-
-      /**
-       * Translates the specified text.
-       *
-       * It has a few formats:
-       * I18n.translate("Text");
-       * I18n.translate(["Text {0}/{1}", 0, 1]);
-       * I18n.translate({raw: "Raw string"});
-       *
-       * @method translate
-       * @param {String/Object/Array} text Text to translate.
-       * @return {String} String that got translated.
-       */
-      translate: function (text) {
-        var langData = data[code] || {};
-
-        /**
-         * number - string
-         * null, undefined and empty string - empty string
-         * array - comma-delimited string
-         * object - in [object Object]
-         * function - in [object Function]
-         *
-         * @param obj
-         * @returns {string}
-         */
-        function toString(obj) {
-          if (Tools.is(obj, 'function')) {
-            return Object.prototype.toString.call(obj);
-          }
-          return !isEmpty(obj) ? '' + obj : '';
-        }
-
-        function isEmpty(text) {
-          return text === '' || text === null || Tools.is(text, 'undefined');
-        }
-
-        function getLangData(text) {
-          // make sure we work on a string and return a string
-          text = toString(text);
-          return Tools.hasOwn(langData, text) ? toString(langData[text]) : text;
-        }
-
-
-        if (isEmpty(text)) {
-          return '';
-        }
-
-        if (Tools.is(text, 'object') && Tools.hasOwn(text, 'raw')) {
-          return toString(text.raw);
-        }
-
-        if (Tools.is(text, 'array')) {
-          var values = text.slice(1);
-          text = getLangData(text[0]).replace(/\{([0-9]+)\}/g, function ($1, $2) {
-            return Tools.hasOwn(values, $2) ? toString(values[$2]) : $1;
-          });
-        }
-
-        return getLangData(text).replace(/{context:\w+}$/, '');
-      },
-
-      data: data
-    };
-  }
-);
-/**
</del><span class="cx" style="display: block; padding: 0 10px">  * FocusManager.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -46469,25 +48065,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">                 }
</span><span class="cx" style="display: block; padding: 0 10px">               });
</span><span class="cx" style="display: block; padding: 0 10px">             }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-            // Handles the issue with WebKit not retaining selection within inline document
-            // If the user releases the mouse out side the body since a mouse up event wont occur on the body
-            if (Env.webkit && !selectionChangeHandler) {
-              selectionChangeHandler = function () {
-                var activeEditor = editorManager.activeEditor;
-
-                if (activeEditor && activeEditor.selection) {
-                  var rng = activeEditor.selection.getRng();
-
-                  // Store when it's non collapsed
-                  if (rng && !rng.collapsed) {
-                    editor.lastRng = rng;
-                  }
-                }
-              };
-
-              DOM.bind(document, 'selectionchange', selectionChangeHandler);
-            }
</del><span class="cx" style="display: block; padding: 0 10px">           }
</span><span class="cx" style="display: block; padding: 0 10px">         });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -46713,6 +48290,150 @@
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * I18n.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * I18n class that handles translation of TinyMCE UI.
+ * Uses po style with csharp style parameters.
+ *
+ * @class tinymce.util.I18n
+ */
+define(
+  'tinymce.core.util.I18n',
+  [
+    "tinymce.core.util.Tools"
+  ],
+  function (Tools) {
+    "use strict";
+
+    var data = {}, code = "en";
+
+    return {
+      /**
+       * Sets the current language code.
+       *
+       * @method setCode
+       * @param {String} newCode Current language code.
+       */
+      setCode: function (newCode) {
+        if (newCode) {
+          code = newCode;
+          this.rtl = this.data[newCode] ? this.data[newCode]._dir === 'rtl' : false;
+        }
+      },
+
+      /**
+       * Returns the current language code.
+       *
+       * @method getCode
+       * @return {String} Current language code.
+       */
+      getCode: function () {
+        return code;
+      },
+
+      /**
+       * Property gets set to true if a RTL language pack was loaded.
+       *
+       * @property rtl
+       * @type Boolean
+       */
+      rtl: false,
+
+      /**
+       * Adds translations for a specific language code.
+       *
+       * @method add
+       * @param {String} code Language code like sv_SE.
+       * @param {Array} items Name/value array with English en_US to sv_SE.
+       */
+      add: function (code, items) {
+        var langData = data[code];
+
+        if (!langData) {
+          data[code] = langData = {};
+        }
+
+        for (var name in items) {
+          langData[name] = items[name];
+        }
+
+        this.setCode(code);
+      },
+
+      /**
+       * Translates the specified text.
+       *
+       * It has a few formats:
+       * I18n.translate("Text");
+       * I18n.translate(["Text {0}/{1}", 0, 1]);
+       * I18n.translate({raw: "Raw string"});
+       *
+       * @method translate
+       * @param {String/Object/Array} text Text to translate.
+       * @return {String} String that got translated.
+       */
+      translate: function (text) {
+        var langData = data[code] || {};
+
+        /**
+         * number - string
+         * null, undefined and empty string - empty string
+         * array - comma-delimited string
+         * object - in [object Object]
+         * function - in [object Function]
+         *
+         * @param obj
+         * @returns {string}
+         */
+        function toString(obj) {
+          if (Tools.is(obj, 'function')) {
+            return Object.prototype.toString.call(obj);
+          }
+          return !isEmpty(obj) ? '' + obj : '';
+        }
+
+        function isEmpty(text) {
+          return text === '' || text === null || Tools.is(text, 'undefined');
+        }
+
+        function getLangData(text) {
+          // make sure we work on a string and return a string
+          text = toString(text);
+          return Tools.hasOwn(langData, text) ? toString(langData[text]) : text;
+        }
+
+
+        if (isEmpty(text)) {
+          return '';
+        }
+
+        if (Tools.is(text, 'object') && Tools.hasOwn(text, 'raw')) {
+          return toString(text.raw);
+        }
+
+        if (Tools.is(text, 'array')) {
+          var values = text.slice(1);
+          text = getLangData(text[0]).replace(/\{([0-9]+)\}/g, function ($1, $2) {
+            return Tools.hasOwn(values, $2) ? toString(values[$2]) : $1;
+          });
+        }
+
+        return getLangData(text).replace(/{context:\w+}$/, '');
+      },
+
+      data: data
+    };
+  }
+);
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * EditorManager.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -46735,6 +48456,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><span class="cx" style="display: block; padding: 0 10px">   'tinymce.core.EditorManager',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.katamari.api.Arr',
+    'ephox.katamari.api.Type',
</ins><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.AddOnManager',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.dom.DomQuery',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.dom.DOMUtils',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -46749,13 +48472,20 @@
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.Tools',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.URI'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (AddOnManager, DomQuery, DOMUtils, Editor, Env, ErrorReporter, FocusManager, LegacyInput, I18n, Observable, Promise, Tools, URI) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Arr, Type, AddOnManager, DomQuery, DOMUtils, Editor, Env, ErrorReporter, FocusManager, LegacyInput, I18n, Observable, Promise, Tools, URI) {
</ins><span class="cx" style="display: block; padding: 0 10px">     var DOM = DOMUtils.DOM;
</span><span class="cx" style="display: block; padding: 0 10px">     var explode = Tools.explode, each = Tools.each, extend = Tools.extend;
</span><span class="cx" style="display: block; padding: 0 10px">     var instanceCounter = 0, beforeUnloadDelegate, EditorManager, boundGlobalEvents = false;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var legacyEditors = [], editors = [];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var isValidLegacyKey = function (id) {
+      // In theory we could filter out any editor id:s that clash
+      // with array prototype items but that could break existing integrations
+      return id !== 'length';
+    };
+
</ins><span class="cx" style="display: block; padding: 0 10px">     function globalEventDelegate(e) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      each(EditorManager.editors, function (editor) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      each(EditorManager.get(), function (editor) {
</ins><span class="cx" style="display: block; padding: 0 10px">         if (e.type === 'scroll') {
</span><span class="cx" style="display: block; padding: 0 10px">           editor.fire('ScrollWindow', e);
</span><span class="cx" style="display: block; padding: 0 10px">         } else {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -46764,7 +48494,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">       });
</span><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function toggleGlobalEvents(editors, state) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function toggleGlobalEvents(state) {
</ins><span class="cx" style="display: block; padding: 0 10px">       if (state !== boundGlobalEvents) {
</span><span class="cx" style="display: block; padding: 0 10px">         if (state) {
</span><span class="cx" style="display: block; padding: 0 10px">           DomQuery(window).on('resize scroll', globalEventDelegate);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -46776,30 +48506,32 @@
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function removeEditorFromList(editor) {
-      var editors = EditorManager.editors, removedFromList;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function removeEditorFromList(targetEditor) {
+      var oldEditors = editors;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      delete editors[editor.id];
-
-      for (var i = 0; i < editors.length; i++) {
-        if (editors[i] == editor) {
-          editors.splice(i, 1);
-          removedFromList = true;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      delete legacyEditors[targetEditor.id];
+      for (var i = 0; i < legacyEditors.length; i++) {
+        if (legacyEditors[i] === targetEditor) {
+          legacyEditors.splice(i, 1);
</ins><span class="cx" style="display: block; padding: 0 10px">           break;
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      editors = Arr.filter(editors, function (editor) {
+        return targetEditor !== editor;
+      });
+
</ins><span class="cx" style="display: block; padding: 0 10px">       // Select another editor since the active one was removed
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (EditorManager.activeEditor == editor) {
-        EditorManager.activeEditor = editors[0];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (EditorManager.activeEditor === targetEditor) {
+        EditorManager.activeEditor = editors.length > 0 ? editors[0] : null;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // Clear focusedEditor if necessary, so that we don't try to blur the destroyed editor
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (EditorManager.focusedEditor == editor) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (EditorManager.focusedEditor === targetEditor) {
</ins><span class="cx" style="display: block; padding: 0 10px">         EditorManager.focusedEditor = null;
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return removedFromList;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return oldEditors.length !== editors.length;
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     function purgeDestroyedEditor(editor) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -46838,7 +48570,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        * @property minorVersion
</span><span class="cx" style="display: block; padding: 0 10px">        * @type String
</span><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      minorVersion: '6.3',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      minorVersion: '6.7',
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       /**
</span><span class="cx" style="display: block; padding: 0 10px">        * Release date of TinyMCE build.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -46846,18 +48578,15 @@
</span><span class="cx" style="display: block; padding: 0 10px">        * @property releaseDate
</span><span class="cx" style="display: block; padding: 0 10px">        * @type String
</span><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      releaseDate: '2017-05-30',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      releaseDate: '2017-09-18',
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * Collection of editor instances.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * Collection of editor instances. Deprecated use tinymce.get() instead.
</ins><span class="cx" style="display: block; padding: 0 10px">        *
</span><span class="cx" style="display: block; padding: 0 10px">        * @property editors
</span><span class="cx" style="display: block; padding: 0 10px">        * @type Object
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * @example
-       * for (edId in tinymce.editors)
-       *     tinymce.editors[edId].save();
</del><span class="cx" style="display: block; padding: 0 10px">        */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      editors: [],
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      editors: legacyEditors,
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       /**
</span><span class="cx" style="display: block; padding: 0 10px">        * Collection of language pack data.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -46878,6 +48607,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">        */
</span><span class="cx" style="display: block; padding: 0 10px">       activeEditor: null,
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      settings: {},
+
</ins><span class="cx" style="display: block; padding: 0 10px">       setup: function () {
</span><span class="cx" style="display: block; padding: 0 10px">         var self = this, baseURL, documentBaseURL, suffix = "", preInit, src;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -47211,24 +48942,35 @@
</span><span class="cx" style="display: block; padding: 0 10px">        *
</span><span class="cx" style="display: block; padding: 0 10px">        * @method get
</span><span class="cx" style="display: block; padding: 0 10px">        * @param {String/Number} id Editor instance id or index to return.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * @return {tinymce.Editor} Editor instance to return.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * @return {tinymce.Editor/Array} Editor instance to return or array of editor instances.
</ins><span class="cx" style="display: block; padding: 0 10px">        * @example
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-       * // Adds an onclick event to an editor by id (shorter version)
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * // Adds an onclick event to an editor by id
</ins><span class="cx" style="display: block; padding: 0 10px">        * tinymce.get('mytextbox').on('click', function(e) {
</span><span class="cx" style="display: block; padding: 0 10px">        *    ed.windowManager.alert('Hello world!');
</span><span class="cx" style="display: block; padding: 0 10px">        * });
</span><span class="cx" style="display: block; padding: 0 10px">        *
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+       * // Adds an onclick event to an editor by index
+       * tinymce.get(0).on('click', function(e) {
+       *    ed.windowManager.alert('Hello world!');
+       * });
+       *
</ins><span class="cx" style="display: block; padding: 0 10px">        * // Adds an onclick event to an editor by id (longer version)
</span><span class="cx" style="display: block; padding: 0 10px">        * tinymce.EditorManager.get('mytextbox').on('click', function(e) {
</span><span class="cx" style="display: block; padding: 0 10px">        *    ed.windowManager.alert('Hello world!');
</span><span class="cx" style="display: block; padding: 0 10px">        * });
</span><span class="cx" style="display: block; padding: 0 10px">        */
</span><span class="cx" style="display: block; padding: 0 10px">       get: function (id) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (!arguments.length) {
-          return this.editors;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (arguments.length === 0) {
+          return editors.slice(0);
+        } else if (Type.isString(id)) {
+          return Arr.find(editors, function (editor) {
+            return editor.id === id;
+          }).getOr(null);
+        } else if (Type.isNumber(id)) {
+          return editors[id] ? editors[id] : null;
+        } else {
+          return null;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-        return id in this.editors ? this.editors[id] : null;
</del><span class="cx" style="display: block; padding: 0 10px">       },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -47239,14 +48981,29 @@
</span><span class="cx" style="display: block; padding: 0 10px">        * @return {tinymce.Editor} The same instance that got passed in.
</span><span class="cx" style="display: block; padding: 0 10px">        */
</span><span class="cx" style="display: block; padding: 0 10px">       add: function (editor) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var self = this, editors = self.editors;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var self = this, existingEditor;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Add named and index editor instance
-        editors[editor.id] = editor;
-        editors.push(editor);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Prevent existing editors from beeing added again this could happen
+        // if a user calls createEditor then render or add multiple times.
+        existingEditor = legacyEditors[editor.id];
+        if (existingEditor === editor) {
+          return editor;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        toggleGlobalEvents(editors, true);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (self.get(editor.id) === null) {
+          // Add to legacy editors array, this is what breaks in HTML5 where ID:s with numbers are valid
+          // We can't get rid of this strange object and array at the same time since it seems to be used all over the web
+          if (isValidLegacyKey(editor.id)) {
+            legacyEditors[editor.id] = editor;
+          }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          legacyEditors.push(editor);
+
+          editors.push(editor);
+        }
+
+        toggleGlobalEvents(true);
+
</ins><span class="cx" style="display: block; padding: 0 10px">         // Doesn't call setActive method since we don't want
</span><span class="cx" style="display: block; padding: 0 10px">         // to fire a bunch of activate/deactivate calls while initializing
</span><span class="cx" style="display: block; padding: 0 10px">         self.activeEditor = editor;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -47297,7 +49054,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        * @return {tinymce.Editor} The editor that got passed in will be return if it was found otherwise null.
</span><span class="cx" style="display: block; padding: 0 10px">        */
</span><span class="cx" style="display: block; padding: 0 10px">       remove: function (selector) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var self = this, i, editors = self.editors, editor;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var self = this, i, editor;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">         // Remove all editors
</span><span class="cx" style="display: block; padding: 0 10px">         if (!selector) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -47309,11 +49066,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">         // Remove editors by selector
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (typeof selector == "string") {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (Type.isString(selector)) {
</ins><span class="cx" style="display: block; padding: 0 10px">           selector = selector.selector || selector;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">           each(DOM.select(selector), function (elm) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            editor = editors[elm.id];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            editor = self.get(elm.id);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">             if (editor) {
</span><span class="cx" style="display: block; padding: 0 10px">               self.remove(editor);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -47327,7 +49084,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         editor = selector;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">         // Not in the collection
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (!editors[editor.id]) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (Type.isNull(self.get(editor.id))) {
</ins><span class="cx" style="display: block; padding: 0 10px">           return null;
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -47335,13 +49092,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">           self.fire('RemoveEditor', { editor: editor });
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (!editors.length) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (editors.length === 0) {
</ins><span class="cx" style="display: block; padding: 0 10px">           DOM.unbind(window, 'beforeunload', beforeUnloadDelegate);
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">         editor.remove();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        toggleGlobalEvents(editors, editors.length > 0);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        toggleGlobalEvents(editors.length > 0);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">         return editor;
</span><span class="cx" style="display: block; padding: 0 10px">       },
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -47406,7 +49163,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        * tinyMCE.triggerSave();
</span><span class="cx" style="display: block; padding: 0 10px">        */
</span><span class="cx" style="display: block; padding: 0 10px">       triggerSave: function () {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        each(this.editors, function (editor) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        each(editors, function (editor) {
</ins><span class="cx" style="display: block; padding: 0 10px">           editor.save();
</span><span class="cx" style="display: block; padding: 0 10px">         });
</span><span class="cx" style="display: block; padding: 0 10px">       },
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -47464,7 +49221,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * XHR.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Rect.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -47474,939 +49231,211 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * This class enables you to send XMLHTTPRequests cross browser.
- * @class tinymce.util.XHR
- * @mixes tinymce.util.Observable
- * @static
- * @example
- * // Sends a low level Ajax request
- * tinymce.util.XHR.send({
- *    url: 'someurl',
- *    success: function(text) {
- *       console.debug(text);
- *    }
- * });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Contains various tools for rect/position calculation.
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * // Add custom header to XHR request
- * tinymce.util.XHR.on('beforeSend', function(e) {
- *     e.xhr.setRequestHeader('X-Requested-With', 'Something');
- * });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @class tinymce.geom.Rect
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.util.XHR',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.geom.Rect',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    "tinymce.core.util.Observable",
-    "tinymce.core.util.Tools"
</del><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Observable, Tools) {
-    var XHR = {
-      /**
-       * Sends a XMLHTTPRequest.
-       * Consult the Wiki for details on what settings this method takes.
-       *
-       * @method send
-       * @param {Object} settings Object will target URL, callbacks and other info needed to make the request.
-       */
-      send: function (settings) {
-        var xhr, count = 0;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function () {
+    "use strict";
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function ready() {
-          if (!settings.async || xhr.readyState == 4 || count++ > 10000) {
-            if (settings.success && count < 10000 && xhr.status == 200) {
-              settings.success.call(settings.success_scope, '' + xhr.responseText, xhr, settings);
-            } else if (settings.error) {
-              settings.error.call(settings.error_scope, count > 10000 ? 'TIMED_OUT' : 'GENERAL', xhr, settings);
-            }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var min = Math.min, max = Math.max, round = Math.round;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            xhr = null;
-          } else {
-            setTimeout(ready, 10);
-          }
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    /**
+     * Returns the rect positioned based on the relative position name
+     * to the target rect.
+     *
+     * @method relativePosition
+     * @param {Rect} rect Source rect to modify into a new rect.
+     * @param {Rect} targetRect Rect to move relative to based on the rel option.
+     * @param {String} rel Relative position. For example: tr-bl.
+     */
+    function relativePosition(rect, targetRect, rel) {
+      var x, y, w, h, targetW, targetH;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // Default settings
-        settings.scope = settings.scope || this;
-        settings.success_scope = settings.success_scope || settings.scope;
-        settings.error_scope = settings.error_scope || settings.scope;
-        settings.async = settings.async === false ? false : true;
-        settings.data = settings.data || '';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      x = targetRect.x;
+      y = targetRect.y;
+      w = rect.w;
+      h = rect.h;
+      targetW = targetRect.w;
+      targetH = targetRect.h;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        XHR.fire('beforeInitialize', { settings: settings });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      rel = (rel || '').split('');
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        xhr = new XMLHttpRequest();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (rel[0] === 'b') {
+        y += targetH;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (xhr) {
-          if (xhr.overrideMimeType) {
-            xhr.overrideMimeType(settings.content_type);
-          }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (rel[1] === 'r') {
+        x += targetW;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          xhr.open(settings.type || (settings.data ? 'POST' : 'GET'), settings.url, settings.async);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (rel[0] === 'c') {
+        y += round(targetH / 2);
+      }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if (settings.crossDomain) {
-            xhr.withCredentials = true;
-          }
-
-          if (settings.content_type) {
-            xhr.setRequestHeader('Content-Type', settings.content_type);
-          }
-
-          if (settings.requestheaders) {
-            Tools.each(settings.requestheaders, function (header) {
-              xhr.setRequestHeader(header.key, header.value);
-            });
-          }
-
-          xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
-
-          xhr = XHR.fire('beforeSend', { xhr: xhr, settings: settings }).xhr;
-          xhr.send(settings.data);
-
-          // Syncronous request
-          if (!settings.async) {
-            return ready();
-          }
-
-          // Wait for response, onReadyStateChange can not be used since it leaks memory in IE
-          setTimeout(ready, 10);
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (rel[1] === 'c') {
+        x += round(targetW / 2);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    Tools.extend(XHR, Observable);
-
-    return XHR;
-  }
-);
-
-/**
- * JSON.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * JSON parser and serializer class.
- *
- * @class tinymce.util.JSON
- * @static
- * @example
- * // JSON parse a string into an object
- * var obj = tinymce.util.JSON.parse(somestring);
- *
- * // JSON serialize a object into an string
- * var str = tinymce.util.JSON.serialize(obj);
- */
-define(
-  'tinymce.core.util.JSON',
-  [
-  ],
-  function () {
-    function serialize(o, quote) {
-      var i, v, t, name;
-
-      quote = quote || '"';
-
-      if (o === null) {
-        return 'null';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (rel[3] === 'b') {
+        y -= h;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      t = typeof o;
-
-      if (t == 'string') {
-        v = '\bb\tt\nn\ff\rr\""\'\'\\\\';
-
-        /*eslint no-control-regex:0 */
-        return quote + o.replace(/([\u0080-\uFFFF\x00-\x1f\"\'\\])/g, function (a, b) {
-          // Make sure single quotes never get encoded inside double quotes for JSON compatibility
-          if (quote === '"' && a === "'") {
-            return a;
-          }
-
-          i = v.indexOf(b);
-
-          if (i + 1) {
-            return '\\' + v.charAt(i + 1);
-          }
-
-          a = b.charCodeAt().toString(16);
-
-          return '\\u' + '0000'.substring(a.length) + a;
-        }) + quote;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (rel[4] === 'r') {
+        x -= w;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (t == 'object') {
-        if (o.hasOwnProperty && Object.prototype.toString.call(o) === '[object Array]') {
-          for (i = 0, v = '['; i < o.length; i++) {
-            v += (i > 0 ? ',' : '') + serialize(o[i], quote);
-          }
-
-          return v + ']';
-        }
-
-        v = '{';
-
-        for (name in o) {
-          if (o.hasOwnProperty(name)) {
-            v += typeof o[name] != 'function' ? (v.length > 1 ? ',' + quote : quote) + name +
-              quote + ':' + serialize(o[name], quote) : '';
-          }
-        }
-
-        return v + '}';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (rel[3] === 'c') {
+        y -= round(h / 2);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return '' + o;
-    }
-
-    return {
-      /**
-       * Serializes the specified object as a JSON string.
-       *
-       * @method serialize
-       * @param {Object} obj Object to serialize as a JSON string.
-       * @param {String} quote Optional quote string defaults to ".
-       * @return {string} JSON string serialized from input.
-       */
-      serialize: serialize,
-
-      /**
-       * Unserializes/parses the specified JSON string into a object.
-       *
-       * @method parse
-       * @param {string} s JSON String to parse into a JavaScript object.
-       * @return {Object} Object from input JSON string or undefined if it failed.
-       */
-      parse: function (text) {
-        try {
-          // Trick uglify JS
-          return window[String.fromCharCode(101) + 'val']('(' + text + ')');
-        } catch (ex) {
-          // Ignore
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (rel[4] === 'c') {
+        x -= round(w / 2);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      /**#@-*/
-    };
-  }
-);
-
-/**
- * JSONRequest.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * This class enables you to use JSON-RPC to call backend methods.
- *
- * @class tinymce.util.JSONRequest
- * @example
- * var json = new tinymce.util.JSONRequest({
- *     url: 'somebackend.php'
- * });
- *
- * // Send RPC call 1
- * json.send({
- *     method: 'someMethod1',
- *     params: ['a', 'b'],
- *     success: function(result) {
- *         console.dir(result);
- *     }
- * });
- *
- * // Send RPC call 2
- * json.send({
- *     method: 'someMethod2',
- *     params: ['a', 'b'],
- *     success: function(result) {
- *         console.dir(result);
- *     }
- * });
- */
-define(
-  'tinymce.core.util.JSONRequest',
-  [
-    "tinymce.core.util.JSON",
-    "tinymce.core.util.XHR",
-    "tinymce.core.util.Tools"
-  ],
-  function (JSON, XHR, Tools) {
-    var extend = Tools.extend;
-
-    function JSONRequest(settings) {
-      this.settings = extend({}, settings);
-      this.count = 0;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return create(x, y, w, h);
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-     * Simple helper function to send a JSON-RPC request without the need to initialize an object.
-     * Consult the Wiki API documentation for more details on what you can pass to this function.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+     * Tests various positions to get the most suitable one.
</ins><span class="cx" style="display: block; padding: 0 10px">      *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-     * @method sendRPC
-     * @static
-     * @param {Object} o Call object where there are three field id, method and params this object should also contain callbacks etc.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+     * @method findBestRelativePosition
+     * @param {Rect} rect Rect to use as source.
+     * @param {Rect} targetRect Rect to move relative to.
+     * @param {Rect} constrainRect Rect to constrain within.
+     * @param {Array} rels Array of relative positions to test against.
</ins><span class="cx" style="display: block; padding: 0 10px">      */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    JSONRequest.sendRPC = function (o) {
-      return new JSONRequest().send(o);
-    };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function findBestRelativePosition(rect, targetRect, constrainRect, rels) {
+      var pos, i;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    JSONRequest.prototype = {
-      /**
-       * Sends a JSON-RPC call. Consult the Wiki API documentation for more details on what you can pass to this function.
-       *
-       * @method send
-       * @param {Object} args Call object where there are three field id, method and params this object should also contain callbacks etc.
-       */
-      send: function (args) {
-        var ecb = args.error, scb = args.success;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      for (i = 0; i < rels.length; i++) {
+        pos = relativePosition(rect, targetRect, rels[i]);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        args = extend(this.settings, args);
-
-        args.success = function (c, x) {
-          c = JSON.parse(c);
-
-          if (typeof c == 'undefined') {
-            c = {
-              error: 'JSON Parse error.'
-            };
-          }
-
-          if (c.error) {
-            ecb.call(args.error_scope || args.scope, c.error, x);
-          } else {
-            scb.call(args.success_scope || args.scope, c.result);
-          }
-        };
-
-        args.error = function (ty, x) {
-          if (ecb) {
-            ecb.call(args.error_scope || args.scope, ty, x);
-          }
-        };
-
-        args.data = JSON.serialize({
-          id: args.id || 'c' + (this.count++),
-          method: args.method,
-          params: args.params
-        });
-
-        // JSON content type for Ruby on rails. Bug: #1883287
-        args.content_type = 'application/json';
-
-        XHR.send(args);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (pos.x >= constrainRect.x && pos.x + pos.w <= constrainRect.w + constrainRect.x &&
+          pos.y >= constrainRect.y && pos.y + pos.h <= constrainRect.h + constrainRect.y) {
+          return rels[i];
+        }
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    };
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return JSONRequest;
-  }
-);
-/**
- * JSONP.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-define(
-  'tinymce.core.util.JSONP',
-  [
-    "tinymce.core.dom.DOMUtils"
-  ],
-  function (DOMUtils) {
-    return {
-      callbacks: {},
-      count: 0,
-
-      send: function (settings) {
-        var self = this, dom = DOMUtils.DOM, count = settings.count !== undefined ? settings.count : self.count;
-        var id = 'tinymce_jsonp_' + count;
-
-        self.callbacks[count] = function (json) {
-          dom.remove(id);
-          delete self.callbacks[count];
-
-          settings.callback(json);
-        };
-
-        dom.add(dom.doc.body, 'script', {
-          id: id,
-          src: settings.url,
-          type: 'text/javascript'
-        });
-
-        self.count++;
-      }
-    };
-  }
-);
-/**
- * LocalStorage.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * This class will simulate LocalStorage on IE 7 and return the native version on modern browsers.
- * Storage is done using userData on IE 7 and a special serialization format. The format is designed
- * to be as small as possible by making sure that the keys and values doesn't need to be encoded. This
- * makes it possible to store for example HTML data.
- *
- * Storage format for userData:
- * <base 32 key length>,<key string>,<base 32 value length>,<value>,...
- *
- * For example this data key1=value1,key2=value2 would be:
- * 4,key1,6,value1,4,key2,6,value2
- *
- * @class tinymce.util.LocalStorage
- * @static
- * @version 4.0
- * @example
- * tinymce.util.LocalStorage.setItem('key', 'value');
- * var value = tinymce.util.LocalStorage.getItem('key');
- */
-define(
-  'tinymce.core.util.LocalStorage',
-  [
-  ],
-  function () {
-    var LocalStorage, storageElm, items, keys, userDataKey, hasOldIEDataSupport;
-
-    // Check for native support
-    try {
-      if (window.localStorage) {
-        return localStorage;
-      }
-    } catch (ex) {
-      // Ignore
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return null;
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    userDataKey = "tinymce";
-    storageElm = document.documentElement;
-    hasOldIEDataSupport = !!storageElm.addBehavior;
-
-    if (hasOldIEDataSupport) {
-      storageElm.addBehavior('#default#userData');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    /**
+     * Inflates the rect in all directions.
+     *
+     * @method inflate
+     * @param {Rect} rect Rect to expand.
+     * @param {Number} w Relative width to expand by.
+     * @param {Number} h Relative height to expand by.
+     * @return {Rect} New expanded rect.
+     */
+    function inflate(rect, w, h) {
+      return create(rect.x - w, rect.y - h, rect.w + w * 2, rect.h + h * 2);
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-     * Gets the keys names and updates LocalStorage.length property. Since IE7 doesn't have any getters/setters.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+     * Returns the intersection of the specified rectangles.
+     *
+     * @method intersect
+     * @param {Rect} rect The first rectangle to compare.
+     * @param {Rect} cropRect The second rectangle to compare.
+     * @return {Rect} The intersection of the two rectangles or null if they don't intersect.
</ins><span class="cx" style="display: block; padding: 0 10px">      */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function updateKeys() {
-      keys = [];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function intersect(rect, cropRect) {
+      var x1, y1, x2, y2;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      for (var key in items) {
-        keys.push(key);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      x1 = max(rect.x, cropRect.x);
+      y1 = max(rect.y, cropRect.y);
+      x2 = min(rect.x + rect.w, cropRect.x + cropRect.w);
+      y2 = min(rect.y + rect.h, cropRect.y + cropRect.h);
+
+      if (x2 - x1 < 0 || y2 - y1 < 0) {
+        return null;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      LocalStorage.length = keys.length;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return create(x1, y1, x2 - x1, y2 - y1);
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-     * Loads the userData string and parses it into the items structure.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+     * Returns a rect clamped within the specified clamp rect. This forces the
+     * rect to be inside the clamp rect.
+     *
+     * @method clamp
+     * @param {Rect} rect Rectangle to force within clamp rect.
+     * @param {Rect} clampRect Rectable to force within.
+     * @param {Boolean} fixedSize True/false if size should be fixed.
+     * @return {Rect} Clamped rect.
</ins><span class="cx" style="display: block; padding: 0 10px">      */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function load() {
-      var key, data, value, pos = 0;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function clamp(rect, clampRect, fixedSize) {
+      var underflowX1, underflowY1, overflowX2, overflowY2,
+        x1, y1, x2, y2, cx2, cy2;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      items = {};
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      x1 = rect.x;
+      y1 = rect.y;
+      x2 = rect.x + rect.w;
+      y2 = rect.y + rect.h;
+      cx2 = clampRect.x + clampRect.w;
+      cy2 = clampRect.y + clampRect.h;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // localStorage can be disabled on WebKit/Gecko so make a dummy storage
-      if (!hasOldIEDataSupport) {
-        return;
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      underflowX1 = max(0, clampRect.x - x1);
+      underflowY1 = max(0, clampRect.y - y1);
+      overflowX2 = max(0, x2 - cx2);
+      overflowY2 = max(0, y2 - cy2);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      function next(end) {
-        var value, nextPos;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      x1 += underflowX1;
+      y1 += underflowY1;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        nextPos = end !== undefined ? pos + end : data.indexOf(',', pos);
-        if (nextPos === -1 || nextPos > data.length) {
-          return null;
-        }
-
-        value = data.substring(pos, nextPos);
-        pos = nextPos + 1;
-
-        return value;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (fixedSize) {
+        x2 += underflowX1;
+        y2 += underflowY1;
+        x1 -= overflowX2;
+        y1 -= overflowY2;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      storageElm.load(userDataKey);
-      data = storageElm.getAttribute(userDataKey) || '';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      x2 -= overflowX2;
+      y2 -= overflowY2;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      do {
-        var offset = next();
-        if (offset === null) {
-          break;
-        }
-
-        key = next(parseInt(offset, 32) || 0);
-        if (key !== null) {
-          offset = next();
-          if (offset === null) {
-            break;
-          }
-
-          value = next(parseInt(offset, 32) || 0);
-
-          if (key) {
-            items[key] = value;
-          }
-        }
-      } while (key !== null);
-
-      updateKeys();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return create(x1, y1, x2 - x1, y2 - y1);
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-     * Saves the items structure into a the userData format.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+     * Creates a new rectangle object.
+     *
+     * @method create
+     * @param {Number} x Rectangle x location.
+     * @param {Number} y Rectangle y location.
+     * @param {Number} w Rectangle width.
+     * @param {Number} h Rectangle height.
+     * @return {Rect} New rectangle object.
</ins><span class="cx" style="display: block; padding: 0 10px">      */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function save() {
-      var value, data = '';
-
-      // localStorage can be disabled on WebKit/Gecko so make a dummy storage
-      if (!hasOldIEDataSupport) {
-        return;
-      }
-
-      for (var key in items) {
-        value = items[key];
-        data += (data ? ',' : '') + key.length.toString(32) + ',' + key + ',' + value.length.toString(32) + ',' + value;
-      }
-
-      storageElm.setAttribute(userDataKey, data);
-
-      try {
-        storageElm.save(userDataKey);
-      } catch (ex) {
-        // Ignore disk full
-      }
-
-      updateKeys();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function create(x, y, w, h) {
+      return { x: x, y: y, w: w, h: h };
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    LocalStorage = {
-      /**
-       * Length of the number of items in storage.
-       *
-       * @property length
-       * @type Number
-       * @return {Number} Number of items in storage.
-       */
-      //length:0,
-
-      /**
-       * Returns the key name by index.
-       *
-       * @method key
-       * @param {Number} index Index of key to return.
-       * @return {String} Key value or null if it wasn't found.
-       */
-      key: function (index) {
-        return keys[index];
-      },
-
-      /**
-       * Returns the value if the specified key or null if it wasn't found.
-       *
-       * @method getItem
-       * @param {String} key Key of item to retrieve.
-       * @return {String} Value of the specified item or null if it wasn't found.
-       */
-      getItem: function (key) {
-        return key in items ? items[key] : null;
-      },
-
-      /**
-       * Sets the value of the specified item by it's key.
-       *
-       * @method setItem
-       * @param {String} key Key of the item to set.
-       * @param {String} value Value of the item to set.
-       */
-      setItem: function (key, value) {
-        items[key] = "" + value;
-        save();
-      },
-
-      /**
-       * Removes the specified item by key.
-       *
-       * @method removeItem
-       * @param {String} key Key of item to remove.
-       */
-      removeItem: function (key) {
-        delete items[key];
-        save();
-      },
-
-      /**
-       * Removes all items.
-       *
-       * @method clear
-       */
-      clear: function () {
-        items = {};
-        save();
-      }
-    };
-
-    load();
-
-    return LocalStorage;
-  }
-);
-
-/**
- * Compat.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * TinyMCE core class.
- *
- * @static
- * @class tinymce
- * @borrow-members tinymce.EditorManager
- * @borrow-members tinymce.util.Tools
- */
-define(
-  'tinymce.core.api.Compat',
-  [
-    "tinymce.core.dom.DOMUtils",
-    "tinymce.core.dom.EventUtils",
-    "tinymce.core.dom.ScriptLoader",
-    "tinymce.core.AddOnManager",
-    "tinymce.core.util.Tools",
-    "tinymce.core.Env"
-  ],
-  function (DOMUtils, EventUtils, ScriptLoader, AddOnManager, Tools, Env) {
-    var register = function (tinymce) {
-      /**
-       * @property {tinymce.dom.DOMUtils} DOM Global DOM instance.
-       * @property {tinymce.dom.ScriptLoader} ScriptLoader Global ScriptLoader instance.
-       * @property {tinymce.AddOnManager} PluginManager Global PluginManager instance.
-       * @property {tinymce.AddOnManager} ThemeManager Global ThemeManager instance.
-       */
-      tinymce.DOM = DOMUtils.DOM;
-      tinymce.ScriptLoader = ScriptLoader.ScriptLoader;
-      tinymce.PluginManager = AddOnManager.PluginManager;
-      tinymce.ThemeManager = AddOnManager.ThemeManager;
-
-      tinymce.dom = tinymce.dom || {};
-      tinymce.dom.Event = EventUtils.Event;
-
-      Tools.each(
-        'trim isArray is toArray makeMap each map grep inArray extend create walk createNS resolve explode _addCacheSuffix'.split(' '),
-        function (key) {
-          tinymce[key] = Tools[key];
-        }
-      );
-
-      Tools.each('isOpera isWebKit isIE isGecko isMac'.split(' '), function (name) {
-        tinymce[name] = Env[name.substr(2).toLowerCase()];
-      });
-    };
-
-    return {
-      register: register
-    };
-  }
-);
-
-// Describe the different namespaces
-
-/**
- * Root level namespace this contains classes directly related to the TinyMCE editor.
- *
- * @namespace tinymce
- */
-
-/**
- * Contains classes for handling the browsers DOM.
- *
- * @namespace tinymce.dom
- */
-
-/**
- * Contains html parser and serializer logic.
- *
- * @namespace tinymce.html
- */
-
-/**
- * Contains the different UI types such as buttons, listboxes etc.
- *
- * @namespace tinymce.ui
- */
-
-/**
- * Contains various utility classes such as json parser, cookies etc.
- *
- * @namespace tinymce.util
- */
-
-/**
- * Contains modules to handle data binding.
- *
- * @namespace tinymce.data
- */
-
-/**
- * Color.js
- *
- * Released under LGPL License.
- * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * This class lets you parse/serialize colors and convert rgb/hsb.
- *
- * @class tinymce.util.Color
- * @example
- * var white = new tinymce.util.Color({r: 255, g: 255, b: 255});
- * var red = new tinymce.util.Color('#FF0000');
- *
- * console.log(white.toHex(), red.toHsv());
- */
-define(
-  'tinymce.core.util.Color',
-  [
-  ],
-  function () {
-    var min = Math.min, max = Math.max, round = Math.round;
-
</del><span class="cx" style="display: block; padding: 0 10px">     /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-     * Constructs a new color instance.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+     * Creates a new rectangle object form a clientRects object.
</ins><span class="cx" style="display: block; padding: 0 10px">      *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-     * @constructor
-     * @method Color
-     * @param {String} value Optional initial value to parse.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+     * @method fromClientRect
+     * @param {ClientRect} clientRect DOM ClientRect object.
+     * @return {Rect} New rectangle object.
</ins><span class="cx" style="display: block; padding: 0 10px">      */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    function Color(value) {
-      var self = this, r = 0, g = 0, b = 0;
-
-      function rgb2hsv(r, g, b) {
-        var h, s, v, d, minRGB, maxRGB;
-
-        h = 0;
-        s = 0;
-        v = 0;
-        r = r / 255;
-        g = g / 255;
-        b = b / 255;
-
-        minRGB = min(r, min(g, b));
-        maxRGB = max(r, max(g, b));
-
-        if (minRGB == maxRGB) {
-          v = minRGB;
-
-          return {
-            h: 0,
-            s: 0,
-            v: v * 100
-          };
-        }
-
-        /*eslint no-nested-ternary:0 */
-        d = (r == minRGB) ? g - b : ((b == minRGB) ? r - g : b - r);
-        h = (r == minRGB) ? 3 : ((b == minRGB) ? 1 : 5);
-        h = 60 * (h - d / (maxRGB - minRGB));
-        s = (maxRGB - minRGB) / maxRGB;
-        v = maxRGB;
-
-        return {
-          h: round(h),
-          s: round(s * 100),
-          v: round(v * 100)
-        };
-      }
-
-      function hsvToRgb(hue, saturation, brightness) {
-        var side, chroma, x, match;
-
-        hue = (parseInt(hue, 10) || 0) % 360;
-        saturation = parseInt(saturation, 10) / 100;
-        brightness = parseInt(brightness, 10) / 100;
-        saturation = max(0, min(saturation, 1));
-        brightness = max(0, min(brightness, 1));
-
-        if (saturation === 0) {
-          r = g = b = round(255 * brightness);
-          return;
-        }
-
-        side = hue / 60;
-        chroma = brightness * saturation;
-        x = chroma * (1 - Math.abs(side % 2 - 1));
-        match = brightness - chroma;
-
-        switch (Math.floor(side)) {
-          case 0:
-            r = chroma;
-            g = x;
-            b = 0;
-            break;
-
-          case 1:
-            r = x;
-            g = chroma;
-            b = 0;
-            break;
-
-          case 2:
-            r = 0;
-            g = chroma;
-            b = x;
-            break;
-
-          case 3:
-            r = 0;
-            g = x;
-            b = chroma;
-            break;
-
-          case 4:
-            r = x;
-            g = 0;
-            b = chroma;
-            break;
-
-          case 5:
-            r = chroma;
-            g = 0;
-            b = x;
-            break;
-
-          default:
-            r = g = b = 0;
-        }
-
-        r = round(255 * (r + match));
-        g = round(255 * (g + match));
-        b = round(255 * (b + match));
-      }
-
-      /**
-       * Returns the hex string of the current color. For example: #ff00ff
-       *
-       * @method toHex
-       * @return {String} Hex string of current color.
-       */
-      function toHex() {
-        function hex(val) {
-          val = parseInt(val, 10).toString(16);
-
-          return val.length > 1 ? val : '0' + val;
-        }
-
-        return '#' + hex(r) + hex(g) + hex(b);
-      }
-
-      /**
-       * Returns the r, g, b values of the color. Each channel has a range from 0-255.
-       *
-       * @method toRgb
-       * @return {Object} Object with r, g, b fields.
-       */
-      function toRgb() {
-        return {
-          r: r,
-          g: g,
-          b: b
-        };
-      }
-
-      /**
-       * Returns the h, s, v values of the color. Ranges: h=0-360, s=0-100, v=0-100.
-       *
-       * @method toHsv
-       * @return {Object} Object with h, s, v fields.
-       */
-      function toHsv() {
-        return rgb2hsv(r, g, b);
-      }
-
-      /**
-       * Parses the specified value and populates the color instance.
-       *
-       * Supported format examples:
-       *  * rbg(255,0,0)
-       *  * #ff0000
-       *  * #fff
-       *  * {r: 255, g: 0, b: 0}
-       *  * {h: 360, s: 100, v: 100}
-       *
-       * @method parse
-       * @param {Object/String} value Color value to parse.
-       * @return {tinymce.util.Color} Current color instance.
-       */
-      function parse(value) {
-        var matches;
-
-        if (typeof value == 'object') {
-          if ("r" in value) {
-            r = value.r;
-            g = value.g;
-            b = value.b;
-          } else if ("v" in value) {
-            hsvToRgb(value.h, value.s, value.v);
-          }
-        } else {
-          if ((matches = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)[^\)]*\)/gi.exec(value))) {
-            r = parseInt(matches[1], 10);
-            g = parseInt(matches[2], 10);
-            b = parseInt(matches[3], 10);
-          } else if ((matches = /#([0-F]{2})([0-F]{2})([0-F]{2})/gi.exec(value))) {
-            r = parseInt(matches[1], 16);
-            g = parseInt(matches[2], 16);
-            b = parseInt(matches[3], 16);
-          } else if ((matches = /#([0-F])([0-F])([0-F])/gi.exec(value))) {
-            r = parseInt(matches[1] + matches[1], 16);
-            g = parseInt(matches[2] + matches[2], 16);
-            b = parseInt(matches[3] + matches[3], 16);
-          }
-        }
-
-        r = r < 0 ? 0 : (r > 255 ? 255 : r);
-        g = g < 0 ? 0 : (g > 255 ? 255 : g);
-        b = b < 0 ? 0 : (b > 255 ? 255 : b);
-
-        return self;
-      }
-
-      if (value) {
-        parse(value);
-      }
-
-      self.toRgb = toRgb;
-      self.toHsv = toHsv;
-      self.toHex = toHex;
-      self.parse = parse;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    function fromClientRect(clientRect) {
+      return create(clientRect.left, clientRect.top, clientRect.width, clientRect.height);
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return Color;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return {
+      inflate: inflate,
+      relativePosition: relativePosition,
+      findBestRelativePosition: findBestRelativePosition,
+      intersect: intersect,
+      clamp: clamp,
+      create: create,
+      fromClientRect: fromClientRect
+    };
</ins><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -48745,7 +49774,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">         return (
</span><span class="cx" style="display: block; padding: 0 10px">           '<div id="' + id + '" class="' + self.classes + '" tabindex="-1">' +
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          '<button role="presentation" type="button" tabindex="-1">' +
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          '<button id="' + id + '-button" role="presentation" type="button" tabindex="-1">' +
</ins><span class="cx" style="display: block; padding: 0 10px">           (icon ? '<i class="' + icon + '"' + image + '></i>' : '') +
</span><span class="cx" style="display: block; padding: 0 10px">           textHtml +
</span><span class="cx" style="display: block; padding: 0 10px">           '</button>' +
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -49652,7 +50681,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">           self.panel.show();
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        self.panel.moveRel(self.getEl(), settings.popoverAlign || (self.isRtl() ? ['bc-tr', 'bc-tc'] : ['bc-tl', 'bc-tc']));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var rel = self.panel.testMoveRel(self.getEl(), settings.popoverAlign || (self.isRtl() ? ['bc-tc', 'bc-tl', 'bc-tr'] : ['bc-tc', 'bc-tr', 'bc-tl']));
+
+        self.panel.classes.toggle('start', rel === 'bc-tl');
+        self.panel.classes.toggle('end', rel === 'bc-tr');
+
+        self.panel.moveRel(self.getEl(), rel);
</ins><span class="cx" style="display: block; padding: 0 10px">       },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -49833,6 +50867,247 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Color.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This class lets you parse/serialize colors and convert rgb/hsb.
+ *
+ * @class tinymce.util.Color
+ * @example
+ * var white = new tinymce.util.Color({r: 255, g: 255, b: 255});
+ * var red = new tinymce.util.Color('#FF0000');
+ *
+ * console.log(white.toHex(), red.toHsv());
+ */
+define(
+  'tinymce.core.util.Color',
+  [
+  ],
+  function () {
+    var min = Math.min, max = Math.max, round = Math.round;
+
+    /**
+     * Constructs a new color instance.
+     *
+     * @constructor
+     * @method Color
+     * @param {String} value Optional initial value to parse.
+     */
+    function Color(value) {
+      var self = this, r = 0, g = 0, b = 0;
+
+      function rgb2hsv(r, g, b) {
+        var h, s, v, d, minRGB, maxRGB;
+
+        h = 0;
+        s = 0;
+        v = 0;
+        r = r / 255;
+        g = g / 255;
+        b = b / 255;
+
+        minRGB = min(r, min(g, b));
+        maxRGB = max(r, max(g, b));
+
+        if (minRGB == maxRGB) {
+          v = minRGB;
+
+          return {
+            h: 0,
+            s: 0,
+            v: v * 100
+          };
+        }
+
+        /*eslint no-nested-ternary:0 */
+        d = (r == minRGB) ? g - b : ((b == minRGB) ? r - g : b - r);
+        h = (r == minRGB) ? 3 : ((b == minRGB) ? 1 : 5);
+        h = 60 * (h - d / (maxRGB - minRGB));
+        s = (maxRGB - minRGB) / maxRGB;
+        v = maxRGB;
+
+        return {
+          h: round(h),
+          s: round(s * 100),
+          v: round(v * 100)
+        };
+      }
+
+      function hsvToRgb(hue, saturation, brightness) {
+        var side, chroma, x, match;
+
+        hue = (parseInt(hue, 10) || 0) % 360;
+        saturation = parseInt(saturation, 10) / 100;
+        brightness = parseInt(brightness, 10) / 100;
+        saturation = max(0, min(saturation, 1));
+        brightness = max(0, min(brightness, 1));
+
+        if (saturation === 0) {
+          r = g = b = round(255 * brightness);
+          return;
+        }
+
+        side = hue / 60;
+        chroma = brightness * saturation;
+        x = chroma * (1 - Math.abs(side % 2 - 1));
+        match = brightness - chroma;
+
+        switch (Math.floor(side)) {
+          case 0:
+            r = chroma;
+            g = x;
+            b = 0;
+            break;
+
+          case 1:
+            r = x;
+            g = chroma;
+            b = 0;
+            break;
+
+          case 2:
+            r = 0;
+            g = chroma;
+            b = x;
+            break;
+
+          case 3:
+            r = 0;
+            g = x;
+            b = chroma;
+            break;
+
+          case 4:
+            r = x;
+            g = 0;
+            b = chroma;
+            break;
+
+          case 5:
+            r = chroma;
+            g = 0;
+            b = x;
+            break;
+
+          default:
+            r = g = b = 0;
+        }
+
+        r = round(255 * (r + match));
+        g = round(255 * (g + match));
+        b = round(255 * (b + match));
+      }
+
+      /**
+       * Returns the hex string of the current color. For example: #ff00ff
+       *
+       * @method toHex
+       * @return {String} Hex string of current color.
+       */
+      function toHex() {
+        function hex(val) {
+          val = parseInt(val, 10).toString(16);
+
+          return val.length > 1 ? val : '0' + val;
+        }
+
+        return '#' + hex(r) + hex(g) + hex(b);
+      }
+
+      /**
+       * Returns the r, g, b values of the color. Each channel has a range from 0-255.
+       *
+       * @method toRgb
+       * @return {Object} Object with r, g, b fields.
+       */
+      function toRgb() {
+        return {
+          r: r,
+          g: g,
+          b: b
+        };
+      }
+
+      /**
+       * Returns the h, s, v values of the color. Ranges: h=0-360, s=0-100, v=0-100.
+       *
+       * @method toHsv
+       * @return {Object} Object with h, s, v fields.
+       */
+      function toHsv() {
+        return rgb2hsv(r, g, b);
+      }
+
+      /**
+       * Parses the specified value and populates the color instance.
+       *
+       * Supported format examples:
+       *  * rbg(255,0,0)
+       *  * #ff0000
+       *  * #fff
+       *  * {r: 255, g: 0, b: 0}
+       *  * {h: 360, s: 100, v: 100}
+       *
+       * @method parse
+       * @param {Object/String} value Color value to parse.
+       * @return {tinymce.util.Color} Current color instance.
+       */
+      function parse(value) {
+        var matches;
+
+        if (typeof value == 'object') {
+          if ("r" in value) {
+            r = value.r;
+            g = value.g;
+            b = value.b;
+          } else if ("v" in value) {
+            hsvToRgb(value.h, value.s, value.v);
+          }
+        } else {
+          if ((matches = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)[^\)]*\)/gi.exec(value))) {
+            r = parseInt(matches[1], 10);
+            g = parseInt(matches[2], 10);
+            b = parseInt(matches[3], 10);
+          } else if ((matches = /#([0-F]{2})([0-F]{2})([0-F]{2})/gi.exec(value))) {
+            r = parseInt(matches[1], 16);
+            g = parseInt(matches[2], 16);
+            b = parseInt(matches[3], 16);
+          } else if ((matches = /#([0-F])([0-F])([0-F])/gi.exec(value))) {
+            r = parseInt(matches[1] + matches[1], 16);
+            g = parseInt(matches[2] + matches[2], 16);
+            b = parseInt(matches[3] + matches[3], 16);
+          }
+        }
+
+        r = r < 0 ? 0 : (r > 255 ? 255 : r);
+        g = g < 0 ? 0 : (g > 255 ? 255 : g);
+        b = b < 0 ? 0 : (b > 255 ? 255 : b);
+
+        return self;
+      }
+
+      if (value) {
+        parse(value);
+      }
+
+      self.toRgb = toRgb;
+      self.toHsv = toHsv;
+      self.toHex = toHex;
+      self.parse = parse;
+    }
+
+    return Color;
+  }
+);
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * ColorPicker.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -50559,6 +51834,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><span class="cx" style="display: block; padding: 0 10px">   'tinymce.core.content.LinkTargets',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.search.SelectorFilter',
</ins><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.dom.DOMUtils',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.dom.NodeType',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.Arr',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -50566,7 +51843,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.Tools',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.Uuid'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (DOMUtils, NodeType, Arr, Fun, Tools, Uuid) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Element, SelectorFilter, DOMUtils, NodeType, Arr, Fun, Tools, Uuid) {
</ins><span class="cx" style="display: block; padding: 0 10px">     var trim = Tools.trim;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var create = function (type, title, url, level, attach) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -50591,7 +51868,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var select = function (selector, root) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return DOMUtils.DOM.select(selector, root);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return Arr.map(SelectorFilter.descendants(Element.fromDom(root), selector), function (element) {
+        return element.dom();
+      });
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var getElementText = function (elm) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -50690,15 +51969,15 @@
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><span class="cx" style="display: block; padding: 0 10px">   'tinymce.core.ui.FilePicker',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.katamari.api.Arr',
+    'ephox.katamari.api.Fun',
</ins><span class="cx" style="display: block; padding: 0 10px">     'global!window',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.content.LinkTargets',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.EditorManager',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.ui.ComboBox',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.util.Arr',
-    'tinymce.core.util.Fun',
</del><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.util.Tools'
</span><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (window, LinkTargets, EditorManager, ComboBox, Arr, Fun, Tools) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Arr, Fun, window, LinkTargets, EditorManager, ComboBox, Tools) {
</ins><span class="cx" style="display: block; padding: 0 10px">     "use strict";
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var getActiveEditor = function () {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -50735,7 +52014,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var isUniqueUrl = function (url, targets) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var foundTarget = Arr.find(targets, function (target) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var foundTarget = Arr.exists(targets, function (target) {
</ins><span class="cx" style="display: block; padding: 0 10px">         return target.url === url;
</span><span class="cx" style="display: block; padding: 0 10px">       });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -50751,7 +52030,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">       var separator = { title: '-' };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       var fromHistoryMenuItems = function (history) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var uniqueHistory = Arr.filter(history[fileType], function (url) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var historyItems = history.hasOwnProperty(fileType) ? history[fileType] : [ ];
+        var uniqueHistory = Arr.filter(historyItems, function (url) {
</ins><span class="cx" style="display: block; padding: 0 10px">           return isUniqueUrl(url, targets);
</span><span class="cx" style="display: block; padding: 0 10px">         });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -50769,7 +52049,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       var fromMenuItems = function (type) {
</span><span class="cx" style="display: block; padding: 0 10px">         var filteredTargets = Arr.filter(targets, function (target) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          return target.type == type;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          return target.type === type;
</ins><span class="cx" style="display: block; padding: 0 10px">         });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">         return toMenuItems(filteredTargets);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -50792,7 +52072,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">       };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       var join = function (items) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return Arr.reduce(items, function (a, b) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return Arr.foldl(items, function (a, b) {
</ins><span class="cx" style="display: block; padding: 0 10px">           var bothEmpty = a.length === 0 || b.length === 0;
</span><span class="cx" style="display: block; padding: 0 10px">           return bothEmpty ? a.concat(b) : a.concat(separator, b);
</span><span class="cx" style="display: block; padding: 0 10px">         }, []);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -51432,21 +52712,24 @@
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><span class="cx" style="display: block; padding: 0 10px">   'tinymce.core.ui.FormatControls',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    "tinymce.core.ui.Control",
-    "tinymce.core.ui.Widget",
-    "tinymce.core.ui.FloatPanel",
-    "tinymce.core.util.Tools",
-    "tinymce.core.util.Arr",
-    "tinymce.core.dom.DOMUtils",
-    "tinymce.core.EditorManager",
-    "tinymce.core.Env",
-    "tinymce.core.fmt.FontInfo"
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.katamari.api.Arr',
+    'ephox.katamari.api.Fun',
+    'ephox.sugar.api.node.Element',
+    'ephox.sugar.api.search.SelectorFind',
+    'tinymce.core.dom.DOMUtils',
+    'tinymce.core.EditorManager',
+    'tinymce.core.Env',
+    'tinymce.core.fmt.FontInfo',
+    'tinymce.core.ui.Control',
+    'tinymce.core.ui.FloatPanel',
+    'tinymce.core.ui.Widget',
+    'tinymce.core.util.Tools'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (Control, Widget, FloatPanel, Tools, Arr, DOMUtils, EditorManager, Env, FontInfo) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Arr, Fun, Element, SelectorFind, DOMUtils, EditorManager, Env, FontInfo, Control, FloatPanel, Widget, Tools) {
</ins><span class="cx" style="display: block; padding: 0 10px">     var each = Tools.each;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var flatten = function (ar) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return Arr.reduce(ar, function (result, item) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return Arr.foldl(ar, function (result, item) {
</ins><span class="cx" style="display: block; padding: 0 10px">         return result.concat(item);
</span><span class="cx" style="display: block; padding: 0 10px">       }, []);
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -51467,7 +52750,9 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     function setupContainer(editor) {
</span><span class="cx" style="display: block; padding: 0 10px">       if (editor.settings.ui_container) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        Env.container = DOMUtils.DOM.select(editor.settings.ui_container)[0];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        Env.container = SelectorFind.descendant(Element.fromDom(document.body), editor.settings.ui_container).fold(Fun.constant(null), function (elm) {
+          return elm.dom();
+        });
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -51525,7 +52810,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">             return fontFamily ? fontFamily.split(',')[0] : '';
</span><span class="cx" style="display: block; padding: 0 10px">           };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          editor.on('nodeChange', function (e) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          editor.on('init nodeChange', function (e) {
</ins><span class="cx" style="display: block; padding: 0 10px">             var fontFamily, value = null;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">             fontFamily = FontInfo.getFontFamily(editor.getBody(), e.element);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -51555,7 +52840,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         return function () {
</span><span class="cx" style="display: block; padding: 0 10px">           var self = this;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          editor.on('nodeChange', function (e) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          editor.on('init nodeChange', function (e) {
</ins><span class="cx" style="display: block; padding: 0 10px">             var px, pt, value = null;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">             px = FontInfo.getFontSize(editor.getBody(), e.element);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -55028,7 +56313,279 @@
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+defineGlobal("global!RegExp", RegExp);
</ins><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * DropZone.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * Creates a new dropzone.
+ *
+ * @-x-less DropZone.less
+ * @class tinymce.ui.DropZone
+ * @extends tinymce.ui.Widget
+ */
+define(
+  'tinymce.core.ui.DropZone',
+  [
+    'tinymce.core.ui.Widget',
+    'tinymce.core.util.Tools',
+    'tinymce.core.ui.DomUtils',
+    'global!RegExp'
+  ],
+  function (Widget, Tools, DomUtils, RegExp) {
+    return Widget.extend({
+      /**
+       * Constructs a instance with the specified settings.
+       *
+       * @constructor
+       * @param {Object} settings Name/value object with settings.
+       * @setting {Boolean} multiple True if the dropzone is a multiple control.
+       * @setting {Number} maxLength Max length for the dropzone.
+       * @setting {Number} size Size of the dropzone in characters.
+       */
+      init: function (settings) {
+        var self = this;
+
+        settings = Tools.extend({
+          height: 100,
+          text: "Drop an image here",
+          multiple: false,
+          accept: null // by default accept any files
+        }, settings);
+
+        self._super(settings);
+
+        self.classes.add('dropzone');
+
+        if (settings.multiple) {
+          self.classes.add('multiple');
+        }
+      },
+
+      /**
+       * Renders the control as a HTML string.
+       *
+       * @method renderHtml
+       * @return {String} HTML representing the control.
+       */
+      renderHtml: function () {
+        var self = this, attrs, elm;
+        var cfg = self.settings;
+
+        attrs = {
+          id: self._id,
+          hidefocus: '1'
+        };
+
+        elm = DomUtils.create('div', attrs, '<span>' + this.translate(cfg.text) + '</span>');
+
+        if (cfg.height) {
+          DomUtils.css(elm, 'height', cfg.height + 'px');
+        }
+
+        if (cfg.width) {
+          DomUtils.css(elm, 'width', cfg.width + 'px');
+        }
+
+        elm.className = self.classes;
+
+        return elm.outerHTML;
+      },
+
+
+        /**
+       * Called after the control has been rendered.
+       *
+       * @method postRender
+       */
+      postRender: function () {
+        var self = this;
+
+        var toggleDragClass = function (e) {
+          e.preventDefault();
+          self.classes.toggle('dragenter');
+          self.getEl().className = self.classes;
+        };
+
+        var filter = function (files) {
+          var accept = self.settings.accept;
+          if (typeof accept !== 'string') {
+            return files;
+          }
+
+          var re = new RegExp('(' + accept.split(/\s*,\s*/).join('|') + ')$', 'i');
+          return Tools.grep(files, function (file) {
+            return re.test(file.name);
+          });
+        };
+
+        self._super();
+
+        self.$el.on('dragover', function (e) {
+          e.preventDefault();
+        });
+
+        self.$el.on('dragenter', toggleDragClass);
+        self.$el.on('dragleave', toggleDragClass);
+
+        self.$el.on('drop', function (e) {
+          e.preventDefault();
+
+          if (self.state.get('disabled')) {
+            return;
+          }
+
+          var files = filter(e.dataTransfer.files);
+
+          self.value = function () {
+            if (!files.length) {
+              return null;
+            } else if (self.settings.multiple) {
+              return files;
+            } else {
+              return files[0];
+            }
+          };
+
+          if (files.length) {
+            self.fire('change', e);
+          }
+        });
+      },
+
+      remove: function () {
+        this.$el.off();
+        this._super();
+      }
+    });
+  }
+);
+
+/**
+ * BrowseButton.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * Creates a new browse button.
+ *
+ * @-x-less BrowseButton.less
+ * @class tinymce.ui.BrowseButton
+ * @extends tinymce.ui.Widget
+ */
+define(
+  'tinymce.core.ui.BrowseButton',
+  [
+    'tinymce.core.ui.Button',
+    'tinymce.core.util.Tools',
+    'tinymce.core.ui.DomUtils',
+    'tinymce.core.dom.DomQuery',
+    'global!RegExp'
+  ],
+  function (Button, Tools, DomUtils, $, RegExp) {
+    return Button.extend({
+      /**
+       * Constructs a instance with the specified settings.
+       *
+       * @constructor
+       * @param {Object} settings Name/value object with settings.
+       * @setting {Boolean} multiple True if the dropzone is a multiple control.
+       * @setting {Number} maxLength Max length for the dropzone.
+       * @setting {Number} size Size of the dropzone in characters.
+       */
+      init: function (settings) {
+        var self = this;
+
+        settings = Tools.extend({
+          text: "Browse...",
+          multiple: false,
+          accept: null // by default accept any files
+        }, settings);
+
+        self._super(settings);
+
+        self.classes.add('browsebutton');
+
+        if (settings.multiple) {
+          self.classes.add('multiple');
+        }
+      },
+
+       /**
+       * Called after the control has been rendered.
+       *
+       * @method postRender
+       */
+      postRender: function () {
+        var self = this;
+
+        var input = DomUtils.create('input', {
+          type: 'file',
+          id: self._id + '-browse',
+          accept: self.settings.accept
+        });
+
+        self._super();
+
+        $(input).on('change', function (e) {
+          var files = e.target.files;
+
+          self.value = function () {
+            if (!files.length) {
+              return null;
+            } else if (self.settings.multiple) {
+              return files;
+            } else {
+              return files[0];
+            }
+          };
+
+          e.preventDefault();
+
+          if (files.length) {
+            self.fire('change', e);
+          }
+        });
+
+        // ui.Button prevents default on click, so we shouldn't let the click to propagate up to it
+        $(input).on('click', function (e) {
+          e.stopPropagation();
+        });
+
+        $(self.getEl('button')).on('click', function (e) {
+          e.stopPropagation();
+          input.click();
+        });
+
+        // in newer browsers input doesn't have to be attached to dom to trigger browser dialog
+        // however older IE11 (< 11.1358.14393.0) still requires this
+        self.getEl().appendChild(input);
+      },
+
+
+      remove: function () {
+        $(this.getEl('button')).off();
+        $(this.getEl('input')).off();
+
+        this._super();
+      }
+    });
+  }
+);
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * Api.js
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -55099,7 +56656,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.ui.SplitButton',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.ui.StackLayout',
</span><span class="cx" style="display: block; padding: 0 10px">     'tinymce.core.ui.TabPanel',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.ui.TextBox'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'tinymce.core.ui.TextBox',
+    'tinymce.core.ui.DropZone',
+    'tinymce.core.ui.BrowseButton'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><span class="cx" style="display: block; padding: 0 10px">   function (
</span><span class="cx" style="display: block; padding: 0 10px">     Selector, Collection, ReflowQueue, Control, Factory, KeyboardNavigation, Container, DragHelper, Scrollable, Panel, Movable,
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -55107,7 +56666,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">     ButtonGroup, Checkbox, ComboBox, ColorBox, PanelButton, ColorButton, ColorPicker, Path, ElementPath, FormItem, Form,
</span><span class="cx" style="display: block; padding: 0 10px">     FieldSet, FilePicker, FitLayout, FlexLayout, FlowLayout, FormatControls, GridLayout, Iframe, InfoBox, Label, Toolbar,
</span><span class="cx" style="display: block; padding: 0 10px">     MenuBar, MenuButton, MenuItem, Throbber, Menu, ListBox, Radio, ResizeHandle, SelectBox, Slider, Spacer, SplitButton,
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    StackLayout, TabPanel, TextBox
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    StackLayout, TabPanel, TextBox, DropZone, BrowseButton
</ins><span class="cx" style="display: block; padding: 0 10px">   ) {
</span><span class="cx" style="display: block; padding: 0 10px">     "use strict";
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -55192,6 +56751,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">       expose(target, 'ui.StackLayout', StackLayout);
</span><span class="cx" style="display: block; padding: 0 10px">       expose(target, 'ui.TabPanel', TabPanel);
</span><span class="cx" style="display: block; padding: 0 10px">       expose(target, 'ui.TextBox', TextBox);
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      expose(target, 'ui.DropZone', DropZone);
+      expose(target, 'ui.BrowseButton', BrowseButton);
</ins><span class="cx" style="display: block; padding: 0 10px">       expose(target, 'ui.Api', Api);
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -55203,7 +56764,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Tinymce.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * JSON.js
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -55212,143 +56773,272 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Contributing: http://www.tinymce.com/contributing
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/**
+ * JSON parser and serializer class.
+ *
+ * @class tinymce.util.JSON
+ * @static
+ * @example
+ * // JSON parse a string into an object
+ * var obj = tinymce.util.JSON.parse(somestring);
+ *
+ * // JSON serialize a object into an string
+ * var str = tinymce.util.JSON.serialize(obj);
+ */
</ins><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.api.Tinymce',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.util.JSON',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.geom.Rect',
-    'tinymce.core.util.Promise',
-    'tinymce.core.util.Delay',
-    'tinymce.core.Env',
-    'tinymce.core.dom.EventUtils',
-    'tinymce.core.dom.Sizzle',
-    'tinymce.core.util.Tools',
-    'tinymce.core.dom.DomQuery',
-    'tinymce.core.html.Styles',
-    'tinymce.core.dom.TreeWalker',
-    'tinymce.core.html.Entities',
-    'tinymce.core.dom.DOMUtils',
-    'tinymce.core.dom.ScriptLoader',
-    'tinymce.core.AddOnManager',
-    'tinymce.core.dom.RangeUtils',
-    'tinymce.core.html.Node',
-    'tinymce.core.html.Schema',
-    'tinymce.core.html.SaxParser',
-    'tinymce.core.html.DomParser',
-    'tinymce.core.html.Writer',
-    'tinymce.core.html.Serializer',
-    'tinymce.core.dom.Serializer',
-    'tinymce.core.util.VK',
-    'tinymce.core.dom.ControlSelection',
-    'tinymce.core.dom.BookmarkManager',
-    'tinymce.core.dom.Selection',
-    'tinymce.core.Formatter',
-    'tinymce.core.UndoManager',
-    'tinymce.core.EditorCommands',
-    'tinymce.core.util.URI',
-    'tinymce.core.util.Class',
-    'tinymce.core.util.EventDispatcher',
-    'tinymce.core.util.Observable',
-    'tinymce.core.WindowManager',
-    'tinymce.core.NotificationManager',
-    'tinymce.core.EditorObservable',
-    'tinymce.core.Shortcuts',
-    'tinymce.core.Editor',
-    'tinymce.core.util.I18n',
-    'tinymce.core.FocusManager',
-    'tinymce.core.EditorManager',
-    'tinymce.core.util.XHR',
-    'tinymce.core.util.JSON',
-    'tinymce.core.util.JSONRequest',
-    'tinymce.core.util.JSONP',
-    'tinymce.core.util.LocalStorage',
-    'tinymce.core.api.Compat',
-    'tinymce.core.util.Color',
-    'tinymce.core.ui.Api'
</del><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (
-    Rect, Promise, Delay, Env, EventUtils, Sizzle, Tools, DomQuery, Styles, TreeWalker, Entities, DOMUtils, ScriptLoader, AddOnManager,
-    RangeUtils, Node, Schema, SaxParser, DomParser, Writer, HtmlSerializer, DomSerializer, VK, ControlSelection, BookmarkManager, Selection,
-    Formatter, UndoManager, EditorCommands, URI, Class, EventDispatcher, Observable, WindowManager,
-    NotificationManager, EditorObservable, Shortcuts, Editor, I18n, FocusManager, EditorManager,
-    XHR, JSON, JSONRequest, JSONP, LocalStorage, Compat, Color, Api
-  ) {
-    var tinymce = EditorManager;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function () {
+    function serialize(o, quote) {
+      var i, v, t, name;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var expose = function (target, id, ref) {
-      var i, fragments;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      quote = quote || '"';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      fragments = id.split(/[.\/]/);
-      for (i = 0; i < fragments.length - 1; ++i) {
-        if (target[fragments[i]] === undefined) {
-          target[fragments[i]] = {};
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (o === null) {
+        return 'null';
+      }
+
+      t = typeof o;
+
+      if (t == 'string') {
+        v = '\bb\tt\nn\ff\rr\""\'\'\\\\';
+
+        /*eslint no-control-regex:0 */
+        return quote + o.replace(/([\u0080-\uFFFF\x00-\x1f\"\'\\])/g, function (a, b) {
+          // Make sure single quotes never get encoded inside double quotes for JSON compatibility
+          if (quote === '"' && a === "'") {
+            return a;
+          }
+
+          i = v.indexOf(b);
+
+          if (i + 1) {
+            return '\\' + v.charAt(i + 1);
+          }
+
+          a = b.charCodeAt().toString(16);
+
+          return '\\u' + '0000'.substring(a.length) + a;
+        }) + quote;
+      }
+
+      if (t == 'object') {
+        if (o.hasOwnProperty && Object.prototype.toString.call(o) === '[object Array]') {
+          for (i = 0, v = '['; i < o.length; i++) {
+            v += (i > 0 ? ',' : '') + serialize(o[i], quote);
+          }
+
+          return v + ']';
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        target = target[fragments[i]];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        v = '{';
+
+        for (name in o) {
+          if (o.hasOwnProperty(name)) {
+            v += typeof o[name] != 'function' ? (v.length > 1 ? ',' + quote : quote) + name +
+              quote + ':' + serialize(o[name], quote) : '';
+          }
+        }
+
+        return v + '}';
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      target[fragments[fragments.length - 1]] = ref;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return '' + o;
+    }
+
+    return {
+      /**
+       * Serializes the specified object as a JSON string.
+       *
+       * @method serialize
+       * @param {Object} obj Object to serialize as a JSON string.
+       * @param {String} quote Optional quote string defaults to ".
+       * @return {string} JSON string serialized from input.
+       */
+      serialize: serialize,
+
+      /**
+       * Unserializes/parses the specified JSON string into a object.
+       *
+       * @method parse
+       * @param {string} s JSON String to parse into a JavaScript object.
+       * @return {Object} Object from input JSON string or undefined if it failed.
+       */
+      parse: function (text) {
+        try {
+          // Trick uglify JS
+          return window[String.fromCharCode(101) + 'val']('(' + text + ')');
+        } catch (ex) {
+          // Ignore
+        }
+      }
+
+      /**#@-*/
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  }
+);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    expose(tinymce, 'geom.Rect', Rect);
-    expose(tinymce, 'util.Promise', Promise);
-    expose(tinymce, 'util.Delay', Delay);
-    expose(tinymce, 'Env', Env);
-    expose(tinymce, 'dom.EventUtils', EventUtils);
-    expose(tinymce, 'dom.Sizzle', Sizzle);
-    expose(tinymce, 'util.Tools', Tools);
-    expose(tinymce, 'dom.DomQuery', DomQuery);
-    expose(tinymce, 'html.Styles', Styles);
-    expose(tinymce, 'dom.TreeWalker', TreeWalker);
-    expose(tinymce, 'html.Entities', Entities);
-    expose(tinymce, 'dom.DOMUtils', DOMUtils);
-    expose(tinymce, 'dom.ScriptLoader', ScriptLoader);
-    expose(tinymce, 'AddOnManager', AddOnManager);
-    expose(tinymce, 'dom.RangeUtils', RangeUtils);
-    expose(tinymce, 'html.Node', Node);
-    expose(tinymce, 'html.Schema', Schema);
-    expose(tinymce, 'html.SaxParser', SaxParser);
-    expose(tinymce, 'html.DomParser', DomParser);
-    expose(tinymce, 'html.Writer', Writer);
-    expose(tinymce, 'html.Serializer', HtmlSerializer);
-    expose(tinymce, 'dom.Serializer', DomSerializer);
-    expose(tinymce, 'util.VK', VK);
-    expose(tinymce, 'dom.ControlSelection', ControlSelection);
-    expose(tinymce, 'dom.BookmarkManager', BookmarkManager);
-    expose(tinymce, 'dom.Selection', Selection);
-    expose(tinymce, 'Formatter', Formatter);
-    expose(tinymce, 'UndoManager', UndoManager);
-    expose(tinymce, 'EditorCommands', EditorCommands);
-    expose(tinymce, 'util.URI', URI);
-    expose(tinymce, 'util.Class', Class);
-    expose(tinymce, 'util.EventDispatcher', EventDispatcher);
-    expose(tinymce, 'util.Observable', Observable);
-    expose(tinymce, 'WindowManager', WindowManager);
-    expose(tinymce, 'NotificationManager', NotificationManager);
-    expose(tinymce, 'EditorObservable', EditorObservable);
-    expose(tinymce, 'Shortcuts', Shortcuts);
-    expose(tinymce, 'Editor', Editor);
-    expose(tinymce, 'util.I18n', I18n);
-    expose(tinymce, 'FocusManager', FocusManager);
-    expose(tinymce, 'EditorManager', EditorManager);
-    expose(tinymce, 'util.XHR', XHR);
-    expose(tinymce, 'util.JSON', JSON);
-    expose(tinymce, 'util.JSONRequest', JSONRequest);
-    expose(tinymce, 'util.JSONP', JSONP);
-    expose(tinymce, 'util.LocalStorage', LocalStorage);
-    expose(tinymce, 'Compat', Compat);
-    expose(tinymce, 'util.Color', Color);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/**
+ * JSONP.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    Api.appendTo(tinymce);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+define(
+  'tinymce.core.util.JSONP',
+  [
+    "tinymce.core.dom.DOMUtils"
+  ],
+  function (DOMUtils) {
+    return {
+      callbacks: {},
+      count: 0,
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    Compat.register(tinymce);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      send: function (settings) {
+        var self = this, dom = DOMUtils.DOM, count = settings.count !== undefined ? settings.count : self.count;
+        var id = 'tinymce_jsonp_' + count;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return tinymce;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        self.callbacks[count] = function (json) {
+          dom.remove(id);
+          delete self.callbacks[count];
+
+          settings.callback(json);
+        };
+
+        dom.add(dom.doc.body, 'script', {
+          id: id,
+          src: settings.url,
+          type: 'text/javascript'
+        });
+
+        self.count++;
+      }
+    };
</ins><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/**
+ * XHR.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Register.js
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * This class enables you to send XMLHTTPRequests cross browser.
+ * @class tinymce.util.XHR
+ * @mixes tinymce.util.Observable
+ * @static
+ * @example
+ * // Sends a low level Ajax request
+ * tinymce.util.XHR.send({
+ *    url: 'someurl',
+ *    success: function(text) {
+ *       console.debug(text);
+ *    }
+ * });
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * // Add custom header to XHR request
+ * tinymce.util.XHR.on('beforeSend', function(e) {
+ *     e.xhr.setRequestHeader('X-Requested-With', 'Something');
+ * });
+ */
+define(
+  'tinymce.core.util.XHR',
+  [
+    "tinymce.core.util.Observable",
+    "tinymce.core.util.Tools"
+  ],
+  function (Observable, Tools) {
+    var XHR = {
+      /**
+       * Sends a XMLHTTPRequest.
+       * Consult the Wiki for details on what settings this method takes.
+       *
+       * @method send
+       * @param {Object} settings Object will target URL, callbacks and other info needed to make the request.
+       */
+      send: function (settings) {
+        var xhr, count = 0;
+
+        function ready() {
+          if (!settings.async || xhr.readyState == 4 || count++ > 10000) {
+            if (settings.success && count < 10000 && xhr.status == 200) {
+              settings.success.call(settings.success_scope, '' + xhr.responseText, xhr, settings);
+            } else if (settings.error) {
+              settings.error.call(settings.error_scope, count > 10000 ? 'TIMED_OUT' : 'GENERAL', xhr, settings);
+            }
+
+            xhr = null;
+          } else {
+            setTimeout(ready, 10);
+          }
+        }
+
+        // Default settings
+        settings.scope = settings.scope || this;
+        settings.success_scope = settings.success_scope || settings.scope;
+        settings.error_scope = settings.error_scope || settings.scope;
+        settings.async = settings.async === false ? false : true;
+        settings.data = settings.data || '';
+
+        XHR.fire('beforeInitialize', { settings: settings });
+
+        xhr = new XMLHttpRequest();
+
+        if (xhr) {
+          if (xhr.overrideMimeType) {
+            xhr.overrideMimeType(settings.content_type);
+          }
+
+          xhr.open(settings.type || (settings.data ? 'POST' : 'GET'), settings.url, settings.async);
+
+          if (settings.crossDomain) {
+            xhr.withCredentials = true;
+          }
+
+          if (settings.content_type) {
+            xhr.setRequestHeader('Content-Type', settings.content_type);
+          }
+
+          if (settings.requestheaders) {
+            Tools.each(settings.requestheaders, function (header) {
+              xhr.setRequestHeader(header.key, header.value);
+            });
+          }
+
+          xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
+
+          xhr = XHR.fire('beforeSend', { xhr: xhr, settings: settings }).xhr;
+          xhr.send(settings.data);
+
+          // Syncronous request
+          if (!settings.async) {
+            return ready();
+          }
+
+          // Wait for response, onReadyStateChange can not be used since it leaks memory in IE
+          setTimeout(ready, 10);
+        }
+      }
+    };
+
+    Tools.extend(XHR, Observable);
+
+    return XHR;
+  }
+);
+
+/**
+ * JSONRequest.js
+ *
</ins><span class="cx" style="display: block; padding: 0 10px">  * Released under LGPL License.
</span><span class="cx" style="display: block; padding: 0 10px">  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -55357,42 +57047,499 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * This registers tinymce in common module loaders.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * This class enables you to use JSON-RPC to call backend methods.
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @private
- * @class tinymce.Register
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @class tinymce.util.JSONRequest
+ * @example
+ * var json = new tinymce.util.JSONRequest({
+ *     url: 'somebackend.php'
+ * });
+ *
+ * // Send RPC call 1
+ * json.send({
+ *     method: 'someMethod1',
+ *     params: ['a', 'b'],
+ *     success: function(result) {
+ *         console.dir(result);
+ *     }
+ * });
+ *
+ * // Send RPC call 2
+ * json.send({
+ *     method: 'someMethod2',
+ *     params: ['a', 'b'],
+ *     success: function(result) {
+ *         console.dir(result);
+ *     }
+ * });
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  'tinymce.core.Register',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  'tinymce.core.util.JSONRequest',
</ins><span class="cx" style="display: block; padding: 0 10px">   [
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    "tinymce.core.util.JSON",
+    "tinymce.core.util.XHR",
+    "tinymce.core.util.Tools"
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (JSON, XHR, Tools) {
+    var extend = Tools.extend;
+
+    function JSONRequest(settings) {
+      this.settings = extend({}, settings);
+      this.count = 0;
+    }
+
+    /**
+     * Simple helper function to send a JSON-RPC request without the need to initialize an object.
+     * Consult the Wiki API documentation for more details on what you can pass to this function.
+     *
+     * @method sendRPC
+     * @static
+     * @param {Object} o Call object where there are three field id, method and params this object should also contain callbacks etc.
+     */
+    JSONRequest.sendRPC = function (o) {
+      return new JSONRequest().send(o);
+    };
+
+    JSONRequest.prototype = {
+      /**
+       * Sends a JSON-RPC call. Consult the Wiki API documentation for more details on what you can pass to this function.
+       *
+       * @method send
+       * @param {Object} args Call object where there are three field id, method and params this object should also contain callbacks etc.
+       */
+      send: function (args) {
+        var ecb = args.error, scb = args.success;
+
+        args = extend(this.settings, args);
+
+        args.success = function (c, x) {
+          c = JSON.parse(c);
+
+          if (typeof c == 'undefined') {
+            c = {
+              error: 'JSON Parse error.'
+            };
+          }
+
+          if (c.error) {
+            ecb.call(args.error_scope || args.scope, c.error, x);
+          } else {
+            scb.call(args.success_scope || args.scope, c.result);
+          }
+        };
+
+        args.error = function (ty, x) {
+          if (ecb) {
+            ecb.call(args.error_scope || args.scope, ty, x);
+          }
+        };
+
+        args.data = JSON.serialize({
+          id: args.id || 'c' + (this.count++),
+          method: args.method,
+          params: args.params
+        });
+
+        // JSON content type for Ruby on rails. Bug: #1883287
+        args.content_type = 'application/json';
+
+        XHR.send(args);
+      }
+    };
+
+    return JSONRequest;
+  }
+);
+/**
+ * LocalStorage.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This class will simulate LocalStorage on IE 7 and return the native version on modern browsers.
+ * Storage is done using userData on IE 7 and a special serialization format. The format is designed
+ * to be as small as possible by making sure that the keys and values doesn't need to be encoded. This
+ * makes it possible to store for example HTML data.
+ *
+ * Storage format for userData:
+ * <base 32 key length>,<key string>,<base 32 value length>,<value>,...
+ *
+ * For example this data key1=value1,key2=value2 would be:
+ * 4,key1,6,value1,4,key2,6,value2
+ *
+ * @class tinymce.util.LocalStorage
+ * @static
+ * @version 4.0
+ * @example
+ * tinymce.util.LocalStorage.setItem('key', 'value');
+ * var value = tinymce.util.LocalStorage.getItem('key');
+ */
+define(
+  'tinymce.core.util.LocalStorage',
+  [
+  ],
</ins><span class="cx" style="display: block; padding: 0 10px">   function () {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    /*eslint consistent-this: 0 */
-    var context = this || window;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var LocalStorage, storageElm, items, keys, userDataKey, hasOldIEDataSupport;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var exposeToModuleLoaders = function (tinymce) {
-      if (typeof context.define === "function") {
-        // Bolt
-        if (!context.define.amd) {
-          context.define("ephox/tinymce", [], function () {
-            return tinymce;
-          });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Check for native support
+    try {
+      if (window.localStorage) {
+        return localStorage;
+      }
+    } catch (ex) {
+      // Ignore
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          context.define("tinymce.core.EditorManager", [], function () {
-            return tinymce;
-          });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    userDataKey = "tinymce";
+    storageElm = document.documentElement;
+    hasOldIEDataSupport = !!storageElm.addBehavior;
+
+    if (hasOldIEDataSupport) {
+      storageElm.addBehavior('#default#userData');
+    }
+
+    /**
+     * Gets the keys names and updates LocalStorage.length property. Since IE7 doesn't have any getters/setters.
+     */
+    function updateKeys() {
+      keys = [];
+
+      for (var key in items) {
+        keys.push(key);
+      }
+
+      LocalStorage.length = keys.length;
+    }
+
+    /**
+     * Loads the userData string and parses it into the items structure.
+     */
+    function load() {
+      var key, data, value, pos = 0;
+
+      items = {};
+
+      // localStorage can be disabled on WebKit/Gecko so make a dummy storage
+      if (!hasOldIEDataSupport) {
+        return;
+      }
+
+      function next(end) {
+        var value, nextPos;
+
+        nextPos = end !== undefined ? pos + end : data.indexOf(',', pos);
+        if (nextPos === -1 || nextPos > data.length) {
+          return null;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+        value = data.substring(pos, nextPos);
+        pos = nextPos + 1;
+
+        return value;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (typeof module === 'object') {
-        /* global module */
-        module.exports = tinymce;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      storageElm.load(userDataKey);
+      data = storageElm.getAttribute(userDataKey) || '';
+
+      do {
+        var offset = next();
+        if (offset === null) {
+          break;
+        }
+
+        key = next(parseInt(offset, 32) || 0);
+        if (key !== null) {
+          offset = next();
+          if (offset === null) {
+            break;
+          }
+
+          value = next(parseInt(offset, 32) || 0);
+
+          if (key) {
+            items[key] = value;
+          }
+        }
+      } while (key !== null);
+
+      updateKeys();
+    }
+
+    /**
+     * Saves the items structure into a the userData format.
+     */
+    function save() {
+      var value, data = '';
+
+      // localStorage can be disabled on WebKit/Gecko so make a dummy storage
+      if (!hasOldIEDataSupport) {
+        return;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+      for (var key in items) {
+        value = items[key];
+        data += (data ? ',' : '') + key.length.toString(32) + ',' + key + ',' + value.length.toString(32) + ',' + value;
+      }
+
+      storageElm.setAttribute(userDataKey, data);
+
+      try {
+        storageElm.save(userDataKey);
+      } catch (ex) {
+        // Ignore disk full
+      }
+
+      updateKeys();
+    }
+
+    LocalStorage = {
+      /**
+       * Length of the number of items in storage.
+       *
+       * @property length
+       * @type Number
+       * @return {Number} Number of items in storage.
+       */
+      //length:0,
+
+      /**
+       * Returns the key name by index.
+       *
+       * @method key
+       * @param {Number} index Index of key to return.
+       * @return {String} Key value or null if it wasn't found.
+       */
+      key: function (index) {
+        return keys[index];
+      },
+
+      /**
+       * Returns the value if the specified key or null if it wasn't found.
+       *
+       * @method getItem
+       * @param {String} key Key of item to retrieve.
+       * @return {String} Value of the specified item or null if it wasn't found.
+       */
+      getItem: function (key) {
+        return key in items ? items[key] : null;
+      },
+
+      /**
+       * Sets the value of the specified item by it's key.
+       *
+       * @method setItem
+       * @param {String} key Key of the item to set.
+       * @param {String} value Value of the item to set.
+       */
+      setItem: function (key, value) {
+        items[key] = "" + value;
+        save();
+      },
+
+      /**
+       * Removes the specified item by key.
+       *
+       * @method removeItem
+       * @param {String} key Key of item to remove.
+       */
+      removeItem: function (key) {
+        delete items[key];
+        save();
+      },
+
+      /**
+       * Removes all items.
+       *
+       * @method clear
+       */
+      clear: function () {
+        items = {};
+        save();
+      }
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return {
-      exposeToModuleLoaders: exposeToModuleLoaders
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    load();
+
+    return LocalStorage;
+  }
+);
+
+/**
+ * Tinymce.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+define(
+  'tinymce.core.api.Tinymce',
+  [
+    'tinymce.core.AddOnManager',
+    'tinymce.core.api.Formatter',
+    'tinymce.core.api.NotificationManager',
+    'tinymce.core.api.WindowManager',
+    'tinymce.core.dom.BookmarkManager',
+    'tinymce.core.dom.ControlSelection',
+    'tinymce.core.dom.DomQuery',
+    'tinymce.core.dom.DOMUtils',
+    'tinymce.core.dom.EventUtils',
+    'tinymce.core.dom.RangeUtils',
+    'tinymce.core.dom.ScriptLoader',
+    'tinymce.core.dom.Selection',
+    'tinymce.core.dom.Serializer',
+    'tinymce.core.dom.Sizzle',
+    'tinymce.core.dom.TreeWalker',
+    'tinymce.core.Editor',
+    'tinymce.core.EditorCommands',
+    'tinymce.core.EditorManager',
+    'tinymce.core.EditorObservable',
+    'tinymce.core.Env',
+    'tinymce.core.FocusManager',
+    'tinymce.core.geom.Rect',
+    'tinymce.core.html.DomParser',
+    'tinymce.core.html.Entities',
+    'tinymce.core.html.Node',
+    'tinymce.core.html.SaxParser',
+    'tinymce.core.html.Schema',
+    'tinymce.core.html.Serializer',
+    'tinymce.core.html.Styles',
+    'tinymce.core.html.Writer',
+    'tinymce.core.Shortcuts',
+    'tinymce.core.ui.Api',
+    'tinymce.core.UndoManager',
+    'tinymce.core.util.Class',
+    'tinymce.core.util.Color',
+    'tinymce.core.util.Delay',
+    'tinymce.core.util.EventDispatcher',
+    'tinymce.core.util.I18n',
+    'tinymce.core.util.JSON',
+    'tinymce.core.util.JSONP',
+    'tinymce.core.util.JSONRequest',
+    'tinymce.core.util.LocalStorage',
+    'tinymce.core.util.Observable',
+    'tinymce.core.util.Promise',
+    'tinymce.core.util.Tools',
+    'tinymce.core.util.URI',
+    'tinymce.core.util.VK',
+    'tinymce.core.util.XHR'
+  ],
+  function (
+    AddOnManager, Formatter, NotificationManager, WindowManager, BookmarkManager, ControlSelection, DomQuery, DOMUtils, EventUtils, RangeUtils, ScriptLoader,
+    Selection, DomSerializer, Sizzle, TreeWalker, Editor, EditorCommands, EditorManager, EditorObservable, Env, FocusManager, Rect, DomParser, Entities, Node,
+    SaxParser, Schema, HtmlSerializer, Styles, Writer, Shortcuts, UiApi, UndoManager, Class, Color, Delay, EventDispatcher, I18n, JSON, JSONP, JSONRequest, LocalStorage,
+    Observable, Promise, Tools, URI, VK, XHR
+  ) {
+    var tinymce = EditorManager;
+
+    /**
+     * @include ../../../../../../tools/docs/tinymce.js
+     */
+    var publicApi = {
+      geom: {
+        Rect: Rect
+      },
+
+      util: {
+        Promise: Promise,
+        Delay: Delay,
+        Tools: Tools,
+        VK: VK,
+        URI: URI,
+        Class: Class,
+        EventDispatcher: EventDispatcher,
+        Observable: Observable,
+        I18n: I18n,
+        XHR: XHR,
+        JSON: JSON,
+        JSONRequest: JSONRequest,
+        JSONP: JSONP,
+        LocalStorage: LocalStorage,
+        Color: Color
+      },
+
+      dom: {
+        EventUtils: EventUtils,
+        Sizzle: Sizzle,
+        DomQuery: DomQuery,
+        TreeWalker: TreeWalker,
+        DOMUtils: DOMUtils,
+        ScriptLoader: ScriptLoader,
+        RangeUtils: RangeUtils,
+        Serializer: DomSerializer,
+        ControlSelection: ControlSelection,
+        BookmarkManager: BookmarkManager,
+        Selection: Selection,
+        Event: EventUtils.Event
+      },
+
+      html: {
+        Styles: Styles,
+        Entities: Entities,
+        Node: Node,
+        Schema: Schema,
+        SaxParser: SaxParser,
+        DomParser: DomParser,
+        Writer: Writer,
+        Serializer: HtmlSerializer
+      },
+
+      Env: Env,
+      AddOnManager: AddOnManager,
+      Formatter: Formatter,
+      UndoManager: UndoManager,
+      EditorCommands: EditorCommands,
+      WindowManager: WindowManager,
+      NotificationManager: NotificationManager,
+      EditorObservable: EditorObservable,
+      Shortcuts: Shortcuts,
+      Editor: Editor,
+      FocusManager: FocusManager,
+      EditorManager: EditorManager,
+
+      // Global instances
+      DOM: DOMUtils.DOM,
+      ScriptLoader: ScriptLoader.ScriptLoader,
+      PluginManager: AddOnManager.PluginManager,
+      ThemeManager: AddOnManager.ThemeManager,
+
+      // Global utility functions
+      trim: Tools.trim,
+      isArray: Tools.isArray,
+      is: Tools.is,
+      toArray: Tools.toArray,
+      makeMap: Tools.makeMap,
+      each: Tools.each,
+      map: Tools.map,
+      grep: Tools.grep,
+      inArray: Tools.inArray,
+      extend: Tools.extend,
+      create: Tools.create,
+      walk: Tools.walk,
+      createNS: Tools.createNS,
+      resolve: Tools.resolve,
+      explode: Tools.explode,
+      _addCacheSuffix: Tools._addCacheSuffix,
+
+      // Legacy browser detection
+      isOpera: Env.opera,
+      isWebKit: Env.webkit,
+      isIE: Env.ie,
+      isGecko: Env.gecko,
+      isMac: Env.mac
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+    tinymce = Tools.extend(tinymce, publicApi);
+    UiApi.appendTo(tinymce);
+
+    return tinymce;
</ins><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -55409,16 +57556,37 @@
</span><span class="cx" style="display: block; padding: 0 10px"> define(
</span><span class="cx" style="display: block; padding: 0 10px">   'tinymce.core.api.Main',
</span><span class="cx" style="display: block; padding: 0 10px">   [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    'tinymce.core.api.Tinymce',
-    'tinymce.core.Register'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    'ephox.katamari.api.Fun',
+    'tinymce.core.api.Tinymce'
</ins><span class="cx" style="display: block; padding: 0 10px">   ],
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  function (tinymce, Register) {
-    return function () {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  function (Fun, Tinymce) {
+    /*eslint consistent-this: 0 */
+    var context = this || window;
+
+    var exportToModuleLoaders = function (tinymce) {
+      // Bolt
+      if (typeof context.define === "function" && !context.define.amd) {
+        context.define("ephox/tinymce", [], Fun.constant(tinymce));
+        context.define("tinymce.core.EditorManager", [], Fun.constant(tinymce));
+      }
+
+      // CommonJS
+      if (typeof module === 'object') {
+        /* global module */
+        module.exports = tinymce;
+      }
+    };
+
+    var exportToWindowGlobal = function (tinymce) {
</ins><span class="cx" style="display: block; padding: 0 10px">       window.tinymce = tinymce;
</span><span class="cx" style="display: block; padding: 0 10px">       window.tinyMCE = tinymce;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      Register.exposeToModuleLoaders(tinymce);
-      return tinymce;
</del><span class="cx" style="display: block; padding: 0 10px">     };
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+    return function () {
+      exportToWindowGlobal(Tinymce);
+      exportToModuleLoaders(Tinymce);
+      return Tinymce;
+    };
</ins><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunksrcwpincludesjstinymcetinymceminjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/tinymce/tinymce.min.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/tinymce/tinymce.min.js   2017-09-26 20:32:46 UTC (rev 41603)
+++ trunk/src/wp-includes/js/tinymce/tinymce.min.js     2017-09-26 21:14:28 UTC (rev 41604)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,16 +1,17 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-// 4.6.3 (2017-05-30)
-!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};g("3",[],function(){"use strict";function a(a,b,c){var d,e,g,h,i,k;return d=b.x,e=b.y,g=a.w,h=a.h,i=b.w,k=b.h,c=(c||"").split(&quo
 t;"),"b"===c[0]&&(e+=k),"r"===c[1]&&(d+=i),"c"===c[0]&&(e+=j(k/2)),"c"===c[1]&&(d+=j(i/2)),"b"===c[3]&&(e-=h),"r"===c[4]&&(d-=g),"c"===c[3]&&(e-=j(h/2)),"c"===c[4]&&(d-=j(g/2)),f(d,e,g,h)}function b(b,c,d,e){var f,g;for(g=0;g<e.length;g++)if(f=a(b,c,e[g]),f.x>=d.x&&f.x+f.w<=d.w+d.x&&f.y>=d.y&&f.y+f.h<=d.h+d.y)return e[g];return null}function c(a,b,c){return f(a.x-b,a.y-c,a.w+2*b,a.h+2*c)}function d(a,b){var c,d,e,g;return c=i(a.x,b.x),d=i(a.y,b.y),e=h(a.x+a.w,b.x+b.w),g=h(a.y+a.h,b.y+b.h),e-c<0||g-d<0?null:f(c,d,e-c,g-d)}function e(a,b,c){var d,e,g,h,j,k,l,m,n,o;return j=a.x,k=a.y,l=a.x+a.w,m=a.y+a.h,n=b.x+b.w,o=b.y+b.h,d=i(0,b.x-j),e=i(0,b.y-k),g=i(0,l-n),h=i(0,m-o),j+=d,k+=e,c&&(l+=d,m+=e,j-=g,k-=h),l-=g,m-=h,f(j,k,l-j,m-k)}function f(a,b,c,d){return{x:a,y:b,w:c,h:d}}function g(a){r
 eturn f(a.left,a.top,a.width,a.height)}var h=Math.min,i=Math.max,j=Math.round;return{inflate:c,relativePosition:a,findBestRelativePosition:b,intersect:d,clamp:e,create:f,fromClientRect:g}}),g("4",[],function(){function a(a,b){return function(){a.apply(b,arguments)}}function b(b){if("object"!=typeof this)throw new TypeError("Promises must be constructed via new");if("function"!=typeof b)throw new TypeError("not a function");this._state=null,this._value=null,this._deferreds=[],h(b,a(d,this),a(e,this))}function c(a){var b=this;return null===this._state?void this._deferreds.push(a):void i(function(){var c=b._state?a.onFulfilled:a.onRejected;if(null===c)return void(b._state?a.resolve:a.reject)(b._value);var d;try{d=c(b._value)}catch(b){return void a.reject(b)}a.resolve(d)})}function d(b){try{if(b===this)throw new TypeError("A promise cannot be resolved with itself.");if(b&&("object"==typeof b||"function&qu
 ot;==typeof b)){var c=b.then;if("function"==typeof c)return void h(a(c,b),a(d,this),a(e,this))}this._state=!0,this._value=b,f.call(this)}catch(a){e.call(this,a)}}function e(a){this._state=!1,this._value=a,f.call(this)}function f(){for(var a=0,b=this._deferreds.length;a<b;a++)c.call(this,this._deferreds[a]);this._deferreds=null}function g(a,b,c,d){this.onFulfilled="function"==typeof a?a:null,this.onRejected="function"==typeof b?b:null,this.resolve=c,this.reject=d}function h(a,b,c){var d=!1;try{a(function(a){d||(d=!0,b(a))},function(a){d||(d=!0,c(a))})}catch(a){if(d)return;d=!0,c(a)}}if(window.Promise)return window.Promise;var i=b.immediateFn||"function"==typeof setImmediate&&setImmediate||function(a){setTimeout(a,1)},j=Array.isArray||function(a){return"[object Array]"===Object.prototype.toString.call(a)};return b.prototype["catch"]=function(a){return this.then(null,a)},b.prototype.then=function(a,d){var e=this;ret
 urn new b(function(b,f){c.call(e,new g(a,d,b,f))})},b.all=function(){var a=Array.prototype.slice.call(1===arguments.length&&j(arguments[0])?arguments[0]:arguments);return new b(function(b,c){function d(f,g){try{if(g&&("object"==typeof g||"function"==typeof g)){var h=g.then;if("function"==typeof h)return void h.call(g,function(a){d(f,a)},c)}a[f]=g,0===--e&&b(a)}catch(a){c(a)}}if(0===a.length)return b([]);for(var e=a.length,f=0;f<a.length;f++)d(f,a[f])})},b.resolve=function(a){return a&&"object"==typeof a&&a.constructor===b?a:new b(function(b){b(a)})},b.reject=function(a){return new b(function(b,c){c(a)})},b.race=function(a){return new b(function(b,c){for(var d=0,e=a.length;d<e;d++)a[d].then(b,c)})},b}),g("5",["4"],function(a){function b(a,b){function c(a){window.setTimeout(a,0)}var d,e=window.requestAnimationFrame,f=["ms","moz","webkit"];for(d=0;d&lt
 ;f.length&&!e;d++)e=window[f[d]+"RequestAnimationFrame"];e||(e=c),e(a,b)}function c(a,b){return"number"!=typeof b&&(b=0),setTimeout(a,b)}function d(a,b){return"number"!=typeof b&&(b=1),setInterval(a,b)}function e(a){return clearTimeout(a)}function f(a){return clearInterval(a)}function g(a,b){var d,e;return e=function(){var e=arguments;clearTimeout(d),d=c(function(){a.apply(this,e)},b)},e.stop=function(){clearTimeout(d)},e}var h;return{requestAnimationFrame:function(c,d){return h?void h.then(c):void(h=new a(function(a){d||(d=document.body),b(a,d)}).then(c))},setTimeout:c,setInterval:d,setEditorTimeout:function(a,b,d){return c(function(){a.removed||b()},d)},setEditorInterval:function(a,b,c){var e;return e=d(function(){a.removed?clearInterval(e):b()},c)},debounce:g,throttle:g,clearInterval:f,clearTimeout:e}}),g("6",[],function(){function a(a){return"matchMedia"in window&&matchMedia(a).matches}var b,c,d,e,
 f,g,h,i,j,k,l,m,n,o=navigator,p=o.userAgent;b=window.opera&&window.opera.buildNumber,j=/Android/.test(p),c=/WebKit/.test(p),d=!c&&!b&&/MSIE/gi.test(p)&&/Explorer/gi.test(o.appName),d=d&&/MSIE (\w+)\./.exec(p)[1],e=p.indexOf("Trident/")!=-1&&(p.indexOf("rv:")!=-1||o.appName.indexOf("Netscape")!=-1)&&11,f=p.indexOf("Edge/")!=-1&&!d&&!e&&12,d=d||e||f,g=!c&&!e&&/Gecko/.test(p),h=p.indexOf("Mac")!=-1,i=/(iPad|iPhone)/.test(p),k="FormData"in window&&"FileReader"in window&&"URL"in window&&!!URL.createObjectURL,l=a("only screen and (max-device-width: 480px)")&&(j||i),m=a("only screen and (min-width: 800px)")&&(j||i),n=p.indexOf("Windows Phone")!=-1,f&&(c=!1);var q=!i||k||p.match(/AppleWebKit\/(\d*)/)[1]>=534;return{opera:b,webkit:c,ie:d,g
 ecko:g,mac:h,iOS:i,android:j,contentEditable:q,transparentSrc:"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",caretAfter:8!=d,range:window.getSelection&&"Range"in window,documentMode:d&&!f?document.documentMode||7:10,fileApi:k,ceFalse:d===!1||d>8,canHaveCSP:d===!1||d>11,desktop:!l&&!m,windowsPhone:n}}),g("7",["5","6"],function(a,b){"use strict";function c(a,b,c,d){a.addEventListener?a.addEventListener(b,c,d||!1):a.attachEvent&&a.attachEvent("on"+b,c)}function d(a,b,c,d){a.removeEventListener?a.removeEventListener(b,c,d||!1):a.detachEvent&&a.detachEvent("on"+b,c)}function e(a,b){var c,d=b;return c=a.path,c&&c.length>0&&(d=c[0]),a.deepPath&&(c=a.deepPath(),c&&c.length>0&&(d=c[0])),d}function f(a,c){var d,f,g=c||{};for(d in a)k[d]||(g[d]=a[d]);if(g.target||(g.target=g.srcElement||docu
 ment),b.experimentalShadowDom&&(g.target=e(a,g.target)),a&&j.test(a.type)&&a.pageX===f&&a.clientX!==f){var h=g.target.ownerDocument||document,i=h.documentElement,o=h.body;g.pageX=a.clientX+(i&&i.scrollLeft||o&&o.scrollLeft||0)-(i&&i.clientLeft||o&&o.clientLeft||0),g.pageY=a.clientY+(i&&i.scrollTop||o&&o.scrollTop||0)-(i&&i.clientTop||o&&o.clientTop||0)}return g.preventDefault=function(){g.isDefaultPrevented=n,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},g.stopPropagation=function(){g.isPropagationStopped=n,a&&(a.stopPropagation?a.stopPropagation():a.cancelBubble=!0)},g.stopImmediatePropagation=function(){g.isImmediatePropagationStopped=n,g.stopPropagation()},l(g)===!1&&(g.isDefaultPrevented=m,g.isPropagationStopped=m,g.isImmediatePropagationStopped=m),"undefined"==typeof g.metaKey&&(g.metaKey=!1),g}function g(e,f,g){function h(){retu
 rn"complete"===l.readyState||"interactive"===l.readyState&&l.body}function i(){g.domLoaded||(g.domLoaded=!0,f(m))}function j(){h()&&(d(l,"readystatechange",j),i())}function k(){try{l.documentElement.doScroll("left")}catch(b){return void a.setTimeout(k)}i()}var l=e.document,m={type:"ready"};return g.domLoaded?void f(m):(!l.addEventListener||b.ie&&b.ie<11?(c(l,"readystatechange",j),l.documentElement.doScroll&&e.self===e.top&&k()):h()?i():c(e,"DOMContentLoaded",i),void c(e,"load",i))}function h(){function a(a,b){var c,d,e,f,g=m[b];if(c=g&&g[a.type])for(d=0,e=c.length;d<e;d++)if(f=c[d],f&&f.func.call(f.scope,a)===!1&&a.preventDefault(),a.isImmediatePropagationStopped())return}var b,e,h,j,k,l=this,m={};e=i+(+new Date).toString(32),j="onmouseenter"in document.documentElement,h="onfocusin"in document.documentElement,k={mou
 seenter:"mouseover",mouseleave:"mouseout"},b=1,l.domLoaded=!1,l.events=m,l.bind=function(d,i,n,o){function p(b){a(f(b||x.event),q)}var q,r,s,t,u,v,w,x=window;if(d&&3!==d.nodeType&&8!==d.nodeType){for(d[e]?q=d[e]:(q=b++,d[e]=q,m[q]={}),o=o||d,i=i.split(" "),s=i.length;s--;)t=i[s],v=p,u=w=!1,"DOMContentLoaded"===t&&(t="ready"),l.domLoaded&&"ready"===t&&"complete"==d.readyState?n.call(o,f({type:t})):(j||(u=k[t],u&&(v=function(b){var c,d;if(c=b.currentTarget,d=b.relatedTarget,d&&c.contains)d=c.contains(d);else for(;d&&d!==c;)d=d.parentNode;d||(b=f(b||x.event),b.type="mouseout"===b.type?"mouseleave":"mouseenter",b.target=c,a(b,q))})),h||"focusin"!==t&&"focusout"!==t||(w=!0,u="focusin"===t?"focus":"blur",v=function(b){b=f(b||x.event),b.type="focus"===b.type?&qu
 ot;focusin":"focusout",a(b,q)}),r=m[q][t],r?"ready"===t&&l.domLoaded?n({type:t}):r.push({func:n,scope:o}):(m[q][t]=r=[{func:n,scope:o}],r.fakeName=u,r.capture=w,r.nativeHandler=v,"ready"===t?g(d,v,l):c(d,u||t,v,w)));return d=r=0,n}},l.unbind=function(a,b,c){var f,g,h,i,j,k;if(!a||3===a.nodeType||8===a.nodeType)return l;if(f=a[e]){if(k=m[f],b){for(b=b.split(" "),h=b.length;h--;)if(j=b[h],g=k[j]){if(c)for(i=g.length;i--;)if(g[i].func===c){var n=g.nativeHandler,o=g.fakeName,p=g.capture;g=g.slice(0,i).concat(g.slice(i+1)),g.nativeHandler=n,g.fakeName=o,g.capture=p,k[j]=g}c&&0!==g.length||(delete k[j],d(a,g.fakeName||j,g.nativeHandler,g.capture))}}else{for(j in k)g=k[j],d(a,g.fakeName||j,g.nativeHandler,g.capture);k={}}for(j in k)return l;delete m[f];try{delete a[e]}catch(b){a[e]=null}}return l},l.fire=function(b,c,d){var g;if(!b||3===b.nodeType||8===b.nodeType)return l;d=f(null,d),d.type=c,d.target=b;do g=b[e],g&&a(d,g
 ),b=b.parentNode||b.ownerDocument||b.defaultView||b.parentWindow;while(b&&!d.isPropagationStopped());return l},l.clean=function(a){var b,c,d=l.unbind;if(!a||3===a.nodeType||8===a.nodeType)return l;if(a[e]&&d(a),a.getElementsByTagName||(a=a.document),a&&a.getElementsByTagName)for(d(a),c=a.getElementsByTagName("*"),b=c.length;b--;)a=c[b],a[e]&&d(a);return l},l.destroy=function(){m={}},l.cancel=function(a){return a&&(a.preventDefault(),a.stopImmediatePropagation()),!1}}var i="mce-data-",j=/^(?:mouse|contextmenu)|click/,k={keyLocation:1,layerX:1,layerY:1,returnValue:1,webkitMovementX:1,webkitMovementY:1,keyIdentifier:1},l=function(a){return a.isDefaultPrevented===n||a.isDefaultPrevented===m},m=function(){return!1},n=function(){return!0};return h.Event=new h,h.Event.bind(window,"ready",function(){}),h}),g("8",[],function(){function a(a,b,c,d){var e,f,g,h,i,k,m,n,o,p;if((b?b.ownerDocument||b:N)!==F&&E(
 b),b=b||F,c=c||[],!a||"string"!=typeof a)return c;if(1!==(h=b.nodeType)&&9!==h)return[];if(H&&!d){if(e=qa.exec(a))if(g=e[1]){if(9===h){if(f=b.getElementById(g),!f||!f.parentNode)return c;if(f.id===g)return c.push(f),c}else if(b.ownerDocument&&(f=b.ownerDocument.getElementById(g))&&L(b,f)&&f.id===g)return c.push(f),c}else{if(e[2])return $.apply(c,b.getElementsByTagName(a)),c;if((g=e[3])&&u.getElementsByClassName)return $.apply(c,b.getElementsByClassName(g)),c}if(u.qsa&&(!I||!I.test(a))){if(n=m=M,o=b,p=9===h&&a,1===h&&"object"!==b.nodeName.toLowerCase()){for(k=y(a),(m=b.getAttribute("id"))?n=m.replace(sa,"\\$&"):b.setAttribute("id",n),n="[id='"+n+"'] ",i=k.length;i--;)k[i]=n+l(k[i]);o=ra.test(a)&&j(b.parentNode)||b,p=k.join(",")}if(p)try{return $.apply(c,o.querySelectorAll(p)),c}catch(a){}finally{m||b.removeAttribute("
 id")}}}return A(a.replace(ga,"$1"),b,c,d)}function b(){function a(c,d){return b.push(c+" ")>v.cacheLength&&delete a[b.shift()],a[c+" "]=d}var b=[];return a}function c(a){return a[M]=!0,a}function d(a){var b=F.createElement("div");try{return!!a(b)}catch(a){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function e(a,b){for(var c=a.split("|"),d=a.length;d--;)v.attrHandle[c[d]]=b}function f(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||V)-(~a.sourceIndex||V);if(d)return d;if(c)for(;c=c.nextSibling;)if(c===b)return-1;return a?1:-1}function g(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function h(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function i(a){return c(function(b){return b=+b,c(function(c,d){
 for(var e,f=a([],c.length,b),g=f.length;g--;)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function j(a){return a&&typeof a.getElementsByTagName!==U&&a}function k(){}function l(a){for(var b=0,c=a.length,d="";b<c;b++)d+=a[b].value;return d}function m(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=P++;return b.first?function(b,c,f){for(;b=b[d];)if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[O,f];if(g){for(;b=b[d];)if((1===b.nodeType||e)&&a(b,c,g))return!0}else for(;b=b[d];)if(1===b.nodeType||e){if(i=b[M]||(b[M]={}),(h=i[d])&&h[0]===O&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function n(a){return a.length>1?function(b,c,d){for(var e=a.length;e--;)if(!a[e](b,c,d))return!1;return!0}:a[0]}function o(b,c,d){for(var e=0,f=c.length;e<f;e++)a(b,c[e],d);return d}function p(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;h<i;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&
 amp;&b.push(h)));return g}function q(a,b,d,e,f,g){return e&&!e[M]&&(e=q(e)),f&&!f[M]&&(f=q(f,g)),c(function(c,g,h,i){var j,k,l,m=[],n=[],q=g.length,r=c||o(b||"*",h.nodeType?[h]:h,[]),s=!a||!c&&b?r:p(r,m,a,h,i),t=d?f||(c?a:q||e)?[]:g:s;if(d&&d(s,t,h,i),e)for(j=p(t,n),e(j,[],h,i),k=j.length;k--;)(l=j[k])&&(t[n[k]]=!(s[n[k]]=l));if(c){if(f||a){if(f){for(j=[],k=t.length;k--;)(l=t[k])&&j.push(s[k]=l);f(null,t=[],j,i)}for(k=t.length;k--;)(l=t[k])&&(j=f?aa.call(c,l):m[k])>-1&&(c[j]=!(g[j]=l))}}else t=p(t===g?t.splice(q,t.length):t),f?f(null,g,t,i):$.apply(g,t)})}function r(a){for(var b,c,d,e=a.length,f=v.relative[a[0].type],g=f||v.relative[" "],h=f?1:0,i=m(function(a){return a===b},g,!0),j=m(function(a){return aa.call(b,a)>-1},g,!0),k=[function(a,c,d){return!f&&(d||c!==B)||((b=c).nodeType?i(a,c,d):j(a,c,d))}];h<e;h++)if(c=v.relative[a[h].type])k=[m(n(k),c)];else{if(c=v.f
 ilter[a[h].type].apply(null,a[h].matches),c[M]){for(d=++h;d<e&&!v.relative[a[d].type];d++);return q(h>1&&n(k),h>1&&l(a.slice(0,h-1).concat({value:" "===a[h-2].type?"*":""})).replace(ga,"$1"),c,h<d&&r(a.slice(h,d)),d<e&&r(a=a.slice(d)),d<e&&l(a))}k.push(c)}return n(k)}function s(b,d){var e=d.length>0,f=b.length>0,g=function(c,g,h,i,j){var k,l,m,n=0,o="0",q=c&&[],r=[],s=B,t=c||f&&v.find.TAG("*",j),u=O+=null==s?1:Math.random()||.1,w=t.length;for(j&&(B=g!==F&&g);o!==w&&null!=(k=t[o]);o++){if(f&&k){for(l=0;m=b[l++];)if(m(k,g,h)){i.push(k);break}j&&(O=u)}e&&((k=!m&&k)&&n--,c&&q.push(k))}if(n+=o,e&&o!==n){for(l=0;m=d[l++];)m(q,r,g,h);if(c){if(n>0)for(;o--;)q[o]||r[o]||(r[o]=Y.call(i));r=p(r)}$.apply(i,r),j&&!c&&r.length>0&&n+d.length&gt
 ;1&&a.uniqueSort(i)}return j&&(O=u,B=s),q};return e?c(g):g}var t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M="sizzle"+-new Date,N=window.document,O=0,P=0,Q=b(),R=b(),S=b(),T=function(a,b){return a===b&&(D=!0),0},U="undefined",V=1<<31,W={}.hasOwnProperty,X=[],Y=X.pop,Z=X.push,$=X.push,_=X.slice,aa=X.indexOf||function(a){for(var b=0,c=this.length;b<c;b++)if(this[b]===a)return b;return-1},ba="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",ca="[\\x20\\t\\r\\n\\f]",da="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",ea="\\["+ca+"*("+da+")(?:"+ca+"*([*^$|!~]?=)"+ca+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+da+"))|)"+ca+"*\\]",fa=":("+da+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|
 "+ea+")*)|.*)\\)|)",ga=new RegExp("^"+ca+"+|((?:^|[^\\\\])(?:\\\\.)*)"+ca+"+$","g"),ha=new RegExp("^"+ca+"*,"+ca+"*"),ia=new RegExp("^"+ca+"*([>+~]|"+ca+")"+ca+"*"),ja=new RegExp("="+ca+"*([^\\]'\"]*?)"+ca+"*\\]","g"),ka=new RegExp(fa),la=new RegExp("^"+da+"$"),ma={ID:new RegExp("^#("+da+")"),CLASS:new RegExp("^\\.("+da+")"),TAG:new RegExp("^("+da+"|[*])"),ATTR:new RegExp("^"+ea),PSEUDO:new RegExp("^"+fa),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ca+"*(even|odd|(([+-]|)(\\d*)n|)"+ca+"*(?:([+-]|)"+ca+"*(\\d+)|))"+ca+"*\\)|)","i"),bool:new RegExp("^(?:"+ba+")$","i"),needsContext:new RegExp("^
 "+ca+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ca+"*((?:-\\d)?\\d*)"+ca+"*\\)|)(?=[^-]|$)","i")},na=/^(?:input|select|textarea|button)$/i,oa=/^h\d$/i,pa=/^[^{]+\{\s*\[native \w/,qa=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ra=/[+~]/,sa=/'|\\/g,ta=new RegExp("\\\\([\\da-f]{1,6}"+ca+"?|("+ca+")|.)","ig"),ua=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{$.apply(X=_.call(N.childNodes),N.childNodes),X[N.childNodes.length].nodeType}catch(a){$={apply:X.length?function(a,b){Z.apply(a,_.call(b))}:function(a,b){for(var c=a.length,d=0;a[c++]=b[d++];);a.length=c-1}}}u=a.support={},x=a.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},E=a.setDocument=function(a){function b(a){try{return a.top}catch(a){}return null}var c,e=a?
 a.ownerDocument||a:N,g=e.defaultView;return e!==F&&9===e.nodeType&&e.documentElement?(F=e,G=e.documentElement,H=!x(e),g&&g!==b(g)&&(g.addEventListener?g.addEventListener("unload",function(){E()},!1):g.attachEvent&&g.attachEvent("onunload",function(){E()})),u.attributes=d(function(a){return a.className="i",!a.getAttribute("className")}),u.getElementsByTagName=d(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),u.getElementsByClassName=pa.test(e.getElementsByClassName),u.getById=d(function(a){return G.appendChild(a).id=M,!e.getElementsByName||!e.getElementsByName(M).length}),u.getById?(v.find.ID=function(a,b){if(typeof b.getElementById!==U&&H){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},v.filter.ID=function(a){var b=a.replace(ta,ua);return function(a){return a.getAttribute("id")===b}}):(delete v.find.ID,v.
 filter.ID=function(a){var b=a.replace(ta,ua);return function(a){var c=typeof a.getAttributeNode!==U&&a.getAttributeNode("id");return c&&c.value===b}}),v.find.TAG=u.getElementsByTagName?function(a,b){if(typeof b.getElementsByTagName!==U)return b.getElementsByTagName(a)}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){for(;c=f[e++];)1===c.nodeType&&d.push(c);return d}return f},v.find.CLASS=u.getElementsByClassName&&function(a,b){if(H)return b.getElementsByClassName(a)},J=[],I=[],(u.qsa=pa.test(e.querySelectorAll))&&(d(function(a){a.innerHTML="<select msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&I.push("[*^$]="+ca+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||I.push("\\["+ca+"*(?:value|"+ba+")"),a.querySelectorAl
 l(":checked").length||I.push(":checked")}),d(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&I.push("name"+ca+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||I.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),I.push(",.*:")})),(u.matchesSelector=pa.test(K=G.matches||G.webkitMatchesSelector||G.mozMatchesSelector||G.oMatchesSelector||G.msMatchesSelector))&&d(function(a){u.disconnectedMatch=K.call(a,"div"),K.call(a,"[s!='']:x"),J.push("!=",fa)}),I=I.length&&new RegExp(I.join("|")),J=J.length&&new RegExp(J.join("|")),c=pa.test(G.compareDocumentPosition),L=c||pa.test(G.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&
 &b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)for(;b=b.parentNode;)if(b===a)return!0;return!1},T=c?function(a,b){if(a===b)return D=!0,0;var c=!a.compareDocumentPosition-!b.compareDocumentPosition;return c?c:(c=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&c||!u.sortDetached&&b.compareDocumentPosition(a)===c?a===e||a.ownerDocument===N&&L(N,a)?-1:b===e||b.ownerDocument===N&&L(N,b)?1:C?aa.call(C,a)-aa.call(C,b):0:4&c?-1:1)}:function(a,b){if(a===b)return D=!0,0;var c,d=0,g=a.parentNode,h=b.parentNode,i=[a],j=[b];if(!g||!h)return a===e?-1:b===e?1:g?-1:h?1:C?aa.call(C,a)-aa.call(C,b):0;if(g===h)return f(a,b);for(c=a;c=c.parentNode;)i.unshift(c);for(c=b;c=c.parentNode;)j.unshift(c);for(;i[d]===j[d];)d++;return d?f(i[d],j[d]):i[d]===N?-1:j[d]===N?1:0},e):F},a.matches=function(b,c){return a(b,null,null,c
 )},a.matchesSelector=function(b,c){if((b.ownerDocument||b)!==F&&E(b),c=c.replace(ja,"='$1']"),u.matchesSelector&&H&&(!J||!J.test(c))&&(!I||!I.test(c)))try{var d=K.call(b,c);if(d||u.disconnectedMatch||b.document&&11!==b.document.nodeType)return d}catch(a){}return a(c,F,null,[b]).length>0},a.contains=function(a,b){return(a.ownerDocument||a)!==F&&E(a),L(a,b)},a.attr=function(a,b){(a.ownerDocument||a)!==F&&E(a);var c=v.attrHandle[b.toLowerCase()],d=c&&W.call(v.attrHandle,b.toLowerCase())?c(a,b,!H):void 0;return void 0!==d?d:u.attributes||!H?a.getAttribute(b):(d=a.getAttributeNode(b))&&d.specified?d.value:null},a.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},a.uniqueSort=function(a){var b,c=[],d=0,e=0;if(D=!u.detectDuplicates,C=!u.sortStable&&a.slice(0),a.sort(T),D){for(;b=a[e++];)b===a[e]&&(d=c.push(e));for(;d--;)a.splice(c[d],1)}return C=null,
 a},w=a.getText=function(a){var b,c="",d=0,e=a.nodeType;if(e){if(1===e||9===e||11===e){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=w(a)}else if(3===e||4===e)return a.nodeValue}else for(;b=a[d++];)c+=w(b);return c},v=a.selectors={cacheLength:50,createPseudo:c,match:ma,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ta,ua),a[3]=(a[3]||a[4]||a[5]||"").replace(ta,ua),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(b){return b[1]=b[1].toLowerCase(),"nth"===b[1].slice(0,3)?(b[3]||a.error(b[0]),b[4]=+(b[4]?b[5]+(b[6]||1):2*("even"===b[3]||"odd"===b[3])),b[5]=+(b[7]+b[8]||"odd"===b[3])
 ):b[3]&&a.error(b[0]),b},PSEUDO:function(a){var b,c=!a[6]&&a[2];return ma.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&ka.test(c)&&(b=y(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ta,ua).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=Q[a+" "];return b||(b=new RegExp("(^|"+ca+")"+a+"("+ca+"|$)"))&&Q(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==U&&a.getAttribute("class")||"")})},ATTR:function(b,c,d){return function(e){var f=a.attr(e,b);return null==f?"!="===c:!c||(f+="","="===c?f===d:"!="===c?f!==d:"^="===c?d
 &&0===f.indexOf(d):"*="===c?d&&f.indexOf(d)>-1:"$="===c?d&&f.slice(-d.length)===d:"~="===c?(" "+f+" ").indexOf(d)>-1:"|="===c&&(f===d||f.slice(0,d.length+1)===d+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){for(;p;){for(l=b;l=l[p];)if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){for(k=q[M]||(q[M]={}),j=k[a]||[],n=j[0]===O&&j[1],m=j[0]===O&&j[2],l=n&&q.childNodes[n];l=++n&&l&&l[p]||(m=n=0)|
 |o.pop();)if(1===l.nodeType&&++m&&l===b){k[a]=[O,n,m];break}}else if(s&&(j=(b[M]||(b[M]={}))[a])&&j[0]===O)m=j[1];else for(;(l=++n&&l&&l[p]||(m=n=0)||o.pop())&&((h?l.nodeName.toLowerCase()!==r:1!==l.nodeType)||!++m||(s&&((l[M]||(l[M]={}))[a]=[O,m]),l!==b)););return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(b,d){var e,f=v.pseudos[b]||v.setFilters[b.toLowerCase()]||a.error("unsupported pseudo: "+b);return f[M]?f(d):f.length>1?(e=[b,b,"",d],v.setFilters.hasOwnProperty(b.toLowerCase())?c(function(a,b){for(var c,e=f(a,d),g=e.length;g--;)c=aa.call(a,e[g]),a[c]=!(b[c]=e[g])}):function(a){return f(a,0,e)}):f}},pseudos:{not:c(function(a){var b=[],d=[],e=z(a.replace(ga,"$1"));return e[M]?c(function(a,b,c,d){for(var f,g=e(a,null,d,[]),h=a.length;h--;)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,c,f){return b[0]=a,e(b,null,f,d),!d.pop()}}),has:c(function(b){return function(c){retu
 rn a(b,c).length>0}}),contains:c(function(a){return a=a.replace(ta,ua),function(b){return(b.textContent||b.innerText||w(b)).indexOf(a)>-1}}),lang:c(function(b){return la.test(b||"")||a.error("unsupported lang: "+b),b=b.replace(ta,ua).toLowerCase(),function(a){var c;do if(c=H?a.lang:a.getAttribute("xml:lang")||a.getAttribute("lang"))return c=c.toLowerCase(),c===b||0===c.indexOf(b+"-");while((a=a.parentNode)&&1===a.nodeType);return!1}}),target:function(a){var b=window.location&&window.location.hash;return b&&b.slice(1)===a.id},root:function(a){return a===G},focus:function(a){return a===F.activeElement&&(!F.hasFocus||F.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selec
 ted},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!v.pseudos.empty(a)},header:function(a){return oa.test(a.nodeName)},input:function(a){return na.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:i(function(){return[0]}),last:i(function(a,b){return[b-1]}),eq:i(function(a,b,c){return[c<0?c+b:c]}),even:i(function(a,b){for(var c=0;c<b;c+=2)a.push(c);return a}),odd:i(function(a,b){for(var c=1;c<b;c+=2)a.push(c);return a}),lt:i(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:i(func
 tion(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},v.pseudos.nth=v.pseudos.eq;for(t in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})v.pseudos[t]=g(t);for(t in{submit:!0,reset:!0})v.pseudos[t]=h(t);return k.prototype=v.filters=v.pseudos,v.setFilters=new k,y=a.tokenize=function(b,c){var d,e,f,g,h,i,j,k=R[b+" "];if(k)return c?0:k.slice(0);for(h=b,i=[],j=v.preFilter;h;){d&&!(e=ha.exec(h))||(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),d=!1,(e=ia.exec(h))&&(d=e.shift(),f.push({value:d,type:e[0].replace(ga," ")}),h=h.slice(d.length));for(g in v.filter)!(e=ma[g].exec(h))||j[g]&&!(e=j[g](e))||(d=e.shift(),f.push({value:d,type:g,matches:e}),h=h.slice(d.length));if(!d)break}return c?h.length:h?a.error(b):R(b,i).slice(0)},z=a.compile=function(a,b){var c,d=[],e=[],f=S[a+" "];if(!f){for(b||(b=y(a)),c=b.length;c--;)f=r(b[c]),f[M]?d.push(f):e.push(f);f=S(a,s(e,d)),f.selector=a}return f},A=a.select=function(a,b,c,d
 ){var e,f,g,h,i,k="function"==typeof a&&a,m=!d&&y(a=k.selector||a);if(c=c||[],1===m.length){if(f=m[0]=m[0].slice(0),f.length>2&&"ID"===(g=f[0]).type&&u.getById&&9===b.nodeType&&H&&v.relative[f[1].type]){if(b=(v.find.ID(g.matches[0].replace(ta,ua),b)||[])[0],!b)return c;k&&(b=b.parentNode),a=a.slice(f.shift().value.length)}for(e=ma.needsContext.test(a)?0:f.length;e--&&(g=f[e],!v.relative[h=g.type]);)if((i=v.find[h])&&(d=i(g.matches[0].replace(ta,ua),ra.test(f[0].type)&&j(b.parentNode)||b))){if(f.splice(e,1),a=d.length&&l(f),!a)return $.apply(c,d),c;break}}return(k||z(a,m))(d,b,!H,c,ra.test(a)&&j(b.parentNode)||b),c},u.sortStable=M.split("").sort(T).join("")===M,u.detectDuplicates=!!D,E(),u.sortDetached=d(function(a){return 1&a.compareDocumentPosition(F.createElement("div"))}),d(function(a){return a.innerHTML="<a href=
 '#'></a>","#"===a.firstChild.getAttribute("href")})||e("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),u.attributes&&d(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||e("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),d(function(a){return null==a.getAttribute("disabled")})||e(ba,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),a}),g("1g",[],function(){function a(a){var b,c,d=a;if(!j(a))for(d=[],b=0,c=a.length;b<c;b++)d[b]=a[b];return d}function b(a,b,c){var d,e;if(!a)return 0;if(c=c||a,void 0!==a.length){for(d=0,e=a.length;d<e;d++)if(b.call(c,a[d],d,a)===!1)return 0}else fo
 r(d in a)if(a.hasOwnProperty(d)&&b.call(c,a[d],d,a)===!1)return 0;return 1}function c(a,c){var d=[];return b(a,function(b,e){d.push(c(b,e,a))}),d}function d(a,c){var d=[];return b(a,function(b,e){c&&!c(b,e,a)||d.push(b)}),d}function e(a,b){var c,d;if(a)for(c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1}function f(a,b,c,d){var e=0;for(arguments.length<3&&(c=a[0]);e<a.length;e++)c=b.call(d,c,a[e],e);return c}function g(a,b,c){var d,e;for(d=0,e=a.length;d<e;d++)if(b.call(c,a[d],d,a))return d;return-1}function h(a,b,c){var d=g(a,b,c);if(d!==-1)return a[d]}function i(a){return a[a.length-1]}var j=Array.isArray||function(a){return"[object Array]"===Object.prototype.toString.call(a)};return{isArray:j,toArray:a,each:b,map:c,filter:d,indexOf:e,reduce:f,findIndex:g,find:h,last:i}}),g("9",["6","1g"],function(a,b){function c(a){return null===a||void 0===a?"":(""+a).replace(n,"")}funct
 ion d(a,c){return c?!("array"!=c||!b.isArray(a))||typeof a==c:void 0!==a}function e(a,b,c){var d;for(a=a||[],b=b||",","string"==typeof a&&(a=a.split(b)),c=c||{},d=a.length;d--;)c[a[d]]={};return c}function f(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function g(a,b,c){var d,e,f,g,h,i=this,j=0;if(a=/^((static) )?([\w.]+)(:([\w.]+))?/.exec(a),f=a[3].match(/(^|\.)(\w+)$/i)[2],e=i.createNS(a[3].replace(/\.\w+$/,""),c),!e[f]){if("static"==a[2])return e[f]=b,void(this.onCreate&&this.onCreate(a[2],a[3],e[f]));b[f]||(b[f]=function(){},j=1),e[f]=b[f],i.extend(e[f].prototype,b),a[5]&&(d=i.resolve(a[5]).prototype,g=a[5].match(/\.(\w+)$/i)[1],h=e[f],j?e[f]=function(){return d[g].apply(this,arguments)}:e[f]=function(){return this.parent=d[g],h.apply(this,arguments)},e[f].prototype[f]=e[f],i.each(d,function(a,b){e[f].prototype[b]=d[b]}),i.each(b,function(a,b){d[b]?e[f].prototype[b]=function(){return this.parent=d
 [b],a.apply(this,arguments)}:b!=f&&(e[f].prototype[b]=a)})),i.each(b["static"],function(a,b){e[f][b]=a})}}function h(a,b){var c,d,e,f,g=arguments;for(c=1,d=g.length;c<d;c++){b=g[c];for(e in b)b.hasOwnProperty(e)&&(f=b[e],void 0!==f&&(a[e]=f))}return a}function i(a,c,d,e){e=e||this,a&&(d&&(a=a[d]),b.each(a,function(a,b){return c.call(e,a,b,d)!==!1&&void i(a,c,d,e)}))}function j(a,b){var c,d;for(b=b||window,a=a.split("."),c=0;c<a.length;c++)d=a[c],b[d]||(b[d]={}),b=b[d];return b}function k(a,b){var c,d;for(b=b||window,a=a.split("."),c=0,d=a.length;c<d&&(b=b[a[c]],b);c++);return b}function l(a,e){return!a||d(a,"array")?a:b.map(a.split(e||","),c)}function m(b){var c=a.cacheSuffix;return c&&(b+=(b.indexOf("?")===-1?"?":"&")+c),b}var n=/^\s*|\s*$/g;return{trim:c,isArray:b.isArray,is:d,toArray:b.toArray,makeMap:e,each:b.each,map:b.map,
-grep:b.filter,inArray:b.indexOf,hasOwn:f,extend:h,create:g,walk:i,createNS:j,resolve:k,explode:l,_addCacheSuffix:m}}),g("a",["7","8","9","6"],function(a,b,c,d){function e(a){return"undefined"!=typeof a}function f(a){return"string"==typeof a}function g(a){return a&&a==a.window}function h(a,b){var c,d,e;for(b=b||w,e=b.createElement("div"),c=b.createDocumentFragment(),e.innerHTML=a;d=e.firstChild;)c.appendChild(d);return c}function i(a,b,c,d){var e;if(f(b))b=h(b,q(a[0]));else if(b.length&&!b.nodeType){if(b=l.makeArray(b),d)for(e=b.length-1;e>=0;e--)i(a,b[e],c,d);else for(e=0;e<b.length;e++)i(a,b[e],c,d);return a}if(b.nodeType)for(e=a.length;e--;)c.call(a[e],b);return a}function j(a,b){return a&&b&&(" "+a.className+" ").indexOf(" "+b+" ")!==-1}function k(a,b,c){var d,e;return b=l(b)[0],a.each(function(){var a=this;c&&d==a.p
 arentNode?e.appendChild(a):(d=a.parentNode,e=b.cloneNode(!1),a.parentNode.insertBefore(e,a),e.appendChild(a))}),a}function l(a,b){return new l.fn.init(a,b)}function m(a,b){var c;if(b.indexOf)return b.indexOf(a);for(c=b.length;c--;)if(b[c]===a)return c;return-1}function n(a){return null===a||a===v?"":(""+a).replace(I,"")}function o(a,b){var c,d,e,f,g;if(a)if(c=a.length,c===f){for(d in a)if(a.hasOwnProperty(d)&&(g=a[d],b.call(g,d,g)===!1))break}else for(e=0;e<c&&(g=a[e],b.call(g,e,g)!==!1);e++);return a}function p(a,b){var c=[];return o(a,function(a,d){b(d,a)&&c.push(d)}),c}function q(a){return a?9==a.nodeType?a:a.ownerDocument:w}function r(a,b,c){var d=[],e=a[b];for("string"!=typeof c&&c instanceof l&&(c=c[0]);e&&9!==e.nodeType;){if(void 0!==c){if(e===c)break;if("string"==typeof c&&l(e).is(c))break}1===e.nodeType&&d.push(e),e=e[b]}return d}function s(a,b,c,d){var e=[];
 for(d instanceof l&&(d=d[0]);a;a=a[b])if(!c||a.nodeType===c){if(void 0!==d){if(a===d)break;if("string"==typeof d&&l(a).is(d))break}e.push(a)}return e}function t(a,b,c){for(a=a[b];a;a=a[b])if(a.nodeType==c)return a;return null}function u(a,b,c){o(c,function(c,d){a[c]=a[c]||{},a[c][b]=d})}var v,w=document,x=Array.prototype.push,y=Array.prototype.slice,z=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,A=a.Event,B=c.makeMap("children,contents,next,prev"),C=c.makeMap("fillOpacity fontWeight lineHeight opacity orphans widows zIndex zoom"," "),D=c.makeMap("checked compact declare defer disabled ismap multiple nohref noshade nowrap readonly selected"," "),E={"for":"htmlFor","class":"className",readonly:"readOnly"},F={"float":"cssFloat"},G={},H={},I=/^\s*|\s*$/g;return l.fn=l.prototype={constructor:l,selector:"",context:null,length
 :0,init:function(a,b){var c,d,e=this;if(!a)return e;if(a.nodeType)return e.context=e[0]=a,e.length=1,e;if(b&&b.nodeType)e.context=b;else{if(b)return l(a).attr(b);e.context=b=document}if(f(a)){if(e.selector=a,c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c)return l(b).find(a);if(c[1])for(d=h(a,q(b)).firstChild;d;)x.call(e,d),d=d.nextSibling;else{if(d=q(b).getElementById(c[2]),!d)return e;if(d.id!==c[2])return e.find(a);e.length=1,e[0]=d}}else this.add(a,!1);return e},toArray:function(){return c.toArray(this)},add:function(a,b){var c,d,e=this;if(f(a))return e.add(l(a));if(b!==!1)for(c=l.unique(e.toArray().concat(l.makeArray(a))),e.length=c.length,d=0;d<c.length;d++)e[d]=c[d];else x.apply(e,l.makeArray(a));return e},attr:function(a,b){var c,d=this;if("object"==typeof a)o(a,function(a,b){d.attr(a,b)});else{if(!e(b)){if(d[0]&&1===d[0].nodeType){if(c=G[a],c&&c.get)retu
 rn c.get(d[0],a);if(D[a])return d.prop(a)?a:v;b=d[0].getAttribute(a,2),null===b&&(b=v)}return b}this.each(function(){var c;if(1===this.nodeType){if(c=G[a],c&&c.set)return void c.set(this,b);null===b?this.removeAttribute(a,2):this.setAttribute(a,b,2)}})}return d},removeAttr:function(a){return this.attr(a,null)},prop:function(a,b){var c=this;if(a=E[a]||a,"object"==typeof a)o(a,function(a,b){c.prop(a,b)});else{if(!e(b))return c[0]&&c[0].nodeType&&a in c[0]?c[0][a]:b;this.each(function(){1==this.nodeType&&(this[a]=b)})}return c},css:function(a,b){function c(a){return a.replace(/-(\D)/g,function(a,b){return b.toUpperCase()})}function d(a){return a.replace(/[A-Z]/g,function(a){return"-"+a})}var f,g,h=this;if("object"==typeof a)o(a,function(a,b){h.css(a,b)});else if(e(b))a=c(a),"number"!=typeof b||C[a]||(b+="px"),h.each(function(){var c=this.style;if(g=H[a],g&&g.set)return void g.set(this,b);t
 ry{this.style[F[a]||a]=b}catch(a){}null!==b&&""!==b||(c.removeProperty?c.removeProperty(d(a)):c.removeAttribute(a))});else{if(f=h[0],g=H[a],g&&g.get)return g.get(f);if(f.ownerDocument.defaultView)try{return f.ownerDocument.defaultView.getComputedStyle(f,null).getPropertyValue(d(a))}catch(a){return v}else if(f.currentStyle)return f.currentStyle[c(a)]}return h},remove:function(){for(var a,b=this,c=this.length;c--;)a=b[c],A.clean(a),a.parentNode&&a.parentNode.removeChild(a);return this},empty:function(){for(var a,b=this,c=this.length;c--;)for(a=b[c];a.firstChild;)a.removeChild(a.firstChild);return this},html:function(a){var b,c=this;if(e(a)){b=c.length;try{for(;b--;)c[b].innerHTML=a}catch(d){l(c[b]).empty().append(a)}return c}return c[0]?c[0].innerHTML:""},text:function(a){var b,c=this;if(e(a)){for(b=c.length;b--;)"innerText"in c[b]?c[b].innerText=a:c[0].textContent=a;return c}return c[0]?c[0].innerText||c[0].textContent:"&quot
 ;},append:function(){return i(this,arguments,function(a){(1===this.nodeType||this.host&&1===this.host.nodeType)&&this.appendChild(a)})},prepend:function(){return i(this,arguments,function(a){(1===this.nodeType||this.host&&1===this.host.nodeType)&&this.insertBefore(a,this.firstChild)},!0)},before:function(){var a=this;return a[0]&&a[0].parentNode?i(a,arguments,function(a){this.parentNode.insertBefore(a,this)}):a},after:function(){var a=this;return a[0]&&a[0].parentNode?i(a,arguments,function(a){this.parentNode.insertBefore(a,this.nextSibling)},!0):a},appendTo:function(a){return l(a).append(this),this},prependTo:function(a){return l(a).prepend(this),this},replaceWith:function(a){return this.before(a).remove()},wrap:function(a){return k(this,a)},wrapAll:function(a){return k(this,a,!0)},wrapInner:function(a){return this.each(function(){l(this).contents().wrapAll(a)}),this},unwrap:function(){return this.parent().each(function(){l(this).repl
 aceWith(this.childNodes)})},clone:function(){var a=[];return this.each(function(){a.push(this.cloneNode(!0))}),l(a)},addClass:function(a){return this.toggleClass(a,!0)},removeClass:function(a){return this.toggleClass(a,!1)},toggleClass:function(a,b){var c=this;return"string"!=typeof a?c:(a.indexOf(" ")!==-1?o(a.split(" "),function(){c.toggleClass(this,b)}):c.each(function(c,d){var e,f;f=j(d,a),f!==b&&(e=d.className,f?d.className=n((" "+e+" ").replace(" "+a+" "," ")):d.className+=e?" "+a:a)}),c)},hasClass:function(a){return j(this[0],a)},each:function(a){return o(this,a)},on:function(a,b){return this.each(function(){A.bind(this,a,b)})},off:function(a,b){return this.each(function(){A.unbind(this,a,b)})},trigger:function(a){return this.each(function(){"object"==typeof a?A.fire(this,a.type,a):A.fire(this,a)})},show:function(){return this.css("display","")},hide
 :function(){return this.css("display","none")},slice:function(){return new l(y.apply(this,arguments))},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},find:function(a){var b,c,d=[];for(b=0,c=this.length;b<c;b++)l.find(a,this[b],d);return l(d)},filter:function(a){return l("function"==typeof a?p(this.toArray(),function(b,c){return a(c,b)}):l.filter(a,this.toArray()))},closest:function(a){var b=[];return a instanceof l&&(a=a[0]),this.each(function(c,d){for(;d;){if("string"==typeof a&&l(d).is(a)){b.push(d);break}if(d==a){b.push(d);break}d=d.parentNode}}),l(b)},offset:function(a){var b,c,d,e,f=0,g=0;return a?this.css(a):(b=this[0],b&&(c=b.ownerDocument,d=c.documentElement,b.getBoundingClientRect&&(e=b.getBoundingClientRect(),f=e.left+(d.scrollLeft||c.body.scrollLeft)-d.clientLeft,g=e.top+(d.scrollTop||c.body.scrollTop)-d.clientT
 op)),{left:f,top:g})},push:x,sort:[].sort,splice:[].splice},c.extend(l,{extend:c.extend,makeArray:function(a){return g(a)||a.nodeType?[a]:c.toArray(a)},inArray:m,isArray:c.isArray,each:o,trim:n,grep:p,find:b,expr:b.selectors,unique:b.uniqueSort,text:b.getText,contains:b.contains,filter:function(a,b,c){var d=b.length;for(c&&(a=":not("+a+")");d--;)1!=b[d].nodeType&&b.splice(d,1);return b=1===b.length?l.find.matchesSelector(b[0],a)?[b[0]]:[]:l.find.matches(a,b)}}),o({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return r(a,"parentNode")},next:function(a){return t(a,"nextSibling",1)},prev:function(a){return t(a,"previousSibling",1)},children:function(a){return s(a.firstChild,"nextSibling",1)},contents:function(a){return c.toArray(("iframe"===a.nodeName?a.contentDocument||a.contentWindow.document:a).childNodes)}},function(a,b){l.fn[a]=function(c){var
  d=this,e=[];return d.each(function(){var a=b.call(e,this,c,e);a&&(l.isArray(a)?e.push.apply(e,a):e.push(a))}),this.length>1&&(B[a]||(e=l.unique(e)),0===a.indexOf("parents")&&(e=e.reverse())),e=l(e),c?e.filter(c):e}}),o({parentsUntil:function(a,b){return r(a,"parentNode",b)},nextUntil:function(a,b){return s(a,"nextSibling",1,b).slice(1)},prevUntil:function(a,b){return s(a,"previousSibling",1,b).slice(1)}},function(a,b){l.fn[a]=function(c,d){var e=this,f=[];return e.each(function(){var a=b.call(f,this,c,f);a&&(l.isArray(a)?f.push.apply(f,a):f.push(a))}),this.length>1&&(f=l.unique(f),0!==a.indexOf("parents")&&"prevUntil"!==a||(f=f.reverse())),f=l(f),d?f.filter(d):f}}),l.fn.is=function(a){return!!a&&this.filter(a).length>0},l.fn.init.prototype=l.fn,l.overrideDefaults=function(a){function b(d,e){return c=c||a(),0===arguments.length&&(d=c.element),e||(e=c.c
 ontext),new b.fn.init(d,e)}var c;return l.extend(b,this),b},d.ie&&d.ie<8&&(u(G,"get",{maxlength:function(a){var b=a.maxLength;return 2147483647===b?v:b},size:function(a){var b=a.size;return 20===b?v:b},"class":function(a){return a.className},style:function(a){var b=a.style.cssText;return 0===b.length?v:b}}),u(G,"set",{"class":function(a,b){a.className=b},style:function(a,b){a.style.cssText=b}})),d.ie&&d.ie<9&&(F["float"]="styleFloat",u(H,"set",{opacity:function(a,b){var c=a.style;null===b||""===b?c.removeAttribute("filter"):(c.zoom=1,c.filter="alpha(opacity="+100*b+")")}})),l.attrHooks=G,l.cssHooks=H,l}),g("b",[],function(){return function(a,b){function c(a,b,c,d){function e(a){return a=parseInt(a,10).toString(16),a.length>1?a:"0"+a}return"#"+e(b)+e(c)+e(d)}var d,e,f,g,h=/rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+
 )\s*,\s*([0-9]+)\s*\)/gi,i=/(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi,j=/\s*([^:]+):\s*([^;]+);?/g,k=/\s+$/,l={},m="\ufeff";for(a=a||{},b&&(f=b.getValidStyles(),g=b.getInvalidStyles()),e=("\\\" \\' \\; \\: ; : "+m).split(" "),d=0;d<e.length;d++)l[e[d]]=m+d,l[m+d]=e[d];return{toHex:function(a){return a.replace(h,c)},parse:function(b){function e(a,b,c){var e,f,g,h;if(e=w[a+"-top"+b],e&&(f=w[a+"-right"+b],f&&(g=w[a+"-bottom"+b],g&&(h=w[a+"-left"+b])))){var i=[e,f,g,h];for(d=i.length-1;d--&&i[d]===i[d+1];);d>-1&&c||(w[a+b]=d==-1?i[0]:i.join(" "),delete w[a+"-top"+b],delete w[a+"-right"+b],delete w[a+"-bottom"+b],delete w[a+"-left"+b])}}function f(a){var b,c=w[a];if(c){for(c=c.split(" "),b=
 c.length;b--;)if(c[b]!==c[0])return!1;return w[a]=c[0],!0}}function g(a,b,c,d){f(b)&&f(c)&&f(d)&&(w[a]=w[b]+" "+w[c]+" "+w[d],delete w[b],delete w[c],delete w[d])}function n(a){return v=!0,l[a]}function o(a,b){return v&&(a=a.replace(/\uFEFF[0-9]/g,function(a){return l[a]})),b||(a=a.replace(/\\([\'\";:])/g,"$1")),a}function p(a){return String.fromCharCode(parseInt(a.slice(1),16))}function q(a){return a.replace(/\\[0-9a-f]+/gi,p)}function r(b,c,d,e,f,g){if(f=f||g)return f=o(f),"'"+f.replace(/\'/g,"\\'")+"'";if(c=o(c||d||e),!a.allow_script_urls){var h=c.replace(/[\s\r\n]+/g,"");if(/(java|vb)script:/i.test(h))return"";if(!a.allow_svg_data_urls&&/^data:image\/svg/i.test(h))return""}return x&&(c=x.call(y,c,"style")),"url('"+c.replace(/\'/g,"\\'")+"')"}var s,t,u,v,w={},x=a.url_converter,y=a.url_converter_scope
 ||this;if(b){for(b=b.replace(/[\u0000-\u001F]/g,""),b=b.replace(/\\[\"\';:\uFEFF]/g,n).replace(/\"[^\"]+\"|\'[^\']+\'/g,function(a){return a.replace(/[;:]/g,n)});s=j.exec(b);)if(j.lastIndex=s.index+s[0].length,t=s[1].replace(k,"").toLowerCase(),u=s[2].replace(k,""),t&&u){if(t=q(t),u=q(u),t.indexOf(m)!==-1||t.indexOf('"')!==-1)continue;if(!a.allow_script_urls&&("behavior"==t||/expression\s*\(|\/\*|\*\//.test(u)))continue;"font-weight"===t&&"700"===u?u="bold":"color"!==t&&"background-color"!==t||(u=u.toLowerCase()),u=u.replace(h,c),u=u.replace(i,r),w[t]=v?o(u,!0):u}e("border","",!0),e("border","-width"),e("border","-color"),e("border","-style"),e("padding",""),e("margin",""),g("border","border-width",&q
 uot;border-style","border-color"),"medium none"===w.border&&delete w.border,"none"===w["border-image"]&&delete w["border-image"]}return w},serialize:function(a,b){function c(b){var c,d,e,g;if(c=f[b])for(d=0,e=c.length;d<e;d++)b=c[d],g=a[b],g&&(i+=(i.length>0?" ":"")+b+": "+g+";")}function d(a,b){var c;return c=g["*"],(!c||!c[a])&&(c=g[b],!c||!c[a])}var e,h,i="";if(b&&f)c("*"),c(b);else for(e in a)h=a[e],!h||g&&!d(e,b)||(i+=(i.length>0?" ":"")+e+": "+h+";");return i}}}}),g("c",[],function(){return function(a,b){function c(a,c,d,e){var f,g;if(a){if(!e&&a[c])return a[c];if(a!=b){if(f=a[d])return f;for(g=a.parentNode;g&&g!=b;g=g.parentNode)if(f=g[d])return f}}}function d(a,c,d,e){var f,g,h;if(a){if(f=a[d],b&&f===b)return;if(f){if(!e)fo
 r(h=f[c];h;h=h[c])if(!h[c])return h;return f}if(g=a.parentNode,g&&g!==b)return g}}var e=a;this.current=function(){return e},this.next=function(a){return e=c(e,"firstChild","nextSibling",a)},this.prev=function(a){return e=c(e,"lastChild","previousSibling",a)},this.prev2=function(a){return e=d(e,"lastChild","previousSibling",a)}}}),g("d",["9"],function(a){function b(a){var b;return b=document.createElement("div"),b.innerHTML=a,b.textContent||b.innerText||a}function c(a,b){var c,d,f,g={};if(a){for(a=a.split(","),b=b||10,c=0;c<a.length;c+=2)d=String.fromCharCode(parseInt(a[c],b)),e[d]||(f="&"+a[c+1]+";",g[d]=f,g[f]=d);return g}}var d,e,f,g=a.makeMap,h=/[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,i=/[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,j=/[<>&\"\']/g,k=/&#
 ([a-z0-9]+);?|&([a-z0-9]+);/gi,l={128:"\u20ac",130:"\u201a",131:"\u0192",132:"\u201e",133:"\u2026",134:"\u2020",135:"\u2021",136:"\u02c6",137:"\u2030",138:"\u0160",139:"\u2039",140:"\u0152",142:"\u017d",145:"\u2018",146:"\u2019",147:"\u201c",148:"\u201d",149:"\u2022",150:"\u2013",151:"\u2014",152:"\u02dc",153:"\u2122",154:"\u0161",155:"\u203a",156:"\u0153",158:"\u017e",159:"\u0178"};e={'"':"&quot;","'":"&#39;","<":"&lt;",">":"&gt;","&":"&amp;","`":"&#96;"},f={"&lt;":"<","&gt;":">","&amp;":"&&
 quot;,"&quot;":'"',"&apos;":"'"},d=c("50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,sj,Gamma,sk,Delta,s
 l,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,t9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,rfloor,8p9,lang
 ,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro",32);var m={encodeRaw:function(a,b){return a.replace(b?h:i,function(a){return e[a]||a})},encodeAllRaw:function(a){return(""+a).replace(j,function(a){return e[a]||a})},encodeNumeric:function(a,b){return a.replace(b?h:i,function(a){return a.length>1?"&#"+(1024*(a.charCodeAt(0)-55296)+(a.charCodeAt(1)-56320)+65536)+";":e[a]||"&#"+a.charCodeAt(0)+";"})},encodeNamed:function(a,b,c){return c=c||d,a.replace(b?h:i,function(a){return e[a]||c[a]||a})},getEncodeFunc:function(a,b){function f(a,c){return a.replace(c?h:i,function(a){return void 0!==e[a]?e[a]:void 0!==b[a]?b[a]:a.length>1?"&#"
 +(1024*(a.charCodeAt(0)-55296)+(a.charCodeAt(1)-56320)+65536)+";":"&#"+a.charCodeAt(0)+";"})}function j(a,c){return m.encodeNamed(a,c,b)}return b=c(b)||d,a=g(a.replace(/\+/g,",")),a.named&&a.numeric?f:a.named?b?j:m.encodeNamed:a.numeric?m.encodeNumeric:m.encodeRaw},decode:function(a){return a.replace(k,function(a,c){return c?(c="x"===c.charAt(0).toLowerCase()?parseInt(c.substr(1),16):parseInt(c,10),c>65535?(c-=65536,String.fromCharCode(55296+(c>>10),56320+(1023&c))):l[c]||String.fromCharCode(c)):f[a]||d[a]||b(a)})}};return m}),g("1h",["9"],function(a){function b(c){function d(){return J.createDocumentFragment()}function e(a,b){x(N,a,b)}function f(a,b){x(O,a,b)}function g(a){e(a.parentNode,U(a))}function h(a){e(a.parentNode,U(a)+1)}function i(a){f(a.parentNode,U(a))}function j(a){f(a.parentNode,U(a)+1)}function k(a){a?(I[R]=I[Q],I[S]=I[P]):(I[Q]=I[R],I[P]=I[S]),I.collapsed=N}function l(a){g
 (a),j(a)}function m(a){e(a,0),f(a,1===a.nodeType?a.childNodes.length:a.nodeValue.length)}function n(a,b){var c=I[Q],d=I[P],e=I[R],f=I[S],g=b.startContainer,h=b.startOffset,i=b.endContainer,j=b.endOffset;return 0===a?w(c,d,g,h):1===a?w(e,f,g,h):2===a?w(e,f,i,j):3===a?w(c,d,i,j):void 0}function o(){y(M)}function p(){return y(K)}function q(){return y(L)}function r(a){var b,d,e=this[Q],f=this[P];3!==e.nodeType&&4!==e.nodeType||!e.nodeValue?(e.childNodes.length>0&&(d=e.childNodes[f]),d?e.insertBefore(a,d):3==e.nodeType?c.insertAfter(a,e):e.appendChild(a)):f?f>=e.nodeValue.length?c.insertAfter(a,e):(b=e.splitText(f),e.parentNode.insertBefore(a,b)):e.parentNode.insertBefore(a,e)}function s(a){var b=I.extractContents();I.insertNode(a),a.appendChild(b),I.selectNode(a)}function t(){return T(new b(c),{startContainer:I[Q],startOffset:I[P],endContainer:I[R],endOffset:I[S],collapsed:I.collapsed,commonAncestorContainer:I.commonAncestorContainer})}function u(a,b){var c;if(3==a
 .nodeType)return a;if(b<0)return a;for(c=a.firstChild;c&&b>0;)--b,c=c.nextSibling;return c?c:a}function v(){return I[Q]==I[R]&&I[P]==I[S]}function w(a,b,d,e){var f,g,h,i,j,k;if(a==d)return b==e?0:b<e?-1:1;for(f=d;f&&f.parentNode!=a;)f=f.parentNode;if(f){for(g=0,h=a.firstChild;h!=f&&g<b;)g++,h=h.nextSibling;return b<=g?-1:1}for(f=a;f&&f.parentNode!=d;)f=f.parentNode;if(f){for(g=0,h=d.firstChild;h!=f&&g<e;)g++,h=h.nextSibling;return g<e?-1:1}for(i=c.findCommonAncestor(a,d),j=a;j&&j.parentNode!=i;)j=j.parentNode;for(j||(j=i),k=d;k&&k.parentNode!=i;)k=k.parentNode;if(k||(k=i),j==k)return 0;for(h=i.firstChild;h;){if(h==j)return-1;if(h==k)return 1;h=h.nextSibling}}function x(a,b,d){var e,f;for(a?(I[Q]=b,I[P]=d):(I[R]=b,I[S]=d),e=I[R];e.parentNode;)e=e.parentNode;for(f=I[Q];f.parentNode;)f=f.parentNode;f==e?w(I[Q],I[P],I[R],I[S])>0&&I.collapse(a):I.collapse(a),I.collapsed=v(),I.commonAncestorCon
 tainer=c.findCommonAncestor(I[Q],I[R])}function y(a){var b,c,d,e,f,g,h,i=0,j=0;if(I[Q]==I[R])return z(a);for(b=I[R],c=b.parentNode;c;b=c,c=c.parentNode){if(c==I[Q])return A(b,a);++i}for(b=I[Q],c=b.parentNode;c;b=c,c=c.parentNode){if(c==I[R])return B(b,a);++j}for(d=j-i,e=I[Q];d>0;)e=e.parentNode,d--;for(f=I[R];d<0;)f=f.parentNode,d++;for(g=e.parentNode,h=f.parentNode;g!=h;g=g.parentNode,h=h.parentNode)e=g,f=h;return C(e,f,a)}function z(a){var b,c,e,f,g,h,i,j,k;if(a!=M&&(b=d()),I[P]==I[S])return b;if(3==I[Q].nodeType){if(c=I[Q].nodeValue,e=c.substring(I[P],I[S]),a!=L&&(f=I[Q],j=I[P],k=I[S]-I[P],0===j&&k>=f.nodeValue.length-1?f.parentNode.removeChild(f):f.deleteData(j,k),I.collapse(N)),a==M)return;return e.length>0&&b.appendChild(J.createTextNode(e)),b}for(f=u(I[Q],I[P]),g=I[S]-I[P];f&&g>0;)h=f.nextSibling,i=G(f,a),b&&b.appendChild(i),--g,f=h;return a!=L&&I.collapse(N),b}function A(a,b){var c,e,f,g,h,i;if(b!=M&&
 amp;(c=d()),e=D(a,b),c&&c.appendChild(e),f=U(a),g=f-I[P],g<=0)return b!=L&&(I.setEndBefore(a),I.collapse(O)),c;for(e=a.previousSibling;g>0;)h=e.previousSibling,i=G(e,b),c&&c.insertBefore(i,c.firstChild),--g,e=h;return b!=L&&(I.setEndBefore(a),I.collapse(O)),c}function B(a,b){var c,e,f,g,h,i;for(b!=M&&(c=d()),f=E(a,b),c&&c.appendChild(f),e=U(a),++e,g=I[S]-e,f=a.nextSibling;f&&g>0;)h=f.nextSibling,i=G(f,b),c&&c.appendChild(i),--g,f=h;return b!=L&&(I.setStartAfter(a),I.collapse(N)),c}function C(a,b,c){var e,f,g,h,i,j,k;for(c!=M&&(f=d()),e=E(a,c),f&&f.appendChild(e),g=U(a),h=U(b),++g,i=h-g,j=a.nextSibling;i>0;)k=j.nextSibling,e=G(j,c),f&&f.appendChild(e),j=k,--i;return e=D(b,c),f&&f.appendChild(e),c!=L&&(I.setStartAfter(a),I.collapse(N)),f}function D(a,b){var c,d,e,f,g,h=u(I[R],I[S]-1),i=h!=I[R];if(h==a)return F(h,i,O,b);for(c=h.parentNode,d=F(c,O,O,b);c;){for(;h;)
 e=h.previousSibling,f=F(h,i,O,b),b!=M&&d.insertBefore(f,d.firstChild),i=N,h=e;if(c==a)return d;h=c.previousSibling,c=c.parentNode,g=F(c,O,O,b),b!=M&&g.appendChild(d),d=g}}function E(a,b){var c,d,e,f,g,h=u(I[Q],I[P]),i=h!=I[Q];if(h==a)return F(h,i,N,b);for(c=h.parentNode,d=F(c,O,N,b);c;){for(;h;)e=h.nextSibling,f=F(h,i,N,b),b!=M&&d.appendChild(f),i=N,h=e;if(c==a)return d;h=c.nextSibling,c=c.parentNode,g=F(c,O,N,b),b!=M&&g.appendChild(d),d=g}}function F(a,b,d,e){var f,g,h,i,j;if(b)return G(a,e);if(3==a.nodeType){if(f=a.nodeValue,d?(i=I[P],g=f.substring(i),h=f.substring(0,i)):(i=I[S],g=f.substring(0,i),h=f.substring(i)),e!=L&&(a.nodeValue=h),e==M)return;return j=c.clone(a,O),j.nodeValue=g,j}if(e!=M)return c.clone(a,O)}function G(a,b){return b!=M?b==L?c.clone(a,N):a:void a.parentNode.removeChild(a)}function H(){return c.create("body",null,q()).outerText}var I=this,J=c.doc,K=0,L=1,M=2,N=!0,O=!1,P="startOffset",Q="startConta
 iner",R="endContainer",S="endOffset",T=a.extend,U=c.nodeIndex;return T(I,{startContainer:J,startOffset:0,endContainer:J,endOffset:0,collapsed:N,commonAncestorContainer:J,START_TO_START:0,START_TO_END:1,END_TO_END:2,END_TO_START:3,setStart:e,setEnd:f,setStartBefore:g,setStartAfter:h,setEndBefore:i,setEndAfter:j,collapse:k,selectNode:l,selectNodeContents:m,compareBoundaryPoints:n,deleteContents:o,extractContents:p,cloneContents:q,insertNode:r,surroundContents:s,cloneRange:t,toStringIE:H}),I}return b.prototype.toString=function(){return this.toStringIE()},b}),h("4r",Array),h("4s",Error),g("3t",["4r","4s"],function(a,b){var c=function(){},d=function(a,b){return function(){return a(b.apply(null,arguments))}},e=function(a){return function(){return a}},f=function(a){return a},g=function(a,b){return a===b},h=function(b){for(var c=new a(arguments.length-1),d=1;d<arguments.length;d++)c[d-1]=arguments[d];return funct
 ion(){for(var d=new a(arguments.length),e=0;e<d.length;e++)d[e]=arguments[e];var f=c.concat(d);return b.apply(null,f)}},i=function(a){return function(){return!a.apply(null,arguments)}},j=function(a){return function(){throw new b(a)}},k=function(a){return a()},l=function(a){a()},m=e(!1),n=e(!0);return{noop:c,compose:d,constant:e,identity:f,tripleEquals:g,curry:h,not:i,die:j,apply:k,call:l,never:m,always:n}}),h("5j",Object),g("4q",["3t","5j"],function(a,b){var c=a.never,d=a.always,e=function(){return f},f=function(){var f=function(a){return a.isNone()},g=function(a){return a()},h=function(a){return a},i=function(){},j={fold:function(a,b){return a()},is:c,isSome:c,isNone:d,getOr:h,getOrThunk:g,getOrDie:function(a){throw new Error(a||"error: getOrDie called on none.")},or:h,orThunk:g,map:e,ap:e,each:i,bind:e,flatten:e,exists:c,forall:d,filter:e,equals:f,equals_:f,toArray:function(){return[]},toString:a.constant("none()")};re
 turn b.freeze&&b.freeze(j),j}(),g=function(a){var b=function(){return a},h=function(){return k},i=function(b){return g(b(a))},j=function(b){return b(a)},k={fold:function(b,c){return c(a)},is:function(b){return a===b},isSome:d,isNone:c,getOr:b,getOrThunk:b,getOrDie:b,or:h,orThunk:h,map:i,ap:function(b){return b.fold(e,function(b){return g(b(a))})},each:function(b){b(a)},bind:j,flatten:b,exists:j,forall:j,filter:function(b){return b(a)?k:f},equals:function(b){return b.is(a)},equals_:function(b,d){return b.fold(c,function(b){return d(a,b)})},toArray:function(){return[a]},toString:function(){return"some("+a+")"}};return k},h=function(a){return null===a||void 0===a?f:g(a)};return{some:g,none:e,from:h}}),h("4t",String),g("3s",["4q","4r","4s","4t"],function(a,b,c,d){var e=function(){var a=b.prototype.indexOf,c=function(b,c){return a.call(b,c)},d=function(a,b){return u(a,b)};return void 0===a?d:c}(),f=fu
 nction(b,c){var d=e(b,c);return d===-1?a.none():a.some(d)},g=function(a,b){return e(a,b)>-1},h=function(a,b){return t(a,b).isSome()},i=function(a,b){for(var c=[],d=0;d<a;d++)c.push(b(d));return c},j=function(a,b){for(var c=[],d=0;d<a.length;d+=b){var e=a.slice(d,d+b);c.push(e)}return c},k=function(a,c){for(var d=a.length,e=new b(d),f=0;f<d;f++){var g=a[f];e[f]=c(g,f,a)}return e},l=function(a,b){for(var c=0,d=a.length;c<d;c++){var e=a[c];b(e,c,a)}},m=function(a,b){for(var c=a.length-1;c>=0;c--){var d=a[c];b(d,c,a)}},n=function(a,b){for(var c=[],d=[],e=0,f=a.length;e<f;e++){var g=a[e],h=b(g,e,a)?c:d;h.push(g)}return{pass:c,fail:d}},o=function(a,b){for(var c=[],d=0,e=a.length;d<e;d++){var f=a[d];b(f,d,a)&&c.push(f)}return c},p=function(a,b){if(0===a.length)return[];for(var c=b(a[0]),d=[],e=[],f=0,g=a.length;f<g;f++){var h=a[f],i=b(h);i!==c&&(d.push(e),e=[]),c=i,e.push(h)}return 0!==e.length&&d.push(e),d},q=function(a,b,c){return m(a,fu
 nction(a){c=b(c,a)}),c},r=function(a,b,c){return l(a,function(a){c=b(c,a)}),c},s=function(b,c){for(var d=0,e=b.length;d<e;d++){var f=b[d];if(c(f,d,b))return a.some(f)}return a.none()},t=function(b,c){for(var d=0,e=b.length;d<e;d++){var f=b[d];if(c(f,d,b))return a.some(d)}return a.none()},u=function(a,b){for(var c=0,d=a.length;c<d;++c)if(a[c]===b)return c;return-1},v=b.prototype.push,w=function(a){for(var d=[],e=0,f=a.length;e<f;++e){if(!b.prototype.isPrototypeOf(a[e]))throw new c("Arr.flatten item "+e+" was not an array, input: "+a);v.apply(d,a[e])}return d},x=function(a,b){var c=k(a,b);return w(c)},y=function(a,b){for(var c=0,d=a.length;c<d;++c){var e=a[c];if(b(e,c,a)!==!0)return!1}return!0},z=function(a,b){return a.length===b.length&&y(a,function(a,c){return a===b[c]})},A=b.prototype.slice,B=function(a){var b=A.call(a,0);return b.reverse(),b},C=function(a,b){return o(a,function(a){return!g(b,a)})},D=function(a,b){for(var c={},e=0,f=a.leng
 th;e<f;e++){var g=a[e];c[d(g)]=b(g,e)}return c},E=function(a){return[a]},F=function(a,b){var c=A.call(a,0);return c.sort(b),c};return{map:k,each:l,eachr:m,partition:n,filter:o,groupBy:p,indexOf:f,foldr:q,foldl:r,find:s,findIndex:t,flatten:w,bind:x,forall:y,exists:h,contains:g,equal:z,reverse:B,chunk:j,difference:C,mapToObject:D,pure:E,sort:F,range:i}}),h("5k",setTimeout),g("4u",["3s","4q","5k"],function(a,b,c){var d=function(e){var f=b.none(),g=[],h=function(a){return d(function(b){i(function(c){b(a(c))})})},i=function(a){k()?m(a):g.push(a)},j=function(a){f=b.some(a),l(g),g=[]},k=function(){return f.isSome()},l=function(b){a.each(b,m)},m=function(a){f.each(function(b){c(function(){a(b)},0)})};return e(j),{get:i,map:h,isReady:k}},e=function(a){return d(function(b){b(a)})};return{nu:d,pure:e}}),g("4v",["4r","5k"],function(a,b){var c=function(c){return function(){var d=a.prototype.slice.call(arguments),e
 =this;b(function(){c.apply(e,d)},0)}};return{bounce:c}}),g("3u",["4u","4v"],function(a,b){var c=function(d){var e=function(a){d(b.bounce(a))},f=function(a){return c(function(b){e(function(c){var d=a(c);b(d)})})},g=function(a){return c(function(b){e(function(c){a(c).get(b)})})},h=function(a){return c(function(b){e(function(c){a.get(b)})})},i=function(){return a.nu(e)};return{map:f,bind:g,anonBind:h,toLazy:i,get:e}},d=function(a){return c(function(b){b(a)})};return{nu:c,pure:d}}),g("4w",["3s"],function(a){var b=function(b,c){return c(function(c){var d=[],e=0,f=function(a){return function(f){d[a]=f,e++,e>=b.length&&c(d)}};0===b.length?c([]):a.each(b,function(a,b){a.get(f(b))})})};return{par:b}}),g("3v",["3s","3u","4w"],function(a,b,c){var d=function(a){return c.par(a,b.nu)},e=function(b,c){var e=a.map(b,c);return d(e)},f=function(a,b){return function(c){return b(c).bind(a)}};return{par:
 d,mapM:e,compose:f}}),g("3w",["3t","4q"],function(a,b){var c=function(d){var e=function(a){return d===a},f=function(a){return c(d)},g=function(a){return c(d)},h=function(a){return c(a(d))},i=function(a){a(d)},j=function(a){return a(d)},k=function(a,b){return b(d)},l=function(a){return a(d)},m=function(a){return a(d)},n=function(){return b.some(d)};return{is:e,isValue:a.constant(!0),isError:a.constant(!1),getOr:a.constant(d),getOrThunk:a.constant(d),getOrDie:a.constant(d),or:f,orThunk:g,fold:k,map:h,each:i,bind:j,exists:l,forall:m,toOption:n}},d=function(c){var e=function(a){return a()},f=function(){return a.die(c)()},g=function(a){return a},h=function(a){return a()},i=function(a){return d(c)},j=function(a){return d(c)},k=function(a,b){return a(c)};return{is:a.constant(!1),isValue:a.constant(!1),isError:a.constant(!0),getOr:a.identity,getOrThunk:e,getOrDie:f,or:g,orThunk:h,fold:k,map:i,each:a.noop,bind:j,exists:a.constant(!1),forall:a.constant(!0),toOpti
 on:b.none}};return{value:c,error:d}}),g("1i",["3s","3t","3u","3v","3w","5","9"],function(a,b,c,d,e,f,g){"use strict";return function(h,i){function j(a){h.getElementsByTagName("head")[0].appendChild(a)}function k(a,b,c){function d(){for(var a=t.passed,b=a.length;b--;)a[b]();t.status=2,t.passed=[],t.failed=[]}function e(){for(var a=t.failed,b=a.length;b--;)a[b]();t.status=3,t.passed=[],t.failed=[]}function i(){var a=navigator.userAgent.match(/WebKit\/(\d*)/);return!!(a&&a[1]<536)}function k(a,b){a()||((new Date).getTime()-s<l?f.setTimeout(b):e())}function o(){k(function(){for(var a,b,c=h.styleSheets,e=c.length;e--;)if(a=c[e],b=a.ownerNode?a.ownerNode:a.owningElement,b&&b.id===q.id)return d(),!0},o)}function p(){k(function(){try{var a=r.sheet.cssRules;return d(),!!a}catch(a){}},p)}var q,r,s,t;if(a=g._addCacheSuffix(a),n[a]?t=n[a]:(t={passed:[],failed:[]},n[a]=t),b&a
 mp;&t.passed.push(b),c&&t.failed.push(c),1!=t.status){if(2==t.status)return void d();if(3==t.status)return void e();if(t.status=1,q=h.createElement("link"),q.rel="stylesheet",q.type="text/css",q.id="u"+m++,q.async=!1,q.defer=!1,s=(new Date).getTime(),"onload"in q&&!i())q.onload=o,q.onerror=e;else{if(navigator.userAgent.indexOf("Firefox")>0)return r=h.createElement("style"),
-r.textContent='@import "'+a+'"',p(),void j(r);o()}j(q),q.href=a}}var l,m=0,n={};i=i||{},l=i.maxLoadTime||5e3;var o=function(a){return c.nu(function(c){k(a,b.compose(c,b.constant(e.value(a))),b.compose(c,b.constant(e.error(a))))})},p=function(a){return a.fold(b.identity,b.identity)},q=function(b,c,e){d.par(a.map(b,o)).get(function(b){var d=a.partition(b,function(a){return a.isValue()});d.fail.length>0?e(d.fail.map(p)):c(d.pass.map(p))})};return{load:k,loadAll:q}}}),g("j",["9"],function(a){function b(b,c){return b=a.trim(b),b?b.split(c||" "):[]}function c(a){function c(a,c,d){function e(a,b){var c,d,e={};for(c=0,d=a.length;c<d;c++)e[a[c]]=b||{};return e}var h,i,j;for(d=d||[],c=c||"","string"==typeof d&&(d=b(d)),a=b(a),h=a.length;h--;)i=b([g,c].join(" ")),j={attributes:e(i),attributesOrder:i,children:e(d,f)},n[a[h]]=j}function d(a,c){var d,e,f,g;for(a=b(a),d=a.length,c=b(c);d--;)for(e=n[a[d]],f=0,g=c.le
 ngth;f<g;f++)e.attributes[c[f]]={},e.attributesOrder.push(c[f])}var g,i,j,k,l,m,n={};return e[a]?e[a]:(g="id accesskey class dir lang style tabindex title role",i="address blockquote div dl fieldset form h1 h2 h3 h4 h5 h6 hr menu ol p pre table ul",j="a abbr b bdo br button cite code del dfn em embed i iframe img input ins kbd label map noscript object q s samp script select small span strong sub sup textarea u var #text #comment","html4"!=a&&(g+=" contenteditable contextmenu draggable dropzone hidden spellcheck translate",i+=" article aside details dialog figure header footer hgroup section nav",j+=" audio canvas command datalist mark meter output picture progress time wbr video ruby bdi keygen"),"html5-strict"!=a&&(g+=" xml:lang",m="acronym applet basefont big font strike tt",j=[j,m].join(" "),h(b(m),function(a){c(a,"",j)}),l="center dir i
 sindex noframes",i=[i,l].join(" "),k=[i,j].join(" "),h(b(l),function(a){c(a,"",k)})),k=k||[i,j].join(" "),c("html","manifest","head body"),c("head","","base command link meta noscript script style title"),c("title hr noscript br"),c("base","href target"),c("link","href rel media hreflang type sizes hreflang"),c("meta","name http-equiv content charset"),c("style","media type scoped"),c("script","src async defer type charset"),c("body","onafterprint onbeforeprint onbeforeunload onblur onerror onfocus onhashchange onload onmessage onoffline ononline onpagehide onpageshow onpopstate onresize onscroll onstorage onunload",k),c("address dt dd div caption","",k),c("h1 h2 h3 h4 h5 h6 pre p abbr code var samp kbd sub sup i b u bdo span l
 egend em strong small s cite dfn","",j),c("blockquote","cite",k),c("ol","reversed start type","li"),c("ul","","li"),c("li","value",k),c("dl","","dt dd"),c("a","href target rel media hreflang type",j),c("q","cite",j),c("ins del","cite datetime",k),c("img","src sizes srcset alt usemap ismap width height"),c("iframe","src name width height",k),c("embed","src type width height"),c("object","data type typemustmatch name usemap form width height",[k,"param"].join(" ")),c("param","name value"),c("map","name",[k,"area"].join(" ")),c("area","alt coords shape href target rel media hreflang type"),c("table&quot
 ;,"border","caption colgroup thead tfoot tbody tr"+("html4"==a?" col":"")),c("colgroup","span","col"),c("col","span"),c("tbody thead tfoot","","tr"),c("tr","","td th"),c("td","colspan rowspan headers",k),c("th","colspan rowspan headers scope abbr",k),c("form","accept-charset action autocomplete enctype method name novalidate target",k),c("fieldset","disabled form name",[k,"legend"].join(" ")),c("label","form for",j),c("input","accept alt autocomplete checked dirname disabled form formaction formenctype formmethod formnovalidate formtarget height list max maxlength min multiple name pattern readonly required size src step type value width"),c("button","disabled form formacti
 on formenctype formmethod formnovalidate formtarget name type value","html4"==a?k:j),c("select","disabled form multiple name required size","option optgroup"),c("optgroup","disabled label","option"),c("option","disabled label selected value"),c("textarea","cols dirname disabled form maxlength name readonly required rows wrap"),c("menu","type label",[k,"li"].join(" ")),c("noscript","",k),"html4"!=a&&(c("wbr"),c("ruby","",[j,"rt rp"].join(" ")),c("figcaption","",k),c("mark rt rp summary bdi","",j),c("canvas","width height",k),c("video","src crossorigin poster preload autoplay mediagroup loop muted controls width height buffered",[k,"track source"].join(&quot
 ; ")),c("audio","src crossorigin preload autoplay mediagroup loop muted controls buffered volume",[k,"track source"].join(" ")),c("picture","","img source"),c("source","src srcset type media sizes"),c("track","kind src srclang label default"),c("datalist","",[j,"option"].join(" ")),c("article section nav aside header footer","",k),c("hgroup","","h1 h2 h3 h4 h5 h6"),c("figure","",[k,"figcaption"].join(" ")),c("time","datetime",j),c("dialog","open",k),c("command","type label icon disabled checked radiogroup command"),c("output","for form name",j),c("progress","value max",j),c("meter","value min max low high optimum",j),c(&quot
 ;details","open",[k,"summary"].join(" ")),c("keygen","autofocus challenge disabled form keytype name")),"html5-strict"!=a&&(d("script","language xml:space"),d("style","xml:space"),d("object","declare classid code codebase codetype archive standby align border hspace vspace"),d("embed","align name hspace vspace"),d("param","valuetype type"),d("a","charset name rev shape coords"),d("br","clear"),d("applet","codebase archive code object alt name width height align hspace vspace"),d("img","name longdesc align border hspace vspace"),d("iframe","longdesc frameborder marginwidth marginheight scrolling align"),d("font basefont","size color face"),d("input","usemap align"),d("sel
 ect","onchange"),d("textarea"),d("h1 h2 h3 h4 h5 h6 div p legend caption","align"),d("ul","type compact"),d("li","type"),d("ol dl menu dir","compact"),d("pre","width xml:space"),d("hr","align noshade size width"),d("isindex","prompt"),d("table","summary width frame rules cellspacing cellpadding align bgcolor"),d("col","width align char charoff valign"),d("colgroup","width align char charoff valign"),d("thead","align char charoff valign"),d("tr","align char charoff valign bgcolor"),d("th","axis align char charoff valign nowrap bgcolor width height"),d("form","accept"),d("td","abbr axis scope align char charoff valign nowrap bgcolor width height"),d("tfoot&quot
 ;,"align char charoff valign"),d("tbody","align char charoff valign"),d("area","nohref"),d("body","background bgcolor text link vlink alink")),"html4"!=a&&(d("input button select textarea","autofocus"),d("input textarea","placeholder"),d("a","download"),d("link script img","crossorigin"),d("iframe","sandbox seamless allowfullscreen")),h(b("a form meter progress dfn"),function(a){n[a]&&delete n[a].children[a]}),delete n.caption.children.table,delete n.script,e[a]=n,n)}function d(a,b){var c;return a&&(c={},"string"==typeof a&&(a={"*":a}),h(a,function(a,d){c[d]=c[d.toUpperCase()]="map"==b?g(a,/[, ]/):j(a,/[, ]/)})),c}var e={},f={},g=a.makeMap,h=a.each,i=a.extend,j=a.explode,k=a.inArray;return function(a){function f(b,c,d){var f=a[b];retur
 n f?f=g(f,/[, ]/,g(f.toUpperCase(),/[, ]/)):(f=e[b],f||(f=g(c," ",g(c.toUpperCase()," ")),f=i(f,d),e[b]=f)),f}function l(a){return new RegExp("^"+a.replace(/([?+*])/g,".$1")+"$")}function m(a){var c,d,e,f,h,i,j,m,n,o,p,q,r,s,t,u,v,w,x,y=/^([#+\-])?([^\[!\/]+)(?:\/([^\[!]+))?(?:(!?)\[([^\]]+)\])?$/,z=/^([!\-])?(\w+::\w+|[^=:<]+)?(?:([=:<])(.*))?$/,A=/[*?+]/;if(a)for(a=b(a,","),F["@"]&&(u=F["@"].attributes,v=F["@"].attributesOrder),c=0,d=a.length;c<d;c++)if(h=y.exec(a[c])){if(s=h[1],n=h[2],t=h[3],m=h[5],q={},r=[],i={attributes:q,attributesOrder:r},"#"===s&&(i.paddEmpty=!0),"-"===s&&(i.removeEmpty=!0),"!"===h[4]&&(i.removeEmptyAttrs=!0),u){for(w in u)q[w]=u[w];r.push.apply(r,v)}if(m)for(m=b(m,"|"),e=0,f=m.length;e<f;e++)if(h=z.exec(m[e])){if(j={},p=h[1],o=h[2].replace(/::/g,":"),s=h[3],x=h[4],"!&quot
 ;===p&&(i.attributesRequired=i.attributesRequired||[],i.attributesRequired.push(o),j.required=!0),"-"===p){delete q[o],r.splice(k(r,o),1);continue}s&&("="===s&&(i.attributesDefault=i.attributesDefault||[],i.attributesDefault.push({name:o,value:x}),j.defaultValue=x),":"===s&&(i.attributesForced=i.attributesForced||[],i.attributesForced.push({name:o,value:x}),j.forcedValue=x),"<"===s&&(j.validValues=g(x,"?"))),A.test(o)?(i.attributePatterns=i.attributePatterns||[],j.pattern=l(o),i.attributePatterns.push(j)):(q[o]||r.push(o),q[o]=j)}u||"@"!=n||(u=q,v=r),t&&(i.outputName=n,F[t]=i),A.test(n)?(i.pattern=l(n),H.push(i)):F[n]=i}}function n(a){F={},H=[],m(a),h(t,function(a,b){G[b]=a.children})}function o(a){var c=/^(~)?(.+)$/;a&&(e.text_block_elements=e.block_elements=null,h(b(a,","),function(a){var b=c.exec(a),d="~"===b[1],e=d?"span":"div&
 quot;,f=b[2];if(G[f]=G[e],I[f]=e,d||(z[f.toUpperCase()]={},z[f]={}),!F[f]){var g=F[e];g=i({},g),delete g.removeEmptyAttrs,delete g.removeEmpty,F[f]=g}h(G,function(a,b){a[e]&&(G[b]=a=i({},G[b]),a[f]=a[e])})}))}function p(c){var d=/^([+\-]?)(\w+)\[([^\]]+)\]$/;e[a.schema]=null,c&&h(b(c,","),function(a){var c,e,f=d.exec(a);f&&(e=f[1],c=e?G[f[2]]:G[f[2]]={"#comment":{}},c=G[f[2]],h(b(f[3],"|"),function(a){"-"===e?delete c[a]:c[a]={}}))})}function q(a){var b,c=F[a];if(c)return c;for(b=H.length;b--;)if(c=H[b],c.pattern.test(a))return c}var r,s,t,u,v,w,x,y,z,A,B,C,D,E=this,F={},G={},H=[],I={},J={};a=a||{},t=c(a.schema),a.verify_html===!1&&(a.valid_elements="*[*]"),r=d(a.valid_styles),s=d(a.invalid_styles,"map"),y=d(a.valid_classes,"map"),u=f("whitespace_elements","pre script noscript style textarea video audio iframe object code"),v=f("self_closing_elements",&
 quot;colgroup dd dt li option p td tfoot th thead tr"),w=f("short_ended_elements","area base basefont br col frame hr img input isindex link meta param embed source wbr track"),x=f("boolean_attributes","checked compact declare defer disabled ismap multiple nohref noresize noshade nowrap readonly selected autoplay loop controls"),A=f("non_empty_elements","td th iframe video audio object script pre code",w),B=f("move_caret_before_on_enter_elements","table",A),C=f("text_block_elements","h1 h2 h3 h4 h5 h6 p div address pre form blockquote center dir fieldset header footer article section hgroup aside nav figure"),z=f("block_elements","hr table tbody thead tfoot th tr td li ol ul caption dl dt dd noscript menu isindex option datalist select optgroup figcaption",C),D=f("text_inline_elements","span strong b em i font strike u var cite dfn code mark q s
 up sub samp"),h((a.special||"script noscript style textarea").split(" "),function(a){J[a]=new RegExp("</"+a+"[^>]*>","gi")}),a.valid_elements?n(a.valid_elements):(h(t,function(a,b){F[b]={attributes:a.attributes,attributesOrder:a.attributesOrder},G[b]=a.children}),"html5"!=a.schema&&h(b("strong/b em/i"),function(a){a=b(a,"/"),F[a[1]].outputName=a[0]}),h(b("ol ul sub sup blockquote span font a table tbody tr strong em b i"),function(a){F[a]&&(F[a].removeEmpty=!0)}),h(b("p h1 h2 h3 h4 h5 h6 th td pre div address caption"),function(a){F[a].paddEmpty=!0}),h(b("span"),function(a){F[a].removeEmptyAttrs=!0})),o(a.custom_elements),p(a.valid_children),m(a.extended_valid_elements),p("+ol[ul|ol],+ul[ul|ol]"),h({dd:"dl",dt:"dl",li:"ul ol",td:"tr",th:"tr",tr:"tbody thead tfoot",tbody:"
 table",thead:"table",tfoot:"table",legend:"fieldset",area:"map",param:"video audio object"},function(a,c){F[c]&&(F[c].parentsRequired=b(a))}),a.invalid_elements&&h(j(a.invalid_elements),function(a){F[a]&&delete F[a]}),q("span")||m("span[!data-mce-type|*]"),E.children=G,E.getValidStyles=function(){return r},E.getInvalidStyles=function(){return s},E.getValidClasses=function(){return y},E.getBoolAttrs=function(){return x},E.getBlockElements=function(){return z},E.getTextBlockElements=function(){return C},E.getTextInlineElements=function(){return D},E.getShortEndedElements=function(){return w},E.getSelfClosingElements=function(){return v},E.getNonEmptyElements=function(){return A},E.getMoveCaretBeforeOnEnterElements=function(){return B},E.getWhiteSpaceElements=function(){return u},E.getSpecialElements=function(){return J},E.isValidChild=function(a,b){var c=G[a.toLowerCase()];return!(!c||!c
 [b.toLowerCase()])},E.isValid=function(a,b){var c,d,e=q(a);if(e){if(!b)return!0;if(e.attributes[b])return!0;if(c=e.attributePatterns)for(d=c.length;d--;)if(c[d].pattern.test(a))return!0}return!1},E.getElementRule=q,E.getCustomElements=function(){return I},E.addValidElements=m,E.setValidElements=n,E.addCustomElements=o,E.addValidChildren=p,E.elements=F}}),g("e",["a","7","1h","8","1i","c","6","d","j","b","9"],function(a,b,c,d,e,f,g,h,i,j,k){function l(a,b){var c,d={},e=b.keep_values;return c={set:function(c,d,e){b.url_converter&&(d=b.url_converter.call(b.url_converter_scope||a,d,e,c[0])),c.attr("data-mce-"+e,d).attr(e,d)},get:function(a,b){return a.attr("data-mce-"+b)||a.attr(b)}},d={style:{set:function(a,b){return null!==b&&"object"==typeof b?void a.css(b):(e&&a.attr("data-mce-style",b),void a.attr(&quo
 t;style",b))},get:function(b){var c=b.attr("data-mce-style")||b.attr("style");return c=a.serializeStyle(a.parseStyle(c),b[0].nodeName)}}},e&&(d.href=d.src=c),d}function m(a,b){var c=b.attr("style");c=a.serializeStyle(a.parseStyle(c),b[0].nodeName),c||(c=null),b.attr("data-mce-style",c)}function n(a,b){var c,d,e=0;if(a)for(c=a.nodeType,a=a.previousSibling;a;a=a.previousSibling)d=a.nodeType,(!b||3!=d||d!=c&&a.nodeValue.length)&&(e++,c=d);return e}function o(c,d){var f,g=this;g.doc=c,g.win=window,g.files={},g.counter=0,g.stdMode=!t||c.documentMode>=8,g.boxModel=!t||"CSS1Compat"==c.compatMode||g.stdMode,g.styleSheetLoader=new e(c),g.boundEvents=[],g.settings=d=d||{},g.schema=d.schema?d.schema:new i({}),g.styles=new j({url_converter:d.url_converter,url_converter_scope:d.url_converter_scope},d.schema),g.fixDoc(c),g.events=d.ownEvents?new b(d.proxy):b.Event,g.attrHooks=l(g,d),f=d.schema?d.schema.getBlockEleme
 nts():{},g.$=a.overrideDefaults(function(){return{context:c,element:g.getRoot()}}),g.isBlock=function(a){if(!a)return!1;var b=a.nodeType;return b?!(1!==b||!f[a.nodeName]):!!f[a]}}var p=k.each,q=k.is,r=k.grep,s=k.trim,t=g.ie,u=/^([a-z0-9],?)+$/i,v=/^[ \t\r\n]*$/;return o.prototype={$$:function(a){return"string"==typeof a&&(a=this.get(a)),this.$(a)},root:null,fixDoc:function(a){var b,c=this.settings;if(t&&c.schema){"abbr article aside audio canvas details figcaption figure footer header hgroup mark menu meter nav output progress section summary time video".replace(/\w+/g,function(b){a.createElement(b)});for(b in c.schema.getCustomElements())a.createElement(b)}},clone:function(a,b){var c,d,e=this;return!t||1!==a.nodeType||b?a.cloneNode(b):(d=e.doc,b?c.firstChild:(c=d.createElement(a.nodeName),p(e.getAttribs(a),function(b){e.setAttrib(c,b.nodeName,e.getAttrib(a,b.nodeName))}),c))},getRoot:function(){var a=this;return a.settings.root_element||a.doc.bod
 y},getViewPort:function(a){var b,c;return a=a?a:this.win,b=a.document,c=this.boxModel?b.documentElement:b.body,{x:a.pageXOffset||c.scrollLeft,y:a.pageYOffset||c.scrollTop,w:a.innerWidth||c.clientWidth,h:a.innerHeight||c.clientHeight}},getRect:function(a){var b,c,d=this;return a=d.get(a),b=d.getPos(a),c=d.getSize(a),{x:b.x,y:b.y,w:c.w,h:c.h}},getSize:function(a){var b,c,d=this;return a=d.get(a),b=d.getStyle(a,"width"),c=d.getStyle(a,"height"),b.indexOf("px")===-1&&(b=0),c.indexOf("px")===-1&&(c=0),{w:parseInt(b,10)||a.offsetWidth||a.clientWidth,h:parseInt(c,10)||a.offsetHeight||a.clientHeight}},getParent:function(a,b,c){return this.getParents(a,b,c,!1)},getParents:function(a,b,c,d){var e,f=this,g=[];for(a=f.get(a),d=void 0===d,c=c||("BODY"!=f.getRoot().nodeName?f.getRoot().parentNode:null),q(b,"string")&&(e=b,b="*"===b?function(a){return 1==a.nodeType}:function(a){return f.is(a,e)});a&&a
 mp;a!=c&&a.nodeType&&9!==a.nodeType;){if(!b||b(a)){if(!d)return a;g.push(a)}a=a.parentNode}return d?g:null},get:function(a){var b;return a&&this.doc&&"string"==typeof a&&(b=a,a=this.doc.getElementById(a),a&&a.id!==b)?this.doc.getElementsByName(b)[1]:a},getNext:function(a,b){return this._findSib(a,b,"nextSibling")},getPrev:function(a,b){return this._findSib(a,b,"previousSibling")},select:function(a,b){var c=this;return d(a,c.get(b)||c.settings.root_element||c.doc,[])},is:function(a,b){var c;if(!a)return!1;if(void 0===a.length){if("*"===b)return 1==a.nodeType;if(u.test(b)){for(b=b.toLowerCase().split(/,/),a=a.nodeName.toLowerCase(),c=b.length-1;c>=0;c--)if(b[c]==a)return!0;return!1}}if(a.nodeType&&1!=a.nodeType)return!1;var e=a.nodeType?[a]:a;return d(b,e[0].ownerDocument||e[0],null,e).length>0},add:function(a,b,c,d,e){var f=this;return this.run(a,function(a){var g;return g=q(b,"
 string")?f.doc.createElement(b):b,f.setAttribs(g,c),d&&(d.nodeType?g.appendChild(d):f.setHTML(g,d)),e?g:a.appendChild(g)})},create:function(a,b,c){return this.add(this.doc.createElement(a),a,b,c,1)},createHTML:function(a,b,c){var d,e="";e+="<"+a;for(d in b)b.hasOwnProperty(d)&&null!==b[d]&&"undefined"!=typeof b[d]&&(e+=" "+d+'="'+this.encode(b[d])+'"');return"undefined"!=typeof c?e+">"+c+"</"+a+">":e+" />"},createFragment:function(a){var b,c,d,e=this.doc;for(d=e.createElement("div"),b=e.createDocumentFragment(),a&&(d.innerHTML=a);c=d.firstChild;)b.appendChild(c);return b},remove:function(a,b){return a=this.$$(a),b?a.each(function(){for(var a;a=this.firstChild;)3==a.nodeType&&0===a.data.length?this.removeChild(a):this.parentNode.insertBefore(a,this)}).remove():a.remove(),a.length>1?a.toArray():a[0]},setSty
 le:function(a,b,c){a=this.$$(a).css(b,c),this.settings.update_styles&&m(this,a)},getStyle:function(a,b,c){return a=this.$$(a),c?a.css(b):(b=b.replace(/-(\D)/g,function(a,b){return b.toUpperCase()}),"float"==b&&(b=g.ie&&g.ie<12?"styleFloat":"cssFloat"),a[0]&&a[0].style?a[0].style[b]:void 0)},setStyles:function(a,b){a=this.$$(a).css(b),this.settings.update_styles&&m(this,a)},removeAllAttribs:function(a){return this.run(a,function(a){var b,c=a.attributes;for(b=c.length-1;b>=0;b--)a.removeAttributeNode(c.item(b))})},setAttrib:function(a,b,c){var d,e,f=this,g=f.settings;""===c&&(c=null),a=f.$$(a),d=a.attr(b),a.length&&(e=f.attrHooks[b],e&&e.set?e.set(a,c,b):a.attr(b,c),d!=c&&g.onSetAttrib&&g.onSetAttrib({attrElm:a,attrName:b,attrValue:c}))},setAttribs:function(a,b){var c=this;c.$$(a).each(function(a,d){p(b,function(a,b){c.setAttrib(d,b,a)})})},getAttrib:function(a
 ,b,c){var d,e,f=this;return a=f.$$(a),a.length&&(d=f.attrHooks[b],e=d&&d.get?d.get(a,b):a.attr(b)),"undefined"==typeof e&&(e=c||""),e},getPos:function(b,c){var d,e,f=this,g=0,h=0,i=f.doc,j=i.body;if(b=f.get(b),c=c||j,b){if(c===j&&b.getBoundingClientRect&&"static"===a(j).css("position"))return e=b.getBoundingClientRect(),c=f.boxModel?i.documentElement:j,g=e.left+(i.documentElement.scrollLeft||j.scrollLeft)-c.clientLeft,h=e.top+(i.documentElement.scrollTop||j.scrollTop)-c.clientTop,{x:g,y:h};for(d=b;d&&d!=c&&d.nodeType;)g+=d.offsetLeft||0,h+=d.offsetTop||0,d=d.offsetParent;for(d=b.parentNode;d&&d!=c&&d.nodeType;)g-=d.scrollLeft||0,h-=d.scrollTop||0,d=d.parentNode}return{x:g,y:h}},parseStyle:function(a){return this.styles.parse(a)},serializeStyle:function(a,b){return this.styles.serialize(a,b)},addStyle:function(a){var b,c,d=this,e=d.doc;if(d!==o.DOM&&e===document){va
 r f=o.DOM.addedStyles;if(f=f||[],f[a])return;f[a]=!0,o.DOM.addedStyles=f}c=e.getElementById("mceDefaultStyles"),c||(c=e.createElement("style"),c.id="mceDefaultStyles",c.type="text/css",b=e.getElementsByTagName("head")[0],b.firstChild?b.insertBefore(c,b.firstChild):b.appendChild(c)),c.styleSheet?c.styleSheet.cssText+=a:c.appendChild(e.createTextNode(a))},loadCSS:function(a){var b,c=this,d=c.doc;return c!==o.DOM&&d===document?void o.DOM.loadCSS(a):(a||(a=""),b=d.getElementsByTagName("head")[0],void p(a.split(","),function(a){var e;a=k._addCacheSuffix(a),c.files[a]||(c.files[a]=!0,e=c.create("link",{rel:"stylesheet",href:a}),t&&d.documentMode&&d.recalc&&(e.onload=function(){d.recalc&&d.recalc(),e.onload=null}),b.appendChild(e))}))},addClass:function(a,b){this.$$(a).addClass(b)},removeClass:function(a,b){this.toggleClass(a,b,!1)},hasClass:function(a
 ,b){return this.$$(a).hasClass(b)},toggleClass:function(b,c,d){this.$$(b).toggleClass(c,d).each(function(){""===this.className&&a(this).attr("class",null)})},show:function(a){this.$$(a).show()},hide:function(a){this.$$(a).hide()},isHidden:function(a){return"none"==this.$$(a).css("display")},uniqueId:function(a){return(a?a:"mce_")+this.counter++},setHTML:function(b,c){b=this.$$(b),t?b.each(function(b,d){if(d.canHaveHTML!==!1){for(;d.firstChild;)d.removeChild(d.firstChild);try{d.innerHTML="<br>"+c,d.removeChild(d.firstChild)}catch(b){a("<div></div>").html("<br>"+c).contents().slice(1).appendTo(d)}return c}}):b.html(c)},getOuterHTML:function(b){return b=this.get(b),1==b.nodeType&&"outerHTML"in b?b.outerHTML:a("<div></div>").append(a(b).clone()).html()},setOuterHTML:function(b,c){var d=this;d.$$(b).each(function(){try{if("outerHTML&
 quot;in this)return void(this.outerHTML=c)}catch(a){}d.remove(a(this).html(c),!0)})},decode:h.decode,encode:h.encodeAllRaw,insertAfter:function(a,b){return b=this.get(b),this.run(a,function(a){var c,d;return c=b.parentNode,d=b.nextSibling,d?c.insertBefore(a,d):c.appendChild(a),a})},replace:function(a,b,c){var d=this;return d.run(b,function(b){return q(b,"array")&&(a=a.cloneNode(!0)),c&&p(r(b.childNodes),function(b){a.appendChild(b)}),b.parentNode.replaceChild(a,b)})},rename:function(a,b){var c,d=this;return a.nodeName!=b.toUpperCase()&&(c=d.create(b),p(d.getAttribs(a),function(b){d.setAttrib(c,b.nodeName,d.getAttrib(a,b.nodeName))}),d.replace(c,a,1)),c||a},findCommonAncestor:function(a,b){for(var c,d=a;d;){for(c=b;c&&d!=c;)c=c.parentNode;if(d==c)break;d=d.parentNode}return!d&&a.ownerDocument?a.ownerDocument.documentElement:d},toHex:function(a){return this.styles.toHex(k.trim(a))},run:function(a,b,c){var d,e=this;return"string&qu
 ot;==typeof a&&(a=e.get(a)),!!a&&(c=c||this,a.nodeType||!a.length&&0!==a.length?b.call(c,a):(d=[],p(a,function(a,f){a&&("string"==typeof a&&(a=e.get(a)),d.push(b.call(c,a,f)))}),d))},getAttribs:function(a){var b;if(a=this.get(a),!a)return[];if(t){if(b=[],"OBJECT"==a.nodeName)return a.attributes;"OPTION"===a.nodeName&&this.getAttrib(a,"selected")&&b.push({specified:1,nodeName:"selected"});var c=/<\/?[\w:\-]+ ?|=[\"][^\"]+\"|=\'[^\']+\'|=[\w\-]+|>/gi;return a.cloneNode(!1).outerHTML.replace(c,"").replace(/[\w:\-]+/gi,function(a){b.push({specified:1,nodeName:a})}),b}return a.attributes},isEmpty:function(a,b){var c,d,e,g,h,i,j=this,k=0;if(a=a.firstChild){h=new f(a,a.parentNode),b=b||(j.schema?j.schema.getNonEmptyElements():null),g=j.schema?j.schema.getWhiteSpaceElements():{};do{if(e=a.nodeType,1===e){var l=a.getAttribute("data-mce-bogus");if(
 l){a=h.next("all"===l);continue}if(i=a.nodeName.toLowerCase(),b&&b[i]){if("br"===i){k++,a=h.next();continue}return!1}for(d=j.getAttribs(a),c=d.length;c--;)if(i=d[c].nodeName,"name"===i||"data-mce-bookmark"===i)return!1}if(8==e)return!1;if(3===e&&!v.test(a.nodeValue))return!1;if(3===e&&a.parentNode&&g[a.parentNode.nodeName]&&v.test(a.nodeValue))return!1;a=h.next()}while(a)}return k<=1},createRng:function(){var a=this.doc;return a.createRange?a.createRange():new c(this)},nodeIndex:n,split:function(a,b,c){function d(a){function b(a){var b=a.previousSibling&&"SPAN"==a.previousSibling.nodeName,c=a.nextSibling&&"SPAN"==a.nextSibling.nodeName;return b&&c}var c,e=a.childNodes,f=a.nodeType;if(1!=f||"bookmark"!=a.getAttribute("data-mce-type")){for(c=e.length-1;c>=0;c--)d(e[c]);if(9!=f){if(3==f&&a.nodeValue.length>0){var g=s(a.nodeValu
 e).length;if(!h.isBlock(a.parentNode)||g>0||0===g&&b(a))return}else if(1==f&&(e=a.childNodes,1==e.length&&e[0]&&1==e[0].nodeType&&"bookmark"==e[0].getAttribute("data-mce-type")&&a.parentNode.insertBefore(e[0],a),e.length||/^(br|hr|input|img)$/i.test(a.nodeName)))return;h.remove(a)}return a}}var e,f,g,h=this,i=h.createRng();if(a&&b)return i.setStart(a.parentNode,h.nodeIndex(a)),i.setEnd(b.parentNode,h.nodeIndex(b)),e=i.extractContents(),i=h.createRng(),i.setStart(b.parentNode,h.nodeIndex(b)+1),i.setEnd(a.parentNode,h.nodeIndex(a)+1),f=i.extractContents(),g=a.parentNode,g.insertBefore(d(e),a),c?g.insertBefore(c,a):g.insertBefore(b,a),g.insertBefore(d(f),a),h.remove(a),c||b},bind:function(a,b,c,d){var e=this;if(k.isArray(a)){for(var f=a.length;f--;)a[f]=e.bind(a[f],b,c,d);return a}return!e.settings.collect||a!==e.doc&&a!==e.win||e.boundEvents.push([a,b,c,d]),e.events.bind(a,b,c,d||e)},unbind:function
 (a,b,c){var d,e=this;if(k.isArray(a)){for(d=a.length;d--;)a[d]=e.unbind(a[d],b,c);return a}if(e.boundEvents&&(a===e.doc||a===e.win))for(d=e.boundEvents.length;d--;){var f=e.boundEvents[d];a!=f[0]||b&&b!=f[1]||c&&c!=f[2]||this.events.unbind(f[0],f[1],f[2])}return this.events.unbind(a,b,c)},fire:function(a,b,c){return this.events.fire(a,b,c)},getContentEditable:function(a){var b;return a&&1==a.nodeType?(b=a.getAttribute("data-mce-contenteditable"),b&&"inherit"!==b?b:"inherit"!==a.contentEditable?a.contentEditable:null):null},getContentEditableParent:function(a){for(var b=this.getRoot(),c=null;a&&a!==b&&(c=this.getContentEditable(a),null===c);a=a.parentNode);return c},destroy:function(){var a=this;if(a.boundEvents){for(var b=a.boundEvents.length;b--;){var c=a.boundEvents[b];this.events.unbind(c[0],c[1],c[2])}a.boundEvents=null}d.setDocument&&d.setDocument(),a.win=a.doc=a.root=a.events=a.frag=n
 ull},isChildOf:function(a,b){for(;a;){if(b===a)return!0;a=a.parentNode}return!1},dumpRng:function(a){return"startContainer: "+a.startContainer.nodeName+", startOffset: "+a.startOffset+", endContainer: "+a.endContainer.nodeName+", endOffset: "+a.endOffset},_findSib:function(a,b,c){var d=this,e=b;if(a)for("string"==typeof e&&(e=function(a){return d.is(a,b)}),a=a[c];a;a=a[c])if(e(a))return a;return null}},o.DOM=new o(document),o.nodeIndex=n,o}),g("f",["e","9"],function(a,b){function c(){function a(a,c,e){function f(){k.remove(j),i&&(i.onreadystatechange=i.onload=i=null),c()}function h(){g(e)?e():"undefined"!=typeof console&&console.log&&console.log("Failed to load script: "+a)}var i,j,k=d;j=k.uniqueId(),i=document.createElement("script"),i.id=j,i.type="text/javascript",i.src=b._addCacheSuffix(a),"onreadystatechange"in i?i.onre
 adystatechange=function(){/loaded|complete/.test(i.readyState)&&f()}:i.onload=f,i.onerror=h,(document.getElementsByTagName("head")[0]||document.body).appendChild(i)}var c,h=0,i=1,j=2,k=3,l={},m=[],n={},o=[],p=0;this.isDone=function(a){return l[a]==j},this.markDone=function(a){l[a]=j},this.add=this.load=function(a,b,d,e){var f=l[a];f==c&&(m.push(a),l[a]=h),b&&(n[a]||(n[a]=[]),n[a].push({success:b,failure:e,scope:d||this}))},this.remove=function(a){delete l[a],delete n[a]},this.loadQueue=function(a,b,c){this.loadScripts(m,a,b,c)},this.loadScripts=function(b,d,h,m){function q(a,b){e(n[b],function(b){g(b[a])&&b[a].call(b.scope)}),n[b]=c}var r,s=[];o.push({success:d,failure:m,scope:h||this}),(r=function(){var c=f(b);b.length=0,e(c,function(b){return l[b]===j?void q("success",b):l[b]===k?void q("failure",b):void(l[b]!==i&&(l[b]=i,p++,a(b,function(){l[b]=j,p--,q("success",b),r()},function(){l[b]=k,p--,s.push(b)
 ,q("failure",b),r()})))}),p||(e(o,function(a){0===s.length?g(a.success)&&a.success.call(a.scope):g(a.failure)&&a.failure.call(a.scope,s)}),o.length=0)})()}}var d=a.DOM,e=b.each,f=b.grep,g=function(a){return"function"==typeof a};return c.ScriptLoader=new c,c}),g("g",["f","9"],function(a,b){function c(){var a=this;a.items=[],a.urls={},a.lookup={}}var d=b.each;return c.prototype={get:function(a){if(this.lookup[a])return this.lookup[a].instance},dependencies:function(a){var b;return this.lookup[a]&&(b=this.lookup[a].dependencies),b||[]},requireLangPack:function(b,d){var e=c.language;if(e&&c.languageLoad!==!1){if(d)if(d=","+d+",",d.indexOf(","+e.substr(0,2)+",")!=-1)e=e.substr(0,2);else if(d.indexOf(","+e+",")==-1)return;a.ScriptLoader.add(this.urls[b]+"/langs/"+e+".js")}},add:function(a,b,c){return this.items.push(b),this.looku
 p[a]={instance:b,dependencies:c},b},remove:function(a){delete this.urls[a],delete this.lookup[a]},createUrl:function(a,b){return"object"==typeof b?b:{prefix:a.prefix,resource:b,suffix:a.suffix}},addComponents:function(b,c){var e=this.urls[b];d(c,function(b){a.ScriptLoader.add(e+"/"+b)})},load:function(b,e,f,g,h){function i(){var c=j.dependencies(b);d(c,function(a){var b=j.createUrl(e,a);j.load(b.resource,b,void 0,void 0)}),f&&(g?f.call(g):f.call(a))}var j=this,k=e;j.urls[b]||("object"==typeof e&&(k=e.prefix+e.resource+e.suffix),0!==k.indexOf("/")&&k.indexOf("://")==-1&&(k=c.baseURL+"/"+k),j.urls[b]=k.substring(0,k.lastIndexOf("/")),j.lookup[b]?i():a.ScriptLoader.add(k,i,g,h))}},c.PluginManager=new c,c.ThemeManager=new c,c}),g("1j",[],function(){function a(a){return function(b){return!!b&&b.nodeType==a}}function b(a){return a=a.toLowerCase().split(" "),fun
 ction(b){var c,d;if(b&&b.nodeType)for(d=b.nodeName.toLowerCase(),c=0;c<a.length;c++)if(d===a[c])return!0;return!1}}function c(a,b){return b=b.toLowerCase().split(" "),function(c){var d,e;if(i(c))for(d=0;d<b.length;d++)if(e=c.ownerDocument.defaultView.getComputedStyle(c,null).getPropertyValue(a),e===b[d])return!0;return!1}}function d(a,b){return function(c){return i(c)&&c[a]===b}}function e(a,b){return function(b){return i(b)&&b.hasAttribute(a)}}function f(a,b){return function(c){return i(c)&&c.getAttribute(a)===b}}function g(a){return i(a)&&a.hasAttribute("data-mce-bogus")}function h(a){return function(b){if(i(b)){if(b.contentEditable===a)return!0;if(b.getAttribute("data-mce-contenteditable")===a)return!0}return!1}}var i=a(1);return{isText:a(3),isElement:i,isComment:a(8),isBr:b("br"),isContentEditableTrue:h("true"),isContentEditableFalse:h("false"),matchNodeNames:b,hasPropValue:
 d,hasAttribute:e,hasAttributeValue:f,matchStyleValues:c,isBogus:g}}),g("1l",[],function(){var a="\ufeff",b=function(b){return b===a},c=function(b){return b.replace(new RegExp(a,"g"),"")};return{isZwsp:b,ZWSP:a,trim:c}}),g("1k",["1j","1l"],function(a,b){function c(a){return n(a)&&(a=a.parentNode),m(a)&&a.hasAttribute("data-mce-caret")}function d(a){return n(a)&&b.isZwsp(a.data)}function e(a){return c(a)||d(a)}function f(a,c){var d,f,g,h;if(d=a.ownerDocument,g=d.createTextNode(b.ZWSP),h=a.parentNode,c){if(f=a.previousSibling,n(f)){if(e(f))return f;if(j(f))return f.splitText(f.data.length-1)}h.insertBefore(g,a)}else{if(f=a.nextSibling,n(f)){if(e(f))return f;if(i(f))return f.splitText(1),f}a.nextSibling?h.insertBefore(g,a.nextSibling):h.appendChild(g)}return g}function g(){var a=document.createElement("br");return a.setAttribute("data-mce-bogus","1"),a}fu
 nction h(a,b,c){var d,e,f;return d=b.ownerDocument,e=d.createElement(a),e.setAttribute("data-mce-caret",c?"before":"after"),e.setAttribute("data-mce-bogus","all"),e.appendChild(g()),f=b.parentNode,c?f.insertBefore(e,b):b.nextSibling?f.insertBefore(e,b.nextSibling):f.appendChild(e),e}function i(a){return n(a)&&a.data[0]==b.ZWSP}function j(a){return n(a)&&a.data[a.data.length-1]==b.ZWSP}function k(b){var c=b.getElementsByTagName("br"),d=c[c.length-1];a.isBogus(d)&&d.parentNode.removeChild(d)}function l(a){return a&&a.hasAttribute("data-mce-caret")?(k(a),a.removeAttribute("data-mce-caret"),a.removeAttribute("data-mce-bogus"),a.removeAttribute("style"),a.removeAttribute("_moz_abspos"),a):null}var m=a.isElement,n=a.isText,o=function(b){return b.firstChild!==b.lastChild||!a.isBr(b.firstChild)},p=function(c){if(a.isText(c)){var d=c.data;return d.leng
 th>0&&d.charAt(0)!==b.ZWSP&&c.insertData(0,b.ZWSP),c}return null},q=function(c){if(a.isText(c)){var d=c.data;return d.length>0&&d.charAt(d.length-1)!==b.ZWSP&&c.insertData(d.length,b.ZWSP),c}return null},r=function(c){return c&&a.isText(c.container())&&c.container().data.charAt(c.offset())===b.ZWSP},s=function(c){return c&&a.isText(c.container())&&c.container().data.charAt(c.offset()-1)===b.ZWSP};return{isCaretContainer:e,isCaretContainerBlock:c,isCaretContainerInline:d,showCaretContainerBlock:l,insertInline:f,prependInline:p,appendInline:q,isBeforeInline:r,isAfterInline:s,
-insertBlock:h,hasContent:o,startsWithCaretContainer:i,endsWithCaretContainer:j}}),g("h",["9","c","1j","1h","1k"],function(a,b,c,d,e){function f(a){return q(a)||r(a)}function g(a,b){var c=a.childNodes;return b--,b>c.length-1?b=c.length-1:b<0&&(b=0),c[b]||a}function h(a,b,c){for(;a&&a!==b;){if(c(a))return a;a=a.parentNode}return null}function i(a,b,c){return null!==h(a,b,c)}function j(a,b,c){return i(a,b,function(a){return a.nodeName===c})}function k(a){return"_mce_caret"===a.id}function l(a,b){return s(a)&&i(a,b,k)===!1}function m(a){this.walk=function(b,c){function d(a){var b;return b=a[0],3===b.nodeType&&b===q&&r>=b.nodeValue.length&&a.splice(0,1),b=a[a.length-1],0===t&&a.length>0&&b===s&&3===b.nodeType&&a.splice(a.length-1,1),a}function e(a,b,c){for(var d=[];a&&a!=c;a=a[b])d.push(a);return d}function f(a,b){do{if(
 a.parentNode==b)return a;a=a.parentNode}while(a)}function h(a,b,f){var g=f?"nextSibling":"previousSibling";for(l=a,m=l.parentNode;l&&l!=b;l=m)m=l.parentNode,n=e(l==a?l:l[g],g),n.length&&(f||n.reverse(),c(d(n)))}var i,j,k,l,m,n,o,q=b.startContainer,r=b.startOffset,s=b.endContainer,t=b.endOffset;if(o=a.select("td[data-mce-selected],th[data-mce-selected]"),o.length>0)return void p(o,function(a){c([a])});if(1==q.nodeType&&q.hasChildNodes()&&(q=q.childNodes[r]),1==s.nodeType&&s.hasChildNodes()&&(s=g(s,t)),q==s)return c(d([q]));for(i=a.findCommonAncestor(q,s),l=q;l;l=l.parentNode){if(l===s)return h(q,i,!0);if(l===i)break}for(l=s;l;l=l.parentNode){if(l===q)return h(s,i);if(l===i)break}j=f(q,i)||q,k=f(s,i)||s,h(q,j,!0),n=e(j==q?j:j.nextSibling,"nextSibling",k==s?k.nextSibling:k),n.length&&c(d(n)),h(s,k)},this.split=function(a){function b(a,b){return a.splitText(b)}var c=a.startContainer,d=a.st
 artOffset,e=a.endContainer,f=a.endOffset;return c==e&&3==c.nodeType?d>0&&d<c.nodeValue.length&&(e=b(c,d),c=e.previousSibling,f>d?(f-=d,c=e=b(e,f).previousSibling,f=e.nodeValue.length,d=0):f=0):(3==c.nodeType&&d>0&&d<c.nodeValue.length&&(c=b(c,d),d=0),3==e.nodeType&&f>0&&f<e.nodeValue.length&&(e=b(e,f).previousSibling,f=e.nodeValue.length)),{startContainer:c,startOffset:d,endContainer:e,endOffset:f}},this.normalize=function(c){function d(d){function g(a){return a&&/^(TD|TH|CAPTION)$/.test(a.nodeName)}function h(c,d){for(var e=new b(c,a.getParent(c.parentNode,a.isBlock)||w);c=e[d?"prev":"next"]();)if("BR"===c.nodeName)return!0}function i(a){for(;a&&a!=w;){if(r(a))return!0;a=a.parentNode}return!1}function k(a,b){return a.previousSibling&&a.previousSibling.nodeName==b}function m(c,d){var g,h,i;if(d=d||n,i=a.getParent(d.parentNode,a.isBlock)||
 w,c&&"BR"==d.nodeName&&v&&a.isEmpty(i))return n=d.parentNode,o=a.nodeIndex(d),void(f=!0);for(g=new b(d,i);q=g[c?"prev":"next"]();){if("false"===a.getContentEditableParent(q)||l(q,a.getRoot()))return;if(3===q.nodeType&&q.nodeValue.length>0)return void(j(q,w,"A")===!1&&(n=q,o=c?q.nodeValue.length:0,f=!0));if(a.isBlock(q)||t[q.nodeName.toLowerCase()])return;h=q}e&&h&&(n=h,f=!0,o=0)}var n,o,p,q,t,u,v,w=a.getRoot();if(n=c[(d?"start":"end")+"Container"],o=c[(d?"start":"end")+"Offset"],v=1==n.nodeType&&o===n.childNodes.length,t=a.schema.getNonEmptyElements(),u=d,!s(n)){if(1==n.nodeType&&o>n.childNodes.length-1&&(u=!1),9===n.nodeType&&(n=a.getRoot(),o=0),n===w){if(u&&(q=n.childNodes[o>0?o-1:0])){if(s(q))return;if(t[q.nodeName]||"TABLE"==q.nodeName)return}if(n.hasChildNo
 des()){if(o=Math.min(!u&&o>0?o-1:o,n.childNodes.length-1),n=n.childNodes[o],o=0,!e&&n===w.lastChild&&"TABLE"===n.nodeName)return;if(i(n)||s(n))return;if(n.hasChildNodes()&&!/TABLE/.test(n.nodeName)){q=n,p=new b(n,w);do{if(r(q)||s(q)){f=!1;break}if(3===q.nodeType&&q.nodeValue.length>0){o=u?0:q.nodeValue.length,n=q,f=!0;break}if(t[q.nodeName.toLowerCase()]&&!g(q)){o=a.nodeIndex(q),n=q.parentNode,"IMG"!=q.nodeName||u||o++,f=!0;break}}while(q=u?p.next():p.prev())}}}e&&(3===n.nodeType&&0===o&&m(!0),1===n.nodeType&&(q=n.childNodes[o],q||(q=n.childNodes[o-1]),!q||"BR"!==q.nodeName||k(q,"A")||h(q)||h(q,!0)||m(!0,q))),u&&!e&&3===n.nodeType&&o===n.nodeValue.length&&m(!1),f&&c["set"+(d?"Start":"End")](n,o)}}var e,f=!1;return e=c.collapsed,d(!0),e||d(),f&&e&&c.collapse(!0),f}}function n
 (b,c,d){var e,f,g;if(e=d.elementFromPoint(b,c),f=d.body.createTextRange(),e&&"HTML"!=e.tagName||(e=d.body),f.moveToElementText(e),g=a.toArray(f.getClientRects()),g=g.sort(function(a,b){return a=Math.abs(Math.max(a.top-c,a.bottom-c)),b=Math.abs(Math.max(b.top-c,b.bottom-c)),a-b}),g.length>0){c=(g[0].bottom+g[0].top)/2;try{return f.moveToPoint(b,c),f.collapse(!0),f}catch(a){}}return null}function o(a,b){var c=a&&a.parentElement?a.parentElement():null;return r(h(c,b,f))?null:a}var p=a.each,q=c.isContentEditableTrue,r=c.isContentEditableFalse,s=e.isCaretContainer;return m.compareRanges=function(a,b){if(a&&b){if(!a.item&&!a.duplicate)return a.startContainer==b.startContainer&&a.startOffset==b.startOffset;if(a.item&&b.item&&a.item(0)===b.item(0))return!0;if(a.isEqual&&b.isEqual&&b.isEqual(a))return!0}return!1},m.getCaretRangeFromPoint=function(a,b,c){var d,e;if(c.caretPositionFromPoint)e=c.caretPositionFr
 omPoint(a,b),d=c.createRange(),d.setStart(e.offsetNode,e.offset),d.collapse(!0);else if(c.caretRangeFromPoint)d=c.caretRangeFromPoint(a,b);else if(c.body.createTextRange){d=c.body.createTextRange();try{d.moveToPoint(a,b),d.collapse(!0)}catch(e){d=n(a,b,c)}return o(d,c.body)}return d},m.getSelectedNode=function(a){var b=a.startContainer,c=a.startOffset;return b.hasChildNodes()&&a.endOffset==c+1?b.childNodes[c]:null},m.getNode=function(a,b){return 1==a.nodeType&&a.hasChildNodes()&&(b>=a.childNodes.length&&(b=a.childNodes.length-1),a=a.childNodes[b]),a},m}),g("i",[],function(){function a(a,b,c){var d,e,f=c?"lastChild":"firstChild",g=c?"prev":"next";if(a[f])return a[f];if(a!==b){if(d=a[g])return d;for(e=a.parent;e&&e!==b;e=e.parent)if(d=e[g])return d}}function b(a,b){this.name=a,this.type=b,1===b&&(this.attributes=[],this.attributes.map={})}var c=/^[ \t\r\n]*$/,d={"#text":3,&qu
 ot;#comment":8,"#cdata":4,"#pi":7,"#doctype":10,"#document-fragment":11};return b.prototype={replace:function(a){var b=this;return a.parent&&a.remove(),b.insert(a,b),b.remove(),b},attr:function(a,b){var c,d,e,f=this;if("string"!=typeof a){for(d in a)f.attr(d,a[d]);return f}if(c=f.attributes){if(b!==e){if(null===b){if(a in c.map)for(delete c.map[a],d=c.length;d--;)if(c[d].name===a)return c=c.splice(d,1),f;return f}if(a in c.map){for(d=c.length;d--;)if(c[d].name===a){c[d].value=b;break}}else c.push({name:a,value:b});return c.map[a]=b,f}return c.map[a]}},clone:function(){var a,c,d,e,f,g=this,h=new b(g.name,g.type);if(d=g.attributes){for(f=[],f.map={},a=0,c=d.length;a<c;a++)e=d[a],"id"!==e.name&&(f[f.length]={name:e.name,value:e.value},f.map[e.name]=e.value);h.attributes=f}return h.value=g.value,h.shortEnded=g.shortEnded,h},wrap:function(a){var b=this;return b.parent.insert(a,b),a.append(b),b},unwrap:fun
 ction(){var a,b,c=this;for(a=c.firstChild;a;)b=a.next,c.insert(a,c,!0),a=b;c.remove()},remove:function(){var a=this,b=a.parent,c=a.next,d=a.prev;return b&&(b.firstChild===a?(b.firstChild=c,c&&(c.prev=null)):d.next=c,b.lastChild===a?(b.lastChild=d,d&&(d.next=null)):c.prev=d,a.parent=a.next=a.prev=null),a},append:function(a){var b,c=this;return a.parent&&a.remove(),b=c.lastChild,b?(b.next=a,a.prev=b,c.lastChild=a):c.lastChild=c.firstChild=a,a.parent=c,a},insert:function(a,b,c){var d;return a.parent&&a.remove(),d=b.parent||this,c?(b===d.firstChild?d.firstChild=a:b.prev.next=a,a.prev=b.prev,a.next=b,b.prev=a):(b===d.lastChild?d.lastChild=a:b.next.prev=a,a.next=b.next,a.prev=b,b.next=a),a.parent=d,a},getAll:function(b){var c,d=this,e=[];for(c=d.firstChild;c;c=a(c,d))c.name===b&&e.push(c);return e},empty:function(){var b,c,d,e=this;if(e.firstChild){for(b=[],d=e.firstChild;d;d=a(d,e))b.push(d);for(c=b.length;c--;)d=b[c],d.parent=d.firstChild=
 d.lastChild=d.next=d.prev=null}return e.firstChild=e.lastChild=null,e},isEmpty:function(b,d){var e,f,g=this,h=g.firstChild;if(d=d||{},h)do{if(1===h.type){if(h.attributes.map["data-mce-bogus"])continue;if(b[h.name])return!1;for(e=h.attributes.length;e--;)if(f=h.attributes[e].name,"name"===f||0===f.indexOf("data-mce-bookmark"))return!1}if(8===h.type)return!1;if(3===h.type&&!c.test(h.value))return!1;if(3===h.type&&h.parent&&d[h.parent.name]&&c.test(h.value))return!1}while(h=a(h,g));return!0},walk:function(b){return a(this,null,b)}},b.create=function(a,c){var e,f;if(e=new b(a,d[a]||1),c)for(f in c)e.attr(f,c[f]);return e},b}),g("k",["j","d","9"],function(a,b,c){function d(a,b,c){var d,e,f,g,h=1;for(g=a.getShortEndedElements(),f=/<([!?\/])?([A-Za-z0-9\-_\:\.]+)((?:\s+[^"\'>]+(?:(?:"[^"]*")|(?:\'[^\']*\')|[^>]*))*|\/|\s+)>/g,f.lastIndex=d=c;e=f.exec(b);){if
 (d=f.lastIndex,"/"===e[1])h--;else if(!e[1]){if(e[2]in g)continue;h++}if(0===h)break}return d}function e(e,h){function i(){}var j=this;e=e||{},j.schema=h=h||new a,e.fix_self_closing!==!1&&(e.fix_self_closing=!0),f("comment cdata text start end pi doctype".split(" "),function(a){a&&(j[a]=e[a]||i)}),j.parse=function(a){function f(a){var b,c;for(b=P.length;b--&&P[b].name!==a;);if(b>=0){for(c=P.length-1;c>=b;c--)a=P[c],a.valid&&N.end(a.name);P.length=b}}function i(a,b,c,d,f){var h,i,j=/[\s\u0000-\u001F]+/g;if(b=b.toLowerCase(),c=b in t?b:R(c||d||f||""),v&&!q&&g(b)===!1){if(h=A[b],!h&&B){for(i=B.length;i--&&(h=B[i],!h.pattern.test(b)););i===-1&&(h=null)}if(!h)return;if(h.validValues&&!(c in h.validValues))return}if(S[b]&&!e.allow_script_urls){var k=c.replace(j,"");try{k=decodeURIComponent(k)}catch(a){k=unescape(k)}if(T.test(k))return;if(!e.allow_
 html_data_urls&&U.test(k)&&!/^data:image\//i.test(k))return}m.map[b]=c,m.push({name:b,value:c})}var j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N=this,O=0,P=[],Q=0,R=b.decode,S=c.makeMap("src,href,data,background,formaction,poster"),T=/((java|vb)script|mhtml):/i,U=/^data:/i;for(I=new RegExp("<(?:(?:!--([\\w\\W]*?)-->)|(?:!\\[CDATA\\[([\\w\\W]*?)\\]\\]>)|(?:!DOCTYPE([\\w\\W]*?)>)|(?:\\?([^\\s\\/<>]+) ?([\\w\\W]*?)[?/]>)|(?:\\/([A-Za-z][A-Za-z0-9\\-_\\:\\.]*)>)|(?:([A-Za-z][A-Za-z0-9\\-_\\:\\.]*)((?:\\s+[^\"'>]+(?:(?:\"[^\"]*\")|(?:'[^']*')|[^>]*))*|\\/|\\s+)>))","g"),J=/([\w:\-]+)(?:\s*=\s*(?:(?:\"((?:[^\"])*)\")|(?:\'((?:[^\'])*)\')|([^>\s]+)))?/g,s=h.getShortEndedElements(),H=e.self_closing_elements||h.getSelfClosingElements(),t=h.getBoolAttrs(),v=e.validate,r=e.remove_internals,M=e.fix_self_closing,K=h.getSpecialElements(),F=a+">";j=I.ex
 ec(F);){if(O<j.index&&N.text(R(a.substr(O,j.index-O))),k=j[6])k=k.toLowerCase(),":"===k.charAt(0)&&(k=k.substr(1)),f(k);else if(k=j[7]){if(j.index+j[0].length>a.length){N.text(R(a.substr(j.index))),O=j.index+j[0].length;continue}if(k=k.toLowerCase(),":"===k.charAt(0)&&(k=k.substr(1)),u=k in s,M&&H[k]&&P.length>0&&P[P.length-1].name===k&&f(k),!v||(w=h.getElementRule(k))){if(x=!0,v&&(A=w.attributes,B=w.attributePatterns),(z=j[8])?(q=z.indexOf("data-mce-type")!==-1,q&&r&&(x=!1),m=[],m.map={},z.replace(J,i)):(m=[],m.map={}),v&&!q){if(C=w.attributesRequired,D=w.attributesDefault,E=w.attributesForced,G=w.removeEmptyAttrs,G&&!m.length&&(x=!1),E)for(n=E.length;n--;)y=E[n],p=y.name,L=y.value,"{$uid}"===L&&(L="mce_"+Q++),m.map[p]=L,m.push({name:p,value:L});if(D)for(n=D.length;n--;)y=D[n],p=y.name,p in m.map||(L=y.value,&quot
 ;{$uid}"===L&&(L="mce_"+Q++),m.map[p]=L,m.push({name:p,value:L}));if(C){for(n=C.length;n--&&!(C[n]in m.map););n===-1&&(x=!1)}if(y=m.map["data-mce-bogus"]){if("all"===y){O=d(h,a,I.lastIndex),I.lastIndex=O;continue}x=!1}}x&&N.start(k,m,u)}else x=!1;if(l=K[k]){l.lastIndex=O=j.index+j[0].length,(j=l.exec(a))?(x&&(o=a.substr(O,j.index-O)),O=j.index+j[0].length):(o=a.substr(O),O=a.length),x&&(o.length>0&&N.text(o,!0),N.end(k)),I.lastIndex=O;continue}u||(z&&z.indexOf("/")==z.length-1?x&&N.end(k):P.push({name:k,valid:x}))}else(k=j[1])?(">"===k.charAt(0)&&(k=" "+k),e.allow_conditional_comments||"[if"!==k.substr(0,3).toLowerCase()||(k=" "+k),N.comment(k)):(k=j[2])?N.cdata(k):(k=j[3])?N.doctype(k):(k=j[4])&&N.pi(k,j[5]);O=j.index+j[0].length}for(O<a.length&&N.text(R(a.substr(O))),n=P.length-1;n>=0;n--)k=
 P[n],k.valid&&N.end(k.name)}}var f=c.each,g=function(a){return 0===a.indexOf("data-")||0===a.indexOf("aria-")};return e.findEndTag=d,e}),g("l",["i","j","k","9"],function(a,b,c,d){var e=d.makeMap,f=d.each,g=d.explode,h=d.extend,i=function(b,c){b.padd_empty_with_br?c.empty().append(new a("br","1")).shortEnded=!0:c.empty().append(new a("#text","3")).value="\xa0"},j=function(a,b){return a&&a.firstChild===a.lastChild&&a.firstChild.name===b};return function(k,l){function m(b){var c,d,f,g,h,i,k,m,o,p,q,r,s,t,u,v;for(r=e("tr,td,th,tbody,thead,tfoot,table"),p=l.getNonEmptyElements(),q=l.getWhiteSpaceElements(),s=l.getTextBlockElements(),t=l.getSpecialElements(),c=0;c<b.length;c++)if(d=b[c],d.parent&&!d.fixed)if(s[d.name]&&"li"==d.parent.name){for(u=d.next;u&&s[u.name];)u.name="li",u.fixed=!0,d.
 parent.insert(u,d.parent),u=u.next;d.unwrap(d)}else{for(g=[d],f=d.parent;f&&!l.isValidChild(f.name,d.name)&&!r[f.name];f=f.parent)g.push(f);if(f&&g.length>1){for(g.reverse(),h=i=n.filterNode(g[0].clone()),o=0;o<g.length-1;o++){for(l.isValidChild(i.name,g[o].name)?(k=n.filterNode(g[o].clone()),i.append(k)):k=i,m=g[o].firstChild;m&&m!=g[o+1];)v=m.next,k.append(m),m=v;i=k}h.isEmpty(p,q)?f.insert(d,g[0],!0):(f.insert(h,g[0],!0),f.insert(d,h)),f=g[0],(f.isEmpty(p,q)||j(f,"br"))&&f.empty().remove()}else if(d.parent){if("li"===d.name){if(u=d.prev,u&&("ul"===u.name||"ul"===u.name)){u.append(d);continue}if(u=d.next,u&&("ul"===u.name||"ul"===u.name)){u.insert(d,u.firstChild,!0);continue}d.wrap(n.filterNode(new a("ul",1)));continue}l.isValidChild(d.parent.name,"div")&&l.isValidChild("div",d.name)?d.wrap(n.filterNode(new a("div&quot
 ;,1))):t[d.name]?d.empty().remove():d.unwrap()}}}var n=this,o={},p=[],q={},r={};k=k||{},k.validate=!("validate"in k)||k.validate,k.root_name=k.root_name||"body",n.schema=l=l||new b,n.filterNode=function(a){var b,c,d;c in o&&(d=q[c],d?d.push(a):q[c]=[a]),b=p.length;for(;b--;)c=p[b].name,c in a.attributes.map&&(d=r[c],d?d.push(a):r[c]=[a]);return a},n.addNodeFilter=function(a,b){f(g(a),function(a){var c=o[a];c||(o[a]=c=[]),c.push(b)})},n.addAttributeFilter=function(a,b){f(g(a),function(a){var c;for(c=0;c<p.length;c++)if(p[c].name===a)return void p[c].callbacks.push(b);p.push({name:a,callbacks:[b]})})},n.parse=function(b,d){function f(){function a(a){a&&(d=a.firstChild,d&&3==d.type&&(d.value=d.value.replace(E,"")),d=a.lastChild,d&&3==d.type&&(d.value=d.value.replace(G,"")))}var b,c,d=t.firstChild;if(l.isValidChild(t.name,M.toLowerCase())){for(;d;)b=d.next,3==d.type||1==d.type&&&qu
 ot;p"!==d.name&&!D[d.name]&&!d.attr("data-mce-type")?c?c.append(d):(c=g(M,1),c.attr(k.forced_root_block_attrs),t.insert(c,d),c.append(d)):(a(c),c=null),d=b;a(c)}}function g(b,c){var d,e=new a(b,c);return b in o&&(d=q[b],d?d.push(e):q[b]=[e]),e}function j(a){var b,c,d,e,f=l.getBlockElements();for(b=a.prev;b&&3===b.type;){if(d=b.value.replace(G,""),d.length>0)return void(b.value=d);if(c=b.next){if(3==c.type&&c.value.length){b=b.prev;continue}if(!f[c.name]&&"script"!=c.name&&"style"!=c.name){b=b.prev;continue}}e=b.prev,b.remove(),b=e}}function n(a){var b,c={};for(b in a)"li"!==b&&"p"!=b&&(c[b]=a[b]);return c}var s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N=[];if(d=d||{},q={},r={},D=h(e("script,style,head,html,body,title,meta,param"),l.getBlockElements()),L=l.getNonEmptyElements(),K=l.children,C=k.validate,M="forced_root_block"in 
 d?d.forced_root_block:k.forced_root_block,J=l.getWhiteSpaceElements(),E=/^[ \t\r\n]+/,G=/[ \t\r\n]+$/,H=/[ \t\r\n]+/g,I=/^[ \t\r\n]+$/,s=new c({validate:C,allow_script_urls:k.allow_script_urls,allow_conditional_comments:k.allow_conditional_comments,self_closing_elements:n(l.getSelfClosingElements()),cdata:function(a){u.append(g("#cdata",4)).value=a},text:function(a,b){var c;F||(a=a.replace(H," "),u.lastChild&&D[u.lastChild.name]&&(a=a.replace(E,""))),0!==a.length&&(c=g("#text",3),c.raw=!!b,u.append(c).value=a)},comment:function(a){u.append(g("#comment",8)).value=a},pi:function(a,b){u.append(g(a,7)).value=b,j(u)},doctype:function(a){var b;b=u.append(g("#doctype",10)),b.value=a,j(u)},start:function(a,b,c){var d,e,f,h,i;if(f=C?l.getElementRule(a):{}){for(d=g(f.outputName||a,1),d.attributes=b,d.shortEnded=c,u.append(d),i=K[u.name],i&&K[d.name]&&!i[d.name]&&N.push(d),e=p.length;e--
 ;)h=p[e].name,h in b.map&&(A=r[h],A?A.push(d):r[h]=[d]);D[a]&&j(d),c||(u=d),!F&&J[a]&&(F=!0)}},end:function(a){var b,c,d,e,f;if(c=C?l.getElementRule(a):{}){if(D[a]&&!F){if(b=u.firstChild,b&&3===b.type)if(d=b.value.replace(E,""),d.length>0)b.value=d,b=b.next;else for(e=b.next,b.remove(),b=e;b&&3===b.type;)d=b.value,e=b.next,(0===d.length||I.test(d))&&(b.remove(),b=e),b=e;if(b=u.lastChild,b&&3===b.type)if(d=b.value.replace(G,""),d.length>0)b.value=d,b=b.prev;else for(e=b.prev,b.remove(),b=e;b&&3===b.type;)d=b.value,e=b.prev,(0===d.length||I.test(d))&&(b.remove(),b=e),b=e}if(F&&J[a]&&(F=!1),(c.removeEmpty||c.paddEmpty)&&u.isEmpty(L,J))if(c.paddEmpty)i(k,u);else if(!u.attributes.map.name&&!u.attributes.map.id)return f=u.parent,D[u.name]?u.empty().remove():u.unwrap(),void(u=f);u=u.parent}}},l),t=u=new a(d.context||k.root_name,11),s.parse(b),C&a
 mp;&N.length&&(d.context?d.invalid=!0:m(N)),M&&("body"==t.name||d.isRootContent)&&f(),!d.invalid){for(B in q){for(A=o[B],v=q[B],y=v.length;y--;)v[y].parent||v.splice(y,1);for(w=0,x=A.length;w<x;w++)A[w](v,B,d)}for(w=0,x=p.length;w<x;w++)if(A=p[w],A.name in r){for(v=r[A.name],y=v.length;y--;)v[y].parent||v.splice(y,1);for(y=0,z=A.callbacks.length;y<z;y++)A.callbacks[y](v,A.name,d)}}return t},k.remove_trailing_brs&&n.addNodeFilter("br",function(b){var c,d,e,f,g,j,m,n,o=b.length,p=h({},l.getBlockElements()),q=l.getNonEmptyElements(),r=l.getNonEmptyElements();for(p.body=1,c=0;c<o;c++)if(d=b[c],e=d.parent,p[d.parent.name]&&d===e.lastChild){for(g=d.prev;g;){if(j=g.name,"span"!==j||"bookmark"!==g.attr("data-mce-type")){if("br"!==j)break;if("br"===j){d=null;break}}g=g.prev}d&&(d.remove(),e.isEmpty(q,r)&&(m=l.getElementRule(e.name),m&&(m.remove
 Empty?e.remove():m.paddEmpty&&i(k,e))))}else{for(f=d;e&&e.firstChild===f&&e.lastChild===f&&(f=e,!p[e.name]);)e=e.parent;f===e&&k.padd_empty_with_br!==!0&&(n=new a("#text",3),n.value="\xa0",d.replace(n))}}),k.allow_unsafe_link_target||n.addAttributeFilter("href",function(a){for(var b,c=a.length,e=function(a){var b=a.split(" ").filter(function(a){return a.length>0});return b.concat(["noopener"]).join(" ")},f=function(a){var b=a?d.trim(a):"";return/\b(noopener)\b/g.test(b)?b:e(b)};c--;)b=a[c],"a"===b.name&&"_blank"===b.attr("target")&&b.attr("rel",f(b.attr("rel")))}),k.allow_html_in_named_anchor||n.addAttributeFilter("id,name",function(a){for(var b,c,d,e,f=a.length;f--;)if(e=a[f],"a"===e.name&&e.firstChild&&!e.attr("href")){d=e.parent,b=e.lastChild;do c=b.p
 rev,d.insert(b,e),b=c;while(b)}}),k.fix_list_elements&&n.addNodeFilter("ul,ol",function(b){for(var c,d,e=b.length;e--;)if(c=b[e],d=c.parent,"ul"===d.name||"ol"===d.name)if(c.prev&&"li"===c.prev.name)c.prev.append(c);else{var f=new a("li",1);f.attr("style","list-style-type: none"),c.wrap(f)}}),k.validate&&l.getValidClasses()&&n.addAttributeFilter("class",function(a){for(var b,c,d,e,f,g,h,i=a.length,j=l.getValidClasses();i--;){for(b=a[i],c=b.attr("class").split(" "),f="",d=0;d<c.length;d++)e=c[d],h=!1,g=j["*"],g&&g[e]&&(h=!0),g=j[b.name],!h&&g&&g[e]&&(h=!0),h&&(f&&(f+=" "),f+=e);f.length||(f=null),b.attr("class",f)}})}}),g("m",["d","9"],function(a,b){var c=b.makeMap;return function(b){var d,e,f,g,h,i=[];return b=b||{},d=b.indent
 ,e=c(b.indent_before||""),f=c(b.indent_after||""),g=a.getEncodeFunc(b.entity_encoding||"raw",b.entities),h="html"==b.element_format,{start:function(a,b,c){var j,k,l,m;if(d&&e[a]&&i.length>0&&(m=i[i.length-1],m.length>0&&"\n"!==m&&i.push("\n")),i.push("<",a),b)for(j=0,k=b.length;j<k;j++)l=b[j],i.push(" ",l.name,'="',g(l.value,!0),'"');!c||h?i[i.length]=">":i[i.length]=" />",c&&d&&f[a]&&i.length>0&&(m=i[i.length-1],m.length>0&&"\n"!==m&&i.push("\n"))},end:function(a){var b;i.push("</",a,">"),d&&f[a]&&i.length>0&&(b=i[i.length-1],b.length>0&&"\n"!==b&&i.push("\n"))},text:function(a,b){a.length>0&&(i[i.length]=b?a:g(a))},cdata:function(a){i.push(&q
 uot;<![CDATA[",a,"]]>")},comment:function(a){i.push("<!--",a,"-->")},pi:function(a,b){b?i.push("<?",a," ",g(b),"?>"):i.push("<?",a,"?>"),d&&i.push("\n")},doctype:function(a){i.push("<!DOCTYPE",a,">",d?"\n":"")},reset:function(){i.length=0},getContent:function(){return i.join("").replace(/\n$/,"")}}}}),g("n",["m","j"],function(a,b){return function(c,d){var e=this,f=new a(c);c=c||{},c.validate=!("validate"in c)||c.validate,e.schema=d=d||new b,e.writer=f,e.serialize=function(a){function b(a){var c,h,i,j,k,l,m,n,o,p=e[a.type];if(p)p(a);else{if(c=a.name,h=a.shortEnded,i=a.attributes,g&&i&&i.length>1&&(l=[],l.map={},o=d.getElementRule(a.name))){for(m=0,n=o.attributesOrder.length;m<n;m++)j=o.attributesOrder[m],j in i.map&&(
 k=i.map[j],l.map[j]=k,l.push({name:j,value:k}));for(m=0,n=i.length;m<n;m++)j=i[m].name,j in l.map||(k=i.map[j],l.map[j]=k,l.push({name:j,value:k}));i=l}if(f.start(a.name,i,h),!h){if(a=a.firstChild)do b(a);while(a=a.next);f.end(c)}}}var e,g;return g=c.validate,e={3:function(a){f.text(a.value,a.raw)},8:function(a){f.comment(a.value)},7:function(a){f.pi(a.name,a.value)},10:function(a){f.doctype(a.value)},4:function(a){f.cdata(a.value)},11:function(a){if(a=a.firstChild)do b(a);while(a=a.next)}},f.reset(),1!=a.type||c.inner?e[11](a):b(a),f.getContent()}}}),g("o",["e","l","k","d","n","i","j","6","9","1l"],function(a,b,c,d,e,f,g,h,i,j){function k(a){function b(a){return a&&"br"===a.name}var c,d;c=a.lastChild,b(c)&&(d=c.prev,b(d)&&(c.remove(),d.remove()))}var l=i.each,m=i.trim,n=a.DOM;return function(a,f){function o(a){var b=new RegExp(["&lt
 ;span[^>]+data-mce-bogus[^>]+>[\u200b\ufeff]+<\\/span>","\\s?("+v.join("|")+')="[^"]+"'].join("|"),"gi");return a=j.trim(a.replace(b,""))}function p(a){var b,d,e,g,h,i=a,j=/<(\w+) [^>]*data-mce-bogus="all"[^>]*>/g,k=f.schema;for(i=o(i),h=k.getShortEndedElements();g=j.exec(i);)d=j.lastIndex,e=g[0].length,b=h[g[1]]?d:c.findEndTag(k,i,d),i=i.substring(0,d-e)+i.substring(b),j.lastIndex=d-e;return i}function q(){return p(f.getBody().innerHTML)}function r(a){i.inArray(v,a)===-1&&(u.addAttributeFilter(a,function(a,b){for(var c=a.length;c--;)a[c].attr(b,null)}),v.push(a))}var s,t,u,v=["data-mce-selected"];return f&&(s=f.dom,t=f.schema),s=s||n,t=t||new g(a),a.entity_encoding=a.entity_encoding||"named",a.remove_trailing_brs=!("remove_trailing_brs"in a)||a.remove_trailing_brs,u=new b(a,t),u.addAttributeFilter("data-mce-tabindex",func
 tion(a,b){for(var c,d=a.length;d--;)c=a[d],c.attr("tabindex",c.attributes.map["data-mce-tabindex"]),c.attr(b,null)}),u.addAttributeFilter("src,href,style",function(b,c){for(var d,e,f,g=b.length,h="data-mce-"+c,i=a.url_converter,j=a.url_converter_scope;g--;)d=b[g],e=d.attributes.map[h],e!==f?(d.attr(c,e.length>0?e:null),d.attr(h,null)):(e=d.attributes.map[c],"style"===c?e=s.serializeStyle(s.parseStyle(e),d.name):i&&(e=i.call(j,e,c,d.name)),d.attr(c,e.length>0?e:null))}),u.addAttributeFilter("class",function(a){for(var b,c,d=a.length;d--;)b=a[d],c=b.attr("class"),c&&(c=b.attr("class").replace(/(?:^|\s)mce-item-\w+(?!\S)/g,""),b.attr("class",c.length>0?c:null))}),u.addAttributeFilter("data-mce-type",function(a,b,c){for(var d,e=a.length;e--;)d=a[e],"bookmark"!==d.attributes.map["data-mce-type"]||c.cleanup||d.remove()}),u.addNodeFilter
 ("noscript",function(a){for(var b,c=a.length;c--;)b=a[c].firstChild,b&&(b.value=d.decode(b.value))}),u.addNodeFilter("script,style",function(a,b){function c(a){return a.replace(/(<!--\[CDATA\[|\]\]-->)/g,"\n").replace(/^[\r\n]*|[\r\n]*$/g,"").replace(/^\s*((<!--)?(\s*\/\/)?\s*<!\[CDATA\[|(<!--\s*)?\/\*\s*<!\[CDATA\[\s*\*\/|(\/\/)?\s*<!--|\/\*\s*<!--\s*\*\/)\s*[\r\n]*/gi,"").replace(/\s*(\/\*\s*\]\]>\s*\*\/(-->)?|\s*\/\/\s*\]\]>(-->)?|\/\/\s*(-->)?|\]\]>|\/\*\s*-->\s*\*\/|\s*-->\s*)\s*$/g,"")}for(var d,e,f,g=a.length;g--;)d=a[g],e=d.firstChild?d.firstChild.value:"","script"===b?(f=d.attr("type"),f&&d.attr("type","mce-no/type"==f?null:f.replace(/^mce\-/,"")),e.length>0&&(d.firstChild.value="// <![CDATA[\n"+c(e)+"\n// ]]>")):e.length>0&&(d.firstChild.value=&
 quot;<!--\n"+c(e)+"\n-->")}),u.addNodeFilter("#comment",function(a){for(var b,c=a.length;c--;)b=a[c],0===b.value.indexOf("[CDATA[")?(b.name="#cdata",b.type=4,b.value=b.value.replace(/^\[CDATA\[|\]\]$/g,"")):0===b.value.indexOf("mce:protected ")&&(b.name="#text",b.type=3,b.raw=!0,b.value=unescape(b.value).substr(14))}),u.addNodeFilter("xml:namespace,input",function(a,b){for(var c,d=a.length;d--;)c=a[d],7===c.type?c.remove():1===c.type&&("input"!==b||"type"in c.attributes.map||c.attr("type","text"))}),u.addAttributeFilter("data-mce-src,data-mce-href,data-mce-style,data-mce-selected,data-mce-expando,data-mce-type,data-mce-resize",function(a,b){for(var c=a.length;c--;)a[c].attr(b,null)}),{schema:t,addNodeFilter:u.addNodeFilter,addAttributeFilter:u.addAttributeFilter,serialize:function(b,c){var d,f,g,i,n,o,p=this;return h.ie&&amp
 ;s.select("script,style,select,map").length>0?(n=b.innerHTML,b=b.cloneNode(!1),s.setHTML(b,n)):b=b.cloneNode(!0),d=document.implementation,d.createHTMLDocument&&(f=d.createHTMLDocument(""),l("BODY"==b.nodeName?b.childNodes:[b],function(a){f.body.appendChild(f.importNode(a,!0))}),b="BODY"!=b.nodeName?f.body.firstChild:f.body,g=s.doc,s.doc=f),c=c||{},c.format=c.format||"html",c.selection&&(c.forced_root_block=""),c.no_events||(c.node=b,p.onPreProcess(c)),o=u.parse(m(c.getInner?b.innerHTML:s.getOuterHTML(b)),c),k(o),i=new e(a,t),c.content=i.serialize(o),c.cleanup||(c.content=j.trim(c.content),c.content=c.content.replace(/\uFEFF/g,"")),c.no_events||p.onPostProcess(c),g&&(s.doc=g),c.node=null,c.content},addRules:function(a){t.addValidElements(a)},setRules:function(a){t.setValidElements(a)},onPreProcess:function(a){f&&f.fire("PreProcess",a)},onPostProcess:function(a){f&&a
 mp;f.fire("PostProcess",a)},addTempAttr:r,trimHtml:o,getTrimmedContent:q,trimContent:p}}}),g("p",["6"],function(a){return{BACKSPACE:8,DELETE:46,DOWN:40,ENTER:13,LEFT:37,RIGHT:39,SPACEBAR:32,TAB:9,UP:38,modifierPressed:function(a){return a.shiftKey||a.ctrlKey||a.altKey||this.metaKeyPressed(a)},metaKeyPressed:function(b){return a.mac?b.metaKey:b.ctrlKey&&!b.altKey}}}),g("q",["p","9","5","6","1j"],function(a,b,c,d,e){function f(a,b){for(;b&&b!=a;){if(h(b)||g(b))return b;b=b.parentNode}return null}var g=e.isContentEditableFalse,h=e.isContentEditableTrue;return function(e,h){function i(a){var b=h.settings.object_resizing;return b!==!1&&!d.iOS&&("string"!=typeof b&&(b="table,img,div"),"false"!==a.getAttribute("data-mce-resize")&&(a!=h.getBody()&&h.dom.is(a,b)))}function j(b){var c,d,e,f,g;c=b.screenX-F,d=b
 .screenY-G,N=c*D[2]+J,O=d*D[3]+K,N=N<5?5:N,O=O<5?5:O,e="IMG"==z.nodeName&&h.settings.resize_img_proportional!==!1?!a.modifierPressed(b):a.modifierPressed(b)||"IMG"==z.nodeName&&D[2]*D[3]!==0,e&&(W(c)>W(d)?(O=X(N*L),N=X(O/L)):(N=X(O/L),O=X(N*L))),R.setStyles(A,{width:N,height:O}),f=D.startPos.x+c,g=D.startPos.y+d,f=f>0?f:0,g=g>0?g:0,R.setStyles(B,{left:f,top:g,display:"block"}),B.innerHTML=N+" &times; "+O,D[2]<0&&A.clientWidth<=N&&R.setStyle(A,"left",H+(J-N)),D[3]<0&&A.clientHeight<=O&&R.setStyle(A,"top",I+(K-O)),c=Y.scrollWidth-P,d=Y.scrollHeight-Q,c+d!==0&&R.setStyles(B,{left:f-c,top:g-d}),M||(h.fire("ObjectResizeStart",{target:z,width:J,height:K}),M=!0)}function k(){function a(a,b){b&&(z.style[a]||!h.schema.isValid(z.nodeName.toLowerCase(),a)?R.setStyle(z,a,b):R.setAttrib(z,a,b))}M=!1,a("width",N),a(&
 quot;height",O),R.unbind(T,"mousemove",j),R.unbind(T,"mouseup",k),U!=T&&(R.unbind(U,"mousemove",j),R.unbind(U,"mouseup",k)),R.remove(A),R.remove(B),V&&"TABLE"!=z.nodeName||l(z),h.fire("ObjectResized",{target:z,width:N,height:O}),R.setAttrib(z,"style",R.getAttrib(z,"style")),h.nodeChanged()}function l(a,b,c){var e,f,g,l,n;m(),v(),e=R.getPos(a,Y),H=e.x,I=e.y,n=a.getBoundingClientRect(),f=n.width||n.right-n.left,g=n.height||n.bottom-n.top,z!=a&&(u(),z=a,N=O=0),l=h.fire("ObjectSelected",{target:a}),i(a)&&!l.isDefaultPrevented()?S(C,function(a,e){function h(b){F=b.screenX,G=b.screenY,J=z.clientWidth,K=z.clientHeight,L=K/J,D=a,a.startPos={x:f*a[0]+H,y:g*a[1]+I},P=Y.scrollWidth,Q=Y.scrollHeight,A=z.cloneNode(!0),R.addClass(A,"mce-clonedresizable"),R.setAttrib(A,"data-mce-bogus","all"),A.contentEditable=!1,A.unSelectabe=!0,R.setStyles(A
 ,{left:H,top:I,margin:0}),A.removeAttribute("data-mce-selected"),Y.appendChild(A),R.bind(T,"mousemove",j),R.bind(T,"mouseup",k),U!=T&&(R.bind(U,"mousemove",j),R.bind(U,"mouseup",k)),B=R.add(Y,"div",{"class":"mce-resize-helper","data-mce-bogus":"all"},J+" &times; "+K)}var i;return b?void(e==b&&h(c)):(i=R.get("mceResizeHandle"+e),i&&R.remove(i),i=R.add(Y,"div",{id:"mceResizeHandle"+e,"data-mce-bogus":"all","class":"mce-resizehandle",unselectable:!0,style:"cursor:"+e+"-resize; margin:0; padding:0"}),d.ie&&(i.contentEditable=!1),R.bind(i,"mousedown",function(a){a.stopImmediatePropagation(),a.preventDefault(),h(a)}),a.elm=i,void R.setStyles(i,{left:f*a[0]+H-i.offsetWidth/2,top:g*a[1]+I-i.offsetHeight/2}))}):m(),z.setAttribute("data-mce-selec
 ted","1")}function m(){var a,b;v(),z&&z.removeAttribute("data-mce-selected");for(a in C)b=R.get("mceResizeHandle"+a),b&&(R.unbind(b),R.remove(b))}function n(a){function b(a,b){if(a)do if(a===b)return!0;while(a=a.parentNode)}var c,d;if(!M&&!h.removed)return S(R.select("img[data-mce-selected],hr[data-mce-selected]"),function(a){a.removeAttribute("data-mce-selected")}),d="mousedown"==a.type?a.target:e.getNode(),d=R.$(d).closest(V?"table":"table,img,hr")[0],b(d,Y)&&(w(),c=e.getStart(!0),b(c,d)&&b(e.getEnd(!0),d)&&(!V||d!=c&&"IMG"!==c.nodeName))?void l(d):void m()}function o(a,b,c){a&&a.attachEvent&&a.attachEvent("on"+b,c)}function p(a,b,c){a&&a.detachEvent&&a.detachEvent("on"+b,c)}function q(a){var b,c,d,e,f,g,i,j=a.srcElement;b=j.getBoundingClientRect(),g=E.clientX-b.left,i=E.clientY-b.
 top;for(c in C)if(d=C[c],e=j.offsetWidth*d[0],f=j.offsetHeight*d[1],W(e-g)<8&&W(f-i)<8){D=d;break}M=!0,h.fire("ObjectResizeStart",{target:z,width:z.clientWidth,height:z.clientHeight}),h.getDoc().selection.empty(),l(j,c,E)}function r(a){a.preventDefault?a.preventDefault():a.returnValue=!1}function s(a){return g(f(h.getBody(),a))}function t(a){var b=a.srcElement;if(s(b))return void r(a);if(b!=z){if(h.fire("ObjectSelected",{target:b}),u(),0===b.id.indexOf("mceResizeHandle"))return void(a.returnValue=!1);"IMG"!=b.nodeName&&"TABLE"!=b.nodeName||(m(),z=b,o(b,"resizestart",q))}}function u(){p(z,"resizestart",q)}function v(){for(var a in C){var b=C[a];b.elm&&(R.unbind(b.elm),delete b.elm)}}function w(){try{h.getDoc().execCommand("enableObjectResizing",!1,!1)}catch(a){}}function x(a){var b;if(V){b=T.body.createControlRange();try{return b.addElement(a),b.select(),!0}catch(a){}}}functi
 on y(){z=A=null,V&&(u(),p(Y,"controlselect",t))}var z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R=h.dom,S=b.each,T=h.getDoc(),U=document,V=d.ie&&d.ie<11,W=Math.abs,X=Math.round,Y=h.getBody();C={nw:[0,0,-1,-1],ne:[1,0,1,-1],se:[1,1,1,1],sw:[0,1,-1,1]};var Z=".mce-content-body";return h.contentStyles.push(Z+" div.mce-resizehandle {position: absolute;border: 1px solid black;box-sizing: box-sizing;background: #FFF;width: 7px;height: 7px;z-index: 10000}"+Z+" .mce-resizehandle:hover {background: #000}"+Z+" img[data-mce-selected],"+Z+" hr[data-mce-selected] {outline: 1px solid black;resize: none}"+Z+" .mce-clonedresizable {position: absolute;"+(d.gecko?"":"outline: 1px dashed black;")+"opacity: .5;filter: alpha(opacity=50);z-index: 10000}"+Z+" .mce-resize-helper {background: #555;background: rgba(0,0,0,0.75);border-radius: 3px;border: 1px;color: white;display: none;font-famil
 y: sans-serif;font-size: 12px;white-space: nowrap;line-height: 14px;margin: 5px 10px;padding: 5px;position: absolute;z-index: 10001}"),h.on("init",function(){V?(h.on("ObjectResized",function(a){"TABLE"!=a.target.nodeName&&(m(),x(a.target))}),o(Y,"controlselect",t),h.on("mousedown",function(a){E=a})):(w(),d.ie>=11&&(h.on("mousedown click",function(a){var b=a.target,c=b.nodeName;M||!/^(TABLE|IMG|HR)$/.test(c)||s(b)||(h.selection.select(b,"TABLE"==c),"mousedown"==a.type&&h.nodeChanged());
-}),h.dom.bind(Y,"mscontrolselect",function(a){function b(a){c.setEditorTimeout(h,function(){h.selection.select(a)})}return s(a.target)?(a.preventDefault(),void b(a.target)):void(/^(TABLE|IMG|HR)$/.test(a.target.nodeName)&&(a.preventDefault(),"IMG"==a.target.tagName&&b(a.target)))})));var a=c.throttle(function(a){h.composing||n(a)});h.on("nodechange ResizeEditor ResizeWindow drop",a),h.on("keyup compositionend",function(b){z&&"TABLE"==z.nodeName&&a(b)}),h.on("hide blur",m)}),h.on("remove",v),{isResizable:i,showResizeRect:l,hideResizeRect:m,updateResizeRect:n,controlSelect:x,destroy:y}}}),g("1s",[],function(){function a(a){return function(){return a}}function b(a){return function(b){return!a(b)}}function c(a,b){return function(c){return a(b(c))}}function d(){var a=h.call(arguments);return function(b){for(var c=0;c<a.length;c++)if(a[c](b))return!0;return!1}}function e(){va
 r a=h.call(arguments);return function(b){for(var c=0;c<a.length;c++)if(!a[c](b))return!1;return!0}}function f(a){var b=h.call(arguments);return b.length-1>=a.length?a.apply(this,b.slice(1)):function(){var a=b.concat([].slice.call(arguments));return f.apply(this,a)}}function g(){}var h=[].slice;return{constant:a,negate:b,and:e,or:d,curry:f,compose:c,noop:g}}),g("3x",["1j","1g","1k"],function(a,b,c){function d(a){return!p(a)&&(l(a)?!m(a.parentNode):n(a)||k(a)||o(a)||j(a))}function e(a,b){for(a=a.parentNode;a&&a!=b;a=a.parentNode){if(j(a))return!1;if(i(a))return!0}return!0}function f(a){return!!j(a)&&b.reduce(a.getElementsByTagName("*"),function(a,b){return a||i(b)},!1)!==!0}function g(a){return n(a)||f(a)}function h(a,b){return d(a)&&e(a,b)}var i=a.isContentEditableTrue,j=a.isContentEditableFalse,k=a.isBr,l=a.isText,m=a.matchNodeNames("script style textarea"),n=a.matchNodeNames("img 
 input textarea hr iframe video audio object"),o=a.matchNodeNames("table"),p=c.isCaretContainer;return{isCaretCandidate:d,isInEditable:e,isAtomic:g,isEditableCaretCandidate:h}}),g("3y",[],function(){function a(a){return a?{left:k(a.left),top:k(a.top),bottom:k(a.bottom),right:k(a.right),width:k(a.width),height:k(a.height)}:{left:0,top:0,bottom:0,right:0,width:0,height:0}}function b(b,c){return b=a(b),c?b.right=b.left:(b.left=b.left+b.width,b.right=b.left),b.width=0,b}function c(a,b){return a.left===b.left&&a.top===b.top&&a.bottom===b.bottom&&a.right===b.right}function d(a,b,c){return a>=0&&a<=Math.min(b.height,c.height)/2}function e(a,b){return a.bottom-a.height/2<b.top||!(a.top>b.bottom)&&d(b.top-a.bottom,a,b)}function f(a,b){return a.top>b.bottom||!(a.bottom<b.top)&&d(b.bottom-a.top,a,b)}function g(a,b){return a.left<b.left}function h(a,b){return a.right>b.right}function i(a,b){return e(
 a,b)?-1:f(a,b)?1:g(a,b)?-1:h(a,b)?1:0}function j(a,b,c){return b>=a.left&&b<=a.right&&c>=a.top&&c<=a.bottom}var k=Math.round;return{clone:a,collapse:b,isEqual:c,isAbove:e,isBelow:f,isLeft:g,isRight:h,compare:i,containsXY:j}}),g("3z",[],function(){function a(a){return"string"==typeof a&&a.charCodeAt(0)>=768&&b.test(a)}var b=new RegExp("[\u0300-\u036f\u0483-\u0487\u0488-\u0489\u0591-\u05bd\u05bf\u05c1-\u05c2\u05c4-\u05c5\u05c7\u0610-\u061a\u064b-\u065f\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7-\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08e3-\u0902\u093a\u093c\u0941-\u0948\u094d\u0951-\u0957\u0962-\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2-\u09e3\u0a01-\u0a02\u0a3c\u0a41-\u0a42\u0a47-\u0a48\u0a4b-\u0a4d\u0a51\u0a70-\u0a71\u0a75\u0a81-\u0a82\u0abc\u0ac1-\u0ac5\u0ac7-\u0ac8\u0acd\u0ae2-\u0ae3\u0b01\u0b3c\u0b3e\u0b
 3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62-\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c00\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55-\u0c56\u0c62-\u0c63\u0c81\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc-\u0ccd\u0cd5-\u0cd6\u0ce2-\u0ce3\u0d01\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62-\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb-\u0ebc\u0ec8-\u0ecd\u0f18-\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86-\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039-\u103a\u103d-\u103e\u1058-\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085-\u1086\u108d\u109d\u135d-\u135f\u1712-\u1714\u1732-\u1734\u1752-\u1753\u1772-\u1773\u17b4-\u17b5\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927-\u1928\u1932\u1939-\u193b\u1a17-\u1a18\u1a1b\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1ab0-\u1abd\u1abe\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80-\u1b81\u1ba2-\u1ba5\u1ba8-\u1ba9\u1bab-\u1bad\u1
 be6\u1be8-\u1be9\u1bed\u1bef-\u1bf1\u1c2c-\u1c33\u1c36-\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1cf4\u1cf8-\u1cf9\u1dc0-\u1df5\u1dfc-\u1dff\u200c-\u200d\u20d0-\u20dc\u20dd-\u20e0\u20e1\u20e2-\u20e4\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302d\u302e-\u302f\u3099-\u309a\ua66f\ua670-\ua672\ua674-\ua67d\ua69e-\ua69f\ua6f0-\ua6f1\ua802\ua806\ua80b\ua825-\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\ua9e5\uaa29-\uaa2e\uaa31-\uaa32\uaa35-\uaa36\uaa43\uaa4c\uaa7c\uaab0\uaab2-\uaab4\uaab7-\uaab8\uaabe-\uaabf\uaac1\uaaec-\uaaed\uaaf6\uabe5\uabe8\uabed\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\uff9e-\uff9f]");return{isExtendingChar:a}}),g("1n",["1s","1j","e","h","3x","3y","3z"],function(a,b,c,d,e,f,g){function h(a){return"createRange"in a?a.createRange():c.DOM.createRng()}function i(a){return a&&/[\r\n\t ]/.test(a)}function j(a){var b
 ,c=a.startContainer,d=a.startOffset;return!!(i(a.toString())&&r(c.parentNode)&&(b=c.data,i(b[d-1])||i(b[d+1])))}function k(a){function b(a){var b,c=a.ownerDocument,d=h(c),e=c.createTextNode("\xa0"),g=a.parentNode;return g.insertBefore(e,a),d.setStart(e,0),d.setEnd(e,1),b=f.clone(d.getBoundingClientRect()),g.removeChild(e),b}function c(a){var c,d;return d=a.getClientRects(),c=d.length>0?f.clone(d[0]):f.clone(a.getBoundingClientRect()),t(a)&&0===c.left?b(a):c}function d(a,b){return a=f.collapse(a,b),a.width=1,a.right=a.left+1,a}function e(a){0!==a.height&&(n.length>0&&f.isEqual(a,n[n.length-1])||n.push(a))}function i(a,b){var f=h(a.ownerDocument);if(b<a.data.length){if(g.isExtendingChar(a.data[b]))return n;if(g.isExtendingChar(a.data[b-1])&&(f.setStart(a,b),f.setEnd(a,b+1),!j(f)))return e(d(c(f),!1)),n}b>0&&(f.setStart(a,b-1),f.setEnd(a,b),j(f)||e(d(c(f),!1))),b<a.data.length&&(f.setStart(a,b),f.s
 etEnd(a,b+1),j(f)||e(d(c(f),!0)))}var k,l,n=[];if(s(a.container()))return i(a.container(),a.offset()),n;if(m(a.container()))if(a.isAtEnd())l=v(a.container(),a.offset()),s(l)&&i(l,l.data.length),q(l)&&!t(l)&&e(d(c(l),!1));else{if(l=v(a.container(),a.offset()),s(l)&&i(l,0),q(l)&&a.isAtEnd())return e(d(c(l),!1)),n;k=v(a.container(),a.offset()-1),q(k)&&!t(k)&&(o(k)||o(l)||!q(l))&&e(d(c(k),!1)),q(l)&&e(d(c(l),!0))}return n}function l(b,c,d){function e(){return s(b)?0===c:0===c}function f(){return s(b)?c>=b.data.length:c>=b.childNodes.length}function g(){var a;return a=h(b.ownerDocument),a.setStart(b,c),a.setEnd(b,c),a}function i(){return d||(d=k(new l(b,c))),d}function j(){return i().length>0}function m(a){return a&&b===a.container()&&c===a.offset()}function n(a){return v(b,a?c-1:c)}return{container:a.constant(b),offset:a.constant(c),toRange:g,getClientRects:i,isVisible:j,isAtStart:e,isAtEnd:
 f,isEqual:m,getNode:n}}var m=b.isElement,n=e.isCaretCandidate,o=b.matchStyleValues("display","block table"),p=b.matchStyleValues("float","left right"),q=a.and(m,n,a.negate(p)),r=a.negate(b.matchStyleValues("white-space","pre pre-line pre-wrap")),s=b.isText,t=b.isBr,u=c.nodeIndex,v=d.getNode;return l.fromRangeStart=function(a){return new l(a.startContainer,a.startOffset)},l.fromRangeEnd=function(a){return new l(a.endContainer,a.endOffset)},l.after=function(a){return new l(a.parentNode,u(a)+1)},l.before=function(a){return new l(a.parentNode,u(a))},l.isAtStart=function(a){return!!a&&a.isAtStart()},l.isAtEnd=function(a){return!!a&&a.isAtEnd()},l.isTextPosition=function(a){return!!a&&b.isText(a.container())},l}),g("1m",["1j","e","1s","1g","1n"],function(a,b,c,d,e){function f(a){var b=a.parentNode;return r(b)?f(b):b}function g(a){return a?d.reduce
 (a.childNodes,function(a,b){return r(b)&&"BR"!=b.nodeName?a=a.concat(g(b)):a.push(b),a},[]):[]}function h(a,b){for(;(a=a.previousSibling)&&q(a);)b+=a.data.length;return b}function i(a){return function(b){return a===b}}function j(b){var c,e,h;return c=g(f(b)),e=d.findIndex(c,i(b),b),c=c.slice(0,e+1),h=d.reduce(c,function(a,b,d){return q(b)&&q(c[d-1])&&a++,a},0),c=d.filter(c,a.matchNodeNames(b.nodeName)),e=d.findIndex(c,i(b),b),e-h}function k(a){var b;return b=q(a)?"text()":a.nodeName.toLowerCase(),b+"["+j(a)+"]"}function l(a,b,c){var d=[];for(b=b.parentNode;b!=a&&(!c||!c(b));b=b.parentNode)d.push(b);return d}function m(b,e){var f,g,i,j,m,n=[];return f=e.container(),g=e.offset(),q(f)?i=h(f,g):(j=f.childNodes,g>=j.length?(i="after",g=j.length-1):i="before",f=j[g]),n.push(k(f)),m=l(b,f),m=d.filter(m,c.negate(a.isBogus)),n=n.concat(d.map(m,function(a){return k(a)})),n.reverse().join(&qu
 ot;/")+","+i}function n(b,c,e){var f=g(b);return f=d.filter(f,function(a,b){return!q(a)||!q(f[b-1])}),f=d.filter(f,a.matchNodeNames(c)),f[e]}function o(a,b){for(var c,d=a,f=0;q(d);){if(c=d.data.length,b>=f&&b<=f+c){a=d,b-=f;break}if(!q(d.nextSibling)){a=d,b=c;break}f+=c,d=d.nextSibling}return b>a.data.length&&(b=a.data.length),new e(a,b)}function p(a,b){var c,f,g;return b?(c=b.split(","),b=c[0].split("/"),g=c.length>1?c[1]:"before",f=d.reduce(b,function(a,b){return(b=/([\w\-\(\)]+)\[([0-9]+)\]/.exec(b))?("text()"===b[1]&&(b[1]="#text"),n(a,b[1],parseInt(b[2],10))):null},a),f?q(f)?o(f,parseInt(g,10)):(g="after"===g?s(f)+1:s(f),new e(f.parentNode,g)):null):null}var q=a.isText,r=a.isBogus,s=b.nodeIndex;return{create:m,resolve:p}}),g("r",["1m","1k","1n","1j","h","6","1l","9"],function(a,b,
 c,d,e,f,g,h){function i(g){var i=g.dom;this.getBookmark=function(f,l){function m(a,b){var c=0;return h.each(i.select(a),function(a){if("all"!==a.getAttribute("data-mce-bogus"))return a!=b&&void c++}),c}function n(a){function b(b){var c,d,e,f=b?"start":"end";c=a[f+"Container"],d=a[f+"Offset"],1==c.nodeType&&"TR"==c.nodeName&&(e=c.childNodes,c=e[Math.min(b?d:d-1,e.length-1)],c&&(d=b?0:c.childNodes.length,a["set"+(b?"Start":"End")](c,d)))}return b(!0),b(),a}function o(a){function b(a,b){var d,e=a[b?"startContainer":"endContainer"],f=a[b?"startOffset":"endOffset"],g=[],h=0;for(3===e.nodeType?g.push(l?k(e,f):f):(d=e.childNodes,f>=d.length&&d.length&&(h=1,f=Math.max(0,d.length-1)),g.push(i.nodeIndex(d[f],l)+h));e&&e!=c;e=e.parentNode)g.push(i.nodeIndex(e,l));return g}var c=i.getRoot(),d={};ret
 urn d.start=b(a,!0),g.isCollapsed()||(d.end=b(a)),d}function p(a){function c(a,c){var f;if(d.isElement(a)&&(a=e.getNode(a,c),j(a)))return a;if(b.isCaretContainer(a)){if(d.isText(a)&&b.isCaretContainerBlock(a)&&(a=a.parentNode),f=a.previousSibling,j(f))return f;if(f=a.nextSibling,j(f))return f}}return c(a.startContainer,a.startOffset)||c(a.endContainer,a.endOffset)}var q,r,s,t,u,v,w,x="&#xFEFF;";if(2==f)return v=g.getNode(),u=v?v.nodeName:null,q=g.getRng(),j(v)||"IMG"==u?{name:u,index:m(u,v)}:g.tridentSel?g.tridentSel.getBookmark(f):(v=p(q),v?(u=v.tagName,{name:u,index:m(u,v)}):o(q));if(3==f)return q=g.getRng(),{start:a.create(i.getRoot(),c.fromRangeStart(q)),end:a.create(i.getRoot(),c.fromRangeEnd(q))};if(f)return{rng:g.getRng()};if(q=g.getRng(),s=i.uniqueId(),t=g.isCollapsed(),w="overflow:hidden;line-height:0px",q.duplicate||q.item){if(q.item)return v=q.item(0),u=v.nodeName,{name:u,index:m(u,v)};r=q.duplicate();try{q.collaps
 e(),q.pasteHTML('<span data-mce-type="bookmark" id="'+s+'_start" style="'+w+'">'+x+"</span>"),t||(r.collapse(!1),q.moveToElementText(r.parentElement()),0===q.compareEndPoints("StartToEnd",r)&&r.move("character",-1),r.pasteHTML('<span data-mce-type="bookmark" id="'+s+'_end" style="'+w+'">'+x+"</span>"))}catch(a){return null}}else{if(v=g.getNode(),u=v.nodeName,"IMG"==u)return{name:u,index:m(u,v)};r=n(q.cloneRange()),t||(r.collapse(!1),r.insertNode(i.create("span",{"data-mce-type":"bookmark",id:s+"_end",style:w},x))),q=n(q),q.collapse(!0),q.insertNode(i.create("span",{"data-mce-type":"bookmark",id:s+"_start",style:w},x))}return g.moveToBookmark({id:s,keep:1}),{id:s}},this.moveToBookmark=function(b){function c(a){var c,d,e,f,g=b[a?"start":"end"];if(
 g){for(e=g[0],d=l,c=g.length-1;c>=1;c--){if(f=d.childNodes,g[c]>f.length-1)return;d=f[g[c]]}3===d.nodeType&&(e=Math.min(g[0],d.nodeValue.length)),1===d.nodeType&&(e=Math.min(g[0],d.childNodes.length)),a?k.setStart(d,e):k.setEnd(d,e)}return!0}function d(a){var c,d,e,g,j=i.get(b.id+"_"+a),k=b.keep;if(j&&(c=j.parentNode,"start"==a?(k?(c=j.firstChild,d=1):d=i.nodeIndex(j),m=n=c,o=p=d):(k?(c=j.firstChild,d=1):d=i.nodeIndex(j),n=c,p=d),!k)){for(g=j.previousSibling,e=j.nextSibling,h.each(h.grep(j.childNodes),function(a){3==a.nodeType&&(a.nodeValue=a.nodeValue.replace(/\uFEFF/g,""))});j=i.get(b.id+"_"+a);)i.remove(j,1);g&&e&&g.nodeType==e.nodeType&&3==g.nodeType&&!f.opera&&(d=g.nodeValue.length,g.appendData(e.nodeValue),i.remove(e),"start"==a?(m=n=g,o=p=d):(n=g,p=d))}}function e(a){return!i.isBlock(a)||a.innerHTML||f.ie||(a.innerHTML='<br data-mce-bogus="1&
 quot; />'),a}function j(){var c,d;return c=i.createRng(),d=a.resolve(i.getRoot(),b.start),c.setStart(d.container(),d.offset()),d=a.resolve(i.getRoot(),b.end),c.setEnd(d.container(),d.offset()),c}var k,l,m,n,o,p;if(b)if(h.isArray(b.start)){if(k=i.createRng(),l=i.getRoot(),g.tridentSel)return g.tridentSel.moveToBookmark(b);c(!0)&&c()&&g.setRng(k)}else"string"==typeof b.start?g.setRng(j(b)):b.id?(d("start"),d("end"),m&&(k=i.createRng(),k.setStart(e(m),o),k.setEnd(e(n),p),g.setRng(k))):b.name?g.select(i.select(b.name)[b.index]):b.rng&&g.setRng(b.rng)}}var j=d.isContentEditableFalse,k=function(a,b){var c,d;for(d=g.trim(a.data.slice(0,b)).length,c=a.previousSibling;c&&3===c.nodeType;c=c.previousSibling)d+=g.trim(c.data).length;return d};return i.isBookmarkNode=function(a){return a&&"SPAN"===a.tagName&&"bookmark"===a.getAttribute("data-mce-type")},i}),g("1o",[&qu
 ot;1j"],function(a){var b=function(a){for(var b=0,c=0,d=a;d&&d.nodeType;)b+=d.offsetLeft||0,c+=d.offsetTop||0,d=d.offsetParent;return{x:b,y:c}},c=function(a,b,c){var d={elm:b,alignToTop:c};return a.fire("scrollIntoView",d),d.isDefaultPrevented()},d=function(d,e,f){var g,h,i,j,k=d.dom,l=k.getRoot(),m=0;if(!c(d,e,f)&&a.isElement(e)){if(f===!1&&(m=e.offsetHeight),"BODY"!==l.nodeName){var n=d.selection.getScrollContainer();if(n)return g=b(e).y-b(n).y+m,j=n.clientHeight,i=n.scrollTop,void((g<i||g+25>i+j)&&(n.scrollTop=g<i?g:g-j+25))}h=k.getViewPort(d.getWin()),g=k.getPos(e).y+m,i=h.y,j=h.h,(g<h.y||g+25>i+j)&&d.getWin().scrollTo(0,g<i?g:g-j+25)}};return{scrollIntoView:d}}),g("1p",[],function(){function a(a){function b(b,c){var d,e,f,g,h,i,j,k,l=0,m=-1;if(d=b.duplicate(),d.collapse(c),k=d.parentElement(),k.ownerDocument===a.dom.doc){for(;"false"===k.contentEditable;)k=k.parentNode;if(!k.h
 asChildNodes())return{node:k,inside:1};for(g=k.children,e=g.length-1;l<=e;)if(j=Math.floor((l+e)/2),h=g[j],d.moveToElementText(h),m=d.compareEndPoints(c?"StartToStart":"EndToEnd",b),m>0)e=j-1;else{if(!(m<0))return{node:h};l=j+1}if(m<0)for(h?d.collapse(!1):(d.moveToElementText(k),d.collapse(!0),h=k,f=!0),i=0;0!==d.compareEndPoints(c?"StartToStart":"StartToEnd",b)&&0!==d.move("character",1)&&k==d.parentElement();)i++;else for(d.collapse(!0),i=0;0!==d.compareEndPoints(c?"StartToStart":"StartToEnd",b)&&0!==d.move("character",-1)&&k==d.parentElement();)i++;return{node:h,position:m,offset:i,inside:f}}}function c(){function c(a){var c,d,e,f,g,h=b(k,a),i=0;if(c=h.node,d=h.offset,h.inside&&!c.hasChildNodes())return void l[a?"setStart":"setEnd"](c,0);if(d===f)return void l[a?"setStartBefore":"setEndAfter"](c);if(h.position&
 lt;0){if(e=h.inside?c.firstChild:c.nextSibling,!e)return void l[a?"setStartAfter":"setEndAfter"](c);if(!d)return void(3==e.nodeType?l[a?"setStart":"setEnd"](e,0):l[a?"setStartBefore":"setEndBefore"](e));for(;e;){if(3==e.nodeType&&(g=e.nodeValue,i+=g.length,i>=d)){c=e,i-=d,i=g.length-i;break}e=e.nextSibling}}else{if(e=c.previousSibling,!e)return l[a?"setStartBefore":"setEndBefore"](c);if(!d)return void(3==c.nodeType?l[a?"setStart":"setEnd"](e,c.nodeValue.length):l[a?"setStartAfter":"setEndAfter"](e));for(;e;){if(3==e.nodeType&&(i+=e.nodeValue.length,i>=d)){c=e,i-=d;break}e=e.previousSibling}}l[a?"setStart":"setEnd"](c,i)}var f,g,h,i,j,k=a.getRng(),l=e.createRng();if(f=k.item?k.item(0):k.parentElement(),f.ownerDocument!=e.doc)return l;if(g=a.isCollapsed(),k.item)return l.setStart(f.parentNode,e.nodeIndex(f)),l.setEnd(l.startC
 ontainer,l.startOffset+1),l;try{c(!0),g||c()}catch(b){if(b.number!=-2147024809)throw b;j=d.getBookmark(2),h=k.duplicate(),h.collapse(!0),f=h.parentElement(),g||(h=k.duplicate(),h.collapse(!1),i=h.parentElement(),i.innerHTML=i.innerHTML),f.innerHTML=f.innerHTML,d.moveToBookmark(j),k=a.getRng(),c(!0),g||c()}return l}var d=this,e=a.dom,f=!1;this.getBookmark=function(c){function d(a){var b,c,d,f,g=[];for(b=a.parentNode,c=e.getRoot().parentNode;b!=c&&9!==b.nodeType;){for(d=b.children,f=d.length;f--;)if(a===d[f]){g.push(f);break}a=b,b=b.parentNode}return g}function f(a){var c;if(c=b(g,a))return{position:c.position,offset:c.offset,indexes:d(c.node),inside:c.inside}}var g=a.getRng(),h={};return 2===c&&(g.item?h.start={ctrl:!0,indexes:d(g.item(0))}:(h.start=f(!0),a.isCollapsed()||(h.end=f()))),h},this.moveToBookmark=function(a){function b(a){var b,c,d,f;for(b=e.getRoot(),c=a.length-1;c>=0;c--)f=b.children,d=a[c],d<=f.length-1&&(b=f[d]);return b}function c(c){var
  e,g,h,i,j=a[c?"start":"end"];j&&(e=j.position>0,g=f.createTextRange(),g.moveToElementText(b(j.indexes)),i=j.offset,i!==h?(g.collapse(j.inside||e),g.moveStart("character",e?-i:i)):g.collapse(c),d.setEndPoint(c?"StartToStart":"EndToStart",g),c&&d.collapse(!0))}var d,f=e.doc.body;a.start&&(a.start.ctrl?(d=f.createControlRange(),d.addElement(b(a.start.indexes)),d.select()):(d=f.createTextRange(),c(!0),c(),d.select()))},this.addRange=function(b){function c(a){var b,c,g,l,m;g=e.create("a"),b=a?h:j,c=a?i:k,l=d.duplicate(),b!=o&&b!=o.documentElement||(b=p,c=0),3==b.nodeType?(b.parentNode.insertBefore(g,b),l.moveToElementText(g),l.moveStart("character",c),e.remove(g),d.setEndPoint(a?"StartToStart":"EndToEnd",l)):(m=b.childNodes,m.length?(c>=m.length?e.insertAfter(g,m[m.length-1]):b.insertBefore(g,m[c]),l.moveToElementText(g)):b.canHaveHTML&&(b.innerHTML=&qu
 ot;<span>&#xFEFF;</span>",g=b.firstChild,l.moveToElementText(g),l.collapse(f)),d.setEndPoint(a?"StartToStart":"EndToEnd",l),e.remove(g))}var d,g,h,i,j,k,l,m,n,o=a.dom.doc,p=o.body;if(h=b.startContainer,i=b.startOffset,j=b.endContainer,k=b.endOffset,d=p.createTextRange(),h==j&&1==h.nodeType){if(i==k&&!h.hasChildNodes()){if(h.canHaveHTML)return l=h.previousSibling,l&&!l.hasChildNodes()&&e.isBlock(l)?l.innerHTML="&#xFEFF;":l=null,h.innerHTML="<span>&#xFEFF;</span><span>&#xFEFF;</span>",d.moveToElementText(h.lastChild),d.select(),e.doc.selection.clear(),h.innerHTML="",void(l&&(l.innerHTML=""));i=e.nodeIndex(h),h=h.parentNode}if(i==k-1)try{if(n=h.childNodes[i],g=p.createControlRange(),g.addElement(n),g.select(),m=a.getRng(),m.item&&n===m.item(0))return}catch(a){}}c(!0),c(),d.select()},this.getRangeAt=c}return a}),g("5l&q
 uot;,["4r","4t"],function(a,b){var c=function(c){if(null===c)return"null";var d=typeof c;return"object"===d&&a.prototype.isPrototypeOf(c)?"array":"object"===d&&b.prototype.isPrototypeOf(c)?"string":d},d=function(a){return function(b){return c(b)===a}};return{isString:d("string"),isObject:d("object"),isArray:d("array"),isNull:d("null"),isBoolean:d("boolean"),isUndefined:d("undefined"),isFunction:d("function"),isNumber:d("number")}}),g("67",["3s","3t","4r","4s"],function(a,b,c,d){return function(){var e=arguments;return function(){for(var f=new c(arguments.length),g=0;g<f.length;g++)f[g]=arguments[g];if(e.length!==f.length)throw new d('Wrong number of arguments to struct. Expected "['+e.length+']", got '+f.length+" arguments");var h={};return a.each(
 e,function(a,c){h[a]=b.constant(f[c])}),h}}}),g("5r",["4q","5j"],function(a,b){var c=function(){var a=b.keys,c=function(a){var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c);return b};return void 0===a?c:a}(),d=function(a,b){for(var d=c(a),e=0,f=d.length;e<f;e++){var g=d[e],h=a[g];b(h,g,a)}},e=function(a,b){return f(a,function(a,c,d){return{k:c,v:b(a,c,d)}})},f=function(a,b){var c={};return d(a,function(d,e){var f=b(d,e,a);c[f.k]=f.v}),c},g=function(a,b){var c={},e={};return d(a,function(a,d){var f=b(a,d)?c:e;f[d]=a}),{t:c,f:e}},h=function(a,b){var c=[];return d(a,function(a,d){c.push(b(a,d))}),c},i=function(b,d){for(var e=c(b),f=0,g=e.length;f<g;f++){var h=e[f],i=b[h];if(d(i,h,b))return a.some(i)}return a.none()},j=function(a){return h(a,function(a){return a})},k=function(a){return j(a).length};return{bifilter:g,each:d,map:e,mapToArray:h,tupleMap:f,find:i,keys:c,values:j,size:k}}),g("6t",["3s","5l","
 4s"],function(a,b,c){var d=function(a){return a.slice(0).sort()},e=function(a,b){throw new c("All required keys ("+d(a).join(", ")+") were not specified. Specified keys were: "+d(b).join(", ")+".")},f=function(a){throw new c("Unsupported keys for object: "+d(a).join(", "))},g=function(d,e){if(!b.isArray(e))throw new c("The "+d+" fields must be an array. Was: "+e+".");a.each(e,function(a){if(!b.isString(a))throw new c("The value "+a+" in the "+d+" fields was not a string.")})},h=function(a,b){throw new c("All values need to be of type: "+b+". Keys ("+d(a).join(", ")+") were not.")},i=function(b){var e=d(b),f=a.find(e,function(a,b){return b<e.length-1&&a===e[b+1]});f.each(function(a){throw new c("The field: "+a+" occurs more than once in the combined fields: ["+e.join(", "
 )+"].")})};return{sort:d,reqMessage:e,unsuppMessage:f,validateStrArr:g,invalidTypeMessage:h,checkDupes:i}}),g("68",["3s","3t","5r","4q","6t","4s","5j"],function(a,b,c,d,e,f,g){return function(h,i){var j=h.concat(i);if(0===j.length)throw new f("You must specify at least one required or optional field.");return e.validateStrArr("required",h),e.validateStrArr("optional",i),e.checkDupes(j),function(f){var k=c.keys(f),l=a.forall(h,function(b){return a.contains(k,b)});l||e.reqMessage(h,k);var m=a.filter(k,function(b){return!a.contains(j,b)});m.length>0&&e.unsuppMessage(m);var n={};return a.each(h,function(a){n[a]=b.constant(f[a])}),a.each(i,function(a){n[a]=b.constant(g.prototype.hasOwnProperty.call(f,a)?d.some(f[a]):d.none())}),n}}}),g("5m",["67","68"],function(a,b){return{immutable:a,immutableBag:b}}),g("5n",[],functio
 n(){var a=function(a,b){var c=[],d=function(a){return c.push(a),b(a)},e=b(a);do e=e.bind(d);while(e.isSome());return c};return{toArray:a}}),g("78",[],function(){return"undefined"!=typeof window?window:Function("return this;")()}),g("6u",["78"],function(a){var b=function(b,c){for(var d=void 0!==c?c:a,e=0;e<b.length&&void 0!==d&&null!==d;++e)d=d[b[e]];return d},c=function(a,c){var d=a.split(".");return b(d,c)},d=function(a,b){return void 0!==a[b]&&null!==a[b]||(a[b]={}),a[b]},e=function(b,c){for(var e=void 0!==c?c:a,f=0;f<b.length;++f)e=d(e,b[f]);return e},f=function(a,b){var c=a.split(".");return e(c,b)};return{path:b,resolve:c,forge:e,namespace:f}}),g("69",["6u"],function(a){var b=function(b,c){return a.resolve(b,c)},c=function(a,c){var d=b(a,c);if(void 0===d)throw a+" not available on this browser";return d};return{getOrDie:c}}),g("5o",["6
 9"],function(a){var b=function(){var b=a.getOrDie("Node");return b},c=function(a,b,c){return 0!==(a.compareDocumentPosition(b)&c)},d=function(a,d){return c(a,d,b().DOCUMENT_POSITION_PRECEDING)},e=function(a,d){return c(a,d,b().DOCUMENT_POSITION_CONTAINED_BY)};return{documentPositionPreceding:d,documentPositionContainedBy:e}}),g("6a",[],function(){var a=function(a){var b,c=!1;return function(){return c||(c=!0,b=a.apply(null,arguments)),b}};return{cached:a}}),h("7d",Number),g("79",["3s","7d","4t"],function(a,b,c){var d=function(a,b){for(var c=0;c<a.length;c++){var d=a[c];if(d.test(b))return d}},e=function(a,c){var e=d(a,c);if(!e)return{major:0,minor:0};var f=function(a){return b(c.replace(e,"$"+a))};return h(f(1),f(2))},f=function(a,b){var d=c(b).toLowerCase();return 0===a.length?g():e(a,d)},g=function(){return h(0,0)},h=function(a,b){return{major:a,minor:b}};return{nu:h,detect:f,unknown:g}}),g
 ("6v",["3t","79"],function(a,b){var c="Edge",d="Chrome",e="IE",f="Opera",g="Firefox",h="Safari",i=function(a,b){return function(){return b===a}},j=function(){return k({current:void 0,version:b.unknown()})},k=function(a){var b=a.current,j=a.version;return{current:b,version:j,isEdge:i(c,b),isChrome:i(d,b),isIE:i(e,b),isOpera:i(f,b),isFirefox:i(g,b),isSafari:i(h,b)}};return{unknown:j,nu:k,edge:a.constant(c),chrome:a.constant(d),ie:a.constant(e),opera:a.constant(f),firefox:a.constant(g),safari:a.constant(h)}}),g("6w",["3t","79"],function(a,b){var c="Windows",d="iOS",e="Android",f="Linux",g="OSX",h="Solaris",i="FreeBSD",j=function(a,b){return function(){return b===a}},k=function(){return l({current:void 0,version:b.unknown()})},l=function(a){var b=a.current,k=a.version;return{current:b,version:k,isWin
 dows:j(c,b),isiOS:j(d,b),isAndroid:j(e,b),isOSX:j(g,b),isLinux:j(f,b),isSolaris:j(h,b),isFreeBSD:j(i,b)}};return{unknown:k,nu:l,windows:a.constant(c),ios:a.constant(d),android:a.constant(e),linux:a.constant(f),osx:a.constant(g),solaris:a.constant(h),freebsd:a.constant(i)}}),g("6x",["3t"],function(a){return function(b,c,d){var e=b.isiOS()&&/ipad/i.test(d)===!0,f=b.isiOS()&&!e,g=b.isAndroid()&&3===b.version.major,h=b.isAndroid()&&4===b.version.major,i=e||g||h&&/mobile/i.test(d)===!0,j=b.isiOS()||b.isAndroid(),k=j&&!i,l=c.isSafari()&&b.isiOS()&&/safari/i.test(d)===!1;return{isiPad:a.constant(e),isiPhone:a.constant(f),isTablet:a.constant(i),isPhone:a.constant(k),isTouch:a.constant(j),isAndroid:b.isAndroid,isiOS:b.isiOS,isWebView:a.constant(l)}}}),g("6y",["3s","79","4t"],function(a,b,c){var d=function(b,d){var e=c(d).toLowerCase();return a.find(b,function(a){return 
 a.search(e)})},e=function(a,c){return d(a,c).map(function(a){var d=b.detect(a.versionRegexes,c);return{current:a.name,version:d}})},f=function(a,c){return d(a,c).map(function(a){var d=b.detect(a.versionRegexes,c);return{current:a.name,version:d}})};return{detectBrowser:e,detectOs:f}}),g("7e",[],function(){var a=function(a,b){return b+a},b=function(a,b){return a+b},c=function(a,b){return a.substring(b)},d=function(a,b){return a.substring(0,a.length-b)};return{addToStart:a,addToEnd:b,removeFromStart:c,removeFromEnd:d}}),g("7f",["4q","4s"],function(a,b){var c=function(a,b){return a.substr(0,b)},d=function(a,b){return a.substr(a.length-b,a.length)},e=function(b){return""===b?a.none():a.some(b.substr(0,1))},f=function(b){return""===b?a.none():a.some(b.substring(1))};return{first:c,last:d,head:e,tail:f}}),g("7a",["7e","7f","4s"],function(a,b,c){var d=function(a,b,c){if(""===b)retu
 rn!0;if(a.length<b.length)return!1;var d=a.substr(c,c+b.length);return d===b},e=function(a,b){var c=function(a){var b=typeof a;return"string"===b||"number"===b};return a.replace(/\${([^{}]*)}/g,function(a,d){var e=b[d];return c(e)?e:a})},f=function(b,c){return l(b,c)?a.removeFromStart(b,c.length):b},g=function(b,c){return m(b,c)?a.removeFromEnd(b,c.length):b},h=function(b,c){return l(b,c)?b:a.addToStart(b,c)},i=function(b,c){return m(b,c)?b:a.addToEnd(b,c)},j=function(a,b){return a.indexOf(b)!==-1},k=function(a){return b.head(a).bind(function(c){return b.tail(a).map(function(a){return c.toUpperCase()+a})}).getOr(a)},l=function(a,b){return d(a,b,0)},m=function(a,b){return d(a,b,a.length-b.length)},n=function(a){return a.replace(/^\s+|\s+$/g,"")},o=function(a){return a.replace(/^\s+/g,"")},p=function(a){return a.replace(/\s+$/g,"")};return{supplant:e,startsWith:l,removeLeading:f,removeTrailing:g,ensureLeading:h,ensureTrailing:i,ends
 With:m,contains:j,trim:n,lTrim:o,rTrim:p,capitalize:k}}),g("6z",["3t","7a"],function(a,b){var c=/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,d=function(a){return function(c){return b.contains(c,a)}},e=[{name:"Edge",versionRegexes:[/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],search:function(a){var c=b.contains(a,"edge/")&&b.contains(a,"chrome")&&b.contains(a,"safari")&&b.contains(a,"applewebkit");return c}},{name:"Chrome",versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/,c],search:function(a){return b.contains(a,"chrome")&&!b.contains(a,"chromeframe")}},{name:"IE",versionRegexes:[/.*?msie\ ?([0-9]+)\.([0-9]+).*/,/.*?rv:([0-9]+)\.([0-9]+).*/],search:function(a){return b.contains(a,"msie")||b.contains(a,"trident")}},{name:"Opera",versionRegexes:[c,/.*?opera\/([0-9]+)\.([0-9]+).*/],search:d("opera")},{name:"Fi
 refox",versionRegexes:[/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],search:d("firefox")},{name:"Safari",versionRegexes:[c,/.*?cpu os ([0-9]+)_([0-9]+).*/],search:function(a){return(b.contains(a,"safari")||b.contains(a,"mobile/"))&&b.contains(a,"applewebkit")}}],f=[{name:"Windows",search:d("win"),versionRegexes:[/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]},{name:"iOS",search:function(a){return b.contains(a,"iphone")||b.contains(a,"ipad")},versionRegexes:[/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,/.*cpu os ([0-9]+)_([0-9]+).*/,/.*cpu iphone os ([0-9]+)_([0-9]+).*/]},{name:"Android",search:d("android"),versionRegexes:[/.*?android\ ?([0-9]+)\.([0-9]+).*/]},{name:"OSX",search:d("os x"),versionRegexes:[/.*?os\ x\ ?([0-9]+)_([0-9]+).*/]},{name:"Linux",search:d("linux"),versionRegexes:[]},{name:"Solaris",search:d("suno
 s"),versionRegexes:[]},{name:"FreeBSD",search:d("freebsd"),versionRegexes:[]}];return{browsers:a.constant(e),oses:a.constant(f)}}),g("6b",["6v","6w","6x","6y","6z"],function(a,b,c,d,e){var f=function(f){var g=e.browsers(),h=e.oses(),i=d.detectBrowser(g,f).fold(a.unknown,a.nu),j=d.detectOs(h,f).fold(b.unknown,b.nu),k=c(j,i,f);return{browser:i,os:j,deviceType:k}};return{detect:f}}),h("6c",navigator),g("5p",["6a","6b","6c"],function(a,b,c){var d=a.cached(function(){var a=c.userAgent;return b.detect(a)});return{detect:d}}),g("4z",[],function(){return"undefined"==typeof console&&(console={log:function(){}}),console}),h("1y",document),g("42",["3t","4s","4z","1y"],function(a,b,c,d){var e=function(a,b){var e=b||d,f=e.createElement("div");if(f.innerHTML=a,!f.hasC
 hildNodes()||f.childNodes.length>1)throw c.error("HTML does not have a single root node",a),"HTML must have a single root node";return h(f.childNodes[0])},f=function(a,b){var c=b||d,e=c.createElement(a);return h(e)},g=function(a,b){var c=b||d,e=c.createTextNode(a);return h(e)},h=function(c){if(null===c||void 0===c)throw new b("Node cannot be null or undefined");return{dom:a.constant(c)}};return{fromHtml:e,fromTag:f,fromText:g,fromDom:h}}),g("52",[],function(){return{ATTRIBUTE:2,CDATA_SECTION:4,COMMENT:8,DOCUMENT:9,DOCUMENT_TYPE:10,DOCUMENT_FRAGMENT:11,ELEMENT:1,TEXT:3,PROCESSING_INSTRUCTION:7,ENTITY_REFERENCE:5,ENTITY:6,NOTATION:12}}),g("5q",["3s","4q","42","52","4s","1y"],function(a,b,c,d,e,f){var g=0,h=1,i=2,j=3,k=function(){var a=f.createElement("span");return void 0!==a.matches?g:void 0!==a.msMatchesSelector?h:void 0!==a.webkitMatchesSelector?i:void 0!==a.mo
 zMatchesSelector?j:-1}(),l=d.ELEMENT,m=d.DOCUMENT,n=function(a,b){var c=a.dom();if(c.nodeType!==l)return!1;if(k===g)return c.matches(b);if(k===h)return c.msMatchesSelector(b);if(k===i)return c.webkitMatchesSelector(b);if(k===j)return c.mozMatchesSelector(b);throw new e("Browser lacks native selectors")},o=function(a){return a.nodeType!==l&&a.nodeType!==m||0===a.childElementCount},p=function(b,d){var e=void 0===d?f:d.dom();return o(e)?[]:a.map(e.querySelectorAll(b),c.fromDom)},q=function(a,d){var e=void 0===d?f:d.dom();return o(e)?b.none():b.from(e.querySelector(a)).map(c.fromDom)};return{all:p,is:n,one:q}}),g("53",["3s","3t","5o","5p","5q"],function(a,b,c,d,e){var f=function(a,b){return a.dom()===b.dom()},g=function(a,b){return a.dom().isEqualNode(b.dom())},h=function(c,d){return a.exists(d,b.curry(f,c))},i=function(a,b){var c=a.dom(),d=b.dom();return c!==d&&c.contains(d)},j=function(a,b){return c.
 documentPositionContainedBy(a.dom(),b.dom())},k=d.detect().browser,l=k.isIE()?j:i;
-return{eq:f,isEqualNode:g,member:h,contains:l,is:e.is}}),g("4x",["5l","3s","3t","4q","5m","5n","53","42"],function(a,b,c,d,e,f,g,h){var i=function(a){return h.fromDom(a.dom().ownerDocument)},j=function(a){var b=i(a);return h.fromDom(b.dom().documentElement)},k=function(a){var b=a.dom(),c=b.ownerDocument.defaultView;return h.fromDom(c)},l=function(a){var b=a.dom();return d.from(b.parentNode).map(h.fromDom)},m=function(a){return l(a).bind(function(c){var d=u(c);return b.findIndex(d,function(b){return g.eq(a,b)})})},n=function(b,d){for(var e=a.isFunction(d)?d:c.constant(!1),f=b.dom(),g=[];null!==f.parentNode&&void 0!==f.parentNode;){var i=f.parentNode,j=h.fromDom(i);if(g.push(j),e(j)===!0)break;f=i}return g},o=function(a){var c=function(c){return b.filter(c,function(b){return!g.eq(a,b)})};return l(a).map(u).map(c).getOr([])},p=function(a){var b=a.dom();return d.from(b.offsetParent).map(h.f
 romDom)},q=function(a){var b=a.dom();return d.from(b.previousSibling).map(h.fromDom)},r=function(a){var b=a.dom();return d.from(b.nextSibling).map(h.fromDom)},s=function(a){return b.reverse(f.toArray(a,q))},t=function(a){return f.toArray(a,r)},u=function(a){var c=a.dom();return b.map(c.childNodes,h.fromDom)},v=function(a,b){var c=a.dom().childNodes;return d.from(c[b]).map(h.fromDom)},w=function(a){return v(a,0)},x=function(a){return v(a,a.dom().childNodes.length-1)},y=e.immutable("element","offset"),z=function(a,b){var c=u(a);return c.length>0&&b<c.length?y(c[b],0):y(a,b)};return{owner:i,defaultView:k,documentElement:j,parent:l,findIndex:m,parents:n,siblings:o,prevSibling:q,offsetParent:p,prevSiblings:s,nextSibling:r,nextSiblings:t,children:u,child:v,firstChild:w,lastChild:x,leaf:z}}),g("40",["4x"],function(a){var b=function(b,c){var d=a.parent(b);d.each(function(a){a.dom().insertBefore(c.dom(),b.dom())})},c=function(c,d){var f=a
 .nextSibling(c);f.fold(function(){var b=a.parent(c);b.each(function(a){e(a,d)})},function(a){b(a,d)})},d=function(b,c){var d=a.firstChild(b);d.fold(function(){e(b,c)},function(a){b.dom().insertBefore(c.dom(),a.dom())})},e=function(a,b){a.dom().appendChild(b.dom())},f=function(c,d,f){a.child(c,f).fold(function(){e(c,d)},function(a){b(a,d)})},g=function(a,c){b(a,c),e(c,a)};return{before:b,after:c,prepend:d,append:e,appendAt:f,wrap:g}}),g("44",["52"],function(a){var b=function(a){var b=a.dom().nodeName;return b.toLowerCase()},c=function(a){return a.dom().nodeType},d=function(a){return a.dom().nodeValue},e=function(a){return function(b){return c(b)===a}},f=function(d){return c(d)===a.COMMENT||"#comment"===b(d)},g=e(a.ELEMENT),h=e(a.TEXT),i=e(a.DOCUMENT);return{name:b,type:c,value:d,isElement:g,isText:h,isDocument:i,isComment:f}}),g("4y",["5l","3s","5r","44","4s","4z"],function(a,b,c,d,e,f
 ){var g=function(b,c,d){if(!(a.isString(d)||a.isBoolean(d)||a.isNumber(d)))throw f.error("Invalid call to Attr.set. Key ",c,":: Value ",d,":: Element ",b),new e("Attribute value was not simple");b.setAttribute(c,d+"")},h=function(a,b,c){g(a.dom(),b,c)},i=function(a,b){var d=a.dom();c.each(b,function(a,b){g(d,b,a)})},j=function(a,b){var c=a.dom().getAttribute(b);return null===c?void 0:c},k=function(a,b){var c=a.dom();return!(!c||!c.hasAttribute)&&c.hasAttribute(b)},l=function(a,b){a.dom().removeAttribute(b)},m=function(a){var b=a.dom().attributes;return void 0===b||null===b||0===b.length},n=function(a){return b.foldl(a.dom().attributes,function(a,b){return a[b.name]=b.value,a},{})},o=function(a,b,c){k(a,c)&&!k(b,c)&&h(b,c,j(a,c))},p=function(a,c,e){d.isElement(a)&&d.isElement(c)&&b.each(e,function(b){o(a,c,b)})};return{clone:n,set:h,setAll:i,get:j,has:k,remove:l,hasNone:m,transfer:p}}),g("5
 0",["3s","40"],function(a,b){var c=function(c,d){a.each(d,function(a){b.before(c,a)})},d=function(c,d){a.each(d,function(a,e){var f=0===e?c:d[e-1];b.after(f,a)})},e=function(c,d){a.each(d.slice().reverse(),function(a){b.prepend(c,a)})},f=function(c,d){a.each(d,function(a){b.append(c,a)})};return{before:c,after:d,prepend:e,append:f}}),g("51",["3s","50","4x"],function(a,b,c){var d=function(b){b.dom().textContent="",a.each(c.children(b),function(a){e(a)})},e=function(a){var b=a.dom();null!==b.parentNode&&b.parentNode.removeChild(b)},f=function(a){var d=c.children(a);d.length>0&&b.before(a,d),e(a)};return{empty:d,remove:e,unwrap:f}}),g("41",["4y","42","40","50","51","4x"],function(a,b,c,d,e,f){var g=function(a,c){return b.fromDom(a.dom().cloneNode(c))},h=function(a){return g(a,!1)},i=function(a){return g(a,!0)},j=function(c,d
 ){var e=b.fromTag(d),f=a.clone(c);return a.setAll(e,f),e},k=function(a,b){var c=j(a,b),e=f.children(i(a));return d.append(c,e),c},l=function(a,b){var g=j(a,b);c.before(a,g);var h=f.children(a);return d.append(g,h),e.remove(a),g};return{shallow:h,shallowAs:j,deep:i,copy:k,mutate:l}}),g("43",["3s","42","1y"],function(a,b,c){var d=function(d,e){var f=e||c,g=f.createDocumentFragment();return a.each(d,function(a){g.appendChild(a.dom())}),b.fromDom(g)};return{fromElements:d}}),g("45",["3s","3t","44"],function(a,b,c){var d=["article","aside","details","div","dt","figcaption","footer","form","fieldset","header","hgroup","html","main","nav","section","summary","body","p","dl","multicol","dd","figure&qu
 ot;,"address","center","blockquote","h1","h2","h3","h4","h5","h6","listing","xmp","pre","plaintext","menu","dir","ul","ol","li","hr","table","tbody","thead","tfoot","th","tr","td","caption"],e=["area","base","basefont","br","col","frame","hr","img","input","isindex","link","meta","param","embed","source","wbr","track"],f=["td","th"],g=["h1","h2","h3","h4","h5","h6","p","div","address","pre","form","blockquote",&qu
 ot;center","dir","fieldset","header","footer","article","section","hgroup","aside","nav","figure"],h=["h1","h2","h3","h4","h5","h6"],i=function(d){var e;return function(f){return e=e?e:a.mapToObject(d,b.constant(!0)),e.hasOwnProperty(c.name(f))}},j=i(h),k=i(d),l=function(a){return c.isElement(a)&&!k(a)};return{isBlock:k,isInline:l,isHeading:j,isTextBlock:i(g),isVoid:i(e),isTableCell:i(f)}}),g("46",["3t","53","4x"],function(a,b,c){var d=function(a){return a.slice(0,-1)},e=function(a,e,f){return b.contains(e,a)?d(c.parents(a,function(a){return f(a)||b.eq(a,e)})):[]},f=function(b,c){return e(b,c,a.constant(!1))},g=function(a,b){return[a].concat(f(a,b))};return{parentsUntil:e,parents:f,parentsAndSelf:g}}),g("54",["4q"],function(a){var b=function(a){for(var b
 =[],c=function(a){b.push(a)},d=0;d<a.length;d++)a[d].each(c);return b},c=function(b,c){for(var d=0;d<b.length;d++){var e=c(b[d],d);if(e.isSome())return e}return a.none()},d=function(b,c){for(var d=[],e=0;e<b.length;e++){var f=b[e];if(!f.isSome())return a.none();d.push(f.getOrDie())}return a.some(c.apply(null,d))};return{cat:b,findMap:c,liftN:d}}),g("47",["3s","3t","4q","54","53","42","44","4x","1j"],function(a,b,c,d,e,f,g,h,i){var j=function(a){var b=a.startContainer,d=a.startOffset;return i.isText(b)?0===d?c.some(f.fromDom(b)):c.none():c.from(b.childNodes[d]).map(f.fromDom)},k=function(a){var b=a.endContainer,d=a.endOffset;return i.isText(b)?d===b.data.length?c.some(f.fromDom(b)):c.none():c.from(b.childNodes[d-1]).map(f.fromDom)},l=function(a){return h.firstChild(a).fold(b.constant([a]),function(b){return[a].concat(l(b))})},m=function(a){return h.lastChild(a).fold(b.constant
 ([a]),function(b){return"br"===g.name(b)?h.prevSibling(b).map(function(b){return[a].concat(m(b))}).getOr([]):[a].concat(m(b))})},n=function(c,f){return d.liftN([j(f),k(f)],function(d,f){var g=a.find(l(c),b.curry(e.eq,d)),h=a.find(m(c),b.curry(e.eq,f));return g.isSome()&&h.isSome()}).getOr(!1)};return{hasAllContentsSelected:n}}),g("1q",["3s","3t","40","41","42","43","44","45","46","47"],function(a,b,c,d,e,f,g,h,i,j){var k=function(b){return a.find(b,function(a){return"ul"===g.name(a)||"ol"===g.name(a)})},l=function(c,d){return a.find(c,function(a){return"li"===g.name(a)&&j.hasAllContentsSelected(a,d)}).fold(b.constant([]),function(a){return k(c).map(function(a){return[e.fromTag("li"),e.fromTag(g.name(a))]}).getOr([])})},m=function(b,d){var e=a.foldl(d,function(a,b){return c.append(b,a),b},b);return d.length>
 0?f.fromElements([e]):e},n=function(b,c){var f=i.parentsAndSelf(e.fromDom(c.commonAncestorContainer),e.fromDom(b)),g=a.filter(f,function(a){return h.isInline(a)||h.isHeading(a)}),j=l(f,c);return a.map(g.concat(j),d.shallow)},o=function(a,b){return m(e.fromDom(b.cloneContents()),n(a,b))},p=function(a,b){return b.collapsed?f.fromElements([]):o(a,b)};return{read:p}}),g("s",["1n","r","q","1j","h","1o","c","1p","6","1q","1l","9"],function(a,b,c,d,e,f,g,h,i,j,k,l){function m(a,d,e,f){var g=this;g.dom=a,g.win=d,g.serializer=e,g.editor=f,g.bookmarkManager=new b(g),g.controlSelection=new c(g,f),g.win.getSelection||(g.tridentSel=new h(g))}var n=l.each,o=l.trim,p=i.ie,q=function(a){if(a){if(a.select)return!0;var b=a.startContainer,c=a.endContainer;return!!(b&&b.parentNode&&c&&c.parentNode)}return!1};return m.prototype={setCursorLocation:funct
 ion(a,b){var c=this,d=c.dom.createRng();a?(d.setStart(a,b),d.setEnd(a,b),c.setRng(d),c.collapse(!1)):(c._moveEndPoint(d,c.editor.getBody(),!0),c.setRng(d))},getContent:function(a){var b,c,d,e=this,f=e.getRng(),g=e.dom.create("body"),h=e.getSel();return a=a||{},b=c="",a.get=!0,a.format=a.format||"html",a.selection=!0,e.editor.fire("BeforeGetContent",a),"text"===a.format?e.isCollapsed()?"":k.trim(f.text||(h.toString?h.toString():"")):(f.cloneContents?(d=a.contextual?j.read(e.editor.getBody(),f).dom():f.cloneContents(),d&&g.appendChild(d)):void 0!==f.item||void 0!==f.htmlText?(g.innerHTML="<br>"+(f.item?f.item(0).outerHTML:f.htmlText),g.removeChild(g.firstChild)):g.innerHTML=f.toString(),/^\s/.test(g.innerHTML)&&(b=" "),/\s+$/.test(g.innerHTML)&&(c=" "),a.getInner=!0,a.content=e.isCollapsed()?"":b+e.serializer.serialize(g,a)+c,e.editor.fire("G
 etContent",a),a.content)},setContent:function(a,b){var c,d,e,f=this,g=f.getRng(),h=f.win.document;if(b=b||{format:"html"},b.set=!0,b.selection=!0,b.content=a,b.no_events||f.editor.fire("BeforeSetContent",b),a=b.content,g.insertNode){a+='<span id="__caret">_</span>',g.startContainer==h&&g.endContainer==h?h.body.innerHTML=a:(g.deleteContents(),0===h.body.childNodes.length?h.body.innerHTML=a:g.createContextualFragment?g.insertNode(g.createContextualFragment(a)):(d=h.createDocumentFragment(),e=h.createElement("div"),d.appendChild(e),e.outerHTML=a,g.insertNode(d))),c=f.dom.get("__caret"),g=h.createRange(),g.setStartBefore(c),g.setEndBefore(c),f.setRng(g),f.dom.remove("__caret");try{f.setRng(g)}catch(a){}}else g.item&&(h.execCommand("Delete",!1,null),g=f.getRng()),/^\s+/.test(a)?(g.pasteHTML('<span id="__mce_tmp">_</span>'+a),f.dom.remove("__mce_tmp")):g.p
 asteHTML(a);b.no_events||f.editor.fire("SetContent",b)},getStart:function(a){var b,c,d,e,f=this,g=f.getRng();if(g.duplicate||g.item){if(g.item)return g.item(0);for(d=g.duplicate(),d.collapse(1),b=d.parentElement(),b.ownerDocument!==f.dom.doc&&(b=f.dom.getRoot()),c=e=g.parentElement();e=e.parentNode;)if(e==b){b=c;break}return b}return b=g.startContainer,1==b.nodeType&&b.hasChildNodes()&&(a&&g.collapsed||(b=b.childNodes[Math.min(b.childNodes.length-1,g.startOffset)])),b&&3==b.nodeType?b.parentNode:b},getEnd:function(a){var b,c,d=this,e=d.getRng();return e.duplicate||e.item?e.item?e.item(0):(e=e.duplicate(),e.collapse(0),b=e.parentElement(),b.ownerDocument!==d.dom.doc&&(b=d.dom.getRoot()),b&&"BODY"==b.nodeName?b.lastChild||b:b):(b=e.endContainer,c=e.endOffset,1==b.nodeType&&b.hasChildNodes()&&(a&&e.collapsed||(b=b.childNodes[c>0?c-1:c])),b&&3==b.nodeType?b.parentNode:b)},getBo
 okmark:function(a,b){return this.bookmarkManager.getBookmark(a,b)},moveToBookmark:function(a){return this.bookmarkManager.moveToBookmark(a)},select:function(a,b){var c,d=this,e=d.dom,f=e.createRng();if(d.lastFocusBookmark=null,a){if(!b&&d.controlSelection.controlSelect(a))return;c=e.nodeIndex(a),f.setStart(a.parentNode,c),f.setEnd(a.parentNode,c+1),b&&(d._moveEndPoint(f,a,!0),d._moveEndPoint(f,a)),d.setRng(f)}return a},isCollapsed:function(){var a=this,b=a.getRng(),c=a.getSel();return!(!b||b.item)&&(b.compareEndPoints?0===b.compareEndPoints("StartToEnd",b):!c||b.collapsed)},collapse:function(a){var b,c=this,d=c.getRng();d.item&&(b=d.item(0),d=c.win.document.body.createTextRange(),d.moveToElementText(b)),d.collapse(!!a),c.setRng(d)},getSel:function(){var a=this.win;return a.getSelection?a.getSelection():a.document.selection},getRng:function(a){function b(a,b,c){try{return b.compareBoundaryPoints(a,c)}catch(a){return-1}}var c,d,e,f,g,h,i=this;
 if(!i.win)return null;if(f=i.win.document,"undefined"==typeof f||null===f)return null;if(!a&&i.lastFocusBookmark){var j=i.lastFocusBookmark;return j.startContainer?(d=f.createRange(),d.setStart(j.startContainer,j.startOffset),d.setEnd(j.endContainer,j.endOffset)):d=j,d}if(a&&i.tridentSel)return i.tridentSel.getRangeAt(0);try{(c=i.getSel())&&(d=c.rangeCount>0?c.getRangeAt(0):c.createRange?c.createRange():f.createRange())}catch(a){}if(h=i.editor.fire("GetSelectionRange",{range:d}),h.range!==d)return h.range;if(p&&d&&d.setStart&&f.selection){try{g=f.selection.createRange()}catch(a){}g&&g.item&&(e=g.item(0),d=f.createRange(),d.setStartBefore(e),d.setEndAfter(e))}return d||(d=f.createRange?f.createRange():f.body.createTextRange()),d.setStart&&9===d.startContainer.nodeType&&d.collapsed&&(e=i.dom.getRoot(),d.setStart(e,0),d.setEnd(e,0)),i.selectedRange&&i.explicitRange&amp
 ;&(0===b(d.START_TO_START,d,i.selectedRange)&&0===b(d.END_TO_END,d,i.selectedRange)?d=i.explicitRange:(i.selectedRange=null,i.explicitRange=null)),d},setRng:function(a,b){var c,d,e,f=this;if(q(a))if(a.select){f.explicitRange=null;try{a.select()}catch(a){}}else if(f.tridentSel){if(a.cloneRange)try{f.tridentSel.addRange(a)}catch(a){}}else{if(c=f.getSel(),e=f.editor.fire("SetSelectionRange",{range:a,forward:b}),a=e.range,c){f.explicitRange=a;try{c.removeAllRanges(),c.addRange(a)}catch(a){}b===!1&&c.extend&&(c.collapse(a.endContainer,a.endOffset),c.extend(a.startContainer,a.startOffset)),f.selectedRange=c.rangeCount>0?c.getRangeAt(0):null}a.collapsed||a.startContainer!==a.endContainer||!c.setBaseAndExtent||i.ie||a.endOffset-a.startOffset<2&&a.startContainer.hasChildNodes()&&(d=a.startContainer.childNodes[a.startOffset],d&&"IMG"===d.tagName&&(c.setBaseAndExtent(a.startContainer,a.startOffset,a.endContai
 ner,a.endOffset),c.anchorNode===a.startContainer&&c.focusNode===a.endContainer||c.setBaseAndExtent(d,0,d,1))),f.editor.fire("AfterSetSelectionRange",{range:a,forward:b})}},setNode:function(a){var b=this;return b.setContent(b.dom.getOuterHTML(a)),a},getNode:function(){function a(a,b){for(var c=a;a&&3===a.nodeType&&0===a.length;)a=b?a.nextSibling:a.previousSibling;return a||c}var b,c,d,e,f,g=this,h=g.getRng(),i=g.dom.getRoot();return h?(c=h.startContainer,d=h.endContainer,e=h.startOffset,f=h.endOffset,h.setStart?(b=h.commonAncestorContainer,!h.collapsed&&(c==d&&f-e<2&&c.hasChildNodes()&&(b=c.childNodes[e]),3===c.nodeType&&3===d.nodeType&&(c=c.length===e?a(c.nextSibling,!0):c.parentNode,d=0===f?a(d.previousSibling,!1):d.parentNode,c&&c===d))?c:b&&3==b.nodeType?b.parentNode:b):(b=h.item?h.item(0):h.parentElement(),b.ownerDocument!==g.win.document&&(b=i),b)):i},getSelectedBlocks:f
 unction(a,b){var c,d,e=this,f=e.dom,h=[];if(d=f.getRoot(),a=f.getParent(a||e.getStart(),f.isBlock),b=f.getParent(b||e.getEnd(),f.isBlock),a&&a!=d&&h.push(a),a&&b&&a!=b){c=a;for(var i=new g(a,d);(c=i.next())&&c!=b;)f.isBlock(c)&&h.push(c)}return b&&a!=b&&b!=d&&h.push(b),h},isForward:function(){var a,b,c=this.dom,d=this.getSel();return!(d&&d.anchorNode&&d.focusNode)||(a=c.createRng(),a.setStart(d.anchorNode,d.anchorOffset),a.collapse(!0),b=c.createRng(),b.setStart(d.focusNode,d.focusOffset),b.collapse(!0),a.compareBoundaryPoints(a.START_TO_START,b)<=0)},normalize:function(){var a=this,b=a.getRng();return i.range&&new e(a.dom).normalize(b)&&a.setRng(b,a.isForward()),b},selectorChanged:function(a,b){var c,d=this;return d.selectorChangedData||(d.selectorChangedData={},c={},d.editor.on("NodeChange",function(a){var b=a.element,e=d.dom,f=e.getParents(b,null,e.getRoot()),g={};
 n(d.selectorChangedData,function(a,b){n(f,function(d){if(e.is(d,b))return c[b]||(n(a,function(a){a(!0,{node:d,selector:b,parents:f})}),c[b]=a),g[b]=a,!1})}),n(c,function(a,d){g[d]||(delete c[d],n(a,function(a){a(!1,{node:b,selector:d,parents:f})}))})})),d.selectorChangedData[a]||(d.selectorChangedData[a]=[]),d.selectorChangedData[a].push(b),d},getScrollContainer:function(){for(var a,b=this.dom.getRoot();b&&"BODY"!=b.nodeName;){if(b.scrollHeight>b.clientHeight){a=b;break}b=b.parentNode}return a},scrollIntoView:function(a,b){f.scrollIntoView(this.editor,a,b)},placeCaretAt:function(a,b){this.setRng(e.getCaretRangeFromPoint(a,b,this.editor.getDoc()))},_moveEndPoint:function(a,b,c){var d=b,e=new g(b,d),f=this.dom.schema.getNonEmptyElements();do{if(3==b.nodeType&&0!==o(b.nodeValue).length)return void(c?a.setStart(b,0):a.setEnd(b,b.nodeValue.length));if(f[b.nodeName]&&!/^(TD|TH)$/.test(b.nodeName))return void(c?a.setStartBefore(b):"BR"==b.node
 Name?a.setEndBefore(b):a.setEndAfter(b));if(i.ie&&i.ie<11&&this.dom.isBlock(b)&&this.dom.isEmpty(b))return void(c?a.setStart(b,0):a.setEnd(b,0))}while(b=c?e.next():e.prev());"BODY"==d.nodeName&&(c?a.setStart(d,0):a.setEnd(d,d.childNodes.length))},getBoundingClientRect:function(){var b=this.getRng();return b.collapsed?a.fromRangeStart(b).getClientRects()[0]:b.getBoundingClientRect()},destroy:function(){this.win=null,this.controlSelection.destroy()}},m}),g("1r",["r","9"],function(a,b){function c(b){this.compare=function(c,e){function f(a){var c={};return d(b.getAttribs(a),function(d){var e=d.nodeName.toLowerCase();0!==e.indexOf("_")&&"style"!==e&&0!==e.indexOf("data-")&&(c[e]=b.getAttrib(a,e))}),c}function g(a,b){var c,d;for(d in a)if(a.hasOwnProperty(d)){if(c=b[d],"undefined"==typeof c)return!1;if(a[d]!=c)return!1;delete b[d]}for(d in b)if(b.hasOw
 nProperty(d))return!1;return!0}return c.nodeName==e.nodeName&&(!!g(f(c),f(e))&&(!!g(b.parseStyle(b.getAttrib(c,"style")),b.parseStyle(b.getAttrib(e,"style")))&&(!a.isBookmarkNode(c)&&!a.isBookmarkNode(e))))}}var d=b.each;return c}),g("1t",["e","9","j"],function(a,b,c){function d(a,d){function e(a,b){b.classes.length&&j.addClass(a,b.classes.join(" ")),j.setAttribs(a,b.attrs)}function f(a){var b;return k="string"==typeof a?{name:a,classes:[],attrs:{}}:a,b=j.create(k.name),e(b,k),b}function g(a,c){var d="string"!=typeof a?a.nodeName.toLowerCase():a,e=m.getElementRule(d),f=e&&e.parentsRequired;return!(!f||!f.length)&&(c&&b.inArray(f,c)!==-1?c:f[0])}function h(a,c,d){var e,i,k,l=c.length>0&&c[0],m=l&&l.name;if(k=g(a,m))m==k?(i=c[0],c=c.slice(1)):i=k;else if(l)i=c[0],c=c.slice(1);else if(!d)return a;return i&&(
 e=f(i),e.appendChild(a)),d&&(e||(e=j.create("div"),e.appendChild(a)),b.each(d,function(b){var c=f(b);e.insertBefore(c,a)})),h(e,c,i&&i.siblings)}var i,k,l,m=d&&d.schema||new c({});return a&&a.length?(k=a[0],i=f(k),l=j.create("div"),l.appendChild(h(i,a.slice(1),k.siblings)),l):""}function e(a,b){return d(g(a),b)}function f(a){var c,d={classes:[],attrs:{}};return a=d.selector=b.trim(a),"*"!==a&&(c=a.replace(/(?:([#\.]|::?)([\w\-]+)|(\[)([^\]]+)\]?)/g,function(a,c,e,f,g){switch(c){case"#":d.attrs.id=e;break;case".":d.classes.push(e);break;case":":b.inArray("checked disabled enabled read-only required".split(" "),e)!==-1&&(d.attrs[e]=e)}if("["==f){var h=g.match(/([\w\-]+)(?:\=\"([^\"]+))?/);h&&(d.attrs[h[1]]=h[2])}return""})),d.name=c||"div",d}function g(a){return a&&"string"==typeof a?
 (a=a.split(/\s*,\s*/)[0],a=a.replace(/\s*(~\+|~|\+|>)\s*/g,"$1"),b.map(a.split(/(?:>|\s+(?![^\[\]]+\]))/),function(a){var c=b.map(a.split(/(?:~\+|~|\+)/),f),d=c.pop();return c.length&&(d.siblings=c),d}).reverse()):[]}function h(a,b){function c(a){return a.replace(/%(\w+)/g,"")}var e,f,h,k,l,m,n="";if(m=a.settings.preview_styles,m===!1)return"";if("string"!=typeof m&&(m="font-family font-size font-weight font-style text-decoration text-transform color background-color border border-radius outline text-shadow"),"string"==typeof b){if(b=a.formatter.get(b),!b)return;b=b[0]}return"preview"in b&&(m=b.preview,m===!1)?"":(e=b.block||b.inline||"span",k=g(b.selector),k.length?(k[0].name||(k[0].name=e),e=b.selector,f=d(k,a)):f=d([e],a),h=j.select(e,f)[0]||f.firstChild,i(b.styles,function(a,b){a=c(a),a&&j.setStyle(h,b,a)}),i(b.attributes,function(a,b){a=c(a),
 a&&j.setAttrib(h,b,a)}),i(b.classes,function(a){a=c(a),j.hasClass(h,a)||j.addClass(h,a)}),a.fire("PreviewFormats"),j.setStyles(f,{position:"absolute",left:-65535}),a.getBody().appendChild(f),l=j.getStyle(a.getBody(),"fontSize",!0),l=/px$/.test(l)?parseInt(l,10):0,i(m.split(" "),function(b){var c=j.getStyle(h,b,!0);if(!("background-color"==b&&/transparent|rgba\s*\([^)]+,\s*0\)/.test(c)&&(c=j.getStyle(a.getBody(),b,!0),"#ffffff"==j.toHex(c).toLowerCase())||"color"==b&&"#000000"==j.toHex(c).toLowerCase())){if("font-size"==b&&/em|%$/.test(c)){if(0===l)return;c=parseFloat(c,10)/(/%$/.test(c)?100:1),c=c*l+"px"}"border"==b&&c&&(n+="padding:0 2px;"),n+=b+":"+c+";"}}),a.fire("AfterPreviewFormats"),j.remove(f),n)}var i=b.each,j=a.DOM;return{getCssText:h,parseSelector:g,selectorToHtml:e}}),g
 ("1u",["1g","1j","a"],function(a,b,c){function d(a,b){var c=f[a];c||(f[a]=c=[]),f[a].push(b)}function e(a,b){h(f[a],function(a){a(b)})}var f={},g=a.filter,h=a.each;return d("pre",function(d){function e(b){return i(b.previousSibling)&&a.indexOf(j,b.previousSibling)!=-1}function f(a,b){c(b).remove(),c(a).append("<br><br>").append(b.childNodes)}var i,j,k=d.selection.getRng();i=b.matchNodeNames("pre"),k.collapsed||(j=d.selection.getSelectedBlocks(),h(g(g(j,i),e),function(a){f(a.previousSibling,a)}))}),{postProcess:e}}),g("t",["c","h","r","1r","1j","1s","9","1t","1u"],function(a,b,c,d,e,f,g,h,i){return function(j){function k(a){return a.nodeType&&(a=a.nodeName),!!j.schema.getTextBlockElements()[a.toLowerCase()]}function l(a){return/^(TH|TD)$/.test(a.nodeName)}function m(a){return a&&/^
 (IMG)$/.test(a.nodeName)}function n(a,b){return da.getParents(a,b,da.getRoot())}function o(a){return 1===a.nodeType&&"_mce_caret"===a.id}function p(){s({valigntop:[{selector:"td,th",styles:{verticalAlign:"top"}}],valignmiddle:[{selector:"td,th",styles:{verticalAlign:"middle"}}],valignbottom:[{selector:"td,th",styles:{verticalAlign:"bottom"}}],alignleft:[{selector:"figure.image",collapsed:!1,classes:"align-left",ceFalseOverride:!0,preview:"font-family font-size"},{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li",styles:{textAlign:"left"},inherit:!1,preview:!1,defaultBlock:"div"},{selector:"img,table",collapsed:!1,styles:{"float":"left"},preview:"font-family font-size"}],aligncenter:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li",styles:{textAlign:"center"},inherit:
 !1,preview:!1,defaultBlock:"div"},{selector:"figure.image",collapsed:!1,classes:"align-center",ceFalseOverride:!0,preview:"font-family font-size"},{selector:"img",collapsed:!1,styles:{display:"block",marginLeft:"auto",marginRight:"auto"},preview:!1},{selector:"table",collapsed:!1,styles:{marginLeft:"auto",marginRight:"auto"},preview:"font-family font-size"}],alignright:[{selector:"figure.image",collapsed:!1,classes:"align-right",ceFalseOverride:!0,preview:"font-family font-size"},{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li",styles:{textAlign:"right"},inherit:!1,preview:"font-family font-size",defaultBlock:"div"},{selector:"img,table",collapsed:!1,styles:{"float":"right"},preview:"font-family font-size"}],alignjustify:[{selector:"figure,
 p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li",styles:{textAlign:"justify"},inherit:!1,defaultBlock:"div",preview:"font-family font-size"}],bold:[{inline:"strong",remove:"all"},{inline:"span",styles:{fontWeight:"bold"}},{inline:"b",remove:"all"}],italic:[{inline:"em",remove:"all"},{inline:"span",styles:{fontStyle:"italic"}},{inline:"i",remove:"all"}],underline:[{inline:"span",styles:{textDecoration:"underline"},exact:!0},{inline:"u",remove:"all"}],strikethrough:[{inline:"span",styles:{textDecoration:"line-through"},exact:!0},{inline:"strike",remove:"all"}],forecolor:{inline:"span",styles:{color:"%value"},links:!0,remove_similar:!0,clear_child_styles:!0},hilitecolor:{inline:"span",styles:{backgroundColor:"%value"},lin
 ks:!0,remove_similar:!0,clear_child_styles:!0},fontname:{inline:"span",styles:{fontFamily:"%value"},clear_child_styles:!0},fontsize:{inline:"span",styles:{fontSize:"%value"},clear_child_styles:!0},fontsize_class:{inline:"span",attributes:{"class":"%value"}},blockquote:{block:"blockquote",wrapper:1,remove:"all"},subscript:{inline:"sub"},superscript:{inline:"sup"},code:{inline:"code"},link:{inline:"a",selector:"a",remove:"all",split:!0,deep:!0,onmatch:function(){return!0},onformat:function(a,b,c){qa(c,function(b,c){da.setAttrib(a,c,b)})}},removeformat:[{selector:"b,strong,em,i,font,u,strike,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins",remove:"all",split:!0,expand:!1,block_expand:!0,deep:!0},{selector:"span",attributes:["style","class"],remove:"empty",split:!0,expand:!1,dee
 p:!0},{selector:"*",attributes:["style","class"],split:!1,expand:!1,deep:!0}]}),qa("p h1 h2 h3 h4 h5 h6 div address pre div dt dd samp".split(/\s/),function(a){s(a,{block:a,remove:"all"})}),s(j.settings.formats)}function q(){j.addShortcut("meta+b","bold_desc","Bold"),j.addShortcut("meta+i","italic_desc","Italic"),j.addShortcut("meta+u","underline_desc","Underline");for(var a=1;a<=6;a++)j.addShortcut("access+"+a,"",["FormatBlock",!1,"h"+a]);j.addShortcut("access+7","",["FormatBlock",!1,"p"]),j.addShortcut("access+8","",["FormatBlock",!1,"div"]),j.addShortcut("access+9","",["FormatBlock",!1,"address"])}function r(a){return a?ca[a]:ca}function s(a,b){a&&("string"!=typeof
  a?qa(a,function(a,b){s(b,a)}):(b=b.length?b:[b],qa(b,function(a){a.deep===_&&(a.deep=!a.selector),a.split===_&&(a.split=!a.selector||a.inline),a.remove===_&&a.selector&&!a.inline&&(a.remove="none"),a.selector&&a.inline&&(a.mixed=!0,a.block_expand=!0),"string"==typeof a.classes&&(a.classes=a.classes.split(/\s+/))}),ca[a]=b))}function t(a){return a&&ca[a]&&delete ca[a],ca}function u(a,b){var c=r(b);if(c)for(var d=0;d<c.length;d++)if(c[d].inherit===!1&&da.is(a,c[d].selector))return!0;return!1}function v(a){var b;return j.dom.getParent(a,function(a){return b=j.dom.getStyle(a,"text-decoration"),b&&"none"!==b}),b}function w(a){var b;1===a.nodeType&&a.parentNode&&1===a.parentNode.nodeType&&(b=v(a.parentNode),j.dom.getStyle(a,"color")&&b?j.dom.setStyle(a,"text-decoration",b):j.dom.getStyle(a,"text
 -decoration")===b&&j.dom.setStyle(a,"text-decoration",null))}function x(b,c,d){function e(a,b){if(b=b||p,a){if(b.onformat&&b.onformat(a,b,c,d),qa(b.styles,function(b,d){da.setStyle(a,d,O(b,c))}),b.styles){var e=da.getAttrib(a,"style");e&&a.setAttribute("data-mce-style",e)}qa(b.attributes,function(b,d){da.setAttrib(a,d,O(b,c))}),qa(b.classes,function(b){b=O(b,c),da.hasClass(a,b)||da.addClass(a,b)})}}function f(a,b){var c=!1;return!!p.selector&&(qa(a,function(a){if(!("collapsed"in a&&a.collapsed!==q))return da.is(b,a.selector)&&!o(b)?(e(b,a),c=!0,!1):void 0}),c)}function g(){function b(b,c){var e=new a(c);for(d=e.prev2();d;d=e.prev2()){if(3==d.nodeType&&d.data.length>0)return d;if(d.childNodes.length>1||d==b||"BR"==d.tagName)return d}}var c=j.selection.getRng(),e=c.startContainer,f=c.endContainer;if(e!=f&&0===c.endOffset){var g=b(e,f),h=3==g.nodeType?g.data.leng
 th:g.childNodes.length;c.setEnd(g,h)}return c}function h(a,d,g){var h,i,j=[],l=!0;h=p.inline||p.block,i=da.create(h),e(i),fa.walk(a,function(a){function d(a){var q,r,s,t;if(t=l,q=a.nodeName.toLowerCase(),r=a.parentNode.nodeName.toLowerCase(),1===a.nodeType&&oa(a)&&(t=l,l="true"===oa(a),s=!0),H(q,"br"))return m=0,void(p.block&&da.remove(a));if(p.wrapper&&A(a,b,c))return void(m=0);if(l&&!s&&p.block&&!p.wrapper&&k(q)&&ga(r,h))return a=da.rename(a,h),e(a),j.push(a),void(m=0);if(p.selector){var u=f(n,a);if(!p.inline||u)return void(m=0)}!l||s||!ga(h,q)||!ga(r,h)||!g&&3===a.nodeType&&1===a.nodeValue.length&&65279===a.nodeValue.charCodeAt(0)||o(a)||p.inline&&ha(a)?(m=0,qa(ra(a.childNodes),d),s&&(l=t),m=0):(m||(m=da.clone(i,ma),a.parentNode.insertBefore(m,a),j.push(m)),m.appendChild(a))}var m;qa(a,d)}),p.links===!0&&qa(j,function(a){function b(a){"A
 "===a.nodeName&&e(a,p),qa(ra(a.childNodes),b)}b(a)}),qa(j,function(a){function d(a){var b=0;return qa(a.childNodes,function(a){P(a)||pa(a)||b++}),b}function f(a){var b=!1;return qa(a.childNodes,function(a){if(J(a))return b=a,!1}),b}function g(a,b){do{if(1!==d(a))break;if(a=f(a),!a)break;if(b(a))return a}while(a);return null}function h(a){var b,c;return b=f(a),b&&!pa(b)&&G(b,p)&&(c=da.clone(b,ma),e(c),da.replace(c,a,na),da.remove(b,1)),c||a}var i;if(i=d(a),(j.length>1||!ha(a))&&0===i)return void da.remove(a,1);if(p.inline||p.wrapper){if(p.exact||1!==i||(a=h(a)),qa(n,function(b){qa(da.select(b.inline,a),function(a){J(a)&&T(b,c,a,b.exact?a:null)}),ua(b,a)}),A(a.parentNode,b,c)&&T(p,c,a)&&(a=0),p.merge_with_parents&&da.getParent(a.parentNode,function(d){if(A(d,b,c))return T(p,c,a)&&(a=0),na}),a&&!ha(a)&&!M(a,"fontSize")){var k=g(a,K("fontSize"));k&&x("
 fontsize",{value:M(k,"fontSize")},a)}a&&p.merge_siblings!==!1&&(a=W(V(a),a),a=W(a,V(a,na)))}})}var l,m,n=r(b),p=n[0],q=!d&&ea.isCollapsed();if("false"!==oa(ea.getNode())){if(p){if(d)d.nodeType?f(n,d)||(m=da.createRng(),m.setStartBefore(d),m.setEndAfter(d),h(R(m,n),null,!0)):h(d,null,!0);else if(q&&p.inline&&!da.select("td[data-mce-selected],th[data-mce-selected]").length)Y("apply",b,c);else{var s=j.selection.getNode();ia||!n[0].defaultBlock||da.getParent(s,da.isBlock)||x(n[0].defaultBlock),j.selection.setRng(g()),l=ea.getBookmark(),h(R(ea.getRng(na),n),l),p.styles&&((p.styles.color||p.styles.textDecoration)&&(sa(s,w,"childNodes"),w(s)),p.styles.backgroundColor&&I(s,K("fontSize"),L("backgroundColor",O(p.styles.backgroundColor,c)))),ea.moveToBookmark(l),Z(ea.getRng(na)),j.nodeChanged()}i.postProcess(b,j)}}else{d=ea.getNode();for(var t=0,u=n.length;
 t<u;t++)if(n[t].ceFalseOverride&&da.is(d,n[t].selector))return void e(d,n[t])}}function y(a,b,c,d){function e(a){var c,d,f,g,h;if(1===a.nodeType&&oa(a)&&(g=s,s="true"===oa(a),h=!0),c=ra(a.childNodes),s&&!h)for(d=0,f=p.length;d<f&&!T(p[d],b,a,a);d++);if(q.deep&&c.length){for(d=0,f=c.length;d<f;d++)e(c[d]);h&&(s=g)}}function f(c){var e;return qa(n(c.parentNode).reverse(),function(c){var f;e||"_start"==c.id||"_end"==c.id||(f=A(c,a,b,d),f&&f.split!==!1&&(e=c))}),e}function g(a,c,d,e){var f,g,h,i,j,k;if(a){for(k=a.parentNode,f=c.parentNode;f&&f!=k;f=f.parentNode){for(g=da.clone(f,ma),j=0;j<p.length;j++)if(T(p[j],b,g,g)){g=0;break}g&&(h&&g.appendChild(h),i||(i=g),h=g)}!e||q.mixed&&ha(a)||(c=da.split(a,c)),h&&(d.parentNode.insertBefore(h,d),i.appendChild(d))}return c}function h(a){return g(f(a),a,a,!0)}function i(a){var b=da.get(a?"_
 start":"_end"),c=b[a?"firstChild":"lastChild"];return pa(c)&&(c=c[a?"firstChild":"lastChild"]),3==c.nodeType&&0===c.data.length&&(c=a?b.previousSibling||b.nextSibling:b.nextSibling||b.previousSibling),da.remove(b,!0),c}function k(a){var b,c,d=a.commonAncestorContainer;if(a=R(a,p,na),q.split){if(b=X(a,na),c=X(a),b!=c){if(/^(TR|TH|TD)$/.test(b.nodeName)&&b.firstChild&&(b="TR"==b.nodeName?b.firstChild.firstChild||b:b.firstChild||b),d&&/^T(HEAD|BODY|FOOT|R)$/.test(d.nodeName)&&l(c)&&c.firstChild&&(c=c.firstChild||c),da.isChildOf(b,c)&&!ha(c)&&!l(b)&&!l(c))return b=Q(b,"span",{id:"_start","data-mce-type":"bookmark"}),h(b),void(b=i(na));b=Q(b,"span",{id:"_start","data-mce-type":"bookmark"}),c=Q(c,"span",{id:"_end","data-mce-typ
 e":"bookmark"}),h(b),h(c),b=i(na),c=i()}else b=c=h(b);a.startContainer=b.parentNode?b.parentNode:b,a.startOffset=ja(b),a.endContainer=c.parentNode?c.parentNode:c,a.endOffset=ja(c)+1}fa.walk(a,function(a){qa(a,function(a){e(a),1===a.nodeType&&"underline"===j.dom.getStyle(a,"text-decoration")&&a.parentNode&&"underline"===v(a.parentNode)&&T({deep:!1,exact:!0,inline:"span",styles:{textDecoration:"underline"}},null,a)})})}var m,o,p=r(a),q=p[0],s=!0;if(c)return void(c.nodeType?(o=da.createRng(),o.setStartBefore(c),o.setEndAfter(c),k(o)):k(c));if("false"!==oa(ea.getNode()))ea.isCollapsed()&&q.inline&&!da.select("td[data-mce-selected],th[data-mce-selected]").length?Y("remove",a,b,d):(m=ea.getBookmark(),
-k(ea.getRng(na)),ea.moveToBookmark(m),q.inline&&B(a,b,ea.getStart())&&Z(ea.getRng(!0)),j.nodeChanged());else{c=ea.getNode();for(var t=0,u=p.length;t<u&&(!p[t].ceFalseOverride||!T(p[t],b,c,c));t++);}}function z(a,b,c){var d=r(a);!B(a,b,c)||"toggle"in d[0]&&!d[0].toggle?x(a,b,c):y(a,b,c)}function A(a,b,c,d){function e(a,b,e){var f,g,h,i=b[e];if(b.onmatch)return b.onmatch(a,b,e);if(i)if(i.length===_){for(f in i)if(i.hasOwnProperty(f)){if(g="attributes"===e?da.getAttrib(a,f):M(a,f),d&&!g&&!b.exact)return;if((!d||b.exact)&&!H(g,N(O(i[f],c),f)))return}}else for(h=0;h<i.length;h++)if("attributes"===e?da.getAttrib(a,i[h]):M(a,i[h]))return b;return b}var f,g,h,i=r(b);if(i&&a)for(g=0;g<i.length;g++)if(f=i[g],G(a,f)&&e(a,f,"attributes")&&e(a,f,"styles")){if(h=f.classes)for(g=0;g<h.length;g++)if(!da.hasClass(a,h[g]))return;return f}}function B(a,b,c){func
 tion d(c){var d=da.getRoot();return c!==d&&(c=da.getParent(c,function(c){return!!u(c,a)||(c.parentNode===d||!!A(c,a,b,!0))}),A(c,a,b))}var e;return c?d(c):(c=ea.getNode(),d(c)?na:(e=ea.getStart(),e!=c&&d(e)?na:ma))}function C(a,b){var c,d=[],e={};return c=ea.getStart(),da.getParent(c,function(c){var f,g;for(f=0;f<a.length;f++)g=a[f],!e[g]&&A(c,g,b)&&(e[g]=!0,d.push(g))},da.getRoot()),d}function D(a){var b,c,d,e,f,g=r(a);if(g)for(b=ea.getStart(),c=n(b),e=g.length-1;e>=0;e--){if(f=g[e].selector,!f||g[e].defaultBlock)return na;for(d=c.length-1;d>=0;d--)if(da.is(c[d],f))return na}return ma}function E(a,b,c){var d;return $||($={},d={},j.on("NodeChange",function(a){var b=n(a.element),c={};b=g.grep(b,function(a){return 1==a.nodeType&&!a.getAttribute("data-mce-bogus")}),qa($,function(a,e){qa(b,function(f){return A(f,e,{},a.similar)?(d[e]||(qa(a,function(a){a(!0,{node:f,format:e,parents:b})}),d[e]=a),c[e]=a,!1):!u(f,e)&
 &void 0})}),qa(d,function(e,f){c[f]||(delete d[f],qa(e,function(c){c(!1,{node:a.element,format:f,parents:b})}))})})),qa(a.split(","),function(a){$[a]||($[a]=[],$[a].similar=c),$[a].push(b)}),this}function F(a){return h.getCssText(j,a)}function G(a,b){return H(a,b.inline)?na:H(a,b.block)?na:b.selector?1==a.nodeType&&da.is(a,b.selector):void 0}function H(a,b){return a=a||"",b=b||"",a=""+(a.nodeName||a),b=""+(b.nodeName||b),a.toLowerCase()==b.toLowerCase()}function I(a,b,c){qa(a.childNodes,function(a){J(a)&&(b(a)&&c(a),a.hasChildNodes()&&I(a,b,c))})}function J(a){return a&&1===a.nodeType&&!pa(a)&&!o(a)&&!e.isBogus(a)}function K(a){return f.curry(function(a,b){return!(!b||!M(b,a))},a)}function L(a,b){return f.curry(function(a,b,c){da.setStyle(c,a,b)},a,b)}function M(a,b){return N(da.getStyle(a,b),b)}function N(a,b){return"color"!=b&&"backgroundColo
 r"!=b||(a=da.toHex(a)),"fontWeight"==b&&700==a&&(a="bold"),"fontFamily"==b&&(a=a.replace(/[\'\"]/g,"").replace(/,\s+/g,",")),""+a}function O(a,b){return"string"!=typeof a?a=a(b):b&&(a=a.replace(/%(\w+)/g,function(a,c){return b[c]||a})),a}function P(a){return a&&3===a.nodeType&&/^([\t \r\n]+|)$/.test(a.nodeValue)}function Q(a,b,c){var d=da.create(b,c);return a.parentNode.insertBefore(d,a),d.appendChild(a),d}function R(b,c,d){function e(a){function b(a){return"BR"==a.nodeName&&a.getAttribute("data-mce-bogus")&&!a.nextSibling}var d,e,f,g,h;if(d=e=a?q:s,g=a?"previousSibling":"nextSibling",h=da.getRoot(),3==d.nodeType&&!P(d)&&(a?r>0:t<d.nodeValue.length))return d;for(;;){if(!c[0].block_expand&&ha(e))return e;for(f=e[g];f;f=f[g])if(!pa(f)&&!P(f)&&!b(f))return e;i
 f(e==h||e.parentNode==h){d=e;break}e=e.parentNode}return d}function f(a,b){for(b===_&&(b=3===a.nodeType?a.length:a.childNodes.length);a&&a.hasChildNodes();)a=a.childNodes[b],a&&(b=3===a.nodeType?a.length:a.childNodes.length);return{node:a,offset:b}}function g(a){for(var b=a;b;){if(1===b.nodeType&&oa(b))return"false"===oa(b)?b:a;b=b.parentNode}return a}function h(b,c,e){function f(a,b){var c,f,g=a.nodeValue;return"undefined"==typeof b&&(b=e?g.length:0),e?(c=g.lastIndexOf(" ",b),f=g.lastIndexOf("\xa0",b),c=c>f?c:f,c===-1||d||c++):(c=g.indexOf(" ",b),f=g.indexOf("\xa0",b),c=c!==-1&&(f===-1||c<f)?c:f),c}var g,h,i,k;if(3===b.nodeType){if(i=f(b,c),i!==-1)return{container:b,offset:i};k=b}for(g=new a(b,da.getParent(b,ha)||j.getBody());h=g[e?"prev":"next"]();)if(3===h.nodeType){if(k=h,i=f(h),i!==-1)return{container:h,offset:i}}else if(ha(h))break;if(k)return c
 =e?0:k.length,{container:k,offset:c}}function i(a,d){var e,f,g,h;for(3==a.nodeType&&0===a.nodeValue.length&&a[d]&&(a=a[d]),e=n(a),f=0;f<e.length;f++)for(g=0;g<c.length;g++)if(h=c[g],!("collapsed"in h&&h.collapsed!==b.collapsed)&&da.is(e[f],h.selector))return e[f];return a}function l(a,b){var d,e=da.getRoot();if(c[0].wrapper||(d=da.getParent(a,c[0].block,e)),d||(d=da.getParent(3==a.nodeType?a.parentNode:a,function(a){return a!=e&&k(a)})),d&&c[0].wrapper&&(d=n(d,"ul,ol").reverse()[0]||d),!d)for(d=a;d[b]&&!ha(d[b])&&(d=d[b],!H(d,"br")););return d||a}var m,o,p,q=b.startContainer,r=b.startOffset,s=b.endContainer,t=b.endOffset;if(1==q.nodeType&&q.hasChildNodes()&&(m=q.childNodes.length-1,q=q.childNodes[r>m?m:r],3==q.nodeType&&(r=0)),1==s.nodeType&&s.hasChildNodes()&&(m=s.childNodes.length-1,s=s.childNodes[t>m?m:t-1],3==s.nodeType
 &&(t=s.nodeValue.length)),q=g(q),s=g(s),(pa(q.parentNode)||pa(q))&&(q=pa(q)?q:q.parentNode,q=q.nextSibling||q,3==q.nodeType&&(r=0)),(pa(s.parentNode)||pa(s))&&(s=pa(s)?s:s.parentNode,s=s.previousSibling||s,3==s.nodeType&&(t=s.length)),c[0].inline&&(b.collapsed&&(p=h(q,r,!0),p&&(q=p.container,r=p.offset),p=h(s,t),p&&(s=p.container,t=p.offset)),o=f(s,t),o.node)){for(;o.node&&0===o.offset&&o.node.previousSibling;)o=f(o.node.previousSibling);o.node&&o.offset>0&&3===o.node.nodeType&&" "===o.node.nodeValue.charAt(o.offset-1)&&o.offset>1&&(s=o.node,s.splitText(o.offset-1))}return(c[0].inline||c[0].block_expand)&&(c[0].inline&&3==q.nodeType&&0!==r||(q=e(!0)),c[0].inline&&3==s.nodeType&&t!==s.nodeValue.length||(s=e())),c[0].selector&&c[0].expand!==ma&&!c[0].inline&&(q=i(q,"previousS
 ibling"),s=i(s,"nextSibling")),(c[0].block||c[0].selector)&&(q=l(q,"previousSibling"),s=l(s,"nextSibling"),c[0].block&&(ha(q)||(q=e(!0)),ha(s)||(s=e()))),1==q.nodeType&&(r=ja(q),q=q.parentNode),1==s.nodeType&&(t=ja(s)+1,s=s.parentNode),{startContainer:q,startOffset:r,endContainer:s,endOffset:t}}function S(a,b){return b.links&&"A"==a.tagName}function T(a,b,c,d){var e,f,g;if(!G(c,a)&&!S(c,a))return ma;if("all"!=a.remove)for(qa(a.styles,function(e,f){e=N(O(e,b),f),"number"==typeof f&&(f=e,d=0),(a.remove_similar||!d||H(M(d,f),e))&&da.setStyle(c,f,""),g=1}),g&&""===da.getAttrib(c,"style")&&(c.removeAttribute("style"),c.removeAttribute("data-mce-style")),qa(a.attributes,function(a,e){var f;if(a=O(a,b),"number"==typeof e&&(e=a,d=0),!d||H(da.getAttrib(d,e),a)){if("class"=
 =e&&(a=da.getAttrib(c,e),a&&(f="",qa(a.split(/\s+/),function(a){/mce\-\w+/.test(a)&&(f+=(f?" ":"")+a)}),f)))return void da.setAttrib(c,e,f);"class"==e&&c.removeAttribute("className"),la.test(e)&&c.removeAttribute("data-mce-"+e),c.removeAttribute(e)}}),qa(a.classes,function(a){a=O(a,b),d&&!da.hasClass(d,a)||da.removeClass(c,a)}),f=da.getAttribs(c),e=0;e<f.length;e++){var h=f[e].nodeName;if(0!==h.indexOf("_")&&0!==h.indexOf("data-"))return ma}return"none"!=a.remove?(U(c,a),na):void 0}function U(a,b){function c(a,b,c){return a=V(a,b,c),!a||"BR"==a.nodeName||ha(a)}var d,e=a.parentNode;b.block&&(ia?e==da.getRoot()&&(b.list_block&&H(a,b.list_block)||qa(ra(a.childNodes),function(a){ga(ia,a.nodeName.toLowerCase())?d?d.appendChild(a):(d=Q(a,ia),da.setAttribs(d,j.settings.forced_root_block_attrs)):d=0})):ha(a)&am
 p;&!ha(e)&&(c(a,ma)||c(a.firstChild,na,1)||a.insertBefore(da.create("br"),a.firstChild),c(a,na)||c(a.lastChild,ma,1)||a.appendChild(da.create("br")))),b.selector&&b.inline&&!H(b.inline,a)||da.remove(a,1)}function V(a,b,c){if(a)for(b=b?"nextSibling":"previousSibling",a=c?a:a[b];a;a=a[b])if(1==a.nodeType||!P(a))return a}function W(a,b){function c(a,b){for(e=a;e;e=e[b]){if(3==e.nodeType&&0!==e.nodeValue.length)return a;if(1==e.nodeType&&!pa(e))return e}return a}var e,f,g=new d(da);if(a&&b&&(a=c(a,"previousSibling"),b=c(b,"nextSibling"),g.compare(a,b))){for(e=a.nextSibling;e&&e!=b;)f=e,e=e.nextSibling,a.appendChild(f);return da.remove(b),qa(ra(b.childNodes),function(b){a.appendChild(b)}),a}return b}function X(b,c){var d,e,f;return d=b[c?"startContainer":"endContainer"],e=b[c?"startOffset":"endOffset"],1==d.nodeType&&a
 mp;(f=d.childNodes.length-1,!c&&e&&e--,d=d.childNodes[e>f?f:e]),3===d.nodeType&&c&&e>=d.nodeValue.length&&(d=new a(d,j.getBody()).next()||d),3!==d.nodeType||c||0!==e||(d=new a(d,j.getBody()).prev()||d),d}function Y(b,c,d,e){function f(a){var b=da.create("span",{id:p,"data-mce-bogus":!0,style:q?"color:red":""});return a&&b.appendChild(j.getDoc().createTextNode(ka)),b}function g(a,b){for(;a;){if(3===a.nodeType&&a.nodeValue!==ka||a.childNodes.length>1)return!1;b&&1===a.nodeType&&b.push(a),a=a.firstChild}return!0}function h(a){for(;a;){if(a.id===p)return a;a=a.parentNode}}function i(b){var c;if(b)for(c=new a(b,b),b=c.current();b;b=c.next())if(3===b.nodeType)return b}function l(a,b){var c,d;if(a)d=ea.getRng(!0),g(a)?(b!==!1&&(d.setStartBefore(a),d.setEndBefore(a)),da.remove(a)):(c=i(a),c.nodeValue.charAt(0)===ka&&(c.deleteData(0,1),d.startContainer==c&a
 mp;&d.startOffset>0&&d.setStart(c,d.startOffset-1),d.endContainer==c&&d.endOffset>0&&d.setEnd(c,d.endOffset-1)),da.remove(a,1)),ea.setRng(d);else if(a=h(ea.getStart()),!a)for(;a=da.get(p);)l(a,!1)}function m(){var a,b,e,g,j,k,l;a=ea.getRng(!0),g=a.startOffset,k=a.startContainer,l=k.nodeValue,b=h(ea.getStart()),b&&(e=i(b));var m=/[^\s\u00a0\u00ad\u200b\ufeff]/;l&&g>0&&g<l.length&&m.test(l.charAt(g))&&m.test(l.charAt(g-1))?(j=ea.getBookmark(),a.collapse(!0),a=R(a,r(c)),a=fa.split(a),x(c,d,a),ea.moveToBookmark(j)):(b&&e.nodeValue===ka?x(c,d,b):(b=f(!0),e=b.firstChild,a.insertNode(b),g=1,x(c,d,b)),ea.setCursorLocation(e,g))}function n(){var a,b,g,h,i,j,l,m,n=ea.getRng(!0),o=[];for(a=n.startContainer,b=n.startOffset,i=a,3==a.nodeType&&(b!=a.nodeValue.length&&(h=!0),i=i.parentNode);i;){if(A(i,c,d,e)){j=i;break}i.nextSibling&&(h=!0),o.push(i),i=i.parentNode}if(j)if(h)g=ea.getBook
 mark(),n.collapse(!0),n=R(n,r(c),!0),n=fa.split(n),y(c,d,n),ea.moveToBookmark(g);else{for(m=f(),i=m,l=o.length-1;l>=0;l--)i.appendChild(da.clone(o[l],!1)),i=i.firstChild;i.appendChild(da.doc.createTextNode(ka)),i=i.firstChild;var p=da.getParent(j,k);p&&da.isEmpty(p)?j.parentNode.replaceChild(m,j):da.insertAfter(m,j),ea.setCursorLocation(i,1),da.isEmpty(j)&&da.remove(j)}}function o(){var a;a=h(ea.getStart()),a&&!da.isEmpty(a)&&sa(a,function(a){1!=a.nodeType||a.id===p||da.isEmpty(a)||da.setAttrib(a,"data-mce-bogus",null)},"childNodes")}var p="_mce_caret",q=j.settings.caret_debug;j._hasCaretEvents||(ba=function(){var a,b=[];if(g(h(ea.getStart()),b))for(a=b.length;a--;)da.setAttrib(b[a],"data-mce-bogus","1")},aa=function(a){var b=a.keyCode;l(),8==b&&ea.isCollapsed()&&ea.getStart().innerHTML==ka&&l(h(ea.getStart())),37!=b&&39!=b||l(h(ea.getStart())),o()},j.on("SetCont
 ent",function(a){a.selection&&o()}),j._hasCaretEvents=!0),"apply"==b?m():n()}function Z(b){var c,d,e,f=b.startContainer,g=b.startOffset;if((b.startContainer!=b.endContainer||!m(b.startContainer.childNodes[b.startOffset]))&&(3==f.nodeType&&g>=f.nodeValue.length&&(g=ja(f),f=f.parentNode),1==f.nodeType))for(e=f.childNodes,g<e.length?(f=e[g],c=new a(f,da.getParent(f,da.isBlock))):(f=e[e.length-1],c=new a(f,da.getParent(f,da.isBlock)),c.next(!0)),d=c.current();d;d=c.next())if(3==d.nodeType&&!P(d))return b.setStart(d,0),void ea.setRng(b)}var $,_,aa,ba,ca={},da=j.dom,ea=j.selection,fa=new b(da),ga=j.schema.isValidChild,ha=da.isBlock,ia=j.settings.forced_root_block,ja=da.nodeIndex,ka="\ufeff",la=/^(src|href|style)$/,ma=!1,na=!0,oa=da.getContentEditable,pa=c.isBookmarkNode,qa=g.each,ra=g.grep,sa=g.walk,ta=g.extend,ua=function(a,b){a.clear_child_styles&&qa(da.select("*",b),function(b){qa(a.styles,function
 (a,c){da.setStyle(b,c,"")})})};ta(this,{get:r,register:s,unregister:t,apply:x,remove:y,toggle:z,match:B,matchAll:C,matchNode:A,canApply:D,formatChanged:E,getCssText:F}),p(),q(),j.on("BeforeGetContent",function(a){ba&&"raw"!=a.format&&ba()}),j.on("mouseup keydown",function(a){aa&&aa(a)})}}),g("55",[],function(){var a=0,b=1,c=2,d=function(d,e){var f=d.length+e.length+2,g=new Array(f),h=new Array(f),i=function(a,b,c){return{start:a,end:b,diag:c}},j=function(f,g,h,i,k){var m=l(f,g,h,i);if(null===m||m.start===g&&m.diag===g-i||m.end===f&&m.diag===f-h)for(var n=f,o=h;n<g||o<i;)n<g&&o<i&&d[n]===e[o]?(k.push([a,d[n]]),++n,++o):g-f>i-h?(k.push([c,d[n]]),++n):(k.push([b,e[o]]),++o);else{j(f,m.start,h,m.start-m.diag,k);for(var p=m.start;p<m.end;++p)k.push([a,d[p]]);j(m.end,g,m.end-m.diag,i,k)}},k=function(a,b,c,f){for(var g=a;g-b<f&&g<c&&d[g]===e[g-b]
 ;)++g;return i(a,g,b)},l=function(a,b,c,f){var i=b-a,j=f-c;if(0===i||0===j)return null;var l=i-j,m=j+i,n=(m%2===0?m:m+1)/2;g[1+n]=a,h[1+n]=b+1;for(var o=0;o<=n;++o){for(var p=-o;p<=o;p+=2){var q=p+n;p===-o||p!=o&&g[q-1]<g[q+1]?g[q]=g[q+1]:g[q]=g[q-1]+1;for(var r=g[q],s=r-a+c-p;r<b&&s<f&&d[r]===e[s];)g[q]=++r,++s;if(l%2!=0&&l-o<=p&&p<=l+o&&h[q-l]<=g[q])return k(h[q-l],p+a-c,b,f)}for(p=l-o;p<=l+o;p+=2){for(q=p+n-l,p===l-o||p!=l+o&&h[q+1]<=h[q-1]?h[q]=h[q+1]-1:h[q]=h[q-1],r=h[q]-1,s=r-a+c-p;r>=a&&s>=c&&d[r]===e[s];)h[q]=r--,s--;if(l%2===0&&-o<=p&&p<=o&&h[q]<=g[q+l])return k(h[q],p+a-c,b,f)}}},m=[];return j(0,d.length,0,e.length,m),m};return{KEEP:a,DELETE:c,INSERT:b,diff:d}}),g("48",["1g","d","55"],function(a,b,c){var d=function(a){return 1===a.nodeType?a.outerHTML:3===a.nodeType?b.encodeRaw(a.data,!1):8===a.
 nodeType?"<!--"+a.data+"-->":""},e=function(a){var b,c,d;for(d=document.createElement("div"),b=document.createDocumentFragment(),a&&(d.innerHTML=a);c=d.firstChild;)b.appendChild(c);return b},f=function(a,b,c){var d=e(b);if(a.hasChildNodes()&&c<a.childNodes.length){var f=a.childNodes[c];f.parentNode.insertBefore(d,f)}else a.appendChild(d)},g=function(a,b){if(a.hasChildNodes()&&b<a.childNodes.length){var c=a.childNodes[b];c.parentNode.removeChild(c)}},h=function(b,d){var e=0;a.each(b,function(a){a[0]===c.KEEP?e++:a[0]===c.INSERT?(f(d,a[1],e),e++):a[0]===c.DELETE&&g(d,e)})},i=function(b){return a.filter(a.map(b.childNodes,d),function(a){return a.length>0})},j=function(b,e){var f=a.map(e.childNodes,d);return h(c.diff(f,b),e),e};return{read:i,write:j}}),g("1v",["1g","48"],function(a,b){var c=function(a){return a.indexOf("</iframe>")!==-1},d=function(a){retu
 rn{type:"fragmented",fragments:a,content:"",bookmark:null,beforeBookmark:null}},e=function(a){return{type:"complete",fragments:null,content:a,bookmark:null,beforeBookmark:null}},f=function(f){var g,h,i;return g=b.read(f.getBody()),i=a.map(g,function(a){return f.serializer.trimContent(a)}),h=i.join(""),c(h)?d(i):e(h)},g=function(a,c,d){"fragmented"===c.type?b.write(c.fragments,a.getBody()):a.setContent(c.content,{format:"raw"}),a.selection.moveToBookmark(d?c.beforeBookmark:c.bookmark)},h=function(a){return"fragmented"===a.type?a.fragments.join(""):a.content},i=function(a,b){return h(a)===h(b)};return{createFragmentedLevel:d,createCompleteLevel:e,createFromEditor:f,applyToEditor:g,isEq:i}}),g("u",["p","9","1v"],function(a,b,c){return function(a){function d(b){a.setDirty(b)}function e(a){n(!1),i.add({},a)}function f(){i.typing&&(n(!1),i.add())}var g,h,i=this,j
 =0,k=[],l=0,m=function(){return 0===l},n=function(a){m()&&(i.typing=a)};return a.on("init",function(){i.add()}),a.on("BeforeExecCommand",function(a){var b=a.command;"Undo"!==b&&"Redo"!==b&&"mceRepaint"!==b&&(f(),i.beforeChange())}),a.on("ExecCommand",function(a){var b=a.command;"Undo"!==b&&"Redo"!==b&&"mceRepaint"!==b&&e(a)}),a.on("ObjectResizeStart Cut",function(){i.beforeChange()}),a.on("SaveContent ObjectResized blur",e),a.on("DragEnd",e),a.on("KeyUp",function(b){var f=b.keyCode;b.isDefaultPrevented()||((f>=33&&f<=36||f>=37&&f<=40||45===f||b.ctrlKey)&&(e(),a.nodeChanged()),46!==f&&8!==f||a.nodeChanged(),h&&i.typing&&c.isEq(c.createFromEditor(a),k[0])===!1&&(a.isDirty()===!1&&(d(!0),a.fire("change",{level:k[0],las
 tLevel:null})),a.fire("TypingUndo"),h=!1,a.nodeChanged()))}),a.on("KeyDown",function(a){var b=a.keyCode;if(!a.isDefaultPrevented()){if(b>=33&&b<=36||b>=37&&b<=40||45===b)return void(i.typing&&e(a));var c=a.ctrlKey&&!a.altKey||a.metaKey;!(b<16||b>20)||224===b||91===b||i.typing||c||(i.beforeChange(),n(!0),i.add({},a),h=!0)}}),a.on("MouseDown",function(a){i.typing&&e(a)}),a.addShortcut("meta+z","","Undo"),a.addShortcut("meta+y,meta+shift+z","","Redo"),a.on("AddUndo Undo Redo ClearUndos",function(b){b.isDefaultPrevented()||a.nodeChanged()}),i={data:k,typing:!1,beforeChange:function(){m()&&(g=a.selection.getBookmark(2,!0))},add:function(e,f){var h,i,l,n=a.settings;if(l=c.createFromEditor(a),e=e||{},e=b.extend(e,l),m()===!1||a.removed)return null;if(i=k[j],a.fire("BeforeAddUndo",{level:e,lastLevel:i,originalEvent:f}
 ).isDefaultPrevented())return null;if(i&&c.isEq(i,e))return null;if(k[j]&&(k[j].beforeBookmark=g),n.custom_undo_redo_levels&&k.length>n.custom_undo_redo_levels){for(h=0;h<k.length-1;h++)k[h]=k[h+1];k.length--,j=k.length}e.bookmark=a.selection.getBookmark(2,!0),j<k.length-1&&(k.length=j+1),k.push(e),j=k.length-1;var o={level:e,lastLevel:i,originalEvent:f};return a.fire("AddUndo",o),j>0&&(d(!0),a.fire("change",o)),e},undo:function(){var b;return i.typing&&(i.add(),i.typing=!1,n(!1)),j>0&&(b=k[--j],c.applyToEditor(a,b,!0),d(!0),a.fire("undo",{level:b})),b},redo:function(){var b;return j<k.length-1&&(b=k[++j],c.applyToEditor(a,b,!1),d(!0),a.fire("redo",{level:b})),b},clear:function(){k=[],j=0,i.typing=!1,i.data=k,a.fire("ClearUndos")},hasUndo:function(){return j>0||i.typing&&k[0]&&!c.isEq(c.createFromEditor(a),k[0])},hasRedo:function(){re
 turn j<k.length-1&&!i.typing},transact:function(a){return f(),i.beforeChange(),i.ignore(a),i.add()},ignore:function(a){try{l++,a()}finally{l--}},extra:function(b,d){var e,f;i.transact(b)&&(f=k[j].bookmark,e=k[j-1],c.applyToEditor(a,e,!0),i.transact(d)&&(k[j-1].beforeBookmark=f))}}}}),g("6d",["6a","42","44","1y"],function(a,b,c,d){var e=function(a){var b=c.isText(a)?a.dom().parentNode:a.dom();return void 0!==b&&null!==b&&b.ownerDocument.body.contains(b)},f=a.cached(function(){return g(b.fromDom(d))}),g=function(a){var c=a.dom().body;if(null===c||void 0===c)throw"Body is not available yet";return b.fromDom(c)};return{body:f,getBody:g,inBody:e}}),g("6e",["5l","4q"],function(a,b){return function(c,d,e,f,g){return c(e,f)?b.some(e):a.isFunction(g)&&g(e)?b.none():d(e,f,g)}}),g("5s",["5l","3s","3t","4q"
 ,"6d","53","42","6e"],function(a,b,c,d,e,f,g,h){var i=function(a){return n(e.body(),a)},j=function(b,e,f){for(var h=b.dom(),i=a.isFunction(f)?f:c.constant(!1);h.parentNode;){h=h.parentNode;var j=g.fromDom(h);if(e(j))return d.some(j);if(i(j))break}return d.none()},k=function(a,b,c){var d=function(a){return b(a)};return h(d,j,a,b,c)},l=function(a,b){var c=a.dom();return c.parentNode?m(g.fromDom(c.parentNode),function(c){return!f.eq(a,c)&&b(c)}):d.none()},m=function(a,d){var e=b.find(a.dom().childNodes,c.compose(d,g.fromDom));return e.map(g.fromDom)},n=function(a,b){var c=function(a){for(var e=0;e<a.childNodes.length;e++){if(b(g.fromDom(a.childNodes[e])))return d.some(g.fromDom(a.childNodes[e]));var f=c(a.childNodes[e]);if(f.isSome())return f}return d.none()};return c(a.dom())};return{first:i,ancestor:j,closest:k,sibling:l,child:m,descendant:n}}),g("59",["1s","c","1j","1n","1k&quot
 ;,"3x"],function(a,b,c,d,e,f){function g(a){return a>0}function h(a){return a<0}function i(a,b){for(var c;c=a(b);)if(!y(c))return c;return null}function j(a,c,d,e,f){var j=new b(a,e);if(h(c)){if((v(a)||y(a))&&(a=i(j.prev,!0),d(a)))return a;for(;a=i(j.prev,f);)if(d(a))return a}if(g(c)){if((v(a)||y(a))&&(a=i(j.next,!0),d(a)))return a;for(;a=i(j.next,f);)if(d(a))return a}return null}function k(a,b){for(a=a.parentNode;a&&a!=b;a=a.parentNode)if(u(a))return a;return b}function l(a,b){for(;a&&a!=b;){if(w(a))return a;a=a.parentNode}return null}function m(a,b,c){return l(a.container(),c)==l(b.container(),c)}function n(a,b,c){return k(a.container(),c)==k(b.container(),c)}function o(a,b){var c,d;return b?(c=b.container(),d=b.offset(),A(c)?c.childNodes[d+a]:null):null}function p(a,b){var c=b.ownerDocument.createRange();return a?(c.setStartBefore(b),c.setEndBefore(b)):(c.setStartAfter(b),c.setEndAfter(b)),c}function q(a,b,c){return l(b,a)==l(c,a)}f
 unction r(a,b,c){var d,e;for(e=a?"previousSibling":"nextSibling";c&&c!=b;){if(d=c[e],x(d)&&(d=d[e]),v(d)){if(q(b,d,c))return d;break}if(B(d))break;c=c.parentNode}return null}function s(a,b,d){var f,g,h,i,j=z(r,!0,b),k=z(r,!1,b);if(g=d.startContainer,h=d.startOffset,e.isCaretContainerBlock(g)){if(A(g)||(g=g.parentNode),i=g.getAttribute("data-mce-caret"),"before"==i&&(f=g.nextSibling,v(f)))return C(f);if("after"==i&&(f=g.previousSibling,v(f)))return D(f)}if(!d.collapsed)return d;if(c.isText(g)){if(x(g)){if(1===a){if(f=k(g))return C(f);if(f=j(g))return D(f)}if(a===-1){if(f=j(g))return D(f);if(f=k(g))return C(f)}return d}if(e.endsWithCaretContainer(g)&&h>=g.data.length-1)return 1===a&&(f=k(g))?C(f):d;if(e.startsWithCaretContainer(g)&&h<=1)return a===-1&&(f=j(g))?D(f):d;if(h===g.data.length)return f=k(g),f?C(f):d;if(0===h)return f=j(g),f?D(f):d}return d}function t(a,b){
 return v(o(a,b))}var u=c.isContentEditableTrue,v=c.isContentEditableFalse,w=c.matchStyleValues("display","block table table-cell table-caption list-item"),x=e.isCaretContainer,y=e.isCaretContainerBlock,z=a.curry,A=c.isElement,B=f.isCaretCandidate,C=z(p,!0),D=z(p,!1);return{isForwards:g,isBackwards:h,findNode:j,getEditingHost:k,getParentBlock:l,isInSameBlock:m,isInSameEditingHost:n,isBeforeContentEditableFalse:z(t,0),isAfterContentEditableFalse:z(t,-1),normalizeRange:s}}),g("4d",["1j","3x","1n","59","1g","1s"],function(a,b,c,d,e,f){function g(a,b){for(var c=[];a&&a!=b;)c.push(a),a=a.parentNode;return c}function h(a,b){return a.hasChildNodes()&&b<a.childNodes.length?a.childNodes[b]:null}function i(a,b){if(p(a)){if(r(b.previousSibling)&&!m(b.previousSibling))return c.before(b);if(m(b))return c(b,0)}if(q(a)){if(r(b.nextSibling)&&!m(b.nextSibling))return c.after(b)
 ;if(m(b))return c(b,b.data.length)}return q(a)?o(b)?c.before(b):c.after(b):c.before(b)}function j(b,e){var f;return!!a.isBr(b)&&(f=k(1,c.after(b),e),!!f&&!d.isInSameBlock(c.before(b),c.before(f),e))}function k(a,b,u){var v,w,x,y,z,A,B;if(!n(u)||!b)return null;if(b.isEqual(c.after(u))&&u.lastChild){if(B=c.after(u.lastChild),q(a)&&r(u.lastChild)&&n(u.lastChild))return o(u.lastChild)?c.before(u.lastChild):B}else B=b;if(v=B.container(),w=B.offset(),m(v)){if(q(a)&&w>0)return c(v,--w);if(p(a)&&w<v.length)return c(v,++w);x=v}else{if(q(a)&&w>0&&(y=h(v,w-1),r(y)))return!s(y)&&(z=d.findNode(y,a,t,y))?m(z)?c(z,z.data.length):c.after(z):m(y)?c(y,y.data.length):c.before(y);if(p(a)&&w<v.childNodes.length&&(y=h(v,w),r(y)))return j(y,u)?k(a,c.after(y),u):!s(y)&&(z=d.findNode(y,a,t,y))?m(z)?c(z,0):c.before(z):m(y)?c(y,0):c.after(y);x=B.getNode()}return(p(a)&&B.isAtEnd()||q(a)&a
 mp;&B.isAtStart())&&(x=d.findNode(x,a,f.constant(!0),u,!0),t(x))?i(a,x):(y=d.findNode(x,a,t,u),A=e.last(e.filter(g(v,u),l)),!A||y&&A.contains(y)?y?i(a,y):null:B=p(a)?c.after(A):c.before(A))}var l=a.isContentEditableFalse,m=a.isText,n=a.isElement,o=a.isBr,p=d.isForwards,q=d.isBackwards,r=b.isCaretCandidate,s=b.isAtomic,t=b.isEditableCaretCandidate;return function(a){return{next:function(b){return k(1,b,a)},prev:function(b){return k(-1,b,a)}}}}),g("5c",["3t","4q","3x","1n","59","4d","1j"],function(a,b,c,d,e,f,g){var h=function(a,b,c){var e=a?d.before(c):d.after(c);return o(a,b,e)},i=function(a){return g.isBr(a)?d.before(a):d.after(a)},j=function(a){return d.isTextPosition(a)?0===a.offset():c.isCaretCandidate(a.getNode())},k=function(a){return d.isTextPosition(a)?a.offset()===a.container().data.length:c.isCaretCandidate(a.getNode(!0))},l=function(a,b){return!d.isTextPosition(a)&&
 !d.isTextPosition(b)&&a.getNode()===b.getNode(!0)},m=function(a){return!d.isTextPosition(a)&&g.isBr(a.getNode())},n=function(a,b,c){return a?!l(b,c)&&!m(b)&&k(b)&&j(c):!l(c,b)&&j(b)&&k(c)},o=function(a,c,d){var e=new f(c);return b.from(a?e.next(d):e.prev(d))},p=function(a,c,d){return o(a,c,d).bind(function(f){return e.isInSameBlock(d,f,c)&&n(a,d,f)?o(a,c,f):b.some(f)})},q=function(a,e){var f=a?e.firstChild:e.lastChild;return g.isText(f)?b.some(new d(f,a?0:f.data.length)):f?c.isCaretCandidate(f)?b.some(a?d.before(f):i(f)):h(a,e,f):b.none()};return{fromPosition:o,navigate:p,positionIn:q}}),g("58",["3s","4q","53","42","44","5s"],function(a,b,c,d,e,f){var g=function(b){var c=a.foldl(b,function(a,b){return a[b]=!0,a},{});return function(a){return c[e.name(a)]===!0}},h=g(["h1","h2","h3","h4","h5","h6&qu
 ot;,"p","div","address","pre","form","blockquote","center","dir","fieldset","header","footer","article","section","hgroup","aside","nav","figure"]),i=function(a){return function(b){return c.eq(a,d.fromDom(b.dom().parentNode))}},j=function(a,d){return c.contains(a,d)?f.closest(d,h,i(a)):b.none()};return{getParentTextBlock:j}}),g("70",["5s","5q","6e"],function(a,b,c){var d=function(a){return b.one(a)},e=function(c,d,e){return a.ancestor(c,function(a){return b.is(a,d)},e)},f=function(c,d){return a.sibling(c,function(a){return b.is(a,d)})},g=function(c,d){return a.child(c,function(a){return b.is(a,d)})},h=function(a,c){return b.one(c,a)},i=function(a,d,f){return c(b.is,e,a,d,f)};return{first:d,ancestor:e,sibling:f,child:g,descendant:h,closest:i}}),g("6f",["70"]
 ,function(a){var b=function(b){return a.first(b).isSome()},c=function(b,c,d){return a.ancestor(b,c,d).isSome()},d=function(b,c){return a.sibling(b,c).isSome()},e=function(b,c){return a.child(b,c).isSome()},f=function(b,c){return a.descendant(b,c).isSome()},g=function(b,c,d){return a.closest(b,c,d).isSome()};return{any:b,ancestor:c,sibling:d,child:e,descendant:f,closest:g}}),g("5t",["3t","53","42","6f","3x","1j","c"],function(a,b,c,d,e,f,g){var h=function(e,f){var g=c.fromDom(e),h=c.fromDom(f);return d.ancestor(h,"pre,code",a.curry(b.eq,g))},i=function(a,b){return f.isText(b)&&/^[ \t\r\n]*$/.test(b.data)&&h(a,b)===!1},j=function(a){return f.isElement(a)&&"A"===a.nodeName&&a.hasAttribute("name")},k=function(a,b){return e.isCaretCandidate(b)&&i(a,b)===!1||j(b)||l(b)},l=f.hasAttribute("data-mce-bookmark"),m=f.hasAttribute("d
 ata-mce-bogus"),n=f.hasAttributeValue("data-mce-bogus","all"),o=function(a){var b,c,d=0;if(k(a,a))return!1;if(c=a.firstChild,!c)return!0;b=new g(c,a);do if(n(c))c=b.next(!0);else if(m(c))c=b.next();else if(f.isBr(c))d++,c=b.next();else{if(k(a,c))return!1;c=b.next()}while(c);return d<=1},p=function(a){return o(a.dom())};return{isEmpty:p}}),g("56",["3s","3t","4q","54","5m","53","42","44","5s","4x","5c","1n","58","5t","1j"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o){var p=e.immutable("block","position"),q=e.immutable("from","to"),r=function(a,b){var c=g.fromDom(a),d=g.fromDom(b.container());return m.getParentTextBlock(c,d).map(function(a){return p(a,b)})},s=function(a){return f.eq(a.from().block(),a.to().block())===!1},t=function(a){return j.parent(a.from().block()
 ).bind(function(b){return j.parent(a.to().block()).filter(function(a){return f.eq(b,a)})}).isSome()},u=function(a){return o.isContentEditableFalse(a.from().block())===!1&&o.isContentEditableFalse(a.to().block())===!1},v=function(a,b,d){return o.isBr(d.position().getNode())&&n.isEmpty(d.block())===!1?k.positionIn(!1,d.block().dom()).bind(function(e){return e.isEqual(d.position())?k.fromPosition(b,a,e).bind(function(b){return r(a,b)}):c.some(d)}).getOr(d):d},w=function(a,b,c){var e=r(a,l.fromRangeStart(c)),f=e.bind(function(c){return k.fromPosition(b,a,c.position()).bind(function(c){return r(a,c).map(function(c){return v(a,b,c)})})});return d.liftN([e,f],q).filter(function(a){return s(a)&&t(a)&&u(a)})},x=function(a,b,d){return d.collapsed?w(a,b,d):c.none()};return{read:x}}),g("57",["3s","4q","40","51","42","4x","5c","1n","5t","1j"],function(a,b,
 c,d,e,f,g,h,i,j){var k=function(h,k,l,m){var n=f.children(k);return j.isBr(m.getNode())&&(d.remove(e.fromDom(m.getNode())),m=g.positionIn(!1,l.dom()).getOr(m)),i.isEmpty(k)===!1&&a.each(n,function(a){c.append(l,a)}),i.isEmpty(k)&&d.remove(k),n.length>0?b.from(m):b.none()},l=function(a,b,c){return a?i.isEmpty(b)?(d.remove(b),g.positionIn(!0,c.dom())):g.positionIn(!1,b.dom()).bind(function(d){return k(a,c,b,d)}):i.isEmpty(c)?(d.remove(c),g.positionIn(!0,b.dom())):g.positionIn(!1,c.dom()).bind(function(d){return k(a,b,c,d)})};return{mergeBlocks:l}}),g("49",["56","57"],function(a,b){var c=function(c,d){var e;return e=a.read(c.getBody(),d,c.selection.getRng()).bind(function(a){return b.mergeBlocks(d,a.from().block(),a.to().block())}),e.each(function(a){c.selection.setRng(a.toRange())}),e.isSome()};return{backspaceDelete:c}}),g("4a",["54","53","42","58","57"],function(a,b,c
 ,d,e){var f=function(f,g){var h=g.getRng();return a.liftN([d.getParentTextBlock(f,c.fromDom(h.startContainer)),d.getParentTextBlock(f,c.fromDom(h.endContainer))],function(a,c){return b.eq(a,c)===!1&&(h.deleteContents(),e.mergeBlocks(!0,a,c).each(function(a){g.setRng(a.toRange())}),!0)}).getOr(!1)},g=function(a,b){var d=c.fromDom(a.getBody());return a.selection.isCollapsed()===!1&&f(d,a.selection)};return{backspaceDelete:g}}),g("5u",["3s","5r","5l","4r","4s","4z"],function(a,b,c,d,e,f){var g=function(g){if(!c.isArray(g))throw new e("cases must be an array");if(0===g.length)throw new e("there must be at least one case");var h=[],i={};return a.each(g,function(j,k){var l=b.keys(j);if(1!==l.length)throw new e("one and only one name per case");var m=l[0],n=j[m];if(void 0!==i[m])throw new e("duplicate key detected:"+m);if("cata"===m)throw new e("canno
 t have a case named cata (sorry)");if(!c.isArray(n))throw new e("case arguments must be an array");h.push(m),i[m]=function(){var c=arguments.length;if(c!==n.length)throw new e("Wrong number of arguments to case "+m+". Expected "+n.length+" ("+n+"), got "+c);for(var i=new d(c),j=0;j<i.length;j++)i[j]=arguments[j];var l=function(c){var d=b.keys(c);if(h.length!==d.length)throw new e("Wrong number of arguments to match. Expected: "+h.join(",")+"\nActual: "+d.join(","));var f=a.forall(h,function(b){return a.contains(d,b)});if(!f)throw new e("Not all branches were specified when using match. Specified: "+d.join(", ")+"\nRequired: "+h.join(", "));return c[m].apply(null,i)};return{fold:function(){if(arguments.length!==g.length)throw new e("Wrong number of arguments to fold. Expected "+g.length+", got "+arguments.length);var a=arguments
 [k];return a.apply(null,i)},match:l,log:function(a){f.log(a,{constructors:h,constructor:m,params:i})}}}}),i};return{generate:g}}),g("5a",["5u","4q","42","5c","1n","59","58","5t","1j"],function(a,b,c,d,e,f,g,h,i){var j=a.generate([{remove:["element"]},{moveToElement:["element"]},{moveToPosition:["position"]}]),k=function(a,b){var c=b.getNode(a===!1),d=a?"after":"before";return i.isElement(c)&&c.getAttribute("data-mce-caret")===d},l=function(a,d,e,f){var i=f.getNode(d===!1);return g.getParentTextBlock(c.fromDom(a),c.fromDom(e.getNode())).map(function(a){return h.isEmpty(a)?j.remove(a.dom()):j.moveToElement(i)}).orThunk(function(){return b.some(j.moveToElement(i))})},m=function(a,c,e){return d.fromPosition(c,a,e).bind(function(d){return c&&i.isContentEditableFalse(d.getNode())?l(a,c,e,d):c===!1&&i.isConte
 ntEditableFalse(d.getNode(!0))?l(a,c,e,d):c&&f.isAfterContentEditableFalse(e)?b.some(j.moveToPosition(d)):c===!1&&f.isBeforeContentEditableFalse(e)?b.some(j.moveToPosition(d)):b.none()})},n=function(a,c){return a&&i.isContentEditableFalse(c.nextSibling)?b.some(j.moveToElement(c.nextSibling)):a===!1&&i.isContentEditableFalse(c.previousSibling)?b.some(j.moveToElement(c.previousSibling)):b.none()},o=function(a,c,d){return k(c,d)?n(c,d.getNode(c===!1)).fold(function(){return m(a,c,d)},b.some):m(a,c,d)},p=function(a,c,d){var g=f.normalizeRange(c?1:-1,a,d),h=e.fromRangeStart(g);return c===!1&&f.isAfterContentEditableFalse(h)?b.some(j.remove(h.getNode(!0))):c&&f.isBeforeContentEditableFalse(h)?b.some(j.remove(h.getNode())):o(a,c,h)};return{read:p}}),g("5v",[],function(){var a=/[\u0591-\u07FF\uFB1D-\uFDFF\uFE70-\uFEFC]/,b=function(b){
-return a.test(b)};return{hasStrongRtl:b}}),g("5g",["3s","3t","4q","54","1k","5c","1n","59","4d","e","1j","5v"],function(a,b,c,d,e,f,g,h,i,j,k,l){var m=function(a){return j.DOM.is(a,"a[href],code")},n=function(a){return"rtl"===j.DOM.getStyle(a,"direction",!0)||l.hasStrongRtl(a.textContent)},o=function(b,c){return a.filter(j.DOM.getParents(c.container(),"*",b),m)},p=function(a,b){var d=o(a,b);return c.from(d[0])},q=function(a,b){var d=o(a,b);return c.from(d[d.length-1])},r=function(a,b,c){var d=h.getParentBlock(b,a),e=h.getParentBlock(c,a);return d&&d===e},s=function(a,b){return!!b&&q(a,b).isSome()},t=function(a,b){return q(a,b).map(function(a){return w(a,!1,b).isNone()||w(a,!0,b).isNone()}).getOr(!1)},u=function(a){return e.isBeforeInline(a)||e.isAfterInline(a)},v=function(a,b){return f.positionIn(b,a
 )},w=function(a,b,c){return f.fromPosition(b,a,c)},x=function(a,b){var c=b.container(),d=b.offset();return a?e.isCaretContainerInline(c)?k.isText(c.nextSibling)?new g(c.nextSibling,0):g.after(c):e.isBeforeInline(b)?new g(c,d+1):b:e.isCaretContainerInline(c)?k.isText(c.previousSibling)?new g(c.previousSibling,c.previousSibling.data.length):g.before(c):e.isAfterInline(b)?new g(c,d-1):b},y=b.curry(x,!0),z=b.curry(x,!1);return{isInlineTarget:m,findInline:p,findRootInline:q,isInInline:s,isRtl:n,isAtInlineEndPoint:t,isAtZwsp:u,findCaretPositionIn:v,findCaretPosition:w,normalizePosition:x,normalizeForwards:y,normalizeBackwards:z,hasSameParentBlock:r}}),g("5b",["3t","4q","54","40","51","42","44","5s","4x","3x","1n","5t","1j","5g"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n){var o=function(a,b){var c=a.container(),d=a.offset();return k.isTextPosition
 (a)===!1&&c===b.parentNode&&d>k.before(b).offset()},p=function(a,b){return o(b,a)?new k(b.container(),b.offset()-1):b},q=function(a){return m.isText(a)?new k(a,0):k.before(a)},r=function(a){return m.isText(a)?new k(a,a.data.length):k.after(a)},s=function(a){return j.isCaretCandidate(a.previousSibling)?b.some(r(a.previousSibling)):a.previousSibling?n.findCaretPositionIn(a.previousSibling,!1):b.none()},t=function(a){return j.isCaretCandidate(a.nextSibling)?b.some(q(a.nextSibling)):a.nextSibling?n.findCaretPositionIn(a.nextSibling,!0):b.none()},u=function(a,c){var d=k.before(c.previousSibling?c.previousSibling:c.parentNode);return n.findCaretPosition(a,!1,d).fold(function(){return n.findCaretPosition(a,!0,k.after(c))},b.some)},v=function(a,c){return n.findCaretPosition(a,!0,k.after(c)).fold(function(){return n.findCaretPosition(a,!1,k.before(c))},b.some)},w=function(a,b){return s(b).orThunk(function(){return t(b)}).orThunk(function(){return u(a,b)})},x=function(a,b){
 return t(b).orThunk(function(){return s(b)}).orThunk(function(){return v(a,b)})},y=function(a,b,c){return a?x(b,c):w(b,c)},z=function(b,c,d){return y(b,c,d).map(a.curry(p,d))},A=function(a,b,c){c.fold(function(){a.focus()},function(c){a.selection.setRng(c.toRange(),b)})},B=function(a){return function(b){return b.dom()===a}},C=function(a,b){return b&&a.schema.getBlockElements().hasOwnProperty(g.name(b))},D=function(a){if(l.isEmpty(a)){var c=f.fromHtml('<br data-mce-bogus="1">');return e.empty(a),d.append(a,c),b.some(k.before(c.dom()))}return b.none()},E=function(a,b){return c.liftN([i.prevSibling(a),i.nextSibling(a),b],function(b,c,d){var f,g=b.dom(),h=c.dom();return m.isText(g)&&m.isText(h)?(f=g.data.length,g.appendData(h.data),e.remove(c),e.remove(a),d.container()===h?new k(g,f):d):(e.remove(a),d)}).orThunk(function(){return e.remove(a),b})},F=function(c,d,e){var f=z(d,c.getBody(),e.dom()),g=h.ancestor(e,a.curry(C,c),B(c.getBody())),i=E(e,f);g.bind(D
 ).fold(function(){A(c,d,i)},function(a){A(c,d,b.some(a))})};return{deleteElement:F}}),g("4b",["42","1n","59","56","5a","5b","57","1j"],function(a,b,c,d,e,f,g,h){var i=function(b,c){return function(d){return f.deleteElement(b,c,a.fromDom(d)),!0}},j=function(a,c){return function(d){var e=c?b.before(d):b.after(d);return a.selection.setRng(e.toRange()),!0}},k=function(a){return function(b){return a.selection.setRng(b.toRange()),!0}},l=function(a,b){var c=e.read(a.getBody(),b,a.selection.getRng()).map(function(c){return c.fold(i(a,b),j(a,b),k(a))});return c.getOr(!1)},m=function(b,c){var d=b.selection.getNode();return!!h.isContentEditableFalse(d)&&(f.deleteElement(b,c,a.fromDom(b.selection.getNode())),!0)},n=function(a,b){for(;b&&b!==a;){if(h.isContentEditableTrue(b)||h.isContentEditableFalse(b))return b;b=b.parentNode}return null},o=function(a){var c,d=n(a.getBody(),a.selection.getN
 ode());return h.isContentEditableTrue(d)&&a.dom.isBlock(d)&&a.dom.isEmpty(d)&&(c=a.dom.create("br",{"data-mce-bogus":"1"}),a.dom.setHTML(d,""),d.appendChild(c),a.selection.setRng(b.before(c).toRange())),!0},p=function(a,b){return a.selection.isCollapsed()?l(a,b):m(a,b)};return{backspaceDelete:p,paddEmptyElement:o}}),g("5w",["3t","1j","1l"],function(a,b,c){var d=b.isText,e=function(a){return d(a)&&a.data[0]===c.ZWSP},f=function(a){return d(a)&&a.data[a.data.length-1]===c.ZWSP},g=function(a){return a.ownerDocument.createTextNode(c.ZWSP)},h=function(a){if(d(a.previousSibling))return f(a.previousSibling)?a.previousSibling:(a.previousSibling.appendData(c.ZWSP),a.previousSibling);if(d(a))return e(a)?a:(a.insertData(0,c.ZWSP),a);var b=g(a);return a.parentNode.insertBefore(b,a),b},i=function(a){if(d(a.nextSibling))return e(a.nextSibling)?a.nextSibling:(a.nextSibling.insert
 Data(0,c.ZWSP),a.nextSibling);if(d(a))return f(a)?a:(a.appendData(c.ZWSP),a);var b=g(a);return a.nextSibling?a.parentNode.insertBefore(b,a.nextSibling):a.parentNode.appendChild(b),b},j=function(a,b){return a?h(b):i(b)};return{insertInline:j,insertInlineBefore:a.curry(j,!0),insertInlineAfter:a.curry(j,!1)}}),g("5x",["3s","1k","1n","1j","1l","9"],function(a,b,c,d,e,f){var g=d.isElement,h=d.isText,i=function(a){var b=a.parentNode;b&&b.removeChild(a)},j=function(a){try{return a.nodeValue}catch(a){return""}},k=function(a,b){0===b.length?i(a):a.nodeValue=b},l=function(a){var b=e.trim(a);return{count:a.length-b.length,text:b}},m=function(a,b){return s(a),b},n=function(a,b){var d=l(a.data.substr(0,b.offset())),e=l(a.data.substr(b.offset())),f=d.text+e.text;return f.length>0?(k(a,f),new c(a,b.offset()-d.count)):b},o=function(b,d){var e=d.container(),f=a.indexOf(e.childNodes,b).map(function(a){return a&
 lt;d.offset()?new c(e,d.offset()-1):d}).getOr(d);return s(b),f},p=function(a,b){return b.container()===a?n(a,b):m(a,b)},q=function(a,b){return b.container()===a.parentNode?o(a,b):m(a,b)},r=function(a,b){return c.isTextPosition(b)?p(a,b):q(a,b)},s=function(a){if(g(a)&&b.isCaretContainer(a)&&(b.hasContent(a)?a.removeAttribute("data-mce-caret"):i(a)),h(a)){var c=e.trim(j(a));k(a,c)}};return{removeAndReposition:r,remove:s}}),g("5d",["4q","1k","5w","5x","1n","1j","5g"],function(a,b,c,d,e,f,g){var h=function(a,b){return f.isText(a.container())?c.insertInline(b,a.container()):c.insertInline(b,a.getNode())},i=function(a,c){var d=c.get();return d&&a.container()===d&&b.isCaretContainerInline(d)},j=function(b,f){return f.fold(function(f){d.remove(b.get());var g=c.insertInlineBefore(f);return b.set(g),a.some(new e(g,g.length-1))},function(a){return g.findCaretPositionIn(a,!0
 ).map(function(a){if(i(a,b))return new e(b.get(),1);d.remove(b.get());var c=h(a,!0);return b.set(c),new e(c,1)})},function(a){return g.findCaretPositionIn(a,!1).map(function(a){if(i(a,b))return new e(b.get(),b.get().length-1);d.remove(b.get());var c=h(a,!1);return b.set(c),new e(c,c.length-1)})},function(f){d.remove(b.get());var g=c.insertInlineAfter(f);return b.set(g),a.some(new e(g,1))})};return{renderCaret:j}}),g("5y",["4q"],function(a){var b=function(b,c){for(var d=0;d<b.length;d++){var e=b[d].apply(null,c);if(e.isSome())return e}return a.none()};return{evaluateUntil:b}}),g("5e",["5u","3t","4q","54","1k","1n","59","1j","5g","5y"],function(a,b,c,d,e,f,g,h,i,j){var k=a.generate([{before:["element"]},{start:["element"]},{end:["element"]},{after:["element"]}]),l=function(a,b){var c=g.getParentBlock(b,a);return c?
 c:a},m=function(a,d){var e=i.normalizeForwards(d),f=l(a,e.container());return i.findRootInline(f,e).fold(function(){return i.findCaretPosition(f,!0,e).bind(b.curry(i.findRootInline,f)).map(function(a){return k.before(a)})},c.none)},n=function(a,b){var d=i.normalizeBackwards(b);return i.findRootInline(a,d).bind(function(a){var b=i.findCaretPosition(a,!1,d);return b.isNone()?c.some(k.start(a)):c.none()})},o=function(a,b){var d=i.normalizeForwards(b);return i.findRootInline(a,d).bind(function(a){var b=i.findCaretPosition(a,!0,d);return b.isNone()?c.some(k.end(a)):c.none()})},p=function(a,d){var e=i.normalizeBackwards(d),f=l(a,e.container());return i.findRootInline(f,e).fold(function(){return i.findCaretPosition(f,!1,e).bind(b.curry(i.findRootInline,f)).map(function(a){return k.after(a)})},c.none)},q=function(a){return i.isRtl(s(a))===!1},r=function(a,b){var c=j.evaluateUntil([m,n,o,p],[a,b]);return c.filter(q)},s=function(a){return a.fold(b.identity,b.identity,b.identity,b.identity)},t
 =function(a){return a.fold(b.constant("before"),b.constant("start"),b.constant("end"),b.constant("after"))},u=function(a){return a.fold(k.before,k.before,k.after,k.after)},v=function(a){return a.fold(k.start,k.start,k.end,k.end)},w=function(a,b){return t(a)===t(b)&&s(a)===s(b)},x=function(a,b,c,e,f){return d.liftN([i.findRootInline(b,c),i.findRootInline(b,e)],function(c,d){return c!==d&&i.hasSameParentBlock(b,c,d)?k.after(a?c:d):f}).getOr(f)},y=function(a,c){return a.fold(b.constant(!0),function(a){return!w(a,c)})},z=function(a,c,d,e){var f=i.normalizePosition(a,e),g=i.findCaretPosition(c,a,f).map(b.curry(i.normalizePosition,a)),h=g.fold(function(){return d.map(u)},function(e){return r(c,e).map(b.curry(x,a,c,f,e)).filter(b.curry(y,d))});return h.filter(q)},A=function(a,d){return a?d.fold(b.compose(c.some,k.start),c.none,b.compose(c.some,k.after),c.none):d.fold(c.none,b.compose(c.some,k.before),c.none,b.compose(c.some,k.end))},B
 =function(a,c,d){var e=i.normalizePosition(a,d),f=r(c,e);return r(c,e).bind(b.curry(A,a)).orThunk(function(){return z(a,c,f,d)})};return{readLocation:r,prevLocation:b.curry(B,!1),nextLocation:b.curry(B,!0),getElement:s,outside:u,inside:v}}),g("5z",[],function(){var a=function(b){var c=b,d=function(){return c},e=function(a){c=a},f=function(){return a(d())};return{get:d,set:e,clone:f}};return a}),g("5f",["3s","5z","3t","5x","1n","5d","5e","5g"],function(a,b,c,d,e,f,g,h){var i=function(a,b){var c=a.dom.createRng();c.setStart(b.container(),b.offset()),c.setEnd(b.container(),b.offset()),a.selection.setRng(c)},j=function(a){return a.settings.inline_boundaries!==!1},k=function(a,b){a?b.setAttribute("data-mce-selected","1"):b.removeAttribute("data-mce-selected","1")},l=function(a,b,c){return f.renderCaret(b,c).map(function(b){return i(a,b),c})},m=functi
 on(a,b,c){var d=a.getBody(),f=e.fromRangeStart(a.selection.getRng()),h=c?g.nextLocation(d,f):g.prevLocation(d,f);return h.bind(function(c){return l(a,b,c)})},n=function(b,d){var e=b.select("a[href][data-mce-selected],code[data-mce-selected]"),f=a.filter(d,h.isInlineTarget);a.each(a.difference(e,f),c.curry(k,!1)),a.each(a.difference(f,e),c.curry(k,!0))},o=function(a,b){if(a.selection.isCollapsed()&&a.composing!==!0&&b.get()){var c=e.fromRangeStart(a.selection.getRng());e.isTextPosition(c)&&h.isAtZwsp(c)===!1&&(i(a,d.removeAndReposition(b.get(),c)),b.set(null))}},p=function(b,c,d){if(b.selection.isCollapsed()){var f=a.filter(d,h.isInlineTarget);a.each(f,function(a){var d=e.fromRangeStart(b.selection.getRng());g.readLocation(b.getBody(),d).bind(function(a){return l(b,c,a)})})}},q=function(a,b,c){return function(){return!!j(a)&&m(a,b,c).isSome()}},r=function(a){var c=new b(null);return a.on("NodeChange",function(b){j(a)&&am
 p;(n(a.dom,b.parents),o(a,c),p(a,c,b.parents))}),c};return{move:q,setupSelectedState:r,setCaretPosition:i}}),g("4c",["3t","4q","54","42","1k","5c","1n","59","5b","5d","5e","5f","5g"],function(a,b,c,d,e,f,g,h,i,j,k,l,m){var n=function(a){return a.settings.inline_boundaries!==!1},o=function(a,b){var c=document.createRange();return c.setStart(a.container(),a.offset()),c.setEnd(b.container(),b.offset()),c},p=function(a){return c.liftN([m.findCaretPositionIn(a,!0),m.findCaretPositionIn(a,!1)],function(b,c){var d=m.normalizePosition(!0,b),e=m.normalizePosition(!1,c);return m.findCaretPosition(a,!0,d).map(function(a){return a.isEqual(e)}).getOr(!0)}).getOr(!0)},q=function(a,b){return function(c){return j.renderCaret(b,c).map(function(b){return l.setCaretPosition(a,b),!0}).getOr(!1)}},r=function(a,b,c,d){var e=a.getBody();a.undoManager.ignore(function()
 {a.selection.setRng(o(c,d)),a.execCommand("Delete"),k.readLocation(e,g.fromRangeStart(a.selection.getRng())).map(k.inside).map(q(a,b))}),a.nodeChanged()},s=function(a,b){var c=h.getParentBlock(b,a);return c?c:a},t=function(c,e,g,h){var j=s(c.getBody(),h.container()),l=k.readLocation(j,h);return l.bind(function(c){return g?c.fold(a.constant(b.some(k.inside(c))),b.none,a.constant(b.some(k.outside(c))),b.none):c.fold(b.none,a.constant(b.some(k.outside(c))),b.none,a.constant(b.some(k.inside(c))))}).map(q(c,e)).getOrThunk(function(){var a=f.navigate(g,j,h),b=a.bind(function(a){return k.readLocation(j,a)});return l.isSome()&&b.isSome()?m.findRootInline(j,h).map(function(a){return!!p(a)&&(i.deleteElement(c,g,d.fromDom(a)),!0)}).getOr(!1):b.bind(function(b){return a.map(function(a){return g?r(c,e,h,a):r(c,e,a,h),!0})}).getOr(!1)})},u=function(a,b,c){if(a.selection.isCollapsed()&&n(a)){var d=g.fromRangeStart(a.selection.getRng());return t(a,b,c,d)}return!1};
 return{backspaceDelete:u}}),g("1w",["49","4a","4b","4c"],function(a,b,c,d){var e=function(a,b){a.getDoc().execCommand(b,!1,null)},f=function(a){var b=a.dom,c=a.getBody();b.isEmpty(c)&&(a.setContent(""),c.firstChild&&b.isBlock(c.firstChild)?a.selection.setCursorLocation(c.firstChild,0):a.selection.setCursorLocation(c,0))},g=function(g){c.backspaceDelete(g,!1)||d.backspaceDelete(g,!1)||a.backspaceDelete(g,!1)||b.backspaceDelete(g,!1)||(e(g,"Delete"),f(g))},h=function(f){c.backspaceDelete(f,!0)||d.backspaceDelete(f,!0)||a.backspaceDelete(f,!0)||b.backspaceDelete(f,!0)||e(f,"ForwardDelete")};return{deleteCommand:g,forwardDeleteCommand:h}}),g("4e",["5c","1n","59","1j"],function(a,b,c,d){var e=function(a){return d.isElement(a)&&/^(P|H[1-6]|DIV)$/.test(a.nodeName)},f=function(a,b){return b(a.endContainer)},g=function(a,b,c,d){var e=docume
 nt.createRange();return e.setStart(a,b),e.setEnd(c,d),e},h=function(d){var h=b.fromRangeStart(d),i=b.fromRangeEnd(d),j=d.commonAncestorContainer;return d.collapsed===!1&&f(d,e)&&0===d.endOffset?a.fromPosition(!1,j,i).map(function(a){return!c.isInSameBlock(h,i,j)&&c.isInSameBlock(h,a,j)?g(h.container(),h.offset(),a.container(),a.offset()):d}).getOr(d):d},i=function(a){return h(a)};return{normalize:i}}),g("4f",["9","4d","1n"],function(a,b,c){var d=function(a){var b=a.firstChild,c=a.lastChild;return b&&"meta"===b.name&&(b=b.next),c&&"mce_marker"===c.attr("id")&&(c=c.prev),!(!b||b!==c)&&("ul"===b.name||"ol"===b.name)},e=function(a){var b=a.firstChild,c=a.lastChild;return b&&"META"===b.nodeName&&b.parentNode.removeChild(b),c&&"mce_marker"===c.id&&c.parentNode.removeChild(c),a},f=functi
 on(a,b,c){var d=b.serialize(c),f=a.createFragment(d);return e(f)},g=function(b){return a.grep(b.childNodes,function(a){return"LI"===a.nodeName})},h=function(a){return!a.firstChild},i=function(a){return a.length>0&&h(a[a.length-1])?a.slice(0,-1):a},j=function(a,b){var c=a.getParent(b,a.isBlock);return c&&"LI"===c.nodeName?c:null},k=function(a,b){return!!j(a,b)},l=function(a,b){var c=b.cloneRange(),d=b.cloneRange();return c.setStartBefore(a),d.setEndAfter(a),[c.cloneContents(),d.cloneContents()]},m=function(a,d){var e=c.before(a),f=new b(d),g=f.next(e);return g?g.toRange():null},n=function(a,d){var e=c.after(a),f=new b(d),g=f.prev(e);return g?g.toRange():null},o=function(b,c,d,e){var f=l(b,e),g=b.parentNode;return g.insertBefore(f[0],b),a.each(c,function(a){g.insertBefore(a,b)}),g.insertBefore(f[1],b),g.removeChild(b),n(c[c.length-1],d)},p=function(b,c,d){var e=b.parentNode;return a.each(c,function(a){e.insertBefore(a,b)}),m(b,d)},q=function(a,b,
 c,d){return d.insertAfter(b.reverse(),a),n(b[0],c)},r=function(a,d,e,h){var k=f(d,a,h),l=j(d,e.startContainer),m=i(g(k.firstChild)),n=1,r=2,s=d.getRoot(),t=function(a){var f=c.fromRangeStart(e),g=new b(d.getRoot()),h=a===n?g.prev(f):g.next(f);return!h||j(d,h.getNode())!==l};return t(n)?p(l,m,s):t(r)?q(l,m,s,d):o(l,m,s,e)};return{isListFragment:d,insertAtCaret:r,isParentBlockLi:k,trimListItems:i,listItems:g}}),g("1x",["1n","4d","1r","1j","4e","6","n","4f","9"],function(a,b,c,d,e,f,g,h,i){var j=d.matchNodeNames("td th"),k=function(a,b,c){if("all"===c.getAttribute("data-mce-bogus"))c.parentNode.insertBefore(a.dom.createFragment(b),c);else{var d=c.firstChild,e=c.lastChild;!d||d===e&&"BR"===d.nodeName?a.dom.setHTML(c,b):a.selection.setContent(b)}},l=function(d,l,m){function n(a){function b(a){return d[a]&&3==d[a].nodeType}var c,d,e;re
 turn c=I.getRng(!0),d=c.startContainer,e=c.startOffset,3==d.nodeType&&(e>0?a=a.replace(/^&nbsp;/," "):b("previousSibling")||(a=a.replace(/^ /,"&nbsp;")),e<d.length?a=a.replace(/&nbsp;(<br>|)$/," "):b("nextSibling")||(a=a.replace(/(&nbsp;| )(<br>|)$/,"&nbsp;"))),a}function o(){var a,b,c;a=I.getRng(!0),b=a.startContainer,c=a.startOffset,3==b.nodeType&&a.collapsed&&("\xa0"===b.data[c]?(b.deleteData(c,1),/[\u00a0| ]$/.test(l)||(l+=" ")):"\xa0"===b.data[c-1]&&(b.deleteData(c-1,1),/[\u00a0| ]$/.test(l)||(l=" "+l)))}function p(){if(G){var a=d.getBody(),b=new c(J);i.each(J.select("*[data-mce-fragment]"),function(c){for(var d=c.parentNode;d&&d!=a;d=d.parentNode)H[c.nodeName.toLowerCase()]&&b.compare(d,c)&&J.remove(c,!0)})}}function q(a){for(var b=a;b=b.walk();)1===b.type&&b.attr(&quo
 t;data-mce-fragment","1")}function r(a){i.each(a.getElementsByTagName("*"),function(a){a.removeAttribute("data-mce-fragment")})}function s(a){return!!a.getAttribute("data-mce-fragment")}function t(a){return a&&!d.schema.getShortEndedElements()[a.nodeName]}function u(c){function e(a){for(var b=d.getBody();a&&a!==b;a=a.parentNode)if("false"===d.dom.getContentEditable(a))return a;return null}function g(c){var e=a.fromRangeStart(c),f=new b(d.getBody());if(e=f.next(e))return e.toRange()}var h,i,k;if(c){if(I.scrollIntoView(c),h=e(c))return J.remove(c),void I.select(h);C=J.createRng(),D=c.previousSibling,D&&3==D.nodeType?(C.setStart(D,D.nodeValue.length),f.ie||(E=c.nextSibling,E&&3==E.nodeType&&(D.appendData(E.data),E.parentNode.removeChild(E)))):(C.setStartBefore(c),C.setEndBefore(c)),i=J.getParent(c,J.isBlock),J.remove(c),i&&J.isEmpty(i)&&(d.$(i).empty(),C.setStart(i,0),C.setEnd
 (i,0),j(i)||s(i)||!(k=g(C))?J.add(i,J.create("br",{"data-mce-bogus":"1"})):(C=k,J.remove(i))),I.setRng(C)}}var v,w,x,y,z,A,B,C,D,E,F,G,H=d.schema.getTextInlineElements(),I=d.selection,J=d.dom;/^ | $/.test(l)&&(l=n(l)),v=d.parser,G=m.merge,w=new g({validate:d.settings.validate},d.schema),F='<span id="mce_marker" data-mce-type="bookmark">&#xFEFF;&#x200B;</span>',A={content:l,format:"html",selection:!0},d.fire("BeforeSetContent",A),l=A.content,l.indexOf("{$caret}")==-1&&(l+="{$caret}"),l=l.replace(/\{\$caret\}/,F),C=I.getRng();var K=C.startContainer||(C.parentElement?C.parentElement():null),L=d.getBody();K===L&&I.isCollapsed()&&J.isBlock(L.firstChild)&&t(L.firstChild)&&J.isEmpty(L.firstChild)&&(C=J.createRng(),C.setStart(L.firstChild,0),C.setEnd(L.firstChild,0),I.setRng(C)),I.isCollapsed()||(d.selection.setRng(e.normalize(
 d.selection.getRng())),d.getDoc().execCommand("Delete",!1,null),o()),x=I.getNode();var M={context:x.nodeName.toLowerCase(),data:m.data};if(z=v.parse(l,M),m.paste===!0&&h.isListFragment(z)&&h.isParentBlockLi(J,x))return C=h.insertAtCaret(w,J,d.selection.getRng(!0),z),d.selection.setRng(C),void d.fire("SetContent",A);if(q(z),D=z.lastChild,"mce_marker"==D.attr("id"))for(B=D,D=D.prev;D;D=D.walk(!0))if(3==D.type||!J.isBlock(D.name)){d.schema.isValidChild(D.parent.name,"span")&&D.parent.insert(B,D,"br"===D.name);break}if(d._selectionOverrides.showBlockCaretContainer(x),M.invalid){for(I.setContent(F),x=I.getNode(),y=d.getBody(),9==x.nodeType?x=D=y:D=x;D!==y;)x=D,D=D.parentNode;l=x==y?y.innerHTML:J.getOuterHTML(x),l=w.serialize(v.parse(l.replace(/<span (id="mce_marker"|id=mce_marker).+?<\/span>/i,function(){return w.serialize(z)}))),x==y?J.setHTML(y,l):J.setOuterHTML(x,l)}else l=w.serializ
 e(z),k(d,l,x);p(),u(J.get("mce_marker")),r(d.getBody()),d.fire("SetContent",A),d.addVisual()},m=function(a){var b;return"string"!=typeof a?(b=i.extend({paste:a.paste,data:{paste:a.paste}},a),{content:a.content,details:b}):{content:a,details:{}}},n=function(a,b){var c=m(b);l(a,c.content,c.details)};return{insertAtCaret:n}}),g("v",["1w","1j","h","c","6","1x","9"],function(a,b,c,d,e,f,g){var h=g.each,i=g.extend,j=g.map,k=g.inArray,l=g.explode,m=e.ie&&e.ie<11,n=!0,o=!1;return function(g){function p(a,b,c,d){var e,f,i=0;if(!g.removed){if(/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint)$/.test(a)||d&&d.skip_focus||g.focus(),d=g.fire("BeforeExecCommand",{command:a,ui:b,value:c}),d.isDefaultPrevented())return!1;if(f=a.toLowerCase(),e=H.exec[f])return e(f,b,c),g.fire("ExecCommand",{command:a,ui:b,value:c}),!0;if(h(g.plugins,funct
 ion(d){if(d.execCommand&&d.execCommand(a,b,c))return g.fire("ExecCommand",{command:a,ui:b,value:c}),i=!0,!1}),i)return i;if(g.theme&&g.theme.execCommand&&g.theme.execCommand(a,b,c))return g.fire("ExecCommand",{command:a,ui:b,value:c}),!0;try{i=g.getDoc().execCommand(a,b,c)}catch(a){}return!!i&&(g.fire("ExecCommand",{command:a,ui:b,value:c}),!0)}}function q(a){var b;if(!g.quirks.isHidden()&&!g.removed){if(a=a.toLowerCase(),b=H.state[a])return b(a);try{return g.getDoc().queryCommandState(a)}catch(a){}return!1}}function r(a){var b;if(!g.quirks.isHidden()&&!g.removed){if(a=a.toLowerCase(),b=H.value[a])return b(a);try{return g.getDoc().queryCommandValue(a)}catch(a){}}}function s(a,b){b=b||"exec",h(a,function(a,c){h(c.toLowerCase().split(","),function(c){H[b][c]=a})})}function t(a,b,c){a=a.toLowerCase(),H.exec[a]=function(a,d,e,f){return b.call(c||g,d,e,f)}}function u(a){if(a=a.toLowerCase(),
 H.exec[a])return!0;try{return g.getDoc().queryCommandSupported(a)}catch(a){}return!1}function v(a,b,c){a=a.toLowerCase(),H.state[a]=function(){return b.call(c||g)}}function w(a,b,c){a=a.toLowerCase(),H.value[a]=function(){return b.call(c||g)}}function x(a){return a=a.toLowerCase(),!!H.exec[a]}function y(a,b,c){return void 0===b&&(b=o),void 0===c&&(c=null),g.getDoc().execCommand(a,b,c)}function z(a){return F.match(a)}function A(a,b){F.toggle(a,b?{value:b}:void 0),g.nodeChanged()}function B(a){G=E.getBookmark(a)}function C(){E.moveToBookmark(G)}var D,E,F,G,H={state:{},exec:{},value:{}},I=g.settings;g.on("PreInit",function(){D=g.dom,E=g.selection,I=g.settings,F=g.formatter}),i(this,{execCommand:p,queryCommandState:q,queryCommandValue:r,queryCommandSupported:u,addCommands:s,addCommand:t,addQueryStateHandler:v,addQueryValueHandler:w,hasCustomCommand:x}),s({"mceResetDesignMode,mceBeginUndoLevel":function(){},"mceEndUndoLevel,mceAddUndoLevel":f
 unction(){g.undoManager.add()},"Cut,Copy,Paste":function(a){var b,c=g.getDoc();try{y(a)}catch(a){b=n}if("paste"!==a||c.queryCommandEnabled(a)||(b=!0),b||!c.queryCommandSupported(a)){var d=g.translate("Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.");e.mac&&(d=d.replace(/Ctrl\+/g,"\u2318+")),g.notificationManager.open({text:d,type:"error"})}},unlink:function(){if(E.isCollapsed()){var a=g.dom.getParent(g.selection.getStart(),"a");return void(a&&g.dom.remove(a,!0))}F.remove("link")},"JustifyLeft,JustifyCenter,JustifyRight,JustifyFull,JustifyNone":function(a){var b=a.substring(7);"full"==b&&(b="justify"),h("left,center,right,justify".split(","),function(a){b!=a&&F.remove("align"+a)}),"none"!=b&&A("align"+b)},"InsertUnorderedList
 ,InsertOrderedList":function(a){var b,c;y(a),b=D.getParent(E.getNode(),"ol,ul"),b&&(c=b.parentNode,/^(H[1-6]|P|ADDRESS|PRE)$/.test(c.nodeName)&&(B(),D.split(c,b),C()))},"Bold,Italic,Underline,Strikethrough,Superscript,Subscript":function(a){A(a)},"ForeColor,HiliteColor,FontName":function(a,b,c){A(a,c)},FontSize:function(a,b,c){var d,e;c>=1&&c<=7&&(e=l(I.font_size_style_values),d=l(I.font_size_classes),c=d?d[c-1]||c:e[c-1]||c),A(a,c)},RemoveFormat:function(a){F.remove(a)},mceBlockQuote:function(){A("blockquote")},FormatBlock:function(a,b,c){return A(c||"p")},mceCleanup:function(){var a=E.getBookmark();g.setContent(g.getContent({cleanup:n}),{cleanup:n}),E.moveToBookmark(a)},mceRemoveNode:function(a,b,c){var d=c||E.getNode();d!=g.getBody()&&(B(),g.dom.remove(d,n),C())},mceSelectNodeDepth:function(a,b,c){var d=0;D.getParent(E.getNode(),function(a){if(1==a.nodeType&&d++==c)return 
 E.select(a),o},g.getBody())},mceSelectNode:function(a,b,c){E.select(c)},mceInsertContent:function(a,b,c){f.insertAtCaret(g,c)},mceInsertRawHTML:function(a,b,c){E.setContent("tiny_mce_marker"),g.setContent(g.getContent().replace(/tiny_mce_marker/g,function(){return c}))},mceToggleFormat:function(a,b,c){A(c)},mceSetContent:function(a,b,c){g.setContent(c)},"Indent,Outdent":function(a){var b,c,d;b=I.indentation,c=/[a-z%]+$/i.exec(b),b=parseInt(b,10),q("InsertUnorderedList")||q("InsertOrderedList")?y(a):(I.forced_root_block||D.getParent(E.getNode(),D.isBlock)||F.apply("div"),h(E.getSelectedBlocks(),function(e){if("false"!==D.getContentEditable(e)&&"LI"!==e.nodeName){var f=g.getParam("indent_use_margin",!1)?"margin":"padding";f="TABLE"===e.nodeName?"margin":f,f+="rtl"==D.getStyle(e,"direction",!0)?"Right":"Left","outde
 nt"==a?(d=Math.max(0,parseInt(e.style[f]||0,10)-b),D.setStyle(e,f,d?d+c:"")):(d=parseInt(e.style[f]||0,10)+b+c,D.setStyle(e,f,d))}}))},mceRepaint:function(){},InsertHorizontalRule:function(){g.execCommand("mceInsertContent",!1,"<hr />")},mceToggleVisualAid:function(){g.hasVisual=!g.hasVisual,g.addVisual()},mceReplaceContent:function(a,b,c){g.execCommand("mceInsertContent",!1,c.replace(/\{\$selection\}/g,E.getContent({format:"text"})))},mceInsertLink:function(a,b,c){var d;"string"==typeof c&&(c={href:c}),d=D.getParent(E.getNode(),"a"),c.href=c.href.replace(" ","%20"),d&&c.href||F.remove("link"),c.href&&F.apply("link",c,d)},selectAll:function(){var a,c=D.getRoot();if(E.getRng().setStart){var d=D.getParent(E.getStart(),b.isContentEditableTrue);d&&(a=D.createRng(),a.selectNodeContents(d),E.setRng(a))}else a=E.getRng(),a.item||(a.moveToE
 lementText(c),a.select())},"delete":function(){a.deleteCommand(g)},forwardDelete:function(){a.forwardDeleteCommand(g)},mceNewDocument:function(){g.setContent("")},InsertLineBreak:function(a,b,e){function f(){for(var a,b=new d(p,r),c=g.schema.getNonEmptyElements();a=b.next();)if(c[a.nodeName.toLowerCase()]||a.length>0)return!0}var h,i,j,k=e,l=E.getRng(!0);new c(D).normalize(l);var o=l.startOffset,p=l.startContainer;if(1==p.nodeType&&p.hasChildNodes()){var q=o>p.childNodes.length-1;p=p.childNodes[Math.min(o,p.childNodes.length-1)]||p,o=q&&3==p.nodeType?p.nodeValue.length:0}var r=D.getParent(p,D.isBlock),s=r?r.nodeName.toUpperCase():"",t=r?D.getParent(r.parentNode,D.isBlock):null,u=t?t.nodeName.toUpperCase():"",v=k&&k.ctrlKey;"LI"!=u||v||(r=t,s=u),p&&3==p.nodeType&&o>=p.nodeValue.length&&(m||f()||(h=D.create("br"),l.insertNode(h),l.setStartAfter(h),l.setEndAfter(h),i=!0)
 ),h=D.create("br"),l.insertNode(h);var w=D.doc.documentMode;return m&&"PRE"==s&&(!w||w<8)&&h.parentNode.insertBefore(D.doc.createTextNode("\r"),h),j=D.create("span",{},"&nbsp;"),h.parentNode.insertBefore(j,h),E.scrollIntoView(j),D.remove(j),i?(l.setStartBefore(h),l.setEndBefore(h)):(l.setStartAfter(h),l.setEndAfter(h)),E.setRng(l),g.undoManager.add(),n}}),s({"JustifyLeft,JustifyCenter,JustifyRight,JustifyFull":function(a){var b="align"+a.substring(7),c=E.isCollapsed()?[D.getParent(E.getNode(),D.isBlock)]:E.getSelectedBlocks(),d=j(c,function(a){return!!F.matchNode(a,b)});return k(d,n)!==-1},"Bold,Italic,Underline,Strikethrough,Superscript,Subscript":function(a){return z(a)},mceBlockQuote:function(){return z("blockquote")},Outdent:function(){var a;if(I.inline_styles){if((a=D.getParent(E.getStart(),D.isBlock))&&parseInt(a.style.paddingLeft,10)>0)return n;i
 f((a=D.getParent(E.getEnd(),D.isBlock))&&parseInt(a.style.paddingLeft,10)>0)return n}return q("InsertUnorderedList")||q("InsertOrderedList")||!I.inline_styles&&!!D.getParent(E.getNode(),"BLOCKQUOTE")},"InsertUnorderedList,InsertOrderedList":function(a){var b=D.getParent(E.getNode(),"ul,ol");return b&&("insertunorderedlist"===a&&"UL"===b.tagName||"insertorderedlist"===a&&"OL"===b.tagName)}},"state"),s({"FontSize,FontName":function(a){var b,c=0;return(b=D.getParent(E.getNode(),"span"))&&(c="fontsize"==a?b.style.fontSize:b.style.fontFamily.replace(/, /g,",").replace(/[\'\"]/g,"").toLowerCase()),c}},"value"),s({Undo:function(){g.undoManager.undo()},Redo:function(){g.undoManager.redo()}})}}),g("w",["1y","9"],function(a,b){function c(b,g){var h,i,
 j=this;if(b=e(b),g=j.settings=g||{},h=g.base_uri,/^([\w\-]+):([^\/]{2})/i.test(b)||/^\s*#/.test(b))return void(j.source=b);var k=0===b.indexOf("//");0!==b.indexOf("/")||k||(b=(h?h.protocol||"http":"http")+"://mce_host"+b),/^[\w\-]*:?\/\//.test(b)||(i=g.base_uri?g.base_uri.path:new c(a.location.href).directory,""===g.base_uri.protocol?b="//mce_host"+j.toAbsPath(i,b):(b=/([^#?]*)([#?]?.*)/.exec(b),b=(h&&h.protocol||"http")+"://mce_host"+j.toAbsPath(i,b[1])+b[2])),b=b.replace(/@@/g,"(mce_at)"),b=/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(b),d(f,function(a,c){var d=b[c];d&&(d=d.replace(/\(mce_at\)/g,"@@")),j[a]=d}),h&&(j.protocol||(j.protocol=h.protocol),j.userInfo||(j.userInfo=h.userInfo),j.port||&qu
 ot;mce_host"!==j.host||(j.port=h.port),j.host&&"mce_host"!==j.host||(j.host=h.host),j.source=""),k&&(j.protocol="")}var d=b.each,e=b.trim,f="source protocol authority userInfo user password host port relative path directory file query anchor".split(" "),g={ftp:21,http:80,https:443,mailto:25};return c.prototype={setPath:function(a){var b=this;a=/^(.*?)\/?(\w+)?$/.exec(a),b.path=a[0],b.directory=a[1],b.file=a[2],b.source="",b.getURI()},toRelative:function(a){var b,d=this;if("./"===a)return a;if(a=new c(a,{base_uri:d}),"mce_host"!=a.host&&d.host!=a.host&&a.host||d.port!=a.port||d.protocol!=a.protocol&&""!==a.protocol)return a.getURI();var e=d.getURI(),f=a.getURI();return e==f||"/"==e.charAt(e.length-1)&&e.substr(0,e.length-1)==f?e:(b=d.toRelPath(d.path,a.path),a.query&&(b+="?"+a.query),a.anchor&&(b+="#&qu
 ot;+a.anchor),b)},toAbsolute:function(a,b){return a=new c(a,{base_uri:this}),a.getURI(b&&this.isSameOrigin(a))},isSameOrigin:function(a){if(this.host==a.host&&this.protocol==a.protocol){if(this.port==a.port)return!0;var b=g[this.protocol];if(b&&(this.port||b)==(a.port||b))return!0}return!1},toRelPath:function(a,b){var c,d,e,f=0,g="";if(a=a.substring(0,a.lastIndexOf("/")),a=a.split("/"),c=b.split("/"),a.length>=c.length)for(d=0,e=a.length;d<e;d++)if(d>=c.length||a[d]!=c[d]){f=d+1;break}if(a.length<c.length)for(d=0,e=c.length;d<e;d++)if(d>=a.length||a[d]!=c[d]){f=d+1;break}if(1===f)return b;for(d=0,e=a.length-(f-1);d<e;d++)g+="../";for(d=f-1,e=c.length;d<e;d++)g+=d!=f-1?"/"+c[d]:c[d];return g},toAbsPath:function(a,b){var c,e,f,g=0,h=[];for(e=/\/$/.test(b)?"/":"",a=a.split("/"),b=b.split("/"),d(a,function(a){a&&h.push(a)}),a=h,c=b.l
 ength-1,h=[];c>=0;c--)0!==b[c].length&&"."!==b[c]&&(".."!==b[c]?g>0?g--:h.push(b[c]):g++);return c=a.length-g,f=c<=0?h.reverse().join("/"):a.slice(0,c).join("/")+"/"+h.reverse().join("/"),0!==f.indexOf("/")&&(f="/"+f),e&&f.lastIndexOf("/")!==f.length-1&&(f+=e),f},getURI:function(a){var b,c=this;return c.source&&!a||(b="",a||(b+=c.protocol?c.protocol+"://":"//",c.userInfo&&(b+=c.userInfo+"@"),c.host&&(b+=c.host),c.port&&(b+=":"+c.port)),c.path&&(b+=c.path),c.query&&(b+="?"+c.query),c.anchor&&(b+="#"+c.anchor),c.source=b),c.source}},c.parseDataUri=function(a){var b,c;return a=decodeURIComponent(a).split(","),
-c=/data:([^;]+)/.exec(a[0]),c&&(b=c[1]),{type:b,data:a[1]}},c.getDocumentBaseUrl=function(a){var b;return b=0!==a.protocol.indexOf("http")&&"file:"!==a.protocol?a.href:a.protocol+"//"+a.host+a.pathname,/^[^:]+:\/\/\/?[^\/]+\//.test(b)&&(b=b.replace(/[\?#].*$/,"").replace(/[\/\\][^\/]+$/,""),/[\/\\]$/.test(b)||(b+="/")),b},c}),g("x",["9"],function(a){function b(){}var c,d,e=a.each,f=a.extend;return b.extend=c=function(a){function b(){var a,b,c,e=this;if(!d&&(e.init&&e.init.apply(e,arguments),b=e.Mixins))for(a=b.length;a--;)c=b[a],c.init&&c.init.apply(e,arguments)}function g(){return this}function h(a,b){return function(){var c,d=this,e=d._super;return d._super=m[a],c=b.apply(d,arguments),d._super=e,c}}var i,j,k,l=this,m=l.prototype;d=!0,i=new l,d=!1,a.Mixins&&(e(a.Mixins,function(b){for(var c in b)"init"!==c&&(a[c]=b[c])}),m.Mixins&
 amp;&(a.Mixins=m.Mixins.concat(a.Mixins))),a.Methods&&e(a.Methods.split(","),function(b){a[b]=g}),a.Properties&&e(a.Properties.split(","),function(b){var c="_"+b;a[b]=function(a){var b,d=this;return a!==b?(d[c]=a,d):d[c]}}),a.Statics&&e(a.Statics,function(a,c){b[c]=a}),a.Defaults&&m.Defaults&&(a.Defaults=f({},m.Defaults,a.Defaults));for(j in a)k=a[j],"function"==typeof k&&m[j]?i[j]=h(j,k):i[j]=k;return b.prototype=i,b.constructor=b,b.extend=c,b},b}),g("y",["9"],function(a){function b(b){function c(){return!1}function d(){return!0}function e(a,e){var f,h,i,k;if(a=a.toLowerCase(),e=e||{},e.type=a,e.target||(e.target=j),e.preventDefault||(e.preventDefault=function(){e.isDefaultPrevented=d},e.stopPropagation=function(){e.isPropagationStopped=d},e.stopImmediatePropagation=function(){e.isImmediatePropagationStopped=d},e.isDefaultPrevented=c,e.isPropagationStopped=c,e.isImmediate
 PropagationStopped=c),b.beforeFire&&b.beforeFire(e),f=m[a])for(h=0,i=f.length;h<i;h++){if(k=f[h],k.once&&g(a,k.func),e.isImmediatePropagationStopped())return e.stopPropagation(),e;if(k.func.call(j,e)===!1)return e.preventDefault(),e}return e}function f(b,d,e,f){var g,h,i;if(d===!1&&(d=c),d)for(d={func:d},f&&a.extend(d,f),h=b.toLowerCase().split(" "),i=h.length;i--;)b=h[i],g=m[b],g||(g=m[b]=[],k(b,!0)),e?g.unshift(d):g.push(d);return l}function g(a,b){var c,d,e,f,g;if(a)for(f=a.toLowerCase().split(" "),c=f.length;c--;){if(a=f[c],d=m[a],!a){for(e in m)k(e,!1),delete m[e];return l}if(d){if(b)for(g=d.length;g--;)d[g].func===b&&(d=d.slice(0,g).concat(d.slice(g+1)),m[a]=d);else d.length=0;d.length||(k(a,!1),delete m[a])}}else{for(a in m)k(a,!1);m={}}return l}function h(a,b,c){return f(a,b,c,{once:!0})}function i(a){return a=a.toLowerCase(),!(!m[a]||0===m[a].length)}var j,k,l=this,m={};b=b||{},j=b.scope||l,k=b.toggleEvent||c,l.
 fire=e,l.on=f,l.off=g,l.once=h,l.has=i}var c=a.makeMap("focus blur focusin focusout click dblclick mousedown mouseup mousemove mouseover beforepaste paste cut copy selectionchange mouseout mouseenter mouseleave wheel keydown keypress keyup input contextmenu dragstart dragend dragover draggesture dragdrop drop drag submit compositionstart compositionend compositionupdate touchstart touchmove touchend"," ");return b.isNative=function(a){return!!c[a.toLowerCase()]},b}),g("z",["y"],function(a){function b(b){return b._eventDispatcher||(b._eventDispatcher=new a({scope:b,toggleEvent:function(c,d){a.isNative(c)&&b.toggleNativeEvent&&b.toggleNativeEvent(c,d)}})),b._eventDispatcher}return{fire:function(a,c,d){var e=this;if(e.removed&&"remove"!==a)return c;if(c=b(e).fire(a,c,d),d!==!1&&e.parent)for(var f=e.parent();f&&!c.isPropagationStopped();)f.fire(a,c,!1),f=f.parent();return c},on:function(a,c,d){retu
 rn b(this).on(a,c,d)},off:function(a,c){return b(this).off(a,c)},once:function(a,c){return b(this).once(a,c)},hasEventListeners:function(a){return b(this).has(a)}}}),g("5h",[],function(){function a(a){this.create=a.create}return a.create=function(b,c){return new a({create:function(a,d){function e(b){a.set(d,b.value)}function f(a){b.set(c,a.value)}var g;return a.on("change:"+d,f),b.on("change:"+c,e),g=a._bindings,g||(g=a._bindings=[],a.on("destroy",function(){for(var a=g.length;a--;)g[a]()})),g.push(function(){b.off("change:"+c,e)}),b.get(c)}})},a}),g("4g",["5h","x","z","9"],function(a,b,c,d){function e(a){return a.nodeType>0}function f(a,b){var c,g;if(a===b)return!0;if(null===a||null===b)return a===b;if("object"!=typeof a||"object"!=typeof b)return a===b;if(d.isArray(b)){if(a.length!==b.length)return!1;for(c=a.length;c--;)if(!f(a[c],b[c]))return!1}if(e(a)||e(b))
 return a===b;g={};for(c in b){if(!f(a[c],b[c]))return!1;g[c]=!0}for(c in a)if(!g[c]&&!f(a[c],b[c]))return!1;return!0}return b.extend({Mixins:[c],init:function(b){var c,d;b=b||{};for(c in b)d=b[c],d instanceof a&&(b[c]=d.create(this,c));this.data=b},set:function(b,c){var d,e,g=this.data[b];if(c instanceof a&&(c=c.create(this,b)),"object"==typeof b){for(d in b)this.set(d,b[d]);return this}return f(g,c)||(this.data[b]=c,e={target:this,name:b,value:c,oldValue:g},this.fire("change:"+b,e),this.fire("change",e)),this},get:function(a){return this.data[a]},has:function(a){return a in this.data},bind:function(b){return a.create(this,b)},destroy:function(){this.fire("destroy")}})}),g("28",["x"],function(a){"use strict";function b(a){for(var b,c=[],d=a.length;d--;)b=a[d],b.__checked||(c.push(b),b.__checked=1);for(d=c.length;d--;)delete c[d].__checked;return c}var c,d=/^([\w\\*]+)?(?:#([\w\-\\]+))?(?:\.
 ([\w\\\.]+))?(?:\[\@?([\w\\]+)([\^\$\*!~]?=)([\w\\]+)\])?(?:\:(.+))?/i,e=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,f=/^\s*|\s*$/g,g=a.extend({init:function(a){function b(a){if(a)return a=a.toLowerCase(),function(b){return"*"===a||b.type===a}}function c(a){if(a)return function(b){return b._name===a}}function g(a){if(a)return a=a.split("."),function(b){for(var c=a.length;c--;)if(!b.classes.contains(a[c]))return!1;return!0}}function h(a,b,c){if(a)return function(d){var e=d[a]?d[a]():"";return b?"="===b?e===c:"*="===b?e.indexOf(c)>=0:"~="===b?(" "+e+" ").indexOf(" "+c+" ")>=0:"!="===b?e!=c:"^="===b?0===e.indexOf(c):"$="===b&&e.substr(e.length-c.length)===c:!!c}}function i(a){var b;if(a)return a=/(?:not\((.+)\))|(.+)/i.exec(a),a[1
 ]?(b=k(a[1],[]),function(a){return!l(a,b)}):(a=a[2],function(b,c,d){return"first"===a?0===c:"last"===a?c===d-1:"even"===a?c%2===0:"odd"===a?c%2===1:!!b[a]&&b[a]()})}function j(a,e,j){function k(a){a&&e.push(a)}var l;return l=d.exec(a.replace(f,"")),k(b(l[1])),k(c(l[2])),k(g(l[3])),k(h(l[4],l[5],l[6])),k(i(l[7])),e.pseudo=!!l[7],e.direct=j,e}function k(a,b){var c,d,f,g=[];do if(e.exec(""),d=e.exec(a),d&&(a=d[3],g.push(d[1]),d[2])){c=d[3];break}while(d);for(c&&k(c,b),a=[],f=0;f<g.length;f++)">"!=g[f]&&a.push(j(g[f],[],">"===g[f-1]));return b.push(a),b}var l=this.match;this._selectors=k(a,[])},match:function(a,b){var c,d,e,f,g,h,i,j,k,l,m,n,o;for(b=b||this._selectors,c=0,d=b.length;c<d;c++){for(g=b[c],f=g.length,o=a,n=0,e=f-1;e>=0;e--)for(j=g[e];o;){if(j.pseudo)for(m=o.parent().items(),k=l=m.length;k--&&m[k]!==o;);for(h=0,i=j.length;h<i;h++)i
 f(!j[h](o,k,l)){h=i+1;break}if(h===i){n++;break}if(e===f-1)break;o=o.parent()}if(n===f)return!0}return!1},find:function(a){function d(a,b,c){var e,f,g,i,j,k=b[c];for(e=0,f=a.length;e<f;e++){for(j=a[e],g=0,i=k.length;g<i;g++)if(!k[g](j,e,f)){g=i+1;break}if(g===i)c==b.length-1?h.push(j):j.items&&d(j.items(),b,c+1);else if(k.direct)return;j.items&&d(j.items(),b,c)}}var e,f,h=[],i=this._selectors;if(a.items){for(e=0,f=i.length;e<f;e++)d(a.items(),i[e],0);f>1&&(h=b(h))}return c||(c=g.Collection),new c(h)}});return g}),g("29",["9","28","x"],function(a,b,c){"use strict";var d,e,f=Array.prototype.push,g=Array.prototype.slice;return e={length:0,init:function(a){a&&this.add(a)},add:function(b){var c=this;return a.isArray(b)?f.apply(c,b):b instanceof d?c.add(b.toArray()):f.call(c,b),c},set:function(a){var b,c=this,d=c.length;for(c.length=0,c.add(a),b=c.length;b<d;b++)delete c[b];return c},filter:fu
 nction(a){var c,e,f,g,h=this,i=[];for("string"==typeof a?(a=new b(a),g=function(b){return a.match(b)}):g=a,c=0,e=h.length;c<e;c++)f=h[c],g(f)&&i.push(f);return new d(i)},slice:function(){return new d(g.apply(this,arguments))},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},each:function(b){return a.each(this,b),this},toArray:function(){return a.toArray(this)},indexOf:function(a){for(var b=this,c=b.length;c--&&b[c]!==a;);return c},reverse:function(){return new d(a.toArray(this).reverse())},hasClass:function(a){return!!this[0]&&this[0].classes.contains(a)},prop:function(a,b){var c,d,e=this;return b!==c?(e.each(function(c){c[a]&&c[a](b)}),e):(d=e[0],d&&d[a]?d[a]():void 0)},exec:function(b){var c=this,d=a.toArray(arguments).slice(1);return c.each(function(a){a[b]&&a[b].apply(a,d)}),c},remove:function(){for(var a=this.length;a--;)this[a].remove();return this},addClass:function(a){return this.each(function(b){b.cl
 asses.add(a)})},removeClass:function(a){return this.each(function(b){b.classes.remove(a)})}},a.each("fire on off show hide append prepend before after reflow".split(" "),function(b){e[b]=function(){var c=a.toArray(arguments);return this.each(function(a){b in a&&a[b].apply(a,c)}),this}}),a.each("text name disabled active selected checked visible parent value data".split(" "),function(a){e[a]=function(b){return this.prop(a,b)}}),d=c.extend(e),b.Collection=d,d}),g("4h",["6","9","e"],function(a,b,c){"use strict";var d=0,e={id:function(){return"mceu_"+d++},create:function(a,d,e){var f=document.createElement(a);return c.DOM.setAttribs(f,d),"string"==typeof e?f.innerHTML=e:b.each(e,function(a){a.nodeType&&f.appendChild(a)}),f},createFragment:function(a){return c.DOM.createFragment(a)},getWindowSize:function(){return c.DOM.getViewPort()},getSize:function(a){var b,c;i
 f(a.getBoundingClientRect){var d=a.getBoundingClientRect();b=Math.max(d.width||d.right-d.left,a.offsetWidth),c=Math.max(d.height||d.bottom-d.bottom,a.offsetHeight)}else b=a.offsetWidth,c=a.offsetHeight;return{width:b,height:c}},getPos:function(a,b){return c.DOM.getPos(a,b||e.getContainer())},getContainer:function(){return a.container?a.container:document.body},getViewPort:function(a){return c.DOM.getViewPort(a)},get:function(a){return document.getElementById(a)},addClass:function(a,b){return c.DOM.addClass(a,b)},removeClass:function(a,b){return c.DOM.removeClass(a,b)},hasClass:function(a,b){return c.DOM.hasClass(a,b)},toggleClass:function(a,b,d){return c.DOM.toggleClass(a,b,d)},css:function(a,b,d){return c.DOM.setStyle(a,b,d)},getRuntimeStyle:function(a,b){return c.DOM.getStyle(a,b,!0)},on:function(a,b,d,e){return c.DOM.bind(a,b,d,e)},off:function(a,b,d){return c.DOM.unbind(a,b,d)},fire:function(a,b,d){return c.DOM.fire(a,b,d)},innerHtml:function(a,b){c.DOM.setHTML(a,b)}};return e})
 ,g("4i",[],function(){"use strict";return{parseBox:function(a){var b,c=10;if(a)return"number"==typeof a?(a=a||0,{top:a,left:a,bottom:a,right:a}):(a=a.split(" "),b=a.length,1===b?a[1]=a[2]=a[3]=a[0]:2===b?(a[2]=a[0],a[3]=a[1]):3===b&&(a[3]=a[1]),{top:parseInt(a[0],c)||0,right:parseInt(a[1],c)||0,bottom:parseInt(a[2],c)||0,left:parseInt(a[3],c)||0})},measureBox:function(a,b){function c(b){var c=document.defaultView;return c?(b=b.replace(/[A-Z]/g,function(a){return"-"+a}),c.getComputedStyle(a,null).getPropertyValue(b)):a.currentStyle[b]}function d(a){var b=parseFloat(c(a),10);return isNaN(b)?0:b}return{top:d(b+"TopWidth"),right:d(b+"RightWidth"),bottom:d(b+"BottomWidth"),left:d(b+"LeftWidth")}}}}),g("4j",["9"],function(a){"use strict";function b(){}function c(a){this.cls=[],this.cls._map={},this.onchange=a||b,this.prefix=""}return a.extend(c.prototyp
 e,{add:function(a){return a&&!this.contains(a)&&(this.cls._map[a]=!0,this.cls.push(a),this._change()),this},remove:function(a){if(this.contains(a)){for(var b=0;b<this.cls.length&&this.cls[b]!==a;b++);this.cls.splice(b,1),delete this.cls._map[a],this._change()}return this},toggle:function(a,b){var c=this.contains(a);return c!==b&&(c?this.remove(a):this.add(a),this._change()),this},contains:function(a){return!!this.cls._map[a]},_change:function(){delete this.clsValue,this.onchange.call(this)}}),c.prototype.toString=function(){var a;if(this.clsValue)return this.clsValue;a="";for(var b=0;b<this.cls.length;b++)b>0&&(a+=" "),a+=this.prefix+this.cls[b];return a},c}),g("2a",["5"],function(a){var b,c={};return{add:function(d){var e=d.parent();if(e){if(!e._layout||e._layout.isNative())return;c[e._id]||(c[e._id]=e),b||(b=!0,a.requestAnimationFrame(function(){var a,d;b=!1;for(a in c)d=c[a],d.state.get(&quot
 ;rendered")&&d.reflow();c={}},document.body))}},remove:function(a){c[a._id]&&delete c[a._id]}}}),g("2b",["x","9","y","4g","29","4h","a","4i","4j","2a"],function(a,b,c,d,e,f,g,h,i,j){"use strict";function k(a){return a._eventDispatcher||(a._eventDispatcher=new c({scope:a,toggleEvent:function(b,d){d&&c.isNative(b)&&(a._nativeEvents||(a._nativeEvents={}),a._nativeEvents[b]=!0,a.state.get("rendered")&&l(a))}})),a._eventDispatcher}function l(a){function b(b){var c=a.getParentCtrl(b.target);c&&c.fire(b.type,b)}function c(){var a=j._lastHoverCtrl;a&&(a.fire("mouseleave",{target:a.getEl()}),a.parents().each(function(a){a.fire("mouseleave",{target:a.getEl()})}),j._lastHoverCtrl=null)}function d(b){var c,d,e,f=a.getParentCtrl(b.target),g=j._lastHoverCtrl,h=0;if(f!==g){if(j._lastHoverCt
 rl=f,d=f.parents().toArray().reverse(),d.push(f),g){for(e=g.parents().toArray().reverse(),e.push(g),h=0;h<e.length&&d[h]===e[h];h++);for(c=e.length-1;c>=h;c--)g=e[c],g.fire("mouseleave",{target:g.getEl()})}for(c=h;c<d.length;c++)f=d[c],f.fire("mouseenter",{target:f.getEl()})}}function e(b){b.preventDefault(),"mousewheel"==b.type?(b.deltaY=-.025*b.wheelDelta,b.wheelDeltaX&&(b.deltaX=-.025*b.wheelDeltaX)):(b.deltaX=0,b.deltaY=b.detail),b=a.fire("wheel",b)}var f,h,i,j,k,l;if(k=a._nativeEvents){for(i=a.parents().toArray(),i.unshift(a),f=0,h=i.length;!j&&f<h;f++)j=i[f]._eventsRoot;for(j||(j=i[i.length-1]||a),a._eventsRoot=j,h=f,f=0;f<h;f++)i[f]._eventsRoot=j;var m=j._delegates;m||(m=j._delegates={});for(l in k){if(!k)return!1;"wheel"!==l||o?("mouseenter"===l||"mouseleave"===l?j._hasMouseEnter||(g(j.getEl()).on("mouseleave",c).on("mouseover",d),j._hasMouseEnter=
 1):m[l]||(g(j.getEl()).on(l,b),m[l]=!0),k[l]=!1):n?g(a.getEl()).on("mousewheel",e):g(a.getEl()).on("DOMMouseScroll",e)}}}var m,n="onmousewheel"in document,o=!1,p="mce-",q=0,r={Statics:{classPrefix:p},isRtl:function(){return m.rtl},classPrefix:p,init:function(a){function c(a){var b;for(a=a.split(" "),b=0;b<a.length;b++)j.classes.add(a[b])}var e,f,j=this;j.settings=a=b.extend({},j.Defaults,a),j._id=a.id||"mceu_"+q++,j._aria={role:a.role},j._elmCache={},j.$=g,j.state=new d({visible:!0,active:!1,disabled:!1,value:""}),j.data=new d(a.data),j.classes=new i(function(){j.state.get("rendered")&&(j.getEl().className=this.toString())}),j.classes.prefix=j.classPrefix,e=a.classes,e&&(j.Defaults&&(f=j.Defaults.classes,f&&e!=f&&c(f)),c(e)),b.each("title text name visible disabled active value".split(" "),function(b){b in a&&j[b](a[b])}),j.on("c
 lick",function(){if(j.disabled())return!1}),j.settings=a,j.borderBox=h.parseBox(a.border),j.paddingBox=h.parseBox(a.padding),j.marginBox=h.parseBox(a.margin),a.hidden&&j.hide()},Properties:"parent,name",getContainerElm:function(){return f.getContainer()},getParentCtrl:function(a){for(var b,c=this.getRoot().controlIdLookup;a&&c&&!(b=c[a.id]);)a=a.parentNode;return b},initLayoutRect:function(){var a,b,c,d,e,g,i,j,k,l,m=this,n=m.settings,o=m.getEl();a=m.borderBox=m.borderBox||h.measureBox(o,"border"),m.paddingBox=m.paddingBox||h.measureBox(o,"padding"),m.marginBox=m.marginBox||h.measureBox(o,"margin"),l=f.getSize(o),j=n.minWidth,k=n.minHeight,e=j||l.width,g=k||l.height,c=n.width,d=n.height,i=n.autoResize,i="undefined"!=typeof i?i:!c&&!d,c=c||e,d=d||g;var p=a.left+a.right,q=a.top+a.bottom,r=n.maxWidth||65535,s=n.maxHeight||65535;return m._layoutRect=b={x:n.x||0,y:n.y||0,w:c,h:d,deltaW:p,deltaH:q,conte
 ntW:c-p,contentH:d-q,innerW:c-p,innerH:d-q,startMinWidth:j||0,startMinHeight:k||0,minW:Math.min(e,r),minH:Math.min(g,s),maxW:r,maxH:s,autoResize:i,scrollW:0},m._lastLayoutRect={},b},layoutRect:function(a){var b,c,d,e,f,g,h=this,i=h._layoutRect;return i||(i=h.initLayoutRect()),a?(d=i.deltaW,e=i.deltaH,a.x!==f&&(i.x=a.x),a.y!==f&&(i.y=a.y),a.minW!==f&&(i.minW=a.minW),a.minH!==f&&(i.minH=a.minH),c=a.w,c!==f&&(c=c<i.minW?i.minW:c,c=c>i.maxW?i.maxW:c,i.w=c,i.innerW=c-d),c=a.h,c!==f&&(c=c<i.minH?i.minH:c,c=c>i.maxH?i.maxH:c,i.h=c,i.innerH=c-e),c=a.innerW,c!==f&&(c=c<i.minW-d?i.minW-d:c,c=c>i.maxW-d?i.maxW-d:c,i.innerW=c,i.w=c+d),c=a.innerH,c!==f&&(c=c<i.minH-e?i.minH-e:c,c=c>i.maxH-e?i.maxH-e:c,i.innerH=c,i.h=c+e),a.contentW!==f&&(i.contentW=a.contentW),a.contentH!==f&&(i.contentH=a.contentH),b=h._lastLayoutRect,b.x===i.x&&b.y===i.y&&b.w===i.w&&b.h===i.h||(g=m.re
 paintControls,g&&g.map&&!g.map[h._id]&&(g.push(h),g.map[h._id]=!0),b.x=i.x,b.y=i.y,b.w=i.w,b.h=i.h),h):i},repaint:function(){var a,b,c,d,e,f,g,h,i,j,k=this;i=document.createRange?function(a){return a}:Math.round,a=k.getEl().style,d=k._layoutRect,h=k._lastRepaintRect||{},e=k.borderBox,f=e.left+e.right,g=e.top+e.bottom,d.x!==h.x&&(a.left=i(d.x)+"px",h.x=d.x),d.y!==h.y&&(a.top=i(d.y)+"px",h.y=d.y),d.w!==h.w&&(j=i(d.w-f),a.width=(j>=0?j:0)+"px",h.w=d.w),d.h!==h.h&&(j=i(d.h-g),a.height=(j>=0?j:0)+"px",h.h=d.h),k._hasBody&&d.innerW!==h.innerW&&(j=i(d.innerW),c=k.getEl("body"),c&&(b=c.style,b.width=(j>=0?j:0)+"px"),h.innerW=d.innerW),k._hasBody&&d.innerH!==h.innerH&&(j=i(d.innerH),c=c||k.getEl("body"),c&&(b=b||c.style,b.height=(j>=0?j:0)+"px"),h.innerH=d.innerH),k._lastRepaintRect=h,k.fire("r
 epaint",{},!1)},updateLayoutRect:function(){var a=this;a.parent()._lastRect=null,f.css(a.getEl(),{width:"",height:""}),a._layoutRect=a._lastRepaintRect=a._lastLayoutRect=null,a.initLayoutRect()},on:function(a,b){function c(a){var b,c;return"string"!=typeof a?a:function(e){return b||d.parentsAndSelf().each(function(d){var e=d.settings.callbacks;if(e&&(b=e[a]))return c=d,!1}),b?b.call(c,e):(e.action=a,void this.fire("execute",e))}}var d=this;return k(d).on(a,c(b)),d},off:function(a,b){return k(this).off(a,b),this},fire:function(a,b,c){var d=this;if(b=b||{},b.control||(b.control=d),b=k(d).fire(a,b),c!==!1&&d.parent)for(var e=d.parent();e&&!b.isPropagationStopped();)e.fire(a,b,!1),e=e.parent();return b},hasEventListeners:function(a){return k(this).has(a)},parents:function(a){var b,c=this,d=new e;for(b=c.parent();b;b=b.parent())d.add(b);return a&&(d=d.filter(a)),d},parentsAndSelf:function(a){return new e(this).a
 dd(this.parents(a))},next:function(){var a=this.parent().items();return a[a.indexOf(this)+1]},prev:function(){var a=this.parent().items();return a[a.indexOf(this)-1]},innerHtml:function(a){return this.$el.html(a),this},getEl:function(a){var b=a?this._id+"-"+a:this._id;return this._elmCache[b]||(this._elmCache[b]=g("#"+b)[0]),this._elmCache[b]},show:function(){return this.visible(!0)},hide:function(){return this.visible(!1)},focus:function(){try{this.getEl().focus()}catch(a){}return this},blur:function(){return this.getEl().blur(),this},aria:function(a,b){var c=this,d=c.getEl(c.ariaTarget);return"undefined"==typeof b?c._aria[a]:(c._aria[a]=b,c.state.get("rendered")&&d.setAttribute("role"==a?a:"aria-"+a,b),c)},encode:function(a,b){return b!==!1&&(a=this.translate(a)),(a||"").replace(/[&<>"]/g,function(a){return"&#"+a.charCodeAt(0)+";"})},translate:function(a){re
 turn m.translate?m.translate(a):a},before:function(a){var b=this,c=b.parent();return c&&c.insert(a,c.items().indexOf(b),!0),b},after:function(a){var b=this,c=b.parent();return c&&c.insert(a,c.items().indexOf(b)),b},remove:function(){var a,b,c=this,d=c.getEl(),e=c.parent();if(c.items){var f=c.items().toArray();for(b=f.length;b--;)f[b].remove()}e&&e.items&&(a=[],e.items().each(function(b){b!==c&&a.push(b)}),e.items().set(a),e._lastRect=null),c._eventsRoot&&c._eventsRoot==c&&g(d).off();var h=c.getRoot().controlIdLookup;return h&&delete h[c._id],d&&d.parentNode&&d.parentNode.removeChild(d),c.state.set("rendered",!1),c.state.destroy(),c.fire("remove"),c},renderBefore:function(a){return g(a).before(this.renderHtml()),this.postRender(),this},renderTo:function(a){return g(a||this.getContainerElm()).append(this.renderHtml()),this.postRender(),this},preRender:function(){},render:function(){},re
 nderHtml:function(){return'<div id="'+this._id+'" class="'+this.classes+'"></div>'},postRender:function(){var a,b,c,d,e,f=this,h=f.settings;f.$el=g(f.getEl()),f.state.set("rendered",!0);for(d in h)0===d.indexOf("on")&&f.on(d.substr(2),h[d]);if(f._eventsRoot){for(c=f.parent();!e&&c;c=c.parent())e=c._eventsRoot;if(e)for(d in e._nativeEvents)f._nativeEvents[d]=!0}l(f),h.style&&(a=f.getEl(),a&&(a.setAttribute("style",h.style),a.style.cssText=h.style)),f.settings.border&&(b=f.borderBox,f.$el.css({"border-top-width":b.top,"border-right-width":b.right,"border-bottom-width":b.bottom,"border-left-width":b.left}));var i=f.getRoot();i.controlIdLookup||(i.controlIdLookup={}),i.controlIdLookup[f._id]=f;for(var k in f._aria)f.aria(k,f._aria[k]);f.state.get("visible")===!1&&(f.getEl().style.display="none"),f.bindStates(),f.state.o
 n("change:visible",function(a){var b,c=a.value;f.state.get("rendered")&&(f.getEl().style.display=c===!1?"none":"",f.getEl().getBoundingClientRect()),b=f.parent(),b&&(b._lastRect=null),f.fire(c?"show":"hide"),j.add(f)}),f.fire("postrender",{},!1)},bindStates:function(){},scrollIntoView:function(a){function b(a,b){var c,d,e=a;for(c=d=0;e&&e!=b&&e.nodeType;)c+=e.offsetLeft||0,d+=e.offsetTop||0,e=e.offsetParent;return{x:c,y:d}}var c,d,e,f,g,h,i=this.getEl(),j=i.parentNode,k=b(i,j);return c=k.x,d=k.y,e=i.offsetWidth,f=i.offsetHeight,g=j.clientWidth,h=j.clientHeight,"end"==a?(c-=g-e,d-=h-f):"center"==a&&(c-=g/2-e/2,d-=h/2-f/2),j.scrollLeft=c,j.scrollTop=d,this},getRoot:function(){for(var a,b=this,c=[];b;){if(b.rootControl){a=b.rootControl;break}c.push(b),a=b,b=b.parent()}a||(a=this);for(var d=c.length;d--;)c[d].rootControl=a;return a},reflow:function(){j.remove
 (this);var a=this.parent();return a&&a._layout&&!a._layout.isNative()&&a.reflow(),this}};return b.each("text title visible disabled active value".split(" "),function(a){r[a]=function(b){return 0===arguments.length?this.state.get(a):("undefined"!=typeof b&&this.state.set(a,b),this)}}),m=a.extend(r)}),g("2c",[],function(){"use strict";var a={};return{add:function(b,c){a[b.toLowerCase()]=c},has:function(b){return!!a[b.toLowerCase()]},create:function(b,c){var d;if("string"==typeof b?(c=c||{},c.type=b):(c=b,b=c.type),b=b.toLowerCase(),d=a[b],!d)throw new Error("Could not find control by type: "+b);return d=new d(c),d.type=b,d}}}),g("2d",[],function(){"use strict";var a=function(a){return!!a.getAttribute("data-mce-tabstop")};return function(b){function c(a){return a&&1===a.nodeType}function d(a){return a=a||u,c(a)?a.getAttribute("role"):null
 }function e(a){for(var b,c=a||u;c=c.parentNode;)if(b=d(c))return b}function f(a){var b=u;if(c(b))return b.getAttribute("aria-"+a)}function g(a){var b=a.tagName.toUpperCase();return"INPUT"==b||"TEXTAREA"==b||"SELECT"==b}function h(b){return!(!g(b)||b.hidden)||(!!a(b)||!!/^(button|menuitem|checkbox|tab|menuitemcheckbox|option|gridcell|slider)$/.test(d(b)))}function i(a){function b(a){if(1==a.nodeType&&"none"!=a.style.display&&!a.disabled){h(a)&&c.push(a);for(var d=0;d<a.childNodes.length;d++)b(a.childNodes[d])}}var c=[];return b(a||w.getEl()),c}function j(a){var b,c;a=a||v,c=a.parents().toArray(),c.unshift(a);for(var d=0;d<c.length&&(b=c[d],!b.settings.ariaRoot);d++);return b}function k(a){var b=j(a),c=i(b.getEl());b.settings.ariaRemember&&"lastAriaIndex"in b?l(b.lastAriaIndex,c):l(0,c)}function l(a,b){return a<0?a=b.length-1:a>=b.length&&(a=0),b[a]&&b[a].foc
 us(),a}function m(a,b){var c=-1,d=j();b=b||i(d.getEl());for(var e=0;e<b.length;e++)b[e]===u&&(c=e);c+=a,d.lastAriaIndex=l(c,b)}function n(){var a=e();"tablist"==a?m(-1,i(u.parentNode)):v.parent().submenu?s():m(-1)}function o(){var a=d(),b=e();"tablist"==b?m(1,i(u.parentNode)):"menuitem"==a&&"menu"==b&&f("haspopup")?t():m(1)}function p(){m(-1)}function q(){var a=d(),b=e();"menuitem"==a&&"menubar"==b?t():"button"==a&&f("haspopup")?t({key:"down"}):m(1)}function r(a){var b=e();if("tablist"==b){var c=i(v.getEl("body"))[0];c&&c.focus()}else m(a.shiftKey?-1:1)}function s(){v.fire("cancel")}function t(a){a=a||{},v.fire("click",{target:u,aria:a})}var u,v,w=b.root;try{u=document.activeElement}catch(a){u=document.body}return v=w.getParentCtrl(u),w.on("keydown",function(b){function c(b,c){g(u)||a(
 u)||"slider"!==d(u)&&c(b)!==!1&&b.preventDefault()}if(!b.isDefaultPrevented())switch(b.keyCode){case 37:c(b,n);break;case 39:c(b,o);break;case 38:c(b,p);break;case 40:c(b,q);break;case 27:s();break;case 14:case 13:case 32:c(b,t);break;case 9:r(b)!==!1&&b.preventDefault()}}),w.on("focusin",function(a){u=a.target,v=a.control}),{focusFirst:k}}}),g("2e",["2b","29","28","2c","2d","9","a","4j","2a"],function(a,b,c,d,e,f,g,h,i){"use strict";var j={};return a.extend({init:function(a){var c=this;c._super(a),a=c.settings,a.fixed&&c.state.set("fixed",!0),c._items=new b,c.isRtl()&&c.classes.add("rtl"),c.bodyClasses=new h(function(){c.state.get("rendered")&&(c.getEl("body").className=this.toString())}),c.bodyClasses.prefix=c.classPrefix,c.classes.add("container"),c.bodyCl
 asses.add("container-body"),a.containerCls&&c.classes.add(a.containerCls),c._layout=d.create((a.layout||"")+"layout"),c.settings.items?c.add(c.settings.items):c.add(c.render()),c._hasBody=!0},items:function(){return this._items},find:function(a){return a=j[a]=j[a]||new c(a),a.find(this)},add:function(a){var b=this;return b.items().add(b.create(a)).parent(b),b},focus:function(a){var b,c,d,e=this;return a&&(c=e.keyboardNav||e.parents().eq(-1)[0].keyboardNav)?void c.focusFirst(e):(d=e.find("*"),e.statusbar&&d.add(e.statusbar.items()),d.each(function(a){return a.settings.autofocus?(b=null,!1):void(a.canFocus&&(b=b||a))}),b&&b.focus(),e)},replace:function(a,b){for(var c,d=this.items(),e=d.length;e--;)if(d[e]===a){d[e]=b;break}e>=0&&(c=b.getEl(),c&&c.parentNode.removeChild(c),c=a.getEl(),c&&c.parentNode.removeChild(c)),b.parent(this)},create:function(b){var c,e=this,g=[];return f.isA
 rray(b)||(b=[b]),f.each(b,function(b){b&&(b instanceof a||("string"==typeof b&&(b={type:b}),c=f.extend({},e.settings.defaults,b),b.type=c.type=c.type||b.type||e.settings.defaultType||(c.defaults?c.defaults.type:null),b=d.create(c)),g.push(b))}),g},renderNew:function(){var a=this;return a.items().each(function(b,c){var d;b.parent(a),b.state.get("rendered")||(d=a.getEl("body"),d.hasChildNodes()&&c<=d.childNodes.length-1?g(d.childNodes[c]).before(b.renderHtml()):g(d).append(b.renderHtml()),b.postRender(),i.add(b))}),a._layout.applyClasses(a.items().filter(":visible")),a._lastRect=null,a},append:function(a){return this.add(a).renderNew()},prepend:function(a){var b=this;return b.items().set(b.create(a).concat(b.items().toArray())),b.renderNew()},insert:function(a,b,c){var d,e,f,g=this;return a=g.create(a),d=g.items(),!c&&b<d.length-1&&(b+=1),b>=0&&b<d.length&&(e=d.slice(0,b).toArra
 y(),f=d.slice(b).toArray(),d.set(e.concat(a,f))),g.renderNew()},fromJSON:function(a){var b=this;for(var c in a)b.find("#"+c).value(a[c]);return b},toJSON:function(){var a=this,b={};return a.find("*").each(function(a){var c=a.name(),d=a.value();c&&"undefined"!=typeof d&&(b[c]=d)}),b},renderHtml:function(){var a=this,b=a._layout,c=this.settings.role;return a.preRender(),b.preRender(a),'<div id="'+a._id+'" class="'+a.classes+'"'+(c?' role="'+this.settings.role+'"':"")+'><div id="'+a._id+'-body" class="'+a.bodyClasses+'">'+(a.settings.html||"")+b.renderHtml(a)+"</div></div>"},postRender:function(){var a,b=this;return b.items().exec("postRender"),b._super(),b._layout.postRender(b),b.state.set("rendered",!0),b.settings.style&&b.$el.css(b.settings.style),b.settings.border&&(a=b.borderBox,b.$el.css({"bo
 rder-top-width":a.top,"border-right-width":a.right,"border-bottom-width":a.bottom,"border-left-width":a.left})),b.parent()||(b.keyboardNav=new e({root:b})),b},initLayoutRect:function(){var a=this,b=a._super();return a._layout.recalc(a),b},recalc:function(){var a=this,b=a._layoutRect,c=a._lastRect;if(!c||c.w!=b.w||c.h!=b.h)return a._layout.recalc(a),b=a.layoutRect(),a._lastRect={x:b.x,y:b.y,w:b.w,h:b.h},!0},reflow:function(){var b;if(i.remove(this),this.visible()){for(a.repaintControls=[],a.repaintControls.map={},this.recalc(),b=a.repaintControls.length;b--;)a.repaintControls[b].repaint();"flow"!==this.settings.layout&&"stack"!==this.settings.layout&&this.repaint(),a.repaintControls=[]}return this}})}),g("2f",["a"],function(a){"use strict";function b(a){var b,c,d,e,f,g,h,i,j=Math.max;return b=a.documentElement,c=a.body,d=j(b.scrollWidth,c.scrollWidth),e=j(b.clientWidth,c.clientWidth),
 f=j(b.offsetWidth,c.offsetWidth),g=j(b.scrollHeight,c.scrollHeight),h=j(b.clientHeight,c.clientHeight),i=j(b.offsetHeight,c.offsetHeight),{width:d<f?e:d,height:g<i?h:g}}function c(a){var b,c;if(a.changedTouches)for(b="screenX screenY pageX pageY clientX clientY".split(" "),c=0;c<b.length;c++)a[b[c]]=a.changedTouches[0][b[c]]}return function(d,e){function f(){return n.getElementById(e.handle||d)}var g,h,i,j,k,l,m,n=e.document||document;e=e||{},i=function(d){var i,o,p=b(n);c(d),d.preventDefault(),h=d.button,i=f(),l=d.screenX,m=d.screenY,o=window.getComputedStyle?window.getComputedStyle(i,null).getPropertyValue("cursor"):i.runtimeStyle.cursor,g=a("<div></div>").css({position:"absolute",top:0,left:0,width:p.width,height:p.height,zIndex:2147483647,opacity:1e-4,cursor:o}).appendTo(n.body),a(n).on("mousemove touchmove",k).on("mouseup touchend",j),e.start(d)},k=function(a){return c(a),a.button!==h?j(a
 ):(a.deltaX=a.screenX-l,a.deltaY=a.screenY-m,a.preventDefault(),void e.drag(a))},j=function(b){c(b),a(n).off("mousemove touchmove",k).off("mouseup touchend",j),g.remove(),e.stop&&e.stop(b)},this.destroy=function(){a(f()).off()},a(f()).on("mousedown touchstart",i)}}),g("2g",["a","2f"],function(a,b){"use strict";return{init:function(){var a=this;a.on("repaint",a.renderScroll)},renderScroll:function(){function c(){function b(b,g,h,i,j,k){var l,m,n,o,p,q,r,s,t;if(m=e.getEl("scroll"+b)){if(s=g.toLowerCase(),t=h.toLowerCase(),a(e.getEl("absend")).css(s,e.layoutRect()[i]-1),!j)return void a(m).css("display","none");a(m).css("display","block"),l=e.getEl("body"),n=e.getEl("scroll"+b+"t"),o=l["client"+h]-2*f,o-=c&&d?m["client"+k]:0,p=l["scroll"+h],q=o/p,r={},r[s]=l["offset&qu
 ot;+g]+f,r[t]=o,a(m).css(r),r={},r[s]=l["scroll"+g]*q,r[t]=o*q,a(n).css(r)}}var c,d,g;g=e.getEl("body"),c=g.scrollWidth>g.clientWidth,d=g.scrollHeight>g.clientHeight,b("h","Left","Width","contentW",c,"Height"),b("v","Top","Height","contentH",d,"Width")}function d(){function c(c,d,g,h,i){var j,k=e._id+"-scroll"+c,l=e.classPrefix;a(e.getEl()).append('<div id="'+k+'" class="'+l+"scrollbar "+l+"scrollbar-"+c+'"><div id="'+k+'t" class="'+l+'scrollbar-thumb"></div></div>'),e.draghelper=new b(k+"t",{start:function(){j=e.getEl("body")["scroll"+d],a("#"+k).addClass(l+"active")},drag:function(a){var b,k,l,m,n=e.layoutRect();k=n.contentW>n.innerW,l=n.contentH>n.innerH,m=e.getEl("body")["client"+g]-2*f,m
 -=k&&l?e.getEl("scroll"+c)["client"+i]:0,b=m/e.getEl("body")["scroll"+g],e.getEl("body")["scroll"+d]=j+a["delta"+h]/b},stop:function(){a("#"+k).removeClass(l+"active")}})}e.classes.add("scroll"),c("v","Top","Height","Y","Width"),c("h","Left","Width","X","Height")}var e=this,f=2;e.settings.autoScroll&&(e._hasScroll||(e._hasScroll=!0,d(),e.on("wheel",function(a){var b=e.getEl("body");b.scrollLeft+=10*(a.deltaX||0),b.scrollTop+=10*a.deltaY,c()}),a(e.getEl("body")).on("scroll",c)),c())}}}),g("2h",["2e","2g"],function(a,b){"use strict";return a.extend({Defaults:{layout:"fit",containerCls:"panel"},Mixins:[b],renderHtml:function(){var a=this,b=a._layout,c=a.settings.html;return a
 .preRender(),b.preRender(a),"undefined"==typeof c?c='<div id="'+a._id+'-body" class="'+a.bodyClasses+'">'+b.renderHtml(a)+"</div>":("function"==typeof c&&(c=c.call(a)),a._hasBody=!1),'<div id="'+a._id+'" class="'+a.classes+'" hidefocus="1" tabindex="-1" role="group">'+(a._preBodyHtml||"")+c+"</div>";
-}})}),g("2i",["4h"],function(a){"use strict";function b(b,c,d){var e,f,g,h,i,j,k,l,m,n;return m=a.getViewPort(),f=a.getPos(c),g=f.x,h=f.y,b.state.get("fixed")&&"static"==a.getRuntimeStyle(document.body,"position")&&(g-=m.x,h-=m.y),e=b.getEl(),n=a.getSize(e),i=n.width,j=n.height,n=a.getSize(c),k=n.width,l=n.height,d=(d||"").split(""),"b"===d[0]&&(h+=l),"r"===d[1]&&(g+=k),"c"===d[0]&&(h+=Math.round(l/2)),"c"===d[1]&&(g+=Math.round(k/2)),"b"===d[3]&&(h-=j),"r"===d[4]&&(g-=i),"c"===d[3]&&(h-=Math.round(j/2)),"c"===d[4]&&(g-=Math.round(i/2)),{x:g,y:h,w:i,h:j}}return{testMoveRel:function(c,d){for(var e=a.getViewPort(),f=0;f<d.length;f++){var g=b(this,c,d[f]);if(this.state.get("fixed")){if(g.x>0&&g.x+g.w<e.w&&g.y>0&a
 mp;&g.y+g.h<e.h)return d[f]}else if(g.x>e.x&&g.x+g.w<e.w+e.x&&g.y>e.y&&g.y+g.h<e.h+e.y)return d[f]}return d[0]},moveRel:function(a,c){"string"!=typeof c&&(c=this.testMoveRel(a,c));var d=b(this,a,c);return this.moveTo(d.x,d.y)},moveBy:function(a,b){var c=this,d=c.layoutRect();return c.moveTo(d.x+a,d.y+b),c},moveTo:function(b,c){function d(a,b,c){return a<0?0:a+c>b?(a=b-c,a<0?0:a):a}var e=this;if(e.settings.constrainToViewport){var f=a.getViewPort(window),g=e.layoutRect();b=d(b,f.w+f.x,g.w),c=d(c,f.h+f.y,g.h)}return e.state.get("rendered")?e.layoutRect({x:b,y:c}).repaint():(e.settings.x=b,e.settings.y=c),e.fire("move",{x:b,y:c}),e}}}),g("2j",["4h"],function(a){"use strict";return{resizeToContent:function(){this._layoutRect.autoResize=!0,this._lastRect=null,this.reflow()},resizeTo:function(b,c){if(b<=1||c<=1){var d=a.getWindowSize();b=b<=1?b*d.w:b,c=c<=1?c
 *d.h:c}return this._layoutRect.autoResize=!1,this.layoutRect({minW:b,minH:c,w:b,h:c}).reflow()},resizeBy:function(a,b){var c=this,d=c.layoutRect();return c.resizeTo(d.w+a,d.h+b)}}}),g("2k",["2h","2i","2j","4h","a","5"],function(a,b,c,d,e,f){"use strict";function g(a,b){for(;a;){if(a==b)return!0;a=a.parent()}}function h(a){for(var b=s.length;b--;){var c=s[b],d=c.getParentCtrl(a.target);if(c.settings.autohide){if(d&&(g(d,c)||c.parent()===d))continue;a=c.fire("autohide",{target:a.target}),a.isDefaultPrevented()||c.hide()}}}function i(){o||(o=function(a){2!=a.button&&h(a)},e(document).on("click touchstart",o))}function j(){p||(p=function(){var a;for(a=s.length;a--;)l(s[a])},e(window).on("scroll",p))}function k(){if(!q){var a=document.documentElement,b=a.clientWidth,c=a.clientHeight;q=function(){document.all&&b==a.clientWidth&&c==a.clientHeight||(b
 =a.clientWidth,c=a.clientHeight,u.hideAll())},e(window).on("resize",q)}}function l(a){function b(b,c){for(var d,e=0;e<s.length;e++)if(s[e]!=a)for(d=s[e].parent();d&&(d=d.parent());)d==a&&s[e].fixed(b).moveBy(0,c).repaint()}var c=d.getViewPort().y;a.settings.autofix&&(a.state.get("fixed")?a._autoFixY>c&&(a.fixed(!1).layoutRect({y:a._autoFixY}).repaint(),b(!1,a._autoFixY-c)):(a._autoFixY=a.layoutRect().y,a._autoFixY<c&&(a.fixed(!0).layoutRect({y:0}).repaint(),b(!0,c-a._autoFixY))))}function m(a,b){var c,d,f=u.zIndex||65535;if(a)t.push(b);else for(c=t.length;c--;)t[c]===b&&t.splice(c,1);if(t.length)for(c=0;c<t.length;c++)t[c].modal&&(f++,d=t[c]),t[c].getEl().style.zIndex=f,t[c].zIndex=f,f++;var g=e("#"+b.classPrefix+"modal-block",b.getContainerElm())[0];d?e(g).css("z-index",d.zIndex-1):g&&(g.parentNode.removeChild(g),r=!1),u.currentZIndex=f}function n(a){var b;f
 or(b=s.length;b--;)s[b]===a&&s.splice(b,1);for(b=t.length;b--;)t[b]===a&&t.splice(b,1)}var o,p,q,r,s=[],t=[],u=a.extend({Mixins:[b,c],init:function(a){var b=this;b._super(a),b._eventsRoot=b,b.classes.add("floatpanel"),a.autohide&&(i(),k(),s.push(b)),a.autofix&&(j(),b.on("move",function(){l(this)})),b.on("postrender show",function(a){if(a.control==b){var c,d=b.classPrefix;b.modal&&!r&&(c=e("#"+d+"modal-block",b.getContainerElm()),c[0]||(c=e('<div id="'+d+'modal-block" class="'+d+"reset "+d+'fade"></div>').appendTo(b.getContainerElm())),f.setTimeout(function(){c.addClass(d+"in"),e(b.getEl()).addClass(d+"in")}),r=!0),m(!0,b)}}),b.on("show",function(){b.parents().each(function(a){if(a.state.get("fixed"))return b.fixed(!0),!1})}),a.popover&&(b._preBodyHtml='<div class="'+b.classPrefix+'arrow&quo
 t;></div>',b.classes.add("popover").add("bottom").add(b.isRtl()?"end":"start")),b.aria("label",a.ariaLabel),b.aria("labelledby",b._id),b.aria("describedby",b.describedBy||b._id+"-none")},fixed:function(a){var b=this;if(b.state.get("fixed")!=a){if(b.state.get("rendered")){var c=d.getViewPort();a?b.layoutRect().y-=c.y:b.layoutRect().y+=c.y}b.classes.toggle("fixed",a),b.state.set("fixed",a)}return b},show:function(){var a,b=this,c=b._super();for(a=s.length;a--&&s[a]!==b;);return a===-1&&s.push(b),c},hide:function(){return n(this),m(!1,this),this._super()},hideAll:function(){u.hideAll()},close:function(){var a=this;return a.fire("close").isDefaultPrevented()||(a.remove(),m(!1,a)),a},remove:function(){n(this),this._super()},postRender:function(){var a=this;return a.settings.bodyRole&&this.getEl("body").setAttribute(&q
 uot;role",a.settings.bodyRole),a._super()}});return u.hideAll=function(){for(var a=s.length;a--;){var b=s[a];b&&b.settings.autohide&&(b.hide(),s.splice(a,1))}},u}),g("1z",["2k","2h","4h","a","2f","4i","6","5"],function(a,b,c,d,e,f,g,h){"use strict";function i(a){var b,c="width=device-width,initial-scale=1.0,user-scalable=0,minimum-scale=1.0,maximum-scale=1.0",e=d("meta[name=viewport]")[0];g.overrideViewPort!==!1&&(e||(e=document.createElement("meta"),e.setAttribute("name","viewport"),document.getElementsByTagName("head")[0].appendChild(e)),b=e.getAttribute("content"),b&&"undefined"!=typeof n&&(n=b),e.setAttribute("content",a?c:n))}function j(a,b){k()&&b===!1&&d([document.documentElement,document.body]).removeClass(a+"fullscreen&quo
 t;)}function k(){for(var a=0;a<m.length;a++)if(m[a]._fullscreen)return!0;return!1}function l(){function a(){var a,b,d=c.getWindowSize();for(a=0;a<m.length;a++)b=m[a].layoutRect(),m[a].moveTo(m[a].settings.x||Math.max(0,d.w/2-b.w/2),m[a].settings.y||Math.max(0,d.h/2-b.h/2))}if(!g.desktop){var b={w:window.innerWidth,h:window.innerHeight};h.setInterval(function(){var a=window.innerWidth,c=window.innerHeight;b.w==a&&b.h==c||(b={w:a,h:c},d(window).trigger("resize"))},100)}d(window).on("resize",a)}var m=[],n="",o=a.extend({modal:!0,Defaults:{border:1,layout:"flex",containerCls:"panel",role:"dialog",callbacks:{submit:function(){this.fire("submit",{data:this.toJSON()})},close:function(){this.close()}}},init:function(a){var d=this;d._super(a),d.isRtl()&&d.classes.add("rtl"),d.classes.add("window"),d.bodyClasses.add("window-body"),d.state.set("fixed",!0),a.button
 s&&(d.statusbar=new b({layout:"flex",border:"1 0 0 0",spacing:3,padding:10,align:"center",pack:d.isRtl()?"start":"end",defaults:{type:"button"},items:a.buttons}),d.statusbar.classes.add("foot"),d.statusbar.parent(d)),d.on("click",function(a){var b=d.classPrefix+"close";(c.hasClass(a.target,b)||c.hasClass(a.target.parentNode,b))&&d.close()}),d.on("cancel",function(){d.close()}),d.aria("describedby",d.describedBy||d._id+"-none"),d.aria("label",a.title),d._fullscreen=!1},recalc:function(){var a,b,d,e,f=this,g=f.statusbar;f._fullscreen&&(f.layoutRect(c.getWindowSize()),f.layoutRect().contentH=f.layoutRect().innerH),f._super(),a=f.layoutRect(),f.settings.title&&!f._fullscreen&&(b=a.headerW,b>a.w&&(d=a.x-Math.max(0,b/2),f.layoutRect({w:b,x:d}),e=!0)),g&&(g.layoutRect({w:f.layoutRect().innerW}).recalc(),
 b=g.layoutRect().minW+a.deltaW,b>a.w&&(d=a.x-Math.max(0,b-a.w),f.layoutRect({w:b,x:d}),e=!0)),e&&f.recalc()},initLayoutRect:function(){var a,b=this,d=b._super(),e=0;if(b.settings.title&&!b._fullscreen){a=b.getEl("head");var f=c.getSize(a);d.headerW=f.width,d.headerH=f.height,e+=d.headerH}b.statusbar&&(e+=b.statusbar.layoutRect().h),d.deltaH+=e,d.minH+=e,d.h+=e;var g=c.getWindowSize();return d.x=b.settings.x||Math.max(0,g.w/2-d.w/2),d.y=b.settings.y||Math.max(0,g.h/2-d.h/2),d},renderHtml:function(){var a=this,b=a._layout,c=a._id,d=a.classPrefix,e=a.settings,f="",g="",h=e.html;return a.preRender(),b.preRender(a),e.title&&(f='<div id="'+c+'-head" class="'+d+'window-head"><div id="'+c+'-title" class="'+d+'title">'+a.encode(e.title)+'</div><div id="'+c+'-dragh" class="'+d+'dragh"></div><button type="button" class=&
 quot;'+d+'close" aria-hidden="true"><i class="mce-ico mce-i-remove"></i></button></div>'),e.url&&(h='<iframe src="'+e.url+'" tabindex="-1"></iframe>'),"undefined"==typeof h&&(h=b.renderHtml(a)),a.statusbar&&(g=a.statusbar.renderHtml()),'<div id="'+c+'" class="'+a.classes+'" hidefocus="1"><div class="'+a.classPrefix+'reset" role="application">'+f+'<div id="'+c+'-body" class="'+a.bodyClasses+'">'+h+"</div>"+g+"</div></div>"},fullscreen:function(a){var b,e,g=this,i=document.documentElement,j=g.classPrefix;if(a!=g._fullscreen)if(d(window).on("resize",function(){var a;if(g._fullscreen)if(b)g._timer||(g._timer=h.setTimeout(function(){var a=c.getWindowSize();g.moveTo(0,0).resizeTo(a.w,a.h),g._timer=0},50));else{a=(new Date).getTime();var d=
 c.getWindowSize();g.moveTo(0,0).resizeTo(d.w,d.h),(new Date).getTime()-a>50&&(b=!0)}}),e=g.layoutRect(),g._fullscreen=a,a){g._initial={x:e.x,y:e.y,w:e.w,h:e.h},g.borderBox=f.parseBox("0"),g.getEl("head").style.display="none",e.deltaH-=e.headerH+2,d([i,document.body]).addClass(j+"fullscreen"),g.classes.add("fullscreen");var k=c.getWindowSize();g.moveTo(0,0).resizeTo(k.w,k.h)}else g.borderBox=f.parseBox(g.settings.border),g.getEl("head").style.display="",e.deltaH+=e.headerH,d([i,document.body]).removeClass(j+"fullscreen"),g.classes.remove("fullscreen"),g.moveTo(g._initial.x,g._initial.y).resizeTo(g._initial.w,g._initial.h);return g.reflow()},postRender:function(){var a,b=this;setTimeout(function(){b.classes.add("in"),b.fire("open")},0),b._super(),b.statusbar&&b.statusbar.postRender(),b.focus(),this.dragHelper=new e(b._id+"-dragh",{start:function(){
 a={x:b.layoutRect().x,y:b.layoutRect().y}},drag:function(c){b.moveTo(a.x+c.deltaX,a.y+c.deltaY)}}),b.on("submit",function(a){a.isDefaultPrevented()||b.close()}),m.push(b),i(!0)},submit:function(){return this.fire("submit",{data:this.toJSON()})},remove:function(){var a,b=this;for(b.dragHelper.destroy(),b._super(),b.statusbar&&this.statusbar.remove(),j(b.classPrefix,!1),a=m.length;a--;)m[a]===b&&m.splice(a,1);i(m.length>0)},getContentWindow:function(){var a=this.getEl().getElementsByTagName("iframe")[0];return a?a.contentWindow:null}});return l(),o}),g("20",["1z"],function(a){"use strict";var b=a.extend({init:function(a){a={border:1,padding:20,layout:"flex",pack:"center",align:"center",containerCls:"panel",autoScroll:!0,buttons:{type:"button",text:"Ok",action:"ok"},items:{type:"label",multiline:!0,maxWidth:500,maxHeight:200}},th
 is._super(a)},Statics:{OK:1,OK_CANCEL:2,YES_NO:3,YES_NO_CANCEL:4,msgBox:function(c){function d(a,b,c){return{type:"button",text:a,subtype:c?"primary":"",onClick:function(a){a.control.parents()[1].close(),f(b)}}}var e,f=c.callback||function(){};switch(c.buttons){case b.OK_CANCEL:e=[d("Ok",!0,!0),d("Cancel",!1)];break;case b.YES_NO:case b.YES_NO_CANCEL:e=[d("Yes",1,!0),d("No",0)],c.buttons==b.YES_NO_CANCEL&&e.push(d("Cancel",-1));break;default:e=[d("Ok",!0,!0)]}return new a({padding:20,x:c.x,y:c.y,minWidth:300,minHeight:100,layout:"flex",pack:"center",align:"center",buttons:e,title:c.title,role:"alertdialog",items:{type:"label",multiline:!0,maxWidth:500,maxHeight:200,text:c.text},onPostRender:function(){this.aria("describedby",this.items()[0]._id)},onClose:c.onClose,onCancel:function(){f(!1)}}).renderTo(document.body).reflow()},a
 lert:function(a,c){return"string"==typeof a&&(a={text:a}),a.callback=c,b.msgBox(a)},confirm:function(a,c){return"string"==typeof a&&(a={text:a}),a.callback=c,a.buttons=b.OK_CANCEL,b.msgBox(a)}}});return b}),g("10",["1z","20"],function(a,b){return function(c){function d(){if(h.length)return h[h.length-1]}function e(a){c.fire("OpenWindow",{win:a})}function f(a){c.fire("CloseWindow",{win:a})}var g=this,h=[];g.windows=h,c.on("remove",function(){for(var a=h.length;a--;)h[a].close()}),g.open=function(b,d){var g;return c.editorManager.setActive(c),b.title=b.title||" ",b.url=b.url||b.file,b.url&&(b.width=parseInt(b.width||320,10),b.height=parseInt(b.height||240,10)),b.body&&(b.items={defaults:b.defaults,type:b.bodyType||"form",items:b.body,data:b.data,callbacks:b.commands}),b.url||b.buttons||(b.buttons=[{text:"Ok",subtype:"primary",onclick:f
 unction(){g.find("form")[0].submit()}},{text:"Cancel",onclick:function(){g.close()}}]),g=new a(b),h.push(g),g.on("close",function(){for(var a=h.length;a--;)h[a]===g&&h.splice(a,1);h.length||c.focus(),f(g)}),b.data&&g.on("postRender",function(){this.find("*").each(function(a){var c=a.name();c in b.data&&a.value(b.data[c])})}),g.features=b||{},g.params=d||{},1===h.length&&c.nodeChanged(),g=g.renderTo().reflow(),e(g),g},g.alert=function(a,d,g){var h;h=b.alert(a,function(){d?d.call(g||this):c.focus()}),h.on("close",function(){f(h)}),e(h)},g.confirm=function(a,c,d){var g;g=b.confirm(a,function(a){c.call(d||this,a)}),g.on("close",function(){f(g)}),e(g)},g.close=function(){d()&&d().close()},g.getParams=function(){return d()?d().params:null},g.setParams=function(a){d()&&(d().params=a)},g.getWindows=function(){return h}}}),g("2l",["2b","2i"],func
 tion(a,b){return a.extend({Mixins:[b],Defaults:{classes:"widget tooltip tooltip-n"},renderHtml:function(){var a=this,b=a.classPrefix;return'<div id="'+a._id+'" class="'+a.classes+'" role="presentation"><div class="'+b+'tooltip-arrow"></div><div class="'+b+'tooltip-inner">'+a.encode(a.state.get("text"))+"</div></div>"},bindStates:function(){var a=this;return a.state.on("change:text",function(b){a.getEl().lastChild.innerHTML=a.encode(b.value)}),a._super()},repaint:function(){var a,b,c=this;a=c.getEl().style,b=c._layoutRect,a.left=b.x+"px",a.top=b.y+"px",a.zIndex=131070}})}),g("2m",["2b","2l"],function(a,b){"use strict";var c,d=a.extend({init:function(a){var b=this;b._super(a),a=b.settings,b.canFocus=!0,a.tooltip&&d.tooltips!==!1&&(b.on("mouseenter",function(c){var d=b.tooltip(
 ).moveTo(-65535);if(c.control==b){var e=d.text(a.tooltip).show().testMoveRel(b.getEl(),["bc-tc","bc-tl","bc-tr"]);d.classes.toggle("tooltip-n","bc-tc"==e),d.classes.toggle("tooltip-nw","bc-tl"==e),d.classes.toggle("tooltip-ne","bc-tr"==e),d.moveRel(b.getEl(),e)}else d.hide()}),b.on("mouseleave mousedown click",function(){b.tooltip().hide()})),b.aria("label",a.ariaLabel||a.tooltip)},tooltip:function(){return c||(c=new b({type:"tooltip"}),c.renderTo()),c},postRender:function(){var a=this,b=a.settings;a._super(),a.parent()||!b.width&&!b.height||(a.initLayoutRect(),a.repaint()),b.autofocus&&a.focus()},bindStates:function(){function a(a){c.aria("disabled",a),c.classes.toggle("disabled",a)}function b(a){c.aria("pressed",a),c.classes.toggle("active",a)}var c=this;return c.state.on("change:disabled",function
 (b){a(b.value)}),c.state.on("change:active",function(a){b(a.value)}),c.state.get("disabled")&&a(!0),c.state.get("active")&&b(!0),c._super()},remove:function(){this._super(),c&&(c.remove(),c=null)}});return d}),g("2n",["2m"],function(a){"use strict";return a.extend({Defaults:{value:0},init:function(a){var b=this;b._super(a),b.classes.add("progress"),b.settings.filter||(b.settings.filter=function(a){return Math.round(a)})},renderHtml:function(){var a=this,b=a._id,c=this.classPrefix;return'<div id="'+b+'" class="'+a.classes+'"><div class="'+c+'bar-container"><div class="'+c+'bar"></div></div><div class="'+c+'text">0%</div></div>'},postRender:function(){var a=this;return a._super(),a.value(a.settings.value),a},bindStates:function(){function a(a){a=b.settings.filter(a),b.getEl().lastChild.innerHTML=
 a+"%",b.getEl().firstChild.firstChild.style.width=a+"%"}var b=this;return b.state.on("change:value",function(b){a(b.value)}),a(b.state.get("value")),b._super()}})}),g("21",["2b","2i","2n","5"],function(a,b,c,d){return a.extend({Mixins:[b],Defaults:{classes:"widget notification"},init:function(a){var b=this;b._super(a),a.text&&b.text(a.text),a.icon&&(b.icon=a.icon),a.color&&(b.color=a.color),a.type&&b.classes.add("notification-"+a.type),a.timeout&&(a.timeout<0||a.timeout>0)&&!a.closeButton?b.closeButton=!1:(b.classes.add("has-close"),b.closeButton=!0),a.progressBar&&(b.progressBar=new c),b.on("click",function(a){a.target.className.indexOf(b.classPrefix+"close")!=-1&&b.close()})},renderHtml:function(){var a=this,b=a.classPrefix,c="",d="",e="",f=&quo
 t;";return a.icon&&(c='<i class="'+b+"ico "+b+"i-"+a.icon+'"></i>'),a.color&&(f=' style="background-color: '+a.color+'"'),a.closeButton&&(d='<button type="button" class="'+b+'close" aria-hidden="true">\xd7</button>'),a.progressBar&&(e=a.progressBar.renderHtml()),'<div id="'+a._id+'" class="'+a.classes+'"'+f+' role="presentation">'+c+'<div class="'+b+'notification-inner">'+a.state.get("text")+"</div>"+e+d+"</div>"},postRender:function(){var a=this;return d.setTimeout(function(){a.$el.addClass(a.classPrefix+"in")}),a._super()},bindStates:function(){var a=this;return a.state.on("change:text",function(b){a.getEl().childNodes[1].innerHTML=b.value}),a.progressBar&&a.progressBar.bindStates(),a._super()},close:function(){var a=this;return a.f
 ire("close").isDefaultPrevented()||a.remove(),a},repaint:function(){var a,b,c=this;a=c.getEl().style,b=c._layoutRect,a.left=b.x+"px",a.top=b.y+"px",a.zIndex=65534}})}),g("11",["21","5","9"],function(a,b,c){return function(d){function e(){if(m.length)return m[m.length-1]}function f(){b.requestAnimationFrame(function(){g(),h()})}function g(){for(var a=0;a<m.length;a++)m[a].moveTo(0,0)}function h(){if(m.length>0){var a=m.slice(0,1)[0],b=d.inline?d.getElement():d.getContentAreaContainer();if(a.moveRel(b,"tc-tc"),m.length>1)for(var c=1;c<m.length;c++)m[c].moveRel(m[c-1].getEl(),"bc-tc")}}function i(a,b){if(!k(b))return null;var d=c.grep(a,function(a){return j(b,a)});return 0===d.length?null:d[0]}function j(a,b){return a.type===b.settings.type&&a.text===b.settings.text}function k(a){return!a.progressBar&&!a.timeout}var l=this,m=[];l.notifications=m,d.on("remove",
 function(){for(var a=m.length;a--;)m[a].close()}),d.on("ResizeEditor",h),d.on("ResizeWindow",f),l.open=function(b){if(!d.removed){var c;d.editorManager.setActive(d);var e=i(m,b);return null===e?(c=new a(b),m.push(c),b.timeout>0&&(c.timer=setTimeout(function(){c.close()},b.timeout)),c.on("close",function(){var a=m.length;for(c.timer&&d.getWin().clearTimeout(c.timer);a--;)m[a]===c&&m.splice(a,1);h()}),c.renderTo(),h()):c=e,c}},l.close=function(){e()&&e().close()},l.getNotifications=function(){return m},d.on("SkinLoaded",function(){var a=d.settings.service_message;a&&d.notificationManager.open({text:a,type:"warning",timeout:0,icon:""})})}}),g("12",["z","e","9"],function(a,b,c){function d(a,b){return"selectionchange"==b?a.getDoc():!a.inline&&/^mouse|touch|click|contextmenu|drop|dragover|dragend/.test(b)?a.getDoc().documentElemen
 t:a.settings.event_root?(a.eventRoot||(a.eventRoot=g.select(a.settings.event_root)[0]),a.eventRoot):a.getBody()}function e(a,b){function c(a){return!a.hidden&&!a.readonly}var e,h;if(a.delegates||(a.delegates={}),!a.delegates[b]&&!a.removed)if(e=d(a,b),a.settings.event_root){if(f||(f={},a.editorManager.on("removeEditor",function(){var b;if(!a.editorManager.activeEditor&&f){for(b in f)a.dom.unbind(d(a,b));f=null}})),f[b])return;h=function(d){for(var e=d.target,f=a.editorManager.editors,h=f.length;h--;){var i=f[h].getBody();(i===e||g.isChildOf(e,i))&&c(f[h])&&f[h].fire(b,d)}},f[b]=h,g.bind(e,b,h)}else h=function(d){c(a)&&a.fire(b,d)},g.bind(e,b,h),a.delegates[b]=h}var f,g=b.DOM,h={bindPendingEventDelegates:function(){var a=this;c.each(a._pendingNativeEvents,function(b){e(a,b)})},toggleNativeEvent:function(a,b){var c=this;"focus"!=a&&"blur"!=a&&(b?c.initialized?e(c,a):c._pendingNativeEvents?c._
 pendingNativeEvents.push(a):c._pendingNativeEvents=[a]:c.initialized&&(c.dom.unbind(d(c,a),a,c.delegates[a]),delete c.delegates[a]))},unbindAllNativeEvents:function(){var a,b=this;if(b.delegates){for(a in b.delegates)b.dom.unbind(d(b,a),a,b.delegates[a]);delete b.delegates}b.inline||(b.getBody().onload=null,b.dom.unbind(b.getWin()),b.dom.unbind(b.getDoc())),b.dom.unbind(b.getBody()),b.dom.unbind(b.getContainer())}};return h=c.extend({},a,h)}),g("13",["9","6"],function(a,b){var c=a.each,d=a.explode,e={f9:120,f10:121,f11:122},f=a.makeMap("alt,ctrl,shift,meta,access");return function(g){function h(a){var g,h,i={};c(d(a,"+"),function(a){a in f?i[a]=!0:/^[0-9]{2,}$/.test(a)?i.keyCode=parseInt(a,10):(i.charCode=a.charCodeAt(0),i.keyCode=e[a]||a.toUpperCase().charCodeAt(0))}),g=[i.keyCode];for(h in f)i[h]?g.push(h):i[h]=!1;return i.id=g.join(","),i.access&&(i.alt=!0,b.mac?i.ctrl=!0:i.shift=!0),i.meta&&(b.ma
 c?i.meta=!0:(i.ctrl=!0,i.meta=!1)),i}function i(b,c,e,f){var i;return i=a.map(d(b,">"),h),i[i.length-1]=a.extend(i[i.length-1],{func:e,scope:f||g}),a.extend(i[0],{desc:g.translate(c),subpatterns:i.slice(1)})}function j(a){return a.altKey||a.ctrlKey||a.metaKey}function k(a){return"keydown"===a.type&&a.keyCode>=112&&a.keyCode<=123}function l(a,b){return!!b&&(b.ctrl==a.ctrlKey&&b.meta==a.metaKey&&(b.alt==a.altKey&&b.shift==a.shiftKey&&(!!(a.keyCode==b.keyCode||a.charCode&&a.charCode==b.charCode)&&(a.preventDefault(),!0))))}function m(a){return a.func?a.func.call(a.scope):null}var n=this,o={},p=[];g.on("keyup keypress keydown",function(a){!j(a)&&!k(a)||a.isDefaultPrevented()||(c(o,function(b){if(l(a,b))return p=b.subpatterns.slice(0),"keydown"==a.type&&m(b),!0}),l(a,p[0])&&(1===p.length&&"keydown"==a.type&&m(p[0]),p.sh
 ift()))}),n.add=function(b,e,f,h){var j;return j=f,"string"==typeof f?f=function(){g.execCommand(j,!1,null)}:a.isArray(j)&&(f=function(){g.execCommand(j[0],j[1],j[2])}),c(d(a.trim(b.toLowerCase())),function(a){var b=i(a,e,f,h);o[b.id]=b}),!0},n.remove=function(a){var b=i(a);return!!o[b.id]&&(delete o[b.id],!0)}}}),h("4k",window),g("26",["g"],function(a){var b=a.PluginManager,c=function(a,c){for(var d in b.urls){var e=b.urls[d]+"/plugin"+c+".js";if(e===a)return d}return null},d=function(a,b){var d=c(b,a.suffix);return d?"Failed to load plugin: "+d+" from url "+b:"Failed to load plugin url: "+b},e=function(a,b){a.notificationManager.open({type:"error",text:b})},f=function(a,b){a._skinLoaded?e(a,b):a.on("SkinLoaded",function(){e(a,b)})},g=function(a,b){f(a,"Failed to upload image: "+b)},h=function(a,b){f(a,d(a,b))},i=function(a,b){f(a,"Failed to l
 oad content css: "+b[0])},j=function(a){var b=window.console;b&&!window.test&&(b.error?b.error.apply(b,arguments):b.log.apply(b,arguments))};return{pluginLoadError:h,uploadError:g,displayError:f,contentCssError:i,initError:j}}),g("60",["3t","1k"],function(a,b){var c=function(a){return a.dom.select("*[data-mce-caret]")[0]},d=function(a){a.selection.setRng(a.selection.getRng())},e=function(a,c){c.hasAttribute("data-mce-caret")&&(b.showCaretContainerBlock(c),d(a),a.selection.scrollIntoView(c))},f=function(a,d){var f=c(a);if(f)return"compositionstart"===d.type?(d.preventDefault(),d.stopPropagation(),void e(f)):void(b.hasContent(f)&&e(a,f))},g=function(b){b.on("keyup compositionstart",a.curry(f,b))};return{setup:g}}),g("6g",["4","9","1s"],function(a,b,c){return function(c,d){function e(a,b){return a?a.replace(/\/$/,"")+"/"+
 b.replace(/^\//,""):b}function f(a,b,c,f){var g,h;g=new XMLHttpRequest,g.open("POST",d.url),g.withCredentials=d.credentials,g.upload.onprogress=function(a){f(a.loaded/a.total*100)},g.onerror=function(){c("Image upload failed due to a XHR Transport error. Code: "+g.status)},g.onload=function(){var a;return g.status<200||g.status>=300?void c("HTTP Error: "+g.status):(a=JSON.parse(g.responseText),a&&"string"==typeof a.location?void b(e(d.basePath,a.location)):void c("Invalid JSON: "+g.responseText))},h=new FormData,h.append("file",a.blob(),a.filename()),g.send(h)}function g(){return new a(function(a){a([])})}function h(a,b){return{url:b,blobInfo:a,status:!0}}function i(a,b){return{url:"",blobInfo:a,status:!1,error:b}}function j(a,c){b.each(p[a],function(a){a(c)}),delete p[a]}function k(b,d,e){return c.markPending(b.blobUri()),new a(function(a){var f,g,k=function(){};try{var l=function(){f&
 &(f.close(),g=k)},m=function(d){l(),c.markUploaded(b.blobUri(),d),j(b.blobUri(),h(b,d)),a(h(b,d))},n=function(d){l(),c.removeFailed(b.blobUri()),j(b.blobUri(),i(b,d)),a(i(b,d))};g=function(a){a<0||a>100||(f||(f=e()),f.progressBar.value(a))},d(b,m,n,g)}catch(c){a(i(b,c.message))}})}function l(a){return a===f}function m(b){var c=b.blobUri();return new a(function(a){p[c]=p[c]||[],p[c].push(a)})}function n(e,f){return e=b.grep(e,function(a){return!c.isUploaded(a.blobUri())}),a.all(b.map(e,function(a){return c.isPending(a.blobUri())?m(a):k(a,d.handler,f)}))}function o(a,b){return!d.url&&l(d.handler)?g():n(a,b)}var p={};return d=b.extend({credentials:!1,handler:f},d),{upload:o}}}),g("71",["4"],function(a){function b(b){return new a(function(a,c){var d=function(){c("Cannot convert "+b+" to Blob. Resource might not exist or is inaccessible.")};try{var e=new XMLHttpRequest;e.open("GET",b,!0),e.responseType="blob",e
 .onload=function(){200==this.status?a(this.response):d()},e.onerror=d,e.send()}catch(a){d()}})}function c(a){var b,c;return a=decodeURIComponent(a).split(","),c=/data:([^;]+)/.exec(a[0]),c&&(b=c[1]),{type:b,data:a[1]}}function d(b){return new a(function(a){var d,e,f;b=c(b);try{d=atob(b.data)}catch(b){return void a(new Blob([]))}for(e=new Uint8Array(d.length),f=0;f<e.length;f++)e[f]=d.charCodeAt(f);a(new Blob([e],{type:b.type}))})}function e(a){return 0===a.indexOf("blob:")?b(a):0===a.indexOf("data:")?d(a):null}function f(b){return new a(function(a){var c=new FileReader;c.onloadend=function(){a(c.result)},c.readAsDataURL(b)})}return{uriToBlob:e,blobToDataUri:f,parseDataUri:c}}),g("6h",["4","1g","1s","71","6"],function(a,b,c,d,e){var f=0,g=function(a){return(a||"blobid")+f++},h=function(a,b,c,e){var f,h;return 0===b.src.indexOf("blob:")?(h=a.getByUri(b.src),void(h?c
 ({image:b,blobInfo:h}):d.uriToBlob(b.src).then(function(e){d.blobToDataUri(e).then(function(i){f=d.parseDataUri(i).data,h=a.create(g(),e,f),a.add(h),c({image:b,blobInfo:h})})},function(a){e(a)}))):(f=d.parseDataUri(b.src).data,h=a.findFirst(function(a){return a.base64()===f}),void(h?c({image:b,blobInfo:h}):d.uriToBlob(b.src).then(function(d){h=a.create(g(),d,f),a.add(h),c({image:b,blobInfo:h})},function(a){e(a)})))},i=function(a){return a?a.getElementsByTagName("img"):[]};return function(d,f){function g(g,k){var l,m;return k||(k=c.constant(!0)),l=b.filter(i(g),function(a){var b=a.src;return!!e.fileApi&&(!a.hasAttribute("data-mce-bogus")&&(!a.hasAttribute("data-mce-placeholder")&&(!(!b||b==e.transparentSrc)&&(0===b.indexOf("blob:")?!d.isUploaded(b):0===b.indexOf("data:")&&k(a)))))}),m=b.map(l,function(b){var c;return j[b.src]?new a(function(a){j[b.src].then(function(c){return"string"==
 typeof c?c:void a({image:b,blobInfo:c.blobInfo})})}):(c=new a(function(a,c){h(f,b,a,c)}).then(function(a){return delete j[a.image.src],a})["catch"](function(a){return delete j[b.src],a}),j[b.src]=c,c)}),a.all(m)}var j={};return{findAll:g}}}),g("25",[],function(){var a=0,b=function(){var a=function(){return Math.round(4294967295*Math.random()).toString(36)},b=(new Date).getTime();return"s"+b.toString(36)+a()+a()+a()},c=function(c){return c+a++ +b()};return{uuid:c}}),h("72",URL),g("6i",["1g","1s","25","72"],function(a,b,c,d){return function(){function e(a){var b={"image/jpeg":"jpg","image/jpg":"jpg","image/gif":"gif","image/png":"png"};return b[a.toLowerCase()]||"dat"}function f(a,b,c,d){return g("object"==typeof a?a:{id:a,name:d,blob:b,base64:c})}function g(a){var b,f;if(!a.blob||!a.base64)throw&q
 uot;blob and base64 representations of the image are required for BlobInfo to be created";return b=a.id||c.uuid("blobid"),f=a.name||b,{id:o(b),name:o(f),filename:o(f+"."+e(a.blob.type)),blob:o(a.blob),base64:o(a.base64),blobUri:o(a.blobUri||d.createObjectURL(a.blob)),uri:o(a.uri)}}function h(a){i(a.id())||n.push(a)}function i(a){return j(function(b){return b.id()===a})}function j(b){return a.filter(n,b)[0]}function k(a){return j(function(b){return b.blobUri()==a})}function l(b){n=a.filter(n,function(a){return a.blobUri()!==b||(d.revokeObjectURL(a.blobUri()),!1)})}function m(){a.each(n,function(a){d.revokeObjectURL(a.blobUri())}),n=[]}var n=[],o=b.constant;return{create:f,add:h,get:i,getByUri:k,findFirst:j,removeByUri:l,destroy:m}}}),g("6j",[],function(){return function(){function a(a,b){return{status:a,resultUri:b}}function b(a){return a in l}function c(a){var b=l[a];return b?b.resultUri:null}function d(a){return!!b(a)&&l[a].status===j}func
 tion e(a){return!!b(a)&&l[a].status===k}function f(b){l[b]=a(j,null)}function g(b,c){l[b]=a(k,c)}function h(a){delete l[a]}function i(){l={}}var j=1,k=2,l={};return{hasBlobUri:b,getResultUri:c,isPending:d,isUploaded:e,markPending:f,markUploaded:g,removeFailed:h,destroy:i}}}),g("61",["1g","6g","6h","6i","6j","26"],function(a,b,c,d,e,f){return function(g){function h(a){return function(b){return g.selection?a(b):[]}}function i(){return"?"+(new Date).getTime()}function j(a,b,c){var d=0;do d=a.indexOf(b,d),d!==-1&&(a=a.substring(0,d)+c+a.substr(d+b.length),d+=c.length-b.length+1);while(d!==-1);return a}function k(a,b,c){return a=j(a,'src="'+b+'"','src="'+c+'"'),a=j(a,'data-mce-src="'+b+'"','data-mce-src="'+c+'"')}function l(b,c){a.each(g.undoManager.data,function(d){"fragmented"===d.type?d.fragments=a.map(d.fragments,function(a){return k(a,b,c)
 }):d.content=k(d.content,b,c)})}function m(){return g.notificationManager.open({text:g.translate("Image uploading..."),type:"info",timeout:-1,progressBar:!0})}function n(a,b){w.removeByUri(a.src),l(a.src,b),g.$(a).attr({src:x.images_reuse_filename?b+i():b,"data-mce-src":g.convertURL(b,"src")})}function o(c){return u||(u=new b(y,{url:x.images_upload_url,basePath:x.images_upload_base_path,credentials:x.images_upload_credentials,handler:x.images_upload_handler})),r().then(h(function(b){var d;return d=a.map(b,function(a){return a.blobInfo}),u.upload(d,m).then(h(function(d){var e=a.map(d,function(a,c){var d=b[c].image;return a.status&&g.settings.images_replace_blob_uris!==!1?n(d,a.url):a.error&&f.uploadError(g,a.error),{element:d,status:a.status}});return c&&c(e),e}))}))}function p(a){if(x.automatic_uploads!==!1)return o(a)}function q(a){return!x.images_dataimg_filter||x.images_dataimg_filter(a)}function r(){return v||(v=new
  c(y,w)),v.findAll(g.getBody(),q).then(h(function(b){return b=a.filter(b,function(a){return"string"!=typeof a||(f.displayError(g,a),!1)}),a.each(b,function(a){l(a.image.src,a.blobInfo.blobUri()),a.image.src=a.blobInfo.blobUri(),a.image.removeAttribute("data-mce-src")}),b}))}function s(){w.destroy(),y.destroy(),v=u=null}function t(b){return b.replace(/src="(blob:[^"]+)"/g,function(b,c){var d=y.getResultUri(c);if(d)return'src="'+d+'"';var e=w.getByUri(c);return e||(e=a.reduce(g.editorManager.editors,function(a,b){return a||b.editorUpload&&b.editorUpload.blobCache.getByUri(c)},null)),e?'src="data:'+e.blob().type+";base64,"+e.base64()+'"':b})}var u,v,w=new d,x=g.settings,y=new e;return g.on("setContent",function(){g.settings.automatic_uploads!==!1?p():r()}),g.on("RawSaveContent",function(a){a.content=t(a.content)}),g.on("getContent",function(a){a.source_view||"raw"==a.format|
 |(a.content=t(a.content))}),g.on("PostRender",function(){g.parser.addNodeFilter("img",function(b){a.each(b,function(a){var b=a.attr("src");if(!w.getByUri(b)){var c=y.getResultUri(b);c&&a.attr("src",c)}})})}),{blobCache:w,uploadImages:o,uploadImagesAuto:p,scanForImages:r,destroy:s}}}),g("62",["3t"],function(a){var b=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n=a.settings,o=a.dom,p=a.selection,q=a.schema,r=q.getBlockElements(),s=p.getStart(),t=a.getBody(),u=-16777215;if(m=n.forced_root_block,s&&1===s.nodeType&&m){for(;s&&s!==t;){if(r[s.nodeName])return;s=s.parentNode}if(b=p.getRng(),b.setStart){c=b.startContainer,d=b.startOffset,e=b.endContainer,f=b.endOffset;try{j=a.getDoc().activeElement===t}catch(a){}}else b.item&&(s=b.item(0),b=a.getDoc().body.createTextRange(),b.moveToElementText(s)),j=b.parentElement().ownerDocument===a.getDoc(),k=b.duplicate(),k.collapse(!0),d=k.move("character
 ",u)*-1,k.collapsed||(k=b.duplicate(),k.collapse(!1),
-f=k.move("character",u)*-1-d);for(s=t.firstChild,l=t.nodeName.toLowerCase();s;)if((3===s.nodeType||1==s.nodeType&&!r[s.nodeName])&&q.isValidChild(l,m.toLowerCase())){if(3===s.nodeType&&0===s.nodeValue.length){h=s,s=s.nextSibling,o.remove(h);continue}g||(g=o.create(m,a.settings.forced_root_block_attrs),s.parentNode.insertBefore(g,s),i=!0),h=s,s=s.nextSibling,g.appendChild(h)}else g=null,s=s.nextSibling;if(i&&j){if(b.setStart)b.setStart(c,d),b.setEnd(e,f),p.setRng(b);else try{b=a.getDoc().body.createTextRange(),b.moveToElementText(t),b.collapse(!0),b.moveStart("character",d),f>0&&b.moveEnd("character",f),b.select()}catch(a){}a.nodeChanged()}}},c=function(c){c.settings.forced_root_block&&c.on("NodeChange",a.curry(b,c))};return{setup:c}}),g("76",["1g","1j","3y"],function(a,b,c){function d(e){function f(b){return a.map(b,function(a){return a=c.clone(a),a.node
 =e,a})}if(a.isArray(e))return a.reduce(e,function(a,b){return a.concat(d(b))},[]);if(b.isElement(e))return f(e.getClientRects());if(b.isText(e)){var g=e.ownerDocument.createRange();return g.setStart(e,0),g.setEnd(e,e.data.length),f(g.getClientRects())}}return{getClientRects:d}}),g("6p",["1s","1g","1j","76","3y","59","3x"],function(a,b,c,d,e,f,g){function h(a,b){return Math.abs(a.left-b)}function i(a,b){return Math.abs(a.right-b)}function j(a,c){function d(a,b){return a>=b.left&&a<=b.right}return b.reduce(a,function(a,b){var e,f;return e=Math.min(h(a,c),i(a,c)),f=Math.min(h(b,c),i(b,c)),d(c,b)?b:d(c,a)?a:f==e&&p(b.node)?b:f<e?b:a})}function k(a,b,c,d){for(;d=q(d,a,g.isEditableCaretCandidate,b);)if(c(d))return}function l(a,c){function f(a,e){var f;return f=b.filter(d.getClientRects(e),function(b){return!a(b,c)}),g=g.concat(f),0===f.length}var g=[];return g.push(c),k(-1,a,r(f,e.isAb
 ove),c.node),k(1,a,r(f,e.isBelow),c.node),g}function m(a){return b.filter(b.toArray(a.getElementsByTagName("*")),p)}function n(a,b){return{node:a.node,before:h(a,b)<i(a,b)}}function o(a,c,e){var f,g;return f=d.getClientRects(m(a)),f=b.filter(f,function(a){return e>=a.top&&e<=a.bottom}),g=j(f,c),g&&(g=j(l(a,g),c),g&&p(g.node))?n(g,c):null}var p=c.isContentEditableFalse,q=f.findNode,r=a.curry;return{findClosestClientRect:j,findLineNodeRects:l,closestCaret:o}}),g("7b",["1s","1g","76","3x","59","4d","1n","3y"],function(a,b,c,d,e,f,g,h){function i(a,b,c,f){for(;f=e.findNode(f,a,d.isEditableCaretCandidate,b);)if(c(f))return}function j(a,d,e,f,g,h){function j(f){var h,i,j;for(j=c.getClientRects(f),a==-1&&(j=j.reverse()),h=0;h<j.length;h++)if(i=j[h],!e(i,l)){if(n.length>0&&d(i,b.last(n))&&m++,i.line=m,g(i))return!0;n.push(i)}}var 
 k,l,m=0,n=[];return(l=b.last(h.getClientRects()))?(k=h.getNode(),j(k),i(a,f,j,k),n):n}function k(a,b){return b.line>a}function l(a,b){return b.line===a}function m(a,c,d,e){function i(c){return 1==a?b.last(c.getClientRects()):b.last(c.getClientRects())}var j,k,l,m,n,o,p=new f(c),q=[],r=0;1==a?(j=p.next,k=h.isBelow,l=h.isAbove,m=g.after(e)):(j=p.prev,k=h.isAbove,l=h.isBelow,m=g.before(e)),o=i(m);do if(m.isVisible()&&(n=i(m),!l(n,o))){if(q.length>0&&k(n,b.last(q))&&r++,n=h.clone(n),n.position=m,n.line=r,d(n))return q;q.push(n)}while(m=j(m));return q}var n=a.curry,o=n(j,-1,h.isAbove,h.isBelow),p=n(j,1,h.isBelow,h.isAbove);return{upUntil:o,downUntil:p,positionsUntil:m,isAboveLine:n(k),isLine:n(l)}}),g("6r",["1n","59","1j","1s"],function(a,b,c,d){var e=c.isContentEditableTrue,f=c.isContentEditableFalse,g=function(a,b,c,d){return b._selectionOverrides.showCaret(a,c,d)},h=function(a){var b=a.ownerDocument.create
 Range();return b.selectNode(a),b},i=function(a,b){var c;return c=a.fire("BeforeObjectSelected",{target:b}),c.isDefaultPrevented()?null:h(b)},j=function(c,h){var i,j;return h=b.normalizeRange(1,c.getBody(),h),i=a.fromRangeStart(h),f(i.getNode())?g(1,c,i.getNode(),!i.isAtEnd()):f(i.getNode(!0))?g(1,c,i.getNode(!0),!1):(j=c.dom.getParent(i.getNode(),d.or(f,e)),f(j)?g(1,c,j,!1):null)},k=function(a,b){var c;return b&&b.collapsed?(c=j(a,b),c?c:b):b};return{showCaret:g,selectNode:i,renderCaretAtRange:j,renderRangeCaret:k}}),g("73",["1k","1n","59","4d","6p","7b","1j","h","6","6r","1g","1s"],function(a,b,c,d,e,f,g,h,i,j,k,l){var m=g.isContentEditableFalse,n=h.getSelectedNode,o=c.isAfterContentEditableFalse,p=c.isBeforeContentEditableFalse,q=function(a,b){for(;b=a(b);)if(b.isVisible())return b;return b},r=function(a,b){var d=c.isInSameBlock(a,b);r
 eturn!(d||!g.isBr(a.getNode()))||d},s=function(b){return a.isCaretContainerBlock(b.startContainer)},t=function(a,d,e){return e=c.normalizeRange(a,d,e),a===-1?b.fromRangeStart(e):b.fromRangeEnd(e)},u=function(a,b,c,d,e){var f,g,h,i;return!e.collapsed&&(f=n(e),m(f))?j.showCaret(a,b,f,a===-1):(i=s(e),g=t(a,b.getBody(),e),d(g)?j.selectNode(b,g.getNode(a===-1)):(g=c(g))?d(g)?j.showCaret(a,b,g.getNode(a===-1),1===a):(h=c(g),d(h)&&r(g,h)?j.showCaret(a,b,h.getNode(a===-1),1===a):i?j.renderRangeCaret(b,g.toRange()):null):i?e:null)},v=function(a,b,c,d){var g,h,i,l,q,r,s,u,v;if(v=n(d),g=t(a,b.getBody(),d),h=c(b.getBody(),f.isAboveLine(1),g),i=k.filter(h,f.isLine(1)),q=k.last(g.getClientRects()),p(g)&&(v=g.getNode()),o(g)&&(v=g.getNode(!0)),!q)return null;if(r=q.left,l=e.findClosestClientRect(i,r),l&&m(l.node))return s=Math.abs(r-l.left),u=Math.abs(r-l.right),j.showCaret(a,b,l.node,s<u);if(v){var w=f.positionsUntil(a,b.getBody(),f.isAboveLine(1),v);if(
 l=e.findClosestClientRect(k.filter(w,f.isLine(1)),r))return j.renderRangeCaret(b,l.position.toRange());if(l=k.last(k.filter(w,f.isLine(0))))return j.renderRangeCaret(b,l.position.toRange())}},w=function(a){var b=a.dom.create(a.settings.forced_root_block);return(!i.ie||i.ie>=11)&&(b.innerHTML='<br data-mce-bogus="1">'),b},x=function(a,c,e){var f,g,h,i=new d(a.getBody()),j=l.curry(q,i.next),k=l.curry(q,i.prev);if(e.collapsed&&a.settings.forced_root_block){if(f=a.dom.getParent(e.startContainer,"PRE"),!f)return;g=1===c?j(b.fromRangeStart(e)):k(b.fromRangeStart(e)),g||(h=w(a),1===c?a.$(f).after(h):a.$(f).before(h),a.selection.select(h,!0),a.selection.collapse())}},y=function(a,b){var c,e=new d(a.getBody()),f=l.curry(q,e.next),g=l.curry(q,e.prev),h=b?1:-1,i=b?f:g,j=b?p:o,k=a.selection.getRng();return(c=u(h,a,i,j,k))?c:(c=x(a,h,k),c?c:null)},z=function(a,b){var c,d=b?1:-1,e=b?f.downUntil:f.upUntil,g=a.selection.getRng();return(c=v(d,a,e,g))?c:(c
 =x(a,d,g),c?c:null)},A=function(a,b){return function(){var c=y(a,b);return!!c&&(a.selection.setRng(c),!0)}},B=function(a,b){return function(){var c=z(a,b);return!!c&&(a.selection.setRng(c),!0)}};return{moveH:A,moveV:B}}),g("7c",["5l","4r","4s"],function(a,b,c){var d=function(a,b){return b},e=function(b,c){var d=a.isObject(b)&&a.isObject(c);return d?g(b,c):c},f=function(a){return function(){for(var d=new b(arguments.length),e=0;e<d.length;e++)d[e]=arguments[e];if(0===d.length)throw new c("Can't merge zero objects");for(var f={},g=0;g<d.length;g++){var h=d[g];for(var i in h)h.hasOwnProperty(i)&&(f[i]=a(f[i],h[i]))}return f}},g=f(e),h=f(d);return{deepMerge:g,merge:h}}),g("74",["3s","3t","7c"],function(a,b,c){var d=function(d){return a.map(d,function(a){return c.merge({shiftKey:!1,altKey:!1,ctrlKey:!1,metaKey:!1,keyCode:0,action:b.noop},a)})},e=function(a,b){re
 turn b.keyCode===a.keyCode&&b.shiftKey===a.shiftKey&&b.altKey===a.altKey&&b.ctrlKey===a.ctrlKey&&b.metaKey===a.metaKey},f=function(b,c){return a.bind(d(b),function(a){return e(a,c)?[a]:[]})},g=function(a){var b=Array.prototype.slice.call(arguments,1);return function(){return a.apply(null,b)}};return{match:f,action:g}}),g("6k",["3s","5z","5f","73","74","p"],function(a,b,c,d,e,f){var g=function(b,g,h){var i=e.match([{keyCode:f.RIGHT,action:d.moveH(b,!0)},{keyCode:f.LEFT,action:d.moveH(b,!1)},{keyCode:f.UP,action:d.moveV(b,!1)},{keyCode:f.DOWN,action:d.moveV(b,!0)},{keyCode:f.RIGHT,action:c.move(b,g,!0)},{keyCode:f.LEFT,action:c.move(b,g,!1)}],h);a.find(i,function(a){return a.action()}).each(function(a){h.preventDefault()})},h=function(a,b){a.on("keydown",function(c){c.isDefaultPrevented()===!1&&g(a,b,c)})};return{setup:h}}),g("6l",["3s","49&q
 uot;,"4a","4b","4c","74","p"],function(a,b,c,d,e,f,g){var h=function(h,i,j){var k=f.match([{keyCode:g.BACKSPACE,action:f.action(d.backspaceDelete,h,!1)},{keyCode:g.DELETE,action:f.action(d.backspaceDelete,h,!0)},{keyCode:g.BACKSPACE,action:f.action(e.backspaceDelete,h,i,!1)},{keyCode:g.DELETE,action:f.action(e.backspaceDelete,h,i,!0)},{keyCode:g.BACKSPACE,action:f.action(c.backspaceDelete,h,!1)},{keyCode:g.DELETE,action:f.action(c.backspaceDelete,h,!0)},{keyCode:g.BACKSPACE,action:f.action(b.backspaceDelete,h,!1)},{keyCode:g.DELETE,action:f.action(b.backspaceDelete,h,!0)}],j);a.find(k,function(a){return a.action()}).each(function(a){j.preventDefault()})},i=function(b,c){var e=f.match([{keyCode:g.BACKSPACE,action:f.action(d.paddEmptyElement,b)},{keyCode:g.DELETE,action:f.action(d.paddEmptyElement,b)}],c);a.find(e,function(a){return a.action()})},j=function(a,b){a.on("keydown",function(c){c.isDefaultPrevented()===!1&&
 h(a,b,c)}),a.on("keyup",function(b){b.isDefaultPrevented()===!1&&i(a,b)})};return{setup:j}}),g("6m",["1k","1j","h","c","6","1l","9"],function(a,b,c,d,e,f,g){var h=e.ie&&e.ie<11,i=function(a){return a&&"A"===a.nodeName&&0===g.trim(f.trim(a.innerText||a.textContent)).length},j=function(a){return a&&/^(TD|TH|CAPTION)$/.test(a.nodeName)},k=function(a){a.innerHTML=h?"":'<br data-mce-bogus="1">'},l=function(a,b){return a.nodeName===b||a.previousSibling&&a.previousSibling.nodeName===b},m=function(a,b){return b&&a.isBlock(b)&&!/^(TD|TH|CAPTION|FORM)$/.test(b.nodeName)&&!/^(fixed|absolute)/i.test(b.style.position)&&"true"!==a.getContentEditable(b)},n=function(a,b,c){var d;a.isBlock(c)&&(d=b.getRng(),c.appendChild(a.create("span",null,"\xa0")),b.sele
 ct(c),c.lastChild.outerHTML="",b.setRng(d))},o=function(a,b,c){var d,e=c,f=[];if(e){for(;e=e.firstChild;){if(a.isBlock(e))return;1!=e.nodeType||b[e.nodeName.toLowerCase()]||f.push(e)}for(d=f.length;d--;)e=f[d],!e.hasChildNodes()||e.firstChild==e.lastChild&&""===e.firstChild.nodeValue?a.remove(e):i(e)&&a.remove(e)}},p=function(a,c,d){return b.isText(c)===!1?d:a?1===d&&c.data.charAt(d-1)===f.ZWSP?0:d:d===c.data.length-1&&c.data.charAt(d)===f.ZWSP?c.data.length:d},q=function(a){var b=a.cloneRange();return b.setStart(a.startContainer,p(!0,a.startContainer,a.startOffset)),b.setEnd(a.endContainer,p(!1,a.endContainer,a.endOffset)),b},r=function(a){for(;a;){if(1===a.nodeType||3===a.nodeType&&a.data&&/[\r\n\s]/.test(a.data))return a;a=a.nextSibling}},s=function(b){function f(f){function x(a){var b,c,f,h,j=a;if(a){if(e.ie&&e.ie<9&&N&&N.firstChild&&N.firstChild==N.lastChild&&"BR&
 quot;==N.firstChild.tagName&&g.remove(N.firstChild),/^(LI|DT|DD)$/.test(a.nodeName)){var k=r(a.firstChild);k&&/^(UL|OL|DL)$/.test(k.nodeName)&&a.insertBefore(g.doc.createTextNode("\xa0"),a.firstChild)}if(f=g.createRng(),e.ie||a.normalize(),a.hasChildNodes()){for(b=new d(a,a);c=b.current();){if(3==c.nodeType){f.setStart(c,0),f.setEnd(c,0);break}if(w[c.nodeName.toLowerCase()]){f.setStartBefore(c),f.setEndBefore(c);break}j=c,c=b.next()}c||(f.setStart(j,0),f.setEnd(j,0))}else"BR"==a.nodeName?a.nextSibling&&g.isBlock(a.nextSibling)?((!O||O<9)&&(h=g.create("br"),a.parentNode.insertBefore(h,a)),f.setStartBefore(a),f.setEndBefore(a)):(f.setStartAfter(a),f.setEndAfter(a)):(f.setStart(a,0),f.setEnd(a,0));i.setRng(f),g.remove(h),i.scrollIntoView(a)}}function y(a){var b=s.forced_root_block;b&&b.toLowerCase()===a.tagName.toLowerCase()&&g.setAttribs(a,s.forced_root_block_attrs)}function z(a){var b,c,d,e=L,f=u
 .getTextInlineElements();if(a||"TABLE"==T||"HR"==T?(b=g.create(a||V),y(b)):b=N.cloneNode(!1),d=b,s.keep_styles===!1)g.setAttrib(b,"style",null),g.setAttrib(b,"class",null);else do if(f[e.nodeName]){if("_mce_caret"==e.id)continue;c=e.cloneNode(!1),g.setAttrib(c,"id",""),b.hasChildNodes()?(c.appendChild(b.firstChild),b.appendChild(c)):(d=c,b.appendChild(c))}while((e=e.parentNode)&&e!=K);return h||(d.innerHTML='<br data-mce-bogus="1">'),b}function A(a){var b,c,e,f;if(f=p(a,L,M),3==L.nodeType&&(a?f>0:f<L.nodeValue.length))return!1;if(L.parentNode==N&&W&&!a)return!0;if(a&&1==L.nodeType&&L==N.firstChild)return!0;if(l(L,"TABLE")||l(L,"HR"))return W&&!a||!W&&a;for(b=new d(L,N),3==L.nodeType&&(a&&0===f?b.prev():a||f!=L.nodeValue.length||b.next());c=b.current();){if(1===c.nodeType){if(!c.getAttribute(&qu
 ot;data-mce-bogus")&&(e=c.nodeName.toLowerCase(),v[e]&&"br"!==e))return!1}else if(3===c.nodeType&&!/^[ \t\r\n]*$/.test(c.nodeValue))return!1;a?b.prev():b.next()}return!0}function B(a,c){var d,e,f,h,i,k,l=V||"P";if(e=g.getParent(a,g.isBlock),!e||!m(g,e)){if(e=e||K,k=e==b.getBody()||j(e)?e.nodeName.toLowerCase():e.parentNode.nodeName.toLowerCase(),!e.hasChildNodes())return d=g.create(l),y(d),e.appendChild(d),I.setStart(d,0),I.setEnd(d,0),d;for(h=a;h.parentNode!=e;)h=h.parentNode;for(;h&&!g.isBlock(h);)f=h,h=h.previousSibling;if(f&&u.isValidChild(k,l.toLowerCase())){for(d=g.create(l),y(d),f.parentNode.insertBefore(d,f),h=f;h&&!g.isBlock(h);)i=h.nextSibling,d.appendChild(h),h=i;I.setStart(a,c),I.setEnd(a,c)}}return a}function C(){function a(a){for(var b=S[a?"firstChild":"lastChild"];b&&1!=b.nodeType;)b=b[a?"nextSibling":"previousSibling"];return b===N}function c(){var
  a=S.parentNode;return/^(LI|DT|DD)$/.test(a.nodeName)?a:S}if(S!=b.getBody()){var d=S.parentNode.nodeName;/^(OL|UL|LI)$/.test(d)&&(V="LI"),Q=V?z(V):g.create("BR"),a(!0)&&a()?"LI"==d?g.insertAfter(Q,c()):g.replace(Q,S):a(!0)?"LI"==d?(g.insertAfter(Q,c()),Q.appendChild(g.doc.createTextNode(" ")),Q.appendChild(S)):S.parentNode.insertBefore(Q,S):a()?(g.insertAfter(Q,c()),n(g,i,Q)):(S=c(),J=I.cloneRange(),J.setStartAfter(N),J.setEndAfter(S),R=J.extractContents(),"LI"==V&&"LI"==R.firstChild.nodeName?(Q=R.firstChild,g.insertAfter(R,S)):(g.insertAfter(R,S),g.insertAfter(Q,S))),g.remove(N),x(Q),t.add()}}function D(){b.execCommand("InsertLineBreak",!1,f)}function E(a){do 3===a.nodeType&&(a.nodeValue=a.nodeValue.replace(/^[\r\n]+/,"")),a=a.firstChild;while(a)}function F(a){var b,c,d=g.getRoot();for(b=a;b!==d&&"false"!==g.getContentEditable(b);)"true&qu
 ot;===g.getContentEditable(b)&&(c=b),b=b.parentNode;return b!==d?c:d}function G(a){var b;h||(a.normalize(),b=a.lastChild,b&&!/^(left|right)$/gi.test(g.getStyle(b,"float",!0))||g.add(a,"br"))}function H(){Q=/^(H[1-6]|PRE|FIGURE)$/.test(T)&&"HGROUP"!=U?z(V):z(),s.end_container_on_empty_block&&m(g,S)&&g.isEmpty(N)?Q=g.split(S,N):g.insertAfter(Q,N),x(Q)}var I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W;if(I=i.getRng(!0),!f.isDefaultPrevented()){if(!I.collapsed)return void b.execCommand("Delete");if(new c(g).normalize(I),L=I.startContainer,M=I.startOffset,V=(s.force_p_newlines?"p":"")||s.forced_root_block,V=V?V.toUpperCase():"",O=g.doc.documentMode,P=f.shiftKey,1==L.nodeType&&L.hasChildNodes()&&(W=M>L.childNodes.length-1,L=L.childNodes[Math.min(M,L.childNodes.length-1)]||L,M=W&&3==L.nodeType?L.nodeValue.length:0),K=F(L)){if(t.beforeChange(),!g.isBlock(K)&&K!=g.
 getRoot())return void(V&&!P||D());if((V&&!P||!V&&P)&&(L=B(L,M)),N=g.getParent(L,g.isBlock),S=N?g.getParent(N.parentNode,g.isBlock):null,T=N?N.nodeName.toUpperCase():"",U=S?S.nodeName.toUpperCase():"","LI"!=U||f.ctrlKey||(N=S,T=U),b.undoManager.typing&&(b.undoManager.typing=!1,b.undoManager.add()),/^(LI|DT|DD)$/.test(T)){if(!V&&P)return void D();if(g.isEmpty(N))return void C()}if("PRE"==T&&s.br_in_pre!==!1){if(!P)return void D()}else if(!V&&!P&&"LI"!=T||V&&P)return void D();V&&N===b.getBody()||(V=V||"P",a.isCaretContainerBlock(N)?(Q=a.showCaretContainerBlock(N),g.isEmpty(N)&&k(N),x(Q)):A()?H():A(!0)?(Q=N.parentNode.insertBefore(z(),N),n(g,i,Q),x(l(N,"HR")?Q:N)):(J=q(I).cloneRange(),J.setEndAfter(N),R=J.extractContents(),E(R),Q=R.firstChild,g.insertAfter(R,N),o(g,v,Q),G(N),g.isEmpty(N)&&k(N),Q.normalize(),g.isEmpt
 y(Q)?(g.remove(Q),H()):x(Q)),g.setAttrib(Q,"id",""),b.fire("NewBlock",{newBlock:Q}),t.typing=!1,t.add())}}}var g=b.dom,i=b.selection,s=b.settings,t=b.undoManager,u=b.schema,v=u.getNonEmptyElements(),w=u.getMoveCaretBeforeOnEnterElements();b.on("keydown",function(a){13==a.keyCode&&f(a)!==!1&&a.preventDefault()})};return{setup:s}}),g("75",["3t","1n","1j","5e"],function(a,b,c,d){var e=function(a,b){return i(a)&&c.isText(b.container())},f=function(a,b){var c=b.container(),d=b.offset();c.insertData(d,"\xa0"),a.selection.setCursorLocation(c,d+1)},g=function(a,b,c){return!!e(c,b)&&(f(a,b),!0)},h=function(c){var e=b.fromRangeStart(c.selection.getRng()),f=d.readLocation(c.getBody(),e);return f.map(a.curry(g,c,e)).getOr(!1)},i=function(b){return b.fold(a.constant(!1),a.constant(!0),a.constant(!0),a.constant(!1))},j=function(a){return!!a.selection.isCollapsed()&am
 p;&h(a)};return{insertAtSelection:j}}),g("6n",["3s","75","74","p"],function(a,b,c,d){var e=function(e,f){var g=c.match([{keyCode:d.SPACEBAR,action:c.action(b.insertAtSelection,e)}],f);a.find(g,function(a){return a.action()}).each(function(a){f.preventDefault()})},f=function(a){a.on("keydown",function(b){b.isDefaultPrevented()===!1&&e(a,b)})};return{setup:f}}),g("63",["6k","5f","6l","6m","6n"],function(a,b,c,d,e){var f=function(f){var g=b.setupSelectedState(f);a.setup(f,g),c.setup(f,g),d.setup(f),e.setup(f)};return{setup:f}}),g("64",["h","6","5"],function(a,b,c){return function(d){function e(a){var b,c;if(c=d.$(a).parentsUntil(d.getBody()).add(a),c.length===g.length){for(b=c.length;b>=0&&c[b]===g[b];b--);if(b===-1)return g=c,!0}return g=c,!1}var f,g=[];"onselectionchange"in d.getDoc()||d.on(&qu
 ot;NodeChange Click MouseUp KeyUp Focus",function(b){var c,e;c=d.selection.getRng(),e={startContainer:c.startContainer,startOffset:c.startOffset,endContainer:c.endContainer,endOffset:c.endOffset},"nodechange"!=b.type&&a.compareRanges(e,f)||d.fire("SelectionChange"),f=e}),d.on("contextmenu",function(){d.fire("SelectionChange")}),d.on("SelectionChange",function(){var a=d.selection.getStart(!0);!b.range&&d.selection.isCollapsed()||!e(a)&&d.dom.isChildOf(a,d.getBody())&&d.nodeChanged({selectionChange:!0})}),d.on("MouseUp",function(a){a.isDefaultPrevented()||("IMG"==d.selection.getNode().nodeName?c.setEditorTimeout(d,function(){d.nodeChanged()}):d.nodeChanged())}),this.nodeChanged=function(a){var b,c,e,f=d.selection;d.initialized&&f&&!d.settings.disable_nodechange&&!d.readonly&&(e=d.getBody(),b=f.getStart(!0)||e,b.ownerDocument==d.getDoc()&&d.
 dom.isChildOf(b,e)||(b=e),c=[],d.dom.getParent(b,function(a){return a===e||void c.push(a)}),a=a||{},a.element=b,a.parents=c,d.fire("NodeChange",a))}}}),g("6o",["1k","5x","1n","a","1j","h","3y","5"],function(a,b,c,d,e,f,g,h){var i=e.isContentEditableFalse,j=function(a){return a&&/^(TD|TH)$/i.test(a.nodeName)};return function(c,e){function f(a,b){var d,e,f,h,i,j=g.collapse(a.getBoundingClientRect(),b);return"BODY"==c.tagName?(d=c.ownerDocument.documentElement,e=c.scrollLeft||d.scrollLeft,f=c.scrollTop||d.scrollTop):(i=c.getBoundingClientRect(),e=c.scrollLeft-i.left,f=c.scrollTop-i.top),j.left+=e,j.right+=e,j.top+=f,j.bottom+=f,j.width=1,h=a.offsetWidth-a.clientWidth,h>0&&(b&&(h*=-1),j.left+=h,j.right+=h),j}function k(){var b,e,f,g,h;for(b=d("*[contentEditable=false]",c),g=0;g<b.length;g++)e=b[g],f=e.previousSibling,a.endsWithCaretContain
 er(f)&&(h=f.data,1==h.length?f.parentNode.removeChild(f):f.deleteData(h.length-1,1)),f=e.nextSibling,a.startsWithCaretContainer(f)&&(h=f.data,1==h.length?f.parentNode.removeChild(f):f.deleteData(0,1));return null}function l(b,g){var h,k;return m(),j(g)?null:e(g)?(s=a.insertBlock("p",g,b),h=f(g,b),d(s).css("top",h.top),r=d('<div class="mce-visual-caret" data-mce-bogus="all"></div>').css(h).appendTo(c),b&&r.addClass("mce-visual-caret-before"),n(),k=g.ownerDocument.createRange(),k.setStart(s,0),k.setEnd(s,0),k):(s=a.insertInline(g,b),k=g.ownerDocument.createRange(),i(s.nextSibling)?(k.setStart(s,0),k.setEnd(s,0)):(k.setStart(s,1),k.setEnd(s,1)),k)}function m(){k(),s&&(b.remove(s),s=null),r&&(r.remove(),r=null),clearInterval(q)}function n(){q=h.setInterval(function(){d("div.mce-visual-caret",c).toggleClass("mce-visual-caret-hidden")},500)}function o(){h.clearInterval
 (q)}function p(){return".mce-visual-caret {position: absolute;background-color: black;background-color: currentcolor;}.mce-visual-caret-hidden {display: none;}*[data-mce-caret] {position: absolute;left: -1000px;right: auto;top: 0;margin: 0;padding: 0;}"}var q,r,s;return{show:l,hide:m,getCss:p,destroy:o}}}),g("77",[],function(){var a=function(a){var b,c,d,e;return e=a.getBoundingClientRect(),b=a.ownerDocument,c=b.documentElement,d=b.defaultView,{top:e.top+d.pageYOffset-c.clientTop,left:e.left+d.pageXOffset-c.clientLeft}},b=function(b){return b.inline?a(b.getBody()):{left:0,top:0}},c=function(a){var b=a.getBody();return a.inline?{left:b.scrollLeft,top:b.scrollTop}:{left:0,top:0}},d=function(a){var b=a.getBody(),c=a.getDoc().documentElement,d={left:b.scrollLeft,top:b.scrollTop},e={left:b.scrollLeft||c.scrollLeft,top:b.scrollTop||c.scrollTop};return a.inline?d:e},e=function(b,c){if(c.target.ownerDocument!==b.getDoc()){var e=a(b.getContentAreaContainer()),f=d(b);retur
 n{left:c.pageX-e.left+f.left,top:c.pageY-e.top+f.top}}return{left:c.pageX,top:c.pageY}},f=function(a,b,c){return{pageX:c.left-a.left+b.left,pageY:c.top-a.top+b.top}},g=function(a,d){return f(b(a),c(a),e(a,d))};return{calc:g}}),g("6q",["1j","1g","1s","5","e","77"],function(a,b,c,d,e,f){var g=a.isContentEditableFalse,h=a.isContentEditableTrue,i=function(a,b){return g(b)&&b!==a},j=function(a,b,c){return b!==c&&!a.dom.isChildOf(b,c)&&!g(b)},k=function(a){var b=a.cloneNode(!0);return b.removeAttribute("data-mce-selected"),b},l=function(a,b,c,d){var e=b.cloneNode(!0);a.dom.setStyles(e,{width:c,height:d}),a.dom.setAttrib(e,"data-mce-selected",null);var f=a.dom.create("div",{"class":"mce-drag-container","data-mce-bogus":"all",unselectable:"on",contenteditable:"false"});return a.dom.setStyles(f,{position:"
 absolute",opacity:.5,overflow:"hidden",border:0,padding:0,margin:0,width:c,height:d}),a.dom.setStyles(e,{margin:0,boxSizing:"border-box"}),f.appendChild(e),f},m=function(a,b){a.parentNode!==b&&b.appendChild(a)},n=function(a,b,c,d,e,f){var g=0,h=0;a.style.left=b.pageX+"px",a.style.top=b.pageY+"px",b.pageX+c>e&&(g=b.pageX+c-e),b.pageY+d>f&&(h=b.pageY+d-f),a.style.width=c-g+"px",a.style.height=d-h+"px"},o=function(a){a&&a.parentNode&&a.parentNode.removeChild(a)},p=function(a){return 0===a.button},q=function(a){return a.element},r=function(a,b){return{pageX:b.pageX-a.relX,pageY:b.pageY+5}},s=function(a,d){return function(e){if(p(e)){var f=b.find(d.dom.getParents(e.target),c.or(g,h));if(i(d.getBody(),f)){var j=d.dom.getPos(f),k=d.getBody(),m=d.getDoc().documentElement;a.element=f,a.screenX=e.screenX,a.screenY=e.screenY,a.maxX=(d.inline?k.scrollWidth:m.offsetWidth)-2,a.maxY=(d.in
 line?k.scrollHeight:m.offsetHeight)-2,a.relX=e.pageX-j.x,a.relY=e.pageY-j.y,a.width=f.offsetWidth,a.height=f.offsetHeight,a.ghost=l(d,f,a.width,a.height)}}}},t=function(a,b){var c=d.throttle(function(a,c){b._selectionOverrides.hideFakeCaret(),b.selection.placeCaretAt(a,c)},0);return function(d){var e=Math.max(Math.abs(d.screenX-a.screenX),Math.abs(d.screenY-a.screenY));if(q(a)&&!a.dragging&&e>10){var g=b.fire("dragstart",{target:a.element});if(g.isDefaultPrevented())return;a.dragging=!0,b.focus()}if(a.dragging){var h=r(a,f.calc(b,d));m(a.ghost,b.getBody()),n(a.ghost,h,a.width,a.height,a.maxX,a.maxY),c(d.clientX,d.clientY)}}},u=function(a){var b=a.getSel().getRangeAt(0),c=b.startContainer;return 3===c.nodeType?c.parentNode:c},v=function(a,b){return function(c){if(a.dragging&&j(b,u(b.selection),a.element)){var d=k(a.element),e=b.fire("drop",{targetClone:d,clientX:c.clientX,clientY:c.clientY});e.isDefaultPrevented()||(d=e.targetClone,b.und
 oManager.transact(function(){o(a.element),b.insertContent(b.dom.getOuterHTML(d)),b._selectionOverrides.hideFakeCaret()}))}x(a)}},w=function(a,b){return function(){x(a),a.dragging&&b.fire("dragend")}},x=function(a){a.dragging=!1,a.element=null,o(a.ghost)},y=function(a){var b,c,d,f,g,h,i={};b=e.DOM,h=document,c=s(i,a),d=t(i,a),f=v(i,a),g=w(i,a),a.on("mousedown",c),a.on("mousemove",d),a.on("mouseup",f),b.bind(h,"mousemove",d),b.bind(h,"mouseup",g),a.on("remove",function(){b.unbind(h,"mousemove",d),b.unbind(h,"mouseup",g)})},z=function(a){a.on("drop",function(b){var c="undefined"!=typeof b.clientX?a.getDoc().elementFromPoint(b.clientX,b.clientY):null;(g(c)||g(a.dom.getContentEditableParent(c)))&&b.preventDefault()})},A=function(a){y(a),z(a)};return{init:A}});g("65",["1k","1n","59","4d","6o","6p&quot
 ;,"1j","6q","6","3y","6r","1g","5","1s","p"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o){function p(g){function n(a){return g.dom.hasClass(a,"mce-offscreen-selection")}function p(){var a=g.dom.get(M);return a?a.getElementsByTagName("*")[0]:a}function u(a){return g.dom.isBlock(a)}function v(a){a&&g.selection.setRng(a)}function w(){return g.selection.getRng()}function x(a,b){g.selection.scrollIntoView(a,b)}function y(a,b,c){var d;return d=g.fire("ShowCaret",{target:b,direction:a,before:c}),d.isDefaultPrevented()?null:(x(b,a===-1),L.show(c,b))}function z(a,d){return d=c.normalizeRange(a,K,d),a==-1?b.fromRangeStart(d):b.fromRangeEnd(d)}function A(b){b.hasAttribute("data-mce-caret")&&(a.showCaretContainerBlock(b),v(w()),x(b[0]))}function B(){function a(a){for(var b=g.getBody();a&&a!=b;){if(q(a)||r(a))return a;a=a.parentNode}return null}func
 tion c(a,b,c){return!c.collapsed&&l.reduce(c.getClientRects(),function(c,d){return c||j.containsXY(d,a,b)},!1)}function e(b){var c=!1;b.on("touchstart",function(){c=!1}),b.on("touchmove",function(){c=!0}),b.on("touchend",function(d){var e=a(d.target);r(e)&&(c||(d.preventDefault(),F(k.selectNode(b,e))))})}g.on("mouseup",function(){var a=w();a.collapsed&&v(k.renderCaretAtRange(g,a))}),g.on("click",function(b){var c;c=a(b.target),c&&(r(c)&&(b.preventDefault(),g.focus()),q(c)&&g.dom.isChildOf(c,g.selection.getNode())&&G())}),g.on("blur NewBlock",function(){G(),I()});var u=function(a){var c=new d(a);if(!a.firstChild)return!1;var e=b.before(a.firstChild),f=c.next(e);return f&&!t(f)&&!s(f)},x=function(a,b){var c=g.dom.getParent(a,g.dom.isBlock),d=g.dom.getParent(b,g.dom.isBlock);return c===d},z=function(a,b){var c=g.dom.getParent(a,g.dom.isBlock),d=g.dom.getPa
 rent(b,g.dom.isBlock);return c&&!x(c,d)&&u(c)};e(g),g.on("mousedown",function(b){var d;if(d=a(b.target))r(d)?(b.preventDefault(),F(k.selectNode(g,d))):(G(),q(d)&&b.shiftKey||c(b.clientX,b.clientY,g.selection.getRng())||g.selection.placeCaretAt(b.clientX,b.clientY));else{G(),I();var e=f.closestCaret(K,b.clientX,b.clientY);e&&(z(b.target,e.node)||(b.preventDefault(),g.getBody().focus(),v(y(1,e.node,e.before))))}}),g.on("keypress",function(a){if(!o.modifierPressed(a))switch(a.keyCode){default:r(g.selection.getNode())&&a.preventDefault()}}),g.on("getSelectionRange",function(a){var b=a.range;if(J){if(!J.parentNode)return void(J=null);b=b.cloneRange(),b.selectNode(J),a.range=b}}),g.on("setSelectionRange",function(a){var b;b=F(a.range,a.forward),b&&(a.range=b)}),g.on("AfterSetSelectionRange",function(a){var b=a.range;E(b)||I(),n(b.startContainer.parentNode)||G()}),g.on("focus",functi
 on(){m.setEditorTimeout(g,function(){g.selection.setRng(k.renderRangeCaret(g,g.selection.getRng()))},0)}),g.on("copy",function(a){var b=a.clipboardData;if(!a.isDefaultPrevented()&&a.clipboardData&&!i.ie){var c=p();c&&(a.preventDefault(),b.clearData(),b.setData("text/html",c.outerHTML),b.setData("text/plain",c.outerText))}}),h.init(g)}function C(){var a=g.contentStyles,b=".mce-content-body";a.push(L.getCss()),a.push(b+" .mce-offscreen-selection {position: absolute;left: -9999999999px;max-width: 1000000px;}"+b+" *[contentEditable=false] {cursor: default;}"+b+" *[contentEditable=true] {cursor: text;}")}function D(b){return a.isCaretContainer(b)||a.startsWithCaretContainer(b)||a.endsWithCaretContainer(b)}function E(a){return D(a.startContainer)||D(a.endContainer)}function F(a,b){var c,d,e,f,h,j,k,l,m,n,o=g.$,p=g.dom;if(!a)return null;if(a.collapsed){if(!E(a))if(b===!1){if(l=z(-1,a),r(l.getNode(
 !0)))return y(-1,l.getNode(!0),!1);if(r(l.getNode()))return y(-1,l.getNode(),!l.isAtEnd())}else{if(l=z(1,a),r(l.getNode()))return y(1,l.getNode(),!l.isAtEnd());if(r(l.getNode(!0)))return y(1,l.getNode(!0),!1)}return null}return f=a.startContainer,h=a.startOffset,j=a.endOffset,3==f.nodeType&&0==h&&r(f.parentNode)&&(f=f.parentNode,h=p.nodeIndex(f),f=f.parentNode),1!=f.nodeType?null:(j==h+1&&(c=f.childNodes[h]),r(c)?(m=n=c.cloneNode(!0),k=g.fire("ObjectSelected",{target:c,targetClone:m}),k.isDefaultPrevented()?null:(m=k.targetClone,d=o("#"+M),0===d.length&&(d=o('<div data-mce-bogus="all" class="mce-offscreen-selection"></div>').attr("id",M),d.appendTo(g.getBody())),a=g.dom.createRng(),m===n&&i.ie?(d.empty().append('<p style="font-size: 0" data-mce-bogus="all">\xa0</p>').append(m),a.setStartAfter(d[0].firstChild.firstChild),a.setEndAfter(m)):(d.em
 pty().append("\xa0").append(m).append("\xa0"),a.setStart(d[0].firstChild,1),a.setEnd(d[0].lastChild,0)),d.css({top:p.getPos(c,g.getBody()).y}),d[0].focus(),e=g.selection.getSel(),e.removeAllRanges(),e.addRange(a),g.$("*[data-mce-selected]").removeAttr("data-mce-selected"),c.setAttribute("data-mce-selected",1),J=c,I(),a)):null)}function G(){J&&(J.removeAttribute("data-mce-selected"),g.$("#"+M).remove(),J=null)}function H(){L.destroy(),J=null}function I(){L.hide()}var J,K=g.getBody(),L=new e(g.getBody(),u),M="sel-"+g.dom.uniqueId();return i.ceFalse&&(B(),C()),{showCaret:y,showBlockCaretContainer:A,hideFakeCaret:I,destroy:H}}var q=g.isContentEditableTrue,r=g.isContentEditableFalse,s=c.isAfterContentEditableFalse,t=c.isBeforeContentEditableFalse;return p});g("6s",["e"],function(a){function b(b,c,d){for(var e=[];c&&c!=b;c=c.parentNode)e.push(a.nodeIndex(c,d));return
  e}function c(a,b){var c,d,e;for(d=a,c=b.length-1;c>=0;c--){if(e=d.childNodes,b[c]>e.length-1)return null;d=e[b[c]]}return d}return{create:b,resolve:c}}),g("66",["p","h","c","6s","i","d","6","9","5","1k","1n","4d"],function(a,b,c,d,e,f,g,h,i,j,k,l){return function(c){function d(a,b){try{c.getDoc().execCommand(a,!1,b)}catch(a){}}function m(){var a=c.getDoc().documentMode;return a?a:6}function n(a){return a.isDefaultPrevented()}function o(a){var b,d;a.dataTransfer&&(c.selection.isCollapsed()&&"IMG"==a.target.tagName&&_.select(a.target),b=c.selection.getContent(),b.length>0&&(d=ga+escape(c.id)+","+escape(b),a.dataTransfer.setData(ha,d)))}function p(a){var b;return a.dataTransfer&&(b=a.dataTransfer.getData(ha),b&&b.indexOf(ga)>=0)?(b=b.substr(ga.length).split(","),{id:un
 escape(b[0]),html:unescape(b[1])}):null}function q(a,b){c.queryCommandSupported("mceInsertClipboardContent")?c.execCommand("mceInsertClipboardContent",!1,{content:a,internal:b}):c.execCommand("mceInsertContent",!1,a)}function r(){function a(a){var b=$.create("body"),c=a.cloneContents();return b.appendChild(c),_.serializer.serialize(b,{format:"html"})}function d(d){if(!d.setStart){if(d.item)return!1;var e=d.duplicate();return e.moveToElementText(c.getBody()),b.compareRanges(d,e)}var f=a(d),g=$.createRng();g.selectNode(c.getBody());var h=a(g);return f===h}c.on("keydown",function(a){var b,e,f=a.keyCode;if(!n(a)&&(f==Z||f==Y)){if(b=c.selection.isCollapsed(),e=c.getBody(),b&&!$.isEmpty(e))return;if(!b&&!d(c.selection.getRng()))return;a.preventDefault(),c.setContent(""),e.firstChild&&$.isBlock(e.firstChild)?c.selection.setCursorLocation(e.firstChild,0):c.selection.setCursorLocation(e,0),c
 .nodeChanged()}})}function s(){c.shortcuts.add("meta+a",null,"SelectAll")}function t(){c.settings.content_editable||$.bind(c.getDoc(),"mousedown mouseup",function(a){var b;if(a.target==c.getDoc().documentElement)if(b=_.getRng(),c.getBody().focus(),"mousedown"==a.type){if(j.isCaretContainer(b.startContainer))return;_.placeCaretAt(a.clientX,a.clientY)}else _.setRng(b)})}function u(){c.on("keydown",function(a){if(!n(a)&&a.keyCode===Y){if(!c.getBody().getElementsByTagName("hr").length)return;if(_.isCollapsed()&&0===_.getRng(!0).startOffset){var b=_.getNode(),d=b.previousSibling;if("HR"==b.nodeName)return $.remove(b),void a.preventDefault();d&&d.nodeName&&"hr"===d.nodeName.toLowerCase()&&($.remove(d),a.preventDefault())}}})}function v(){window.Range.prototype.getClientRects||c.on("mousedown",function(a){
-if(!n(a)&&"HTML"===a.target.nodeName){var b=c.getBody();b.blur(),i.setEditorTimeout(c,function(){b.focus()})}})}function w(){c.on("click",function(a){var b=a.target;/^(IMG|HR)$/.test(b.nodeName)&&"false"!==$.getContentEditableParent(b)&&(a.preventDefault(),c.selection.select(b),c.nodeChanged()),"A"==b.nodeName&&$.hasClass(b,"mce-item-anchor")&&(a.preventDefault(),_.select(b))})}function x(){function a(){var a=$.getAttribs(_.getStart().cloneNode(!1));return function(){var b=_.getStart();b!==c.getBody()&&($.setAttrib(b,"style",null),X(a,function(a){b.setAttributeNode(a.cloneNode(!0))}))}}function b(){return!_.isCollapsed()&&$.getParent(_.getStart(),$.isBlock)!=$.getParent(_.getEnd(),$.isBlock)}c.on("keypress",function(d){var e;if(!n(d)&&(8==d.keyCode||46==d.keyCode)&&b())return e=a(),c.getDoc().execCommand("delete",!1,null),e(),d.preve
 ntDefault(),!1}),$.bind(c.getDoc(),"cut",function(d){var e;!n(d)&&b()&&(e=a(),i.setEditorTimeout(c,function(){e()}))})}function y(){document.body.setAttribute("role","application")}function z(){c.on("keydown",function(a){if(!n(a)&&a.keyCode===Y&&_.isCollapsed()&&0===_.getRng(!0).startOffset){var b=_.getNode().previousSibling;if(b&&b.nodeName&&"table"===b.nodeName.toLowerCase())return a.preventDefault(),!1}})}function A(){m()>7||(d("RespectVisibilityInDesign",!0),c.contentStyles.push(".mceHideBrInPre pre br {display: none}"),$.addClass(c.getBody(),"mceHideBrInPre"),ba.addNodeFilter("pre",function(a){for(var b,c,d,f,g=a.length;g--;)for(b=a[g].getAll("br"),c=b.length;c--;)d=b[c],f=d.prev,f&&3===f.type&&"\n"!=f.value.charAt(f.value-1)?f.value+="\n":d.parent.insert(new e("#text",3),d,!0
 ).value="\n"}),ca.addNodeFilter("pre",function(a){for(var b,c,d,e,f=a.length;f--;)for(b=a[f].getAll("br"),c=b.length;c--;)d=b[c],e=d.prev,e&&3==e.type&&(e.value=e.value.replace(/\r?\n$/,""))}))}function B(){$.bind(c.getBody(),"mouseup",function(){var a,b=_.getNode();"IMG"==b.nodeName&&((a=$.getStyle(b,"width"))&&($.setAttrib(b,"width",a.replace(/[^0-9%]+/g,"")),$.setStyle(b,"width","")),(a=$.getStyle(b,"height"))&&($.setAttrib(b,"height",a.replace(/[^0-9%]+/g,"")),$.setStyle(b,"height","")))})}function C(){c.on("keydown",function(b){var d,e,f,g,h;if(!n(b)&&b.keyCode==a.BACKSPACE&&(d=_.getRng(),e=d.startContainer,f=d.startOffset,g=$.getRoot(),h=e,d.collapsed&&0===f)){for(;h&&h.parentNode&&h.parentNode.firstChild==h&&h.parentNode!=
 g;)h=h.parentNode;"BLOCKQUOTE"===h.tagName&&(c.formatter.toggle("blockquote",null,h),d=$.createRng(),d.setStart(e,0),d.setEnd(e,0),_.setRng(d))}})}function D(){function a(){U(),d("StyleWithCSS",!1),d("enableInlineTableEditing",!1),aa.object_resizing||d("enableObjectResizing",!1)}aa.readonly||c.on("BeforeExecCommand MouseDown",a)}function E(){function a(){X($.select("a"),function(a){var b=a.parentNode,c=$.getRoot();if(b.lastChild===a){for(;b&&!$.isBlock(b);){if(b.parentNode.lastChild!==b||b===c)return;b=b.parentNode}$.add(b,"br",{"data-mce-bogus":1})}})}c.on("SetContent ExecCommand",function(b){"setcontent"!=b.type&&"mceInsertLink"!==b.command||a()})}function F(){aa.forced_root_block&&c.on("init",function(){d("DefaultParagraphSeparator",aa.forced_root_block)})}function G(){c.on("keydown",function(a){var b
 ;n(a)||a.keyCode!=Y||(b=c.getDoc().selection.createRange(),b&&b.item&&(a.preventDefault(),c.undoManager.beforeChange(),$.remove(b.item(0)),c.undoManager.add()))})}function H(){var a;m()>=10&&(a="",X("p div h1 h2 h3 h4 h5 h6".split(" "),function(b,c){a+=(c>0?",":"")+b+":empty"}),c.contentStyles.push(a+"{padding-right: 1px !important}"))}function I(){m()<9&&(ba.addNodeFilter("noscript",function(a){for(var b,c,d=a.length;d--;)b=a[d],c=b.firstChild,c&&b.attr("data-mce-innertext",c.value)}),ca.addNodeFilter("noscript",function(a){for(var b,c,d,g=a.length;g--;)b=a[g],c=a[g].firstChild,c?c.value=f.decode(c.value):(d=b.attributes.map["data-mce-innertext"],d&&(b.attr("data-mce-innertext",null),c=new e("#text",3),c.value=d,c.raw=!0,b.append(c)))}))}function J(){function a(a,b){var c=h.createTextRange();try{c.
 moveToPoint(a,b)}catch(a){c=null}return c}function b(b){var d;b.button?(d=a(b.x,b.y),d&&(d.compareEndPoints("StartToStart",e)>0?d.setEndPoint("StartToStart",e):d.setEndPoint("EndToEnd",e),d.select())):c()}function c(){var a=g.selection.createRange();e&&!a.item&&0===a.compareEndPoints("StartToEnd",a)&&e.select(),$.unbind(g,"mouseup",c),$.unbind(g,"mousemove",b),e=d=0}var d,e,f,g=$.doc,h=g.body;g.documentElement.unselectable=!0,$.bind(g,"mousedown contextmenu",function(h){if("HTML"===h.target.nodeName){if(d&&c(),f=g.documentElement,f.scrollHeight>f.clientHeight)return;d=1,e=a(h.x,h.y),e&&($.bind(g,"mouseup",c),$.bind(g,"mousemove",b),$.getRoot().focus(),e.select())}})}function K(){c.on("keyup focusin mouseup",function(b){65==b.keyCode&&a.metaKeyPressed(b)||_.normalize()},!0)}function L(){c.contentStyles.push("i
 mg:-moz-broken {-moz-force-broken-image-icon:1;min-width:24px;min-height:24px}")}function M(){c.inline||c.on("keydown",function(){document.activeElement==document.body&&c.getWin().focus()})}function N(){c.inline||(c.contentStyles.push("body {min-height: 150px}"),c.on("click",function(a){var b;if("HTML"==a.target.nodeName){if(g.ie>11)return void c.getBody().focus();b=c.selection.getRng(),c.getBody().focus(),c.selection.setRng(b),c.selection.normalize(),c.nodeChanged()}}))}function O(){g.mac&&c.on("keydown",function(b){!a.metaKeyPressed(b)||b.shiftKey||37!=b.keyCode&&39!=b.keyCode||(b.preventDefault(),c.selection.getSel().modify("move",37==b.keyCode?"backward":"forward","lineboundary"))})}function P(){d("AutoUrlDetect",!1)}function Q(){c.on("click",function(a){var b=a.target;do if("A"===b.tagName)return void a.preventDefault();while(b=
 b.parentNode)}),c.contentStyles.push(".mce-content-body {-webkit-touch-callout: none}")}function R(){c.on("init",function(){c.dom.bind(c.getBody(),"submit",function(a){a.preventDefault()})})}function S(){ba.addNodeFilter("br",function(a){for(var b=a.length;b--;)"Apple-interchange-newline"==a[b].attr("class")&&a[b].remove()})}function T(){c.on("dragstart",function(a){o(a)}),c.on("drop",function(a){if(!n(a)){var d=p(a);if(d&&d.id!=c.id){a.preventDefault();var e=b.getCaretRangeFromPoint(a.x,a.y,c.getDoc());_.setRng(e),q(d.html,!0)}}})}function U(){}function V(){var a;return!da||c.removed?0:(a=c.selection.getSel(),!a||!a.rangeCount||0===a.rangeCount)}function W(){function b(a){var b=new l(a.getBody()),c=a.selection.getRng(),d=k.fromRangeStart(c),e=k.fromRangeEnd(c),f=b.prev(d),g=b.next(e);return!a.selection.isCollapsed()&&(!f||f.isAtStart()&&d.isEqual(f))&&(!g||g.isAtE
 nd()&&d.isEqual(g))}c.on("keypress",function(d){!n(d)&&!_.isCollapsed()&&d.charCode>31&&!a.metaKeyPressed(d)&&b(c)&&(d.preventDefault(),c.setContent(String.fromCharCode(d.charCode)),c.selection.select(c.getBody(),!0),c.selection.collapse(!1),c.nodeChanged())}),c.on("keydown",function(a){var d=a.keyCode;n(a)||d!=Z&&d!=Y||b(c)&&(a.preventDefault(),c.setContent(""),c.nodeChanged())})}var X=h.each,Y=a.BACKSPACE,Z=a.DELETE,$=c.dom,_=c.selection,aa=c.settings,ba=c.parser,ca=c.serializer,da=g.gecko,ea=g.ie,fa=g.webkit,ga="data:text/mce-internal,",ha=ea?"Text":"URL";return C(),r(),g.windowsPhone||K(),fa&&(W(),t(),w(),F(),R(),z(),S(),g.iOS?(M(),N(),Q()):s()),ea&&g.ie<11&&(u(),y(),A(),B(),G(),H(),I(),J()),g.ie>=11&&(N(),z()),g.ie&&(s(),P(),T()),da&&(W(),u(),v(),x(),D(),E(),L(),O(),z()),{refreshContentEditable:U,isH
 idden:V}}}),g("5i",["1y","4k","60","e","s","o","61","26","62","t","l","i","j","63","64","65","u","5","66","9"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t){var u=d.DOM,v=function(a){var b=new k(a.settings,a.schema);return b.addAttributeFilter("src,href,style,tabindex",function(b,c){for(var d,e,f,g=b.length,h=a.dom;g--;)if(d=b[g],e=d.attr(c),f="data-mce-"+c,!d.attributes.map[f]){if(0===e.indexOf("data:")||0===e.indexOf("blob:"))continue;"style"===c?(e=h.serializeStyle(h.parseStyle(e),d.name),e.length||(e=null),d.attr(f,e),d.attr(c,e)):"tabindex"===c?(d.attr(f,e),d.attr(c,null)):d.attr(f,a.convertURL(e,c,d.name))}}),b.addNodeFilter("script",function(a){for(var b,c,d=a.length;d--;)b=a[d],c=b.attr("typ
 e")||"no/type",0!==c.indexOf("mce-")&&b.attr("type","mce-"+c)}),b.addNodeFilter("#cdata",function(a){for(var b,c=a.length;c--;)b=a[c],b.type=8,b.name="#comment",b.value="[CDATA["+b.value+"]]"}),b.addNodeFilter("p,h1,h2,h3,h4,h5,h6,div",function(b){for(var c,d=b.length,e=a.schema.getNonEmptyElements();d--;)c=b[d],c.isEmpty(e)&&0===c.getAll("br").length&&(c.append(new l("br",1)).shortEnded=!0)}),b},w=function(a){a.settings.auto_focus&&r.setEditorTimeout(a,function(){var b;b=a.settings.auto_focus===!0?a:a.editorManager.get(a.settings.auto_focus),b.destroyed||b.focus()},100)},x=function(a){a.bindPendingEventDelegates(),a.initialized=!0,a.fire("init"),a.focus(!0),a.nodeChanged({initial:!0}),a.execCallback("init_instance_callback",a),w(a)},y=function(k,l){var r,w,y=k.settings,z=k.getElement(),A=k.getDoc();y.inline||(k.getEle
 ment().style.visibility=k.orgVisibility),l||y.content_editable||(A.open(),A.write(k.iframeHTML),A.close()),y.content_editable&&(k.on("remove",function(){var a=this.getBody();u.removeClass(a,"mce-content-body"),u.removeClass(a,"mce-edit-focus"),u.setAttrib(a,"contentEditable",null)}),u.addClass(z,"mce-content-body"),k.contentDocument=A=y.content_document||a,k.contentWindow=y.content_window||b,k.bodyElement=z,y.content_document=y.content_window=null,y.root_name=z.nodeName.toLowerCase()),r=k.getBody(),r.disabled=!0,k.readonly=y.readonly,k.readonly||(k.inline&&"static"===u.getStyle(r,"position",!0)&&(r.style.position="relative"),r.contentEditable=k.getParam("content_editable_state",!0)),r.disabled=!1,k.editorUpload=new g(k),k.schema=new m(y),k.dom=new d(A,{keep_values:!0,url_converter:k.convertURL,url_converter_scope:k,hex_colors:y.force_hex_style_colors,class_filter:y.class
 _filter,update_styles:!0,root_element:k.inline?k.getBody():null,collect:y.content_editable,schema:k.schema,onSetAttrib:function(a){k.fire("SetAttrib",a)}}),k.parser=v(k),k.serializer=new f(y,k),k.selection=new e(k.dom,k.getWin(),k.serializer,k),k.formatter=new j(k),k.undoManager=new q(k),k._nodeChangeDispatcher=new o(k),k._selectionOverrides=new p(k),c.setup(k),n.setup(k),i.setup(k),k.fire("PreInit"),y.browser_spellcheck||y.gecko_spellcheck||(A.body.spellcheck=!1,u.setAttrib(r,"spellcheck","false")),k.quirks=new s(k),k.fire("PostRender"),y.directionality&&(r.dir=y.directionality),y.nowrap&&(r.style.whiteSpace="nowrap"),y.protect&&k.on("BeforeSetContent",function(a){t.each(y.protect,function(b){a.content=a.content.replace(b,function(a){return"<!--mce:protected "+escape(a)+"-->"})})}),k.on("SetContent",function(){k.addVisual(k.getBody())}),y.padd_empty_edit
 or&&k.on("PostProcess",function(a){a.content=a.content.replace(/^(<p[^>]*>(&nbsp;|&#160;|\s|\u00a0|<br \/>|)<\/p>[\r\n]*|<br \/>[\r\n]*)$/,"")}),k.load({initial:!0,format:"html"}),k.startContent=k.getContent({format:"raw"}),k.on("compositionstart compositionend",function(a){k.composing="compositionstart"===a.type}),k.contentStyles.length>0&&(w="",t.each(k.contentStyles,function(a){w+=a+"\r\n"}),k.dom.addStyle(w)),k.dom.styleSheetLoader.loadAll(k.contentCSS,function(a){x(k)},function(a){x(k),h.contentCssError(k,a)})};return{initContentBody:y}}),g("4m",["g"],function(a){return a.PluginManager}),g("4n",["g"],function(a){return a.ThemeManager}),g("4l",["1y","4k","e","6","5i","4m","4n","9","25"],function(a,b,c,d,e,f,g,
 h,i){var j=c.DOM,k=function(a,b,c){var d,e,g=f.get(c);if(d=f.urls[c]||a.documentBaseUrl.replace(/\/$/,""),c=h.trim(c),g&&h.inArray(b,c)===-1){if(h.each(f.dependencies(c),function(c){k(a,b,c)}),a.plugins[c])return;e=new g(a,d,a.$),a.plugins[c]=e,e.init&&(e.init(a,d),b.push(c))}},l=function(a){var b=[];h.each(a.settings.plugins.replace(/\-/g,"").split(/[ ,]/),function(c){k(a,b,c)})},m=function(a){var b,c=a.settings;c.theme&&("function"!=typeof c.theme?(c.theme=c.theme.replace(/-/,""),b=g.get(c.theme),a.theme=new b(a,g.urls[c.theme]),a.theme.init&&a.theme.init(a,g.urls[c.theme]||a.documentBaseUrl.replace(/\/$/,""),a.$)):a.theme=c.theme)},n=function(a){var b,c,d,e,f,g=a.settings,h=a.getElement();return g.render_ui&&a.theme&&(a.orgDisplay=h.style.display,"function"!=typeof g.theme?(b=g.width||j.getStyle(h,"width")||"100%",c=g.height||j.getStyle(h,"height&qu
 ot;)||h.offsetHeight,d=g.min_height||100,e=/^[0-9\.]+(|px)$/i,e.test(""+b)&&(b=Math.max(parseInt(b,10),100)),e.test(""+c)&&(c=Math.max(parseInt(c,10),d)),f=a.theme.renderUI({targetNode:h,width:b,height:c,deltaWidth:g.delta_width,deltaHeight:g.delta_height}),g.content_editable||(c=(f.iframeHeight||c)+("number"==typeof c?f.deltaHeight||0:""),c<d&&(c=d))):(f=g.theme(a,h),f.editorContainer.nodeType&&(f.editorContainer.id=f.editorContainer.id||a.id+"_parent"),f.iframeContainer.nodeType&&(f.iframeContainer.id=f.iframeContainer.id||a.id+"_iframecontainer"),c=f.iframeHeight||h.offsetHeight),a.editorContainer=f.editorContainer,f.height=c),f},o=function(c,f){if(a.domain!==b.location.hostname&&d.ie&&d.ie<12){var g=i.uuid("mce");c[g]=function(){e.initContentBody(c)};var h='javascript:(function(){document.open();document.domain="'+a.domain+'";var ed = wind
 ow.parent.tinymce.get("'+c.id+'");document.write(ed.iframeHTML);document.close();ed.'+g+"(true);})()";return j.setAttrib(f,"src",h),!0}return!1},p=function(a,b){var c,e,f=a.settings;a.iframeHTML=f.doctype+"<html><head>",f.document_base_url!=a.documentBaseUrl&&(a.iframeHTML+='<base href="'+a.documentBaseURI.getURI()+'" />'),!d.caretAfter&&f.ie7_compat&&(a.iframeHTML+='<meta http-equiv="X-UA-Compatible" content="IE=7" />'),a.iframeHTML+='<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />',c=f.body_id||"tinymce",c.indexOf("=")!=-1&&(c=a.getParam("body_id","","hash"),c=c[a.id]||c),e=f.body_class||"",e.indexOf("=")!=-1&&(e=a.getParam("body_class","","hash"),e=e[a.id]||""),f.content_security_policy&&a
 mp;(a.iframeHTML+='<meta http-equiv="Content-Security-Policy" content="'+f.content_security_policy+'" />'),a.iframeHTML+='</head><body id="'+c+'" class="mce-content-body '+e+'" data-id="'+a.id+'"><br></body></html>';var g=j.create("iframe",{id:a.id+"_ifr",frameBorder:"0",allowTransparency:"true",title:a.editorManager.translate("Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help"),style:{width:"100%",height:b.height,display:"block"}});g.onload=function(){g.onload=null,a.fire("load")};var h=o(a,g);return a.contentAreaContainer=b.iframeContainer,a.iframeElement=g,j.add(b.iframeContainer,g),h},q=function(a){var b,c=a.settings,d=a.getElement();if(a.rtl=c.rtl_ui||a.editorManager.i18n.rtl,a.editorManager.i18n.setCode(c.language),c.aria_label=c.aria_label||j.getAttrib(d,"aria-label"
 ,a.getLang("aria.rich_text_area")),a.fire("ScriptsLoaded"),m(a),l(a),b=n(a),c.content_css&&h.each(h.explode(c.content_css),function(b){a.contentCSS.push(a.documentBaseURI.toAbsolute(b))}),c.content_style&&a.contentStyles.push(c.content_style),c.content_editable)return e.initContentBody(a);var f=p(a,b);b.editorContainer&&(j.get(b.editorContainer).style.display=a.orgDisplay,a.hidden=j.isHidden(b.editorContainer)),a.getElement().style.display="none",j.setAttrib(a.id,"aria-hidden",!0),f||e.initContentBody(a)};return{init:q}}),g("22",["4k","e","7","f","6","26","4l","11","4m","4n","9","10"],function(a,b,c,d,e,f,g,h,i,j,k,l){var m=b.DOM,n=function(a,b){var c=a.settings,e=d.ScriptLoader;if(c.language&&"en"!=c.language&&!c.language_url&&(c.language_url=a.editorManager
 .baseURL+"/langs/"+c.language+".js"),c.language_url&&e.add(c.language_url),c.theme&&"function"!=typeof c.theme&&"-"!=c.theme.charAt(0)&&!j.urls[c.theme]){var h=c.theme_url;h=h?a.documentBaseURI.toAbsolute(h):"themes/"+c.theme+"/theme"+b+".js",j.load(c.theme,h)}k.isArray(c.plugins)&&(c.plugins=c.plugins.join(" ")),k.each(c.external_plugins,function(a,b){i.load(b,a),c.plugins+=" "+b}),k.each(c.plugins.split(/[ ,]/),function(a){if(a=k.trim(a),a&&!i.urls[a])if("-"===a.charAt(0)){a=a.substr(1,a.length);var c=i.dependencies(a);k.each(c,function(a){var c={prefix:"plugins/",resource:a,suffix:"/plugin"+b+".js"};a=i.createUrl(c,a),i.load(a.resource,a)})}else i.load(a,{prefix:"plugins/",resource:a,suffix:"/plugin"+b+".js"})}),e.loadQueue(function(){a.removed||g.init(a)},a,function(b){f.plu
 ginLoadError(a,b[0]),a.removed||g.init(a)})},o=function(b){function d(){m.unbind(a,"ready",d),b.render()}var f=b.settings,g=b.id;if(!c.Event.domLoaded)return void m.bind(a,"ready",d);if(b.getElement()&&e.contentEditable){f.inline?b.inline=!0:(b.orgVisibility=b.getElement().style.visibility,b.getElement().style.visibility="hidden");var i=b.getElement().form||m.getParent(g,"form");i&&(b.formElement=i,f.hidden_input&&!/TEXTAREA|INPUT/i.test(b.getElement().nodeName)&&(m.insertAfter(m.create("input",{type:"hidden",name:g}),g),b.hasHiddenInput=!0),b.formEventDelegate=function(a){b.fire(a.type,a)},m.bind(i,"submit reset",b.formEventDelegate),b.on("reset",function(){b.setContent(b.startContent,{format:"raw"})}),!f.submit_patch||i.submit.nodeType||i.submit.length||i._mceOldSubmit||(i._mceOldSubmit=i.submit,i.submit=function(){return b.editorManager.triggerSave(),b.setDirt
 y(!1),i._mceOldSubmit(i)})),b.windowManager=new l(b),b.notificationManager=new h(b),"xml"===f.encoding&&b.on("GetContent",function(a){a.save&&(a.content=m.encode(a.content))}),f.add_form_submit_trigger&&b.on("submit",function(){b.initialized&&b.save()}),f.add_unload_trigger&&(b._beforeUnload=function(){!b.initialized||b.destroyed||b.isHidden()||b.save({format:"raw",no_events:!0,set_dirty:!1})},b.editorManager.on("BeforeUnload",b._beforeUnload)),b.editorManager.add(b),n(b,b.suffix)}};return{render:o}}),g("23",[],function(){function a(a,b,c){try{a.getDoc().execCommand(b,!1,c)}catch(a){}}function b(a){var b,c;return b=a.getBody(),c=function(b){a.dom.getParents(b.target,"a").length>0&&b.preventDefault()},a.dom.bind(b,"click",c),{unbind:function(){a.dom.unbind(b,"click",c)}}}function c(c,d){c._clickBlocker&&(c._clickBlocker.unbind(),c._click
 Blocker=null),d?(c._clickBlocker=b(c),c.selection.controlSelection.hideResizeRect(),c.readonly=!0,c.getBody().contentEditable=!1):(c.readonly=!1,c.getBody().contentEditable=!0,a(c,"StyleWithCSS",!1),a(c,"enableInlineTableEditing",!1),a(c,"enableObjectResizing",!1),c.focus(),c.nodeChanged())}function d(a,b){var d=a.readonly?"readonly":"design";b!=d&&(a.initialized?c(a,"readonly"==b):a.on("init",function(){c(a,"readonly"==b)}),a.fire("SwitchMode",{mode:b}))}return{setMode:d}}),g("24",[],function(){var a=function(a,b,c){var d=a.sidebars?a.sidebars:[];d.push({name:b,settings:c}),a.sidebars=d};return{add:a}}),g("14",["g","a","e","v","12","6","n","22","23","13","24","9","w","25"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n){function o(c,e,g){
 var h,i,k,l=this;h=l.documentBaseUrl=g.documentBaseURL,i=g.baseURI,k=g.defaultSettings,e=q({id:c,theme:"modern",delta_width:0,delta_height:0,popup_css:"",plugins:"",document_base_url:h,add_form_submit_trigger:!0,submit_patch:!0,add_unload_trigger:!0,convert_urls:!0,relative_urls:!0,remove_script_host:!0,object_resizing:!0,doctype:"<!DOCTYPE html>",visual:!0,font_size_style_values:"xx-small,x-small,small,medium,large,x-large,xx-large",font_size_legacy_values:"xx-small,small,medium,large,x-large,xx-large,300%",forced_root_block:"p",hidden_input:!0,padd_empty_editor:!0,render_ui:!0,indentation:"30px",inline_styles:!0,convert_fonts_to_spans:!0,indent:"simple",indent_before:"p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,tfoot,tbody,tr,section,article,hgroup,aside,figure,figcaption,option,optgroup,datalist",indent_after:"p,h1,h
 2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,tfoot,tbody,tr,section,article,hgroup,aside,figure,figcaption,option,optgroup,datalist",validate:!0,entity_encoding:"named",url_converter:l.convertURL,url_converter_scope:l,ie7_compat:!0},k,e),k&&k.external_plugins&&e.external_plugins&&(e.external_plugins=q({},k.external_plugins,e.external_plugins)),l.settings=e,a.language=e.language||"en",a.languageLoad=e.language_load,a.baseURL=g.baseURL,l.id=e.id=c,l.setDirty(!1),l.plugins={},l.documentBaseURI=new m(e.document_base_url||h,{base_uri:i}),l.baseURI=i,l.contentCSS=[],l.contentStyles=[],l.shortcuts=new j(l),l.loadedCSS={},l.editorCommands=new d(l),l.suffix=g.suffix,l.editorManager=g,l.inline=e.inline,l.settings.content_editable=l.inline,e.cache_suffix&&(f.cacheSuffix=e.cache_suffix.replace(/^[\?\&]+/,"")),e.override_viewport===!1&&(f.overrideViewPort=!1),g.fire(&quo
 t;SetupEditor",l),l.execCallback("setup",l),l.$=b.overrideDefaults(function(){return{context:l.inline?l.getBody():l.getDoc(),element:l.getBody()}})}var p=c.DOM,q=l.extend,r=l.each,s=l.trim,t=l.resolve,u=f.gecko,v=f.ie;return o.prototype={render:function(){h.render(this)},focus:function(a){function b(a){return g.dom.getParent(a,function(a){return"true"===g.dom.getContentEditable(a)})}var c,d,e,g=this,h=g.selection,i=g.settings.content_editable,j=g.getDoc(),k=g.getBody();if(!g.removed){if(!a){if(c=h.getRng(),c.item&&(d=c.item(0)),g.quirks.refreshContentEditable(),e=b(h.getNode()),g.$.contains(k,e))return e.focus(),h.normalize(),void g.editorManager.setActive(g);if(i||(f.opera||g.getBody().focus(),g.getWin().focus()),u||i){if(k.setActive)try{k.setActive()}catch(a){k.focus()}else k.focus();i&&h.normalize()}d&&d.ownerDocument==j&&(c=j.body.createControlRange(),c.addElement(d),c.select())}g.editorManager.setActive(g)}},execCallback:
 function(a){var b,c=this,d=c.settings[a];if(d)return c.callbackLookup&&(b=c.callbackLookup[a])&&(d=b.func,b=b.scope),"string"==typeof d&&(b=d.replace(/\.\w+$/,""),b=b?t(b):0,d=t(d),c.callbackLookup=c.callbackLookup||{},c.callbackLookup[a]={func:d,scope:b}),d.apply(b||c,Array.prototype.slice.call(arguments,1))},translate:function(a){var b=this.settings.language||"en",c=this.editorManager.i18n;return a?(a=c.data[b+"."+a]||a.replace(/\{\#([^\}]+)\}/g,function(a,d){return c.data[b+"."+d]||"{#"+d+"}"}),this.editorManager.translate(a)):""},getLang:function(a,b){return this.editorManager.i18n.data[(this.settings.language||"en")+"."+a]||(void 0!==b?b:"{#"+a+"}")},getParam:function(a,b,c){var d,e=a in this.settings?this.settings[a]:b;return"hash"===c?(d={},"string"==typeof e?r(e.indexOf("=")>0?e.split(/[;,](?![^=;,]*(
 ?:[;,]|$))/):e.split(","),function(a){a=a.split("="),a.length>1?d[s(a[0])]=s(a[1]):d[s(a[0])]=s(a)}):d=e,d):e},nodeChanged:function(a){this._nodeChangeDispatcher.nodeChanged(a)},addButton:function(a,b){var c=this;b.cmd&&(b.onclick=function(){c.execCommand(b.cmd)}),b.text||b.icon||(b.icon=a),c.buttons=c.buttons||{},b.tooltip=b.tooltip||b.title,c.buttons[a]=b},addSidebar:function(a,b){return k.add(this,a,b)},addMenuItem:function(a,b){var c=this;b.cmd&&(b.onclick=function(){c.execCommand(b.cmd)}),c.menuItems=c.menuItems||{},c.menuItems[a]=b},addContextToolbar:function(a,b){var c,d=this;d.contextToolbars=d.contextToolbars||[],"string"==typeof a&&(c=a,a=function(a){return d.dom.is(a,c)}),d.contextToolbars.push({id:n.uuid("mcet"),predicate:a,items:b})},addCommand:function(a,b,c){this.editorCommands.addCommand(a,b,c)},addQueryStateHandler:function(a,b,c){this.editorCommands.addQueryStateHandler(a,b,c)},addQueryValueHandler:
 function(a,b,c){this.editorCommands.addQueryValueHandler(a,b,c)},addShortcut:function(a,b,c,d){this.shortcuts.add(a,b,c,d)},execCommand:function(a,b,c,d){return this.editorCommands.execCommand(a,b,c,d)},queryCommandState:function(a){return this.editorCommands.queryCommandState(a)},queryCommandValue:function(a){return this.editorCommands.queryCommandValue(a)},queryCommandSupported:function(a){return this.editorCommands.queryCommandSupported(a)},show:function(){var a=this;a.hidden&&(a.hidden=!1,a.inline?a.getBody().contentEditable=!0:(p.show(a.getContainer()),p.hide(a.id)),a.load(),a.fire("show"))},hide:function(){var a=this,b=a.getDoc();a.hidden||(v&&b&&!a.inline&&b.execCommand("SelectAll"),a.save(),a.inline?(a.getBody().contentEditable=!1,a==a.editorManager.focusedEditor&&(a.editorManager.focusedEditor=null)):(p.hide(a.getContainer()),p.setStyle(a.id,"display",a.orgDisplay)),a.hidden=!0,a.fire("hide"))},
 isHidden:function(){return!!this.hidden},setProgressState:function(a,b){this.fire("ProgressState",{state:a,time:b})},load:function(a){var b,c=this,d=c.getElement();return c.removed?"":d?(a=a||{},a.load=!0,b=c.setContent(void 0!==d.value?d.value:d.innerHTML,a),a.element=d,a.no_events||c.fire("LoadContent",a),a.element=d=null,b):void 0},save:function(a){var b,c,d=this,e=d.getElement();if(e&&d.initialized&&!d.removed)return a=a||{},a.save=!0,a.element=e,b=a.content=d.getContent(a),a.no_events||d.fire("SaveContent",a),"raw"==a.format&&d.fire("RawSaveContent",a),b=a.content,/TEXTAREA|INPUT/i.test(e.nodeName)?e.value=b:(d.inline||(e.innerHTML=b),(c=p.getParent(d.id,"form"))&&r(c.elements,function(a){if(a.name==d.id)return a.value=b,!1})),a.element=e=null,a.set_dirty!==!1&&d.setDirty(!1),b},setContent:function(a,b){var c,d,e=this,f=e.getBody();return b=b||{},b.format=b.format||&quo
 t;html",b.set=!0,b.content=a,b.no_events||e.fire("BeforeSetContent",b),a=b.content,0===a.length||/^\s+$/.test(a)?(d=v&&v<11?"":'<br data-mce-bogus="1">',"TABLE"==f.nodeName?a="<tr><td>"+d+"</td></tr>":/^(UL|OL)$/.test(f.nodeName)&&(a="<li>"+d+"</li>"),c=e.settings.forced_root_block,c&&e.schema.isValidChild(f.nodeName.toLowerCase(),c.toLowerCase())?(a=d,a=e.dom.createHTML(c,e.settings.forced_root_block_attrs,a)):v||a||(a='<br data-mce-bogus="1">'),e.dom.setHTML(f,a),e.fire("SetContent",b)):("raw"!==b.format&&(a=new g({validate:e.validate},e.schema).serialize(e.parser.parse(a,{isRootContent:!0}))),b.content=s(a),e.dom.setHTML(f,b.content),b.no_events||e.fire("SetContent",b)),b.content},getContent:function(a){var b,c=this,d=c.getBody();return c.removed?"":(a=a||{},a.forma
 t=a.format||"html",a.get=!0,a.getInner=!0,a.no_events||c.fire("BeforeGetContent",a),b="raw"==a.format?l.trim(c.serializer.getTrimmedContent()):"text"==a.format?d.innerText||d.textContent:c.serializer.serialize(d,a),"text"!=a.format?a.content=s(b):a.content=b,a.no_events||c.fire("GetContent",a),a.content)},insertContent:function(a,b){b&&(a=q({content:a},b)),this.execCommand("mceInsertContent",!1,a)},isDirty:function(){return!this.isNotDirty},setDirty:function(a){var b=!this.isNotDirty;this.isNotDirty=!a,a&&a!=b&&this.fire("dirty")},setMode:function(a){i.setMode(this,a)},getContainer:function(){var a=this;return a.container||(a.container=p.get(a.editorContainer||a.id+"_parent")),a.container},getContentAreaContainer:function(){return this.contentAreaContainer},getElement:function(){return this.targetElm||(this.targetElm=p.get(this.id)),this.targetElm},getWin:function(){var 
 a,b=this;return b.contentWindow||(a=b.iframeElement,a&&(b.contentWindow=a.contentWindow)),b.contentWindow},getDoc:function(){var a,b=this;return b.contentDocument||(a=b.getWin(),a&&(b.contentDocument=a.document)),b.contentDocument},getBody:function(){var a=this.getDoc();return this.bodyElement||(a?a.body:null)},convertURL:function(a,b,c){var d=this,e=d.settings;return e.urlconverter_callback?d.execCallback("urlconverter_callback",a,c,!0,b):!e.convert_urls||c&&"LINK"==c.nodeName||0===a.indexOf("file:")||0===a.length?a:e.relative_urls?d.documentBaseURI.toRelative(a):a=d.documentBaseURI.toAbsolute(a,e.remove_script_host)},addVisual:function(a){var b,c=this,d=c.settings,e=c.dom;a=a||c.getBody(),void 0===c.hasVisual&&(c.hasVisual=d.visual),r(e.select("table,a",a),function(a){var f;switch(a.nodeName){case"TABLE":return b=d.visual_table_class||"mce-item-table",f=e.getAttrib(a,"border"),voi
 d(f&&"0"!=f||!c.hasVisual?e.removeClass(a,b):e.addClass(a,b));case"A":return void(e.getAttrib(a,"href",!1)||(f=e.getAttrib(a,"name")||a.id,b=d.visual_anchor_class||"mce-item-anchor",f&&c.hasVisual?e.addClass(a,b):e.removeClass(a,b)))}}),c.fire("VisualAid",{element:a,hasVisual:c.hasVisual})},remove:function(){var a=this;a.removed||(a.save(),a.removed=1,a.unbindAllNativeEvents(),a.hasHiddenInput&&p.remove(a.getElement().nextSibling),a.inline||(v&&v<10&&a.getDoc().execCommand("SelectAll",!1,null),p.setStyle(a.id,"display",a.orgDisplay),a.getBody().onload=null),a.fire("remove"),a.editorManager.remove(a),p.remove(a.getContainer()),a._selectionOverrides.destroy(),a.editorUpload.destroy(),a.destroy())},destroy:function(a){var b,c=this;if(!c.destroyed){if(!a&&!c.removed)return void c.remove();a||(c.editorManager.off("beforeunload",c._beforeUn
 load),c.theme&&c.theme.destroy&&c.theme.destroy(),c.selection.destroy(),c.dom.destroy()),b=c.formElement,b&&(b._mceOldSubmit&&(b.submit=b._mceOldSubmit,b._mceOldSubmit=null),p.unbind(b,"submit reset",c.formEventDelegate)),c.contentAreaContainer=c.formElement=c.container=c.editorContainer=null,c.bodyElement=c.contentDocument=c.contentWindow=null,c.iframeElement=c.targetElm=null,c.selection&&(c.selection=c.selection.win=c.selection.dom=c.selection.dom.doc=null),c.destroyed=1}},uploadImages:function(a){return this.editorUpload.uploadImages(a)},_scanForImages:function(){return this.editorUpload.scanForImages()}},q(o.prototype,e),o}),g("15",["9"],function(a){"use strict";var b={},c="en";return{setCode:function(a){a&&(c=a,this.rtl=!!this.data[a]&&"rtl"===this.data[a]._dir)},getCode:function(){return c},rtl:!1,add:function(a,c){var d=b[a];d||(b[a]=d={});for(var e in c)d[e]=c[
 e];this.setCode(a)},translate:function(d){function e(b){return a.is(b,"function")?Object.prototype.toString.call(b):f(b)?"":""+b}function f(b){return""===b||null===b||a.is(b,"undefined")}function g(b){return b=e(b),a.hasOwn(h,b)?e(h[b]):b}var h=b[c]||{};if(f(d))return"";if(a.is(d,"object")&&a.hasOwn(d,"raw"))return e(d.raw);if(a.is(d,"array")){var i=d.slice(1);d=g(d[0]).replace(/\{([0-9]+)\}/g,function(b,c){return a.hasOwn(i,c)?e(i[c]):b})}return g(d).replace(/{context:\w+}$/,"")},data:b}}),g("16",["e","5","6"],function(a,b,c){function d(a){function d(){try{return document.activeElement}catch(a){return document.body}}function j(a,b){if(b&&b.startContainer){if(!a.isChildOf(b.startContainer,a.getRoot())||!a.isChildOf(b.endContainer,a.getRoot()))return;return{startContainer:b.startContainer,startOffset:b.startOffset,endContainer:b.e
 ndContainer,endOffset:b.endOffset}}return b}function l(a,b){var c;return b.startContainer?(c=a.getDoc().createRange(),c.setStart(b.startContainer,b.startOffset),c.setEnd(b.endContainer,b.endOffset)):c=b,c}function m(m){var n=m.editor;n.on("init",function(){(n.inline||c.ie)&&("onbeforedeactivate"in document&&c.ie<9?n.dom.bind(n.getBody(),"beforedeactivate",function(a){if(a.target==n.getBody())try{n.lastRng=n.selection.getRng()}catch(a){}}):n.on("nodechange mouseup keyup",function(a){var b=d();"nodechange"==a.type&&a.selectionChange||(b&&b.id==n.id+"_ifr"&&(b=n.getBody()),n.dom.isChildOf(b,n.getBody())&&(n.lastRng=n.selection.getRng()))}),c.webkit&&!e&&(e=function(){var b=a.activeEditor;if(b&&b.selection){var c=b.selection.getRng();c&&!c.collapsed&&(n.lastRng=c)}},h.bind(document,"selectionchange",e)))}),n.on("setcontent&
 quot;,function(){n.lastRng=null}),n.on("mousedown",function(){n.selection.lastFocusBookmark=null}),n.on("focusin",function(){var b,c=a.focusedEditor;n.selection.lastFocusBookmark&&(b=l(n,n.selection.lastFocusBookmark),n.selection.lastFocusBookmark=null,n.selection.setRng(b)),c!=n&&(c&&c.fire("blur",{focusedEditor:n}),a.setActive(n),a.focusedEditor=n,n.fire("focus",{blurredEditor:c}),n.focus(!0)),n.lastRng=null}),n.on("focusout",function(){b.setEditorTimeout(n,function(){var b=a.focusedEditor;i(n,d())||b!=n||(n.fire("blur",{focusedEditor:null}),a.focusedEditor=null,n.selection&&(n.selection.lastFocusBookmark=null))})}),f||(f=function(b){var c,d=a.activeEditor;c=b.target,d&&c.ownerDocument===document&&(d.selection&&c!==d.getBody()&&k(n,c)&&(d.selection.lastFocusBookmark=j(d.dom,d.lastRng)),c===document.body||i(d,c)||a.focusedEditor!==d||(d.fire("blur
 ",{focusedEditor:null}),a.focusedEditor=null))},h.bind(document,"focusin",f)),n.inline&&!g&&(g=function(b){var c=a.activeEditor,d=c.dom;if(c.inline&&d&&!d.isChildOf(b.target,c.getBody())){var e=c.selection.getRng();e.collapsed||(c.lastRng=e)}},h.bind(document,"mouseup",g));
-}function n(b){a.focusedEditor==b.editor&&(a.focusedEditor=null),a.activeEditor||(h.unbind(document,"selectionchange",e),h.unbind(document,"focusin",f),h.unbind(document,"mouseup",g),e=f=g=null)}a.on("AddEditor",m),a.on("RemoveEditor",n)}var e,f,g,h=a.DOM,i=function(a,b){var c=a?a.settings.custom_ui_selector:"",e=h.getParent(b,function(b){return d.isEditorUIElement(b)||!!c&&a.dom.is(b,c)});return null!==e},j=function(a){return a.inline===!0},k=function(a,b){return j(a)===!1||a.dom.isChildOf(b,a.getBody())===!1};return d.isEditorUIElement=function(a){return a.className.toString().indexOf("mce-")!==-1},d._isUIElement=i,d}),g("27",["9"],function(a){var b=a.each,c=a.explode,d=function(a){a.on("AddEditor",function(a){var d=a.editor;d.on("preInit",function(){function a(a,c){b(c,function(b,c){b&&h.setStyle(a,c,b)}),h.rename(a,"span")}function e(a){
 h=d.dom,i.convert_fonts_to_spans&&b(h.select("font,u,strike",a.node),function(a){f[a.nodeName.toLowerCase()](h,a)})}var f,g,h,i=d.settings;i.inline_styles&&(g=c(i.font_size_legacy_values),f={font:function(b,c){a(c,{backgroundColor:c.style.backgroundColor,color:c.color,fontFamily:c.face,fontSize:g[parseInt(c.size,10)-1]})},u:function(b,c){"html4"===d.settings.schema&&a(c,{textDecoration:"underline"})},strike:function(b,c){a(c,{textDecoration:"line-through"})}},d.on("PreProcess SetContent",e))})})};return{register:d}}),g("17",["g","a","e","14","6","26","16","27","15","z","4","9","w"],function(a,b,c,d,e,f,g,h,i,j,k,l,m){function n(a){v(s.editors,function(b){"scroll"===a.type?b.fire("ScrollWindow",a):b.fire("ResizeWindow",a)})}function o(a,c){c!==
 y&&(c?b(window).on("resize scroll",n):b(window).off("resize scroll",n),y=c)}function p(a){var b,c=s.editors;delete c[a.id];for(var d=0;d<c.length;d++)if(c[d]==a){c.splice(d,1),b=!0;break}return s.activeEditor==a&&(s.activeEditor=c[0]),s.focusedEditor==a&&(s.focusedEditor=null),b}function q(a){return a&&a.initialized&&!(a.getContainer()||a.getBody()).parentNode&&(p(a),a.unbindAllNativeEvents(),a.destroy(!0),a.removed=!0,a=null),a}var r,s,t=c.DOM,u=l.explode,v=l.each,w=l.extend,x=0,y=!1;return s={$:b,majorVersion:"4",minorVersion:"6.3",releaseDate:"2017-05-30",editors:[],i18n:i,activeEditor:null,setup:function(){var a,b,c,d,e=this,f="";if(b=m.getDocumentBaseUrl(document.location),/^[^:]+:\/\/\/?[^\/]+\//.test(b)&&(b=b.replace(/[\?#].*$/,"").replace(/[\/\\][^\/]+$/,""),/[\/\\]$/.test(b)||(b+="/")),c=window.tinymce||window.tinyMCEPreInit)a=
 c.base||c.baseURL,f=c.suffix;else{for(var h=document.getElementsByTagName("script"),i=0;i<h.length;i++){d=h[i].src;var j=d.substring(d.lastIndexOf("/"));if(/tinymce(\.full|\.jquery|)(\.min|\.dev|)\.js/.test(d)){j.indexOf(".min")!=-1&&(f=".min"),a=d.substring(0,d.lastIndexOf("/"));break}}!a&&document.currentScript&&(d=document.currentScript.src,d.indexOf(".min")!=-1&&(f=".min"),a=d.substring(0,d.lastIndexOf("/")))}e.baseURL=new m(b).toAbsolute(a),e.documentBaseURL=b,e.baseURI=new m(e.baseURL),e.suffix=f,e.focusManager=new g(e)},overrideDefaults:function(b){var c,d;c=b.base_url,c&&(this.baseURL=new m(this.documentBaseURL).toAbsolute(c.replace(/\/+$/,"")),this.baseURI=new m(this.baseURL)),d=b.suffix,b.suffix&&(this.suffix=d),this.defaultSettings=b;var e=b.plugin_base_urls;for(var f in e)a.PluginManager.urls[f]=e[f]},init:function(a){function c(a,b
 ){return a.inline&&b.tagName.toLowerCase()in o}function g(a){var b=a.id;return b||(b=a.name,b=b&&!t.get(b)?a.name:t.uniqueId(),a.setAttribute("id",b)),b}function h(b){var c=a[b];if(c)return c.apply(p,Array.prototype.slice.call(arguments,2))}function i(a,b){return b.constructor===RegExp?b.test(a.className):t.hasClass(a,b)}function j(a){var b,c=[];if(e.ie&&e.ie<11)return f.initError("TinyMCE does not support the browser you are using. For a list of supported browsers please see: https://www.tinymce.com/docs/get-started/system-requirements/"),[];if(a.types)return v(a.types,function(a){c=c.concat(t.select(a.selector))}),c;if(a.selector)return t.select(a.selector);if(a.target)return[a.target];switch(a.mode){case"exact":b=a.elements||"",b.length>0&&v(u(b),function(a){var b;(b=t.get(a))?c.push(b):v(document.forms,function(b){v(b.elements,function(b){b.name===a&&(a="mce_editor_"+x++,t.setAttrib(b
 ,"id",a),c.push(b))})})});break;case"textareas":case"specific_textareas":v(t.select("textarea"),function(b){a.editor_deselector&&i(b,a.editor_deselector)||a.editor_selector&&!i(b,a.editor_selector)||c.push(b)})}return c}function m(){function e(a,b,c){var e=new d(a,b,p);n.push(e),e.on("init",function(){++k===i.length&&r(n)}),e.targetElm=e.targetElm||c,e.render()}var i,k=0,n=[];return t.unbind(window,"ready",m),h("onpageload"),i=b.unique(j(a)),a.types?void v(a.types,function(b){l.each(i,function(c){return!t.is(c,b.selector)||(e(g(c),w({},a,b),c),!1)})}):(l.each(i,function(a){q(p.get(a.id))}),i=l.grep(i,function(a){return!p.get(a.id)}),void(0===i.length?r([]):v(i,function(b){c(a,b)?f.initError("Could not initialize inline editor on invalid inline target element",b):e(g(b),a,b)})))}var n,o,p=this;o=l.makeMap("area base basefont br col frame hr img input isindex link meta param em
 bed source wbr track colgroup option tbody tfoot thead tr script noscript style textarea video audio iframe object menu"," ");var r=function(a){n=a};return p.settings=a,t.bind(window,"ready",m),new k(function(a){n?a(n):r=function(b){a(b)}})},get:function(a){return arguments.length?a in this.editors?this.editors[a]:null:this.editors},add:function(a){var b=this,c=b.editors;return c[a.id]=a,c.push(a),o(c,!0),b.activeEditor=a,b.fire("AddEditor",{editor:a}),r||(r=function(){b.fire("BeforeUnload")},t.bind(window,"beforeunload",r)),a},createEditor:function(a,b){return this.add(new d(a,b,this))},remove:function(a){var b,c,d=this,e=d.editors;{if(a)return"string"==typeof a?(a=a.selector||a,void v(t.select(a),function(a){c=e[a.id],c&&d.remove(c)})):(c=a,e[c.id]?(p(c)&&d.fire("RemoveEditor",{editor:c}),e.length||t.unbind(window,"beforeunload",r),c.remove(),o(e,e.length>0),c):null);for(b=e.len
 gth-1;b>=0;b--)d.remove(e[b])}},execCommand:function(a,b,c){var e=this,f=e.get(c);switch(a){case"mceAddEditor":return e.get(c)||new d(c,e.settings,e).render(),!0;case"mceRemoveEditor":return f&&f.remove(),!0;case"mceToggleEditor":return f?(f.isHidden()?f.show():f.hide(),!0):(e.execCommand("mceAddEditor",0,c),!0)}return!!e.activeEditor&&e.activeEditor.execCommand(a,b,c)},triggerSave:function(){v(this.editors,function(a){a.save()})},addI18n:function(a,b){i.add(a,b)},translate:function(a){return i.translate(a)},setActive:function(a){var b=this.activeEditor;this.activeEditor!=a&&(b&&b.fire("deactivate",{relatedTarget:a}),a.fire("activate",{relatedTarget:b})),this.activeEditor=a}},w(s,j),s.setup(),h.register(s),s}),g("18",["z","9"],function(a,b){var c={send:function(a){function d(){!a.async||4==e.readyState||f++>1e4?(a.success&&f<1e4&&200==e.s
 tatus?a.success.call(a.success_scope,""+e.responseText,e,a):a.error&&a.error.call(a.error_scope,f>1e4?"TIMED_OUT":"GENERAL",e,a),e=null):setTimeout(d,10)}var e,f=0;if(a.scope=a.scope||this,a.success_scope=a.success_scope||a.scope,a.error_scope=a.error_scope||a.scope,a.async=a.async!==!1,a.data=a.data||"",c.fire("beforeInitialize",{settings:a}),e=new XMLHttpRequest){if(e.overrideMimeType&&e.overrideMimeType(a.content_type),e.open(a.type||(a.data?"POST":"GET"),a.url,a.async),a.crossDomain&&(e.withCredentials=!0),a.content_type&&e.setRequestHeader("Content-Type",a.content_type),a.requestheaders&&b.each(a.requestheaders,function(a){e.setRequestHeader(a.key,a.value)}),e.setRequestHeader("X-Requested-With","XMLHttpRequest"),e=c.fire("beforeSend",{xhr:e,settings:a}).xhr,e.send(a.data),!a.async)return d();setTimeout(d,10)}}};return b.extend
 (c,a),c}),g("19",[],function(){function a(b,c){var d,e,f,g;if(c=c||'"',null===b)return"null";if(f=typeof b,"string"==f)return e="\bb\tt\nn\ff\rr\"\"''\\\\",c+b.replace(/([\u0080-\uFFFF\x00-\x1f\"\'\\])/g,function(a,b){return'"'===c&&"'"===a?a:(d=e.indexOf(b),d+1?"\\"+e.charAt(d+1):(a=b.charCodeAt().toString(16),"\\u"+"0000".substring(a.length)+a))})+c;if("object"==f){if(b.hasOwnProperty&&"[object Array]"===Object.prototype.toString.call(b)){for(d=0,e="[";d<b.length;d++)e+=(d>0?",":"")+a(b[d],c);return e+"]"}e="{";for(g in b)b.hasOwnProperty(g)&&(e+="function"!=typeof b[g]?(e.length>1?","+c:c)+g+c+":"+a(b[g],c):"");return e+"}"}return""+b}return{serialize:a,parse:function(a){try{return window[String.fromCharCode(101)+&qu
 ot;val"]("("+a+")")}catch(a){}}}}),g("1a",["19","18","9"],function(a,b,c){function d(a){this.settings=e({},a),this.count=0}var e=c.extend;return d.sendRPC=function(a){return(new d).send(a)},d.prototype={send:function(c){var d=c.error,f=c.success;c=e(this.settings,c),c.success=function(b,e){b=a.parse(b),"undefined"==typeof b&&(b={error:"JSON Parse error."}),b.error?d.call(c.error_scope||c.scope,b.error,e):f.call(c.success_scope||c.scope,b.result)},c.error=function(a,b){d&&d.call(c.error_scope||c.scope,a,b)},c.data=a.serialize({id:c.id||"c"+this.count++,method:c.method,params:c.params}),c.content_type="application/json",b.send(c)}},d}),g("1b",["e"],function(a){return{callbacks:{},count:0,send:function(b){var c=this,d=a.DOM,e=void 0!==b.count?b.count:c.count,f="tinymce_jsonp_"+e;c.callbacks[e]=function(a){d.remove(f),delete c.callbacks[e
 ],b.callback(a)},d.add(d.doc.body,"script",{id:f,src:b.url,type:"text/javascript"}),c.count++}}}),g("1c",[],function(){function a(){g=[];for(var a in f)g.push(a);d.length=g.length}function b(){function b(a){var b,c;return c=void 0!==a?j+a:d.indexOf(",",j),c===-1||c>d.length?null:(b=d.substring(j,c),j=c+1,b)}var c,d,g,j=0;if(f={},i){e.load(h),d=e.getAttribute(h)||"";do{var k=b();if(null===k)break;if(c=b(parseInt(k,32)||0),null!==c){if(k=b(),null===k)break;g=b(parseInt(k,32)||0),c&&(f[c]=g)}}while(null!==c);a()}}function c(){var b,c="";if(i){for(var d in f)b=f[d],c+=(c?",":"")+d.length.toString(32)+","+d+","+b.length.toString(32)+","+b;e.setAttribute(h,c);try{e.save(h)}catch(a){}a()}}var d,e,f,g,h,i;try{if(window.localStorage)return localStorage}catch(a){}return h="tinymce",e=document.documentElement,i=!!e.addBehavior,i&&e.addBehavior("#defaul
 t#userData"),d={key:function(a){return g[a]},getItem:function(a){return a in f?f[a]:null},setItem:function(a,b){f[a]=""+b,c()},removeItem:function(a){delete f[a],c()},clear:function(){f={},c()}},b(),d}),g("1d",["e","7","f","g","9","6"],function(a,b,c,d,e,f){var g=function(g){g.DOM=a.DOM,g.ScriptLoader=c.ScriptLoader,g.PluginManager=d.PluginManager,g.ThemeManager=d.ThemeManager,g.dom=g.dom||{},g.dom.Event=b.Event,e.each("trim isArray is toArray makeMap each map grep inArray extend create walk createNS resolve explode _addCacheSuffix".split(" "),function(a){g[a]=e[a]}),e.each("isOpera isWebKit isIE isGecko isMac".split(" "),function(a){g[a]=f[a.substr(2).toLowerCase()]})};return{register:g}}),g("1e",[],function(){function a(a){function e(a,e,f){var g,h,i,j,k,l;return g=0,h=0,i=0,a/=255,e/=255,f/=255,k=b(a,b(e,f)),l=c(a,c(e,f)),k==l?(i=k,{h:0,s:0,v:100*
 i}):(j=a==k?e-f:f==k?a-e:f-a,g=a==k?3:f==k?1:5,g=60*(g-j/(l-k)),h=(l-k)/l,i=l,{h:d(g),s:d(100*h),v:d(100*i)})}function f(a,e,f){var g,h,i,j;if(a=(parseInt(a,10)||0)%360,e=parseInt(e,10)/100,f=parseInt(f,10)/100,e=c(0,b(e,1)),f=c(0,b(f,1)),0===e)return void(l=m=n=d(255*f));switch(g=a/60,h=f*e,i=h*(1-Math.abs(g%2-1)),j=f-h,Math.floor(g)){case 0:l=h,m=i,n=0;break;case 1:l=i,m=h,n=0;break;case 2:l=0,m=h,n=i;break;case 3:l=0,m=i,n=h;break;case 4:l=i,m=0,n=h;break;case 5:l=h,m=0,n=i;break;default:l=m=n=0}l=d(255*(l+j)),m=d(255*(m+j)),n=d(255*(n+j))}function g(){function a(a){return a=parseInt(a,10).toString(16),a.length>1?a:"0"+a}return"#"+a(l)+a(m)+a(n)}function h(){return{r:l,g:m,b:n}}function i(){return e(l,m,n)}function j(a){var b;return"object"==typeof a?"r"in a?(l=a.r,m=a.g,n=a.b):"v"in a&&f(a.h,a.s,a.v):(b=/rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)[^\)]*\)/gi.exec(a))?(l=parseInt(b[1],10),m=parseInt(b[2],10),n=par
 seInt(b[3],10)):(b=/#([0-F]{2})([0-F]{2})([0-F]{2})/gi.exec(a))?(l=parseInt(b[1],16),m=parseInt(b[2],16),n=parseInt(b[3],16)):(b=/#([0-F])([0-F])([0-F])/gi.exec(a))&&(l=parseInt(b[1]+b[1],16),m=parseInt(b[2]+b[2],16),n=parseInt(b[3]+b[3],16)),l=l<0?0:l>255?255:l,m=m<0?0:m>255?255:m,n=n<0?0:n>255?255:n,k}var k=this,l=0,m=0,n=0;a&&j(a),k.toRgb=h,k.toHsv=i,k.toHex=g,k.parse=j}var b=Math.min,c=Math.max,d=Math.round;return a}),g("2o",["x","9"],function(a,b){"use strict";return a.extend({Defaults:{firstControlClass:"first",lastControlClass:"last"},init:function(a){this.settings=b.extend({},this.Defaults,a)},preRender:function(a){a.bodyClasses.add(this.settings.containerClass)},applyClasses:function(a){var b,c,d,e,f=this,g=f.settings;b=g.firstControlClass,c=g.lastControlClass,a.each(function(a){a.classes.remove(b).remove(c).add(g.controlClass),a.visible()&&(d||(d=a),e=a)}),d&&d.cla
 sses.add(b),e&&e.classes.add(c)},renderHtml:function(a){var b=this,c="";return b.applyClasses(a.items()),a.items().each(function(a){c+=a.renderHtml()}),c},recalc:function(){},postRender:function(){},isNative:function(){return!1}})}),g("2p",["2o"],function(a){"use strict";return a.extend({Defaults:{containerClass:"abs-layout",controlClass:"abs-layout-item"},recalc:function(a){a.items().filter(":visible").each(function(a){var b=a.settings;a.layoutRect({x:b.x,y:b.y,w:b.w,h:b.h}),a.recalc&&a.recalc()})},renderHtml:function(a){return'<div id="'+a._id+'-absend" class="'+a.classPrefix+'abs-end"></div>'+this._super(a)}})}),g("2q",["2m"],function(a){"use strict";return a.extend({Defaults:{classes:"widget btn",role:"button"},init:function(a){var b,c=this;c._super(a),a=c.settings,b=c.settings.size,c.on("click mousedown&quot
 ;,function(a){a.preventDefault()}),c.on("touchstart",function(a){c.fire("click",a),a.preventDefault()}),a.subtype&&c.classes.add(a.subtype),b&&c.classes.add("btn-"+b),a.icon&&c.icon(a.icon)},icon:function(a){return arguments.length?(this.state.set("icon",a),this):this.state.get("icon")},repaint:function(){var a,b=this.getEl().firstChild;b&&(a=b.style,a.width=a.height="100%"),this._super()},renderHtml:function(){var a,b=this,c=b._id,d=b.classPrefix,e=b.state.get("icon"),f=b.state.get("text"),g="";return a=b.settings.image,a?(e="none","string"!=typeof a&&(a=window.getSelection?a[0]:a[1]),a=" style=\"background-image: url('"+a+"')\""):a="",f&&(b.classes.add("btn-has-text"),g='<span class="'+d+'txt">'+b.encode(f)+"</span>"),e=e?d+"ico "+d+&q
 uot;i-"+e:"",'<div id="'+c+'" class="'+b.classes+'" tabindex="-1"><button role="presentation" type="button" tabindex="-1">'+(e?'<i class="'+e+'"'+a+"></i>":"")+g+"</button></div>"},bindStates:function(){function a(a){var e=c("span."+d,b.getEl());a?(e[0]||(c("button:first",b.getEl()).append('<span class="'+d+'"></span>'),e=c("span."+d,b.getEl())),e.html(b.encode(a))):e.remove(),b.classes.toggle("btn-has-text",!!a)}var b=this,c=b.$,d=b.classPrefix+"txt";return b.state.on("change:text",function(b){a(b.value)}),b.state.on("change:icon",function(c){var d=c.value,e=b.classPrefix;b.settings.icon=d,d=d?e+"ico "+e+"i-"+b.settings.icon:"";var f=b.getEl().firstChild,g=f.getElementsByTagName("i")[0];d?(g&&g==
 f.firstChild||(g=document.createElement("i"),f.insertBefore(g,f.firstChild)),g.className=d):g&&f.removeChild(g),a(b.state.get("text"))}),b._super()}})}),g("2r",["2e"],function(a){"use strict";return a.extend({Defaults:{defaultType:"button",role:"group"},renderHtml:function(){var a=this,b=a._layout;return a.classes.add("btn-group"),a.preRender(),b.preRender(a),'<div id="'+a._id+'" class="'+a.classes+'"><div id="'+a._id+'-body">'+(a.settings.html||"")+b.renderHtml(a)+"</div></div>"}})}),g("2s",["2m"],function(a){"use strict";return a.extend({Defaults:{classes:"checkbox",role:"checkbox",checked:!1},init:function(a){var b=this;b._super(a),b.on("click mousedown",function(a){a.preventDefault()}),b.on("click",function(a){a.preventDefault(),b.disabled()||b.checke
 d(!b.checked())}),b.checked(b.settings.checked)},checked:function(a){return arguments.length?(this.state.set("checked",a),this):this.state.get("checked")},value:function(a){return arguments.length?this.checked(a):this.checked()},renderHtml:function(){var a=this,b=a._id,c=a.classPrefix;return'<div id="'+b+'" class="'+a.classes+'" unselectable="on" aria-labelledby="'+b+'-al" tabindex="-1"><i class="'+c+"ico "+c+'i-checkbox"></i><span id="'+b+'-al" class="'+c+'label">'+a.encode(a.state.get("text"))+"</span></div>"},bindStates:function(){function a(a){b.classes.toggle("checked",a),b.aria("checked",a)}var b=this;return b.state.on("change:text",function(a){b.getEl("al").firstChild.data=b.translate(a.value)}),b.state.on("change:checked change:value",function(c){b.fire("cha
 nge"),a(c.value)}),b.state.on("change:icon",function(a){var c=a.value,d=b.classPrefix;if("undefined"==typeof c)return b.settings.icon;b.settings.icon=c,c=c?d+"ico "+d+"i-"+b.settings.icon:"";var e=b.getEl().firstChild,f=e.getElementsByTagName("i")[0];c?(f&&f==e.firstChild||(f=document.createElement("i"),e.insertBefore(f,e.firstChild)),f.className=c):f&&e.removeChild(f)}),b.state.get("checked")&&a(!0),b._super()}})}),g("2t",["2m","2c","4h","a","p","9"],function(a,b,c,d,e,f){"use strict";return a.extend({init:function(a){var b=this;b._super(a),a=b.settings,b.classes.add("combobox"),b.subinput=!0,b.ariaTarget="inp",a.menu=a.menu||a.values,a.menu&&(a.icon="caret"),b.on("click",function(c){var e=c.target,f=b.getEl();if(d.contains(f,e)||e==f)for(;e&&am
 p;e!=f;)e.id&&e.id.indexOf("-open")!=-1&&(b.fire("action"),a.menu&&(b.showMenu(),c.aria&&b.menu.items()[0].focus())),e=e.parentNode}),b.on("keydown",function(a){var c;13==a.keyCode&&"INPUT"===a.target.nodeName&&(a.preventDefault(),b.parents().reverse().each(function(a){if(a.toJSON)return c=a,!1}),b.fire("submit",{data:c.toJSON()}))}),b.on("keyup",function(a){if("INPUT"==a.target.nodeName){var c=b.state.get("value"),d=a.target.value;d!==c&&(b.state.set("value",d),b.fire("autocomplete",a))}}),b.on("mouseover",function(a){var c=b.tooltip().moveTo(-65535);if(b.statusLevel()&&a.target.className.indexOf(b.classPrefix+"status")!==-1){var d=b.statusMessage()||"Ok",e=c.text(d).show().testMoveRel(a.target,["bc-tc","bc-tl","bc-tr"]);c.classes.toggle("tooltip-n",&q
 uot;bc-tc"==e),c.classes.toggle("tooltip-nw","bc-tl"==e),c.classes.toggle("tooltip-ne","bc-tr"==e),c.moveRel(a.target,e)}})},statusLevel:function(a){return arguments.length>0&&this.state.set("statusLevel",a),this.state.get("statusLevel")},statusMessage:function(a){return arguments.length>0&&this.state.set("statusMessage",a),this.state.get("statusMessage")},showMenu:function(){var a,c=this,d=c.settings;c.menu||(a=d.menu||[],a.length?a={type:"menu",items:a}:a.type=a.type||"menu",c.menu=b.create(a).parent(c).renderTo(c.getContainerElm()),c.fire("createmenu"),c.menu.reflow(),c.menu.on("cancel",function(a){a.control===c.menu&&c.focus()}),c.menu.on("show hide",function(a){a.control.items().each(function(a){a.active(a.value()==c.value())})}).fire("show"),c.menu.on("select",function(a){c.value(a.control.value
 ())}),c.on("focusin",function(a){"INPUT"==a.target.tagName.toUpperCase()&&c.menu.hide()}),c.aria("expanded",!0)),c.menu.show(),c.menu.layoutRect({w:c.layoutRect().w}),c.menu.moveRel(c.getEl(),c.isRtl()?["br-tr","tr-br"]:["bl-tl","tl-bl"])},focus:function(){this.getEl("inp").focus()},repaint:function(){var a,b,e=this,f=e.getEl(),g=e.getEl("open"),h=e.layoutRect(),i=0,j=f.firstChild;e.statusLevel()&&"none"!==e.statusLevel()&&(i=parseInt(c.getRuntimeStyle(j,"padding-right"),10)-parseInt(c.getRuntimeStyle(j,"padding-left"),10)),a=g?h.w-c.getSize(g).width-10:h.w-10;var k=document;return k.all&&(!k.documentMode||k.documentMode<=8)&&(b=e.layoutRect().h-2+"px"),d(j).css({width:a-i,lineHeight:b}),e._super(),e},postRender:function(){var a=this;return d(this.getEl("inp")).on("change",function(b){a.state.
 set("value",b.target.value),a.fire("change",b)}),a._super()},renderHtml:function(){var a,b,c=this,d=c._id,e=c.settings,f=c.classPrefix,g=c.state.get("value")||"",h="",i="",j="";return"spellcheck"in e&&(i+=' spellcheck="'+e.spellcheck+'"'),e.maxLength&&(i+=' maxlength="'+e.maxLength+'"'),e.size&&(i+=' size="'+e.size+'"'),e.subtype&&(i+=' type="'+e.subtype+'"'),j='<i id="'+d+'-status" class="mce-status mce-ico" style="display: none"></i>',c.disabled()&&(i+=' disabled="disabled"'),a=e.icon,a&&"caret"!=a&&(a=f+"ico "+f+"i-"+e.icon),b=c.state.get("text"),(a||b)&&(h='<div id="'+d+'-open" class="'+f+"btn "+f+'open" tabIndex="-1" role="button"><button id="'
 +d+'-action" type="button" hidefocus="1" tabindex="-1">'+("caret"!=a?'<i class="'+a+'"></i>':'<i class="'+f+'caret"></i>')+(b?(a?" ":"")+b:"")+"</button></div>",c.classes.add("has-open")),'<div id="'+d+'" class="'+c.classes+'"><input id="'+d+'-inp" class="'+f+'textbox" value="'+c.encode(g,!1)+'" hidefocus="1"'+i+' placeholder="'+c.encode(e.placeholder)+'" />'+j+h+"</div>"},value:function(a){return arguments.length?(this.state.set("value",a),this):(this.state.get("rendered")&&this.state.set("value",this.getEl("inp").value),this.state.get("value"))},showAutoComplete:function(a,c){var d=this;if(0===a.length)return void d.hideMenu();var e=function(a,b){return function(){d.fire(&quot
 ;selectitem",{title:b,value:a})}};d.menu?d.menu.items().remove():d.menu=b.create({type:"menu",classes:"combobox-menu",layout:"flow"}).parent(d).renderTo(),f.each(a,function(a){d.menu.add({text:a.title,url:a.previewUrl,match:c,classes:"menu-item-ellipsis",onclick:e(a.value,a.title)})}),d.menu.renderNew(),d.hideMenu(),d.menu.on("cancel",function(a){a.control.parent()===d.menu&&(a.stopPropagation(),d.focus(),d.hideMenu())}),d.menu.on("select",function(){d.focus()});var g=d.layoutRect().w;d.menu.layoutRect({w:g,minW:0,maxW:g}),d.menu.reflow(),d.menu.show(),d.menu.moveRel(d.getEl(),d.isRtl()?["br-tr","tr-br"]:["bl-tl","tl-bl"])},hideMenu:function(){this.menu&&this.menu.hide()},bindStates:function(){var a=this;a.state.on("change:value",function(b){a.getEl("inp").value!=b.value&&(a.getEl("inp").value=b.value)}),a.state.on("chang
 e:disabled",function(b){a.getEl("inp").disabled=b.value}),a.state.on("change:statusLevel",function(b){var d=a.getEl("status"),e=a.classPrefix,f=b.value;c.css(d,"display","none"===f?"none":""),c.toggleClass(d,e+"i-checkmark","ok"===f),c.toggleClass(d,e+"i-warning","warn"===f),c.toggleClass(d,e+"i-error","error"===f),a.classes.toggle("has-status","none"!==f),a.repaint()}),c.on(a.getEl("status"),"mouseleave",function(){a.tooltip().hide()}),a.on("cancel",function(b){a.menu&&a.menu.visible()&&(b.stopPropagation(),a.hideMenu())});var b=function(a,b){b&&b.items().length>0&&b.items().eq(a)[0].focus()};return a.on("keydown",function(c){var d=c.keyCode;"INPUT"===c.target.nodeName&&(d===e.DOWN?(c.preventDefault(),a.fire("autocomplete"),b(0,
 a.menu)):d===e.UP&&(c.preventDefault(),b(-1,a.menu)))}),a._super()},remove:function(){d(this.getEl("inp")).off(),this.menu&&this.menu.remove(),this._super()}})}),g("2u",["2t"],function(a){"use strict";return a.extend({init:function(a){var b=this;a.spellcheck=!1,a.onaction&&(a.icon="none"),b._super(a),b.classes.add("colorbox"),b.on("change keyup postrender",function(){b.repaintColor(b.value())})},repaintColor:function(a){var b=this.getEl("open"),c=b?b.getElementsByTagName("i")[0]:null;if(c)try{c.style.background=a}catch(a){}},bindStates:function(){var a=this;return a.state.on("change:value",function(b){a.state.get("rendered")&&a.repaintColor(b.value)}),a._super()}})}),g("2v",["2q","2k"],function(a,b){"use strict";return a.extend({showPanel:function(){var a=this,c=a.settings;if(a.active(!0),a.panel)a.panel
 .show();else{var d=c.panel;d.type&&(d={layout:"grid",items:d}),d.role=d.role||"dialog",d.popover=!0,d.autohide=!0,d.ariaRoot=!0,a.panel=new b(d).on("hide",function(){a.active(!1)}).on("cancel",function(b){b.stopPropagation(),a.focus(),a.hidePanel()}).parent(a).renderTo(a.getContainerElm()),a.panel.fire("show"),a.panel.reflow()}a.panel.moveRel(a.getEl(),c.popoverAlign||(a.isRtl()?["bc-tr","bc-tc"]:["bc-tl","bc-tc"]))},hidePanel:function(){var a=this;a.panel&&a.panel.hide()},postRender:function(){var a=this;return a.aria("haspopup",!0),a.on("click",function(b){b.control===a&&(a.panel&&a.panel.visible()?a.hidePanel():(a.showPanel(),a.panel.focus(!!b.aria)))}),a._super()},remove:function(){return this.panel&&(this.panel.remove(),this.panel=null),this._super()}})}),g("2w",["2v","e"],function(a,b){"use stri
 ct";var c=b.DOM;return a.extend({init:function(a){this._super(a),this.classes.add("colorbutton")},color:function(a){return a?(this._color=a,this.getEl("preview").style.backgroundColor=a,this):this._color},resetColor:function(){return this._color=null,this.getEl("preview").style.backgroundColor=null,this},renderHtml:function(){var a=this,b=a._id,c=a.classPrefix,d=a.state.get("text"),e=a.settings.icon?c+"ico "+c+"i-"+a.settings.icon:"",f=a.settings.image?" style=\"background-image: url('"+a.settings.image+"')\"":"",g="";return d&&(a.classes.add("btn-has-text"),g='<span class="'+c+'txt">'+a.encode(d)+"</span>"),'<div id="'+b+'" class="'+a.classes+'" role="button" tabindex="-1" aria-haspopup="true"><button role="presentation" hidefocus="1&quo
 t; type="button" tabindex="-1">'+(e?'<i class="'+e+'"'+f+"></i>":"")+'<span id="'+b+'-preview" class="'+c+'preview"></span>'+g+'</button><button type="button" class="'+c+'open" hidefocus="1" tabindex="-1"> <i class="'+c+'caret"></i></button></div>'},postRender:function(){var a=this,b=a.settings.onclick;return a.on("click",function(d){d.aria&&"down"==d.aria.key||d.control!=a||c.getParent(d.target,"."+a.classPrefix+"open")||(d.stopImmediatePropagation(),b.call(a,d))}),delete a.settings.onclick,a._super()}})}),g("2x",["2m","2f","4h","1e"],function(a,b,c,d){"use strict";return a.extend({Defaults:{classes:"widget colorpicker"},init:function(a){this._super(a)},postRender:function(){function a(
 a,b){var d,e,f=c.getPos(a);return d=b.pageX-f.x,e=b.pageY-f.y,d=Math.max(0,Math.min(d/a.clientWidth,1)),e=Math.max(0,Math.min(e/a.clientHeight,1)),{x:d,y:e}}function e(a,b){var e=(360-a.h)/360;c.css(j,{top:100*e+"%"}),b||c.css(l,{left:a.s+"%",top:100-a.v+"%"}),k.style.background=new d({s:100,v:100,h:a.h}).toHex(),m.color().parse({s:a.s,v:a.v,h:a.h})}function f(b){var c;c=a(k,b),h.s=100*c.x,h.v=100*(1-c.y),e(h),m.fire("change")}function g(b){var c;c=a(i,b),h=n.toHsv(),h.h=360*(1-c.y),e(h,!0),m.fire("change")}var h,i,j,k,l,m=this,n=m.color();i=m.getEl("h"),j=m.getEl("hp"),k=m.getEl("sv"),l=m.getEl("svp"),m._repaint=function(){h=n.toHsv(),e(h)},m._super(),m._svdraghelper=new b(m._id+"-sv",{start:f,drag:f}),m._hdraghelper=new b(m._id+"-h",{start:g,drag:g}),m._repaint()},rgb:function(){return this.color().toRgb()},value:function(a){var b=this;return arguments.length?(b.color().pa
 rse(a),void(b._rendered&&b._repaint())):b.color().toHex()},color:function(){return this._color||(this._color=new d),this._color},renderHtml:function(){function a(){var a,b,c,d,g="";for(c="filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=",d=f.split(","),a=0,b=d.length-1;a<b;a++)g+='<div class="'+e+'colorpicker-h-chunk" style="height:'+100/b+"%;"+c+d[a]+",endColorstr="+d[a+1]+");-ms-"+c+d[a]+",endColorstr="+d[a+1]+')"></div>';return g}var b,c=this,d=c._id,e=c.classPrefix,f="#ff0000,#ff0080,#ff00ff,#8000ff,#0000ff,#0080ff,#00ffff,#00ff80,#00ff00,#80ff00,#ffff00,#ff8000,#ff0000",g="background: -ms-linear-gradient(top,"+f+");background: linear-gradient(to bottom,"+f+");";return b='<div id="'+d+'-h" class="'+e+'colorpicker-h" style="'+g+'">'+a()+'<div id="'+d+'-hp&
 quot; class="'+e+'colorpicker-h-marker"></div></div>','<div id="'+d+'" class="'+c.classes+'"><div id="'+d+'-sv" class="'+e+'colorpicker-sv"><div class="'+e+'colorpicker-overlay1"><div class="'+e+'colorpicker-overlay2"><div id="'+d+'-svp" class="'+e+'colorpicker-selector1"><div class="'+e+'colorpicker-selector2"></div></div></div></div></div>'+b+"</div>"}})}),g("2y",["2m"],function(a){"use strict";return a.extend({init:function(a){var b=this;a.delimiter||(a.delimiter="\xbb"),b._super(a),b.classes.add("path"),b.canFocus=!0,b.on("click",function(a){var c,d=a.target;(c=d.getAttribute("data-index"))&&b.fire("select",{value:b.row()[c],index:c})}),b.row(b.settings.row)},focus:function(){var a=this;return a.get
 El().firstChild.focus(),a},row:function(a){return arguments.length?(this.state.set("row",a),this):this.state.get("row")},renderHtml:function(){var a=this;return'<div id="'+a._id+'" class="'+a.classes+'">'+a._getDataPathHtml(a.state.get("row"))+"</div>"},bindStates:function(){var a=this;return a.state.on("change:row",function(b){a.innerHtml(a._getDataPathHtml(b.value))}),a._super()},_getDataPathHtml:function(a){var b,c,d=this,e=a||[],f="",g=d.classPrefix;for(b=0,c=e.length;b<c;b++)f+=(b>0?'<div class="'+g+'divider" aria-hidden="true"> '+d.settings.delimiter+" </div>":"")+'<div role="button" class="'+g+"path-item"+(b==c-1?" "+g+"last":"")+'" data-index="'+b+'" tabindex="-1" id="'+d._id+"-"+b+'" aria-level="'+(b+1)+'">'+e[b]
 .name+"</div>";return f||(f='<div class="'+g+'path-item">\xa0</div>'),f}})}),g("2z",["2y"],function(a){return a.extend({postRender:function(){function a(a){if(1===a.nodeType){if("BR"==a.nodeName||a.getAttribute("data-mce-bogus"))return!0;if("bookmark"===a.getAttribute("data-mce-type"))return!0}return!1}var b=this,c=b.settings.editor;return c.settings.elementpath!==!1&&(b.on("select",function(a){c.focus(),c.selection.select(this.row()[a.index].element),c.nodeChanged()}),c.on("nodeChange",function(d){for(var e=[],f=d.parents,g=f.length;g--;)if(1==f[g].nodeType&&!a(f[g])){var h=c.fire("ResolveName",{name:f[g].nodeName.toLowerCase(),target:f[g]});if(h.isDefaultPrevented()||e.push({name:h.name,element:f[g]}),h.isPropagationStopped())break}b.row(e)})),b._super()}})}),g("30",["2e"],function(a){"use strict";return a.ext
 end({Defaults:{layout:"flex",align:"center",defaults:{flex:1}},renderHtml:function(){var a=this,b=a._layout,c=a.classPrefix;return a.classes.add("formitem"),b.preRender(a),'<div id="'+a._id+'" class="'+a.classes+'" hidefocus="1" tabindex="-1">'+(a.settings.title?'<div id="'+a._id+'-title" class="'+c+'title">'+a.settings.title+"</div>":"")+'<div id="'+a._id+'-body" class="'+a.bodyClasses+'">'+(a.settings.html||"")+b.renderHtml(a)+"</div></div>"}})}),g("31",["2e","30","9"],function(a,b,c){"use strict";return a.extend({Defaults:{containerCls:"form",layout:"flex",direction:"column",align:"stretch",flex:1,padding:20,labelGap:30,spacing:10,callbacks:{submit:function(){this.submit()}}},preRender:function(){var a=this,d
 =a.items();a.settings.formItemDefaults||(a.settings.formItemDefaults={layout:"flex",autoResize:"overflow",defaults:{flex:1}}),d.each(function(d){var e,f=d.settings.label;f&&(e=new b(c.extend({items:{type:"label",id:d._id+"-l",text:f,flex:0,forId:d._id,disabled:d.disabled()}},a.settings.formItemDefaults)),e.type="formitem",d.aria("labelledby",d._id+"-l"),"undefined"==typeof d.settings.flex&&(d.settings.flex=1),a.replace(d,e),e.add(d))})},submit:function(){return this.fire("submit",{data:this.toJSON()})},postRender:function(){var a=this;a._super(),a.fromJSON(a.settings.data)},bindStates:function(){function a(){var a,c,d,e=0,f=[];if(b.settings.labelGapCalc!==!1)for(d="children"==b.settings.labelGapCalc?b.find("formitem"):b.items(),d.filter("formitem").each(function(a){var b=a.items()[0],c=b.getEl().clientWidth;e=c>e?c:e,f.push(b)}),c=b.settings.labe
 lGap||0,a=f.length;a--;)f[a].settings.minWidth=e+c}var b=this;b._super(),b.on("show",a),a()}})}),g("32",["31"],function(a){"use strict";return a.extend({Defaults:{containerCls:"fieldset",layout:"flex",direction:"column",align:"stretch",flex:1,padding:"25 15 5 15",labelGap:30,spacing:10,border:1},renderHtml:function(){var a=this,b=a._layout,c=a.classPrefix;return a.preRender(),b.preRender(a),'<fieldset id="'+a._id+'" class="'+a.classes+'" hidefocus="1" tabindex="-1">'+(a.settings.title?'<legend id="'+a._id+'-title" class="'+c+'fieldset-title">'+a.settings.title+"</legend>":"")+'<div id="'+a._id+'-body" class="'+a.bodyClasses+'">'+(a.settings.html||"")+b.renderHtml(a)+"</div></fieldset>"}})}),g("4o",["e","1j",&quo
 t;1g","1s","9","25"],function(a,b,c,d,e,f){
-var g=e.trim,h=function(a,b,c,d,e){return{type:a,title:b,url:c,level:d,attach:e}},i=function(a){for(;a=a.parentNode;){var c=a.contentEditable;if(c&&"inherit"!==c)return b.isContentEditableTrue(a)}return!1},j=function(b,c){return a.DOM.select(b,c)},k=function(a){return a.innerText||a.textContent},l=function(a){return a.id?a.id:f.uuid("h")},m=function(a){return a&&"A"===a.nodeName&&(a.id||a.name)},n=function(a){return m(a)&&p(a)},o=function(a){return a&&/^(H[1-6])$/.test(a.nodeName)},p=function(a){return i(a)&&!b.isContentEditableFalse(a)},q=function(a){return o(a)&&p(a)},r=function(a){return o(a)?parseInt(a.nodeName.substr(1),10):0},s=function(a){var b=l(a),c=function(){a.id=b};return h("header",k(a),"#"+b,r(a),c)},t=function(a){var b=a.id||a.name,c=k(a);return h("anchor",c?c:"#"+b,"#"+b,0,d.noop)},u=function(a){return c.map(c.filter(a,q),s)},v=funct
 ion(a){return c.map(c.filter(a,n),t)},w=function(a){var b=j("h1,h2,h3,h4,h5,h6,a:not([href])",a);return b},x=function(a){return g(a.title).length>0},y=function(a){var b=w(a);return c.filter(u(b).concat(v(b)),x)};return{find:y}}),g("33",["4k","4o","17","2t","1g","1s","9"],function(a,b,c,d,e,f,g){"use strict";var h=function(){return a.tinymce?a.tinymce.activeEditor:c.activeEditor},i={},j=5,k=function(a){return{title:a.title,value:{title:{raw:a.title},url:a.url,attach:a.attach}}},l=function(a){return g.map(a,k)},m=function(a,b){return{title:a,value:{title:a,url:b,attach:f.noop}}},n=function(a,b){var c=e.find(b,function(b){return b.url===a});return!c},o=function(a,b,c){var d=b in a?a[b]:c;return d===!1?null:d},p=function(a,b,c,d){var h={title:"-"},j=function(a){var d=e.filter(a[c],function(a){return n(a,b)});return g.map(d,function(a){return{title:a,value:{title:a,url:a,attac
 h:f.noop}}})},k=function(a){var c=e.filter(b,function(b){return b.type==a});return l(c)},p=function(){var a=k("anchor"),b=o(d,"anchor_top","#top"),c=o(d,"anchor_bottom","#bottom");return null!==b&&a.unshift(m("<top>",b)),null!==c&&a.push(m("<bottom>",c)),a},q=function(a){return e.reduce(a,function(a,b){var c=0===a.length||0===b.length;return c?a.concat(b):a.concat(h,b)},[])};return d.typeahead_urls===!1?[]:"file"===c?q([r(a,j(i)),r(a,k("header")),r(a,p())]):r(a,j(i))},q=function(a,b){var c=i[b];/^https?/.test(a)&&(c?e.indexOf(c,a)===-1&&(i[b]=c.slice(0,j).concat(a)):i[b]=[a])},r=function(a,b){var c=a.toLowerCase(),d=g.grep(b,function(a){return a.title.toLowerCase().indexOf(c)!==-1});return 1===d.length&&d[0].title===a?[]:d},s=function(a){var b=a.title;return b.raw?b.raw:b},t=function(a,c,d,e){var f=function(f){var g=b.find(d),h=p(f,g,e,c);a.sh
 owAutoComplete(h,f)};a.on("autocomplete",function(){f(a.value())}),a.on("selectitem",function(b){var c=b.value;a.value(c.url);var d=s(c);"image"===e?a.fire("change",{meta:{alt:d,attach:c.attach}}):a.fire("change",{meta:{text:d,attach:c.attach}}),a.focus()}),a.on("click",function(b){0===a.value().length&&"INPUT"===b.target.nodeName&&f("")}),a.on("PostRender",function(){a.getRoot().on("submit",function(b){b.isDefaultPrevented()||q(a.value(),e)})})},u=function(a){var b=a.status,c=a.message;return"valid"===b?{status:"ok",message:c}:"unknown"===b?{status:"warn",message:c}:"invalid"===b?{status:"warn",message:c}:{status:"none",message:""}},v=function(a,b,c){var d=b.filepicker_validator_handler;if(d){var e=function(b){return 0===b.length?void a.statusLevel("none"):void d({url:b,type:c},f
 unction(b){var c=u(b);a.statusMessage(c.message),a.statusLevel(c.status)})};a.state.on("change:value",function(a){e(a.value)})}};return d.extend({init:function(b){var c,d,e,f=this,i=h(),j=i.settings,k=b.filetype;b.spellcheck=!1,e=j.file_picker_types||j.file_browser_callback_types,e&&(e=g.makeMap(e,/[, ]/)),e&&!e[k]||(d=j.file_picker_callback,!d||e&&!e[k]?(d=j.file_browser_callback,!d||e&&!e[k]||(c=function(){d(f.getEl("inp").id,f.value(),k,a)})):c=function(){var a=f.fire("beforecall").meta;a=g.extend({filetype:k},a),d.call(i,function(a,b){f.value(a).fire("change",{meta:b})},f.value(),a)}),c&&(b.icon="browse",b.onaction=c),f._super(b),t(f,j,i.getBody(),k),v(f,j,k)}})}),g("34",["2p"],function(a){"use strict";return a.extend({recalc:function(a){var b=a.layoutRect(),c=a.paddingBox;a.items().filter(":visible").each(function(a){a.layoutRect({x:c.left,y:c.top,w:
 b.innerW-c.right-c.left,h:b.innerH-c.top-c.bottom}),a.recalc&&a.recalc()})}})}),g("35",["2p"],function(a){"use strict";return a.extend({recalc:function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N=[],O=Math.max,P=Math.min;for(d=a.items().filter(":visible"),e=a.layoutRect(),f=a.paddingBox,g=a.settings,m=a.isRtl()?g.direction||"row-reversed":g.direction,h=g.align,i=a.isRtl()?g.pack||"end":g.pack,j=g.spacing||0,"row-reversed"!=m&&"column-reverse"!=m||(d=d.set(d.toArray().reverse()),m=m.split("-")[0]),"column"==m?(z="y",x="h",y="minH",A="maxH",C="innerH",B="top",D="deltaH",E="contentH",J="left",H="w",F="x",G="innerW",I="minW",K="right",L="deltaW",M="contentW"):(z="x"
 ,x="w",y="minW",A="maxW",C="innerW",B="left",D="deltaW",E="contentW",J="top",H="h",F="y",G="innerH",I="minH",K="bottom",L="deltaH",M="contentH"),l=e[C]-f[B]-f[B],w=k=0,b=0,c=d.length;b<c;b++)n=d[b],o=n.layoutRect(),p=n.settings,q=p.flex,l-=b<c-1?j:0,q>0&&(k+=q,o[A]&&N.push(n),o.flex=q),l-=o[y],r=f[J]+o[I]+f[K],r>w&&(w=r);if(u={},l<0?u[y]=e[y]-l+e[D]:u[y]=e[C]-l+e[D],u[I]=w+e[L],u[E]=e[C]-l,u[M]=w,u.minW=P(u.minW,e.maxW),u.minH=P(u.minH,e.maxH),u.minW=O(u.minW,e.startMinWidth),u.minH=O(u.minH,e.startMinHeight),!e.autoResize||u.minW==e.minW&&u.minH==e.minH){for(t=l/k,b=0,c=N.length;b<c;b++)n=N[b],o=n.layoutRect(),s=o[A],r=o[y]+o.flex*t,r>s?(l-=o[A]-o[y],k-=o.flex,o.flex=0,o.maxFlexSize=s):o.maxFlexSize=0;for(t=l/k,v=f[B],u={},0===k&&("end"==i?v=l+f[B]:"center&quo
 t;==i?(v=Math.round(e[C]/2-(e[C]-l)/2)+f[B],v<0&&(v=f[B])):"justify"==i&&(v=f[B],j=Math.floor(l/(d.length-1)))),u[F]=f[J],b=0,c=d.length;b<c;b++)n=d[b],o=n.layoutRect(),r=o.maxFlexSize||o[y],"center"===h?u[F]=Math.round(e[G]/2-o[H]/2):"stretch"===h?(u[H]=O(o[I]||0,e[G]-f[J]-f[K]),u[F]=f[J]):"end"===h&&(u[F]=e[G]-o[H]-f.top),o.flex>0&&(r+=o.flex*t),u[x]=r,u[z]=v,n.layoutRect(u),n.recalc&&n.recalc(),v+=r+j}else if(u.w=u.minW,u.h=u.minH,a.layoutRect(u),this.recalc(a),null===a._lastRect){var Q=a.parent();Q&&(Q._lastRect=null,Q.recalc())}}})}),g("36",["2o"],function(a){return a.extend({Defaults:{containerClass:"flow-layout",controlClass:"flow-layout-item",endClass:"break"},recalc:function(a){a.items().filter(":visible").each(function(a){a.recalc&&a.recalc()})},isNative:function(){return!0}})}),g("4p",["3t"
 ,"4q","42","44","e"],function(a,b,c,d,e){var f=function(a,c,d){for(;d!==c;){if(d.style[a]){var e=d.style[a];return""!==e?b.some(e):b.none()}d=d.parentNode}return b.none()},g=function(a){return/[0-9.]+px$/.test(a)?Math.round(72*parseInt(a,10)/96)+"pt":a},h=function(a){return a.replace(/[\'\"]/g,"").replace(/,\s+/g,",")},i=function(a,c){return b.from(e.DOM.getStyle(c,a,!0))},j=function(a){return function(e,g){return b.from(g).map(c.fromDom).filter(d.isElement).bind(function(b){return f(a,e,b.dom()).or(i(a,b.dom()))}).getOr("")}};return{getFontSize:j("fontSize"),getFontFamily:a.compose(h,j("fontFamily")),toPt:g}}),g("37",["2b","2m","2k","9","1g","e","17","6","4p"],function(a,b,c,d,e,f,g,h,i){function j(a){a.settings.ui_container&&(h.container=f.DOM.select(a.settings.
 ui_container)[0])}function k(b){b.on("ScriptsLoaded",function(){b.rtl&&(a.rtl=!0)})}function l(a){function b(b,c){return function(){var d=this;a.on("nodeChange",function(e){var f=a.formatter,g=null;m(e.parents,function(a){if(m(b,function(b){if(c?f.matchNode(a,c,{value:b.value})&&(g=b.value):f.matchNode(a,b.value)&&(g=b.value),g)return!1}),g)return!1}),d.value(g)})}}function e(b){return function(){var c=this,d=function(a){return a?a.split(",")[0]:""};a.on("nodeChange",function(e){var f,g=null;f=i.getFontFamily(a.getBody(),e.element),m(b,function(a){a.value.toLowerCase()===f.toLowerCase()&&(g=a.value)}),m(b,function(a){g||d(a.value).toLowerCase()!==d(f).toLowerCase()||(g=a.value)}),c.value(g),!g&&f&&c.text(d(f))})}}function f(b){return function(){var c=this;a.on("nodeChange",function(d){var e,f,g=null;e=i.getFontSize(a.getBody(),d.element),f=i.toPt(e),m(b,function(a){a.value===e
 ?g=e:a.value===f&&(g=f)}),c.value(g),g||c.text(f)})}}function g(a){a=a.replace(/;$/,"").split(";");for(var b=a.length;b--;)a[b]=a[b].split("=");return a}function h(){function b(a){var c=[];if(a)return m(a,function(a){var f={text:a.title,icon:a.icon};if(a.items)f.menu=b(a.items);else{var g=a.format||"custom"+d++;a.format||(a.name=g,e.push(a)),f.format=g,f.cmd=a.cmd}c.push(f)}),c}function c(){var c;return c=b(a.settings.style_formats_merge?a.settings.style_formats?f.concat(a.settings.style_formats):f:a.settings.style_formats||f)}var d=0,e=[],f=[{title:"Headings",items:[{title:"Heading 1",format:"h1"},{title:"Heading 2",format:"h2"},{title:"Heading 3",format:"h3"},{title:"Heading 4",format:"h4"},{title:"Heading 5",format:"h5"},{title:"Heading 6",format:"h6"}]},{title:"Inline",items:[{title:"Bold&
 quot;,icon:"bold",format:"bold"},{title:"Italic",icon:"italic",format:"italic"},{title:"Underline",icon:"underline",format:"underline"},{title:"Strikethrough",icon:"strikethrough",format:"strikethrough"},{title:"Superscript",icon:"superscript",format:"superscript"},{title:"Subscript",icon:"subscript",format:"subscript"},{title:"Code",icon:"code",format:"code"}]},{title:"Blocks",items:[{title:"Paragraph",format:"p"},{title:"Blockquote",format:"blockquote"},{title:"Div",format:"div"},{title:"Pre",format:"pre"}]},{title:"Alignment",items:[{title:"Left",icon:"alignleft",format:"alignleft"},{title:"Center",icon:"aligncenter",format:"alignc
 enter"},{title:"Right",icon:"alignright",format:"alignright"},{title:"Justify",icon:"alignjustify",format:"alignjustify"}]}];return a.on("init",function(){m(e,function(b){a.formatter.register(b.name,b)})}),{type:"menu",items:c(),onPostRender:function(b){a.fire("renderFormatsMenu",{control:b.control})},itemDefaults:{preview:!0,textStyle:function(){if(this.settings.format)return a.formatter.getCssText(this.settings.format)},onPostRender:function(){var b=this;b.parent().on("show",function(){var c,d;c=b.settings.format,c&&(b.disabled(!a.formatter.canApply(c)),b.active(a.formatter.match(c))),d=b.settings.cmd,d&&b.active(a.queryCommandState(d))})},onclick:function(){this.settings.format&&o(this.settings.format),this.settings.cmd&&a.execCommand(this.settings.cmd)}}}}function j(b){return function(){var c=this;a.formatter?a.formatter.formatChanged(b,functio
 n(a){c.active(a)}):a.on("init",function(){a.formatter.formatChanged(b,function(a){c.active(a)})})}}function k(b){return function(){function c(){var c="redo"==b?"hasRedo":"hasUndo";return!!a.undoManager&&a.undoManager[c]()}var d=this;d.disabled(!c()),a.on("Undo Redo AddUndo TypingUndo ClearUndos SwitchMode",function(){d.disabled(a.readonly||!c())})}}function l(){var b=this;a.on("VisualAid",function(a){b.active(a.hasVisual)}),b.active(a.hasVisual)}function o(b){b.control&&(b=b.control.value()),b&&a.execCommand("mceToggleFormat",!1,b)}function p(b){var c=b.length;return d.each(b,function(b){b.menu&&(b.hidden=0===p(b.menu));var d=b.format;d&&(b.hidden=!a.formatter.canApply(d)),b.hidden&&c--}),c}function q(b){var c=b.items().length;return b.items().each(function(b){b.menu&&b.visible(q(b.menu)>0),!b.menu&&b.settings.menu&&b.visible(p(b.settings.m
 enu)>0);var d=b.settings.format;d&&b.visible(a.formatter.canApply(d)),b.visible()||c--}),c}var r;r=h(),m({bold:"Bold",italic:"Italic",underline:"Underline",strikethrough:"Strikethrough",subscript:"Subscript",superscript:"Superscript"},function(b,c){a.addButton(c,{tooltip:b,onPostRender:j(c),onclick:function(){o(c)}})}),m({outdent:["Decrease indent","Outdent"],indent:["Increase indent","Indent"],cut:["Cut","Cut"],copy:["Copy","Copy"],paste:["Paste","Paste"],help:["Help","mceHelp"],selectall:["Select all","SelectAll"],removeformat:["Clear formatting","RemoveFormat"],visualaid:["Visual aids","mceToggleVisualAid"],newdocument:["New document","mceNewDocument"]},function(b,c){a.addButton(c,{tooltip:b[0],cmd:b[1]})}),m({blo
 ckquote:["Blockquote","mceBlockQuote"],subscript:["Subscript","Subscript"],superscript:["Superscript","Superscript"],alignleft:["Align left","JustifyLeft"],aligncenter:["Align center","JustifyCenter"],alignright:["Align right","JustifyRight"],alignjustify:["Justify","JustifyFull"],alignnone:["No alignment","JustifyNone"]},function(b,c){a.addButton(c,{tooltip:b[0],cmd:b[1],onPostRender:j(c)})});var s=function(a){var b=a;return b.length>0&&"-"===b[0].text&&(b=b.slice(1)),b.length>0&&"-"===b[b.length-1].text&&(b=b.slice(0,b.length-1)),b},t=function(b){var c,e;if("string"==typeof b)e=b.split(" ");else if(d.isArray(b))return n(d.map(b,t));return c=d.grep(e,function(b){return"|"===b||b in a.menuItems}),d.map(c,function(b){return"|"===b
 ?{text:"-"}:a.menuItems[b]})},u=function(b){var c=[{text:"-"}],e=d.grep(a.menuItems,function(a){return a.context===b});return d.each(e,function(a){"before"==a.separator&&c.push({text:"|"}),a.prependToContext?c.unshift(a):c.push(a),"after"==a.separator&&c.push({text:"|"})}),c},v=function(a){return s(a.insert_button_items?t(a.insert_button_items):u("insert"))};a.addButton("undo",{tooltip:"Undo",onPostRender:k("undo"),cmd:"undo"}),a.addButton("redo",{tooltip:"Redo",onPostRender:k("redo"),cmd:"redo"}),a.addMenuItem("newdocument",{text:"New document",icon:"newdocument",cmd:"mceNewDocument"}),a.addMenuItem("undo",{text:"Undo",icon:"undo",shortcut:"Meta+Z",onPostRender:k("undo"),cmd:"undo"}),a.addMenuItem("redo",{text:
 "Redo",icon:"redo",shortcut:"Meta+Y",onPostRender:k("redo"),cmd:"redo"}),a.addMenuItem("visualaid",{text:"Visual aids",selectable:!0,onPostRender:l,cmd:"mceToggleVisualAid"}),a.addButton("remove",{tooltip:"Remove",icon:"remove",cmd:"Delete"}),a.addButton("insert",{type:"menubutton",icon:"insert",menu:[],oncreatemenu:function(){this.menu.add(v(a.settings)),this.menu.renderNew()}}),m({cut:["Cut","Cut","Meta+X"],copy:["Copy","Copy","Meta+C"],paste:["Paste","Paste","Meta+V"],selectall:["Select all","SelectAll","Meta+A"],bold:["Bold","Bold","Meta+B"],italic:["Italic","Italic","Meta+I"],underline:["Underline","Underline","Meta+U"],stri
 kethrough:["Strikethrough","Strikethrough"],subscript:["Subscript","Subscript"],superscript:["Superscript","Superscript"],removeformat:["Clear formatting","RemoveFormat"]},function(b,c){a.addMenuItem(c,{text:b[0],icon:c,shortcut:b[2],cmd:b[1]})}),a.on("mousedown",function(){c.hideAll()}),a.addButton("styleselect",{type:"menubutton",text:"Formats",menu:r,onShowMenu:function(){a.settings.style_formats_autohide&&q(this.menu)}}),a.addButton("formatselect",function(){var c=[],d=g(a.settings.block_formats||"Paragraph=p;Heading 1=h1;Heading 2=h2;Heading 3=h3;Heading 4=h4;Heading 5=h5;Heading 6=h6;Preformatted=pre");return m(d,function(b){c.push({text:b[0],value:b[1],textStyle:function(){return a.formatter.getCssText(b[1])}})}),{type:"listbox",text:d[0][0],values:c,fixedWidth:!0,onselect:o,onPostRender:b(c)}}),a.addButton("fontsel
 ect",function(){var b="Andale Mono=andale mono,monospace;Arial=arial,helvetica,sans-serif;Arial Black=arial black,sans-serif;Book Antiqua=book antiqua,palatino,serif;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier,monospace;Georgia=georgia,palatino,serif;Helvetica=helvetica,arial,sans-serif;Impact=impact,sans-serif;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco,monospace;Times New Roman=times new roman,times,serif;Trebuchet MS=trebuchet ms,geneva,sans-serif;Verdana=verdana,geneva,sans-serif;Webdings=webdings;Wingdings=wingdings,zapf dingbats",c=[],d=g(a.settings.font_formats||b);return m(d,function(a){c.push({text:{raw:a[0]},value:a[1],textStyle:a[1].indexOf("dings")==-1?"font-family:"+a[1]:""})}),{type:"listbox",text:"Font Family",tooltip:"Font Family",values:c,fixedWidth:!0,onPostRender:e(c),onselect:function(b){b.control.settings.value&&a.exec
 Command("FontName",!1,b.control.settings.value)}}}),a.addButton("fontsizeselect",function(){var b=[],c="8pt 10pt 12pt 14pt 18pt 24pt 36pt",d=a.settings.fontsize_formats||c;return m(d.split(" "),function(a){var c=a,d=a,e=a.split("=");e.length>1&&(c=e[0],d=e[1]),b.push({text:c,value:d})}),{type:"listbox",text:"Font Sizes",tooltip:"Font Sizes",values:b,fixedWidth:!0,onPostRender:f(b),onclick:function(b){b.control.settings.value&&a.execCommand("FontSize",!1,b.control.settings.value)}}}),a.addMenuItem("formats",{text:"Formats",menu:r})}var m=d.each,n=function(a){return e.reduce(a,function(a,b){return a.concat(b)},[])};return g.on("AddEditor",function(a){var b=a.editor;k(b),l(b),j(b)}),a.translate=function(a){return g.translate(a)},b.tooltips=!h.iOS,{}}),g("38",["2p"],function(a){"use strict";return a.extend({recalc:functi
 on(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E=[],F=[];b=a.settings,e=a.items().filter(":visible"),f=a.layoutRect(),d=b.columns||Math.ceil(Math.sqrt(e.length)),c=Math.ceil(e.length/d),s=b.spacingH||b.spacing||0,t=b.spacingV||b.spacing||0,u=b.alignH||b.align,v=b.alignV||b.align,q=a.paddingBox,C="reverseRows"in b?b.reverseRows:a.isRtl(),u&&"string"==typeof u&&(u=[u]),v&&"string"==typeof v&&(v=[v]);for(l=0;l<d;l++)E.push(0);for(m=0;m<c;m++)F.push(0);for(m=0;m<c;m++)for(l=0;l<d&&(k=e[m*d+l],k);l++)j=k.layoutRect(),y=j.minW,z=j.minH,E[l]=y>E[l]?y:E[l],F[m]=z>F[m]?z:F[m];for(A=f.innerW-q.left-q.right,w=0,l=0;l<d;l++)w+=E[l]+(l>0?s:0),A-=(l>0?s:0)+E[l];for(B=f.innerH-q.top-q.bottom,x=0,m=0;m<c;m++)x+=F[m]+(m>0?t:0),B-=(m>0?t:0)+F[m];if(w+=q.left+q.right,x+=q.top+q.bottom,i={},i.minW=w+(f.w-f.innerW),i.minH=x+(f.h-f.innerH),i.contentW=i.minW-f.deltaW,i.c
 ontentH=i.minH-f.deltaH,i.minW=Math.min(i.minW,f.maxW),i.minH=Math.min(i.minH,f.maxH),i.minW=Math.max(i.minW,f.startMinWidth),i.minH=Math.max(i.minH,f.startMinHeight),!f.autoResize||i.minW==f.minW&&i.minH==f.minH){f.autoResize&&(i=a.layoutRect(i),i.contentW=i.minW-f.deltaW,i.contentH=i.minH-f.deltaH);var G;G="start"==b.packV?0:B>0?Math.floor(B/c):0;var H=0,I=b.flexWidths;if(I)for(l=0;l<I.length;l++)H+=I[l];else H=d;var J=A/H;for(l=0;l<d;l++)E[l]+=I?I[l]*J:J;for(o=q.top,m=0;m<c;m++){for(n=q.left,h=F[m]+G,l=0;l<d&&(D=C?m*d+d-1-l:m*d+l,k=e[D],k);l++)p=k.settings,j=k.layoutRect(),g=Math.max(E[l],j.startMinWidth),j.x=n,j.y=o,r=p.alignH||(u?u[l]||u[0]:null),"center"==r?j.x=n+g/2-j.w/2:"right"==r?j.x=n+g-j.w:"stretch"==r&&(j.w=g),r=p.alignV||(v?v[l]||v[0]:null),"center"==r?j.y=o+h/2-j.h/2:"bottom"==r?j.y=o+h-j.h:"stretch"==r&&(j.h=h),k.layoutRect(j),n+=g+s,k.recalc&a
 mp;&k.recalc();o+=h+t}}else if(i.w=i.minW,i.h=i.minH,a.layoutRect(i),this.recalc(a),null===a._lastRect){var K=a.parent();K&&(K._lastRect=null,K.recalc())}}})}),g("39",["2m","5"],function(a,b){"use strict";return a.extend({renderHtml:function(){var a=this;return a.classes.add("iframe"),a.canFocus=!1,'<iframe id="'+a._id+'" class="'+a.classes+'" tabindex="-1" src="'+(a.settings.url||"javascript:''")+'" frameborder="0"></iframe>'},src:function(a){this.getEl().src=a},html:function(a,c){var d=this,e=this.getEl().contentWindow.document.body;return e?(e.innerHTML=a,c&&c()):b.setTimeout(function(){d.html(a)}),this}})}),g("3a",["2m"],function(a){"use strict";return a.extend({init:function(a){var b=this;b._super(a),b.classes.add("widget").add("infobox"),b.canFocus=!1},severity:function(a){this.classes.re
 move("error"),this.classes.remove("warning"),this.classes.remove("success"),this.classes.add(a)},help:function(a){this.state.set("help",a)},renderHtml:function(){var a=this,b=a.classPrefix;return'<div id="'+a._id+'" class="'+a.classes+'"><div id="'+a._id+'-body">'+a.encode(a.state.get("text"))+'<button role="button" tabindex="-1"><i class="'+b+"ico "+b+'i-help"></i></button></div></div>'},bindStates:function(){var a=this;return a.state.on("change:text",function(b){a.getEl("body").firstChild.data=a.encode(b.value),a.state.get("rendered")&&a.updateLayoutRect()}),a.state.on("change:help",function(b){a.classes.toggle("has-help",b.value),a.state.get("rendered")&&a.updateLayoutRect()}),a._super()}})}),g("3b",["2m","4h"]
 ,function(a,b){"use strict";return a.extend({init:function(a){var b=this;b._super(a),b.classes.add("widget").add("label"),b.canFocus=!1,a.multiline&&b.classes.add("autoscroll"),a.strong&&b.classes.add("strong")},initLayoutRect:function(){var a=this,c=a._super();if(a.settings.multiline){var d=b.getSize(a.getEl());d.width>c.maxW&&(c.minW=c.maxW,a.classes.add("multiline")),a.getEl().style.width=c.minW+"px",c.startMinH=c.h=c.minH=Math.min(c.maxH,b.getSize(a.getEl()).height)}return c},repaint:function(){var a=this;return a.settings.multiline||(a.getEl().style.lineHeight=a.layoutRect().h+"px"),a._super()},severity:function(a){this.classes.remove("error"),this.classes.remove("warning"),this.classes.remove("success"),this.classes.add(a)},renderHtml:function(){var a,b,c=this,d=c.settings.forId,e=c.settings.html?c.settings.html:c.encode(c.state.get("tex
 t"));return!d&&(b=c.settings.forName)&&(a=c.getRoot().find("#"+b)[0],a&&(d=a._id)),d?'<label id="'+c._id+'" class="'+c.classes+'"'+(d?' for="'+d+'"':"")+">"+e+"</label>":'<span id="'+c._id+'" class="'+c.classes+'">'+e+"</span>"},bindStates:function(){var a=this;return a.state.on("change:text",function(b){a.innerHtml(a.encode(b.value)),a.state.get("rendered")&&a.updateLayoutRect()}),a._super()}})}),g("3c",["2e"],function(a){"use strict";return a.extend({Defaults:{role:"toolbar",layout:"flow"},init:function(a){var b=this;b._super(a),b.classes.add("toolbar")},postRender:function(){var a=this;return a.items().each(function(a){a.classes.add("toolbar-item")}),a._super()}})}),g("3d",["3c"],function(a){"use strict"
 ;return a.extend({Defaults:{role:"menubar",containerCls:"menubar",ariaRoot:!0,defaults:{type:"menubutton"}}})}),g("3e",["2q","2c","3d"],function(a,b,c){"use strict";function d(a,b){for(;a;){if(b===a)return!0;a=a.parentNode}return!1}var e=a.extend({init:function(a){var b=this;b._renderOpen=!0,b._super(a),a=b.settings,b.classes.add("menubtn"),a.fixedWidth&&b.classes.add("fixed-width"),b.aria("haspopup",!0),b.state.set("menu",a.menu||b.render())},showMenu:function(a){var c,d=this;return d.menu&&d.menu.visible()&&a!==!1?d.hideMenu():(d.menu||(c=d.state.get("menu")||[],c.length?c={type:"menu",items:c}:c.type=c.type||"menu",c.renderTo?d.menu=c.parent(d).show().renderTo():d.menu=b.create(c).parent(d).renderTo(),d.fire("createmenu"),d.menu.reflow(),d.menu.on("cancel",function(a){a.control.parent()===
 d.menu&&(a.stopPropagation(),d.focus(),d.hideMenu())}),d.menu.on("select",function(){d.focus()}),d.menu.on("show hide",function(a){a.control==d.menu&&d.activeMenu("show"==a.type),d.aria("expanded","show"==a.type)}).fire("show")),d.menu.show(),d.menu.layoutRect({w:d.layoutRect().w}),d.menu.moveRel(d.getEl(),d.isRtl()?["br-tr","tr-br"]:["bl-tl","tl-bl"]),void d.fire("showmenu"))},hideMenu:function(){var a=this;a.menu&&(a.menu.items().each(function(a){a.hideMenu&&a.hideMenu()}),a.menu.hide())},activeMenu:function(a){this.classes.toggle("active",a)},renderHtml:function(){var a,b=this,d=b._id,e=b.classPrefix,f=b.settings.icon,g=b.state.get("text"),h="";return a=b.settings.image,a?(f="none","string"!=typeof a&&(a=window.getSelection?a[0]:a[1]),a=" style=\"background-image: url('&quo
 t;+a+"')\""):a="",g&&(b.classes.add("btn-has-text"),h='<span class="'+e+'txt">'+b.encode(g)+"</span>"),f=b.settings.icon?e+"ico "+e+"i-"+f:"",b.aria("role",b.parent()instanceof c?"menuitem":"button"),'<div id="'+d+'" class="'+b.classes+'" tabindex="-1" aria-labelledby="'+d+'"><button id="'+d+'-open" role="presentation" type="button" tabindex="-1">'+(f?'<i class="'+f+'"'+a+"></i>":"")+h+' <i class="'+e+'caret"></i></button></div>'},postRender:function(){var a=this;return a.on("click",function(b){b.control===a&&d(b.target,a.getEl())&&(a.focus(),a.showMenu(!b.aria),b.aria&&a.menu.items().filter(":visible")[0].focus())}),a.on("mouseenter&quo
 t;,function(b){var c,d=b.control,f=a.parent();d&&f&&d instanceof e&&d.parent()==f&&(f.items().filter("MenuButton").each(function(a){a.hideMenu&&a!=d&&(a.menu&&a.menu.visible()&&(c=!0),a.hideMenu())}),c&&(d.focus(),d.showMenu()))}),a._super()},bindStates:function(){var a=this;return a.state.on("change:menu",function(){a.menu&&a.menu.remove(),a.menu=null}),a._super()},remove:function(){this._super(),this.menu&&this.menu.remove()}});return e}),g("3f",["2m","2c","6","5"],function(a,b,c,d){"use strict";return a.extend({Defaults:{border:0,role:"menuitem"},init:function(a){var b,c=this;c._super(a),a=c.settings,c.classes.add("menu-item"),a.menu&&c.classes.add("menu-item-expand"),a.preview&&c.classes.add("menu-item-preview"),b=c.state.get("text"),"-"!=
 =b&&"|"!==b||(c.classes.add("menu-item-sep"),c.aria("role","separator"),c.state.set("text","-")),a.selectable&&(c.aria("role","menuitemcheckbox"),c.classes.add("menu-item-checkbox"),a.icon="selected"),a.preview||a.selectable||c.classes.add("menu-item-normal"),c.on("mousedown",function(a){a.preventDefault()}),a.menu&&!a.ariaHideMenu&&c.aria("haspopup",!0)},hasMenus:function(){return!!this.settings.menu},showMenu:function(){var a,c=this,d=c.settings,e=c.parent();if(e.items().each(function(a){a!==c&&a.hideMenu()}),d.menu){a=c.menu,a?a.show():(a=d.menu,a.length?a={type:"menu",items:a}:a.type=a.type||"menu",e.settings.itemDefaults&&(a.itemDefaults=e.settings.itemDefaults),a=c.menu=b.create(a).parent(c).renderTo(),a.reflow(),a.on("cancel",function(b){b.stopPropagation(),c.focus(),a.hi
 de()}),a.on("show hide",function(a){a.control.items&&a.control.items().each(function(a){a.active(a.settings.selected)})}).fire("show"),a.on("hide",function(b){b.control===a&&c.classes.remove("selected")}),a.submenu=!0),a._parentMenu=e,a.classes.add("menu-sub");var f=a.testMoveRel(c.getEl(),c.isRtl()?["tl-tr","bl-br","tr-tl","br-bl"]:["tr-tl","br-bl","tl-tr","bl-br"]);a.moveRel(c.getEl(),f),a.rel=f,f="menu-sub-"+f,a.classes.remove(a._lastRel).add(f),a._lastRel=f,c.classes.add("selected"),c.aria("expanded",!0)}},hideMenu:function(){var a=this;return a.menu&&(a.menu.items().each(function(a){a.hideMenu&&a.hideMenu()}),a.menu.hide(),a.aria("expanded",!1)),a},renderHtml:function(){function a(a){var b,d,e={};for(e=c.mac?{alt:"&#x2325;",ctrl:"&#x2318;",shift:"
 &#x21E7;",meta:"&#x2318;"}:{meta:"Ctrl"},a=a.split("+"),b=0;b<a.length;b++)d=e[a[b].toLowerCase()],d&&(a[b]=d);return a.join("+")}function b(a){return a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function d(a){var c=h.match||"";return c?a.replace(new RegExp(b(c),"gi"),function(a){return"!mce~match["+a+"]mce~match!"}):a}function e(a){return a.replace(new RegExp(b("!mce~match["),"g"),"<b>").replace(new RegExp(b("]mce~match!"),"g"),"</b>")}var f=this,g=f._id,h=f.settings,i=f.classPrefix,j=f.state.get("text"),k=f.settings.icon,l="",m=h.shortcut,n=f.encode(h.url),o="";return k&&f.parent().classes.add("menu-has-icons"),h.image&&(l=" style=\"background-image: url('"+h.image+"')\""),m&&(m=a(m)),k=i+"ico "+i
 +"i-"+(f.settings.icon||"none"),o="-"!==j?'<i class="'+k+'"'+l+"></i>\xa0":"",j=e(f.encode(d(j))),n=e(f.encode(d(n))),'<div id="'+g+'" class="'+f.classes+'" tabindex="-1">'+o+("-"!==j?'<span id="'+g+'-text" class="'+i+'text">'+j+"</span>":"")+(m?'<div id="'+g+'-shortcut" class="'+i+'menu-shortcut">'+m+"</div>":"")+(h.menu?'<div class="'+i+'caret"></div>':"")+(n?'<div class="'+i+'menu-item-link">'+n+"</div>":"")+"</div>"},postRender:function(){var a=this,b=a.settings,c=b.textStyle;if("function"==typeof c&&(c=c.call(this)),c){var e=a.getEl("text");e&&e.setAttribute("style",c)}return a.on("mouseenter click",function(c){c.con
 trol===a&&(b.menu||"click"!==c.type?(a.showMenu(),c.aria&&a.menu.focus(!0)):(a.fire("select"),d.requestAnimationFrame(function(){a.parent().hideAll()})))}),a._super(),a},hover:function(){var a=this;return a.parent().items().each(function(a){a.classes.remove("selected")}),a.classes.toggle("selected",!0),a},active:function(a){return"undefined"!=typeof a&&this.aria("checked",a),this._super(a)},remove:function(){this._super(),this.menu&&this.menu.remove()}})}),g("3g",["a","2b","5"],function(a,b,c){"use strict";return function(d,e){var f,g,h=this,i=b.classPrefix;h.show=function(b,j){function k(){f&&(a(d).append('<div class="'+i+"throbber"+(e?" "+i+"throbber-inline":"")+'"></div>'),j&&j())}return h.hide(),f=!0,b?g=c.setTimeout(k,b):k(),h},h.hide=function(){var a=d.lastChil
 d;return c.clearTimeout(g),a&&a.className.indexOf("throbber")!=-1&&a.parentNode.removeChild(a),f=!1,h}}}),g("3h",["2k","3f","3g","9"],function(a,b,c,d){"use strict";return a.extend({Defaults:{defaultType:"menuitem",border:1,layout:"stack",role:"application",bodyRole:"menu",ariaRoot:!0},init:function(a){var b=this;if(a.autohide=!0,a.constrainToViewport=!0,"function"==typeof a.items&&(a.itemsFactory=a.items,a.items=[]),a.itemDefaults)for(var c=a.items,e=c.length;e--;)c[e]=d.extend({},a.itemDefaults,c[e]);b._super(a),b.classes.add("menu")},repaint:function(){return this.classes.toggle("menu-align",!0),this._super(),this.getEl().style.height="",this.getEl("body").style.height="",this},cancel:function(){var a=this;a.hideAll(),a.fire("select")},load:function(){function a(){e.throbber&
 &(e.throbber.hide(),e.throbber=null)}var b,d,e=this;d=e.settings.itemsFactory,d&&(e.throbber||(e.throbber=new c(e.getEl("body"),!0),0===e.items().length?(e.throbber.show(),e.fire("loading")):e.throbber.show(100,function(){e.items().remove(),e.fire("loading")}),e.on("hide close",a)),e.requestTime=b=(new Date).getTime(),e.settings.itemsFactory(function(c){return 0===c.length?void e.hide():void(e.requestTime===b&&(e.getEl().style.width="",e.getEl("body").style.width="",a(),e.items().remove(),e.getEl("body").innerHTML="",e.add(c),e.renderNew(),e.fire("loaded")))}))},hideAll:function(){var a=this;return this.find("menuitem").exec("hideMenu"),a._super()},preRender:function(){var a=this;return a.items().each(function(b){var c=b.settings;if(c.icon||c.image||c.selectable)return a._hasIcons=!0,!1}),a.settings.itemsFactory&&a.on("postrender&qu
 ot;,function(){a.settings.itemsFactory&&a.load()}),a._super()}})}),g("3i",["3e","3h"],function(a,b){"use strict";return a.extend({init:function(a){function b(c){for(var f=0;f<c.length;f++){if(d=c[f].selected||a.value===c[f].value)return e=e||c[f].text,g.state.set("value",c[f].value),!0;if(c[f].menu&&b(c[f].menu))return!0}}var c,d,e,f,g=this;g._super(a),a=g.settings,g._values=c=a.values,c&&("undefined"!=typeof a.value&&b(c),!d&&c.length>0&&(e=c[0].text,g.state.set("value",c[0].value)),g.state.set("menu",c)),g.state.set("text",a.text||e),g.classes.add("listbox"),g.on("select",function(b){var c=b.control;f&&(b.lastControl=f),a.multiple?c.active(!c.active()):g.value(b.control.value()),f=c})},bindStates:function(){function a(a,c){a instanceof b&&a.items().each(function(a){a.hasMenus()||a.active(a.value()===c)})
 }function c(a,b){var d;if(a)for(var e=0;e<a.length;e++){if(a[e].value===b)return a[e];if(a[e].menu&&(d=c(a[e].menu,b)))return d}}var d=this;return d.on("show",function(b){a(b.control,d.value())}),d.state.on("change:value",function(a){var b=c(d.state.get("menu"),a.value);b?d.text(b.text):d.text(d.settings.text)}),d._super()}})}),g("3j",["2s"],function(a){"use strict";return a.extend({Defaults:{classes:"radio",role:"radio"}})}),g("3k",["2m","2f"],function(a,b){"use strict";return a.extend({renderHtml:function(){var a=this,b=a.classPrefix;return a.classes.add("resizehandle"),"both"==a.settings.direction&&a.classes.add("resizehandle-both"),a.canFocus=!1,'<div id="'+a._id+'" class="'+a.classes+'"><i class="'+b+"ico "+b+'i-resize"></i></div>'},postRender:funct
 ion(){var a=this;a._super(),a.resizeDragHelper=new b(this._id,{start:function(){a.fire("ResizeStart")},drag:function(b){"both"!=a.settings.direction&&(b.deltaX=0),a.fire("Resize",b)},stop:function(){a.fire("ResizeEnd")}})},remove:function(){return this.resizeDragHelper&&this.resizeDragHelper.destroy(),this._super()}})}),g("3l",["2m"],function(a){"use strict";function b(a){var b="";if(a)for(var c=0;c<a.length;c++)b+='<option value="'+a[c]+'">'+a[c]+"</option>";return b}return a.extend({Defaults:{classes:"selectbox",role:"selectbox",options:[]
-},init:function(a){var b=this;b._super(a),b.settings.size&&(b.size=b.settings.size),b.settings.options&&(b._options=b.settings.options),b.on("keydown",function(a){var c;13==a.keyCode&&(a.preventDefault(),b.parents().reverse().each(function(a){if(a.toJSON)return c=a,!1}),b.fire("submit",{data:c.toJSON()}))})},options:function(a){return arguments.length?(this.state.set("options",a),this):this.state.get("options")},renderHtml:function(){var a,c=this,d="";return a=b(c._options),c.size&&(d=' size = "'+c.size+'"'),'<select id="'+c._id+'" class="'+c.classes+'"'+d+">"+a+"</select>"},bindStates:function(){var a=this;return a.state.on("change:options",function(c){a.getEl().innerHTML=b(c.value)}),a._super()}})}),g("3m",["2m","2f","4h"],function(a,b,c){"use strict";function d(a,b,c){return a&lt
 ;b&&(a=b),a>c&&(a=c),a}function e(a,b,c){a.setAttribute("aria-"+b,c)}function f(a,b){var d,f,g,h,i,j;"v"==a.settings.orientation?(h="top",g="height",f="h"):(h="left",g="width",f="w"),j=a.getEl("handle"),d=(a.layoutRect()[f]||100)-c.getSize(j)[g],i=d*((b-a._minValue)/(a._maxValue-a._minValue))+"px",j.style[h]=i,j.style.height=a.layoutRect().h+"px",e(j,"valuenow",b),e(j,"valuetext",""+a.settings.previewFilter(b)),e(j,"valuemin",a._minValue),e(j,"valuemax",a._maxValue)}return a.extend({init:function(a){var b=this;a.previewFilter||(a.previewFilter=function(a){return Math.round(100*a)/100}),b._super(a),b.classes.add("slider"),"v"==a.orientation&&b.classes.add("vertical"),b._minValue=a.minValue||0,b._maxValue=a.maxValue||100,b._initValue=b.state.get("value")},render
 Html:function(){var a=this,b=a._id,c=a.classPrefix;return'<div id="'+b+'" class="'+a.classes+'"><div id="'+b+'-handle" class="'+c+'slider-handle" role="slider" tabindex="-1"></div></div>'},reset:function(){this.value(this._initValue).repaint()},postRender:function(){function a(a,b,c){return(c+a)/(b-a)}function e(a,b,c){return c*(b-a)-a}function f(b,c){function f(f){var g;g=n.value(),g=e(b,c,a(b,c,g)+.05*f),g=d(g,b,c),n.value(g),n.fire("dragstart",{value:g}),n.fire("drag",{value:g}),n.fire("dragend",{value:g})}n.on("keydown",function(a){switch(a.keyCode){case 37:case 38:f(-1);break;case 39:case 40:f(1)}})}function g(a,e,f){var g,h,i,o,p;n._dragHelper=new b(n._id,{handle:n._id+"-handle",start:function(a){g=a[j],h=parseInt(n.getEl("handle").style[k],10),i=(n.layoutRect()[m]||100)-c.getSize(f)[l],n.fire("dragstart",{value:p})},drag:fun
 ction(b){var c=b[j]-g;o=d(h+c,0,i),f.style[k]=o+"px",p=a+o/i*(e-a),n.value(p),n.tooltip().text(""+n.settings.previewFilter(p)).show().moveRel(f,"bc tc"),n.fire("drag",{value:p})},stop:function(){n.tooltip().hide(),n.fire("dragend",{value:p})}})}var h,i,j,k,l,m,n=this;h=n._minValue,i=n._maxValue,"v"==n.settings.orientation?(j="screenY",k="top",l="height",m="h"):(j="screenX",k="left",l="width",m="w"),n._super(),f(h,i,n.getEl("handle")),g(h,i,n.getEl("handle"))},repaint:function(){this._super(),f(this,this.value())},bindStates:function(){var a=this;return a.state.on("change:value",function(b){f(a,b.value)}),a._super()}})}),g("3n",["2m"],function(a){"use strict";return a.extend({renderHtml:function(){var a=this;return a.classes.add("spacer"),a.canFocus=!1,'<div id="'+a._id
 +'" class="'+a.classes+'"></div>'}})}),g("3o",["3e","4h","a"],function(a,b,c){return a.extend({Defaults:{classes:"widget btn splitbtn",role:"button"},repaint:function(){var a,d,e=this,f=e.getEl(),g=e.layoutRect();return e._super(),a=f.firstChild,d=f.lastChild,c(a).css({width:g.w-b.getSize(d).width,height:g.h-2}),c(d).css({height:g.h-2}),e},activeMenu:function(a){var b=this;c(b.getEl().lastChild).toggleClass(b.classPrefix+"active",a)},renderHtml:function(){var a,b=this,c=b._id,d=b.classPrefix,e=b.state.get("icon"),f=b.state.get("text"),g="";return a=b.settings.image,a?(e="none","string"!=typeof a&&(a=window.getSelection?a[0]:a[1]),a=" style=\"background-image: url('"+a+"')\""):a="",e=b.settings.icon?d+"ico "+d+"i-"+e:"",f&&(b.classes.add("btn-has-text&q
 uot;),g='<span class="'+d+'txt">'+b.encode(f)+"</span>"),'<div id="'+c+'" class="'+b.classes+'" role="button" tabindex="-1"><button type="button" hidefocus="1" tabindex="-1">'+(e?'<i class="'+e+'"'+a+"></i>":"")+g+'</button><button type="button" class="'+d+'open" hidefocus="1" tabindex="-1">'+(b._menuBtnText?(e?"\xa0":"")+b._menuBtnText:"")+' <i class="'+d+'caret"></i></button></div>'},postRender:function(){var a=this,b=a.settings.onclick;return a.on("click",function(a){var c=a.target;if(a.control==this)for(;c;){if(a.aria&&"down"!=a.aria.key||"BUTTON"==c.nodeName&&c.className.indexOf("open")==-1)return a.stopImmediatePropagation(),void(b&&b.call(this,a)
 );c=c.parentNode}}),delete a.settings.onclick,a._super()}})}),g("3p",["36"],function(a){"use strict";return a.extend({Defaults:{containerClass:"stack-layout",controlClass:"stack-layout-item",endClass:"break"},isNative:function(){return!0}})}),g("3q",["2h","a","4h"],function(a,b,c){"use strict";return a.extend({Defaults:{layout:"absolute",defaults:{type:"panel"}},activateTab:function(a){var c;this.activeTabId&&(c=this.getEl(this.activeTabId),b(c).removeClass(this.classPrefix+"active"),c.setAttribute("aria-selected","false")),this.activeTabId="t"+a,c=this.getEl("t"+a),c.setAttribute("aria-selected","true"),b(c).addClass(this.classPrefix+"active"),this.items()[a].show().fire("showtab"),this.reflow(),this.items().each(function(b,c){a!=c&&b.hide()})},rende
 rHtml:function(){var a=this,b=a._layout,c="",d=a.classPrefix;return a.preRender(),b.preRender(a),a.items().each(function(b,e){var f=a._id+"-t"+e;b.aria("role","tabpanel"),b.aria("labelledby",f),c+='<div id="'+f+'" class="'+d+'tab" unselectable="on" role="tab" aria-controls="'+b._id+'" aria-selected="false" tabIndex="-1">'+a.encode(b.settings.title)+"</div>"}),'<div id="'+a._id+'" class="'+a.classes+'" hidefocus="1" tabindex="-1"><div id="'+a._id+'-head" class="'+d+'tabs" role="tablist">'+c+'</div><div id="'+a._id+'-body" class="'+a.bodyClasses+'">'+b.renderHtml(a)+"</div></div>"},postRender:function(){var a=this;a._super(),a.settings.activeTab=a.settings.activeTab||0,a.activateTab(a.settings.activeTab),this.on
 ("click",function(b){var c=b.target.parentNode;if(c&&c.id==a._id+"-head")for(var d=c.childNodes.length;d--;)c.childNodes[d]==b.target&&a.activateTab(d)})},initLayoutRect:function(){var a,b,d,e=this;b=c.getSize(e.getEl("head")).width,b=b<0?0:b,d=0,e.items().each(function(a){b=Math.max(b,a.layoutRect().minW),d=Math.max(d,a.layoutRect().minH)}),e.items().each(function(a){a.settings.x=0,a.settings.y=0,a.settings.w=b,a.settings.h=d,a.layoutRect({x:0,y:0,w:b,h:d})});var f=c.getSize(e.getEl("head")).height;return e.settings.minWidth=b,e.settings.minHeight=d+f,a=e._super(),a.deltaH+=f,a.innerH=a.h-a.deltaH,a}})}),g("3r",["2m","9","4h"],function(a,b,c){return a.extend({init:function(a){var b=this;b._super(a),b.classes.add("textbox"),a.multiline?b.classes.add("multiline"):(b.on("keydown",function(a){var c;13==a.keyCode&&(a.preventDefault(),b.parents().revers
 e().each(function(a){if(a.toJSON)return c=a,!1}),b.fire("submit",{data:c.toJSON()}))}),b.on("keyup",function(a){b.state.set("value",a.target.value)}))},repaint:function(){var a,b,c,d,e,f=this,g=0;a=f.getEl().style,b=f._layoutRect,e=f._lastRepaintRect||{};var h=document;return!f.settings.multiline&&h.all&&(!h.documentMode||h.documentMode<=8)&&(a.lineHeight=b.h-g+"px"),c=f.borderBox,d=c.left+c.right+8,g=c.top+c.bottom+(f.settings.multiline?8:0),b.x!==e.x&&(a.left=b.x+"px",e.x=b.x),b.y!==e.y&&(a.top=b.y+"px",e.y=b.y),b.w!==e.w&&(a.width=b.w-d+"px",e.w=b.w),b.h!==e.h&&(a.height=b.h-g+"px",e.h=b.h),f._lastRepaintRect=e,f.fire("repaint",{},!1),f},renderHtml:function(){var a,d,e=this,f=e.settings;return a={id:e._id,hidefocus:"1"},b.each(["rows","spellcheck","maxLength","size","readonly&quo
 t;,"min","max","step","list","pattern","placeholder","required","multiple"],function(b){a[b]=f[b]}),e.disabled()&&(a.disabled="disabled"),f.subtype&&(a.type=f.subtype),d=c.create(f.multiline?"textarea":"input",a),d.value=e.state.get("value"),d.className=e.classes,d.outerHTML},value:function(a){return arguments.length?(this.state.set("value",a),this):(this.state.get("rendered")&&this.state.set("value",this.getEl().value),this.state.get("value"))},postRender:function(){var a=this;a.getEl().value=a.state.get("value"),a._super(),a.$el.on("change",function(b){a.state.set("value",b.target.value),a.fire("change",b)})},bindStates:function(){var a=this;return a.state.on("change:value",function(b){a.getEl().value!=b.value&&(a.getEl().value=b.value)}),a.st
 ate.on("change:disabled",function(b){a.getEl().disabled=b.value}),a._super()},remove:function(){this.$el.off(),this._super()}})}),g("1f",["28","29","2a","2b","2c","2d","2e","2f","2g","2h","2i","2j","2k","1z","20","2l","2m","2n","21","2o","2p","2q","2r","2s","2t","2u","2v","2w","2x","2y","2z","30","31","32","33","34","35","36","37","38","39","3a","3b","3c","3d","3e","3f","3g","3h","3i","3j","3k","3l","3m","3n","3o"
 ,"3p","3q","3r"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,$,_,aa,ba,ca,da,ea){"use strict";var fa=function(a,b){e.add(a.split(".").pop(),b)},ga=function(a,b,c){var d,e;for(e=b.split(/[.\/]/),d=0;d<e.length-1;++d)void 0===a[e[d]]&&(a[e[d]]={}),a=a[e[d]];a[e[e.length-1]]=c,fa(b,c)},ha=function(fa){ga(fa,"ui.Selector",a),ga(fa,"ui.Collection",b),ga(fa,"ui.ReflowQueue",c),ga(fa,"ui.Control",d),ga(fa,"ui.Factory",e),ga(fa,"ui.KeyboardNavigation",f),ga(fa,"ui.Container",g),ga(fa,"ui.DragHelper",h),ga(fa,"ui.Scrollable",i),ga(fa,"ui.Panel",j),ga(fa,"ui.Movable",k),ga(fa,"ui.Resizable",l),ga(fa,"ui.FloatPanel",m),ga(fa,"ui.Window",n),ga(fa,"ui.MessageBox",o),ga(fa,"ui.Tooltip",p),ga(fa,"ui.Widget&q
 uot;,q),ga(fa,"ui.Progress",r),ga(fa,"ui.Notification",s),ga(fa,"ui.Layout",t),ga(fa,"ui.AbsoluteLayout",u),ga(fa,"ui.Button",v),ga(fa,"ui.ButtonGroup",w),ga(fa,"ui.Checkbox",x),ga(fa,"ui.ComboBox",y),ga(fa,"ui.ColorBox",z),ga(fa,"ui.PanelButton",A),ga(fa,"ui.ColorButton",B),ga(fa,"ui.ColorPicker",C),ga(fa,"ui.Path",D),ga(fa,"ui.ElementPath",E),ga(fa,"ui.FormItem",F),ga(fa,"ui.Form",G),ga(fa,"ui.FieldSet",H),ga(fa,"ui.FilePicker",I),ga(fa,"ui.FitLayout",J),ga(fa,"ui.FlexLayout",K),ga(fa,"ui.FlowLayout",L),ga(fa,"ui.FormatControls",M),ga(fa,"ui.GridLayout",N),ga(fa,"ui.Iframe",O),ga(fa,"ui.InfoBox",P),ga(fa,"ui.Label",Q),ga(fa,"ui.Toolbar",R),ga(fa,"ui.MenuBar",S),ga(fa,"ui.MenuButton",T),ga(fa,&quo
 t;ui.MenuItem",U),ga(fa,"ui.Throbber",V),ga(fa,"ui.Menu",W),ga(fa,"ui.ListBox",X),ga(fa,"ui.Radio",Y),ga(fa,"ui.ResizeHandle",Z),ga(fa,"ui.SelectBox",$),ga(fa,"ui.Slider",_),ga(fa,"ui.Spacer",aa),ga(fa,"ui.SplitButton",ba),ga(fa,"ui.StackLayout",ca),ga(fa,"ui.TabPanel",da),ga(fa,"ui.TextBox",ea),ga(fa,"ui.Api",ia)},ia={appendTo:ha};return ia}),g("1",["3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","10","11","1
 2","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W){var X=O,Y=function(a,b,c){var d,e;for(e=b.split(/[.\/]/),d=0;d<e.length-1;++d)void 0===a[e[d]]&&(a[e[d]]={}),a=a[e[d]];a[e[e.length-1]]=c};return Y(X,"geom.Rect",a),Y(X,"util.Promise",b),Y(X,"util.Delay",c),Y(X,"Env",d),Y(X,"dom.EventUtils",e),Y(X,"dom.Sizzle",f),Y(X,"util.Tools",g),Y(X,"dom.DomQuery",h),Y(X,"html.Styles",i),Y(X,"dom.TreeWalker",j),Y(X,"html.Entities",k),Y(X,"dom.DOMUtils",l),Y(X,"dom.ScriptLoader",m),Y(X,"AddOnManager",n),Y(X,"dom.RangeUtils",o),Y(X,"html.Node",p),Y(X,"html.Schema"
 ,q),Y(X,"html.SaxParser",r),Y(X,"html.DomParser",s),Y(X,"html.Writer",t),Y(X,"html.Serializer",u),Y(X,"dom.Serializer",v),Y(X,"util.VK",w),Y(X,"dom.ControlSelection",x),Y(X,"dom.BookmarkManager",y),Y(X,"dom.Selection",z),Y(X,"Formatter",A),Y(X,"UndoManager",B),Y(X,"EditorCommands",C),Y(X,"util.URI",D),Y(X,"util.Class",E),Y(X,"util.EventDispatcher",F),Y(X,"util.Observable",G),Y(X,"WindowManager",H),Y(X,"NotificationManager",I),Y(X,"EditorObservable",J),Y(X,"Shortcuts",K),Y(X,"Editor",L),Y(X,"util.I18n",M),Y(X,"FocusManager",N),Y(X,"EditorManager",O),Y(X,"util.XHR",P),Y(X,"util.JSON",Q),Y(X,"util.JSONRequest",R),Y(X,"util.JSONP",S),Y(X,"util.LocalStorage",T),Y(X,"Compat",U),Y(X,"util.C
 olor",V),W.appendTo(X),U.register(X),X}),g("2",[],function(){var a=this||window,b=function(b){"function"==typeof a.define&&(a.define.amd||(a.define("ephox/tinymce",[],function(){return b}),a.define("17",[],function(){return b}))),"object"==typeof module&&(module.exports=b)};return{exposeToModuleLoaders:b}}),g("0",["1","2"],function(a,b){return function(){return window.tinymce=a,window.tinyMCE=a,b.exposeToModuleLoaders(a),a}}),d("0")()}();
</del><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+// 4.6.7 (2017-09-18)
+!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e.push(d(a[f]));b.apply(null,b)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("3",Array),h("4",Error),g("1",["3","4"],function(a,b){var c=function(){},d=function(a,b){return function(){r
 eturn a(b.apply(null,arguments))}},e=function(a){return function(){return a}},f=function(a){return a},g=function(a,b){return a===b},h=function(b){for(var c=new a(arguments.length-1),d=1;d<arguments.length;d++)c[d-1]=arguments[d];return function(){for(var d=new a(arguments.length),e=0;e<d.length;e++)d[e]=arguments[e];var f=c.concat(d);return b.apply(null,f)}},i=function(a){return function(){return!a.apply(null,arguments)}},j=function(a){return function(){throw new b(a)}},k=function(a){return a()},l=function(a){a()},m=e(!1),n=e(!0);return{noop:c,compose:d,constant:e,identity:f,tripleEquals:g,curry:h,not:i,die:j,apply:k,call:l,never:m,always:n}}),g("1c",[],function(){function a(a,b){return function(){a.apply(b,arguments)}}function b(b){if("object"!=typeof this)throw new TypeError("Promises must be constructed via new");if("function"!=typeof b)throw new TypeError("not a function");this._state=null,this._value=null,this._deferreds=[
 ],h(b,a(d,this),a(e,this))}function c(a){var b=this;return null===this._state?void this._deferreds.push(a):void i(function(){var c=b._state?a.onFulfilled:a.onRejected;if(null===c)return void(b._state?a.resolve:a.reject)(b._value);var d;try{d=c(b._value)}catch(b){return void a.reject(b)}a.resolve(d)})}function d(b){try{if(b===this)throw new TypeError("A promise cannot be resolved with itself.");if(b&&("object"==typeof b||"function"==typeof b)){var c=b.then;if("function"==typeof c)return void h(a(c,b),a(d,this),a(e,this))}this._state=!0,this._value=b,f.call(this)}catch(a){e.call(this,a)}}function e(a){this._state=!1,this._value=a,f.call(this)}function f(){for(var a=0,b=this._deferreds.length;a<b;a++)c.call(this,this._deferreds[a]);this._deferreds=null}function g(a,b,c,d){this.onFulfilled="function"==typeof a?a:null,this.onRejected="function"==typeof b?b:null,this.resolve=c,this.reject=d}function h(a,b,c){var d=!1;t
 ry{a(function(a){d||(d=!0,b(a))},function(a){d||(d=!0,c(a))})}catch(a){if(d)return;d=!0,c(a)}}if(window.Promise)return window.Promise;var i=b.immediateFn||"function"==typeof setImmediate&&setImmediate||function(a){setTimeout(a,1)},j=Array.isArray||function(a){return"[object Array]"===Object.prototype.toString.call(a)};return b.prototype["catch"]=function(a){return this.then(null,a)},b.prototype.then=function(a,d){var e=this;return new b(function(b,f){c.call(e,new g(a,d,b,f))})},b.all=function(){var a=Array.prototype.slice.call(1===arguments.length&&j(arguments[0])?arguments[0]:arguments);return new b(function(b,c){function d(f,g){try{if(g&&("object"==typeof g||"function"==typeof g)){var h=g.then;if("function"==typeof h)return void h.call(g,function(a){d(f,a)},c)}a[f]=g,0===--e&&b(a)}catch(a){c(a)}}if(0===a.length)return b([]);for(var e=a.length,f=0;f<a.length;f++)d(f,a[f])})},b.resolve=fun
 ction(a){return a&&"object"==typeof a&&a.constructor===b?a:new b(function(b){b(a)})},b.reject=function(a){return new b(function(b,c){c(a)})},b.race=function(a){return new b(function(b,c){for(var d=0,e=a.length;d<e;d++)a[d].then(b,c)})},b}),g("14",["1c"],function(a){function b(a,b){function c(a){window.setTimeout(a,0)}var d,e=window.requestAnimationFrame,f=["ms","moz","webkit"];for(d=0;d<f.length&&!e;d++)e=window[f[d]+"RequestAnimationFrame"];e||(e=c),e(a,b)}function c(a,b){return"number"!=typeof b&&(b=0),setTimeout(a,b)}function d(a,b){return"number"!=typeof b&&(b=1),setInterval(a,b)}function e(a){return clearTimeout(a)}function f(a){return clearInterval(a)}function g(a,b){var d,e;return e=function(){var e=arguments;clearTimeout(d),d=c(function(){a.apply(this,e)},b)},e.stop=function(){clearTimeout(d)},e}var h;return{requestAnimationFrame:function(c,
 d){return h?void h.then(c):void(h=new a(function(a){d||(d=document.body),b(a,d)}).then(c))},setTimeout:c,setInterval:d,setEditorTimeout:function(a,b,d){return c(function(){a.removed||b()},d)},setEditorInterval:function(a,b,c){var e;return e=d(function(){a.removed?clearInterval(e):b()},c)},debounce:g,throttle:g,clearInterval:f,clearTimeout:e}}),g("o",[],function(){function a(a){return"matchMedia"in window&&matchMedia(a).matches}var b,c,d,e,f,g,h,i,j,k,l,m,n,o=navigator,p=o.userAgent;b=window.opera&&window.opera.buildNumber,j=/Android/.test(p),c=/WebKit/.test(p),d=!c&&!b&&/MSIE/gi.test(p)&&/Explorer/gi.test(o.appName),d=d&&/MSIE (\w+)\./.exec(p)[1],e=p.indexOf("Trident/")!=-1&&(p.indexOf("rv:")!=-1||o.appName.indexOf("Netscape")!=-1)&&11,f=p.indexOf("Edge/")!=-1&&!d&&!e&&12,d=d||e||f,g=!c&&!e&&/Gecko/.test(p),h=p.indexOf(&q
 uot;Mac")!=-1,i=/(iPad|iPhone)/.test(p),k="FormData"in window&&"FileReader"in window&&"URL"in window&&!!URL.createObjectURL,l=a("only screen and (max-device-width: 480px)")&&(j||i),m=a("only screen and (min-width: 800px)")&&(j||i),n=p.indexOf("Windows Phone")!=-1,f&&(c=!1);var q=!i||k||p.match(/AppleWebKit\/(\d*)/)[1]>=534;return{opera:b,webkit:c,ie:d,gecko:g,mac:h,iOS:i,android:j,contentEditable:q,transparentSrc:"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",caretAfter:8!=d,range:window.getSelection&&"Range"in window,documentMode:d&&!f?document.documentMode||7:10,fileApi:k,ceFalse:d===!1||d>8,canHaveCSP:d===!1||d>11,desktop:!l&&!m,windowsPhone:n}}),g("d",["14","o"],function(a,b){"use strict";function c(a,b,c,d){a.addEventListener?a.addEventListen
 er(b,c,d||!1):a.attachEvent&&a.attachEvent("on"+b,c)}function d(a,b,c,d){a.removeEventListener?a.removeEventListener(b,c,d||!1):a.detachEvent&&a.detachEvent("on"+b,c)}function e(a,b){var c,d=b;return c=a.path,c&&c.length>0&&(d=c[0]),a.deepPath&&(c=a.deepPath(),c&&c.length>0&&(d=c[0])),d}function f(a,c){var d,f,g=c||{};for(d in a)k[d]||(g[d]=a[d]);if(g.target||(g.target=g.srcElement||document),b.experimentalShadowDom&&(g.target=e(a,g.target)),a&&j.test(a.type)&&a.pageX===f&&a.clientX!==f){var h=g.target.ownerDocument||document,i=h.documentElement,o=h.body;g.pageX=a.clientX+(i&&i.scrollLeft||o&&o.scrollLeft||0)-(i&&i.clientLeft||o&&o.clientLeft||0),g.pageY=a.clientY+(i&&i.scrollTop||o&&o.scrollTop||0)-(i&&i.clientTop||o&&o.clientTop||0)}return g.preventDefault=function(){g.isDefaultPrevented=n,a&&(a.pr
 eventDefault?a.preventDefault():a.returnValue=!1)},g.stopPropagation=function(){g.isPropagationStopped=n,a&&(a.stopPropagation?a.stopPropagation():a.cancelBubble=!0)},g.stopImmediatePropagation=function(){g.isImmediatePropagationStopped=n,g.stopPropagation()},l(g)===!1&&(g.isDefaultPrevented=m,g.isPropagationStopped=m,g.isImmediatePropagationStopped=m),"undefined"==typeof g.metaKey&&(g.metaKey=!1),g}function g(e,f,g){function h(){return"complete"===l.readyState||"interactive"===l.readyState&&l.body}function i(){g.domLoaded||(g.domLoaded=!0,f(m))}function j(){h()&&(d(l,"readystatechange",j),i())}function k(){try{l.documentElement.doScroll("left")}catch(b){return void a.setTimeout(k)}i()}var l=e.document,m={type:"ready"};return g.domLoaded?void f(m):(!l.addEventListener||b.ie&&b.ie<11?(c(l,"readystatechange",j),l.documentElement.doScroll&&e.self===e.top&
 &k()):h()?i():c(e,"DOMContentLoaded",i),void c(e,"load",i))}function h(){function a(a,b){var c,d,e,f,g=m[b];if(c=g&&g[a.type])for(d=0,e=c.length;d<e;d++)if(f=c[d],f&&f.func.call(f.scope,a)===!1&&a.preventDefault(),a.isImmediatePropagationStopped())return}var b,e,h,j,k,l=this,m={};e=i+(+new Date).toString(32),j="onmouseenter"in document.documentElement,h="onfocusin"in document.documentElement,k={mouseenter:"mouseover",mouseleave:"mouseout"},b=1,l.domLoaded=!1,l.events=m,l.bind=function(d,i,n,o){function p(b){a(f(b||x.event),q)}var q,r,s,t,u,v,w,x=window;if(d&&3!==d.nodeType&&8!==d.nodeType){for(d[e]?q=d[e]:(q=b++,d[e]=q,m[q]={}),o=o||d,i=i.split(" "),s=i.length;s--;)t=i[s],v=p,u=w=!1,"DOMContentLoaded"===t&&(t="ready"),l.domLoaded&&"ready"===t&&"complete"==d.readyState?n.call(o,f({type:t})):(j||(u=k[t],u&a
 mp;&(v=function(b){var c,d;if(c=b.currentTarget,d=b.relatedTarget,d&&c.contains)d=c.contains(d);else for(;d&&d!==c;)d=d.parentNode;d||(b=f(b||x.event),b.type="mouseout"===b.type?"mouseleave":"mouseenter",b.target=c,a(b,q))})),h||"focusin"!==t&&"focusout"!==t||(w=!0,u="focusin"===t?"focus":"blur",v=function(b){b=f(b||x.event),b.type="focus"===b.type?"focusin":"focusout",a(b,q)}),r=m[q][t],r?"ready"===t&&l.domLoaded?n({type:t}):r.push({func:n,scope:o}):(m[q][t]=r=[{func:n,scope:o}],r.fakeName=u,r.capture=w,r.nativeHandler=v,"ready"===t?g(d,v,l):c(d,u||t,v,w)));return d=r=0,n}},l.unbind=function(a,b,c){var f,g,h,i,j,k;if(!a||3===a.nodeType||8===a.nodeType)return l;if(f=a[e]){if(k=m[f],b){for(b=b.split(" "),h=b.length;h--;)if(j=b[h],g=k[j]){if(c)for(i=g.length;i--;)if(g[i].func===c){var n=g.nativeHandler,o=g.fakeN
 ame,p=g.capture;g=g.slice(0,i).concat(g.slice(i+1)),g.nativeHandler=n,g.fakeName=o,g.capture=p,k[j]=g}c&&0!==g.length||(delete k[j],d(a,g.fakeName||j,g.nativeHandler,g.capture))}}else{for(j in k)g=k[j],d(a,g.fakeName||j,g.nativeHandler,g.capture);k={}}for(j in k)return l;delete m[f];try{delete a[e]}catch(b){a[e]=null}}return l},l.fire=function(b,c,d){var g;if(!b||3===b.nodeType||8===b.nodeType)return l;d=f(null,d),d.type=c,d.target=b;do g=b[e],g&&a(d,g),b=b.parentNode||b.ownerDocument||b.defaultView||b.parentWindow;while(b&&!d.isPropagationStopped());return l},l.clean=function(a){var b,c,d=l.unbind;if(!a||3===a.nodeType||8===a.nodeType)return l;if(a[e]&&d(a),a.getElementsByTagName||(a=a.document),a&&a.getElementsByTagName)for(d(a),c=a.getElementsByTagName("*"),b=c.length;b--;)a=c[b],a[e]&&d(a);return l},l.destroy=function(){m={}},l.cancel=function(a){return a&&(a.preventDefault(),a.stopImmediatePropagation()),!1}}var 
 i="mce-data-",j=/^(?:mouse|contextmenu)|click/,k={keyLocation:1,layerX:1,layerY:1,returnValue:1,webkitMovementX:1,webkitMovementY:1,keyIdentifier:1},l=function(a){return a.isDefaultPrevented===n||a.isDefaultPrevented===m},m=function(){return!1},n=function(){return!0};return h.Event=new h,h.Event.bind(window,"ready",function(){}),h}),g("i",[],function(){function a(a,b,c,d){var e,f,g,i,k,l,m,n,o,p;if((b?b.ownerDocument||b:L)!==D&&C(b),b=b||D,c=c||[],!a||"string"!=typeof a)return c;if(1!==(i=b.nodeType)&&9!==i)return[];if(F&&!d){if(e=oa.exec(a))if(g=e[1]){if(9===i){if(f=b.getElementById(g),!f||!f.parentNode)return c;if(f.id===g)return c.push(f),c}else if(b.ownerDocument&&(f=b.ownerDocument.getElementById(g))&&J(b,f)&&f.id===g)return c.push(f),c}else{if(e[2])return Y.apply(c,b.getElementsByTagName(a)),c;if((g=e[3])&&s.getElementsByClassName)return Y.apply(c,b.getElementsByClassName(g)),c}if(s
 .qsa&&(!G||!G.test(a))){if(n=m=K,o=b,p=9===i&&a,1===i&&"object"!==b.nodeName.toLowerCase()){for(l=w(a),(m=b.getAttribute("id"))?n=m.replace(qa,"\\$&"):b.setAttribute("id",n),n="[id='"+n+"'] ",k=l.length;k--;)l[k]=n+j(l[k]);o=pa.test(a)&&h(b.parentNode)||b,p=l.join(",")}if(p)try{return Y.apply(c,o.querySelectorAll(p)),c}catch(a){}finally{m||b.removeAttribute("id")}}}return y(a.replace(ea,"$1"),b,c,d)}function b(){function a(c,d){return b.push(c+" ")>t.cacheLength&&delete a[b.shift()],a[c+" "]=d}var b=[];return a}function c(a){return a[K]=!0,a}function d(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||T)-(~a.sourceIndex||T);if(d)return d;if(c)for(;c=c.nextSibling;)if(c===b)return-1;return a?1:-1}function e(a){return function(b){var c=b.nodeName.toLowerCase();return"input&q
 uot;===c&&b.type===a}}function f(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function g(a){return c(function(b){return b=+b,c(function(c,d){for(var e,f=a([],c.length,b),g=f.length;g--;)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function h(a){return a&&typeof a.getElementsByTagName!==S&&a}function i(){}function j(a){for(var b=0,c=a.length,d="";b<c;b++)d+=a[b].value;return d}function k(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=N++;return b.first?function(b,c,f){for(;b=b[d];)if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[M,f];if(g){for(;b=b[d];)if((1===b.nodeType||e)&&a(b,c,g))return!0}else for(;b=b[d];)if(1===b.nodeType||e){if(i=b[K]||(b[K]={}),(h=i[d])&&h[0]===M&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function l(a){return a.length>1?function(b,c,d){for(var e=a.length;e--;)if(!a[e]
 (b,c,d))return!1;return!0}:a[0]}function m(b,c,d){for(var e=0,f=c.length;e<f;e++)a(b,c[e],d);return d}function n(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;h<i;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function o(a,b,d,e,f,g){return e&&!e[K]&&(e=o(e)),f&&!f[K]&&(f=o(f,g)),c(function(c,g,h,i){var j,k,l,o=[],p=[],q=g.length,r=c||m(b||"*",h.nodeType?[h]:h,[]),s=!a||!c&&b?r:n(r,o,a,h,i),t=d?f||(c?a:q||e)?[]:g:s;if(d&&d(s,t,h,i),e)for(j=n(t,p),e(j,[],h,i),k=j.length;k--;)(l=j[k])&&(t[p[k]]=!(s[p[k]]=l));if(c){if(f||a){if(f){for(j=[],k=t.length;k--;)(l=t[k])&&j.push(s[k]=l);f(null,t=[],j,i)}for(k=t.length;k--;)(l=t[k])&&(j=f?$.call(c,l):o[k])>-1&&(c[j]=!(g[j]=l))}}else t=n(t===g?t.splice(q,t.length):t),f?f(null,g,t,i):Y.apply(g,t)})}function p(a){for(var b,c,d,e=a.length,f=t.relative[a[0].type],g=f||t.relative[" "],h=f?1:0,i=k(f
 unction(a){return a===b},g,!0),m=k(function(a){return $.call(b,a)>-1},g,!0),n=[function(a,c,d){return!f&&(d||c!==z)||((b=c).nodeType?i(a,c,d):m(a,c,d))}];h<e;h++)if(c=t.relative[a[h].type])n=[k(l(n),c)];else{if(c=t.filter[a[h].type].apply(null,a[h].matches),c[K]){for(d=++h;d<e&&!t.relative[a[d].type];d++);return o(h>1&&l(n),h>1&&j(a.slice(0,h-1).concat({value:" "===a[h-2].type?"*":""})).replace(ea,"$1"),c,h<d&&p(a.slice(h,d)),d<e&&p(a=a.slice(d)),d<e&&j(a))}n.push(c)}return l(n)}function q(b,d){var e=d.length>0,f=b.length>0,g=function(c,g,h,i,j){var k,l,m,o=0,p="0",q=c&&[],r=[],s=z,u=c||f&&t.find.TAG("*",j),v=M+=null==s?1:Math.random()||.1,w=u.length;for(j&&(z=g!==D&&g);p!==w&&null!=(k=u[p]);p++){if(f&&k){for(l=0;m=b[l++];)if(m(k,g,h)){i.push(k);break}j&&(M=v)}e&&((k=!m&&a
 mp;k)&&o--,c&&q.push(k))}if(o+=p,e&&p!==o){for(l=0;m=d[l++];)m(q,r,g,h);if(c){if(o>0)for(;p--;)q[p]||r[p]||(r[p]=W.call(i));r=n(r)}Y.apply(i,r),j&&!c&&r.length>0&&o+d.length>1&&a.uniqueSort(i)}return j&&(M=v,z=s),q};return e?c(g):g}var r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K="sizzle"+-new Date,L=window.document,M=0,N=0,O=b(),P=b(),Q=b(),R=function(a,b){return a===b&&(B=!0),0},S="undefined",T=1<<31,U={}.hasOwnProperty,V=[],W=V.pop,X=V.push,Y=V.push,Z=V.slice,$=V.indexOf||function(a){for(var b=0,c=this.length;b<c;b++)if(this[b]===a)return b;return-1},_="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",aa="[\\x20\\t\\r\\n\\f]",ba="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",ca="\\["+aa+"*("+ba+")(?:"+aa+"*([*^$|!~]?=)"+aa+"*(?:'((?:\\\\.|[^
 \\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+ba+"))|)"+aa+"*\\]",da=":("+ba+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+ca+")*)|.*)\\)|)",ea=new RegExp("^"+aa+"+|((?:^|[^\\\\])(?:\\\\.)*)"+aa+"+$","g"),fa=new RegExp("^"+aa+"*,"+aa+"*"),ga=new RegExp("^"+aa+"*([>+~]|"+aa+")"+aa+"*"),ha=new RegExp("="+aa+"*([^\\]'\"]*?)"+aa+"*\\]","g"),ia=new RegExp(da),ja=new RegExp("^"+ba+"$"),ka={ID:new RegExp("^#("+ba+")"),CLASS:new RegExp("^\\.("+ba+")"),TAG:new RegExp("^("+ba+"|[*])"),ATTR:new RegExp("^"+ca),PSEUDO:new RegExp("^"+da),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+aa+
 "*(even|odd|(([+-]|)(\\d*)n|)"+aa+"*(?:([+-]|)"+aa+"*(\\d+)|))"+aa+"*\\)|)","i"),bool:new RegExp("^(?:"+_+")$","i"),needsContext:new RegExp("^"+aa+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+aa+"*((?:-\\d)?\\d*)"+aa+"*\\)|)(?=[^-]|$)","i")},la=/^(?:input|select|textarea|button)$/i,ma=/^h\d$/i,na=/^[^{]+\{\s*\[native \w/,oa=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,pa=/[+~]/,qa=/'|\\/g,ra=new RegExp("\\\\([\\da-f]{1,6}"+aa+"?|("+aa+")|.)","ig"),sa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{Y.apply(V=Z.call(L.childNodes),L.childNodes),V[L.childNodes.length].nodeType}catch(a){Y={apply:V.length?function(a,b){X.apply(a,Z.call(b))}:function(a,b){for(var c=a.length,d=0;a[c++]=b[d++];);a.length=c-1}}}s=a.s
 upport={},v=a.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},C=a.setDocument=function(a){function b(a){try{return a.top}catch(a){}return null}var c,e=a?a.ownerDocument||a:L,f=e.defaultView;return e!==D&&9===e.nodeType&&e.documentElement?(D=e,E=e.documentElement,F=!v(e),f&&f!==b(f)&&(f.addEventListener?f.addEventListener("unload",function(){C()},!1):f.attachEvent&&f.attachEvent("onunload",function(){C()})),s.attributes=!0,s.getElementsByTagName=!0,s.getElementsByClassName=na.test(e.getElementsByClassName),s.getById=!0,t.find.ID=function(a,b){if(typeof b.getElementById!==S&&F){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},t.filter.ID=function(a){var b=a.replace(ra,sa);return function(a){return a.getAttribute("id")===b}},t.find.TAG=s.getElementsByTagName?function(a,b){if(typeof b.getElementsByTagName!==S)return b.ge
 tElementsByTagName(a)}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){for(;c=f[e++];)1===c.nodeType&&d.push(c);return d}return f},t.find.CLASS=s.getElementsByClassName&&function(a,b){if(F)return b.getElementsByClassName(a)},H=[],G=[],s.disconnectedMatch=!0,G=G.length&&new RegExp(G.join("|")),H=H.length&&new RegExp(H.join("|")),c=na.test(E.compareDocumentPosition),J=c||na.test(E.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)for(;b=b.parentNode;)if(b===a)return!0;return!1},R=c?function(a,b){if(a===b)return B=!0,0;var c=!a.compareDocumentPosition-!b.compareDocumentPosition;return c?c:(c=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&c||!s.sortDetached&&b.compareDoc
 umentPosition(a)===c?a===e||a.ownerDocument===L&&J(L,a)?-1:b===e||b.ownerDocument===L&&J(L,b)?1:A?$.call(A,a)-$.call(A,b):0:4&c?-1:1)}:function(a,b){if(a===b)return B=!0,0;var c,f=0,g=a.parentNode,h=b.parentNode,i=[a],j=[b];if(!g||!h)return a===e?-1:b===e?1:g?-1:h?1:A?$.call(A,a)-$.call(A,b):0;if(g===h)return d(a,b);for(c=a;c=c.parentNode;)i.unshift(c);for(c=b;c=c.parentNode;)j.unshift(c);for(;i[f]===j[f];)f++;return f?d(i[f],j[f]):i[f]===L?-1:j[f]===L?1:0},e):D},a.matches=function(b,c){return a(b,null,null,c)},a.matchesSelector=function(b,c){if((b.ownerDocument||b)!==D&&C(b),c=c.replace(ha,"='$1']"),s.matchesSelector&&F&&(!H||!H.test(c))&&(!G||!G.test(c)))try{var d=I.call(b,c);if(d||s.disconnectedMatch||b.document&&11!==b.document.nodeType)return d}catch(a){}return a(c,D,null,[b]).length>0},a.contains=function(a,b){return(a.ownerDocument||a)!==D&&C(a),J(a,b)},a.attr=function(a,b){(a.ownerDocument||a)!=
 =D&&C(a);var c=t.attrHandle[b.toLowerCase()],d=c&&U.call(t.attrHandle,b.toLowerCase())?c(a,b,!F):void 0;return void 0!==d?d:s.attributes||!F?a.getAttribute(b):(d=a.getAttributeNode(b))&&d.specified?d.value:null},a.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},a.uniqueSort=function(a){var b,c=[],d=0,e=0;if(B=!s.detectDuplicates,A=!s.sortStable&&a.slice(0),a.sort(R),B){for(;b=a[e++];)b===a[e]&&(d=c.push(e));for(;d--;)a.splice(c[d],1)}return A=null,a},u=a.getText=function(a){var b,c="",d=0,e=a.nodeType;if(e){if(1===e||9===e||11===e){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=u(a)}else if(3===e||4===e)return a.nodeValue}else for(;b=a[d++];)c+=u(b);return c},t=a.selectors={cacheLength:50,createPseudo:c,match:ka,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode&qu
 ot;},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ra,sa),a[3]=(a[3]||a[4]||a[5]||"").replace(ra,sa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(b){return b[1]=b[1].toLowerCase(),"nth"===b[1].slice(0,3)?(b[3]||a.error(b[0]),b[4]=+(b[4]?b[5]+(b[6]||1):2*("even"===b[3]||"odd"===b[3])),b[5]=+(b[7]+b[8]||"odd"===b[3])):b[3]&&a.error(b[0]),b},PSEUDO:function(a){var b,c=!a[6]&&a[2];return ka.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&ia.test(c)&&(b=w(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ra,sa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.n
 odeName.toLowerCase()===b}},CLASS:function(a){var b=O[a+" "];return b||(b=new RegExp("(^|"+aa+")"+a+"("+aa+"|$)"))&&O(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==S&&a.getAttribute("class")||"")})},ATTR:function(b,c,d){return function(e){var f=a.attr(e,b);return null==f?"!="===c:!c||(f+="","="===c?f===d:"!="===c?f!==d:"^="===c?d&&0===f.indexOf(d):"*="===c?d&&f.indexOf(d)>-1:"$="===c?d&&f.slice(-d.length)===d:"~="===c?(" "+f+" ").indexOf(d)>-1:"|="===c&&(f===d||f.slice(0,d.length+1)===d+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:fu
 nction(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){for(;p;){for(l=b;l=l[p];)if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){for(k=q[K]||(q[K]={}),j=k[a]||[],n=j[0]===M&&j[1],m=j[0]===M&&j[2],l=n&&q.childNodes[n];l=++n&&l&&l[p]||(m=n=0)||o.pop();)if(1===l.nodeType&&++m&&l===b){k[a]=[M,n,m];break}}else if(s&&(j=(b[K]||(b[K]={}))[a])&&j[0]===M)m=j[1];else for(;(l=++n&&l&&l[p]||(m=n=0)||o.pop())&&((h?l.nodeName.toLowerCase()!==r:1!==l.nodeType)||!++m||(s&&((l[K]||(l[K]={}))[a]=[M,m]),l!==b)););return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(b,d){var e,f=t.pseudos[b]||t.setFilters[b.toLowerCase()]||a.error("uns
 upported pseudo: "+b);return f[K]?f(d):f.length>1?(e=[b,b,"",d],t.setFilters.hasOwnProperty(b.toLowerCase())?c(function(a,b){for(var c,e=f(a,d),g=e.length;g--;)c=$.call(a,e[g]),a[c]=!(b[c]=e[g])}):function(a){return f(a,0,e)}):f}},pseudos:{not:c(function(a){var b=[],d=[],e=x(a.replace(ea,"$1"));return e[K]?c(function(a,b,c,d){for(var f,g=e(a,null,d,[]),h=a.length;h--;)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,c,f){return b[0]=a,e(b,null,f,d),!d.pop()}}),has:c(function(b){return function(c){return a(b,c).length>0}}),contains:c(function(a){return a=a.replace(ra,sa),function(b){return(b.textContent||b.innerText||u(b)).indexOf(a)>-1}}),lang:c(function(b){return ja.test(b||"")||a.error("unsupported lang: "+b),b=b.replace(ra,sa).toLowerCase(),function(a){var c;do if(c=F?a.lang:a.getAttribute("xml:lang")||a.getAttribute("lang"))return c=c.toLowerCase(),c===b||0===c.indexOf(b+"-");while((a=a.parentNode
 )&&1===a.nodeType);return!1}}),target:function(a){var b=window.location&&window.location.hash;return b&&b.slice(1)===a.id},root:function(a){return a===E},focus:function(a){return a===D.activeElement&&(!D.hasFocus||D.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!t.pseudos.empty(a)},header:function(a){return ma.test(a.nodeName)},input:function(a){return la.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button&quot
 ;===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:g(function(){return[0]}),last:g(function(a,b){return[b-1]}),eq:g(function(a,b,c){return[c<0?c+b:c]}),even:g(function(a,b){for(var c=0;c<b;c+=2)a.push(c);return a}),odd:g(function(a,b){for(var c=1;c<b;c+=2)a.push(c);return a}),lt:g(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:g(function(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},t.pseudos.nth=t.pseudos.eq;for(r in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})t.pseudos[r]=e(r);for(r in{submit:!0,reset:!0})t.pseudos[r]=f(r);return i.prototype=t.filters=t.pseudos,t.setFilters=new i,w=a.tokenize=function(b,c){var d,e,f,g,h,i,j,k=P[b+" "];if(k)return c?0:k.slice(0);for(h=b,i=[],j=t.preFilter;h;){d&&!(e=fa.exec(h))||(e&&(h=h.slice(e[0].length
 )||h),i.push(f=[])),d=!1,(e=ga.exec(h))&&(d=e.shift(),f.push({value:d,type:e[0].replace(ea," ")}),h=h.slice(d.length));for(g in t.filter)!(e=ka[g].exec(h))||j[g]&&!(e=j[g](e))||(d=e.shift(),f.push({value:d,type:g,matches:e}),h=h.slice(d.length));if(!d)break}return c?h.length:h?a.error(b):P(b,i).slice(0)},x=a.compile=function(a,b){var c,d=[],e=[],f=Q[a+" "];if(!f){for(b||(b=w(a)),c=b.length;c--;)f=p(b[c]),f[K]?d.push(f):e.push(f);f=Q(a,q(e,d)),f.selector=a}return f},y=a.select=function(a,b,c,d){var e,f,g,i,k,l="function"==typeof a&&a,m=!d&&w(a=l.selector||a);if(c=c||[],1===m.length){if(f=m[0]=m[0].slice(0),f.length>2&&"ID"===(g=f[0]).type&&s.getById&&9===b.nodeType&&F&&t.relative[f[1].type]){if(b=(t.find.ID(g.matches[0].replace(ra,sa),b)||[])[0],!b)return c;l&&(b=b.parentNode),a=a.slice(f.shift().value.length)}for(e=ka.needsContext.test(a)?0:f.length;e--&&amp
 ;(g=f[e],!t.relative[i=g.type]);)if((k=t.find[i])&&(d=k(g.matches[0].replace(ra,sa),pa.test(f[0].type)&&h(b.parentNode)||b))){if(f.splice(e,1),a=d.length&&j(f),!a)return Y.apply(c,d),c;break}}return(l||x(a,m))(d,b,!F,c,pa.test(a)&&h(b.parentNode)||b),c},s.sortStable=K.split("").sort(R).join("")===K,s.detectDuplicates=!!B,C(),s.sortDetached=!0,a}),g("1h",[],function(){function a(a){var b,c,d=a;if(!j(a))for(d=[],b=0,c=a.length;b<c;b++)d[b]=a[b];return d}function b(a,b,c){var d,e;if(!a)return 0;if(c=c||a,void 0!==a.length){for(d=0,e=a.length;d<e;d++)if(b.call(c,a[d],d,a)===!1)return 0}else for(d in a)if(a.hasOwnProperty(d)&&b.call(c,a[d],d,a)===!1)return 0;return 1}function c(a,c){var d=[];return b(a,function(b,e){d.push(c(b,e,a))}),d}function d(a,c){var d=[];return b(a,function(b,e){c&&!c(b,e,a)||d.push(b)}),d}function e(a,b){var c,d;if(a)for(c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1}func
 tion f(a,b,c,d){var e=0;for(arguments.length<3&&(c=a[0]);e<a.length;e++)c=b.call(d,c,a[e],e);return c}function g(a,b,c){var d,e;for(d=0,e=a.length;d<e;d++)if(b.call(c,a[d],d,a))return d;return-1}function h(a,b,c){var d=g(a,b,c);if(d!==-1)return a[d]}function i(a){return a[a.length-1]}var j=Array.isArray||function(a){return"[object Array]"===Object.prototype.toString.call(a)};return{isArray:j,toArray:a,each:b,map:c,filter:d,indexOf:e,reduce:f,findIndex:g,find:h,last:i}}),g("1d",["o","1h"],function(a,b){function c(a){return null===a||void 0===a?"":(""+a).replace(n,"")}function d(a,c){return c?!("array"!=c||!b.isArray(a))||typeof a==c:void 0!==a}function e(a,b,c){var d;for(a=a||[],b=b||",","string"==typeof a&&(a=a.split(b)),c=c||{},d=a.length;d--;)c[a[d]]={};return c}function f(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function g(a,b,c){var d,e,f,g,h,
 i=this,j=0;if(a=/^((static) )?([\w.]+)(:([\w.]+))?/.exec(a),f=a[3].match(/(^|\.)(\w+)$/i)[2],e=i.createNS(a[3].replace(/\.\w+$/,""),c),!e[f]){if("static"==a[2])return e[f]=b,void(this.onCreate&&this.onCreate(a[2],a[3],e[f]));b[f]||(b[f]=function(){},j=1),e[f]=b[f],i.extend(e[f].prototype,b),a[5]&&(d=i.resolve(a[5]).prototype,g=a[5].match(/\.(\w+)$/i)[1],h=e[f],j?e[f]=function(){return d[g].apply(this,arguments)}:e[f]=function(){return this.parent=d[g],h.apply(this,arguments)},e[f].prototype[f]=e[f],i.each(d,function(a,b){e[f].prototype[b]=d[b]}),i.each(b,function(a,b){d[b]?e[f].prototype[b]=function(){return this.parent=d[b],a.apply(this,arguments)}:b!=f&&(e[f].prototype[b]=a)})),i.each(b["static"],function(a,b){e[f][b]=a})}}function h(a,b){var c,d,e,f,g=arguments;for(c=1,d=g.length;c<d;c++){b=g[c];for(e in b)b.hasOwnProperty(e)&&(f=b[e],void 0!==f&&(a[e]=f))}return a}function i(a,c,d,e){e=e||this,a&&(d
 &&(a=a[d]),b.each(a,function(a,b){return c.call(e,a,b,d)!==!1&&void i(a,c,d,e)}))}function j(a,b){var c,d;for(b=b||window,a=a.split("."),c=0;c<a.length;c++)d=a[c],b[d]||(b[d]={}),b=b[d];return b}function k(a,b){var c,d;for(b=b||window,a=a.split("."),c=0,d=a.length;c<d&&(b=b[a[c]],b);c++);return b}function l(a,e){return!a||d(a,"array")?a:b.map(a.split(e||","),c)}function m(b){var c=a.cacheSuffix;return c&&(b+=(b.indexOf("?")===-1?"?":"&")+c),b}var n=/^\s*|\s*$/g;return{trim:c,isArray:b.isArray,is:d,toArray:b.toArray,makeMap:e,each:b.each,map:b.map,grep:b.filter,inArray:b.indexOf,hasOwn:f,extend:h,create:g,walk:i,createNS:j,resolve:k,explode:l,_addCacheSuffix:m}}),g("b",["d","i","1d","o"],function(a,b,c,d){function e(a){return"undefined"!=typeof a}function f(a){return"string"==typeof a}function g(a){return
  a&&a==a.window}function h(a,b){var c,d,e;for(b=b||w,e=b.createElement("div"),c=b.createDocumentFragment(),e.innerHTML=a;d=e.firstChild;)c.appendChild(d);return c}function i(a,b,c,d){var e;if(f(b))b=h(b,q(a[0]));else if(b.length&&!b.nodeType){if(b=l.makeArray(b),d)for(e=b.length-1;e>=0;e--)i(a,b[e],c,d);else for(e=0;e<b.length;e++)i(a,b[e],c,d);return a}if(b.nodeType)for(e=a.length;e--;)c.call(a[e],b);return a}function j(a,b){return a&&b&&(" "+a.className+" ").indexOf(" "+b+" ")!==-1}function k(a,b,c){var d,e;return b=l(b)[0],a.each(function(){var a=this;c&&d==a.parentNode?e.appendChild(a):(d=a.parentNode,e=b.cloneNode(!1),a.parentNode.insertBefore(e,a),e.appendChild(a))}),a}function l(a,b){return new l.fn.init(a,b)}function m(a,b){var c;if(b.indexOf)return b.indexOf(a);for(c=b.length;c--;)if(b[c]===a)return c;return-1}function n(a){return null===a||a===v?"":(""+a).rep
 lace(I,"")}function o(a,b){var c,d,e,f,g;if(a)if(c=a.length,c===f){for(d in a)if(a.hasOwnProperty(d)&&(g=a[d],b.call(g,d,g)===!1))break}else for(e=0;e<c&&(g=a[e],b.call(g,e,g)!==!1);e++);return a}function p(a,b){var c=[];return o(a,function(a,d){b(d,a)&&c.push(d)}),c}function q(a){return a?9==a.nodeType?a:a.ownerDocument:w}function r(a,b,c){var d=[],e=a[b];for("string"!=typeof c&&c instanceof l&&(c=c[0]);e&&9!==e.nodeType;){if(void 0!==c){if(e===c)break;if("string"==typeof c&&l(e).is(c))break}1===e.nodeType&&d.push(e),e=e[b]}return d}function s(a,b,c,d){var e=[];for(d instanceof l&&(d=d[0]);a;a=a[b])if(!c||a.nodeType===c){if(void 0!==d){if(a===d)break;if("string"==typeof d&&l(a).is(d))break}e.push(a)}return e}function t(a,b,c){for(a=a[b];a;a=a[b])if(a.nodeType==c)return a;return null}function u(a,b,c){o(c,function(c,d){a[c]=a[c]||{},a[c][b]=d})}var v,w=document,
 x=Array.prototype.push,y=Array.prototype.slice,z=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,A=a.Event,B=c.makeMap("children,contents,next,prev"),C=c.makeMap("fillOpacity fontWeight lineHeight opacity orphans widows zIndex zoom"," "),D=c.makeMap("checked compact declare defer disabled ismap multiple nohref noshade nowrap readonly selected"," "),E={"for":"htmlFor","class":"className",readonly:"readOnly"},F={"float":"cssFloat"},G={},H={},I=/^\s*|\s*$/g;return l.fn=l.prototype={constructor:l,selector:"",context:null,
+length:0,init:function(a,b){var c,d,e=this;if(!a)return e;if(a.nodeType)return e.context=e[0]=a,e.length=1,e;if(b&&b.nodeType)e.context=b;else{if(b)return l(a).attr(b);e.context=b=document}if(f(a)){if(e.selector=a,c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c)return l(b).find(a);if(c[1])for(d=h(a,q(b)).firstChild;d;)x.call(e,d),d=d.nextSibling;else{if(d=q(b).getElementById(c[2]),!d)return e;if(d.id!==c[2])return e.find(a);e.length=1,e[0]=d}}else this.add(a,!1);return e},toArray:function(){return c.toArray(this)},add:function(a,b){var c,d,e=this;if(f(a))return e.add(l(a));if(b!==!1)for(c=l.unique(e.toArray().concat(l.makeArray(a))),e.length=c.length,d=0;d<c.length;d++)e[d]=c[d];else x.apply(e,l.makeArray(a));return e},attr:function(a,b){var c,d=this;if("object"==typeof a)o(a,function(a,b){d.attr(a,b)});else{if(!e(b)){if(d[0]&&1===d[0].nodeType){if(c=G[a],c&&c.ge
 t)return c.get(d[0],a);if(D[a])return d.prop(a)?a:v;b=d[0].getAttribute(a,2),null===b&&(b=v)}return b}this.each(function(){var c;if(1===this.nodeType){if(c=G[a],c&&c.set)return void c.set(this,b);null===b?this.removeAttribute(a,2):this.setAttribute(a,b,2)}})}return d},removeAttr:function(a){return this.attr(a,null)},prop:function(a,b){var c=this;if(a=E[a]||a,"object"==typeof a)o(a,function(a,b){c.prop(a,b)});else{if(!e(b))return c[0]&&c[0].nodeType&&a in c[0]?c[0][a]:b;this.each(function(){1==this.nodeType&&(this[a]=b)})}return c},css:function(a,b){function c(a){return a.replace(/-(\D)/g,function(a,b){return b.toUpperCase()})}function d(a){return a.replace(/[A-Z]/g,function(a){return"-"+a})}var f,g,h=this;if("object"==typeof a)o(a,function(a,b){h.css(a,b)});else if(e(b))a=c(a),"number"!=typeof b||C[a]||(b+="px"),h.each(function(){var c=this.style;if(g=H[a],g&&g.set)return void g.set(thi
 s,b);try{this.style[F[a]||a]=b}catch(a){}null!==b&&""!==b||(c.removeProperty?c.removeProperty(d(a)):c.removeAttribute(a))});else{if(f=h[0],g=H[a],g&&g.get)return g.get(f);if(f.ownerDocument.defaultView)try{return f.ownerDocument.defaultView.getComputedStyle(f,null).getPropertyValue(d(a))}catch(a){return v}else if(f.currentStyle)return f.currentStyle[c(a)]}return h},remove:function(){for(var a,b=this,c=this.length;c--;)a=b[c],A.clean(a),a.parentNode&&a.parentNode.removeChild(a);return this},empty:function(){for(var a,b=this,c=this.length;c--;)for(a=b[c];a.firstChild;)a.removeChild(a.firstChild);return this},html:function(a){var b,c=this;if(e(a)){b=c.length;try{for(;b--;)c[b].innerHTML=a}catch(d){l(c[b]).empty().append(a)}return c}return c[0]?c[0].innerHTML:""},text:function(a){var b,c=this;if(e(a)){for(b=c.length;b--;)"innerText"in c[b]?c[b].innerText=a:c[0].textContent=a;return c}return c[0]?c[0].innerText||c[0].textContent:&quot
 ;"},append:function(){return i(this,arguments,function(a){(1===this.nodeType||this.host&&1===this.host.nodeType)&&this.appendChild(a)})},prepend:function(){return i(this,arguments,function(a){(1===this.nodeType||this.host&&1===this.host.nodeType)&&this.insertBefore(a,this.firstChild)},!0)},before:function(){var a=this;return a[0]&&a[0].parentNode?i(a,arguments,function(a){this.parentNode.insertBefore(a,this)}):a},after:function(){var a=this;return a[0]&&a[0].parentNode?i(a,arguments,function(a){this.parentNode.insertBefore(a,this.nextSibling)},!0):a},appendTo:function(a){return l(a).append(this),this},prependTo:function(a){return l(a).prepend(this),this},replaceWith:function(a){return this.before(a).remove()},wrap:function(a){return k(this,a)},wrapAll:function(a){return k(this,a,!0)},wrapInner:function(a){return this.each(function(){l(this).contents().wrapAll(a)}),this},unwrap:function(){return this.parent().each(function(){l(this
 ).replaceWith(this.childNodes)})},clone:function(){var a=[];return this.each(function(){a.push(this.cloneNode(!0))}),l(a)},addClass:function(a){return this.toggleClass(a,!0)},removeClass:function(a){return this.toggleClass(a,!1)},toggleClass:function(a,b){var c=this;return"string"!=typeof a?c:(a.indexOf(" ")!==-1?o(a.split(" "),function(){c.toggleClass(this,b)}):c.each(function(c,d){var e,f;f=j(d,a),f!==b&&(e=d.className,f?d.className=n((" "+e+" ").replace(" "+a+" "," ")):d.className+=e?" "+a:a)}),c)},hasClass:function(a){return j(this[0],a)},each:function(a){return o(this,a)},on:function(a,b){return this.each(function(){A.bind(this,a,b)})},off:function(a,b){return this.each(function(){A.unbind(this,a,b)})},trigger:function(a){return this.each(function(){"object"==typeof a?A.fire(this,a.type,a):A.fire(this,a)})},show:function(){return this.css("display","")
 },hide:function(){return this.css("display","none")},slice:function(){return new l(y.apply(this,arguments))},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},find:function(a){var b,c,d=[];for(b=0,c=this.length;b<c;b++)l.find(a,this[b],d);return l(d)},filter:function(a){return l("function"==typeof a?p(this.toArray(),function(b,c){return a(c,b)}):l.filter(a,this.toArray()))},closest:function(a){var b=[];return a instanceof l&&(a=a[0]),this.each(function(c,d){for(;d;){if("string"==typeof a&&l(d).is(a)){b.push(d);break}if(d==a){b.push(d);break}d=d.parentNode}}),l(b)},offset:function(a){var b,c,d,e,f=0,g=0;return a?this.css(a):(b=this[0],b&&(c=b.ownerDocument,d=c.documentElement,b.getBoundingClientRect&&(e=b.getBoundingClientRect(),f=e.left+(d.scrollLeft||c.body.scrollLeft)-d.clientLeft,g=e.top+(d.scrollTop||c.body.scrollTop)-d.c
 lientTop)),{left:f,top:g})},push:x,sort:[].sort,splice:[].splice},c.extend(l,{extend:c.extend,makeArray:function(a){return g(a)||a.nodeType?[a]:c.toArray(a)},inArray:m,isArray:c.isArray,each:o,trim:n,grep:p,find:b,expr:b.selectors,unique:b.uniqueSort,text:b.getText,contains:b.contains,filter:function(a,b,c){var d=b.length;for(c&&(a=":not("+a+")");d--;)1!=b[d].nodeType&&b.splice(d,1);return b=1===b.length?l.find.matchesSelector(b[0],a)?[b[0]]:[]:l.find.matches(a,b)}}),o({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return r(a,"parentNode")},next:function(a){return t(a,"nextSibling",1)},prev:function(a){return t(a,"previousSibling",1)},children:function(a){return s(a.firstChild,"nextSibling",1)},contents:function(a){return c.toArray(("iframe"===a.nodeName?a.contentDocument||a.contentWindow.document:a).childNodes)}},function(a,b){l.fn[a]=function(
 c){var d=this,e=[];return d.each(function(){var a=b.call(e,this,c,e);a&&(l.isArray(a)?e.push.apply(e,a):e.push(a))}),this.length>1&&(B[a]||(e=l.unique(e)),0===a.indexOf("parents")&&(e=e.reverse())),e=l(e),c?e.filter(c):e}}),o({parentsUntil:function(a,b){return r(a,"parentNode",b)},nextUntil:function(a,b){return s(a,"nextSibling",1,b).slice(1)},prevUntil:function(a,b){return s(a,"previousSibling",1,b).slice(1)}},function(a,b){l.fn[a]=function(c,d){var e=this,f=[];return e.each(function(){var a=b.call(f,this,c,f);a&&(l.isArray(a)?f.push.apply(f,a):f.push(a))}),this.length>1&&(f=l.unique(f),0!==a.indexOf("parents")&&"prevUntil"!==a||(f=f.reverse())),f=l(f),d?f.filter(d):f}}),l.fn.is=function(a){return!!a&&this.filter(a).length>0},l.fn.init.prototype=l.fn,l.overrideDefaults=function(a){function b(d,e){return c=c||a(),0===arguments.length&&(d=c.element),e||
 (e=c.context),new b.fn.init(d,e)}var c;return l.extend(b,this),b},d.ie&&d.ie<8&&(u(G,"get",{maxlength:function(a){var b=a.maxLength;return 2147483647===b?v:b},size:function(a){var b=a.size;return 20===b?v:b},"class":function(a){return a.className},style:function(a){var b=a.style.cssText;return 0===b.length?v:b}}),u(G,"set",{"class":function(a,b){a.className=b},style:function(a,b){a.style.cssText=b}})),d.ie&&d.ie<9&&(F["float"]="styleFloat",u(H,"set",{opacity:function(a,b){var c=a.style;null===b||""===b?c.removeAttribute("filter"):(c.zoom=1,c.filter="alpha(opacity="+100*b+")")}})),l.attrHooks=G,l.cssHooks=H,l}),g("1i",["1d"],function(a){function b(c){function d(){return J.createDocumentFragment()}function e(a,b){x(N,a,b)}function f(a,b){x(O,a,b)}function g(a){e(a.parentNode,U(a))}function h(a){e(a.parentNode,U(a)+1)}fu
 nction i(a){f(a.parentNode,U(a))}function j(a){f(a.parentNode,U(a)+1)}function k(a){a?(I[R]=I[Q],I[S]=I[P]):(I[Q]=I[R],I[P]=I[S]),I.collapsed=N}function l(a){g(a),j(a)}function m(a){e(a,0),f(a,1===a.nodeType?a.childNodes.length:a.nodeValue.length)}function n(a,b){var c=I[Q],d=I[P],e=I[R],f=I[S],g=b.startContainer,h=b.startOffset,i=b.endContainer,j=b.endOffset;return 0===a?w(c,d,g,h):1===a?w(e,f,g,h):2===a?w(e,f,i,j):3===a?w(c,d,i,j):void 0}function o(){y(M)}function p(){return y(K)}function q(){return y(L)}function r(a){var b,d,e=this[Q],f=this[P];3!==e.nodeType&&4!==e.nodeType||!e.nodeValue?(e.childNodes.length>0&&(d=e.childNodes[f]),d?e.insertBefore(a,d):3==e.nodeType?c.insertAfter(a,e):e.appendChild(a)):f?f>=e.nodeValue.length?c.insertAfter(a,e):(b=e.splitText(f),e.parentNode.insertBefore(a,b)):e.parentNode.insertBefore(a,e)}function s(a){var b=I.extractContents();I.insertNode(a),a.appendChild(b),I.selectNode(a)}function t(){return T(new b(c),{startContainer
 :I[Q],startOffset:I[P],endContainer:I[R],endOffset:I[S],collapsed:I.collapsed,commonAncestorContainer:I.commonAncestorContainer})}function u(a,b){var c;if(3==a.nodeType)return a;if(b<0)return a;for(c=a.firstChild;c&&b>0;)--b,c=c.nextSibling;return c?c:a}function v(){return I[Q]==I[R]&&I[P]==I[S]}function w(a,b,d,e){var f,g,h,i,j,k;if(a==d)return b==e?0:b<e?-1:1;for(f=d;f&&f.parentNode!=a;)f=f.parentNode;if(f){for(g=0,h=a.firstChild;h!=f&&g<b;)g++,h=h.nextSibling;return b<=g?-1:1}for(f=a;f&&f.parentNode!=d;)f=f.parentNode;if(f){for(g=0,h=d.firstChild;h!=f&&g<e;)g++,h=h.nextSibling;return g<e?-1:1}for(i=c.findCommonAncestor(a,d),j=a;j&&j.parentNode!=i;)j=j.parentNode;for(j||(j=i),k=d;k&&k.parentNode!=i;)k=k.parentNode;if(k||(k=i),j==k)return 0;for(h=i.firstChild;h;){if(h==j)return-1;if(h==k)return 1;h=h.nextSibling}}function x(a,b,d){var e,f;for(a?(I[Q]=b,I[P]=d):(I[R]=b,I[S]=d),e=I[R];e.parentNode;)e
 =e.parentNode;for(f=I[Q];f.parentNode;)f=f.parentNode;f==e?w(I[Q],I[P],I[R],I[S])>0&&I.collapse(a):I.collapse(a),I.collapsed=v(),I.commonAncestorContainer=c.findCommonAncestor(I[Q],I[R])}function y(a){var b,c,d,e,f,g,h,i=0,j=0;if(I[Q]==I[R])return z(a);for(b=I[R],c=b.parentNode;c;b=c,c=c.parentNode){if(c==I[Q])return A(b,a);++i}for(b=I[Q],c=b.parentNode;c;b=c,c=c.parentNode){if(c==I[R])return B(b,a);++j}for(d=j-i,e=I[Q];d>0;)e=e.parentNode,d--;for(f=I[R];d<0;)f=f.parentNode,d++;for(g=e.parentNode,h=f.parentNode;g!=h;g=g.parentNode,h=h.parentNode)e=g,f=h;return C(e,f,a)}function z(a){var b,c,e,f,g,h,i,j,k;if(a!=M&&(b=d()),I[P]==I[S])return b;if(3==I[Q].nodeType){if(c=I[Q].nodeValue,e=c.substring(I[P],I[S]),a!=L&&(f=I[Q],j=I[P],k=I[S]-I[P],0===j&&k>=f.nodeValue.length-1?f.parentNode.removeChild(f):f.deleteData(j,k),I.collapse(N)),a==M)return;return e.length>0&&b.appendChild(J.createTextNode(e)),b}for(f=u(I[Q],I[P]),g=I[S]-I[P];f&a
 mp;&g>0;)h=f.nextSibling,i=G(f,a),b&&b.appendChild(i),--g,f=h;return a!=L&&I.collapse(N),b}function A(a,b){var c,e,f,g,h,i;if(b!=M&&(c=d()),e=D(a,b),c&&c.appendChild(e),f=U(a),g=f-I[P],g<=0)return b!=L&&(I.setEndBefore(a),I.collapse(O)),c;for(e=a.previousSibling;g>0;)h=e.previousSibling,i=G(e,b),c&&c.insertBefore(i,c.firstChild),--g,e=h;return b!=L&&(I.setEndBefore(a),I.collapse(O)),c}function B(a,b){var c,e,f,g,h,i;for(b!=M&&(c=d()),f=E(a,b),c&&c.appendChild(f),e=U(a),++e,g=I[S]-e,f=a.nextSibling;f&&g>0;)h=f.nextSibling,i=G(f,b),c&&c.appendChild(i),--g,f=h;return b!=L&&(I.setStartAfter(a),I.collapse(N)),c}function C(a,b,c){var e,f,g,h,i,j,k;for(c!=M&&(f=d()),e=E(a,c),f&&f.appendChild(e),g=U(a),h=U(b),++g,i=h-g,j=a.nextSibling;i>0;)k=j.nextSibling,e=G(j,c),f&&f.appendChild(e),j=k,--i;return e=D(b,c),f&&f.appendChild(e),c!=L&&(I.se
 tStartAfter(a),I.collapse(N)),f}function D(a,b){var c,d,e,f,g,h=u(I[R],I[S]-1),i=h!=I[R];if(h==a)return F(h,i,O,b);for(c=h.parentNode,d=F(c,O,O,b);c;){for(;h;)e=h.previousSibling,f=F(h,i,O,b),b!=M&&d.insertBefore(f,d.firstChild),i=N,h=e;if(c==a)return d;h=c.previousSibling,c=c.parentNode,g=F(c,O,O,b),b!=M&&g.appendChild(d),d=g}}function E(a,b){var c,d,e,f,g,h=u(I[Q],I[P]),i=h!=I[Q];if(h==a)return F(h,i,N,b);for(c=h.parentNode,d=F(c,O,N,b);c;){for(;h;)e=h.nextSibling,f=F(h,i,N,b),b!=M&&d.appendChild(f),i=N,h=e;if(c==a)return d;h=c.nextSibling,c=c.parentNode,g=F(c,O,N,b),b!=M&&g.appendChild(d),d=g}}function F(a,b,d,e){var f,g,h,i,j;if(b)return G(a,e);if(3==a.nodeType){if(f=a.nodeValue,d?(i=I[P],g=f.substring(i),h=f.substring(0,i)):(i=I[S],g=f.substring(0,i),h=f.substring(i)),e!=L&&(a.nodeValue=h),e==M)return;return j=c.clone(a,O),j.nodeValue=g,j}if(e!=M)return c.clone(a,O)}function G(a,b){return b!=M?b==L?c.clone(a,N):a:void a.parentNode.removeC
 hild(a)}function H(){return c.create("body",null,q()).outerText}var I=this,J=c.doc,K=0,L=1,M=2,N=!0,O=!1,P="startOffset",Q="startContainer",R="endContainer",S="endOffset",T=a.extend,U=c.nodeIndex;return T(I,{startContainer:J,startOffset:0,endContainer:J,endOffset:0,collapsed:N,commonAncestorContainer:J,START_TO_START:0,START_TO_END:1,END_TO_END:2,END_TO_START:3,setStart:e,setEnd:f,setStartBefore:g,setStartAfter:h,setEndBefore:i,setEndAfter:j,collapse:k,selectNode:l,selectNodeContents:m,compareBoundaryPoints:n,deleteContents:o,extractContents:p,cloneContents:q,insertNode:r,surroundContents:s,cloneRange:t,toStringIE:H}),I}return b.prototype.toString=function(){return this.toStringIE()},b}),h("4d",Object),g("1u",["1","4d"],function(a,b){var c=a.never,d=a.always,e=function(){return f},f=function(){var f=function(a){return a.isNone()},g=function(a){return a()},h=function(a){return a},i=function(){},
 j={fold:function(a,b){return a()},is:c,isSome:c,isNone:d,getOr:h,getOrThunk:g,getOrDie:function(a){throw new Error(a||"error: getOrDie called on none.")},or:h,orThunk:g,map:e,ap:e,each:i,bind:e,flatten:e,exists:c,forall:d,filter:e,equals:f,equals_:f,toArray:function(){return[]},toString:a.constant("none()")};return b.freeze&&b.freeze(j),j}(),g=function(a){var b=function(){return a},h=function(){return k},i=function(b){return g(b(a))},j=function(b){return b(a)},k={fold:function(b,c){return c(a)},is:function(b){return a===b},isSome:d,isNone:c,getOr:b,getOrThunk:b,getOrDie:b,or:h,orThunk:h,map:i,ap:function(b){return b.fold(e,function(b){return g(b(a))})},each:function(b){b(a)},bind:j,flatten:b,exists:j,forall:j,filter:function(b){return b(a)?k:f},equals:function(b){return b.is(a)},equals_:function(b,d){return b.fold(c,function(b){return d(a,b)})},toArray:function(){return[a]},toString:function(){return"some("+a+")"}};return k},h=function
 (a){return null===a||void 0===a?f:g(a)};return{some:g,none:e,from:h}}),h("4e",String),g("1t",["1u","3","4","4e"],function(a,b,c,d){var e=function(){var a=b.prototype.indexOf,c=function(b,c){return a.call(b,c)},d=function(a,b){return u(a,b)};return void 0===a?d:c}(),f=function(b,c){var d=e(b,c);return d===-1?a.none():a.some(d)},g=function(a,b){return e(a,b)>-1},h=function(a,b){return t(a,b).isSome()},i=function(a,b){for(var c=[],d=0;d<a;d++)c.push(b(d));return c},j=function(a,b){for(var c=[],d=0;d<a.length;d+=b){var e=a.slice(d,d+b);c.push(e)}return c},k=function(a,c){for(var d=a.length,e=new b(d),f=0;f<d;f++){var g=a[f];e[f]=c(g,f,a)}return e},l=function(a,b){for(var c=0,d=a.length;c<d;c++){var e=a[c];b(e,c,a)}},m=function(a,b){for(var c=a.length-1;c>=0;c--){var d=a[c];b(d,c,a)}},n=function(a,b){for(var c=[],d=[],e=0,f=a.length;e<f;e++){var g=a[e],h=b(g,e,a)?c:d;h.push(g)}return{pass:c,fail:d}},o=functi
 on(a,b){for(var c=[],d=0,e=a.length;d<e;d++){var f=a[d];b(f,d,a)&&c.push(f)}return c},p=function(a,b){if(0===a.length)return[];for(var c=b(a[0]),d=[],e=[],f=0,g=a.length;f<g;f++){var h=a[f],i=b(h);i!==c&&(d.push(e),e=[]),c=i,e.push(h)}return 0!==e.length&&d.push(e),d},q=function(a,b,c){return m(a,function(a){c=b(c,a)}),c},r=function(a,b,c){return l(a,function(a){c=b(c,a)}),c},s=function(b,c){for(var d=0,e=b.length;d<e;d++){var f=b[d];if(c(f,d,b))return a.some(f)}return a.none()},t=function(b,c){for(var d=0,e=b.length;d<e;d++){var f=b[d];if(c(f,d,b))return a.some(d)}return a.none()},u=function(a,b){for(var c=0,d=a.length;c<d;++c)if(a[c]===b)return c;return-1},v=b.prototype.push,w=function(a){for(var d=[],e=0,f=a.length;e<f;++e){if(!b.prototype.isPrototypeOf(a[e]))throw new c("Arr.flatten item "+e+" was not an array, input: "+a);v.apply(d,a[e])}return d},x=function(a,b){var c=k(a,b);return w(c)},y=function(a,b){for(var c=0,
 d=a.length;c<d;++c){var e=a[c];if(b(e,c,a)!==!0)return!1}return!0},z=function(a,b){return a.length===b.length&&y(a,function(a,c){return a===b[c]})},A=b.prototype.slice,B=function(a){var b=A.call(a,0);return b.reverse(),b},C=function(a,b){return o(a,function(a){return!g(b,a)})},D=function(a,b){for(var c={},e=0,f=a.length;e<f;e++){var g=a[e];c[d(g)]=b(g,e)}return c},E=function(a){return[a]},F=function(a,b){var c=A.call(a,0);return c.sort(b),c};return{map:k,each:l,eachr:m,partition:n,filter:o,groupBy:p,indexOf:f,foldr:q,foldl:r,find:s,findIndex:t,flatten:w,bind:x,forall:y,exists:h,contains:g,equal:z,reverse:B,chunk:j,difference:C,mapToObject:D,pure:E,sort:F,range:i}}),h("6y",setTimeout),g("5z",["1t","1u","6y"],function(a,b,c){var d=function(e){var f=b.none(),g=[],h=function(a){return d(function(b){i(function(c){b(a(c))})})},i=function(a){k()?m(a):g.push(a)},j=function(a){f=b.some(a),l(g),g=[]},k=function(){return f.isSome(
 )},l=function(b){a.each(b,m)},m=function(a){f.each(function(b){c(function(){a(b)},0)})};return e(j),{get:i,map:h,isReady:k}},e=function(a){return d(function(b){b(a)})};return{nu:d,pure:e}}),g("60",["3","6y"],function(a,b){var c=function(c){return function(){var d=a.prototype.slice.call(arguments),e=this;b(function(){c.apply(e,d)},0)}};return{bounce:c}}),g("4f",["5z","60"],function(a,b){var c=function(d){var e=function(a){d(b.bounce(a))},f=function(a){return c(function(b){e(function(c){var d=a(c);b(d)})})},g=function(a){return c(function(b){e(function(c){a(c).get(b)})})},h=function(a){return c(function(b){e(function(c){a.get(b)})})},i=function(){return a.nu(e)};return{map:f,bind:g,anonBind:h,toLazy:i,get:e}},d=function(a){return c(function(b){b(a)})};return{nu:c,pure:d}}),g("61",["1t"],function(a){var b=function(b,c){return c(function(c){var d=[],e=0,f=function(a){return function(f){d[a]=f,e++,e>=b.len
 gth&&c(d)}};0===b.length?c([]):a.each(b,function(a,b){a.get(f(b))})})};return{par:b}}),g("4g",["1t","4f","61"],function(a,b,c){var d=function(a){return c.par(a,b.nu)},e=function(b,c){var e=a.map(b,c);return d(e)},f=function(a,b){return function(c){return b(c).bind(a)}};return{par:d,mapM:e,compose:f}}),g("4h",["1","1u"],function(a,b){var c=function(d){var e=function(a){return d===a},f=function(a){return c(d)},g=function(a){return c(d)},h=function(a){return c(a(d))},i=function(a){a(d)},j=function(a){return a(d)},k=function(a,b){return b(d)},l=function(a){return a(d)},m=function(a){return a(d)},n=function(){return b.some(d)};return{is:e,isValue:a.constant(!0),isError:a.constant(!1),getOr:a.constant(d),getOrThunk:a.constant(d),getOrDie:a.constant(d),or:f,orThunk:g,fold:k,map:h,each:i,bind:j,exists:l,forall:m,toOption:n}},d=function(c){var e=function(a){return a()},f=function(){return a.die(c)()},g=function(a){
 return a},h=function(a){return a()},i=function(a){return d(c)},j=function(a){return d(c)},k=function(a,b){return a(c)};return{is:a.constant(!1),isValue:a.constant(!1),isError:a.constant(!0),getOr:a.identity,getOrThunk:e,getOrDie:f,or:g,orThunk:h,fold:k,map:i,each:a.noop,bind:j,exists:a.constant(!1),forall:a.constant(!0),toOption:b.none}};return{value:c,error:d}}),g("1j",["1t","1","4f","4g","4h","14","1d"],function(a,b,c,d,e,f,g){"use strict";return function(h,i){function j(a){h.getElementsByTagName("head")[0].appendChild(a)}function k(a,b,c){function d(){for(var a=t.passed,b=a.length;b--;)a[b]();t.status=2,t.passed=[],t.failed=[]}function e(){for(var a=t.failed,b=a.length;b--;)a[b]();t.status=3,t.passed=[],t.failed=[]}function i(){var a=navigator.userAgent.match(/WebKit\/(\d*)/);return!!(a&&a[1]<536)}function k(a,b){a()||((new Date).getTime()-s<l?f.setTimeout(b):e())}fun
 ction o(){k(function(){for(var a,b,c=h.styleSheets,e=c.length;e--;)if(a=c[e],b=a.ownerNode?a.ownerNode:a.owningElement,b&&b.id===q.id)return d(),!0},o)}function p(){k(function(){try{var a=r.sheet.cssRules;return d(),!!a}catch(a){}},p)}var q,r,s,t;if(a=g._addCacheSuffix(a),n[a]?t=n[a]:(t={passed:[],failed:[]},n[a]=t),b&&t.passed.push(b),c&&t.failed.push(c),1!=t.status){if(2==t.status)return void d();if(3==t.status)return void e();if(t.status=1,q=h.createElement("link"),q.rel="stylesheet",q.type="text/css",q.id="u"+m++,q.async=!1,q.defer=!1,s=(new Date).getTime(),"onload"in q&&!i())q.onload=o,q.onerror=e;else{if(navigator.userAgent.indexOf("Firefox")>0)return r=h.createElement("style"),r.textContent='@import "'+a+'"',p(),void j(r);o()}j(q),q.href=a}}var l,m=0,n={};i=i||{},l=i.maxLoadTime||5e3;var o=function(a){return c.nu(function(c){k(a,b.compose(c,b.constant(e.value(a))
 ),b.compose(c,b.constant(e.error(a))))})},p=function(a){return a.fold(b.identity,b.identity)},q=function(b,c,e){d.par(a.map(b,o)).get(function(b){var d=a.partition(b,function(a){return a.isValue()});d.fail.length>0?e(d.fail.map(p)):c(d.pass.map(p))})};return{load:k,loadAll:q}}}),g("j",[],function(){return function(a,b){function c(a,c,d,e){var f,g;if(a){if(!e&&a[c])return a[c];if(a!=b){if(f=a[d])return f;for(g=a.parentNode;g&&g!=b;g=g.parentNode)if(f=g[d])return f}}}function d(a,c,d,e){var f,g,h;if(a){if(f=a[d],b&&f===b)return;if(f){if(!e)for(h=f[c];h;h=h[c])if(!h[c])return h;return f}if(g=a.parentNode,g&&g!==b)return g}}var e=a;this.current=function(){return e},this.next=function(a){return e=c(e,"firstChild","nextSibling",a)},this.prev=function(a){return e=c(e,"lastChild","previousSibling",a)},this.prev2=function(a){return e=d(e,"lastChild","previousSibling",a)}}}),g("s&quot
 ;,["1d"],function(a){function b(a){var b;return b=document.createElement("div"),b.innerHTML=a,b.textContent||b.innerText||a}function c(a,b){var c,d,f,g={};if(a){for(a=a.split(","),b=b||10,c=0;c<a.length;c+=2)d=String.fromCharCode(parseInt(a[c],b)),e[d]||(f="&"+a[c+1]+";",g[d]=f,g[f]=d);return g}}var d,e,f,g=a.makeMap,h=/[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,i=/[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,j=/[<>&\"\']/g,k=/&#([a-z0-9]+);?|&([a-z0-9]+);/gi,l={128:"\u20ac",130:"\u201a",131:"\u0192",132:"\u201e",133:"\u2026",134:"\u2020",135:"\u2021",136:"\u02c6",137:"\u2030",138:"\u0160",139:"\u2039",140:"\u0152",142:"\u017d",145:"\u2018",146:"\u2019",147:"\u201c",148:&qu
 ot;\u201d",149:"\u2022",150:"\u2013",151:"\u2014",152:"\u02dc",153:"\u2122",154:"\u0161",155:"\u203a",156:"\u0153",158:"\u017e",159:"\u0178"};e={'"':"&quot;","'":"&#39;","<":"&lt;",">":"&gt;","&":"&amp;","`":"&#96;"},f={"&lt;":"<","&gt;":">","&amp;":"&","&quot;":'"',"&apos;":"'"},d=c("50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Arin
 g,66,AElig,67,Ccedil,68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,t9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip
 ,81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro",32);var m={encodeRaw:function(a,b){return a.replace(b?h:i,function(a){return e
 [a]||a})},encodeAllRaw:function(a){return(""+a).replace(j,function(a){return e[a]||a})},encodeNumeric:function(a,b){return a.replace(b?h:i,function(a){return a.length>1?"&#"+(1024*(a.charCodeAt(0)-55296)+(a.charCodeAt(1)-56320)+65536)+";":e[a]||"&#"+a.charCodeAt(0)+";"})},encodeNamed:function(a,b,c){return c=c||d,a.replace(b?h:i,function(a){return e[a]||c[a]||a})},getEncodeFunc:function(a,b){function f(a,c){return a.replace(c?h:i,function(a){return void 0!==e[a]?e[a]:void 0!==b[a]?b[a]:a.length>1?"&#"+(1024*(a.charCodeAt(0)-55296)+(a.charCodeAt(1)-56320)+65536)+";":"&#"+a.charCodeAt(0)+";"})}function j(a,c){return m.encodeNamed(a,c,b)}return b=c(b)||d,a=g(a.replace(/\+/g,",")),a.named&&a.numeric?f:a.named?b?j:m.encodeNamed:a.numeric?m.encodeNumeric:m.encodeRaw},decode:function(a){return a.replace(k,function(a,c){return c?(c="x"===c.charAt(0).toL
 owerCase()?parseInt(c.substr(1),16):parseInt(c,10),c>65535?(c-=65536,String.fromCharCode(55296+(c>>10),56320+(1023&c))):l[c]||String.fromCharCode(c)):f[a]||d[a]||b(a)})}};return m}),g("v",["1d"],function(a){function b(b,c){return b=a.trim(b),b?b.split(c||" "):[]}function c(a){function c(a,c,d){function e(a,b){var c,d,e={};for(c=0,d=a.length;c<d;c++)e[a[c]]=b||{};return e}var h,i,j;for(d=d||[],c=c||"","string"==typeof d&&(d=b(d)),a=b(a),h=a.length;h--;)i=b([g,c].join(" ")),j={attributes:e(i),attributesOrder:i,children:e(d,f)},n[a[h]]=j}function d(a,c){var d,e,f,g;for(a=b(a),d=a.length,c=b(c);d--;)for(e=n[a[d]],f=0,g=c.length;f<g;f++)e.attributes[c[f]]={},e.attributesOrder.push(c[f])}var g,i,j,k,l,m,n={};return e[a]?e[a]:(g="id accesskey class dir lang style tabindex title role",i="address blockquote div dl fieldset form h1 h2 h3 h4 h5 h6 hr menu ol p pre table ul",j="a abbr
  b bdo br button cite code del dfn em embed i iframe img input ins kbd label map noscript object q s samp script select small span strong sub sup textarea u var #text #comment","html4"!=a&&(g+=" contenteditable contextmenu draggable dropzone hidden spellcheck translate",i+=" article aside details dialog figure header footer hgroup section nav",j+=" audio canvas command datalist mark meter output picture progress time wbr video ruby bdi keygen"),"html5-strict"!=a&&(g+=" xml:lang",m="acronym applet basefont big font strike tt",j=[j,m].join(" "),h(b(m),function(a){c(a,"",j)}),l="center dir isindex noframes",i=[i,l].join(" "),k=[i,j].join(" "),h(b(l),function(a){c(a,"",k)})),k=k||[i,j].join(" "),c("html","manifest","head body"),c("head","","base command link meta noscript sc
 ript style title"),c("title hr noscript br"),c("base","href target"),c("link","href rel media hreflang type sizes hreflang"),c("meta","name http-equiv content charset"),c("style","media type scoped"),c("script","src async defer type charset"),c("body","onafterprint onbeforeprint onbeforeunload onblur onerror onfocus onhashchange onload onmessage onoffline ononline onpagehide onpageshow onpopstate onresize onscroll onstorage onunload",k),c("address dt dd div caption","",k),c("h1 h2 h3 h4 h5 h6 pre p abbr code var samp kbd sub sup i b u bdo span legend em strong small s cite dfn","",j),c("blockquote","cite",k),c("ol","reversed start type","li"),c("ul","","li"),c("li","value",k),c("dl","","d
 t dd"),c("a","href target rel media hreflang type",j),c("q","cite",j),c("ins del","cite datetime",k),c("img","src sizes srcset alt usemap ismap width height"),c("iframe","src name width height",k),c("embed","src type width height"),c("object","data type typemustmatch name usemap form width height",[k,"param"].join(" ")),c("param","name value"),c("map","name",[k,"area"].join(" ")),c("area","alt coords shape href target rel media hreflang type"),c("table","border","caption colgroup thead tfoot tbody tr"+("html4"==a?" col":"")),c("colgroup","span","col"),c("col","span"),c("tbody thead tfoot","","tr"),c(&quot
 ;tr","","td th"),c("td","colspan rowspan headers",k),c("th","colspan rowspan headers scope abbr",k),c("form","accept-charset action autocomplete enctype method name novalidate target",k),c("fieldset","disabled form name",[k,"legend"].join(" ")),c("label","form for",j),c("input","accept alt autocomplete checked dirname disabled form formaction formenctype formmethod formnovalidate formtarget height list max maxlength min multiple name pattern readonly required size src step type value width"),c("button","disabled form formaction formenctype formmethod formnovalidate formtarget name type value","html4"==a?k:j),c("select","disabled form multiple name required size","option optgroup"),c("optgroup","disabled label","option"),c("opti
 on","disabled label selected value"),c("textarea","cols dirname disabled form maxlength name readonly required rows wrap"),c("menu","type label",[k,"li"].join(" ")),c("noscript","",k),"html4"!=a&&(c("wbr"),c("ruby","",[j,"rt rp"].join(" ")),c("figcaption","",k),c("mark rt rp summary bdi","",j),c("canvas","width height",k),c("video","src crossorigin poster preload autoplay mediagroup loop muted controls width height buffered",[k,"track source"].join(" ")),c("audio","src crossorigin preload autoplay mediagroup loop muted controls buffered volume",[k,"track source"].join(" ")),c("picture","","img source"),c("source","src srcset type media sizes
 "),c("track","kind src srclang label default"),c("datalist","",[j,"option"].join(" ")),c("article section nav aside header footer","",k),c("hgroup","","h1 h2 h3 h4 h5 h6"),c("figure","",[k,"figcaption"].join(" ")),c("time","datetime",j),c("dialog","open",k),c("command","type label icon disabled checked radiogroup command"),c("output","for form name",j),c("progress","value max",j),c("meter","value min max low high optimum",j),c("details","open",[k,"summary"].join(" ")),c("keygen","autofocus challenge disabled form keytype name")),"html5-strict"!=a&&(d("script","language xml:space"),d("style","xml:space&
 quot;),d("object","declare classid code codebase codetype archive standby align border hspace vspace"),d("embed","align name hspace vspace"),d("param","valuetype type"),d("a","charset name rev shape coords"),d("br","clear"),d("applet","codebase archive code object alt name width height align hspace vspace"),d("img","name longdesc align border hspace vspace"),d("iframe","longdesc frameborder marginwidth marginheight scrolling align"),d("font basefont","size color face"),d("input","usemap align"),d("select","onchange"),d("textarea"),d("h1 h2 h3 h4 h5 h6 div p legend caption","align"),d("ul","type compact"),d("li","type"),d("ol dl menu dir","compact"),d("pre","width 
 xml:space"),d("hr","align noshade size width"),d("isindex","prompt"),d("table","summary width frame rules cellspacing cellpadding align bgcolor"),d("col","width align char charoff valign"),d("colgroup","width align char charoff valign"),d("thead","align char charoff valign"),d("tr","align char charoff valign bgcolor"),d("th","axis align char charoff valign nowrap bgcolor width height"),
+d("form","accept"),d("td","abbr axis scope align char charoff valign nowrap bgcolor width height"),d("tfoot","align char charoff valign"),d("tbody","align char charoff valign"),d("area","nohref"),d("body","background bgcolor text link vlink alink")),"html4"!=a&&(d("input button select textarea","autofocus"),d("input textarea","placeholder"),d("a","download"),d("link script img","crossorigin"),d("iframe","sandbox seamless allowfullscreen")),h(b("a form meter progress dfn"),function(a){n[a]&&delete n[a].children[a]}),delete n.caption.children.table,delete n.script,e[a]=n,n)}function d(a,b){var c;return a&&(c={},"string"==typeof a&&(a={"*":a}),h(a,function(a,d){c[d]=c[d.toUpperCase()]="map&quot
 ;==b?g(a,/[, ]/):j(a,/[, ]/)})),c}var e={},f={},g=a.makeMap,h=a.each,i=a.extend,j=a.explode,k=a.inArray;return function(a){function f(b,c,d){var f=a[b];return f?f=g(f,/[, ]/,g(f.toUpperCase(),/[, ]/)):(f=e[b],f||(f=g(c," ",g(c.toUpperCase()," ")),f=i(f,d),e[b]=f)),f}function l(a){return new RegExp("^"+a.replace(/([?+*])/g,".$1")+"$")}function m(a){var c,d,e,f,h,i,j,m,n,o,p,q,r,s,t,u,v,w,x,y=/^([#+\-])?([^\[!\/]+)(?:\/([^\[!]+))?(?:(!?)\[([^\]]+)\])?$/,z=/^([!\-])?(\w+::\w+|[^=:<]+)?(?:([=:<])(.*))?$/,A=/[*?+]/;if(a)for(a=b(a,","),F["@"]&&(u=F["@"].attributes,v=F["@"].attributesOrder),c=0,d=a.length;c<d;c++)if(h=y.exec(a[c])){if(s=h[1],n=h[2],t=h[3],m=h[5],q={},r=[],i={attributes:q,attributesOrder:r},"#"===s&&(i.paddEmpty=!0),"-"===s&&(i.removeEmpty=!0),"!"===h[4]&&(i.removeEmptyAttrs=!0),u){for(w in u)q[w]=u[w];r.push.apply(
 r,v)}if(m)for(m=b(m,"|"),e=0,f=m.length;e<f;e++)if(h=z.exec(m[e])){if(j={},p=h[1],o=h[2].replace(/::/g,":"),s=h[3],x=h[4],"!"===p&&(i.attributesRequired=i.attributesRequired||[],i.attributesRequired.push(o),j.required=!0),"-"===p){delete q[o],r.splice(k(r,o),1);continue}s&&("="===s&&(i.attributesDefault=i.attributesDefault||[],i.attributesDefault.push({name:o,value:x}),j.defaultValue=x),":"===s&&(i.attributesForced=i.attributesForced||[],i.attributesForced.push({name:o,value:x}),j.forcedValue=x),"<"===s&&(j.validValues=g(x,"?"))),A.test(o)?(i.attributePatterns=i.attributePatterns||[],j.pattern=l(o),i.attributePatterns.push(j)):(q[o]||r.push(o),q[o]=j)}u||"@"!=n||(u=q,v=r),t&&(i.outputName=n,F[t]=i),A.test(n)?(i.pattern=l(n),H.push(i)):F[n]=i}}function n(a){F={},H=[],m(a),h(t,function(a,b){G[b]=a.children})}function o(a){var c=/^(~)?(.+)$/;a&
 amp;&(e.text_block_elements=e.block_elements=null,h(b(a,","),function(a){var b=c.exec(a),d="~"===b[1],e=d?"span":"div",f=b[2];if(G[f]=G[e],I[f]=e,d||(z[f.toUpperCase()]={},z[f]={}),!F[f]){var g=F[e];g=i({},g),delete g.removeEmptyAttrs,delete g.removeEmpty,F[f]=g}h(G,function(a,b){a[e]&&(G[b]=a=i({},G[b]),a[f]=a[e])})}))}function p(c){var d=/^([+\-]?)(\w+)\[([^\]]+)\]$/;e[a.schema]=null,c&&h(b(c,","),function(a){var c,e,f=d.exec(a);f&&(e=f[1],c=e?G[f[2]]:G[f[2]]={"#comment":{}},c=G[f[2]],h(b(f[3],"|"),function(a){"-"===e?delete c[a]:c[a]={}}))})}function q(a){var b,c=F[a];if(c)return c;for(b=H.length;b--;)if(c=H[b],c.pattern.test(a))return c}var r,s,t,u,v,w,x,y,z,A,B,C,D,E=this,F={},G={},H=[],I={},J={};a=a||{},t=c(a.schema),a.verify_html===!1&&(a.valid_elements="*[*]"),r=d(a.valid_styles),s=d(a.invalid_styles,"map"),y=d(a.valid_classes,"map&quot
 ;),u=f("whitespace_elements","pre script noscript style textarea video audio iframe object code"),v=f("self_closing_elements","colgroup dd dt li option p td tfoot th thead tr"),w=f("short_ended_elements","area base basefont br col frame hr img input isindex link meta param embed source wbr track"),x=f("boolean_attributes","checked compact declare defer disabled ismap multiple nohref noresize noshade nowrap readonly selected autoplay loop controls"),A=f("non_empty_elements","td th iframe video audio object script pre code",w),B=f("move_caret_before_on_enter_elements","table",A),C=f("text_block_elements","h1 h2 h3 h4 h5 h6 p div address pre form blockquote center dir fieldset header footer article section hgroup aside nav figure"),z=f("block_elements","hr table tbody thead tfoot th tr td li ol ul caption dl dt dd noscript menu isind
 ex option datalist select optgroup figcaption",C),D=f("text_inline_elements","span strong b em i font strike u var cite dfn code mark q sup sub samp"),h((a.special||"script noscript noframes noembed title style textarea xmp").split(" "),function(a){J[a]=new RegExp("</"+a+"[^>]*>","gi")}),a.valid_elements?n(a.valid_elements):(h(t,function(a,b){F[b]={attributes:a.attributes,attributesOrder:a.attributesOrder},G[b]=a.children}),"html5"!=a.schema&&h(b("strong/b em/i"),function(a){a=b(a,"/"),F[a[1]].outputName=a[0]}),h(b("ol ul sub sup blockquote span font a table tbody tr strong em b i"),function(a){F[a]&&(F[a].removeEmpty=!0)}),h(b("p h1 h2 h3 h4 h5 h6 th td pre div address caption"),function(a){F[a].paddEmpty=!0}),h(b("span"),function(a){F[a].removeEmptyAttrs=!0})),o(a.custom_elements),p(a.valid_children),m(a.extended_valid_elem
 ents),p("+ol[ul|ol],+ul[ul|ol]"),h({dd:"dl",dt:"dl",li:"ul ol",td:"tr",th:"tr",tr:"tbody thead tfoot",tbody:"table",thead:"table",tfoot:"table",legend:"fieldset",area:"map",param:"video audio object"},function(a,c){F[c]&&(F[c].parentsRequired=b(a))}),a.invalid_elements&&h(j(a.invalid_elements),function(a){F[a]&&delete F[a]}),q("span")||m("span[!data-mce-type|*]"),E.children=G,E.getValidStyles=function(){return r},E.getInvalidStyles=function(){return s},E.getValidClasses=function(){return y},E.getBoolAttrs=function(){return x},E.getBlockElements=function(){return z},E.getTextBlockElements=function(){return C},E.getTextInlineElements=function(){return D},E.getShortEndedElements=function(){return w},E.getSelfClosingElements=function(){return v},E.getNonEmptyElements=function(){return A},E.getMoveCaretBeforeOnEnterE
 lements=function(){return B},E.getWhiteSpaceElements=function(){return u},E.getSpecialElements=function(){return J},E.isValidChild=function(a,b){var c=G[a.toLowerCase()];return!(!c||!c[b.toLowerCase()])},E.isValid=function(a,b){var c,d,e=q(a);if(e){if(!b)return!0;if(e.attributes[b])return!0;if(c=e.attributePatterns)for(d=c.length;d--;)if(c[d].pattern.test(a))return!0}return!1},E.getElementRule=q,E.getCustomElements=function(){return I},E.addValidElements=m,E.setValidElements=n,E.addCustomElements=o,E.addValidChildren=p,E.elements=F}}),g("x",[],function(){return function(a,b){function c(a,b,c,d){function e(a){return a=parseInt(a,10).toString(16),a.length>1?a:"0"+a}return"#"+e(b)+e(c)+e(d)}var d,e,f,g,h=/rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi,i=/(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi,j=/\s*([^:]+):\s*([^;]+);?/g,k=/\s+
 $/,l={},m="\ufeff";for(a=a||{},b&&(f=b.getValidStyles(),g=b.getInvalidStyles()),e=("\\\" \\' \\; \\: ; : "+m).split(" "),d=0;d<e.length;d++)l[e[d]]=m+d,l[m+d]=e[d];return{toHex:function(a){return a.replace(h,c)},parse:function(b){function e(a,b,c){var e,f,g,h;if(e=w[a+"-top"+b],e&&(f=w[a+"-right"+b],f&&(g=w[a+"-bottom"+b],g&&(h=w[a+"-left"+b])))){var i=[e,f,g,h];for(d=i.length-1;d--&&i[d]===i[d+1];);d>-1&&c||(w[a+b]=d==-1?i[0]:i.join(" "),delete w[a+"-top"+b],delete w[a+"-right"+b],delete w[a+"-bottom"+b],delete w[a+"-left"+b])}}function f(a){var b,c=w[a];if(c){for(c=c.split(" "),b=c.length;b--;)if(c[b]!==c[0])return!1;return w[a]=c[0],!0}}function g(a,b,c,d){f(b)&&f(c)&&f(d)&&(w[a]=w[b]+" "+w[c]+" "+w[d],delete w[b],delete w[c],delete w[d])}function n(a
 ){return v=!0,l[a]}function o(a,b){return v&&(a=a.replace(/\uFEFF[0-9]/g,function(a){return l[a]})),b||(a=a.replace(/\\([\'\";:])/g,"$1")),a}function p(a){return String.fromCharCode(parseInt(a.slice(1),16))}function q(a){return a.replace(/\\[0-9a-f]+/gi,p)}function r(b,c,d,e,f,g){if(f=f||g)return f=o(f),"'"+f.replace(/\'/g,"\\'")+"'";if(c=o(c||d||e),!a.allow_script_urls){var h=c.replace(/[\s\r\n]+/g,"");if(/(java|vb)script:/i.test(h))return"";if(!a.allow_svg_data_urls&&/^data:image\/svg/i.test(h))return""}return x&&(c=x.call(y,c,"style")),"url('"+c.replace(/\'/g,"\\'")+"')"}var s,t,u,v,w={},x=a.url_converter,y=a.url_converter_scope||this;if(b){for(b=b.replace(/[\u0000-\u001F]/g,""),b=b.replace(/\\[\"\';:\uFEFF]/g,n).replace(/\"[^\"]+\"|\'[^\']+\'/g,function(a){return a.replace(/[;:]/g,n)});s=j.exec(b);)if(j.lastIndex
 =s.index+s[0].length,t=s[1].replace(k,"").toLowerCase(),u=s[2].replace(k,""),t&&u){if(t=q(t),u=q(u),t.indexOf(m)!==-1||t.indexOf('"')!==-1)continue;if(!a.allow_script_urls&&("behavior"==t||/expression\s*\(|\/\*|\*\//.test(u)))continue;"font-weight"===t&&"700"===u?u="bold":"color"!==t&&"background-color"!==t||(u=u.toLowerCase()),u=u.replace(h,c),u=u.replace(i,r),w[t]=v?o(u,!0):u}e("border","",!0),e("border","-width"),e("border","-color"),e("border","-style"),e("padding",""),e("margin",""),g("border","border-width","border-style","border-color"),"medium none"===w.border&&delete w.border,"none"===w["border-image"]&&delete w["border-image"]}return w},serialize
 :function(a,b){function c(b){var c,d,e,g;if(c=f[b])for(d=0,e=c.length;d<e;d++)b=c[d],g=a[b],g&&(i+=(i.length>0?" ":"")+b+": "+g+";")}function d(a,b){var c;return c=g["*"],(!c||!c[a])&&(c=g[b],!c||!c[a])}var e,h,i="";if(b&&f)c("*"),c(b);else for(e in a)h=a[e],!h||g&&!d(e,b)||(i+=(i.length>0?" ":"")+e+": "+h+";");return i}}}}),g("c",["b","d","1i","i","1j","j","o","s","v","x","1d"],function(a,b,c,d,e,f,g,h,i,j,k){function l(a,b){var c,d={},e=b.keep_values;return c={set:function(c,d,e){b.url_converter&&(d=b.url_converter.call(b.url_converter_scope||a,d,e,c[0])),c.attr("data-mce-"+e,d).attr(e,d)},get:function(a,b){return a.attr("data-mce-"+b)||a.attr(b)}},d={style:{set:function(a,b){return null
 !==b&&"object"==typeof b?void a.css(b):(e&&a.attr("data-mce-style",b),void a.attr("style",b))},get:function(b){var c=b.attr("data-mce-style")||b.attr("style");return c=a.serializeStyle(a.parseStyle(c),b[0].nodeName)}}},e&&(d.href=d.src=c),d}function m(a,b){var c=b.attr("style");c=a.serializeStyle(a.parseStyle(c),b[0].nodeName),c||(c=null),b.attr("data-mce-style",c)}function n(a,b){var c,d,e=0;if(a)for(c=a.nodeType,a=a.previousSibling;a;a=a.previousSibling)d=a.nodeType,(!b||3!=d||d!=c&&a.nodeValue.length)&&(e++,c=d);return e}function o(c,d){var f,g=this;g.doc=c,g.win=window,g.files={},g.counter=0,g.stdMode=!t||c.documentMode>=8,g.boxModel=!t||"CSS1Compat"==c.compatMode||g.stdMode,g.styleSheetLoader=new e(c),g.boundEvents=[],g.settings=d=d||{},g.schema=d.schema?d.schema:new i({}),g.styles=new j({url_converter:d.url_converter,url_converter_scope:d.url_converter_sco
 pe},d.schema),g.fixDoc(c),g.events=d.ownEvents?new b(d.proxy):b.Event,g.attrHooks=l(g,d),f=d.schema?d.schema.getBlockElements():{},g.$=a.overrideDefaults(function(){return{context:c,element:g.getRoot()}}),g.isBlock=function(a){if(!a)return!1;var b=a.nodeType;return b?!(1!==b||!f[a.nodeName]):!!f[a]}}var p=k.each,q=k.is,r=k.grep,s=k.trim,t=g.ie,u=/^([a-z0-9],?)+$/i,v=/^[ \t\r\n]*$/;return o.prototype={$$:function(a){return"string"==typeof a&&(a=this.get(a)),this.$(a)},root:null,fixDoc:function(a){var b,c=this.settings;if(t&&c.schema){"abbr article aside audio canvas details figcaption figure footer header hgroup mark menu meter nav output progress section summary time video".replace(/\w+/g,function(b){a.createElement(b)});for(b in c.schema.getCustomElements())a.createElement(b)}},clone:function(a,b){var c,d,e=this;return!t||1!==a.nodeType||b?a.cloneNode(b):(d=e.doc,b?c.firstChild:(c=d.createElement(a.nodeName),p(e.getAttribs(a),function(b){e.setAtt
 rib(c,b.nodeName,e.getAttrib(a,b.nodeName))}),c))},getRoot:function(){var a=this;return a.settings.root_element||a.doc.body},getViewPort:function(a){var b,c;return a=a?a:this.win,b=a.document,c=this.boxModel?b.documentElement:b.body,{x:a.pageXOffset||c.scrollLeft,y:a.pageYOffset||c.scrollTop,w:a.innerWidth||c.clientWidth,h:a.innerHeight||c.clientHeight}},getRect:function(a){var b,c,d=this;return a=d.get(a),b=d.getPos(a),c=d.getSize(a),{x:b.x,y:b.y,w:c.w,h:c.h}},getSize:function(a){var b,c,d=this;return a=d.get(a),b=d.getStyle(a,"width"),c=d.getStyle(a,"height"),b.indexOf("px")===-1&&(b=0),c.indexOf("px")===-1&&(c=0),{w:parseInt(b,10)||a.offsetWidth||a.clientWidth,h:parseInt(c,10)||a.offsetHeight||a.clientHeight}},getParent:function(a,b,c){return this.getParents(a,b,c,!1)},getParents:function(a,b,c,d){var e,f=this,g=[];for(a=f.get(a),d=void 0===d,c=c||("BODY"!=f.getRoot().nodeName?f.getRoot().parentNode:null),q(b,&quot
 ;string")&&(e=b,b="*"===b?function(a){return 1==a.nodeType}:function(a){return f.is(a,e)});a&&a!=c&&a.nodeType&&9!==a.nodeType;){if(!b||b(a)){if(!d)return a;g.push(a)}a=a.parentNode}return d?g:null},get:function(a){var b;return a&&this.doc&&"string"==typeof a&&(b=a,a=this.doc.getElementById(a),a&&a.id!==b)?this.doc.getElementsByName(b)[1]:a},getNext:function(a,b){return this._findSib(a,b,"nextSibling")},getPrev:function(a,b){return this._findSib(a,b,"previousSibling")},select:function(a,b){var c=this;return d(a,c.get(b)||c.settings.root_element||c.doc,[])},is:function(a,b){var c;if(!a)return!1;if(void 0===a.length){if("*"===b)return 1==a.nodeType;if(u.test(b)){for(b=b.toLowerCase().split(/,/),a=a.nodeName.toLowerCase(),c=b.length-1;c>=0;c--)if(b[c]==a)return!0;return!1}}if(a.nodeType&&1!=a.nodeType)return!1;var e=a.nodeType?[a]:a;return d(b,e[0].ownerDocu
 ment||e[0],null,e).length>0},add:function(a,b,c,d,e){var f=this;return this.run(a,function(a){var g;return g=q(b,"string")?f.doc.createElement(b):b,f.setAttribs(g,c),d&&(d.nodeType?g.appendChild(d):f.setHTML(g,d)),e?g:a.appendChild(g)})},create:function(a,b,c){return this.add(this.doc.createElement(a),a,b,c,1)},createHTML:function(a,b,c){var d,e="";e+="<"+a;for(d in b)b.hasOwnProperty(d)&&null!==b[d]&&"undefined"!=typeof b[d]&&(e+=" "+d+'="'+this.encode(b[d])+'"');return"undefined"!=typeof c?e+">"+c+"</"+a+">":e+" />"},createFragment:function(a){var b,c,d,e=this.doc;for(d=e.createElement("div"),b=e.createDocumentFragment(),a&&(d.innerHTML=a);c=d.firstChild;)b.appendChild(c);return b},remove:function(a,b){return a=this.$$(a),b?a.each(function(){for(var a;a=this.firstChild;)3==a.nodeType&&0===a.data.le
 ngth?this.removeChild(a):this.parentNode.insertBefore(a,this)}).remove():a.remove(),a.length>1?a.toArray():a[0]},setStyle:function(a,b,c){a=this.$$(a).css(b,c),this.settings.update_styles&&m(this,a)},getStyle:function(a,b,c){return a=this.$$(a),c?a.css(b):(b=b.replace(/-(\D)/g,function(a,b){return b.toUpperCase()}),"float"==b&&(b=g.ie&&g.ie<12?"styleFloat":"cssFloat"),a[0]&&a[0].style?a[0].style[b]:void 0)},setStyles:function(a,b){a=this.$$(a).css(b),this.settings.update_styles&&m(this,a)},removeAllAttribs:function(a){return this.run(a,function(a){var b,c=a.attributes;for(b=c.length-1;b>=0;b--)a.removeAttributeNode(c.item(b))})},setAttrib:function(a,b,c){var d,e,f=this,g=f.settings;""===c&&(c=null),a=f.$$(a),d=a.attr(b),a.length&&(e=f.attrHooks[b],e&&e.set?e.set(a,c,b):a.attr(b,c),d!=c&&g.onSetAttrib&&g.onSetAttrib({attrElm:a,attrName:b,attrValue:c}))},set
 Attribs:function(a,b){var c=this;c.$$(a).each(function(a,d){p(b,function(a,b){c.setAttrib(d,b,a)})})},getAttrib:function(a,b,c){var d,e,f=this;return a=f.$$(a),a.length&&(d=f.attrHooks[b],e=d&&d.get?d.get(a,b):a.attr(b)),"undefined"==typeof e&&(e=c||""),e},getPos:function(b,c){var d,e,f=this,g=0,h=0,i=f.doc,j=i.body;if(b=f.get(b),c=c||j,b){if(c===j&&b.getBoundingClientRect&&"static"===a(j).css("position"))return e=b.getBoundingClientRect(),c=f.boxModel?i.documentElement:j,g=e.left+(i.documentElement.scrollLeft||j.scrollLeft)-c.clientLeft,h=e.top+(i.documentElement.scrollTop||j.scrollTop)-c.clientTop,{x:g,y:h};for(d=b;d&&d!=c&&d.nodeType;)g+=d.offsetLeft||0,h+=d.offsetTop||0,d=d.offsetParent;for(d=b.parentNode;d&&d!=c&&d.nodeType;)g-=d.scrollLeft||0,h-=d.scrollTop||0,d=d.parentNode}return{x:g,y:h}},parseStyle:function(a){return this.styles.parse(a)},serializeStyle:function(
 a,b){return this.styles.serialize(a,b)},addStyle:function(a){var b,c,d=this,e=d.doc;if(d!==o.DOM&&e===document){var f=o.DOM.addedStyles;if(f=f||[],f[a])return;f[a]=!0,o.DOM.addedStyles=f}c=e.getElementById("mceDefaultStyles"),c||(c=e.createElement("style"),c.id="mceDefaultStyles",c.type="text/css",b=e.getElementsByTagName("head")[0],b.firstChild?b.insertBefore(c,b.firstChild):b.appendChild(c)),c.styleSheet?c.styleSheet.cssText+=a:c.appendChild(e.createTextNode(a))},loadCSS:function(a){var b,c=this,d=c.doc;return c!==o.DOM&&d===document?void o.DOM.loadCSS(a):(a||(a=""),b=d.getElementsByTagName("head")[0],void p(a.split(","),function(a){var e;a=k._addCacheSuffix(a),c.files[a]||(c.files[a]=!0,e=c.create("link",{rel:"stylesheet",href:a}),t&&d.documentMode&&d.recalc&&(e.onload=function(){d.recalc&&d.recalc(),e.onload=null}),b.appendChild(e))}
 ))},addClass:function(a,b){this.$$(a).addClass(b)},removeClass:function(a,b){this.toggleClass(a,b,!1)},hasClass:function(a,b){return this.$$(a).hasClass(b)},toggleClass:function(b,c,d){this.$$(b).toggleClass(c,d).each(function(){""===this.className&&a(this).attr("class",null)})},show:function(a){this.$$(a).show()},hide:function(a){this.$$(a).hide()},isHidden:function(a){return"none"==this.$$(a).css("display")},uniqueId:function(a){return(a?a:"mce_")+this.counter++},setHTML:function(b,c){b=this.$$(b),t?b.each(function(b,d){if(d.canHaveHTML!==!1){for(;d.firstChild;)d.removeChild(d.firstChild);try{d.innerHTML="<br>"+c,d.removeChild(d.firstChild)}catch(b){a("<div></div>").html("<br>"+c).contents().slice(1).appendTo(d)}return c}}):b.html(c)},getOuterHTML:function(b){return b=this.get(b),1==b.nodeType&&"outerHTML"in b?b.outerHTML:a("<div></div>
 ").append(a(b).clone()).html()},setOuterHTML:function(b,c){var d=this;d.$$(b).each(function(){try{if("outerHTML"in this)return void(this.outerHTML=c)}catch(a){}d.remove(a(this).html(c),!0)})},decode:h.decode,encode:h.encodeAllRaw,insertAfter:function(a,b){return b=this.get(b),this.run(a,function(a){var c,d;return c=b.parentNode,d=b.nextSibling,d?c.insertBefore(a,d):c.appendChild(a),a})},replace:function(a,b,c){var d=this;return d.run(b,function(b){return q(b,"array")&&(a=a.cloneNode(!0)),c&&p(r(b.childNodes),function(b){a.appendChild(b)}),b.parentNode.replaceChild(a,b)})},rename:function(a,b){var c,d=this;return a.nodeName!=b.toUpperCase()&&(c=d.create(b),p(d.getAttribs(a),function(b){d.setAttrib(c,b.nodeName,d.getAttrib(a,b.nodeName))}),d.replace(c,a,1)),c||a},findCommonAncestor:function(a,b){for(var c,d=a;d;){for(c=b;c&&d!=c;)c=c.parentNode;if(d==c)break;d=d.parentNode}return!d&&a.ownerDocument?a.ownerDocument.docume
 ntElement:d},toHex:function(a){return this.styles.toHex(k.trim(a))},run:function(a,b,c){var d,e=this;return"string"==typeof a&&(a=e.get(a)),!!a&&(c=c||this,a.nodeType||!a.length&&0!==a.length?b.call(c,a):(d=[],p(a,function(a,f){a&&("string"==typeof a&&(a=e.get(a)),d.push(b.call(c,a,f)))}),d))},getAttribs:function(a){var b;if(a=this.get(a),!a)return[];if(t){if(b=[],"OBJECT"==a.nodeName)return a.attributes;"OPTION"===a.nodeName&&this.getAttrib(a,"selected")&&b.push({specified:1,nodeName:"selected"});var c=/<\/?[\w:\-]+ ?|=[\"][^\"]+\"|=\'[^\']+\'|=[\w\-]+|>/gi;return a.cloneNode(!1).outerHTML.replace(c,"").replace(/[\w:\-]+/gi,function(a){b.push({specified:1,nodeName:a})}),b}return a.attributes},isEmpty:function(a,b){var c,d,e,g,h,i,j=this,k=0;if(a=a.firstChild){h=new f(a,a.parentNode),b=b||(j.schema?j.schema.getNonEmptyElements():null),g=j
 .schema?j.schema.getWhiteSpaceElements():{};do{if(e=a.nodeType,1===e){var l=a.getAttribute("data-mce-bogus");if(l){a=h.next("all"===l);continue}if(i=a.nodeName.toLowerCase(),b&&b[i]){if("br"===i){k++,a=h.next();continue}return!1}for(d=j.getAttribs(a),c=d.length;c--;)if(i=d[c].nodeName,"name"===i||"data-mce-bookmark"===i)return!1}if(8==e)return!1;if(3===e&&!v.test(a.nodeValue))return!1;if(3===e&&a.parentNode&&g[a.parentNode.nodeName]&&v.test(a.nodeValue))return!1;a=h.next()}while(a)}return k<=1},createRng:function(){var a=this.doc;return a.createRange?a.createRange():new c(this)},nodeIndex:n,split:function(a,b,c){function d(a){function b(a){var b=a.previousSibling&&"SPAN"==a.previousSibling.nodeName,c=a.nextSibling&&"SPAN"==a.nextSibling.nodeName;return b&&c}var c,e=a.childNodes,f=a.nodeType;if(1!=f||"bookmark"!=a.getAttribute("data-m
 ce-type")){for(c=e.length-1;c>=0;c--)d(e[c]);if(9!=f){if(3==f&&a.nodeValue.length>0){var g=s(a.nodeValue).length;if(!h.isBlock(a.parentNode)||g>0||0===g&&b(a))return}else if(1==f&&(e=a.childNodes,1==e.length&&e[0]&&1==e[0].nodeType&&"bookmark"==e[0].getAttribute("data-mce-type")&&a.parentNode.insertBefore(e[0],a),e.length||/^(br|hr|input|img)$/i.test(a.nodeName)))return;h.remove(a)}return a}}var e,f,g,h=this,i=h.createRng();if(a&&b)return i.setStart(a.parentNode,h.nodeIndex(a)),i.setEnd(b.parentNode,h.nodeIndex(b)),e=i.extractContents(),i=h.createRng(),i.setStart(b.parentNode,h.nodeIndex(b)+1),i.setEnd(a.parentNode,h.nodeIndex(a)+1),f=i.extractContents(),g=a.parentNode,g.insertBefore(d(e),a),c?g.insertBefore(c,a):g.insertBefore(b,a),g.insertBefore(d(f),a),h.remove(a),c||b},bind:function(a,b,c,d){var e=this;if(k.isArray(a)){for(var f=a.length;f--;)a[f]=e.bind(a[f],b,c,d);return a}return!
 e.settings.collect||a!==e.doc&&a!==e.win||e.boundEvents.push([a,b,c,d]),e.events.bind(a,b,c,d||e)},unbind:function(a,b,c){var d,e=this;if(k.isArray(a)){for(d=a.length;d--;)a[d]=e.unbind(a[d],b,c);return a}if(e.boundEvents&&(a===e.doc||a===e.win))for(d=e.boundEvents.length;d--;){var f=e.boundEvents[d];a!=f[0]||b&&b!=f[1]||c&&c!=f[2]||this.events.unbind(f[0],f[1],f[2])}return this.events.unbind(a,b,c)},fire:function(a,b,c){return this.events.fire(a,b,c)},getContentEditable:function(a){var b;return a&&1==a.nodeType?(b=a.getAttribute("data-mce-contenteditable"),b&&"inherit"!==b?b:"inherit"!==a.contentEditable?a.contentEditable:null):null},getContentEditableParent:function(a){for(var b=this.getRoot(),c=null;a&&a!==b&&(c=this.getContentEditable(a),null===c);a=a.parentNode);return c},destroy:function(){var a=this;if(a.boundEvents){for(var b=a.boundEvents.length;b--;){var c=a.boundEvents[b];this.ev
 ents.unbind(c[0],c[1],c[2])}a.boundEvents=null}d.setDocument&&d.setDocument(),a.win=a.doc=a.root=a.events=a.frag=null},isChildOf:function(a,b){for(;a;){if(b===a)return!0;a=a.parentNode}return!1},dumpRng:function(a){return"startContainer: "+a.startContainer.nodeName+", startOffset: "+a.startOffset+", endContainer: "+a.endContainer.nodeName+", endOffset: "+a.endOffset},_findSib:function(a,b,c){var d=this,e=b;if(a)for("string"==typeof e&&(e=function(a){return d.is(a,b)}),a=a[c];a;a=a[c])if(e(a))return a;return null}},o.DOM=new o(document),o.nodeIndex=n,o}),g("f",["c","1d"],function(a,b){function c(){function a(a,c,e){function f(){k.remove(j),i&&(i.onreadystatechange=i.onload=i=null),c()}function h(){g(e)?e():"undefined"!=typeof console&&console.log&&console.log("Failed to load script: "+a)}var i,j,k=d;j=k.uniqueId(),i=document.createElement("s
 cript"),i.id=j,i.type="text/javascript",i.src=b._addCacheSuffix(a),"onreadystatechange"in i?i.onreadystatechange=function(){/loaded|complete/.test(i.readyState)&&f()}:i.onload=f,i.onerror=h,(document.getElementsByTagName("head")[0]||document.body).appendChild(i)}var c,h=0,i=1,j=2,k=3,l={},m=[],n={},o=[],p=0;this.isDone=function(a){return l[a]==j},this.markDone=function(a){l[a]=j},this.add=this.load=function(a,b,d,e){var f=l[a];f==c&&(m.push(a),l[a]=h),b&&(n[a]||(n[a]=[]),n[a].push({success:b,failure:e,scope:d||this}))},this.remove=function(a){delete l[a],delete n[a]},this.loadQueue=function(a,b,c){this.loadScripts(m,a,b,c)},this.loadScripts=function(b,d,h,m){function q(a,b){e(n[b],function(b){g(b[a])&&b[a].call(b.scope)}),n[b]=c}var r,s=[];o.push({success:d,failure:m,scope:h||this}),(r=function(){var c=f(b);b.length=0,e(c,function(b){return l[b]===j?void q("success",b):l[b]===k?void q("failure",b)
 :void(l[b]!==i&&(l[b]=i,p++,a(b,function(){l[b]=j,p--,q("success",b),r()},function(){l[b]=k,p--,s.push(b),q("failure",b),r()})))}),p||(e(o,function(a){0===s.length?g(a.success)&&a.success.call(a.scope):g(a.failure)&&a.failure.call(a.scope,s)}),o.length=0)})()}}var d=a.DOM,e=b.each,f=b.grep,g=function(a){return"function"==typeof a};return c.ScriptLoader=new c,c}),g("5",["f","1d"],function(a,b){function c(){var a=this;a.items=[],a.urls={},a.lookup={}}var d=b.each;return c.prototype={get:function(a){if(this.lookup[a])return this.lookup[a].instance},dependencies:function(a){var b;return this.lookup[a]&&(b=this.lookup[a].dependencies),b||[]},requireLangPack:function(b,d){var e=c.language;if(e&&c.languageLoad!==!1){if(d)if(d=","+d+",",d.indexOf(","+e.substr(0,2)+",")!=-1)e=e.substr(0,2);else if(d.indexOf(","+e+",")==-1)return;a.Scr
 iptLoader.add(this.urls[b]+"/langs/"+e+".js")}},add:function(a,b,c){return this.items.push(b),this.lookup[a]={instance:b,dependencies:c},b},remove:function(a){delete this.urls[a],delete this.lookup[a]},createUrl:function(a,b){return"object"==typeof b?b:{prefix:a.prefix,resource:b,suffix:a.suffix}},addComponents:function(b,c){var e=this.urls[b];d(c,function(b){a.ScriptLoader.add(e+"/"+b)})},load:function(b,e,f,g,h){function i(){var c=j.dependencies(b);d(c,function(a){var b=j.createUrl(e,a);j.load(b.resource,b,void 0,void 0)}),f&&(g?f.call(g):f.call(a))}var j=this,k=e;j.urls[b]||("object"==typeof e&&(k=e.prefix+e.resource+e.suffix),0!==k.indexOf("/")&&k.indexOf("://")==-1&&(k=c.baseURL+"/"+k),j.urls[b]=k.substring(0,k.lastIndexOf("/")),j.lookup[b]?i():a.ScriptLoader.add(k,i,g,h))}},c.PluginManager=new c,c.ThemeManager=new c,c}),g("1k",[],function(){var a=
 function(b){var c=b,d=function(){return c},e=function(a){c=a},f=function(){return a(d())};return{get:d,set:e,clone:f}};return a}),g("21",[],function(){function a(a){return function(b){return!!b&&b.nodeType==a}}function b(a){return a=a.toLowerCase().split(" "),function(b){var c,d;if(b&&b.nodeType)for(d=b.nodeName.toLowerCase(),c=0;c<a.length;c++)if(d===a[c])return!0;return!1}}function c(a,b){return b=b.toLowerCase().split(" "),function(c){var d,e;if(i(c))for(d=0;d<b.length;d++)if(e=c.ownerDocument.defaultView.getComputedStyle(c,null).getPropertyValue(a),e===b[d])return!0;return!1}}function d(a,b){return function(c){return i(c)&&c[a]===b}}function e(a,b){return function(b){return i(b)&&b.hasAttribute(a)}}function f(a,b){return function(c){return i(c)&&c.getAttribute(a)===b}}function g(a){return i(a)&&a.hasAttribute("data-mce-bogus")}function h(a){return function(b){if(i(b)){if(b.contentEditab
 le===a)return!0;if(b.getAttribute("data-mce-contenteditable")===a)return!0}return!1}}var i=a(1);return{isText:a(3),isElement:i,isComment:a(8),isBr:b("br"),isContentEditableTrue:h("true"),isContentEditableFalse:h("false"),matchNodeNames:b,hasPropValue:d,hasAttribute:e,hasAttributeValue:f,matchStyleValues:c,isBogus:g}}),g("4i",[],function(){function a(a){return function(){return a}}function b(a){return function(b){return!a(b)}}function c(a,b){return function(c){return a(b(c))}}function d(){var a=h.call(arguments);return function(b){for(var c=0;c<a.length;c++)if(a[c](b))return!0;return!1}}function e(){var a=h.call(arguments);return function(b){for(var c=0;c<a.length;c++)if(!a[c](b))return!1;return!0}}function f(a){var b=h.call(arguments);return b.length-1>=a.length?a.apply(this,b.slice(1)):function(){var a=b.concat([].slice.call(arguments));return f.apply(this,a)}}function g(){}var h=[].slice;return{constant:a,negate:b,and:e,or
 :d,curry:f,compose:c,noop:g}}),g("22",[],function(){var a="\ufeff",b=function(b){return b===a},c=function(b){return b.replace(new RegExp(a,"g"),"")};return{isZwsp:b,ZWSP:a,trim:c}}),g("1z",["21","22"],function(a,b){function c(a){return n(a)&&(a=a.parentNode),m(a)&&a.hasAttribute("data-mce-caret")}function d(a){return n(a)&&b.isZwsp(a.data)}function e(a){return c(a)||d(a)}function f(a,c){var d,f,g,h;if(d=a.ownerDocument,g=d.createTextNode(b.ZWSP),h=a.parentNode,c){if(f=a.previousSibling,n(f)){if(e(f))return f;if(j(f))return f.splitText(f.data.length-1)}h.insertBefore(g,a)}else{if(f=a.nextSibling,n(f)){if(e(f))return f;if(i(f))return f.splitText(1),f}a.nextSibling?h.insertBefore(g,a.nextSibling):h.appendChild(g)}return g}function g(){var a=document.createElement("br");return a.setAttribute("data-mce-bogus","1"),a}function h(a,b,c){var d,e,f;return d=b.o
 wnerDocument,e=d.createElement(a),e.setAttribute("data-mce-caret",c?"before":"after"),e.setAttribute("data-mce-bogus","all"),e.appendChild(g()),f=b.parentNode,c?f.insertBefore(e,b):b.nextSibling?f.insertBefore(e,b.nextSibling):f.appendChild(e),e}function i(a){return n(a)&&a.data[0]==b.ZWSP}function j(a){return n(a)&&a.data[a.data.length-1]==b.ZWSP}function k(b){var c=b.getElementsByTagName("br"),d=c[c.length-1];a.isBogus(d)&&d.parentNode.removeChild(d)}function l(a){return a&&a.hasAttribute("data-mce-caret")?(k(a),a.removeAttribute("data-mce-caret"),a.removeAttribute("data-mce-bogus"),a.removeAttribute("style"),a.removeAttribute("_moz_abspos"),a):null}var m=a.isElement,n=a.isText,o=function(b){return b.firstChild!==b.lastChild||!a.isBr(b.firstChild)},p=function(c){if(a.isText(c)){var d=c.data;return d.length>0&&d.charAt(0)!==b.ZWSP&
 amp;&c.insertData(0,b.ZWSP),c}return null},q=function(c){if(a.isText(c)){var d=c.data;return d.length>0&&d.charAt(d.length-1)!==b.ZWSP&&c.insertData(d.length,b.ZWSP),c}return null},r=function(c){return c&&a.isText(c.container())&&c.container().data.charAt(c.offset())===b.ZWSP},s=function(c){return c&&a.isText(c.container())&&c.container().data.charAt(c.offset()-1)===b.ZWSP};return{isCaretContainer:e,isCaretContainerBlock:c,isCaretContainerInline:d,showCaretContainerBlock:l,insertInline:f,prependInline:p,appendInline:q,isBeforeInline:r,isAfterInline:s,insertBlock:h,hasContent:o,startsWithCaretContainer:i,endsWithCaretContainer:j}}),g("e",["1d","j","21","1i","1z"],function(a,b,c,d,e){function f(a){return q(a)||r(a)}function g(a,b){var c=a.childNodes;return b--,b>c.length-1?b=c.length-1:b<0&&(b=0),c[b]||a}function h(a,b,c){for(;a&&a!==b;){if(c(a))retu
 rn a;a=a.parentNode}return null}function i(a,b,c){return null!==h(a,b,c)}function j(a,b,c){return i(a,b,function(a){return a.nodeName===c})}function k(a){return"_mce_caret"===a.id}function l(a,b){return s(a)&&i(a,b,k)===!1}function m(a){this.walk=function(b,c){function d(a){var b;return b=a[0],3===b.nodeType&&b===q&&r>=b.nodeValue.length&&a.splice(0,1),b=a[a.length-1],0===t&&a.length>0&&b===s&&3===b.nodeType&&a.splice(a.length-1,1),a}function e(a,b,c){for(var d=[];a&&a!=c;a=a[b])d.push(a);return d}function f(a,b){do{if(a.parentNode==b)return a;a=a.parentNode}while(a)}function h(a,b,f){var g=f?"nextSibling":"previousSibling";for(l=a,m=l.parentNode;l&&l!=b;l=m)m=l.parentNode,n=e(l==a?l:l[g],g),n.length&&(f||n.reverse(),c(d(n)))}var i,j,k,l,m,n,o,q=b.startContainer,r=b.startOffset,s=b.endContainer,t=b.endOffset;if(o=a.select("td[data-mce-selected],th[data-mce
 -selected]"),o.length>0)return void p(o,function(a){c([a])});if(1==q.nodeType&&q.hasChildNodes()&&(q=q.childNodes[r]),1==s.nodeType&&s.hasChildNodes()&&(s=g(s,t)),q==s)return c(d([q]));for(i=a.findCommonAncestor(q,s),l=q;l;l=l.parentNode){if(l===s)return h(q,i,!0);if(l===i)break}for(l=s;l;l=l.parentNode){if(l===q)return h(s,i);if(l===i)break}j=f(q,i)||q,k=f(s,i)||s,h(q,j,!0),n=e(j==q?j:j.nextSibling,"nextSibling",k==s?k.nextSibling:k),n.length&&c(d(n)),h(s,k)},this.split=function(a){function b(a,b){return a.splitText(b)}var c=a.startContainer,d=a.startOffset,e=a.endContainer,f=a.endOffset;return c==e&&3==c.nodeType?d>0&&d<c.nodeValue.length&&(e=b(c,d),c=e.previousSibling,f>d?(f-=d,c=e=b(e,f).previousSibling,f=e.nodeValue.length,d=0):f=0):(3==c.nodeType&&d>0&&d<c.nodeValue.length&&(c=b(c,d),d=0),3==e.nodeType&&f>0&&f<e.nodeValue.length&&am
 p;(e=b(e,f).previousSibling,f=e.nodeValue.length)),{startContainer:c,startOffset:d,endContainer:e,endOffset:f}},this.normalize=function(c){function d(d){function g(a){return a&&/^(TD|TH|CAPTION)$/.test(a.nodeName)}function h(c,d){for(var e=new b(c,a.getParent(c.parentNode,a.isBlock)||w);c=e[d?"prev":"next"]();)if("BR"===c.nodeName)return!0}function i(a){for(;a&&a!=w;){if(r(a))return!0;a=a.parentNode}return!1}function k(a,b){return a.previousSibling&&a.previousSibling.nodeName==b;
+}function m(c,d){var g,h,i;if(d=d||n,i=a.getParent(d.parentNode,a.isBlock)||w,c&&"BR"==d.nodeName&&v&&a.isEmpty(i))return n=d.parentNode,o=a.nodeIndex(d),void(f=!0);for(g=new b(d,i);q=g[c?"prev":"next"]();){if("false"===a.getContentEditableParent(q)||l(q,a.getRoot()))return;if(3===q.nodeType&&q.nodeValue.length>0)return void(j(q,w,"A")===!1&&(n=q,o=c?q.nodeValue.length:0,f=!0));if(a.isBlock(q)||t[q.nodeName.toLowerCase()])return;h=q}e&&h&&(n=h,f=!0,o=0)}var n,o,p,q,t,u,v,w=a.getRoot();if(n=c[(d?"start":"end")+"Container"],o=c[(d?"start":"end")+"Offset"],v=1==n.nodeType&&o===n.childNodes.length,t=a.schema.getNonEmptyElements(),u=d,!s(n)){if(1==n.nodeType&&o>n.childNodes.length-1&&(u=!1),9===n.nodeType&&(n=a.getRoot(),o=0),n===w){if(u&&(q=n.childNodes[o>0?o-1:0])){if(s(q))r
 eturn;if(t[q.nodeName]||"TABLE"==q.nodeName)return}if(n.hasChildNodes()){if(o=Math.min(!u&&o>0?o-1:o,n.childNodes.length-1),n=n.childNodes[o],o=0,!e&&n===w.lastChild&&"TABLE"===n.nodeName)return;if(i(n)||s(n))return;if(n.hasChildNodes()&&!/TABLE/.test(n.nodeName)){q=n,p=new b(n,w);do{if(r(q)||s(q)){f=!1;break}if(3===q.nodeType&&q.nodeValue.length>0){o=u?0:q.nodeValue.length,n=q,f=!0;break}if(t[q.nodeName.toLowerCase()]&&!g(q)){o=a.nodeIndex(q),n=q.parentNode,"IMG"!==q.nodeName&&"PRE"!==q.nodeName||u||o++,f=!0;break}}while(q=u?p.next():p.prev())}}}e&&(3===n.nodeType&&0===o&&m(!0),1===n.nodeType&&(q=n.childNodes[o],q||(q=n.childNodes[o-1]),!q||"BR"!==q.nodeName||k(q,"A")||h(q)||h(q,!0)||m(!0,q))),u&&!e&&3===n.nodeType&&o===n.nodeValue.length&&m(!1),f&&c["set"+(d?"Start":&quo
 t;End")](n,o)}}var e,f=!1;return e=c.collapsed,d(!0),e||d(),f&&e&&c.collapse(!0),f}}function n(b,c,d){var e,f,g;if(e=d.elementFromPoint(b,c),f=d.body.createTextRange(),e&&"HTML"!=e.tagName||(e=d.body),f.moveToElementText(e),g=a.toArray(f.getClientRects()),g=g.sort(function(a,b){return a=Math.abs(Math.max(a.top-c,a.bottom-c)),b=Math.abs(Math.max(b.top-c,b.bottom-c)),a-b}),g.length>0){c=(g[0].bottom+g[0].top)/2;try{return f.moveToPoint(b,c),f.collapse(!0),f}catch(a){}}return null}function o(a,b){var c=a&&a.parentElement?a.parentElement():null;return r(h(c,b,f))?null:a}var p=a.each,q=c.isContentEditableTrue,r=c.isContentEditableFalse,s=e.isCaretContainer;return m.compareRanges=function(a,b){if(a&&b){if(!a.item&&!a.duplicate)return a.startContainer==b.startContainer&&a.startOffset==b.startOffset;if(a.item&&b.item&&a.item(0)===b.item(0))return!0;if(a.isEqual&&b.isEqual&&b.isEqual(a))
 return!0}return!1},m.getCaretRangeFromPoint=function(a,b,c){var d,e;if(c.caretPositionFromPoint)e=c.caretPositionFromPoint(a,b),d=c.createRange(),d.setStart(e.offsetNode,e.offset),d.collapse(!0);else if(c.caretRangeFromPoint)d=c.caretRangeFromPoint(a,b);else if(c.body.createTextRange){d=c.body.createTextRange();try{d.moveToPoint(a,b),d.collapse(!0)}catch(e){d=n(a,b,c)}return o(d,c.body)}return d},m.getSelectedNode=function(a){var b=a.startContainer,c=a.startOffset;return b.hasChildNodes()&&a.endOffset==c+1?b.childNodes[c]:null},m.getNode=function(a,b){return 1===a.nodeType&&a.hasChildNodes()&&(b>=a.childNodes.length&&(b=a.childNodes.length-1),a=a.childNodes[b]),a},m}),g("4j",["21","1h","1z"],function(a,b,c){function d(a){return!p(a)&&(l(a)?!m(a.parentNode):n(a)||k(a)||o(a)||j(a))}function e(a,b){for(a=a.parentNode;a&&a!=b;a=a.parentNode){if(j(a))return!1;if(i(a))return!0}return!0}function f(a)
 {return!!j(a)&&b.reduce(a.getElementsByTagName("*"),function(a,b){return a||i(b)},!1)!==!0}function g(a){return n(a)||f(a)}function h(a,b){return d(a)&&e(a,b)}var i=a.isContentEditableTrue,j=a.isContentEditableFalse,k=a.isBr,l=a.isText,m=a.matchNodeNames("script style textarea"),n=a.matchNodeNames("img input textarea hr iframe video audio object"),o=a.matchNodeNames("table"),p=c.isCaretContainer;return{isCaretCandidate:d,isInEditable:e,isAtomic:g,isEditableCaretCandidate:h}}),g("4k",[],function(){function a(a){return a?{left:k(a.left),top:k(a.top),bottom:k(a.bottom),right:k(a.right),width:k(a.width),height:k(a.height)}:{left:0,top:0,bottom:0,right:0,width:0,height:0}}function b(b,c){return b=a(b),c?b.right=b.left:(b.left=b.left+b.width,b.right=b.left),b.width=0,b}function c(a,b){return a.left===b.left&&a.top===b.top&&a.bottom===b.bottom&&a.right===b.right}function d(a,b,c){return a>=0&&a
 mp;a<=Math.min(b.height,c.height)/2}function e(a,b){return a.bottom-a.height/2<b.top||!(a.top>b.bottom)&&d(b.top-a.bottom,a,b)}function f(a,b){return a.top>b.bottom||!(a.bottom<b.top)&&d(b.bottom-a.top,a,b)}function g(a,b){return a.left<b.left}function h(a,b){return a.right>b.right}function i(a,b){return e(a,b)?-1:f(a,b)?1:g(a,b)?-1:h(a,b)?1:0}function j(a,b,c){return b>=a.left&&b<=a.right&&c>=a.top&&c<=a.bottom}var k=Math.round;return{clone:a,collapse:b,isEqual:c,isAbove:e,isBelow:f,isLeft:g,isRight:h,compare:i,containsXY:j}}),g("4l",[],function(){function a(a){return"string"==typeof a&&a.charCodeAt(0)>=768&&b.test(a)}var b=new RegExp("[\u0300-\u036f\u0483-\u0487\u0488-\u0489\u0591-\u05bd\u05bf\u05c1-\u05c2\u05c4-\u05c5\u05c7\u0610-\u061a\u064b-\u065f\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7-\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u
 081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08e3-\u0902\u093a\u093c\u0941-\u0948\u094d\u0951-\u0957\u0962-\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2-\u09e3\u0a01-\u0a02\u0a3c\u0a41-\u0a42\u0a47-\u0a48\u0a4b-\u0a4d\u0a51\u0a70-\u0a71\u0a75\u0a81-\u0a82\u0abc\u0ac1-\u0ac5\u0ac7-\u0ac8\u0acd\u0ae2-\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62-\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c00\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55-\u0c56\u0c62-\u0c63\u0c81\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc-\u0ccd\u0cd5-\u0cd6\u0ce2-\u0ce3\u0d01\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62-\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb-\u0ebc\u0ec8-\u0ecd\u0f18-\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86-\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039-\u103a\u103d-\u103e\u1058-\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085-\u1086\u108d\u109d\u135d-\u135f\u1712-\u1714\u1732-\u1734\u1752-\u
 1753\u1772-\u1773\u17b4-\u17b5\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927-\u1928\u1932\u1939-\u193b\u1a17-\u1a18\u1a1b\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1ab0-\u1abd\u1abe\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80-\u1b81\u1ba2-\u1ba5\u1ba8-\u1ba9\u1bab-\u1bad\u1be6\u1be8-\u1be9\u1bed\u1bef-\u1bf1\u1c2c-\u1c33\u1c36-\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1cf4\u1cf8-\u1cf9\u1dc0-\u1df5\u1dfc-\u1dff\u200c-\u200d\u20d0-\u20dc\u20dd-\u20e0\u20e1\u20e2-\u20e4\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302d\u302e-\u302f\u3099-\u309a\ua66f\ua670-\ua672\ua674-\ua67d\ua69e-\ua69f\ua6f0-\ua6f1\ua802\ua806\ua80b\ua825-\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\ua9e5\uaa29-\uaa2e\uaa31-\uaa32\uaa35-\uaa36\uaa43\uaa4c\uaa7c\uaab0\uaab2-\uaab4\uaab7-\uaab8\uaabe-\uaabf\uaac1\uaaec-\uaaed\uaaf6\uabe5\uabe8\uabed\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\uff
 9e-\uff9f]");return{isExtendingChar:a}}),g("20",["4i","21","c","e","4j","4k","4l"],function(a,b,c,d,e,f,g){function h(a){return"createRange"in a?a.createRange():c.DOM.createRng()}function i(a){return a&&/[\r\n\t ]/.test(a)}function j(a){var b,c=a.startContainer,d=a.startOffset;return!!(i(a.toString())&&r(c.parentNode)&&(b=c.data,i(b[d-1])||i(b[d+1])))}function k(a){function b(a){var b,c=a.ownerDocument,d=h(c),e=c.createTextNode("\xa0"),g=a.parentNode;return g.insertBefore(e,a),d.setStart(e,0),d.setEnd(e,1),b=f.clone(d.getBoundingClientRect()),g.removeChild(e),b}function c(a){var c,d;return d=a.getClientRects(),c=d.length>0?f.clone(d[0]):f.clone(a.getBoundingClientRect()),t(a)&&0===c.left?b(a):c}function d(a,b){return a=f.collapse(a,b),a.width=1,a.right=a.left+1,a}function e(a){0!==a.height&&(n.length>0&&f.isEqual(a,n[n.length-
 1])||n.push(a))}function i(a,b){var f=h(a.ownerDocument);if(b<a.data.length){if(g.isExtendingChar(a.data[b]))return n;if(g.isExtendingChar(a.data[b-1])&&(f.setStart(a,b),f.setEnd(a,b+1),!j(f)))return e(d(c(f),!1)),n}b>0&&(f.setStart(a,b-1),f.setEnd(a,b),j(f)||e(d(c(f),!1))),b<a.data.length&&(f.setStart(a,b),f.setEnd(a,b+1),j(f)||e(d(c(f),!0)))}var k,l,n=[];if(s(a.container()))return i(a.container(),a.offset()),n;if(m(a.container()))if(a.isAtEnd())l=v(a.container(),a.offset()),s(l)&&i(l,l.data.length),q(l)&&!t(l)&&e(d(c(l),!1));else{if(l=v(a.container(),a.offset()),s(l)&&i(l,0),q(l)&&a.isAtEnd())return e(d(c(l),!1)),n;k=v(a.container(),a.offset()-1),q(k)&&!t(k)&&(o(k)||o(l)||!q(l))&&e(d(c(k),!1)),q(l)&&e(d(c(l),!0))}return n}function l(b,c,d){function e(){return s(b)?0===c:0===c}function f(){return s(b)?c>=b.data.length:c>=b.childNodes.length}function g(){var a;return a=h(b.
 ownerDocument),a.setStart(b,c),a.setEnd(b,c),a}function i(){return d||(d=k(new l(b,c))),d}function j(){return i().length>0}function m(a){return a&&b===a.container()&&c===a.offset()}function n(a){return v(b,a?c-1:c)}return{container:a.constant(b),offset:a.constant(c),toRange:g,getClientRects:i,isVisible:j,isAtStart:e,isAtEnd:f,isEqual:m,getNode:n}}var m=b.isElement,n=e.isCaretCandidate,o=b.matchStyleValues("display","block table"),p=b.matchStyleValues("float","left right"),q=a.and(m,n,a.negate(p)),r=a.negate(b.matchStyleValues("white-space","pre pre-line pre-wrap")),s=b.isText,t=b.isBr,u=c.nodeIndex,v=d.getNode;return l.fromRangeStart=function(a){return new l(a.startContainer,a.startOffset)},l.fromRangeEnd=function(a){return new l(a.endContainer,a.endOffset)},l.after=function(a){return new l(a.parentNode,u(a)+1)},l.before=function(a){return new l(a.parentNode,u(a))},l.isAtStart=function(a){return!!a&&a
 mp;a.isAtStart()},l.isAtEnd=function(a){return!!a&&a.isAtEnd()},l.isTextPosition=function(a){return!!a&&b.isText(a.container())},l}),g("1y",["21","c","4i","1h","20"],function(a,b,c,d,e){function f(a){var b=a.parentNode;return r(b)?f(b):b}function g(a){return a?d.reduce(a.childNodes,function(a,b){return r(b)&&"BR"!=b.nodeName?a=a.concat(g(b)):a.push(b),a},[]):[]}function h(a,b){for(;(a=a.previousSibling)&&q(a);)b+=a.data.length;return b}function i(a){return function(b){return a===b}}function j(b){var c,e,h;return c=g(f(b)),e=d.findIndex(c,i(b),b),c=c.slice(0,e+1),h=d.reduce(c,function(a,b,d){return q(b)&&q(c[d-1])&&a++,a},0),c=d.filter(c,a.matchNodeNames(b.nodeName)),e=d.findIndex(c,i(b),b),e-h}function k(a){var b;return b=q(a)?"text()":a.nodeName.toLowerCase(),b+"["+j(a)+"]"}function l(a,b,c){var d=[];for(b=b.parentNode;b!=a&&(!c
 ||!c(b));b=b.parentNode)d.push(b);return d}function m(b,e){var f,g,i,j,m,n=[];return f=e.container(),g=e.offset(),q(f)?i=h(f,g):(j=f.childNodes,g>=j.length?(i="after",g=j.length-1):i="before",f=j[g]),n.push(k(f)),m=l(b,f),m=d.filter(m,c.negate(a.isBogus)),n=n.concat(d.map(m,function(a){return k(a)})),n.reverse().join("/")+","+i}function n(b,c,e){var f=g(b);return f=d.filter(f,function(a,b){return!q(a)||!q(f[b-1])}),f=d.filter(f,a.matchNodeNames(c)),f[e]}function o(a,b){for(var c,d=a,f=0;q(d);){if(c=d.data.length,b>=f&&b<=f+c){a=d,b-=f;break}if(!q(d.nextSibling)){a=d,b=c;break}f+=c,d=d.nextSibling}return b>a.data.length&&(b=a.data.length),new e(a,b)}function p(a,b){var c,f,g;return b?(c=b.split(","),b=c[0].split("/"),g=c.length>1?c[1]:"before",f=d.reduce(b,function(a,b){return(b=/([\w\-\(\)]+)\[([0-9]+)\]/.exec(b))?("text()"===b[1]&&(b[1]="#text"),n(a,b[1],
 parseInt(b[2],10))):null},a),f?q(f)?o(f,parseInt(g,10)):(g="after"===g?s(f)+1:s(f),new e(f.parentNode,g)):null):null}var q=a.isText,r=a.isBogus,s=b.nodeIndex;return{create:m,resolve:p}}),g("9",["1y","1z","20","21","e","o","22","1d"],function(a,b,c,d,e,f,g,h){function i(g){var i=g.dom;this.getBookmark=function(f,m){function n(a,b){var c=0;return h.each(i.select(a),function(a){if("all"!==a.getAttribute("data-mce-bogus"))return a!=b&&void c++}),c}function o(a){function b(b){var c,d,e,f=b?"start":"end";c=a[f+"Container"],d=a[f+"Offset"],1==c.nodeType&&"TR"==c.nodeName&&(e=c.childNodes,c=e[Math.min(b?d:d-1,e.length-1)],c&&(d=b?0:c.childNodes.length,a["set"+(b?"Start":"End")](c,d)))}return b(!0),b(),a}function p(a){function b(a,b){var d,e=a[b?"startContain
 er":"endContainer"],f=a[b?"startOffset":"endOffset"],g=[],h=0;for(3===e.nodeType?g.push(m?k(e,f):f):(d=e.childNodes,f>=d.length&&d.length&&(h=1,f=Math.max(0,d.length-1)),g.push(i.nodeIndex(d[f],m)+h));e&&e!=c;e=e.parentNode)g.push(i.nodeIndex(e,m));return g}var c=i.getRoot(),d={};return d.start=b(a,!0),g.isCollapsed()||(d.end=b(a)),d}function q(a){function c(a,c){var f;if(d.isElement(a)&&(a=e.getNode(a,c),j(a)))return a;if(b.isCaretContainer(a)){if(d.isText(a)&&b.isCaretContainerBlock(a)&&(a=a.parentNode),f=a.previousSibling,j(f))return f;if(f=a.nextSibling,j(f))return f}}return c(a.startContainer,a.startOffset)||c(a.endContainer,a.endOffset)}var r,s,t,u,v,w,x,y="&#xFEFF;";if(2==f)return w=g.getNode(),v=w?w.nodeName:null,r=g.getRng(),j(w)||"IMG"==v?{name:v,index:n(v,w)}:g.tridentSel?g.tridentSel.getBookmark(f):(w=q(r),w?(v=w.tagName,{name:v,index:n(v,w)}):p(r));if(3==f)retur
 n r=g.getRng(),{start:a.create(i.getRoot(),c.fromRangeStart(r)),end:a.create(i.getRoot(),c.fromRangeEnd(r))};if(f)return{rng:g.getRng()};if(r=g.getRng(),t=i.uniqueId(),u=g.isCollapsed(),x="overflow:hidden;line-height:0px",r.duplicate||r.item){if(r.item)return w=r.item(0),v=w.nodeName,{name:v,index:n(v,w)};s=r.duplicate();try{r.collapse(),r.pasteHTML('<span data-mce-type="bookmark" id="'+t+'_start" style="'+x+'">'+y+"</span>"),u||(s.collapse(!1),r.moveToElementText(s.parentElement()),0===r.compareEndPoints("StartToEnd",s)&&s.move("character",-1),s.pasteHTML('<span data-mce-type="bookmark" id="'+t+'_end" style="'+x+'">'+y+"</span>"))}catch(a){return null}}else{if(w=g.getNode(),v=w.nodeName,"IMG"==v)return{name:v,index:n(v,w)};if(s=o(r.cloneRange()),!u){s.collapse(!1);var z=i.create("span",{"data-mce-type":"book
 mark",id:t+"_end",style:x},y);s.insertNode(z),l(z.nextSibling)}r=o(r),r.collapse(!0);var A=i.create("span",{"data-mce-type":"bookmark",id:t+"_start",style:x},y);r.insertNode(A),l(A.previousSibling)}return g.moveToBookmark({id:t,keep:1}),{id:t}},this.moveToBookmark=function(b){function c(a){var c,d,e,f,g=b[a?"start":"end"];if(g){for(e=g[0],d=l,c=g.length-1;c>=1;c--){if(f=d.childNodes,g[c]>f.length-1)return;d=f[g[c]]}3===d.nodeType&&(e=Math.min(g[0],d.nodeValue.length)),1===d.nodeType&&(e=Math.min(g[0],d.childNodes.length)),a?k.setStart(d,e):k.setEnd(d,e)}return!0}function d(a){var c,d,e,g,j=i.get(b.id+"_"+a),k=b.keep;if(j&&(c=j.parentNode,"start"==a?(k?(c=j.firstChild,d=1):d=i.nodeIndex(j),m=n=c,o=p=d):(k?(c=j.firstChild,d=1):d=i.nodeIndex(j),n=c,p=d),!k)){for(g=j.previousSibling,e=j.nextSibling,h.each(h.grep(j.childNodes),function(a){3==a.nodeType&&(a.
 nodeValue=a.nodeValue.replace(/\uFEFF/g,""))});j=i.get(b.id+"_"+a);)i.remove(j,1);g&&e&&g.nodeType==e.nodeType&&3==g.nodeType&&!f.opera&&(d=g.nodeValue.length,g.appendData(e.nodeValue),i.remove(e),"start"==a?(m=n=g,o=p=d):(n=g,p=d))}}function e(a){return!i.isBlock(a)||a.innerHTML||f.ie||(a.innerHTML='<br data-mce-bogus="1" />'),a}function j(){var c,d;return c=i.createRng(),d=a.resolve(i.getRoot(),b.start),c.setStart(d.container(),d.offset()),d=a.resolve(i.getRoot(),b.end),c.setEnd(d.container(),d.offset()),c}var k,l,m,n,o,p;if(b)if(h.isArray(b.start)){if(k=i.createRng(),l=i.getRoot(),g.tridentSel)return g.tridentSel.moveToBookmark(b);c(!0)&&c()&&g.setRng(k)}else"string"==typeof b.start?g.setRng(j(b)):b.id?(d("start"),d("end"),m&&(k=i.createRng(),k.setStart(e(m),o),k.setEnd(e(n),p),g.setRng(k))):b.name?g.select(i.select(b.name)[b.index]):b.rng&am
 p;&g.setRng(b.rng)}}var j=d.isContentEditableFalse,k=function(a,b){var c,d;for(d=g.trim(a.data.slice(0,b)).length,c=a.previousSibling;c&&3===c.nodeType;c=c.previousSibling)d+=g.trim(c.data).length;return d},l=function(a){d.isText(a)&&0===a.data.length&&a.parentNode.removeChild(a)};return i.isBookmarkNode=function(a){return a&&"SPAN"===a.tagName&&"bookmark"===a.getAttribute("data-mce-type")},i}),g("62",["4i","j","21","20","1z","4j"],function(a,b,c,d,e,f){function g(a){return a>0}function h(a){return a<0}function i(a,b){for(var c;c=a(b);)if(!y(c))return c;return null}function j(a,c,d,e,f){var j=new b(a,e);if(h(c)){if((v(a)||y(a))&&(a=i(j.prev,!0),d(a)))return a;for(;a=i(j.prev,f);)if(d(a))return a}if(g(c)){if((v(a)||y(a))&&(a=i(j.next,!0),d(a)))return a;for(;a=i(j.next,f);)if(d(a))return a}return null}function k(a,b){for(
 a=a.parentNode;a&&a!=b;a=a.parentNode)if(u(a))return a;return b}function l(a,b){for(;a&&a!=b;){if(w(a))return a;a=a.parentNode}return null}function m(a,b,c){return l(a.container(),c)==l(b.container(),c)}function n(a,b,c){return k(a.container(),c)==k(b.container(),c)}function o(a,b){var c,d;return b?(c=b.container(),d=b.offset(),A(c)?c.childNodes[d+a]:null):null}function p(a,b){var c=b.ownerDocument.createRange();return a?(c.setStartBefore(b),c.setEndBefore(b)):(c.setStartAfter(b),c.setEndAfter(b)),c}function q(a,b,c){return l(b,a)==l(c,a)}function r(a,b,c){var d,e;for(e=a?"previousSibling":"nextSibling";c&&c!=b;){if(d=c[e],x(d)&&(d=d[e]),v(d)){if(q(b,d,c))return d;break}if(B(d))break;c=c.parentNode}return null}function s(a,b,d){var f,g,h,i,j=z(r,!0,b),k=z(r,!1,b);if(g=d.startContainer,h=d.startOffset,e.isCaretContainerBlock(g)){if(A(g)||(g=g.parentNode),i=g.getAttribute("data-mce-caret"),"before"==i&&(f=
 g.nextSibling,v(f)))return C(f);if("after"==i&&(f=g.previousSibling,v(f)))return D(f)}if(!d.collapsed)return d;if(c.isText(g)){if(x(g)){if(1===a){if(f=k(g))return C(f);if(f=j(g))return D(f)}if(a===-1){if(f=j(g))return D(f);if(f=k(g))return C(f)}return d}if(e.endsWithCaretContainer(g)&&h>=g.data.length-1)return 1===a&&(f=k(g))?C(f):d;if(e.startsWithCaretContainer(g)&&h<=1)return a===-1&&(f=j(g))?D(f):d;if(h===g.data.length)return f=k(g),f?C(f):d;if(0===h)return f=j(g),f?D(f):d}return d}function t(a,b){return v(o(a,b))}var u=c.isContentEditableTrue,v=c.isContentEditableFalse,w=c.matchStyleValues("display","block table table-cell table-caption list-item"),x=e.isCaretContainer,y=e.isCaretContainerBlock,z=a.curry,A=c.isElement,B=f.isCaretCandidate,C=z(p,!0),D=z(p,!1);return{isForwards:g,isBackwards:h,findNode:j,getEditingHost:k,getParentBlock:l,isInSameBlock:m,isInSameEditingHost:n,isBeforeContentEditableFalse:z(
 t,0),isAfterContentEditableFalse:z(t,-1),normalizeRange:s}}),g("5j",["21","4j","20","62","1h","4i"],function(a,b,c,d,e,f){function g(a,b){for(var c=[];a&&a!=b;)c.push(a),a=a.parentNode;return c}function h(a,b){return a.hasChildNodes()&&b<a.childNodes.length?a.childNodes[b]:null}function i(a,b){if(p(a)){if(r(b.previousSibling)&&!m(b.previousSibling))return c.before(b);if(m(b))return c(b,0)}if(q(a)){if(r(b.nextSibling)&&!m(b.nextSibling))return c.after(b);if(m(b))return c(b,b.data.length)}return q(a)?o(b)?c.before(b):c.after(b):c.before(b)}function j(b,e){var f;return!!a.isBr(b)&&(f=k(1,c.after(b),e),!!f&&!d.isInSameBlock(c.before(b),c.before(f),e))}function k(a,b,u){var v,w,x,y,z,A,B;if(!n(u)||!b)return null;if(b.isEqual(c.after(u))&&u.lastChild){if(B=c.after(u.lastChild),q(a)&&r(u.lastChild)&&n(u.lastChild))return o(u.lastChild)?c.before(u.
 lastChild):B}else B=b;if(v=B.container(),w=B.offset(),m(v)){if(q(a)&&w>0)return c(v,--w);if(p(a)&&w<v.length)return c(v,++w);x=v}else{if(q(a)&&w>0&&(y=h(v,w-1),r(y)))return!s(y)&&(z=d.findNode(y,a,t,y))?m(z)?c(z,z.data.length):c.after(z):m(y)?c(y,y.data.length):c.before(y);if(p(a)&&w<v.childNodes.length&&(y=h(v,w),r(y)))return j(y,u)?k(a,c.after(y),u):!s(y)&&(z=d.findNode(y,a,t,y))?m(z)?c(z,0):c.before(z):m(y)?c(y,0):c.after(y);x=B.getNode()}return(p(a)&&B.isAtEnd()||q(a)&&B.isAtStart())&&(x=d.findNode(x,a,f.constant(!0),u,!0),t(x))?i(a,x):(y=d.findNode(x,a,t,u),A=e.last(e.filter(g(v,u),l)),!A||y&&A.contains(y)?y?i(a,y):null:B=p(a)?c.after(A):c.before(A))}var l=a.isContentEditableFalse,m=a.isText,n=a.isElement,o=a.isBr,p=d.isForwards,q=d.isBackwards,r=b.isCaretCandidate,s=b.isAtomic,t=b.isEditableCaretCandidate;return function(a){return{next:function(b){return k(1,b,a)},prev:f
 unction(b){return k(-1,b,a)}}}}),g("5n",["1","1u","4j","20","62","5j","21"],function(a,b,c,d,e,f,g){var h=function(a,b,c){var e=a?d.before(c):d.after(c);return o(a,b,e)},i=function(a){return g.isBr(a)?d.before(a):d.after(a)},j=function(a){return d.isTextPosition(a)?0===a.offset():c.isCaretCandidate(a.getNode())},k=function(a){return d.isTextPosition(a)?a.offset()===a.container().data.length:c.isCaretCandidate(a.getNode(!0))},l=function(a,b){return!d.isTextPosition(a)&&!d.isTextPosition(b)&&a.getNode()===b.getNode(!0)},m=function(a){return!d.isTextPosition(a)&&g.isBr(a.getNode())},n=function(a,b,c){return a?!l(b,c)&&!m(b)&&k(b)&&j(c):!l(c,b)&&j(b)&&k(c)},o=function(a,c,d){var e=new f(c);return b.from(a?e.next(d):e.prev(d))},p=function(a,c,d){return o(a,c,d).bind(function(f){return e.isInSameBlock(d,f,c)&&n(a,d,f)?o(a,c,f):b.some(f)})}
 ,q=function(a,e){var f=a?e.firstChild:e.lastChild;return g.isText(f)?b.some(new d(f,a?0:f.data.length)):f?c.isCaretCandidate(f)?b.some(a?d.before(f):i(f)):h(a,e,f):b.none()};return{fromPosition:o,nextPosition:a.curry(o,!0),prevPosition:a.curry(o,!1),navigate:p,positionIn:q,firstPositionIn:a.curry(q,!0),lastPositionIn:a.curry(q,!1)}}),g("4m",["5n","20","62"],function(a,b,c){var d=function(a,b,c,d){var e=document.createRange();return e.setStart(a,b),e.setEnd(c,d),e},e=function(e){var f=b.fromRangeStart(e),g=b.fromRangeEnd(e),h=e.commonAncestorContainer;return a.fromPosition(!1,h,g).map(function(a){return!c.isInSameBlock(f,g,h)&&c.isInSameBlock(f,a,h)?d(f.container(),f.offset(),a.container(),a.offset()):e}).getOr(e)},f=function(a){return a.collapsed?a:e(a)},g=function(a){return f(a)};return{normalize:g}}),g("4v",[],function(){return"undefined"==typeof console&&(console={log:function(){}}),console}),h("2i&q
 uot;,document),g("23",["1","4","4v","2i"],function(a,b,c,d){var e=function(a,b){var e=b||d,f=e.createElement("div");if(f.innerHTML=a,!f.hasChildNodes()||f.childNodes.length>1)throw c.error("HTML does not have a single root node",a),"HTML must have a single root node";return h(f.childNodes[0])},f=function(a,b){var c=b||d,e=c.createElement(a);return h(e)},g=function(a,b){var c=b||d,e=c.createTextNode(a);return h(e)},h=function(c){if(null===c||void 0===c)throw new b("Node cannot be null or undefined");return{dom:a.constant(c)}};return{fromHtml:e,fromTag:f,fromText:g,fromDom:h}}),g("2k",["3","4e"],function(a,b){var c=function(c){if(null===c)return"null";var d=typeof c;return"object"===d&&a.prototype.isPrototypeOf(c)?"array":"object"===d&&b.prototype.isPrototypeOf(c)?"string":d},d=function(a){return fu
 nction(b){return c(b)===a}};return{isString:d("string"),isObject:d("object"),isArray:d("array"),isNull:d("null"),isBoolean:d("boolean"),isUndefined:d("undefined"),isFunction:d("function"),isNumber:d("number")}}),g("63",["1t","1","3","4"],function(a,b,c,d){return function(){var e=arguments;return function(){for(var f=new c(arguments.length),g=0;g<f.length;g++)f[g]=arguments[g];if(e.length!==f.length)throw new d('Wrong number of arguments to struct. Expected "['+e.length+']", got '+f.length+" arguments");var h={};return a.each(e,function(a,c){h[a]=b.constant(f[c])}),h}}}),g("5o",["1u","4d"],function(a,b){var c=function(){var a=b.keys,c=function(a){var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c);return b};return void 0===a?c:a}(),d=function(a,b){for(var d=c(a),e=0,f=d.length;e<f;e++){var 
 g=d[e],h=a[g];b(h,g,a)}},e=function(a,b){return f(a,function(a,c,d){return{k:c,v:b(a,c,d)}})},f=function(a,b){var c={};return d(a,function(d,e){var f=b(d,e,a);c[f.k]=f.v}),c},g=function(a,b){var c={},e={};return d(a,function(a,d){var f=b(a,d)?c:e;f[d]=a}),{t:c,f:e}},h=function(a,b){var c=[];return d(a,function(a,d){c.push(b(a,d))}),c},i=function(b,d){for(var e=c(b),f=0,g=e.length;f<g;f++){var h=e[f],i=b[h];if(d(i,h,b))return a.some(i)}return a.none()},j=function(a){return h(a,function(a){return a})},k=function(a){return j(a).length};return{bifilter:g,each:d,map:e,mapToArray:h,tupleMap:f,find:i,keys:c,values:j,size:k}}),g("6z",["1t","2k","4"],function(a,b,c){var d=function(a){return a.slice(0).sort()},e=function(a,b){throw new c("All required keys ("+d(a).join(", ")+") were not specified. Specified keys were: "+d(b).join(", ")+".")},f=function(a){throw new c("Unsupported keys for object:
  "+d(a).join(", "))},g=function(d,e){if(!b.isArray(e))throw new c("The "+d+" fields must be an array. Was: "+e+".");a.each(e,function(a){if(!b.isString(a))throw new c("The value "+a+" in the "+d+" fields was not a string.")})},h=function(a,b){throw new c("All values need to be of type: "+b+". Keys ("+d(a).join(", ")+") were not.")},i=function(b){var e=d(b),f=a.find(e,function(a,b){return b<e.length-1&&a===e[b+1]});f.each(function(a){throw new c("The field: "+a+" occurs more than once in the combined fields: ["+e.join(", ")+"].")})};return{sort:d,reqMessage:e,unsuppMessage:f,validateStrArr:g,invalidTypeMessage:h,checkDupes:i}}),g("64",["1t","1","5o","1u","6z","4","4d"],function(a,b,c,d,e,f,g){return function(h,i){var j=h.concat(i);if(0===j.le
 ngth)throw new f("You must specify at least one required or optional field.");return e.validateStrArr("required",h),e.validateStrArr("optional",i),e.checkDupes(j),function(f){var k=c.keys(f),l=a.forall(h,function(b){return a.contains(k,b)});l||e.reqMessage(h,k);var m=a.filter(k,function(b){return!a.contains(j,b)});m.length>0&&e.unsuppMessage(m);var n={};return a.each(h,function(a){n[a]=b.constant(f[a])}),a.each(i,function(a){n[a]=b.constant(g.prototype.hasOwnProperty.call(f,a)?d.some(f[a]):d.none())}),n}}}),g("5q",["63","64"],function(a,b){return{immutable:a,immutableBag:b}}),g("65",[],function(){var a=function(a,b){var c=[],d=function(a){return c.push(a),b(a)},e=b(a);do e=e.bind(d);while(e.isSome());return c};return{toArray:a}}),g("7l",[],function(){return"undefined"!=typeof window?window:Function("return this;")()}),g("70",["7l"],function(a){var b=func
 tion(b,c){for(var d=void 0!==c?c:a,e=0;e<b.length&&void 0!==d&&null!==d;++e)d=d[b[e]];return d},c=function(a,c){var d=a.split(".");return b(d,c)},d=function(a,b){return void 0!==a[b]&&null!==a[b]||(a[b]={}),a[b]},e=function(b,c){for(var e=void 0!==c?c:a,f=0;f<b.length;++f)e=d(e,b[f]);return e},f=function(a,b){var c=a.split(".");return e(c,b)};return{path:b,resolve:c,forge:e,namespace:f}}),g("66",["70"],function(a){var b=function(b,c){return a.resolve(b,c)},c=function(a,c){var d=b(a,c);if(void 0===d)throw a+" not available on this browser";return d};return{getOrDie:c}}),g("4t",["66"],function(a){var b=function(){var b=a.getOrDie("Node");return b},c=function(a,b,c){return 0!==(a.compareDocumentPosition(b)&c)},d=function(a,d){return c(a,d,b().DOCUMENT_POSITION_PRECEDING)},e=function(a,d){return c(a,d,b().DOCUMENT_POSITION_CONTAINED_BY)};return{documentPositionPreceding:d,do
 cumentPositionContainedBy:e}}),g("67",[],function(){var a=function(a){var b,c=!1;return function(){return c||(c=!0,b=a.apply(null,arguments)),b}};return{cached:a}}),h("81",Number),g("7m",["1t","81","4e"],function(a,b,c){var d=function(a,b){for(var c=0;c<a.length;c++){var d=a[c];if(d.test(b))return d}},e=function(a,c){var e=d(a,c);if(!e)return{major:0,minor:0};var f=function(a){return b(c.replace(e,"$"+a))};return h(f(1),f(2))},f=function(a,b){var d=c(b).toLowerCase();return 0===a.length?g():e(a,d)},g=function(){return h(0,0)},h=function(a,b){return{major:a,minor:b}};return{nu:h,detect:f,unknown:g}}),g("71",["1","7m"],function(a,b){var c="Edge",d="Chrome",e="IE",f="Opera",g="Firefox",h="Safari",i=function(a,b){return function(){return b===a}},j=function(){return k({current:void 0,version:b.unknown()})},k=function(a){var b=a
 .current,j=a.version;return{current:b,version:j,isEdge:i(c,b),isChrome:i(d,b),isIE:i(e,b),isOpera:i(f,b),isFirefox:i(g,b),isSafari:i(h,b)}};return{unknown:j,nu:k,edge:a.constant(c),chrome:a.constant(d),ie:a.constant(e),opera:a.constant(f),firefox:a.constant(g),safari:a.constant(h)}}),g("72",["1","7m"],function(a,b){var c="Windows",d="iOS",e="Android",f="Linux",g="OSX",h="Solaris",i="FreeBSD",j=function(a,b){return function(){return b===a}},k=function(){return l({current:void 0,version:b.unknown()})},l=function(a){var b=a.current,k=a.version;return{current:b,version:k,isWindows:j(c,b),isiOS:j(d,b),isAndroid:j(e,b),isOSX:j(g,b),isLinux:j(f,b),isSolaris:j(h,b),isFreeBSD:j(i,b)}};return{unknown:k,nu:l,windows:a.constant(c),ios:a.constant(d),android:a.constant(e),linux:a.constant(f),osx:a.constant(g),solaris:a.constant(h),freebsd:a.constant(i)}}),g("73",["1"],function(a
 ){return function(b,c,d){var e=b.isiOS()&&/ipad/i.test(d)===!0,f=b.isiOS()&&!e,g=b.isAndroid()&&3===b.version.major,h=b.isAndroid()&&4===b.version.major,i=e||g||h&&/mobile/i.test(d)===!0,j=b.isiOS()||b.isAndroid(),k=j&&!i,l=c.isSafari()&&b.isiOS()&&/safari/i.test(d)===!1;return{isiPad:a.constant(e),isiPhone:a.constant(f),isTablet:a.constant(i),isPhone:a.constant(k),isTouch:a.constant(j),isAndroid:b.isAndroid,isiOS:b.isiOS,isWebView:a.constant(l)}}}),g("74",["1t","7m","4e"],function(a,b,c){var d=function(b,d){var e=c(d).toLowerCase();return a.find(b,function(a){return a.search(e)})},e=function(a,c){return d(a,c).map(function(a){var d=b.detect(a.versionRegexes,c);return{current:a.name,version:d}})},f=function(a,c){return d(a,c).map(function(a){var d=b.detect(a.versionRegexes,c);return{current:a.name,version:d}})};return{detectBrowser:e,detectOs:f}}),g("6g",[],function(){va
 r a=function(a,b){return b+a},b=function(a,b){return a+b},c=function(a,b){return a.substring(b)},d=function(a,b){return a.substring(0,a.length-b)};return{addToStart:a,addToEnd:b,removeFromStart:c,removeFromEnd:d}}),g("6h",["1u","4"],function(a,b){var c=function(a,b){return a.substr(0,b)},d=function(a,b){return a.substr(a.length-b,a.length)},e=function(b){return""===b?a.none():a.some(b.substr(0,1))},f=function(b){return""===b?a.none():a.some(b.substring(1))};return{first:c,last:d,head:e,tail:f}}),g("5p",["6g","6h","4"],function(a,b,c){var d=function(a,b,c){if(""===b)return!0;if(a.length<b.length)return!1;var d=a.substr(c,c+b.length);return d===b},e=function(a,b){var c=function(a){var b=typeof a;return"string"===b||"number"===b};return a.replace(/\${([^{}]*)}/g,function(a,d){var e=b[d];return c(e)?e:a})},f=function(b,c){return l(b,c)?a.removeFromStart(b,c.length):
 b},g=function(b,c){return m(b,c)?a.removeFromEnd(b,c.length):b},h=function(b,c){return l(b,c)?b:a.addToStart(b,c)},i=function(b,c){return m(b,c)?b:a.addToEnd(b,c)},j=function(a,b){return a.indexOf(b)!==-1},k=function(a){return b.head(a).bind(function(c){return b.tail(a).map(function(a){return c.toUpperCase()+a})}).getOr(a)},l=function(a,b){return d(a,b,0)},m=function(a,b){return d(a,b,a.length-b.length)},n=function(a){return a.replace(/^\s+|\s+$/g,"")},o=function(a){return a.replace(/^\s+/g,"")},p=function(a){return a.replace(/\s+$/g,"")};return{supplant:e,startsWith:l,removeLeading:f,removeTrailing:g,ensureLeading:h,ensureTrailing:i,endsWith:m,contains:j,trim:n,lTrim:o,rTrim:p,capitalize:k}}),g("75",["1","5p"],function(a,b){var c=/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,d=function(a){return function(c){return b.contains(c,a)}},e=[{name:"Edge",versionRegexes:[/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],search:function(a){var c
 =b.contains(a,"edge/")&&b.contains(a,"chrome")&&b.contains(a,"safari")&&b.contains(a,"applewebkit");return c}},{name:"Chrome",versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/,c],search:function(a){return b.contains(a,"chrome")&&!b.contains(a,"chromeframe")}},{name:"IE",versionRegexes:[/.*?msie\ ?([0-9]+)\.([0-9]+).*/,/.*?rv:([0-9]+)\.([0-9]+).*/],search:function(a){return b.contains(a,"msie")||b.contains(a,"trident")}},{name:"Opera",versionRegexes:[c,/.*?opera\/([0-9]+)\.([0-9]+).*/],search:d("opera")},{name:"Firefox",versionRegexes:[/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],search:d("firefox")},{name:"Safari",versionRegexes:[c,/.*?cpu os ([0-9]+)_([0-9]+).*/],search:function(a){return(b.contains(a,"safari")||b.contains(a,"mobile/"))&&b.contains(a,"applewebkit")}}],f=[
 {
+name:"Windows",search:d("win"),versionRegexes:[/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]},{name:"iOS",search:function(a){return b.contains(a,"iphone")||b.contains(a,"ipad")},versionRegexes:[/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,/.*cpu os ([0-9]+)_([0-9]+).*/,/.*cpu iphone os ([0-9]+)_([0-9]+).*/]},{name:"Android",search:d("android"),versionRegexes:[/.*?android\ ?([0-9]+)\.([0-9]+).*/]},{name:"OSX",search:d("os x"),versionRegexes:[/.*?os\ x\ ?([0-9]+)_([0-9]+).*/]},{name:"Linux",search:d("linux"),versionRegexes:[]},{name:"Solaris",search:d("sunos"),versionRegexes:[]},{name:"FreeBSD",search:d("freebsd"),versionRegexes:[]}];return{browsers:a.constant(e),oses:a.constant(f)}}),g("68",["71","72","73","74","75"],function(a,b,c,d,e){var f=function(f){var g=e.browsers(),h=e.oses(),i=d.d
 etectBrowser(g,f).fold(a.unknown,a.nu),j=d.detectOs(h,f).fold(b.unknown,b.nu),k=c(j,i,f);return{browser:i,os:j,deviceType:k}};return{detect:f}}),h("69",navigator),g("4u",["67","68","69"],function(a,b,c){var d=a.cached(function(){var a=c.userAgent;return b.detect(a)});return{detect:d}}),g("4w",[],function(){return{ATTRIBUTE:2,CDATA_SECTION:4,COMMENT:8,DOCUMENT:9,DOCUMENT_TYPE:10,DOCUMENT_FRAGMENT:11,ELEMENT:1,TEXT:3,PROCESSING_INSTRUCTION:7,ENTITY_REFERENCE:5,ENTITY:6,NOTATION:12}}),g("24",["1t","1u","23","4w","4","2i"],function(a,b,c,d,e,f){var g=0,h=1,i=2,j=3,k=function(){var a=f.createElement("span");return void 0!==a.matches?g:void 0!==a.msMatchesSelector?h:void 0!==a.webkitMatchesSelector?i:void 0!==a.mozMatchesSelector?j:-1}(),l=d.ELEMENT,m=d.DOCUMENT,n=function(a,b){var c=a.dom();if(c.nodeType!==l)return!1;if(k===g)return c.matches(b);if(k
 ===h)return c.msMatchesSelector(b);if(k===i)return c.webkitMatchesSelector(b);if(k===j)return c.mozMatchesSelector(b);throw new e("Browser lacks native selectors")},o=function(a){return a.nodeType!==l&&a.nodeType!==m||0===a.childElementCount},p=function(b,d){var e=void 0===d?f:d.dom();return o(e)?[]:a.map(e.querySelectorAll(b),c.fromDom)},q=function(a,d){var e=void 0===d?f:d.dom();return o(e)?b.none():b.from(e.querySelector(a)).map(c.fromDom)};return{all:p,is:n,one:q}}),g("26",["1t","1","4t","4u","24"],function(a,b,c,d,e){var f=function(a,b){return a.dom()===b.dom()},g=function(a,b){return a.dom().isEqualNode(b.dom())},h=function(c,d){return a.exists(d,b.curry(f,c))},i=function(a,b){var c=a.dom(),d=b.dom();return c!==d&&c.contains(d)},j=function(a,b){return c.documentPositionContainedBy(a.dom(),b.dom())},k=d.detect().browser,l=k.isIE()?j:i;return{eq:f,isEqualNode:g,member:h,contains:l,is:e.is}}),g(
 "4y",["2k","1t","1","1u","5q","65","26","23"],function(a,b,c,d,e,f,g,h){var i=function(a){return h.fromDom(a.dom().ownerDocument)},j=function(a){var b=i(a);return h.fromDom(b.dom().documentElement)},k=function(a){var b=a.dom(),c=b.ownerDocument.defaultView;return h.fromDom(c)},l=function(a){var b=a.dom();return d.from(b.parentNode).map(h.fromDom)},m=function(a){return l(a).bind(function(c){var d=u(c);return b.findIndex(d,function(b){return g.eq(a,b)})})},n=function(b,d){for(var e=a.isFunction(d)?d:c.constant(!1),f=b.dom(),g=[];null!==f.parentNode&&void 0!==f.parentNode;){var i=f.parentNode,j=h.fromDom(i);if(g.push(j),e(j)===!0)break;f=i}return g},o=function(a){var c=function(c){return b.filter(c,function(b){return!g.eq(a,b)})};return l(a).map(u).map(c).getOr([])},p=function(a){var b=a.dom();return d.from(b.offsetParent).map(h.fromDom)},q=function(a){var b=a.dom();return d.from(b.previou
 sSibling).map(h.fromDom)},r=function(a){var b=a.dom();return d.from(b.nextSibling).map(h.fromDom)},s=function(a){return b.reverse(f.toArray(a,q))},t=function(a){return f.toArray(a,r)},u=function(a){var c=a.dom();return b.map(c.childNodes,h.fromDom)},v=function(a,b){var c=a.dom().childNodes;return d.from(c[b]).map(h.fromDom)},w=function(a){return v(a,0)},x=function(a){return v(a,a.dom().childNodes.length-1)},y=e.immutable("element","offset"),z=function(a,b){var c=u(a);return c.length>0&&b<c.length?y(c[b],0):y(a,b)};return{owner:i,defaultView:k,documentElement:j,parent:l,findIndex:m,parents:n,siblings:o,prevSibling:q,offsetParent:p,prevSiblings:s,nextSibling:r,nextSiblings:t,children:u,child:v,firstChild:w,lastChild:x,leaf:z}}),g("53",["4y"],function(a){var b=function(b,c){var d=a.parent(b);d.each(function(a){a.dom().insertBefore(c.dom(),b.dom())})},c=function(c,d){var f=a.nextSibling(c);f.fold(function(){var b=a.parent(c);b.each(f
 unction(a){e(a,d)})},function(a){b(a,d)})},d=function(b,c){var d=a.firstChild(b);d.fold(function(){e(b,c)},function(a){b.dom().insertBefore(c.dom(),a.dom())})},e=function(a,b){a.dom().appendChild(b.dom())},f=function(c,d,f){a.child(c,f).fold(function(){e(c,d)},function(a){b(a,d)})},g=function(a,c){b(a,c),e(c,a)};return{before:b,after:c,prepend:d,append:e,appendAt:f,wrap:g}}),g("6j",["1t","53"],function(a,b){var c=function(c,d){a.each(d,function(a){b.before(c,a)})},d=function(c,d){a.each(d,function(a,e){var f=0===e?c:d[e-1];b.after(f,a)})},e=function(c,d){a.each(d.slice().reverse(),function(a){b.prepend(c,a)})},f=function(c,d){a.each(d,function(a){b.append(c,a)})};return{before:c,after:d,prepend:e,append:f}}),g("6a",["1t","6j","4y"],function(a,b,c){var d=function(b){b.dom().textContent="",a.each(c.children(b),function(a){e(a)})},e=function(a){var b=a.dom();null!==b.parentNode&&b.parentNode.removeC
 hild(b)},f=function(a){var d=c.children(a);d.length>0&&b.before(a,d),e(a)};return{empty:d,remove:e,unwrap:f}}),g("56",["4w"],function(a){var b=function(a){var b=a.dom().nodeName;return b.toLowerCase()},c=function(a){return a.dom().nodeType},d=function(a){return a.dom().nodeValue},e=function(a){return function(b){return c(b)===a}},f=function(d){return c(d)===a.COMMENT||"#comment"===b(d)},g=e(a.ELEMENT),h=e(a.TEXT),i=e(a.DOCUMENT);return{name:b,type:c,value:d,isElement:g,isText:h,isDocument:i,isComment:f}}),g("76",["4u","1u","4"],function(a,b,c){return function(d,e){var f=function(a){if(!d(a))throw new c("Can only get "+e+" value of a "+e+" node");return j(a).getOr("")},g=function(a){try{return h(a)}catch(a){return b.none()}},h=function(a){return d(a)?b.from(a.dom().nodeValue):b.none()},i=a.detect().browser,j=i.isIE()&&10===i.version.major?g:h,k=function(a,b
 ){if(!d(a))throw new c("Can only set raw "+e+" value of a "+e+" node");a.dom().nodeValue=b};return{get:f,getOption:j,set:k}}}),g("6b",["56","76"],function(a,b){var c=b(a.isText,"text"),d=function(a){return c.get(a)},e=function(a){return c.getOption(a)},f=function(a,b){c.set(a,b)};return{get:d,getOption:e,set:f}}),g("6e",["67","23","56","2i"],function(a,b,c,d){var e=function(a){var b=c.isText(a)?a.dom().parentNode:a.dom();return void 0!==b&&null!==b&&b.ownerDocument.body.contains(b)},f=a.cached(function(){return g(b.fromDom(d))}),g=function(a){var c=a.dom().body;if(null===c||void 0===c)throw"Body is not available yet";return b.fromDom(c)};return{body:f,getBody:g,inBody:e}}),g("77",["1t","6e","4y"],function(a,b,c){var d=function(a){return h(b.body(),a)},e=function(b,d,e){return a.filter(c.parents(b,e),
 d)},f=function(b,d){return a.filter(c.siblings(b),d)},g=function(b,d){return a.filter(c.children(b),d)},h=function(b,d){var e=[];return a.each(c.children(b),function(a){d(a)&&(e=e.concat([a])),e=e.concat(h(a,d))}),e};return{all:d,ancestors:e,siblings:f,children:g,descendants:h}}),g("6c",["77","24"],function(a,b){var c=function(a){return b.all(a)},d=function(c,d,e){return a.ancestors(c,function(a){return b.is(a,d)},e)},e=function(c,d){return a.siblings(c,function(a){return b.is(a,d)})},f=function(c,d){return a.children(c,function(a){return b.is(a,d)})},g=function(a,c){return b.all(c,a)};return{all:c,ancestors:d,siblings:e,children:f,descendants:g}}),g("58",["1t","1","56"],function(a,b,c){var d=["article","aside","details","div","dt","figcaption","footer","form","fieldset","header","hgroup","htm
 l","main","nav","section","summary","body","p","dl","multicol","dd","figure","address","center","blockquote","h1","h2","h3","h4","h5","h6","listing","xmp","pre","plaintext","menu","dir","ul","ol","li","hr","table","tbody","thead","tfoot","th","tr","td","caption"],e=["area","base","basefont","br","col","frame","hr","img","input","isindex","link","meta","param","embed","source","wbr","track"],f=["td","th"],g=["thead",&qu
 ot;tbody","tfoot"],h=["h1","h2","h3","h4","h5","h6","p","div","address","pre","form","blockquote","center","dir","fieldset","header","footer","article","section","hgroup","aside","nav","figure"],i=["h1","h2","h3","h4","h5","h6"],j=["li","dd","dt"],k=["ul","ol","dl"],l=function(d){var e;return function(f){return e=e?e:a.mapToObject(d,b.constant(!0)),e.hasOwnProperty(c.name(f))}},m=l(i),n=l(d),o=function(a){return c.isElement(a)&&!n(a)},p=function(a){return c.isElement(a)&&"br"===c.name(a)};return{isBlock:n,isInline:o,isHeading:m,isTextBlock:l(h),isList:l(k),isListItem:l(j),isVoid:l(e),isTableSection:
 l(g),isTableCell:l(f),isBr:p}}),g("5l",["1t","53","6a","23","56","6b","6c","4y","58"],function(a,b,c,d,e,f,g,h,i){var j=function(a){for(var b=[],c=a.dom();c;)b.push(d.fromDom(c)),c=c.lastChild;return b},k=function(b){var d=g.descendants(b,"br"),e=a.filter(j(b).slice(-1),i.isBr);d.length===e.length&&a.each(e,c.remove)},l=function(a){c.empty(a),b.append(a,d.fromHtml('<br data-mce-bogus="1">'))},m=function(a){return e.isText(a)?"\xa0"===f.get(a):i.isBr(a)},n=function(b){return 1===a.filter(h.children(b),m).length},o=function(a){h.lastChild(a).each(function(b){h.prevSibling(b).each(function(d){i.isBlock(a)&&i.isBr(b)&&i.isBlock(d)&&c.remove(b)})})};return{removeTrailingBr:k,fillWithPaddingBr:l,isPaddedElement:n,trimBlockTrailingBr:o}}),g("4p",["j"],function(a){var b=function(a){return a&&/^(IMG
 )$/.test(a.nodeName)},c=function(c,d,e){var f,h,i,j=e.startContainer,k=e.startOffset;if((e.startContainer!==e.endContainer||!b(e.startContainer.childNodes[e.startOffset]))&&(3===j.nodeType&&k>=j.nodeValue.length&&(k=c.nodeIndex(j),j=j.parentNode),1===j.nodeType))for(i=j.childNodes,k<i.length?(j=i[k],f=new a(j,c.getParent(j,c.isBlock))):(j=i[i.length-1],f=new a(j,c.getParent(j,c.isBlock)),f.next(!0)),h=f.current();h;h=f.next())if(3===h.nodeType&&!g(h))return e.setStart(h,0),void d.setRng(e)},d=function(a,b,c){if(a)for(b=b?"nextSibling":"previousSibling",a=c?a:a[b];a;a=a[b])if(1===a.nodeType||!g(a))return a},e=function(a,b){return b.nodeType&&(b=b.nodeName),!!a.schema.getTextBlockElements()[b.toLowerCase()]},f=function(a,b,c){return a.schema.isValidChild(b,c)},g=function(a){return a&&3===a.nodeType&&/^([\t \r\n]+|)$/.test(a.nodeValue)},h=function(a,b){return"string"!=typeof a?a=a(b):b&&
 (a=a.replace(/%(\w+)/g,function(a,c){return b[c]||a})),a},i=function(a,b){return a=a||"",b=b||"",a=""+(a.nodeName||a),b=""+(b.nodeName||b),a.toLowerCase()===b.toLowerCase()},j=function(a,b,c){return"color"!==c&&"backgroundColor"!==c||(b=a.toHex(b)),"fontWeight"===c&&700===b&&(b="bold"),"fontFamily"===c&&(b=b.replace(/[\'\"]/g,"").replace(/,\s+/g,",")),""+b},k=function(a,b,c){return j(a,a.getStyle(b,c),c)},l=function(a,b){var c;return a.getParent(b,function(b){return c=a.getStyle(b,"text-decoration"),c&&"none"!==c}),c},m=function(a,b,c){return a.getParents(b,c,a.getRoot())};return{isInlineBlock:b,moveStart:c,getNonWhiteSpaceSibling:d,isTextBlock:e,isValid:f,isWhiteSpaceNode:g,replaceVars:h,isEq:i,normalizeStyleValue:j,getStyle:k,getTextDecoration:l,getParents:m}}),g("4o",["9","
 j","4p"],function(a,b,c){var d=a.isBookmarkNode,e=c.getParents,f=c.isWhiteSpaceNode,g=c.isTextBlock,h=function(a,b){for("undefined"==typeof b&&(b=3===a.nodeType?a.length:a.childNodes.length);a&&a.hasChildNodes();)a=a.childNodes[b],a&&(b=3===a.nodeType?a.length:a.childNodes.length);return{node:a,offset:b}},i=function(a,b){var c=h(a,b);if(c.node){for(;c.node&&0===c.offset&&c.node.previousSibling;)c=h(c.node.previousSibling);c.node&&c.offset>0&&3===c.node.nodeType&&" "===c.node.nodeValue.charAt(c.offset-1)&&c.offset>1&&(a=c.node,a.splitText(c.offset-1))}return a},j=function(a){return"BR"===a.nodeName&&a.getAttribute("data-mce-bogus")&&!a.nextSibling},k=function(a,h,k,l){var m,n,o=h.startContainer,p=h.startOffset,q=h.endContainer,r=h.endOffset,s=a.dom,t=function(a){var b,c,e,g,h;if(b=c=a?o:q,g=a?"previousSibling":"nex
 tSibling",h=s.getRoot(),3===b.nodeType&&!f(b)&&(a?p>0:r<b.nodeValue.length))return b;for(;;){if(!k[0].block_expand&&s.isBlock(c))return c;for(e=c[g];e;e=e[g])if(!d(e)&&!f(e)&&!j(e))return c;if(c===h||c.parentNode===h){b=c;break}c=c.parentNode}return b};1===o.nodeType&&o.hasChildNodes()&&(m=o.childNodes.length-1,o=o.childNodes[p>m?m:p],3===o.nodeType&&(p=0)),1===q.nodeType&&q.hasChildNodes()&&(m=q.childNodes.length-1,q=q.childNodes[r>m?m:r-1],3===q.nodeType&&(r=q.nodeValue.length));var u=function(a){for(var b=a;b;){if(1===b.nodeType&&s.getContentEditable(b))return"false"===s.getContentEditable(b)?b:a;b=b.parentNode}return a},v=function(c,d,e){var f,g,h,i,j=function(a,b){var c,d,f=a.nodeValue;return"undefined"==typeof b&&(b=e?f.length:0),e?(c=f.lastIndexOf(" ",b),d=f.lastIndexOf("\xa0",b),c=c>d?c:d,c===-1||l||c++):(c=f.inde
 xOf(" ",b),d=f.indexOf("\xa0",b),c=c!==-1&&(d===-1||c<d)?c:d),c};if(3===c.nodeType){if(h=j(c,d),h!==-1)return{container:c,offset:h};i=c}for(f=new b(c,s.getParent(c,s.isBlock)||a.getBody());g=f[e?"prev":"next"]();)if(3===g.nodeType){if(i=g,h=j(g),h!==-1)return{container:g,offset:h}}else if(s.isBlock(g))break;if(i)return d=e?0:i.length,{container:i,offset:d}},w=function(a,b){var c,d,f,g;for(3===a.nodeType&&0===a.nodeValue.length&&a[b]&&(a=a[b]),c=e(s,a),d=0;d<c.length;d++)for(f=0;f<k.length;f++)if(g=k[f],!("collapsed"in g&&g.collapsed!==h.collapsed)&&s.is(c[d],g.selector))return c[d];return a},x=function(b,d){var f,h=s.getRoot();if(k[0].wrapper||(f=s.getParent(b,k[0].block,h)),!f){var i=s.getParent(b,"LI,TD,TH");f=s.getParent(3===b.nodeType?b.parentNode:b,function(b){return b!==h&&g(a,b)},i)}if(f&&k[0].wrapper&&(f=e(s,f,"ul,ol").reverse
 ()[0]||f),!f)for(f=b;f[d]&&!s.isBlock(f[d])&&(f=f[d],!c.isEq(f,"br")););return f||b};return o=u(o),q=u(q),(d(o.parentNode)||d(o))&&(o=d(o)?o:o.parentNode,o=o.nextSibling||o,3===o.nodeType&&(p=0)),(d(q.parentNode)||d(q))&&(q=d(q)?q:q.parentNode,q=q.previousSibling||q,3===q.nodeType&&(r=q.length)),k[0].inline&&(h.collapsed&&(n=v(o,p,!0),n&&(o=n.container,p=n.offset),n=v(q,r),n&&(q=n.container,r=n.offset)),q=l?q:i(q,r)),(k[0].inline||k[0].block_expand)&&(k[0].inline&&3===o.nodeType&&0!==p||(o=t(!0)),k[0].inline&&3===q.nodeType&&r!==q.nodeValue.length||(q=t())),k[0].selector&&k[0].expand!==!1&&!k[0].inline&&(o=w(o,"previousSibling"),q=w(q,"nextSibling")),(k[0].block||k[0].selector)&&(o=x(o,"previousSibling"),q=x(q,"nextSibling"),k[0].block&&(s.isBlock(o)||(o=t(!0)),s.isBlock(q)||(
 q=t()))),1===o.nodeType&&(p=s.nodeIndex(o),o=o.parentNode),1===q.nodeType&&(r=s.nodeIndex(q)+1,q=q.parentNode),{startContainer:o,startOffset:p,endContainer:q,endOffset:r}};return{expandRng:k}}),g("1o",["4p"],function(a){var b=a.isEq,c=function(a,b,c){var d=a.formatter.get(c);if(d)for(var e=0;e<d.length;e++)if(d[e].inherit===!1&&a.dom.is(b,d[e].selector))return!0;return!1},d=function(a,b,d,e){var f=a.dom.getRoot();return b!==f&&(b=a.dom.getParent(b,function(b){return!!c(a,b,d)||(b.parentNode===f||!!g(a,b,d,e,!0))}),g(a,b,d,e))},e=function(a,c,d){return!!b(c,d.inline)||(!!b(c,d.block)||(d.selector?1===c.nodeType&&a.is(c,d.selector):void 0))},f=function(c,d,e,f,g,h){var i,j,k,l=e[f];if(e.onmatch)return e.onmatch(d,e,f);if(l)if("undefined"==typeof l.length){for(i in l)if(l.hasOwnProperty(i)){if(j="attributes"===f?c.getAttrib(d,i):a.getStyle(c,d,i),g&&!j&&!e.exact)return;if((!g||e.exact)&am
 p;&!b(j,a.normalizeStyleValue(c,a.replaceVars(l[i],h),i)))return}}else for(k=0;k<l.length;k++)if("attributes"===f?c.getAttrib(d,l[k]):a.getStyle(c,d,l[k]))return e;return e},g=function(a,b,c,d,g){var h,i,j,k,l=a.formatter.get(c),m=a.dom;if(l&&b)for(i=0;i<l.length;i++)if(h=l[i],e(a.dom,b,h)&&f(m,b,h,"attributes",g,d)&&f(m,b,h,"styles",g,d)){if(k=h.classes)for(j=0;j<k.length;j++)if(!a.dom.hasClass(b,k[j]))return;return h}},h=function(a,b,c,e){var f;return e?d(a,e,b,c):(e=a.selection.getNode(),!!d(a,e,b,c)||(f=a.selection.getStart(),!(f===e||!d(a,f,b,c))))},i=function(a,b,c){var d,e=[],f={};return d=a.selection.getStart(),a.dom.getParent(d,function(d){var h,i;for(h=0;h<b.length;h++)i=b[h],!f[i]&&g(a,d,i,c)&&(f[i]=!0,e.push(i))},a.dom.getRoot()),e},j=function(b,c){var d,e,f,g,h,i=b.formatter.get(c),j=b.dom;if(i)for(d=b.selection.getStart(),e=a.getParents(j,d),g=i.length-1;g>=0;g--){if(h=i[g].selecto
 r,!h||i[g].defaultBlock)return!0;for(f=e.length-1;f>=0;f--)if(j.is(e[f],h))return!0}return!1};return{matchNode:g,matchName:e,match:h,matchAll:i,canApply:j,matchesUnInheritedFormatSelector:c}}),g("4n",["1t","23","5l","e","j","4o","4p","1o","22","4i","1d"],function(a,b,c,d,e,f,g,h,i,j,k){var l=i.ZWSP,m="_mce_caret",n=!1,o=function(a){return 1===a.nodeType&&a.id===m},p=function(a,b){for(;a;){if(3===a.nodeType&&a.nodeValue!==l||a.childNodes.length>1)return!1;b&&1===a.nodeType&&b.push(a),a=a.firstChild}return!0},q=function(a){var b;if(a)for(b=new e(a,a),a=b.current();a;a=b.next())if(3===a.nodeType)return a;return null},r=function(a,b){var c=a.create("span",{id:m,"data-mce-bogus":"1",style:n?"color:red":""});return b&&c.appendChild(a.doc.createTextNode(l)),c},s=funct
 ion(a){for(;a;){if(a.id===m)return a;a=a.parentNode}},t=function(a,b){var c;c=s(b.getStart()),c&&!a.isEmpty(c)&&k.walk(c,function(b){1!==b.nodeType||b.id===m||a.isEmpty(b)||a.setAttrib(b,"data-mce-bogus",null)},"childNodes")},u=function(a){var b=q(a);return b&&b.nodeValue.charAt(0)===l&&b.deleteData(0,1),b},v=function(a,d,e,f){var g,h,i;g=d.getRng(!0),h=a.getParent(e,a.isBlock),p(e)?(f!==!1&&(g.setStartBefore(e),g.setEndBefore(e)),a.remove(e)):(i=u(e),g.startContainer===i&&g.startOffset>0&&g.setStart(i,g.startOffset-1),g.endContainer===i&&g.endOffset>0&&g.setEnd(i,g.endOffset-1),a.remove(e,!0)),h&&a.isEmpty(h)&&c.fillWithPaddingBr(b.fromDom(h)),d.setRng(g)},w=function(a,b,c,d){if(c)v(a,b,c,d);else if(c=s(b.getStart()),!c)for(;c=a.get(m);)v(a,b,c,!1)},x=function(a,d,e){var f=a.dom,h=f.getParent(e,j.curry(g.isTextBlock,a));h&&f.isEmpty(h)?e.parentNode.replaceChild(
 d,e):(c.removeTrailingBr(b.fromDom(e)),f.isEmpty(e)?e.parentNode.replaceChild(d,e):f.insertAfter(d,e))},y=function(a,b){return a.appendChild(b),b},z=function(b,c){var d=a.foldr(b,function(a,b){return y(a,b.cloneNode(!1))},c);return y(d,d.ownerDocument.createTextNode(l))},A=function(a){a._hasCaretEvents||(D(a),a._hasCaretEvents=!0)},B=function(a,b,c){var e,g,h,i,j,k,m,n=a.dom,o=a.selection;A(a),e=o.getRng(!0),i=e.startOffset,k=e.startContainer,m=k.nodeValue,g=s(o.getStart()),g&&(h=q(g));var p=/[^\s\u00a0\u00ad\u200b\ufeff]/;m&&i>0&&i<m.length&&p.test(m.charAt(i))&&p.test(m.charAt(i-1))?(j=o.getBookmark(),e.collapse(!0),e=f.expandRng(a,e,a.formatter.get(b)),e=new d(n).split(e),a.formatter.apply(b,c,e),o.moveToBookmark(j)):(g&&h.nodeValue===l?a.formatter.apply(b,c,g):(g=r(n,!0),h=g.firstChild,e.insertNode(g),i=1,a.formatter.apply(b,c,g)),o.setCursorLocation(h,i))},C=function(a,b,c,e){var g,i,j,k,l,m,n,o=a.dom,p=a.selection,q=p.getRn
 g(!0),t=[];for(A(a),g=q.startContainer,i=q.startOffset,l=g,3===g.nodeType&&(i!==g.nodeValue.length&&(k=!0),l=l.parentNode);l;){if(h.matchNode(a,l,b,c,e)){m=l;break}l.nextSibling&&(k=!0),t.push(l),l=l.parentNode}if(m)if(k)j=p.getBookmark(),q.collapse(!0),q=f.expandRng(a,q,a.formatter.get(b),!0),q=new d(o).split(q),a.formatter.remove(b,c,q),p.moveToBookmark(j);else{n=s(m);var u=r(o,!1),w=z(t,u);n?x(a,u,n):x(a,u,m),v(o,p,n,!1),p.setCursorLocation(w,1),o.isEmpty(m)&&o.remove(m)}},D=function(a){var b=a.dom,c=a.selection;if(!a._hasCaretEvents){var d,e;a.on("BeforeGetContent",function(a){d&&"raw"!==a.format&&d()}),a.on("mouseup keydown",function(a){e&&e(a)}),d=function(){var a,d=[];if(p(s(c.getStart()),d))for(a=d.length;a--;)b.setAttrib(d[a],"data-mce-bogus","1")},e=function(a){var d=a.keyCode;w(b,c,null,!1),8===d&&c.isCollapsed()&&c.getStart().innerHTML===l&&w(
 b,c,s(c.getStart())),37!==d&&39!==d||w(b,c,s(c.getStart())),t(b,c)},a.on("SetContent",function(a){a.selection&&t(b,c)}),a._hasCaretEvents=!0}};return{applyCaretFormat:B,removeCaretFormat:C,isCaretNode:o}}),g("4q",["1h","21","b"],function(a,b,c){function d(a,b){var c=f[a];c||(f[a]=c=[]),f[a].push(b)}function e(a,b){h(f[a],function(a){a(b)})}var f={},g=a.filter,h=a.each;return d("pre",function(d){function e(b){return i(b.previousSibling)&&a.indexOf(j,b.previousSibling)!==-1}function f(a,b){c(b).remove(),c(a).append("<br><br>").append(b.childNodes)}var i,j,k=d.selection.getRng();i=b.matchNodeNames("pre"),k.collapsed||(j=d.selection.getSelectedBlocks(),h(g(g(j,i),e),function(a){f(a.previousSibling,a)}))}),{postProcess:e}}),g("5k",["9","1d"],function(a,b){function c(b){this.compare=function(c,e){function f(a){var c={};return d(b.getAttribs(a),f
 unction(d){var e=d.nodeName.toLowerCase();0!==e.indexOf("_")&&"style"!==e&&0!==e.indexOf("data-")&&(c[e]=b.getAttrib(a,e))}),c}function g(a,b){var c,d;for(d in a)if(a.hasOwnProperty(d)){if(c=b[d],"undefined"==typeof c)return!1;if(a[d]!=c)return!1;delete b[d]}for(d in b)if(b.hasOwnProperty(d))return!1;return!0}return c.nodeName==e.nodeName&&(!!g(f(c),f(e))&&(!!g(b.parseStyle(b.getAttrib(c,"style")),b.parseStyle(b.getAttrib(e,"style")))&&(!a.isBookmarkNode(c)&&!a.isBookmarkNode(e))))}}var d=b.each;return c}),g("1q",["1","9","e","j","4n","4o","4p","1o","1d"],function(a,b,c,d,e,f,g,h,i){var j=/^(src|href|style)$/,k=i.each,l=g.isEq,m=function(a){return/^(TH|TD)$/.test(a.nodeName)},n=function(a,b,c){var e,f,g;return e=b[c?"startContainer":"endContainer"],f=
 b[c?"startOffset":"endOffset"],1===e.nodeType&&(g=e.childNodes.length-1,!c&&f&&f--,e=e.childNodes[f>g?g:f]),3===e.nodeType&&c&&f>=e.nodeValue.length&&(e=new d(e,a.getBody()).next()||e),3!==e.nodeType||c||0!==f||(e=new d(e,a.getBody()).prev()||e),e},o=function(a,b,c,d){var e=a.create(c,d);return b.parentNode.insertBefore(e,b),e.appendChild(b),e},p=function(a,b,c){return!!l(b,c.inline)||(!!l(b,c.block)||(c.selector?1===b.nodeType&&a.is(b,c.selector):void 0))},q=function(a,b){return b.links&&"A"===a.tagName},r=function(a,b,c,d){return b=g.getNonWhiteSpaceSibling(b,c,d),!b||"BR"===b.nodeName||a.isBlock(b)},s=function(a,b,c){var d,e=b.parentNode,f=a.dom,h=a.settings.forced_root_block;c.block&&(h?e===f.getRoot()&&(c.list_block&&l(b,c.list_block)||k(i.grep(b.childNodes),function(b){g.isValid(a,h,b.nodeName.toLowerCase())?d?d.appendChild(b):(d=o(f,b,h),f.setA
 ttribs(d,a.settings.forced_root_block_attrs)):d=0})):f.isBlock(b)&&!f.isBlock(e)&&(r(f,b,!1)||r(f,b.firstChild,!0,1)||b.insertBefore(f.create("br"),b.firstChild),r(f,b,!0)||r(f,b.lastChild,!1,1)||b.appendChild(f.create("br")))),c.selector&&c.inline&&!l(c.inline,b)||f.remove(b,1)},t=function(a,b,c,d,e){var f,h,i,m=a.dom;if(!p(m,d,b)&&!q(d,b))return!1;if("all"!==b.remove)for(k(b.styles,function(a,f){a=g.normalizeStyleValue(m,g.replaceVars(a,c),f),"number"==typeof f&&(f=a,e=0),(b.remove_similar||!e||l(g.getStyle(m,e,f),a))&&m.setStyle(d,f,""),i=1}),i&&""===m.getAttrib(d,"style")&&(d.removeAttribute("style"),d.removeAttribute("data-mce-style")),k(b.attributes,function(a,b){var f;if(a=g.replaceVars(a,c),"number"==typeof b&&(b=a,e=0),!e||l(m.getAttrib(e,b),a)){if("class"===b&&(a=m.getAttrib(d,b
 ),a&&(f="",k(a.split(/\s+/),function(a){/mce\-\w+/.test(a)&&(f+=(f?" ":"")+a)}),f)))return void m.setAttrib(d,b,f);"class"===b&&d.removeAttribute("className"),j.test(b)&&d.removeAttribute("data-mce-"+b),d.removeAttribute(b)}}),k(b.classes,function(a){a=g.replaceVars(a,c),e&&!m.hasClass(e,a)||m.removeClass(d,a)}),h=m.getAttribs(d),f=0;f<h.length;f++){var n=h[f].nodeName;if(0!==n.indexOf("_")&&0!==n.indexOf("data-"))return!1}return"none"!==b.remove?(s(a,d,b),!0):void 0},u=function(a,b,c,d,e){var f;return k(g.getParents(a.dom,b.parentNode).reverse(),function(b){var g;f||"_start"===b.id||"_end"===b.id||(g=h.matchNode(a,b,c,d,e),g&&g.split!==!1&&(f=b))}),f},v=function(a,b,c,d,e,f,g,h){var i,j,k,l,m,n,o=a.dom;if(c){for(n=c.parentNode,i=d.parentNode;i&&i!==n;i=i.parentNode){for(j=o.clone(i,!1),m=0;m<b.len
 gth;m++)if(t(a,b[m],h,j,j)){j=0;break}j&&(k&&j.appendChild(k),l||(l=j),k=j)}!f||g.mixed&&o.isBlock(c)||(d=o.split(c,d)),k&&(e.parentNode.insertBefore(k,e),l.appendChild(e))}return d},w=function(a,d,j,l,p){var q,r,s=a.formatter.get(d),w=s[0],x=!0,y=a.dom,z=a.selection,A=function(b){var c=u(a,b,d,j,p);return v(a,s,c,b,b,!0,w,j)},B=function(b){var c,d,e,f,g;if(1===b.nodeType&&y.getContentEditable(b)&&(f=x,x="true"===y.getContentEditable(b),g=!0),c=i.grep(b.childNodes),x&&!g)for(d=0,e=s.length;d<e&&!t(a,s[d],j,b,b);d++);if(w.deep&&c.length){for(d=0,e=c.length;d<e;d++)B(c[d]);g&&(x=f)}},C=function(a){var c=y.get(a?"_start":"_end"),d=c[a?"firstChild":"lastChild"];return b.isBookmarkNode(d)&&(d=d[a?"firstChild":"lastChild"]),3===d.nodeType&&0===d.data.length&&(d=a?c.previousSibling||c.nextSibling:c.nextSibling||c
 .previousSibling),y.remove(c,!0),d},D=function(b){var d,e,h=b.commonAncestorContainer;if(b=f.expandRng(a,b,s,!0),w.split){if(d=n(a,b,!0),e=n(a,b),d!==e){if(/^(TR|TH|TD)$/.test(d.nodeName)&&d.firstChild&&(d="TR"===d.nodeName?d.firstChild.firstChild||d:d.firstChild||d),h&&/^T(HEAD|BODY|FOOT|R)$/.test(h.nodeName)&&m(e)&&e.firstChild&&(e=e.firstChild||e),y.isChildOf(d,e)&&!y.isBlock(e)&&!m(d)&&!m(e))return d=o(y,d,"span",{id:"_start","data-mce-type":"bookmark"}),A(d),void(d=C(!0));d=o(y,d,"span",{id:"_start","data-mce-type":"bookmark"}),e=o(y,e,"span",{id:"_end","data-mce-type":"bookmark"}),A(d),A(e),d=C(!0),e=C()}else d=e=A(d);b.startContainer=d.parentNode?d.parentNode:d,b.startOffset=y.nodeIndex(d),b.endContainer=e.parentNode?e.parentNode:e,b.endOffset=y.nodeIndex(e)+1}new c(y).walk(b,f
 unction(b){k(b,function(b){B(b),1===b.nodeType&&"underline"===a.dom.getStyle(b,"text-decoration")&&b.parentNode&&"underline"===g.getTextDecoration(y,b.parentNode)&&t(a,{deep:!1,exact:!0,inline:"span",styles:{textDecoration:"underline"}},null,b)})})};if(l)return void(l.nodeType?(r=y.createRng(),r.setStartBefore(l),r.setEndAfter(l),D(r)):D(l));if("false"!==y.getContentEditable(z.getNode()))z.isCollapsed()&&w.inline&&!y.select("td[data-mce-selected],th[data-mce-selected]").length?e.removeCaretFormat(a,d,j,p):(q=z.getBookmark(),D(z.getRng(!0)),z.moveToBookmark(q),w.inline&&h.match(a,d,j,z.getStart())&&g.moveStart(y,z,z.getRng(!0)),a.nodeChanged());else{l=z.getNode();for(var E=0,F=s.length;E<F&&(!s[E].ceFalseOverride||!t(a,s[E],j,l,l));E++);}};return{removeFormat:t,remove:w}}),g("4r",["1","9","5k","21
 ","4n","4p","1o","1q","1d"],function(a,b,c,d,e,f,g,h,i){var j=i.each,k=function(a){return a&&1===a.nodeType&&!b.isBookmarkNode(a)&&!e.isCaretNode(a)&&!d.isBogus(a)},l=function(a,c){var d;for(d=a;d;d=d[c]){if(3===d.nodeType&&0!==d.nodeValue.length)return a;if(1===d.nodeType&&!b.isBookmarkNode(d))return d}return a},m=function(a,b,d){var e,f,g=new c(a);if(b&&d&&(b=l(b,"previousSibling"),d=l(d,"nextSibling"),g.compare(b,d))){for(e=b.nextSibling;e&&e!==d;)f=e,e=e.nextSibling,b.appendChild(f);return a.remove(d),i.each(i.grep(d.childNodes),function(a){b.appendChild(a)}),b}return d},n=function(a,b,c){j(a.childNodes,function(a){k(a)&&(b(a)&&c(a),a.hasChildNodes()&&n(a,b,c))})},o=function(b,c){return a.curry(function(a,c){return!(!c||!f.getStyle(b,c,a))},c)},p=function(b,c,d){return a.curry(function(a,c,d){b.setStyle(d,a,c),
 ""===d.getAttribute("style")&&d.removeAttribute("style"),q(b,d)},c,d)},q=function(a,b){"SPAN"===b.nodeName&&0===a.getAttribs(b).length&&a.remove(b,!0)},r=function(a,b){var c;1===b.nodeType&&b.parentNode&&1===b.parentNode.nodeType&&(c=f.getTextDecoration(a,b.parentNode),a.getStyle(b,"color")&&c?a.setStyle(b,"text-decoration",c):a.getStyle(b,"text-decoration")===c&&a.setStyle(b,"text-decoration",null))},s=function(b,c,d,e){(c.styles.color||c.styles.textDecoration)&&(i.walk(e,a.curry(r,b),"childNodes"),r(b,e))},t=function(a,b,c,d){b.styles&&b.styles.backgroundColor&&n(d,o(a,"fontSize"),p(a,"backgroundColor",f.replaceVars(b.styles.backgroundColor,c)))},u=function(a,b,c,d){"sub"!==b.inline&&"sup"!==b.inline||(n(d,o(a,"fontSize"),p(a,"fontSize",&q
 uot;")),a.remove(a.select("sup"===b.inline?"sub":"sup",d),!0))},v=function(a,b,c,d){d&&b.merge_siblings!==!1&&(d=m(a,f.getNonWhiteSpaceSibling(d),d),d=m(a,d,f.getNonWhiteSpaceSibling(d,!0)))},w=function(a,b,c){if(b.clear_child_styles){var d=b.links?"*:not(a)":"*";j(a.select(d,c),function(c){k(c)&&j(b.styles,function(b,d){a.setStyle(c,d,"")})})}},x=function(a,b,c,d){j(b,function(b){j(a.dom.select(b.inline,d),function(d){k(d)&&h.removeFormat(a,b,c,d,b.exact?d:null)}),w(a.dom,b,d)})},y=function(a,b,c,d,e){g.matchNode(a,e.parentNode,c,d)&&h.removeFormat(a,b,d,e)||b.merge_with_parents&&a.dom.getParent(e.parentNode,function(f){if(g.matchNode(a,f,c,d))return h.removeFormat(a,b,d,e),!0})};return{mergeWithChildren:x,mergeUnderlineAndColor:s,mergeBackgroundColorAndFontSize:t,mergeSubSup:u,mergeSiblings:v,mergeWithParents:y}}),g("1l",["9","21","4m&
 quot;,"e","4n","4o","4p","4q","1o","4r","1d"],function(a,b,c,d,e,f,g,h,i,j,k){var l=k.each,m=function(c){return c&&1===c.nodeType&&!a.isBookmarkNode(c)&&!e.isCaretNode(c)&&!b.isBogus(c)},n=function(b,o,p,q){var r,s,t=b.formatter.get(o),u=t[0],v=!q&&b.selection.isCollapsed(),w=b.dom,x=b.selection,y=function(a,b){if(b=b||u,a){if(b.onformat&&b.onformat(a,b,p,q),l(b.styles,function(b,c){w.setStyle(a,c,g.replaceVars(b,p))}),b.styles){var c=w.getAttrib(a,"style");c&&a.setAttribute("data-mce-style",c)}l(b.attributes,function(b,c){w.setAttrib(a,c,g.replaceVars(b,p))}),l(b.classes,function(b){b=g.replaceVars(b,p),w.hasClass(a,b)||w.addClass(a,b)})}},z=function(a,b){var c=!1;return!!u.selector&&(l(a,function(a){if(!("collapsed"in a&&a.collapsed!==v))return w.is(b,a.selector)&&!e.isCaretNode(b)?(y(b,a),c=!0
 ,!1):void 0}),c)},A=function(c,f,h,n){var q,r,s=[],v=!0;q=u.inline||u.block,r=c.create(q),y(r),new d(c).walk(f,function(a){var d,f=function(a){var h,j,m,w;if(w=v,h=a.nodeName.toLowerCase(),j=a.parentNode.nodeName.toLowerCase(),1===a.nodeType&&c.getContentEditable(a)&&(w=v,v="true"===c.getContentEditable(a),m=!0),g.isEq(h,"br"))return d=0,void(u.block&&c.remove(a));if(u.wrapper&&i.matchNode(b,a,o,p))return void(d=0);if(v&&!m&&u.block&&!u.wrapper&&g.isTextBlock(b,h)&&g.isValid(b,j,q))return a=c.rename(a,q),y(a),s.push(a),void(d=0);if(u.selector){var x=z(t,a);if(!u.inline||x)return void(d=0)}!v||m||!g.isValid(b,q,h)||!g.isValid(b,j,q)||!n&&3===a.nodeType&&1===a.nodeValue.length&&65279===a.nodeValue.charCodeAt(0)||e.isCaretNode(a)||u.inline&&c.isBlock(a)?(d=0,l(k.grep(a.childNodes),f),m&&(v=w),d=0):(d||(d=c.clone(r,!1),a.parentNode.insertBefore(d,a),s.push(
 d)),d.appendChild(a))};l(a,f)}),u.links===!0&&l(s,function(a){var b=function(a){"A"===a.nodeName&&y(a,u),l(k.grep(a.childNodes),b)};b(a)}),l(s,function(d){var e,f=function(b){var c=0;return l(b.childNodes,function(b){g.isWhiteSpaceNode(b)||a.isBookmarkNode(b)||c++}),c},h=function(a){var b=!1;return l(a.childNodes,function(a){if(m(a))return b=a,!1}),b},k=function(b){var d,e;return d=h(b),d&&!a.isBookmarkNode(d)&&i.matchName(c,d,u)&&(e=c.clone(d,!1),y(e),c.replace(e,b,!0),c.remove(d,1)),e||b};return e=f(d),(s.length>1||!c.isBlock(d))&&0===e?void c.remove(d,1):void((u.inline||u.wrapper)&&(u.exact||1!==e||(d=k(d)),j.mergeWithChildren(b,t,p,d),j.mergeWithParents(b,u,o,p,d),j.mergeBackgroundColorAndFontSize(c,u,p,d),j.mergeSubSup(c,u,p,d),j.mergeSiblings(c,u,p,d)))})};if("false"!==w.getContentEditable(x.getNode())){if(u){if(q)q.nodeType?z(t,q)||(s=w.createRng(),s.setStartBefore(q),s.setEndAfter(q),A(w,f.expandR
 ng(b,s,t),null,!0)):A(w,q,null,!0);else if(v&&u.inline&&!w.select("td[data-mce-selected],th[data-mce-selected]").length)e.applyCaretFormat(b,o,p);else{var B=b.selection.getNode();b.settings.forced_root_block||!t[0].defaultBlock||w.getParent(B,w.isBlock)||n(b,t[0].defaultBlock),b.selection.setRng(c.normalize(b.selection.getRng())),r=x.getBookmark(),A(w,f.expandRng(b,x.getRng(!0),t),r),u.styles&&j.mergeUnderlineAndColor(w,u,p,B),x.moveToBookmark(r),g.moveStart(w,x,x.getRng(!0)),b.nodeChanged()}h.postProcess(o,b)}}else{q=x.getNode();for(var C=0,D=t.length;C<D;C++)if(t[C].ceFalseOverride&&w.is(q,t[C].selector))return void y(q,t[C])}};return{applyFormat:n
+}}),g("1m",["1k","4p","1o","1d"],function(a,b,c,d){var e=d.each,f=function(a,f){var g={};a.set({}),f.on("NodeChange",function(h){var i=b.getParents(f.dom,h.element),j={};i=d.grep(i,function(a){return 1===a.nodeType&&!a.getAttribute("data-mce-bogus")}),e(a.get(),function(a,b){e(i,function(d){return f.formatter.matchNode(d,b,{},a.similar)?(g[b]||(e(a,function(a){a(!0,{node:d,format:b,parents:i})}),g[b]=a),j[b]=a,!1):!c.matchesUnInheritedFormatSelector(f,d,b)&&void 0})}),e(g,function(a,b){j[b]||(delete g[b],e(a,function(a){a(!1,{node:h.element,format:b,parents:i})}))})})},g=function(a,b,c,d){var f=a.get();e(b.split(","),function(a){f[a]||(f[a]=[],f[a].similar=d),f[a].push(c)}),a.set(f)},h=function(a,b,c,d,e){null===b.get()&&f(b,a),g(b,c,d,e)};return{formatChanged:h}}),g("4s",["1d"],function(a){var b=function(b){var c={valigntop:[{selector:"td,th",styles:
 {verticalAlign:"top"}}],valignmiddle:[{selector:"td,th",styles:{verticalAlign:"middle"}}],valignbottom:[{selector:"td,th",styles:{verticalAlign:"bottom"}}],alignleft:[{selector:"figure.image",collapsed:!1,classes:"align-left",ceFalseOverride:!0,preview:"font-family font-size"},{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li",styles:{textAlign:"left"},inherit:!1,preview:!1,defaultBlock:"div"},{selector:"img,table",collapsed:!1,styles:{"float":"left"},preview:"font-family font-size"}],aligncenter:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li",styles:{textAlign:"center"},inherit:!1,preview:"font-family font-size",defaultBlock:"div"},{selector:"figure.image",collapsed:!1,classes:"align-center",ceFalseOverride:!0,preview:"font-family font-size"}
 ,{selector:"img",collapsed:!1,styles:{display:"block",marginLeft:"auto",marginRight:"auto"},preview:!1},{selector:"table",collapsed:!1,styles:{marginLeft:"auto",marginRight:"auto"},preview:"font-family font-size"}],alignright:[{selector:"figure.image",collapsed:!1,classes:"align-right",ceFalseOverride:!0,preview:"font-family font-size"},{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li",styles:{textAlign:"right"},inherit:!1,preview:"font-family font-size",defaultBlock:"div"},{selector:"img,table",collapsed:!1,styles:{"float":"right"},preview:"font-family font-size"}],alignjustify:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li",styles:{textAlign:"justify"},inherit:!1,defaultBlock:"div",preview:"font-family font-size"}],bold:[{inline:&
 quot;strong",remove:"all"},{inline:"span",styles:{fontWeight:"bold"}},{inline:"b",remove:"all"}],italic:[{inline:"em",remove:"all"},{inline:"span",styles:{fontStyle:"italic"}},{inline:"i",remove:"all"}],underline:[{inline:"span",styles:{textDecoration:"underline"},exact:!0},{inline:"u",remove:"all"}],strikethrough:[{inline:"span",styles:{textDecoration:"line-through"},exact:!0},{inline:"strike",remove:"all"}],forecolor:{inline:"span",styles:{color:"%value"},links:!0,remove_similar:!0,clear_child_styles:!0},hilitecolor:{inline:"span",styles:{backgroundColor:"%value"},links:!0,remove_similar:!0,clear_child_styles:!0},fontname:{inline:"span",styles:{fontFamily:"%value"},clear_child_styles:!0},fontsize:{inline:"span",styles:{f
 ontSize:"%value"},clear_child_styles:!0},fontsize_class:{inline:"span",attributes:{"class":"%value"}},blockquote:{block:"blockquote",wrapper:1,remove:"all"},subscript:{inline:"sub"},superscript:{inline:"sup"},code:{inline:"code"},link:{inline:"a",selector:"a",remove:"all",split:!0,deep:!0,onmatch:function(){return!0},onformat:function(c,d,e){a.each(e,function(a,d){b.setAttrib(c,d,a)})}},removeformat:[{selector:"b,strong,em,i,font,u,strike,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins",remove:"all",split:!0,expand:!1,block_expand:!0,deep:!0},{selector:"span",attributes:["style","class"],remove:"empty",split:!0,expand:!1,deep:!0},{selector:"*",attributes:["style","class"],split:!1,expand:!1,deep:!0}]};return a.each("p h1 h2 h3 h4 h5 h6 div address pre div dt dd samp&quo
 t;.split(/\s/),function(a){c[a]={block:a,remove:"all"}}),c};return{get:b}}),g("1n",["4s","1d"],function(a,b){return function(c){var d={},e=function(a){return a?d[a]:d},f=function(a,c){a&&("string"!=typeof a?b.each(a,function(a,b){f(b,a)}):(c=c.length?c:[c],b.each(c,function(a){"undefined"==typeof a.deep&&(a.deep=!a.selector),"undefined"==typeof a.split&&(a.split=!a.selector||a.inline),"undefined"==typeof a.remove&&a.selector&&!a.inline&&(a.remove="none"),a.selector&&a.inline&&(a.mixed=!0,a.block_expand=!0),"string"==typeof a.classes&&(a.classes=a.classes.split(/\s+/))}),d[a]=c))},g=function(a){return a&&d[a]&&delete d[a],d};return f(a.get(c.dom)),f(c.settings.formats),{get:e,register:f,unregister:g}}}),g("1p",["c","1d","v"],function(a,b,c){function d(a,d){fun
 ction e(a,b){b.classes.length&&j.addClass(a,b.classes.join(" ")),j.setAttribs(a,b.attrs)}function f(a){var b;return k="string"==typeof a?{name:a,classes:[],attrs:{}}:a,b=j.create(k.name),e(b,k),b}function g(a,c){var d="string"!=typeof a?a.nodeName.toLowerCase():a,e=m.getElementRule(d),f=e&&e.parentsRequired;return!(!f||!f.length)&&(c&&b.inArray(f,c)!==-1?c:f[0])}function h(a,c,d){var e,i,k,l=c.length>0&&c[0],m=l&&l.name;if(k=g(a,m))m===k?(i=c[0],c=c.slice(1)):i=k;else if(l)i=c[0],c=c.slice(1);else if(!d)return a;return i&&(e=f(i),e.appendChild(a)),d&&(e||(e=j.create("div"),e.appendChild(a)),b.each(d,function(b){var c=f(b);e.insertBefore(c,a)})),h(e,c,i&&i.siblings)}var i,k,l,m=d&&d.schema||new c({});return a&&a.length?(k=a[0],i=f(k),l=j.create("div"),l.appendChild(h(i,a.slice(1),k.siblings)),l):""}function e(a,b){return d(g(a),b)}func
 tion f(a){var c,d={classes:[],attrs:{}};return a=d.selector=b.trim(a),"*"!==a&&(c=a.replace(/(?:([#\.]|::?)([\w\-]+)|(\[)([^\]]+)\]?)/g,function(a,c,e,f,g){switch(c){case"#":d.attrs.id=e;break;case".":d.classes.push(e);break;case":":b.inArray("checked disabled enabled read-only required".split(" "),e)!==-1&&(d.attrs[e]=e)}if("["===f){var h=g.match(/([\w\-]+)(?:\=\"([^\"]+))?/);h&&(d.attrs[h[1]]=h[2])}return""})),d.name=c||"div",d}function g(a){return a&&"string"==typeof a?(a=a.split(/\s*,\s*/)[0],a=a.replace(/\s*(~\+|~|\+|>)\s*/g,"$1"),b.map(a.split(/(?:>|\s+(?![^\[\]]+\]))/),function(a){var c=b.map(a.split(/(?:~\+|~|\+)/),f),d=c.pop();return c.length&&(d.siblings=c),d}).reverse()):[]}function h(a,b){function c(a){return a.replace(/%(\w+)/g,"")}var e,f,h,k,l,m,n="";if(m=a.settings.preview_styles,m===
 !1)return"";if("string"!=typeof m&&(m="font-family font-size font-weight font-style text-decoration text-transform color background-color border border-radius outline text-shadow"),"string"==typeof b){if(b=a.formatter.get(b),!b)return;b=b[0]}return"preview"in b&&(m=b.preview,m===!1)?"":(e=b.block||b.inline||"span",k=g(b.selector),k.length?(k[0].name||(k[0].name=e),e=b.selector,f=d(k,a)):f=d([e],a),h=j.select(e,f)[0]||f.firstChild,i(b.styles,function(a,b){a=c(a),a&&j.setStyle(h,b,a)}),i(b.attributes,function(a,b){a=c(a),a&&j.setAttrib(h,b,a)}),i(b.classes,function(a){a=c(a),j.hasClass(h,a)||j.addClass(h,a)}),a.fire("PreviewFormats"),j.setStyles(f,{position:"absolute",left:-65535}),a.getBody().appendChild(f),l=j.getStyle(a.getBody(),"fontSize",!0),l=/px$/.test(l)?parseInt(l,10):0,i(m.split(" "),function(b){var c=j.getStyle(h,b,!0);if(!("bac
 kground-color"===b&&/transparent|rgba\s*\([^)]+,\s*0\)/.test(c)&&(c=j.getStyle(a.getBody(),b,!0),"#ffffff"===j.toHex(c).toLowerCase())||"color"===b&&"#000000"===j.toHex(c).toLowerCase())){if("font-size"===b&&/em|%$/.test(c)){if(0===l)return;c=parseFloat(c,10)/(/%$/.test(c)?100:1),c=c*l+"px"}"border"===b&&c&&(n+="padding:0 2px;"),n+=b+":"+c+";"}}),a.fire("AfterPreviewFormats"),j.remove(f),n)}var i=b.each,j=a.DOM;return{getCssText:h,parseSelector:g,selectorToHtml:e}}),g("1r",["1l","1o","1q"],function(a,b,c){var d=function(d,e,f,g,h){var i=e.get(f);!b.match(d,f,g,h)||"toggle"in i[0]&&!i[0].toggle?a.applyFormat(d,f,g,h):c.remove(d,f,g,h)};return{toggle:d}}),g("1s",[],function(){var a=function(a){a.addShortcut("meta+b","","Bold"),a.addShortc
 ut("meta+i","","Italic"),a.addShortcut("meta+u","","Underline");for(var b=1;b<=6;b++)a.addShortcut("access+"+b,"",["FormatBlock",!1,"h"+b]);a.addShortcut("access+7","",["FormatBlock",!1,"p"]),a.addShortcut("access+8","",["FormatBlock",!1,"div"]),a.addShortcut("access+9","",["FormatBlock",!1,"address"])};return{setup:a}}),g("6",["1k","1","1l","1m","1n","1o","1p","1q","1r","1s"],function(a,b,c,d,e,f,g,h,i,j){return function(k){var l=e(k),m=a(null);return j.setup(k),{get:l.get,register:l.register,unregister:l.unregister,apply:b.curry(c.applyFormat,k),remove:b.curry(h.remove,k),toggle:b.curry(i.toggle,k,l),match:b.curry(f.match,k),matchAll:b.curry(f.matchAll,k
 ),matchNode:b.curry(f.matchNode,k),canApply:b.curry(f.canApply,k),formatChanged:b.curry(d.formatChanged,k,m),getCssText:b.curry(g.getCssText,k)}}}),g("6d",["2k","1t","5o","56","4","4v"],function(a,b,c,d,e,f){var g=function(b,c,d){if(!(a.isString(d)||a.isBoolean(d)||a.isNumber(d)))throw f.error("Invalid call to Attr.set. Key ",c,":: Value ",d,":: Element ",b),new e("Attribute value was not simple");b.setAttribute(c,d+"")},h=function(a,b,c){g(a.dom(),b,c)},i=function(a,b){var d=a.dom();c.each(b,function(a,b){g(d,b,a)})},j=function(a,b){var c=a.dom().getAttribute(b);return null===c?void 0:c},k=function(a,b){var c=a.dom();return!(!c||!c.hasAttribute)&&c.hasAttribute(b)},l=function(a,b){a.dom().removeAttribute(b)},m=function(a){var b=a.dom().attributes;return void 0===b||null===b||0===b.length},n=function(a){return b.foldl(a.dom().attributes,function(a,b){return
  a[b.name]=b.value,a},{})},o=function(a,b,c){k(a,c)&&!k(b,c)&&h(b,c,j(a,c))},p=function(a,c,e){d.isElement(a)&&d.isElement(c)&&b.each(e,function(b){o(a,c,b)})};return{clone:n,set:h,setAll:i,get:j,has:k,remove:l,hasNone:m,transfer:p}}),g("6f",[],function(){var a=function(a){return void 0!==a.style};return{isSupported:a}}),h("5r",window),g("4x",["2k","1t","5o","1u","6d","6e","23","56","6f","5p","4","4v","5r"],function(a,b,c,d,e,f,g,h,i,j,k,l,m){var n=function(b,c,d){if(!a.isString(d))throw l.error("Invalid call to CSS.set. Property ",c,":: Value ",d,":: Element ",b),new k("CSS value must be a string: "+d);i.isSupported(b)&&b.style.setProperty(c,d)},o=function(a,b){i.isSupported(a)&&a.style.removeProperty(b)},p=function(a,b,c){var d=a.dom();n
 (d,b,c)},q=function(a,b){var d=a.dom();c.each(b,function(a,b){n(d,b,a)})},r=function(a,b){var d=a.dom();c.each(b,function(a,b){a.fold(function(){o(d,b)},function(a){n(d,b,a)})})},s=function(a,b){var c=a.dom(),d=m.getComputedStyle(c),e=d.getPropertyValue(b),g=""!==e||f.inBody(a)?e:t(c,b);return null===g?void 0:g},t=function(a,b){return i.isSupported(a)?a.style.getPropertyValue(b):""},u=function(a,b){var c=a.dom(),e=t(c,b);return d.from(e).filter(function(a){return a.length>0})},v=function(a,b,c){var d=g.fromTag(a);p(d,b,c);var e=u(d,b);return e.isSome()},w=function(a,b){var c=a.dom();o(c,b),e.has(a,"style")&&""===j.trim(e.get(a,"style"))&&e.remove(a,"style")},x=function(a,b){var c=e.get(a,"style"),d=b(a),f=void 0===c?e.remove:e.set;return f(a,"style",c),d},y=function(a,b){var c=a.dom(),d=b.dom();i.isSupported(c)&&i.isSupported(d)&&(d.style.cssText=c.style.cssText)},z=fun
 ction(a){return a.dom().offsetWidth},A=function(a,b,c){u(a,c).each(function(a){u(b,c).isNone()&&p(b,c,a)})},B=function(a,c,d){h.isElement(a)&&h.isElement(c)&&b.each(d,function(b){A(a,c,b)})};return{copy:y,set:p,preserve:x,setAll:q,setOptions:r,remove:w,get:s,getRaw:u,isValidValue:v,reflow:z,transfer:B}}),g("1v",["1","1u","26","23","4x","4y"],function(a,b,c,d,e,f){var g=function(a,b){var c=b.dom();return c[a]},h=function(a,b){return parseInt(e.get(b,a),10)},i=a.curry(g,"clientWidth"),j=a.curry(g,"clientHeight"),k=a.curry(h,"margin-top"),l=a.curry(h,"margin-left"),m=function(a){return a.dom().getBoundingClientRect()},n=function(a,b,c){var d=i(a),e=j(a);return b>=0&&c>=0&&b<=d&&c<=e},o=function(a,b,c,d){var e=m(b),f=a?e.left+b.dom().clientLeft+l(b):0,g=a?e.top+b.dom().clientTop+k(b):0,h=c-f,i=d-g;return{x:h,y:i}},p=fun
 ction(a,b,c){var e=d.fromDom(a.getBody()),g=a.inline?e:f.documentElement(e),h=o(a.inline,g,b,c);return n(g,h.x,h.y)},q=function(a){return b.from(a).map(d.fromDom)},r=function(a){var b=a.inline?a.getBody():a.getContentAreaContainer();return q(b).map(function(a){return c.contains(f.owner(a),a)}).getOr(!1)};return{isXYInContentArea:p,isEditorAttachedToDom:r}}),g("4z",["o","1d","c"],function(a,b,c){"use strict";var d=0,e={id:function(){return"mceu_"+d++},create:function(a,d,e){var f=document.createElement(a);return c.DOM.setAttribs(f,d),"string"==typeof e?f.innerHTML=e:b.each(e,function(a){a.nodeType&&f.appendChild(a)}),f},createFragment:function(a){return c.DOM.createFragment(a)},getWindowSize:function(){return c.DOM.getViewPort()},getSize:function(a){var b,c;if(a.getBoundingClientRect){var d=a.getBoundingClientRect();b=Math.max(d.width||d.right-d.left,a.offsetWidth),c=Math.max(d.height||d.bottom-d.bottom,a.o
 ffsetHeight)}else b=a.offsetWidth,c=a.offsetHeight;return{width:b,height:c}},getPos:function(a,b){return c.DOM.getPos(a,b||e.getContainer())},getContainer:function(){return a.container?a.container:document.body},getViewPort:function(a){return c.DOM.getViewPort(a)},get:function(a){return document.getElementById(a)},addClass:function(a,b){return c.DOM.addClass(a,b)},removeClass:function(a,b){return c.DOM.removeClass(a,b)},hasClass:function(a,b){return c.DOM.hasClass(a,b)},toggleClass:function(a,b,d){return c.DOM.toggleClass(a,b,d)},css:function(a,b,d){return c.DOM.setStyle(a,b,d)},getRuntimeStyle:function(a,b){return c.DOM.getStyle(a,b,!0)},on:function(a,b,d,e){return c.DOM.bind(a,b,d,e)},off:function(a,b,d){return c.DOM.unbind(a,b,d)},fire:function(a,b,d){return c.DOM.fire(a,b,d)},innerHtml:function(a,b){c.DOM.setHTML(a,b)}};return e}),g("12",["1d"],function(a){function b(){}var c,d,e=a.each,f=a.extend;return b.extend=c=function(a){function b(){var a,b,c,e=this;if
 (!d&&(e.init&&e.init.apply(e,arguments),b=e.Mixins))for(a=b.length;a--;)c=b[a],c.init&&c.init.apply(e,arguments)}function g(){return this}function h(a,b){return function(){var c,d=this,e=d._super;return d._super=m[a],c=b.apply(d,arguments),d._super=e,c}}var i,j,k,l=this,m=l.prototype;d=!0,i=new l,d=!1,a.Mixins&&(e(a.Mixins,function(b){for(var c in b)"init"!==c&&(a[c]=b[c])}),m.Mixins&&(a.Mixins=m.Mixins.concat(a.Mixins))),a.Methods&&e(a.Methods.split(","),function(b){a[b]=g}),a.Properties&&e(a.Properties.split(","),function(b){var c="_"+b;a[b]=function(a){var b,d=this;return a!==b?(d[c]=a,d):d[c]}}),a.Statics&&e(a.Statics,function(a,c){b[c]=a}),a.Defaults&&m.Defaults&&(a.Defaults=f({},m.Defaults,a.Defaults));for(j in a)k=a[j],"function"==typeof k&&m[j]?i[j]=h(j,k):i[j]=k;return b.prototype=i,b.constructor=b,b.extend=c,b},b}),g("15&quo
 t;,["1d"],function(a){function b(b){function c(){return!1}function d(){return!0}function e(a,e){var f,h,i,k;if(a=a.toLowerCase(),e=e||{},e.type=a,e.target||(e.target=j),e.preventDefault||(e.preventDefault=function(){e.isDefaultPrevented=d},e.stopPropagation=function(){e.isPropagationStopped=d},e.stopImmediatePropagation=function(){e.isImmediatePropagationStopped=d},e.isDefaultPrevented=c,e.isPropagationStopped=c,e.isImmediatePropagationStopped=c),b.beforeFire&&b.beforeFire(e),f=m[a])for(h=0,i=f.length;h<i;h++){if(k=f[h],k.once&&g(a,k.func),e.isImmediatePropagationStopped())return e.stopPropagation(),e;if(k.func.call(j,e)===!1)return e.preventDefault(),e}return e}function f(b,d,e,f){var g,h,i;if(d===!1&&(d=c),d)for(d={func:d},f&&a.extend(d,f),h=b.toLowerCase().split(" "),i=h.length;i--;)b=h[i],g=m[b],g||(g=m[b]=[],k(b,!0)),e?g.unshift(d):g.push(d);return l}function g(a,b){var c,d,e,f,g;if(a)for(f=a.toLowerCase().split(" &quo
 t;),c=f.length;c--;){if(a=f[c],d=m[a],!a){for(e in m)k(e,!1),delete m[e];return l}if(d){if(b)for(g=d.length;g--;)d[g].func===b&&(d=d.slice(0,g).concat(d.slice(g+1)),m[a]=d);else d.length=0;d.length||(k(a,!1),delete m[a])}}else{for(a in m)k(a,!1);m={}}return l}function h(a,b,c){return f(a,b,c,{once:!0})}function i(a){return a=a.toLowerCase(),!(!m[a]||0===m[a].length)}var j,k,l=this,m={};b=b||{},j=b.scope||l,k=b.toggleEvent||c,l.fire=e,l.on=f,l.off=g,l.once=h,l.has=i}var c=a.makeMap("focus blur focusin focusout click dblclick mousedown mouseup mousemove mouseover beforepaste paste cut copy selectionchange mouseout mouseenter mouseleave wheel keydown keypress keyup input contextmenu dragstart dragend dragover draggesture dragdrop drop drag submit compositionstart compositionend compositionupdate touchstart touchmove touchend"," ");return b.isNative=function(a){return!!c[a.toLowerCase()]},b}),g("6i",[],function(){function a(a){this.create=a.create}r
 eturn a.create=function(b,c){return new a({create:function(a,d){function e(b){a.set(d,b.value)}function f(a){b.set(c,a.value)}var g;return a.on("change:"+d,f),b.on("change:"+c,e),g=a._bindings,g||(g=a._bindings=[],a.on("destroy",function(){for(var a=g.length;a--;)g[a]()})),g.push(function(){b.off("change:"+c,e)}),b.get(c)}})},a}),g("1b",["15"],function(a){function b(b){return b._eventDispatcher||(b._eventDispatcher=new a({scope:b,toggleEvent:function(c,d){a.isNative(c)&&b.toggleNativeEvent&&b.toggleNativeEvent(c,d)}})),b._eventDispatcher}return{fire:function(a,c,d){var e=this;if(e.removed&&"remove"!==a)return c;if(c=b(e).fire(a,c,d),d!==!1&&e.parent)for(var f=e.parent();f&&!c.isPropagationStopped();)f.fire(a,c,!1),f=f.parent();return c},on:function(a,c,d){return b(this).on(a,c,d)},off:function(a,c){return b(this).off(a,c)},once:function(a,c){return b(this).once(a,c)},hasEven
 tListeners:function(a){return b(this).has(a)}}}),g("50",["6i","12","1b","1d"],function(a,b,c,d){function e(a){return a.nodeType>0}function f(a,b){var c,g;if(a===b)return!0;if(null===a||null===b)return a===b;if("object"!=typeof a||"object"!=typeof b)return a===b;if(d.isArray(b)){if(a.length!==b.length)return!1;for(c=a.length;c--;)if(!f(a[c],b[c]))return!1}if(e(a)||e(b))return a===b;g={};for(c in b){if(!f(a[c],b[c]))return!1;g[c]=!0}for(c in a)if(!g[c]&&!f(a[c],b[c]))return!1;return!0}return b.extend({Mixins:[c],init:function(b){var c,d;b=b||{};for(c in b)d=b[c],d instanceof a&&(b[c]=d.create(this,c));this.data=b},set:function(b,c){var d,e,g=this.data[b];if(c instanceof a&&(c=c.create(this,b)),"object"==typeof b){for(d in b)this.set(d,b[d]);return this}return f(g,c)||(this.data[b]=c,e={target:this,name:b,value:c,oldValue:g},this.fire("change:"+b,e),this.fire("chang
 e",e)),this},get:function(a){return this.data[a]},has:function(a){return a in this.data},bind:function(b){return a.create(this,b)},destroy:function(){this.fire("destroy")}})}),g("2n",["12"],function(a){"use strict";function b(a){for(var b,c=[],d=a.length;d--;)b=a[d],b.__checked||(c.push(b),b.__checked=1);for(d=c.length;d--;)delete c[d].__checked;return c}var c,d=/^([\w\\*]+)?(?:#([\w\-\\]+))?(?:\.([\w\\\.]+))?(?:\[\@?([\w\\]+)([\^\$\*!~]?=)([\w\\]+)\])?(?:\:(.+))?/i,e=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,f=/^\s*|\s*$/g,g=a.extend({init:function(a){function b(a){if(a)return a=a.toLowerCase(),function(b){return"*"===a||b.type===a}}function c(a){if(a)return function(b){return b._name===a}}function g(a){if(a)return a=a.split("."),function(b){for(var c=a.length;c--;)if(!b.classes.contains(a[c]))return!1
 ;return!0}}function h(a,b,c){if(a)return function(d){var e=d[a]?d[a]():"";return b?"="===b?e===c:"*="===b?e.indexOf(c)>=0:"~="===b?(" "+e+" ").indexOf(" "+c+" ")>=0:"!="===b?e!=c:"^="===b?0===e.indexOf(c):"$="===b&&e.substr(e.length-c.length)===c:!!c}}function i(a){var b;if(a)return a=/(?:not\((.+)\))|(.+)/i.exec(a),a[1]?(b=k(a[1],[]),function(a){return!l(a,b)}):(a=a[2],function(b,c,d){return"first"===a?0===c:"last"===a?c===d-1:"even"===a?c%2===0:"odd"===a?c%2===1:!!b[a]&&b[a]()})}function j(a,e,j){function k(a){a&&e.push(a)}var l;return l=d.exec(a.replace(f,"")),k(b(l[1])),k(c(l[2])),k(g(l[3])),k(h(l[4],l[5],l[6])),k(i(l[7])),e.pseudo=!!l[7],e.direct=j,e}function k(a,b){var c,d,f,g=[];do if(e.exec(""),d=e.exec(a),d&&(a=d[3],g.push(d[1]),d[2])){c=d[3];break}while(d);for(c&&a
 mp;k(c,b),a=[],f=0;f<g.length;f++)">"!=g[f]&&a.push(j(g[f],[],">"===g[f-1]));return b.push(a),b}var l=this.match;this._selectors=k(a,[])},match:function(a,b){var c,d,e,f,g,h,i,j,k,l,m,n,o;for(b=b||this._selectors,c=0,d=b.length;c<d;c++){for(g=b[c],f=g.length,o=a,n=0,e=f-1;e>=0;e--)for(j=g[e];o;){if(j.pseudo)for(m=o.parent().items(),k=l=m.length;k--&&m[k]!==o;);for(h=0,i=j.length;h<i;h++)if(!j[h](o,k,l)){h=i+1;break}if(h===i){n++;break}if(e===f-1)break;o=o.parent()}if(n===f)return!0}return!1},find:function(a){function d(a,b,c){var e,f,g,i,j,k=b[c];for(e=0,f=a.length;e<f;e++){for(j=a[e],g=0,i=k.length;g<i;g++)if(!k[g](j,e,f)){g=i+1;break}if(g===i)c==b.length-1?h.push(j):j.items&&d(j.items(),b,c+1);else if(k.direct)return;j.items&&d(j.items(),b,c)}}var e,f,h=[],i=this._selectors;if(a.items){for(e=0,f=i.length;e<f;e++)d(a.items(),i[e],0);f>1&&(h=b(h))}return c||(c=g.Collection),new c(h)}});return g
 }),g("2o",["1d","2n","12"],function(a,b,c){"use strict";var d,e,f=Array.prototype.push,g=Array.prototype.slice;return e={length:0,init:function(a){a&&this.add(a)},add:function(b){var c=this;return a.isArray(b)?f.apply(c,b):b instanceof d?c.add(b.toArray()):f.call(c,b),c},set:function(a){var b,c=this,d=c.length;for(c.length=0,c.add(a),b=c.length;b<d;b++)delete c[b];return c},filter:function(a){var c,e,f,g,h=this,i=[];for("string"==typeof a?(a=new b(a),g=function(b){return a.match(b)}):g=a,c=0,e=h.length;c<e;c++)f=h[c],g(f)&&i.push(f);return new d(i)},slice:function(){return new d(g.apply(this,arguments))},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},each:function(b){return a.each(this,b),this},toArray:function(){return a.toArray(this)},indexOf:function(a){for(var b=this,c=b.length;c--&&b[c]!==a;);return c},reverse:function(){return new d(a.toArray(this).reverse())},hasClass:fun
 ction(a){return!!this[0]&&this[0].classes.contains(a)},prop:function(a,b){var c,d,e=this;return b!==c?(e.each(function(c){c[a]&&c[a](b)}),e):(d=e[0],d&&d[a]?d[a]():void 0)},exec:function(b){var c=this,d=a.toArray(arguments).slice(1);return c.each(function(a){a[b]&&a[b].apply(a,d)}),c},remove:function(){for(var a=this.length;a--;)this[a].remove();return this},addClass:function(a){return this.each(function(b){b.classes.add(a)})},removeClass:function(a){return this.each(function(b){b.classes.remove(a)})}},a.each("fire on off show hide append prepend before after reflow".split(" "),function(b){e[b]=function(){var c=a.toArray(arguments);return this.each(function(a){b in a&&a[b].apply(a,c)}),this}}),a.each("text name disabled active selected checked visible parent value data".split(" "),function(a){e[a]=function(b){return this.prop(a,b)}}),d=c.extend(e),b.Collection=d,d}),g("51",[],function(){"u
 se strict";return{parseBox:function(a){var b,c=10;if(a)return"number"==typeof a?(a=a||0,{top:a,left:a,bottom:a,right:a}):(a=a.split(" "),b=a.length,1===b?a[1]=a[2]=a[3]=a[0]:2===b?(a[2]=a[0],a[3]=a[1]):3===b&&(a[3]=a[1]),{top:parseInt(a[0],c)||0,right:parseInt(a[1],c)||0,bottom:parseInt(a[2],c)||0,left:parseInt(a[3],c)||0})},measureBox:function(a,b){function c(b){var c=document.defaultView;return c?(b=b.replace(/[A-Z]/g,function(a){return"-"+a}),c.getComputedStyle(a,null).getPropertyValue(b)):a.currentStyle[b]}function d(a){var b=parseFloat(c(a),10);return isNaN(b)?0:b}return{top:d(b+"TopWidth"),right:d(b+"RightWidth"),bottom:d(b+"BottomWidth"),left:d(b+"LeftWidth")}}}}),g("52",["1d"],function(a){"use strict";function b(){}function c(a){this.cls=[],this.cls._map={},this.onchange=a||b,this.prefix=""}return a.extend(c.prototype,{add:function(a){return a&&!
 this.contains(a)&&(this.cls._map[a]=!0,this.cls.push(a),this._change()),this},remove:function(a){if(this.contains(a)){for(var b=0;b<this.cls.length&&this.cls[b]!==a;b++);this.cls.splice(b,1),delete this.cls._map[a],this._change()}return this},toggle:function(a,b){var c=this.contains(a);return c!==b&&(c?this.remove(a):this.add(a),this._change()),this},contains:function(a){return!!this.cls._map[a]},_change:function(){delete this.clsValue,this.onchange.call(this)}}),c.prototype.toString=function(){var a;if(this.clsValue)return this.clsValue;a="";for(var b=0;b<this.cls.length;b++)b>0&&(a+=" "),a+=this.prefix+this.cls[b];return a},c}),g("2p",["14"],function(a){var b,c={};return{add:function(d){var e=d.parent();if(e){if(!e._layout||e._layout.isNative())return;c[e._id]||(c[e._id]=e),b||(b=!0,a.requestAnimationFrame(function(){var a,d;b=!1;for(a in c)d=c[a],d.state.get("rendered")&&d.reflow();
 c={}},document.body))}},remove:function(a){c[a._id]&&delete c[a._id]}}}),g("2q",["12","1d","15","50","2o","4z","b","51","52","2p"],function(a,b,c,d,e,f,g,h,i,j){"use strict";function k(a){return a._eventDispatcher||(a._eventDispatcher=new c({scope:a,toggleEvent:function(b,d){d&&c.isNative(b)&&(a._nativeEvents||(a._nativeEvents={}),a._nativeEvents[b]=!0,a.state.get("rendered")&&l(a))}})),a._eventDispatcher}function l(a){function b(b){var c=a.getParentCtrl(b.target);c&&c.fire(b.type,b)}function c(){var a=j._lastHoverCtrl;a&&(a.fire("mouseleave",{target:a.getEl()}),a.parents().each(function(a){a.fire("mouseleave",{target:a.getEl()})}),j._lastHoverCtrl=null)}function d(b){var c,d,e,f=a.getParentCtrl(b.target),g=j._lastHoverCtrl,h=0;if(f!==g){if(j._lastHoverCtrl=f,d=f.parents().toArray().rever
 se(),d.push(f),g){for(e=g.parents().toArray().reverse(),e.push(g),h=0;h<e.length&&d[h]===e[h];h++);for(c=e.length-1;c>=h;c--)g=e[c],g.fire("mouseleave",{target:g.getEl()})}for(c=h;c<d.length;c++)f=d[c],f.fire("mouseenter",{target:f.getEl()})}}function e(b){b.preventDefault(),"mousewheel"==b.type?(b.deltaY=-.025*b.wheelDelta,b.wheelDeltaX&&(b.deltaX=-.025*b.wheelDeltaX)):(b.deltaX=0,b.deltaY=b.detail),b=a.fire("wheel",b)}var f,h,i,j,k,l;if(k=a._nativeEvents){for(i=a.parents().toArray(),i.unshift(a),f=0,h=i.length;!j&&f<h;f++)j=i[f]._eventsRoot;for(j||(j=i[i.length-1]||a),a._eventsRoot=j,h=f,f=0;f<h;f++)i[f]._eventsRoot=j;var m=j._delegates;m||(m=j._delegates={});for(l in k){if(!k)return!1;"wheel"!==l||o?("mouseenter"===l||"mouseleave"===l?j._hasMouseEnter||(g(j.getEl()).on("mouseleave",c).on("mouseover",d),j._hasMouseEnter=1):m[l]||(g(j.getEl()).on(l,b),m[l
 ]=!0),k[l]=!1):n?g(a.getEl()).on("mousewheel",e):g(a.getEl()).on("DOMMouseScroll",e)}}}var m,n="onmousewheel"in document,o=!1,p="mce-",q=0,r={Statics:{classPrefix:p},isRtl:function(){return m.rtl},classPrefix:p,init:function(a){function c(a){var b;for(a=a.split(" "),b=0;b<a.length;b++)j.classes.add(a[b])}var e,f,j=this;j.settings=a=b.extend({},j.Defaults,a),j._id=a.id||"mceu_"+q++,j._aria={role:a.role},j._elmCache={},j.$=g,j.state=new d({visible:!0,active:!1,disabled:!1,value:""}),j.data=new d(a.data),j.classes=new i(function(){j.state.get("rendered")&&(j.getEl().className=this.toString())}),j.classes.prefix=j.classPrefix,e=a.classes,e&&(j.Defaults&&(f=j.Defaults.classes,f&&e!=f&&c(f)),c(e)),b.each("title text name visible disabled active value".split(" "),function(b){b in a&&j[b](a[b])}),j.on("click",function(){if(j.disable
 d())return!1}),j.settings=a,j.borderBox=h.parseBox(a.border),j.paddingBox=h.parseBox(a.padding),j.marginBox=h.parseBox(a.margin),a.hidden&&j.hide()},Properties:"parent,name",getContainerElm:function(){return f.getContainer()},getParentCtrl:function(a){for(var b,c=this.getRoot().controlIdLookup;a&&c&&!(b=c[a.id]);)a=a.parentNode;return b},initLayoutRect:function(){var a,b,c,d,e,g,i,j,k,l,m=this,n=m.settings,o=m.getEl();a=m.borderBox=m.borderBox||h.measureBox(o,"border"),m.paddingBox=m.paddingBox||h.measureBox(o,"padding"),m.marginBox=m.marginBox||h.measureBox(o,"margin"),l=f.getSize(o),j=n.minWidth,k=n.minHeight,e=j||l.width,g=k||l.height,c=n.width,d=n.height,i=n.autoResize,i="undefined"!=typeof i?i:!c&&!d,c=c||e,d=d||g;var p=a.left+a.right,q=a.top+a.bottom,r=n.maxWidth||65535,s=n.maxHeight||65535;return m._layoutRect=b={x:n.x||0,y:n.y||0,w:c,h:d,deltaW:p,deltaH:q,contentW:c-p,contentH:d-q,innerW:c-p,in
 nerH:d-q,startMinWidth:j||0,startMinHeight:k||0,minW:Math.min(e,r),minH:Math.min(g,s),maxW:r,maxH:s,autoResize:i,scrollW:0},m._lastLayoutRect={},b},layoutRect:function(a){var b,c,d,e,f,g,h=this,i=h._layoutRect;return i||(i=h.initLayoutRect()),a?(d=i.deltaW,e=i.deltaH,a.x!==f&&(i.x=a.x),a.y!==f&&(i.y=a.y),a.minW!==f&&(i.minW=a.minW),a.minH!==f&&(i.minH=a.minH),c=a.w,c!==f&&(c=c<i.minW?i.minW:c,c=c>i.maxW?i.maxW:c,i.w=c,i.innerW=c-d),c=a.h,c!==f&&(c=c<i.minH?i.minH:c,c=c>i.maxH?i.maxH:c,i.h=c,i.innerH=c-e),c=a.innerW,c!==f&&(c=c<i.minW-d?i.minW-d:c,c=c>i.maxW-d?i.maxW-d:c,i.innerW=c,i.w=c+d),c=a.innerH,c!==f&&(c=c<i.minH-e?i.minH-e:c,c=c>i.maxH-e?i.maxH-e:c,i.innerH=c,i.h=c+e),a.contentW!==f&&(i.contentW=a.contentW),a.contentH!==f&&(i.contentH=a.contentH),b=h._lastLayoutRect,b.x===i.x&&b.y===i.y&&b.w===i.w&&b.h===i.h||(g=m.repaintControls,g&&g.map&amp
 ;&!g.map[h._id]&&(g.push(h),g.map[h._id]=!0),b.x=i.x,b.y=i.y,b.w=i.w,b.h=i.h),h):i},repaint:function(){var a,b,c,d,e,f,g,h,i,j,k=this;i=document.createRange?function(a){return a}:Math.round,a=k.getEl().style,d=k._layoutRect,h=k._lastRepaintRect||{},e=k.borderBox,f=e.left+e.right,g=e.top+e.bottom,d.x!==h.x&&(a.left=i(d.x)+"px",h.x=d.x),d.y!==h.y&&(a.top=i(d.y)+"px",h.y=d.y),d.w!==h.w&&(j=i(d.w-f),a.width=(j>=0?j:0)+"px",h.w=d.w),d.h!==h.h&&(j=i(d.h-g),a.height=(j>=0?j:0)+"px",h.h=d.h),k._hasBody&&d.innerW!==h.innerW&&(j=i(d.innerW),c=k.getEl("body"),c&&(b=c.style,b.width=(j>=0?j:0)+"px"),h.innerW=d.innerW),k._hasBody&&d.innerH!==h.innerH&&(j=i(d.innerH),c=c||k.getEl("body"),c&&(b=b||c.style,b.height=(j>=0?j:0)+"px"),h.innerH=d.innerH),k._lastRepaintRect=h,k.fire("repaint",{},!1)},updateLayoutR
 ect:function(){var a=this;a.parent()._lastRect=null,f.css(a.getEl(),{width:"",height:""}),a._layoutRect=a._lastRepaintRect=a._lastLayoutRect=null,a.initLayoutRect()},on:function(a,b){function c(a){var b,c;return"string"!=typeof a?a:function(e){return b||d.parentsAndSelf().each(function(d){var e=d.settings.callbacks;if(e&&(b=e[a]))return c=d,!1}),b?b.call(c,e):(e.action=a,void this.fire("execute",e))}}var d=this;return k(d).on(a,c(b)),d},off:function(a,b){return k(this).off(a,b),this},fire:function(a,b,c){var d=this;if(b=b||{},b.control||(b.control=d),b=k(d).fire(a,b),c!==!1&&d.parent)for(var e=d.parent();e&&!b.isPropagationStopped();)e.fire(a,b,!1),e=e.parent();return b},hasEventListeners:function(a){return k(this).has(a)},parents:function(a){var b,c=this,d=new e;for(b=c.parent();b;b=b.parent())d.add(b);return a&&(d=d.filter(a)),d},parentsAndSelf:function(a){return new e(this).add(this.parents(a))},next:function
 (){var a=this.parent().items();return a[a.indexOf(this)+1]},prev:function(){var a=this.parent().items();return a[a.indexOf(this)-1]},innerHtml:function(a){return this.$el.html(a),this},getEl:function(a){var b=a?this._id+"-"+a:this._id;return this._elmCache[b]||(this._elmCache[b]=g("#"+b)[0]),this._elmCache[b]},show:function(){return this.visible(!0)},hide:function(){return this.visible(!1)},focus:function(){try{this.getEl().focus()}catch(a){}return this},blur:function(){return this.getEl().blur(),this},aria:function(a,b){var c=this,d=c.getEl(c.ariaTarget);return"undefined"==typeof b?c._aria[a]:(c._aria[a]=b,c.state.get("rendered")&&d.setAttribute("role"==a?a:"aria-"+a,b),c)},encode:function(a,b){return b!==!1&&(a=this.translate(a)),(a||"").replace(/[&<>"]/g,function(a){return"&#"+a.charCodeAt(0)+";"})},translate:function(a){return m.translate?m.translate(a):a}
 ,before:function(a){var b=this,c=b.parent();return c&&c.insert(a,c.items().indexOf(b),!0),b},after:function(a){var b=this,c=b.parent();return c&&c.insert(a,c.items().indexOf(b)),b},remove:function(){var a,b,c=this,d=c.getEl(),e=c.parent();if(c.items){var f=c.items().toArray();for(b=f.length;b--;)f[b].remove()}e&&e.items&&(a=[],e.items().each(function(b){b!==c&&a.push(b)}),e.items().set(a),e._lastRect=null),c._eventsRoot&&c._eventsRoot==c&&g(d).off();var h=c.getRoot().controlIdLookup;return h&&delete h[c._id],d&&d.parentNode&&d.parentNode.removeChild(d),c.state.set("rendered",!1),c.state.destroy(),c.fire("remove"),c},renderBefore:function(a){
+return g(a).before(this.renderHtml()),this.postRender(),this},renderTo:function(a){return g(a||this.getContainerElm()).append(this.renderHtml()),this.postRender(),this},preRender:function(){},render:function(){},renderHtml:function(){return'<div id="'+this._id+'" class="'+this.classes+'"></div>'},postRender:function(){var a,b,c,d,e,f=this,h=f.settings;f.$el=g(f.getEl()),f.state.set("rendered",!0);for(d in h)0===d.indexOf("on")&&f.on(d.substr(2),h[d]);if(f._eventsRoot){for(c=f.parent();!e&&c;c=c.parent())e=c._eventsRoot;if(e)for(d in e._nativeEvents)f._nativeEvents[d]=!0}l(f),h.style&&(a=f.getEl(),a&&(a.setAttribute("style",h.style),a.style.cssText=h.style)),f.settings.border&&(b=f.borderBox,f.$el.css({"border-top-width":b.top,"border-right-width":b.right,"border-bottom-width":b.bottom,"border-left-width":b.left}));var i=f.getRoot();i.controlId
 Lookup||(i.controlIdLookup={}),i.controlIdLookup[f._id]=f;for(var k in f._aria)f.aria(k,f._aria[k]);f.state.get("visible")===!1&&(f.getEl().style.display="none"),f.bindStates(),f.state.on("change:visible",function(a){var b,c=a.value;f.state.get("rendered")&&(f.getEl().style.display=c===!1?"none":"",f.getEl().getBoundingClientRect()),b=f.parent(),b&&(b._lastRect=null),f.fire(c?"show":"hide"),j.add(f)}),f.fire("postrender",{},!1)},bindStates:function(){},scrollIntoView:function(a){function b(a,b){var c,d,e=a;for(c=d=0;e&&e!=b&&e.nodeType;)c+=e.offsetLeft||0,d+=e.offsetTop||0,e=e.offsetParent;return{x:c,y:d}}var c,d,e,f,g,h,i=this.getEl(),j=i.parentNode,k=b(i,j);return c=k.x,d=k.y,e=i.offsetWidth,f=i.offsetHeight,g=j.clientWidth,h=j.clientHeight,"end"==a?(c-=g-e,d-=h-f):"center"==a&&(c-=g/2-e/2,d-=h/2-f/2),j.scrollLeft=c,j.scrollT
 op=d,this},getRoot:function(){for(var a,b=this,c=[];b;){if(b.rootControl){a=b.rootControl;break}c.push(b),a=b,b=b.parent()}a||(a=this);for(var d=c.length;d--;)c[d].rootControl=a;return a},reflow:function(){j.remove(this);var a=this.parent();return a&&a._layout&&!a._layout.isNative()&&a.reflow(),this}};return b.each("text title visible disabled active value".split(" "),function(a){r[a]=function(b){return 0===arguments.length?this.state.get(a):("undefined"!=typeof b&&this.state.set(a,b),this)}}),m=a.extend(r)}),g("2x",["4z"],function(a){"use strict";function b(b,c,d){var e,f,g,h,i,j,k,l,m,n;return m=a.getViewPort(),f=a.getPos(c),g=f.x,h=f.y,b.state.get("fixed")&&"static"==a.getRuntimeStyle(document.body,"position")&&(g-=m.x,h-=m.y),e=b.getEl(),n=a.getSize(e),i=n.width,j=n.height,n=a.getSize(c),k=n.width,l=n.height,d=(d||"").split("&qu
 ot;),"b"===d[0]&&(h+=l),"r"===d[1]&&(g+=k),"c"===d[0]&&(h+=Math.round(l/2)),"c"===d[1]&&(g+=Math.round(k/2)),"b"===d[3]&&(h-=j),"r"===d[4]&&(g-=i),"c"===d[3]&&(h-=Math.round(j/2)),"c"===d[4]&&(g-=Math.round(i/2)),{x:g,y:h,w:i,h:j}}return{testMoveRel:function(c,d){for(var e=a.getViewPort(),f=0;f<d.length;f++){var g=b(this,c,d[f]);if(this.state.get("fixed")){if(g.x>0&&g.x+g.w<e.w&&g.y>0&&g.y+g.h<e.h)return d[f]}else if(g.x>e.x&&g.x+g.w<e.w+e.x&&g.y>e.y&&g.y+g.h<e.h+e.y)return d[f]}return d[0]},moveRel:function(a,c){"string"!=typeof c&&(c=this.testMoveRel(a,c));var d=b(this,a,c);return this.moveTo(d.x,d.y)},moveBy:function(a,b){var c=this,d=c.layoutRect();return c.moveTo(d.x+a,d.y+b),c},moveTo:function(b,c){function d(a,b,c){return a<0?0:a+
 c>b?(a=b-c,a<0?0:a):a}var e=this;if(e.settings.constrainToViewport){var f=a.getViewPort(window),g=e.layoutRect();b=d(b,f.w+f.x,g.w),c=d(c,f.h+f.y,g.h)}return e.state.get("rendered")?e.layoutRect({x:b,y:c}).repaint():(e.settings.x=b,e.settings.y=c),e.fire("move",{x:b,y:c}),e}}}),g("32",["2q","2x"],function(a,b){return a.extend({Mixins:[b],Defaults:{classes:"widget tooltip tooltip-n"},renderHtml:function(){var a=this,b=a.classPrefix;return'<div id="'+a._id+'" class="'+a.classes+'" role="presentation"><div class="'+b+'tooltip-arrow"></div><div class="'+b+'tooltip-inner">'+a.encode(a.state.get("text"))+"</div></div>"},bindStates:function(){var a=this;return a.state.on("change:text",function(b){a.getEl().lastChild.innerHTML=a.encode(b.value)}),a._super()},repaint:function(){var a,b,c=this;a=c.getEl().style,b=
 c._layoutRect,a.left=b.x+"px",a.top=b.y+"px",a.zIndex=131070}})}),g("33",["2q","32"],function(a,b){"use strict";var c,d=a.extend({init:function(a){var b=this;b._super(a),a=b.settings,b.canFocus=!0,a.tooltip&&d.tooltips!==!1&&(b.on("mouseenter",function(c){var d=b.tooltip().moveTo(-65535);if(c.control==b){var e=d.text(a.tooltip).show().testMoveRel(b.getEl(),["bc-tc","bc-tl","bc-tr"]);d.classes.toggle("tooltip-n","bc-tc"==e),d.classes.toggle("tooltip-nw","bc-tl"==e),d.classes.toggle("tooltip-ne","bc-tr"==e),d.moveRel(b.getEl(),e)}else d.hide()}),b.on("mouseleave mousedown click",function(){b.tooltip().hide()})),b.aria("label",a.ariaLabel||a.tooltip)},tooltip:function(){return c||(c=new b({type:"tooltip"}),c.renderTo()),c},postRender:function(){var a=this,b=a.settings;a._super(),a.pa
 rent()||!b.width&&!b.height||(a.initLayoutRect(),a.repaint()),b.autofocus&&a.focus()},bindStates:function(){function a(a){c.aria("disabled",a),c.classes.toggle("disabled",a)}function b(a){c.aria("pressed",a),c.classes.toggle("active",a)}var c=this;return c.state.on("change:disabled",function(b){a(b.value)}),c.state.on("change:active",function(a){b(a.value)}),c.state.get("disabled")&&a(!0),c.state.get("active")&&b(!0),c._super()},remove:function(){this._super(),c&&(c.remove(),c=null)}});return d}),g("34",["33"],function(a){"use strict";return a.extend({Defaults:{value:0},init:function(a){var b=this;b._super(a),b.classes.add("progress"),b.settings.filter||(b.settings.filter=function(a){return Math.round(a)})},renderHtml:function(){var a=this,b=a._id,c=this.classPrefix;return'<div id="'+b+'" class="'+a.classes+
 '"><div class="'+c+'bar-container"><div class="'+c+'bar"></div></div><div class="'+c+'text">0%</div></div>'},postRender:function(){var a=this;return a._super(),a.value(a.settings.value),a},bindStates:function(){function a(a){a=b.settings.filter(a),b.getEl().lastChild.innerHTML=a+"%",b.getEl().firstChild.firstChild.style.width=a+"%"}var b=this;return b.state.on("change:value",function(b){a(b.value)}),a(b.state.get("value")),b._super()}})}),g("35",["2q","2x","34","14"],function(a,b,c,d){var e=function(a,b){a.getEl().lastChild.textContent=b+(a.progressBar?" "+a.progressBar.value()+"%":"")};return a.extend({Mixins:[b],Defaults:{classes:"widget notification"},init:function(a){var b=this;b._super(a),b.maxWidth=a.maxWidth,a.text&&b.text(a.text),a.icon&&(b.icon=a.icon)
 ,a.color&&(b.color=a.color),a.type&&b.classes.add("notification-"+a.type),a.timeout&&(a.timeout<0||a.timeout>0)&&!a.closeButton?b.closeButton=!1:(b.classes.add("has-close"),b.closeButton=!0),a.progressBar&&(b.progressBar=new c),b.on("click",function(a){a.target.className.indexOf(b.classPrefix+"close")!=-1&&b.close()})},renderHtml:function(){var a=this,b=a.classPrefix,c="",d="",e="",f="";return a.icon&&(c='<i class="'+b+"ico "+b+"i-"+a.icon+'"></i>'),f=' style="max-width: '+a.maxWidth+"px;"+(a.color?"background-color: "+a.color+';"':'"'),a.closeButton&&(d='<button type="button" class="'+b+'close" aria-hidden="true">\xd7</button>'),a.progressBar&&(e=a.progressBar.renderHtml()),'<div id="'+a._id+'" cl
 ass="'+a.classes+'"'+f+' role="presentation">'+c+'<div class="'+b+'notification-inner">'+a.state.get("text")+"</div>"+e+d+'<div style="clip: rect(1px, 1px, 1px, 1px);height: 1px;overflow: hidden;position: absolute;width: 1px;" aria-live="assertive" aria-relevant="additions" aria-atomic="true"></div></div>'},postRender:function(){var a=this;return d.setTimeout(function(){a.$el.addClass(a.classPrefix+"in"),e(a,a.state.get("text"))},100),a._super()},bindStates:function(){var a=this;return a.state.on("change:text",function(b){a.getEl().firstChild.innerHTML=b.value,e(a,b.value)}),a.progressBar&&(a.progressBar.bindStates(),a.progressBar.state.on("change:value",function(b){e(a,a.state.get("text"))})),a._super()},close:function(){var a=this;return a.fire("close").isDefaultPrevented()||a.remove(),a},repa
 int:function(){var a,b,c=this;a=c.getEl().style,b=c._layoutRect,a.left=b.x+"px",a.top=b.y+"px",a.zIndex=65534}})}),g("1w",["1t","4z","35","1d"],function(a,b,c,d){return function(e){var f=function(a){return a.inline?a.getElement():a.getContentAreaContainer()},g=function(){var a=f(e);return b.getSize(a).width},h=function(b){a.each(b,function(a){a.moveTo(0,0)})},i=function(b){if(b.length>0){var c=b.slice(0,1)[0],d=f(e);c.moveRel(d,"tc-tc"),a.each(b,function(a,c){c>0&&a.moveRel(b[c-1].getEl(),"bc-tc")})}},j=function(a){h(a),i(a)},k=function(a,b){var e=d.extend(a,{maxWidth:g()}),f=new c(e);return f.args=e,e.timeout>0&&(f.timer=setTimeout(function(){f.close(),b()},e.timeout)),f.on("close",function(){b()}),f.renderTo(),f},l=function(a){a.close()},m=function(a){return a.args};return{open:k,close:l,reposition:j,getArgs:m}}}),g("7",["1t","1u&quo
 t;,"1v","1w","14"],function(a,b,c,d,e){return function(f){var g=[],h=function(){var a=f.theme;return a.getNotificationManagerImpl?a.getNotificationManagerImpl():d(f)},i=function(){return b.from(g[0])},j=function(a,b){return!(a.type!==b.type||a.text!==b.text||a.progressBar||a.timeout||b.progressBar||b.timeout)},k=function(){h().reposition(g)},l=function(a){g.push(a)},m=function(b){a.findIndex(g,function(a){return a===b}).each(function(a){g.splice(a,1)})},n=function(b){if(!f.removed&&c.isEditorAttachedToDom(f))return a.find(g,function(a){return j(h().getArgs(a),b)}).getOrThunk(function(){f.editorManager.setActive(f);var a=h().open(b,function(){m(a),k()});return l(a),k(),a})},o=function(){i().each(function(a){h().close(a),m(a),k()})},p=function(){return g},q=function(b){b.on("SkinLoaded",function(){var a=b.settings.service_message;a&&n({text:a,type:"warning",timeout:0,icon:""})}),b.on("ResizeEditor ResizeW
 indow",function(){e.requestAnimationFrame(k)}),b.on("remove",function(){a.each(g,function(a){h().close(a)})})};return q(f),{open:n,close:o,getNotifications:p}}}),g("2r",[],function(){"use strict";var a={};return{add:function(b,c){a[b.toLowerCase()]=c},has:function(b){return!!a[b.toLowerCase()]},get:function(b){var c=b.toLowerCase(),d=a.hasOwnProperty(c)?a[c]:null;if(null===d)throw new Error("Could not find module for type: "+b);return d},create:function(b,c){var d;if("string"==typeof b?(c=c||{},c.type=b):(c=b,b=c.type),b=b.toLowerCase(),d=a[b],!d)throw new Error("Could not find control by type: "+b);return d=new d(c),d.type=b,d}}}),g("2s",[],function(){"use strict";var a=function(a){return!!a.getAttribute("data-mce-tabstop")};return function(b){function c(a){return a&&1===a.nodeType}function d(a){return a=a||u,c(a)?a.getAttribute("role"):null}function e(a){for(var b,c=a||
 u;c=c.parentNode;)if(b=d(c))return b}function f(a){var b=u;if(c(b))return b.getAttribute("aria-"+a)}function g(a){var b=a.tagName.toUpperCase();return"INPUT"==b||"TEXTAREA"==b||"SELECT"==b}function h(b){return!(!g(b)||b.hidden)||(!!a(b)||!!/^(button|menuitem|checkbox|tab|menuitemcheckbox|option|gridcell|slider)$/.test(d(b)))}function i(a){function b(a){if(1==a.nodeType&&"none"!=a.style.display&&!a.disabled){h(a)&&c.push(a);for(var d=0;d<a.childNodes.length;d++)b(a.childNodes[d])}}var c=[];return b(a||w.getEl()),c}function j(a){var b,c;a=a||v,c=a.parents().toArray(),c.unshift(a);for(var d=0;d<c.length&&(b=c[d],!b.settings.ariaRoot);d++);return b}function k(a){var b=j(a),c=i(b.getEl());b.settings.ariaRemember&&"lastAriaIndex"in b?l(b.lastAriaIndex,c):l(0,c)}function l(a,b){return a<0?a=b.length-1:a>=b.length&&(a=0),b[a]&&b[a].focus(),a}function m(a,b){var c=-
 1,d=j();b=b||i(d.getEl());for(var e=0;e<b.length;e++)b[e]===u&&(c=e);c+=a,d.lastAriaIndex=l(c,b)}function n(){var a=e();"tablist"==a?m(-1,i(u.parentNode)):v.parent().submenu?s():m(-1)}function o(){var a=d(),b=e();"tablist"==b?m(1,i(u.parentNode)):"menuitem"==a&&"menu"==b&&f("haspopup")?t():m(1)}function p(){m(-1)}function q(){var a=d(),b=e();"menuitem"==a&&"menubar"==b?t():"button"==a&&f("haspopup")?t({key:"down"}):m(1)}function r(a){var b=e();if("tablist"==b){var c=i(v.getEl("body"))[0];c&&c.focus()}else m(a.shiftKey?-1:1)}function s(){v.fire("cancel")}function t(a){a=a||{},v.fire("click",{target:u,aria:a})}var u,v,w=b.root;try{u=document.activeElement}catch(a){u=document.body}return v=w.getParentCtrl(u),w.on("keydown",function(b){function c(b,c){g(u)||a(u)||"slider"!==d(u)&
 amp;&c(b)!==!1&&b.preventDefault()}if(!b.isDefaultPrevented())switch(b.keyCode){case 37:c(b,n);break;case 39:c(b,o);break;case 38:c(b,p);break;case 40:c(b,q);break;case 27:s();break;case 14:case 13:case 32:c(b,t);break;case 9:r(b)!==!1&&b.preventDefault()}}),w.on("focusin",function(a){u=a.target,v=a.control}),{focusFirst:k}}}),g("2t",["2q","2o","2n","2r","2s","1d","b","52","2p"],function(a,b,c,d,e,f,g,h,i){"use strict";var j={};return a.extend({init:function(a){var c=this;c._super(a),a=c.settings,a.fixed&&c.state.set("fixed",!0),c._items=new b,c.isRtl()&&c.classes.add("rtl"),c.bodyClasses=new h(function(){c.state.get("rendered")&&(c.getEl("body").className=this.toString())}),c.bodyClasses.prefix=c.classPrefix,c.classes.add("container"),c.bodyClasses.add("container-bod
 y"),a.containerCls&&c.classes.add(a.containerCls),c._layout=d.create((a.layout||"")+"layout"),c.settings.items?c.add(c.settings.items):c.add(c.render()),c._hasBody=!0},items:function(){return this._items},find:function(a){return a=j[a]=j[a]||new c(a),a.find(this)},add:function(a){var b=this;return b.items().add(b.create(a)).parent(b),b},focus:function(a){var b,c,d,e=this;return a&&(c=e.keyboardNav||e.parents().eq(-1)[0].keyboardNav)?void c.focusFirst(e):(d=e.find("*"),e.statusbar&&d.add(e.statusbar.items()),d.each(function(a){return a.settings.autofocus?(b=null,!1):void(a.canFocus&&(b=b||a))}),b&&b.focus(),e)},replace:function(a,b){for(var c,d=this.items(),e=d.length;e--;)if(d[e]===a){d[e]=b;break}e>=0&&(c=b.getEl(),c&&c.parentNode.removeChild(c),c=a.getEl(),c&&c.parentNode.removeChild(c)),b.parent(this)},create:function(b){var c,e=this,g=[];return f.isArray(b)||(b=[b]),f.each(b,fun
 ction(b){b&&(b instanceof a||("string"==typeof b&&(b={type:b}),c=f.extend({},e.settings.defaults,b),b.type=c.type=c.type||b.type||e.settings.defaultType||(c.defaults?c.defaults.type:null),b=d.create(c)),g.push(b))}),g},renderNew:function(){var a=this;return a.items().each(function(b,c){var d;b.parent(a),b.state.get("rendered")||(d=a.getEl("body"),d.hasChildNodes()&&c<=d.childNodes.length-1?g(d.childNodes[c]).before(b.renderHtml()):g(d).append(b.renderHtml()),b.postRender(),i.add(b))}),a._layout.applyClasses(a.items().filter(":visible")),a._lastRect=null,a},append:function(a){return this.add(a).renderNew()},prepend:function(a){var b=this;return b.items().set(b.create(a).concat(b.items().toArray())),b.renderNew()},insert:function(a,b,c){var d,e,f,g=this;return a=g.create(a),d=g.items(),!c&&b<d.length-1&&(b+=1),b>=0&&b<d.length&&(e=d.slice(0,b).toArray(),f=d.slice(b).toArray(),d.
 set(e.concat(a,f))),g.renderNew()},fromJSON:function(a){var b=this;for(var c in a)b.find("#"+c).value(a[c]);return b},toJSON:function(){var a=this,b={};return a.find("*").each(function(a){var c=a.name(),d=a.value();c&&"undefined"!=typeof d&&(b[c]=d)}),b},renderHtml:function(){var a=this,b=a._layout,c=this.settings.role;return a.preRender(),b.preRender(a),'<div id="'+a._id+'" class="'+a.classes+'"'+(c?' role="'+this.settings.role+'"':"")+'><div id="'+a._id+'-body" class="'+a.bodyClasses+'">'+(a.settings.html||"")+b.renderHtml(a)+"</div></div>"},postRender:function(){var a,b=this;return b.items().exec("postRender"),b._super(),b._layout.postRender(b),b.state.set("rendered",!0),b.settings.style&&b.$el.css(b.settings.style),b.settings.border&&(a=b.borderBox,b.$el.css({"border-top-width":a.top,&q
 uot;border-right-width":a.right,"border-bottom-width":a.bottom,"border-left-width":a.left})),b.parent()||(b.keyboardNav=new e({root:b})),b},initLayoutRect:function(){var a=this,b=a._super();return a._layout.recalc(a),b},recalc:function(){var a=this,b=a._layoutRect,c=a._lastRect;if(!c||c.w!=b.w||c.h!=b.h)return a._layout.recalc(a),b=a.layoutRect(),a._lastRect={x:b.x,y:b.y,w:b.w,h:b.h},!0},reflow:function(){var b;if(i.remove(this),this.visible()){for(a.repaintControls=[],a.repaintControls.map={},this.recalc(),b=a.repaintControls.length;b--;)a.repaintControls[b].repaint();"flow"!==this.settings.layout&&"stack"!==this.settings.layout&&this.repaint(),a.repaintControls=[]}return this}})}),g("2u",["b"],function(a){"use strict";function b(a){var b,c,d,e,f,g,h,i,j=Math.max;return b=a.documentElement,c=a.body,d=j(b.scrollWidth,c.scrollWidth),e=j(b.clientWidth,c.clientWidth),f=j(b.offsetWidth,c.offsetWid
 th),g=j(b.scrollHeight,c.scrollHeight),h=j(b.clientHeight,c.clientHeight),i=j(b.offsetHeight,c.offsetHeight),{width:d<f?e:d,height:g<i?h:g}}function c(a){var b,c;if(a.changedTouches)for(b="screenX screenY pageX pageY clientX clientY".split(" "),c=0;c<b.length;c++)a[b[c]]=a.changedTouches[0][b[c]]}return function(d,e){function f(){return n.getElementById(e.handle||d)}var g,h,i,j,k,l,m,n=e.document||document;e=e||{},i=function(d){var i,o,p=b(n);c(d),d.preventDefault(),h=d.button,i=f(),l=d.screenX,m=d.screenY,o=window.getComputedStyle?window.getComputedStyle(i,null).getPropertyValue("cursor"):i.runtimeStyle.cursor,g=a("<div></div>").css({position:"absolute",top:0,left:0,width:p.width,height:p.height,zIndex:2147483647,opacity:1e-4,cursor:o}).appendTo(n.body),a(n).on("mousemove touchmove",k).on("mouseup touchend",j),e.start(d)},k=function(a){return c(a),a.button!==h?j(a):(a.deltaX=a.screenX-l,a.del
 taY=a.screenY-m,a.preventDefault(),void e.drag(a))},j=function(b){c(b),a(n).off("mousemove touchmove",k).off("mouseup touchend",j),g.remove(),e.stop&&e.stop(b)},this.destroy=function(){a(f()).off()},a(f()).on("mousedown touchstart",i)}}),g("2v",["b","2u"],function(a,b){"use strict";return{init:function(){var a=this;a.on("repaint",a.renderScroll)},renderScroll:function(){function c(){function b(b,g,h,i,j,k){var l,m,n,o,p,q,r,s,t;if(m=e.getEl("scroll"+b)){if(s=g.toLowerCase(),t=h.toLowerCase(),a(e.getEl("absend")).css(s,e.layoutRect()[i]-1),!j)return void a(m).css("display","none");a(m).css("display","block"),l=e.getEl("body"),n=e.getEl("scroll"+b+"t"),o=l["client"+h]-2*f,o-=c&&d?m["client"+k]:0,p=l["scroll"+h],q=o/p,r={},r[s]=l["offset"+g]+f,r[t]=o,a(m).css(r),r
 ={},r[s]=l["scroll"+g]*q,r[t]=o*q,a(n).css(r)}}var c,d,g;g=e.getEl("body"),c=g.scrollWidth>g.clientWidth,d=g.scrollHeight>g.clientHeight,b("h","Left","Width","contentW",c,"Height"),b("v","Top","Height","contentH",d,"Width")}function d(){function c(c,d,g,h,i){var j,k=e._id+"-scroll"+c,l=e.classPrefix;a(e.getEl()).append('<div id="'+k+'" class="'+l+"scrollbar "+l+"scrollbar-"+c+'"><div id="'+k+'t" class="'+l+'scrollbar-thumb"></div></div>'),e.draghelper=new b(k+"t",{start:function(){j=e.getEl("body")["scroll"+d],a("#"+k).addClass(l+"active")},drag:function(a){var b,k,l,m,n=e.layoutRect();k=n.contentW>n.innerW,l=n.contentH>n.innerH,m=e.getEl("body")["client"+g]-2*f,m-=k&&l?e.getEl("
 scroll"+c)["client"+i]:0,b=m/e.getEl("body")["scroll"+g],e.getEl("body")["scroll"+d]=j+a["delta"+h]/b},stop:function(){a("#"+k).removeClass(l+"active")}})}e.classes.add("scroll"),c("v","Top","Height","Y","Width"),c("h","Left","Width","X","Height")}var e=this,f=2;e.settings.autoScroll&&(e._hasScroll||(e._hasScroll=!0,d(),e.on("wheel",function(a){var b=e.getEl("body");b.scrollLeft+=10*(a.deltaX||0),b.scrollTop+=10*a.deltaY,c()}),a(e.getEl("body")).on("scroll",c)),c())}}}),g("2w",["2t","2v"],function(a,b){"use strict";return a.extend({Defaults:{layout:"fit",containerCls:"panel"},Mixins:[b],renderHtml:function(){var a=this,b=a._layout,c=a.settings.html;return a.preRender(),b.preRender(a),&
 quot;undefined"==typeof c?c='<div id="'+a._id+'-body" class="'+a.bodyClasses+'">'+b.renderHtml(a)+"</div>":("function"==typeof c&&(c=c.call(a)),a._hasBody=!1),'<div id="'+a._id+'" class="'+a.classes+'" hidefocus="1" tabindex="-1" role="group">'+(a._preBodyHtml||"")+c+"</div>"}})}),g("2y",["4z"],function(a){"use strict";return{resizeToContent:function(){this._layoutRect.autoResize=!0,this._lastRect=null,this.reflow()},resizeTo:function(b,c){if(b<=1||c<=1){var d=a.getWindowSize();b=b<=1?b*d.w:b,c=c<=1?c*d.h:c}return this._layoutRect.autoResize=!1,this.layoutRect({minW:b,minH:c,w:b,h:c}).reflow()},resizeBy:function(a,b){var c=this,d=c.layoutRect();return c.resizeTo(d.w+a,d.h+b)}}}),g("2z",["2w","2x","2y","4z","b","14"],function(a,b
 ,c,d,e,f){"use strict";function g(a,b){for(;a;){if(a==b)return!0;a=a.parent()}}function h(a){for(var b=s.length;b--;){var c=s[b],d=c.getParentCtrl(a.target);if(c.settings.autohide){if(d&&(g(d,c)||c.parent()===d))continue;a=c.fire("autohide",{target:a.target}),a.isDefaultPrevented()||c.hide()}}}function i(){o||(o=function(a){2!=a.button&&h(a)},e(document).on("click touchstart",o))}function j(){p||(p=function(){var a;for(a=s.length;a--;)l(s[a])},e(window).on("scroll",p))}function k(){if(!q){var a=document.documentElement,b=a.clientWidth,c=a.clientHeight;q=function(){document.all&&b==a.clientWidth&&c==a.clientHeight||(b=a.clientWidth,c=a.clientHeight,u.hideAll())},e(window).on("resize",q)}}function l(a){function b(b,c){for(var d,e=0;e<s.length;e++)if(s[e]!=a)for(d=s[e].parent();d&&(d=d.parent());)d==a&&s[e].fixed(b).moveBy(0,c).repaint()}var c=d.getViewPort().y;a.settings.autofix&&a
 mp;(a.state.get("fixed")?a._autoFixY>c&&(a.fixed(!1).layoutRect({y:a._autoFixY}).repaint(),b(!1,a._autoFixY-c)):(a._autoFixY=a.layoutRect().y,a._autoFixY<c&&(a.fixed(!0).layoutRect({y:0}).repaint(),b(!0,c-a._autoFixY))))}function m(a,b){var c,d,f=u.zIndex||65535;if(a)t.push(b);else for(c=t.length;c--;)t[c]===b&&t.splice(c,1);if(t.length)for(c=0;c<t.length;c++)t[c].modal&&(f++,d=t[c]),t[c].getEl().style.zIndex=f,t[c].zIndex=f,f++;var g=e("#"+b.classPrefix+"modal-block",b.getContainerElm())[0];d?e(g).css("z-index",d.zIndex-1):g&&(g.parentNode.removeChild(g),r=!1),u.currentZIndex=f}function n(a){var b;for(b=s.length;b--;)s[b]===a&&s.splice(b,1);for(b=t.length;b--;)t[b]===a&&t.splice(b,1)}var o,p,q,r,s=[],t=[],u=a.extend({Mixins:[b,c],init:function(a){var b=this;b._super(a),b._eventsRoot=b,b.classes.add("floatpanel"),a.autohide&&(i(),k(),s.push(b)),a.autofix&&am
 p;(j(),b.on("move",function(){l(this)})),b.on("postrender show",function(a){if(a.control==b){var c,d=b.classPrefix;b.modal&&!r&&(c=e("#"+d+"modal-block",b.getContainerElm()),c[0]||(c=e('<div id="'+d+'modal-block" class="'+d+"reset "+d+'fade"></div>').appendTo(b.getContainerElm())),f.setTimeout(function(){c.addClass(d+"in"),e(b.getEl()).addClass(d+"in")}),r=!0),m(!0,b)}}),b.on("show",function(){b.parents().each(function(a){if(a.state.get("fixed"))return b.fixed(!0),!1})}),a.popover&&(b._preBodyHtml='<div class="'+b.classPrefix+'arrow"></div>',b.classes.add("popover").add("bottom").add(b.isRtl()?"end":"start")),b.aria("label",a.ariaLabel),b.aria("labelledby",b._id),b.aria("describedby",b.describedBy||b._id+"-none")},fixed:function(a){var b=t
 his;if(b.state.get("fixed")!=a){if(b.state.get("rendered")){var c=d.getViewPort();a?b.layoutRect().y-=c.y:b.layoutRect().y+=c.y}b.classes.toggle("fixed",a),b.state.set("fixed",a)}return b},show:function(){var a,b=this,c=b._super();for(a=s.length;a--&&s[a]!==b;);return a===-1&&s.push(b),c},hide:function(){return n(this),m(!1,this),this._super()},hideAll:function(){u.hideAll()},close:function(){var a=this;return a.fire("close").isDefaultPrevented()||(a.remove(),m(!1,a)),a},remove:function(){n(this),this._super()},postRender:function(){var a=this;return a.settings.bodyRole&&this.getEl("body").setAttribute("role",a.settings.bodyRole),a._super()}});return u.hideAll=function(){for(var a=s.length;a--;){var b=s[a];b&&b.settings.autohide&&(b.hide(),s.splice(a,1))}},u}),g("30",["2z","2w","4z","b","2u","51","o&q
 uot;,"14"],function(a,b,c,d,e,f,g,h){"use strict";function i(a){var b,c="width=device-width,initial-scale=1.0,user-scalable=0,minimum-scale=1.0,maximum-scale=1.0",e=d("meta[name=viewport]")[0];g.overrideViewPort!==!1&&(e||(e=document.createElement("meta"),e.setAttribute("name","viewport"),document.getElementsByTagName("head")[0].appendChild(e)),b=e.getAttribute("content"),b&&"undefined"!=typeof n&&(n=b),e.setAttribute("content",a?c:n))}function j(a,b){k()&&b===!1&&d([document.documentElement,document.body]).removeClass(a+"fullscreen")}function k(){for(var a=0;a<m.length;a++)if(m[a]._fullscreen)return!0;return!1}function l(){function a(){var a,b,d=c.getWindowSize();for(a=0;a<m.length;a++)b=m[a].layoutRect(),m[a].moveTo(m[a].settings.x||Math.max(0,d.w/2-b.w/2),m[a].settings.y||Math.max(0,d.h/2-b.h/2))}if(!g.desktop){var b
 ={w:window.innerWidth,h:window.innerHeight};h.setInterval(function(){var a=window.innerWidth,c=window.innerHeight;b.w==a&&b.h==c||(b={w:a,h:c},d(window).trigger("resize"))},100)}d(window).on("resize",a)}var m=[],n="",o=a.extend({modal:!0,Defaults:{border:1,layout:"flex",containerCls:"panel",role:"dialog",callbacks:{submit:function(){this.fire("submit",{data:this.toJSON()})},close:function(){this.close()}}},init:function(a){var d=this;d._super(a),d.isRtl()&&d.classes.add("rtl"),d.classes.add("window"),d.bodyClasses.add("window-body"),d.state.set("fixed",!0),a.buttons&&(d.statusbar=new b({layout:"flex",border:"1 0 0 0",spacing:3,padding:10,align:"center",pack:d.isRtl()?"start":"end",defaults:{type:"button"},items:a.buttons}),d.statusbar.classes.add("foot"),d.statusbar.parent(d)),d.on(
 "click",function(a){var b=d.classPrefix+"close";(c.hasClass(a.target,b)||c.hasClass(a.target.parentNode,b))&&d.close()}),d.on("cancel",function(){d.close()}),d.aria("describedby",d.describedBy||d._id+"-none"),d.aria("label",a.title),d._fullscreen=!1},recalc:function(){var a,b,d,e,f=this,g=f.statusbar;f._fullscreen&&(f.layoutRect(c.getWindowSize()),f.layoutRect().contentH=f.layoutRect().innerH),f._super(),a=f.layoutRect(),f.settings.title&&!f._fullscreen&&(b=a.headerW,b>a.w&&(d=a.x-Math.max(0,b/2),f.layoutRect({w:b,x:d}),e=!0)),g&&(g.layoutRect({w:f.layoutRect().innerW}).recalc(),b=g.layoutRect().minW+a.deltaW,b>a.w&&(d=a.x-Math.max(0,b-a.w),f.layoutRect({w:b,x:d}),e=!0)),e&&f.recalc()},initLayoutRect:function(){var a,b=this,d=b._super(),e=0;if(b.settings.title&&!b._fullscreen){a=b.getEl("head");var f=c.getSize(a);d.headerW=f.width,d.head
 erH=f.height,e+=d.headerH}b.statusbar&&(e+=b.statusbar.layoutRect().h),d.deltaH+=e,d.minH+=e,d.h+=e;var g=c.getWindowSize();return d.x=b.settings.x||Math.max(0,g.w/2-d.w/2),d.y=b.settings.y||Math.max(0,g.h/2-d.h/2),d},renderHtml:function(){var a=this,b=a._layout,c=a._id,d=a.classPrefix,e=a.settings,f="",g="",h=e.html;return a.preRender(),b.preRender(a),e.title&&(f='<div id="'+c+'-head" class="'+d+'window-head"><div id="'+c+'-title" class="'+d+'title">'+a.encode(e.title)+'</div><div id="'+c+'-dragh" class="'+d+'dragh"></div><button type="button" class="'+d+'close" aria-hidden="true"><i class="mce-ico mce-i-remove"></i></button></div>'),e.url&&(h='<iframe src="'+e.url+'" tabindex="-1"></iframe>'),"undefined"==typeof h&&(h=b.renderHtml(
 a)),a.statusbar&&(g=a.statusbar.renderHtml()),'<div id="'+c+'" class="'+a.classes+'" hidefocus="1"><div class="'+a.classPrefix+'reset" role="application">'+f+'<div id="'+c+'-body" class="'+a.bodyClasses+'">'+h+"</div>"+g+"</div></div>"},fullscreen:function(a){var b,e,g=this,i=document.documentElement,j=g.classPrefix;if(a!=g._fullscreen)if(d(window).on("resize",function(){var a;if(g._fullscreen)if(b)g._timer||(g._timer=h.setTimeout(function(){var a=c.getWindowSize();g.moveTo(0,0).resizeTo(a.w,a.h),g._timer=0},50));else{a=(new Date).getTime();var d=c.getWindowSize();g.moveTo(0,0).resizeTo(d.w,d.h),(new Date).getTime()-a>50&&(b=!0)}}),e=g.layoutRect(),g._fullscreen=a,a){g._initial={x:e.x,y:e.y,w:e.w,h:e.h},g.borderBox=f.parseBox("0"),g.getEl("head").style.display="none",e.deltaH-=e.headerH+2,d([i,documen
 t.body]).addClass(j+"fullscreen"),g.classes.add("fullscreen");var k=c.getWindowSize();g.moveTo(0,0).resizeTo(k.w,k.h)}else g.borderBox=f.parseBox(g.settings.border),g.getEl("head").style.display="",e.deltaH+=e.headerH,d([i,document.body]).removeClass(j+"fullscreen"),g.classes.remove("fullscreen"),g.moveTo(g._initial.x,g._initial.y).resizeTo(g._initial.w,g._initial.h);return g.reflow()},postRender:function(){var a,b=this;setTimeout(function(){b.classes.add("in"),b.fire("open")},0),b._super(),b.statusbar&&b.statusbar.postRender(),b.focus(),this.dragHelper=new e(b._id+"-dragh",{start:function(){a={x:b.layoutRect().x,y:b.layoutRect().y}},drag:function(c){b.moveTo(a.x+c.deltaX,a.y+c.deltaY)}}),b.on("submit",function(a){a.isDefaultPrevented()||b.close()}),m.push(b),i(!0)},submit:function(){return this.fire("submit",{data:this.toJSON()})},remove:function(){var a,b=this;for(
 b.dragHelper.destroy(),b._super(),b.statusbar&&this.statusbar.remove(),j(b.classPrefix,!1),a=m.length;a--;)m[a]===b&&m.splice(a,1);i(m.length>0)},getContentWindow:function(){var a=this.getEl().getElementsByTagName("iframe")[0];return a?a.contentWindow:null}});return l(),o}),g("31",["30"],function(a){"use strict";var b=a.extend({init:function(a){a={border:1,padding:20,layout:"flex",pack:"center",align:"center",containerCls:"panel",autoScroll:!0,buttons:{type:"button",text:"Ok",action:"ok"},items:{type:"label",multiline:!0,maxWidth:500,maxHeight:200}},this._super(a)},Statics:{OK:1,OK_CANCEL:2,YES_NO:3,YES_NO_CANCEL:4,msgBox:function(c){function d(a,b,c){return{type:"button",text:a,subtype:c?"primary":"",onClick:function(a){a.control.parents()[1].close(),f(b)}}}var e,f=c.callback||function(){};switch(c.buttons){case b.O
 K_CANCEL:e=[d("Ok",!0,!0),d("Cancel",!1)];break;case b.YES_NO:case b.YES_NO_CANCEL:e=[d("Yes",1,!0),d("No",0)],c.buttons==b.YES_NO_CANCEL&&e.push(d("Cancel",-1));break;default:e=[d("Ok",!0,!0)]}return new a({padding:20,x:c.x,y:c.y,minWidth:300,minHeight:100,layout:"flex",pack:"center",align:"center",buttons:e,title:c.title,role:"alertdialog",items:{type:"label",multiline:!0,maxWidth:500,maxHeight:200,text:c.text},onPostRender:function(){this.aria("describedby",this.items()[0]._id)},onClose:c.onClose,onCancel:function(){f(!1)}}).renderTo(document.body).reflow()},alert:function(a,c){return"string"==typeof a&&(a={text:a}),a.callback=c,b.msgBox(a)},confirm:function(a,c){return"string"==typeof a&&(a={text:a}),a.callback=c,a.buttons=b.OK_CANCEL,b.msgBox(a)}}});return b}),g("1x",["30","31"],function
 (a,b){return function(c){var d=function(b,c,d){var e;return b.title=b.title||" ",b.url=b.url||b.file,b.url&&(b.width=parseInt(b.width||320,10),b.height=parseInt(b.height||240,10)),b.body&&(b.items={defaults:b.defaults,type:b.bodyType||"form",items:b.body,data:b.data,callbacks:b.commands}),b.url||b.buttons||(b.buttons=[{text:"Ok",subtype:"primary",onclick:function(){e.find("form")[0].submit()}},{text:"Cancel",onclick:function(){e.close()}}]),e=new a(b),e.on("close",function(){d(e)}),b.data&&e.on("postRender",function(){this.find("*").each(function(a){var c=a.name();c in b.data&&a.value(b.data[c])})}),e.features=b||{},e.params=c||{},e=e.renderTo().reflow()},e=function(a,c,d){var e;return e=b.alert(a,function(){c()}),e.on("close",function(){d(e)}),e},f=function(a,c,d){var e;return e=b.confirm(a,function(a){c(a)}),e.on("close",function(){d(e)}),e}
 ,g=function(a){a.close()},h=function(a){return a.params},i=function(a,b){a.params=b};return{open:d,alert:e,confirm:f,close:g,getParams:h,setParams:i}}}),g("8",["1t","1u","1x"],function(a,b,c){return function(d){var e=[],f=function(){var a=d.theme;return a.getWindowManagerImpl?a.getWindowManagerImpl():c(d)},g=function(a,b){return function(){return b?b.apply(a,arguments):void 0}},h=function(a){d.fire("OpenWindow",{win:a})},i=function(a){d.fire("CloseWindow",{win:a})},j=function(a){e.push(a),h(a)},k=function(b){a.findIndex(e,function(a){return a===b}).each(function(a){e.splice(a,1),i(b),0===e.length&&d.focus()})},l=function(){return b.from(e[0])},m=function(a,b){d.editorManager.setActive(d),0===e.length&&d.nodeChanged();var c=f().open(a,b,k);return j(c),c},n=function(a,b,c){var d=f().alert(a,g(c?c:this,b),k);j(d)},o=function(a,b,c){var d=f().confirm(a,g(c?c:this,b),k);j(d)},p=function(){l().each(function(a){f()
 .close(a),k(a)})},q=function(){return l().map(f().getParams).getOr(null);
+},r=function(a){l().each(function(b){f().setParams(b,a)})},s=function(){return e};return d.on("remove",function(){a.each(e.slice(0),function(a){f().close(a)})}),{windows:e,open:m,alert:n,confirm:o,close:p,getParams:q,setParams:r,getWindows:s}}}),g("25",["1t","4k"],function(a,b){var c=function(c,d,e){return!e.collapsed&&a.foldl(e.getClientRects(),function(a,e){return a||b.containsXY(e,c,d)},!1)};return{isXYWithinRange:c}}),g("1f",["o"],function(a){return{BACKSPACE:8,DELETE:46,DOWN:40,ENTER:13,LEFT:37,RIGHT:39,SPACEBAR:32,TAB:9,UP:38,modifierPressed:function(a){return a.shiftKey||a.ctrlKey||a.altKey||this.metaKeyPressed(a)},metaKeyPressed:function(b){return a.mac?b.metaKey:b.ctrlKey&&!b.altKey}}}),g("a",["1","23","24","21","25","o","14","1d","1f"],function(a,b,c,d,e,f,g,h,i){function j(a,b){for(;b&&b!=a;
 ){if(l(b)||k(b))return b;b=b.parentNode}return null}var k=d.isContentEditableFalse,l=d.isContentEditableTrue,m=function(a){return a&&"IMG"===a.nodeName},n=function(a,b){return m(a.target)&&!e.isXYWithinRange(a.clientX,a.clientY,b)},o=function(a,b){var c=b.target;n(b,a.selection.getRng())&&!b.isDefaultPrevented()&&(b.preventDefault(),a.selection.select(c))};return function(d,e){function l(a){var d=e.settings.object_resizing;return d!==!1&&!f.iOS&&("string"!=typeof d&&(d="table,img,div"),"false"!==a.getAttribute("data-mce-resize")&&(a!=e.getBody()&&c.is(b.fromDom(a),d)))}function m(a){var b,c,d,f,g;b=a.screenX-J,c=a.screenY-K,R=b*H[2]+N,S=c*H[3]+O,R=R<5?5:R,S=S<5?5:S,d="IMG"==D.nodeName&&e.settings.resize_img_proportional!==!1?!i.modifierPressed(a):i.modifierPressed(a)||"IMG"==D.nodeName&&H[2]*H[3]!==0,d&&($(b)>$
 (c)?(S=_(R*P),R=_(S/P)):(R=_(S/P),S=_(R*P))),V.setStyles(E,{width:R,height:S}),f=H.startPos.x+b,g=H.startPos.y+c,f=f>0?f:0,g=g>0?g:0,V.setStyles(F,{left:f,top:g,display:"block"}),F.innerHTML=R+" &times; "+S,H[2]<0&&E.clientWidth<=R&&V.setStyle(E,"left",L+(N-R)),H[3]<0&&E.clientHeight<=S&&V.setStyle(E,"top",M+(O-S)),b=aa.scrollWidth-T,c=aa.scrollHeight-U,b+c!==0&&V.setStyles(F,{left:f-b,top:g-c}),Q||(e.fire("ObjectResizeStart",{target:D,width:N,height:O}),Q=!0)}function n(){function a(a,b){b&&(D.style[a]||!e.schema.isValid(D.nodeName.toLowerCase(),a)?V.setStyle(D,a,b):V.setAttrib(D,a,b))}Q=!1,a("width",R),a("height",S),V.unbind(X,"mousemove",m),V.unbind(X,"mouseup",n),Y!=X&&(V.unbind(Y,"mousemove",m),V.unbind(Y,"mouseup",n)),V.remove(E),V.remove(F),Z&&"TABLE"!=D.nodeName||p(D),e.fi
 re("ObjectResized",{target:D,width:R,height:S}),V.setAttrib(D,"style",V.getAttrib(D,"style")),e.nodeChanged()}function p(a,b,c){var d,g,h,i,j;q(),z(),d=V.getPos(a,aa),L=d.x,M=d.y,j=a.getBoundingClientRect(),g=j.width||j.right-j.left,h=j.height||j.bottom-j.top,D!=a&&(y(),D=a,R=S=0),i=e.fire("ObjectSelected",{target:a}),l(a)&&!i.isDefaultPrevented()?W(G,function(a,d){function e(b){J=b.screenX,K=b.screenY,N=D.clientWidth,O=D.clientHeight,P=O/N,H=a,a.startPos={x:g*a[0]+L,y:h*a[1]+M},T=aa.scrollWidth,U=aa.scrollHeight,E=D.cloneNode(!0),V.addClass(E,"mce-clonedresizable"),V.setAttrib(E,"data-mce-bogus","all"),E.contentEditable=!1,E.unSelectabe=!0,V.setStyles(E,{left:L,top:M,margin:0}),E.removeAttribute("data-mce-selected"),aa.appendChild(E),V.bind(X,"mousemove",m),V.bind(X,"mouseup",n),Y!=X&&(V.bind(Y,"mousemove",m),V.bind(Y,"mouseup",n)),F=V.add(
 aa,"div",{"class":"mce-resize-helper","data-mce-bogus":"all"},N+" &times; "+O)}var i;return b?void(d==b&&e(c)):(i=V.get("mceResizeHandle"+d),i&&V.remove(i),i=V.add(aa,"div",{id:"mceResizeHandle"+d,"data-mce-bogus":"all","class":"mce-resizehandle",unselectable:!0,style:"cursor:"+d+"-resize; margin:0; padding:0"}),f.ie&&(i.contentEditable=!1),V.bind(i,"mousedown",function(a){a.stopImmediatePropagation(),a.preventDefault(),e(a)}),a.elm=i,void V.setStyles(i,{left:g*a[0]+L-i.offsetWidth/2,top:h*a[1]+M-i.offsetHeight/2}))}):q(),D.setAttribute("data-mce-selected","1")}function q(){var a,b;z(),D&&D.removeAttribute("data-mce-selected");for(a in G)b=V.get("mceResizeHandle"+a),b&&(V.unbind(b),V.remove(b))}function r(a){function b(a,b){if(a)do if(a===b)re
 turn!0;while(a=a.parentNode)}var c,f;if(!Q&&!e.removed)return W(V.select("img[data-mce-selected],hr[data-mce-selected]"),function(a){a.removeAttribute("data-mce-selected")}),f="mousedown"==a.type?a.target:d.getNode(),f=V.$(f).closest(Z?"table":"table,img,hr")[0],b(f,aa)&&(A(),c=d.getStart(!0),b(c,f)&&b(d.getEnd(!0),f)&&(!Z||f!=c&&"IMG"!==c.nodeName))?void p(f):void q()}function s(a,b,c){a&&a.attachEvent&&a.attachEvent("on"+b,c)}function t(a,b,c){a&&a.detachEvent&&a.detachEvent("on"+b,c)}function u(a){var b,c,d,f,g,h,i,j=a.srcElement;b=j.getBoundingClientRect(),h=I.clientX-b.left,i=I.clientY-b.top;for(c in G)if(d=G[c],f=j.offsetWidth*d[0],g=j.offsetHeight*d[1],$(f-h)<8&&$(g-i)<8){H=d;break}Q=!0,e.fire("ObjectResizeStart",{target:D,width:D.clientWidth,height:D.clientHeight}),e.getDoc().selection.empty(),p(j,c,I)
 }function v(a){a.preventDefault?a.preventDefault():a.returnValue=!1}function w(a){return k(j(e.getBody(),a))}function x(a){var b=a.srcElement;if(w(b))return void v(a);if(b!=D){if(e.fire("ObjectSelected",{target:b}),y(),0===b.id.indexOf("mceResizeHandle"))return void(a.returnValue=!1);"IMG"!=b.nodeName&&"TABLE"!=b.nodeName||(q(),D=b,s(b,"resizestart",u))}}function y(){t(D,"resizestart",u)}function z(){for(var a in G){var b=G[a];b.elm&&(V.unbind(b.elm),delete b.elm)}}function A(){try{e.getDoc().execCommand("enableObjectResizing",!1,!1)}catch(a){}}function B(a){var b;if(Z){b=X.body.createControlRange();try{return b.addElement(a),b.select(),!0}catch(a){}}}function C(){D=E=null,Z&&(y(),t(aa,"controlselect",x))}var D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V=e.dom,W=h.each,X=e.getDoc(),Y=document,Z=f.ie&&f.ie<11,$=Math.abs,_=Math.round,aa=e.getBody();G={nw:[0,0,-1,-1],ne:[1,0,1,-1]
 ,se:[1,1,1,1],sw:[0,1,-1,1]};var ba=".mce-content-body";return e.contentStyles.push(ba+" div.mce-resizehandle {position: absolute;border: 1px solid black;box-sizing: box-sizing;background: #FFF;width: 7px;height: 7px;z-index: 10000}"+ba+" .mce-resizehandle:hover {background: #000}"+ba+" img[data-mce-selected],"+ba+" hr[data-mce-selected] {outline: 1px solid black;resize: none}"+ba+" .mce-clonedresizable {position: absolute;"+(f.gecko?"":"outline: 1px dashed black;")+"opacity: .5;filter: alpha(opacity=50);z-index: 10000}"+ba+" .mce-resize-helper {background: #555;background: rgba(0,0,0,0.75);border-radius: 3px;border: 1px;color: white;display: none;font-family: sans-serif;font-size: 12px;white-space: nowrap;line-height: 14px;margin: 5px 10px;padding: 5px;position: absolute;z-index: 10001}"),e.on("init",function(){Z?(e.on("ObjectResized",function(a){"TABLE"
 !=a.target.nodeName&&(q(),B(a.target))}),s(aa,"controlselect",x),e.on("mousedown",function(a){I=a})):(A(),f.ie>=11&&(e.on("mousedown click",function(a){var b=a.target,c=b.nodeName;Q||!/^(TABLE|IMG|HR)$/.test(c)||w(b)||(2!==a.button&&e.selection.select(b,"TABLE"==c),"mousedown"==a.type&&e.nodeChanged())}),e.dom.bind(aa,"mscontrolselect",function(a){function b(a){g.setEditorTimeout(e,function(){e.selection.select(a)})}return w(a.target)?(a.preventDefault(),void b(a.target)):void(/^(TABLE|IMG|HR)$/.test(a.target.nodeName)&&(a.preventDefault(),"IMG"==a.target.tagName&&b(a.target)))})));var b=g.throttle(function(a){e.composing||r(a)});e.on("nodechange ResizeEditor ResizeWindow drop",b),e.on("keyup compositionend",function(a){D&&"TABLE"==D.nodeName&&b(a)}),e.on("hide blur",q),e.on("contextmenu",a.curry(o,
 e))}),e.on("remove",z),{isResizable:l,showResizeRect:p,hideResizeRect:q,updateResizeRect:r,controlSelect:B,destroy:C}}}),g("27",["21"],function(a){var b=function(a){for(var b=0,c=0,d=a;d&&d.nodeType;)b+=d.offsetLeft||0,c+=d.offsetTop||0,d=d.offsetParent;return{x:b,y:c}},c=function(a,b,c){var d={elm:b,alignToTop:c};return a.fire("scrollIntoView",d),d.isDefaultPrevented()},d=function(d,e,f){var g,h,i,j,k=d.dom,l=k.getRoot(),m=0;if(!c(d,e,f)&&a.isElement(e)){if(f===!1&&(m=e.offsetHeight),"BODY"!==l.nodeName){var n=d.selection.getScrollContainer();if(n)return g=b(e).y-b(n).y+m,j=n.clientHeight,i=n.scrollTop,void((g<i||g+25>i+j)&&(n.scrollTop=g<i?g:g-j+25))}h=k.getViewPort(d.getWin()),g=k.getPos(e).y+m,i=h.y,j=h.h,(g<h.y||g+25>i+j)&&d.getWin().scrollTo(0,g<i?g:g-j+25)}};return{scrollIntoView:d}}),g("28",[],function(){function a(a){function b(b,c){var d,e,f,g,h,i,j,k,l=0,m
 =-1;if(d=b.duplicate(),d.collapse(c),k=d.parentElement(),k.ownerDocument===a.dom.doc){for(;"false"===k.contentEditable;)k=k.parentNode;if(!k.hasChildNodes())return{node:k,inside:1};for(g=k.children,e=g.length-1;l<=e;)if(j=Math.floor((l+e)/2),h=g[j],d.moveToElementText(h),m=d.compareEndPoints(c?"StartToStart":"EndToEnd",b),m>0)e=j-1;else{if(!(m<0))return{node:h};l=j+1}if(m<0)for(h?d.collapse(!1):(d.moveToElementText(k),d.collapse(!0),h=k,f=!0),i=0;0!==d.compareEndPoints(c?"StartToStart":"StartToEnd",b)&&0!==d.move("character",1)&&k==d.parentElement();)i++;else for(d.collapse(!0),i=0;0!==d.compareEndPoints(c?"StartToStart":"StartToEnd",b)&&0!==d.move("character",-1)&&k==d.parentElement();)i++;return{node:h,position:m,offset:i,inside:f}}}function c(){function c(a){var c,d,e,f,g,h=b(k,a),i=0;if(c=h.node,d=h.offset,h.inside&&!c.hasChildNodes())retu
 rn void l[a?"setStart":"setEnd"](c,0);if(d===f)return void l[a?"setStartBefore":"setEndAfter"](c);if(h.position<0){if(e=h.inside?c.firstChild:c.nextSibling,!e)return void l[a?"setStartAfter":"setEndAfter"](c);if(!d)return void(3==e.nodeType?l[a?"setStart":"setEnd"](e,0):l[a?"setStartBefore":"setEndBefore"](e));for(;e;){if(3==e.nodeType&&(g=e.nodeValue,i+=g.length,i>=d)){c=e,i-=d,i=g.length-i;break}e=e.nextSibling}}else{if(e=c.previousSibling,!e)return l[a?"setStartBefore":"setEndBefore"](c);if(!d)return void(3==c.nodeType?l[a?"setStart":"setEnd"](e,c.nodeValue.length):l[a?"setStartAfter":"setEndAfter"](e));for(;e;){if(3==e.nodeType&&(i+=e.nodeValue.length,i>=d)){c=e,i-=d;break}e=e.previousSibling}}l[a?"setStart":"setEnd"](c,i)}var f,g,h,i,j,k=a.getRng(),l=e.createRng();if(f=k.item?
 k.item(0):k.parentElement(),f.ownerDocument!=e.doc)return l;if(g=a.isCollapsed(),k.item)return l.setStart(f.parentNode,e.nodeIndex(f)),l.setEnd(l.startContainer,l.startOffset+1),l;try{c(!0),g||c()}catch(b){if(b.number!=-2147024809)throw b;j=d.getBookmark(2),h=k.duplicate(),h.collapse(!0),f=h.parentElement(),g||(h=k.duplicate(),h.collapse(!1),i=h.parentElement(),i.innerHTML=i.innerHTML),f.innerHTML=f.innerHTML,d.moveToBookmark(j),k=a.getRng(),c(!0),g||c()}return l}var d=this,e=a.dom,f=!1;this.getBookmark=function(c){function d(a){var b,c,d,f,g=[];for(b=a.parentNode,c=e.getRoot().parentNode;b!=c&&9!==b.nodeType;){for(d=b.children,f=d.length;f--;)if(a===d[f]){g.push(f);break}a=b,b=b.parentNode}return g}function f(a){var c;if(c=b(g,a))return{position:c.position,offset:c.offset,indexes:d(c.node),inside:c.inside}}var g=a.getRng(),h={};return 2===c&&(g.item?h.start={ctrl:!0,indexes:d(g.item(0))}:(h.start=f(!0),a.isCollapsed()||(h.end=f()))),h},this.moveToBookmark=function(a
 ){function b(a){var b,c,d,f;for(b=e.getRoot(),c=a.length-1;c>=0;c--)f=b.children,d=a[c],d<=f.length-1&&(b=f[d]);return b}function c(c){var e,g,h,i,j=a[c?"start":"end"];j&&(e=j.position>0,g=f.createTextRange(),g.moveToElementText(b(j.indexes)),i=j.offset,i!==h?(g.collapse(j.inside||e),g.moveStart("character",e?-i:i)):g.collapse(c),d.setEndPoint(c?"StartToStart":"EndToStart",g),c&&d.collapse(!0))}var d,f=e.doc.body;a.start&&(a.start.ctrl?(d=f.createControlRange(),d.addElement(b(a.start.indexes)),d.select()):(d=f.createTextRange(),c(!0),c(),d.select()))},this.addRange=function(b){function c(a){var b,c,g,l,m;g=e.create("a"),b=a?h:j,c=a?i:k,l=d.duplicate(),b!=o&&b!=o.documentElement||(b=p,c=0),3==b.nodeType?(b.parentNode.insertBefore(g,b),l.moveToElementText(g),l.moveStart("character",c),e.remove(g),d.setEndPoint(a?"StartToStart":"EndToEnd",l)):(m=b.c
 hildNodes,m.length?(c>=m.length?e.insertAfter(g,m[m.length-1]):b.insertBefore(g,m[c]),l.moveToElementText(g)):b.canHaveHTML&&(b.innerHTML="<span>&#xFEFF;</span>",g=b.firstChild,l.moveToElementText(g),l.collapse(f)),d.setEndPoint(a?"StartToStart":"EndToEnd",l),e.remove(g))}var d,g,h,i,j,k,l,m,n,o=a.dom.doc,p=o.body;if(h=b.startContainer,i=b.startOffset,j=b.endContainer,k=b.endOffset,d=p.createTextRange(),h==j&&1==h.nodeType){if(i==k&&!h.hasChildNodes()){if(h.canHaveHTML)return l=h.previousSibling,l&&!l.hasChildNodes()&&e.isBlock(l)?l.innerHTML="&#xFEFF;":l=null,h.innerHTML="<span>&#xFEFF;</span><span>&#xFEFF;</span>",d.moveToElementText(h.lastChild),d.select(),e.doc.selection.clear(),h.innerHTML="",void(l&&(l.innerHTML=""));i=e.nodeIndex(h),h=h.parentNode}if(i==k-1)try{if(n=h.childNodes[i],g=p.createControlRange()
 ,g.addElement(n),g.select(),m=a.getRng(),m.item&&n===m.item(0))return}catch(a){}}c(!0),c(),d.select()},this.getRangeAt=c}return a}),g("54",["6d","23","53","6j","6a","4y"],function(a,b,c,d,e,f){var g=function(a,c){return b.fromDom(a.dom().cloneNode(c))},h=function(a){return g(a,!1)},i=function(a){return g(a,!0)},j=function(c,d){var e=b.fromTag(d),f=a.clone(c);return a.setAll(e,f),e},k=function(a,b){var c=j(a,b),e=f.children(i(a));return d.append(c,e),c},l=function(a,b){var g=j(a,b);c.before(a,g);var h=f.children(a);return d.append(g,h),e.remove(a),g};return{shallow:h,shallowAs:j,deep:i,copy:k,mutate:l}}),g("55",["1t","23","2i"],function(a,b,c){var d=function(d,e){var f=e||c,g=f.createDocumentFragment();return a.each(d,function(a){g.appendChild(a.dom())}),b.fromDom(g)};return{fromElements:d}}),g("6l",["2k","1u"],function(a,b){return functi
 on(c,d,e,f,g){return c(e,f)?b.some(e):a.isFunction(g)&&g(e)?b.none():d(e,f,g)}}),g("6k",["2k","1t","1","1u","6e","26","23","6l"],function(a,b,c,d,e,f,g,h){var i=function(a){return n(e.body(),a)},j=function(b,e,f){for(var h=b.dom(),i=a.isFunction(f)?f:c.constant(!1);h.parentNode;){h=h.parentNode;var j=g.fromDom(h);if(e(j))return d.some(j);if(i(j))break}return d.none()},k=function(a,b,c){var d=function(a){return b(a)};return h(d,j,a,b,c)},l=function(a,b){var c=a.dom();return c.parentNode?m(g.fromDom(c.parentNode),function(c){return!f.eq(a,c)&&b(c)}):d.none()},m=function(a,d){var e=b.find(a.dom().childNodes,c.compose(d,g.fromDom));return e.map(g.fromDom)},n=function(a,b){var c=function(a){for(var e=0;e<a.childNodes.length;e++){if(b(g.fromDom(a.childNodes[e])))return d.some(g.fromDom(a.childNodes[e]));var f=c(a.childNodes[e]);if(f.isSome())return f}return d.none()};return c(a.dom
 ())};return{first:i,ancestor:j,closest:k,sibling:l,child:m,descendant:n}}),g("57",["6k","24","6l"],function(a,b,c){var d=function(a){return b.one(a)},e=function(c,d,e){return a.ancestor(c,function(a){return b.is(a,d)},e)},f=function(c,d){return a.sibling(c,function(a){return b.is(a,d)})},g=function(c,d){return a.child(c,function(a){return b.is(a,d)})},h=function(a,c){return b.one(c,a)},i=function(a,d,f){return c(b.is,e,a,d,f)};return{first:d,ancestor:e,sibling:f,child:g,descendant:h,closest:i}}),g("59",["1","26","4y"],function(a,b,c){var d=function(a){return a.slice(0,-1)},e=function(a,e,f){return b.contains(e,a)?d(c.parents(a,function(a){return f(a)||b.eq(a,e)})):[]},f=function(b,c){return e(b,c,a.constant(!1))},g=function(a,b){return[a].concat(f(a,b))};return{parentsUntil:e,parents:f,parentsAndSelf:g}}),g("6m",["1u"],function(a){var b=function(a){for(var b=[],c=function(a){b.push(a)
 },d=0;d<a.length;d++)a[d].each(c);return b},c=function(b,c){for(var d=0;d<b.length;d++){var e=c(b[d],d);if(e.isSome())return e}return a.none()},d=function(b,c){for(var d=[],e=0;e<b.length;e++){var f=b[e];if(!f.isSome())return a.none();d.push(f.getOrDie())}return a.some(c.apply(null,d))};return{cat:b,findMap:c,liftN:d}}),g("5a",["1t","1","1u","6m","26","23","56","4y","21"],function(a,b,c,d,e,f,g,h,i){var j=function(a){var b=a.startContainer,d=a.startOffset;return i.isText(b)?0===d?c.some(f.fromDom(b)):c.none():c.from(b.childNodes[d]).map(f.fromDom)},k=function(a){var b=a.endContainer,d=a.endOffset;return i.isText(b)?d===b.data.length?c.some(f.fromDom(b)):c.none():c.from(b.childNodes[d-1]).map(f.fromDom)},l=function(a){return h.firstChild(a).fold(b.constant([a]),function(b){return[a].concat(l(b))})},m=function(a){return h.lastChild(a).fold(b.constant([a]),function(b){return&quo
 t;br"===g.name(b)?h.prevSibling(b).map(function(b){return[a].concat(m(b))}).getOr([]):[a].concat(m(b))})},n=function(c,f){return d.liftN([j(f),k(f)],function(d,f){var g=a.find(l(c),b.curry(e.eq,d)),h=a.find(m(c),b.curry(e.eq,f));return g.isSome()&&h.isSome()}).getOr(!1)};return{hasAllContentsSelected:n}}),g("5b",["1t","1u","5q","26","53","6j","54","23","6d","6c"],function(a,b,c,d,e,f,g,h,i,j){var k=c.immutable("element","width","rows"),l=c.immutable("element","cells"),m=c.immutable("x","y"),n=function(a,b){var c=parseInt(i.get(a,b),10);return isNaN(c)?1:c},o=function(a,b,c,d,e){for(var f=n(e,"rowspan"),h=n(e,"colspan"),i=a.rows(),j=c;j<c+f;j++){i[j]||(i[j]=l(g.deep(d),[]));for(var k=b;k<b+h;k++){var m=i[j].cells();m[k]=j==c&&k==b?e:g.shallow(e)}}},p=function(a
 ,b,c){var d=a.rows(),e=d[c]?d[c].cells():[];return!!e[b]},q=function(a,b,c){for(;p(a,b,c);)b++;return b},r=function(b){return a.foldl(b,function(a,b){return b.cells().length>a?b.cells().length:a},0)},s=function(a,c){for(var e=a.rows(),f=0;f<e.length;f++)for(var g=e[f].cells(),h=0;h<g.length;h++)if(d.eq(g[h],c))return b.some(m(h,f));return b.none()},t=function(a,b,c,d,e){for(var f=[],g=a.rows(),h=c;h<=e;h++){var i=g[h].cells(),j=b<d?i.slice(b,d+1):i.slice(d,b+1);f.push(l(g[h].element(),j))}return f},u=function(a,b,c){var d=b.x(),e=b.y(),f=c.x(),g=c.y(),h=e<g?t(a,d,e,f,g):t(a,d,g,f,e);return k(a.element(),r(h),h)},v=function(a,b){var c=g.shallow(a.element()),d=h.fromTag("tbody");return f.append(d,b),e.append(c,d),c},w=function(b){return a.map(b.rows(),function(b){var c=a.map(b.cells(),function(a){var b=g.deep(a);return i.remove(b,"colspan"),i.remove(b,"rowspan"),b}),d=g.shallow(b.element());return f.append(d,c),d})},x=function(b){var c=k
 (g.shallow(b),0,[]);return a.each(j.descendants(b,"tr"),function(b,d){a.each(j.descendants(b,"td,th"),function(a,e){o(c,q(c,e,d),d,b,a)})}),k(c.element(),r(c.rows()),c.rows())},y=function(a){return v(a,w(a))},z=function(a,b,c){return s(a,b).bind(function(b){return s(a,c).map(function(c){return u(a,b,c)})})};return{fromDom:x,toDom:y,subsection:z}}),g("2a",["1t","23","e"],function(a,b,c){var d=function(a){for(var b=[],c=0;c<a.rangeCount;c++)b.push(a.getRangeAt(c));return b},e=function(d){return a.bind(d,function(a){var d=c.getSelectedNode(a);return d?[b.fromDom(d)]:[]})},f=function(a){return d(a).length>1};return{getRanges:d,getSelectedNodes:e,hasMultipleRanges:f}}),g("5c",["1t","23","6c","58","2a"],function(a,b,c,d,e){var f=function(b){return a.filter(e.getSelectedNodes(b),d.isTableCell)},g=function(a){var b=c.descendants(a,"td[data-mce-selected],th[data-
 mce-selected]");return b},h=function(a,b){var c=g(b),d=f(a);return c.length>0?c:d},i=function(a){return h(e.getRanges(a.selection.getSel()),b.fromDom(a.getBody()))};return{getCellsFromRanges:f,getCellsFromElement:g,getCellsFromElementOrRanges:h,getCellsFromEditor:i}}),g("29",["1t","1","26","53","54","23","55","56","57","4y","58","59","5a","5b","5c"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o){var p=function(b){return a.find(b,function(a){return"ul"===h.name(a)||"ol"===h.name(a)})},q=function(c,d){return a.find(c,function(a){return"li"===h.name(a)&&m.hasAllContentsSelected(a,d)}).fold(b.constant([]),function(a){return p(c).map(function(a){return[f.fromTag("li"),f.fromTag(h.name(a))]}).getOr([])})},r=function(b,c){var e=a.foldl(c,function(a,b){return d.append(b,a),b},b);return
  c.length>0?g.fromElements([e]):e},s=function(a){return k.isListItem(a)?j.parent(a).filter(k.isList).fold(b.constant([]),function(b){return[a,b]}):k.isList(a)?[a]:[]},t=function(b,c){var d=f.fromDom(c.commonAncestorContainer),g=l.parentsAndSelf(d,b),h=a.filter(g,function(a){return k.isInline(a)||k.isHeading(a)}),i=q(g,c),j=h.concat(i.length?i:s(d));return a.map(j,e.shallow)},u=function(){return g.fromElements([])},v=function(a,b){return r(f.fromDom(b.cloneContents()),t(a,b))},w=function(a,d){return i.ancestor(d,"table",b.curry(c.eq,a))},x=function(a,b){return w(a,b[0]).bind(function(a){var c=b[0],d=b[b.length-1],e=n.fromDom(a);return n.subsection(e,c,d).map(function(a){return g.fromElements([n.toDom(a)])})}).getOrThunk(u)},y=function(a,b){return b.length>0&&b[0].collapsed?u():v(a,b[0])},z=function(a,b){var c=o.getCellsFromElementOrRanges(b,a);return c.length>0?x(a,c):y(a,b)};return{read:z}}),g("g",["1t","26","23",&qu
 ot;20","9","a","21","e","27","j","28","o","29","2a","22","1d"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p){function q(a,b,c,d){var g=this;g.dom=a,g.win=b,g.serializer=c,g.editor=d,g.bookmarkManager=new e(g),g.controlSelection=new f(g,d),g.win.getSelection||(g.tridentSel=new k(g))}var r=p.each,s=p.trim,t=l.ie,u=function(a){return!(!a||!a.ownerDocument)&&b.contains(c.fromDom(a.ownerDocument),c.fromDom(a))},v=function(a){return!!a&&(!!a.select||u(a.startContainer)&&u(a.endContainer))},w=function(b,c){return a.map(c,function(a){var c=b.fire("GetSelectionRange",{range:a});return c.range!==a?c.range:a})};return q.prototype={setCursorLocation:function(a,b){var c=this,d=c.dom.createRng();a?(d.setStart(a,b),d.setEnd(a,b),c.setRng(d),c.collapse(!1)):(c._moveEndPoint(d,c.editor.getBody(),!0),c.setRng(d))},getContent:function(a){var b,d,e,f
 =this,g=f.getRng(),h=f.dom.create("body"),i=f.getSel(),j=w(f.editor,n.getRanges(this.getSel()));return a=a||{},b=d="",a.get=!0,a.format=a.format||"html",a.selection=!0,f.editor.fire("BeforeGetContent",a),"text"===a.format?f.isCollapsed()?"":o.trim(g.text||(i.toString?i.toString():"")):(g.cloneContents?(e=a.contextual?m.read(c.fromDom(f.editor.getBody()),j).dom():g.cloneContents(),e&&h.appendChild(e)):void 0!==g.item||void 0!==g.htmlText?(h.innerHTML="<br>"+(g.item?g.item(0).outerHTML:g.htmlText),h.removeChild(h.firstChild)):h.innerHTML=g.toString(),/^\s/.test(h.innerHTML)&&(b=" "),/\s+$/.test(h.innerHTML)&&(d=" "),a.getInner=!0,a.content=f.isCollapsed()?"":b+f.serializer.serialize(h,a)+d,f.editor.fire("GetContent",a),a.content)},setContent:function(a,b){var c,d,e,f=this,g=f.getRng(),h=f.win.document;if(b=b||{format:"html"},b.
 set=!0,b.selection=!0,b.content=a,b.no_events||f.editor.fire("BeforeSetContent",b),a=b.content,g.insertNode){a+='<span id="__caret">_</span>',g.startContainer==h&&g.endContainer==h?h.body.innerHTML=a:(g.deleteContents(),0===h.body.childNodes.length?h.body.innerHTML=a:g.createContextualFragment?g.insertNode(g.createContextualFragment(a)):(d=h.createDocumentFragment(),e=h.createElement("div"),d.appendChild(e),e.outerHTML=a,g.insertNode(d))),c=f.dom.get("__caret"),g=h.createRange(),g.setStartBefore(c),g.setEndBefore(c),f.setRng(g),f.dom.remove("__caret");try{f.setRng(g)}catch(a){}}else g.item&&(h.execCommand("Delete",!1,null),g=f.getRng()),/^\s+/.test(a)?(g.pasteHTML('<span id="__mce_tmp">_</span>'+a),f.dom.remove("__mce_tmp")):g.pasteHTML(a);b.no_events||f.editor.fire("SetContent",b)},getStart:function(a){var b,c,d,e,f=this,g=f.getRng();if(g.duplicate||g.it
 em){if(g.item)return g.item(0);for(d=g.duplicate(),d.collapse(1),b=d.parentElement(),b.ownerDocument!==f.dom.doc&&(b=f.dom.getRoot()),c=e=g.parentElement();e=e.parentNode;)if(e==b){b=c;break}return b}return b=g.startContainer,1==b.nodeType&&b.hasChildNodes()&&(a&&g.collapsed||(b=b.childNodes[Math.min(b.childNodes.length-1,g.startOffset)])),b&&3==b.nodeType?b.parentNode:b},getEnd:function(a){var b,c,d=this,e=d.getRng();return e.duplicate||e.item?e.item?e.item(0):(e=e.duplicate(),e.collapse(0),b=e.parentElement(),b.ownerDocument!==d.dom.doc&&(b=d.dom.getRoot()),b&&"BODY"==b.nodeName?b.lastChild||b:b):(b=e.endContainer,c=e.endOffset,1==b.nodeType&&b.hasChildNodes()&&(a&&e.collapsed||(b=b.childNodes[c>0?c-1:c])),b&&3==b.nodeType?b.parentNode:b)},getBookmark:function(a,b){return this.bookmarkManager.getBookmark(a,b)},moveToBookmark:function(a){return this.bookmarkManager.moveToBookmark(a)
 },select:function(a,b){var c,d=this,e=d.dom,f=e.createRng();if(d.lastFocusBookmark=null,a){if(!b&&d.controlSelection.controlSelect(a))return;c=e.nodeIndex(a),f.setStart(a.parentNode,c),f.setEnd(a.parentNode,c+1),b&&(d._moveEndPoint(f,a,!0),d._moveEndPoint(f,a)),d.setRng(f)}return a},isCollapsed:function(){var a=this,b=a.getRng(),c=a.getSel();return!(!b||b.item)&&(b.compareEndPoints?0===b.compareEndPoints("StartToEnd",b):!c||b.collapsed)},collapse:function(a){var b,c=this,d=c.getRng();d.item&&(b=d.item(0),d=c.win.document.body.createTextRange(),d.moveToElementText(b)),d.collapse(!!a),c.setRng(d)},getSel:function(){var a=this.win;return a.getSelection?a.getSelection():a.document.selection},getRng:function(a){function b(a,b,c){try{return b.compareBoundaryPoints(a,c)}catch(a){return-1}}var c,d,e,f,g,h=this;if(!h.win)return null;if(f=h.win.document,"undefined"==typeof f||null===f)return null;if(!a&&h.lastFocusBookmark){var i=h.l
 astFocusBookmark;return i.startContainer?(d=f.createRange(),d.setStart(i.startContainer,i.startOffset),d.setEnd(i.endContainer,i.endOffset)):d=i,d}if(a&&h.tridentSel)return h.tridentSel.getRangeAt(0);try{(c=h.getSel())&&(d=c.rangeCount>0?c.getRangeAt(0):c.createRange?c.createRange():f.createRange())}catch(a){}if(d=w(h.editor,[d])[0],t&&d&&d.setStart&&f.selection){try{g=f.selection.createRange()}catch(a){}g&&g.item&&(e=g.item(0),d=f.createRange(),d.setStartBefore(e),d.setEndAfter(e))}return d||(d=f.createRange?f.createRange():f.body.createTextRange()),d.setStart&&9===d.startContainer.nodeType&&d.collapsed&&(e=h.dom.getRoot(),d.setStart(e,0),d.setEnd(e,0)),h.selectedRange&&h.explicitRange&&(0===b(d.START_TO_START,d,h.selectedRange)&&0===b(d.END_TO_END,d,h.selectedRange)?d=h.explicitRange:(h.selectedRange=null,h.explicitRange=null)),d},setRng:function(a,b){var c,d,e,f=this;if(v(a)
 )if(a.select){f.explicitRange=null;try{a.select()}catch(a){}}else if(f.tridentSel){if(a.cloneRange)try{f.tridentSel.addRange(a)}catch(a){}}else{if(c=f.getSel(),e=f.editor.fire("SetSelectionRange",{range:a,forward:b}),a=e.range,c){f.explicitRange=a;try{c.removeAllRanges(),c.addRange(a)}catch(a){}b===!1&&c.extend&&(c.collapse(a.endContainer,a.endOffset),c.extend(a.startContainer,a.startOffset)),f.selectedRange=c.rangeCount>0?c.getRangeAt(0):null}a.collapsed||a.startContainer!==a.endContainer||!c.setBaseAndExtent||l.ie||a.endOffset-a.startOffset<2&&a.startContainer.hasChildNodes()&&(d=a.startContainer.childNodes[a.startOffset],d&&"IMG"===d.tagName&&(c.setBaseAndExtent(a.startContainer,a.startOffset,a.endContainer,a.endOffset),c.anchorNode===a.startContainer&&c.focusNode===a.endContainer||c.setBaseAndExtent(d,0,d,1))),f.editor.fire("AfterSetSelectionRange",{range:a,forward:b})}},setNode:function(
 a){var b=this;return b.setContent(b.dom.getOuterHTML(a)),a},getNode:function(){function a(a,b){for(var c=a;a&&3===a.nodeType&&0===a.length;)a=b?a.nextSibling:a.previousSibling;return a||c}var b,c,d,e,f,g=this,h=g.getRng(),i=g.dom.getRoot();return h?(c=h.startContainer,d=h.endContainer,e=h.startOffset,f=h.endOffset,h.setStart?(b=h.commonAncestorContainer,!h.collapsed&&(c==d&&f-e<2&&c.hasChildNodes()&&(b=c.childNodes[e]),3===c.nodeType&&3===d.nodeType&&(c=c.length===e?a(c.nextSibling,!0):c.parentNode,d=0===f?a(d.previousSibling,!1):d.parentNode,c&&c===d))?c:b&&3==b.nodeType?b.parentNode:b):(b=h.item?h.item(0):h.parentElement(),b.ownerDocument!==g.win.document&&(b=i),b)):i},getSelectedBlocks:function(a,b){var c,d,e=this,f=e.dom,g=[];if(d=f.getRoot(),a=f.getParent(a||e.getStart(),f.isBlock),b=f.getParent(b||e.getEnd(),f.isBlock),a&&a!=d&&g.push(a),a&&b&&a!=b){c=a;fo
 r(var h=new j(a,d);(c=h.next())&&c!=b;)f.isBlock(c)&&g.push(c)}return b&&a!=b&&b!=d&&g.push(b),g},isForward:function(){var a,b,c=this.dom,d=this.getSel();return!(d&&d.anchorNode&&d.focusNode)||(a=c.createRng(),a.setStart(d.anchorNode,d.anchorOffset),a.collapse(!0),b=c.createRng(),b.setStart(d.focusNode,d.focusOffset),b.collapse(!0),a.compareBoundaryPoints(a.START_TO_START,b)<=0)},normalize:function(){var a=this,b=a.getRng();return new h(a.dom).normalize(b)&&!n.hasMultipleRanges(a.getSel())&&a.setRng(b,a.isForward()),b},selectorChanged:function(a,b){var c,d=this;return d.selectorChangedData||(d.selectorChangedData={},c={},d.editor.on("NodeChange",function(a){var b=a.element,e=d.dom,f=e.getParents(b,null,e.getRoot()),g={};r(d.selectorChangedData,function(a,b){r(f,function(d){if(e.is(d,b))return c[b]||(r(a,function(a){a(!0,{node:d,selector:b,parents:f})}),c[b]=a),g[b]=a,!1})}),r(c,function(a,d){g[d]||(
 delete c[d],r(a,function(a){a(!1,{node:b,selector:d,parents:f})}))})})),d.selectorChangedData[a]||(d.selectorChangedData[a]=[]),d.selectorChangedData[a].push(b),d},getScrollContainer:function(){for(var a,b=this.dom.getRoot();b&&"BODY"!=b.nodeName;){if(b.scrollHeight>b.clientHeight){a=b;break}b=b.parentNode}return a},scrollIntoView:function(a,b){i.scrollIntoView(this.editor,a,b)},placeCaretAt:function(a,b){this.setRng(h.getCaretRangeFromPoint(a,b,this.editor.getDoc()))},_moveEndPoint:function(a,b,c){var d=b,e=new j(b,d),f=this.dom.schema.getNonEmptyElements();do{if(3==b.nodeType&&0!==s(b.nodeValue).length)return void(c?a.setStart(b,0):a.setEnd(b,b.nodeValue.length));if(f[b.nodeName]&&!/^(TD|TH)$/.test(b.nodeName))return void(c?a.setStartBefore(b):"BR"==b.nodeName?a.setEndBefore(b):a.setEndAfter(b));if(l.ie&&l.ie<11&&this.dom.isBlock(b)&&this.dom.isEmpty(b))return void(c?a.setStart(b,0):a.setEnd(b,0))}while(b=c?
 e.next():e.prev());"BODY"==d.nodeName&&(c?a.setStart(d,0):a.setEnd(d,d.childNodes.length))},getBoundingClientRect:function(){var a=this.getRng();return a.collapsed?d.fromRangeStart(a).getClientRects()[0]:a.getBoundingClientRect()},destroy:function(){this.win=null,this.controlSelection.destroy()}},q}),g("t",[],function(){function a(a,b,c){var d,e,f=c?"lastChild":"firstChild",g=c?"prev":"next";if(a[f])return a[f];if(a!==b){if(d=a[g])return d;for(e=a.parent;e&&e!==b;e=e.parent)if(d=e[g])return d}}function b(a,b){this.name=a,this.type=b,1===b&&(this.attributes=[],this.attributes.map={})}var c=/^[ \t\r\n]*$/,d={"#text":3,"#comment":8,"#cdata":4,"#pi":7,"#doctype":10,"#document-fragment":11};return b.prototype={replace:function(a){var b=this;return a.parent&&a.remove(),b.insert(a,b),b.remove(),b},attr:function(a,b){var c,d,e,f=this;if(&quo
 t;string"!=typeof a){for(d in a)f.attr(d,a[d]);return f}if(c=f.attributes){if(b!==e){if(null===b){if(a in c.map)for(delete c.map[a],d=c.length;d--;)if(c[d].name===a)return c=c.splice(d,1),f;return f}if(a in c.map){for(d=c.length;d--;)if(c[d].name===a){c[d].value=b;break}}else c.push({name:a,value:b});return c.map[a]=b,f}return c.map[a]}},clone:function(){var a,c,d,e,f,g=this,h=new b(g.name,g.type);if(d=g.attributes){for(f=[],f.map={},a=0,c=d.length;a<c;a++)e=d[a],"id"!==e.name&&(f[f.length]={name:e.name,value:e.value},f.map[e.name]=e.value);h.attributes=f}return h.value=g.value,h.shortEnded=g.shortEnded,h},wrap:function(a){var b=this;return b.parent.insert(a,b),a.append(b),b},unwrap:function(){var a,b,c=this;for(a=c.firstChild;a;)b=a.next,c.insert(a,c,!0),a=b;c.remove()},remove:function(){var a=this,b=a.parent,c=a.next,d=a.prev;return b&&(b.firstChild===a?(b.firstChild=c,c&&(c.prev=null)):d.next=c,b.lastChild===a?(b.lastChild=d,d&&(d
 .next=null)):c.prev=d,a.parent=a.next=a.prev=null),a},append:function(a){var b,c=this;return a.parent&&a.remove(),b=c.lastChild,b?(b.next=a,a.prev=b,c.lastChild=a):c.lastChild=c.firstChild=a,a.parent=c,a},insert:function(a,b,c){var d;return a.parent&&a.remove(),d=b.parent||this,c?(b===d.firstChild?d.firstChild=a:b.prev.next=a,a.prev=b.prev,a.next=b,b.prev=a):(b===d.lastChild?d.lastChild=a:b.next.prev=a,a.next=b.next,a.prev=b,b.next=a),a.parent=d,a},getAll:function(b){var c,d=this,e=[];for(c=d.firstChild;c;c=a(c,d))c.name===b&&e.push(c);return e},empty:function(){var b,c,d,e=this;if(e.firstChild){for(b=[],d=e.firstChild;d;d=a(d,e))b.push(d);for(c=b.length;c--;)d=b[c],d.parent=d.firstChild=d.lastChild=d.next=d.prev=null}return e.firstChild=e.lastChild=null,e},isEmpty:function(b,d,e){var f,g,h=this,i=h.firstChild;if(d=d||{},i)do{if(1===i.type){if(i.attributes.map["data-mce-bogus"])continue;if(b[i.name])return!1;for(f=i.attributes.length;f--;)if(g=i.att
 ributes[f].name,
+"name"===g||0===g.indexOf("data-mce-bookmark"))return!1}if(8===i.type)return!1;if(3===i.type&&!c.test(i.value))return!1;if(3===i.type&&i.parent&&d[i.parent.name]&&c.test(i.value))return!1;if(e&&e(i))return!1}while(i=a(i,h));return!0},walk:function(b){return a(this,null,b)}},b.create=function(a,c){var e,f;if(e=new b(a,d[a]||1),c)for(f in c)e.attr(f,c[f]);return e},b}),g("u",["v","s","1d"],function(a,b,c){function d(a,b,c){var d,e,f,g,h=1;for(g=a.getShortEndedElements(),f=/<([!?\/])?([A-Za-z0-9\-_\:\.]+)((?:\s+[^"\'>]+(?:(?:"[^"]*")|(?:\'[^\']*\')|[^>]*))*|\/|\s+)>/g,f.lastIndex=d=c;e=f.exec(b);){if(d=f.lastIndex,"/"===e[1])h--;else if(!e[1]){if(e[2]in g)continue;h++}if(0===h)break}return d}function e(e,i){function j(){}var k=this;e=e||{},k.schema=i=i||new a,e.fix_self_closing!==!1&&(e.fix_self_closing=!0),f("comment cdata text star
 t end pi doctype".split(" "),function(a){a&&(k[a]=e[a]||j)}),k.parse=function(a){function f(a){var b,c;for(b=Q.length;b--&&Q[b].name!==a;);if(b>=0){for(c=Q.length-1;c>=b;c--)a=Q[c],a.valid&&O.end(a.name);Q.length=b}}function j(a,b,c,d,f){var h,i,j=/[\s\u0000-\u001F]+/g;if(b=b.toLowerCase(),c=b in u?b:S(c||d||f||""),w&&!r&&g(b)===!1){if(h=B[b],!h&&C){for(i=C.length;i--&&(h=C[i],!h.pattern.test(b)););i===-1&&(h=null)}if(!h)return;if(h.validValues&&!(c in h.validValues))return}if(T[b]&&!e.allow_script_urls){var k=c.replace(j,"");try{k=decodeURIComponent(k)}catch(a){k=unescape(k)}if(U.test(k))return;if(!e.allow_html_data_urls&&V.test(k)&&!/^data:image\//i.test(k))return}r&&(b in T||0===b.indexOf("on"))||(n.map[b]=c,n.push({name:b,value:c}))}var k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O=this,P=0,Q=[],R=0,S=b.decode,
 T=c.makeMap("src,href,data,background,formaction,poster"),U=/((java|vb)script|mhtml):/i,V=/^data:/i;for(J=new RegExp("<(?:(?:!--([\\w\\W]*?)-->)|(?:!\\[CDATA\\[([\\w\\W]*?)\\]\\]>)|(?:!DOCTYPE([\\w\\W]*?)>)|(?:\\?([^\\s\\/<>]+) ?([\\w\\W]*?)[?/]>)|(?:\\/([A-Za-z][A-Za-z0-9\\-_\\:\\.]*)>)|(?:([A-Za-z][A-Za-z0-9\\-_\\:\\.]*)((?:\\s+[^\"'>]+(?:(?:\"[^\"]*\")|(?:'[^']*')|[^>]*))*|\\/|\\s+)>))","g"),K=/([\w:\-]+)(?:\s*=\s*(?:(?:\"((?:[^\"])*)\")|(?:\'((?:[^\'])*)\')|([^>\s]+)))?/g,t=i.getShortEndedElements(),I=e.self_closing_elements||i.getSelfClosingElements(),u=i.getBoolAttrs(),w=e.validate,s=e.remove_internals,N=e.fix_self_closing,L=i.getSpecialElements(),G=a+">";k=J.exec(G);){if(P<k.index&&O.text(S(a.substr(P,k.index-P))),l=k[6])l=l.toLowerCase(),":"===l.charAt(0)&&(l=l.substr(1)),f(l);else if(l=k[7]){if(k.index+k[0].length>a.length){O.text
 (S(a.substr(k.index))),P=k.index+k[0].length;continue}if(l=l.toLowerCase(),":"===l.charAt(0)&&(l=l.substr(1)),v=l in t,N&&I[l]&&Q.length>0&&Q[Q.length-1].name===l&&f(l),!w||(x=i.getElementRule(l))){if(y=!0,w&&(B=x.attributes,C=x.attributePatterns),(A=k[8])?(r=A.indexOf("data-mce-type")!==-1,r&&s&&(y=!1),n=[],n.map={},A.replace(K,j)):(n=[],n.map={}),w&&!r){if(D=x.attributesRequired,E=x.attributesDefault,F=x.attributesForced,H=x.removeEmptyAttrs,H&&!n.length&&(y=!1),F)for(o=F.length;o--;)z=F[o],q=z.name,M=z.value,"{$uid}"===M&&(M="mce_"+R++),n.map[q]=M,n.push({name:q,value:M});if(E)for(o=E.length;o--;)z=E[o],q=z.name,q in n.map||(M=z.value,"{$uid}"===M&&(M="mce_"+R++),n.map[q]=M,n.push({name:q,value:M}));if(D){for(o=D.length;o--&&!(D[o]in n.map););o===-1&&(y=!1)}if(z=n.map["data-mce-bogus"]){if(
 "all"===z){P=d(i,a,J.lastIndex),J.lastIndex=P;continue}y=!1}}y&&O.start(l,n,v)}else y=!1;if(m=L[l]){m.lastIndex=P=k.index+k[0].length,(k=m.exec(a))?(y&&(p=a.substr(P,k.index-P)),P=k.index+k[0].length):(p=a.substr(P),P=a.length),y&&(p.length>0&&O.text(p,!0),O.end(l)),J.lastIndex=P;continue}v||(A&&A.indexOf("/")==A.length-1?y&&O.end(l):Q.push({name:l,valid:y}))}else(l=k[1])?(">"===l.charAt(0)&&(l=" "+l),e.allow_conditional_comments||"[if"!==l.substr(0,3).toLowerCase()||(l=" "+l),O.comment(l)):(l=k[2])?O.cdata(h(l)):(l=k[3])?O.doctype(l):(l=k[4])&&O.pi(l,k[5]);P=k.index+k[0].length}for(P<a.length&&O.text(S(a.substr(P))),o=Q.length-1;o>=0;o--)l=Q[o],l.valid&&O.end(l.name)}}var f=c.each,g=function(a){return 0===a.indexOf("data-")||0===a.indexOf("aria-")},h=function(a){return a.replace(/<!--|-->/g,"")};r
 eturn e.findEndTag=d,e}),g("r",["t","v","u","1d"],function(a,b,c,d){var e=d.makeMap,f=d.each,g=d.explode,h=d.extend,i=function(b,c){b.padd_empty_with_br?c.empty().append(new a("br","1")).shortEnded=!0:c.empty().append(new a("#text","3")).value="\xa0"},j=function(a,b){return a&&a.firstChild===a.lastChild&&a.firstChild.name===b},k=function(a,b){var c=a.getElementRule(b.name);return c&&c.paddEmpty},l=function(a,b,c,d){return d.isEmpty(b,c,function(b){return k(a,b)})};return function(k,m){function n(b){var c,d,f,g,h,i,k,n,p,q,r,s,t,u,v,w;for(s=e("tr,td,th,tbody,thead,tfoot,table"),q=m.getNonEmptyElements(),r=m.getWhiteSpaceElements(),t=m.getTextBlockElements(),u=m.getSpecialElements(),c=0;c<b.length;c++)if(d=b[c],d.parent&&!d.fixed)if(t[d.name]&&"li"==d.parent.name){for(v=d.next;v&&t[v.name];)v.name="li",v.fi
 xed=!0,d.parent.insert(v,d.parent),v=v.next;d.unwrap(d)}else{for(g=[d],f=d.parent;f&&!m.isValidChild(f.name,d.name)&&!s[f.name];f=f.parent)g.push(f);if(f&&g.length>1){for(g.reverse(),h=i=o.filterNode(g[0].clone()),p=0;p<g.length-1;p++){for(m.isValidChild(i.name,g[p].name)?(k=o.filterNode(g[p].clone()),i.append(k)):k=i,n=g[p].firstChild;n&&n!=g[p+1];)w=n.next,k.append(n),n=w;i=k}l(m,q,r,h)?f.insert(d,g[0],!0):(f.insert(h,g[0],!0),f.insert(d,h)),f=g[0],(l(m,q,r,f)||j(f,"br"))&&f.empty().remove()}else if(d.parent){if("li"===d.name){if(v=d.prev,v&&("ul"===v.name||"ul"===v.name)){v.append(d);continue}if(v=d.next,v&&("ul"===v.name||"ul"===v.name)){v.insert(d,v.firstChild,!0);continue}d.wrap(o.filterNode(new a("ul",1)));continue}m.isValidChild(d.parent.name,"div")&&m.isValidChild("div",d.name)?d.wrap(o.filterNode(new a("div&quo
 t;,1))):u[d.name]?d.empty().remove():d.unwrap()}}}var o=this,p={},q=[],r={},s={};k=k||{},k.validate=!("validate"in k)||k.validate,k.root_name=k.root_name||"body",o.schema=m=m||new b,o.filterNode=function(a){var b,c,d;c in p&&(d=r[c],d?d.push(a):r[c]=[a]),b=q.length;for(;b--;)c=q[b].name,c in a.attributes.map&&(d=s[c],d?d.push(a):s[c]=[a]);return a},o.addNodeFilter=function(a,b){f(g(a),function(a){var c=p[a];c||(p[a]=c=[]),c.push(b)})},o.addAttributeFilter=function(a,b){f(g(a),function(a){var c;for(c=0;c<q.length;c++)if(q[c].name===a)return void q[c].callbacks.push(b);q.push({name:a,callbacks:[b]})})},o.parse=function(b,d){function f(){function a(a){a&&(d=a.firstChild,d&&3==d.type&&(d.value=d.value.replace(F,"")),d=a.lastChild,d&&3==d.type&&(d.value=d.value.replace(H,"")))}var b,c,d=u.firstChild;if(m.isValidChild(u.name,N.toLowerCase())){for(;d;)b=d.next,3==d.type||1==d.type&&&q
 uot;p"!==d.name&&!E[d.name]&&!d.attr("data-mce-type")?c?c.append(d):(c=g(N,1),c.attr(k.forced_root_block_attrs),u.insert(c,d),c.append(d)):(a(c),c=null),d=b;a(c)}}function g(b,c){var d,e=new a(b,c);return b in p&&(d=r[b],d?d.push(e):r[b]=[e]),e}function j(a){var b,c,d,e,f=m.getBlockElements();for(b=a.prev;b&&3===b.type;){if(d=b.value.replace(H,""),d.length>0)return void(b.value=d);if(c=b.next){if(3==c.type&&c.value.length){b=b.prev;continue}if(!f[c.name]&&"script"!=c.name&&"style"!=c.name){b=b.prev;continue}}e=b.prev,b.remove(),b=e}}function o(a){var b,c={};for(b in a)"li"!==b&&"p"!=b&&(c[b]=a[b]);return c}var t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O=[];if(d=d||{},r={},s={},E=h(e("script,style,head,html,body,title,meta,param"),m.getBlockElements()),M=m.getNonEmptyElements(),L=m.children,D=k.validate,N="forced_root_block"in
  d?d.forced_root_block:k.forced_root_block,K=m.getWhiteSpaceElements(),F=/^[ \t\r\n]+/,H=/[ \t\r\n]+$/,I=/[ \t\r\n]+/g,J=/^[ \t\r\n]+$/,t=new c({validate:D,allow_script_urls:k.allow_script_urls,allow_conditional_comments:k.allow_conditional_comments,self_closing_elements:o(m.getSelfClosingElements()),cdata:function(a){v.append(g("#cdata",4)).value=a},text:function(a,b){var c;G||(a=a.replace(I," "),v.lastChild&&E[v.lastChild.name]&&(a=a.replace(F,""))),0!==a.length&&(c=g("#text",3),c.raw=!!b,v.append(c).value=a)},comment:function(a){v.append(g("#comment",8)).value=a},pi:function(a,b){v.append(g(a,7)).value=b,j(v)},doctype:function(a){var b;b=v.append(g("#doctype",10)),b.value=a,j(v)},start:function(a,b,c){var d,e,f,h,i;if(f=D?m.getElementRule(a):{}){for(d=g(f.outputName||a,1),d.attributes=b,d.shortEnded=c,v.append(d),i=L[v.name],i&&L[d.name]&&!i[d.name]&&O.push(d),e=q.length;e-
 -;)h=q[e].name,h in b.map&&(B=s[h],B?B.push(d):s[h]=[d]);E[a]&&j(d),c||(v=d),!G&&K[a]&&(G=!0)}},end:function(a){var b,c,d,e,f;if(c=D?m.getElementRule(a):{}){if(E[a]&&!G){if(b=v.firstChild,b&&3===b.type)if(d=b.value.replace(F,""),d.length>0)b.value=d,b=b.next;else for(e=b.next,b.remove(),b=e;b&&3===b.type;)d=b.value,e=b.next,(0===d.length||J.test(d))&&(b.remove(),b=e),b=e;if(b=v.lastChild,b&&3===b.type)if(d=b.value.replace(H,""),d.length>0)b.value=d,b=b.prev;else for(e=b.prev,b.remove(),b=e;b&&3===b.type;)d=b.value,e=b.prev,(0===d.length||J.test(d))&&(b.remove(),b=e),b=e}if(G&&K[a]&&(G=!1),(c.removeEmpty||c.paddEmpty)&&l(m,M,K,v))if(c.paddEmpty)i(k,v);else if(!v.attributes.map.name&&!v.attributes.map.id)return f=v.parent,E[v.name]?v.empty().remove():v.unwrap(),void(v=f);v=v.parent}}},m),u=v=new a(d.context||k.root_name,11),t.parse(b),D&
 &O.length&&(d.context?d.invalid=!0:n(O)),N&&("body"==u.name||d.isRootContent)&&f(),!d.invalid){for(C in r){for(B=p[C],w=r[C],z=w.length;z--;)w[z].parent||w.splice(z,1);for(x=0,y=B.length;x<y;x++)B[x](w,C,d)}for(x=0,y=q.length;x<y;x++)if(B=q[x],B.name in s){for(w=s[B.name],z=w.length;z--;)w[z].parent||w.splice(z,1);for(z=0,A=B.callbacks.length;z<A;z++)B.callbacks[z](w,B.name,d)}}return u},k.remove_trailing_brs&&o.addNodeFilter("br",function(b){var c,d,e,f,g,j,n,o,p=b.length,q=h({},m.getBlockElements()),r=m.getNonEmptyElements(),s=m.getNonEmptyElements();for(q.body=1,c=0;c<p;c++)if(d=b[c],e=d.parent,q[d.parent.name]&&d===e.lastChild){for(g=d.prev;g;){if(j=g.name,"span"!==j||"bookmark"!==g.attr("data-mce-type")){if("br"!==j)break;if("br"===j){d=null;break}}g=g.prev}d&&(d.remove(),l(m,r,s,e)&&(n=m.getElementRule(e.name),n&&(n.removeEmpty?e
 .remove():n.paddEmpty&&i(k,e))))}else{for(f=d;e&&e.firstChild===f&&e.lastChild===f&&(f=e,!q[e.name]);)e=e.parent;f===e&&k.padd_empty_with_br!==!0&&(o=new a("#text",3),o.value="\xa0",d.replace(o))}}),o.addAttributeFilter("href",function(a){var b,c=a.length,e=function(a){var b=a.split(" ").filter(function(a){return a.length>0});return b.concat(["noopener"]).sort().join(" ")},f=function(a){var b=a?d.trim(a):"";return/\b(noopener)\b/g.test(b)?b:e(b)};if(!k.allow_unsafe_link_target)for(;c--;)b=a[c],"a"===b.name&&"_blank"===b.attr("target")&&b.attr("rel",f(b.attr("rel")))}),k.allow_html_in_named_anchor||o.addAttributeFilter("id,name",function(a){for(var b,c,d,e,f=a.length;f--;)if(e=a[f],"a"===e.name&&e.firstChild&&!e.attr("href")){d=e.parent,b=e.lastChild;do c
 =b.prev,d.insert(b,e),b=c;while(b)}}),k.fix_list_elements&&o.addNodeFilter("ul,ol",function(b){for(var c,d,e=b.length;e--;)if(c=b[e],d=c.parent,"ul"===d.name||"ol"===d.name)if(c.prev&&"li"===c.prev.name)c.prev.append(c);else{var f=new a("li",1);f.attr("style","list-style-type: none"),c.wrap(f)}}),k.validate&&m.getValidClasses()&&o.addAttributeFilter("class",function(a){for(var b,c,d,e,f,g,h,i=a.length,j=m.getValidClasses();i--;){for(b=a[i],c=b.attr("class").split(" "),f="",d=0;d<c.length;d++)e=c[d],h=!1,g=j["*"],g&&g[e]&&(h=!0),g=j[b.name],!h&&g&&g[e]&&(h=!0),h&&(f&&(f+=" "),f+=e);f.length||(f=null),b.attr("class",f)}})}}),g("y",["s","1d"],function(a,b){var c=b.makeMap;return function(b){var d,e,f,g,h,i=[];return b=b||{},d=b.i
 ndent,e=c(b.indent_before||""),f=c(b.indent_after||""),g=a.getEncodeFunc(b.entity_encoding||"raw",b.entities),h="html"==b.element_format,{start:function(a,b,c){var j,k,l,m;if(d&&e[a]&&i.length>0&&(m=i[i.length-1],m.length>0&&"\n"!==m&&i.push("\n")),i.push("<",a),b)for(j=0,k=b.length;j<k;j++)l=b[j],i.push(" ",l.name,'="',g(l.value,!0),'"');!c||h?i[i.length]=">":i[i.length]=" />",c&&d&&f[a]&&i.length>0&&(m=i[i.length-1],m.length>0&&"\n"!==m&&i.push("\n"))},end:function(a){var b;i.push("</",a,">"),d&&f[a]&&i.length>0&&(b=i[i.length-1],b.length>0&&"\n"!==b&&i.push("\n"))},text:function(a,b){a.length>0&&(i[i.length]=b?a:g(a))},cdata:function(a){i.pu
 sh("<![CDATA[",a,"]]>")},comment:function(a){i.push("<!--",a,"-->")},pi:function(a,b){b?i.push("<?",a," ",g(b),"?>"):i.push("<?",a,"?>"),d&&i.push("\n")},doctype:function(a){i.push("<!DOCTYPE",a,">",d?"\n":"")},reset:function(){i.length=0},getContent:function(){return i.join("").replace(/\n$/,"")}}}}),g("w",["y","v"],function(a,b){return function(c,d){var e=this,f=new a(c);c=c||{},c.validate=!("validate"in c)||c.validate,e.schema=d=d||new b,e.writer=f,e.serialize=function(a){function b(a){var c,h,i,j,k,l,m,n,o,p=e[a.type];if(p)p(a);else{if(c=a.name,h=a.shortEnded,i=a.attributes,g&&i&&i.length>1&&(l=[],l.map={},o=d.getElementRule(a.name))){for(m=0,n=o.attributesOrder.length;m<n;m++)j=o.attributesOrder[m],j in i.map&&
 amp;(k=i.map[j],l.map[j]=k,l.push({name:j,value:k}));for(m=0,n=i.length;m<n;m++)j=i[m].name,j in l.map||(k=i.map[j],l.map[j]=k,l.push({name:j,value:k}));i=l}if(f.start(a.name,i,h),!h){if(a=a.firstChild)do b(a);while(a=a.next);f.end(c)}}}var e,g;return g=c.validate,e={3:function(a){f.text(a.value,a.raw)},8:function(a){f.comment(a.value)},7:function(a){f.pi(a.name,a.value)},10:function(a){f.doctype(a.value)},4:function(a){f.cdata(a.value)},11:function(a){if(a=a.firstChild)do b(a);while(a=a.next)}},f.reset(),1!=a.type||c.inner?e[11](a):b(a),f.getContent()}}}),g("h",["c","r","u","s","w","t","v","o","1d","22"],function(a,b,c,d,e,f,g,h,i,j){function k(a){function b(a){return a&&"br"===a.name}var c,d;c=a.lastChild,b(c)&&(d=c.prev,b(d)&&(c.remove(),d.remove()))}var l=i.each,m=i.trim,n=a.DOM;return function(a,f){function o(a){var b=new RegExp([&qu
 ot;<span[^>]+data-mce-bogus[^>]+>[\u200b\ufeff]+<\\/span>","\\s?("+v.join("|")+')="[^"]+"'].join("|"),"gi");return a=j.trim(a.replace(b,""))}function p(a){var b,d,e,g,h,i=a,j=/<(\w+) [^>]*data-mce-bogus="all"[^>]*>/g,k=f.schema;for(i=o(i),h=k.getShortEndedElements();g=j.exec(i);)d=j.lastIndex,e=g[0].length,b=h[g[1]]?d:c.findEndTag(k,i,d),i=i.substring(0,d-e)+i.substring(b),j.lastIndex=d-e;return i}function q(){return p(f.getBody().innerHTML)}function r(a){i.inArray(v,a)===-1&&(u.addAttributeFilter(a,function(a,b){for(var c=a.length;c--;)a[c].attr(b,null)}),v.push(a))}var s,t,u,v=["data-mce-selected"];return f&&(s=f.dom,t=f.schema),s=s||n,t=t||new g(a),a.entity_encoding=a.entity_encoding||"named",a.remove_trailing_brs=!("remove_trailing_brs"in a)||a.remove_trailing_brs,u=new b(a,t),u.addAttributeFilter("data-mce-tabindex&quot
 ;,function(a,b){for(var c,d=a.length;d--;)c=a[d],c.attr("tabindex",c.attributes.map["data-mce-tabindex"]),c.attr(b,null)}),u.addAttributeFilter("src,href,style",function(b,c){for(var d,e,f,g=b.length,h="data-mce-"+c,i=a.url_converter,j=a.url_converter_scope;g--;)d=b[g],e=d.attributes.map[h],e!==f?(d.attr(c,e.length>0?e:null),d.attr(h,null)):(e=d.attributes.map[c],"style"===c?e=s.serializeStyle(s.parseStyle(e),d.name):i&&(e=i.call(j,e,c,d.name)),d.attr(c,e.length>0?e:null))}),u.addAttributeFilter("class",function(a){for(var b,c,d=a.length;d--;)b=a[d],c=b.attr("class"),c&&(c=b.attr("class").replace(/(?:^|\s)mce-item-\w+(?!\S)/g,""),b.attr("class",c.length>0?c:null))}),u.addAttributeFilter("data-mce-type",function(a,b,c){for(var d,e=a.length;e--;)d=a[e],"bookmark"!==d.attributes.map["data-mce-type"]||c.cleanup||d.remove()}),u.addNode
 Filter("noscript",function(a){for(var b,c=a.length;c--;)b=a[c].firstChild,b&&(b.value=d.decode(b.value))}),u.addNodeFilter("script,style",function(a,b){function c(a){return a.replace(/(<!--\[CDATA\[|\]\]-->)/g,"\n").replace(/^[\r\n]*|[\r\n]*$/g,"").replace(/^\s*((<!--)?(\s*\/\/)?\s*<!\[CDATA\[|(<!--\s*)?\/\*\s*<!\[CDATA\[\s*\*\/|(\/\/)?\s*<!--|\/\*\s*<!--\s*\*\/)\s*[\r\n]*/gi,"").replace(/\s*(\/\*\s*\]\]>\s*\*\/(-->)?|\s*\/\/\s*\]\]>(-->)?|\/\/\s*(-->)?|\]\]>|\/\*\s*-->\s*\*\/|\s*-->\s*)\s*$/g,"")}for(var d,e,f,g=a.length;g--;)d=a[g],e=d.firstChild?d.firstChild.value:"","script"===b?(f=d.attr("type"),f&&d.attr("type","mce-no/type"==f?null:f.replace(/^mce\-/,"")),e.length>0&&(d.firstChild.value="// <![CDATA[\n"+c(e)+"\n// ]]>")):e.length>0&&(d.firstChild.v
 alue="<!--\n"+c(e)+"\n-->")}),u.addNodeFilter("#comment",function(a){for(var b,c=a.length;c--;)b=a[c],0===b.value.indexOf("[CDATA[")?(b.name="#cdata",b.type=4,b.value=b.value.replace(/^\[CDATA\[|\]\]$/g,"")):0===b.value.indexOf("mce:protected ")&&(b.name="#text",b.type=3,b.raw=!0,b.value=unescape(b.value).substr(14))}),u.addNodeFilter("xml:namespace,input",function(a,b){for(var c,d=a.length;d--;)c=a[d],7===c.type?c.remove():1===c.type&&("input"!==b||"type"in c.attributes.map||c.attr("type","text"))}),u.addAttributeFilter("data-mce-src,data-mce-href,data-mce-style,data-mce-selected,data-mce-expando,data-mce-type,data-mce-resize",function(a,b){for(var c=a.length;c--;)a[c].attr(b,null)}),{schema:t,addNodeFilter:u.addNodeFilter,addAttributeFilter:u.addAttributeFilter,serialize:function(b,c){var d,f,g,i,n,o,p=this;return h.ie&am
 p;&s.select("script,style,select,map").length>0?(n=b.innerHTML,b=b.cloneNode(!1),s.setHTML(b,n)):b=b.cloneNode(!0),d=document.implementation,d.createHTMLDocument&&(f=d.createHTMLDocument(""),l("BODY"==b.nodeName?b.childNodes:[b],function(a){f.body.appendChild(f.importNode(a,!0))}),b="BODY"!=b.nodeName?f.body.firstChild:f.body,g=s.doc,s.doc=f),c=c||{},c.format=c.format||"html",c.selection&&(c.forced_root_block=""),c.no_events||(c.node=b,p.onPreProcess(c)),n=j.trim(m(c.getInner?b.innerHTML:s.getOuterHTML(b))),o=u.parse(n,c),k(o),i=new e(a,t),c.content=i.serialize(o),c.no_events||p.onPostProcess(c),g&&(s.doc=g),c.node=null,c.content},addRules:function(a){t.addValidElements(a)},setRules:function(a){t.setValidElements(a)},onPreProcess:function(a){f&&f.fire("PreProcess",a)},onPostProcess:function(a){f&&f.fire("PostProcess",a)},addTempAttr:r,trimHtml:o,getTrimmedCo
 ntent:q,trimContent:p}}}),g("5g",["1u","26","23","6k","58"],function(a,b,c,d,e){var f=function(a){return function(d){return b.eq(a,c.fromDom(d.dom().parentNode))}},g=function(c,g){return b.contains(c,g)?d.closest(g,function(a){return e.isTextBlock(a)||e.isListItem(a)},f(c)):a.none()},h=function(a){var b=a.getBody(),c=b.firstChild&&a.dom.isBlock(b.firstChild)?b.firstChild:b;a.selection.setCursorLocation(c,0)},i=function(a){a.dom.isEmpty(a.getBody())&&(a.setContent(""),h(a))};return{getParentBlock:g,paddEmptyBody:i}}),g("7n",["57"],function(a){var b=function(b){return a.first(b).isSome()},c=function(b,c,d){return a.ancestor(b,c,d).isSome()},d=function(b,c){return a.sibling(b,c).isSome()},e=function(b,c){return a.child(b,c).isSome()},f=function(b,c){return a.descendant(b,c).isSome()},g=function(b,c,d){return a.closest(b,c,d).isSome()};return{any:b,ancestor:c,sibling:d,child:e,desce
 ndant:f,closest:g}}),g("78",["1","26","23","7n","4j","21","j"],function(a,b,c,d,e,f,g){var h=function(e,f){var g=c.fromDom(e),h=c.fromDom(f);return d.ancestor(h,"pre,code",a.curry(b.eq,g))},i=function(a,b){return f.isText(b)&&/^[ \t\r\n]*$/.test(b.data)&&h(a,b)===!1},j=function(a){return f.isElement(a)&&"A"===a.nodeName&&a.hasAttribute("name")},k=function(a,b){return e.isCaretCandidate(b)&&i(a,b)===!1||j(b)||l(b)},l=f.hasAttribute("data-mce-bookmark"),m=f.hasAttribute("data-mce-bogus"),n=f.hasAttributeValue("data-mce-bogus","all"),o=function(a){var b,c,d=0;if(k(a,a))return!1;if(c=a.firstChild,!c)return!0;b=new g(c,a);do if(n(c))c=b.next(!0);else if(m(c))c=b.next();else if(f.isBr(c))d++,c=b.next();else{if(k(a,c))return!1;c=b.next()}while(c);return d<=1},p=function(a){return o(a.dom())};return{i
 sEmpty:p}}),g("6n",["1t","1","1u","6m","5q","26","23","56","6k","4y","5n","20","5g","78","21"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o){var p=e.immutable("block","position"),q=e.immutable("from","to"),r=function(a,b){var c=g.fromDom(a),d=g.fromDom(b.container());return m.getParentBlock(c,d).map(function(a){return p(a,b)})},s=function(a){return f.eq(a.from().block(),a.to().block())===!1},t=function(a){return j.parent(a.from().block()).bind(function(b){return j.parent(a.to().block()).filter(function(a){return f.eq(b,a)})}).isSome()},u=function(a){return o.isContentEditableFalse(a.from().block())===!1&&o.isContentEditableFalse(a.to().block())===!1},v=function(a,b,d){return o.isBr(d.position().getNode())&&n.isEmpty(d.block())===!1?k.positionIn(!1,d.block().dom()).bind(functio
 n(e){return e.isEqual(d.position())?k.fromPosition(b,a,e).bind(function(b){return r(a,b)}):c.some(d)}).getOr(d):d},w=function(a,b,c){var e=r(a,l.fromRangeStart(c)),f=e.bind(function(c){return k.fromPosition(b,a,c.position()).bind(function(c){return r(a,c).map(function(c){return v(a,b,c)})})});return d.liftN([e,f],q).filter(function(a){return s(a)&&t(a)&&u(a)})},x=function(a,b,d){return d.collapsed?w(a,b,d):c.none()};return{read:x}}),g("6o",["1t","1u","26","53","6a","23","4y","5n","20","58","78","21","59"],function(a,b,c,d,e,f,g,h,i,j,k,l,m){var n=function(b){var c=g.children(b);return a.findIndex(c,j.isBlock).fold(function(){return c},function(a){return c.slice(0,a)})},o=function(b){var c=n(b);return a.each(c,function(a){e.remove(a)}),c},p=function(a,b){h.positionIn(a,b.dom()).each(function(a){var b=a.getNode();l.isBr(b)&&amp
 ;e.remove(f.fromDom(b))})},q=function(b,c){var d=m.parentsAndSelf(c,b);return a.find(d.reverse(),k.isEmpty).each(e.remove)},r=function(a,d){var e=g.parents(d,function(b){return c.eq(b,a)});return b.from(e[e.length-2])},s=function(a,d){return c.contains(d,a)?g.parent(a).bind(function(e){return c.eq(e,d)?b.some(a):r(d,a)}):b.none()},t=function(b,c,f){if(k.isEmpty(f))return e.remove(f),h.firstPositionIn(c.dom());p(!0,c),p(!1,f);var g=o(c);return s(c,f).fold(function(){q(b,c);var e=h.lastPositionIn(f.dom());return a.each(g,function(a){d.append(f,a)}),e},function(e){var j=h.prevPosition(f.dom(),i.before(e.dom()));return a.each(g,function(a){d.before(e,a)}),q(b,c),j})},u=function(a,b,c,d){return b?t(a,d,c):t(a,c,d)};return{mergeBlocks:u}}),g("5d",["23","6n","6o"],function(a,b,c){var d=function(d,e){var f,g=a.fromDom(d.getBody());return f=b.read(g.dom(),e,d.selection.getRng()).bind(function(a){return c.mergeBlocks(g,e,a.from().block(),a.to().block())
 }),f.each(function(a){d.selection.setRng(a.toRange())}),f.isSome()};return{backspaceDelete:d}}),g("5e",["6m","26","23","5n","20","5g","6o"],function(a,b,c,d,e,f,g){var h=function(d,e){var h=e.getRng();return a.liftN([f.getParentBlock(d,c.fromDom(h.startContainer)),f.getParentBlock(d,c.fromDom(h.endContainer))],function(a,c){return b.eq(a,c)===!1&&(h.deleteContents(),g.mergeBlocks(d,!0,a,c).each(function(a){e.setRng(a.toRange())}),!0)}).getOr(!1)},i=function(a,b){var c=d.prevPosition(a.dom(),e.fromRangeStart(b)).isNone(),f=d.nextPosition(a.dom(),e.fromRangeEnd(b)).isNone();return c&&f},j=function(a){return a.setContent(""),a.selection.setCursorLocation(),!0},k=function(a){var b=c.fromDom(a.getBody()),d=a.selection.getRng();return i(b,d)?j(a):h(b,a.selection)},l=function(a,b){return!a.selection.isCollapsed()&&k(a,a.selection.getRng())};return{backspaceDelete:l}}),g("7
 9",["1t","5o","2k","3","4","4v"],function(a,b,c,d,e,f){var g=function(g){if(!c.isArray(g))throw new e("cases must be an array");if(0===g.length)throw new e("there must be at least one case");var h=[],i={};return a.each(g,function(j,k){var l=b.keys(j);if(1!==l.length)throw new e("one and only one name per case");var m=l[0],n=j[m];if(void 0!==i[m])throw new e("duplicate key detected:"+m);if("cata"===m)throw new e("cannot have a case named cata (sorry)");if(!c.isArray(n))throw new e("case arguments must be an array");h.push(m),i[m]=function(){var c=arguments.length;if(c!==n.length)throw new e("Wrong number of arguments to case "+m+". Expected "+n.length+" ("+n+"), got "+c);for(var i=new d(c),j=0;j<i.length;j++)i[j]=arguments[j];var l=function(c){var d=b.keys(c);if(h.length!==d.length)throw new e("Wrong num
 ber of arguments to match. Expected: "+h.join(",")+"\nActual: "+d.join(","));var f=a.forall(h,function(b){return a.contains(d,b)});if(!f)throw new e("Not all branches were specified when using match. Specified: "+d.join(", ")+"\nRequired: "+h.join(", "));return c[m].apply(null,i)};return{fold:function(){if(arguments.length!==g.length)throw new e("Wrong number of arguments to fold. Expected "+g.length+", got "+arguments.length);var a=arguments[k];return a.apply(null,i)},match:l,log:function(a){f.log(a,{constructors:h,constructor:m,params:i})}}}}),i};return{generate:g}}),g("6p",["79","1u","23","5n","20","62","5g","78","21"],function(a,b,c,d,e,f,g,h,i){var j=a.generate([{remove:["element"]},{moveToElement:["element"]},{moveToPosition:["position"]}]),k=function(a,b)
 {var c=b.getNode(a===!1),d=a?"after":"before";return i.isElement(c)&&c.getAttribute("data-mce-caret")===d},l=function(a,d,e,f){var i=f.getNode(d===!1);return g.getParentBlock(c.fromDom(a),c.fromDom(e.getNode())).map(function(a){return h.isEmpty(a)?j.remove(a.dom()):j.moveToElement(i)}).orThunk(function(){return b.some(j.moveToElement(i))})},m=function(a,c,e){return d.fromPosition(c,a,e).bind(function(d){return c&&i.isContentEditableFalse(d.getNode())?l(a,c,e,d):c===!1&&i.isContentEditableFalse(d.getNode(!0))?l(a,c,e,d):c&&f.isAfterContentEditableFalse(e)?b.some(j.moveToPosition(d)):c===!1&&f.isBeforeContentEditableFalse(e)?b.some(j.moveToPosition(d)):b.none()})},n=function(a,c){return a&&i.isContentEditableFalse(c.nextSibling)?b.some(j.moveToElement(c.nextSibling)):a===!1&&i.isContentEditableFalse(c.previousSibling)?b.some(j.moveToElement(c.previousSibling)):b.none()},o=function(a,c,d){return k(c,d
 )?n(c,d.getNode(c===!1)).fold(function(){return m(a,c,d)},b.some):m(a,c,d)},p=function(a,c,d){var g=f.normalizeRange(c?1:-1,a,d),h=e.fromRangeStart(g);return c===!1&&f.isAfterContentEditableFalse(h)?b.some(j.remove(h.getNode(!0))):c&&f.isBeforeContentEditableFalse(h)?b.some(j.remove(h.getNode())):o(a,c,h)};return{read:p}}),g("6q",["1","1u","6m","53","6a","23","56","6k","4y","4j","5n","20","78","21"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n){var o=function(a,b){var c=a.container(),d=a.offset();return l.isTextPosition(a)===!1&&c===b.parentNode&&d>l.before(b).offset()},p=function(a,b){return o(b,a)?new l(b.container(),b.offset()-1):b},q=function(a){return n.isText(a)?new l(a,0):l.before(a)},r=function(a){return n.isText(a)?new l(a,a.data.length):l.after(a)},s=function(a){return j.isCaretCandidate(a.previousS
 ibling)?b.some(r(a.previousSibling)):a.previousSibling?k.lastPositionIn(a.previousSibling):b.none()},t=function(a){return j.isCaretCandidate(a.nextSibling)?b.some(q(a.nextSibling)):a.nextSibling?k.firstPositionIn(a.nextSibling):b.none()},u=function(a,c){var d=l.before(c.previousSibling?c.previousSibling:c.parentNode);return k.prevPosition(a,d).fold(function(){return k.nextPosition(a,l.after(c))},b.some)},v=function(a,c){return k.nextPosition(a,l.after(c)).fold(function(){return k.prevPosition(a,l.before(c))},b.some)},w=function(a,b){return s(b).orThunk(function(){return t(b)}).orThunk(function(){return u(a,b)})},x=function(a,b){return t(b).orThunk(function(){return s(b)}).orThunk(function(){return v(a,b)})},y=function(a,b,c){return a?x(b,c):w(b,c)},z=function(b,c,d){return y(b,c,d).map(a.curry(p,d))},A=function(a,b,c){c.fold(function(){a.focus()},function(c){a.selection.setRng(c.toRange(),b)})},B=function(a){return function(b){return b.dom()===a}},C=function(a,b){return b&&a
 .schema.getBlockElements().hasOwnProperty(g.name(b))},D=function(a){if(m.isEmpty(a)){var c=f.fromHtml('<br data-mce-bogus="1">');return e.empty(a),d.append(a,c),b.some(l.before(c.dom()))}return b.none()},E=function(a,b){return c.liftN([i.prevSibling(a),i.nextSibling(a),b],function(b,c,d){var f,g=b.dom(),h=c.dom();return n.isText(g)&&n.isText(h)?(f=g.data.length,g.appendData(h.data),e.remove(c),e.remove(a),d.container()===h?new l(g,f):d):(e.remove(a),d)}).orThunk(function(){return e.remove(a),b})},F=function(c,d,e){var f=z(d,c.getBody(),e.dom()),g=h.ancestor(e,a.curry(C,c),B(c.getBody())),i=E(e,f);g.bind(D).fold(function(){A(c,d,i)},function(a){A(c,d,b.some(a))})};return{deleteElement:F}}),g("5f",["1t","6a","23","6c","20","6p","6q","5g","21"],function(a,b,c,d,e,f,g,h,i){var j=function(a,b){return function(d){return g.deleteElement(a,b,c.fromDom(d)),!0}},k=functi
 on(a,b){return function(c){var d=b?e.before(c):e.after(c);return a.selection.setRng(d.toRange()),!0}},l=function(a){return function(b){return a.selection.setRng(b.toRange()),!0}},m=function(a,b){var c=f.read(a.getBody(),b,a.selection.getRng()).map(function(c){return c.fold(j(a,b),k(a,b),l(a))});return c.getOr(!1)},n=function(c){a.each(d.descendants(c,".mce-offscreen-selection"),b.remove)},o=function(a,b){var d=a.selection.getNode();return!!i.isContentEditableFalse(d)&&(n(c.fromDom(a.getBody())),g.deleteElement(a,b,c.fromDom(a.selection.getNode())),h.paddEmptyBody(a),!0)},p=function(a,b){for(;b&&b!==a;){if(i.isContentEditableTrue(b)||i.isContentEditableFalse(b))return b;b=b.parentNode}return null},q=function(a){var b,c=p(a.getBody(),a.selection.getNode());return i.isContentEditableTrue(c)&&a.dom.isBlock(c)&&a.dom.isEmpty(c)&&(b=a.dom.create("br",{"data-mce-bogus":"1"}),a.dom.setHTML(c,""),c.appe
 ndChild(b),a.selection.setRng(e.before(b).toRange())),!0},r=function(a,b){return a.selection.isCollapsed()?m(a,b):o(a,b)};return{backspaceDelete:r,paddEmptyElement:q}}),g("7a",["1","21","22"],function(a,b,c){var d=b.isText,e=function(a){return d(a)&&a.data[0]===c.ZWSP},f=function(a){return d(a)&&a.data[a.data.length-1]===c.ZWSP},g=function(a){return a.ownerDocument.createTextNode(c.ZWSP)},h=function(a){if(d(a.previousSibling))return f(a.previousSibling)?a.previousSibling:(a.previousSibling.appendData(c.ZWSP),a.previousSibling);if(d(a))return e(a)?a:(a.insertData(0,c.ZWSP),a);var b=g(a);return a.parentNode.insertBefore(b,a),b},i=function(a){if(d(a.nextSibling))return e(a.nextSibling)?a.nextSibling:(a.nextSibling.insertData(0,c.ZWSP),a.nextSibling);if(d(a))return f(a)?a:(a.appendData(c.ZWSP),a);var b=g(a);return a.nextSibling?a.parentNode.insertBefore(b,a.nextSibling):a.parentNode.appendChild(b),b},j=function(a,b){return a?h(b):i
 (b)};return{insertInline:j,insertInlineBefore:a.curry(j,!0),insertInlineAfter:a.curry(j,!1)}}),g("7b",["1t","1z","20","21","22","1d"],function(a,b,c,d,e,f){var g=d.isElement,h=d.isText,i=function(a){var b=a.parentNode;b&&b.removeChild(a)},j=function(a){try{return a.nodeValue}catch(a){return""}},k=function(a,b){0===b.length?i(a):a.nodeValue=b},l=function(a){var b=e.trim(a);return{count:a.length-b.length,text:b}},m=function(a,b){return s(a),b},n=function(a,b){var d=l(a.data.substr(0,b.offset())),e=l(a.data.substr(b.offset())),f=d.text+e.text;return f.length>0?(k(a,f),new c(a,b.offset()-d.count)):b},o=function(b,d){var e=d.container(),f=a.indexOf(e.childNodes,b).map(function(a){return a<d.offset()?new c(e,d.offset()-1):d}).getOr(d);return s(b),f},p=function(a,b){return b.container()===a?n(a,b):m(a,b)},q=function(a,b){return b.container()===a.parentNode?o(a,b):m(a,b)},r=function(a,b){return c.i
 sTextPosition(b)?p(a,b):q(a,b)},s=function(a){if(g(a)&&b.isCaretContainer(a)&&(b.hasContent(a)?a.removeAttribute("data-mce-caret"):i(a)),h(a)){var c=e.trim(j(a));k(a,c)}};return{removeAndReposition:r,remove:s}}),g("2e",["1t","1","5o","1u","5p","5q","2k","4u","1d"],function(a,b,c,d,e,f,g,h,i){var j=f.immutable("sections","settings"),k=h.detect(),l=k.deviceType.isTouch(),m=["lists","autolink","autosave"],n=function(a){return g.isArray(a)?a.join(" "):a},o=function(c){var d=a.map(n(c).split(" "),e.trim);return a.filter(d,b.curry(a.contains,m)).join(" ")},p=function(b,d){var e=c.bifilter(d,function(c,d){return a.contains(b,d)});return j(e.t,e.f)},q=function(a,b){var c=a.sections();return c.hasOwnProperty(b)?c[b]:{}},r=function(a,b){return a.sections().hasOwnProperty(b)},s=function(a,b,
 c){return{id:a,theme:"modern",delta_width:0,delta_height:0,popup_css:"",plugins:"",document_base_url:b,add_form_submit_trigger:!0,submit_patch:!0,add_unload_trigger:!0,convert_urls:!0,relative_urls:!0,
+remove_script_host:!0,object_resizing:!0,doctype:"<!DOCTYPE html>",visual:!0,font_size_style_values:"xx-small,x-small,small,medium,large,x-large,xx-large",font_size_legacy_values:"xx-small,small,medium,large,x-large,xx-large,300%",forced_root_block:"p",hidden_input:!0,padd_empty_editor:!0,render_ui:!0,indentation:"30px",inline_styles:!0,convert_fonts_to_spans:!0,indent:"simple",indent_before:"p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,tfoot,tbody,tr,section,article,hgroup,aside,figure,figcaption,option,optgroup,datalist",indent_after:"p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,tfoot,tbody,tr,section,article,hgroup,aside,figure,figcaption,option,optgroup,datalist",entity_encoding:"named",url_converter:c.convertURL,url_converter_scope:c,ie7_compat:!0}},t=function(a,b){var c=b.exte
 rnal_plugins?b.external_plugins:{};return a&&a.external_plugins?i.extend({},a.external_plugins,c):c},u=function(a,b,c){var d=p(["mobile"],c),e=d.settings().plugins,f=i.extend(a,b,d.settings(),l?q(d,"mobile"):{},{validate:!0,content_editable:d.settings().inline,external_plugins:t(b,d.settings())},l&&e&&r(d,"mobile")?{plugins:o(e)}:{});return f},v=function(a,b,c,d,e){var f=s(b,c,a);return u(f,d,e)},w=function(a,b){return d.from(a.settings[b])},x=function(a,b,c){return d.from(b.settings[c]).filter(a)};return{getEditorSettings:v,get:w,getString:b.curry(x,g.isString),filterMobilePlugins:o}}),g("7c",[],function(){var a=/[\u0591-\u07FF\uFB1D-\uFDFF\uFE70-\uFEFC]/,b=function(b){return a.test(b)};return{hasStrongRtl:b}}),g("6u",["1t","1","1u","6m","2k","23","24","1z","5n","20","62","5j","c",
 "21","2e","7c"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p){var q=function(a,b){var c=o.getString(a,"inline_boundaries_selector").getOr("a[href],code");return g.is(f.fromDom(b),c)},r=function(a){return"rtl"===m.DOM.getStyle(a,"direction",!0)||p.hasStrongRtl(a.textContent)},s=function(b,c,d){return a.filter(m.DOM.getParents(d.container(),"*",c),b)},t=function(a,b,d){var e=s(a,b,d);return c.from(e[e.length-1])},u=function(a,b,c){var d=k.getParentBlock(b,a),e=k.getParentBlock(c,a);return d&&d===e},v=function(a){return h.isBeforeInline(a)||h.isAfterInline(a)},w=function(a,b){var c=b.container(),d=b.offset();return a?h.isCaretContainerInline(c)?n.isText(c.nextSibling)?new j(c.nextSibling,0):j.after(c):h.isBeforeInline(b)?new j(c,d+1):b:h.isCaretContainerInline(c)?n.isText(c.previousSibling)?new j(c.previousSibling,c.previousSibling.data.length):j.before(c):h.isAfterInline(b)?new j(c,d-1):b},x=b.curry(w,
 !0),y=b.curry(w,!1);return{isInlineTarget:q,findRootInline:t,isRtl:r,isAtZwsp:v,normalizePosition:w,normalizeForwards:x,normalizeBackwards:y,hasSameParentBlock:u}}),g("6r",["1u","1z","7a","7b","5n","20","21","6u"],function(a,b,c,d,e,f,g,h){var i=function(a,b){return g.isText(a.container())?c.insertInline(b,a.container()):c.insertInline(b,a.getNode())},j=function(a,c){var d=c.get();return d&&a.container()===d&&b.isCaretContainerInline(d)},k=function(b,g){return g.fold(function(e){d.remove(b.get());var g=c.insertInlineBefore(e);return b.set(g),a.some(new f(g,g.length-1))},function(a){return e.firstPositionIn(a).map(function(a){if(j(a,b))return new f(b.get(),1);d.remove(b.get());var c=i(a,!0);return b.set(c),new f(c,1)})},function(a){return e.lastPositionIn(a).map(function(a){if(j(a,b))return new f(b.get(),b.get().length-1);d.remove(b.get());var c=i(a,!1);return b.set(c),new f(c,c.
 length-1)})},function(e){d.remove(b.get());var g=c.insertInlineAfter(e);return b.set(g),a.some(new f(g,1))})};return{renderCaret:k}}),g("7d",["1u"],function(a){var b=function(b,c){for(var d=0;d<b.length;d++){var e=b[d].apply(null,c);if(e.isSome())return e}return a.none()};return{evaluateUntil:b}}),g("6s",["79","1","1u","6m","1z","5n","20","62","21","6u","7d"],function(a,b,c,d,e,f,g,h,i,j,k){var l=a.generate([{before:["element"]},{start:["element"]},{end:["element"]},{after:["element"]}]),m=function(a,b){var c=h.getParentBlock(b,a);return c?c:a},n=function(a,d,e){var g=j.normalizeForwards(e),h=m(d,g.container());return j.findRootInline(a,h,g).fold(function(){return f.nextPosition(h,g).bind(b.curry(j.findRootInline,a,h)).map(function(a){return l.before(a)})},c.none)},o=function(a,b,d){var e=j.normalizeBac
 kwards(d);return j.findRootInline(a,b,e).bind(function(a){var b=f.prevPosition(a,e);return b.isNone()?c.some(l.start(a)):c.none()})},p=function(a,b,d){var e=j.normalizeForwards(d);return j.findRootInline(a,b,e).bind(function(a){var b=f.nextPosition(a,e);return b.isNone()?c.some(l.end(a)):c.none()})},q=function(a,d,e){var g=j.normalizeBackwards(e),h=m(d,g.container());return j.findRootInline(a,h,g).fold(function(){return f.prevPosition(h,g).bind(b.curry(j.findRootInline,a,h)).map(function(a){return l.after(a)})},c.none)},r=function(a){return j.isRtl(t(a))===!1},s=function(a,b,c){var d=k.evaluateUntil([n,o,p,q],[a,b,c]);return d.filter(r)},t=function(a){return a.fold(b.identity,b.identity,b.identity,b.identity)},u=function(a){return a.fold(b.constant("before"),b.constant("start"),b.constant("end"),b.constant("after"))},v=function(a){return a.fold(l.before,l.before,l.after,l.after)},w=function(a){return a.fold(l.start,l.start,l.end,l.end)},x=func
 tion(a,b){return u(a)===u(b)&&t(a)===t(b)},y=function(a,b,c,e,f,g){return d.liftN([j.findRootInline(b,c,e),j.findRootInline(b,c,f)],function(b,d){return b!==d&&j.hasSameParentBlock(c,b,d)?l.after(a?b:d):g}).getOr(g)},z=function(a,c){return a.fold(b.constant(!0),function(a){return!x(a,c)})},A=function(a,c,d,e,g){var h=j.normalizePosition(a,g),i=f.fromPosition(a,d,h).map(b.curry(j.normalizePosition,a)),k=i.fold(function(){return e.map(v)},function(f){return s(c,d,f).map(b.curry(y,a,c,d,h,f)).filter(b.curry(z,e))});return k.filter(r)},B=function(a,d){return a?d.fold(b.compose(c.some,l.start),c.none,b.compose(c.some,l.after),c.none):d.fold(c.none,b.compose(c.some,l.before),c.none,b.compose(c.some,l.end))},C=function(a,c,d,e){var f=j.normalizePosition(a,e),g=s(c,d,f);return s(c,d,f).bind(b.curry(B,a)).orThunk(function(){return A(a,c,d,g,e)})};return{readLocation:s,findLocation:C,prevLocation:b.curry(C,!1),nextLocation:b.curry(C,!0),getElement:t,outside:v,inside:w}}),g(&qu
 ot;6t",["1t","1k","1","7b","20","6r","6s","6u"],function(a,b,c,d,e,f,g,h){var i=function(a,b){var c=a.dom.createRng();c.setStart(b.container(),b.offset()),c.setEnd(b.container(),b.offset()),a.selection.setRng(c)},j=function(a){return a.settings.inline_boundaries!==!1},k=function(a,b){a?b.setAttribute("data-mce-selected","1"):b.removeAttribute("data-mce-selected","1")},l=function(a,b,c){return f.renderCaret(b,c).map(function(b){return i(a,b),c})},m=function(a,b,d){var f=a.getBody(),i=e.fromRangeStart(a.selection.getRng()),j=c.curry(h.isInlineTarget,a),k=g.findLocation(d,j,f,i);return k.bind(function(c){return l(a,b,c)})},n=function(b,d,e){var f=a.filter(d.select("*[data-mce-selected]"),b),g=a.filter(e,b);a.each(a.difference(f,g),c.curry(k,!1)),a.each(a.difference(g,f),c.curry(k,!0))},o=function(a,b){if(a.selection.isCollapsed()&&a.composing!==
 !0&&b.get()){var c=e.fromRangeStart(a.selection.getRng());e.isTextPosition(c)&&h.isAtZwsp(c)===!1&&(i(a,d.removeAndReposition(b.get(),c)),b.set(null))}},p=function(b,c,d,f){if(c.selection.isCollapsed()){var h=a.filter(f,b);a.each(h,function(a){var f=e.fromRangeStart(c.selection.getRng());g.readLocation(b,c.getBody(),f).bind(function(a){return l(c,d,a)})})}},q=function(a,b,c){return function(){return!!j(a)&&m(a,b,c).isSome()}},r=function(a){var d=new b(null),e=c.curry(h.isInlineTarget,a);return a.on("NodeChange",function(b){j(a)&&(n(e,a.dom,b.parents),o(a,d),p(e,a,d,b.parents))}),d};return{move:q,setupSelectedState:r,setCaretPosition:i}}),g("5h",["1","1u","6m","23","1z","5n","20","62","6q","6r","6s","6t","6u"],function(a,b,c,d,e,f,g,h,i,j,k,l,m){var n=function(a){return a.settings.inline_boundarie
 s!==!1},o=function(a,b){var c=document.createRange();return c.setStart(a.container(),a.offset()),c.setEnd(b.container(),b.offset()),c},p=function(a){return c.liftN([f.firstPositionIn(a),f.lastPositionIn(a)],function(b,c){var d=m.normalizePosition(!0,b),e=m.normalizePosition(!1,c);return f.nextPosition(a,d).map(function(a){return a.isEqual(e)}).getOr(!0)}).getOr(!0)},q=function(a,b){return function(c){return j.renderCaret(b,c).map(function(b){return l.setCaretPosition(a,b),!0}).getOr(!1)}},r=function(b,c,d,e){var f=b.getBody(),h=a.curry(m.isInlineTarget,b);b.undoManager.ignore(function(){b.selection.setRng(o(d,e)),b.execCommand("Delete"),k.readLocation(h,f,g.fromRangeStart(b.selection.getRng())).map(k.inside).map(q(b,c))}),b.nodeChanged()},s=function(a,b){var c=h.getParentBlock(b,a);return c?c:a},t=function(c,e,g,h){var j=s(c.getBody(),h.container()),l=a.curry(m.isInlineTarget,c),n=k.readLocation(l,j,h);return n.bind(function(c){return g?c.fold(a.constant(b.some(k.inside(c)
 )),b.none,a.constant(b.some(k.outside(c))),b.none):c.fold(b.none,a.constant(b.some(k.outside(c))),b.none,a.constant(b.some(k.inside(c))))}).map(q(c,e)).getOrThunk(function(){var a=f.navigate(g,j,h),b=a.bind(function(a){return k.readLocation(l,j,a)});return n.isSome()&&b.isSome()?m.findRootInline(l,j,h).map(function(a){return!!p(a)&&(i.deleteElement(c,g,d.fromDom(a)),!0)}).getOr(!1):b.bind(function(b){return a.map(function(a){return g?r(c,e,h,a):r(c,e,a,h),!0})}).getOr(!1)})},u=function(a,b,c){if(a.selection.isCollapsed()&&n(a)){var d=g.fromRangeStart(a.selection.getRng());return t(a,b,c,d)}return!1};return{backspaceDelete:u}}),g("6v",["79","1t","1","1u","6m","5q","26","23","6c","57"],function(a,b,c,d,e,f,g,h,i,j){var k=f.immutable("start","end"),l=f.immutable("rng","table","cells"),m=a.generate([{remov
 eTable:["element"]},{emptyCells:["cells"]}]),n=function(a,b){return j.closest(h.fromDom(a),"td,th",b)},o=function(a,b){return j.ancestor(a,"table",b)},p=function(a){return g.eq(a.start(),a.end())===!1},q=function(a,b){return o(a.start(),b).bind(function(c){return o(a.end(),b).bind(function(a){return g.eq(c,a)?d.some(c):d.none()})})},r=function(a,b){return e.liftN([n(a.startContainer,b),n(a.endContainer,b)],k).filter(p)},s=function(a,b){return q(a,b).bind(function(b){var c=i.descendants(b,"td,th");return l(a,b,c)})},t=function(a,b){var d=c.curry(g.eq,a);return r(b,d).map(function(a){return s(a,d)})},u=function(a,c){return b.findIndex(a,function(a){return g.eq(a,c)})},v=function(a){return e.liftN([u(a.cells(),a.rng().start()),u(a.cells(),a.rng().end())],function(b,c){return a.cells().slice(b,c+1)})},w=function(a){return v(a).bind(function(b){var c=a.cells();return b.length===c.length?m.removeTable(a.table()):m.emptyCells(b)})},x=functi
 on(a){return m.emptyCells(a)},y=function(a,b){return t(a,b).map(w)};return{getActionFromRange:y,getActionFromCells:x}}),g("5i",["1t","1","23","6q","6v","5l","5c"],function(a,b,c,d,e,f,g){var h=function(b,c){return a.each(c,f.fillWithPaddingBr),b.selection.setCursorLocation(c[0].dom(),0),!0},i=function(a,b){return d.deleteElement(a,!1,b),!0},j=function(a,c,d){return e.getActionFromRange(c,d).map(function(c){return c.fold(b.curry(i,a),b.curry(h,a))}).getOr(!1)},k=function(a){var b=c.fromDom(a.getBody()),d=a.selection.getRng(),e=g.getCellsFromEditor(a);return 0!==e.length?h(a,e):j(a,b,d)},l=function(a){return!a.selection.isCollapsed()&&k(a)};return{backspaceDelete:l}}),g("2b",["5d","5e","5f","5g","5h","5i"],function(a,b,c,d,e,f){var g=function(a,b){a.getDoc().execCommand(b,!1,null)},h=function(h){c.backspaceDelete(h,!1)||e.backspa
 ceDelete(h,!1)||a.backspaceDelete(h,!1)||f.backspaceDelete(h)||b.backspaceDelete(h,!1)||(g(h,"Delete"),d.paddEmptyBody(h))},i=function(d){c.backspaceDelete(d,!0)||e.backspaceDelete(d,!0)||a.backspaceDelete(d,!0)||f.backspaceDelete(d)||b.backspaceDelete(d,!0)||g(d,"ForwardDelete")};return{deleteCommand:h,forwardDeleteCommand:i}}),g("5m",["1d","5j","20"],function(a,b,c){var d=function(a){return a.firstChild&&a.firstChild===a.lastChild},e=function(a){return"br"===a.name||"\xa0"===a.value},f=function(a,b){var c=a.getBlockElements();return c[b.name]&&d(b)&&e(b.firstChild)},g=function(a,b){var c=a.getNonEmptyElements();return b&&(b.isEmpty(c)||f(a,b))},h=function(a,b){var c=b.firstChild,d=b.lastChild;return c&&"meta"===c.name&&(c=c.next),d&&"mce_marker"===d.attr("id")&&(d=d.prev),g(a,d)&&(d=d.prev),!(!c||c!==d
 )&&("ul"===c.name||"ol"===c.name)},i=function(a){var b=a.firstChild,c=a.lastChild;return b&&"META"===b.nodeName&&b.parentNode.removeChild(b),c&&"mce_marker"===c.id&&c.parentNode.removeChild(c),a},j=function(a,b,c){var d=b.serialize(c),e=a.createFragment(d);return i(e)},k=function(b){return a.grep(b.childNodes,function(a){return"LI"===a.nodeName})},l=function(a){return!a.firstChild},m=function(a){return a.length>0&&l(a[a.length-1])?a.slice(0,-1):a},n=function(a,b){var c=a.getParent(b,a.isBlock);return c&&"LI"===c.nodeName?c:null},o=function(a,b){return!!n(a,b)},p=function(a,b){var c=b.cloneRange(),d=b.cloneRange();return c.setStartBefore(a),d.setEndAfter(a),[c.cloneContents(),d.cloneContents()]},q=function(a,d){var e=c.before(a),f=new b(d),g=f.next(e);return g?g.toRange():null},r=function(a,d){var e=c.after(a),f=new b(d),g=f.prev(e);return g?g.toRange():null},s=funct
 ion(b,c,d,e){var f=p(b,e),g=b.parentNode;return g.insertBefore(f[0],b),a.each(c,function(a){g.insertBefore(a,b)}),g.insertBefore(f[1],b),g.removeChild(b),r(c[c.length-1],d)},t=function(b,c,d){var e=b.parentNode;return a.each(c,function(a){e.insertBefore(a,b)}),q(b,d)},u=function(a,b,c,d){return d.insertAfter(b.reverse(),a),r(b[0],c)},v=function(a,d,e,f){var g=j(d,a,f),h=n(d,e.startContainer),i=m(k(g.firstChild)),l=1,o=2,p=d.getRoot(),q=function(a){var f=c.fromRangeStart(e),g=new b(d.getRoot()),i=a===l?g.prev(f):g.next(f);return!i||n(d,i.getNode())!==h};return q(l)?t(h,i,p):q(o)?u(h,i,p,d):s(h,i,p,e)};return{isListFragment:h,insertAtCaret:v,isParentBlockLi:o,trimListItems:m,listItems:k}}),g("2c",["1u","23","20","5j","5k","21","5l","4m","o","w","5m","1d"],function(a,b,c,d,e,f,g,h,i,j,k,l){var m=f.matchNodeNames("td th"),n=function(a,b,c){if("
 all"===c.getAttribute("data-mce-bogus"))c.parentNode.insertBefore(a.dom.createFragment(b),c);else{var d=c.firstChild,e=c.lastChild;!d||d===e&&"BR"===d.nodeName?a.dom.setHTML(c,b):a.selection.setContent(b)}},o=function(c,d){a.from(c.getParent(d,"td,th")).map(b.fromDom).each(g.trimBlockTrailingBr)},p=function(a,b,f){function g(a){function b(a){return d[a]&&3==d[a].nodeType}var c,d,e;return c=J.getRng(!0),d=c.startContainer,e=c.startOffset,3==d.nodeType&&(e>0?a=a.replace(/^&nbsp;/," "):b("previousSibling")||(a=a.replace(/^ /,"&nbsp;")),e<d.length?a=a.replace(/&nbsp;(<br>|)$/," "):b("nextSibling")||(a=a.replace(/(&nbsp;| )(<br>|)$/,"&nbsp;"))),a}function p(){var a,c,d;a=J.getRng(!0),c=a.startContainer,d=a.startOffset,3==c.nodeType&&a.collapsed&&("\xa0"===c.data[d]?(c.deleteData(d,1),/[\u00a0| ]$/.test(b)||(
 b+=" ")):"\xa0"===c.data[d-1]&&(c.deleteData(d-1,1),/[\u00a0| ]$/.test(b)||(b=" "+b)))}function q(){if(H){var b=a.getBody(),c=new e(K);l.each(K.select("*[data-mce-fragment]"),function(a){for(var d=a.parentNode;d&&d!=b;d=d.parentNode)I[a.nodeName.toLowerCase()]&&c.compare(d,a)&&K.remove(a,!0)})}}function r(a){for(var b=a;b=b.walk();)1===b.type&&b.attr("data-mce-fragment","1")}function s(a){l.each(a.getElementsByTagName("*"),function(a){a.removeAttribute("data-mce-fragment")})}function t(a){return!!a.getAttribute("data-mce-fragment")}function u(b){return b&&!a.schema.getShortEndedElements()[b.nodeName]}function v(b){function e(b){for(var c=a.getBody();b&&b!==c;b=b.parentNode)if("false"===a.dom.getContentEditable(b))return b;return null}function f(b){var e=c.fromRangeStart(b),f=new d(a.getBody());if(e=f.next(e))return e.toRange()}va
 r g,h,j;if(b){if(J.scrollIntoView(b),g=e(b))return K.remove(b),void J.select(g);D=K.createRng(),E=b.previousSibling,E&&3==E.nodeType?(D.setStart(E,E.nodeValue.length),i.ie||(F=b.nextSibling,F&&3==F.nodeType&&(E.appendData(F.data),F.parentNode.removeChild(F)))):(D.setStartBefore(b),D.setEndBefore(b)),h=K.getParent(b,K.isBlock),K.remove(b),h&&K.isEmpty(h)&&(a.$(h).empty(),D.setStart(h,0),D.setEnd(h,0),m(h)||t(h)||!(j=f(D))?K.add(h,K.create("br",{"data-mce-bogus":"1"})):(D=j,K.remove(h))),J.setRng(D)}}var w,x,y,z,A,B,C,D,E,F,G,H,I=a.schema.getTextInlineElements(),J=a.selection,K=a.dom;/^ | $/.test(b)&&(b=g(b)),w=a.parser,H=f.merge,x=new j({validate:a.settings.validate},a.schema),G='<span id="mce_marker" data-mce-type="bookmark">&#xFEFF;&#x200B;</span>',B={content:b,format:"html",selection:!0},a.fire("BeforeSetContent",B),b=B.content,b.indexOf("{
 $caret}")==-1&&(b+="{$caret}"),b=b.replace(/\{\$caret\}/,G),D=J.getRng();var L=D.startContainer||(D.parentElement?D.parentElement():null),M=a.getBody();L===M&&J.isCollapsed()&&K.isBlock(M.firstChild)&&u(M.firstChild)&&K.isEmpty(M.firstChild)&&(D=K.createRng(),D.setStart(M.firstChild,0),D.setEnd(M.firstChild,0),J.setRng(D)),J.isCollapsed()||(a.selection.setRng(h.normalize(a.selection.getRng())),a.getDoc().execCommand("Delete",!1,null),p()),y=J.getNode();var N={context:y.nodeName.toLowerCase(),data:f.data};if(A=w.parse(b,N),f.paste===!0&&k.isListFragment(a.schema,A)&&k.isParentBlockLi(K,y))return D=k.insertAtCaret(x,K,a.selection.getRng(!0),A),a.selection.setRng(D),void a.fire("SetContent",B);if(r(A),E=A.lastChild,"mce_marker"==E.attr("id"))for(C=E,E=E.prev;E;E=E.walk(!0))if(3==E.type||!K.isBlock(E.name)){a.schema.isValidChild(E.parent.name,"span")&&
 E.parent.insert(C,E,"br"===E.name);break}if(a._selectionOverrides.showBlockCaretContainer(y),N.invalid){for(J.setContent(G),y=J.getNode(),z=a.getBody(),9==y.nodeType?y=E=z:E=y;E!==z;)y=E,E=E.parentNode;b=y==z?z.innerHTML:K.getOuterHTML(y),b=x.serialize(w.parse(b.replace(/<span (id="mce_marker"|id=mce_marker).+?<\/span>/i,function(){return x.serialize(A)}))),y==z?K.setHTML(z,b):K.setOuterHTML(y,b)}else b=x.serialize(A),n(a,b,y);q(),v(K.get("mce_marker")),s(a.getBody()),o(a.dom,a.selection.getStart()),a.fire("SetContent",B),a.addVisual()},q=function(a){var b;return"string"!=typeof a?(b=l.extend({paste:a.paste,data:{paste:a.paste}},a),{content:a.content,details:b}):{content:a,details:{}}},r=function(a,b){var c=q(b);p(a,c.content,c.details)};return{insertAtCaret:r}}),g("l",["2b","21","e","j","o","2c","1d"],function(a,b,c,d,e,f,g){var h=g.each,i=g.ext
 end,j=g.map,k=g.inArray,l=g.explode,m=e.ie&&e.ie<11,n=!0,o=!1;return function(g){function p(a,b,c,d){var e,f,i=0;if(!g.removed){if(/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint)$/.test(a)||d&&d.skip_focus||g.focus(),d=g.fire("BeforeExecCommand",{command:a,ui:b,value:c}),d.isDefaultPrevented())return!1;if(f=a.toLowerCase(),e=H.exec[f])return e(f,b,c),g.fire("ExecCommand",{command:a,ui:b,value:c}),!0;if(h(g.plugins,function(d){if(d.execCommand&&d.execCommand(a,b,c))return g.fire("ExecCommand",{command:a,ui:b,value:c}),i=!0,!1}),i)return i;if(g.theme&&g.theme.execCommand&&g.theme.execCommand(a,b,c))return g.fire("ExecCommand",{command:a,ui:b,value:c}),!0;try{i=g.getDoc().execCommand(a,b,c)}catch(a){}return!!i&&(g.fire("ExecCommand",{command:a,ui:b,value:c}),!0)}}function q(a){var b;if(!g.quirks.isHidden()&&!g.removed){if(a=a.toLowerCase(),b=H.state[a])return b(
 a);try{return g.getDoc().queryCommandState(a)}catch(a){}return!1}}function r(a){var b;if(!g.quirks.isHidden()&&!g.removed){if(a=a.toLowerCase(),b=H.value[a])return b(a);try{return g.getDoc().queryCommandValue(a)}catch(a){}}}function s(a,b){b=b||"exec",h(a,function(a,c){h(c.toLowerCase().split(","),function(c){H[b][c]=a})})}function t(a,b,c){a=a.toLowerCase(),H.exec[a]=function(a,d,e,f){return b.call(c||g,d,e,f)}}function u(a){if(a=a.toLowerCase(),H.exec[a])return!0;try{return g.getDoc().queryCommandSupported(a)}catch(a){}return!1}function v(a,b,c){a=a.toLowerCase(),H.state[a]=function(){return b.call(c||g)}}function w(a,b,c){a=a.toLowerCase(),H.value[a]=function(){return b.call(c||g)}}function x(a){return a=a.toLowerCase(),!!H.exec[a]}function y(a,b,c){return void 0===b&&(b=o),void 0===c&&(c=null),g.getDoc().execCommand(a,b,c)}function z(a){return F.match(a)}function A(a,b){F.toggle(a,b?{value:b}:void 0),g.nodeChanged()}function B(a){G=E.g
 etBookmark(a)}function C(){E.moveToBookmark(G)}var D,E,F,G,H={state:{},exec:{},value:{}},I=g.settings;g.on("PreInit",function(){D=g.dom,E=g.selection,I=g.settings,F=g.formatter}),i(this,{execCommand:p,queryCommandState:q,queryCommandValue:r,queryCommandSupported:u,addCommands:s,addCommand:t,addQueryStateHandler:v,addQueryValueHandler:w,hasCustomCommand:x}),s({"mceResetDesignMode,mceBeginUndoLevel":function(){},"mceEndUndoLevel,mceAddUndoLevel":function(){g.undoManager.add()},"Cut,Copy,Paste":function(a){var b,c=g.getDoc();try{y(a)}catch(a){b=n}if("paste"!==a||c.queryCommandEnabled(a)||(b=!0),b||!c.queryCommandSupported(a)){var d=g.translate("Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.");e.mac&&(d=d.replace(/Ctrl\+/g,"\u2318+")),g.notificationManager.open({text:d,type:"error"})}},unlink:function(){if(E.isCollapsed()){var a=g.do
 m.getParent(g.selection.getStart(),"a");return void(a&&g.dom.remove(a,!0))}F.remove("link")},"JustifyLeft,JustifyCenter,JustifyRight,JustifyFull,JustifyNone":function(a){var b=a.substring(7);"full"==b&&(b="justify"),h("left,center,right,justify".split(","),function(a){b!=a&&F.remove("align"+a)}),"none"!=b&&A("align"+b)},"InsertUnorderedList,InsertOrderedList":function(a){var b,c;y(a),b=D.getParent(E.getNode(),"ol,ul"),b&&(c=b.parentNode,/^(H[1-6]|P|ADDRESS|PRE)$/.test(c.nodeName)&&(B(),D.split(c,b),C()))},"Bold,Italic,Underline,Strikethrough,Superscript,Subscript":function(a){A(a)},"ForeColor,HiliteColor,FontName":function(a,b,c){A(a,c)},FontSize:function(a,b,c){var d,e;c>=1&&c<=7&&(e=l(I.font_size_style_values),d=l(I.font_size_classes),c=d?d[c-1]||c:e[c-1]||c),A(a,c)},RemoveF
 ormat:function(a){F.remove(a)},mceBlockQuote:function(){A("blockquote")},FormatBlock:function(a,b,c){return A(c||"p")},mceCleanup:function(){var a=E.getBookmark();g.setContent(g.getContent({cleanup:n}),{cleanup:n}),E.moveToBookmark(a)},mceRemoveNode:function(a,b,c){var d=c||E.getNode();d!=g.getBody()&&(B(),g.dom.remove(d,n),C())},mceSelectNodeDepth:function(a,b,c){var d=0;D.getParent(E.getNode(),function(a){if(1==a.nodeType&&d++==c)return E.select(a),o},g.getBody())},mceSelectNode:function(a,b,c){E.select(c)},mceInsertContent:function(a,b,c){f.insertAtCaret(g,c)},mceInsertRawHTML:function(a,b,c){E.setContent("tiny_mce_marker"),g.setContent(g.getContent().replace(/tiny_mce_marker/g,function(){return c}))},mceToggleFormat:function(a,b,c){A(c)},mceSetContent:function(a,b,c){g.setContent(c)},"Indent,Outdent":function(a){var b,c,d;b=I.indentation,c=/[a-z%]+$/i.exec(b),b=parseInt(b,10),q("InsertUnorderedList")||q("Inse
 rtOrderedList")?y(a):(I.forced_root_block||D.getParent(E.getNode(),D.isBlock)||F.apply("div"),h(E.getSelectedBlocks(),function(e){if("false"!==D.getContentEditable(e)&&"LI"!==e.nodeName){var f=g.getParam("indent_use_margin",!1)?"margin":"padding";f="TABLE"===e.nodeName?"margin":f,f+="rtl"==D.getStyle(e,"direction",!0)?"Right":"Left","outdent"==a?(d=Math.max(0,parseInt(e.style[f]||0,10)-b),D.setStyle(e,f,d?d+c:"")):(d=parseInt(e.style[f]||0,10)+b+c,D.setStyle(e,f,d))}}))},mceRepaint:function(){},InsertHorizontalRule:function(){g.execCommand("mceInsertContent",!1,"<hr />")},mceToggleVisualAid:function(){g.hasVisual=!g.hasVisual,g.addVisual()},mceReplaceContent:function(a,b,c){g.execCommand("mceInsertContent",!1,c.replace(/\{\$selection\}/g,E.getContent({format:"text"})))},mceInsertLink:fun
 ction(a,b,c){var d;"string"==typeof c&&(c={href:c}),d=D.getParent(E.getNode(),"a"),c.href=c.href.replace(" ","%20"),d&&c.href||F.remove("link"),c.href&&F.apply("link",c,d)},selectAll:function(){var a,c=D.getRoot();if(E.getRng().setStart){var d=D.getParent(E.getStart(),b.isContentEditableTrue);d&&(a=D.createRng(),a.selectNodeContents(d),E.setRng(a))}else a=E.getRng(),a.item||(a.moveToElementText(c),a.select())},"delete":function(){a.deleteCommand(g)},forwardDelete:function(){a.forwardDeleteCommand(g)},mceNewDocument:function(){g.setContent("")},InsertLineBreak:function(a,b,e){function f(){for(var a,b=new d(p,r),c=g.schema.getNonEmptyElements();a=b.next();)if(c[a.nodeName.toLowerCase()]||a.length>0)return!0}var h,i,j,k=e,l=E.getRng(!0);new c(D).normalize(l);var o=l.startOffset,p=l.startContainer;if(1==p.nodeType&&p.hasChildNodes()){var q=o>p.childNodes.length-1
 ;p=p.childNodes[Math.min(o,p.childNodes.length-1)]||p,o=q&&3==p.nodeType?p.nodeValue.length:0}var r=D.getParent(p,D.isBlock),s=r?r.nodeName.toUpperCase():"",t=r?D.getParent(r.parentNode,D.isBlock):null,u=t?t.nodeName.toUpperCase():"",v=k&&k.ctrlKey;"LI"!=u||v||(r=t,s=u),p&&3==p.nodeType&&o>=p.nodeValue.length&&(m||f()||(h=D.create("br"),l.insertNode(h),l.setStartAfter(h),l.setEndAfter(h),i=!0)),h=D.create("br"),l.insertNode(h);var w=D.doc.documentMode;return m&&"PRE"==s&&(!w||w<8)&&h.parentNode.insertBefore(D.doc.createTextNode("\r"),h),j=D.create("span",{},"&nbsp;"),h.parentNode.insertBefore(j,h),E.scrollIntoView(j),D.remove(j),i?(l.setStartBefore(h),l.setEndBefore(h)):(l.setStartAfter(h),l.setEndAfter(h)),E.setRng(l),g.undoManager.add(),n}}),s({"JustifyLeft,JustifyCenter,JustifyRight,JustifyFull":function(a){v
 ar b="align"+a.substring(7),c=E.isCollapsed()?[D.getParent(E.getNode(),D.isBlock)]:E.getSelectedBlocks(),d=j(c,function(a){return!!F.matchNode(a,b)});return k(d,n)!==-1},"Bold,Italic,Underline,Strikethrough,Superscript,Subscript":function(a){return z(a)},mceBlockQuote:function(){return z("blockquote")},Outdent:function(){var a;if(I.inline_styles){if((a=D.getParent(E.getStart(),D.isBlock))&&parseInt(a.style.paddingLeft,10)>0)return n;if((a=D.getParent(E.getEnd(),D.isBlock))&&parseInt(a.style.paddingLeft,10)>0)return n}return q("InsertUnorderedList")||q("InsertOrderedList")||!I.inline_styles&&!!D.getParent(E.getNode(),"BLOCKQUOTE")},"InsertUnorderedList,InsertOrderedList":function(a){var b=D.getParent(E.getNode(),"ul,ol");return b&&("insertunorderedlist"===a&&"UL"===b.tagName||"insertorderedlist"===a&&"OL"===b.tag
 Name)}},"state"),s({"FontSize,FontName":function(a){var b,c=0;return(b=D.getParent(E.getNode(),"span"))&&(c="fontsize"==a?b.style.fontSize:b.style.fontFamily.replace(/, /g,",").replace(/[\'\"]/g,"").toLowerCase()),c}},"value"),s({Undo:function(){g.undoManager.undo()},Redo:function(){g.undoManager.redo()}})}}),g("2d",["1u","26","23","5n","58","e","o"],function(a,b,c,d,e,f,g){var h=function(a,b){return a.dom.getParent(b,function(b){return"true"===a.dom.getContentEditable(b)})},i=function(b){return b.collapsed?a.from(f.getNode(b.startContainer,b.startOffset)).map(c.fromDom):a.none()},j=function(c,d){return i(d).bind(function(d){return e.isTableSection(d)?a.some(d):b.contains(c,d)===!1?a.some(c):a.none()})},k=function(a,b){j(c.fromDom(a.getBody()),b).bind(function(a){return d.firstPositionIn(a.dom())}).fold(function(
 ){a.selection.normalize()},function(b){a.selection.setRng(b.toRange())})},l=function(a){if(a.setActive)try{a.setActive()}catch(b){a.focus()}else a.focus()},m=function(a){var b,c,d,e=a.selection,f=a.settings.content_editable,i=a.getDoc(),j=a.getBody();return b=e.getRng(),b.item&&(c=b.item(0)),a.quirks.refreshContentEditable(),d=h(a,e.getNode()),a.$.contains(j,d)?(l(d),k(a,b),void n(a)):(f||(g.opera||l(j),a.getWin().focus()),(g.gecko||f)&&(f&&document.activeElement!==j&&a.selection.setRng(a.lastRng),l(j),k(a,b)),c&&c.ownerDocument===i&&(b=i.body.createControlRange(),b.addElement(c),b.select()),void n(a))},n=function(a){a.editorManager.setActive(a)},o=function(a,b){a.removed||(b?n(a):m(a))};return{focus:o}}),g("n",["1b","c","1d"],function(a,b,c){function d(a,b){return"selectionchange"==b?a.getDoc():!a.inline&&/^mouse|touch|click|contextmenu|drop|dragover|dragend/.test(b)?a.getDoc()
 .documentElement:a.settings.event_root?(a.eventRoot||(a.eventRoot=g.select(a.settings.event_root)[0]),a.eventRoot):a.getBody()}function e(a,b){function c(a){return!a.hidden&&!a.readonly}var e,h;if(a.delegates||(a.delegates={}),!a.delegates[b]&&!a.removed)if(e=d(a,b),a.settings.event_root){if(f||(f={},a.editorManager.on("removeEditor",function(){var b;if(!a.editorManager.activeEditor&&f){for(b in f)a.dom.unbind(d(a,b));f=null}})),f[b])return;h=function(d){for(var e=d.target,f=a.editorManager.get(),h=f.length;h--;){var i=f[h].getBody();(i===e||g.isChildOf(e,i))&&c(f[h])&&f[h].fire(b,d)}},f[b]=h,g.bind(e,b,h)}else h=function(d){c(a)&&a.fire(b,d)},g.bind(e,b,h),a.delegates[b]=h}var f,g=b.DOM,h={bindPendingEventDelegates:function(){var a=this;c.each(a._pendingNativeEvents,function(b){e(a,b)})},toggleNativeEvent:function(a,b){var c=this;"focus"!=a&&"blur"!=a&&(b?c.initialized?e(c,a):c._pendingNat
 iveEvents?c._pendingNativeEvents.push(a):c._pendingNativeEvents=[a]:c.initialized&&(c.dom.unbind(d(c,a),a,c.delegates[a]),delete c.delegates[a]))},unbindAllNativeEvents:function(){var a,b=this;if(b.delegates){for(a in b.delegates)b.dom.unbind(d(b,a),a,b.delegates[a]);delete b.delegates}b.inline||(b.getBody().onload=null,b.dom.unbind(b.getWin()),b.dom.unbind(b.getDoc())),b.dom.unbind(b.getBody()),b.dom.unbind(b.getContainer())}};return h=c.extend({},a,h)}),g("2l",["5"],function(a){var b=a.PluginManager,c=function(a,c){for(var d in b.urls){var e=b.urls[d]+"/plugin"+c+".js";if(e===a)return d}return null},d=function(a,b){var d=c(b,a.suffix);return d?"Failed to load plugin: "+d+" from url "+b:"Failed to load plugin url: "+b},e=function(a,b){a.notificationManager.open({type:"error",text:b})},f=function(a,b){a._skinLoaded?e(a,b):a.on("SkinLoaded",function(){e(a,b)})},g=function(a,b){f(a,"
 Failed to upload image: "+b)},h=function(a,b){f(a,d(a,b))},i=function(a){var b=window.console;b&&!window.test&&(b.error?b.error.apply(b,arguments):b.log.apply(b,arguments))};return{pluginLoadError:h,uploadError:g,displayError:f,initError:i}}),g("7e",["1","23","57","1z"],function(a,b,c,d){var e=function(d){return c.descendant(b.fromDom(d.getBody()),"*[data-mce-caret]").fold(a.constant(null),function(a){return a.dom()})},f=function(a){a.selection.setRng(a.selection.getRng())},g=function(a,b){b.hasAttribute("data-mce-caret")&&(d.showCaretContainerBlock(b),f(a),a.selection.scrollIntoView(b))},h=function(a,b){var c=e(a);if(c)return"compositionstart"===b.type?(b.preventDefault(),b.stopPropagation(),void g(c)):void(d.hasContent(c)&&g(a,c))},i=function(b){b.on("keyup compositionstart",a.curry(h,b))};return{setup:i}}),g("7o",["1c","1d",&
 quot;4i"],function(a,b,c){return function(c,d){function e(a,b){return a?a.replace(/\/$/,"")+"/"+b.replace(/^\//,""):b}function f(a,b,c,f){var g,h;g=new XMLHttpRequest,g.open("POST",d.url),g.withCredentials=d.credentials,g.upload.onprogress=function(a){f(a.loaded/a.total*100)},g.onerror=function(){c("Image upload failed due to a XHR Transport error. Code: "+g.status)},g.onload=function(){var a;return g.status<200||g.status>=300?void c("HTTP Error: "+g.status):(a=JSON.parse(g.responseText),a&&"string"==typeof a.location?void b(e(d.basePath,a.location)):void c("Invalid JSON: "+g.responseText))},h=new FormData,h.append("file",a.blob(),a.filename()),g.send(h)}function g(){return new a(function(a){a([])})}function h(a,b){return{url:b,blobInfo:a,status:!0}}function i(a,b){return{url:"",blobInfo:a,status:!1,error:b}}function j(a,c){b.each(p[a],function(a){a(c)}),delete p[a]
 }function k(b,d,e){return c.markPending(b.blobUri()),new a(function(a){var f,g,k=function(){};try{var l=function(){f&&(f.close(),g=k)},m=function(d){l(),c.markUploaded(b.blobUri(),d),j(b.blobUri(),h(b,d)),a(h(b,d))},n=function(d){l(),c.removeFailed(b.blobUri()),j(b.blobUri(),i(b,d)),a(i(b,d))};g=function(a){a<0||a>100||(f||(f=e()),f.progressBar.value(a))},d(b,m,n,g)}catch(c){a(i(b,c.message))}})}function l(a){return a===f}function m(b){var c=b.blobUri();return new a(function(a){p[c]=p[c]||[],p[c].push(a)})}function n(e,f){return e=b.grep(e,function(a){return!c.isUploaded(a.blobUri())}),a.all(b.map(e,function(a){return c.isPending(a.blobUri())?m(a):k(a,d.handler,f)}))}function o(a,b){return!d.url&&l(d.handler)?g():n(a,b)}var p={};
+return d=b.extend({credentials:!1,handler:f},d),{upload:o}}}),g("8a",["66"],function(a){var b=function(b){var c=a.getOrDie("requestAnimationFrame");c(b)},c=function(b){var c=a.getOrDie("atob");return c(b)};return{atob:c,requestAnimationFrame:b}}),g("82",["8a","1c"],function(a,b){function c(a){return new b(function(b,c){var d=function(){c("Cannot convert "+a+" to Blob. Resource might not exist or is inaccessible.")};try{var e=new XMLHttpRequest;e.open("GET",a,!0),e.responseType="blob",e.onload=function(){200==this.status?b(this.response):d()},e.onerror=d,e.send()}catch(a){d()}})}function d(a){var b,c;return a=decodeURIComponent(a).split(","),c=/data:([^;]+)/.exec(a[0]),c&&(b=c[1]),{type:b,data:a[1]}}function e(c){return new b(function(b){var e,f,g;c=d(c);try{e=a.atob(c.data)}catch(a){return void b(new Blob([]))}for(f=new Uint8Array(e.length),g=0;g<f.lengt
 h;g++)f[g]=e.charCodeAt(g);b(new Blob([f],{type:c.type}))})}function f(a){return 0===a.indexOf("blob:")?c(a):0===a.indexOf("data:")?e(a):null}function g(a){return new b(function(b){var c=new FileReader;c.onloadend=function(){b(c.result)},c.readAsDataURL(a)})}return{uriToBlob:f,blobToDataUri:g,parseDataUri:d}});g("7p",["1c","1h","4i","82","o"],function(a,b,c,d,e){var f=0,g=function(a){return(a||"blobid")+f++},h=function(a,b,c,e){var f,h;return 0===b.src.indexOf("blob:")?(h=a.getByUri(b.src),void(h?c({image:b,blobInfo:h}):d.uriToBlob(b.src).then(function(e){d.blobToDataUri(e).then(function(i){f=d.parseDataUri(i).data,h=a.create(g(),e,f),a.add(h),c({image:b,blobInfo:h})})},function(a){e(a)}))):(f=d.parseDataUri(b.src).data,h=a.findFirst(function(a){return a.base64()===f}),void(h?c({image:b,blobInfo:h}):d.uriToBlob(b.src).then(function(d){h=a.create(g(),d,f),a.add(h),c({image:b,blobInfo:h
 })},function(a){e(a)})))},i=function(a){return a?a.getElementsByTagName("img"):[]};return function(d,f){function g(g,k){var l,m;return k||(k=c.constant(!0)),l=b.filter(i(g),function(a){var b=a.src;return!!e.fileApi&&(!a.hasAttribute("data-mce-bogus")&&(!a.hasAttribute("data-mce-placeholder")&&(!(!b||b==e.transparentSrc)&&(0===b.indexOf("blob:")?!d.isUploaded(b):0===b.indexOf("data:")&&k(a)))))}),m=b.map(l,function(b){var c;return j[b.src]?new a(function(a){j[b.src].then(function(c){return"string"==typeof c?c:void a({image:b,blobInfo:c.blobInfo})})}):(c=new a(function(a,c){h(f,b,a,c)}).then(function(a){return delete j[a.image.src],a})["catch"](function(a){return delete j[b.src],a}),j[b.src]=c,c)}),a.all(m)}var j={};return{findAll:g}}});g("83",["66"],function(a){var b=function(){return a.getOrDie("URL")},c=function(a){return b().createObjectURL(a)
 },d=function(a){b().revokeObjectURL(a)};return{createObjectURL:c,revokeObjectURL:d}}),g("2j",[],function(){var a=0,b=function(){var a=function(){return Math.round(4294967295*Math.random()).toString(36)},b=(new Date).getTime();return"s"+b.toString(36)+a()+a()+a()},c=function(c){return c+a++ +b()};return{uuid:c}}),g("7q",["83","1h","4i","2j"],function(a,b,c,d){return function(){function e(a){var b={"image/jpeg":"jpg","image/jpg":"jpg","image/gif":"gif","image/png":"png"};return b[a.toLowerCase()]||"dat"}function f(a,b,c,d){return g("object"==typeof a?a:{id:a,name:d,blob:b,base64:c})}function g(b){var c,f;if(!b.blob||!b.base64)throw"blob and base64 representations of the image are required for BlobInfo to be created";return c=b.id||d.uuid("blobid"),f=b.name||c,{id:o(c),name:o(f),filename:o(f+".
 "+e(b.blob.type)),blob:o(b.blob),base64:o(b.base64),blobUri:o(b.blobUri||a.createObjectURL(b.blob)),uri:o(b.uri)}}function h(a){i(a.id())||n.push(a)}function i(a){return j(function(b){return b.id()===a})}function j(a){return b.filter(n,a)[0]}function k(a){return j(function(b){return b.blobUri()==a})}function l(c){n=b.filter(n,function(b){return b.blobUri()!==c||(a.revokeObjectURL(b.blobUri()),!1)})}function m(){b.each(n,function(b){a.revokeObjectURL(b.blobUri())}),n=[]}var n=[],o=c.constant;return{create:f,add:h,get:i,getByUri:k,findFirst:j,removeByUri:l,destroy:m}}}),g("7r",[],function(){return function(){function a(a,b){return{status:a,resultUri:b}}function b(a){return a in l}function c(a){var b=l[a];return b?b.resultUri:null}function d(a){return!!b(a)&&l[a].status===j}function e(a){return!!b(a)&&l[a].status===k}function f(b){l[b]=a(j,null)}function g(b,c){l[b]=a(k,c)}function h(a){delete l[a]}function i(){l={}}var j=1,k=2,l={};return{hasBlobUri:b,ge
 tResultUri:c,isPending:d,isUploaded:e,markPending:f,markUploaded:g,removeFailed:h,destroy:i}}}),g("7f",["1h","7o","7p","7q","7r","2l"],function(a,b,c,d,e,f){return function(g){function h(a){return function(b){return g.selection?a(b):[]}}function i(){return"?"+(new Date).getTime()}function j(a,b,c){var d=0;do d=a.indexOf(b,d),d!==-1&&(a=a.substring(0,d)+c+a.substr(d+b.length),d+=c.length-b.length+1);while(d!==-1);return a}function k(a,b,c){return a=j(a,'src="'+b+'"','src="'+c+'"'),a=j(a,'data-mce-src="'+b+'"','data-mce-src="'+c+'"')}function l(b,c){a.each(g.undoManager.data,function(d){"fragmented"===d.type?d.fragments=a.map(d.fragments,function(a){return k(a,b,c)}):d.content=k(d.content,b,c)})}function m(){return g.notificationManager.open({text:g.translate("Image uploading..."),type:"info",timeout:-1,progressBar:!0})}function 
 n(a,b){w.removeByUri(a.src),l(a.src,b),g.$(a).attr({src:x.images_reuse_filename?b+i():b,"data-mce-src":g.convertURL(b,"src")})}function o(c){return u||(u=new b(y,{url:x.images_upload_url,basePath:x.images_upload_base_path,credentials:x.images_upload_credentials,handler:x.images_upload_handler})),r().then(h(function(b){var d;return d=a.map(b,function(a){return a.blobInfo}),u.upload(d,m).then(h(function(d){var e=a.map(d,function(a,c){var d=b[c].image;return a.status&&g.settings.images_replace_blob_uris!==!1?n(d,a.url):a.error&&f.uploadError(g,a.error),{element:d,status:a.status}});return c&&c(e),e}))}))}function p(a){if(x.automatic_uploads!==!1)return o(a)}function q(a){return!x.images_dataimg_filter||x.images_dataimg_filter(a)}function r(){return v||(v=new c(y,w)),v.findAll(g.getBody(),q).then(h(function(b){return b=a.filter(b,function(a){return"string"!=typeof a||(f.displayError(g,a),!1)}),a.each(b,function(a){l(a.image.src,a.blo
 bInfo.blobUri()),a.image.src=a.blobInfo.blobUri(),a.image.removeAttribute("data-mce-src")}),b}))}function s(){w.destroy(),y.destroy(),v=u=null}function t(b){return b.replace(/src="(blob:[^"]+)"/g,function(b,c){var d=y.getResultUri(c);if(d)return'src="'+d+'"';var e=w.getByUri(c);return e||(e=a.reduce(g.editorManager.get(),function(a,b){return a||b.editorUpload&&b.editorUpload.blobCache.getByUri(c)},null)),e?'src="data:'+e.blob().type+";base64,"+e.base64()+'"':b})}var u,v,w=new d,x=g.settings,y=new e;return g.on("setContent",function(){g.settings.automatic_uploads!==!1?p():r()}),g.on("RawSaveContent",function(a){a.content=t(a.content)}),g.on("getContent",function(a){a.source_view||"raw"==a.format||(a.content=t(a.content))}),g.on("PostRender",function(){g.parser.addNodeFilter("img",function(b){a.each(b,function(a){var b=a.attr("src");if(!w.getByUri(b)){va
 r c=y.getResultUri(b);c&&a.attr("src",c)}})})}),{blobCache:w,uploadImages:o,uploadImagesAuto:p,scanForImages:r,destroy:s}}}),g("7g",["1"],function(a){var b=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n=a.settings,o=a.dom,p=a.selection,q=a.schema,r=q.getBlockElements(),s=p.getStart(),t=a.getBody(),u=-16777215;if(m=n.forced_root_block,s&&1===s.nodeType&&m){for(;s&&s!==t;){if(r[s.nodeName])return;s=s.parentNode}if(b=p.getRng(),b.setStart){c=b.startContainer,d=b.startOffset,e=b.endContainer,f=b.endOffset;try{j=a.getDoc().activeElement===t}catch(a){}}else b.item&&(s=b.item(0),b=a.getDoc().body.createTextRange(),b.moveToElementText(s)),j=b.parentElement().ownerDocument===a.getDoc(),k=b.duplicate(),k.collapse(!0),d=k.move("character",u)*-1,k.collapsed||(k=b.duplicate(),k.collapse(!1),f=k.move("character",u)*-1-d);for(s=t.firstChild,l=t.nodeName.toLowerCase();s;)if((3===s.nodeType||1==s.nodeType&&!
 r[s.nodeName])&&q.isValidChild(l,m.toLowerCase())){if(3===s.nodeType&&0===s.nodeValue.length){h=s,s=s.nextSibling,o.remove(h);continue}g||(g=o.create(m,a.settings.forced_root_block_attrs),s.parentNode.insertBefore(g,s),i=!0),h=s,s=s.nextSibling,g.appendChild(h)}else g=null,s=s.nextSibling;if(i&&j){if(b.setStart)b.setStart(c,d),b.setEnd(e,f),p.setRng(b);else try{b=a.getDoc().body.createTextRange(),b.moveToElementText(t),b.collapse(!0),b.moveStart("character",d),f>0&&b.moveEnd("character",f),b.select()}catch(a){}a.nodeChanged()}}},c=function(c){c.settings.forced_root_block&&c.on("NodeChange",a.curry(b,c))};return{setup:c}}),g("89",["1h","21","4k"],function(a,b,c){function d(e){function f(b){return a.map(b,function(a){return a=c.clone(a),a.node=e,a})}if(a.isArray(e))return a.reduce(e,function(a,b){return a.concat(d(b))},[]);if(b.isElement(e))return f(e.getClientRects());if(b
 .isText(e)){var g=e.ownerDocument.createRange();return g.setStart(e,0),g.setEnd(e,e.data.length),f(g.getClientRects())}}return{getClientRects:d}}),g("7y",["4i","1h","21","89","4k","62","4j"],function(a,b,c,d,e,f,g){function h(a,b){return Math.abs(a.left-b)}function i(a,b){return Math.abs(a.right-b)}function j(a,c){function d(a,b){return a>=b.left&&a<=b.right}return b.reduce(a,function(a,b){var e,f;return e=Math.min(h(a,c),i(a,c)),f=Math.min(h(b,c),i(b,c)),d(c,b)?b:d(c,a)?a:f==e&&p(b.node)?b:f<e?b:a})}function k(a,b,c,d){for(;d=q(d,a,g.isEditableCaretCandidate,b);)if(c(d))return}function l(a,c){function f(a,e){var f;return f=b.filter(d.getClientRects(e),function(b){return!a(b,c)}),g=g.concat(f),0===f.length}var g=[];return g.push(c),k(-1,a,r(f,e.isAbove),c.node),k(1,a,r(f,e.isBelow),c.node),g}function m(a){return b.filter(b.toArray(a.getElementsByTagName("*")),p)}functio
 n n(a,b){return{node:a.node,before:h(a,b)<i(a,b)}}function o(a,c,e){var f,g;return f=d.getClientRects(m(a)),f=b.filter(f,function(a){return e>=a.top&&e<=a.bottom}),g=j(f,c),g&&(g=j(l(a,g),c),g&&p(g.node))?n(g,c):null}var p=c.isContentEditableFalse,q=f.findNode,r=a.curry;return{findClosestClientRect:j,findLineNodeRects:l,closestCaret:o}}),g("8b",["4i","1h","89","4j","62","5j","20","4k"],function(a,b,c,d,e,f,g,h){function i(a,b,c,f){for(;f=e.findNode(f,a,d.isEditableCaretCandidate,b);)if(c(f))return}function j(a,d,e,f,g,h){function j(f){var h,i,j;for(j=c.getClientRects(f),a==-1&&(j=j.reverse()),h=0;h<j.length;h++)if(i=j[h],!e(i,l)){if(n.length>0&&d(i,b.last(n))&&m++,i.line=m,g(i))return!0;n.push(i)}}var k,l,m=0,n=[];return(l=b.last(h.getClientRects()))?(k=h.getNode(),j(k),i(a,f,j,k),n):n}function k(a,b){return b.line>a}function l(a
 ,b){return b.line===a}function m(a,c,d,e){function i(c){return 1==a?b.last(c.getClientRects()):b.last(c.getClientRects())}var j,k,l,m,n,o,p=new f(c),q=[],r=0;1==a?(j=p.next,k=h.isBelow,l=h.isAbove,m=g.after(e)):(j=p.prev,k=h.isAbove,l=h.isBelow,m=g.before(e)),o=i(m);do if(m.isVisible()&&(n=i(m),!l(n,o))){if(q.length>0&&k(n,b.last(q))&&r++,n=h.clone(n),n.position=m,n.line=r,d(n))return q;q.push(n)}while(m=j(m));return q}var n=a.curry,o=n(j,-1,h.isAbove,h.isBelow),p=n(j,1,h.isBelow,h.isAbove);return{upUntil:o,downUntil:p,positionsUntil:m,isAboveLine:n(k),isLine:n(l)}}),g("7z",["20","62","21","4i"],function(a,b,c,d){var e=c.isContentEditableTrue,f=c.isContentEditableFalse,g=function(a,b,c,d){return b._selectionOverrides.showCaret(a,c,d)},h=function(a){var b=a.ownerDocument.createRange();return b.selectNode(a),b},i=function(a,b){var c;return c=a.fire("BeforeObjectSelected",{target:b}),c.isDefaultPreve
 nted()?null:h(b)},j=function(c,h){var i,j;return h=b.normalizeRange(1,c.getBody(),h),i=a.fromRangeStart(h),f(i.getNode())?g(1,c,i.getNode(),!i.isAtEnd()):f(i.getNode(!0))?g(1,c,i.getNode(!0),!1):(j=c.dom.getParent(i.getNode(),d.or(f,e)),f(j)?g(1,c,j,!1):null)},k=function(a,b){var c;return b&&b.collapsed?(c=j(a,b),c?c:b):b};return{showCaret:g,selectNode:i,renderCaretAtRange:j,renderRangeCaret:k}}),g("84",["1z","20","62","5j","7y","8b","21","e","o","7z","1h","4i"],function(a,b,c,d,e,f,g,h,i,j,k,l){var m=g.isContentEditableFalse,n=h.getSelectedNode,o=c.isAfterContentEditableFalse,p=c.isBeforeContentEditableFalse,q=function(a,b){for(;b=a(b);)if(b.isVisible())return b;return b},r=function(a,b){var d=c.isInSameBlock(a,b);return!(d||!g.isBr(a.getNode()))||d},s=function(b){return a.isCaretContainerBlock(b.startContainer)},t=function(a,d,e){return e=c.norm
 alizeRange(a,d,e),a===-1?b.fromRangeStart(e):b.fromRangeEnd(e)},u=function(a,b,c,d,e){var f,g,h,i;return!e.collapsed&&(f=n(e),m(f))?j.showCaret(a,b,f,a===-1):(i=s(e),g=t(a,b.getBody(),e),d(g)?j.selectNode(b,g.getNode(a===-1)):(g=c(g))?d(g)?j.showCaret(a,b,g.getNode(a===-1),1===a):(h=c(g),d(h)&&r(g,h)?j.showCaret(a,b,h.getNode(a===-1),1===a):i?j.renderRangeCaret(b,g.toRange()):null):i?e:null)},v=function(a,b,c,d){var g,h,i,l,q,r,s,u,v;if(v=n(d),g=t(a,b.getBody(),d),h=c(b.getBody(),f.isAboveLine(1),g),i=k.filter(h,f.isLine(1)),q=k.last(g.getClientRects()),p(g)&&(v=g.getNode()),o(g)&&(v=g.getNode(!0)),!q)return null;if(r=q.left,l=e.findClosestClientRect(i,r),l&&m(l.node))return s=Math.abs(r-l.left),u=Math.abs(r-l.right),j.showCaret(a,b,l.node,s<u);if(v){var w=f.positionsUntil(a,b.getBody(),f.isAboveLine(1),v);if(l=e.findClosestClientRect(k.filter(w,f.isLine(1)),r))return j.renderRangeCaret(b,l.position.toRange());if(l=k.last(k.filter(w,f.isLin
 e(0))))return j.renderRangeCaret(b,l.position.toRange())}},w=function(a){var b=a.dom.create(a.settings.forced_root_block);return(!i.ie||i.ie>=11)&&(b.innerHTML='<br data-mce-bogus="1">'),b},x=function(a,c,e){var f,g,h,i=new d(a.getBody()),j=l.curry(q,i.next),k=l.curry(q,i.prev);if(e.collapsed&&a.settings.forced_root_block){if(f=a.dom.getParent(e.startContainer,"PRE"),!f)return;g=1===c?j(b.fromRangeStart(e)):k(b.fromRangeStart(e)),g||(h=w(a),1===c?a.$(f).after(h):a.$(f).before(h),a.selection.select(h,!0),a.selection.collapse())}},y=function(a,b){var c,e=new d(a.getBody()),f=l.curry(q,e.next),g=l.curry(q,e.prev),h=b?1:-1,i=b?f:g,j=b?p:o,k=a.selection.getRng();return(c=u(h,a,i,j,k))?c:(c=x(a,h,k),c?c:null)},z=function(a,b){var c,d=b?1:-1,e=b?f.downUntil:f.upUntil,g=a.selection.getRng();return(c=v(d,a,e,g))?c:(c=x(a,d,g),c?c:null)},A=function(a,b){return function(){var c=y(a,b);return!!c&&(a.selection.setRng(c),!0)}},B=function(a,b){r
 eturn function(){var c=z(a,b);return!!c&&(a.selection.setRng(c),!0)}};return{moveH:A,moveV:B}}),g("8c",["2k","3","4"],function(a,b,c){var d=function(a,b){return b},e=function(b,c){var d=a.isObject(b)&&a.isObject(c);return d?g(b,c):c},f=function(a){return function(){for(var d=new b(arguments.length),e=0;e<d.length;e++)d[e]=arguments[e];if(0===d.length)throw new c("Can't merge zero objects");for(var f={},g=0;g<d.length;g++){var h=d[g];for(var i in h)h.hasOwnProperty(i)&&(f[i]=a(f[i],h[i]))}return f}},g=f(e),h=f(d);return{deepMerge:g,merge:h}}),g("85",["1t","1","8c"],function(a,b,c){var d=function(d){return a.map(d,function(a){return c.merge({shiftKey:!1,altKey:!1,ctrlKey:!1,metaKey:!1,keyCode:0,action:b.noop},a)})},e=function(a,b){return b.keyCode===a.keyCode&&b.shiftKey===a.shiftKey&&b.altKey===a.altKey&&b.ctrlKey===a.ctrlKey&&b.metaK
 ey===a.metaKey},f=function(b,c){return a.bind(d(b),function(a){return e(a,c)?[a]:[]})},g=function(a){var b=Array.prototype.slice.call(arguments,1);return function(){return a.apply(null,b)}},h=function(b,c){return a.find(f(b,c),function(a){return a.action()})};return{match:f,action:g,execute:h}}),g("7s",["6t","84","85","1f"],function(a,b,c,d){var e=function(e,f,g){c.execute([{keyCode:d.RIGHT,action:b.moveH(e,!0)},{keyCode:d.LEFT,action:b.moveH(e,!1)},{keyCode:d.UP,action:b.moveV(e,!1)},{keyCode:d.DOWN,action:b.moveV(e,!0)},{keyCode:d.RIGHT,action:a.move(e,f,!0)},{keyCode:d.LEFT,action:a.move(e,f,!1)}],g).each(function(a){g.preventDefault()})},f=function(a,b){a.on("keydown",function(c){c.isDefaultPrevented()===!1&&e(a,b,c)})};return{setup:f}}),g("7t",["5d","5e","5f","5h","85","1f"],function(a,b,c,d,e,f){var g=function(g,h,i){e.execute([{keyCode:f.BA
 CKSPACE,action:e.action(c.backspaceDelete,g,!1)},{keyCode:f.DELETE,action:e.action(c.backspaceDelete,g,!0)},{keyCode:f.BACKSPACE,action:e.action(d.backspaceDelete,g,h,!1)},{keyCode:f.DELETE,action:e.action(d.backspaceDelete,g,h,!0)},{keyCode:f.BACKSPACE,action:e.action(b.backspaceDelete,g,!1)},{keyCode:f.DELETE,action:e.action(b.backspaceDelete,g,!0)},{keyCode:f.BACKSPACE,action:e.action(a.backspaceDelete,g,!1)},{keyCode:f.DELETE,action:e.action(a.backspaceDelete,g,!0)}],i).each(function(a){i.preventDefault()})},h=function(a,b){e.execute([{keyCode:f.BACKSPACE,action:e.action(c.paddEmptyElement,a)},{keyCode:f.DELETE,action:e.action(c.paddEmptyElement,a)}],b)},i=function(a,b){a.on("keydown",function(c){c.isDefaultPrevented()===!1&&g(a,b,c)}),a.on("keyup",function(b){b.isDefaultPrevented()===!1&&h(a,b)})};return{setup:i}}),g("86",["1z","21","e","j","22","1d"],function(a,b,c,d,e,f){
 var g=function(a){return a&&"A"===a.nodeName&&0===f.trim(e.trim(a.innerText||a.textContent)).length},h=function(a){return a&&/^(TD|TH|CAPTION)$/.test(a.nodeName)},i=function(a,b){return a.firstChild&&a.firstChild.nodeName==b},j=function(a,b){return a&&a.parentNode&&a.parentNode.nodeName===b},k=function(a){a.innerHTML='<br data-mce-bogus="1">'},l=function(a,b){return a.nodeName===b||a.previousSibling&&a.previousSibling.nodeName===b},m=function(a){return a&&/^(OL|UL|LI)$/.test(a.nodeName)},n=function(a){return m(a)&&m(a.parentNode)},o=function(a,b){return b&&a.isBlock(b)&&!/^(TD|TH|CAPTION|FORM)$/.test(b.nodeName)&&!/^(fixed|absolute)/i.test(b.style.position)&&"true"!==a.getContentEditable(b)},p=function(a,b,c){var d,e=c,f=[];if(e){for(;e=e.firstChild;){if(a.isBlock(e))return;1!=e.nodeType||b[e.nodeName.toLowerCase()]||f.push(e)}for(d=f.length;d--
 ;)e=f[d],!e.hasChildNodes()||e.firstChild==e.lastChild&&""===e.firstChild.nodeValue?a.remove(e):g(e)&&a.remove(e)}},q=function(a,c,d){return b.isText(c)===!1?d:a?1===d&&c.data.charAt(d-1)===e.ZWSP?0:d:d===c.data.length-1&&c.data.charAt(d)===e.ZWSP?c.data.length:d},r=function(a){var b=a.cloneRange();return b.setStart(a.startContainer,q(!0,a.startContainer,a.startOffset)),b.setEnd(a.endContainer,q(!1,a.endContainer,a.endOffset)),b},s=function(a){for(;a;){if(1===a.nodeType||3===a.nodeType&&a.data&&/[\r\n\s]/.test(a.data))return a;a=a.nextSibling}},t=function(a,b){a.execCommand("InsertLineBreak",!1,b)},u=function(a){do 3===a.nodeType&&(a.nodeValue=a.nodeValue.replace(/^[\r\n]+/,"")),a=a.firstChild;while(a)},v=function(a,b){var c,d,e=a.getRoot();for(c=b;c!==e&&"false"!==a.getContentEditable(c);)"true"===a.getContentEditable(c)&&(d=c),c=c.parentNode;return c!==e?d:e},w
 =function(a,b){var c=a.settings.forced_root_block;c&&c.toLowerCase()===b.tagName.toLowerCase()&&a.dom.setAttribs(b,a.settings.forced_root_block_attrs)},x=function(a,b,c,d,e){var f,g,i,j,k,l,m=b||"P",n=a.dom,p=v(n,d);if(g=n.getParent(d,n.isBlock),!g||!o(n,g)){if(g=g||p,l=g==a.getBody()||h(g)?g.nodeName.toLowerCase():g.parentNode.nodeName.toLowerCase(),!g.hasChildNodes())return f=n.create(m),w(a,f),g.appendChild(f),c.setStart(f,0),c.setEnd(f,0),f;for(j=d;j.parentNode!=g;)j=j.parentNode;for(;j&&!n.isBlock(j);)i=j,j=j.previousSibling;if(i&&a.schema.isValidChild(l,m.toLowerCase())){for(f=n.create(m),w(a,f),i.parentNode.insertBefore(f,i),j=i;j&&!n.isBlock(j);)k=j.nextSibling,f.appendChild(j),j=k;c.setStart(d,e),c.setEnd(d,e)}}return d},y=function(a,b){var c;b.normalize(),c=b.lastChild,c&&!/^(left|right)$/gi.test(a.getStyle(c,"float",!0))||a.add(b,"br")},z=function(a){var b=a.parentNode;return/^(LI|DT|DD)$/.test(
 b.nodeName)?b:a},A=function(a,b,c){for(var d=a[c?"firstChild":"lastChild"];d&&1!=d.nodeType;)d=d[c?"nextSibling":"previousSibling"];return d===b},B=function(b,e){function f(a){var b,c,e,f,g=a,h=S.getMoveCaretBeforeOnEnterElements();if(a){if(/^(LI|DT|DD)$/.test(a.nodeName)){var i=s(a.firstChild);i&&/^(UL|OL|DL)$/.test(i.nodeName)&&a.insertBefore(P.doc.createTextNode("\xa0"),a.firstChild)}if(e=P.createRng(),a.normalize(),a.hasChildNodes()){for(b=new d(a,a);c=b.current();){if(3==c.nodeType){e.setStart(c,0),e.setEnd(c,0);break}if(h[c.nodeName.toLowerCase()]){e.setStartBefore(c),e.setEndBefore(c);break}g=c,c=b.next()}c||(e.setStart(g,0),e.setEnd(g,0))}else"BR"==a.nodeName?a.nextSibling&&P.isBlock(a.nextSibling)?(e.setStartBefore(a),e.setEndBefore(a)):(e.setStartAfter(a),e.setEndAfter(a)):(e.setStart(a,0),e.setEnd(a,0));Q.setRng(e),P.remove(f),Q.scrollIntoView(a)}}function g(a){var c,d,e,f=E,g=S.ge
 tTextInlineElements();if(a||"TABLE"==L||"HR"==L?(c=P.create(a||N),w(b,c)):c=G.cloneNode(!1),e=c,R.keep_styles===!1)P.setAttrib(c,"style",null),P.setAttrib(c,"class",null);else do if(g[f.nodeName]){if("_mce_caret"==f.id)continue;d=f.cloneNode(!1),P.setAttrib(d,"id",""),c.hasChildNodes()?(d.appendChild(c.firstChild),c.appendChild(d)):(e=d,c.appendChild(d))}while((f=f.parentNode)&&f!=D);return k(e),c}function h(a){var b,c,e,f;if(f=q(a,E,F),3==E.nodeType&&(a?f>0:f<E.nodeValue.length))return!1;if(E.parentNode==G&&O&&!a)return!0;if(a&&1==E.nodeType&&E==G.firstChild)return!0;if(l(E,"TABLE")||l(E,"HR"))return O&&!a||!O&&a;for(b=new d(E,G),3==E.nodeType&&(a&&0===f?b.prev():a||f!=E.nodeValue.length||b.next());c=b.current();){if(1===c.nodeType){if(!c.getAttribute("data-mce-bogus")&&(e=c.nodeName.toLower
 Case(),T[e]&&"br"!==e))return!1}else if(3===c.nodeType&&!/^[ \t\r\n]*$/.test(c.nodeValue))return!1;a?b.prev():b.next()}return!0}function m(){K!=b.getBody()&&(n(K)&&(N="LI"),I=N?g(N):P.create("BR"),A(K,G,!0)&&A(K,G,!1)?j(K,"LI")?P.insertAfter(I,z(K)):P.replace(I,K):A(K,G,!0)?j(K,"LI")?(P.insertAfter(I,z(K)),I.appendChild(P.doc.createTextNode(" ")),I.appendChild(K)):K.parentNode.insertBefore(I,K):A(K,G,!1)?P.insertAfter(I,z(K)):(K=z(K),C=U.cloneRange(),C.setStartAfter(G),C.setEndAfter(K),J=C.extractContents(),"LI"===N&&i(J,"LI")?(I=J.firstChild,P.insertAfter(J,K)):(P.insertAfter(J,K),P.insertAfter(I,K))),P.remove(G),f(I))}function B(){I=/^(H[1-6]|PRE|FIGURE)$/.test(L)&&"HGROUP"!=M?g(N):g(),R.end_container_on_empty_block&&o(P,K)&&P.isEmpty(G)?I=P.split(K,G):P.insertAfter(I,G),f(I)}var C,D,E,F,G,H,I,J,K,L,M,N,O,P=b.dom,Q=b.sele
 ction,R=b.settings,S=b.schema,T=S.getNonEmptyElements(),U=b.selection.getRng();if(new c(P).normalize(U),E=U.startContainer,F=U.startOffset,N=(R.force_p_newlines?"p":"")||R.forced_root_block,N=N?N.toUpperCase():"",H=e.shiftKey,1==E.nodeType&&E.hasChildNodes()&&(O=F>E.childNodes.length-1,E=E.childNodes[Math.min(F,E.childNodes.length-1)]||E,F=O&&3==E.nodeType?E.nodeValue.length:0),D=v(P,E)){if(!P.isBlock(D)&&D!=P.getRoot())return void(N&&!H||t(b,e));if((N&&!H||!N&&H)&&(E=x(b,N,U,E,F)),G=P.getParent(E,P.isBlock),K=G?P.getParent(G.parentNode,P.isBlock):null,L=G?G.nodeName.toUpperCase():"",M=K?K.nodeName.toUpperCase():"","LI"!=M||e.ctrlKey||(G=K,K=K.parentNode,L=M),/^(LI|DT|DD)$/.test(L)){if(!N&&H)return void t(b,e);if(P.isEmpty(G))return void m()}if("PRE"==L&&R.br_in_pre!==!1){if(!H)return void t(b,e)}else if(!N&&!H&&&quo
 t;LI"!=L||N&&H)return void t(b,e);N&&G===b.getBody()||(N=N||"P",a.isCaretContainerBlock(G)?(I=a.showCaretContainerBlock(G),P.isEmpty(G)&&k(G),f(I)):h()?B():h(!0)?(I=G.parentNode.insertBefore(g(),G),f(l(G,"HR")?I:G)):(C=r(U).cloneRange(),C.setEndAfter(G),J=C.extractContents(),u(J),I=J.firstChild,P.insertAfter(J,G),p(P,T,I),y(P,G),P.isEmpty(G)&&k(G),I.normalize(),P.isEmpty(I)?(P.remove(I),B()):f(I)),P.setAttrib(I,"id",""),b.fire("NewBlock",{newBlock:I}))}};return{insert:B}}),g("7u",["86","1f"],function(a,b){var c=function(a){a.typing&&(a.typing=!1,a.add())},d=function(b,d){d.isDefaultPrevented()||(d.preventDefault(),c(b.undoManager),b.undoManager.transact(function(){b.selection.isCollapsed()===!1&&b.execCommand("Delete"),a.insert(b,d)}))},e=function(a){a.on("keydown",function(c){c.keyCode===b.ENTER&&d(a,c)})};return{setup:e}})
 ,g("87",["1","20","21","6s","6u"],function(a,b,c,d,e){var f=function(a,b){return j(a)&&c.isText(b.container())},g=function(a,b){var c=b.container(),d=b.offset();c.insertData(d,"\xa0"),a.selection.setCursorLocation(c,d+1)},h=function(a,b,c){return!!f(c,b)&&(g(a,b),!0)},i=function(c){var f=a.curry(e.isInlineTarget,c),g=b.fromRangeStart(c.selection.getRng()),i=d.readLocation(f,c.getBody(),g);return i.map(a.curry(h,c,g)).getOr(!1)},j=function(b){return b.fold(a.constant(!1),a.constant(!0),a.constant(!0),a.constant(!1))},k=function(a){return!!a.selection.isCollapsed()&&i(a)};return{insertAtSelection:k}}),g("7v",["87","85","1f"],function(a,b,c){var d=function(d,e){b.execute([{keyCode:c.SPACEBAR,action:b.action(a.insertAtSelection,d)}],e).each(function(a){e.preventDefault()})},e=function(a){a.on("keydown",function(b){b.isDefaultPrevented()===!1&amp
 ;&d(a,b)})};return{setup:e}}),g("7h",["7s","6t","7t","7u","7v"],function(a,b,c,d,e){var f=function(f){var g=b.setupSelectedState(f);a.setup(f,g),c.setup(f,g),d.setup(f),e.setup(f)};return{setup:f}}),g("7i",["e","o","14"],function(a,b,c){return function(d){function e(a){var b,c;if(c=d.$(a).parentsUntil(d.getBody()).add(a),c.length===g.length){for(b=c.length;b>=0&&c[b]===g[b];b--);if(b===-1)return g=c,!0}return g=c,!1}var f,g=[];"onselectionchange"in d.getDoc()||d.on("NodeChange Click MouseUp KeyUp Focus",function(b){var c,e;c=d.selection.getRng(),e={startContainer:c.startContainer,startOffset:c.startOffset,endContainer:c.endContainer,endOffset:c.endOffset},"nodechange"!=b.type&&a.compareRanges(e,f)||d.fire("SelectionChange"),f=e}),d.on("contextmenu",function(){d.fire("SelectionChange")}),d.on("Selec
 tionChange",function(){var a=d.selection.getStart(!0);!a||!b.range&&d.selection.isCollapsed()||!e(a)&&d.dom.isChildOf(a,d.getBody())&&d.nodeChanged({selectionChange:!0})}),d.on("MouseUp",function(a){a.isDefaultPrevented()||("IMG"==d.selection.getNode().nodeName?c.setEditorTimeout(d,function(){d.nodeChanged()}):d.nodeChanged())}),this.nodeChanged=function(a){var b,c,e,f=d.selection;d.initialized&&f&&!d.settings.disable_nodechange&&!d.readonly&&(e=d.getBody(),b=f.getStart(!0)||e,b.ownerDocument==d.getDoc()&&d.dom.isChildOf(b,e)||(b=e),c=[],d.dom.getParent(b,function(a){return a===e||void c.push(a)}),a=a||{},a.element=b,a.parents=c,d.fire("NodeChange",a))}}}),g("88",[],function(){var a=function(a){var b,c,d,e;return e=a.getBoundingClientRect(),b=a.ownerDocument,c=b.documentElement,d=b.defaultView,{top:e.top+d.pageYOffset-c.clientTop,left:e.left+d.pageXOffset-c.clientLeft}},b=fun
 ction(b){return b.inline?a(b.getBody()):{left:0,top:0}},c=function(a){var b=a.getBody();return a.inline?{left:b.scrollLeft,top:b.scrollTop}:{left:0,top:0}},d=function(a){var b=a.getBody(),c=a.getDoc().documentElement,d={left:b.scrollLeft,top:b.scrollTop},e={left:b.scrollLeft||c.scrollLeft,top:b.scrollTop||c.scrollTop};return a.inline?d:e},e=function(b,c){if(c.target.ownerDocument!==b.getDoc()){var e=a(b.getContentAreaContainer()),f=d(b);return{left:c.pageX-e.left+f.left,top:c.pageY-e.top+f.top}}return{left:c.pageX,top:c.pageY}},f=function(a,b,c){return{pageX:c.left-a.left+b.left,pageY:c.top-a.top+b.top}},g=function(a,d){return f(b(a),c(a),e(a,d))};return{calc:g}}),g("7w",["21","1h","4i","14","c","88"],function(a,b,c,d,e,f){var g=a.isContentEditableFalse,h=a.isContentEditableTrue,i=function(a,b){return g(b)&&b!==a},j=function(a,b,c){return b!==c&&!a.dom.isChildOf(b,c)&&!g(b)},k=function(a){v
 ar b=a.cloneNode(!0);return b.removeAttribute("data-mce-selected"),b},l=function(a,b,c,d){var e=b.cloneNode(!0);a.dom.setStyles(e,{width:c,height:d}),a.dom.setAttrib(e,"data-mce-selected",null);var f=a.dom.create("div",{"class":"mce-drag-container","data-mce-bogus":"all",unselectable:"on",contenteditable:"false"});return a.dom.setStyles(f,{position:"absolute",opacity:.5,overflow:"hidden",border:0,padding:0,margin:0,width:c,height:d}),a.dom.setStyles(e,{margin:0,boxSizing:"border-box"}),f.appendChild(e),f},m=function(a,b){a.parentNode!==b&&b.appendChild(a)},n=function(a,b,c,d,e,f){var g=0,h=0;a.style.left=b.pageX+"px",a.style.top=b.pageY+"px",b.pageX+c>e&&(g=b.pageX+c-e),b.pageY+d>f&&(h=b.pageY+d-f),a.style.width=c-g+"px",a.style.height=d-h+"px"},o=function(a){a&&a.parentNode&&a.pa
 rentNode.removeChild(a)},p=function(a){return 0===a.button},q=function(a){return a.element},r=function(a,b){return{pageX:b.pageX-a.relX,pageY:b.pageY+5}},s=function(a,d){return function(e){if(p(e)){var f=b.find(d.dom.getParents(e.target),c.or(g,h));if(i(d.getBody(),f)){var j=d.dom.getPos(f),k=d.getBody(),m=d.getDoc().documentElement;a.element=f,a.screenX=e.screenX,a.screenY=e.screenY,a.maxX=(d.inline?k.scrollWidth:m.offsetWidth)-2,a.maxY=(d.inline?k.scrollHeight:m.offsetHeight)-2,a.relX=e.pageX-j.x,a.relY=e.pageY-j.y,a.width=f.offsetWidth,a.height=f.offsetHeight,a.ghost=l(d,f,a.width,a.height)}}}},t=function(a,b){var c=d.throttle(function(a,c){b._selectionOverrides.hideFakeCaret(),b.selection.placeCaretAt(a,c)},0);return function(d){var e=Math.max(Math.abs(d.screenX-a.screenX),Math.abs(d.screenY-a.screenY));if(q(a)&&!a.dragging&&e>10){var g=b.fire("dragstart",{target:a.element});if(g.isDefaultPrevented())return;a.dragging=!0,b.focus()}if(a.dragging){var 
 h=r(a,f.calc(b,d));m(a.ghost,b.getBody()),n(a.ghost,h,a.width,a.height,a.maxX,a.maxY),c(d.clientX,d.clientY)}}},u=function(a){var b=a.getSel().getRangeAt(0),c=b.startContainer;return 3===c.nodeType?c.parentNode:c},v=function(a,b){return function(c){if(a.dragging&&j(b,u(b.selection),a.element)){var d=k(a.element),e=b.fire("drop",{targetClone:d,clientX:c.clientX,clientY:c.clientY});e.isDefaultPrevented()||(d=e.targetClone,b.undoManager.transact(function(){o(a.element),b.insertContent(b.dom.getOuterHTML(d)),b._selectionOverrides.hideFakeCaret()}))}x(a)}},w=function(a,b){return function(){x(a),a.dragging&&b.fire("dragend")}},x=function(a){a.dragging=!1,a.element=null,o(a.ghost)},y=function(a){var b,c,d,f,g,h,i={};b=e.DOM,h=document,c=s(i,a),d=t(i,a),f=v(i,a),g=w(i,a),a.on("mousedown",c),a.on("mousemove",d),a.on("mouseup",f),b.bind(h,"mousemove",d),b.bind(h,"mouseup",g),a.on("remove",function(
 ){b.unbind(h,"mousemove",d),b.unbind(h,"mouseup",g)})},z=function(a){a.on("drop",function(b){var c="undefined"!=typeof b.clientX?a.getDoc().elementFromPoint(b.clientX,b.clientY):null;(g(c)||g(a.dom.getContentEditableParent(c)))&&b.preventDefault()})},A=function(a){y(a),z(a)};return{init:A}}),g("7x",["1z","7b","20","b","21","e","4k","14"],function(a,b,c,d,e,f,g,h){var i=e.isContentEditableFalse,j=function(a){return a&&/^(TD|TH)$/i.test(a.nodeName)};return function(c,e){function f(a,b){var d,e,f,h,i,j=g.collapse(a.getBoundingClientRect(),b);return"BODY"==c.tagName?(d=c.ownerDocument.documentElement,e=c.scrollLeft||d.scrollLeft,f=c.scrollTop||d.scrollTop):(i=c.getBoundingClientRect(),e=c.scrollLeft-i.left,f=c.scrollTop-i.top),j.left+=e,j.right+=e,j.top+=f,j.bottom+=f,j.width=1,h=a.offsetWidth-a.clientWidth,h>0&&(b&&am
 p;(h*=-1),j.left+=h,j.right+=h),j}function k(){var b,e,f,g,h;for(b=d("*[contentEditable=false]",c),g=0;g<b.length;g++)e=b[g],f=e.previousSibling,a.endsWithCaretContainer(f)&&(h=f.data,1==h.length?f.parentNode.removeChild(f):f.deleteData(h.length-1,1)),f=e.nextSibling,a.startsWithCaretContainer(f)&&(h=f.data,1==h.length?f.parentNode.removeChild(f):f.deleteData(0,1));return null}function l(b,g){var h,k;return m(),j(g)?null:e(g)?(s=a.insertBlock("p",g,b),h=f(g,b),d(s).css("top",h.top),r=d('<div class="mce-visual-caret" data-mce-bogus="all"></div>').css(h).appendTo(c),b&&r.addClass("mce-visual-caret-before"),n(),k=g.ownerDocument.createRange(),k.setStart(s,0),k.setEnd(s,0),k):(s=a.insertInline(g,b),k=g.ownerDocument.createRange(),i(s.nextSibling)?(k.setStart(s,0),k.setEnd(s,0)):(k.setStart(s,1),k.setEnd(s,1)),k)}function m(){k(),s&&(b.remove(s),s=null),r&&(r.remove(),r=null
 ),clearInterval(q)}function n(){q=h.setInterval(function(){d("div.mce-visual-caret",c).toggleClass("mce-visual-caret-hidden")},500)}function o(){h.clearInterval(q)}function p(){return".mce-visual-caret {position: absolute;background-color: black;background-color: currentcolor;}.mce-visual-caret-hidden {display: none;}*[data-mce-caret] {position: absolute;left: -1000px;right: auto;top: 0;margin: 0;padding: 0;}"}var q,r,s;return{show:l,hide:m,getCss:p,destroy:o}}}),g("7j",["1t","6a","23","6d","6c","57","7w","1v","o","1z","20","62","5j","7x","7y","58","21","25","7z","14","1f"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u){
+function v(q){function v(a){return q.dom.hasClass(a,"mce-offscreen-selection")}function A(){var a=q.dom.get(T);return a?a.getElementsByTagName("*")[0]:a}function B(a){return q.dom.isBlock(a)}function C(a){a&&q.selection.setRng(a)}function D(){return q.selection.getRng()}function E(a,b){q.selection.scrollIntoView(a,b)}function F(a,b,c){var d;return d=q.fire("ShowCaret",{target:b,direction:a,before:c}),d.isDefaultPrevented()?null:(E(b,a===-1),S.show(c,b))}function G(a,b){return b=l.normalizeRange(a,R,b),a==-1?k.fromRangeStart(b):k.fromRangeEnd(b)}function H(a){a.hasAttribute("data-mce-caret")&&(j.showCaretContainerBlock(a),C(D()),E(a[0]))}function I(){function a(a){for(var b=q.getBody();a&&a!=b;){if(w(a)||x(a))return a;a=a.parentNode}return null}function b(b){var c=!1;b.on("touchstart",function(){c=!1}),b.on("touchmove",function(){c=!0}),b.on("touchend",function(d){var e=a(d.target);x(e)&
 &(c||(d.preventDefault(),M(s.selectNode(b,e))))})}q.on("mouseup",function(a){var b=D();b.collapsed&&h.isXYInContentArea(q,a.clientX,a.clientY)&&C(s.renderCaretAtRange(q,b))}),q.on("click",function(b){var c;c=a(b.target),c&&(x(c)&&(b.preventDefault(),q.focus()),w(c)&&q.dom.isChildOf(c,q.selection.getNode())&&N())}),q.on("blur NewBlock",function(){N(),P()});var d=function(a){var b=new m(a);if(!a.firstChild)return!1;var c=k.before(a.firstChild),d=b.next(c);return d&&!z(d)&&!y(d)},e=function(a,b){var c=q.dom.getParent(a,q.dom.isBlock),d=q.dom.getParent(b,q.dom.isBlock);return c===d},f=function(a,b){var c=q.dom.getParent(a,q.dom.isBlock),f=q.dom.getParent(b,q.dom.isBlock);return c&&!e(c,f)&&d(c)};b(q),q.on("mousedown",function(b){var d;if(h.isXYInContentArea(q,b.clientX,b.clientY)!==!1)if(d=a(b.target))x(d)?(b.preventDefault(),M(s.selectNode(q,d))):(N(),w(d)&&am
 p;b.shiftKey||r.isXYWithinRange(b.clientX,b.clientY,q.selection.getRng())||(p.isVoid(c.fromDom(b.target))?q.selection.select(b.target):q.selection.placeCaretAt(b.clientX,b.clientY)));else{N(),P();var e=o.closestCaret(R,b.clientX,b.clientY);e&&(f(b.target,e.node)||(b.preventDefault(),q.getBody().focus(),C(F(1,e.node,e.before))))}}),q.on("keypress",function(a){if(!u.modifierPressed(a))switch(a.keyCode){default:x(q.selection.getNode())&&a.preventDefault()}}),q.on("getSelectionRange",function(a){var b=a.range;if(Q){if(!Q.parentNode)return void(Q=null);b=b.cloneRange(),b.selectNode(Q),a.range=b}}),q.on("setSelectionRange",function(a){var b;b=M(a.range,a.forward),b&&(a.range=b)}),q.on("AfterSetSelectionRange",function(a){var b=a.range;L(b)||P(),v(b.startContainer.parentNode)||N()}),q.on("focus",function(){t.setEditorTimeout(q,function(){q.selection.setRng(s.renderRangeCaret(q,q.selection.getRng()))},0)}),q.on("
 copy",function(a){var b=a.clipboardData;if(!a.isDefaultPrevented()&&a.clipboardData&&!i.ie){var c=A();c&&(a.preventDefault(),b.clearData(),b.setData("text/html",c.outerHTML),b.setData("text/plain",c.outerText))}}),g.init(q)}function J(){var a=q.contentStyles,b=".mce-content-body";a.push(S.getCss()),a.push(b+" .mce-offscreen-selection {position: absolute;left: -9999999999px;max-width: 1000000px;}"+b+" *[contentEditable=false] {cursor: default;}"+b+" *[contentEditable=true] {cursor: text;}")}function K(a){return j.isCaretContainer(a)||j.startsWithCaretContainer(a)||j.endsWithCaretContainer(a)}function L(a){return K(a.startContainer)||K(a.endContainer)}function M(b,g){var h,j,k,l,m,n,o,p,r,s,t=q.$,u=q.dom;if(!b)return null;if(b.collapsed){if(!L(b))if(g===!1){if(p=G(-1,b),x(p.getNode(!0)))return F(-1,p.getNode(!0),!1);if(x(p.getNode()))return F(-1,p.getNode(),!p.isAtEnd())}else{if(p=G(1,b),x(p.getNo
 de()))return F(1,p.getNode(),!p.isAtEnd());if(x(p.getNode(!0)))return F(1,p.getNode(!0),!1)}return null}return l=b.startContainer,m=b.startOffset,n=b.endOffset,3==l.nodeType&&0==m&&x(l.parentNode)&&(l=l.parentNode,m=u.nodeIndex(l),l=l.parentNode),1!=l.nodeType?null:(n==m+1&&(h=l.childNodes[m]),x(h)?(r=s=h.cloneNode(!0),o=q.fire("ObjectSelected",{target:h,targetClone:r}),o.isDefaultPrevented()?null:(j=f.descendant(c.fromDom(q.getBody()),"#"+T).fold(function(){return t([])},function(a){return t([a.dom()])}),r=o.targetClone,0===j.length&&(j=t('<div data-mce-bogus="all" class="mce-offscreen-selection"></div>').attr("id",T),j.appendTo(q.getBody())),b=q.dom.createRng(),r===s&&i.ie?(j.empty().append('<p style="font-size: 0" data-mce-bogus="all">\xa0</p>').append(r),b.setStartAfter(j[0].firstChild.firstChild),b.setEndAfter(r)):(j.empty().append("
 \xa0").append(r).append("\xa0"),b.setStart(j[0].firstChild,1),b.setEnd(j[0].lastChild,0)),j.css({top:u.getPos(h,q.getBody()).y}),j[0].focus(),k=q.selection.getSel(),k.removeAllRanges(),k.addRange(b),a.each(e.descendants(c.fromDom(q.getBody()),"*[data-mce-selected]"),function(a){d.remove(a,"data-mce-selected")}),h.setAttribute("data-mce-selected",1),Q=h,P(),b)):null)}function N(){Q&&(Q.removeAttribute("data-mce-selected"),f.descendant(c.fromDom(q.getBody()),"#"+T).each(b.remove),Q=null)}function O(){S.destroy(),Q=null}function P(){S.hide()}var Q,R=q.getBody(),S=new n(q.getBody(),B),T="sel-"+q.dom.uniqueId();return i.ceFalse&&(I(),J()),{showCaret:F,showBlockCaretContainer:H,hideFakeCaret:P,destroy:O}}var w=q.isContentEditableTrue,x=q.isContentEditableFalse,y=l.isAfterContentEditableFalse,z=l.isBeforeContentEditableFalse;return v}),g("6x",[],function(){var a=0,b=1,c=2,d=function(d,e){va
 r f=d.length+e.length+2,g=new Array(f),h=new Array(f),i=function(a,b,c){return{start:a,end:b,diag:c}},j=function(f,g,h,i,k){var m=l(f,g,h,i);if(null===m||m.start===g&&m.diag===g-i||m.end===f&&m.diag===f-h)for(var n=f,o=h;n<g||o<i;)n<g&&o<i&&d[n]===e[o]?(k.push([a,d[n]]),++n,++o):g-f>i-h?(k.push([c,d[n]]),++n):(k.push([b,e[o]]),++o);else{j(f,m.start,h,m.start-m.diag,k);for(var p=m.start;p<m.end;++p)k.push([a,d[p]]);j(m.end,g,m.end-m.diag,i,k)}},k=function(a,b,c,f){for(var g=a;g-b<f&&g<c&&d[g]===e[g-b];)++g;return i(a,g,b)},l=function(a,b,c,f){var i=b-a,j=f-c;if(0===i||0===j)return null;var l=i-j,m=j+i,n=(m%2===0?m:m+1)/2;g[1+n]=a,h[1+n]=b+1;for(var o=0;o<=n;++o){for(var p=-o;p<=o;p+=2){var q=p+n;p===-o||p!=o&&g[q-1]<g[q+1]?g[q]=g[q+1]:g[q]=g[q-1]+1;for(var r=g[q],s=r-a+c-p;r<b&&s<f&&d[r]===e[s];)g[q]=++r,++s;if(l%2!=0&&l-o<=p&&p<=l+o&&h[q-l]<
 =g[q])return k(h[q-l],p+a-c,b,f)}for(p=l-o;p<=l+o;p+=2){for(q=p+n-l,p===l-o||p!=l+o&&h[q+1]<=h[q-1]?h[q]=h[q+1]-1:h[q]=h[q-1],r=h[q]-1,s=r-a+c-p;r>=a&&s>=c&&d[r]===e[s];)h[q]=r--,s--;if(l%2===0&&-o<=p&&p<=o&&h[q]<=g[q+l])return k(h[q],p+a-c,b,f)}}},m=[];return j(0,d.length,0,e.length,m),m};return{KEEP:a,DELETE:c,INSERT:b,diff:d}}),g("5y",["1h","s","6x"],function(a,b,c){var d=function(a){return 1===a.nodeType?a.outerHTML:3===a.nodeType?b.encodeRaw(a.data,!1):8===a.nodeType?"<!--"+a.data+"-->":""},e=function(a){var b,c,d;for(d=document.createElement("div"),b=document.createDocumentFragment(),a&&(d.innerHTML=a);c=d.firstChild;)b.appendChild(c);return b},f=function(a,b,c){var d=e(b);if(a.hasChildNodes()&&c<a.childNodes.length){var f=a.childNodes[c];f.parentNode.insertBefore(d,f)}else a.appendChild(d)},g=function(a,b
 ){if(a.hasChildNodes()&&b<a.childNodes.length){var c=a.childNodes[b];c.parentNode.removeChild(c)}},h=function(b,d){var e=0;a.each(b,function(a){a[0]===c.KEEP?e++:a[0]===c.INSERT?(f(d,a[1],e),e++):a[0]===c.DELETE&&g(d,e)})},i=function(b){return a.filter(a.map(b.childNodes,d),function(a){return a.length>0})},j=function(b,e){var f=a.map(e.childNodes,d);return h(c.diff(f,b),e),e};return{read:i,write:j}}),g("4c",["1h","5y"],function(a,b){var c=function(a){return a.indexOf("</iframe>")!==-1},d=function(a){return{type:"fragmented",fragments:a,content:"",bookmark:null,beforeBookmark:null}},e=function(a){return{type:"complete",fragments:null,content:a,bookmark:null,beforeBookmark:null}},f=function(f){var g,h,i;return g=b.read(f.getBody()),i=a.map(g,function(a){return f.serializer.trimContent(a)}),h=i.join(""),c(h)?d(i):e(h)},g=function(a,c,d){"fragmented"===c.type?b.write(c.f
 ragments,a.getBody()):a.setContent(c.content,{format:"raw"}),a.selection.moveToBookmark(d?c.beforeBookmark:c.bookmark)},h=function(a){return"fragmented"===a.type?a.fragments.join(""):a.content},i=function(a,b){return!!a&&!!b&&h(a)===h(b)};return{createFragmentedLevel:d,createCompleteLevel:e,createFromEditor:f,applyToEditor:g,isEq:i}}),g("11",["1f","1d","4c"],function(a,b,c){return function(a){function d(b){a.setDirty(b)}function e(a){n(!1),i.add({},a)}function f(){i.typing&&(n(!1),i.add())}var g,h,i=this,j=0,k=[],l=0,m=function(){return 0===l},n=function(a){m()&&(i.typing=a)};return a.on("init",function(){i.add()}),a.on("BeforeExecCommand",function(a){var b=a.command;"Undo"!==b&&"Redo"!==b&&"mceRepaint"!==b&&(f(),i.beforeChange())}),a.on("ExecCommand",function(a){var b=a.command;"Undo"!==b&
 amp;&"Redo"!==b&&"mceRepaint"!==b&&e(a)}),a.on("ObjectResizeStart Cut",function(){i.beforeChange()}),a.on("SaveContent ObjectResized blur",e),a.on("DragEnd",e),a.on("KeyUp",function(b){var f=b.keyCode;b.isDefaultPrevented()||((f>=33&&f<=36||f>=37&&f<=40||45===f||b.ctrlKey)&&(e(),a.nodeChanged()),46!==f&&8!==f||a.nodeChanged(),h&&i.typing&&c.isEq(c.createFromEditor(a),k[0])===!1&&(a.isDirty()===!1&&(d(!0),a.fire("change",{level:k[0],lastLevel:null})),a.fire("TypingUndo"),h=!1,a.nodeChanged()))}),a.on("KeyDown",function(a){var b=a.keyCode;if(!a.isDefaultPrevented()){if(b>=33&&b<=36||b>=37&&b<=40||45===b)return void(i.typing&&e(a));var c=a.ctrlKey&&!a.altKey||a.metaKey;!(b<16||b>20)||224===b||91===b||i.typing||c||(i.beforeChange(),n(!0),i.add({},a),h=!0)
 }}),a.on("MouseDown",function(a){i.typing&&e(a)}),a.addShortcut("meta+z","","Undo"),a.addShortcut("meta+y,meta+shift+z","","Redo"),a.on("AddUndo Undo Redo ClearUndos",function(b){b.isDefaultPrevented()||a.nodeChanged()}),i={data:k,typing:!1,beforeChange:function(){m()&&(g=a.selection.getBookmark(2,!0))},add:function(e,f){var h,i,l,n=a.settings;if(l=c.createFromEditor(a),e=e||{},e=b.extend(e,l),m()===!1||a.removed)return null;if(i=k[j],a.fire("BeforeAddUndo",{level:e,lastLevel:i,originalEvent:f}).isDefaultPrevented())return null;if(i&&c.isEq(i,e))return null;if(k[j]&&(k[j].beforeBookmark=g),n.custom_undo_redo_levels&&k.length>n.custom_undo_redo_levels){for(h=0;h<k.length-1;h++)k[h]=k[h+1];k.length--,j=k.length}e.bookmark=a.selection.getBookmark(2,!0),j<k.length-1&&(k.length=j+1),k.push(e),j=k.length-1;var o={level:e,lastLevel:i,originalEve
 nt:f};return a.fire("AddUndo",o),j>0&&(d(!0),a.fire("change",o)),e},undo:function(){var b;return i.typing&&(i.add(),i.typing=!1,n(!1)),j>0&&(b=k[--j],c.applyToEditor(a,b,!0),d(!0),a.fire("undo",{level:b})),b},redo:function(){var b;return j<k.length-1&&(b=k[++j],c.applyToEditor(a,b,!1),d(!0),a.fire("redo",{level:b})),b},clear:function(){k=[],j=0,i.typing=!1,i.data=k,a.fire("ClearUndos")},hasUndo:function(){return j>0||i.typing&&k[0]&&!c.isEq(c.createFromEditor(a),k[0])},hasRedo:function(){return j<k.length-1&&!i.typing},transact:function(a){return f(),i.beforeChange(),i.ignore(a),i.add()},ignore:function(a){try{l++,a()}finally{l--}},extra:function(b,d){var e,f;i.transact(b)&&(f=k[j].bookmark,e=k[j-1],c.applyToEditor(a,e,!0),i.transact(d)&&(k[j-1].beforeBookmark=f))}}}}),g("80",["c"],function(a){function b(b,c,d){for(var e=[];c&am
 p;&c!=b;c=c.parentNode)e.push(a.nodeIndex(c,d));return e}function c(a,b){var c,d,e;for(d=a,c=b.length-1;c>=0;c--){if(e=d.childNodes,b[c]>e.length-1)return null;d=e[b[c]]}return d}return{create:b,resolve:c}}),g("7k",["1f","e","j","80","t","s","o","1d","14","1z","20","5j"],function(a,b,c,d,e,f,g,h,i,j,k,l){return function(c){function d(a,b){try{c.getDoc().execCommand(a,!1,b)}catch(a){}}function k(){var a=c.getDoc().documentMode;return a?a:6}function l(a){return a.isDefaultPrevented()}function m(a){var b,d;a.dataTransfer&&(c.selection.isCollapsed()&&"IMG"==a.target.tagName&&Y.select(a.target),b=c.selection.getContent(),b.length>0&&(d=da+escape(c.id)+","+escape(b),a.dataTransfer.setData(ea,d)))}function n(a){var b;return a.dataTransfer&&(b=a.dataTransfer.getData(ea),b&&b.indexOf(
 da)>=0)?(b=b.substr(da.length).split(","),{id:unescape(b[0]),html:unescape(b[1])}):null}function o(a,b){c.queryCommandSupported("mceInsertClipboardContent")?c.execCommand("mceInsertClipboardContent",!1,{content:a,internal:b}):c.execCommand("mceInsertContent",!1,a)}function p(){function a(a){var b=X.create("body"),c=a.cloneContents();return b.appendChild(c),Y.serializer.serialize(b,{format:"html"})}function d(d){if(!d.setStart){if(d.item)return!1;var e=d.duplicate();return e.moveToElementText(c.getBody()),b.compareRanges(d,e)}var f=a(d),g=X.createRng();g.selectNode(c.getBody());var h=a(g);return f===h}c.on("keydown",function(a){var b,e,f=a.keyCode;if(!l(a)&&(f==W||f==V)){if(b=c.selection.isCollapsed(),e=c.getBody(),b&&!X.isEmpty(e))return;if(!b&&!d(c.selection.getRng()))return;a.preventDefault(),c.setContent(""),e.firstChild&&X.isBlock(e.firstChild)?c.selection.setCursor
 Location(e.firstChild,0):c.selection.setCursorLocation(e,0),c.nodeChanged()}})}function q(){c.shortcuts.add("meta+a",null,"SelectAll")}function r(){c.settings.content_editable||X.bind(c.getDoc(),"mousedown mouseup",function(a){var b;if(a.target==c.getDoc().documentElement)if(b=Y.getRng(),c.getBody().focus(),"mousedown"==a.type){if(j.isCaretContainer(b.startContainer))return;Y.placeCaretAt(a.clientX,a.clientY)}else Y.setRng(b)})}function s(){c.on("keydown",function(a){if(!l(a)&&a.keyCode===V){if(!c.getBody().getElementsByTagName("hr").length)return;if(Y.isCollapsed()&&0===Y.getRng(!0).startOffset){var b=Y.getNode(),d=b.previousSibling;if("HR"==b.nodeName)return X.remove(b),void a.preventDefault();d&&d.nodeName&&"hr"===d.nodeName.toLowerCase()&&(X.remove(d),a.preventDefault())}}})}function t(){window.Range.prototype.getClientRects||c.on("mousedown",function
 (a){if(!l(a)&&"HTML"===a.target.nodeName){var b=c.getBody();b.blur(),i.setEditorTimeout(c,function(){b.focus()})}})}function u(){c.on("click",function(a){var b=a.target;/^(IMG|HR)$/.test(b.nodeName)&&"false"!==X.getContentEditableParent(b)&&(a.preventDefault(),c.selection.select(b),c.nodeChanged()),"A"==b.nodeName&&X.hasClass(b,"mce-item-anchor")&&(a.preventDefault(),Y.select(b))})}function v(){function a(){var a=X.getAttribs(Y.getStart().cloneNode(!1));return function(){var b=Y.getStart();b!==c.getBody()&&(X.setAttrib(b,"style",null),U(a,function(a){b.setAttributeNode(a.cloneNode(!0))}))}}function b(){return!Y.isCollapsed()&&X.getParent(Y.getStart(),X.isBlock)!=X.getParent(Y.getEnd(),X.isBlock)}c.on("keypress",function(d){var e;if(!l(d)&&(8==d.keyCode||46==d.keyCode)&&b())return e=a(),c.getDoc().execCommand("delete",!1,null),e(),d.p
 reventDefault(),!1}),X.bind(c.getDoc(),"cut",function(d){var e;!l(d)&&b()&&(e=a(),i.setEditorTimeout(c,function(){e()}))})}function w(){document.body.setAttribute("role","application")}function x(){c.on("keydown",function(a){if(!l(a)&&a.keyCode===V&&Y.isCollapsed()&&0===Y.getRng(!0).startOffset){var b=Y.getNode().previousSibling;if(b&&b.nodeName&&"table"===b.nodeName.toLowerCase())return a.preventDefault(),!1}})}function y(){k()>7||(d("RespectVisibilityInDesign",!0),c.contentStyles.push(".mceHideBrInPre pre br {display: none}"),X.addClass(c.getBody(),"mceHideBrInPre"),$.addNodeFilter("pre",function(a){for(var b,c,d,f,g=a.length;g--;)for(b=a[g].getAll("br"),c=b.length;c--;)d=b[c],f=d.prev,f&&3===f.type&&"\n"!=f.value.charAt(f.value-1)?f.value+="\n":d.parent.insert(new e("#text",3),d
 ,!0).value="\n"}),_.addNodeFilter("pre",function(a){for(var b,c,d,e,f=a.length;f--;)for(b=a[f].getAll("br"),c=b.length;c--;)d=b[c],e=d.prev,e&&3==e.type&&(e.value=e.value.replace(/\r?\n$/,""))}))}function z(){X.bind(c.getBody(),"mouseup",function(){var a,b=Y.getNode();"IMG"==b.nodeName&&((a=X.getStyle(b,"width"))&&(X.setAttrib(b,"width",a.replace(/[^0-9%]+/g,"")),X.setStyle(b,"width","")),(a=X.getStyle(b,"height"))&&(X.setAttrib(b,"height",a.replace(/[^0-9%]+/g,"")),X.setStyle(b,"height","")))})}function A(){c.on("keydown",function(b){var d,e,f,g,h;if(!l(b)&&b.keyCode==a.BACKSPACE&&(d=Y.getRng(),e=d.startContainer,f=d.startOffset,g=X.getRoot(),h=e,d.collapsed&&0===f)){for(;h&&h.parentNode&&h.parentNode.firstChild==h&&h.parentNode
 !=g;)h=h.parentNode;"BLOCKQUOTE"===h.tagName&&(c.formatter.toggle("blockquote",null,h),d=X.createRng(),d.setStart(e,0),d.setEnd(e,0),Y.setRng(d))}})}function B(){function a(){S(),d("StyleWithCSS",!1),d("enableInlineTableEditing",!1),Z.object_resizing||d("enableObjectResizing",!1)}Z.readonly||c.on("BeforeExecCommand MouseDown",a)}function C(){function a(){U(X.select("a"),function(a){var b=a.parentNode,c=X.getRoot();if(b.lastChild===a){for(;b&&!X.isBlock(b);){if(b.parentNode.lastChild!==b||b===c)return;b=b.parentNode}X.add(b,"br",{"data-mce-bogus":1})}})}c.on("SetContent ExecCommand",function(b){"setcontent"!=b.type&&"mceInsertLink"!==b.command||a()})}function D(){Z.forced_root_block&&c.on("init",function(){d("DefaultParagraphSeparator",Z.forced_root_block)})}function E(){c.on("keydown",function(a){var b;l
 (a)||a.keyCode!=V||(b=c.getDoc().selection.createRange(),b&&b.item&&(a.preventDefault(),c.undoManager.beforeChange(),X.remove(b.item(0)),c.undoManager.add()))})}function F(){var a;k()>=10&&(a="",U("p div h1 h2 h3 h4 h5 h6".split(" "),function(b,c){a+=(c>0?",":"")+b+":empty"}),c.contentStyles.push(a+"{padding-right: 1px !important}"))}function G(){k()<9&&($.addNodeFilter("noscript",function(a){for(var b,c,d=a.length;d--;)b=a[d],c=b.firstChild,c&&b.attr("data-mce-innertext",c.value)}),_.addNodeFilter("noscript",function(a){for(var b,c,d,g=a.length;g--;)b=a[g],c=a[g].firstChild,c?c.value=f.decode(c.value):(d=b.attributes.map["data-mce-innertext"],d&&(b.attr("data-mce-innertext",null),c=new e("#text",3),c.value=d,c.raw=!0,b.append(c)))}))}function H(){function a(a,b){var c=h.createTextRange();try{c.move
 ToPoint(a,b)}catch(a){c=null}return c}function b(b){var d;b.button?(d=a(b.x,b.y),d&&(d.compareEndPoints("StartToStart",e)>0?d.setEndPoint("StartToStart",e):d.setEndPoint("EndToEnd",e),d.select())):c()}function c(){var a=g.selection.createRange();e&&!a.item&&0===a.compareEndPoints("StartToEnd",a)&&e.select(),X.unbind(g,"mouseup",c),X.unbind(g,"mousemove",b),e=d=0}var d,e,f,g=X.doc,h=g.body;g.documentElement.unselectable=!0,X.bind(g,"mousedown contextmenu",function(h){if("HTML"===h.target.nodeName){if(d&&c(),f=g.documentElement,f.scrollHeight>f.clientHeight)return;d=1,e=a(h.x,h.y),e&&(X.bind(g,"mouseup",c),X.bind(g,"mousemove",b),X.getRoot().focus(),e.select())}})}function I(){c.on("keyup focusin mouseup",function(b){65==b.keyCode&&a.metaKeyPressed(b)||("keyup"!==b.type||c.selection.isCollapsed())&&amp
 ;Y.normalize()},!0)}function J(){c.contentStyles.push("img:-moz-broken {-moz-force-broken-image-icon:1;min-width:24px;min-height:24px}")}function K(){c.inline||c.on("keydown",function(){document.activeElement==document.body&&c.getWin().focus()})}function L(){c.inline||(c.contentStyles.push("body {min-height: 150px}"),c.on("click",function(a){var b;if("HTML"==a.target.nodeName){if(g.ie>11)return void c.getBody().focus();b=c.selection.getRng(),c.getBody().focus(),c.selection.setRng(b),c.selection.normalize(),c.nodeChanged()}}))}function M(){g.mac&&c.on("keydown",function(b){!a.metaKeyPressed(b)||b.shiftKey||37!=b.keyCode&&39!=b.keyCode||(b.preventDefault(),c.selection.getSel().modify("move",37==b.keyCode?"backward":"forward","lineboundary"))})}function N(){d("AutoUrlDetect",!1)}function O(){c.on("click",function(a){var b=a.target;do if(&quo
 t;A"===b.tagName)return void a.preventDefault();while(b=b.parentNode)}),c.contentStyles.push(".mce-content-body {-webkit-touch-callout: none}")}function P(){c.on("init",function(){c.dom.bind(c.getBody(),"submit",function(a){a.preventDefault()})})}function Q(){$.addNodeFilter("br",function(a){for(var b=a.length;b--;)"Apple-interchange-newline"==a[b].attr("class")&&a[b].remove()})}function R(){c.on("dragstart",function(a){m(a)}),c.on("drop",function(a){if(!l(a)){var d=n(a);if(d&&d.id!=c.id){a.preventDefault();var e=b.getCaretRangeFromPoint(a.x,a.y,c.getDoc());Y.setRng(e),o(d.html,!0)}}})}function S(){}function T(){var a;return!aa||c.removed?0:(a=c.selection.getSel(),!a||!a.rangeCount||0===a.rangeCount)}var U=h.each,V=a.BACKSPACE,W=a.DELETE,X=c.dom,Y=c.selection,Z=c.settings,$=c.parser,_=c.serializer,aa=g.gecko,ba=g.ie,ca=g.webkit,da="data:text/mce-internal,",ea=ba?"Text&
 quot;:"URL";return A(),p(),g.windowsPhone||I(),ca&&(r(),u(),D(),P(),x(),Q(),g.iOS?(K(),L(),O()):q()),ba&&g.ie<11&&(s(),w(),y(),z(),E(),F(),G(),H()),g.ie>=11&&(L(),x()),g.ie&&(q(),N(),R()),aa&&(s(),t(),v(),B(),C(),J(),M(),x()),{refreshContentEditable:S,isHidden:T}}}),g("6w",["53","23","6d","2i","5r","6","7e","c","g","h","7f","2l","7g","r","t","v","7h","7i","7j","11","14","7k","1d"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w){var x=h.DOM,y=function(d,e){var f=b.fromDom(d.getDoc().head),g=b.fromTag("style");c.set(g,"type","text/css"),a.append(g,b.fromText(e)),a.append(f,g)},z=function(a){var b=new n(a.settings,a.schema);return b.addAttributeFilte
 r("src,href,style,tabindex",function(b,c){for(var d,e,f,g=b.length,h=a.dom;g--;)if(d=b[g],e=d.attr(c),f="data-mce-"+c,!d.attributes.map[f]){if(0===e.indexOf("data:")||0===e.indexOf("blob:"))continue;"style"===c?(e=h.serializeStyle(h.parseStyle(e),d.name),e.length||(e=null),d.attr(f,e),d.attr(c,e)):"tabindex"===c?(d.attr(f,e),d.attr(c,null)):d.attr(f,a.convertURL(e,c,d.name))}}),b.addNodeFilter("script",function(a){for(var b,c,d=a.length;d--;)b=a[d],c=b.attr("type")||"no/type",0!==c.indexOf("mce-")&&b.attr("type","mce-"+c)}),b.addNodeFilter("#cdata",function(a){for(var b,c=a.length;c--;)b=a[c],b.type=8,b.name="#comment",b.value="[CDATA["+b.value+"]]"}),b.addNodeFilter("p,h1,h2,h3,h4,h5,h6,div",function(b){for(var c,d=b.length,e=a.schema.getNonEmptyElements();d--;)c=b[d],c.isEmpty(e)&&0===c.getAll(&quo
 t;br").length&&(c.append(new o("br",1)).shortEnded=!0)}),b},A=function(a){a.settings.auto_focus&&u.setEditorTimeout(a,function(){var b;b=a.settings.auto_focus===!0?a:a.editorManager.get(a.settings.auto_focus),b.destroyed||b.focus()},100)},B=function(a){a.bindPendingEventDelegates(),a.initialized=!0,a.fire("init"),a.focus(!0),a.nodeChanged({initial:!0}),a.execCallback("init_instance_callback",a),A(a)},C=function(a){return a.inline?x.styleSheetLoader:a.dom.styleSheetLoader},D=function(a,b){var c,l,n=a.settings,o=a.getElement(),u=a.getDoc();n.inline||(a.getElement().style.visibility=a.orgVisibility),b||n.content_editable||(u.open(),u.write(a.iframeHTML),u.close()),n.content_editable&&(a.on("remove",function(){var a=this.getBody();x.removeClass(a,"mce-content-body"),x.removeClass(a,"mce-edit-focus"),x.setAttrib(a,"contentEditable",null)}),x.addClass(o,"mce-content-body"),a.conten
 tDocument=u=n.content_document||d,a.contentWindow=n.content_window||e,a.bodyElement=o,n.content_document=n.content_window=null,n.root_name=o.nodeName.toLowerCase()),c=a.getBody(),c.disabled=!0,a.readonly=n.readonly,a.readonly||(a.inline&&"static"===x.getStyle(c,"position",!0)&&(c.style.position="relative"),c.contentEditable=a.getParam("content_editable_state",!0)),c.disabled=!1,a.editorUpload=new k(a),a.schema=new p(n),a.dom=new h(u,{keep_values:!0,url_converter:a.convertURL,url_converter_scope:a,hex_colors:n.force_hex_style_colors,class_filter:n.class_filter,update_styles:!0,root_element:a.inline?a.getBody():null,collect:n.content_editable,schema:a.schema,onSetAttrib:function(b){a.fire("SetAttrib",b)}}),a.parser=z(a),a.serializer=new j(n,a),a.selection=new i(a.dom,a.getWin(),a.serializer,a),a.formatter=new f(a),a.undoManager=new t(a),a._nodeChangeDispatcher=new r(a),a._selectionOverrides=new s(a),g.setup(a),q.setup(a
 ),m.setup(a),a.fire("PreInit"),n.browser_spellcheck||n.gecko_spellcheck||(u.body.spellcheck=!1,x.setAttrib(c,"spellcheck","false")),a.quirks=new v(a),a.fire("PostRender"),n.directionality&&(c.dir=n.directionality),n.nowrap&&(c.style.whiteSpace="nowrap"),n.protect&&a.on("BeforeSetContent",function(a){w.each(n.protect,function(b){a.content=a.content.replace(b,function(a){return"<!--mce:protected "+escape(a)+"-->"})})}),a.on("SetContent",function(){a.addVisual(a.getBody())}),n.padd_empty_editor&&a.on("PostProcess",function(a){a.content=a.content.replace(/^(<p[^>]*>(&nbsp;|&#160;|\s|\u00a0|<br \/>|)<\/p>[\r\n]*|<br \/>[\r\n]*)$/,"")}),a.load({initial:!0,format:"html"}),a.startContent=a.getContent({format:"raw"}),a.on("compositionstart compositionend",function(b){a.composing=&qu
 ot;compositionstart"===b.type}),a.contentStyles.length>0&&(l="",w.each(a.contentStyles,function(a){l+=a+"\r\n"}),a.dom.addStyle(l)),C(a).loadAll(a.contentCSS,function(b){B(a)},function(b){B(a)}),n.content_style&&y(a,n.content_style)};return{initContentBody:D}}),g("5t",["5"],function(a){return a.PluginManager}),g("5u",["5"],function(a){return a.ThemeManager}),g("5s",["2i","5r","c","o","6w","5t","5u","1d","2j"],function(a,b,c,d,e,f,g,h,i){var j=c.DOM,k=function(a,b,c){var d,e,g=f.get(c);if(d=f.urls[c]||a.documentBaseUrl.replace(/\/$/,""),c=h.trim(c),g&&h.inArray(b,c)===-1){if(h.each(f.dependencies(c),function(c){k(a,b,c)}),a.plugins[c])return;e=new g(a,d,a.$),a.plugins[c]=e,e.init&&(e.init(a,d),b.push(c))}},l=function(a){return a.replace(/^\-/,"")},m=function(a){var b=
 [];h.each(a.settings.plugins.split(/[ ,]/),function(c){k(a,b,l(c))})},n=function(a){var b,c=a.settings;c.theme&&("function"!=typeof c.theme?(c.theme=l(c.theme),b=g.get(c.theme),a.theme=new b(a,g.urls[c.theme]),a.theme.init&&a.theme.init(a,g.urls[c.theme]||a.documentBaseUrl.replace(/\/$/,""),a.$)):a.theme=c.theme)},o=function(a){var b,c,d,e,f,g=a.settings,h=a.getElement();return g.render_ui&&a.theme&&(a.orgDisplay=h.style.display,"function"!=typeof g.theme?(b=g.width||j.getStyle(h,"width")||"100%",c=g.height||j.getStyle(h,"height")||h.offsetHeight,d=g.min_height||100,e=/^[0-9\.]+(|px)$/i,e.test(""+b)&&(b=Math.max(parseInt(b,10),100)),e.test(""+c)&&(c=Math.max(parseInt(c,10),d)),f=a.theme.renderUI({targetNode:h,width:b,height:c,deltaWidth:g.delta_width,deltaHeight:g.delta_height}),g.content_editable||(c=(f.iframeHeight||c)+("number"==typeof c?f.delt
 aHeight||0:""),c<d&&(c=d))):(f=g.theme(a,h),f.editorContainer.nodeType&&(f.editorContainer.id=f.editorContainer.id||a.id+"_parent"),f.iframeContainer.nodeType&&(f.iframeContainer.id=f.iframeContainer.id||a.id+"_iframecontainer"),c=f.iframeHeight||h.offsetHeight),a.editorContainer=f.editorContainer,f.height=c),f},p=function(c,f){if(a.domain!==b.location.hostname&&d.ie&&d.ie<12){var g=i.uuid("mce");c[g]=function(){e.initContentBody(c)};var h='javascript:(function(){document.open();document.domain="'+a.domain+'";var ed = window.parent.tinymce.get("'+c.id+'");document.write(ed.iframeHTML);document.close();ed.'+g+"(true);})()";return j.setAttrib(f,"src",h),!0}return!1},q=function(a,b){var c,e,f=a.settings;a.iframeHTML=f.doctype+"<html><head>",f.document_base_url!=a.documentBaseUrl&&(a.iframeHTML+='<base href="'+a.documentBaseU
 RI.getURI()+'" />'),!d.caretAfter&&f.ie7_compat&&(a.iframeHTML+='<meta http-equiv="X-UA-Compatible" content="IE=7" />'),a.iframeHTML+='<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />',c=f.body_id||"tinymce",c.indexOf("=")!=-1&&(c=a.getParam("body_id","","hash"),c=c[a.id]||c),e=f.body_class||"",e.indexOf("=")!=-1&&(e=a.getParam("body_class","","hash"),e=e[a.id]||""),f.content_security_policy&&(a.iframeHTML+='<meta http-equiv="Content-Security-Policy" content="'+f.content_security_policy+'" />'),a.iframeHTML+='</head><body id="'+c+'" class="mce-content-body '+e+'" data-id="'+a.id+'"><br></body></html>';var g=j.create("iframe",{id:a.id+"_ifr",frameBorder
 :"0",allowTransparency:"true",title:a.editorManager.translate("Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help"),style:{width:"100%",height:b.height,display:"block"}});g.onload=function(){g.onload=null,a.fire("load")};var h=p(a,g);return a.contentAreaContainer=b.iframeContainer,a.iframeElement=g,j.add(b.iframeContainer,g),h},r=function(a){var b,c=a.settings,d=a.getElement();if(a.rtl=c.rtl_ui||a.editorManager.i18n.rtl,a.editorManager.i18n.setCode(c.language),c.aria_label=c.aria_label||j.getAttrib(d,"aria-label",a.getLang("aria.rich_text_area")),a.fire("ScriptsLoaded"),n(a),m(a),b=o(a),c.content_css&&h.each(h.explode(c.content_css),function(b){a.contentCSS.push(a.documentBaseURI.toAbsolute(b))}),c.content_editable)return e.initContentBody(a);var f=q(a,b);b.editorContainer&&(j.get(b.editorContainer).style.display=a.orgDisplay,a.hidden=j.isHidd
 en(b.editorContainer)),a.getElement().style.display="none",j.setAttrib(a.id,"aria-hidden",!0),f||e.initContentBody(a)};return{init:r}}),g("2f",["5r","7","8","c","d","f","o","2l","5s","5t","5u","1d"],function(a,b,c,d,e,f,g,h,i,j,k,l){var m=d.DOM,n=function(a,b){var c=a.settings,d=f.ScriptLoader;if(c.language&&"en"!=c.language&&!c.language_url&&(c.language_url=a.editorManager.baseURL+"/langs/"+c.language+".js"),c.language_url&&d.add(c.language_url),c.theme&&"function"!=typeof c.theme&&"-"!=c.theme.charAt(0)&&!k.urls[c.theme]){var e=c.theme_url;e=e?a.documentBaseURI.toAbsolute(e):"themes/"+c.theme+"/theme"+b+".js",k.load(c.theme,e)}l.isArray(c.plugins)&&(c.plugins=c.plugins.join(" ")),l.
 each(c.external_plugins,function(a,b){j.load(b,a),c.plugins+=" "+b}),l.each(c.plugins.split(/[ ,]/),function(a){if(a=l.trim(a),a&&!j.urls[a])if("-"===a.charAt(0)){a=a.substr(1,a.length);var c=j.dependencies(a);l.each(c,function(a){var c={prefix:"plugins/",resource:a,suffix:"/plugin"+b+".js"};a=j.createUrl(c,a),j.load(a.resource,a)})}else j.load(a,{prefix:"plugins/",resource:a,suffix:"/plugin"+b+".js"})}),d.loadQueue(function(){a.removed||i.init(a)},a,function(b){h.pluginLoadError(a,b[0]),a.removed||i.init(a)})},o=function(d){function f(){m.unbind(a,"ready",f),d.render()}var h=d.settings,i=d.id;if(!e.Event.domLoaded)return void m.bind(a,"ready",f);if(d.getElement()&&g.contentEditable){h.inline?d.inline=!0:(d.orgVisibility=d.getElement().style.visibility,d.getElement().style.visibility="hidden");var j=d.getElement().form||m.getParent(i,"form");j&&
 amp;(d.formElement=j,h.hidden_input&&!/TEXTAREA|INPUT/i.test(d.getElement().nodeName)&&(m.insertAfter(m.create("input",{type:"hidden",name:i}),i),d.hasHiddenInput=!0),d.formEventDelegate=function(a){d.fire(a.type,a)},m.bind(j,"submit reset",d.formEventDelegate),d.on("reset",function(){d.setContent(d.startContent,{format:"raw"})}),!h.submit_patch||j.submit.nodeType||j.submit.length||j._mceOldSubmit||(j._mceOldSubmit=j.submit,j.submit=function(){return d.editorManager.triggerSave(),d.setDirty(!1),j._mceOldSubmit(j)})),d.windowManager=new c(d),d.notificationManager=new b(d),"xml"===h.encoding&&d.on("GetContent",function(a){a.save&&(a.content=m.encode(a.content))}),h.add_form_submit_trigger&&d.on("submit",function(){d.initialized&&d.save()}),h.add_unload_trigger&&(d._beforeUnload=function(){!d.initialized||d.destroyed||d.isHidden()||d.save({format:&quot
 ;raw",no_events:!0,set_dirty:!1})},d.editorManager.on("BeforeUnload",d._beforeUnload)),d.editorManager.add(d),n(d,d.suffix)}};return{render:o}}),g("2g",[],function(){function a(a,b,c){try{a.getDoc().execCommand(b,!1,c)}catch(a){}}function b(a){var b,c;return b=a.getBody(),c=function(b){a.dom.getParents(b.target,"a").length>0&&b.preventDefault()},a.dom.bind(b,"click",c),{unbind:function(){a.dom.unbind(b,"click",c)}}}function c(c,d){c._clickBlocker&&(c._clickBlocker.unbind(),c._clickBlocker=null),d?(c._clickBlocker=b(c),c.selection.controlSelection.hideResizeRect(),c.readonly=!0,c.getBody().contentEditable=!1):(c.readonly=!1,c.getBody().contentEditable=!0,a(c,"StyleWithCSS",!1),a(c,"enableInlineTableEditing",!1),a(c,"enableObjectResizing",!1),c.focus(),c.nodeChanged())}function d(a,b){var d=a.readonly?"readonly":"design";b!=d&&(a.initialized?c(a,"rea
 donly"==b):a.on("init",function(){c(a,"readonly"==b)}),a.fire("SwitchMode",{mode:b}))}return{setMode:d}}),g("z",["1d","o"],function(a,b){var c=a.each,d=a.explode,e={f9:120,f10:121,f11:122},f=a.makeMap("alt,ctrl,shift,meta,access");return function(g){function h(a){var g,h,i={};c(d(a,"+"),function(a){a in f?i[a]=!0:/^[0-9]{2,}$/.test(a)?i.keyCode=parseInt(a,10):(i.charCode=a.charCodeAt(0),i.keyCode=e[a]||a.toUpperCase().charCodeAt(0));
+}),g=[i.keyCode];for(h in f)i[h]?g.push(h):i[h]=!1;return i.id=g.join(","),i.access&&(i.alt=!0,b.mac?i.ctrl=!0:i.shift=!0),i.meta&&(b.mac?i.meta=!0:(i.ctrl=!0,i.meta=!1)),i}function i(b,c,e,f){var i;return i=a.map(d(b,">"),h),i[i.length-1]=a.extend(i[i.length-1],{func:e,scope:f||g}),a.extend(i[0],{desc:g.translate(c),subpatterns:i.slice(1)})}function j(a){return a.altKey||a.ctrlKey||a.metaKey}function k(a){return"keydown"===a.type&&a.keyCode>=112&&a.keyCode<=123}function l(a,b){return!!b&&(b.ctrl==a.ctrlKey&&b.meta==a.metaKey&&(b.alt==a.altKey&&b.shift==a.shiftKey&&(!!(a.keyCode==b.keyCode||a.charCode&&a.charCode==b.charCode)&&(a.preventDefault(),!0))))}function m(a){return a.func?a.func.call(a.scope):null}var n=this,o={},p=[];g.on("keyup keypress keydown",function(a){!j(a)&&!k(a)||a.isDefaultPrevented()||(c(o,function(b){if(l(a,b))return p
 =b.subpatterns.slice(0),"keydown"==a.type&&m(b),!0}),l(a,p[0])&&(1===p.length&&"keydown"==a.type&&m(p[0]),p.shift()))}),n.add=function(b,e,f,h){var j;return j=f,"string"==typeof f?f=function(){g.execCommand(j,!1,null)}:a.isArray(j)&&(f=function(){g.execCommand(j[0],j[1],j[2])}),c(d(a.trim(b.toLowerCase())),function(a){var b=i(a,e,f,h);o[b.id]=b}),!0},n.remove=function(a){var b=i(a);return!!o[b.id]&&(delete o[b.id],!0)}}}),g("2h",[],function(){var a=function(a,b,c){var d=a.sidebars?a.sidebars:[];d.push({name:b,settings:c}),a.sidebars=d};return{add:a}}),g("1e",["2i","1d"],function(a,b){function c(b,g){var h,i,j=this;if(b=e(b),g=j.settings=g||{},h=g.base_uri,/^([\w\-]+):([^\/]{2})/i.test(b)||/^\s*#/.test(b))return void(j.source=b);var k=0===b.indexOf("//");0!==b.indexOf("/")||k||(b=(h?h.protocol||"http":"http")+"://mce_host&q
 uot;+b),/^[\w\-]*:?\/\//.test(b)||(i=g.base_uri?g.base_uri.path:new c(a.location.href).directory,""===g.base_uri.protocol?b="//mce_host"+j.toAbsPath(i,b):(b=/([^#?]*)([#?]?.*)/.exec(b),b=(h&&h.protocol||"http")+"://mce_host"+j.toAbsPath(i,b[1])+b[2])),b=b.replace(/@@/g,"(mce_at)"),b=/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(b),d(f,function(a,c){var d=b[c];d&&(d=d.replace(/\(mce_at\)/g,"@@")),j[a]=d}),h&&(j.protocol||(j.protocol=h.protocol),j.userInfo||(j.userInfo=h.userInfo),j.port||"mce_host"!==j.host||(j.port=h.port),j.host&&"mce_host"!==j.host||(j.host=h.host),j.source=""),k&&(j.protocol="")}var d=b.each,e=b.trim,f="source protocol authority userInfo user password host port relative
  path directory file query anchor".split(" "),g={ftp:21,http:80,https:443,mailto:25};return c.prototype={setPath:function(a){var b=this;a=/^(.*?)\/?(\w+)?$/.exec(a),b.path=a[0],b.directory=a[1],b.file=a[2],b.source="",b.getURI()},toRelative:function(a){var b,d=this;if("./"===a)return a;if(a=new c(a,{base_uri:d}),"mce_host"!=a.host&&d.host!=a.host&&a.host||d.port!=a.port||d.protocol!=a.protocol&&""!==a.protocol)return a.getURI();var e=d.getURI(),f=a.getURI();return e==f||"/"==e.charAt(e.length-1)&&e.substr(0,e.length-1)==f?e:(b=d.toRelPath(d.path,a.path),a.query&&(b+="?"+a.query),a.anchor&&(b+="#"+a.anchor),b)},toAbsolute:function(a,b){return a=new c(a,{base_uri:this}),a.getURI(b&&this.isSameOrigin(a))},isSameOrigin:function(a){if(this.host==a.host&&this.protocol==a.protocol){if(this.port==a.port)return!0;var b=g[this.protocol];if(b&
 &(this.port||b)==(a.port||b))return!0}return!1},toRelPath:function(a,b){var c,d,e,f=0,g="";if(a=a.substring(0,a.lastIndexOf("/")),a=a.split("/"),c=b.split("/"),a.length>=c.length)for(d=0,e=a.length;d<e;d++)if(d>=c.length||a[d]!=c[d]){f=d+1;break}if(a.length<c.length)for(d=0,e=c.length;d<e;d++)if(d>=a.length||a[d]!=c[d]){f=d+1;break}if(1===f)return b;for(d=0,e=a.length-(f-1);d<e;d++)g+="../";for(d=f-1,e=c.length;d<e;d++)g+=d!=f-1?"/"+c[d]:c[d];return g},toAbsPath:function(a,b){var c,e,f,g=0,h=[];for(e=/\/$/.test(b)?"/":"",a=a.split("/"),b=b.split("/"),d(a,function(a){a&&h.push(a)}),a=h,c=b.length-1,h=[];c>=0;c--)0!==b[c].length&&"."!==b[c]&&(".."!==b[c]?g>0?g--:h.push(b[c]):g++);return c=a.length-g,f=c<=0?h.reverse().join("/"):a.slice(0,c).join("/")+"/"+h.reverse().join("
 /"),0!==f.indexOf("/")&&(f="/"+f),e&&f.lastIndexOf("/")!==f.length-1&&(f+=e),f},getURI:function(a){var b,c=this;return c.source&&!a||(b="",a||(b+=c.protocol?c.protocol+"://":"//",c.userInfo&&(b+=c.userInfo+"@"),c.host&&(b+=c.host),c.port&&(b+=":"+c.port)),c.path&&(b+=c.path),c.query&&(b+="?"+c.query),c.anchor&&(b+="#"+c.anchor),c.source=b),c.source}},c.parseDataUri=function(a){var b,c;return a=decodeURIComponent(a).split(","),c=/data:([^;]+)/.exec(a[0]),c&&(b=c[1]),{type:b,data:a[1]}},c.getDocumentBaseUrl=function(a){var b;return b=0!==a.protocol.indexOf("http")&&"file:"!==a.protocol?a.href:a.protocol+"//"+a.host+a.pathname,/^[^:]+:\/\/\/?[^\/]+\//.test(b)&&(b=b.replace(/[\?#].*$/,"").replace(/[\/\\][^\/]+$/,""),/[\/\\
 ]$/.test(b)||(b+="/")),b},c}),g("k",["5","b","c","l","2d","n","2e","o","w","2f","2g","z","2h","1d","1e","2j"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p){function q(c,e,f){var i,j,k=this;i=k.documentBaseUrl=f.documentBaseURL,j=f.baseURI,e=g.getEditorSettings(k,c,i,f.defaultSettings,e),k.settings=e,a.language=e.language||"en",a.languageLoad=e.language_load,a.baseURL=f.baseURL,k.id=c,k.setDirty(!1),k.plugins={},k.documentBaseURI=new o(e.document_base_url,{base_uri:j}),k.baseURI=j,k.contentCSS=[],k.contentStyles=[],k.shortcuts=new l(k),k.loadedCSS={},k.editorCommands=new d(k),k.suffix=f.suffix,k.editorManager=f,k.inline=e.inline,e.cache_suffix&&(h.cacheSuffix=e.cache_suffix.replace(/^[\?\&]+/,"")),e.override_viewport===!1&&(h.overrideViewPort=!1),f.fire("SetupEditor&
 quot;,k),k.execCallback("setup",k),k.$=b.overrideDefaults(function(){return{context:k.inline?k.getBody():k.getDoc(),element:k.getBody()}})}var r=c.DOM,s=n.extend,t=n.each,u=n.trim,v=n.resolve,w=h.ie;return q.prototype={render:function(){j.render(this)},focus:function(a){e.focus(this,a)},execCallback:function(a){var b,c=this,d=c.settings[a];if(d)return c.callbackLookup&&(b=c.callbackLookup[a])&&(d=b.func,b=b.scope),"string"==typeof d&&(b=d.replace(/\.\w+$/,""),b=b?v(b):0,d=v(d),c.callbackLookup=c.callbackLookup||{},c.callbackLookup[a]={func:d,scope:b}),d.apply(b||c,Array.prototype.slice.call(arguments,1))},translate:function(a){if(a&&n.is(a,"string")){var b=this.settings.language||"en",c=this.editorManager.i18n;a=c.data[b+"."+a]||a.replace(/\{\#([^\}]+)\}/g,function(a,d){return c.data[b+"."+d]||"{#"+d+"}"})}return this.editorManager.translate(a)},getLang:function(
 a,b){return this.editorManager.i18n.data[(this.settings.language||"en")+"."+a]||(void 0!==b?b:"{#"+a+"}")},getParam:function(a,b,c){var d,e=a in this.settings?this.settings[a]:b;return"hash"===c?(d={},"string"==typeof e?t(e.indexOf("=")>0?e.split(/[;,](?![^=;,]*(?:[;,]|$))/):e.split(","),function(a){a=a.split("="),a.length>1?d[u(a[0])]=u(a[1]):d[u(a[0])]=u(a)}):d=e,d):e},nodeChanged:function(a){this._nodeChangeDispatcher.nodeChanged(a)},addButton:function(a,b){var c=this;b.cmd&&(b.onclick=function(){c.execCommand(b.cmd)}),b.text||b.icon||(b.icon=a),c.buttons=c.buttons||{},b.tooltip=b.tooltip||b.title,c.buttons[a]=b},addSidebar:function(a,b){return m.add(this,a,b)},addMenuItem:function(a,b){var c=this;b.cmd&&(b.onclick=function(){c.execCommand(b.cmd)}),c.menuItems=c.menuItems||{},c.menuItems[a]=b},addContextToolbar:function(a,b){var c,d=this;d.contextToolbars=d.contextToolb
 ars||[],"string"==typeof a&&(c=a,a=function(a){return d.dom.is(a,c)}),d.contextToolbars.push({id:p.uuid("mcet"),predicate:a,items:b})},addCommand:function(a,b,c){this.editorCommands.addCommand(a,b,c)},addQueryStateHandler:function(a,b,c){this.editorCommands.addQueryStateHandler(a,b,c)},addQueryValueHandler:function(a,b,c){this.editorCommands.addQueryValueHandler(a,b,c)},addShortcut:function(a,b,c,d){this.shortcuts.add(a,b,c,d)},execCommand:function(a,b,c,d){return this.editorCommands.execCommand(a,b,c,d)},queryCommandState:function(a){return this.editorCommands.queryCommandState(a)},queryCommandValue:function(a){return this.editorCommands.queryCommandValue(a)},queryCommandSupported:function(a){return this.editorCommands.queryCommandSupported(a)},show:function(){var a=this;a.hidden&&(a.hidden=!1,a.inline?a.getBody().contentEditable=!0:(r.show(a.getContainer()),r.hide(a.id)),a.load(),a.fire("show"))},hide:function(){var a=this,b=a.getDoc()
 ;a.hidden||(w&&b&&!a.inline&&b.execCommand("SelectAll"),a.save(),a.inline?(a.getBody().contentEditable=!1,a==a.editorManager.focusedEditor&&(a.editorManager.focusedEditor=null)):(r.hide(a.getContainer()),r.setStyle(a.id,"display",a.orgDisplay)),a.hidden=!0,a.fire("hide"))},isHidden:function(){return!!this.hidden},setProgressState:function(a,b){this.fire("ProgressState",{state:a,time:b})},load:function(a){var b,c=this,d=c.getElement();return c.removed?"":d?(a=a||{},a.load=!0,b=c.setContent(void 0!==d.value?d.value:d.innerHTML,a),a.element=d,a.no_events||c.fire("LoadContent",a),a.element=d=null,b):void 0},save:function(a){var b,c,d=this,e=d.getElement();if(e&&d.initialized&&!d.removed)return a=a||{},a.save=!0,a.element=e,b=a.content=d.getContent(a),a.no_events||d.fire("SaveContent",a),"raw"==a.format&&d.fire("RawSaveContent",a),b=a.content,/
 TEXTAREA|INPUT/i.test(e.nodeName)?e.value=b:(d.inline||(e.innerHTML=b),(c=r.getParent(d.id,"form"))&&t(c.elements,function(a){if(a.name==d.id)return a.value=b,!1})),a.element=e=null,a.set_dirty!==!1&&d.setDirty(!1),b},setContent:function(a,b){var c,d,e=this,f=e.getBody();return b=b||{},b.format=b.format||"html",b.set=!0,b.content=a,b.no_events||e.fire("BeforeSetContent",b),a=b.content,0===a.length||/^\s+$/.test(a)?(d=w&&w<11?"":'<br data-mce-bogus="1">',"TABLE"==f.nodeName?a="<tr><td>"+d+"</td></tr>":/^(UL|OL)$/.test(f.nodeName)&&(a="<li>"+d+"</li>"),c=e.settings.forced_root_block,c&&e.schema.isValidChild(f.nodeName.toLowerCase(),c.toLowerCase())?(a=d,a=e.dom.createHTML(c,e.settings.forced_root_block_attrs,a)):w||a||(a='<br data-mce-bogus="1">'),e.dom.setHTML(f,a),e.fire("SetConte
 nt",b)):("raw"!==b.format&&(a=new i({validate:e.validate},e.schema).serialize(e.parser.parse(a,{isRootContent:!0}))),b.content=u(a),e.dom.setHTML(f,b.content),b.no_events||e.fire("SetContent",b)),b.content},getContent:function(a){var b,c=this,d=c.getBody();return c.removed?"":(a=a||{},a.format=a.format||"html",a.get=!0,a.getInner=!0,a.no_events||c.fire("BeforeGetContent",a),b="raw"==a.format?n.trim(c.serializer.getTrimmedContent()):"text"==a.format?d.innerText||d.textContent:c.serializer.serialize(d,a),"text"!=a.format?a.content=u(b):a.content=b,a.no_events||c.fire("GetContent",a),a.content)},insertContent:function(a,b){b&&(a=s({content:a},b)),this.execCommand("mceInsertContent",!1,a)},isDirty:function(){return!this.isNotDirty},setDirty:function(a){var b=!this.isNotDirty;this.isNotDirty=!a,a&&a!=b&&this.fire("dirty")},setMode:function(a){
 k.setMode(this,a)},getContainer:function(){var a=this;return a.container||(a.container=r.get(a.editorContainer||a.id+"_parent")),a.container},getContentAreaContainer:function(){return this.contentAreaContainer},getElement:function(){return this.targetElm||(this.targetElm=r.get(this.id)),this.targetElm},getWin:function(){var a,b=this;return b.contentWindow||(a=b.iframeElement,a&&(b.contentWindow=a.contentWindow)),b.contentWindow},getDoc:function(){var a,b=this;return b.contentDocument||(a=b.getWin(),a&&(b.contentDocument=a.document)),b.contentDocument},getBody:function(){var a=this.getDoc();return this.bodyElement||(a?a.body:null)},convertURL:function(a,b,c){var d=this,e=d.settings;return e.urlconverter_callback?d.execCallback("urlconverter_callback",a,c,!0,b):!e.convert_urls||c&&"LINK"==c.nodeName||0===a.indexOf("file:")||0===a.length?a:e.relative_urls?d.documentBaseURI.toRelative(a):a=d.documentBaseURI.toAbsolute(a,e.r
 emove_script_host)},addVisual:function(a){var b,c=this,d=c.settings,e=c.dom;a=a||c.getBody(),void 0===c.hasVisual&&(c.hasVisual=d.visual),t(e.select("table,a",a),function(a){var f;switch(a.nodeName){case"TABLE":return b=d.visual_table_class||"mce-item-table",f=e.getAttrib(a,"border"),void(f&&"0"!=f||!c.hasVisual?e.removeClass(a,b):e.addClass(a,b));case"A":return void(e.getAttrib(a,"href",!1)||(f=e.getAttrib(a,"name")||a.id,b=d.visual_anchor_class||"mce-item-anchor",f&&c.hasVisual?e.addClass(a,b):e.removeClass(a,b)))}}),c.fire("VisualAid",{element:a,hasVisual:c.hasVisual})},remove:function(){var a=this;a.removed||(a.save(),a.removed=1,a.unbindAllNativeEvents(),a.hasHiddenInput&&r.remove(a.getElement().nextSibling),a.inline||(w&&w<10&&a.getDoc().execCommand("SelectAll",!1,null),r.setStyle(a.id,"display",a.orgDisplay)
 ,a.getBody().onload=null),a.fire("remove"),a.editorManager.remove(a),r.remove(a.getContainer()),a._selectionOverrides.destroy(),a.editorUpload.destroy(),a.destroy())},destroy:function(a){var b,c=this;if(!c.destroyed){if(!a&&!c.removed)return void c.remove();a||(c.editorManager.off("beforeunload",c._beforeUnload),c.theme&&c.theme.destroy&&c.theme.destroy(),c.selection.destroy(),c.dom.destroy()),b=c.formElement,b&&(b._mceOldSubmit&&(b.submit=b._mceOldSubmit,b._mceOldSubmit=null),r.unbind(b,"submit reset",c.formEventDelegate)),c.contentAreaContainer=c.formElement=c.container=c.editorContainer=null,c.bodyElement=c.contentDocument=c.contentWindow=null,c.iframeElement=c.targetElm=null,c.selection&&(c.selection=c.selection.win=c.selection.dom=c.selection.dom.doc=null),c.destroyed=1}},uploadImages:function(a){return this.editorUpload.uploadImages(a)},_scanForImages:function(){return this.editorUpload.scanForImages
 ()}},s(q.prototype,f),q}),g("p",["c","14","o"],function(a,b,c){function d(a){function d(){try{return document.activeElement}catch(a){return document.body}}function j(a,b){if(b&&b.startContainer){if(!a.isChildOf(b.startContainer,a.getRoot())||!a.isChildOf(b.endContainer,a.getRoot()))return;return{startContainer:b.startContainer,startOffset:b.startOffset,endContainer:b.endContainer,endOffset:b.endOffset}}return b}function l(a,b){var c;return b.startContainer?(c=a.getDoc().createRange(),c.setStart(b.startContainer,b.startOffset),c.setEnd(b.endContainer,b.endOffset)):c=b,c}function m(e){var m=e.editor;m.on("init",function(){(m.inline||c.ie)&&("onbeforedeactivate"in document&&c.ie<9?m.dom.bind(m.getBody(),"beforedeactivate",function(a){if(a.target==m.getBody())try{m.lastRng=m.selection.getRng()}catch(a){}}):m.on("nodechange mouseup keyup",function(a){var b=d();"nodechange"
 ==a.type&&a.selectionChange||(b&&b.id==m.id+"_ifr"&&(b=m.getBody()),m.dom.isChildOf(b,m.getBody())&&(m.lastRng=m.selection.getRng()))}))}),m.on("setcontent",function(){m.lastRng=null}),m.on("mousedown",function(){m.selection.lastFocusBookmark=null}),m.on("focusin",function(){var b,c=a.focusedEditor;m.selection.lastFocusBookmark&&(b=l(m,m.selection.lastFocusBookmark),m.selection.lastFocusBookmark=null,m.selection.setRng(b)),c!=m&&(c&&c.fire("blur",{focusedEditor:m}),a.setActive(m),a.focusedEditor=m,m.fire("focus",{blurredEditor:c}),m.focus(!0)),m.lastRng=null}),m.on("focusout",function(){b.setEditorTimeout(m,function(){var b=a.focusedEditor;i(m,d())||b!=m||(m.fire("blur",{focusedEditor:null}),a.focusedEditor=null,m.selection&&(m.selection.lastFocusBookmark=null))})}),f||(f=function(b){var c,d=a.activeEditor;c=b.target,d&&c.ownerDocume
 nt===document&&(d.selection&&c!==d.getBody()&&k(m,c)&&(d.selection.lastFocusBookmark=j(d.dom,d.lastRng)),c===document.body||i(d,c)||a.focusedEditor!==d||(d.fire("blur",{focusedEditor:null}),a.focusedEditor=null))},h.bind(document,"focusin",f)),m.inline&&!g&&(g=function(b){var c=a.activeEditor,d=c.dom;if(c.inline&&d&&!d.isChildOf(b.target,c.getBody())){var e=c.selection.getRng();e.collapsed||(c.lastRng=e)}},h.bind(document,"mouseup",g))}function n(b){a.focusedEditor==b.editor&&(a.focusedEditor=null),a.activeEditor||(h.unbind(document,"selectionchange",e),h.unbind(document,"focusin",f),h.unbind(document,"mouseup",g),e=f=g=null)}a.on("AddEditor",m),a.on("RemoveEditor",n)}var e,f,g,h=a.DOM,i=function(a,b){var c=a?a.settings.custom_ui_selector:"",e=h.getParent(b,function(b){return d.isEditorUIElement(b)||!!c&&a.dom.is(b,
 c)});return null!==e},j=function(a){return a.inline===!0},k=function(a,b){return j(a)===!1||a.dom.isChildOf(b,a.getBody())===!1};return d.isEditorUIElement=function(a){return a.className.toString().indexOf("mce-")!==-1},d._isUIElement=i,d}),g("2m",["1d"],function(a){var b=a.each,c=a.explode,d=function(a){a.on("AddEditor",function(a){var d=a.editor;d.on("preInit",function(){function a(a,c){b(c,function(b,c){b&&h.setStyle(a,c,b)}),h.rename(a,"span")}function e(a){h=d.dom,i.convert_fonts_to_spans&&b(h.select("font,u,strike",a.node),function(a){f[a.nodeName.toLowerCase()](h,a)})}var f,g,h,i=d.settings;i.inline_styles&&(g=c(i.font_size_legacy_values),f={font:function(b,c){a(c,{backgroundColor:c.style.backgroundColor,color:c.color,fontFamily:c.face,fontSize:g[parseInt(c.size,10)-1]})},u:function(b,c){"html4"===d.settings.schema&&a(c,{textDecoration:"underline"})},strik
 e:function(b,c){a(c,{textDecoration:"line-through"})}},d.on("PreProcess SetContent",e))})})};return{register:d}}),g("16",["1d"],function(a){"use strict";var b={},c="en";return{setCode:function(a){a&&(c=a,this.rtl=!!this.data[a]&&"rtl"===this.data[a]._dir)},getCode:function(){return c},rtl:!1,add:function(a,c){var d=b[a];d||(b[a]=d={});for(var e in c)d[e]=c[e];this.setCode(a)},translate:function(d){function e(b){return a.is(b,"function")?Object.prototype.toString.call(b):f(b)?"":""+b}function f(b){return""===b||null===b||a.is(b,"undefined")}function g(b){return b=e(b),a.hasOwn(h,b)?e(h[b]):b}var h=b[c]||{};if(f(d))return"";if(a.is(d,"object")&&a.hasOwn(d,"raw"))return e(d.raw);if(a.is(d,"array")){var i=d.slice(1);d=g(d[0]).replace(/\{([0-9]+)\}/g,function(b,c){return a.hasOwn(i,c)?e(i[c]):b})}return g(d
 ).replace(/{context:\w+}$/,"")},data:b}}),g("m",["1t","2k","5","b","c","k","o","2l","p","2m","16","1b","1c","1d","1e"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o){function p(a){x(u.get(),function(b){"scroll"===a.type?b.fire("ScrollWindow",a):b.fire("ResizeWindow",a)})}function q(a){a!==A&&(a?d(window).on("resize scroll",p):d(window).off("resize scroll",p),A=a)}function r(b){var c=C;delete B[b.id];for(var d=0;d<B.length;d++)if(B[d]===b){B.splice(d,1);break}return C=a.filter(C,function(a){return b!==a}),u.activeEditor===b&&(u.activeEditor=C.length>0?C[0]:null),u.focusedEditor===b&&(u.focusedEditor=null),c.length!==C.length}function s(a){return a&&a.initialized&&!(a.getContainer()||a.getBody()).parentNode&&(r(a),a.unbind
 AllNativeEvents(),a.destroy(!0),a.removed=!0,a=null),a}var t,u,v=e.DOM,w=n.explode,x=n.each,y=n.extend,z=0,A=!1,B=[],C=[],D=function(a){return"length"!==a};return u={$:d,majorVersion:"4",minorVersion:"6.7",releaseDate:"2017-09-18",editors:B,i18n:k,activeEditor:null,settings:{},setup:function(){var a,b,c,d,e=this,f="";if(b=o.getDocumentBaseUrl(document.location),/^[^:]+:\/\/\/?[^\/]+\//.test(b)&&(b=b.replace(/[\?#].*$/,"").replace(/[\/\\][^\/]+$/,""),/[\/\\]$/.test(b)||(b+="/")),c=window.tinymce||window.tinyMCEPreInit)a=c.base||c.baseURL,f=c.suffix;else{for(var g=document.getElementsByTagName("script"),h=0;h<g.length;h++){d=g[h].src;var j=d.substring(d.lastIndexOf("/"));if(/tinymce(\.full|\.jquery|)(\.min|\.dev|)\.js/.test(d)){j.indexOf(".min")!=-1&&(f=".min"),a=d.substring(0,d.lastIndexOf("/"));break}}!a&&document.currentScript&
 amp;&(d=document.currentScript.src,d.indexOf(".min")!=-1&&(f=".min"),a=d.substring(0,d.lastIndexOf("/")))}e.baseURL=new o(b).toAbsolute(a),e.documentBaseURL=b,e.baseURI=new o(e.baseURL),e.suffix=f,e.focusManager=new i(e)},overrideDefaults:function(a){var b,d;b=a.base_url,b&&(this.baseURL=new o(this.documentBaseURL).toAbsolute(b.replace(/\/+$/,"")),this.baseURI=new o(this.baseURL)),d=a.suffix,a.suffix&&(this.suffix=d),this.defaultSettings=a;var e=a.plugin_base_urls;for(var f in e)c.PluginManager.urls[f]=e[f]},init:function(a){function b(a,b){return a.inline&&b.tagName.toLowerCase()in o}function c(a){var b=a.id;return b||(b=a.name,b=b&&!v.get(b)?a.name:v.uniqueId(),a.setAttribute("id",b)),b}function e(b){var c=a[b];if(c)return c.apply(p,Array.prototype.slice.call(arguments,2))}function i(a,b){return b.constructor===RegExp?b.test(a.className):v.hasClass(a,b)}function j(a){var b,c=[];if(g.ie&am
 p;&g.ie<11)return h.initError("TinyMCE does not support the browser you are using. For a list of supported browsers please see: https://www.tinymce.com/docs/get-started/system-requirements/"),[];if(a.types)return x(a.types,function(a){c=c.concat(v.select(a.selector))}),c;if(a.selector)return v.select(a.selector);if(a.target)return[a.target];switch(a.mode){case"exact":b=a.elements||"",b.length>0&&x(w(b),function(a){var b;(b=v.get(a))?c.push(b):x(document.forms,function(b){x(b.elements,function(b){b.name===a&&(a="mce_editor_"+z++,v.setAttrib(b,"id",a),c.push(b))})})});break;case"textareas":case"specific_textareas":x(v.select("textarea"),function(b){a.editor_deselector&&i(b,a.editor_deselector)||a.editor_selector&&!i(b,a.editor_selector)||c.push(b)})}return c}function k(){function g(a,b,c){var d=new f(a,b,p);m.push(d),d.on("init",function(){++l===i.length&
 amp;&q(m)}),d.targetElm=d.targetElm||c,d.render()}var i,l=0,m=[];return v.unbind(window,"ready",k),e("onpageload"),i=d.unique(j(a)),a.types?void x(a.types,function(b){n.each(i,function(d){return!v.is(d,b.selector)||(g(c(d),y({},a,b),d),!1)})}):(n.each(i,function(a){s(p.get(a.id))}),i=n.grep(i,function(a){return!p.get(a.id)}),void(0===i.length?q([]):x(i,function(d){b(a,d)?h.initError("Could not initialize inline editor on invalid inline target element",d):g(c(d),a,d)})))}var l,o,p=this;o=n.makeMap("area base basefont br col frame hr img input isindex link meta param embed source wbr track colgroup option tbody tfoot thead tr script noscript style textarea video audio iframe object menu"," ");var q=function(a){l=a};return p.settings=a,v.bind(window,"ready",k),new m(function(a){l?a(l):q=function(b){a(b)}})},get:function(c){return 0===arguments.length?C.slice(0):b.isString(c)?a.find(C,function(a){return a.id===c}).getOr(nul
 l):b.isNumber(c)&&C[c]?C[c]:null},add:function(a){var b,c=this;return b=B[a.id],b===a?a:(null===c.get(a.id)&&(D(a.id)&&(B[a.id]=a),B.push(a),C.push(a)),q(!0),c.activeEditor=a,c.fire("AddEditor",{editor:a}),t||(t=function(){c.fire("BeforeUnload")},v.bind(window,"beforeunload",t)),a)},createEditor:function(a,b){return this.add(new f(a,b,this))},remove:function(a){var c,d,e=this;{if(a)return b.isString(a)?(a=a.selector||a,void x(v.select(a),function(a){d=e.get(a.id),d&&e.remove(d)})):(d=a,b.isNull(e.get(d.id))?null:(r(d)&&e.fire("RemoveEditor",{editor:d}),0===C.length&&v.unbind(window,"beforeunload",t),d.remove(),q(C.length>0),d));for(c=C.length-1;c>=0;c--)e.remove(C[c])}},execCommand:function(a,b,c){var d=this,e=d.get(c);switch(a){case"mceAddEditor":return d.get(c)||new f(c,d.settings,d).render(),!0;case"mceRemoveEditor":return e&&e.remove(),!0;case"
 mceToggleEditor":return e?(e.isHidden()?e.show():e.hide(),!0):(d.execCommand("mceAddEditor",0,c),!0)}return!!d.activeEditor&&d.activeEditor.execCommand(a,b,c)},triggerSave:function(){x(C,function(a){a.save()})},addI18n:function(a,b){k.add(a,b)},translate:function(a){return k.translate(a)},setActive:function(a){var b=this.activeEditor;this.activeEditor!=a&&(b&&b.fire("deactivate",{relatedTarget:a}),a.fire("activate",{relatedTarget:b})),this.activeEditor=a}},y(u,l),u.setup(),j.register(u),u}),g("q",[],function(){"use strict";function a(a,b,c){var d,e,g,h,i,k;return d=b.x,e=b.y,g=a.w,h=a.h,i=b.w,k=b.h,c=(c||"").split(""),"b"===c[0]&&(e+=k),"r"===c[1]&&(d+=i),"c"===c[0]&&(e+=j(k/2)),"c"===c[1]&&(d+=j(i/2)),"b"===c[3]&&(e-=h),"r"===c[4]&&(d-=g),"c"===c[3]&&(e-=j(h/2)
 ),"c"===c[4]&&(d-=j(g/2)),f(d,e,g,h)}function b(b,c,d,e){var f,g;for(g=0;g<e.length;g++)if(f=a(b,c,e[g]),f.x>=d.x&&f.x+f.w<=d.w+d.x&&f.y>=d.y&&f.y+f.h<=d.h+d.y)return e[g];return null}function c(a,b,c){return f(a.x-b,a.y-c,a.w+2*b,a.h+2*c)}function d(a,b){var c,d,e,g;return c=i(a.x,b.x),d=i(a.y,b.y),e=h(a.x+a.w,b.x+b.w),g=h(a.y+a.h,b.y+b.h),e-c<0||g-d<0?null:f(c,d,e-c,g-d)}function e(a,b,c){var d,e,g,h,j,k,l,m,n,o;return j=a.x,k=a.y,l=a.x+a.w,m=a.y+a.h,n=b.x+b.w,o=b.y+b.h,d=i(0,b.x-j),e=i(0,b.y-k),g=i(0,l-n),h=i(0,m-o),j+=d,k+=e,c&&(l+=d,m+=e,j-=g,k-=h),l-=g,m-=h,f(j,k,l-j,m-k)}function f(a,b,c,d){return{x:a,y:b,w:c,h:d}}function g(a){return f(a.left,a.top,a.width,a.height)}var h=Math.min,i=Math.max,j=Math.round;return{inflate:c,relativePosition:a,findBestRelativePosition:b,intersect:d,clamp:e,create:f,fromClientRect:g}}),g("36",["12","1d"],function(a,b){"use strict";return
  a.extend({Defaults:{firstControlClass:"first",lastControlClass:"last"},init:function(a){this.settings=b.extend({},this.Defaults,a)},preRender:function(a){a.bodyClasses.add(this.settings.containerClass)},applyClasses:function(a){var b,c,d,e,f=this,g=f.settings;b=g.firstControlClass,c=g.lastControlClass,a.each(function(a){a.classes.remove(b).remove(c).add(g.controlClass),a.visible()&&(d||(d=a),e=a)}),d&&d.classes.add(b),e&&e.classes.add(c)},renderHtml:function(a){var b=this,c="";return b.applyClasses(a.items()),a.items().each(function(a){c+=a.renderHtml()}),c},recalc:function(){},postRender:function(){},isNative:function(){return!1}})}),g("37",["36"],function(a){"use strict";return a.extend({Defaults:{containerClass:"abs-layout",controlClass:"abs-layout-item"},recalc:function(a){a.items().filter(":visible").each(function(a){var b=a.settings;a.layoutRect({x:b.x,y:b.y,w:b.w
 ,h:b.h}),a.recalc&&a.recalc()})},renderHtml:function(a){return'<div id="'+a._id+'-absend" class="'+a.classPrefix+'abs-end"></div>'+this._super(a)}})}),g("38",["33"],function(a){"use strict";return a.extend({Defaults:{classes:"widget btn",role:"button"},init:function(a){var b,c=this;c._super(a),a=c.settings,b=c.settings.size,c.on("click mousedown",function(a){a.preventDefault()}),c.on("touchstart",function(a){c.fire("click",a),a.preventDefault()}),a.subtype&&c.classes.add(a.subtype),b&&c.classes.add("btn-"+b),a.icon&&c.icon(a.icon)},icon:function(a){return arguments.length?(this.state.set("icon",a),this):this.state.get("icon")},repaint:function(){var a,b=this.getEl().firstChild;b&&(a=b.style,a.width=a.height="100%"),this._super()},renderHtml:function(){var a,b=this,c=b._id,d=b.classPrefix,e=b.st
 ate.get("icon"),f=b.state.get("text"),g="";return a=b.settings.image,a?(e="none","string"!=typeof a&&(a=window.getSelection?a[0]:a[1]),a=" style=\"background-image: url('"+a+"')\""):a="",f&&(b.classes.add("btn-has-text"),g='<span class="'+d+'txt">'+b.encode(f)+"</span>"),e=e?d+"ico "+d+"i-"+e:"",'<div id="'+c+'" class="'+b.classes+'" tabindex="-1"><button id="'+c+'-button" role="presentation" type="button" tabindex="-1">'+(e?'<i class="'+e+'"'+a+"></i>":"")+g+"</button></div>"},bindStates:function(){function a(a){var e=c("span."+d,b.getEl());a?(e[0]||(c("button:first",b.getEl()).append('<span class="'+d+'"></span>'),e=c(&qu
 ot;span."+d,b.getEl())),e.html(b.encode(a))):e.remove(),b.classes.toggle("btn-has-text",!!a)}var b=this,c=b.$,d=b.classPrefix+"txt";return b.state.on("change:text",function(b){a(b.value)}),b.state.on("change:icon",function(c){var d=c.value,e=b.classPrefix;b.settings.icon=d,d=d?e+"ico "+e+"i-"+b.settings.icon:"";var f=b.getEl().firstChild,g=f.getElementsByTagName("i")[0];d?(g&&g==f.firstChild||(g=document.createElement("i"),f.insertBefore(g,f.firstChild)),g.className=d):g&&f.removeChild(g),a(b.state.get("text"))}),b._super()}})}),g("39",["2t"],function(a){"use strict";return a.extend({Defaults:{defaultType:"button",role:"group"},renderHtml:function(){var a=this,b=a._layout;return a.classes.add("btn-group"),a.preRender(),b.preRender(a),'<div id="'+a._id+'" class="'+a.classes+'">&lt
 ;div id="'+a._id+'-body">'+(a.settings.html||"")+b.renderHtml(a)+"</div></div>"}})}),g("3a",["33"],function(a){"use strict";return a.extend({Defaults:{classes:"checkbox",role:"checkbox",checked:!1},init:function(a){var b=this;b._super(a),b.on("click mousedown",function(a){a.preventDefault()}),b.on("click",function(a){a.preventDefault(),b.disabled()||b.checked(!b.checked())}),b.checked(b.settings.checked)},checked:function(a){return arguments.length?(this.state.set("checked",a),this):this.state.get("checked")},value:function(a){return arguments.length?this.checked(a):this.checked()},renderHtml:function(){var a=this,b=a._id,c=a.classPrefix;return'<div id="'+b+'" class="'+a.classes+'" unselectable="on" aria-labelledby="'+b+'-al" tabindex="-1"><i class="'+c+"ico "+c+'i-checkbox&quo
 t;></i><span id="'+b+'-al" class="'+c+'label">'+a.encode(a.state.get("text"))+"</span></div>"},bindStates:function(){function a(a){b.classes.toggle("checked",a),b.aria("checked",a)}var b=this;return b.state.on("change:text",function(a){b.getEl("al").firstChild.data=b.translate(a.value)}),b.state.on("change:checked change:value",function(c){b.fire("change"),a(c.value)}),b.state.on("change:icon",function(a){var c=a.value,d=b.classPrefix;if("undefined"==typeof c)return b.settings.icon;b.settings.icon=c,c=c?d+"ico "+d+"i-"+b.settings.icon:"";var e=b.getEl().firstChild,f=e.getElementsByTagName("i")[0];c?(f&&f==e.firstChild||(f=document.createElement("i"),e.insertBefore(f,e.firstChild)),f.className=c):f&&e.removeChild(f)}),b.state.get("checked")&&a(!0),b._super(
 )}})}),g("3b",["33","2r","4z","b","1f","1d"],function(a,b,c,d,e,f){"use strict";return a.extend({init:function(a){var b=this;b._super(a),a=b.settings,b.classes.add("combobox"),b.subinput=!0,b.ariaTarget="inp",a.menu=a.menu||a.values,a.menu&&(a.icon="caret"),b.on("click",function(c){var e=c.target,f=b.getEl();if(d.contains(f,e)||e==f)for(;e&&e!=f;)e.id&&e.id.indexOf("-open")!=-1&&(b.fire("action"),a.menu&&(b.showMenu(),c.aria&&b.menu.items()[0].focus())),e=e.parentNode}),b.on("keydown",function(a){var c;13==a.keyCode&&"INPUT"===a.target.nodeName&&(a.preventDefault(),b.parents().reverse().each(function(a){if(a.toJSON)return c=a,!1}),b.fire("submit",{data:c.toJSON()}))}),b.on("keyup",function(a){if("INPUT"==a.target.nodeName){var c=b.st
 ate.get("value"),d=a.target.value;d!==c&&(b.state.set("value",d),b.fire("autocomplete",a))}}),b.on("mouseover",function(a){var c=b.tooltip().moveTo(-65535);if(b.statusLevel()&&a.target.className.indexOf(b.classPrefix+"status")!==-1){var d=b.statusMessage()||"Ok",e=c.text(d).show().testMoveRel(a.target,["bc-tc","bc-tl","bc-tr"]);c.classes.toggle("tooltip-n","bc-tc"==e),c.classes.toggle("tooltip-nw","bc-tl"==e),c.classes.toggle("tooltip-ne","bc-tr"==e),c.moveRel(a.target,e)}})},statusLevel:function(a){return arguments.length>0&&this.state.set("statusLevel",a),this.state.get("statusLevel")},statusMessage:function(a){return arguments.length>0&&this.state.set("statusMessage",a),this.state.get("statusMessage")},showMenu:function(){var a,c=this,d=c.settings;c.menu||
 (a=d.menu||[],a.length?a={type:"menu",items:a}:a.type=a.type||"menu",c.menu=b.create(a).parent(c).renderTo(c.getContainerElm()),c.fire("createmenu"),c.menu.reflow(),c.menu.on("cancel",function(a){a.control===c.menu&&c.focus()}),c.menu.on("show hide",function(a){a.control.items().each(function(a){a.active(a.value()==c.value())})}).fire("show"),c.menu.on("select",function(a){c.value(a.control.value())}),c.on("focusin",function(a){"INPUT"==a.target.tagName.toUpperCase()&&c.menu.hide()}),c.aria("expanded",!0)),c.menu.show(),c.menu.layoutRect({w:c.layoutRect().w}),c.menu.moveRel(c.getEl(),c.isRtl()?["br-tr","tr-br"]:["bl-tl","tl-bl"])},focus:function(){this.getEl("inp").focus()},repaint:function(){var a,b,e=this,f=e.getEl(),g=e.getEl("open"),h=e.layoutRect(),i=0,j=f.firstChild;e.statusLevel()&&"none&qu
 ot;!==e.statusLevel()&&(i=parseInt(c.getRuntimeStyle(j,"padding-right"),10)-parseInt(c.getRuntimeStyle(j,"padding-left"),10)),a=g?h.w-c.getSize(g).width-10:h.w-10;var k=document;return k.all&&(!k.documentMode||k.documentMode<=8)&&(b=e.layoutRect().h-2+"px"),d(j).css({width:a-i,lineHeight:b}),e._super(),e},postRender:function(){var a=this;return d(this.getEl("inp")).on("change",function(b){a.state.set("value",b.target.value),a.fire("change",b)}),a._super();
+},renderHtml:function(){var a,b,c=this,d=c._id,e=c.settings,f=c.classPrefix,g=c.state.get("value")||"",h="",i="",j="";return"spellcheck"in e&&(i+=' spellcheck="'+e.spellcheck+'"'),e.maxLength&&(i+=' maxlength="'+e.maxLength+'"'),e.size&&(i+=' size="'+e.size+'"'),e.subtype&&(i+=' type="'+e.subtype+'"'),j='<i id="'+d+'-status" class="mce-status mce-ico" style="display: none"></i>',c.disabled()&&(i+=' disabled="disabled"'),a=e.icon,a&&"caret"!=a&&(a=f+"ico "+f+"i-"+e.icon),b=c.state.get("text"),(a||b)&&(h='<div id="'+d+'-open" class="'+f+"btn "+f+'open" tabIndex="-1" role="button"><button id="'+d+'-action" type="button" hidefocus="1" tabindex=&quo
 t;-1">'+("caret"!=a?'<i class="'+a+'"></i>':'<i class="'+f+'caret"></i>')+(b?(a?" ":"")+b:"")+"</button></div>",c.classes.add("has-open")),'<div id="'+d+'" class="'+c.classes+'"><input id="'+d+'-inp" class="'+f+'textbox" value="'+c.encode(g,!1)+'" hidefocus="1"'+i+' placeholder="'+c.encode(e.placeholder)+'" />'+j+h+"</div>"},value:function(a){return arguments.length?(this.state.set("value",a),this):(this.state.get("rendered")&&this.state.set("value",this.getEl("inp").value),this.state.get("value"))},showAutoComplete:function(a,c){var d=this;if(0===a.length)return void d.hideMenu();var e=function(a,b){return function(){d.fire("selectitem",{title:b,value:a})}};d.menu?d.menu.items().remove():d.menu=b.
 create({type:"menu",classes:"combobox-menu",layout:"flow"}).parent(d).renderTo(),f.each(a,function(a){d.menu.add({text:a.title,url:a.previewUrl,match:c,classes:"menu-item-ellipsis",onclick:e(a.value,a.title)})}),d.menu.renderNew(),d.hideMenu(),d.menu.on("cancel",function(a){a.control.parent()===d.menu&&(a.stopPropagation(),d.focus(),d.hideMenu())}),d.menu.on("select",function(){d.focus()});var g=d.layoutRect().w;d.menu.layoutRect({w:g,minW:0,maxW:g}),d.menu.reflow(),d.menu.show(),d.menu.moveRel(d.getEl(),d.isRtl()?["br-tr","tr-br"]:["bl-tl","tl-bl"])},hideMenu:function(){this.menu&&this.menu.hide()},bindStates:function(){var a=this;a.state.on("change:value",function(b){a.getEl("inp").value!=b.value&&(a.getEl("inp").value=b.value)}),a.state.on("change:disabled",function(b){a.getEl("inp").disabled=b.value}),a.stat
 e.on("change:statusLevel",function(b){var d=a.getEl("status"),e=a.classPrefix,f=b.value;c.css(d,"display","none"===f?"none":""),c.toggleClass(d,e+"i-checkmark","ok"===f),c.toggleClass(d,e+"i-warning","warn"===f),c.toggleClass(d,e+"i-error","error"===f),a.classes.toggle("has-status","none"!==f),a.repaint()}),c.on(a.getEl("status"),"mouseleave",function(){a.tooltip().hide()}),a.on("cancel",function(b){a.menu&&a.menu.visible()&&(b.stopPropagation(),a.hideMenu())});var b=function(a,b){b&&b.items().length>0&&b.items().eq(a)[0].focus()};return a.on("keydown",function(c){var d=c.keyCode;"INPUT"===c.target.nodeName&&(d===e.DOWN?(c.preventDefault(),a.fire("autocomplete"),b(0,a.menu)):d===e.UP&&(c.preventDefault(),b(-1,a.menu)))}),a._super()},rem
 ove:function(){d(this.getEl("inp")).off(),this.menu&&this.menu.remove(),this._super()}})}),g("3c",["3b"],function(a){"use strict";return a.extend({init:function(a){var b=this;a.spellcheck=!1,a.onaction&&(a.icon="none"),b._super(a),b.classes.add("colorbox"),b.on("change keyup postrender",function(){b.repaintColor(b.value())})},repaintColor:function(a){var b=this.getEl("open"),c=b?b.getElementsByTagName("i")[0]:null;if(c)try{c.style.background=a}catch(a){}},bindStates:function(){var a=this;return a.state.on("change:value",function(b){a.state.get("rendered")&&a.repaintColor(b.value)}),a._super()}})}),g("3d",["38","2z"],function(a,b){"use strict";return a.extend({showPanel:function(){var a=this,c=a.settings;if(a.active(!0),a.panel)a.panel.show();else{var d=c.panel;d.type&&(d={layout:"grid",items:d}
 ),d.role=d.role||"dialog",d.popover=!0,d.autohide=!0,d.ariaRoot=!0,a.panel=new b(d).on("hide",function(){a.active(!1)}).on("cancel",function(b){b.stopPropagation(),a.focus(),a.hidePanel()}).parent(a).renderTo(a.getContainerElm()),a.panel.fire("show"),a.panel.reflow()}var e=a.panel.testMoveRel(a.getEl(),c.popoverAlign||(a.isRtl()?["bc-tc","bc-tl","bc-tr"]:["bc-tc","bc-tr","bc-tl"]));a.panel.classes.toggle("start","bc-tl"===e),a.panel.classes.toggle("end","bc-tr"===e),a.panel.moveRel(a.getEl(),e)},hidePanel:function(){var a=this;a.panel&&a.panel.hide()},postRender:function(){var a=this;return a.aria("haspopup",!0),a.on("click",function(b){b.control===a&&(a.panel&&a.panel.visible()?a.hidePanel():(a.showPanel(),a.panel.focus(!!b.aria)))}),a._super()},remove:function(){return this.panel&&(this.panel
 .remove(),this.panel=null),this._super()}})}),g("3e",["3d","c"],function(a,b){"use strict";var c=b.DOM;return a.extend({init:function(a){this._super(a),this.classes.add("colorbutton")},color:function(a){return a?(this._color=a,this.getEl("preview").style.backgroundColor=a,this):this._color},resetColor:function(){return this._color=null,this.getEl("preview").style.backgroundColor=null,this},renderHtml:function(){var a=this,b=a._id,c=a.classPrefix,d=a.state.get("text"),e=a.settings.icon?c+"ico "+c+"i-"+a.settings.icon:"",f=a.settings.image?" style=\"background-image: url('"+a.settings.image+"')\"":"",g="";return d&&(a.classes.add("btn-has-text"),g='<span class="'+c+'txt">'+a.encode(d)+"</span>"),'<div id="'+b+'" class="'+a.classes+'" role="button&quot
 ; tabindex="-1" aria-haspopup="true"><button role="presentation" hidefocus="1" type="button" tabindex="-1">'+(e?'<i class="'+e+'"'+f+"></i>":"")+'<span id="'+b+'-preview" class="'+c+'preview"></span>'+g+'</button><button type="button" class="'+c+'open" hidefocus="1" tabindex="-1"> <i class="'+c+'caret"></i></button></div>'},postRender:function(){var a=this,b=a.settings.onclick;return a.on("click",function(d){d.aria&&"down"==d.aria.key||d.control!=a||c.getParent(d.target,"."+a.classPrefix+"open")||(d.stopImmediatePropagation(),b.call(a,d))}),delete a.settings.onclick,a._super()}})}),g("13",[],function(){function a(a){function e(a,e,f){var g,h,i,j,k,l;return g=0,h=0,i=0,a/=255,e/=255,f/=255,k=b(a,b(e,f)
 ),l=c(a,c(e,f)),k==l?(i=k,{h:0,s:0,v:100*i}):(j=a==k?e-f:f==k?a-e:f-a,g=a==k?3:f==k?1:5,g=60*(g-j/(l-k)),h=(l-k)/l,i=l,{h:d(g),s:d(100*h),v:d(100*i)})}function f(a,e,f){var g,h,i,j;if(a=(parseInt(a,10)||0)%360,e=parseInt(e,10)/100,f=parseInt(f,10)/100,e=c(0,b(e,1)),f=c(0,b(f,1)),0===e)return void(l=m=n=d(255*f));switch(g=a/60,h=f*e,i=h*(1-Math.abs(g%2-1)),j=f-h,Math.floor(g)){case 0:l=h,m=i,n=0;break;case 1:l=i,m=h,n=0;break;case 2:l=0,m=h,n=i;break;case 3:l=0,m=i,n=h;break;case 4:l=i,m=0,n=h;break;case 5:l=h,m=0,n=i;break;default:l=m=n=0}l=d(255*(l+j)),m=d(255*(m+j)),n=d(255*(n+j))}function g(){function a(a){return a=parseInt(a,10).toString(16),a.length>1?a:"0"+a}return"#"+a(l)+a(m)+a(n)}function h(){return{r:l,g:m,b:n}}function i(){return e(l,m,n)}function j(a){var b;return"object"==typeof a?"r"in a?(l=a.r,m=a.g,n=a.b):"v"in a&&f(a.h,a.s,a.v):(b=/rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)[^\)]*\)/gi.exec(a))?(l=pa
 rseInt(b[1],10),m=parseInt(b[2],10),n=parseInt(b[3],10)):(b=/#([0-F]{2})([0-F]{2})([0-F]{2})/gi.exec(a))?(l=parseInt(b[1],16),m=parseInt(b[2],16),n=parseInt(b[3],16)):(b=/#([0-F])([0-F])([0-F])/gi.exec(a))&&(l=parseInt(b[1]+b[1],16),m=parseInt(b[2]+b[2],16),n=parseInt(b[3]+b[3],16)),l=l<0?0:l>255?255:l,m=m<0?0:m>255?255:m,n=n<0?0:n>255?255:n,k}var k=this,l=0,m=0,n=0;a&&j(a),k.toRgb=h,k.toHsv=i,k.toHex=g,k.parse=j}var b=Math.min,c=Math.max,d=Math.round;return a}),g("3f",["33","2u","4z","13"],function(a,b,c,d){"use strict";return a.extend({Defaults:{classes:"widget colorpicker"},init:function(a){this._super(a)},postRender:function(){function a(a,b){var d,e,f=c.getPos(a);return d=b.pageX-f.x,e=b.pageY-f.y,d=Math.max(0,Math.min(d/a.clientWidth,1)),e=Math.max(0,Math.min(e/a.clientHeight,1)),{x:d,y:e}}function e(a,b){var e=(360-a.h)/360;c.css(j,{top:100*e+"%"}),b||c.css(l,{lef
 t:a.s+"%",top:100-a.v+"%"}),k.style.background=new d({s:100,v:100,h:a.h}).toHex(),m.color().parse({s:a.s,v:a.v,h:a.h})}function f(b){var c;c=a(k,b),h.s=100*c.x,h.v=100*(1-c.y),e(h),m.fire("change")}function g(b){var c;c=a(i,b),h=n.toHsv(),h.h=360*(1-c.y),e(h,!0),m.fire("change")}var h,i,j,k,l,m=this,n=m.color();i=m.getEl("h"),j=m.getEl("hp"),k=m.getEl("sv"),l=m.getEl("svp"),m._repaint=function(){h=n.toHsv(),e(h)},m._super(),m._svdraghelper=new b(m._id+"-sv",{start:f,drag:f}),m._hdraghelper=new b(m._id+"-h",{start:g,drag:g}),m._repaint()},rgb:function(){return this.color().toRgb()},value:function(a){var b=this;return arguments.length?(b.color().parse(a),void(b._rendered&&b._repaint())):b.color().toHex()},color:function(){return this._color||(this._color=new d),this._color},renderHtml:function(){function a(){var a,b,c,d,g="";for(c="filter:progid:DXImageTransform.M
 icrosoft.gradient(GradientType=0,startColorstr=",d=f.split(","),a=0,b=d.length-1;a<b;a++)g+='<div class="'+e+'colorpicker-h-chunk" style="height:'+100/b+"%;"+c+d[a]+",endColorstr="+d[a+1]+");-ms-"+c+d[a]+",endColorstr="+d[a+1]+')"></div>';return g}var b,c=this,d=c._id,e=c.classPrefix,f="#ff0000,#ff0080,#ff00ff,#8000ff,#0000ff,#0080ff,#00ffff,#00ff80,#00ff00,#80ff00,#ffff00,#ff8000,#ff0000",g="background: -ms-linear-gradient(top,"+f+");background: linear-gradient(to bottom,"+f+");";return b='<div id="'+d+'-h" class="'+e+'colorpicker-h" style="'+g+'">'+a()+'<div id="'+d+'-hp" class="'+e+'colorpicker-h-marker"></div></div>','<div id="'+d+'" class="'+c.classes+'"><div id="'+d+'-sv" class="'+e+'colorpicker-sv"><div class="'+e+'c
 olorpicker-overlay1"><div class="'+e+'colorpicker-overlay2"><div id="'+d+'-svp" class="'+e+'colorpicker-selector1"><div class="'+e+'colorpicker-selector2"></div></div></div></div></div>'+b+"</div>"}})}),g("3g",["33"],function(a){"use strict";return a.extend({init:function(a){var b=this;a.delimiter||(a.delimiter="\xbb"),b._super(a),b.classes.add("path"),b.canFocus=!0,b.on("click",function(a){var c,d=a.target;(c=d.getAttribute("data-index"))&&b.fire("select",{value:b.row()[c],index:c})}),b.row(b.settings.row)},focus:function(){var a=this;return a.getEl().firstChild.focus(),a},row:function(a){return arguments.length?(this.state.set("row",a),this):this.state.get("row")},renderHtml:function(){var a=this;return'<div id="'+a._id+'" class="'+a.classes+'&quo
 t;>'+a._getDataPathHtml(a.state.get("row"))+"</div>"},bindStates:function(){var a=this;return a.state.on("change:row",function(b){a.innerHtml(a._getDataPathHtml(b.value))}),a._super()},_getDataPathHtml:function(a){var b,c,d=this,e=a||[],f="",g=d.classPrefix;for(b=0,c=e.length;b<c;b++)f+=(b>0?'<div class="'+g+'divider" aria-hidden="true"> '+d.settings.delimiter+" </div>":"")+'<div role="button" class="'+g+"path-item"+(b==c-1?" "+g+"last":"")+'" data-index="'+b+'" tabindex="-1" id="'+d._id+"-"+b+'" aria-level="'+(b+1)+'">'+e[b].name+"</div>";return f||(f='<div class="'+g+'path-item">\xa0</div>'),f}})}),g("3h",["3g"],function(a){return a.extend({postRender:function(){function a(a){if(1===a.nodeType){if("B
 R"==a.nodeName||a.getAttribute("data-mce-bogus"))return!0;if("bookmark"===a.getAttribute("data-mce-type"))return!0}return!1}var b=this,c=b.settings.editor;return c.settings.elementpath!==!1&&(b.on("select",function(a){c.focus(),c.selection.select(this.row()[a.index].element),c.nodeChanged()}),c.on("nodeChange",function(d){for(var e=[],f=d.parents,g=f.length;g--;)if(1==f[g].nodeType&&!a(f[g])){var h=c.fire("ResolveName",{name:f[g].nodeName.toLowerCase(),target:f[g]});if(h.isDefaultPrevented()||e.push({name:h.name,element:f[g]}),h.isPropagationStopped())break}b.row(e)})),b._super()}})}),g("3i",["2t"],function(a){"use strict";return a.extend({Defaults:{layout:"flex",align:"center",defaults:{flex:1}},renderHtml:function(){var a=this,b=a._layout,c=a.classPrefix;return a.classes.add("formitem"),b.preRender(a),'<div id="'+a._id+'" class=&
 quot;'+a.classes+'" hidefocus="1" tabindex="-1">'+(a.settings.title?'<div id="'+a._id+'-title" class="'+c+'title">'+a.settings.title+"</div>":"")+'<div id="'+a._id+'-body" class="'+a.bodyClasses+'">'+(a.settings.html||"")+b.renderHtml(a)+"</div></div>"}})}),g("3j",["2t","3i","1d"],function(a,b,c){"use strict";return a.extend({Defaults:{containerCls:"form",layout:"flex",direction:"column",align:"stretch",flex:1,padding:20,labelGap:30,spacing:10,callbacks:{submit:function(){this.submit()}}},preRender:function(){var a=this,d=a.items();a.settings.formItemDefaults||(a.settings.formItemDefaults={layout:"flex",autoResize:"overflow",defaults:{flex:1}}),d.each(function(d){var e,f=d.settings.label;f&&(e=new b(c.extend({items:{type:"labe
 l",id:d._id+"-l",text:f,flex:0,forId:d._id,disabled:d.disabled()}},a.settings.formItemDefaults)),e.type="formitem",d.aria("labelledby",d._id+"-l"),"undefined"==typeof d.settings.flex&&(d.settings.flex=1),a.replace(d,e),e.add(d))})},submit:function(){return this.fire("submit",{data:this.toJSON()})},postRender:function(){var a=this;a._super(),a.fromJSON(a.settings.data)},bindStates:function(){function a(){var a,c,d,e=0,f=[];if(b.settings.labelGapCalc!==!1)for(d="children"==b.settings.labelGapCalc?b.find("formitem"):b.items(),d.filter("formitem").each(function(a){var b=a.items()[0],c=b.getEl().clientWidth;e=c>e?c:e,f.push(b)}),c=b.settings.labelGap||0,a=f.length;a--;)f[a].settings.minWidth=e+c}var b=this;b._super(),b.on("show",a),a()}})}),g("3k",["3j"],function(a){"use strict";return a.extend({Defaults:{containerCls:"fieldset",layou
 t:"flex",direction:"column",align:"stretch",flex:1,padding:"25 15 5 15",labelGap:30,spacing:10,border:1},renderHtml:function(){var a=this,b=a._layout,c=a.classPrefix;return a.preRender(),b.preRender(a),'<fieldset id="'+a._id+'" class="'+a.classes+'" hidefocus="1" tabindex="-1">'+(a.settings.title?'<legend id="'+a._id+'-title" class="'+c+'fieldset-title">'+a.settings.title+"</legend>":"")+'<div id="'+a._id+'-body" class="'+a.bodyClasses+'">'+(a.settings.html||"")+b.renderHtml(a)+"</div></fieldset>"}})}),g("5v",["23","6c","c","21","1h","4i","1d","2j"],function(a,b,c,d,e,f,g,h){var i=g.trim,j=function(a,b,c,d,e){return{type:a,title:b,url:c,level:d,attach:e}},k=function(a){for(;a=a.parentNode;){var b=a.con
 tentEditable;if(b&&"inherit"!==b)return d.isContentEditableTrue(a)}return!1},l=function(c,d){return e.map(b.descendants(a.fromDom(d),c),function(a){return a.dom()})},m=function(a){return a.innerText||a.textContent},n=function(a){return a.id?a.id:h.uuid("h")},o=function(a){return a&&"A"===a.nodeName&&(a.id||a.name)},p=function(a){return o(a)&&r(a)},q=function(a){return a&&/^(H[1-6])$/.test(a.nodeName)},r=function(a){return k(a)&&!d.isContentEditableFalse(a)},s=function(a){return q(a)&&r(a)},t=function(a){return q(a)?parseInt(a.nodeName.substr(1),10):0},u=function(a){var b=n(a),c=function(){a.id=b};return j("header",m(a),"#"+b,t(a),c)},v=function(a){var b=a.id||a.name,c=m(a);return j("anchor",c?c:"#"+b,"#"+b,0,f.noop)},w=function(a){return e.map(e.filter(a,s),u)},x=function(a){return e.map(e.filter(a,p),v)},y=function(a){var b=l("h1,h2,h3,h4,h5,h
 6,a:not([href])",a);return b},z=function(a){return i(a.title).length>0},A=function(a){var b=y(a);return e.filter(w(b).concat(x(b)),z)};return{find:A}}),g("3l",["1t","1","5r","5v","m","3b","1d"],function(a,b,c,d,e,f,g){"use strict";var h=function(){return c.tinymce?c.tinymce.activeEditor:e.activeEditor},i={},j=5,k=function(a){return{title:a.title,value:{title:{raw:a.title},url:a.url,attach:a.attach}}},l=function(a){return g.map(a,k)},m=function(a,c){return{title:a,value:{title:a,url:c,attach:b.noop}}},n=function(b,c){var d=a.exists(c,function(a){return a.url===b});return!d},o=function(a,b,c){var d=b in a?a[b]:c;return d===!1?null:d},p=function(c,d,e,f){var h={title:"-"},j=function(c){var f=c.hasOwnProperty(e)?c[e]:[],h=a.filter(f,function(a){return n(a,d)});return g.map(h,function(a){return{title:a,value:{title:a,url:a,attach:b.noop}}})},k=function(b){var c=a.filter(d,function(
 a){return a.type===b});return l(c)},p=function(){var a=k("anchor"),b=o(f,"anchor_top","#top"),c=o(f,"anchor_bottom","#bottom");return null!==b&&a.unshift(m("<top>",b)),null!==c&&a.push(m("<bottom>",c)),a},q=function(b){return a.foldl(b,function(a,b){var c=0===a.length||0===b.length;return c?a.concat(b):a.concat(h,b)},[])};return f.typeahead_urls===!1?[]:"file"===e?q([r(c,j(i)),r(c,k("header")),r(c,p())]):r(c,j(i))},q=function(b,c){var d=i[c];/^https?/.test(b)&&(d?a.indexOf(d,b)===-1&&(i[c]=d.slice(0,j).concat(b)):i[c]=[b])},r=function(a,b){var c=a.toLowerCase(),d=g.grep(b,function(a){return a.title.toLowerCase().indexOf(c)!==-1});return 1===d.length&&d[0].title===a?[]:d},s=function(a){var b=a.title;return b.raw?b.raw:b},t=function(a,b,c,e){var f=function(f){var g=d.find(c),h=p(f,g,e,b);a.showAutoComplete(h,f)};a.on("autocomplete",fun
 ction(){f(a.value())}),a.on("selectitem",function(b){var c=b.value;a.value(c.url);var d=s(c);"image"===e?a.fire("change",{meta:{alt:d,attach:c.attach}}):a.fire("change",{meta:{text:d,attach:c.attach}}),a.focus()}),a.on("click",function(b){0===a.value().length&&"INPUT"===b.target.nodeName&&f("")}),a.on("PostRender",function(){a.getRoot().on("submit",function(b){b.isDefaultPrevented()||q(a.value(),e)})})},u=function(a){var b=a.status,c=a.message;return"valid"===b?{status:"ok",message:c}:"unknown"===b?{status:"warn",message:c}:"invalid"===b?{status:"warn",message:c}:{status:"none",message:""}},v=function(a,b,c){var d=b.filepicker_validator_handler;if(d){var e=function(b){return 0===b.length?void a.statusLevel("none"):void d({url:b,type:c},function(b){var c=u(b);a.statusMessage(c.message),a.sta
 tusLevel(c.status)})};a.state.on("change:value",function(a){e(a.value)})}};return f.extend({init:function(a){var b,d,e,f=this,i=h(),j=i.settings,k=a.filetype;a.spellcheck=!1,e=j.file_picker_types||j.file_browser_callback_types,e&&(e=g.makeMap(e,/[, ]/)),e&&!e[k]||(d=j.file_picker_callback,!d||e&&!e[k]?(d=j.file_browser_callback,!d||e&&!e[k]||(b=function(){d(f.getEl("inp").id,f.value(),k,c)})):b=function(){var a=f.fire("beforecall").meta;a=g.extend({filetype:k},a),d.call(i,function(a,b){f.value(a).fire("change",{meta:b})},f.value(),a)}),b&&(a.icon="browse",a.onaction=b),f._super(a),t(f,j,i.getBody(),k),v(f,j,k)}})}),g("3m",["37"],function(a){"use strict";return a.extend({recalc:function(a){var b=a.layoutRect(),c=a.paddingBox;a.items().filter(":visible").each(function(a){a.layoutRect({x:c.left,y:c.top,w:b.innerW-c.right-c.left,h:b.innerH-c.top-c.bottom}),a.
 recalc&&a.recalc()})}})}),g("3n",["37"],function(a){"use strict";return a.extend({recalc:function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N=[],O=Math.max,P=Math.min;for(d=a.items().filter(":visible"),e=a.layoutRect(),f=a.paddingBox,g=a.settings,m=a.isRtl()?g.direction||"row-reversed":g.direction,h=g.align,i=a.isRtl()?g.pack||"end":g.pack,j=g.spacing||0,"row-reversed"!=m&&"column-reverse"!=m||(d=d.set(d.toArray().reverse()),m=m.split("-")[0]),"column"==m?(z="y",x="h",y="minH",A="maxH",C="innerH",B="top",D="deltaH",E="contentH",J="left",H="w",F="x",G="innerW",I="minW",K="right",L="deltaW",M="contentW"):(z="x",x="w",y="minW",A="maxW"
 ,C="innerW",B="left",D="deltaW",E="contentW",J="top",H="h",F="y",G="innerH",I="minH",K="bottom",L="deltaH",M="contentH"),l=e[C]-f[B]-f[B],w=k=0,b=0,c=d.length;b<c;b++)n=d[b],o=n.layoutRect(),p=n.settings,q=p.flex,l-=b<c-1?j:0,q>0&&(k+=q,o[A]&&N.push(n),o.flex=q),l-=o[y],r=f[J]+o[I]+f[K],r>w&&(w=r);if(u={},l<0?u[y]=e[y]-l+e[D]:u[y]=e[C]-l+e[D],u[I]=w+e[L],u[E]=e[C]-l,u[M]=w,u.minW=P(u.minW,e.maxW),u.minH=P(u.minH,e.maxH),u.minW=O(u.minW,e.startMinWidth),u.minH=O(u.minH,e.startMinHeight),!e.autoResize||u.minW==e.minW&&u.minH==e.minH){for(t=l/k,b=0,c=N.length;b<c;b++)n=N[b],o=n.layoutRect(),s=o[A],r=o[y]+o.flex*t,r>s?(l-=o[A]-o[y],k-=o.flex,o.flex=0,o.maxFlexSize=s):o.maxFlexSize=0;for(t=l/k,v=f[B],u={},0===k&&("end"==i?v=l+f[B]:"center"==i?(v=Math.round(e[C]/2-(e[C]-l)/2)+f[B],v<0&amp
 ;&(v=f[B])):"justify"==i&&(v=f[B],j=Math.floor(l/(d.length-1)))),u[F]=f[J],b=0,c=d.length;b<c;b++)n=d[b],o=n.layoutRect(),r=o.maxFlexSize||o[y],"center"===h?u[F]=Math.round(e[G]/2-o[H]/2):"stretch"===h?(u[H]=O(o[I]||0,e[G]-f[J]-f[K]),u[F]=f[J]):"end"===h&&(u[F]=e[G]-o[H]-f.top),o.flex>0&&(r+=o.flex*t),u[x]=r,u[z]=v,n.layoutRect(u),n.recalc&&n.recalc(),v+=r+j}else if(u.w=u.minW,u.h=u.minH,a.layoutRect(u),this.recalc(a),null===a._lastRect){var Q=a.parent();Q&&(Q._lastRect=null,Q.recalc())}}})}),g("3o",["36"],function(a){return a.extend({Defaults:{containerClass:"flow-layout",controlClass:"flow-layout-item",endClass:"break"},recalc:function(a){a.items().filter(":visible").each(function(a){a.recalc&&a.recalc()})},isNative:function(){return!0}})}),g("5w",["1","1u","23","56","c&q
 uot;],function(a,b,c,d,e){var f=function(a,c,d){for(;d!==c;){if(d.style[a]){var e=d.style[a];return""!==e?b.some(e):b.none()}d=d.parentNode}return b.none()},g=function(a){return/[0-9.]+px$/.test(a)?Math.round(72*parseInt(a,10)/96)+"pt":a},h=function(a){return a.replace(/[\'\"]/g,"").replace(/,\s+/g,",")},i=function(a,c){return b.from(e.DOM.getStyle(c,a,!0))},j=function(a){return function(e,g){return b.from(g).map(c.fromDom).filter(d.isElement).bind(function(b){return f(a,e,b.dom()).or(i(a,b.dom()))}).getOr("")}};return{getFontSize:j("fontSize"),getFontFamily:a.compose(h,j("fontFamily")),toPt:g}}),g("3p",["1t","1","23","57","c","m","o","5w","2q","2z","33","1d"],function(a,b,c,d,e,f,g,h,i,j,k,l){function m(a){a.settings.ui_container&&(g.container=d.descendant(c.fromDom(docume
 nt.body),a.settings.ui_container).fold(b.constant(null),function(a){return a.dom()}))}function n(a){a.on("ScriptsLoaded",function(){a.rtl&&(i.rtl=!0)})}function o(a){function b(b,c){return function(){var d=this;a.on("nodeChange",function(e){var f=a.formatter,g=null;p(e.parents,function(a){if(p(b,function(b){if(c?f.matchNode(a,c,{value:b.value})&&(g=b.value):f.matchNode(a,b.value)&&(g=b.value),g)return!1}),g)return!1}),d.value(g)})}}function c(b){return function(){var c=this,d=function(a){return a?a.split(",")[0]:""};a.on("init nodeChange",function(e){var f,g=null;f=h.getFontFamily(a.getBody(),e.element),p(b,function(a){a.value.toLowerCase()===f.toLowerCase()&&(g=a.value)}),p(b,function(a){g||d(a.value).toLowerCase()!==d(f).toLowerCase()||(g=a.value)}),c.value(g),!g&&f&&c.text(d(f))})}}function d(b){return function(){var c=this;a.on("init nodeChange",function(d){var e,f,g=null;
 e=h.getFontSize(a.getBody(),d.element),f=h.toPt(e),p(b,function(a){a.value===e?g=e:a.value===f&&(g=f)}),c.value(g),g||c.text(f)})}}function e(a){a=a.replace(/;$/,"").split(";");for(var b=a.length;b--;)a[b]=a[b].split("=");return a}function f(){function b(a){var c=[];if(a)return p(a,function(a){var f={text:a.title,icon:a.icon};if(a.items)f.menu=b(a.items);else{var g=a.format||"custom"+d++;a.format||(a.name=g,e.push(a)),f.format=g,f.cmd=a.cmd}c.push(f)}),c}function c(){var c;return c=b(a.settings.style_formats_merge?a.settings.style_formats?f.concat(a.settings.style_formats):f:a.settings.style_formats||f)}var d=0,e=[],f=[{title:"Headings",items:[{title:"Heading 1",format:"h1"},{title:"Heading 2",format:"h2"},{title:"Heading 3",format:"h3"},{title:"Heading 4",format:"h4"},{title:"Heading 5",format:"h5"},{title:"Heading 6&quot
 ;,format:"h6"}]},{title:"Inline",items:[{title:"Bold",icon:"bold",format:"bold"},{title:"Italic",icon:"italic",format:"italic"},{title:"Underline",icon:"underline",format:"underline"},{title:"Strikethrough",icon:"strikethrough",format:"strikethrough"},{title:"Superscript",icon:"superscript",format:"superscript"},{title:"Subscript",icon:"subscript",format:"subscript"},{title:"Code",icon:"code",format:"code"}]},{title:"Blocks",items:[{title:"Paragraph",format:"p"},{title:"Blockquote",format:"blockquote"},{title:"Div",format:"div"},{title:"Pre",format:"pre"}]},{title:"Alignment",items:[{title:"Left",icon:"alignleft",format:"alignleft&quo
 t;},{title:"Center",icon:"aligncenter",format:"aligncenter"},{title:"Right",icon:"alignright",format:"alignright"},{title:"Justify",icon:"alignjustify",format:"alignjustify"}]}];return a.on("init",function(){p(e,function(b){a.formatter.register(b.name,b)})}),{type:"menu",items:c(),onPostRender:function(b){a.fire("renderFormatsMenu",{control:b.control})},itemDefaults:{preview:!0,textStyle:function(){if(this.settings.format)return a.formatter.getCssText(this.settings.format)},onPostRender:function(){var b=this;b.parent().on("show",function(){var c,d;c=b.settings.format,c&&(b.disabled(!a.formatter.canApply(c)),b.active(a.formatter.match(c))),d=b.settings.cmd,d&&b.active(a.queryCommandState(d))})},onclick:function(){this.settings.format&&m(this.settings.format),this.settings.cmd&&a.execCommand(this.settings.cmd)}}}}function g(b
 ){return function(){var c=this;a.formatter?a.formatter.formatChanged(b,function(a){c.active(a)}):a.on("init",function(){a.formatter.formatChanged(b,function(a){c.active(a)})})}}function i(b){return function(){function c(){var c="redo"==b?"hasRedo":"hasUndo";return!!a.undoManager&&a.undoManager[c]()}var d=this;d.disabled(!c()),a.on("Undo Redo AddUndo TypingUndo ClearUndos SwitchMode",function(){d.disabled(a.readonly||!c())})}}function k(){var b=this;a.on("VisualAid",function(a){b.active(a.hasVisual)}),b.active(a.hasVisual)}function m(b){b.control&&(b=b.control.value()),b&&a.execCommand("mceToggleFormat",!1,b)}function n(b){var c=b.length;return l.each(b,function(b){b.menu&&(b.hidden=0===n(b.menu));var d=b.format;d&&(b.hidden=!a.formatter.canApply(d)),b.hidden&&c--}),c}function o(b){var c=b.items().length;return b.items().each(function(b){b.menu&&b.visible(o(b.
 menu)>0),!b.menu&&b.settings.menu&&b.visible(n(b.settings.menu)>0);var d=b.settings.format;d&&b.visible(a.formatter.canApply(d)),b.visible()||c--}),c}var r;r=f(),p({bold:"Bold",italic:"Italic",underline:"Underline",strikethrough:"Strikethrough",subscript:"Subscript",superscript:"Superscript"},function(b,c){a.addButton(c,{tooltip:b,onPostRender:g(c),onclick:function(){m(c)}})}),p({outdent:["Decrease indent","Outdent"],indent:["Increase indent","Indent"],cut:["Cut","Cut"],copy:["Copy","Copy"],paste:["Paste","Paste"],help:["Help","mceHelp"],selectall:["Select all","SelectAll"],removeformat:["Clear formatting","RemoveFormat"],visualaid:["Visual aids","mceToggleVisualAid"],newdocument:["New document","mceNew
 Document"]},function(b,c){a.addButton(c,{tooltip:b[0],cmd:b[1]})}),p({blockquote:["Blockquote","mceBlockQuote"],subscript:["Subscript","Subscript"],superscript:["Superscript","Superscript"],alignleft:["Align left","JustifyLeft"],aligncenter:["Align center","JustifyCenter"],alignright:["Align right","JustifyRight"],alignjustify:["Justify","JustifyFull"],alignnone:["No alignment","JustifyNone"]},function(b,c){a.addButton(c,{tooltip:b[0],cmd:b[1],onPostRender:g(c)})});var s=function(a){var b=a;return b.length>0&&"-"===b[0].text&&(b=b.slice(1)),b.length>0&&"-"===b[b.length-1].text&&(b=b.slice(0,b.length-1)),b},t=function(b){var c,d;if("string"==typeof b)d=b.split(" ");else if(l.isArray(b))return q(l.map(b,t));return c=l.grep(d,function(b){return&qu
 ot;|"===b||b in a.menuItems}),l.map(c,function(b){return"|"===b?{text:"-"}:a.menuItems[b]})},u=function(b){var c=[{text:"-"}],d=l.grep(a.menuItems,function(a){return a.context===b});return l.each(d,function(a){"before"==a.separator&&c.push({text:"|"}),a.prependToContext?c.unshift(a):c.push(a),"after"==a.separator&&c.push({text:"|"})}),c},v=function(a){return s(a.insert_button_items?t(a.insert_button_items):u("insert"))};a.addButton("undo",{tooltip:"Undo",onPostRender:i("undo"),cmd:"undo"}),a.addButton("redo",{tooltip:"Redo",onPostRender:i("redo"),cmd:"redo"}),a.addMenuItem("newdocument",{text:"New document",icon:"newdocument",cmd:"mceNewDocument"}),a.addMenuItem("undo",{text:"Undo",icon:"undo",shortcut:"Meta+Z",onPostRender:i(
 "undo"),cmd:"undo"}),a.addMenuItem("redo",{text:"Redo",icon:"redo",shortcut:"Meta+Y",onPostRender:i("redo"),cmd:"redo"}),a.addMenuItem("visualaid",{text:"Visual aids",selectable:!0,onPostRender:k,cmd:"mceToggleVisualAid"}),a.addButton("remove",{tooltip:"Remove",icon:"remove",cmd:"Delete"}),a.addButton("insert",{type:"menubutton",icon:"insert",menu:[],oncreatemenu:function(){this.menu.add(v(a.settings)),this.menu.renderNew()}}),p({cut:["Cut","Cut","Meta+X"],copy:["Copy","Copy","Meta+C"],paste:["Paste","Paste","Meta+V"],selectall:["Select all","SelectAll","Meta+A"],bold:["Bold","Bold","Meta+B"],italic:["Italic","Italic","Meta+I"],u
 nderline:["Underline","Underline","Meta+U"],strikethrough:["Strikethrough","Strikethrough"],subscript:["Subscript","Subscript"],superscript:["Superscript","Superscript"],removeformat:["Clear formatting","RemoveFormat"]},function(b,c){a.addMenuItem(c,{text:b[0],icon:c,shortcut:b[2],cmd:b[1]})}),a.on("mousedown",function(){j.hideAll()}),a.addButton("styleselect",{type:"menubutton",text:"Formats",menu:r,onShowMenu:function(){a.settings.style_formats_autohide&&o(this.menu)}}),a.addButton("formatselect",function(){var c=[],d=e(a.settings.block_formats||"Paragraph=p;Heading 1=h1;Heading 2=h2;Heading 3=h3;Heading 4=h4;Heading 5=h5;Heading 6=h6;Preformatted=pre");return p(d,function(b){c.push({text:b[0],value:b[1],textStyle:function(){return a.formatter.getCssText(b[1])}})}),{type:"listbox",text:d[0][0],va
 lues:c,fixedWidth:!0,onselect:m,onPostRender:b(c)}}),a.addButton("fontselect",function(){var b="Andale Mono=andale mono,monospace;Arial=arial,helvetica,sans-serif;Arial Black=arial black,sans-serif;Book Antiqua=book antiqua,palatino,serif;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier,monospace;Georgia=georgia,palatino,serif;Helvetica=helvetica,arial,sans-serif;Impact=impact,sans-serif;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco,monospace;Times New Roman=times new roman,times,serif;Trebuchet MS=trebuchet ms,geneva,sans-serif;Verdana=verdana,geneva,sans-serif;Webdings=webdings;Wingdings=wingdings,zapf dingbats",d=[],f=e(a.settings.font_formats||b);return p(f,function(a){d.push({text:{raw:a[0]},value:a[1],textStyle:a[1].indexOf("dings")==-1?"font-family:"+a[1]:""})}),{type:"listbox",text:"Font Family",tooltip:"Font Family",values:d,fixedWidth:!0,o
 nPostRender:c(d),onselect:function(b){b.control.settings.value&&a.execCommand("FontName",!1,b.control.settings.value)}}}),a.addButton("fontsizeselect",function(){var b=[],c="8pt 10pt 12pt 14pt 18pt 24pt 36pt",e=a.settings.fontsize_formats||c;return p(e.split(" "),function(a){var c=a,d=a,e=a.split("=");e.length>1&&(c=e[0],d=e[1]),b.push({text:c,value:d})}),{type:"listbox",text:"Font Sizes",tooltip:"Font Sizes",values:b,fixedWidth:!0,onPostRender:d(b),onclick:function(b){b.control.settings.value&&a.execCommand("FontSize",!1,b.control.settings.value)}}}),a.addMenuItem("formats",{text:"Formats",menu:r})}var p=l.each,q=function(b){return a.foldl(b,function(a,b){return a.concat(b)},[])};return f.on("AddEditor",function(a){var b=a.editor;n(b),o(b),m(b)}),i.translate=function(a){return f.translate(a)},k.tooltips=!g.iOS,{}}),g("3q",[&quo
 t;37"],function(a){"use strict";return a.extend({recalc:function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E=[],F=[];b=a.settings,e=a.items().filter(":visible"),f=a.layoutRect(),d=b.columns||Math.ceil(Math.sqrt(e.length)),c=Math.ceil(e.length/d),s=b.spacingH||b.spacing||0,t=b.spacingV||b.spacing||0,u=b.alignH||b.align,v=b.alignV||b.align,q=a.paddingBox,C="reverseRows"in b?b.reverseRows:a.isRtl(),u&&"string"==typeof u&&(u=[u]),v&&"string"==typeof v&&(v=[v]);for(l=0;l<d;l++)E.push(0);for(m=0;m<c;m++)F.push(0);for(m=0;m<c;m++)for(l=0;l<d&&(k=e[m*d+l],k);l++)j=k.layoutRect(),y=j.minW,z=j.minH,E[l]=y>E[l]?y:E[l],F[m]=z>F[m]?z:F[m];for(A=f.innerW-q.left-q.right,w=0,l=0;l<d;l++)w+=E[l]+(l>0?s:0),A-=(l>0?s:0)+E[l];for(B=f.innerH-q.top-q.bottom,x=0,m=0;m<c;m++)x+=F[m]+(m>0?t:0),B-=(m>0?t:0)+F[m];if(w+=q.left+q.right,x+=q.top+q.bottom,i={},i
 .minW=w+(f.w-f.innerW),i.minH=x+(f.h-f.innerH),i.contentW=i.minW-f.deltaW,i.contentH=i.minH-f.deltaH,i.minW=Math.min(i.minW,f.maxW),i.minH=Math.min(i.minH,f.maxH),i.minW=Math.max(i.minW,f.startMinWidth),i.minH=Math.max(i.minH,f.startMinHeight),!f.autoResize||i.minW==f.minW&&i.minH==f.minH){f.autoResize&&(i=a.layoutRect(i),i.contentW=i.minW-f.deltaW,i.contentH=i.minH-f.deltaH);
+var G;G="start"==b.packV?0:B>0?Math.floor(B/c):0;var H=0,I=b.flexWidths;if(I)for(l=0;l<I.length;l++)H+=I[l];else H=d;var J=A/H;for(l=0;l<d;l++)E[l]+=I?I[l]*J:J;for(o=q.top,m=0;m<c;m++){for(n=q.left,h=F[m]+G,l=0;l<d&&(D=C?m*d+d-1-l:m*d+l,k=e[D],k);l++)p=k.settings,j=k.layoutRect(),g=Math.max(E[l],j.startMinWidth),j.x=n,j.y=o,r=p.alignH||(u?u[l]||u[0]:null),"center"==r?j.x=n+g/2-j.w/2:"right"==r?j.x=n+g-j.w:"stretch"==r&&(j.w=g),r=p.alignV||(v?v[l]||v[0]:null),"center"==r?j.y=o+h/2-j.h/2:"bottom"==r?j.y=o+h-j.h:"stretch"==r&&(j.h=h),k.layoutRect(j),n+=g+s,k.recalc&&k.recalc();o+=h+t}}else if(i.w=i.minW,i.h=i.minH,a.layoutRect(i),this.recalc(a),null===a._lastRect){var K=a.parent();K&&(K._lastRect=null,K.recalc())}}})}),g("3r",["33","14"],function(a,b){"use strict";return a.extend({renderHtml:function(){var a=this;return a.c
 lasses.add("iframe"),a.canFocus=!1,'<iframe id="'+a._id+'" class="'+a.classes+'" tabindex="-1" src="'+(a.settings.url||"javascript:''")+'" frameborder="0"></iframe>'},src:function(a){this.getEl().src=a},html:function(a,c){var d=this,e=this.getEl().contentWindow.document.body;return e?(e.innerHTML=a,c&&c()):b.setTimeout(function(){d.html(a)}),this}})}),g("3s",["33"],function(a){"use strict";return a.extend({init:function(a){var b=this;b._super(a),b.classes.add("widget").add("infobox"),b.canFocus=!1},severity:function(a){this.classes.remove("error"),this.classes.remove("warning"),this.classes.remove("success"),this.classes.add(a)},help:function(a){this.state.set("help",a)},renderHtml:function(){var a=this,b=a.classPrefix;return'<div id="'+a._id+'" class="'+a.classes+'"><div id=&q
 uot;'+a._id+'-body">'+a.encode(a.state.get("text"))+'<button role="button" tabindex="-1"><i class="'+b+"ico "+b+'i-help"></i></button></div></div>'},bindStates:function(){var a=this;return a.state.on("change:text",function(b){a.getEl("body").firstChild.data=a.encode(b.value),a.state.get("rendered")&&a.updateLayoutRect()}),a.state.on("change:help",function(b){a.classes.toggle("has-help",b.value),a.state.get("rendered")&&a.updateLayoutRect()}),a._super()}})}),g("3t",["33","4z"],function(a,b){"use strict";return a.extend({init:function(a){var b=this;b._super(a),b.classes.add("widget").add("label"),b.canFocus=!1,a.multiline&&b.classes.add("autoscroll"),a.strong&&b.classes.add("strong")},initLayoutRect:function(){var a=this,c=
 a._super();if(a.settings.multiline){var d=b.getSize(a.getEl());d.width>c.maxW&&(c.minW=c.maxW,a.classes.add("multiline")),a.getEl().style.width=c.minW+"px",c.startMinH=c.h=c.minH=Math.min(c.maxH,b.getSize(a.getEl()).height)}return c},repaint:function(){var a=this;return a.settings.multiline||(a.getEl().style.lineHeight=a.layoutRect().h+"px"),a._super()},severity:function(a){this.classes.remove("error"),this.classes.remove("warning"),this.classes.remove("success"),this.classes.add(a)},renderHtml:function(){var a,b,c=this,d=c.settings.forId,e=c.settings.html?c.settings.html:c.encode(c.state.get("text"));return!d&&(b=c.settings.forName)&&(a=c.getRoot().find("#"+b)[0],a&&(d=a._id)),d?'<label id="'+c._id+'" class="'+c.classes+'"'+(d?' for="'+d+'"':"")+">"+e+"</label>":'<span id="'+c._id+'" c
 lass="'+c.classes+'">'+e+"</span>"},bindStates:function(){var a=this;return a.state.on("change:text",function(b){a.innerHtml(a.encode(b.value)),a.state.get("rendered")&&a.updateLayoutRect()}),a._super()}})}),g("3u",["2t"],function(a){"use strict";return a.extend({Defaults:{role:"toolbar",layout:"flow"},init:function(a){var b=this;b._super(a),b.classes.add("toolbar")},postRender:function(){var a=this;return a.items().each(function(a){a.classes.add("toolbar-item")}),a._super()}})}),g("3v",["3u"],function(a){"use strict";return a.extend({Defaults:{role:"menubar",containerCls:"menubar",ariaRoot:!0,defaults:{type:"menubutton"}}})}),g("3w",["38","2r","3v"],function(a,b,c){"use strict";function d(a,b){for(;a;){if(b===a)return!0;a=a.parentNode}return!1}var e
 =a.extend({init:function(a){var b=this;b._renderOpen=!0,b._super(a),a=b.settings,b.classes.add("menubtn"),a.fixedWidth&&b.classes.add("fixed-width"),b.aria("haspopup",!0),b.state.set("menu",a.menu||b.render())},showMenu:function(a){var c,d=this;return d.menu&&d.menu.visible()&&a!==!1?d.hideMenu():(d.menu||(c=d.state.get("menu")||[],c.length?c={type:"menu",items:c}:c.type=c.type||"menu",c.renderTo?d.menu=c.parent(d).show().renderTo():d.menu=b.create(c).parent(d).renderTo(),d.fire("createmenu"),d.menu.reflow(),d.menu.on("cancel",function(a){a.control.parent()===d.menu&&(a.stopPropagation(),d.focus(),d.hideMenu())}),d.menu.on("select",function(){d.focus()}),d.menu.on("show hide",function(a){a.control==d.menu&&d.activeMenu("show"==a.type),d.aria("expanded","show"==a.type)}).fire("show")),d.menu.show(
 ),d.menu.layoutRect({w:d.layoutRect().w}),d.menu.moveRel(d.getEl(),d.isRtl()?["br-tr","tr-br"]:["bl-tl","tl-bl"]),void d.fire("showmenu"))},hideMenu:function(){var a=this;a.menu&&(a.menu.items().each(function(a){a.hideMenu&&a.hideMenu()}),a.menu.hide())},activeMenu:function(a){this.classes.toggle("active",a)},renderHtml:function(){var a,b=this,d=b._id,e=b.classPrefix,f=b.settings.icon,g=b.state.get("text"),h="";return a=b.settings.image,a?(f="none","string"!=typeof a&&(a=window.getSelection?a[0]:a[1]),a=" style=\"background-image: url('"+a+"')\""):a="",g&&(b.classes.add("btn-has-text"),h='<span class="'+e+'txt">'+b.encode(g)+"</span>"),f=b.settings.icon?e+"ico "+e+"i-"+f:"",b.aria("role",b.parent()instanceof c?"menuitem":&q
 uot;button"),'<div id="'+d+'" class="'+b.classes+'" tabindex="-1" aria-labelledby="'+d+'"><button id="'+d+'-open" role="presentation" type="button" tabindex="-1">'+(f?'<i class="'+f+'"'+a+"></i>":"")+h+' <i class="'+e+'caret"></i></button></div>'},postRender:function(){var a=this;return a.on("click",function(b){b.control===a&&d(b.target,a.getEl())&&(a.focus(),a.showMenu(!b.aria),b.aria&&a.menu.items().filter(":visible")[0].focus())}),a.on("mouseenter",function(b){var c,d=b.control,f=a.parent();d&&f&&d instanceof e&&d.parent()==f&&(f.items().filter("MenuButton").each(function(a){a.hideMenu&&a!=d&&(a.menu&&a.menu.visible()&&(c=!0),a.hideMenu())}),c&&(d.focus(),d.showMenu()))}),a._s
 uper()},bindStates:function(){var a=this;return a.state.on("change:menu",function(){a.menu&&a.menu.remove(),a.menu=null}),a._super()},remove:function(){this._super(),this.menu&&this.menu.remove()}});return e}),g("3x",["33","2r","o","14"],function(a,b,c,d){"use strict";return a.extend({Defaults:{border:0,role:"menuitem"},init:function(a){var b,c=this;c._super(a),a=c.settings,c.classes.add("menu-item"),a.menu&&c.classes.add("menu-item-expand"),a.preview&&c.classes.add("menu-item-preview"),b=c.state.get("text"),"-"!==b&&"|"!==b||(c.classes.add("menu-item-sep"),c.aria("role","separator"),c.state.set("text","-")),a.selectable&&(c.aria("role","menuitemcheckbox"),c.classes.add("menu-item-checkbox"),a.icon="selected")
 ,a.preview||a.selectable||c.classes.add("menu-item-normal"),c.on("mousedown",function(a){a.preventDefault()}),a.menu&&!a.ariaHideMenu&&c.aria("haspopup",!0)},hasMenus:function(){return!!this.settings.menu},showMenu:function(){var a,c=this,d=c.settings,e=c.parent();if(e.items().each(function(a){a!==c&&a.hideMenu()}),d.menu){a=c.menu,a?a.show():(a=d.menu,a.length?a={type:"menu",items:a}:a.type=a.type||"menu",e.settings.itemDefaults&&(a.itemDefaults=e.settings.itemDefaults),a=c.menu=b.create(a).parent(c).renderTo(),a.reflow(),a.on("cancel",function(b){b.stopPropagation(),c.focus(),a.hide()}),a.on("show hide",function(a){a.control.items&&a.control.items().each(function(a){a.active(a.settings.selected)})}).fire("show"),a.on("hide",function(b){b.control===a&&c.classes.remove("selected")}),a.submenu=!0),a._parentMenu=e,a.classes.add("menu-
 sub");var f=a.testMoveRel(c.getEl(),c.isRtl()?["tl-tr","bl-br","tr-tl","br-bl"]:["tr-tl","br-bl","tl-tr","bl-br"]);a.moveRel(c.getEl(),f),a.rel=f,f="menu-sub-"+f,a.classes.remove(a._lastRel).add(f),a._lastRel=f,c.classes.add("selected"),c.aria("expanded",!0)}},hideMenu:function(){var a=this;return a.menu&&(a.menu.items().each(function(a){a.hideMenu&&a.hideMenu()}),a.menu.hide(),a.aria("expanded",!1)),a},renderHtml:function(){function a(a){var b,d,e={};for(e=c.mac?{alt:"&#x2325;",ctrl:"&#x2318;",shift:"&#x21E7;",meta:"&#x2318;"}:{meta:"Ctrl"},a=a.split("+"),b=0;b<a.length;b++)d=e[a[b].toLowerCase()],d&&(a[b]=d);return a.join("+")}function b(a){return a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function d(a){var c=h.match||"";retur
 n c?a.replace(new RegExp(b(c),"gi"),function(a){return"!mce~match["+a+"]mce~match!"}):a}function e(a){return a.replace(new RegExp(b("!mce~match["),"g"),"<b>").replace(new RegExp(b("]mce~match!"),"g"),"</b>")}var f=this,g=f._id,h=f.settings,i=f.classPrefix,j=f.state.get("text"),k=f.settings.icon,l="",m=h.shortcut,n=f.encode(h.url),o="";return k&&f.parent().classes.add("menu-has-icons"),h.image&&(l=" style=\"background-image: url('"+h.image+"')\""),m&&(m=a(m)),k=i+"ico "+i+"i-"+(f.settings.icon||"none"),o="-"!==j?'<i class="'+k+'"'+l+"></i>\xa0":"",j=e(f.encode(d(j))),n=e(f.encode(d(n))),'<div id="'+g+'" class="'+f.classes+'" tabindex="-1">'+o+("-"!==j?'<span id=&
 quot;'+g+'-text" class="'+i+'text">'+j+"</span>":"")+(m?'<div id="'+g+'-shortcut" class="'+i+'menu-shortcut">'+m+"</div>":"")+(h.menu?'<div class="'+i+'caret"></div>':"")+(n?'<div class="'+i+'menu-item-link">'+n+"</div>":"")+"</div>"},postRender:function(){var a=this,b=a.settings,c=b.textStyle;if("function"==typeof c&&(c=c.call(this)),c){var e=a.getEl("text");e&&e.setAttribute("style",c)}return a.on("mouseenter click",function(c){c.control===a&&(b.menu||"click"!==c.type?(a.showMenu(),c.aria&&a.menu.focus(!0)):(a.fire("select"),d.requestAnimationFrame(function(){a.parent().hideAll()})))}),a._super(),a},hover:function(){var a=this;return a.parent().items().each(function(a){a.classes.remove("selected")}
 ),a.classes.toggle("selected",!0),a},active:function(a){return"undefined"!=typeof a&&this.aria("checked",a),this._super(a)},remove:function(){this._super(),this.menu&&this.menu.remove()}})}),g("3y",["b","2q","14"],function(a,b,c){"use strict";return function(d,e){var f,g,h=this,i=b.classPrefix;h.show=function(b,j){function k(){f&&(a(d).append('<div class="'+i+"throbber"+(e?" "+i+"throbber-inline":"")+'"></div>'),j&&j())}return h.hide(),f=!0,b?g=c.setTimeout(k,b):k(),h},h.hide=function(){var a=d.lastChild;return c.clearTimeout(g),a&&a.className.indexOf("throbber")!=-1&&a.parentNode.removeChild(a),f=!1,h}}}),g("3z",["2z","3x","3y","1d"],function(a,b,c,d){"use strict";return a.extend({Defaults:{defaultType:"menuitem",bor
 der:1,layout:"stack",role:"application",bodyRole:"menu",ariaRoot:!0},init:function(a){var b=this;if(a.autohide=!0,a.constrainToViewport=!0,"function"==typeof a.items&&(a.itemsFactory=a.items,a.items=[]),a.itemDefaults)for(var c=a.items,e=c.length;e--;)c[e]=d.extend({},a.itemDefaults,c[e]);b._super(a),b.classes.add("menu")},repaint:function(){return this.classes.toggle("menu-align",!0),this._super(),this.getEl().style.height="",this.getEl("body").style.height="",this},cancel:function(){var a=this;a.hideAll(),a.fire("select")},load:function(){function a(){e.throbber&&(e.throbber.hide(),e.throbber=null)}var b,d,e=this;d=e.settings.itemsFactory,d&&(e.throbber||(e.throbber=new c(e.getEl("body"),!0),0===e.items().length?(e.throbber.show(),e.fire("loading")):e.throbber.show(100,function(){e.items().remove(),e.fire("loading")}),e.on("
 hide close",a)),e.requestTime=b=(new Date).getTime(),e.settings.itemsFactory(function(c){return 0===c.length?void e.hide():void(e.requestTime===b&&(e.getEl().style.width="",e.getEl("body").style.width="",a(),e.items().remove(),e.getEl("body").innerHTML="",e.add(c),e.renderNew(),e.fire("loaded")))}))},hideAll:function(){var a=this;return this.find("menuitem").exec("hideMenu"),a._super()},preRender:function(){var a=this;return a.items().each(function(b){var c=b.settings;if(c.icon||c.image||c.selectable)return a._hasIcons=!0,!1}),a.settings.itemsFactory&&a.on("postrender",function(){a.settings.itemsFactory&&a.load()}),a._super()}})}),g("40",["3w","3z"],function(a,b){"use strict";return a.extend({init:function(a){function b(c){for(var f=0;f<c.length;f++){if(d=c[f].selected||a.value===c[f].value)return e=e||c[f].text,g.state.set
 ("value",c[f].value),!0;if(c[f].menu&&b(c[f].menu))return!0}}var c,d,e,f,g=this;g._super(a),a=g.settings,g._values=c=a.values,c&&("undefined"!=typeof a.value&&b(c),!d&&c.length>0&&(e=c[0].text,g.state.set("value",c[0].value)),g.state.set("menu",c)),g.state.set("text",a.text||e),g.classes.add("listbox"),g.on("select",function(b){var c=b.control;f&&(b.lastControl=f),a.multiple?c.active(!c.active()):g.value(b.control.value()),f=c})},bindStates:function(){function a(a,c){a instanceof b&&a.items().each(function(a){a.hasMenus()||a.active(a.value()===c)})}function c(a,b){var d;if(a)for(var e=0;e<a.length;e++){if(a[e].value===b)return a[e];if(a[e].menu&&(d=c(a[e].menu,b)))return d}}var d=this;return d.on("show",function(b){a(b.control,d.value())}),d.state.on("change:value",function(a){var b=c(d.state.get("menu"),a.value);b?
 d.text(b.text):d.text(d.settings.text)}),d._super()}})}),g("41",["3a"],function(a){"use strict";return a.extend({Defaults:{classes:"radio",role:"radio"}})}),g("42",["33","2u"],function(a,b){"use strict";return a.extend({renderHtml:function(){var a=this,b=a.classPrefix;return a.classes.add("resizehandle"),"both"==a.settings.direction&&a.classes.add("resizehandle-both"),a.canFocus=!1,'<div id="'+a._id+'" class="'+a.classes+'"><i class="'+b+"ico "+b+'i-resize"></i></div>'},postRender:function(){var a=this;a._super(),a.resizeDragHelper=new b(this._id,{start:function(){a.fire("ResizeStart")},drag:function(b){"both"!=a.settings.direction&&(b.deltaX=0),a.fire("Resize",b)},stop:function(){a.fire("ResizeEnd")}})},remove:function(){return this.resizeDragHel
 per&&this.resizeDragHelper.destroy(),this._super()}})}),g("43",["33"],function(a){"use strict";function b(a){var b="";if(a)for(var c=0;c<a.length;c++)b+='<option value="'+a[c]+'">'+a[c]+"</option>";return b}return a.extend({Defaults:{classes:"selectbox",role:"selectbox",options:[]},init:function(a){var b=this;b._super(a),b.settings.size&&(b.size=b.settings.size),b.settings.options&&(b._options=b.settings.options),b.on("keydown",function(a){var c;13==a.keyCode&&(a.preventDefault(),b.parents().reverse().each(function(a){if(a.toJSON)return c=a,!1}),b.fire("submit",{data:c.toJSON()}))})},options:function(a){return arguments.length?(this.state.set("options",a),this):this.state.get("options")},renderHtml:function(){var a,c=this,d="";return a=b(c._options),c.size&&(d=' size = "'+c.size+'"'),'<se
 lect id="'+c._id+'" class="'+c.classes+'"'+d+">"+a+"</select>"},bindStates:function(){var a=this;return a.state.on("change:options",function(c){a.getEl().innerHTML=b(c.value)}),a._super()}})}),g("44",["33","2u","4z"],function(a,b,c){"use strict";function d(a,b,c){return a<b&&(a=b),a>c&&(a=c),a}function e(a,b,c){a.setAttribute("aria-"+b,c)}function f(a,b){var d,f,g,h,i,j;"v"==a.settings.orientation?(h="top",g="height",f="h"):(h="left",g="width",f="w"),j=a.getEl("handle"),d=(a.layoutRect()[f]||100)-c.getSize(j)[g],i=d*((b-a._minValue)/(a._maxValue-a._minValue))+"px",j.style[h]=i,j.style.height=a.layoutRect().h+"px",e(j,"valuenow",b),e(j,"valuetext",""+a.settings.previewFilter(b)),e(j,"valuemin",a._minValue),e
 (j,"valuemax",a._maxValue)}return a.extend({init:function(a){var b=this;a.previewFilter||(a.previewFilter=function(a){return Math.round(100*a)/100}),b._super(a),b.classes.add("slider"),"v"==a.orientation&&b.classes.add("vertical"),b._minValue=a.minValue||0,b._maxValue=a.maxValue||100,b._initValue=b.state.get("value")},renderHtml:function(){var a=this,b=a._id,c=a.classPrefix;return'<div id="'+b+'" class="'+a.classes+'"><div id="'+b+'-handle" class="'+c+'slider-handle" role="slider" tabindex="-1"></div></div>'},reset:function(){this.value(this._initValue).repaint()},postRender:function(){function a(a,b,c){return(c+a)/(b-a)}function e(a,b,c){return c*(b-a)-a}function f(b,c){function f(f){var g;g=n.value(),g=e(b,c,a(b,c,g)+.05*f),g=d(g,b,c),n.value(g),n.fire("dragstart",{value:g}),n.fire("drag",{value:g}),n.fire("dragend&q
 uot;,{value:g})}n.on("keydown",function(a){switch(a.keyCode){case 37:case 38:f(-1);break;case 39:case 40:f(1)}})}function g(a,e,f){var g,h,i,o,p;n._dragHelper=new b(n._id,{handle:n._id+"-handle",start:function(a){g=a[j],h=parseInt(n.getEl("handle").style[k],10),i=(n.layoutRect()[m]||100)-c.getSize(f)[l],n.fire("dragstart",{value:p})},drag:function(b){var c=b[j]-g;o=d(h+c,0,i),f.style[k]=o+"px",p=a+o/i*(e-a),n.value(p),n.tooltip().text(""+n.settings.previewFilter(p)).show().moveRel(f,"bc tc"),n.fire("drag",{value:p})},stop:function(){n.tooltip().hide(),n.fire("dragend",{value:p})}})}var h,i,j,k,l,m,n=this;h=n._minValue,i=n._maxValue,"v"==n.settings.orientation?(j="screenY",k="top",l="height",m="h"):(j="screenX",k="left",l="width",m="w"),n._super(),f(h,i,n.getEl("handle")),g(h,i,n.getEl("handl
 e"))},repaint:function(){this._super(),f(this,this.value())},bindStates:function(){var a=this;return a.state.on("change:value",function(b){f(a,b.value)}),a._super()}})}),g("45",["33"],function(a){"use strict";return a.extend({renderHtml:function(){var a=this;return a.classes.add("spacer"),a.canFocus=!1,'<div id="'+a._id+'" class="'+a.classes+'"></div>'}})}),g("46",["3w","4z","b"],function(a,b,c){return a.extend({Defaults:{classes:"widget btn splitbtn",role:"button"},repaint:function(){var a,d,e=this,f=e.getEl(),g=e.layoutRect();return e._super(),a=f.firstChild,d=f.lastChild,c(a).css({width:g.w-b.getSize(d).width,height:g.h-2}),c(d).css({height:g.h-2}),e},activeMenu:function(a){var b=this;c(b.getEl().lastChild).toggleClass(b.classPrefix+"active",a)},renderHtml:function(){var a,b=this,c=b._id,d=b.classPrefix,e=b.state.get("ic
 on"),f=b.state.get("text"),g="";return a=b.settings.image,a?(e="none","string"!=typeof a&&(a=window.getSelection?a[0]:a[1]),a=" style=\"background-image: url('"+a+"')\""):a="",e=b.settings.icon?d+"ico "+d+"i-"+e:"",f&&(b.classes.add("btn-has-text"),g='<span class="'+d+'txt">'+b.encode(f)+"</span>"),'<div id="'+c+'" class="'+b.classes+'" role="button" tabindex="-1"><button type="button" hidefocus="1" tabindex="-1">'+(e?'<i class="'+e+'"'+a+"></i>":"")+g+'</button><button type="button" class="'+d+'open" hidefocus="1" tabindex="-1">'+(b._menuBtnText?(e?"\xa0":"")+b._menuBtnText:"")+' <i class="'+d+'caret&q
 uot;></i></button></div>'},postRender:function(){var a=this,b=a.settings.onclick;return a.on("click",function(a){var c=a.target;if(a.control==this)for(;c;){if(a.aria&&"down"!=a.aria.key||"BUTTON"==c.nodeName&&c.className.indexOf("open")==-1)return a.stopImmediatePropagation(),void(b&&b.call(this,a));c=c.parentNode}}),delete a.settings.onclick,a._super()}})}),g("47",["3o"],function(a){"use strict";return a.extend({Defaults:{containerClass:"stack-layout",controlClass:"stack-layout-item",endClass:"break"},isNative:function(){return!0}})}),g("48",["2w","b","4z"],function(a,b,c){"use strict";return a.extend({Defaults:{layout:"absolute",defaults:{type:"panel"}},activateTab:function(a){var c;this.activeTabId&&(c=this.getEl(this.activeTabId),b(c).removeClass(this.classPre
 fix+"active"),c.setAttribute("aria-selected","false")),this.activeTabId="t"+a,c=this.getEl("t"+a),c.setAttribute("aria-selected","true"),b(c).addClass(this.classPrefix+"active"),this.items()[a].show().fire("showtab"),this.reflow(),this.items().each(function(b,c){a!=c&&b.hide()})},renderHtml:function(){var a=this,b=a._layout,c="",d=a.classPrefix;return a.preRender(),b.preRender(a),a.items().each(function(b,e){var f=a._id+"-t"+e;b.aria("role","tabpanel"),b.aria("labelledby",f),c+='<div id="'+f+'" class="'+d+'tab" unselectable="on" role="tab" aria-controls="'+b._id+'" aria-selected="false" tabIndex="-1">'+a.encode(b.settings.title)+"</div>"}),'<div id="'+a._id+'" class="'+a.classes+'" hidefocus="1" tabindex="-1&q
 uot;><div id="'+a._id+'-head" class="'+d+'tabs" role="tablist">'+c+'</div><div id="'+a._id+'-body" class="'+a.bodyClasses+'">'+b.renderHtml(a)+"</div></div>"},postRender:function(){var a=this;a._super(),a.settings.activeTab=a.settings.activeTab||0,a.activateTab(a.settings.activeTab),this.on("click",function(b){var c=b.target.parentNode;if(c&&c.id==a._id+"-head")for(var d=c.childNodes.length;d--;)c.childNodes[d]==b.target&&a.activateTab(d)})},initLayoutRect:function(){var a,b,d,e=this;b=c.getSize(e.getEl("head")).width,b=b<0?0:b,d=0,e.items().each(function(a){b=Math.max(b,a.layoutRect().minW),d=Math.max(d,a.layoutRect().minH)}),e.items().each(function(a){a.settings.x=0,a.settings.y=0,a.settings.w=b,a.settings.h=d,a.layoutRect({x:0,y:0,w:b,h:d})});var f=c.getSize(e.getEl("head")).height;return e.settings.minWidth=b,e.settings.minHeight
 =d+f,a=e._super(),a.deltaH+=f,a.innerH=a.h-a.deltaH,a}})}),g("49",["33","1d","4z"],function(a,b,c){return a.extend({init:function(a){var b=this;b._super(a),b.classes.add("textbox"),a.multiline?b.classes.add("multiline"):(b.on("keydown",function(a){var c;13==a.keyCode&&(a.preventDefault(),b.parents().reverse().each(function(a){if(a.toJSON)return c=a,!1}),b.fire("submit",{data:c.toJSON()}))}),b.on("keyup",function(a){b.state.set("value",a.target.value)}))},repaint:function(){var a,b,c,d,e,f=this,g=0;a=f.getEl().style,b=f._layoutRect,e=f._lastRepaintRect||{};var h=document;return!f.settings.multiline&&h.all&&(!h.documentMode||h.documentMode<=8)&&(a.lineHeight=b.h-g+"px"),c=f.borderBox,d=c.left+c.right+8,g=c.top+c.bottom+(f.settings.multiline?8:0),b.x!==e.x&&(a.left=b.x+"px",e.x=b.x),b.y!==e.y&&(a.top=b.y+"px&quot
 ;,e.y=b.y),b.w!==e.w&&(a.width=b.w-d+"px",e.w=b.w),b.h!==e.h&&(a.height=b.h-g+"px",e.h=b.h),f._lastRepaintRect=e,f.fire("repaint",{},!1),f},renderHtml:function(){var a,d,e=this,f=e.settings;return a={id:e._id,hidefocus:"1"},b.each(["rows","spellcheck","maxLength","size","readonly","min","max","step","list","pattern","placeholder","required","multiple"],function(b){a[b]=f[b]}),e.disabled()&&(a.disabled="disabled"),f.subtype&&(a.type=f.subtype),d=c.create(f.multiline?"textarea":"input",a),d.value=e.state.get("value"),d.className=e.classes,d.outerHTML},value:function(a){return arguments.length?(this.state.set("value",a),this):(this.state.get("rendered")&&this.state.set("value",this.getEl().value),this.state.get
 ("value"))},postRender:function(){var a=this;a.getEl().value=a.state.get("value"),a._super(),a.$el.on("change",function(b){a.state.set("value",b.target.value),a.fire("change",b)})},bindStates:function(){var a=this;return a.state.on("change:value",function(b){a.getEl().value!=b.value&&(a.getEl().value=b.value)}),a.state.on("change:disabled",function(b){a.getEl().disabled=b.value}),a._super()},remove:function(){this.$el.off(),this._super()}})}),h("5x",RegExp),g("4a",["33","1d","4z","5x"],function(a,b,c,d){return a.extend({init:function(a){var c=this;a=b.extend({height:100,text:"Drop an image here",multiple:!1,accept:null},a),c._super(a),c.classes.add("dropzone"),a.multiple&&c.classes.add("multiple")},renderHtml:function(){var a,b,d=this,e=d.settings;return a={id:d._id,hidefocus:"1"},b=c.create("di
 v",a,"<span>"+this.translate(e.text)+"</span>"),e.height&&c.css(b,"height",e.height+"px"),e.width&&c.css(b,"width",e.width+"px"),b.className=d.classes,b.outerHTML},postRender:function(){var a=this,c=function(b){b.preventDefault(),a.classes.toggle("dragenter"),a.getEl().className=a.classes},e=function(c){var e=a.settings.accept;if("string"!=typeof e)return c;var f=new d("("+e.split(/\s*,\s*/).join("|")+")$","i");return b.grep(c,function(a){return f.test(a.name)})};a._super(),a.$el.on("dragover",function(a){a.preventDefault()}),a.$el.on("dragenter",c),a.$el.on("dragleave",c),a.$el.on("drop",function(b){if(b.preventDefault(),!a.state.get("disabled")){var c=e(b.dataTransfer.files);a.value=function(){return c.length?a.settings.multiple?c:c[0]:null},c.length&&a.fire("change&qu
 ot;,b)}})},remove:function(){this.$el.off(),this._super()}})}),g("4b",["38","1d","4z","b","5x"],function(a,b,c,d,e){return a.extend({init:function(a){var c=this;a=b.extend({text:"Browse...",multiple:!1,accept:null},a),c._super(a),c.classes.add("browsebutton"),a.multiple&&c.classes.add("multiple")},postRender:function(){var a=this,b=c.create("input",{type:"file",id:a._id+"-browse",accept:a.settings.accept});a._super(),d(b).on("change",function(b){var c=b.target.files;a.value=function(){return c.length?a.settings.multiple?c:c[0]:null},b.preventDefault(),c.length&&a.fire("change",b)}),d(b).on("click",function(a){a.stopPropagation()}),d(a.getEl("button")).on("click",function(a){a.stopPropagation(),b.click()}),a.getEl().appendChild(b)},remove:function(){d(this.getEl("button")).off(),d(this.getEl
 ("input")).off(),this._super()}})}),g("10",["2n","2o","2p","2q","2r","2s","2t","2u","2v","2w","2x","2y","2z","30","31","32","33","34","35","36","37","38","39","3a","3b","3c","3d","3e","3f","3g","3h","3i","3j","3k","3l","3m","3n","3o","3p","3q","3r","3s","3t","3u","3v","3w","3x","3y","3z","40","41","42","43","44","45","46","47","48","49","4a","4b"],function(a,b,c,d,
 e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,$,_,aa,ba,ca,da,ea,fa,ga){"use strict";var ha=function(a,b){e.add(a.split(".").pop(),b)},ia=function(a,b,c){var d,e;for(e=b.split(/[.\/]/),d=0;d<e.length-1;++d)void 0===a[e[d]]&&(a[e[d]]={}),a=a[e[d]];a[e[e.length-1]]=c,ha(b,c)},ja=function(ha){ia(ha,"ui.Selector",a),ia(ha,"ui.Collection",b),ia(ha,"ui.ReflowQueue",c),ia(ha,"ui.Control",d),ia(ha,"ui.Factory",e),ia(ha,"ui.KeyboardNavigation",f),ia(ha,"ui.Container",g),ia(ha,"ui.DragHelper",h),ia(ha,"ui.Scrollable",i),ia(ha,"ui.Panel",j),ia(ha,"ui.Movable",k),ia(ha,"ui.Resizable",l),ia(ha,"ui.FloatPanel",m),ia(ha,"ui.Window",n),ia(ha,"ui.MessageBox",o),ia(ha,"ui.Tooltip",p),ia(ha,"ui.Widget",q),ia(ha,"ui.Progress",r),ia(ha,"ui.No
 tification",s),ia(ha,"ui.Layout",t),ia(ha,"ui.AbsoluteLayout",u),ia(ha,"ui.Button",v),ia(ha,"ui.ButtonGroup",w),ia(ha,"ui.Checkbox",x),ia(ha,"ui.ComboBox",y),ia(ha,"ui.ColorBox",z),ia(ha,"ui.PanelButton",A),ia(ha,"ui.ColorButton",B),ia(ha,"ui.ColorPicker",C),ia(ha,"ui.Path",D),ia(ha,"ui.ElementPath",E),ia(ha,"ui.FormItem",F),ia(ha,"ui.Form",G),ia(ha,"ui.FieldSet",H),ia(ha,"ui.FilePicker",I),ia(ha,"ui.FitLayout",J),ia(ha,"ui.FlexLayout",K),ia(ha,"ui.FlowLayout",L),ia(ha,"ui.FormatControls",M),ia(ha,"ui.GridLayout",N),ia(ha,"ui.Iframe",O),ia(ha,"ui.InfoBox",P),ia(ha,"ui.Label",Q),ia(ha,"ui.Toolbar",R),ia(ha,"ui.MenuBar",S),ia(ha,"ui.MenuButton",T),ia(ha,"ui.MenuItem",U),ia(ha,"ui.Throbber",V),ia
 (ha,"ui.Menu",W),ia(ha,"ui.ListBox",X),ia(ha,"ui.Radio",Y),ia(ha,"ui.ResizeHandle",Z),ia(ha,"ui.SelectBox",$),ia(ha,"ui.Slider",_),ia(ha,"ui.Spacer",aa),ia(ha,"ui.SplitButton",ba),ia(ha,"ui.StackLayout",ca),ia(ha,"ui.TabPanel",da),ia(ha,"ui.TextBox",ea),ia(ha,"ui.DropZone",fa),ia(ha,"ui.BrowseButton",ga),ia(ha,"ui.Api",ka)},ka={appendTo:ja};return ka}),g("17",[],function(){function a(b,c){var d,e,f,g;if(c=c||'"',null===b)return"null";if(f=typeof b,"string"==f)return e="\bb\tt\nn\ff\rr\"\"''\\\\",c+b.replace(/([\u0080-\uFFFF\x00-\x1f\"\'\\])/g,function(a,b){return'"'===c&&"'"===a?a:(d=e.indexOf(b),d+1?"\\"+e.charAt(d+1):(a=b.charCodeAt().toString(16),"\\u"+"0000".substring(a.length)+a))})+c;if("object"==f){if(b.hasOwnProperty
 &&"[object Array]"===Object.prototype.toString.call(b)){for(d=0,e="[";d<b.length;d++)e+=(d>0?",":"")+a(b[d],c);return e+"]"}e="{";for(g in b)b.hasOwnProperty(g)&&(e+="function"!=typeof b[g]?(e.length>1?","+c:c)+g+c+":"+a(b[g],c):"");return e+"}"}return""+b}return{serialize:a,parse:function(a){try{return window[String.fromCharCode(101)+"val"]("("+a+")")}catch(a){}}}}),g("18",["c"],function(a){return{callbacks:{},count:0,send:function(b){var c=this,d=a.DOM,e=void 0!==b.count?b.count:c.count,f="tinymce_jsonp_"+e;c.callbacks[e]=function(a){d.remove(f),delete c.callbacks[e],b.callback(a)},d.add(d.doc.body,"script",{id:f,src:b.url,type:"text/javascript"}),c.count++}}}),g("1g",["1b","1d"],function(a,b){var c={send:function(a){function d(){
 !a.async||4==e.readyState||f++>1e4?(a.success&&f<1e4&&200==e.status?a.success.call(a.success_scope,""+e.responseText,e,a):a.error&&a.error.call(a.error_scope,f>1e4?"TIMED_OUT":"GENERAL",e,a),e=null):setTimeout(d,10)}var e,f=0;if(a.scope=a.scope||this,a.success_scope=a.success_scope||a.scope,a.error_scope=a.error_scope||a.scope,a.async=a.async!==!1,a.data=a.data||"",c.fire("beforeInitialize",{settings:a}),e=new XMLHttpRequest){if(e.overrideMimeType&&e.overrideMimeType(a.content_type),e.open(a.type||(a.data?"POST":"GET"),a.url,a.async),a.crossDomain&&(e.withCredentials=!0),a.content_type&&e.setRequestHeader("Content-Type",a.content_type),a.requestheaders&&b.each(a.requestheaders,function(a){e.setRequestHeader(a.key,a.value)}),e.setRequestHeader("X-Requested-With","XMLHttpRequest"),e=c.fire("beforeSend",{xhr:e,set
 tings:a}).xhr,e.send(a.data),!a.async)return d();setTimeout(d,10)}}};return b.extend(c,a),c}),g("19",["17","1g","1d"],function(a,b,c){function d(a){this.settings=e({},a),this.count=0}var e=c.extend;return d.sendRPC=function(a){return(new d).send(a)},d.prototype={send:function(c){var d=c.error,f=c.success;c=e(this.settings,c),c.success=function(b,e){b=a.parse(b),"undefined"==typeof b&&(b={error:"JSON Parse error."}),b.error?d.call(c.error_scope||c.scope,b.error,e):f.call(c.success_scope||c.scope,b.result)},c.error=function(a,b){d&&d.call(c.error_scope||c.scope,a,b)},c.data=a.serialize({id:c.id||"c"+this.count++,method:c.method,params:c.params}),c.content_type="application/json",b.send(c)}},d}),g("1a",[],function(){function a(){g=[];for(var a in f)g.push(a);d.length=g.length}function b(){function b(a){var b,c;return c=void 0!==a?j+a:d.indexOf(",",j),c===-1||c>d.length
 ?null:(b=d.substring(j,c),j=c+1,b)}var c,d,g,j=0;if(f={},i){e.load(h),d=e.getAttribute(h)||"";do{var k=b();if(null===k)break;if(c=b(parseInt(k,32)||0),null!==c){if(k=b(),null===k)break;g=b(parseInt(k,32)||0),c&&(f[c]=g)}}while(null!==c);a()}}function c(){var b,c="";if(i){for(var d in f)b=f[d],c+=(c?",":"")+d.length.toString(32)+","+d+","+b.length.toString(32)+","+b;e.setAttribute(h,c);try{e.save(h)}catch(a){}a()}}var d,e,f,g,h,i;try{if(window.localStorage)return localStorage}catch(a){}return h="tinymce",e=document.documentElement,i=!!e.addBehavior,i&&e.addBehavior("#default#userData"),d={key:function(a){return g[a]},getItem:function(a){return a in f?f[a]:null},setItem:function(a,b){f[a]=""+b,c()},removeItem:function(a){delete f[a],c()},clear:function(){f={},c()}},b(),d}),g("2",["5","6","7","8","9","a&quot
 ;,"b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","10","11","12","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f","1g"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V){var W=r,X={geom:{Rect:v},util:{Promise:R,Delay:J,Tools:S,VK:U,URI:T,Class:H,EventDispatcher:K,Observable:Q,I18n:L,XHR:V,JSON:M,JSONRequest:O,JSONP:N,LocalStorage:P,Color:I},dom:{EventUtils:i,Sizzle:n,DomQuery:g,TreeWalker:o,DOMUtils:h,ScriptLoader:k,RangeUtils:j,Serializer:m,Control
 Selection:f,BookmarkManager:e,Selection:l,Event:i.Event},html:{Styles:C,Entities:x,Node:y,Schema:A,SaxParser:z,DomParser:w,Writer:D,Serializer:B},Env:t,AddOnManager:a,Formatter:b,UndoManager:G,EditorCommands:q,WindowManager:d,NotificationManager:c,EditorObservable:s,Shortcuts:E,Editor:p,FocusManager:u,EditorManager:r,DOM:h.DOM,ScriptLoader:k.ScriptLoader,PluginManager:a.PluginManager,ThemeManager:a.ThemeManager,trim:S.trim,isArray:S.isArray,is:S.is,toArray:S.toArray,makeMap:S.makeMap,each:S.each,map:S.map,grep:S.grep,inArray:S.inArray,extend:S.extend,create:S.create,walk:S.walk,createNS:S.createNS,resolve:S.resolve,explode:S.explode,_addCacheSuffix:S._addCacheSuffix,isOpera:t.opera,isWebKit:t.webkit,isIE:t.ie,isGecko:t.gecko,isMac:t.mac};return W=S.extend(W,X),F.appendTo(W),W}),g("0",["1","2"],function(a,b){var c=this||window,d=function(b){"function"!=typeof c.define||c.define.amd||(c.define("ephox/tinymce",[],a.constant(b)),c.define
 ("m",[],a.constant(b))),"object"==typeof module&&(module.exports=b);
+},e=function(a){window.tinymce=a,window.tinyMCE=a};return function(){return e(b),d(b),b}}),d("0")()}();
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span></span></pre></div>
<a id="trunksrcwpincludesjstinymceutilsmctabsjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/tinymce/utils/mctabs.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/tinymce/utils/mctabs.js  2017-09-26 20:32:46 UTC (rev 41603)
+++ trunk/src/wp-includes/js/tinymce/utils/mctabs.js    2017-09-26 21:14:28 UTC (rev 41604)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -12,7 +12,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> function MCTabs() {
</span><span class="cx" style="display: block; padding: 0 10px">   this.settings = [];
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  this.onChange = tinyMCEPopup.editor.windowManager.createInstance('tinymce.plugins.util.Dispatcher');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  this.onChange = tinyMCEPopup.editor.windowManager.createInstance('tinymce.util.Dispatcher');
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> MCTabs.prototype.init = function (settings) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -155,7 +155,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">       dom.setAttrib(a, 'tabindex', '-1');
</span><span class="cx" style="display: block; padding: 0 10px">     });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    /*keyNav = tinyMCEPopup.editor.windowManager.createInstance('tinymce.plugins.ui.KeyboardNavigation', {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    /*keyNav = tinyMCEPopup.editor.windowManager.createInstance('tinymce.ui.KeyboardNavigation', {
</ins><span class="cx" style="display: block; padding: 0 10px">       root: tabContainerElm,
</span><span class="cx" style="display: block; padding: 0 10px">       items: items,
</span><span class="cx" style="display: block; padding: 0 10px">       onAction: action,
</span></span></pre></div>
<a id="trunksrcwpincludesversionphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/version.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/version.php 2017-09-26 20:32:46 UTC (rev 41603)
+++ trunk/src/wp-includes/version.php   2017-09-26 21:14:28 UTC (rev 41604)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -18,7 +18,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @global string $tinymce_version
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-$tinymce_version = '4603-20170530';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+$tinymce_version = '4607-20170918';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px">  * Holds the required PHP version
</span></span></pre>
</div>
</div>

</body>
</html>