diff --git a/Gemfile.lock b/Gemfile.lock
index 7f3a6dbf..8540d6b9 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -389,13 +389,13 @@ GEM
thor (0.19.4)
thread_safe (0.3.6)
tilt (2.0.7)
- tinymce-rails (4.5.7)
+ tinymce-rails (4.6.0)
railties (>= 3.1.1)
tinymce-rails-langs (4.20160310)
tinymce-rails (~> 4.1, >= 4.1.10)
turbolinks (5.0.1)
turbolinks-source (~> 5)
- turbolinks-source (5.0.2)
+ turbolinks-source (5.0.3)
twitter (6.1.0)
addressable (~> 2.5)
buftok (~> 0.2.0)
diff --git a/app/models/event_callbacks.rb b/app/models/event_callbacks.rb
index a7f495aa..832c377b 100644
--- a/app/models/event_callbacks.rb
+++ b/app/models/event_callbacks.rb
@@ -42,6 +42,7 @@ class EventCallbacks
def self.after_destroy(event)
return unless ActionMailer::Base.default_url_options[:host]
+ return if event.reason == 'r_0'
EventMailer.destroy(event).deliver_now
ModerationMailer.destroy(event).deliver_now
end
diff --git a/public/assets/.sprockets-manifest-15ceda6913c644f60925b0cd3079d44e.json b/public/assets/.sprockets-manifest-15ceda6913c644f60925b0cd3079d44e.json
index 97825c5d..c821ee0a 100644
--- a/public/assets/.sprockets-manifest-15ceda6913c644f60925b0cd3079d44e.json
+++ b/public/assets/.sprockets-manifest-15ceda6913c644f60925b0cd3079d44e.json
@@ -1 +1 @@
-{"files":{"active_admin-1a6505fe97404d4518ab3540e631c4ba837fd413398b4e75ad4abbcd110398f3.css":{"logical_path":"active_admin.css","mtime":"2016-12-10T11:36:51+01:00","size":78849,"digest":"1a6505fe97404d4518ab3540e631c4ba837fd413398b4e75ad4abbcd110398f3","integrity":"sha256-GmUF/pdATUUYqzVA5jHEuoN/1BM5i051rUq7zREDmPM="},"active_admin/nested_menu_arrow-15084d93c65c1964d7077700ea748bd2d70cfa2d4c19707c58a9c64e232dd442.gif":{"logical_path":"active_admin/nested_menu_arrow.gif","mtime":"2017-05-04T21:49:46+02:00","size":70,"digest":"15084d93c65c1964d7077700ea748bd2d70cfa2d4c19707c58a9c64e232dd442","integrity":"sha256-FQhNk8ZcGWTXB3cA6nSL0tcM+i1MGXB8WKnGTiMt1EI="},"active_admin/nested_menu_arrow_dark-7c43b8e0a5f8823875f49a093c9d7a6b374f885b6f9cc248ae9cd7e6e9b29034.gif":{"logical_path":"active_admin/nested_menu_arrow_dark.gif","mtime":"2017-05-04T21:49:46+02:00","size":70,"digest":"7c43b8e0a5f8823875f49a093c9d7a6b374f885b6f9cc248ae9cd7e6e9b29034","integrity":"sha256-fEO44KX4gjh19JoJPJ16azdPiFtvnMJIrpzX5umykDQ="},"active_admin/datepicker/datepicker-input-icon-d9c2bb73769af777c8a71720d29741f3a499aebd5a043e9a119bd0d9597aed47.png":{"logical_path":"active_admin/datepicker/datepicker-input-icon.png","mtime":"2017-05-04T21:49:46+02:00","size":1535,"digest":"d9c2bb73769af777c8a71720d29741f3a499aebd5a043e9a119bd0d9597aed47","integrity":"sha256-2cK7c3aa93fIpxcg0pdB86SZrr1aBD6aEZvQ2Vl67Uc="},"active_admin/orderable-29374dbb55b0012d78a37c614d573bb3474f0779849b478a147d0f1845ca6617.png":{"logical_path":"active_admin/orderable.png","mtime":"2017-05-04T21:49:46+02:00","size":220,"digest":"29374dbb55b0012d78a37c614d573bb3474f0779849b478a147d0f1845ca6617","integrity":"sha256-KTdNu1WwAS14o3xhTVc7s0dPB3mEm0eKFH0PGEXKZhc="},"active_admin/print-87c5ffc1d869a919123bcc1dc5ec51b20bc79fd9aeab9eed77e3438c6acd4f68.css":{"logical_path":"active_admin/print.css","mtime":"2017-05-04T21:49:46+02:00","size":5494,"digest":"87c5ffc1d869a919123bcc1dc5ec51b20bc79fd9aeab9eed77e3438c6acd4f68","integrity":"sha256-h8X/wdhpqRkSO8wdxexRsgvHn9muq57td+NDjGrNT2g="},"active_admin-5d8dda85fd2e9296c4f9682a0c4441e4dfc6c2779454e8144be78befe3ff05bb.js":{"logical_path":"active_admin.js","mtime":"2017-01-02T09:58:37+01:00","size":692380,"digest":"5d8dda85fd2e9296c4f9682a0c4441e4dfc6c2779454e8144be78befe3ff05bb","integrity":"sha256-XY3ahf0ukpbE+WgqDERB5N/GwneUVOgUS+eL7+P/Bbs="},"layers-2x-0c02a2388f637d21f86e6d4b314ec9a968e7b05ad4c3a005280a3f76c0fd3cb8.png":{"logical_path":"layers-2x.png","mtime":"2016-10-29T16:45:43+02:00","size":2898,"digest":"0c02a2388f637d21f86e6d4b314ec9a968e7b05ad4c3a005280a3f76c0fd3cb8","integrity":"sha256-DAKiOI9jfSH4bm1LMU7JqWjnsFrUw6AFKAo/dsD9PLg="},"layers-0908aa2a72a082fb2563a2427a5e4fb247571862b448b80fb6f720af1109923e.png":{"logical_path":"layers.png","mtime":"2016-10-29T16:45:43+02:00","size":1502,"digest":"0908aa2a72a082fb2563a2427a5e4fb247571862b448b80fb6f720af1109923e","integrity":"sha256-CQiqKnKggvslY6JCel5PskdXGGK0SLgPtvcgrxEJkj4="},"marker-icon-2x-454dc479e82b487529b6b93d6a9b29ac69ca7b4f5a9d5fdf8e01871f6d216113.png":{"logical_path":"marker-icon-2x.png","mtime":"2016-10-29T16:45:43+02:00","size":4033,"digest":"454dc479e82b487529b6b93d6a9b29ac69ca7b4f5a9d5fdf8e01871f6d216113","integrity":"sha256-RU3EeegrSHUptrk9apsprGnKe09anV/fjgGHH20hYRM="},"marker-icon-915e83a6fc798c599e5c9e3f759d6bc065d65151019acd0410d1f4731bcaaf72.png":{"logical_path":"marker-icon.png","mtime":"2016-10-29T16:45:43+02:00","size":1747,"digest":"915e83a6fc798c599e5c9e3f759d6bc065d65151019acd0410d1f4731bcaaf72","integrity":"sha256-kV6Dpvx5jFmeXJ4/dZ1rwGXWUVEBms0EENH0cxvKr3I="},"marker-shadow-4f340d2d61746333dffe056e074ce1704ae4e47fec5a7de98322fbdbcfcb2b6d.png":{"logical_path":"marker-shadow.png","mtime":"2016-10-29T16:45:43+02:00","size":797,"digest":"4f340d2d61746333dffe056e074ce1704ae4e47fec5a7de98322fbdbcfcb2b6d","integrity":"sha256-TzQNLWF0YzPf/gVuB0zhcErk5H/sWn3pgyL728/LK20="},"tinymce-e760fd8b6f08323d2b85a1a7a149a483d75d4bf23628ffb9340280f59b2d359d.js":{"logical_path":"tinymce.js","mtime":"2016-12-17T16:47:53+01:00","size":971,"digest":"e760fd8b6f08323d2b85a1a7a149a483d75d4bf23628ffb9340280f59b2d359d","integrity":"sha256-52D9i28IMj0rhaGnoUmkg9ddS/I2KP+5NAKA9ZstNZ0="},"application-943a3e70ac370e883a0394cbddf7c60a6ec281cd561d3c6817cfa97974531bc8.css":{"logical_path":"application.css","mtime":"2016-12-17T16:47:53+01:00","size":170905,"digest":"943a3e70ac370e883a0394cbddf7c60a6ec281cd561d3c6817cfa97974531bc8","integrity":"sha256-lDo+cKw3Dog6A5TL3ffGCm7Cgc1WHTxoF8+peXRTG8g="},"jquery-ui/ui-icons_444444_256x240-31d988765b4e6f56553c29588c500381dc3e6f0aa2980c8212202e5644aefd5d.png":{"logical_path":"jquery-ui/ui-icons_444444_256x240.png","mtime":"2017-04-24T19:17:54+02:00","size":3756,"digest":"31d988765b4e6f56553c29588c500381dc3e6f0aa2980c8212202e5644aefd5d","integrity":"sha256-MdmIdltOb1ZVPClYjFADgdw+bwqimAyCEiAuVkSu/V0="},"jquery-ui/ui-icons_555555_256x240-32175261daee76c82bb0edf0eea16a56421866fbc31e94f3c1d570aa114502f5.png":{"logical_path":"jquery-ui/ui-icons_555555_256x240.png","mtime":"2017-04-24T19:17:54+02:00","size":3756,"digest":"32175261daee76c82bb0edf0eea16a56421866fbc31e94f3c1d570aa114502f5","integrity":"sha256-MhdSYdrudsgrsO3w7qFqVkIYZvvDHpTzwdVwqhFFAvU="},"jquery-ui/ui-icons_ffffff_256x240-350df1b7131037de20e83c5c0f3a41a770d2ac48b5762ea772b3f4a8a7b9d47a.png":{"logical_path":"jquery-ui/ui-icons_ffffff_256x240.png","mtime":"2017-04-24T19:17:54+02:00","size":3756,"digest":"350df1b7131037de20e83c5c0f3a41a770d2ac48b5762ea772b3f4a8a7b9d47a","integrity":"sha256-NQ3xtxMQN94g6DxcDzpBp3DSrEi1di6ncrP0qKe51Ho="},"jquery-ui/ui-icons_777620_256x240-0b020fc6e696d88d296e7bb1f61f1eb2ad827848e2c7382a4c3e0999e702dd9b.png":{"logical_path":"jquery-ui/ui-icons_777620_256x240.png","mtime":"2017-04-24T19:17:54+02:00","size":3756,"digest":"0b020fc6e696d88d296e7bb1f61f1eb2ad827848e2c7382a4c3e0999e702dd9b","integrity":"sha256-CwIPxuaW2I0pbnux9h8esq2CeEjixzgqTD4JmecC3Zs="},"jquery-ui/ui-icons_cc0000_256x240-40985a64b4d5dd213fba27fcd862a1bd1b337a97674f6ff0b9ec20abcee4bc69.png":{"logical_path":"jquery-ui/ui-icons_cc0000_256x240.png","mtime":"2017-04-24T19:17:54+02:00","size":3756,"digest":"40985a64b4d5dd213fba27fcd862a1bd1b337a97674f6ff0b9ec20abcee4bc69","integrity":"sha256-QJhaZLTV3SE/uif82GKhvRszepdnT2/wuewgq87kvGk="},"jquery-ui/ui-icons_777777_256x240-faf32007ae120c302213557626e660dd10e711c5dd4f1113d35f26dc05b78d2f.png":{"logical_path":"jquery-ui/ui-icons_777777_256x240.png","mtime":"2017-04-24T19:17:54+02:00","size":3756,"digest":"faf32007ae120c302213557626e660dd10e711c5dd4f1113d35f26dc05b78d2f","integrity":"sha256-+vMgB64SDDAiE1V2JuZg3RDnEcXdTxET018m3AW3jS8="},"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot":{"logical_path":"font-awesome/fontawesome-webfont.eot","mtime":"2017-04-24T19:17:40+02:00","size":165742,"digest":"7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979","integrity":"sha256-e/yrbbmdXPvxcFygU23ceFhUMsxfpBu9etDwCQM7KXk="},"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2":{"logical_path":"font-awesome/fontawesome-webfont.woff2","mtime":"2017-04-24T19:17:40+02:00","size":77160,"digest":"2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe","integrity":"sha256-Kt78vAQefRj88tQXh53FoJmXqmTWdbejxLbOM9oT8/4="},"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff":{"logical_path":"font-awesome/fontawesome-webfont.woff","mtime":"2017-04-24T19:17:40+02:00","size":98024,"digest":"ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07","integrity":"sha256-ugxZ3rVFD1y0Gz+TYJ7i0NmVQVh33foiPoqKdTNHTwc="},"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf":{"logical_path":"font-awesome/fontawesome-webfont.ttf","mtime":"2017-04-24T19:17:40+02:00","size":165548,"digest":"aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8","integrity":"sha256-qljzPyOaD7AvXHpsRcBD16msmgkzNYBmlOzW1O3A1qg="},"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg":{"logical_path":"font-awesome/fontawesome-webfont.svg","mtime":"2017-04-24T19:17:40+02:00","size":444379,"digest":"ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4","integrity":"sha256-rWFXkmwWIrpOHQPUePFUE2hSS/xG9R5C/g2UX37zI+Q="},"markers-soft-e78784e4ed70aaffddd73c315fab590233cc4e7b72388d7dd47a14796fc7c739.png":{"logical_path":"markers-soft.png","mtime":"2016-05-21T23:41:15+02:00","size":41226,"digest":"e78784e4ed70aaffddd73c315fab590233cc4e7b72388d7dd47a14796fc7c739","integrity":"sha256-54eE5O1wqv/d1zwxX6tZAjPMTntyOI191HoUeW/Hxzk="},"markers-shadow-8703a2262710f5e3d29e65d2acdf90d6512e159e119d27b8234731d8a6208a20.png":{"logical_path":"markers-shadow.png","mtime":"2016-05-21T23:41:15+02:00","size":535,"digest":"8703a2262710f5e3d29e65d2acdf90d6512e159e119d27b8234731d8a6208a20","integrity":"sha256-hwOiJicQ9ePSnmXSrN+Q1lEuFZ4RnSe4I0cx2KYgiiA="},"markers-soft@2x-c1e77253a8bfbe30cec24885d7046f443b76ebb66f4c961f77083b03f4a5cbaf.png":{"logical_path":"markers-soft@2x.png","mtime":"2016-05-21T23:41:15+02:00","size":66408,"digest":"c1e77253a8bfbe30cec24885d7046f443b76ebb66f4c961f77083b03f4a5cbaf","integrity":"sha256-wedyU6i/vjDOwkiF1wRvRDt267ZvTJYfdwg7A/Sly68="},"markers-shadow@2x-b21a536be27313fb504f69f5899ff0b1245b276571769ac08d6c32c35676e47a.png":{"logical_path":"markers-shadow@2x.png","mtime":"2016-05-21T23:41:15+02:00","size":1469,"digest":"b21a536be27313fb504f69f5899ff0b1245b276571769ac08d6c32c35676e47a","integrity":"sha256-shpTa+JzE/tQT2n1iZ/wsSRbJ2VxdprAjWwyw1Z25Ho="},"france-f4341a7ec8331161a9c8d5298f808014c3fc9c799b5a29ed95eb56a7f3ccd0df.png":{"logical_path":"france.png","mtime":"2014-07-04T14:08:56+02:00","size":276,"digest":"f4341a7ec8331161a9c8d5298f808014c3fc9c799b5a29ed95eb56a7f3ccd0df","integrity":"sha256-9DQafsgzEWGpyNUpj4CAFMP8nHmbWintletWp/PM0N8="},"quebec-776d563b6a4ac4312cae9f0bfe630c20711346e8dbddd41040998eba79f4b588.png":{"logical_path":"quebec.png","mtime":"2015-10-22T22:54:30+02:00","size":567,"digest":"776d563b6a4ac4312cae9f0bfe630c20711346e8dbddd41040998eba79f4b588","integrity":"sha256-d21WO2pKxDEsrp8L/mMMIHETRujb3dQQQJmOunn0tYg="},"belgique-3b8b772a522de2cbae7714b35a956faf2c394419b532a14bba982fed3f341091.png":{"logical_path":"belgique.png","mtime":"2014-07-04T14:08:56+02:00","size":187,"digest":"3b8b772a522de2cbae7714b35a956faf2c394419b532a14bba982fed3f341091","integrity":"sha256-O4t3KlIt4suudxSzWpVvryw5RBm1MqFLupgv7T80EJE="},"suisse-58d067f1c3fcdc4000fa13e95896cd5369a2b91aafd314475aa5e29da0b543d1.png":{"logical_path":"suisse.png","mtime":"2015-10-22T22:54:30+02:00","size":299,"digest":"58d067f1c3fcdc4000fa13e95896cd5369a2b91aafd314475aa5e29da0b543d1","integrity":"sha256-WNBn8cP83EAA+hPpWJbNU2miuRqv0xRHWqXinaC1Q9E="},"modernizr-654222debe8018b12f1993ceddff30dc163a7d5008d79869c399d6d167321f97.js":{"logical_path":"modernizr.js","mtime":"2017-04-24T19:16:49+02:00","size":51365,"digest":"654222debe8018b12f1993ceddff30dc163a7d5008d79869c399d6d167321f97","integrity":"sha256-ZUIi3r6AGLEvGZPO3f8w3BY6fVAI15hpw5nW0WcyH5c="},"agendadescommuns-cd40e342024be0587f8e7a0e3902d32cf67009d349b67c00f687e0499fde9ff6.png":{"logical_path":"agendadescommuns.png","mtime":"2015-10-22T22:54:30+02:00","size":2760,"digest":"cd40e342024be0587f8e7a0e3902d32cf67009d349b67c00f687e0499fde9ff6","integrity":"sha256-zUDjQgJL4Fh/jnoOOQLTLPZwCdNJtnwA9ofgSZ/en/Y="},"alert-762ace9479328243a44061346b64c4d6b997e963c68dfc6bddd9e4d241192906.png":{"logical_path":"alert.png","mtime":"2014-07-04T14:08:56+02:00","size":47876,"digest":"762ace9479328243a44061346b64c4d6b997e963c68dfc6bddd9e4d241192906","integrity":"sha256-dirOlHkygkOkQGE0a2TE1rmX6WPGjfxr3dnk0kEZKQY="},"baby_gnu_adl-232caf355c30740d5d9b30491887cd546b8849b33ca9bdb6cc71f8a47ea61815.png":{"logical_path":"baby_gnu_adl.png","mtime":"2016-09-11T17:42:49+02:00","size":10155,"digest":"232caf355c30740d5d9b30491887cd546b8849b33ca9bdb6cc71f8a47ea61815","integrity":"sha256-IyyvNVwwdA1dmzBJGIfNVGuISbM8qb22zHH4pH6mGBU="},"baby_gnu_adl-97251005d3225cf1d58b8c497d6b7905dbc9560cc8acd50118fcce60d0a2679e.svg":{"logical_path":"baby_gnu_adl.svg","mtime":"2016-09-11T17:42:49+02:00","size":109635,"digest":"97251005d3225cf1d58b8c497d6b7905dbc9560cc8acd50118fcce60d0a2679e","integrity":"sha256-lyUQBdMiXPHVi4xJfWt5BdvJVgzIrNUBGPzOYNCiZ54="},"communs-cd40e342024be0587f8e7a0e3902d32cf67009d349b67c00f687e0499fde9ff6.png":{"logical_path":"communs.png","mtime":"2015-10-22T22:54:30+02:00","size":2760,"digest":"cd40e342024be0587f8e7a0e3902d32cf67009d349b67c00f687e0499fde9ff6","integrity":"sha256-zUDjQgJL4Fh/jnoOOQLTLPZwCdNJtnwA9ofgSZ/en/Y="},"lef-small-160cf5b883add60c9c0f4361bd8425c75f6fb23b0e551a0b941fa0491c70e0c9.png":{"logical_path":"lef-small.png","mtime":"2015-03-29T11:07:15+02:00","size":1089,"digest":"160cf5b883add60c9c0f4361bd8425c75f6fb23b0e551a0b941fa0491c70e0c9","integrity":"sha256-Fgz1uIOt1gycD0NhvYQlx19vsjsOVRoLlB+gSRxw4Mk="},"lef-bec4081a11fbef165216827cf72c7a292ad772a77af6b8132e5bc0bbf83cb2d9.png":{"logical_path":"lef.png","mtime":"2016-01-24T11:38:05+01:00","size":8415,"digest":"bec4081a11fbef165216827cf72c7a292ad772a77af6b8132e5bc0bbf83cb2d9","integrity":"sha256-vsQIGhH77xZSFoJ89yx6KSrXcqd69rgTLlvAu/g8stk="},"priorite-logiciel-libre-je-soutiens-april_2_m-6442e454e96ed45cc1ebc40673a6c50bd286b9c28ea6a8b58572e94f7d6459fc.png":{"logical_path":"priorite-logiciel-libre-je-soutiens-april_2_m.png","mtime":"2015-10-22T22:54:30+02:00","size":16952,"digest":"6442e454e96ed45cc1ebc40673a6c50bd286b9c28ea6a8b58572e94f7d6459fc","integrity":"sha256-ZELkVOlu1FzB68QGc6bFC9KGucKOpqi1hXLpT31kWfw="},"team-cb04c7a311f7160c4eb6a281eae68be84f26991dde5d415bb4e205e6726ae275.png":{"logical_path":"team.png","mtime":"2014-07-04T14:08:56+02:00","size":3586,"digest":"cb04c7a311f7160c4eb6a281eae68be84f26991dde5d415bb4e205e6726ae275","integrity":"sha256-ywTHoxH3FgxOtqKB6uaL6E8mmR3eXUFbtOIF5nJq4nU="},"application-224c876758d567479b1ebc1da354a712a64d27a100fb0ba5b8f1c0ca5188d55c.js":{"logical_path":"application.js","mtime":"2016-12-17T16:47:53+01:00","size":2158066,"digest":"224c876758d567479b1ebc1da354a712a64d27a100fb0ba5b8f1c0ca5188d55c","integrity":"sha256-IkyHZ1jVZ0ebHrwdo1SnEqZNJ6EA+wuluPHAylGI1Vw="},"markers-matte-497826545a90e09a240504d14530eba45823b19fd44175e09e27c47cd822ddb9.png":{"logical_path":"markers-matte.png","mtime":"2016-05-21T23:41:15+02:00","size":14323,"digest":"497826545a90e09a240504d14530eba45823b19fd44175e09e27c47cd822ddb9","integrity":"sha256-SXgmVFqQ4JokBQTRRTDrpFgjsZ/UQXXgnifEfNgi3bk="},"markers-matte@2x-948fc8c4426f04f60964ed20394247f45b0b60e575d02398b9b6810e7a29a823.png":{"logical_path":"markers-matte@2x.png","mtime":"2016-05-21T23:41:15+02:00","size":31113,"digest":"948fc8c4426f04f60964ed20394247f45b0b60e575d02398b9b6810e7a29a823","integrity":"sha256-lI/IxEJvBPYJZO0gOUJH9FsLYOV10COYubaBDnopqCM="},"markers-plain-cf233423aa44e75ac0031e77b8ba571cd3331010517e1197e63fb7b06856c1ff.png":{"logical_path":"markers-plain.png","mtime":"2016-05-21T23:41:15+02:00","size":7946,"digest":"cf233423aa44e75ac0031e77b8ba571cd3331010517e1197e63fb7b06856c1ff","integrity":"sha256-zyM0I6pE51rAAx53uLpXHNMzEBBRfhGX5j+3sGhWwf8="},"jquery-ui/ui-bg_flat_0_aaaaaa_40x100-ae65a7ae22c4c23115948fdeb5c05c9137dbd13ca2d426b3c4c3c4183451e410.png":{"logical_path":"jquery-ui/ui-bg_flat_0_aaaaaa_40x100.png","mtime":"2017-04-24T19:17:54+02:00","size":86,"digest":"ae65a7ae22c4c23115948fdeb5c05c9137dbd13ca2d426b3c4c3c4183451e410","integrity":"sha256-rmWnriLEwjEVlI/etcBckTfb0Tyi1CazxMPEGDRR5BA="},"tinymce-a6d3b77f66eb3e1971dc7bd18d9cefefd2947a846683d2a189a092f94280acf4.js":{"logical_path":"tinymce.js","mtime":"2016-12-17T22:42:28+01:00","size":971,"digest":"a6d3b77f66eb3e1971dc7bd18d9cefefd2947a846683d2a189a092f94280acf4","integrity":"sha256-ptO3f2brPhlx3HvRjZzv79KUeoRmg9KhiaCS+UKArPQ="},"application-6054b0bc1c370f1c7d66e9d0c3d21aa9fa886547e9c7732570440a4f42618a99.css":{"logical_path":"application.css","mtime":"2016-12-17T22:42:28+01:00","size":170862,"digest":"6054b0bc1c370f1c7d66e9d0c3d21aa9fa886547e9c7732570440a4f42618a99","integrity":"sha256-YFSwvBw3Dxx9ZunQw9IaqfqIZUfpx3MlcEQKT0Jhipk="},"application-97155f8afdbec83bd10d2feeaf475014a2d2efa855a16491aa7b922d8c1cbf58.js":{"logical_path":"application.js","mtime":"2016-12-17T22:42:28+01:00","size":2158066,"digest":"97155f8afdbec83bd10d2feeaf475014a2d2efa855a16491aa7b922d8c1cbf58","integrity":"sha256-lxVfiv2+yDvRDS/ur0dQFKLS76hVoWSRqnuSLYwcv1g="},"tinymce-7243549c535fe401a7b69bb597a277ca520491fe82e3f6efb6b800f605ef56fa.js":{"logical_path":"tinymce.js","mtime":"2016-12-17T22:48:39+01:00","size":971,"digest":"7243549c535fe401a7b69bb597a277ca520491fe82e3f6efb6b800f605ef56fa","integrity":"sha256-ckNUnFNf5AGntpu1l6J3ylIEkf6C4/bvtrgA9gXvVvo="},"application-1ea0f88318a587e6ca20994d21c9db4627195434bcc8a52f59e75be21b50f937.css":{"logical_path":"application.css","mtime":"2016-12-17T22:48:39+01:00","size":170862,"digest":"1ea0f88318a587e6ca20994d21c9db4627195434bcc8a52f59e75be21b50f937","integrity":"sha256-HqD4gxilh+bKIJlNIcnbRicZVDS8yKUvWedb4htQ+Tc="},"application-ec97ffd43bcc565dc5aabd8a6e1c3c75b2437f6b27265f56c2fa98eb72866bcd.js":{"logical_path":"application.js","mtime":"2016-12-17T22:48:39+01:00","size":2158066,"digest":"ec97ffd43bcc565dc5aabd8a6e1c3c75b2437f6b27265f56c2fa98eb72866bcd","integrity":"sha256-7Jf/1DvMVl3Fqr2Kbhw8dbJDf2snJl9WwvqY63KGa80="},"layers-2x-066daca850d8ffbef007af00b06eac0015728dee279c51f3cb6c716df7c42edf.png":{"logical_path":"layers-2x.png","mtime":"2017-04-24T19:17:55+02:00","size":1259,"digest":"066daca850d8ffbef007af00b06eac0015728dee279c51f3cb6c716df7c42edf","integrity":"sha256-Bm2sqFDY/77wB68AsG6sABVyje4nnFHzy2xxbffELt8="},"layers-1dbbe9d028e292f36fcba8f8b3a28d5e8932754fc2215b9ac69e4cdecf5107c6.png":{"logical_path":"layers.png","mtime":"2017-04-24T19:17:55+02:00","size":696,"digest":"1dbbe9d028e292f36fcba8f8b3a28d5e8932754fc2215b9ac69e4cdecf5107c6","integrity":"sha256-Hbvp0CjikvNvy6j4s6KNXokydU/CIVuaxp5M3s9RB8Y="},"marker-icon-2x-2d77a2e4c2f08bbac41808324ef946b9a2fe61b6150480d011b72b379c3b238d.png":{"logical_path":"marker-icon-2x.png","mtime":"2017-04-24T19:17:55+02:00","size":2586,"digest":"2d77a2e4c2f08bbac41808324ef946b9a2fe61b6150480d011b72b379c3b238d","integrity":"sha256-LXei5MLwi7rEGAgyTvlGuaL+YbYVBIDQEbcrN5w7I40="},"marker-icon-574c3a5cca85f4114085b6841596d62f00d7c892c7b03f28cbfa301deb1dc437.png":{"logical_path":"marker-icon.png","mtime":"2017-04-24T19:17:55+02:00","size":1466,"digest":"574c3a5cca85f4114085b6841596d62f00d7c892c7b03f28cbfa301deb1dc437","integrity":"sha256-V0w6XMqF9BFAhbaEFZbWLwDXyJLHsD8oy/owHesdxDc="},"marker-shadow-264f5c640339f042dd729062cfc04c17f8ea0f29882b538e3848ed8f10edb4da.png":{"logical_path":"marker-shadow.png","mtime":"2017-04-24T19:17:55+02:00","size":618,"digest":"264f5c640339f042dd729062cfc04c17f8ea0f29882b538e3848ed8f10edb4da","integrity":"sha256-Jk9cZAM58ELdcpBiz8BMF/jqDymIK1OOOEjtjxDttNo="},"tinymce-61f3d9ea006866183d7b56bbc9ecf39545adcc8a1a3b58566ea14ea52db8b902.js":{"logical_path":"tinymce.js","mtime":"2017-01-19T14:51:27+01:00","size":971,"digest":"61f3d9ea006866183d7b56bbc9ecf39545adcc8a1a3b58566ea14ea52db8b902","integrity":"sha256-YfPZ6gBoZhg9e1a7yezzlUWtzIoaO1hWbqFOpS24uQI="},"application-bd35f325ad91254feab551b82972c18f9d928b5016ff20ee040c3380f9c95a7c.css":{"logical_path":"application.css","mtime":"2017-01-19T14:51:27+01:00","size":173942,"digest":"bd35f325ad91254feab551b82972c18f9d928b5016ff20ee040c3380f9c95a7c","integrity":"sha256-vTXzJa2RJU/qtVG4KXLBj52Si1AW/yDuBAwzgPnJWnw="},"leaflet/dist/images/layers-1dbbe9d028e292f36fcba8f8b3a28d5e8932754fc2215b9ac69e4cdecf5107c6.png":{"logical_path":"leaflet/dist/images/layers.png","mtime":"2017-04-24T19:16:54+02:00","size":696,"digest":"1dbbe9d028e292f36fcba8f8b3a28d5e8932754fc2215b9ac69e4cdecf5107c6","integrity":"sha256-Hbvp0CjikvNvy6j4s6KNXokydU/CIVuaxp5M3s9RB8Y="},"leaflet/dist/images/layers-2x-066daca850d8ffbef007af00b06eac0015728dee279c51f3cb6c716df7c42edf.png":{"logical_path":"leaflet/dist/images/layers-2x.png","mtime":"2017-04-24T19:16:54+02:00","size":1259,"digest":"066daca850d8ffbef007af00b06eac0015728dee279c51f3cb6c716df7c42edf","integrity":"sha256-Bm2sqFDY/77wB68AsG6sABVyje4nnFHzy2xxbffELt8="},"leaflet/dist/images/marker-icon-574c3a5cca85f4114085b6841596d62f00d7c892c7b03f28cbfa301deb1dc437.png":{"logical_path":"leaflet/dist/images/marker-icon.png","mtime":"2017-04-24T19:16:54+02:00","size":1466,"digest":"574c3a5cca85f4114085b6841596d62f00d7c892c7b03f28cbfa301deb1dc437","integrity":"sha256-V0w6XMqF9BFAhbaEFZbWLwDXyJLHsD8oy/owHesdxDc="},"application-e76d31e280284497ba66d10672ca0b022ab11b512f1ed51be1b4db85d47330eb.js":{"logical_path":"application.js","mtime":"2017-01-02T09:58:37+01:00","size":2358436,"digest":"e76d31e280284497ba66d10672ca0b022ab11b512f1ed51be1b4db85d47330eb","integrity":"sha256-520x4oAoRJe6ZtEGcsoLAiqxG1EvHtUb4bTbhdRzMOs="},"leaflet/dist/images/marker-icon-2x-2d77a2e4c2f08bbac41808324ef946b9a2fe61b6150480d011b72b379c3b238d.png":{"logical_path":"leaflet/dist/images/marker-icon-2x.png","mtime":"2017-04-24T19:16:54+02:00","size":2586,"digest":"2d77a2e4c2f08bbac41808324ef946b9a2fe61b6150480d011b72b379c3b238d","integrity":"sha256-LXei5MLwi7rEGAgyTvlGuaL+YbYVBIDQEbcrN5w7I40="},"leaflet/dist/images/marker-shadow-264f5c640339f042dd729062cfc04c17f8ea0f29882b538e3848ed8f10edb4da.png":{"logical_path":"leaflet/dist/images/marker-shadow.png","mtime":"2017-04-24T19:16:54+02:00","size":618,"digest":"264f5c640339f042dd729062cfc04c17f8ea0f29882b538e3848ed8f10edb4da","integrity":"sha256-Jk9cZAM58ELdcpBiz8BMF/jqDymIK1OOOEjtjxDttNo="},"tinymce/plugins/emoticons/img/smiley-cool.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-cool.gif","mtime":"2016-12-10T10:15:36+01:00","size":354,"digest":null},"tinymce/plugins/emoticons/img/smiley-cry.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-cry.gif","mtime":"2016-12-10T10:15:36+01:00","size":329,"digest":null},"tinymce/plugins/emoticons/img/smiley-embarassed.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-embarassed.gif","mtime":"2016-12-10T10:15:36+01:00","size":331,"digest":null},"tinymce/plugins/emoticons/img/smiley-foot-in-mouth.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-foot-in-mouth.gif","mtime":"2016-12-10T10:15:36+01:00","size":342,"digest":null},"tinymce/plugins/emoticons/img/smiley-frown.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-frown.gif","mtime":"2016-12-10T10:15:36+01:00","size":340,"digest":null},"tinymce/plugins/emoticons/img/smiley-innocent.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-innocent.gif","mtime":"2016-12-10T10:15:36+01:00","size":336,"digest":null},"tinymce/plugins/emoticons/img/smiley-kiss.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-kiss.gif","mtime":"2016-12-10T10:15:36+01:00","size":338,"digest":null},"tinymce/plugins/emoticons/img/smiley-laughing.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-laughing.gif","mtime":"2016-12-10T10:15:36+01:00","size":343,"digest":null},"tinymce/plugins/emoticons/img/smiley-money-mouth.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-money-mouth.gif","mtime":"2016-12-10T10:15:36+01:00","size":321,"digest":null},"tinymce/plugins/emoticons/img/smiley-sealed.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-sealed.gif","mtime":"2016-12-10T10:15:36+01:00","size":323,"digest":null},"tinymce/plugins/emoticons/img/smiley-smile.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-smile.gif","mtime":"2016-12-10T10:15:36+01:00","size":344,"digest":null},"tinymce/plugins/emoticons/img/smiley-surprised.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-surprised.gif","mtime":"2016-12-10T10:15:36+01:00","size":338,"digest":null},"tinymce/plugins/emoticons/img/smiley-tongue-out.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-tongue-out.gif","mtime":"2016-12-10T10:15:36+01:00","size":328,"digest":null},"tinymce/plugins/emoticons/img/smiley-undecided.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-undecided.gif","mtime":"2016-12-10T10:15:36+01:00","size":337,"digest":null},"tinymce/plugins/emoticons/img/smiley-wink.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-wink.gif","mtime":"2016-12-10T10:15:36+01:00","size":350,"digest":null},"tinymce/plugins/emoticons/img/smiley-yell.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-yell.gif","mtime":"2016-12-10T10:15:36+01:00","size":336,"digest":null},"tinymce/skins/lightgray/img/anchor.gif":{"logical_path":"tinymce/skins/lightgray/img/anchor.gif","mtime":"2016-12-10T10:15:36+01:00","size":53,"digest":null},"tinymce/skins/lightgray/img/loader.gif":{"logical_path":"tinymce/skins/lightgray/img/loader.gif","mtime":"2016-12-10T10:15:36+01:00","size":2608,"digest":null},"tinymce/skins/lightgray/img/object.gif":{"logical_path":"tinymce/skins/lightgray/img/object.gif","mtime":"2016-12-10T10:15:36+01:00","size":152,"digest":null},"tinymce/skins/lightgray/img/trans.gif":{"logical_path":"tinymce/skins/lightgray/img/trans.gif","mtime":"2016-12-10T10:15:36+01:00","size":43,"digest":null},"tinymce/jquery.tinymce.js":{"logical_path":"tinymce/jquery.tinymce.js","mtime":"2016-12-10T10:15:36+01:00","size":3591,"digest":null},"tinymce/langs/readme.md":{"logical_path":"tinymce/langs/readme.md","mtime":"2016-12-10T10:15:36+01:00","size":151,"digest":null},"tinymce/license.txt":{"logical_path":"tinymce/license.txt","mtime":"2016-12-10T10:15:36+01:00","size":26427,"digest":null},"tinymce/plugins/advlist/plugin.js":{"logical_path":"tinymce/plugins/advlist/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":2048,"digest":null},"tinymce/plugins/anchor/plugin.js":{"logical_path":"tinymce/plugins/anchor/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":957,"digest":null},"tinymce/plugins/autolink/plugin.js":{"logical_path":"tinymce/plugins/autolink/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":2060,"digest":null},"tinymce/plugins/autoresize/plugin.js":{"logical_path":"tinymce/plugins/autoresize/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1903,"digest":null},"tinymce/plugins/autosave/plugin.js":{"logical_path":"tinymce/plugins/autosave/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":2187,"digest":null},"tinymce/plugins/bbcode/plugin.js":{"logical_path":"tinymce/plugins/bbcode/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":3136,"digest":null},"tinymce/plugins/charmap/plugin.js":{"logical_path":"tinymce/plugins/charmap/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":8199,"digest":null},"tinymce/plugins/code/plugin.js":{"logical_path":"tinymce/plugins/code/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":721,"digest":null},"tinymce/plugins/codesample/css/prism.css":{"logical_path":"tinymce/plugins/codesample/css/prism.css","mtime":"2016-12-10T10:15:36+01:00","size":2289,"digest":null},"tinymce/plugins/codesample/plugin.dev.js":{"logical_path":"tinymce/plugins/codesample/plugin.dev.js","mtime":"2016-12-10T10:15:36+01:00","size":3168,"digest":null},"tinymce/plugins/codesample/plugin.js":{"logical_path":"tinymce/plugins/codesample/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":20264,"digest":null},"tinymce/plugins/colorpicker/plugin.js":{"logical_path":"tinymce/plugins/colorpicker/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1222,"digest":null},"tinymce/plugins/contextmenu/plugin.js":{"logical_path":"tinymce/plugins/contextmenu/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1131,"digest":null},"tinymce/plugins/directionality/plugin.js":{"logical_path":"tinymce/plugins/directionality/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":726,"digest":null},"tinymce/plugins/emoticons/plugin.js":{"logical_path":"tinymce/plugins/emoticons/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":911,"digest":null},"tinymce/plugins/example/dialog.html":{"logical_path":"tinymce/plugins/example/dialog.html","mtime":"2016-12-10T10:15:36+01:00","size":213,"digest":null},"tinymce/plugins/example/plugin.js":{"logical_path":"tinymce/plugins/example/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":658,"digest":null},"tinymce/plugins/example_dependency/plugin.js":{"logical_path":"tinymce/plugins/example_dependency/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":73,"digest":null},"tinymce/plugins/fullpage/plugin.js":{"logical_path":"tinymce/plugins/fullpage/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":6308,"digest":null},"tinymce/plugins/fullscreen/plugin.js":{"logical_path":"tinymce/plugins/fullscreen/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1675,"digest":null},"tinymce/plugins/hr/plugin.js":{"logical_path":"tinymce/plugins/hr/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":322,"digest":null},"tinymce/plugins/image/plugin.js":{"logical_path":"tinymce/plugins/image/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":8195,"digest":null},"tinymce/plugins/imagetools/plugin.js":{"logical_path":"tinymce/plugins/imagetools/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":30900,"digest":null},"tinymce/plugins/importcss/plugin.js":{"logical_path":"tinymce/plugins/importcss/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":2746,"digest":null},"tinymce/plugins/insertdatetime/plugin.js":{"logical_path":"tinymce/plugins/insertdatetime/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1971,"digest":null},"tinymce/plugins/layer/plugin.js":{"logical_path":"tinymce/plugins/layer/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":2857,"digest":null},"tinymce/plugins/legacyoutput/plugin.js":{"logical_path":"tinymce/plugins/legacyoutput/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":3263,"digest":null},"tinymce/plugins/link/plugin.js":{"logical_path":"tinymce/plugins/link/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":6903,"digest":null},"tinymce/plugins/lists/plugin.js":{"logical_path":"tinymce/plugins/lists/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":10331,"digest":null},"tinymce/plugins/media/plugin.js":{"logical_path":"tinymce/plugins/media/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":14999,"digest":null},"tinymce/plugins/nonbreaking/plugin.js":{"logical_path":"tinymce/plugins/nonbreaking/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":655,"digest":null},"tinymce/plugins/noneditable/plugin.js":{"logical_path":"tinymce/plugins/noneditable/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1270,"digest":null},"tinymce/plugins/pagebreak/plugin.js":{"logical_path":"tinymce/plugins/pagebreak/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1230,"digest":null},"tinymce/plugins/paste/plugin.dev.js":{"logical_path":"tinymce/plugins/paste/plugin.dev.js","mtime":"2016-12-10T10:15:36+01:00","size":3130,"digest":null},"tinymce/plugins/paste/plugin.js":{"logical_path":"tinymce/plugins/paste/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":17676,"digest":null},"tinymce/plugins/preview/plugin.js":{"logical_path":"tinymce/plugins/preview/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1602,"digest":null},"tinymce/plugins/print/plugin.js":{"logical_path":"tinymce/plugins/print/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":293,"digest":null},"tinymce/plugins/save/plugin.js":{"logical_path":"tinymce/plugins/save/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1150,"digest":null},"tinymce/plugins/searchreplace/plugin.js":{"logical_path":"tinymce/plugins/searchreplace/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":6493,"digest":null},"tinymce/plugins/spellchecker/plugin.dev.js":{"logical_path":"tinymce/plugins/spellchecker/plugin.dev.js","mtime":"2016-12-10T10:15:36+01:00","size":3032,"digest":null},"tinymce/plugins/spellchecker/plugin.js":{"logical_path":"tinymce/plugins/spellchecker/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":10044,"digest":null},"tinymce/plugins/tabfocus/plugin.js":{"logical_path":"tinymce/plugins/tabfocus/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1264,"digest":null},"tinymce/plugins/table/plugin.dev.js":{"logical_path":"tinymce/plugins/table/plugin.dev.js","mtime":"2016-12-10T10:15:36+01:00","size":3152,"digest":null},"tinymce/plugins/table/plugin.js":{"logical_path":"tinymce/plugins/table/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":45825,"digest":null},"tinymce/plugins/template/plugin.js":{"logical_path":"tinymce/plugins/template/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":4520,"digest":null},"tinymce/plugins/textcolor/plugin.js":{"logical_path":"tinymce/plugins/textcolor/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":4145,"digest":null},"tinymce/plugins/textpattern/plugin.js":{"logical_path":"tinymce/plugins/textpattern/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":2745,"digest":null},"tinymce/plugins/toc/plugin.js":{"logical_path":"tinymce/plugins/toc/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":2771,"digest":null},"tinymce/plugins/visualblocks/css/visualblocks.css":{"logical_path":"tinymce/plugins/visualblocks/css/visualblocks.css","mtime":"2016-12-10T10:15:36+01:00","size":5092,"digest":null},"tinymce/plugins/visualblocks/plugin.js":{"logical_path":"tinymce/plugins/visualblocks/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1153,"digest":null},"tinymce/plugins/visualchars/plugin.js":{"logical_path":"tinymce/plugins/visualchars/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1178,"digest":null},"tinymce/plugins/wordcount/plugin.js":{"logical_path":"tinymce/plugins/wordcount/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":11674,"digest":null},"tinymce/skins/lightgray/AbsoluteLayout.less":{"logical_path":"tinymce/skins/lightgray/AbsoluteLayout.less","mtime":"2016-12-10T10:15:36+01:00","size":265,"digest":null},"tinymce/skins/lightgray/Animations.less":{"logical_path":"tinymce/skins/lightgray/Animations.less","mtime":"2016-12-10T10:15:36+01:00","size":119,"digest":null},"tinymce/skins/lightgray/Arrows.less":{"logical_path":"tinymce/skins/lightgray/Arrows.less","mtime":"2016-12-10T10:15:36+01:00","size":2437,"digest":null},"tinymce/skins/lightgray/Button.less":{"logical_path":"tinymce/skins/lightgray/Button.less","mtime":"2016-12-10T10:15:36+01:00","size":3853,"digest":null},"tinymce/skins/lightgray/ButtonGroup.less":{"logical_path":"tinymce/skins/lightgray/ButtonGroup.less","mtime":"2016-12-10T10:15:36+01:00","size":1681,"digest":null},"tinymce/skins/lightgray/Checkbox.less":{"logical_path":"tinymce/skins/lightgray/Checkbox.less","mtime":"2016-12-10T10:15:36+01:00","size":1096,"digest":null},"tinymce/skins/lightgray/ColorBox.less":{"logical_path":"tinymce/skins/lightgray/ColorBox.less","mtime":"2016-12-10T10:15:36+01:00","size":103,"digest":null},"tinymce/skins/lightgray/ColorButton.less":{"logical_path":"tinymce/skins/lightgray/ColorButton.less","mtime":"2016-12-10T10:15:36+01:00","size":1301,"digest":null},"tinymce/skins/lightgray/ColorPicker.less":{"logical_path":"tinymce/skins/lightgray/ColorPicker.less","mtime":"2016-12-10T10:15:36+01:00","size":1864,"digest":null},"tinymce/skins/lightgray/ComboBox.less":{"logical_path":"tinymce/skins/lightgray/ComboBox.less","mtime":"2016-12-10T10:15:36+01:00","size":1729,"digest":null},"tinymce/skins/lightgray/Container.less":{"logical_path":"tinymce/skins/lightgray/Container.less","mtime":"2016-12-10T10:15:36+01:00","size":129,"digest":null},"tinymce/skins/lightgray/Content.Inline.less":{"logical_path":"tinymce/skins/lightgray/Content.Inline.less","mtime":"2016-12-10T10:15:36+01:00","size":82,"digest":null},"tinymce/skins/lightgray/Content.Objects.less":{"logical_path":"tinymce/skins/lightgray/Content.Objects.less","mtime":"2016-12-10T10:15:36+01:00","size":3210,"digest":null},"tinymce/skins/lightgray/Content.less":{"logical_path":"tinymce/skins/lightgray/Content.less","mtime":"2016-12-10T10:15:36+01:00","size":592,"digest":null},"tinymce/skins/lightgray/CropRect.less":{"logical_path":"tinymce/skins/lightgray/CropRect.less","mtime":"2016-12-10T10:15:36+01:00","size":1108,"digest":null},"tinymce/skins/lightgray/FieldSet.less":{"logical_path":"tinymce/skins/lightgray/FieldSet.less","mtime":"2016-12-10T10:15:36+01:00","size":233,"digest":null},"tinymce/skins/lightgray/FitLayout.less":{"logical_path":"tinymce/skins/lightgray/FitLayout.less","mtime":"2016-12-10T10:15:36+01:00","size":111,"digest":null},"tinymce/skins/lightgray/FloatPanel.less":{"logical_path":"tinymce/skins/lightgray/FloatPanel.less","mtime":"2016-12-10T10:15:36+01:00","size":1477,"digest":null},"tinymce/skins/lightgray/FlowLayout.less":{"logical_path":"tinymce/skins/lightgray/FlowLayout.less","mtime":"2016-12-10T10:15:36+01:00","size":694,"digest":null},"tinymce/skins/lightgray/Icons.Ie7.less":{"logical_path":"tinymce/skins/lightgray/Icons.Ie7.less","mtime":"2016-12-10T10:15:36+01:00","size":5621,"digest":null},"tinymce/skins/lightgray/Icons.less":{"logical_path":"tinymce/skins/lightgray/Icons.less","mtime":"2016-12-10T10:15:36+01:00","size":9372,"digest":null},"tinymce/skins/lightgray/Iframe.less":{"logical_path":"tinymce/skins/lightgray/Iframe.less","mtime":"2016-12-10T10:15:36+01:00","size":94,"digest":null},"tinymce/skins/lightgray/ImagePanel.less":{"logical_path":"tinymce/skins/lightgray/ImagePanel.less","mtime":"2016-12-10T10:15:36+01:00","size":476,"digest":null},"tinymce/skins/lightgray/InfoBox.less":{"logical_path":"tinymce/skins/lightgray/InfoBox.less","mtime":"2016-12-10T10:15:36+01:00","size":1087,"digest":null},"tinymce/skins/lightgray/Label.less":{"logical_path":"tinymce/skins/lightgray/Label.less","mtime":"2016-12-10T10:15:36+01:00","size":554,"digest":null},"tinymce/skins/lightgray/ListBox.less":{"logical_path":"tinymce/skins/lightgray/ListBox.less","mtime":"2016-12-10T10:15:36+01:00","size":388,"digest":null},"tinymce/skins/lightgray/Menu.less":{"logical_path":"tinymce/skins/lightgray/Menu.less","mtime":"2016-12-10T10:15:36+01:00","size":821,"digest":null},"tinymce/skins/lightgray/MenuBar.less":{"logical_path":"tinymce/skins/lightgray/MenuBar.less","mtime":"2016-12-10T10:15:36+01:00","size":689,"digest":null},"tinymce/skins/lightgray/MenuButton.less":{"logical_path":"tinymce/skins/lightgray/MenuButton.less","mtime":"2016-12-10T10:15:36+01:00","size":607,"digest":null},"tinymce/skins/lightgray/MenuItem.less":{"logical_path":"tinymce/skins/lightgray/MenuItem.less","mtime":"2016-12-10T10:15:36+01:00","size":4782,"digest":null},"tinymce/skins/lightgray/Mixins.less":{"logical_path":"tinymce/skins/lightgray/Mixins.less","mtime":"2016-12-10T10:15:36+01:00","size":1799,"digest":null},"tinymce/skins/lightgray/Notification.less":{"logical_path":"tinymce/skins/lightgray/Notification.less","mtime":"2016-12-10T10:15:36+01:00","size":3628,"digest":null},"tinymce/skins/lightgray/Panel.less":{"logical_path":"tinymce/skins/lightgray/Panel.less","mtime":"2016-12-10T10:15:36+01:00","size":220,"digest":null},"tinymce/skins/lightgray/Path.less":{"logical_path":"tinymce/skins/lightgray/Path.less","mtime":"2016-12-10T10:15:36+01:00","size":650,"digest":null},"tinymce/skins/lightgray/Progress.less":{"logical_path":"tinymce/skins/lightgray/Progress.less","mtime":"2016-12-10T10:15:36+01:00","size":619,"digest":null},"tinymce/skins/lightgray/Radio.less":{"logical_path":"tinymce/skins/lightgray/Radio.less","mtime":"2016-12-10T10:15:36+01:00","size":31,"digest":null},"tinymce/skins/lightgray/Reset.less":{"logical_path":"tinymce/skins/lightgray/Reset.less","mtime":"2016-12-10T10:15:36+01:00","size":905,"digest":null},"tinymce/skins/lightgray/ResizeHandle.less":{"logical_path":"tinymce/skins/lightgray/ResizeHandle.less","mtime":"2016-12-10T10:15:36+01:00","size":301,"digest":null},"tinymce/skins/lightgray/Scrollable.less":{"logical_path":"tinymce/skins/lightgray/Scrollable.less","mtime":"2016-12-10T10:15:36+01:00","size":687,"digest":null},"tinymce/skins/lightgray/SelectBox.less":{"logical_path":"tinymce/skins/lightgray/SelectBox.less","mtime":"2016-12-10T10:15:36+01:00","size":105,"digest":null},"tinymce/skins/lightgray/Sidebar.less":{"logical_path":"tinymce/skins/lightgray/Sidebar.less","mtime":"2016-12-10T10:15:36+01:00","size":956,"digest":null},"tinymce/skins/lightgray/Slider.less":{"logical_path":"tinymce/skins/lightgray/Slider.less","mtime":"2016-12-10T10:15:36+01:00","size":579,"digest":null},"tinymce/skins/lightgray/Spacer.less":{"logical_path":"tinymce/skins/lightgray/Spacer.less","mtime":"2016-12-10T10:15:36+01:00","size":54,"digest":null},"tinymce/skins/lightgray/SplitButton.less":{"logical_path":"tinymce/skins/lightgray/SplitButton.less","mtime":"2016-12-10T10:15:36+01:00","size":980,"digest":null},"tinymce/skins/lightgray/StackLayout.less":{"logical_path":"tinymce/skins/lightgray/StackLayout.less","mtime":"2016-12-10T10:15:36+01:00","size":67,"digest":null},"tinymce/skins/lightgray/TabPanel.less":{"logical_path":"tinymce/skins/lightgray/TabPanel.less","mtime":"2016-12-10T10:15:36+01:00","size":706,"digest":null},"tinymce/skins/lightgray/TextBox.less":{"logical_path":"tinymce/skins/lightgray/TextBox.less","mtime":"2016-12-10T10:15:36+01:00","size":870,"digest":null},"tinymce/skins/lightgray/Throbber.less":{"logical_path":"tinymce/skins/lightgray/Throbber.less","mtime":"2016-12-10T10:15:36+01:00","size":303,"digest":null},"tinymce/skins/lightgray/TinyMCE.less":{"logical_path":"tinymce/skins/lightgray/TinyMCE.less","mtime":"2016-12-10T10:15:36+01:00","size":2449,"digest":null},"tinymce/skins/lightgray/ToolTip.less":{"logical_path":"tinymce/skins/lightgray/ToolTip.less","mtime":"2016-12-10T10:15:36+01:00","size":2533,"digest":null},"tinymce/skins/lightgray/Variables.less":{"logical_path":"tinymce/skins/lightgray/Variables.less","mtime":"2016-12-10T10:15:36+01:00","size":8371,"digest":null},"tinymce/skins/lightgray/Window.less":{"logical_path":"tinymce/skins/lightgray/Window.less","mtime":"2016-12-10T10:15:36+01:00","size":2217,"digest":null},"tinymce/skins/lightgray/content.inline.min.css":{"logical_path":"tinymce/skins/lightgray/content.inline.min.css","mtime":"2016-12-10T10:15:36+01:00","size":2769,"digest":null},"tinymce/skins/lightgray/content.min.css":{"logical_path":"tinymce/skins/lightgray/content.min.css","mtime":"2016-12-10T10:15:36+01:00","size":3193,"digest":null},"tinymce/skins/lightgray/fonts/tinymce-small.eot":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce-small.eot","mtime":"2016-12-10T10:15:36+01:00","size":9492,"digest":null},"tinymce/skins/lightgray/fonts/tinymce-small.svg":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce-small.svg","mtime":"2016-12-10T10:15:36+01:00","size":24727,"digest":null},"tinymce/skins/lightgray/fonts/tinymce-small.ttf":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce-small.ttf","mtime":"2016-12-10T10:15:36+01:00","size":9304,"digest":null},"tinymce/skins/lightgray/fonts/tinymce-small.woff":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce-small.woff","mtime":"2016-12-10T10:15:36+01:00","size":9380,"digest":null},"tinymce/skins/lightgray/fonts/tinymce.eot":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce.eot","mtime":"2016-12-10T10:15:36+01:00","size":17572,"digest":null},"tinymce/skins/lightgray/fonts/tinymce.svg":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce.svg","mtime":"2016-12-10T10:15:36+01:00","size":45991,"digest":null},"tinymce/skins/lightgray/fonts/tinymce.ttf":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce.ttf","mtime":"2016-12-10T10:15:36+01:00","size":17408,"digest":null},"tinymce/skins/lightgray/fonts/tinymce.woff":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce.woff","mtime":"2016-12-10T10:15:36+01:00","size":17484,"digest":null},"tinymce/skins/lightgray/skin.dev.less":{"logical_path":"tinymce/skins/lightgray/skin.dev.less","mtime":"2016-12-10T10:15:36+01:00","size":1201,"digest":null},"tinymce/skins/lightgray/skin.ie7.dev.less":{"logical_path":"tinymce/skins/lightgray/skin.ie7.dev.less","mtime":"2016-12-10T10:15:36+01:00","size":1181,"digest":null},"tinymce/skins/lightgray/skin.ie7.less":{"logical_path":"tinymce/skins/lightgray/skin.ie7.less","mtime":"2016-12-10T10:15:36+01:00","size":61487,"digest":null},"tinymce/skins/lightgray/skin.ie7.min.css":{"logical_path":"tinymce/skins/lightgray/skin.ie7.min.css","mtime":"2016-12-10T10:15:36+01:00","size":34904,"digest":null},"tinymce/skins/lightgray/skin.less":{"logical_path":"tinymce/skins/lightgray/skin.less","mtime":"2016-12-10T10:15:36+01:00","size":66196,"digest":null},"tinymce/skins/lightgray/skin.min.css":{"logical_path":"tinymce/skins/lightgray/skin.min.css","mtime":"2016-12-10T10:15:36+01:00","size":38232,"digest":null},"tinymce/themes/inlite/theme.js":{"logical_path":"tinymce/themes/inlite/theme.js","mtime":"2016-12-10T10:15:36+01:00","size":16364,"digest":null},"tinymce/themes/modern/theme.js":{"logical_path":"tinymce/themes/modern/theme.js","mtime":"2016-12-10T10:15:36+01:00","size":13146,"digest":null},"tinymce/tinymce.js":{"logical_path":"tinymce/tinymce.js","mtime":"2016-12-10T10:15:36+01:00","size":401179,"digest":null},"tinymce/langs/ar.js":{"logical_path":"tinymce/langs/ar.js","mtime":"2016-10-29T16:47:26+02:00","size":17775,"digest":null},"tinymce/langs/ar_SA.js":{"logical_path":"tinymce/langs/ar_SA.js","mtime":"2016-10-29T16:47:26+02:00","size":10002,"digest":null},"tinymce/langs/az.js":{"logical_path":"tinymce/langs/az.js","mtime":"2016-10-29T16:47:26+02:00","size":9679,"digest":null},"tinymce/langs/be.js":{"logical_path":"tinymce/langs/be.js","mtime":"2016-10-29T16:47:26+02:00","size":21063,"digest":null},"tinymce/langs/bg_BG.js":{"logical_path":"tinymce/langs/bg_BG.js","mtime":"2016-10-29T16:47:26+02:00","size":23944,"digest":null},"tinymce/langs/bn_BD.js":{"logical_path":"tinymce/langs/bn_BD.js","mtime":"2016-10-29T16:47:26+02:00","size":6845,"digest":null},"tinymce/langs/bs.js":{"logical_path":"tinymce/langs/bs.js","mtime":"2016-10-29T16:47:26+02:00","size":6969,"digest":null},"tinymce/langs/ca.js":{"logical_path":"tinymce/langs/ca.js","mtime":"2016-10-29T16:47:26+02:00","size":7786,"digest":null},"tinymce/langs/cs.js":{"logical_path":"tinymce/langs/cs.js","mtime":"2016-10-29T16:47:26+02:00","size":8750,"digest":null},"tinymce/langs/cs_CZ.js":{"logical_path":"tinymce/langs/cs_CZ.js","mtime":"2016-10-29T16:47:26+02:00","size":8398,"digest":null},"tinymce/langs/cy.js":{"logical_path":"tinymce/langs/cy.js","mtime":"2016-10-29T16:47:26+02:00","size":6141,"digest":null},"tinymce/langs/da.js":{"logical_path":"tinymce/langs/da.js","mtime":"2016-10-29T16:47:26+02:00","size":7512,"digest":null},"tinymce/langs/de.js":{"logical_path":"tinymce/langs/de.js","mtime":"2016-10-29T16:47:26+02:00","size":8279,"digest":null},"tinymce/langs/de_AT.js":{"logical_path":"tinymce/langs/de_AT.js","mtime":"2016-10-29T16:47:26+02:00","size":8307,"digest":null},"tinymce/langs/dv.js":{"logical_path":"tinymce/langs/dv.js","mtime":"2016-10-29T16:47:26+02:00","size":18099,"digest":null},"tinymce/langs/el.js":{"logical_path":"tinymce/langs/el.js","mtime":"2016-10-29T16:47:26+02:00","size":22972,"digest":null},"tinymce/langs/en_CA.js":{"logical_path":"tinymce/langs/en_CA.js","mtime":"2016-10-29T16:47:26+02:00","size":6915,"digest":null},"tinymce/langs/en_GB.js":{"logical_path":"tinymce/langs/en_GB.js","mtime":"2016-10-29T16:47:26+02:00","size":5906,"digest":null},"tinymce/langs/eo.js":{"logical_path":"tinymce/langs/eo.js","mtime":"2016-10-29T16:47:26+02:00","size":7465,"digest":null},"tinymce/langs/es.js":{"logical_path":"tinymce/langs/es.js","mtime":"2016-10-29T16:47:26+02:00","size":7808,"digest":null},"tinymce/langs/es_MX.js":{"logical_path":"tinymce/langs/es_MX.js","mtime":"2016-10-29T16:47:26+02:00","size":7893,"digest":null},"tinymce/langs/et.js":{"logical_path":"tinymce/langs/et.js","mtime":"2016-10-29T16:47:26+02:00","size":7783,"digest":null},"tinymce/langs/eu.js":{"logical_path":"tinymce/langs/eu.js","mtime":"2016-10-29T16:47:26+02:00","size":7010,"digest":null},"tinymce/langs/fa.js":{"logical_path":"tinymce/langs/fa.js","mtime":"2016-10-29T16:47:26+02:00","size":16461,"digest":null},"tinymce/langs/fa_IR.js":{"logical_path":"tinymce/langs/fa_IR.js","mtime":"2016-10-29T16:47:26+02:00","size":17724,"digest":null},"tinymce/langs/fi.js":{"logical_path":"tinymce/langs/fi.js","mtime":"2016-10-29T16:47:26+02:00","size":8142,"digest":null},"tinymce/langs/fo.js":{"logical_path":"tinymce/langs/fo.js","mtime":"2016-10-29T16:47:26+02:00","size":8043,"digest":null},"tinymce/langs/fr_CH.js":{"logical_path":"tinymce/langs/fr_CH.js","mtime":"2016-10-29T16:47:26+02:00","size":8073,"digest":null},"tinymce/langs/fr_FR.js":{"logical_path":"tinymce/langs/fr_FR.js","mtime":"2016-10-29T16:47:26+02:00","size":8008,"digest":null},"tinymce/langs/ga.js":{"logical_path":"tinymce/langs/ga.js","mtime":"2016-10-29T16:47:26+02:00","size":8590,"digest":null},"tinymce/langs/gd.js":{"logical_path":"tinymce/langs/gd.js","mtime":"2016-10-29T16:47:26+02:00","size":8807,"digest":null},"tinymce/langs/gl.js":{"logical_path":"tinymce/langs/gl.js","mtime":"2016-10-29T16:47:26+02:00","size":7065,"digest":null},"tinymce/langs/he_IL.js":{"logical_path":"tinymce/langs/he_IL.js","mtime":"2016-10-29T16:47:26+02:00","size":16080,"digest":null},"tinymce/langs/hi_IN.js":{"logical_path":"tinymce/langs/hi_IN.js","mtime":"2016-10-29T16:47:26+02:00","size":18457,"digest":null},"tinymce/langs/hr.js":{"logical_path":"tinymce/langs/hr.js","mtime":"2016-10-29T16:47:26+02:00","size":7576,"digest":null},"tinymce/langs/hu_HU.js":{"logical_path":"tinymce/langs/hu_HU.js","mtime":"2016-10-29T16:47:26+02:00","size":9409,"digest":null},"tinymce/langs/hy.js":{"logical_path":"tinymce/langs/hy.js","mtime":"2016-10-29T16:47:26+02:00","size":20374,"digest":null},"tinymce/langs/id.js":{"logical_path":"tinymce/langs/id.js","mtime":"2016-10-29T16:47:26+02:00","size":7140,"digest":null},"tinymce/langs/is_IS.js":{"logical_path":"tinymce/langs/is_IS.js","mtime":"2016-10-29T16:47:26+02:00","size":7927,"digest":null},"tinymce/langs/it.js":{"logical_path":"tinymce/langs/it.js","mtime":"2016-10-29T16:47:26+02:00","size":7597,"digest":null},"tinymce/langs/ja.js":{"logical_path":"tinymce/langs/ja.js","mtime":"2016-10-29T16:47:26+02:00","size":12289,"digest":null},"tinymce/langs/ka_GE.js":{"logical_path":"tinymce/langs/ka_GE.js","mtime":"2016-10-29T16:47:26+02:00","size":21283,"digest":null},"tinymce/langs/kab.js":{"logical_path":"tinymce/langs/kab.js","mtime":"2016-10-29T16:47:26+02:00","size":7390,"digest":null},"tinymce/langs/kk.js":{"logical_path":"tinymce/langs/kk.js","mtime":"2016-10-29T16:47:26+02:00","size":16680,"digest":null},"tinymce/langs/km_KH.js":{"logical_path":"tinymce/langs/km_KH.js","mtime":"2016-10-29T16:47:26+02:00","size":21395,"digest":null},"tinymce/langs/ko.js":{"logical_path":"tinymce/langs/ko.js","mtime":"2016-10-29T16:47:26+02:00","size":10104,"digest":null},"tinymce/langs/ko_KR.js":{"logical_path":"tinymce/langs/ko_KR.js","mtime":"2016-10-29T16:47:26+02:00","size":10004,"digest":null},"tinymce/langs/ku.js":{"logical_path":"tinymce/langs/ku.js","mtime":"2016-10-29T16:47:26+02:00","size":18273,"digest":null},"tinymce/langs/ku_IQ.js":{"logical_path":"tinymce/langs/ku_IQ.js","mtime":"2016-10-29T16:47:26+02:00","size":18363,"digest":null},"tinymce/langs/lb.js":{"logical_path":"tinymce/langs/lb.js","mtime":"2016-10-29T16:47:26+02:00","size":7466,"digest":null},"tinymce/langs/lt.js":{"logical_path":"tinymce/langs/lt.js","mtime":"2016-10-29T16:47:26+02:00","size":8898,"digest":null},"tinymce/langs/lv.js":{"logical_path":"tinymce/langs/lv.js","mtime":"2016-10-29T16:47:26+02:00","size":8281,"digest":null},"tinymce/langs/mk_MK.js":{"logical_path":"tinymce/langs/mk_MK.js","mtime":"2016-10-29T16:47:26+02:00","size":18732,"digest":null},"tinymce/langs/ml.js":{"logical_path":"tinymce/langs/ml.js","mtime":"2016-10-29T16:47:26+02:00","size":7338,"digest":null},"tinymce/langs/ml_IN.js":{"logical_path":"tinymce/langs/ml_IN.js","mtime":"2016-10-29T16:47:26+02:00","size":20018,"digest":null},"tinymce/langs/mn_MN.js":{"logical_path":"tinymce/langs/mn_MN.js","mtime":"2016-10-29T16:47:26+02:00","size":6876,"digest":null},"tinymce/langs/nb_NO.js":{"logical_path":"tinymce/langs/nb_NO.js","mtime":"2016-10-29T16:47:26+02:00","size":7527,"digest":null},"tinymce/langs/nl.js":{"logical_path":"tinymce/langs/nl.js","mtime":"2016-10-29T16:47:26+02:00","size":7234,"digest":null},"tinymce/langs/pl.js":{"logical_path":"tinymce/langs/pl.js","mtime":"2016-10-29T16:47:26+02:00","size":8128,"digest":null},"tinymce/langs/pt_BR.js":{"logical_path":"tinymce/langs/pt_BR.js","mtime":"2016-10-29T16:47:26+02:00","size":8001,"digest":null},"tinymce/langs/pt_PT.js":{"logical_path":"tinymce/langs/pt_PT.js","mtime":"2016-10-29T16:47:26+02:00","size":8144,"digest":null},"tinymce/langs/ro.js":{"logical_path":"tinymce/langs/ro.js","mtime":"2016-10-29T16:47:26+02:00","size":8274,"digest":null},"tinymce/langs/ru.js":{"logical_path":"tinymce/langs/ru.js","mtime":"2016-10-29T16:47:26+02:00","size":22289,"digest":null},"tinymce/langs/ru_RU.js":{"logical_path":"tinymce/langs/ru_RU.js","mtime":"2016-10-29T16:47:26+02:00","size":4954,"digest":null},"tinymce/langs/si_LK.js":{"logical_path":"tinymce/langs/si_LK.js","mtime":"2016-10-29T16:47:26+02:00","size":15855,"digest":null},"tinymce/langs/sk.js":{"logical_path":"tinymce/langs/sk.js","mtime":"2016-10-29T16:47:26+02:00","size":8957,"digest":null},"tinymce/langs/sl_SI.js":{"logical_path":"tinymce/langs/sl_SI.js","mtime":"2016-10-29T16:47:26+02:00","size":7038,"digest":null},"tinymce/langs/sr.js":{"logical_path":"tinymce/langs/sr.js","mtime":"2016-10-29T16:47:26+02:00","size":6335,"digest":null},"tinymce/langs/sv_SE.js":{"logical_path":"tinymce/langs/sv_SE.js","mtime":"2016-10-29T16:47:26+02:00","size":7495,"digest":null},"tinymce/langs/ta.js":{"logical_path":"tinymce/langs/ta.js","mtime":"2016-10-29T16:47:26+02:00","size":22616,"digest":null},"tinymce/langs/ta_IN.js":{"logical_path":"tinymce/langs/ta_IN.js","mtime":"2016-10-29T16:47:26+02:00","size":22619,"digest":null},"tinymce/langs/tg.js":{"logical_path":"tinymce/langs/tg.js","mtime":"2016-10-29T16:47:26+02:00","size":18182,"digest":null},"tinymce/langs/th_TH.js":{"logical_path":"tinymce/langs/th_TH.js","mtime":"2016-10-29T16:47:26+02:00","size":17296,"digest":null},"tinymce/langs/tr.js":{"logical_path":"tinymce/langs/tr.js","mtime":"2016-10-29T16:47:26+02:00","size":8704,"digest":null},"tinymce/langs/tr_TR.js":{"logical_path":"tinymce/langs/tr_TR.js","mtime":"2016-10-29T16:47:26+02:00","size":8140,"digest":null},"tinymce/langs/tt.js":{"logical_path":"tinymce/langs/tt.js","mtime":"2016-10-29T16:47:26+02:00","size":19034,"digest":null},"tinymce/langs/ug.js":{"logical_path":"tinymce/langs/ug.js","mtime":"2016-10-29T16:47:26+02:00","size":16887,"digest":null},"tinymce/langs/uk.js":{"logical_path":"tinymce/langs/uk.js","mtime":"2016-10-29T16:47:26+02:00","size":22263,"digest":null},"tinymce/langs/uk_UA.js":{"logical_path":"tinymce/langs/uk_UA.js","mtime":"2016-10-29T16:47:26+02:00","size":21690,"digest":null},"tinymce/langs/vi.js":{"logical_path":"tinymce/langs/vi.js","mtime":"2016-10-29T16:47:26+02:00","size":9900,"digest":null},"tinymce/langs/vi_VN.js":{"logical_path":"tinymce/langs/vi_VN.js","mtime":"2016-10-29T16:47:26+02:00","size":9898,"digest":null},"tinymce/langs/zh_CN.js":{"logical_path":"tinymce/langs/zh_CN.js","mtime":"2016-10-29T16:47:26+02:00","size":8482,"digest":null},"tinymce/langs/zh_TW.js":{"logical_path":"tinymce/langs/zh_TW.js","mtime":"2016-10-29T16:47:26+02:00","size":9378,"digest":null},"active_admin-5493c4a52f825b68a247f214b88addaf61bada07aefa1441589c72d8d81f8b12.css":{"logical_path":"active_admin.css","mtime":"2017-01-19T14:15:27+01:00","size":78899,"digest":"5493c4a52f825b68a247f214b88addaf61bada07aefa1441589c72d8d81f8b12","integrity":"sha256-VJPEpS+CW2iiR/IUuIrdr2G62geu+hRBWJxy2NgfixI="},"active_admin-9238692e361f8ed7317fd8414cfadeff93c57b9a6ed3fd35cfe9a3fe4ddc3829.js":{"logical_path":"active_admin.js","mtime":"2017-01-19T14:51:27+01:00","size":692387,"digest":"9238692e361f8ed7317fd8414cfadeff93c57b9a6ed3fd35cfe9a3fe4ddc3829","integrity":"sha256-kjhpLjYfjtcxf9hBTPre/5PFe5pu0/01z+mj/k3cOCk="},"lef-9fcdd7ddd4d40de29c3809b59688c668b85f5628e219d4cd8a8810b72a64533b.png":{"logical_path":"lef.png","mtime":"2017-01-07T19:07:36+01:00","size":8332,"digest":"9fcdd7ddd4d40de29c3809b59688c668b85f5628e219d4cd8a8810b72a64533b","integrity":"sha256-n83X3dTUDeKcOAm1lojGaLhfVijiGdTNiogQtypkUzs="},"application-a9c6770a672e537abdfdbea5f842747b5d0b0d402d9216a5f1bb789f051ba10e.js":{"logical_path":"application.js","mtime":"2017-01-19T14:51:27+01:00","size":2365648,"digest":"a9c6770a672e537abdfdbea5f842747b5d0b0d402d9216a5f1bb789f051ba10e","integrity":"sha256-qcZ3CmcuU3q9/b6l+EJ0e10LDUAtkhal8bt4nwUboQ4="},"tinymce/langs/ar-e47a394dbc461d20aa547fa0c2027a9dad45fe55e18adb0da309045be6ed4109.js":{"logical_path":"tinymce/langs/ar.js","mtime":"2017-04-24T19:17:55+02:00","size":17776,"digest":"e47a394dbc461d20aa547fa0c2027a9dad45fe55e18adb0da309045be6ed4109","integrity":"sha256-5Ho5TbxGHSCqVH+gwgJ6na1F/lXhitsNowkEW+btQQk="},"tinymce/langs/ar_SA-24b62c76e99e114ae44480a67edbacf74f9fed0ff7afbeacce4966f1bc80333b.js":{"logical_path":"tinymce/langs/ar_SA.js","mtime":"2017-04-24T19:17:55+02:00","size":10003,"digest":"24b62c76e99e114ae44480a67edbacf74f9fed0ff7afbeacce4966f1bc80333b","integrity":"sha256-JLYsdumeEUrkRICmftus90+f7Q/3r76szklm8byAMzs="},"tinymce/langs/az-d40cecd6eb423f910f528ae98dcdaba4c2449802621759437174cf8c8c0d5b25.js":{"logical_path":"tinymce/langs/az.js","mtime":"2017-04-24T19:17:55+02:00","size":9680,"digest":"d40cecd6eb423f910f528ae98dcdaba4c2449802621759437174cf8c8c0d5b25","integrity":"sha256-1Azs1utCP5EPUorpjc2rpMJEmAJiF1lDcXTPjIwNWyU="},"tinymce/langs/be-42e2884c0f2394afa1a17e31e702660eeea0d84618bbd18155cb0313c6eb5f69.js":{"logical_path":"tinymce/langs/be.js","mtime":"2017-04-24T19:17:55+02:00","size":21064,"digest":"42e2884c0f2394afa1a17e31e702660eeea0d84618bbd18155cb0313c6eb5f69","integrity":"sha256-QuKITA8jlK+hoX4x5wJmDu6g2EYYu9GBVcsDE8brX2k="},"tinymce/langs/bg_BG-2fac9d785519d2791d42881fcc08c6a82e841575785690259d7f64e1b88d7db3.js":{"logical_path":"tinymce/langs/bg_BG.js","mtime":"2017-04-24T19:17:55+02:00","size":23945,"digest":"2fac9d785519d2791d42881fcc08c6a82e841575785690259d7f64e1b88d7db3","integrity":"sha256-L6ydeFUZ0nkdQogfzAjGqC6EFXV4VpAlnX9k4biNfbM="},"tinymce/langs/bn_BD-ef48a9094445dfa624af0c35902f60b7949b30585b5e9bc760a225fe2c07cbd3.js":{"logical_path":"tinymce/langs/bn_BD.js","mtime":"2017-04-24T19:17:55+02:00","size":6846,"digest":"ef48a9094445dfa624af0c35902f60b7949b30585b5e9bc760a225fe2c07cbd3","integrity":"sha256-70ipCURF36Ykrww1kC9gt5SbMFhbXpvHYKIl/iwHy9M="},"tinymce/langs/bs-eb66c6d6910a30b950d7a0e784027ed288e6e5a2c6db7741da3359f2067e2e0e.js":{"logical_path":"tinymce/langs/bs.js","mtime":"2017-04-24T19:17:55+02:00","size":6970,"digest":"eb66c6d6910a30b950d7a0e784027ed288e6e5a2c6db7741da3359f2067e2e0e","integrity":"sha256-62bG1pEKMLlQ16DnhAJ+0ojm5aLG23dB2jNZ8gZ+Lg4="},"tinymce/langs/ca-77ab49d6420318ed7f5fd51b6856bc396c393095bd78ea91dad83e38e5859637.js":{"logical_path":"tinymce/langs/ca.js","mtime":"2017-04-24T19:17:55+02:00","size":7787,"digest":"77ab49d6420318ed7f5fd51b6856bc396c393095bd78ea91dad83e38e5859637","integrity":"sha256-d6tJ1kIDGO1/X9UbaFa8OWw5MJW9eOqR2tg+OOWFljc="},"tinymce/langs/cs-3d7ecd619895e3e4c7e1db06f6526682ef88f22f6e8b50d7b45ed0ae7c206714.js":{"logical_path":"tinymce/langs/cs.js","mtime":"2017-04-24T19:17:55+02:00","size":8751,"digest":"3d7ecd619895e3e4c7e1db06f6526682ef88f22f6e8b50d7b45ed0ae7c206714","integrity":"sha256-PX7NYZiV4+TH4dsG9lJmgu+I8i9ui1DXtF7QrnwgZxQ="},"tinymce/langs/cs_CZ-4b0778d233e200dea350f8361129da2844e23d1c0f2d524aeffa6d34e581368d.js":{"logical_path":"tinymce/langs/cs_CZ.js","mtime":"2017-04-24T19:17:55+02:00","size":8399,"digest":"4b0778d233e200dea350f8361129da2844e23d1c0f2d524aeffa6d34e581368d","integrity":"sha256-Swd40jPiAN6jUPg2ESnaKETiPRwPLVJK7/ptNOWBNo0="},"tinymce/langs/cy-a847ff54657ccf76eec362cc14fbc63adb4c67f9b1de023b29d817aba4fec062.js":{"logical_path":"tinymce/langs/cy.js","mtime":"2017-04-24T19:17:55+02:00","size":6142,"digest":"a847ff54657ccf76eec362cc14fbc63adb4c67f9b1de023b29d817aba4fec062","integrity":"sha256-qEf/VGV8z3buw2LMFPvGOttMZ/mx3gI7KdgXq6T+wGI="},"tinymce/langs/da-a87f3ae1c442c3bb26b81569687e98072d038269360361ec9728f00d6b17c282.js":{"logical_path":"tinymce/langs/da.js","mtime":"2017-04-24T19:17:55+02:00","size":7513,"digest":"a87f3ae1c442c3bb26b81569687e98072d038269360361ec9728f00d6b17c282","integrity":"sha256-qH864cRCw7smuBVpaH6YBy0Dgmk2A2HslyjwDWsXwoI="},"tinymce/langs/de-a10c8f6f1e53da776e7026dffd54ea8ba527492b767e5b54ae5c3974f6953311.js":{"logical_path":"tinymce/langs/de.js","mtime":"2017-04-24T19:17:55+02:00","size":8280,"digest":"a10c8f6f1e53da776e7026dffd54ea8ba527492b767e5b54ae5c3974f6953311","integrity":"sha256-oQyPbx5T2nducCbf/VTqi6UnSSt2fltUrlw5dPaVMxE="},"tinymce/langs/de_AT-a32eec12ce12b06fc2c8919d2372242e9596712c96dc9bcfff1fc8b7dc458627.js":{"logical_path":"tinymce/langs/de_AT.js","mtime":"2017-04-24T19:17:55+02:00","size":8308,"digest":"a32eec12ce12b06fc2c8919d2372242e9596712c96dc9bcfff1fc8b7dc458627","integrity":"sha256-oy7sEs4SsG/CyJGdI3IkLpWWcSyW3JvP/x/It9xFhic="},"tinymce/langs/dv-182756bf33409a8b76bc684d0a2ab86881718c360d1f1fb3fbc609ce3f5e3f49.js":{"logical_path":"tinymce/langs/dv.js","mtime":"2017-04-24T19:17:55+02:00","size":18100,"digest":"182756bf33409a8b76bc684d0a2ab86881718c360d1f1fb3fbc609ce3f5e3f49","integrity":"sha256-GCdWvzNAmot2vGhNCiq4aIFxjDYNHx+z+8YJzj9eP0k="},"tinymce/langs/el-6bbdbf3ccb2b2f22f961eb6749b43fe401c84fd6d89cd3f76a538dc2d06bb071.js":{"logical_path":"tinymce/langs/el.js","mtime":"2017-04-24T19:17:55+02:00","size":22973,"digest":"6bbdbf3ccb2b2f22f961eb6749b43fe401c84fd6d89cd3f76a538dc2d06bb071","integrity":"sha256-a72/PMsrLyL5YetnSbQ/5AHIT9bYnNP3alONwtBrsHE="},"tinymce/langs/en_CA-1a9457da814b0a1f15687a00f3ae4b38da0301445b52c29a423a38c943d9a431.js":{"logical_path":"tinymce/langs/en_CA.js","mtime":"2017-04-24T19:17:55+02:00","size":6916,"digest":"1a9457da814b0a1f15687a00f3ae4b38da0301445b52c29a423a38c943d9a431","integrity":"sha256-GpRX2oFLCh8VaHoA865LONoDAURbUsKaQjo4yUPZpDE="},"tinymce/langs/en_GB-a0f7752ff9ddf3ed3d2cd24fee04fe585bca0babc4ce655560c923ad386c0c07.js":{"logical_path":"tinymce/langs/en_GB.js","mtime":"2017-04-24T19:17:55+02:00","size":5907,"digest":"a0f7752ff9ddf3ed3d2cd24fee04fe585bca0babc4ce655560c923ad386c0c07","integrity":"sha256-oPd1L/nd8+09LNJP7gT+WFvKC6vEzmVVYMkjrThsDAc="},"tinymce/langs/eo-cbac4d7ebcb0679845b852d9354e74586e78cf13eef82de1400cf6b465e203cd.js":{"logical_path":"tinymce/langs/eo.js","mtime":"2017-04-24T19:17:55+02:00","size":7466,"digest":"cbac4d7ebcb0679845b852d9354e74586e78cf13eef82de1400cf6b465e203cd","integrity":"sha256-y6xNfrywZ5hFuFLZNU50WG54zxPu+C3hQAz2tGXiA80="},"tinymce/langs/es-133cb5bd627c2a299544586bf365859b5a1c96c57d18c90e7853048434a809b6.js":{"logical_path":"tinymce/langs/es.js","mtime":"2017-04-24T19:17:55+02:00","size":7809,"digest":"133cb5bd627c2a299544586bf365859b5a1c96c57d18c90e7853048434a809b6","integrity":"sha256-Ezy1vWJ8KimVRFhr82WFm1oclsV9GMkOeFMEhDSoCbY="},"tinymce/langs/es_MX-352fcdff567919ff09a2e19c56d8059d339bffdbd999bcc82aa6d8340c19bbb9.js":{"logical_path":"tinymce/langs/es_MX.js","mtime":"2017-04-24T19:17:55+02:00","size":7894,"digest":"352fcdff567919ff09a2e19c56d8059d339bffdbd999bcc82aa6d8340c19bbb9","integrity":"sha256-NS/N/1Z5Gf8JouGcVtgFnTOb/9vZmbzIKqbYNAwZu7k="},"tinymce/langs/et-2cfc3da0ff39a37f0bd3c896d49604028f231ff0e7d8ebbc30dbfd4b87125f06.js":{"logical_path":"tinymce/langs/et.js","mtime":"2017-04-24T19:17:55+02:00","size":7784,"digest":"2cfc3da0ff39a37f0bd3c896d49604028f231ff0e7d8ebbc30dbfd4b87125f06","integrity":"sha256-LPw9oP85o38L08iW1JYEAo8jH/Dn2Ou8MNv9S4cSXwY="},"tinymce/langs/eu-8698ae4de236fcd490d0f45d485dbd33d8e9de6eb3db51191e1b4f8ea96a4d06.js":{"logical_path":"tinymce/langs/eu.js","mtime":"2017-04-24T19:17:55+02:00","size":7011,"digest":"8698ae4de236fcd490d0f45d485dbd33d8e9de6eb3db51191e1b4f8ea96a4d06","integrity":"sha256-hpiuTeI2/NSQ0PRdSF29M9jp3m6z21EZHhtPjqlqTQY="},"tinymce/langs/fa-7eff96595e93d4b0df484dd90c14b7b412966157ed8293f54429e9418882bdb2.js":{"logical_path":"tinymce/langs/fa.js","mtime":"2017-04-24T19:17:55+02:00","size":16462,"digest":"7eff96595e93d4b0df484dd90c14b7b412966157ed8293f54429e9418882bdb2","integrity":"sha256-fv+WWV6T1LDfSE3ZDBS3tBKWYVftgpP1RCnpQYiCvbI="},"tinymce/langs/fa_IR-2f9d33f16718ae9c1f3642905b58434ed2662fb66448c4d115b8491aa68e7904.js":{"logical_path":"tinymce/langs/fa_IR.js","mtime":"2017-04-24T19:17:55+02:00","size":17725,"digest":"2f9d33f16718ae9c1f3642905b58434ed2662fb66448c4d115b8491aa68e7904","integrity":"sha256-L50z8WcYrpwfNkKQW1hDTtJmL7ZkSMTRFbhJGqaOeQQ="},"tinymce/langs/fi-6ca2a93d045067a86e8ea973d0b89368054b15eb9b9625bf1ca871608a5cb77c.js":{"logical_path":"tinymce/langs/fi.js","mtime":"2017-04-24T19:17:55+02:00","size":8143,"digest":"6ca2a93d045067a86e8ea973d0b89368054b15eb9b9625bf1ca871608a5cb77c","integrity":"sha256-bKKpPQRQZ6hujqlz0LiTaAVLFeubliW/HKhxYIpct3w="},"tinymce/langs/fo-340609cecd5571e4eacb8fe7bd1343c8553d96d12610fb77d9a812dc6d3635fd.js":{"logical_path":"tinymce/langs/fo.js","mtime":"2017-04-24T19:17:55+02:00","size":8044,"digest":"340609cecd5571e4eacb8fe7bd1343c8553d96d12610fb77d9a812dc6d3635fd","integrity":"sha256-NAYJzs1VceTqy4/nvRNDyFU9ltEmEPt32agS3G02Nf0="},"tinymce/langs/fr_CH-e0f43c0f20727368ff0767f3bf099bc23eed9fe3e81f8bbe514381e786526928.js":{"logical_path":"tinymce/langs/fr_CH.js","mtime":"2017-04-24T19:17:55+02:00","size":8074,"digest":"e0f43c0f20727368ff0767f3bf099bc23eed9fe3e81f8bbe514381e786526928","integrity":"sha256-4PQ8DyByc2j/B2fzvwmbwj7tn+PoH4u+UUOB54ZSaSg="},"tinymce/langs/fr_FR-2702de7be93bd1e0d7120ae3c9e637061565186c66886f155ffca0663df25b4c.js":{"logical_path":"tinymce/langs/fr_FR.js","mtime":"2017-04-24T19:17:55+02:00","size":8009,"digest":"2702de7be93bd1e0d7120ae3c9e637061565186c66886f155ffca0663df25b4c","integrity":"sha256-JwLee+k70eDXEgrjyeY3BhVlGGxmiG8VX/ygZj3yW0w="},"tinymce/langs/ga-d2a3de6f28723d75b03f7f42fd3aedfd045d473425ee38f02350b56035383af1.js":{"logical_path":"tinymce/langs/ga.js","mtime":"2017-04-24T19:17:55+02:00","size":8591,"digest":"d2a3de6f28723d75b03f7f42fd3aedfd045d473425ee38f02350b56035383af1","integrity":"sha256-0qPebyhyPXWwP39C/Trt/QRdRzQl7jjwI1C1YDU4OvE="},"tinymce/langs/gd-0453e8b97bf3b6cca4065712ec59f20343ad6131735b38547e865177a1c1c490.js":{"logical_path":"tinymce/langs/gd.js","mtime":"2017-04-24T19:17:55+02:00","size":8808,"digest":"0453e8b97bf3b6cca4065712ec59f20343ad6131735b38547e865177a1c1c490","integrity":"sha256-BFPouXvztsykBlcS7FnyA0OtYTFzWzhUfoZRd6HBxJA="},"tinymce/langs/gl-1ff612222934f558870111f10934110c5656df3bb293c917e4eeceeb6605fcc5.js":{"logical_path":"tinymce/langs/gl.js","mtime":"2017-04-24T19:17:55+02:00","size":7066,"digest":"1ff612222934f558870111f10934110c5656df3bb293c917e4eeceeb6605fcc5","integrity":"sha256-H/YSIik09ViHARHxCTQRDFZW3zuyk8kX5O7O62YF/MU="},"tinymce/langs/he_IL-981f5250a4b8d404b37040ca5a35c30498cbeeb36e298d81bf1592b43fff7656.js":{"logical_path":"tinymce/langs/he_IL.js","mtime":"2017-04-24T19:17:55+02:00","size":16081,"digest":"981f5250a4b8d404b37040ca5a35c30498cbeeb36e298d81bf1592b43fff7656","integrity":"sha256-mB9SUKS41ASzcEDKWjXDBJjL7rNuKY2BvxWStD//dlY="},"tinymce/langs/hi_IN-695e0cdc22974fe45e0f35289f0249ddab87245165c9df765ec1b885ec55f0be.js":{"logical_path":"tinymce/langs/hi_IN.js","mtime":"2017-04-24T19:17:55+02:00","size":18458,"digest":"695e0cdc22974fe45e0f35289f0249ddab87245165c9df765ec1b885ec55f0be","integrity":"sha256-aV4M3CKXT+ReDzUonwJJ3auHJFFlyd92XsG4hexV8L4="},"tinymce/langs/hr-f77f1da2736d13f9a9a86ebf596f592fcc748f2975a0b9904b512d630f2c1a17.js":{"logical_path":"tinymce/langs/hr.js","mtime":"2017-04-24T19:17:55+02:00","size":7577,"digest":"f77f1da2736d13f9a9a86ebf596f592fcc748f2975a0b9904b512d630f2c1a17","integrity":"sha256-938donNtE/mpqG6/WW9ZL8x0jyl1oLmQS1EtYw8sGhc="},"tinymce/langs/hu_HU-1e22021a4f9c61919aa024041af555eac277bfc08ccb8c07fd329b87090a15e5.js":{"logical_path":"tinymce/langs/hu_HU.js","mtime":"2017-04-24T19:17:55+02:00","size":9410,"digest":"1e22021a4f9c61919aa024041af555eac277bfc08ccb8c07fd329b87090a15e5","integrity":"sha256-HiICGk+cYZGaoCQEGvVV6sJ3v8CMy4wH/TKbhwkKFeU="},"tinymce/langs/hy-0d384f3f82cd76793d3e7428a2140ea97f40a943f25ef99a2e3709a3e02b0930.js":{"logical_path":"tinymce/langs/hy.js","mtime":"2017-04-24T19:17:55+02:00","size":20375,"digest":"0d384f3f82cd76793d3e7428a2140ea97f40a943f25ef99a2e3709a3e02b0930","integrity":"sha256-DThPP4LNdnk9PnQoohQOqX9AqUPyXvmaLjcJo+ArCTA="},"tinymce/langs/id-e9fd018be745b5f14f4af47887420f98c590c607e01d57aca77ef5affe188523.js":{"logical_path":"tinymce/langs/id.js","mtime":"2017-04-24T19:17:55+02:00","size":7141,"digest":"e9fd018be745b5f14f4af47887420f98c590c607e01d57aca77ef5affe188523","integrity":"sha256-6f0Bi+dFtfFPSvR4h0IPmMWQxgfgHVesp371r/4YhSM="},"tinymce/langs/is_IS-c6e8c3e7b0e6b447faec3d8d258928f97c84558b29882c056513fb71cf237bfa.js":{"logical_path":"tinymce/langs/is_IS.js","mtime":"2017-04-24T19:17:55+02:00","size":7928,"digest":"c6e8c3e7b0e6b447faec3d8d258928f97c84558b29882c056513fb71cf237bfa","integrity":"sha256-xujD57DmtEf67D2NJYko+XyEVYspiCwFZRP7cc8je/o="},"tinymce/langs/it-25b5546d48c80ad666b600e5be3a05718b80645721b191785c1fafe1853f4a46.js":{"logical_path":"tinymce/langs/it.js","mtime":"2017-04-24T19:17:55+02:00","size":7598,"digest":"25b5546d48c80ad666b600e5be3a05718b80645721b191785c1fafe1853f4a46","integrity":"sha256-JbVUbUjICtZmtgDlvjoFcYuAZFchsZF4XB+v4YU/SkY="},"tinymce/langs/ja-80f0e7414030c32617ff651da1affa0bc85ee514fc9bc81f46edfd8ce0053ac0.js":{"logical_path":"tinymce/langs/ja.js","mtime":"2017-04-24T19:17:55+02:00","size":12290,"digest":"80f0e7414030c32617ff651da1affa0bc85ee514fc9bc81f46edfd8ce0053ac0","integrity":"sha256-gPDnQUAwwyYX/2Udoa/6C8he5RT8m8gfRu39jOAFOsA="},"tinymce/langs/ka_GE-3c6b82346a7070a8b6a15ae6e8faeecc5bfe63ad7e616b7de2e8ab8a75ec39c2.js":{"logical_path":"tinymce/langs/ka_GE.js","mtime":"2017-04-24T19:17:55+02:00","size":21284,"digest":"3c6b82346a7070a8b6a15ae6e8faeecc5bfe63ad7e616b7de2e8ab8a75ec39c2","integrity":"sha256-PGuCNGpwcKi2oVrm6PruzFv+Y61+YWt94uirinXsOcI="},"tinymce/langs/kab-3651d08aacd5bda15a04698f202bf616efbf13d3789aadd9ce4f93e430818c13.js":{"logical_path":"tinymce/langs/kab.js","mtime":"2017-04-24T19:17:55+02:00","size":7391,"digest":"3651d08aacd5bda15a04698f202bf616efbf13d3789aadd9ce4f93e430818c13","integrity":"sha256-NlHQiqzVvaFaBGmPICv2Fu+/E9N4mq3Zzk+T5DCBjBM="},"tinymce/langs/kk-0c1ba792ed9445c6512f310228f64d1cde7b5a98e0b212cca749dcb2d728fe86.js":{"logical_path":"tinymce/langs/kk.js","mtime":"2017-04-24T19:17:55+02:00","size":16681,"digest":"0c1ba792ed9445c6512f310228f64d1cde7b5a98e0b212cca749dcb2d728fe86","integrity":"sha256-DBunku2URcZRLzECKPZNHN57WpjgshLMp0ncstco/oY="},"tinymce/langs/km_KH-8bec84e4078db8c2a680260c073dfb486c85b61df62e14ca330d66d2ca2a85b5.js":{"logical_path":"tinymce/langs/km_KH.js","mtime":"2017-04-24T19:17:55+02:00","size":21396,"digest":"8bec84e4078db8c2a680260c073dfb486c85b61df62e14ca330d66d2ca2a85b5","integrity":"sha256-i+yE5AeNuMKmgCYMBz37SGyFth32LhTKMw1m0soqhbU="},"tinymce/langs/ko-ca535bfa388701fb020d24bdfb3f1e3aab127005b54e943cb1bd60b723c8194d.js":{"logical_path":"tinymce/langs/ko.js","mtime":"2017-04-24T19:17:55+02:00","size":10105,"digest":"ca535bfa388701fb020d24bdfb3f1e3aab127005b54e943cb1bd60b723c8194d","integrity":"sha256-ylNb+jiHAfsCDSS9+z8eOqsScAW1TpQ8sb1gtyPIGU0="},"tinymce/langs/ko_KR-daa3ae950d70260bb0901a5349034952247905523bbc2bcbe527701b6aad8e28.js":{"logical_path":"tinymce/langs/ko_KR.js","mtime":"2017-04-24T19:17:55+02:00","size":10005,"digest":"daa3ae950d70260bb0901a5349034952247905523bbc2bcbe527701b6aad8e28","integrity":"sha256-2qOulQ1wJguwkBpTSQNJUiR5BVI7vCvL5SdwG2qtjig="},"tinymce/langs/ku-95e2ffe4f0112df658f10327c26f2cdddedc2e2ed769767366ae22a465c14725.js":{"logical_path":"tinymce/langs/ku.js","mtime":"2017-04-24T19:17:55+02:00","size":18274,"digest":"95e2ffe4f0112df658f10327c26f2cdddedc2e2ed769767366ae22a465c14725","integrity":"sha256-leL/5PARLfZY8QMnwm8s3d7cLi7XaXZzZq4ipGXBRyU="},"tinymce/langs/ku_IQ-a212e8d41695989e56834facf72474e1934ef166c3fcaf7e255ef573a3c6e76c.js":{"logical_path":"tinymce/langs/ku_IQ.js","mtime":"2017-04-24T19:17:55+02:00","size":18364,"digest":"a212e8d41695989e56834facf72474e1934ef166c3fcaf7e255ef573a3c6e76c","integrity":"sha256-ohLo1BaVmJ5Wg0+s9yR04ZNO8WbD/K9+JV71c6PG52w="},"tinymce/langs/lb-94992279091f1a0be927d5d858d3724037d8d81ee6b63cc9ddde84af6124cc04.js":{"logical_path":"tinymce/langs/lb.js","mtime":"2017-04-24T19:17:55+02:00","size":7467,"digest":"94992279091f1a0be927d5d858d3724037d8d81ee6b63cc9ddde84af6124cc04","integrity":"sha256-lJkieQkfGgvpJ9XYWNNyQDfY2B7mtjzJ3d6Er2EkzAQ="},"tinymce/langs/lt-ae7cefbe2cb5420770b31eabf92605728135ab5d6a2d2cfca2d19809be67e6a8.js":{"logical_path":"tinymce/langs/lt.js","mtime":"2017-04-24T19:17:55+02:00","size":8899,"digest":"ae7cefbe2cb5420770b31eabf92605728135ab5d6a2d2cfca2d19809be67e6a8","integrity":"sha256-rnzvviy1Qgdwsx6r+SYFcoE1q11qLSz8otGYCb5n5qg="},"tinymce/langs/lv-e468ed0c78466d1fff9f4957645606d8aa683cb5dc35931e047df97b8e4f5433.js":{"logical_path":"tinymce/langs/lv.js","mtime":"2017-04-24T19:17:55+02:00","size":8282,"digest":"e468ed0c78466d1fff9f4957645606d8aa683cb5dc35931e047df97b8e4f5433","integrity":"sha256-5GjtDHhGbR//n0lXZFYG2KpoPLXcNZMeBH35e45PVDM="},"tinymce/langs/mk_MK-55aadb5d7c82c940cfcf42f24423ef0471294c9b02994a6b22e1b4173baa7ec6.js":{"logical_path":"tinymce/langs/mk_MK.js","mtime":"2017-04-24T19:17:55+02:00","size":18733,"digest":"55aadb5d7c82c940cfcf42f24423ef0471294c9b02994a6b22e1b4173baa7ec6","integrity":"sha256-VarbXXyCyUDPz0LyRCPvBHEpTJsCmUprIuG0FzuqfsY="},"tinymce/langs/ml-685de0808683c02274dcbe9f8de023a4d72a49b040e7526a99e3d5c786ff71ae.js":{"logical_path":"tinymce/langs/ml.js","mtime":"2017-04-24T19:17:55+02:00","size":7339,"digest":"685de0808683c02274dcbe9f8de023a4d72a49b040e7526a99e3d5c786ff71ae","integrity":"sha256-aF3ggIaDwCJ03L6fjeAjpNcqSbBA51JqmePVx4b/ca4="},"tinymce/langs/ml_IN-1ab433621d6257c7632718048bacc5ed98a302d33cf0438bbbb4200914e01aac.js":{"logical_path":"tinymce/langs/ml_IN.js","mtime":"2017-04-24T19:17:55+02:00","size":20019,"digest":"1ab433621d6257c7632718048bacc5ed98a302d33cf0438bbbb4200914e01aac","integrity":"sha256-GrQzYh1iV8djJxgEi6zF7ZijAtM88EOLu7QgCRTgGqw="},"tinymce/langs/mn_MN-b89f88cb9b0dd7c879e27532b2979c421c1e69648f65a4108a56060f1e1cb009.js":{"logical_path":"tinymce/langs/mn_MN.js","mtime":"2017-04-24T19:17:55+02:00","size":6877,"digest":"b89f88cb9b0dd7c879e27532b2979c421c1e69648f65a4108a56060f1e1cb009","integrity":"sha256-uJ+Iy5sN18h54nUyspecQhweaWSPZaQQilYGDx4csAk="},"tinymce/langs/nb_NO-602ee249e98a26ae24c1ee1311090c68a782050086a835f1e7bd46ebfe7879ef.js":{"logical_path":"tinymce/langs/nb_NO.js","mtime":"2017-04-24T19:17:55+02:00","size":7528,"digest":"602ee249e98a26ae24c1ee1311090c68a782050086a835f1e7bd46ebfe7879ef","integrity":"sha256-YC7iSemKJq4kwe4TEQkMaKeCBQCGqDXx571G6/54ee8="},"tinymce/langs/nl-9c77e9404a27fd7e4bd162ad44538b72d2725b7fee7be7ca3ff801cf217c4968.js":{"logical_path":"tinymce/langs/nl.js","mtime":"2017-04-24T19:17:55+02:00","size":7235,"digest":"9c77e9404a27fd7e4bd162ad44538b72d2725b7fee7be7ca3ff801cf217c4968","integrity":"sha256-nHfpQEon/X5L0WKtRFOLctJyW3/ue+fKP/gBzyF8SWg="},"tinymce/langs/pl-5cdd1586ec8fa67293f2175cd92edbd0392c4c77b24ed64cfdceccba8d99f152.js":{"logical_path":"tinymce/langs/pl.js","mtime":"2017-04-24T19:17:55+02:00","size":8129,"digest":"5cdd1586ec8fa67293f2175cd92edbd0392c4c77b24ed64cfdceccba8d99f152","integrity":"sha256-XN0VhuyPpnKT8hdc2S7b0DksTHeyTtZM/c7Muo2Z8VI="},"tinymce/langs/pt_BR-e3955318582d58bd241a62c3a81afe74e0ae7f31bdc92a562b75243701f114df.js":{"logical_path":"tinymce/langs/pt_BR.js","mtime":"2017-04-24T19:17:55+02:00","size":8002,"digest":"e3955318582d58bd241a62c3a81afe74e0ae7f31bdc92a562b75243701f114df","integrity":"sha256-45VTGFgtWL0kGmLDqBr+dOCufzG9ySpWK3UkNwHxFN8="},"tinymce/langs/pt_PT-1101d080ecd5da091c7ef70b23200adbd5136c5c32f0c79dae665a443d76c35d.js":{"logical_path":"tinymce/langs/pt_PT.js","mtime":"2017-04-24T19:17:55+02:00","size":8145,"digest":"1101d080ecd5da091c7ef70b23200adbd5136c5c32f0c79dae665a443d76c35d","integrity":"sha256-EQHQgOzV2gkcfvcLIyAK29UTbFwy8MedrmZaRD12w10="},"tinymce/langs/ro-484799d182031efab087d749b024014fd06ed06c1e7712b8bf87f3a4a965c2e4.js":{"logical_path":"tinymce/langs/ro.js","mtime":"2017-04-24T19:17:55+02:00","size":8275,"digest":"484799d182031efab087d749b024014fd06ed06c1e7712b8bf87f3a4a965c2e4","integrity":"sha256-SEeZ0YIDHvqwh9dJsCQBT9Bu0GwedxK4v4fzpKllwuQ="},"tinymce/langs/ru-bdd59cb662a7b4d61e770b07014d1791051312c87513ecc1891e80beba617171.js":{"logical_path":"tinymce/langs/ru.js","mtime":"2017-04-24T19:17:55+02:00","size":22290,"digest":"bdd59cb662a7b4d61e770b07014d1791051312c87513ecc1891e80beba617171","integrity":"sha256-vdWctmKntNYedwsHAU0XkQUTEsh1E+zBiR6AvrphcXE="},"tinymce/langs/ru_RU-9f18ef14f3493cc586cc0b4827fd9e1c2ed3d5790ce536d94f87e2d6aac2a688.js":{"logical_path":"tinymce/langs/ru_RU.js","mtime":"2017-04-24T19:17:55+02:00","size":4955,"digest":"9f18ef14f3493cc586cc0b4827fd9e1c2ed3d5790ce536d94f87e2d6aac2a688","integrity":"sha256-nxjvFPNJPMWGzAtIJ/2eHC7T1XkM5TbZT4fi1qrCpog="},"tinymce/langs/si_LK-5bfefe9b2fe82574d8ed839df18fd8ff65f1e1cd458b0a843cf1aadd1be704ea.js":{"logical_path":"tinymce/langs/si_LK.js","mtime":"2017-04-24T19:17:55+02:00","size":15856,"digest":"5bfefe9b2fe82574d8ed839df18fd8ff65f1e1cd458b0a843cf1aadd1be704ea","integrity":"sha256-W/7+my/oJXTY7YOd8Y/Y/2Xx4c1FiwqEPPGq3RvnBOo="},"tinymce/langs/sk-412fa7f982ad2733341203daa035c8ba10035262ca8f5f65e0a41507512209bd.js":{"logical_path":"tinymce/langs/sk.js","mtime":"2017-04-24T19:17:55+02:00","size":8958,"digest":"412fa7f982ad2733341203daa035c8ba10035262ca8f5f65e0a41507512209bd","integrity":"sha256-QS+n+YKtJzM0EgPaoDXIuhADUmLKj19l4KQVB1EiCb0="},"tinymce/langs/sl_SI-2bea4f3854a992ea840808019dc99467dc173b12454ea6016135234a741671d8.js":{"logical_path":"tinymce/langs/sl_SI.js","mtime":"2017-04-24T19:17:55+02:00","size":7039,"digest":"2bea4f3854a992ea840808019dc99467dc173b12454ea6016135234a741671d8","integrity":"sha256-K+pPOFSpkuqECAgBncmUZ9wXOxJFTqYBYTUjSnQWcdg="},"tinymce/langs/sr-e0b97453a0c1000b19f7ce37fcf86bcacbf9125d81076f60a77686820c7925c6.js":{"logical_path":"tinymce/langs/sr.js","mtime":"2017-04-24T19:17:55+02:00","size":6336,"digest":"e0b97453a0c1000b19f7ce37fcf86bcacbf9125d81076f60a77686820c7925c6","integrity":"sha256-4Ll0U6DBAAsZ9843/Phrysv5El2BB29gp3aGggx5JcY="},"tinymce/langs/sv_SE-fa561a7e49fdb42d5913337176fed6bc8a9997eb3ca8f20ecd9520d5391e17be.js":{"logical_path":"tinymce/langs/sv_SE.js","mtime":"2017-04-24T19:17:55+02:00","size":7496,"digest":"fa561a7e49fdb42d5913337176fed6bc8a9997eb3ca8f20ecd9520d5391e17be","integrity":"sha256-+lYafkn9tC1ZEzNxdv7WvIqZl+s8qPIOzZUg1TkeF74="},"tinymce/langs/ta-0fd0e62250fc1a3626ac2111c5adb4194a6a898888bb224414f6dc8adf53d385.js":{"logical_path":"tinymce/langs/ta.js","mtime":"2017-04-24T19:17:55+02:00","size":22617,"digest":"0fd0e62250fc1a3626ac2111c5adb4194a6a898888bb224414f6dc8adf53d385","integrity":"sha256-D9DmIlD8GjYmrCERxa20GUpqiYiIuyJEFPbcit9T04U="},"tinymce/langs/ta_IN-32303f65d2378e8202b17b0920b79277a2580872e3a6bd9409aeceef90867dd0.js":{"logical_path":"tinymce/langs/ta_IN.js","mtime":"2017-04-24T19:17:55+02:00","size":22620,"digest":"32303f65d2378e8202b17b0920b79277a2580872e3a6bd9409aeceef90867dd0","integrity":"sha256-MjA/ZdI3joICsXsJILeSd6JYCHLjpr2UCa7O75CGfdA="},"tinymce/langs/tg-1618248bf0aeda614a37ced9fd28b6623ae24f8453368bfb8c483ce820a3cb34.js":{"logical_path":"tinymce/langs/tg.js","mtime":"2017-04-24T19:17:55+02:00","size":18183,"digest":"1618248bf0aeda614a37ced9fd28b6623ae24f8453368bfb8c483ce820a3cb34","integrity":"sha256-Fhgki/Cu2mFKN87Z/Si2YjriT4RTNov7jEg86CCjyzQ="},"tinymce/langs/th_TH-5279a379afc886c2a31e22aba9d7ee7a8e3edf4c0785f39aaa20ccd03d46b19a.js":{"logical_path":"tinymce/langs/th_TH.js","mtime":"2017-04-24T19:17:55+02:00","size":17297,"digest":"5279a379afc886c2a31e22aba9d7ee7a8e3edf4c0785f39aaa20ccd03d46b19a","integrity":"sha256-Unmjea/IhsKjHiKrqdfueo4+30wHhfOaqiDM0D1GsZo="},"tinymce/langs/tr-3765d4a8923ef22864747d9c825c3e0af401e1356e75a5458bed837d486b7673.js":{"logical_path":"tinymce/langs/tr.js","mtime":"2017-04-24T19:17:55+02:00","size":8705,"digest":"3765d4a8923ef22864747d9c825c3e0af401e1356e75a5458bed837d486b7673","integrity":"sha256-N2XUqJI+8ihkdH2cglw+CvQB4TVudaVFi+2DfUhrdnM="},"tinymce/langs/tr_TR-5c93f80b89e5dd2eb6972f37bf50b76d7705c61f28120b836704a91fa5c14399.js":{"logical_path":"tinymce/langs/tr_TR.js","mtime":"2017-04-24T19:17:55+02:00","size":8141,"digest":"5c93f80b89e5dd2eb6972f37bf50b76d7705c61f28120b836704a91fa5c14399","integrity":"sha256-XJP4C4nl3S62ly83v1C3bXcFxh8oEguDZwSpH6XBQ5k="},"tinymce/langs/tt-22e302672df0a77de14688f58dbedf82de7a26e9089c9535a2a3cd1c0ccd7903.js":{"logical_path":"tinymce/langs/tt.js","mtime":"2017-04-24T19:17:55+02:00","size":19035,"digest":"22e302672df0a77de14688f58dbedf82de7a26e9089c9535a2a3cd1c0ccd7903","integrity":"sha256-IuMCZy3wp33hRoj1jb7fgt56JukInJU1oqPNHAzNeQM="},"tinymce/langs/ug-50232038bf7262c90be4f2919c74ff93792cdb82e6064d0f5c86f885b93271c5.js":{"logical_path":"tinymce/langs/ug.js","mtime":"2017-04-24T19:17:55+02:00","size":16888,"digest":"50232038bf7262c90be4f2919c74ff93792cdb82e6064d0f5c86f885b93271c5","integrity":"sha256-UCMgOL9yYskL5PKRnHT/k3ks24LmBk0PXIb4hbkyccU="},"tinymce/langs/uk-f6d7911714c422b178c0249df323cf7ec415a83195d751c7e4024590b1738c42.js":{"logical_path":"tinymce/langs/uk.js","mtime":"2017-04-24T19:17:55+02:00","size":22264,"digest":"f6d7911714c422b178c0249df323cf7ec415a83195d751c7e4024590b1738c42","integrity":"sha256-9teRFxTEIrF4wCSd8yPPfsQVqDGV11HH5AJFkLFzjEI="},"tinymce/langs/uk_UA-bd8cd7ca66228d85f8a4cadb651c49981f26e007fa2a952856c8c3d3c1baa66a.js":{"logical_path":"tinymce/langs/uk_UA.js","mtime":"2017-04-24T19:17:55+02:00","size":21691,"digest":"bd8cd7ca66228d85f8a4cadb651c49981f26e007fa2a952856c8c3d3c1baa66a","integrity":"sha256-vYzXymYijYX4pMrbZRxJmB8m4Af6KpUoVsjD08G6pmo="},"tinymce/langs/vi-6aa451047e4df911c92e10178e6a70147534e438c64df7a88eee37b4a440726e.js":{"logical_path":"tinymce/langs/vi.js","mtime":"2017-04-24T19:17:55+02:00","size":9901,"digest":"6aa451047e4df911c92e10178e6a70147534e438c64df7a88eee37b4a440726e","integrity":"sha256-aqRRBH5N+RHJLhAXjmpwFHU05DjGTfeoju43tKRAcm4="},"tinymce/langs/vi_VN-aea52c2e9397f8a657d54d50a42b3c5be0ca79480555a4fa1e0f5d785c5f6561.js":{"logical_path":"tinymce/langs/vi_VN.js","mtime":"2017-04-24T19:17:55+02:00","size":9899,"digest":"aea52c2e9397f8a657d54d50a42b3c5be0ca79480555a4fa1e0f5d785c5f6561","integrity":"sha256-rqUsLpOX+KZX1U1QpCs8W+DKeUgFVaT6Hg9deFxfZWE="},"tinymce/langs/zh_CN-8622ec46e2980b6f5baf3b745c6b0187dd2a54ddecbbf69a21f0b3e72f84f6dc.js":{"logical_path":"tinymce/langs/zh_CN.js","mtime":"2017-04-24T19:17:55+02:00","size":8483,"digest":"8622ec46e2980b6f5baf3b745c6b0187dd2a54ddecbbf69a21f0b3e72f84f6dc","integrity":"sha256-hiLsRuKYC29brzt0XGsBh90qVN3su/aaIfCz5y+E9tw="},"tinymce/langs/zh_TW-90723da3b889f2a4477d4aaf00ca3e75439998269b36b359ea4caa37e1defb4a.js":{"logical_path":"tinymce/langs/zh_TW.js","mtime":"2017-04-24T19:17:55+02:00","size":9379,"digest":"90723da3b889f2a4477d4aaf00ca3e75439998269b36b359ea4caa37e1defb4a","integrity":"sha256-kHI9o7iJ8qRHfUqvAMo+dUOZmCabNrNZ6kyqN+He+0o="},"tinymce/preinit-84328a53e798df12f891eb49871773fd9f925439c8630e9e22423a82ef9e6f89.js":{"logical_path":"tinymce/preinit.js","mtime":"2017-01-05T19:24:14+01:00","size":82,"digest":"84328a53e798df12f891eb49871773fd9f925439c8630e9e22423a82ef9e6f89","integrity":"sha256-hDKKU+eY3xL4ketJhxdz/Z+SVDnIYw6eIkI6gu+eb4k="},"tinymce/tinymce-6c5174912bf31a8ee031a9acb5d2b7d05f7bcd42e3ed0d26d7d217a5343eb2bf.js":{"logical_path":"tinymce/tinymce.js","mtime":"2017-01-05T19:24:14+01:00","size":1294513,"digest":"6c5174912bf31a8ee031a9acb5d2b7d05f7bcd42e3ed0d26d7d217a5343eb2bf","integrity":"sha256-bFF0kSvzGo7gMamstdK30F97zULj7Q0m19IXpTQ+sr8="},"tinymce/jquery.tinymce-275e24af4bf53bfb60f7fef218163106ad0648b8ad384ecfab9b4fd52f48603d.js":{"logical_path":"tinymce/jquery.tinymce.js","mtime":"2017-05-02T18:30:07+02:00","size":3592,"digest":"275e24af4bf53bfb60f7fef218163106ad0648b8ad384ecfab9b4fd52f48603d","integrity":"sha256-J14kr0v1O/tg9/7yGBYxBq0GSLitOE7Pq5tP1S9IYD0="},"tinymce/langs/readme-5a8b6a04d57b5c88e3fb7f2a870b8e2d3a48ec03ce6474206c41df78c155b2de.md":{"logical_path":"tinymce/langs/readme.md","mtime":"2017-05-02T18:30:07+02:00","size":151,"digest":"5a8b6a04d57b5c88e3fb7f2a870b8e2d3a48ec03ce6474206c41df78c155b2de","integrity":"sha256-WotqBNV7XIjj+38qhwuOLTpI7APOZHQgbEHfeMFVst4="},"tinymce/license-5fda611b8191f00121f161a93e7399cdb71789dba923e8ed09b50a1f78d32c5e.txt":{"logical_path":"tinymce/license.txt","mtime":"2017-05-02T18:30:07+02:00","size":26427,"digest":"5fda611b8191f00121f161a93e7399cdb71789dba923e8ed09b50a1f78d32c5e","integrity":"sha256-X9phG4GR8AEh8WGpPnOZzbcXidupI+jtCbUKH3jTLF4="},"tinymce/plugins/advlist/plugin-d0bd2b90c1aaf60ddbb048d955f7fbf76e303b5f3227f8e4dc83207548c3fc46.js":{"logical_path":"tinymce/plugins/advlist/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":2092,"digest":"d0bd2b90c1aaf60ddbb048d955f7fbf76e303b5f3227f8e4dc83207548c3fc46","integrity":"sha256-0L0rkMGq9g3bsEjZVff7924wO18yJ/jk3IMgdUjD/EY="},"tinymce/plugins/anchor/plugin-48c211e97cdf2fba4e8456ddc0464c301c61ff2d2751aa178d41c5eca38fbbe9.js":{"logical_path":"tinymce/plugins/anchor/plugin.js","mtime":"2017-01-05T19:24:14+01:00","size":958,"digest":"48c211e97cdf2fba4e8456ddc0464c301c61ff2d2751aa178d41c5eca38fbbe9","integrity":"sha256-SMIR6XzfL7pOhFbdwEZMMBxh/y0nUaoXjUHF7KOPu+k="},"tinymce/plugins/autolink/plugin-9d514baa6f3816a43008241db075d724fcb274632fad3db792e87e5feb6c5d0f.js":{"logical_path":"tinymce/plugins/autolink/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":2061,"digest":"9d514baa6f3816a43008241db075d724fcb274632fad3db792e87e5feb6c5d0f","integrity":"sha256-nVFLqm84FqQwCCQdsHXXJPyydGMvrT23kuh+X+tsXQ8="},"tinymce/plugins/autoresize/plugin-7cd05d5431f8713c948291ad40ef63eabe44908bd831d5675afacaca296a4d7b.js":{"logical_path":"tinymce/plugins/autoresize/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1904,"digest":"7cd05d5431f8713c948291ad40ef63eabe44908bd831d5675afacaca296a4d7b","integrity":"sha256-fNBdVDH4cTyUgpGtQO9j6r5EkIvYMdVnWvrKyilqTXs="},"tinymce/plugins/autosave/plugin-43448ce025b165ed1b509554cadf02cda4ed104ccfae6d0708379f02e981220f.js":{"logical_path":"tinymce/plugins/autosave/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":2188,"digest":"43448ce025b165ed1b509554cadf02cda4ed104ccfae6d0708379f02e981220f","integrity":"sha256-Q0SM4CWxZe0bUJVUyt8CzaTtEEzPrm0HCDefAumBIg8="},"tinymce/plugins/bbcode/plugin-dae2432b6477ca1acc3bd6ac7af33c379797c7f2dcf2c82513475d4c234d851d.js":{"logical_path":"tinymce/plugins/bbcode/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":3137,"digest":"dae2432b6477ca1acc3bd6ac7af33c379797c7f2dcf2c82513475d4c234d851d","integrity":"sha256-2uJDK2R3yhrMO9asevM8N5eXx/Lc8sglE0ddTCNNhR0="},"tinymce/plugins/charmap/plugin-ee3f9ed5d0135f19975a4609701b4b4546f00ab1afee9b74a38bb3d76ab94eca.js":{"logical_path":"tinymce/plugins/charmap/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":8200,"digest":"ee3f9ed5d0135f19975a4609701b4b4546f00ab1afee9b74a38bb3d76ab94eca","integrity":"sha256-7j+e1dATXxmXWkYJcBtLRUbwCrGv7pt0o4uz12q5Tso="},"tinymce/plugins/code/plugin-093b2519070297197c89cabd2b7bf7b7920786fa3ae5b055322fb16d51d113d4.js":{"logical_path":"tinymce/plugins/code/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":722,"digest":"093b2519070297197c89cabd2b7bf7b7920786fa3ae5b055322fb16d51d113d4","integrity":"sha256-CTslGQcClxl8icq9K3v3t5IHhvo65bBVMi+xbVHRE9Q="},"tinymce/plugins/codesample/css/prism-1988b66704b4d23e78c6c20c38a6856cbc1f0be96d6d60a3a0b12f4408f1057e.css":{"logical_path":"tinymce/plugins/codesample/css/prism.css","mtime":"2017-05-02T18:30:07+02:00","size":1776,"digest":"1988b66704b4d23e78c6c20c38a6856cbc1f0be96d6d60a3a0b12f4408f1057e","integrity":"sha256-GYi2ZwS00j54xsIMOKaFbLwfC+ltbWCjoLEvRAjxBX4="},"tinymce/plugins/codesample/plugin-edd0d2e7f821002843d7726182d9a8b1520fcabb753b95ee7956180337be23da.js":{"logical_path":"tinymce/plugins/codesample/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":20333,"digest":"edd0d2e7f821002843d7726182d9a8b1520fcabb753b95ee7956180337be23da","integrity":"sha256-7dDS5/ghAChD13JhgtmosVIPyrt1O5XueVYYAze+I9o="},"tinymce/plugins/colorpicker/plugin-526e08119d96ecdeeb21c1031cba4b471aba860fbc6ed0f8a010275088c00531.js":{"logical_path":"tinymce/plugins/colorpicker/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1223,"digest":"526e08119d96ecdeeb21c1031cba4b471aba860fbc6ed0f8a010275088c00531","integrity":"sha256-Um4IEZ2W7N7rIcEDHLpLRxq6hg+8btD4oBAnUIjABTE="},"tinymce/plugins/contextmenu/plugin-11ad7a2ff14cc47d12a3dd0170741590335e606b0efaa8dc77837409e54afa0a.js":{"logical_path":"tinymce/plugins/contextmenu/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1132,"digest":"11ad7a2ff14cc47d12a3dd0170741590335e606b0efaa8dc77837409e54afa0a","integrity":"sha256-Ea16L/FMxH0So90BcHQVkDNeYGsO+qjcd4N0CeVK+go="},"tinymce/plugins/directionality/plugin-6381fb028625726e50977d00f342fa1f60e39dc794e0ea1c7d9feff8846ab9fc.js":{"logical_path":"tinymce/plugins/directionality/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":727,"digest":"6381fb028625726e50977d00f342fa1f60e39dc794e0ea1c7d9feff8846ab9fc","integrity":"sha256-Y4H7AoYlcm5Ql30A80L6H2DjnceU4OocfZ/v+IRqufw="},"tinymce/plugins/emoticons/img/smiley-cool-bb0e93a050a32df7913e4026b3c88a176998e0e3e073ba06e9b73f6c24227c9c.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-cool.gif","mtime":"2017-05-02T18:30:07+02:00","size":354,"digest":"bb0e93a050a32df7913e4026b3c88a176998e0e3e073ba06e9b73f6c24227c9c","integrity":"sha256-uw6ToFCjLfeRPkAms8iKF2mY4OPgc7oG6bc/bCQifJw="},"tinymce/plugins/emoticons/img/smiley-cry-a0c5f3e7a682449c973c9d9f7c46342081c46920686d2353f57aff91ab907f68.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-cry.gif","mtime":"2017-05-02T18:30:07+02:00","size":329,"digest":"a0c5f3e7a682449c973c9d9f7c46342081c46920686d2353f57aff91ab907f68","integrity":"sha256-oMXz56aCRJyXPJ2ffEY0IIHEaSBobSNT9Xr/kauQf2g="},"tinymce/plugins/emoticons/img/smiley-embarassed-d3cafcb50b335672cb5e9f4600ea9ea261dac7828dd28844d4927c393a25618f.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-embarassed.gif","mtime":"2017-05-02T18:30:07+02:00","size":331,"digest":"d3cafcb50b335672cb5e9f4600ea9ea261dac7828dd28844d4927c393a25618f","integrity":"sha256-08r8tQszVnLLXp9GAOqeomHax4KN0ohE1JJ8OTolYY8="},"tinymce/plugins/emoticons/img/smiley-foot-in-mouth-03fe04d3ed533423ac81f05146584b0c451be3d4a30e76687ceef283ed07071f.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-foot-in-mouth.gif","mtime":"2017-05-02T18:30:07+02:00","size":342,"digest":"03fe04d3ed533423ac81f05146584b0c451be3d4a30e76687ceef283ed07071f","integrity":"sha256-A/4E0+1TNCOsgfBRRlhLDEUb49SjDnZofO7yg+0HBx8="},"tinymce/plugins/emoticons/img/smiley-frown-1b984bf98931dd1debb54461eb9d83e985f2b2999fe14bcb556d6c0921bc83b0.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-frown.gif","mtime":"2017-05-02T18:30:07+02:00","size":340,"digest":"1b984bf98931dd1debb54461eb9d83e985f2b2999fe14bcb556d6c0921bc83b0","integrity":"sha256-G5hL+Ykx3R3rtURh652D6YXyspmf4UvLVW1sCSG8g7A="},"tinymce/plugins/emoticons/img/smiley-innocent-8db353ef102196f2c6ddf5c4666446de955d7b14fc0957c806c9dbfb48fb0c29.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-innocent.gif","mtime":"2017-05-02T18:30:07+02:00","size":336,"digest":"8db353ef102196f2c6ddf5c4666446de955d7b14fc0957c806c9dbfb48fb0c29","integrity":"sha256-jbNT7xAhlvLG3fXEZmRG3pVdexT8CVfIBsnb+0j7DCk="},"tinymce/plugins/emoticons/img/smiley-kiss-3154c3665356c13ab10fefdbac1fe187fff978a0052037c99cdc4a97103413f2.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-kiss.gif","mtime":"2017-05-02T18:30:07+02:00","size":338,"digest":"3154c3665356c13ab10fefdbac1fe187fff978a0052037c99cdc4a97103413f2","integrity":"sha256-MVTDZlNWwTqxD+/brB/hh//5eKAFIDfJnNxKlxA0E/I="},"tinymce/plugins/emoticons/img/smiley-laughing-8f6adedcd091975ffead171867a6304d908bb6541a6ccb4919286ec6b7d4551e.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-laughing.gif","mtime":"2017-05-02T18:30:07+02:00","size":343,"digest":"8f6adedcd091975ffead171867a6304d908bb6541a6ccb4919286ec6b7d4551e","integrity":"sha256-j2re3NCRl1/+rRcYZ6YwTZCLtlQabMtJGShuxrfUVR4="},"tinymce/plugins/emoticons/img/smiley-money-mouth-f0b9f4f22e237f5dbc851f900fed8d7eca4c954ae6fbc606c0cd8be431d0ac80.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-money-mouth.gif","mtime":"2017-05-02T18:30:07+02:00","size":321,"digest":"f0b9f4f22e237f5dbc851f900fed8d7eca4c954ae6fbc606c0cd8be431d0ac80","integrity":"sha256-8Ln08i4jf128hR+QD+2NfspMlUrm+8YGwM2L5DHQrIA="},"tinymce/plugins/emoticons/img/smiley-sealed-9933b442636b6e537df7b564e2c3f7a2873526eea6b022a98eb1e468e5204c32.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-sealed.gif","mtime":"2017-05-02T18:30:07+02:00","size":323,"digest":"9933b442636b6e537df7b564e2c3f7a2873526eea6b022a98eb1e468e5204c32","integrity":"sha256-mTO0QmNrblN997Vk4sP3ooc1Ju6msCKpjrHkaOUgTDI="},"tinymce/plugins/emoticons/img/smiley-smile-fd89cd460ffcacb7e725e00c0275ef5b3924ce468248e5ff4fb43545571cfa65.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-smile.gif","mtime":"2017-05-02T18:30:07+02:00","size":344,"digest":"fd89cd460ffcacb7e725e00c0275ef5b3924ce468248e5ff4fb43545571cfa65","integrity":"sha256-/YnNRg/8rLfnJeAMAnXvWzkkzkaCSOX/T7Q1RVcc+mU="},"tinymce/plugins/emoticons/img/smiley-surprised-3871f356cb41976d7ae8a5f005e8739e4d014352a8adef9b33f773d81b6e6c01.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-surprised.gif","mtime":"2017-05-02T18:30:07+02:00","size":338,"digest":"3871f356cb41976d7ae8a5f005e8739e4d014352a8adef9b33f773d81b6e6c01","integrity":"sha256-OHHzVstBl2166KXwBehznk0BQ1Kore+bM/dz2BtubAE="},"tinymce/plugins/emoticons/img/smiley-tongue-out-5843c85667a8226dc43be83749fd9fbbc5d20b1577de2b763915d99815d37d47.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-tongue-out.gif","mtime":"2017-05-02T18:30:07+02:00","size":328,"digest":"5843c85667a8226dc43be83749fd9fbbc5d20b1577de2b763915d99815d37d47","integrity":"sha256-WEPIVmeoIm3EO+g3Sf2fu8XSCxV33it2ORXZmBXTfUc="},"tinymce/plugins/emoticons/img/smiley-undecided-d8b9bcbb433951ff3c4ca8dd959ac3844239b98e6d52218833e1485a91f67347.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-undecided.gif","mtime":"2017-05-02T18:30:07+02:00","size":337,"digest":"d8b9bcbb433951ff3c4ca8dd959ac3844239b98e6d52218833e1485a91f67347","integrity":"sha256-2Lm8u0M5Uf88TKjdlZrDhEI5uY5tUiGIM+FIWpH2c0c="},"tinymce/plugins/emoticons/img/smiley-wink-2af75ad7b1c08488505513503e34b15f40005e04a2a9568f698f0945d2d8ba1f.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-wink.gif","mtime":"2017-05-02T18:30:07+02:00","size":350,"digest":"2af75ad7b1c08488505513503e34b15f40005e04a2a9568f698f0945d2d8ba1f","integrity":"sha256-Kvda17HAhIhQVRNQPjSxX0AAXgSiqVaPaY8JRdLYuh8="},"tinymce/plugins/emoticons/img/smiley-yell-bba903fbcb46fce8c68b9e01863fd095b3b1d0e6aa72161f3a88d762a5f90a79.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-yell.gif","mtime":"2017-05-02T18:30:07+02:00","size":336,"digest":"bba903fbcb46fce8c68b9e01863fd095b3b1d0e6aa72161f3a88d762a5f90a79","integrity":"sha256-u6kD+8tG/OjGi54Bhj/QlbOx0OaqchYfOojXYqX5Cnk="},"tinymce/plugins/emoticons/plugin-75971da62ade77af7e79b3a560c5ad5ac20ee5f88c7ba236e03902777fdec715.js":{"logical_path":"tinymce/plugins/emoticons/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":912,"digest":"75971da62ade77af7e79b3a560c5ad5ac20ee5f88c7ba236e03902777fdec715","integrity":"sha256-dZcdpired69+ebOlYMWtWsIO5fiMe6I24DkCd3/exxU="},"tinymce/plugins/example/dialog-5c61ad829a494e75c2234019c7941f6dd096ec693cf5a5538c0bf30485097841.html":{"logical_path":"tinymce/plugins/example/dialog.html","mtime":"2017-05-02T18:30:07+02:00","size":213,"digest":"5c61ad829a494e75c2234019c7941f6dd096ec693cf5a5538c0bf30485097841","integrity":"sha256-XGGtgppJTnXCI0AZx5QfbdCW7Gk89aVTjAvzBIUJeEE="},"tinymce/plugins/example/plugin-505b7ee82929e7338700605a4ca63d94dbe6ef2ce2d21104cc01c2adba829868.js":{"logical_path":"tinymce/plugins/example/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":659,"digest":"505b7ee82929e7338700605a4ca63d94dbe6ef2ce2d21104cc01c2adba829868","integrity":"sha256-UFt+6Ckp5zOHAGBaTKY9lNvm7yzi0hEEzAHCrbqCmGg="},"tinymce/plugins/example_dependency/plugin-9bb52c9d45c0f7e4d67c12f546c68095b2d5284aa84ab3a2c45f1d986f464653.js":{"logical_path":"tinymce/plugins/example_dependency/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":74,"digest":"9bb52c9d45c0f7e4d67c12f546c68095b2d5284aa84ab3a2c45f1d986f464653","integrity":"sha256-m7UsnUXA9+TWfBL1RsaAlbLVKEqoSrOixF8dmG9GRlM="},"tinymce/plugins/fullpage/plugin-6cd62d14e4225c1db1d9008a485143d8e8b7a7c699e2ceec16a8012b44875ef5.js":{"logical_path":"tinymce/plugins/fullpage/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":6309,"digest":"6cd62d14e4225c1db1d9008a485143d8e8b7a7c699e2ceec16a8012b44875ef5","integrity":"sha256-bNYtFOQiXB2x2QCKSFFD2Oi3p8aZ4s7sFqgBK0SHXvU="},"tinymce/plugins/fullscreen/plugin-972d5e04901e74c8c657ee88fb3cc245b94aeb005d54adeac00c07a0c5700f7a.js":{"logical_path":"tinymce/plugins/fullscreen/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1676,"digest":"972d5e04901e74c8c657ee88fb3cc245b94aeb005d54adeac00c07a0c5700f7a","integrity":"sha256-ly1eBJAedMjGV+6I+zzCRblK6wBdVK3qwAwHoMVwD3o="},"tinymce/plugins/hr/plugin-92558948637f4349e0f327350ddebdd225313e582f08aacf6cb5549d03fc9a8b.js":{"logical_path":"tinymce/plugins/hr/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":323,"digest":"92558948637f4349e0f327350ddebdd225313e582f08aacf6cb5549d03fc9a8b","integrity":"sha256-klWJSGN/Q0ng8yc1Dd690iUxPlgvCKrPbLVUnQP8mos="},"tinymce/plugins/image/plugin-1c01f4fb87c7523d1ae9bfd7018d883601b59c40edc79c552ef39e8374cb9313.js":{"logical_path":"tinymce/plugins/image/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":8205,"digest":"1c01f4fb87c7523d1ae9bfd7018d883601b59c40edc79c552ef39e8374cb9313","integrity":"sha256-HAH0+4fHUj0a6b/XAY2INgG1nEDtx5xVLvOeg3TLkxM="},"tinymce/plugins/imagetools/plugin-78f93669c67ad2579caa99f1069d5ac7f5dc97af9be40d7b55c036dbe650574f.js":{"logical_path":"tinymce/plugins/imagetools/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":30907,"digest":"78f93669c67ad2579caa99f1069d5ac7f5dc97af9be40d7b55c036dbe650574f","integrity":"sha256-ePk2acZ60lecqpnxBp1ax/Xcl6+b5A17VcA22+ZQV08="},"tinymce/plugins/importcss/plugin-31acbbaaa49b20377e4f5d5a830d9e09babddb9a1c5b7978b843098176e318b5.js":{"logical_path":"tinymce/plugins/importcss/plugin.js","mtime":"2017-01-05T19:24:14+01:00","size":2749,"digest":"31acbbaaa49b20377e4f5d5a830d9e09babddb9a1c5b7978b843098176e318b5","integrity":"sha256-May7qqSbIDd+T11agw2eCbq925ocW3l4uEMJgXbjGLU="},"tinymce/plugins/insertdatetime/plugin-923510af4de6343c5ea6b8e679dbaa87d27a7abdaf84ac1f0000ad5722787577.js":{"logical_path":"tinymce/plugins/insertdatetime/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1972,"digest":"923510af4de6343c5ea6b8e679dbaa87d27a7abdaf84ac1f0000ad5722787577","integrity":"sha256-kjUQr03mNDxeprjmeduqh9J6er2vhKwfAACtVyJ4dXc="},"tinymce/plugins/legacyoutput/plugin-ac8239571ea6699f14a76058ea9e53a2a5d9b7e84bed3446d7bd4137b8cdac9f.js":{"logical_path":"tinymce/plugins/legacyoutput/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":3264,"digest":"ac8239571ea6699f14a76058ea9e53a2a5d9b7e84bed3446d7bd4137b8cdac9f","integrity":"sha256-rII5Vx6maZ8Up2BY6p5ToqXZt+hL7TRG171BN7jNrJ8="},"tinymce/plugins/link/plugin-e38346a4005bc814b0117a2dae6eb04ea9a7a8865d658afce406a8394fec0577.js":{"logical_path":"tinymce/plugins/link/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":6995,"digest":"e38346a4005bc814b0117a2dae6eb04ea9a7a8865d658afce406a8394fec0577","integrity":"sha256-44NGpABbyBSwEXotrm6wTqmnqIZdZYr85AaoOU/sBXc="},"tinymce/plugins/lists/plugin-69b25b69974c739637d6459489642fc95bddc8dc564f2b482d7ec94f3082f935.js":{"logical_path":"tinymce/plugins/lists/plugin.js","mtime":"2017-01-05T19:24:14+01:00","size":10332,"digest":"69b25b69974c739637d6459489642fc95bddc8dc564f2b482d7ec94f3082f935","integrity":"sha256-abJbaZdMc5Y31kWUiWQvyVvdyNxWTytILX7JTzCC+TU="},"tinymce/plugins/media/plugin-deedd7c7d99c7401ab698f65a1e299819b487e52e662c7866f8700ba8d67a351.js":{"logical_path":"tinymce/plugins/media/plugin.js","mtime":"2017-01-05T19:24:14+01:00","size":16223,"digest":"deedd7c7d99c7401ab698f65a1e299819b487e52e662c7866f8700ba8d67a351","integrity":"sha256-3u3Xx9mcdAGraY9loeKZgZtIflLmYseGb4cAuo1no1E="},"tinymce/plugins/nonbreaking/plugin-4b15567cb04f551924ca87994514a09fef17c2c6ea3bb6d50e8ca65dc3243b93.js":{"logical_path":"tinymce/plugins/nonbreaking/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":656,"digest":"4b15567cb04f551924ca87994514a09fef17c2c6ea3bb6d50e8ca65dc3243b93","integrity":"sha256-SxVWfLBPVRkkyoeZRRSgn+8XwsbqO7bVDoymXcMkO5M="},"tinymce/plugins/noneditable/plugin-245b5d236dfea414326bdbcd601333f54d5c2b30a0133cbcbbbae329306b0df3.js":{"logical_path":"tinymce/plugins/noneditable/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1271,"digest":"245b5d236dfea414326bdbcd601333f54d5c2b30a0133cbcbbbae329306b0df3","integrity":"sha256-JFtdI23+pBQya9vNYBMz9U1cKzCgEzy8u7rjKTBrDfM="},"tinymce/plugins/pagebreak/plugin-4c8f35adfd6fb570639318219a4d2ad0e8850619f37ff322ad101683ec00829a.js":{"logical_path":"tinymce/plugins/pagebreak/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1231,"digest":"4c8f35adfd6fb570639318219a4d2ad0e8850619f37ff322ad101683ec00829a","integrity":"sha256-TI81rf1vtXBjkxghmk0q0OiFBhnzf/MirRAWg+wAgpo="},"tinymce/plugins/paste/plugin-f7d8cf6dd7bd24908d5c58c664a54cbe4838c542ec26e35f3c4b198f53f98291.js":{"logical_path":"tinymce/plugins/paste/plugin.js","mtime":"2017-01-05T19:24:14+01:00","size":17685,"digest":"f7d8cf6dd7bd24908d5c58c664a54cbe4838c542ec26e35f3c4b198f53f98291","integrity":"sha256-99jPbde9JJCNXFjGZKVMvkg4xULsJuNfPEsZj1P5gpE="},"tinymce/plugins/preview/plugin-d0b7e78697d7a21e237e170bbb0a9c95c40b8dc0118a5ccb6a8347eba1800ade.js":{"logical_path":"tinymce/plugins/preview/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1603,"digest":"d0b7e78697d7a21e237e170bbb0a9c95c40b8dc0118a5ccb6a8347eba1800ade","integrity":"sha256-0LfnhpfXoh4jfhcLuwqclcQLjcARilzLaoNH66GACt4="},"tinymce/plugins/print/plugin-07acb7cbdb293f598245755b4a5a142b9d7b78f6b7a6268e3a447b8941f64472.js":{"logical_path":"tinymce/plugins/print/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":294,"digest":"07acb7cbdb293f598245755b4a5a142b9d7b78f6b7a6268e3a447b8941f64472","integrity":"sha256-B6y3y9spP1mCRXVbSloUK517ePa3piaOOkR7iUH2RHI="},"tinymce/plugins/save/plugin-ef4b15573e862995e82aadd8ede1117ee36a05b335a74640804e24dbca5ebac1.js":{"logical_path":"tinymce/plugins/save/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1151,"digest":"ef4b15573e862995e82aadd8ede1117ee36a05b335a74640804e24dbca5ebac1","integrity":"sha256-70sVVz6GKZXoKq3Y7eERfuNqBbM1p0ZAgE4k28peusE="},"tinymce/plugins/searchreplace/plugin-e1f614dbe20b45955a82405a9aa38c415ab49288d74d0daf881db666eb5549c6.js":{"logical_path":"tinymce/plugins/searchreplace/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":6494,"digest":"e1f614dbe20b45955a82405a9aa38c415ab49288d74d0daf881db666eb5549c6","integrity":"sha256-4fYU2+ILRZVagkBamqOMQVq0kojXTQ2viB22ZutVScY="},"tinymce/plugins/spellchecker/plugin-8c198efb4ebcd3ae3f53b2906bed0265f883bd3fca5f8a30880aac630f4eb787.js":{"logical_path":"tinymce/plugins/spellchecker/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":10049,"digest":"8c198efb4ebcd3ae3f53b2906bed0265f883bd3fca5f8a30880aac630f4eb787","integrity":"sha256-jBmO+068064/U7KQa+0CZfiDvT/KX4owiAqsYw9Ot4c="},"tinymce/plugins/tabfocus/plugin-4b947a94b9cc31d699fed7bb19d2efd9b62fbbd75f0858040bca4ba6402113a0.js":{"logical_path":"tinymce/plugins/tabfocus/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1265,"digest":"4b947a94b9cc31d699fed7bb19d2efd9b62fbbd75f0858040bca4ba6402113a0","integrity":"sha256-S5R6lLnMMdaZ/te7GdLv2bYvu9dfCFgEC8pLpkAhE6A="},"tinymce/plugins/table/plugin-5f3b35988457fcc9d2c2c35601acb041b7b59246dc16d061433cf741cba9ca26.js":{"logical_path":"tinymce/plugins/table/plugin.js","mtime":"2017-01-05T19:24:14+01:00","size":46153,"digest":"5f3b35988457fcc9d2c2c35601acb041b7b59246dc16d061433cf741cba9ca26","integrity":"sha256-Xzs1mIRX/MnSwsNWAaywQbe1kkbcFtBhQzz3QcupyiY="},"tinymce/plugins/template/plugin-3a7a1a203ced83abdb7f36897c974eed07a876be4f54809e06ad5b17ec957222.js":{"logical_path":"tinymce/plugins/template/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":4521,"digest":"3a7a1a203ced83abdb7f36897c974eed07a876be4f54809e06ad5b17ec957222","integrity":"sha256-OnoaIDztg6vbfzaJfJdO7Qeodr5PVICeBq1bF+yVciI="},"tinymce/plugins/textcolor/plugin-d05a9d9a6fbdcca3f07c45e6ef1ba8913f48c68a68a871343cdce2075c0ef0b6.js":{"logical_path":"tinymce/plugins/textcolor/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":4146,"digest":"d05a9d9a6fbdcca3f07c45e6ef1ba8913f48c68a68a871343cdce2075c0ef0b6","integrity":"sha256-0Fqdmm+9zKPwfEXm7xuokT9IxopoqHE0PNziB1wO8LY="},"tinymce/plugins/textpattern/plugin-d630f2bc3205e400af41041eb224fe793ae950de5d5f4732f63e36f6819d3f35.js":{"logical_path":"tinymce/plugins/textpattern/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":2746,"digest":"d630f2bc3205e400af41041eb224fe793ae950de5d5f4732f63e36f6819d3f35","integrity":"sha256-1jDyvDIF5ACvQQQesiT+eTrpUN5dX0cy9j429oGdPzU="},"tinymce/plugins/toc/plugin-c20dc2987d4fcd8f859871ec0f2988f3c819c373d2fadad8c5b923b9b749d0ef.js":{"logical_path":"tinymce/plugins/toc/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":2772,"digest":"c20dc2987d4fcd8f859871ec0f2988f3c819c373d2fadad8c5b923b9b749d0ef","integrity":"sha256-wg3CmH1PzY+FmHHsDymI88gZw3PS+trYxbkjubdJ0O8="},"tinymce/plugins/visualblocks/css/visualblocks-e44e30ebe30e4d3763425a9ea38b558ff13106b8e16a30a74ae21b4c174b3417.css":{"logical_path":"tinymce/plugins/visualblocks/css/visualblocks.css","mtime":"2017-05-02T18:30:07+02:00","size":4767,"digest":"e44e30ebe30e4d3763425a9ea38b558ff13106b8e16a30a74ae21b4c174b3417","integrity":"sha256-5E4w6+MOTTdjQlqeo4tVj/ExBrjhajCnSuIbTBdLNBc="},"tinymce/plugins/visualblocks/plugin-6cdc811487cbbee106512812da68f1999fcb3db14f99c5cb4a070be578c9bb0a.js":{"logical_path":"tinymce/plugins/visualblocks/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1154,"digest":"6cdc811487cbbee106512812da68f1999fcb3db14f99c5cb4a070be578c9bb0a","integrity":"sha256-bNyBFIfLvuEGUSgS2mjxmZ/LPbFPmcXLSgcL5XjJuwo="},"tinymce/plugins/visualchars/plugin-0e8c1d7cba0b1471014fe3359a04ff4d4d981070777cdf31f4d95a732b83581f.js":{"logical_path":"tinymce/plugins/visualchars/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1179,"digest":"0e8c1d7cba0b1471014fe3359a04ff4d4d981070777cdf31f4d95a732b83581f","integrity":"sha256-DowdfLoLFHEBT+M1mgT/TU2YEHB3fN8x9NlacyuDWB8="},"tinymce/plugins/wordcount/plugin-d9ec660425815b227f5c3fbdc8b5d066a0530ec824ba37b47169aabd3f864ea7.js":{"logical_path":"tinymce/plugins/wordcount/plugin.js","mtime":"2017-01-05T19:24:14+01:00","size":12048,"digest":"d9ec660425815b227f5c3fbdc8b5d066a0530ec824ba37b47169aabd3f864ea7","integrity":"sha256-2exmBCWBWyJ/XD+9yLXQZqBTDsgkuje0cWmqvT+GTqc="},"tinymce/skins/lightgray/content.inline.min-5bb5c69d072a2d17d11e0c54bc81b6f863e5b5a126060d862970f0c22f5d49ec.css":{"logical_path":"tinymce/skins/lightgray/content.inline.min.css","mtime":"2017-05-02T18:30:07+02:00","size":2770,"digest":"5bb5c69d072a2d17d11e0c54bc81b6f863e5b5a126060d862970f0c22f5d49ec","integrity":"sha256-W7XGnQcqLRfRHgxUvIG2+GPltaEmBg2GKXDwwi9dSew="},"tinymce/skins/lightgray/content.min-92e6da84fb5c2dfcc35f34d311ca1914b19064ada45fa9a08ff2a68c0fc0e657.css":{"logical_path":"tinymce/skins/lightgray/content.min.css","mtime":"2017-05-02T18:30:07+02:00","size":3194,"digest":"92e6da84fb5c2dfcc35f34d311ca1914b19064ada45fa9a08ff2a68c0fc0e657","integrity":"sha256-kubahPtcLfzDXzTTEcoZFLGQZK2kX6mgj/KmjA/A5lc="},"tinymce/skins/lightgray/fonts/tinymce-small-a10fc4343d95b716c16d77463d475be5c079599ea67e1cd2bd3a94d5e7f508f9.eot":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce-small.eot","mtime":"2017-05-02T18:30:07+02:00","size":9492,"digest":"a10fc4343d95b716c16d77463d475be5c079599ea67e1cd2bd3a94d5e7f508f9","integrity":"sha256-oQ/END2VtxbBbXdGPUdb5cB5WZ6mfhzSvTqU1ef1CPk="},"tinymce/skins/lightgray/fonts/tinymce-small-e7773001446ab937e1d8d4bd5e8dbd9b31d112037353a14b319e36dd010ed8ee.svg":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce-small.svg","mtime":"2017-05-02T18:30:07+02:00","size":24727,"digest":"e7773001446ab937e1d8d4bd5e8dbd9b31d112037353a14b319e36dd010ed8ee","integrity":"sha256-53cwAURquTfh2NS9Xo29mzHREgNzU6FLMZ423QEO2O4="},"tinymce/skins/lightgray/fonts/tinymce-small-2f657502906d6f5c3fc8df3a82969114ebe030addfdc061c60c974b0f515fd09.ttf":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce-small.ttf","mtime":"2017-05-02T18:30:07+02:00","size":9304,"digest":"2f657502906d6f5c3fc8df3a82969114ebe030addfdc061c60c974b0f515fd09","integrity":"sha256-L2V1ApBtb1w/yN86gpaRFOvgMK3f3AYcYMl0sPUV/Qk="},"tinymce/skins/lightgray/fonts/tinymce-small-d3efbb678ca6de5632902bd93772746ba2f8e4e2322b953936e12694a183aa31.woff":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce-small.woff","mtime":"2017-05-02T18:30:07+02:00","size":9380,"digest":"d3efbb678ca6de5632902bd93772746ba2f8e4e2322b953936e12694a183aa31","integrity":"sha256-0++7Z4ym3lYykCvZN3J0a6L45OIyK5U5NuEmlKGDqjE="},"tinymce/skins/lightgray/fonts/tinymce-2e9c4a68fde992476e0db9e44128cb1f2e898f0de0b80f552a8acb52bb7ca0db.eot":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce.eot","mtime":"2017-05-02T18:30:07+02:00","size":17572,"digest":"2e9c4a68fde992476e0db9e44128cb1f2e898f0de0b80f552a8acb52bb7ca0db","integrity":"sha256-LpxKaP3pkkduDbnkQSjLHy6Jjw3guA9VKorLUrt8oNs="},"tinymce/skins/lightgray/fonts/tinymce-2094ddadc265c7f33570475fc78ef7adcdcb814e49060d17f5b4c4f8d1cb7ec6.svg":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce.svg","mtime":"2017-05-02T18:30:07+02:00","size":45991,"digest":"2094ddadc265c7f33570475fc78ef7adcdcb814e49060d17f5b4c4f8d1cb7ec6","integrity":"sha256-IJTdrcJlx/M1cEdfx473rc3LgU5JBg0X9bTE+NHLfsY="},"tinymce/skins/lightgray/fonts/tinymce-477ea2d46c1a975dd492af4c10235fabfd09069595779cce00ea0381ca9b4a20.ttf":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce.ttf","mtime":"2017-05-02T18:30:07+02:00","size":17408,"digest":"477ea2d46c1a975dd492af4c10235fabfd09069595779cce00ea0381ca9b4a20","integrity":"sha256-R36i1Gwal13Ukq9MECNfq/0JBpWVd5zOAOoDgcqbSiA="},"tinymce/skins/lightgray/fonts/tinymce-1ebc636bb24cbea637946ba8c22cbf4f35d8343ba9763045d2aee59e3714ae78.woff":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce.woff","mtime":"2017-05-02T18:30:07+02:00","size":17484,"digest":"1ebc636bb24cbea637946ba8c22cbf4f35d8343ba9763045d2aee59e3714ae78","integrity":"sha256-Hrxja7JMvqY3lGuowiy/TzXYNDupdjBF0q7lnjcUrng="},"tinymce/skins/lightgray/img/anchor-2861666fd107d278d4449970615136d06d7f746be9bb19072cf9c8f30e565e1e.gif":{"logical_path":"tinymce/skins/lightgray/img/anchor.gif","mtime":"2017-05-02T18:30:07+02:00","size":53,"digest":"2861666fd107d278d4449970615136d06d7f746be9bb19072cf9c8f30e565e1e","integrity":"sha256-KGFmb9EH0njURJlwYVE20G1/dGvpuxkHLPnI8w5WXh4="},"tinymce/skins/lightgray/img/loader-eb7cfd3d959b2e09c170f532e29f8b825f9bc770b2279fde58e595617753e244.gif":{"logical_path":"tinymce/skins/lightgray/img/loader.gif","mtime":"2017-05-02T18:30:07+02:00","size":2608,"digest":"eb7cfd3d959b2e09c170f532e29f8b825f9bc770b2279fde58e595617753e244","integrity":"sha256-63z9PZWbLgnBcPUy4p+Lgl+bx3CyJ5/eWOWVYXdT4kQ="},"tinymce/skins/lightgray/img/object-e6a15e52bc4a17b085073ba8debd4708ead6ae3d4cbeb3880c65cb7afc489777.gif":{"logical_path":"tinymce/skins/lightgray/img/object.gif","mtime":"2017-05-02T18:30:07+02:00","size":152,"digest":"e6a15e52bc4a17b085073ba8debd4708ead6ae3d4cbeb3880c65cb7afc489777","integrity":"sha256-5qFeUrxKF7CFBzuo3r1HCOrWrj1MvrOIDGXLevxIl3c="},"tinymce/skins/lightgray/img/trans-9cf020d7c3bba7f5ab10cda54aabef934f906d4f9a3acf99e9e7dc6c98579635.gif":{"logical_path":"tinymce/skins/lightgray/img/trans.gif","mtime":"2017-05-02T18:30:07+02:00","size":43,"digest":"9cf020d7c3bba7f5ab10cda54aabef934f906d4f9a3acf99e9e7dc6c98579635","integrity":"sha256-nPAg18O7p/WrEM2lSqvvk0+QbU+aOs+Z6efcbJhXljU="},"tinymce/skins/lightgray/skin.ie7.min-f7e68049f5f1ba278870818429ef905d07846781701c40657d9d24ca6638cced.css":{"logical_path":"tinymce/skins/lightgray/skin.ie7.min.css","mtime":"2017-05-02T18:30:07+02:00","size":34904,"digest":"f7e68049f5f1ba278870818429ef905d07846781701c40657d9d24ca6638cced","integrity":"sha256-9+aASfXxuieIcIGEKe+QXQeEZ4FwHEBlfZ0kymY4zO0="},"tinymce/skins/lightgray/skin.min-6d81e56f6d40695f114abe4db834ccb7bf7d89cfa07c10c2cbaebb8066ace27b.css":{"logical_path":"tinymce/skins/lightgray/skin.min.css","mtime":"2017-05-02T18:30:07+02:00","size":38232,"digest":"6d81e56f6d40695f114abe4db834ccb7bf7d89cfa07c10c2cbaebb8066ace27b","integrity":"sha256-bYHlb21AaV8RSr5NuDTMt799ic+gfBDCy667gGas4ns="},"tinymce/themes/inlite/theme-95446aa7daedd3754400947ecc50a607971ef2068d093e7c9a889c5908ff6f40.js":{"logical_path":"tinymce/themes/inlite/theme.js","mtime":"2017-01-05T19:24:14+01:00","size":16382,"digest":"95446aa7daedd3754400947ecc50a607971ef2068d093e7c9a889c5908ff6f40","integrity":"sha256-lURqp9rt03VEAJR+zFCmB5ce8gaNCT58moicWQj/b0A="},"tinymce/themes/modern/theme-f0a3cccc241fa5d46bde8e19160e3f351368881a7c3cdb0c4ce84da11901064c.js":{"logical_path":"tinymce/themes/modern/theme.js","mtime":"2017-05-02T18:30:07+02:00","size":13155,"digest":"f0a3cccc241fa5d46bde8e19160e3f351368881a7c3cdb0c4ce84da11901064c","integrity":"sha256-8KPMzCQfpdRr3o4ZFg4/NRNoiBp8PNsMTOhNoRkBBkw="},"active_admin-f7ef723200f732c68bf56214e1c6ac931008f3de4eba9dcd29e140696b46f0a0.css":{"logical_path":"active_admin.css","mtime":"2017-05-04T21:49:46+02:00","size":79039,"digest":"f7ef723200f732c68bf56214e1c6ac931008f3de4eba9dcd29e140696b46f0a0","integrity":"sha256-9+9yMgD3MsaL9WIU4caskxAI895Oup3NKeFAaWtG8KA="},"active_admin-2b4f9b9e35d46bbace92d14d078b3568dcdbd0183e52827e5c44c54dc7c96266.js":{"logical_path":"active_admin.js","mtime":"2017-05-04T23:06:57+02:00","size":692870,"digest":"2b4f9b9e35d46bbace92d14d078b3568dcdbd0183e52827e5c44c54dc7c96266","integrity":"sha256-K0+bnjXUa7rOktFNB4s1aNzb0Bg+UoJ+XETFTcfJYmY="},"tinymce-8c0346bfe88f5c5405046ebd1cdbd1c7192d503d93623ffc00d2d7b430116b69.js":{"logical_path":"tinymce.js","mtime":"2017-05-04T23:06:57+02:00","size":971,"digest":"8c0346bfe88f5c5405046ebd1cdbd1c7192d503d93623ffc00d2d7b430116b69","integrity":"sha256-jANGv+iPXFQFBG69HNvRxxktUD2TYj/8ANLXtDARa2k="},"application-12922f8d27744fe5233d0c8f855c532cad64561e248ebaa05442fd6b59f73af2.css":{"logical_path":"application.css","mtime":"2017-05-04T23:06:57+02:00","size":174051,"digest":"12922f8d27744fe5233d0c8f855c532cad64561e248ebaa05442fd6b59f73af2","integrity":"sha256-EpIvjSd0T+UjPQyPhVxTLK1kVh4kjrqgVEL9a1n3OvI="},"brasil-0e293d8c9a86f8a98fea23013e9c365b32fd0022a1496309eeabcd97f7be1288.png":{"logical_path":"brasil.png","mtime":"2017-05-04T22:06:49+02:00","size":660,"digest":"0e293d8c9a86f8a98fea23013e9c365b32fd0022a1496309eeabcd97f7be1288","integrity":"sha256-Dik9jJqG+KmP6iMBPpw2WzL9ACKhSWMJ7qvNl/e+Eog="},"application-88a91754f1835c3e582224375aeeccd1d3dce637f71dded6ca23ce71a228d339.js":{"logical_path":"application.js","mtime":"2017-05-04T23:06:57+02:00","size":2376693,"digest":"88a91754f1835c3e582224375aeeccd1d3dce637f71dded6ca23ce71a228d339","integrity":"sha256-iKkXVPGDXD5YIiQ3Wu7M0dPc5jf3Hd7WyiPOcaIo0zk="},"tinymce/preinit-4eb7f4ac58f2f450d20185cf83ca1d8550d2a1419141bfe70eb5a2c4afe67349.js":{"logical_path":"tinymce/preinit.js","mtime":"2017-05-02T18:30:07+02:00","size":248,"digest":"4eb7f4ac58f2f450d20185cf83ca1d8550d2a1419141bfe70eb5a2c4afe67349","integrity":"sha256-Trf0rFjy9FDSAYXPg8odhVDSoUGRQb/nDrWixK/mc0k="},"tinymce/tinymce-d7f6811cb92d1e7638015669d3ec90175d4cb1309ecad56ff9d757b25fe18172.js":{"logical_path":"tinymce/tinymce.js","mtime":"2017-05-02T18:30:07+02:00","size":1299472,"digest":"d7f6811cb92d1e7638015669d3ec90175d4cb1309ecad56ff9d757b25fe18172","integrity":"sha256-1/aBHLktHnY4AVZp0+yQF11MsTCeytVv+ddXsl/hgXI="},"tinymce/plugins/anchor/plugin-f642e411a2a702256b0069e5baf65ef62d31c34e92e993123aad88e22ee295ce.js":{"logical_path":"tinymce/plugins/anchor/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1189,"digest":"f642e411a2a702256b0069e5baf65ef62d31c34e92e993123aad88e22ee295ce","integrity":"sha256-9kLkEaKnAiVrAGnluvZe9i0xw06S6ZMSOq2I4i7ilc4="},"tinymce/plugins/importcss/plugin-5386dd0994914eaf7431876cb0b2d9cf505a8d91c0f8fd739c5166bd21f6376d.js":{"logical_path":"tinymce/plugins/importcss/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":2748,"digest":"5386dd0994914eaf7431876cb0b2d9cf505a8d91c0f8fd739c5166bd21f6376d","integrity":"sha256-U4bdCZSRTq90MYdssLLZz1BajZHA+P1znFFmvSH2N20="},"tinymce/plugins/lists/plugin-c56f1732e8069ebaca97437c3b99a69ed2663f558cd50a817ee721661673510c.js":{"logical_path":"tinymce/plugins/lists/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":14636,"digest":"c56f1732e8069ebaca97437c3b99a69ed2663f558cd50a817ee721661673510c","integrity":"sha256-xW8XMugGnrrKl0N8O5mmntJmP1WM1QqBfuchZhZzUQw="},"tinymce/plugins/media/plugin-f5341fd5503efcd25c050b419868be59073ba2e0bf58bf7a73877c052109e0de.js":{"logical_path":"tinymce/plugins/media/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":16453,"digest":"f5341fd5503efcd25c050b419868be59073ba2e0bf58bf7a73877c052109e0de","integrity":"sha256-9TQf1VA+/NJcBQtBmGi+WQc7ouC/WL96c4d8BSEJ4N4="},"tinymce/plugins/paste/plugin-524c40b866f13bbb8fea23d9b8529d00df10b94695e646bd4303eaff9f658e7c.js":{"logical_path":"tinymce/plugins/paste/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":18069,"digest":"524c40b866f13bbb8fea23d9b8529d00df10b94695e646bd4303eaff9f658e7c","integrity":"sha256-UkxAuGbxO7uP6iPZuFKdAN8QuUaV5ka9QwPq/59ljnw="},"tinymce/plugins/table/plugin-58e9f99c4c09431f853051ab6a87504487a9042e520c68e84d9adc59346659a6.js":{"logical_path":"tinymce/plugins/table/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":47127,"digest":"58e9f99c4c09431f853051ab6a87504487a9042e520c68e84d9adc59346659a6","integrity":"sha256-WOn5nEwJQx+FMFGraodQRIepBC5SDGjoTZrcWTRmWaY="},"tinymce/plugins/wordcount/plugin-649a9308c0183e56c3ba78002d7b480ecbba84ff30361c36bcea6ed07ea6be4f.js":{"logical_path":"tinymce/plugins/wordcount/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":12031,"digest":"649a9308c0183e56c3ba78002d7b480ecbba84ff30361c36bcea6ed07ea6be4f","integrity":"sha256-ZJqTCMAYPlbDungALXtIDsu6hP8wNhw2vOpu0H6mvk8="},"tinymce/themes/inlite/theme-a400085213d427d78d8a1e35089ae6cd00831e51d33a3342a198d1bc62851640.js":{"logical_path":"tinymce/themes/inlite/theme.js","mtime":"2017-05-02T18:30:07+02:00","size":16579,"digest":"a400085213d427d78d8a1e35089ae6cd00831e51d33a3342a198d1bc62851640","integrity":"sha256-pAAIUhPUJ9eNih41CJrmzQCDHlHTOjNCoZjRvGKFFkA="},"tinymce-4c729110e9fbc21457c0701ad636697126e92f7382d61a90a5d1417bce25d351.js":{"logical_path":"tinymce.js","mtime":"2017-05-04T23:44:41+02:00","size":971,"digest":"4c729110e9fbc21457c0701ad636697126e92f7382d61a90a5d1417bce25d351","integrity":"sha256-THKREOn7whRXwHAa1jZpcSbpL3OC1hqQpdFBe84l01E="},"application-bdfbc8eb22d736e3b643562e28b99fe04141f4cf95374182bef07145353c9d93.css":{"logical_path":"application.css","mtime":"2017-05-04T23:44:41+02:00","size":174069,"digest":"bdfbc8eb22d736e3b643562e28b99fe04141f4cf95374182bef07145353c9d93","integrity":"sha256-vfvI6yLXNuO2Q1YuKLmf4EFB9M+VN0GCvvBxRTU8nZM="},"application-903f24210c790f3469e1bc9eb1ce7ee154a7bf349807a3d86d0eda7deb1a8639.js":{"logical_path":"application.js","mtime":"2017-05-04T23:44:41+02:00","size":2376693,"digest":"903f24210c790f3469e1bc9eb1ce7ee154a7bf349807a3d86d0eda7deb1a8639","integrity":"sha256-kD8kIQx5DzRp4byesc5+4VSnvzSYB6PYbQ7afesahjk="},"tinymce-99a0778c7c535b32962fc89f8028c5c266e2635afaf1a4fef18fbea79c64417c.js":{"logical_path":"tinymce.js","mtime":"2017-05-05T00:03:37+02:00","size":971,"digest":"99a0778c7c535b32962fc89f8028c5c266e2635afaf1a4fef18fbea79c64417c","integrity":"sha256-maB3jHxTWzKWL8ifgCjFwmbiY1r68aT+8Y++p5xkQXw="},"application-c9233d317c4304011690c6ce879a873281e2d4c79930b7ea3cf28bb7c5839d24.css":{"logical_path":"application.css","mtime":"2017-05-05T00:03:37+02:00","size":174071,"digest":"c9233d317c4304011690c6ce879a873281e2d4c79930b7ea3cf28bb7c5839d24","integrity":"sha256-ySM9MXxDBAEWkMbOh5qHMoHi1MeZMLfqPPKLt8WDnSQ="},"application-d242f0ecb362deb18f1fb1143feba3afd81da98a6de3e41f805a9e99c6ba03dc.js":{"logical_path":"application.js","mtime":"2017-05-05T00:03:37+02:00","size":2376693,"digest":"d242f0ecb362deb18f1fb1143feba3afd81da98a6de3e41f805a9e99c6ba03dc","integrity":"sha256-0kLw7LNi3rGPH7EUP+ujr9gdqYpt4+QfgFqemca6A9w="},"tinymce-c09e1a38c74241759c70df0385e95b4c46d6cd0342bd271315c2457b25591aad.js":{"logical_path":"tinymce.js","mtime":"2017-05-05T00:07:11+02:00","size":971,"digest":"c09e1a38c74241759c70df0385e95b4c46d6cd0342bd271315c2457b25591aad","integrity":"sha256-wJ4aOMdCQXWccN8DhelbTEbWzQNCvScTFcJFeyVZGq0="},"application-74c16b3b8c70a0ee2d3bc48bb2acbb9925fc52b1cd41171d7cb5063cd119ba3a.css":{"logical_path":"application.css","mtime":"2017-05-05T00:07:11+02:00","size":174066,"digest":"74c16b3b8c70a0ee2d3bc48bb2acbb9925fc52b1cd41171d7cb5063cd119ba3a","integrity":"sha256-dMFrO4xwoO4tO8SLsqy7mSX8UrHNQRcdfLUGPNEZujo="},"application-5b7e43f757edc035a8a8704a7194315f37d111b86a354effc3df4fd3343fa018.js":{"logical_path":"application.js","mtime":"2017-05-05T00:07:11+02:00","size":2376693,"digest":"5b7e43f757edc035a8a8704a7194315f37d111b86a354effc3df4fd3343fa018","integrity":"sha256-W35D91ftwDWoqHBKcZQxXzfREbhqNU7/w99P0zQ/oBg="}},"assets":{"active_admin.css":"active_admin-f7ef723200f732c68bf56214e1c6ac931008f3de4eba9dcd29e140696b46f0a0.css","active_admin/nested_menu_arrow.gif":"active_admin/nested_menu_arrow-15084d93c65c1964d7077700ea748bd2d70cfa2d4c19707c58a9c64e232dd442.gif","active_admin/nested_menu_arrow_dark.gif":"active_admin/nested_menu_arrow_dark-7c43b8e0a5f8823875f49a093c9d7a6b374f885b6f9cc248ae9cd7e6e9b29034.gif","active_admin/datepicker/datepicker-input-icon.png":"active_admin/datepicker/datepicker-input-icon-d9c2bb73769af777c8a71720d29741f3a499aebd5a043e9a119bd0d9597aed47.png","active_admin/orderable.png":"active_admin/orderable-29374dbb55b0012d78a37c614d573bb3474f0779849b478a147d0f1845ca6617.png","active_admin/print.css":"active_admin/print-87c5ffc1d869a919123bcc1dc5ec51b20bc79fd9aeab9eed77e3438c6acd4f68.css","active_admin.js":"active_admin-2b4f9b9e35d46bbace92d14d078b3568dcdbd0183e52827e5c44c54dc7c96266.js","layers-2x.png":"layers-2x-066daca850d8ffbef007af00b06eac0015728dee279c51f3cb6c716df7c42edf.png","layers.png":"layers-1dbbe9d028e292f36fcba8f8b3a28d5e8932754fc2215b9ac69e4cdecf5107c6.png","marker-icon-2x.png":"marker-icon-2x-2d77a2e4c2f08bbac41808324ef946b9a2fe61b6150480d011b72b379c3b238d.png","marker-icon.png":"marker-icon-574c3a5cca85f4114085b6841596d62f00d7c892c7b03f28cbfa301deb1dc437.png","marker-shadow.png":"marker-shadow-264f5c640339f042dd729062cfc04c17f8ea0f29882b538e3848ed8f10edb4da.png","tinymce.js":"tinymce-c09e1a38c74241759c70df0385e95b4c46d6cd0342bd271315c2457b25591aad.js","application.css":"application-74c16b3b8c70a0ee2d3bc48bb2acbb9925fc52b1cd41171d7cb5063cd119ba3a.css","jquery-ui/ui-icons_444444_256x240.png":"jquery-ui/ui-icons_444444_256x240-31d988765b4e6f56553c29588c500381dc3e6f0aa2980c8212202e5644aefd5d.png","jquery-ui/ui-icons_555555_256x240.png":"jquery-ui/ui-icons_555555_256x240-32175261daee76c82bb0edf0eea16a56421866fbc31e94f3c1d570aa114502f5.png","jquery-ui/ui-icons_ffffff_256x240.png":"jquery-ui/ui-icons_ffffff_256x240-350df1b7131037de20e83c5c0f3a41a770d2ac48b5762ea772b3f4a8a7b9d47a.png","jquery-ui/ui-icons_777620_256x240.png":"jquery-ui/ui-icons_777620_256x240-0b020fc6e696d88d296e7bb1f61f1eb2ad827848e2c7382a4c3e0999e702dd9b.png","jquery-ui/ui-icons_cc0000_256x240.png":"jquery-ui/ui-icons_cc0000_256x240-40985a64b4d5dd213fba27fcd862a1bd1b337a97674f6ff0b9ec20abcee4bc69.png","jquery-ui/ui-icons_777777_256x240.png":"jquery-ui/ui-icons_777777_256x240-faf32007ae120c302213557626e660dd10e711c5dd4f1113d35f26dc05b78d2f.png","font-awesome/fontawesome-webfont.eot":"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot","font-awesome/fontawesome-webfont.woff2":"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2","font-awesome/fontawesome-webfont.woff":"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff","font-awesome/fontawesome-webfont.ttf":"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf","font-awesome/fontawesome-webfont.svg":"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg","markers-soft.png":"markers-soft-e78784e4ed70aaffddd73c315fab590233cc4e7b72388d7dd47a14796fc7c739.png","markers-shadow.png":"markers-shadow-8703a2262710f5e3d29e65d2acdf90d6512e159e119d27b8234731d8a6208a20.png","markers-soft@2x.png":"markers-soft@2x-c1e77253a8bfbe30cec24885d7046f443b76ebb66f4c961f77083b03f4a5cbaf.png","markers-shadow@2x.png":"markers-shadow@2x-b21a536be27313fb504f69f5899ff0b1245b276571769ac08d6c32c35676e47a.png","france.png":"france-f4341a7ec8331161a9c8d5298f808014c3fc9c799b5a29ed95eb56a7f3ccd0df.png","quebec.png":"quebec-776d563b6a4ac4312cae9f0bfe630c20711346e8dbddd41040998eba79f4b588.png","belgique.png":"belgique-3b8b772a522de2cbae7714b35a956faf2c394419b532a14bba982fed3f341091.png","suisse.png":"suisse-58d067f1c3fcdc4000fa13e95896cd5369a2b91aafd314475aa5e29da0b543d1.png","modernizr.js":"modernizr-654222debe8018b12f1993ceddff30dc163a7d5008d79869c399d6d167321f97.js","agendadescommuns.png":"agendadescommuns-cd40e342024be0587f8e7a0e3902d32cf67009d349b67c00f687e0499fde9ff6.png","alert.png":"alert-762ace9479328243a44061346b64c4d6b997e963c68dfc6bddd9e4d241192906.png","baby_gnu_adl.png":"baby_gnu_adl-232caf355c30740d5d9b30491887cd546b8849b33ca9bdb6cc71f8a47ea61815.png","baby_gnu_adl.svg":"baby_gnu_adl-97251005d3225cf1d58b8c497d6b7905dbc9560cc8acd50118fcce60d0a2679e.svg","communs.png":"communs-cd40e342024be0587f8e7a0e3902d32cf67009d349b67c00f687e0499fde9ff6.png","lef-small.png":"lef-small-160cf5b883add60c9c0f4361bd8425c75f6fb23b0e551a0b941fa0491c70e0c9.png","lef.png":"lef-9fcdd7ddd4d40de29c3809b59688c668b85f5628e219d4cd8a8810b72a64533b.png","priorite-logiciel-libre-je-soutiens-april_2_m.png":"priorite-logiciel-libre-je-soutiens-april_2_m-6442e454e96ed45cc1ebc40673a6c50bd286b9c28ea6a8b58572e94f7d6459fc.png","team.png":"team-cb04c7a311f7160c4eb6a281eae68be84f26991dde5d415bb4e205e6726ae275.png","application.js":"application-5b7e43f757edc035a8a8704a7194315f37d111b86a354effc3df4fd3343fa018.js","markers-matte.png":"markers-matte-497826545a90e09a240504d14530eba45823b19fd44175e09e27c47cd822ddb9.png","markers-matte@2x.png":"markers-matte@2x-948fc8c4426f04f60964ed20394247f45b0b60e575d02398b9b6810e7a29a823.png","markers-plain.png":"markers-plain-cf233423aa44e75ac0031e77b8ba571cd3331010517e1197e63fb7b06856c1ff.png","tinymce/plugins/emoticons/img/smiley-cool.gif":"tinymce/plugins/emoticons/img/smiley-cool-bb0e93a050a32df7913e4026b3c88a176998e0e3e073ba06e9b73f6c24227c9c.gif","tinymce/plugins/emoticons/img/smiley-cry.gif":"tinymce/plugins/emoticons/img/smiley-cry-a0c5f3e7a682449c973c9d9f7c46342081c46920686d2353f57aff91ab907f68.gif","tinymce/plugins/emoticons/img/smiley-embarassed.gif":"tinymce/plugins/emoticons/img/smiley-embarassed-d3cafcb50b335672cb5e9f4600ea9ea261dac7828dd28844d4927c393a25618f.gif","tinymce/plugins/emoticons/img/smiley-foot-in-mouth.gif":"tinymce/plugins/emoticons/img/smiley-foot-in-mouth-03fe04d3ed533423ac81f05146584b0c451be3d4a30e76687ceef283ed07071f.gif","tinymce/plugins/emoticons/img/smiley-frown.gif":"tinymce/plugins/emoticons/img/smiley-frown-1b984bf98931dd1debb54461eb9d83e985f2b2999fe14bcb556d6c0921bc83b0.gif","tinymce/plugins/emoticons/img/smiley-innocent.gif":"tinymce/plugins/emoticons/img/smiley-innocent-8db353ef102196f2c6ddf5c4666446de955d7b14fc0957c806c9dbfb48fb0c29.gif","tinymce/plugins/emoticons/img/smiley-kiss.gif":"tinymce/plugins/emoticons/img/smiley-kiss-3154c3665356c13ab10fefdbac1fe187fff978a0052037c99cdc4a97103413f2.gif","tinymce/plugins/emoticons/img/smiley-laughing.gif":"tinymce/plugins/emoticons/img/smiley-laughing-8f6adedcd091975ffead171867a6304d908bb6541a6ccb4919286ec6b7d4551e.gif","tinymce/plugins/emoticons/img/smiley-money-mouth.gif":"tinymce/plugins/emoticons/img/smiley-money-mouth-f0b9f4f22e237f5dbc851f900fed8d7eca4c954ae6fbc606c0cd8be431d0ac80.gif","tinymce/plugins/emoticons/img/smiley-sealed.gif":"tinymce/plugins/emoticons/img/smiley-sealed-9933b442636b6e537df7b564e2c3f7a2873526eea6b022a98eb1e468e5204c32.gif","tinymce/plugins/emoticons/img/smiley-smile.gif":"tinymce/plugins/emoticons/img/smiley-smile-fd89cd460ffcacb7e725e00c0275ef5b3924ce468248e5ff4fb43545571cfa65.gif","tinymce/plugins/emoticons/img/smiley-surprised.gif":"tinymce/plugins/emoticons/img/smiley-surprised-3871f356cb41976d7ae8a5f005e8739e4d014352a8adef9b33f773d81b6e6c01.gif","tinymce/plugins/emoticons/img/smiley-tongue-out.gif":"tinymce/plugins/emoticons/img/smiley-tongue-out-5843c85667a8226dc43be83749fd9fbbc5d20b1577de2b763915d99815d37d47.gif","tinymce/plugins/emoticons/img/smiley-undecided.gif":"tinymce/plugins/emoticons/img/smiley-undecided-d8b9bcbb433951ff3c4ca8dd959ac3844239b98e6d52218833e1485a91f67347.gif","tinymce/plugins/emoticons/img/smiley-wink.gif":"tinymce/plugins/emoticons/img/smiley-wink-2af75ad7b1c08488505513503e34b15f40005e04a2a9568f698f0945d2d8ba1f.gif","tinymce/plugins/emoticons/img/smiley-yell.gif":"tinymce/plugins/emoticons/img/smiley-yell-bba903fbcb46fce8c68b9e01863fd095b3b1d0e6aa72161f3a88d762a5f90a79.gif","tinymce/skins/lightgray/img/anchor.gif":"tinymce/skins/lightgray/img/anchor-2861666fd107d278d4449970615136d06d7f746be9bb19072cf9c8f30e565e1e.gif","tinymce/skins/lightgray/img/loader.gif":"tinymce/skins/lightgray/img/loader-eb7cfd3d959b2e09c170f532e29f8b825f9bc770b2279fde58e595617753e244.gif","tinymce/skins/lightgray/img/object.gif":"tinymce/skins/lightgray/img/object-e6a15e52bc4a17b085073ba8debd4708ead6ae3d4cbeb3880c65cb7afc489777.gif","tinymce/skins/lightgray/img/trans.gif":"tinymce/skins/lightgray/img/trans-9cf020d7c3bba7f5ab10cda54aabef934f906d4f9a3acf99e9e7dc6c98579635.gif","jquery-ui/ui-bg_flat_0_aaaaaa_40x100.png":"jquery-ui/ui-bg_flat_0_aaaaaa_40x100-ae65a7ae22c4c23115948fdeb5c05c9137dbd13ca2d426b3c4c3c4183451e410.png","tinymce/jquery.tinymce.js":"tinymce/jquery.tinymce-275e24af4bf53bfb60f7fef218163106ad0648b8ad384ecfab9b4fd52f48603d.js","tinymce/langs/readme.md":"tinymce/langs/readme-5a8b6a04d57b5c88e3fb7f2a870b8e2d3a48ec03ce6474206c41df78c155b2de.md","tinymce/license.txt":"tinymce/license-5fda611b8191f00121f161a93e7399cdb71789dba923e8ed09b50a1f78d32c5e.txt","tinymce/plugins/advlist/plugin.js":"tinymce/plugins/advlist/plugin-d0bd2b90c1aaf60ddbb048d955f7fbf76e303b5f3227f8e4dc83207548c3fc46.js","tinymce/plugins/anchor/plugin.js":"tinymce/plugins/anchor/plugin-f642e411a2a702256b0069e5baf65ef62d31c34e92e993123aad88e22ee295ce.js","tinymce/plugins/autolink/plugin.js":"tinymce/plugins/autolink/plugin-9d514baa6f3816a43008241db075d724fcb274632fad3db792e87e5feb6c5d0f.js","tinymce/plugins/autoresize/plugin.js":"tinymce/plugins/autoresize/plugin-7cd05d5431f8713c948291ad40ef63eabe44908bd831d5675afacaca296a4d7b.js","tinymce/plugins/autosave/plugin.js":"tinymce/plugins/autosave/plugin-43448ce025b165ed1b509554cadf02cda4ed104ccfae6d0708379f02e981220f.js","tinymce/plugins/bbcode/plugin.js":"tinymce/plugins/bbcode/plugin-dae2432b6477ca1acc3bd6ac7af33c379797c7f2dcf2c82513475d4c234d851d.js","tinymce/plugins/charmap/plugin.js":"tinymce/plugins/charmap/plugin-ee3f9ed5d0135f19975a4609701b4b4546f00ab1afee9b74a38bb3d76ab94eca.js","tinymce/plugins/code/plugin.js":"tinymce/plugins/code/plugin-093b2519070297197c89cabd2b7bf7b7920786fa3ae5b055322fb16d51d113d4.js","tinymce/plugins/codesample/css/prism.css":"tinymce/plugins/codesample/css/prism-1988b66704b4d23e78c6c20c38a6856cbc1f0be96d6d60a3a0b12f4408f1057e.css","tinymce/plugins/codesample/plugin.dev.js":"tinymce/plugins/codesample/plugin.dev.js","tinymce/plugins/codesample/plugin.js":"tinymce/plugins/codesample/plugin-edd0d2e7f821002843d7726182d9a8b1520fcabb753b95ee7956180337be23da.js","tinymce/plugins/colorpicker/plugin.js":"tinymce/plugins/colorpicker/plugin-526e08119d96ecdeeb21c1031cba4b471aba860fbc6ed0f8a010275088c00531.js","tinymce/plugins/contextmenu/plugin.js":"tinymce/plugins/contextmenu/plugin-11ad7a2ff14cc47d12a3dd0170741590335e606b0efaa8dc77837409e54afa0a.js","tinymce/plugins/directionality/plugin.js":"tinymce/plugins/directionality/plugin-6381fb028625726e50977d00f342fa1f60e39dc794e0ea1c7d9feff8846ab9fc.js","tinymce/plugins/emoticons/plugin.js":"tinymce/plugins/emoticons/plugin-75971da62ade77af7e79b3a560c5ad5ac20ee5f88c7ba236e03902777fdec715.js","tinymce/plugins/example/dialog.html":"tinymce/plugins/example/dialog-5c61ad829a494e75c2234019c7941f6dd096ec693cf5a5538c0bf30485097841.html","tinymce/plugins/example/plugin.js":"tinymce/plugins/example/plugin-505b7ee82929e7338700605a4ca63d94dbe6ef2ce2d21104cc01c2adba829868.js","tinymce/plugins/example_dependency/plugin.js":"tinymce/plugins/example_dependency/plugin-9bb52c9d45c0f7e4d67c12f546c68095b2d5284aa84ab3a2c45f1d986f464653.js","tinymce/plugins/fullpage/plugin.js":"tinymce/plugins/fullpage/plugin-6cd62d14e4225c1db1d9008a485143d8e8b7a7c699e2ceec16a8012b44875ef5.js","tinymce/plugins/fullscreen/plugin.js":"tinymce/plugins/fullscreen/plugin-972d5e04901e74c8c657ee88fb3cc245b94aeb005d54adeac00c07a0c5700f7a.js","tinymce/plugins/hr/plugin.js":"tinymce/plugins/hr/plugin-92558948637f4349e0f327350ddebdd225313e582f08aacf6cb5549d03fc9a8b.js","tinymce/plugins/image/plugin.js":"tinymce/plugins/image/plugin-1c01f4fb87c7523d1ae9bfd7018d883601b59c40edc79c552ef39e8374cb9313.js","tinymce/plugins/imagetools/plugin.js":"tinymce/plugins/imagetools/plugin-78f93669c67ad2579caa99f1069d5ac7f5dc97af9be40d7b55c036dbe650574f.js","tinymce/plugins/importcss/plugin.js":"tinymce/plugins/importcss/plugin-5386dd0994914eaf7431876cb0b2d9cf505a8d91c0f8fd739c5166bd21f6376d.js","tinymce/plugins/insertdatetime/plugin.js":"tinymce/plugins/insertdatetime/plugin-923510af4de6343c5ea6b8e679dbaa87d27a7abdaf84ac1f0000ad5722787577.js","tinymce/plugins/layer/plugin.js":"tinymce/plugins/layer/plugin.js","tinymce/plugins/legacyoutput/plugin.js":"tinymce/plugins/legacyoutput/plugin-ac8239571ea6699f14a76058ea9e53a2a5d9b7e84bed3446d7bd4137b8cdac9f.js","tinymce/plugins/link/plugin.js":"tinymce/plugins/link/plugin-e38346a4005bc814b0117a2dae6eb04ea9a7a8865d658afce406a8394fec0577.js","tinymce/plugins/lists/plugin.js":"tinymce/plugins/lists/plugin-c56f1732e8069ebaca97437c3b99a69ed2663f558cd50a817ee721661673510c.js","tinymce/plugins/media/plugin.js":"tinymce/plugins/media/plugin-f5341fd5503efcd25c050b419868be59073ba2e0bf58bf7a73877c052109e0de.js","tinymce/plugins/nonbreaking/plugin.js":"tinymce/plugins/nonbreaking/plugin-4b15567cb04f551924ca87994514a09fef17c2c6ea3bb6d50e8ca65dc3243b93.js","tinymce/plugins/noneditable/plugin.js":"tinymce/plugins/noneditable/plugin-245b5d236dfea414326bdbcd601333f54d5c2b30a0133cbcbbbae329306b0df3.js","tinymce/plugins/pagebreak/plugin.js":"tinymce/plugins/pagebreak/plugin-4c8f35adfd6fb570639318219a4d2ad0e8850619f37ff322ad101683ec00829a.js","tinymce/plugins/paste/plugin.dev.js":"tinymce/plugins/paste/plugin.dev.js","tinymce/plugins/paste/plugin.js":"tinymce/plugins/paste/plugin-524c40b866f13bbb8fea23d9b8529d00df10b94695e646bd4303eaff9f658e7c.js","tinymce/plugins/preview/plugin.js":"tinymce/plugins/preview/plugin-d0b7e78697d7a21e237e170bbb0a9c95c40b8dc0118a5ccb6a8347eba1800ade.js","tinymce/plugins/print/plugin.js":"tinymce/plugins/print/plugin-07acb7cbdb293f598245755b4a5a142b9d7b78f6b7a6268e3a447b8941f64472.js","tinymce/plugins/save/plugin.js":"tinymce/plugins/save/plugin-ef4b15573e862995e82aadd8ede1117ee36a05b335a74640804e24dbca5ebac1.js","tinymce/plugins/searchreplace/plugin.js":"tinymce/plugins/searchreplace/plugin-e1f614dbe20b45955a82405a9aa38c415ab49288d74d0daf881db666eb5549c6.js","tinymce/plugins/spellchecker/plugin.dev.js":"tinymce/plugins/spellchecker/plugin.dev.js","tinymce/plugins/spellchecker/plugin.js":"tinymce/plugins/spellchecker/plugin-8c198efb4ebcd3ae3f53b2906bed0265f883bd3fca5f8a30880aac630f4eb787.js","tinymce/plugins/tabfocus/plugin.js":"tinymce/plugins/tabfocus/plugin-4b947a94b9cc31d699fed7bb19d2efd9b62fbbd75f0858040bca4ba6402113a0.js","tinymce/plugins/table/plugin.dev.js":"tinymce/plugins/table/plugin.dev.js","tinymce/plugins/table/plugin.js":"tinymce/plugins/table/plugin-58e9f99c4c09431f853051ab6a87504487a9042e520c68e84d9adc59346659a6.js","tinymce/plugins/template/plugin.js":"tinymce/plugins/template/plugin-3a7a1a203ced83abdb7f36897c974eed07a876be4f54809e06ad5b17ec957222.js","tinymce/plugins/textcolor/plugin.js":"tinymce/plugins/textcolor/plugin-d05a9d9a6fbdcca3f07c45e6ef1ba8913f48c68a68a871343cdce2075c0ef0b6.js","tinymce/plugins/textpattern/plugin.js":"tinymce/plugins/textpattern/plugin-d630f2bc3205e400af41041eb224fe793ae950de5d5f4732f63e36f6819d3f35.js","tinymce/plugins/toc/plugin.js":"tinymce/plugins/toc/plugin-c20dc2987d4fcd8f859871ec0f2988f3c819c373d2fadad8c5b923b9b749d0ef.js","tinymce/plugins/visualblocks/css/visualblocks.css":"tinymce/plugins/visualblocks/css/visualblocks-e44e30ebe30e4d3763425a9ea38b558ff13106b8e16a30a74ae21b4c174b3417.css","tinymce/plugins/visualblocks/plugin.js":"tinymce/plugins/visualblocks/plugin-6cdc811487cbbee106512812da68f1999fcb3db14f99c5cb4a070be578c9bb0a.js","tinymce/plugins/visualchars/plugin.js":"tinymce/plugins/visualchars/plugin-0e8c1d7cba0b1471014fe3359a04ff4d4d981070777cdf31f4d95a732b83581f.js","tinymce/plugins/wordcount/plugin.js":"tinymce/plugins/wordcount/plugin-649a9308c0183e56c3ba78002d7b480ecbba84ff30361c36bcea6ed07ea6be4f.js","tinymce/skins/lightgray/AbsoluteLayout.less":"tinymce/skins/lightgray/AbsoluteLayout.less","tinymce/skins/lightgray/Animations.less":"tinymce/skins/lightgray/Animations.less","tinymce/skins/lightgray/Arrows.less":"tinymce/skins/lightgray/Arrows.less","tinymce/skins/lightgray/Button.less":"tinymce/skins/lightgray/Button.less","tinymce/skins/lightgray/ButtonGroup.less":"tinymce/skins/lightgray/ButtonGroup.less","tinymce/skins/lightgray/Checkbox.less":"tinymce/skins/lightgray/Checkbox.less","tinymce/skins/lightgray/ColorBox.less":"tinymce/skins/lightgray/ColorBox.less","tinymce/skins/lightgray/ColorButton.less":"tinymce/skins/lightgray/ColorButton.less","tinymce/skins/lightgray/ColorPicker.less":"tinymce/skins/lightgray/ColorPicker.less","tinymce/skins/lightgray/ComboBox.less":"tinymce/skins/lightgray/ComboBox.less","tinymce/skins/lightgray/Container.less":"tinymce/skins/lightgray/Container.less","tinymce/skins/lightgray/Content.Inline.less":"tinymce/skins/lightgray/Content.Inline.less","tinymce/skins/lightgray/Content.Objects.less":"tinymce/skins/lightgray/Content.Objects.less","tinymce/skins/lightgray/Content.less":"tinymce/skins/lightgray/Content.less","tinymce/skins/lightgray/CropRect.less":"tinymce/skins/lightgray/CropRect.less","tinymce/skins/lightgray/FieldSet.less":"tinymce/skins/lightgray/FieldSet.less","tinymce/skins/lightgray/FitLayout.less":"tinymce/skins/lightgray/FitLayout.less","tinymce/skins/lightgray/FloatPanel.less":"tinymce/skins/lightgray/FloatPanel.less","tinymce/skins/lightgray/FlowLayout.less":"tinymce/skins/lightgray/FlowLayout.less","tinymce/skins/lightgray/Icons.Ie7.less":"tinymce/skins/lightgray/Icons.Ie7.less","tinymce/skins/lightgray/Icons.less":"tinymce/skins/lightgray/Icons.less","tinymce/skins/lightgray/Iframe.less":"tinymce/skins/lightgray/Iframe.less","tinymce/skins/lightgray/ImagePanel.less":"tinymce/skins/lightgray/ImagePanel.less","tinymce/skins/lightgray/InfoBox.less":"tinymce/skins/lightgray/InfoBox.less","tinymce/skins/lightgray/Label.less":"tinymce/skins/lightgray/Label.less","tinymce/skins/lightgray/ListBox.less":"tinymce/skins/lightgray/ListBox.less","tinymce/skins/lightgray/Menu.less":"tinymce/skins/lightgray/Menu.less","tinymce/skins/lightgray/MenuBar.less":"tinymce/skins/lightgray/MenuBar.less","tinymce/skins/lightgray/MenuButton.less":"tinymce/skins/lightgray/MenuButton.less","tinymce/skins/lightgray/MenuItem.less":"tinymce/skins/lightgray/MenuItem.less","tinymce/skins/lightgray/Mixins.less":"tinymce/skins/lightgray/Mixins.less","tinymce/skins/lightgray/Notification.less":"tinymce/skins/lightgray/Notification.less","tinymce/skins/lightgray/Panel.less":"tinymce/skins/lightgray/Panel.less","tinymce/skins/lightgray/Path.less":"tinymce/skins/lightgray/Path.less","tinymce/skins/lightgray/Progress.less":"tinymce/skins/lightgray/Progress.less","tinymce/skins/lightgray/Radio.less":"tinymce/skins/lightgray/Radio.less","tinymce/skins/lightgray/Reset.less":"tinymce/skins/lightgray/Reset.less","tinymce/skins/lightgray/ResizeHandle.less":"tinymce/skins/lightgray/ResizeHandle.less","tinymce/skins/lightgray/Scrollable.less":"tinymce/skins/lightgray/Scrollable.less","tinymce/skins/lightgray/SelectBox.less":"tinymce/skins/lightgray/SelectBox.less","tinymce/skins/lightgray/Sidebar.less":"tinymce/skins/lightgray/Sidebar.less","tinymce/skins/lightgray/Slider.less":"tinymce/skins/lightgray/Slider.less","tinymce/skins/lightgray/Spacer.less":"tinymce/skins/lightgray/Spacer.less","tinymce/skins/lightgray/SplitButton.less":"tinymce/skins/lightgray/SplitButton.less","tinymce/skins/lightgray/StackLayout.less":"tinymce/skins/lightgray/StackLayout.less","tinymce/skins/lightgray/TabPanel.less":"tinymce/skins/lightgray/TabPanel.less","tinymce/skins/lightgray/TextBox.less":"tinymce/skins/lightgray/TextBox.less","tinymce/skins/lightgray/Throbber.less":"tinymce/skins/lightgray/Throbber.less","tinymce/skins/lightgray/TinyMCE.less":"tinymce/skins/lightgray/TinyMCE.less","tinymce/skins/lightgray/ToolTip.less":"tinymce/skins/lightgray/ToolTip.less","tinymce/skins/lightgray/Variables.less":"tinymce/skins/lightgray/Variables.less","tinymce/skins/lightgray/Window.less":"tinymce/skins/lightgray/Window.less","tinymce/skins/lightgray/content.inline.min.css":"tinymce/skins/lightgray/content.inline.min-5bb5c69d072a2d17d11e0c54bc81b6f863e5b5a126060d862970f0c22f5d49ec.css","tinymce/skins/lightgray/content.min.css":"tinymce/skins/lightgray/content.min-92e6da84fb5c2dfcc35f34d311ca1914b19064ada45fa9a08ff2a68c0fc0e657.css","tinymce/skins/lightgray/fonts/tinymce-small.eot":"tinymce/skins/lightgray/fonts/tinymce-small-a10fc4343d95b716c16d77463d475be5c079599ea67e1cd2bd3a94d5e7f508f9.eot","tinymce/skins/lightgray/fonts/tinymce-small.svg":"tinymce/skins/lightgray/fonts/tinymce-small-e7773001446ab937e1d8d4bd5e8dbd9b31d112037353a14b319e36dd010ed8ee.svg","tinymce/skins/lightgray/fonts/tinymce-small.ttf":"tinymce/skins/lightgray/fonts/tinymce-small-2f657502906d6f5c3fc8df3a82969114ebe030addfdc061c60c974b0f515fd09.ttf","tinymce/skins/lightgray/fonts/tinymce-small.woff":"tinymce/skins/lightgray/fonts/tinymce-small-d3efbb678ca6de5632902bd93772746ba2f8e4e2322b953936e12694a183aa31.woff","tinymce/skins/lightgray/fonts/tinymce.eot":"tinymce/skins/lightgray/fonts/tinymce-2e9c4a68fde992476e0db9e44128cb1f2e898f0de0b80f552a8acb52bb7ca0db.eot","tinymce/skins/lightgray/fonts/tinymce.svg":"tinymce/skins/lightgray/fonts/tinymce-2094ddadc265c7f33570475fc78ef7adcdcb814e49060d17f5b4c4f8d1cb7ec6.svg","tinymce/skins/lightgray/fonts/tinymce.ttf":"tinymce/skins/lightgray/fonts/tinymce-477ea2d46c1a975dd492af4c10235fabfd09069595779cce00ea0381ca9b4a20.ttf","tinymce/skins/lightgray/fonts/tinymce.woff":"tinymce/skins/lightgray/fonts/tinymce-1ebc636bb24cbea637946ba8c22cbf4f35d8343ba9763045d2aee59e3714ae78.woff","tinymce/skins/lightgray/skin.dev.less":"tinymce/skins/lightgray/skin.dev.less","tinymce/skins/lightgray/skin.ie7.dev.less":"tinymce/skins/lightgray/skin.ie7.dev.less","tinymce/skins/lightgray/skin.ie7.less":"tinymce/skins/lightgray/skin.ie7.less","tinymce/skins/lightgray/skin.ie7.min.css":"tinymce/skins/lightgray/skin.ie7.min-f7e68049f5f1ba278870818429ef905d07846781701c40657d9d24ca6638cced.css","tinymce/skins/lightgray/skin.less":"tinymce/skins/lightgray/skin.less","tinymce/skins/lightgray/skin.min.css":"tinymce/skins/lightgray/skin.min-6d81e56f6d40695f114abe4db834ccb7bf7d89cfa07c10c2cbaebb8066ace27b.css","tinymce/themes/inlite/theme.js":"tinymce/themes/inlite/theme-a400085213d427d78d8a1e35089ae6cd00831e51d33a3342a198d1bc62851640.js","tinymce/themes/modern/theme.js":"tinymce/themes/modern/theme-f0a3cccc241fa5d46bde8e19160e3f351368881a7c3cdb0c4ce84da11901064c.js","tinymce/tinymce.js":"tinymce/tinymce-d7f6811cb92d1e7638015669d3ec90175d4cb1309ecad56ff9d757b25fe18172.js","tinymce/langs/ar.js":"tinymce/langs/ar-e47a394dbc461d20aa547fa0c2027a9dad45fe55e18adb0da309045be6ed4109.js","tinymce/langs/ar_SA.js":"tinymce/langs/ar_SA-24b62c76e99e114ae44480a67edbacf74f9fed0ff7afbeacce4966f1bc80333b.js","tinymce/langs/az.js":"tinymce/langs/az-d40cecd6eb423f910f528ae98dcdaba4c2449802621759437174cf8c8c0d5b25.js","tinymce/langs/be.js":"tinymce/langs/be-42e2884c0f2394afa1a17e31e702660eeea0d84618bbd18155cb0313c6eb5f69.js","tinymce/langs/bg_BG.js":"tinymce/langs/bg_BG-2fac9d785519d2791d42881fcc08c6a82e841575785690259d7f64e1b88d7db3.js","tinymce/langs/bn_BD.js":"tinymce/langs/bn_BD-ef48a9094445dfa624af0c35902f60b7949b30585b5e9bc760a225fe2c07cbd3.js","tinymce/langs/bs.js":"tinymce/langs/bs-eb66c6d6910a30b950d7a0e784027ed288e6e5a2c6db7741da3359f2067e2e0e.js","tinymce/langs/ca.js":"tinymce/langs/ca-77ab49d6420318ed7f5fd51b6856bc396c393095bd78ea91dad83e38e5859637.js","tinymce/langs/cs.js":"tinymce/langs/cs-3d7ecd619895e3e4c7e1db06f6526682ef88f22f6e8b50d7b45ed0ae7c206714.js","tinymce/langs/cs_CZ.js":"tinymce/langs/cs_CZ-4b0778d233e200dea350f8361129da2844e23d1c0f2d524aeffa6d34e581368d.js","tinymce/langs/cy.js":"tinymce/langs/cy-a847ff54657ccf76eec362cc14fbc63adb4c67f9b1de023b29d817aba4fec062.js","tinymce/langs/da.js":"tinymce/langs/da-a87f3ae1c442c3bb26b81569687e98072d038269360361ec9728f00d6b17c282.js","tinymce/langs/de.js":"tinymce/langs/de-a10c8f6f1e53da776e7026dffd54ea8ba527492b767e5b54ae5c3974f6953311.js","tinymce/langs/de_AT.js":"tinymce/langs/de_AT-a32eec12ce12b06fc2c8919d2372242e9596712c96dc9bcfff1fc8b7dc458627.js","tinymce/langs/dv.js":"tinymce/langs/dv-182756bf33409a8b76bc684d0a2ab86881718c360d1f1fb3fbc609ce3f5e3f49.js","tinymce/langs/el.js":"tinymce/langs/el-6bbdbf3ccb2b2f22f961eb6749b43fe401c84fd6d89cd3f76a538dc2d06bb071.js","tinymce/langs/en_CA.js":"tinymce/langs/en_CA-1a9457da814b0a1f15687a00f3ae4b38da0301445b52c29a423a38c943d9a431.js","tinymce/langs/en_GB.js":"tinymce/langs/en_GB-a0f7752ff9ddf3ed3d2cd24fee04fe585bca0babc4ce655560c923ad386c0c07.js","tinymce/langs/eo.js":"tinymce/langs/eo-cbac4d7ebcb0679845b852d9354e74586e78cf13eef82de1400cf6b465e203cd.js","tinymce/langs/es.js":"tinymce/langs/es-133cb5bd627c2a299544586bf365859b5a1c96c57d18c90e7853048434a809b6.js","tinymce/langs/es_MX.js":"tinymce/langs/es_MX-352fcdff567919ff09a2e19c56d8059d339bffdbd999bcc82aa6d8340c19bbb9.js","tinymce/langs/et.js":"tinymce/langs/et-2cfc3da0ff39a37f0bd3c896d49604028f231ff0e7d8ebbc30dbfd4b87125f06.js","tinymce/langs/eu.js":"tinymce/langs/eu-8698ae4de236fcd490d0f45d485dbd33d8e9de6eb3db51191e1b4f8ea96a4d06.js","tinymce/langs/fa.js":"tinymce/langs/fa-7eff96595e93d4b0df484dd90c14b7b412966157ed8293f54429e9418882bdb2.js","tinymce/langs/fa_IR.js":"tinymce/langs/fa_IR-2f9d33f16718ae9c1f3642905b58434ed2662fb66448c4d115b8491aa68e7904.js","tinymce/langs/fi.js":"tinymce/langs/fi-6ca2a93d045067a86e8ea973d0b89368054b15eb9b9625bf1ca871608a5cb77c.js","tinymce/langs/fo.js":"tinymce/langs/fo-340609cecd5571e4eacb8fe7bd1343c8553d96d12610fb77d9a812dc6d3635fd.js","tinymce/langs/fr_CH.js":"tinymce/langs/fr_CH-e0f43c0f20727368ff0767f3bf099bc23eed9fe3e81f8bbe514381e786526928.js","tinymce/langs/fr_FR.js":"tinymce/langs/fr_FR-2702de7be93bd1e0d7120ae3c9e637061565186c66886f155ffca0663df25b4c.js","tinymce/langs/ga.js":"tinymce/langs/ga-d2a3de6f28723d75b03f7f42fd3aedfd045d473425ee38f02350b56035383af1.js","tinymce/langs/gd.js":"tinymce/langs/gd-0453e8b97bf3b6cca4065712ec59f20343ad6131735b38547e865177a1c1c490.js","tinymce/langs/gl.js":"tinymce/langs/gl-1ff612222934f558870111f10934110c5656df3bb293c917e4eeceeb6605fcc5.js","tinymce/langs/he_IL.js":"tinymce/langs/he_IL-981f5250a4b8d404b37040ca5a35c30498cbeeb36e298d81bf1592b43fff7656.js","tinymce/langs/hi_IN.js":"tinymce/langs/hi_IN-695e0cdc22974fe45e0f35289f0249ddab87245165c9df765ec1b885ec55f0be.js","tinymce/langs/hr.js":"tinymce/langs/hr-f77f1da2736d13f9a9a86ebf596f592fcc748f2975a0b9904b512d630f2c1a17.js","tinymce/langs/hu_HU.js":"tinymce/langs/hu_HU-1e22021a4f9c61919aa024041af555eac277bfc08ccb8c07fd329b87090a15e5.js","tinymce/langs/hy.js":"tinymce/langs/hy-0d384f3f82cd76793d3e7428a2140ea97f40a943f25ef99a2e3709a3e02b0930.js","tinymce/langs/id.js":"tinymce/langs/id-e9fd018be745b5f14f4af47887420f98c590c607e01d57aca77ef5affe188523.js","tinymce/langs/is_IS.js":"tinymce/langs/is_IS-c6e8c3e7b0e6b447faec3d8d258928f97c84558b29882c056513fb71cf237bfa.js","tinymce/langs/it.js":"tinymce/langs/it-25b5546d48c80ad666b600e5be3a05718b80645721b191785c1fafe1853f4a46.js","tinymce/langs/ja.js":"tinymce/langs/ja-80f0e7414030c32617ff651da1affa0bc85ee514fc9bc81f46edfd8ce0053ac0.js","tinymce/langs/ka_GE.js":"tinymce/langs/ka_GE-3c6b82346a7070a8b6a15ae6e8faeecc5bfe63ad7e616b7de2e8ab8a75ec39c2.js","tinymce/langs/kab.js":"tinymce/langs/kab-3651d08aacd5bda15a04698f202bf616efbf13d3789aadd9ce4f93e430818c13.js","tinymce/langs/kk.js":"tinymce/langs/kk-0c1ba792ed9445c6512f310228f64d1cde7b5a98e0b212cca749dcb2d728fe86.js","tinymce/langs/km_KH.js":"tinymce/langs/km_KH-8bec84e4078db8c2a680260c073dfb486c85b61df62e14ca330d66d2ca2a85b5.js","tinymce/langs/ko.js":"tinymce/langs/ko-ca535bfa388701fb020d24bdfb3f1e3aab127005b54e943cb1bd60b723c8194d.js","tinymce/langs/ko_KR.js":"tinymce/langs/ko_KR-daa3ae950d70260bb0901a5349034952247905523bbc2bcbe527701b6aad8e28.js","tinymce/langs/ku.js":"tinymce/langs/ku-95e2ffe4f0112df658f10327c26f2cdddedc2e2ed769767366ae22a465c14725.js","tinymce/langs/ku_IQ.js":"tinymce/langs/ku_IQ-a212e8d41695989e56834facf72474e1934ef166c3fcaf7e255ef573a3c6e76c.js","tinymce/langs/lb.js":"tinymce/langs/lb-94992279091f1a0be927d5d858d3724037d8d81ee6b63cc9ddde84af6124cc04.js","tinymce/langs/lt.js":"tinymce/langs/lt-ae7cefbe2cb5420770b31eabf92605728135ab5d6a2d2cfca2d19809be67e6a8.js","tinymce/langs/lv.js":"tinymce/langs/lv-e468ed0c78466d1fff9f4957645606d8aa683cb5dc35931e047df97b8e4f5433.js","tinymce/langs/mk_MK.js":"tinymce/langs/mk_MK-55aadb5d7c82c940cfcf42f24423ef0471294c9b02994a6b22e1b4173baa7ec6.js","tinymce/langs/ml.js":"tinymce/langs/ml-685de0808683c02274dcbe9f8de023a4d72a49b040e7526a99e3d5c786ff71ae.js","tinymce/langs/ml_IN.js":"tinymce/langs/ml_IN-1ab433621d6257c7632718048bacc5ed98a302d33cf0438bbbb4200914e01aac.js","tinymce/langs/mn_MN.js":"tinymce/langs/mn_MN-b89f88cb9b0dd7c879e27532b2979c421c1e69648f65a4108a56060f1e1cb009.js","tinymce/langs/nb_NO.js":"tinymce/langs/nb_NO-602ee249e98a26ae24c1ee1311090c68a782050086a835f1e7bd46ebfe7879ef.js","tinymce/langs/nl.js":"tinymce/langs/nl-9c77e9404a27fd7e4bd162ad44538b72d2725b7fee7be7ca3ff801cf217c4968.js","tinymce/langs/pl.js":"tinymce/langs/pl-5cdd1586ec8fa67293f2175cd92edbd0392c4c77b24ed64cfdceccba8d99f152.js","tinymce/langs/pt_BR.js":"tinymce/langs/pt_BR-e3955318582d58bd241a62c3a81afe74e0ae7f31bdc92a562b75243701f114df.js","tinymce/langs/pt_PT.js":"tinymce/langs/pt_PT-1101d080ecd5da091c7ef70b23200adbd5136c5c32f0c79dae665a443d76c35d.js","tinymce/langs/ro.js":"tinymce/langs/ro-484799d182031efab087d749b024014fd06ed06c1e7712b8bf87f3a4a965c2e4.js","tinymce/langs/ru.js":"tinymce/langs/ru-bdd59cb662a7b4d61e770b07014d1791051312c87513ecc1891e80beba617171.js","tinymce/langs/ru_RU.js":"tinymce/langs/ru_RU-9f18ef14f3493cc586cc0b4827fd9e1c2ed3d5790ce536d94f87e2d6aac2a688.js","tinymce/langs/si_LK.js":"tinymce/langs/si_LK-5bfefe9b2fe82574d8ed839df18fd8ff65f1e1cd458b0a843cf1aadd1be704ea.js","tinymce/langs/sk.js":"tinymce/langs/sk-412fa7f982ad2733341203daa035c8ba10035262ca8f5f65e0a41507512209bd.js","tinymce/langs/sl_SI.js":"tinymce/langs/sl_SI-2bea4f3854a992ea840808019dc99467dc173b12454ea6016135234a741671d8.js","tinymce/langs/sr.js":"tinymce/langs/sr-e0b97453a0c1000b19f7ce37fcf86bcacbf9125d81076f60a77686820c7925c6.js","tinymce/langs/sv_SE.js":"tinymce/langs/sv_SE-fa561a7e49fdb42d5913337176fed6bc8a9997eb3ca8f20ecd9520d5391e17be.js","tinymce/langs/ta.js":"tinymce/langs/ta-0fd0e62250fc1a3626ac2111c5adb4194a6a898888bb224414f6dc8adf53d385.js","tinymce/langs/ta_IN.js":"tinymce/langs/ta_IN-32303f65d2378e8202b17b0920b79277a2580872e3a6bd9409aeceef90867dd0.js","tinymce/langs/tg.js":"tinymce/langs/tg-1618248bf0aeda614a37ced9fd28b6623ae24f8453368bfb8c483ce820a3cb34.js","tinymce/langs/th_TH.js":"tinymce/langs/th_TH-5279a379afc886c2a31e22aba9d7ee7a8e3edf4c0785f39aaa20ccd03d46b19a.js","tinymce/langs/tr.js":"tinymce/langs/tr-3765d4a8923ef22864747d9c825c3e0af401e1356e75a5458bed837d486b7673.js","tinymce/langs/tr_TR.js":"tinymce/langs/tr_TR-5c93f80b89e5dd2eb6972f37bf50b76d7705c61f28120b836704a91fa5c14399.js","tinymce/langs/tt.js":"tinymce/langs/tt-22e302672df0a77de14688f58dbedf82de7a26e9089c9535a2a3cd1c0ccd7903.js","tinymce/langs/ug.js":"tinymce/langs/ug-50232038bf7262c90be4f2919c74ff93792cdb82e6064d0f5c86f885b93271c5.js","tinymce/langs/uk.js":"tinymce/langs/uk-f6d7911714c422b178c0249df323cf7ec415a83195d751c7e4024590b1738c42.js","tinymce/langs/uk_UA.js":"tinymce/langs/uk_UA-bd8cd7ca66228d85f8a4cadb651c49981f26e007fa2a952856c8c3d3c1baa66a.js","tinymce/langs/vi.js":"tinymce/langs/vi-6aa451047e4df911c92e10178e6a70147534e438c64df7a88eee37b4a440726e.js","tinymce/langs/vi_VN.js":"tinymce/langs/vi_VN-aea52c2e9397f8a657d54d50a42b3c5be0ca79480555a4fa1e0f5d785c5f6561.js","tinymce/langs/zh_CN.js":"tinymce/langs/zh_CN-8622ec46e2980b6f5baf3b745c6b0187dd2a54ddecbbf69a21f0b3e72f84f6dc.js","tinymce/langs/zh_TW.js":"tinymce/langs/zh_TW-90723da3b889f2a4477d4aaf00ca3e75439998269b36b359ea4caa37e1defb4a.js","leaflet/dist/images/layers.png":"leaflet/dist/images/layers-1dbbe9d028e292f36fcba8f8b3a28d5e8932754fc2215b9ac69e4cdecf5107c6.png","leaflet/dist/images/layers-2x.png":"leaflet/dist/images/layers-2x-066daca850d8ffbef007af00b06eac0015728dee279c51f3cb6c716df7c42edf.png","leaflet/dist/images/marker-icon.png":"leaflet/dist/images/marker-icon-574c3a5cca85f4114085b6841596d62f00d7c892c7b03f28cbfa301deb1dc437.png","leaflet/dist/images/marker-icon-2x.png":"leaflet/dist/images/marker-icon-2x-2d77a2e4c2f08bbac41808324ef946b9a2fe61b6150480d011b72b379c3b238d.png","leaflet/dist/images/marker-shadow.png":"leaflet/dist/images/marker-shadow-264f5c640339f042dd729062cfc04c17f8ea0f29882b538e3848ed8f10edb4da.png","tinymce/preinit.js":"tinymce/preinit-4eb7f4ac58f2f450d20185cf83ca1d8550d2a1419141bfe70eb5a2c4afe67349.js","brasil.png":"brasil-0e293d8c9a86f8a98fea23013e9c365b32fd0022a1496309eeabcd97f7be1288.png"}}
\ No newline at end of file
+{"files":{"active_admin-1a6505fe97404d4518ab3540e631c4ba837fd413398b4e75ad4abbcd110398f3.css":{"logical_path":"active_admin.css","mtime":"2016-12-10T11:36:51+01:00","size":78849,"digest":"1a6505fe97404d4518ab3540e631c4ba837fd413398b4e75ad4abbcd110398f3","integrity":"sha256-GmUF/pdATUUYqzVA5jHEuoN/1BM5i051rUq7zREDmPM="},"active_admin/nested_menu_arrow-15084d93c65c1964d7077700ea748bd2d70cfa2d4c19707c58a9c64e232dd442.gif":{"logical_path":"active_admin/nested_menu_arrow.gif","mtime":"2017-05-04T21:49:46+02:00","size":70,"digest":"15084d93c65c1964d7077700ea748bd2d70cfa2d4c19707c58a9c64e232dd442","integrity":"sha256-FQhNk8ZcGWTXB3cA6nSL0tcM+i1MGXB8WKnGTiMt1EI="},"active_admin/nested_menu_arrow_dark-7c43b8e0a5f8823875f49a093c9d7a6b374f885b6f9cc248ae9cd7e6e9b29034.gif":{"logical_path":"active_admin/nested_menu_arrow_dark.gif","mtime":"2017-05-04T21:49:46+02:00","size":70,"digest":"7c43b8e0a5f8823875f49a093c9d7a6b374f885b6f9cc248ae9cd7e6e9b29034","integrity":"sha256-fEO44KX4gjh19JoJPJ16azdPiFtvnMJIrpzX5umykDQ="},"active_admin/datepicker/datepicker-input-icon-d9c2bb73769af777c8a71720d29741f3a499aebd5a043e9a119bd0d9597aed47.png":{"logical_path":"active_admin/datepicker/datepicker-input-icon.png","mtime":"2017-05-04T21:49:46+02:00","size":1535,"digest":"d9c2bb73769af777c8a71720d29741f3a499aebd5a043e9a119bd0d9597aed47","integrity":"sha256-2cK7c3aa93fIpxcg0pdB86SZrr1aBD6aEZvQ2Vl67Uc="},"active_admin/orderable-29374dbb55b0012d78a37c614d573bb3474f0779849b478a147d0f1845ca6617.png":{"logical_path":"active_admin/orderable.png","mtime":"2017-05-04T21:49:46+02:00","size":220,"digest":"29374dbb55b0012d78a37c614d573bb3474f0779849b478a147d0f1845ca6617","integrity":"sha256-KTdNu1WwAS14o3xhTVc7s0dPB3mEm0eKFH0PGEXKZhc="},"active_admin/print-87c5ffc1d869a919123bcc1dc5ec51b20bc79fd9aeab9eed77e3438c6acd4f68.css":{"logical_path":"active_admin/print.css","mtime":"2017-05-04T21:49:46+02:00","size":5494,"digest":"87c5ffc1d869a919123bcc1dc5ec51b20bc79fd9aeab9eed77e3438c6acd4f68","integrity":"sha256-h8X/wdhpqRkSO8wdxexRsgvHn9muq57td+NDjGrNT2g="},"active_admin-5d8dda85fd2e9296c4f9682a0c4441e4dfc6c2779454e8144be78befe3ff05bb.js":{"logical_path":"active_admin.js","mtime":"2017-01-02T09:58:37+01:00","size":692380,"digest":"5d8dda85fd2e9296c4f9682a0c4441e4dfc6c2779454e8144be78befe3ff05bb","integrity":"sha256-XY3ahf0ukpbE+WgqDERB5N/GwneUVOgUS+eL7+P/Bbs="},"layers-2x-0c02a2388f637d21f86e6d4b314ec9a968e7b05ad4c3a005280a3f76c0fd3cb8.png":{"logical_path":"layers-2x.png","mtime":"2016-10-29T16:45:43+02:00","size":2898,"digest":"0c02a2388f637d21f86e6d4b314ec9a968e7b05ad4c3a005280a3f76c0fd3cb8","integrity":"sha256-DAKiOI9jfSH4bm1LMU7JqWjnsFrUw6AFKAo/dsD9PLg="},"layers-0908aa2a72a082fb2563a2427a5e4fb247571862b448b80fb6f720af1109923e.png":{"logical_path":"layers.png","mtime":"2016-10-29T16:45:43+02:00","size":1502,"digest":"0908aa2a72a082fb2563a2427a5e4fb247571862b448b80fb6f720af1109923e","integrity":"sha256-CQiqKnKggvslY6JCel5PskdXGGK0SLgPtvcgrxEJkj4="},"marker-icon-2x-454dc479e82b487529b6b93d6a9b29ac69ca7b4f5a9d5fdf8e01871f6d216113.png":{"logical_path":"marker-icon-2x.png","mtime":"2016-10-29T16:45:43+02:00","size":4033,"digest":"454dc479e82b487529b6b93d6a9b29ac69ca7b4f5a9d5fdf8e01871f6d216113","integrity":"sha256-RU3EeegrSHUptrk9apsprGnKe09anV/fjgGHH20hYRM="},"marker-icon-915e83a6fc798c599e5c9e3f759d6bc065d65151019acd0410d1f4731bcaaf72.png":{"logical_path":"marker-icon.png","mtime":"2016-10-29T16:45:43+02:00","size":1747,"digest":"915e83a6fc798c599e5c9e3f759d6bc065d65151019acd0410d1f4731bcaaf72","integrity":"sha256-kV6Dpvx5jFmeXJ4/dZ1rwGXWUVEBms0EENH0cxvKr3I="},"marker-shadow-4f340d2d61746333dffe056e074ce1704ae4e47fec5a7de98322fbdbcfcb2b6d.png":{"logical_path":"marker-shadow.png","mtime":"2016-10-29T16:45:43+02:00","size":797,"digest":"4f340d2d61746333dffe056e074ce1704ae4e47fec5a7de98322fbdbcfcb2b6d","integrity":"sha256-TzQNLWF0YzPf/gVuB0zhcErk5H/sWn3pgyL728/LK20="},"tinymce-e760fd8b6f08323d2b85a1a7a149a483d75d4bf23628ffb9340280f59b2d359d.js":{"logical_path":"tinymce.js","mtime":"2016-12-17T16:47:53+01:00","size":971,"digest":"e760fd8b6f08323d2b85a1a7a149a483d75d4bf23628ffb9340280f59b2d359d","integrity":"sha256-52D9i28IMj0rhaGnoUmkg9ddS/I2KP+5NAKA9ZstNZ0="},"application-943a3e70ac370e883a0394cbddf7c60a6ec281cd561d3c6817cfa97974531bc8.css":{"logical_path":"application.css","mtime":"2016-12-17T16:47:53+01:00","size":170905,"digest":"943a3e70ac370e883a0394cbddf7c60a6ec281cd561d3c6817cfa97974531bc8","integrity":"sha256-lDo+cKw3Dog6A5TL3ffGCm7Cgc1WHTxoF8+peXRTG8g="},"jquery-ui/ui-icons_444444_256x240-31d988765b4e6f56553c29588c500381dc3e6f0aa2980c8212202e5644aefd5d.png":{"logical_path":"jquery-ui/ui-icons_444444_256x240.png","mtime":"2017-04-24T19:17:54+02:00","size":3756,"digest":"31d988765b4e6f56553c29588c500381dc3e6f0aa2980c8212202e5644aefd5d","integrity":"sha256-MdmIdltOb1ZVPClYjFADgdw+bwqimAyCEiAuVkSu/V0="},"jquery-ui/ui-icons_555555_256x240-32175261daee76c82bb0edf0eea16a56421866fbc31e94f3c1d570aa114502f5.png":{"logical_path":"jquery-ui/ui-icons_555555_256x240.png","mtime":"2017-04-24T19:17:54+02:00","size":3756,"digest":"32175261daee76c82bb0edf0eea16a56421866fbc31e94f3c1d570aa114502f5","integrity":"sha256-MhdSYdrudsgrsO3w7qFqVkIYZvvDHpTzwdVwqhFFAvU="},"jquery-ui/ui-icons_ffffff_256x240-350df1b7131037de20e83c5c0f3a41a770d2ac48b5762ea772b3f4a8a7b9d47a.png":{"logical_path":"jquery-ui/ui-icons_ffffff_256x240.png","mtime":"2017-04-24T19:17:54+02:00","size":3756,"digest":"350df1b7131037de20e83c5c0f3a41a770d2ac48b5762ea772b3f4a8a7b9d47a","integrity":"sha256-NQ3xtxMQN94g6DxcDzpBp3DSrEi1di6ncrP0qKe51Ho="},"jquery-ui/ui-icons_777620_256x240-0b020fc6e696d88d296e7bb1f61f1eb2ad827848e2c7382a4c3e0999e702dd9b.png":{"logical_path":"jquery-ui/ui-icons_777620_256x240.png","mtime":"2017-04-24T19:17:54+02:00","size":3756,"digest":"0b020fc6e696d88d296e7bb1f61f1eb2ad827848e2c7382a4c3e0999e702dd9b","integrity":"sha256-CwIPxuaW2I0pbnux9h8esq2CeEjixzgqTD4JmecC3Zs="},"jquery-ui/ui-icons_cc0000_256x240-40985a64b4d5dd213fba27fcd862a1bd1b337a97674f6ff0b9ec20abcee4bc69.png":{"logical_path":"jquery-ui/ui-icons_cc0000_256x240.png","mtime":"2017-04-24T19:17:54+02:00","size":3756,"digest":"40985a64b4d5dd213fba27fcd862a1bd1b337a97674f6ff0b9ec20abcee4bc69","integrity":"sha256-QJhaZLTV3SE/uif82GKhvRszepdnT2/wuewgq87kvGk="},"jquery-ui/ui-icons_777777_256x240-faf32007ae120c302213557626e660dd10e711c5dd4f1113d35f26dc05b78d2f.png":{"logical_path":"jquery-ui/ui-icons_777777_256x240.png","mtime":"2017-04-24T19:17:54+02:00","size":3756,"digest":"faf32007ae120c302213557626e660dd10e711c5dd4f1113d35f26dc05b78d2f","integrity":"sha256-+vMgB64SDDAiE1V2JuZg3RDnEcXdTxET018m3AW3jS8="},"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot":{"logical_path":"font-awesome/fontawesome-webfont.eot","mtime":"2017-04-24T19:17:40+02:00","size":165742,"digest":"7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979","integrity":"sha256-e/yrbbmdXPvxcFygU23ceFhUMsxfpBu9etDwCQM7KXk="},"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2":{"logical_path":"font-awesome/fontawesome-webfont.woff2","mtime":"2017-04-24T19:17:40+02:00","size":77160,"digest":"2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe","integrity":"sha256-Kt78vAQefRj88tQXh53FoJmXqmTWdbejxLbOM9oT8/4="},"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff":{"logical_path":"font-awesome/fontawesome-webfont.woff","mtime":"2017-04-24T19:17:40+02:00","size":98024,"digest":"ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07","integrity":"sha256-ugxZ3rVFD1y0Gz+TYJ7i0NmVQVh33foiPoqKdTNHTwc="},"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf":{"logical_path":"font-awesome/fontawesome-webfont.ttf","mtime":"2017-04-24T19:17:40+02:00","size":165548,"digest":"aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8","integrity":"sha256-qljzPyOaD7AvXHpsRcBD16msmgkzNYBmlOzW1O3A1qg="},"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg":{"logical_path":"font-awesome/fontawesome-webfont.svg","mtime":"2017-04-24T19:17:40+02:00","size":444379,"digest":"ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4","integrity":"sha256-rWFXkmwWIrpOHQPUePFUE2hSS/xG9R5C/g2UX37zI+Q="},"markers-soft-e78784e4ed70aaffddd73c315fab590233cc4e7b72388d7dd47a14796fc7c739.png":{"logical_path":"markers-soft.png","mtime":"2016-05-21T23:41:15+02:00","size":41226,"digest":"e78784e4ed70aaffddd73c315fab590233cc4e7b72388d7dd47a14796fc7c739","integrity":"sha256-54eE5O1wqv/d1zwxX6tZAjPMTntyOI191HoUeW/Hxzk="},"markers-shadow-8703a2262710f5e3d29e65d2acdf90d6512e159e119d27b8234731d8a6208a20.png":{"logical_path":"markers-shadow.png","mtime":"2016-05-21T23:41:15+02:00","size":535,"digest":"8703a2262710f5e3d29e65d2acdf90d6512e159e119d27b8234731d8a6208a20","integrity":"sha256-hwOiJicQ9ePSnmXSrN+Q1lEuFZ4RnSe4I0cx2KYgiiA="},"markers-soft@2x-c1e77253a8bfbe30cec24885d7046f443b76ebb66f4c961f77083b03f4a5cbaf.png":{"logical_path":"markers-soft@2x.png","mtime":"2016-05-21T23:41:15+02:00","size":66408,"digest":"c1e77253a8bfbe30cec24885d7046f443b76ebb66f4c961f77083b03f4a5cbaf","integrity":"sha256-wedyU6i/vjDOwkiF1wRvRDt267ZvTJYfdwg7A/Sly68="},"markers-shadow@2x-b21a536be27313fb504f69f5899ff0b1245b276571769ac08d6c32c35676e47a.png":{"logical_path":"markers-shadow@2x.png","mtime":"2016-05-21T23:41:15+02:00","size":1469,"digest":"b21a536be27313fb504f69f5899ff0b1245b276571769ac08d6c32c35676e47a","integrity":"sha256-shpTa+JzE/tQT2n1iZ/wsSRbJ2VxdprAjWwyw1Z25Ho="},"france-f4341a7ec8331161a9c8d5298f808014c3fc9c799b5a29ed95eb56a7f3ccd0df.png":{"logical_path":"france.png","mtime":"2014-07-04T14:08:56+02:00","size":276,"digest":"f4341a7ec8331161a9c8d5298f808014c3fc9c799b5a29ed95eb56a7f3ccd0df","integrity":"sha256-9DQafsgzEWGpyNUpj4CAFMP8nHmbWintletWp/PM0N8="},"quebec-776d563b6a4ac4312cae9f0bfe630c20711346e8dbddd41040998eba79f4b588.png":{"logical_path":"quebec.png","mtime":"2015-10-22T22:54:30+02:00","size":567,"digest":"776d563b6a4ac4312cae9f0bfe630c20711346e8dbddd41040998eba79f4b588","integrity":"sha256-d21WO2pKxDEsrp8L/mMMIHETRujb3dQQQJmOunn0tYg="},"belgique-3b8b772a522de2cbae7714b35a956faf2c394419b532a14bba982fed3f341091.png":{"logical_path":"belgique.png","mtime":"2014-07-04T14:08:56+02:00","size":187,"digest":"3b8b772a522de2cbae7714b35a956faf2c394419b532a14bba982fed3f341091","integrity":"sha256-O4t3KlIt4suudxSzWpVvryw5RBm1MqFLupgv7T80EJE="},"suisse-58d067f1c3fcdc4000fa13e95896cd5369a2b91aafd314475aa5e29da0b543d1.png":{"logical_path":"suisse.png","mtime":"2015-10-22T22:54:30+02:00","size":299,"digest":"58d067f1c3fcdc4000fa13e95896cd5369a2b91aafd314475aa5e29da0b543d1","integrity":"sha256-WNBn8cP83EAA+hPpWJbNU2miuRqv0xRHWqXinaC1Q9E="},"modernizr-654222debe8018b12f1993ceddff30dc163a7d5008d79869c399d6d167321f97.js":{"logical_path":"modernizr.js","mtime":"2017-04-24T19:16:49+02:00","size":51365,"digest":"654222debe8018b12f1993ceddff30dc163a7d5008d79869c399d6d167321f97","integrity":"sha256-ZUIi3r6AGLEvGZPO3f8w3BY6fVAI15hpw5nW0WcyH5c="},"agendadescommuns-cd40e342024be0587f8e7a0e3902d32cf67009d349b67c00f687e0499fde9ff6.png":{"logical_path":"agendadescommuns.png","mtime":"2015-10-22T22:54:30+02:00","size":2760,"digest":"cd40e342024be0587f8e7a0e3902d32cf67009d349b67c00f687e0499fde9ff6","integrity":"sha256-zUDjQgJL4Fh/jnoOOQLTLPZwCdNJtnwA9ofgSZ/en/Y="},"alert-762ace9479328243a44061346b64c4d6b997e963c68dfc6bddd9e4d241192906.png":{"logical_path":"alert.png","mtime":"2014-07-04T14:08:56+02:00","size":47876,"digest":"762ace9479328243a44061346b64c4d6b997e963c68dfc6bddd9e4d241192906","integrity":"sha256-dirOlHkygkOkQGE0a2TE1rmX6WPGjfxr3dnk0kEZKQY="},"baby_gnu_adl-232caf355c30740d5d9b30491887cd546b8849b33ca9bdb6cc71f8a47ea61815.png":{"logical_path":"baby_gnu_adl.png","mtime":"2016-09-11T17:42:49+02:00","size":10155,"digest":"232caf355c30740d5d9b30491887cd546b8849b33ca9bdb6cc71f8a47ea61815","integrity":"sha256-IyyvNVwwdA1dmzBJGIfNVGuISbM8qb22zHH4pH6mGBU="},"baby_gnu_adl-97251005d3225cf1d58b8c497d6b7905dbc9560cc8acd50118fcce60d0a2679e.svg":{"logical_path":"baby_gnu_adl.svg","mtime":"2016-09-11T17:42:49+02:00","size":109635,"digest":"97251005d3225cf1d58b8c497d6b7905dbc9560cc8acd50118fcce60d0a2679e","integrity":"sha256-lyUQBdMiXPHVi4xJfWt5BdvJVgzIrNUBGPzOYNCiZ54="},"communs-cd40e342024be0587f8e7a0e3902d32cf67009d349b67c00f687e0499fde9ff6.png":{"logical_path":"communs.png","mtime":"2015-10-22T22:54:30+02:00","size":2760,"digest":"cd40e342024be0587f8e7a0e3902d32cf67009d349b67c00f687e0499fde9ff6","integrity":"sha256-zUDjQgJL4Fh/jnoOOQLTLPZwCdNJtnwA9ofgSZ/en/Y="},"lef-small-160cf5b883add60c9c0f4361bd8425c75f6fb23b0e551a0b941fa0491c70e0c9.png":{"logical_path":"lef-small.png","mtime":"2015-03-29T11:07:15+02:00","size":1089,"digest":"160cf5b883add60c9c0f4361bd8425c75f6fb23b0e551a0b941fa0491c70e0c9","integrity":"sha256-Fgz1uIOt1gycD0NhvYQlx19vsjsOVRoLlB+gSRxw4Mk="},"lef-bec4081a11fbef165216827cf72c7a292ad772a77af6b8132e5bc0bbf83cb2d9.png":{"logical_path":"lef.png","mtime":"2016-01-24T11:38:05+01:00","size":8415,"digest":"bec4081a11fbef165216827cf72c7a292ad772a77af6b8132e5bc0bbf83cb2d9","integrity":"sha256-vsQIGhH77xZSFoJ89yx6KSrXcqd69rgTLlvAu/g8stk="},"priorite-logiciel-libre-je-soutiens-april_2_m-6442e454e96ed45cc1ebc40673a6c50bd286b9c28ea6a8b58572e94f7d6459fc.png":{"logical_path":"priorite-logiciel-libre-je-soutiens-april_2_m.png","mtime":"2015-10-22T22:54:30+02:00","size":16952,"digest":"6442e454e96ed45cc1ebc40673a6c50bd286b9c28ea6a8b58572e94f7d6459fc","integrity":"sha256-ZELkVOlu1FzB68QGc6bFC9KGucKOpqi1hXLpT31kWfw="},"team-cb04c7a311f7160c4eb6a281eae68be84f26991dde5d415bb4e205e6726ae275.png":{"logical_path":"team.png","mtime":"2014-07-04T14:08:56+02:00","size":3586,"digest":"cb04c7a311f7160c4eb6a281eae68be84f26991dde5d415bb4e205e6726ae275","integrity":"sha256-ywTHoxH3FgxOtqKB6uaL6E8mmR3eXUFbtOIF5nJq4nU="},"application-224c876758d567479b1ebc1da354a712a64d27a100fb0ba5b8f1c0ca5188d55c.js":{"logical_path":"application.js","mtime":"2016-12-17T16:47:53+01:00","size":2158066,"digest":"224c876758d567479b1ebc1da354a712a64d27a100fb0ba5b8f1c0ca5188d55c","integrity":"sha256-IkyHZ1jVZ0ebHrwdo1SnEqZNJ6EA+wuluPHAylGI1Vw="},"markers-matte-497826545a90e09a240504d14530eba45823b19fd44175e09e27c47cd822ddb9.png":{"logical_path":"markers-matte.png","mtime":"2016-05-21T23:41:15+02:00","size":14323,"digest":"497826545a90e09a240504d14530eba45823b19fd44175e09e27c47cd822ddb9","integrity":"sha256-SXgmVFqQ4JokBQTRRTDrpFgjsZ/UQXXgnifEfNgi3bk="},"markers-matte@2x-948fc8c4426f04f60964ed20394247f45b0b60e575d02398b9b6810e7a29a823.png":{"logical_path":"markers-matte@2x.png","mtime":"2016-05-21T23:41:15+02:00","size":31113,"digest":"948fc8c4426f04f60964ed20394247f45b0b60e575d02398b9b6810e7a29a823","integrity":"sha256-lI/IxEJvBPYJZO0gOUJH9FsLYOV10COYubaBDnopqCM="},"markers-plain-cf233423aa44e75ac0031e77b8ba571cd3331010517e1197e63fb7b06856c1ff.png":{"logical_path":"markers-plain.png","mtime":"2016-05-21T23:41:15+02:00","size":7946,"digest":"cf233423aa44e75ac0031e77b8ba571cd3331010517e1197e63fb7b06856c1ff","integrity":"sha256-zyM0I6pE51rAAx53uLpXHNMzEBBRfhGX5j+3sGhWwf8="},"jquery-ui/ui-bg_flat_0_aaaaaa_40x100-ae65a7ae22c4c23115948fdeb5c05c9137dbd13ca2d426b3c4c3c4183451e410.png":{"logical_path":"jquery-ui/ui-bg_flat_0_aaaaaa_40x100.png","mtime":"2017-04-24T19:17:54+02:00","size":86,"digest":"ae65a7ae22c4c23115948fdeb5c05c9137dbd13ca2d426b3c4c3c4183451e410","integrity":"sha256-rmWnriLEwjEVlI/etcBckTfb0Tyi1CazxMPEGDRR5BA="},"tinymce-a6d3b77f66eb3e1971dc7bd18d9cefefd2947a846683d2a189a092f94280acf4.js":{"logical_path":"tinymce.js","mtime":"2016-12-17T22:42:28+01:00","size":971,"digest":"a6d3b77f66eb3e1971dc7bd18d9cefefd2947a846683d2a189a092f94280acf4","integrity":"sha256-ptO3f2brPhlx3HvRjZzv79KUeoRmg9KhiaCS+UKArPQ="},"application-6054b0bc1c370f1c7d66e9d0c3d21aa9fa886547e9c7732570440a4f42618a99.css":{"logical_path":"application.css","mtime":"2016-12-17T22:42:28+01:00","size":170862,"digest":"6054b0bc1c370f1c7d66e9d0c3d21aa9fa886547e9c7732570440a4f42618a99","integrity":"sha256-YFSwvBw3Dxx9ZunQw9IaqfqIZUfpx3MlcEQKT0Jhipk="},"application-97155f8afdbec83bd10d2feeaf475014a2d2efa855a16491aa7b922d8c1cbf58.js":{"logical_path":"application.js","mtime":"2016-12-17T22:42:28+01:00","size":2158066,"digest":"97155f8afdbec83bd10d2feeaf475014a2d2efa855a16491aa7b922d8c1cbf58","integrity":"sha256-lxVfiv2+yDvRDS/ur0dQFKLS76hVoWSRqnuSLYwcv1g="},"tinymce-7243549c535fe401a7b69bb597a277ca520491fe82e3f6efb6b800f605ef56fa.js":{"logical_path":"tinymce.js","mtime":"2016-12-17T22:48:39+01:00","size":971,"digest":"7243549c535fe401a7b69bb597a277ca520491fe82e3f6efb6b800f605ef56fa","integrity":"sha256-ckNUnFNf5AGntpu1l6J3ylIEkf6C4/bvtrgA9gXvVvo="},"application-1ea0f88318a587e6ca20994d21c9db4627195434bcc8a52f59e75be21b50f937.css":{"logical_path":"application.css","mtime":"2016-12-17T22:48:39+01:00","size":170862,"digest":"1ea0f88318a587e6ca20994d21c9db4627195434bcc8a52f59e75be21b50f937","integrity":"sha256-HqD4gxilh+bKIJlNIcnbRicZVDS8yKUvWedb4htQ+Tc="},"application-ec97ffd43bcc565dc5aabd8a6e1c3c75b2437f6b27265f56c2fa98eb72866bcd.js":{"logical_path":"application.js","mtime":"2016-12-17T22:48:39+01:00","size":2158066,"digest":"ec97ffd43bcc565dc5aabd8a6e1c3c75b2437f6b27265f56c2fa98eb72866bcd","integrity":"sha256-7Jf/1DvMVl3Fqr2Kbhw8dbJDf2snJl9WwvqY63KGa80="},"layers-2x-066daca850d8ffbef007af00b06eac0015728dee279c51f3cb6c716df7c42edf.png":{"logical_path":"layers-2x.png","mtime":"2017-04-24T19:17:55+02:00","size":1259,"digest":"066daca850d8ffbef007af00b06eac0015728dee279c51f3cb6c716df7c42edf","integrity":"sha256-Bm2sqFDY/77wB68AsG6sABVyje4nnFHzy2xxbffELt8="},"layers-1dbbe9d028e292f36fcba8f8b3a28d5e8932754fc2215b9ac69e4cdecf5107c6.png":{"logical_path":"layers.png","mtime":"2017-04-24T19:17:55+02:00","size":696,"digest":"1dbbe9d028e292f36fcba8f8b3a28d5e8932754fc2215b9ac69e4cdecf5107c6","integrity":"sha256-Hbvp0CjikvNvy6j4s6KNXokydU/CIVuaxp5M3s9RB8Y="},"marker-icon-2x-2d77a2e4c2f08bbac41808324ef946b9a2fe61b6150480d011b72b379c3b238d.png":{"logical_path":"marker-icon-2x.png","mtime":"2017-04-24T19:17:55+02:00","size":2586,"digest":"2d77a2e4c2f08bbac41808324ef946b9a2fe61b6150480d011b72b379c3b238d","integrity":"sha256-LXei5MLwi7rEGAgyTvlGuaL+YbYVBIDQEbcrN5w7I40="},"marker-icon-574c3a5cca85f4114085b6841596d62f00d7c892c7b03f28cbfa301deb1dc437.png":{"logical_path":"marker-icon.png","mtime":"2017-04-24T19:17:55+02:00","size":1466,"digest":"574c3a5cca85f4114085b6841596d62f00d7c892c7b03f28cbfa301deb1dc437","integrity":"sha256-V0w6XMqF9BFAhbaEFZbWLwDXyJLHsD8oy/owHesdxDc="},"marker-shadow-264f5c640339f042dd729062cfc04c17f8ea0f29882b538e3848ed8f10edb4da.png":{"logical_path":"marker-shadow.png","mtime":"2017-04-24T19:17:55+02:00","size":618,"digest":"264f5c640339f042dd729062cfc04c17f8ea0f29882b538e3848ed8f10edb4da","integrity":"sha256-Jk9cZAM58ELdcpBiz8BMF/jqDymIK1OOOEjtjxDttNo="},"tinymce-61f3d9ea006866183d7b56bbc9ecf39545adcc8a1a3b58566ea14ea52db8b902.js":{"logical_path":"tinymce.js","mtime":"2017-01-19T14:51:27+01:00","size":971,"digest":"61f3d9ea006866183d7b56bbc9ecf39545adcc8a1a3b58566ea14ea52db8b902","integrity":"sha256-YfPZ6gBoZhg9e1a7yezzlUWtzIoaO1hWbqFOpS24uQI="},"application-bd35f325ad91254feab551b82972c18f9d928b5016ff20ee040c3380f9c95a7c.css":{"logical_path":"application.css","mtime":"2017-01-19T14:51:27+01:00","size":173942,"digest":"bd35f325ad91254feab551b82972c18f9d928b5016ff20ee040c3380f9c95a7c","integrity":"sha256-vTXzJa2RJU/qtVG4KXLBj52Si1AW/yDuBAwzgPnJWnw="},"leaflet/dist/images/layers-1dbbe9d028e292f36fcba8f8b3a28d5e8932754fc2215b9ac69e4cdecf5107c6.png":{"logical_path":"leaflet/dist/images/layers.png","mtime":"2017-04-24T19:16:54+02:00","size":696,"digest":"1dbbe9d028e292f36fcba8f8b3a28d5e8932754fc2215b9ac69e4cdecf5107c6","integrity":"sha256-Hbvp0CjikvNvy6j4s6KNXokydU/CIVuaxp5M3s9RB8Y="},"leaflet/dist/images/layers-2x-066daca850d8ffbef007af00b06eac0015728dee279c51f3cb6c716df7c42edf.png":{"logical_path":"leaflet/dist/images/layers-2x.png","mtime":"2017-04-24T19:16:54+02:00","size":1259,"digest":"066daca850d8ffbef007af00b06eac0015728dee279c51f3cb6c716df7c42edf","integrity":"sha256-Bm2sqFDY/77wB68AsG6sABVyje4nnFHzy2xxbffELt8="},"leaflet/dist/images/marker-icon-574c3a5cca85f4114085b6841596d62f00d7c892c7b03f28cbfa301deb1dc437.png":{"logical_path":"leaflet/dist/images/marker-icon.png","mtime":"2017-04-24T19:16:54+02:00","size":1466,"digest":"574c3a5cca85f4114085b6841596d62f00d7c892c7b03f28cbfa301deb1dc437","integrity":"sha256-V0w6XMqF9BFAhbaEFZbWLwDXyJLHsD8oy/owHesdxDc="},"application-e76d31e280284497ba66d10672ca0b022ab11b512f1ed51be1b4db85d47330eb.js":{"logical_path":"application.js","mtime":"2017-01-02T09:58:37+01:00","size":2358436,"digest":"e76d31e280284497ba66d10672ca0b022ab11b512f1ed51be1b4db85d47330eb","integrity":"sha256-520x4oAoRJe6ZtEGcsoLAiqxG1EvHtUb4bTbhdRzMOs="},"leaflet/dist/images/marker-icon-2x-2d77a2e4c2f08bbac41808324ef946b9a2fe61b6150480d011b72b379c3b238d.png":{"logical_path":"leaflet/dist/images/marker-icon-2x.png","mtime":"2017-04-24T19:16:54+02:00","size":2586,"digest":"2d77a2e4c2f08bbac41808324ef946b9a2fe61b6150480d011b72b379c3b238d","integrity":"sha256-LXei5MLwi7rEGAgyTvlGuaL+YbYVBIDQEbcrN5w7I40="},"leaflet/dist/images/marker-shadow-264f5c640339f042dd729062cfc04c17f8ea0f29882b538e3848ed8f10edb4da.png":{"logical_path":"leaflet/dist/images/marker-shadow.png","mtime":"2017-04-24T19:16:54+02:00","size":618,"digest":"264f5c640339f042dd729062cfc04c17f8ea0f29882b538e3848ed8f10edb4da","integrity":"sha256-Jk9cZAM58ELdcpBiz8BMF/jqDymIK1OOOEjtjxDttNo="},"tinymce/plugins/emoticons/img/smiley-cool.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-cool.gif","mtime":"2016-12-10T10:15:36+01:00","size":354,"digest":null},"tinymce/plugins/emoticons/img/smiley-cry.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-cry.gif","mtime":"2016-12-10T10:15:36+01:00","size":329,"digest":null},"tinymce/plugins/emoticons/img/smiley-embarassed.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-embarassed.gif","mtime":"2016-12-10T10:15:36+01:00","size":331,"digest":null},"tinymce/plugins/emoticons/img/smiley-foot-in-mouth.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-foot-in-mouth.gif","mtime":"2016-12-10T10:15:36+01:00","size":342,"digest":null},"tinymce/plugins/emoticons/img/smiley-frown.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-frown.gif","mtime":"2016-12-10T10:15:36+01:00","size":340,"digest":null},"tinymce/plugins/emoticons/img/smiley-innocent.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-innocent.gif","mtime":"2016-12-10T10:15:36+01:00","size":336,"digest":null},"tinymce/plugins/emoticons/img/smiley-kiss.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-kiss.gif","mtime":"2016-12-10T10:15:36+01:00","size":338,"digest":null},"tinymce/plugins/emoticons/img/smiley-laughing.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-laughing.gif","mtime":"2016-12-10T10:15:36+01:00","size":343,"digest":null},"tinymce/plugins/emoticons/img/smiley-money-mouth.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-money-mouth.gif","mtime":"2016-12-10T10:15:36+01:00","size":321,"digest":null},"tinymce/plugins/emoticons/img/smiley-sealed.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-sealed.gif","mtime":"2016-12-10T10:15:36+01:00","size":323,"digest":null},"tinymce/plugins/emoticons/img/smiley-smile.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-smile.gif","mtime":"2016-12-10T10:15:36+01:00","size":344,"digest":null},"tinymce/plugins/emoticons/img/smiley-surprised.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-surprised.gif","mtime":"2016-12-10T10:15:36+01:00","size":338,"digest":null},"tinymce/plugins/emoticons/img/smiley-tongue-out.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-tongue-out.gif","mtime":"2016-12-10T10:15:36+01:00","size":328,"digest":null},"tinymce/plugins/emoticons/img/smiley-undecided.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-undecided.gif","mtime":"2016-12-10T10:15:36+01:00","size":337,"digest":null},"tinymce/plugins/emoticons/img/smiley-wink.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-wink.gif","mtime":"2016-12-10T10:15:36+01:00","size":350,"digest":null},"tinymce/plugins/emoticons/img/smiley-yell.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-yell.gif","mtime":"2016-12-10T10:15:36+01:00","size":336,"digest":null},"tinymce/skins/lightgray/img/anchor.gif":{"logical_path":"tinymce/skins/lightgray/img/anchor.gif","mtime":"2016-12-10T10:15:36+01:00","size":53,"digest":null},"tinymce/skins/lightgray/img/loader.gif":{"logical_path":"tinymce/skins/lightgray/img/loader.gif","mtime":"2016-12-10T10:15:36+01:00","size":2608,"digest":null},"tinymce/skins/lightgray/img/object.gif":{"logical_path":"tinymce/skins/lightgray/img/object.gif","mtime":"2016-12-10T10:15:36+01:00","size":152,"digest":null},"tinymce/skins/lightgray/img/trans.gif":{"logical_path":"tinymce/skins/lightgray/img/trans.gif","mtime":"2016-12-10T10:15:36+01:00","size":43,"digest":null},"tinymce/jquery.tinymce.js":{"logical_path":"tinymce/jquery.tinymce.js","mtime":"2016-12-10T10:15:36+01:00","size":3591,"digest":null},"tinymce/langs/readme.md":{"logical_path":"tinymce/langs/readme.md","mtime":"2016-12-10T10:15:36+01:00","size":151,"digest":null},"tinymce/license.txt":{"logical_path":"tinymce/license.txt","mtime":"2016-12-10T10:15:36+01:00","size":26427,"digest":null},"tinymce/plugins/advlist/plugin.js":{"logical_path":"tinymce/plugins/advlist/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":2048,"digest":null},"tinymce/plugins/anchor/plugin.js":{"logical_path":"tinymce/plugins/anchor/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":957,"digest":null},"tinymce/plugins/autolink/plugin.js":{"logical_path":"tinymce/plugins/autolink/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":2060,"digest":null},"tinymce/plugins/autoresize/plugin.js":{"logical_path":"tinymce/plugins/autoresize/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1903,"digest":null},"tinymce/plugins/autosave/plugin.js":{"logical_path":"tinymce/plugins/autosave/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":2187,"digest":null},"tinymce/plugins/bbcode/plugin.js":{"logical_path":"tinymce/plugins/bbcode/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":3136,"digest":null},"tinymce/plugins/charmap/plugin.js":{"logical_path":"tinymce/plugins/charmap/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":8199,"digest":null},"tinymce/plugins/code/plugin.js":{"logical_path":"tinymce/plugins/code/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":721,"digest":null},"tinymce/plugins/codesample/css/prism.css":{"logical_path":"tinymce/plugins/codesample/css/prism.css","mtime":"2016-12-10T10:15:36+01:00","size":2289,"digest":null},"tinymce/plugins/codesample/plugin.dev.js":{"logical_path":"tinymce/plugins/codesample/plugin.dev.js","mtime":"2016-12-10T10:15:36+01:00","size":3168,"digest":null},"tinymce/plugins/codesample/plugin.js":{"logical_path":"tinymce/plugins/codesample/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":20264,"digest":null},"tinymce/plugins/colorpicker/plugin.js":{"logical_path":"tinymce/plugins/colorpicker/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1222,"digest":null},"tinymce/plugins/contextmenu/plugin.js":{"logical_path":"tinymce/plugins/contextmenu/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1131,"digest":null},"tinymce/plugins/directionality/plugin.js":{"logical_path":"tinymce/plugins/directionality/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":726,"digest":null},"tinymce/plugins/emoticons/plugin.js":{"logical_path":"tinymce/plugins/emoticons/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":911,"digest":null},"tinymce/plugins/example/dialog.html":{"logical_path":"tinymce/plugins/example/dialog.html","mtime":"2016-12-10T10:15:36+01:00","size":213,"digest":null},"tinymce/plugins/example/plugin.js":{"logical_path":"tinymce/plugins/example/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":658,"digest":null},"tinymce/plugins/example_dependency/plugin.js":{"logical_path":"tinymce/plugins/example_dependency/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":73,"digest":null},"tinymce/plugins/fullpage/plugin.js":{"logical_path":"tinymce/plugins/fullpage/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":6308,"digest":null},"tinymce/plugins/fullscreen/plugin.js":{"logical_path":"tinymce/plugins/fullscreen/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1675,"digest":null},"tinymce/plugins/hr/plugin.js":{"logical_path":"tinymce/plugins/hr/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":322,"digest":null},"tinymce/plugins/image/plugin.js":{"logical_path":"tinymce/plugins/image/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":8195,"digest":null},"tinymce/plugins/imagetools/plugin.js":{"logical_path":"tinymce/plugins/imagetools/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":30900,"digest":null},"tinymce/plugins/importcss/plugin.js":{"logical_path":"tinymce/plugins/importcss/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":2746,"digest":null},"tinymce/plugins/insertdatetime/plugin.js":{"logical_path":"tinymce/plugins/insertdatetime/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1971,"digest":null},"tinymce/plugins/layer/plugin.js":{"logical_path":"tinymce/plugins/layer/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":2857,"digest":null},"tinymce/plugins/legacyoutput/plugin.js":{"logical_path":"tinymce/plugins/legacyoutput/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":3263,"digest":null},"tinymce/plugins/link/plugin.js":{"logical_path":"tinymce/plugins/link/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":6903,"digest":null},"tinymce/plugins/lists/plugin.js":{"logical_path":"tinymce/plugins/lists/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":10331,"digest":null},"tinymce/plugins/media/plugin.js":{"logical_path":"tinymce/plugins/media/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":14999,"digest":null},"tinymce/plugins/nonbreaking/plugin.js":{"logical_path":"tinymce/plugins/nonbreaking/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":655,"digest":null},"tinymce/plugins/noneditable/plugin.js":{"logical_path":"tinymce/plugins/noneditable/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1270,"digest":null},"tinymce/plugins/pagebreak/plugin.js":{"logical_path":"tinymce/plugins/pagebreak/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1230,"digest":null},"tinymce/plugins/paste/plugin.dev.js":{"logical_path":"tinymce/plugins/paste/plugin.dev.js","mtime":"2016-12-10T10:15:36+01:00","size":3130,"digest":null},"tinymce/plugins/paste/plugin.js":{"logical_path":"tinymce/plugins/paste/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":17676,"digest":null},"tinymce/plugins/preview/plugin.js":{"logical_path":"tinymce/plugins/preview/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1602,"digest":null},"tinymce/plugins/print/plugin.js":{"logical_path":"tinymce/plugins/print/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":293,"digest":null},"tinymce/plugins/save/plugin.js":{"logical_path":"tinymce/plugins/save/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1150,"digest":null},"tinymce/plugins/searchreplace/plugin.js":{"logical_path":"tinymce/plugins/searchreplace/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":6493,"digest":null},"tinymce/plugins/spellchecker/plugin.dev.js":{"logical_path":"tinymce/plugins/spellchecker/plugin.dev.js","mtime":"2016-12-10T10:15:36+01:00","size":3032,"digest":null},"tinymce/plugins/spellchecker/plugin.js":{"logical_path":"tinymce/plugins/spellchecker/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":10044,"digest":null},"tinymce/plugins/tabfocus/plugin.js":{"logical_path":"tinymce/plugins/tabfocus/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1264,"digest":null},"tinymce/plugins/table/plugin.dev.js":{"logical_path":"tinymce/plugins/table/plugin.dev.js","mtime":"2016-12-10T10:15:36+01:00","size":3152,"digest":null},"tinymce/plugins/table/plugin.js":{"logical_path":"tinymce/plugins/table/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":45825,"digest":null},"tinymce/plugins/template/plugin.js":{"logical_path":"tinymce/plugins/template/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":4520,"digest":null},"tinymce/plugins/textcolor/plugin.js":{"logical_path":"tinymce/plugins/textcolor/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":4145,"digest":null},"tinymce/plugins/textpattern/plugin.js":{"logical_path":"tinymce/plugins/textpattern/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":2745,"digest":null},"tinymce/plugins/toc/plugin.js":{"logical_path":"tinymce/plugins/toc/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":2771,"digest":null},"tinymce/plugins/visualblocks/css/visualblocks.css":{"logical_path":"tinymce/plugins/visualblocks/css/visualblocks.css","mtime":"2016-12-10T10:15:36+01:00","size":5092,"digest":null},"tinymce/plugins/visualblocks/plugin.js":{"logical_path":"tinymce/plugins/visualblocks/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1153,"digest":null},"tinymce/plugins/visualchars/plugin.js":{"logical_path":"tinymce/plugins/visualchars/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":1178,"digest":null},"tinymce/plugins/wordcount/plugin.js":{"logical_path":"tinymce/plugins/wordcount/plugin.js","mtime":"2016-12-10T10:15:36+01:00","size":11674,"digest":null},"tinymce/skins/lightgray/AbsoluteLayout.less":{"logical_path":"tinymce/skins/lightgray/AbsoluteLayout.less","mtime":"2016-12-10T10:15:36+01:00","size":265,"digest":null},"tinymce/skins/lightgray/Animations.less":{"logical_path":"tinymce/skins/lightgray/Animations.less","mtime":"2016-12-10T10:15:36+01:00","size":119,"digest":null},"tinymce/skins/lightgray/Arrows.less":{"logical_path":"tinymce/skins/lightgray/Arrows.less","mtime":"2016-12-10T10:15:36+01:00","size":2437,"digest":null},"tinymce/skins/lightgray/Button.less":{"logical_path":"tinymce/skins/lightgray/Button.less","mtime":"2016-12-10T10:15:36+01:00","size":3853,"digest":null},"tinymce/skins/lightgray/ButtonGroup.less":{"logical_path":"tinymce/skins/lightgray/ButtonGroup.less","mtime":"2016-12-10T10:15:36+01:00","size":1681,"digest":null},"tinymce/skins/lightgray/Checkbox.less":{"logical_path":"tinymce/skins/lightgray/Checkbox.less","mtime":"2016-12-10T10:15:36+01:00","size":1096,"digest":null},"tinymce/skins/lightgray/ColorBox.less":{"logical_path":"tinymce/skins/lightgray/ColorBox.less","mtime":"2016-12-10T10:15:36+01:00","size":103,"digest":null},"tinymce/skins/lightgray/ColorButton.less":{"logical_path":"tinymce/skins/lightgray/ColorButton.less","mtime":"2016-12-10T10:15:36+01:00","size":1301,"digest":null},"tinymce/skins/lightgray/ColorPicker.less":{"logical_path":"tinymce/skins/lightgray/ColorPicker.less","mtime":"2016-12-10T10:15:36+01:00","size":1864,"digest":null},"tinymce/skins/lightgray/ComboBox.less":{"logical_path":"tinymce/skins/lightgray/ComboBox.less","mtime":"2016-12-10T10:15:36+01:00","size":1729,"digest":null},"tinymce/skins/lightgray/Container.less":{"logical_path":"tinymce/skins/lightgray/Container.less","mtime":"2016-12-10T10:15:36+01:00","size":129,"digest":null},"tinymce/skins/lightgray/Content.Inline.less":{"logical_path":"tinymce/skins/lightgray/Content.Inline.less","mtime":"2016-12-10T10:15:36+01:00","size":82,"digest":null},"tinymce/skins/lightgray/Content.Objects.less":{"logical_path":"tinymce/skins/lightgray/Content.Objects.less","mtime":"2016-12-10T10:15:36+01:00","size":3210,"digest":null},"tinymce/skins/lightgray/Content.less":{"logical_path":"tinymce/skins/lightgray/Content.less","mtime":"2016-12-10T10:15:36+01:00","size":592,"digest":null},"tinymce/skins/lightgray/CropRect.less":{"logical_path":"tinymce/skins/lightgray/CropRect.less","mtime":"2016-12-10T10:15:36+01:00","size":1108,"digest":null},"tinymce/skins/lightgray/FieldSet.less":{"logical_path":"tinymce/skins/lightgray/FieldSet.less","mtime":"2016-12-10T10:15:36+01:00","size":233,"digest":null},"tinymce/skins/lightgray/FitLayout.less":{"logical_path":"tinymce/skins/lightgray/FitLayout.less","mtime":"2016-12-10T10:15:36+01:00","size":111,"digest":null},"tinymce/skins/lightgray/FloatPanel.less":{"logical_path":"tinymce/skins/lightgray/FloatPanel.less","mtime":"2016-12-10T10:15:36+01:00","size":1477,"digest":null},"tinymce/skins/lightgray/FlowLayout.less":{"logical_path":"tinymce/skins/lightgray/FlowLayout.less","mtime":"2016-12-10T10:15:36+01:00","size":694,"digest":null},"tinymce/skins/lightgray/Icons.Ie7.less":{"logical_path":"tinymce/skins/lightgray/Icons.Ie7.less","mtime":"2016-12-10T10:15:36+01:00","size":5621,"digest":null},"tinymce/skins/lightgray/Icons.less":{"logical_path":"tinymce/skins/lightgray/Icons.less","mtime":"2016-12-10T10:15:36+01:00","size":9372,"digest":null},"tinymce/skins/lightgray/Iframe.less":{"logical_path":"tinymce/skins/lightgray/Iframe.less","mtime":"2016-12-10T10:15:36+01:00","size":94,"digest":null},"tinymce/skins/lightgray/ImagePanel.less":{"logical_path":"tinymce/skins/lightgray/ImagePanel.less","mtime":"2016-12-10T10:15:36+01:00","size":476,"digest":null},"tinymce/skins/lightgray/InfoBox.less":{"logical_path":"tinymce/skins/lightgray/InfoBox.less","mtime":"2016-12-10T10:15:36+01:00","size":1087,"digest":null},"tinymce/skins/lightgray/Label.less":{"logical_path":"tinymce/skins/lightgray/Label.less","mtime":"2016-12-10T10:15:36+01:00","size":554,"digest":null},"tinymce/skins/lightgray/ListBox.less":{"logical_path":"tinymce/skins/lightgray/ListBox.less","mtime":"2016-12-10T10:15:36+01:00","size":388,"digest":null},"tinymce/skins/lightgray/Menu.less":{"logical_path":"tinymce/skins/lightgray/Menu.less","mtime":"2016-12-10T10:15:36+01:00","size":821,"digest":null},"tinymce/skins/lightgray/MenuBar.less":{"logical_path":"tinymce/skins/lightgray/MenuBar.less","mtime":"2016-12-10T10:15:36+01:00","size":689,"digest":null},"tinymce/skins/lightgray/MenuButton.less":{"logical_path":"tinymce/skins/lightgray/MenuButton.less","mtime":"2016-12-10T10:15:36+01:00","size":607,"digest":null},"tinymce/skins/lightgray/MenuItem.less":{"logical_path":"tinymce/skins/lightgray/MenuItem.less","mtime":"2016-12-10T10:15:36+01:00","size":4782,"digest":null},"tinymce/skins/lightgray/Mixins.less":{"logical_path":"tinymce/skins/lightgray/Mixins.less","mtime":"2016-12-10T10:15:36+01:00","size":1799,"digest":null},"tinymce/skins/lightgray/Notification.less":{"logical_path":"tinymce/skins/lightgray/Notification.less","mtime":"2016-12-10T10:15:36+01:00","size":3628,"digest":null},"tinymce/skins/lightgray/Panel.less":{"logical_path":"tinymce/skins/lightgray/Panel.less","mtime":"2016-12-10T10:15:36+01:00","size":220,"digest":null},"tinymce/skins/lightgray/Path.less":{"logical_path":"tinymce/skins/lightgray/Path.less","mtime":"2016-12-10T10:15:36+01:00","size":650,"digest":null},"tinymce/skins/lightgray/Progress.less":{"logical_path":"tinymce/skins/lightgray/Progress.less","mtime":"2016-12-10T10:15:36+01:00","size":619,"digest":null},"tinymce/skins/lightgray/Radio.less":{"logical_path":"tinymce/skins/lightgray/Radio.less","mtime":"2016-12-10T10:15:36+01:00","size":31,"digest":null},"tinymce/skins/lightgray/Reset.less":{"logical_path":"tinymce/skins/lightgray/Reset.less","mtime":"2016-12-10T10:15:36+01:00","size":905,"digest":null},"tinymce/skins/lightgray/ResizeHandle.less":{"logical_path":"tinymce/skins/lightgray/ResizeHandle.less","mtime":"2016-12-10T10:15:36+01:00","size":301,"digest":null},"tinymce/skins/lightgray/Scrollable.less":{"logical_path":"tinymce/skins/lightgray/Scrollable.less","mtime":"2016-12-10T10:15:36+01:00","size":687,"digest":null},"tinymce/skins/lightgray/SelectBox.less":{"logical_path":"tinymce/skins/lightgray/SelectBox.less","mtime":"2016-12-10T10:15:36+01:00","size":105,"digest":null},"tinymce/skins/lightgray/Sidebar.less":{"logical_path":"tinymce/skins/lightgray/Sidebar.less","mtime":"2016-12-10T10:15:36+01:00","size":956,"digest":null},"tinymce/skins/lightgray/Slider.less":{"logical_path":"tinymce/skins/lightgray/Slider.less","mtime":"2016-12-10T10:15:36+01:00","size":579,"digest":null},"tinymce/skins/lightgray/Spacer.less":{"logical_path":"tinymce/skins/lightgray/Spacer.less","mtime":"2016-12-10T10:15:36+01:00","size":54,"digest":null},"tinymce/skins/lightgray/SplitButton.less":{"logical_path":"tinymce/skins/lightgray/SplitButton.less","mtime":"2016-12-10T10:15:36+01:00","size":980,"digest":null},"tinymce/skins/lightgray/StackLayout.less":{"logical_path":"tinymce/skins/lightgray/StackLayout.less","mtime":"2016-12-10T10:15:36+01:00","size":67,"digest":null},"tinymce/skins/lightgray/TabPanel.less":{"logical_path":"tinymce/skins/lightgray/TabPanel.less","mtime":"2016-12-10T10:15:36+01:00","size":706,"digest":null},"tinymce/skins/lightgray/TextBox.less":{"logical_path":"tinymce/skins/lightgray/TextBox.less","mtime":"2016-12-10T10:15:36+01:00","size":870,"digest":null},"tinymce/skins/lightgray/Throbber.less":{"logical_path":"tinymce/skins/lightgray/Throbber.less","mtime":"2016-12-10T10:15:36+01:00","size":303,"digest":null},"tinymce/skins/lightgray/TinyMCE.less":{"logical_path":"tinymce/skins/lightgray/TinyMCE.less","mtime":"2016-12-10T10:15:36+01:00","size":2449,"digest":null},"tinymce/skins/lightgray/ToolTip.less":{"logical_path":"tinymce/skins/lightgray/ToolTip.less","mtime":"2016-12-10T10:15:36+01:00","size":2533,"digest":null},"tinymce/skins/lightgray/Variables.less":{"logical_path":"tinymce/skins/lightgray/Variables.less","mtime":"2016-12-10T10:15:36+01:00","size":8371,"digest":null},"tinymce/skins/lightgray/Window.less":{"logical_path":"tinymce/skins/lightgray/Window.less","mtime":"2016-12-10T10:15:36+01:00","size":2217,"digest":null},"tinymce/skins/lightgray/content.inline.min.css":{"logical_path":"tinymce/skins/lightgray/content.inline.min.css","mtime":"2016-12-10T10:15:36+01:00","size":2769,"digest":null},"tinymce/skins/lightgray/content.min.css":{"logical_path":"tinymce/skins/lightgray/content.min.css","mtime":"2016-12-10T10:15:36+01:00","size":3193,"digest":null},"tinymce/skins/lightgray/fonts/tinymce-small.eot":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce-small.eot","mtime":"2016-12-10T10:15:36+01:00","size":9492,"digest":null},"tinymce/skins/lightgray/fonts/tinymce-small.svg":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce-small.svg","mtime":"2016-12-10T10:15:36+01:00","size":24727,"digest":null},"tinymce/skins/lightgray/fonts/tinymce-small.ttf":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce-small.ttf","mtime":"2016-12-10T10:15:36+01:00","size":9304,"digest":null},"tinymce/skins/lightgray/fonts/tinymce-small.woff":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce-small.woff","mtime":"2016-12-10T10:15:36+01:00","size":9380,"digest":null},"tinymce/skins/lightgray/fonts/tinymce.eot":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce.eot","mtime":"2016-12-10T10:15:36+01:00","size":17572,"digest":null},"tinymce/skins/lightgray/fonts/tinymce.svg":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce.svg","mtime":"2016-12-10T10:15:36+01:00","size":45991,"digest":null},"tinymce/skins/lightgray/fonts/tinymce.ttf":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce.ttf","mtime":"2016-12-10T10:15:36+01:00","size":17408,"digest":null},"tinymce/skins/lightgray/fonts/tinymce.woff":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce.woff","mtime":"2016-12-10T10:15:36+01:00","size":17484,"digest":null},"tinymce/skins/lightgray/skin.dev.less":{"logical_path":"tinymce/skins/lightgray/skin.dev.less","mtime":"2016-12-10T10:15:36+01:00","size":1201,"digest":null},"tinymce/skins/lightgray/skin.ie7.dev.less":{"logical_path":"tinymce/skins/lightgray/skin.ie7.dev.less","mtime":"2016-12-10T10:15:36+01:00","size":1181,"digest":null},"tinymce/skins/lightgray/skin.ie7.less":{"logical_path":"tinymce/skins/lightgray/skin.ie7.less","mtime":"2016-12-10T10:15:36+01:00","size":61487,"digest":null},"tinymce/skins/lightgray/skin.ie7.min.css":{"logical_path":"tinymce/skins/lightgray/skin.ie7.min.css","mtime":"2016-12-10T10:15:36+01:00","size":34904,"digest":null},"tinymce/skins/lightgray/skin.less":{"logical_path":"tinymce/skins/lightgray/skin.less","mtime":"2016-12-10T10:15:36+01:00","size":66196,"digest":null},"tinymce/skins/lightgray/skin.min.css":{"logical_path":"tinymce/skins/lightgray/skin.min.css","mtime":"2016-12-10T10:15:36+01:00","size":38232,"digest":null},"tinymce/themes/inlite/theme.js":{"logical_path":"tinymce/themes/inlite/theme.js","mtime":"2016-12-10T10:15:36+01:00","size":16364,"digest":null},"tinymce/themes/modern/theme.js":{"logical_path":"tinymce/themes/modern/theme.js","mtime":"2016-12-10T10:15:36+01:00","size":13146,"digest":null},"tinymce/tinymce.js":{"logical_path":"tinymce/tinymce.js","mtime":"2016-12-10T10:15:36+01:00","size":401179,"digest":null},"tinymce/langs/ar.js":{"logical_path":"tinymce/langs/ar.js","mtime":"2016-10-29T16:47:26+02:00","size":17775,"digest":null},"tinymce/langs/ar_SA.js":{"logical_path":"tinymce/langs/ar_SA.js","mtime":"2016-10-29T16:47:26+02:00","size":10002,"digest":null},"tinymce/langs/az.js":{"logical_path":"tinymce/langs/az.js","mtime":"2016-10-29T16:47:26+02:00","size":9679,"digest":null},"tinymce/langs/be.js":{"logical_path":"tinymce/langs/be.js","mtime":"2016-10-29T16:47:26+02:00","size":21063,"digest":null},"tinymce/langs/bg_BG.js":{"logical_path":"tinymce/langs/bg_BG.js","mtime":"2016-10-29T16:47:26+02:00","size":23944,"digest":null},"tinymce/langs/bn_BD.js":{"logical_path":"tinymce/langs/bn_BD.js","mtime":"2016-10-29T16:47:26+02:00","size":6845,"digest":null},"tinymce/langs/bs.js":{"logical_path":"tinymce/langs/bs.js","mtime":"2016-10-29T16:47:26+02:00","size":6969,"digest":null},"tinymce/langs/ca.js":{"logical_path":"tinymce/langs/ca.js","mtime":"2016-10-29T16:47:26+02:00","size":7786,"digest":null},"tinymce/langs/cs.js":{"logical_path":"tinymce/langs/cs.js","mtime":"2016-10-29T16:47:26+02:00","size":8750,"digest":null},"tinymce/langs/cs_CZ.js":{"logical_path":"tinymce/langs/cs_CZ.js","mtime":"2016-10-29T16:47:26+02:00","size":8398,"digest":null},"tinymce/langs/cy.js":{"logical_path":"tinymce/langs/cy.js","mtime":"2016-10-29T16:47:26+02:00","size":6141,"digest":null},"tinymce/langs/da.js":{"logical_path":"tinymce/langs/da.js","mtime":"2016-10-29T16:47:26+02:00","size":7512,"digest":null},"tinymce/langs/de.js":{"logical_path":"tinymce/langs/de.js","mtime":"2016-10-29T16:47:26+02:00","size":8279,"digest":null},"tinymce/langs/de_AT.js":{"logical_path":"tinymce/langs/de_AT.js","mtime":"2016-10-29T16:47:26+02:00","size":8307,"digest":null},"tinymce/langs/dv.js":{"logical_path":"tinymce/langs/dv.js","mtime":"2016-10-29T16:47:26+02:00","size":18099,"digest":null},"tinymce/langs/el.js":{"logical_path":"tinymce/langs/el.js","mtime":"2016-10-29T16:47:26+02:00","size":22972,"digest":null},"tinymce/langs/en_CA.js":{"logical_path":"tinymce/langs/en_CA.js","mtime":"2016-10-29T16:47:26+02:00","size":6915,"digest":null},"tinymce/langs/en_GB.js":{"logical_path":"tinymce/langs/en_GB.js","mtime":"2016-10-29T16:47:26+02:00","size":5906,"digest":null},"tinymce/langs/eo.js":{"logical_path":"tinymce/langs/eo.js","mtime":"2016-10-29T16:47:26+02:00","size":7465,"digest":null},"tinymce/langs/es.js":{"logical_path":"tinymce/langs/es.js","mtime":"2016-10-29T16:47:26+02:00","size":7808,"digest":null},"tinymce/langs/es_MX.js":{"logical_path":"tinymce/langs/es_MX.js","mtime":"2016-10-29T16:47:26+02:00","size":7893,"digest":null},"tinymce/langs/et.js":{"logical_path":"tinymce/langs/et.js","mtime":"2016-10-29T16:47:26+02:00","size":7783,"digest":null},"tinymce/langs/eu.js":{"logical_path":"tinymce/langs/eu.js","mtime":"2016-10-29T16:47:26+02:00","size":7010,"digest":null},"tinymce/langs/fa.js":{"logical_path":"tinymce/langs/fa.js","mtime":"2016-10-29T16:47:26+02:00","size":16461,"digest":null},"tinymce/langs/fa_IR.js":{"logical_path":"tinymce/langs/fa_IR.js","mtime":"2016-10-29T16:47:26+02:00","size":17724,"digest":null},"tinymce/langs/fi.js":{"logical_path":"tinymce/langs/fi.js","mtime":"2016-10-29T16:47:26+02:00","size":8142,"digest":null},"tinymce/langs/fo.js":{"logical_path":"tinymce/langs/fo.js","mtime":"2016-10-29T16:47:26+02:00","size":8043,"digest":null},"tinymce/langs/fr_CH.js":{"logical_path":"tinymce/langs/fr_CH.js","mtime":"2016-10-29T16:47:26+02:00","size":8073,"digest":null},"tinymce/langs/fr_FR.js":{"logical_path":"tinymce/langs/fr_FR.js","mtime":"2016-10-29T16:47:26+02:00","size":8008,"digest":null},"tinymce/langs/ga.js":{"logical_path":"tinymce/langs/ga.js","mtime":"2016-10-29T16:47:26+02:00","size":8590,"digest":null},"tinymce/langs/gd.js":{"logical_path":"tinymce/langs/gd.js","mtime":"2016-10-29T16:47:26+02:00","size":8807,"digest":null},"tinymce/langs/gl.js":{"logical_path":"tinymce/langs/gl.js","mtime":"2016-10-29T16:47:26+02:00","size":7065,"digest":null},"tinymce/langs/he_IL.js":{"logical_path":"tinymce/langs/he_IL.js","mtime":"2016-10-29T16:47:26+02:00","size":16080,"digest":null},"tinymce/langs/hi_IN.js":{"logical_path":"tinymce/langs/hi_IN.js","mtime":"2016-10-29T16:47:26+02:00","size":18457,"digest":null},"tinymce/langs/hr.js":{"logical_path":"tinymce/langs/hr.js","mtime":"2016-10-29T16:47:26+02:00","size":7576,"digest":null},"tinymce/langs/hu_HU.js":{"logical_path":"tinymce/langs/hu_HU.js","mtime":"2016-10-29T16:47:26+02:00","size":9409,"digest":null},"tinymce/langs/hy.js":{"logical_path":"tinymce/langs/hy.js","mtime":"2016-10-29T16:47:26+02:00","size":20374,"digest":null},"tinymce/langs/id.js":{"logical_path":"tinymce/langs/id.js","mtime":"2016-10-29T16:47:26+02:00","size":7140,"digest":null},"tinymce/langs/is_IS.js":{"logical_path":"tinymce/langs/is_IS.js","mtime":"2016-10-29T16:47:26+02:00","size":7927,"digest":null},"tinymce/langs/it.js":{"logical_path":"tinymce/langs/it.js","mtime":"2016-10-29T16:47:26+02:00","size":7597,"digest":null},"tinymce/langs/ja.js":{"logical_path":"tinymce/langs/ja.js","mtime":"2016-10-29T16:47:26+02:00","size":12289,"digest":null},"tinymce/langs/ka_GE.js":{"logical_path":"tinymce/langs/ka_GE.js","mtime":"2016-10-29T16:47:26+02:00","size":21283,"digest":null},"tinymce/langs/kab.js":{"logical_path":"tinymce/langs/kab.js","mtime":"2016-10-29T16:47:26+02:00","size":7390,"digest":null},"tinymce/langs/kk.js":{"logical_path":"tinymce/langs/kk.js","mtime":"2016-10-29T16:47:26+02:00","size":16680,"digest":null},"tinymce/langs/km_KH.js":{"logical_path":"tinymce/langs/km_KH.js","mtime":"2016-10-29T16:47:26+02:00","size":21395,"digest":null},"tinymce/langs/ko.js":{"logical_path":"tinymce/langs/ko.js","mtime":"2016-10-29T16:47:26+02:00","size":10104,"digest":null},"tinymce/langs/ko_KR.js":{"logical_path":"tinymce/langs/ko_KR.js","mtime":"2016-10-29T16:47:26+02:00","size":10004,"digest":null},"tinymce/langs/ku.js":{"logical_path":"tinymce/langs/ku.js","mtime":"2016-10-29T16:47:26+02:00","size":18273,"digest":null},"tinymce/langs/ku_IQ.js":{"logical_path":"tinymce/langs/ku_IQ.js","mtime":"2016-10-29T16:47:26+02:00","size":18363,"digest":null},"tinymce/langs/lb.js":{"logical_path":"tinymce/langs/lb.js","mtime":"2016-10-29T16:47:26+02:00","size":7466,"digest":null},"tinymce/langs/lt.js":{"logical_path":"tinymce/langs/lt.js","mtime":"2016-10-29T16:47:26+02:00","size":8898,"digest":null},"tinymce/langs/lv.js":{"logical_path":"tinymce/langs/lv.js","mtime":"2016-10-29T16:47:26+02:00","size":8281,"digest":null},"tinymce/langs/mk_MK.js":{"logical_path":"tinymce/langs/mk_MK.js","mtime":"2016-10-29T16:47:26+02:00","size":18732,"digest":null},"tinymce/langs/ml.js":{"logical_path":"tinymce/langs/ml.js","mtime":"2016-10-29T16:47:26+02:00","size":7338,"digest":null},"tinymce/langs/ml_IN.js":{"logical_path":"tinymce/langs/ml_IN.js","mtime":"2016-10-29T16:47:26+02:00","size":20018,"digest":null},"tinymce/langs/mn_MN.js":{"logical_path":"tinymce/langs/mn_MN.js","mtime":"2016-10-29T16:47:26+02:00","size":6876,"digest":null},"tinymce/langs/nb_NO.js":{"logical_path":"tinymce/langs/nb_NO.js","mtime":"2016-10-29T16:47:26+02:00","size":7527,"digest":null},"tinymce/langs/nl.js":{"logical_path":"tinymce/langs/nl.js","mtime":"2016-10-29T16:47:26+02:00","size":7234,"digest":null},"tinymce/langs/pl.js":{"logical_path":"tinymce/langs/pl.js","mtime":"2016-10-29T16:47:26+02:00","size":8128,"digest":null},"tinymce/langs/pt_BR.js":{"logical_path":"tinymce/langs/pt_BR.js","mtime":"2016-10-29T16:47:26+02:00","size":8001,"digest":null},"tinymce/langs/pt_PT.js":{"logical_path":"tinymce/langs/pt_PT.js","mtime":"2016-10-29T16:47:26+02:00","size":8144,"digest":null},"tinymce/langs/ro.js":{"logical_path":"tinymce/langs/ro.js","mtime":"2016-10-29T16:47:26+02:00","size":8274,"digest":null},"tinymce/langs/ru.js":{"logical_path":"tinymce/langs/ru.js","mtime":"2016-10-29T16:47:26+02:00","size":22289,"digest":null},"tinymce/langs/ru_RU.js":{"logical_path":"tinymce/langs/ru_RU.js","mtime":"2016-10-29T16:47:26+02:00","size":4954,"digest":null},"tinymce/langs/si_LK.js":{"logical_path":"tinymce/langs/si_LK.js","mtime":"2016-10-29T16:47:26+02:00","size":15855,"digest":null},"tinymce/langs/sk.js":{"logical_path":"tinymce/langs/sk.js","mtime":"2016-10-29T16:47:26+02:00","size":8957,"digest":null},"tinymce/langs/sl_SI.js":{"logical_path":"tinymce/langs/sl_SI.js","mtime":"2016-10-29T16:47:26+02:00","size":7038,"digest":null},"tinymce/langs/sr.js":{"logical_path":"tinymce/langs/sr.js","mtime":"2016-10-29T16:47:26+02:00","size":6335,"digest":null},"tinymce/langs/sv_SE.js":{"logical_path":"tinymce/langs/sv_SE.js","mtime":"2016-10-29T16:47:26+02:00","size":7495,"digest":null},"tinymce/langs/ta.js":{"logical_path":"tinymce/langs/ta.js","mtime":"2016-10-29T16:47:26+02:00","size":22616,"digest":null},"tinymce/langs/ta_IN.js":{"logical_path":"tinymce/langs/ta_IN.js","mtime":"2016-10-29T16:47:26+02:00","size":22619,"digest":null},"tinymce/langs/tg.js":{"logical_path":"tinymce/langs/tg.js","mtime":"2016-10-29T16:47:26+02:00","size":18182,"digest":null},"tinymce/langs/th_TH.js":{"logical_path":"tinymce/langs/th_TH.js","mtime":"2016-10-29T16:47:26+02:00","size":17296,"digest":null},"tinymce/langs/tr.js":{"logical_path":"tinymce/langs/tr.js","mtime":"2016-10-29T16:47:26+02:00","size":8704,"digest":null},"tinymce/langs/tr_TR.js":{"logical_path":"tinymce/langs/tr_TR.js","mtime":"2016-10-29T16:47:26+02:00","size":8140,"digest":null},"tinymce/langs/tt.js":{"logical_path":"tinymce/langs/tt.js","mtime":"2016-10-29T16:47:26+02:00","size":19034,"digest":null},"tinymce/langs/ug.js":{"logical_path":"tinymce/langs/ug.js","mtime":"2016-10-29T16:47:26+02:00","size":16887,"digest":null},"tinymce/langs/uk.js":{"logical_path":"tinymce/langs/uk.js","mtime":"2016-10-29T16:47:26+02:00","size":22263,"digest":null},"tinymce/langs/uk_UA.js":{"logical_path":"tinymce/langs/uk_UA.js","mtime":"2016-10-29T16:47:26+02:00","size":21690,"digest":null},"tinymce/langs/vi.js":{"logical_path":"tinymce/langs/vi.js","mtime":"2016-10-29T16:47:26+02:00","size":9900,"digest":null},"tinymce/langs/vi_VN.js":{"logical_path":"tinymce/langs/vi_VN.js","mtime":"2016-10-29T16:47:26+02:00","size":9898,"digest":null},"tinymce/langs/zh_CN.js":{"logical_path":"tinymce/langs/zh_CN.js","mtime":"2016-10-29T16:47:26+02:00","size":8482,"digest":null},"tinymce/langs/zh_TW.js":{"logical_path":"tinymce/langs/zh_TW.js","mtime":"2016-10-29T16:47:26+02:00","size":9378,"digest":null},"active_admin-5493c4a52f825b68a247f214b88addaf61bada07aefa1441589c72d8d81f8b12.css":{"logical_path":"active_admin.css","mtime":"2017-01-19T14:15:27+01:00","size":78899,"digest":"5493c4a52f825b68a247f214b88addaf61bada07aefa1441589c72d8d81f8b12","integrity":"sha256-VJPEpS+CW2iiR/IUuIrdr2G62geu+hRBWJxy2NgfixI="},"active_admin-9238692e361f8ed7317fd8414cfadeff93c57b9a6ed3fd35cfe9a3fe4ddc3829.js":{"logical_path":"active_admin.js","mtime":"2017-01-19T14:51:27+01:00","size":692387,"digest":"9238692e361f8ed7317fd8414cfadeff93c57b9a6ed3fd35cfe9a3fe4ddc3829","integrity":"sha256-kjhpLjYfjtcxf9hBTPre/5PFe5pu0/01z+mj/k3cOCk="},"lef-9fcdd7ddd4d40de29c3809b59688c668b85f5628e219d4cd8a8810b72a64533b.png":{"logical_path":"lef.png","mtime":"2017-01-07T19:07:36+01:00","size":8332,"digest":"9fcdd7ddd4d40de29c3809b59688c668b85f5628e219d4cd8a8810b72a64533b","integrity":"sha256-n83X3dTUDeKcOAm1lojGaLhfVijiGdTNiogQtypkUzs="},"application-a9c6770a672e537abdfdbea5f842747b5d0b0d402d9216a5f1bb789f051ba10e.js":{"logical_path":"application.js","mtime":"2017-01-19T14:51:27+01:00","size":2365648,"digest":"a9c6770a672e537abdfdbea5f842747b5d0b0d402d9216a5f1bb789f051ba10e","integrity":"sha256-qcZ3CmcuU3q9/b6l+EJ0e10LDUAtkhal8bt4nwUboQ4="},"tinymce/langs/ar-e47a394dbc461d20aa547fa0c2027a9dad45fe55e18adb0da309045be6ed4109.js":{"logical_path":"tinymce/langs/ar.js","mtime":"2017-04-24T19:17:55+02:00","size":17776,"digest":"e47a394dbc461d20aa547fa0c2027a9dad45fe55e18adb0da309045be6ed4109","integrity":"sha256-5Ho5TbxGHSCqVH+gwgJ6na1F/lXhitsNowkEW+btQQk="},"tinymce/langs/ar_SA-24b62c76e99e114ae44480a67edbacf74f9fed0ff7afbeacce4966f1bc80333b.js":{"logical_path":"tinymce/langs/ar_SA.js","mtime":"2017-04-24T19:17:55+02:00","size":10003,"digest":"24b62c76e99e114ae44480a67edbacf74f9fed0ff7afbeacce4966f1bc80333b","integrity":"sha256-JLYsdumeEUrkRICmftus90+f7Q/3r76szklm8byAMzs="},"tinymce/langs/az-d40cecd6eb423f910f528ae98dcdaba4c2449802621759437174cf8c8c0d5b25.js":{"logical_path":"tinymce/langs/az.js","mtime":"2017-04-24T19:17:55+02:00","size":9680,"digest":"d40cecd6eb423f910f528ae98dcdaba4c2449802621759437174cf8c8c0d5b25","integrity":"sha256-1Azs1utCP5EPUorpjc2rpMJEmAJiF1lDcXTPjIwNWyU="},"tinymce/langs/be-42e2884c0f2394afa1a17e31e702660eeea0d84618bbd18155cb0313c6eb5f69.js":{"logical_path":"tinymce/langs/be.js","mtime":"2017-04-24T19:17:55+02:00","size":21064,"digest":"42e2884c0f2394afa1a17e31e702660eeea0d84618bbd18155cb0313c6eb5f69","integrity":"sha256-QuKITA8jlK+hoX4x5wJmDu6g2EYYu9GBVcsDE8brX2k="},"tinymce/langs/bg_BG-2fac9d785519d2791d42881fcc08c6a82e841575785690259d7f64e1b88d7db3.js":{"logical_path":"tinymce/langs/bg_BG.js","mtime":"2017-04-24T19:17:55+02:00","size":23945,"digest":"2fac9d785519d2791d42881fcc08c6a82e841575785690259d7f64e1b88d7db3","integrity":"sha256-L6ydeFUZ0nkdQogfzAjGqC6EFXV4VpAlnX9k4biNfbM="},"tinymce/langs/bn_BD-ef48a9094445dfa624af0c35902f60b7949b30585b5e9bc760a225fe2c07cbd3.js":{"logical_path":"tinymce/langs/bn_BD.js","mtime":"2017-04-24T19:17:55+02:00","size":6846,"digest":"ef48a9094445dfa624af0c35902f60b7949b30585b5e9bc760a225fe2c07cbd3","integrity":"sha256-70ipCURF36Ykrww1kC9gt5SbMFhbXpvHYKIl/iwHy9M="},"tinymce/langs/bs-eb66c6d6910a30b950d7a0e784027ed288e6e5a2c6db7741da3359f2067e2e0e.js":{"logical_path":"tinymce/langs/bs.js","mtime":"2017-04-24T19:17:55+02:00","size":6970,"digest":"eb66c6d6910a30b950d7a0e784027ed288e6e5a2c6db7741da3359f2067e2e0e","integrity":"sha256-62bG1pEKMLlQ16DnhAJ+0ojm5aLG23dB2jNZ8gZ+Lg4="},"tinymce/langs/ca-77ab49d6420318ed7f5fd51b6856bc396c393095bd78ea91dad83e38e5859637.js":{"logical_path":"tinymce/langs/ca.js","mtime":"2017-04-24T19:17:55+02:00","size":7787,"digest":"77ab49d6420318ed7f5fd51b6856bc396c393095bd78ea91dad83e38e5859637","integrity":"sha256-d6tJ1kIDGO1/X9UbaFa8OWw5MJW9eOqR2tg+OOWFljc="},"tinymce/langs/cs-3d7ecd619895e3e4c7e1db06f6526682ef88f22f6e8b50d7b45ed0ae7c206714.js":{"logical_path":"tinymce/langs/cs.js","mtime":"2017-04-24T19:17:55+02:00","size":8751,"digest":"3d7ecd619895e3e4c7e1db06f6526682ef88f22f6e8b50d7b45ed0ae7c206714","integrity":"sha256-PX7NYZiV4+TH4dsG9lJmgu+I8i9ui1DXtF7QrnwgZxQ="},"tinymce/langs/cs_CZ-4b0778d233e200dea350f8361129da2844e23d1c0f2d524aeffa6d34e581368d.js":{"logical_path":"tinymce/langs/cs_CZ.js","mtime":"2017-04-24T19:17:55+02:00","size":8399,"digest":"4b0778d233e200dea350f8361129da2844e23d1c0f2d524aeffa6d34e581368d","integrity":"sha256-Swd40jPiAN6jUPg2ESnaKETiPRwPLVJK7/ptNOWBNo0="},"tinymce/langs/cy-a847ff54657ccf76eec362cc14fbc63adb4c67f9b1de023b29d817aba4fec062.js":{"logical_path":"tinymce/langs/cy.js","mtime":"2017-04-24T19:17:55+02:00","size":6142,"digest":"a847ff54657ccf76eec362cc14fbc63adb4c67f9b1de023b29d817aba4fec062","integrity":"sha256-qEf/VGV8z3buw2LMFPvGOttMZ/mx3gI7KdgXq6T+wGI="},"tinymce/langs/da-a87f3ae1c442c3bb26b81569687e98072d038269360361ec9728f00d6b17c282.js":{"logical_path":"tinymce/langs/da.js","mtime":"2017-04-24T19:17:55+02:00","size":7513,"digest":"a87f3ae1c442c3bb26b81569687e98072d038269360361ec9728f00d6b17c282","integrity":"sha256-qH864cRCw7smuBVpaH6YBy0Dgmk2A2HslyjwDWsXwoI="},"tinymce/langs/de-a10c8f6f1e53da776e7026dffd54ea8ba527492b767e5b54ae5c3974f6953311.js":{"logical_path":"tinymce/langs/de.js","mtime":"2017-04-24T19:17:55+02:00","size":8280,"digest":"a10c8f6f1e53da776e7026dffd54ea8ba527492b767e5b54ae5c3974f6953311","integrity":"sha256-oQyPbx5T2nducCbf/VTqi6UnSSt2fltUrlw5dPaVMxE="},"tinymce/langs/de_AT-a32eec12ce12b06fc2c8919d2372242e9596712c96dc9bcfff1fc8b7dc458627.js":{"logical_path":"tinymce/langs/de_AT.js","mtime":"2017-04-24T19:17:55+02:00","size":8308,"digest":"a32eec12ce12b06fc2c8919d2372242e9596712c96dc9bcfff1fc8b7dc458627","integrity":"sha256-oy7sEs4SsG/CyJGdI3IkLpWWcSyW3JvP/x/It9xFhic="},"tinymce/langs/dv-182756bf33409a8b76bc684d0a2ab86881718c360d1f1fb3fbc609ce3f5e3f49.js":{"logical_path":"tinymce/langs/dv.js","mtime":"2017-04-24T19:17:55+02:00","size":18100,"digest":"182756bf33409a8b76bc684d0a2ab86881718c360d1f1fb3fbc609ce3f5e3f49","integrity":"sha256-GCdWvzNAmot2vGhNCiq4aIFxjDYNHx+z+8YJzj9eP0k="},"tinymce/langs/el-6bbdbf3ccb2b2f22f961eb6749b43fe401c84fd6d89cd3f76a538dc2d06bb071.js":{"logical_path":"tinymce/langs/el.js","mtime":"2017-04-24T19:17:55+02:00","size":22973,"digest":"6bbdbf3ccb2b2f22f961eb6749b43fe401c84fd6d89cd3f76a538dc2d06bb071","integrity":"sha256-a72/PMsrLyL5YetnSbQ/5AHIT9bYnNP3alONwtBrsHE="},"tinymce/langs/en_CA-1a9457da814b0a1f15687a00f3ae4b38da0301445b52c29a423a38c943d9a431.js":{"logical_path":"tinymce/langs/en_CA.js","mtime":"2017-04-24T19:17:55+02:00","size":6916,"digest":"1a9457da814b0a1f15687a00f3ae4b38da0301445b52c29a423a38c943d9a431","integrity":"sha256-GpRX2oFLCh8VaHoA865LONoDAURbUsKaQjo4yUPZpDE="},"tinymce/langs/en_GB-a0f7752ff9ddf3ed3d2cd24fee04fe585bca0babc4ce655560c923ad386c0c07.js":{"logical_path":"tinymce/langs/en_GB.js","mtime":"2017-04-24T19:17:55+02:00","size":5907,"digest":"a0f7752ff9ddf3ed3d2cd24fee04fe585bca0babc4ce655560c923ad386c0c07","integrity":"sha256-oPd1L/nd8+09LNJP7gT+WFvKC6vEzmVVYMkjrThsDAc="},"tinymce/langs/eo-cbac4d7ebcb0679845b852d9354e74586e78cf13eef82de1400cf6b465e203cd.js":{"logical_path":"tinymce/langs/eo.js","mtime":"2017-04-24T19:17:55+02:00","size":7466,"digest":"cbac4d7ebcb0679845b852d9354e74586e78cf13eef82de1400cf6b465e203cd","integrity":"sha256-y6xNfrywZ5hFuFLZNU50WG54zxPu+C3hQAz2tGXiA80="},"tinymce/langs/es-133cb5bd627c2a299544586bf365859b5a1c96c57d18c90e7853048434a809b6.js":{"logical_path":"tinymce/langs/es.js","mtime":"2017-04-24T19:17:55+02:00","size":7809,"digest":"133cb5bd627c2a299544586bf365859b5a1c96c57d18c90e7853048434a809b6","integrity":"sha256-Ezy1vWJ8KimVRFhr82WFm1oclsV9GMkOeFMEhDSoCbY="},"tinymce/langs/es_MX-352fcdff567919ff09a2e19c56d8059d339bffdbd999bcc82aa6d8340c19bbb9.js":{"logical_path":"tinymce/langs/es_MX.js","mtime":"2017-04-24T19:17:55+02:00","size":7894,"digest":"352fcdff567919ff09a2e19c56d8059d339bffdbd999bcc82aa6d8340c19bbb9","integrity":"sha256-NS/N/1Z5Gf8JouGcVtgFnTOb/9vZmbzIKqbYNAwZu7k="},"tinymce/langs/et-2cfc3da0ff39a37f0bd3c896d49604028f231ff0e7d8ebbc30dbfd4b87125f06.js":{"logical_path":"tinymce/langs/et.js","mtime":"2017-04-24T19:17:55+02:00","size":7784,"digest":"2cfc3da0ff39a37f0bd3c896d49604028f231ff0e7d8ebbc30dbfd4b87125f06","integrity":"sha256-LPw9oP85o38L08iW1JYEAo8jH/Dn2Ou8MNv9S4cSXwY="},"tinymce/langs/eu-8698ae4de236fcd490d0f45d485dbd33d8e9de6eb3db51191e1b4f8ea96a4d06.js":{"logical_path":"tinymce/langs/eu.js","mtime":"2017-04-24T19:17:55+02:00","size":7011,"digest":"8698ae4de236fcd490d0f45d485dbd33d8e9de6eb3db51191e1b4f8ea96a4d06","integrity":"sha256-hpiuTeI2/NSQ0PRdSF29M9jp3m6z21EZHhtPjqlqTQY="},"tinymce/langs/fa-7eff96595e93d4b0df484dd90c14b7b412966157ed8293f54429e9418882bdb2.js":{"logical_path":"tinymce/langs/fa.js","mtime":"2017-04-24T19:17:55+02:00","size":16462,"digest":"7eff96595e93d4b0df484dd90c14b7b412966157ed8293f54429e9418882bdb2","integrity":"sha256-fv+WWV6T1LDfSE3ZDBS3tBKWYVftgpP1RCnpQYiCvbI="},"tinymce/langs/fa_IR-2f9d33f16718ae9c1f3642905b58434ed2662fb66448c4d115b8491aa68e7904.js":{"logical_path":"tinymce/langs/fa_IR.js","mtime":"2017-04-24T19:17:55+02:00","size":17725,"digest":"2f9d33f16718ae9c1f3642905b58434ed2662fb66448c4d115b8491aa68e7904","integrity":"sha256-L50z8WcYrpwfNkKQW1hDTtJmL7ZkSMTRFbhJGqaOeQQ="},"tinymce/langs/fi-6ca2a93d045067a86e8ea973d0b89368054b15eb9b9625bf1ca871608a5cb77c.js":{"logical_path":"tinymce/langs/fi.js","mtime":"2017-04-24T19:17:55+02:00","size":8143,"digest":"6ca2a93d045067a86e8ea973d0b89368054b15eb9b9625bf1ca871608a5cb77c","integrity":"sha256-bKKpPQRQZ6hujqlz0LiTaAVLFeubliW/HKhxYIpct3w="},"tinymce/langs/fo-340609cecd5571e4eacb8fe7bd1343c8553d96d12610fb77d9a812dc6d3635fd.js":{"logical_path":"tinymce/langs/fo.js","mtime":"2017-04-24T19:17:55+02:00","size":8044,"digest":"340609cecd5571e4eacb8fe7bd1343c8553d96d12610fb77d9a812dc6d3635fd","integrity":"sha256-NAYJzs1VceTqy4/nvRNDyFU9ltEmEPt32agS3G02Nf0="},"tinymce/langs/fr_CH-e0f43c0f20727368ff0767f3bf099bc23eed9fe3e81f8bbe514381e786526928.js":{"logical_path":"tinymce/langs/fr_CH.js","mtime":"2017-04-24T19:17:55+02:00","size":8074,"digest":"e0f43c0f20727368ff0767f3bf099bc23eed9fe3e81f8bbe514381e786526928","integrity":"sha256-4PQ8DyByc2j/B2fzvwmbwj7tn+PoH4u+UUOB54ZSaSg="},"tinymce/langs/fr_FR-2702de7be93bd1e0d7120ae3c9e637061565186c66886f155ffca0663df25b4c.js":{"logical_path":"tinymce/langs/fr_FR.js","mtime":"2017-04-24T19:17:55+02:00","size":8009,"digest":"2702de7be93bd1e0d7120ae3c9e637061565186c66886f155ffca0663df25b4c","integrity":"sha256-JwLee+k70eDXEgrjyeY3BhVlGGxmiG8VX/ygZj3yW0w="},"tinymce/langs/ga-d2a3de6f28723d75b03f7f42fd3aedfd045d473425ee38f02350b56035383af1.js":{"logical_path":"tinymce/langs/ga.js","mtime":"2017-04-24T19:17:55+02:00","size":8591,"digest":"d2a3de6f28723d75b03f7f42fd3aedfd045d473425ee38f02350b56035383af1","integrity":"sha256-0qPebyhyPXWwP39C/Trt/QRdRzQl7jjwI1C1YDU4OvE="},"tinymce/langs/gd-0453e8b97bf3b6cca4065712ec59f20343ad6131735b38547e865177a1c1c490.js":{"logical_path":"tinymce/langs/gd.js","mtime":"2017-04-24T19:17:55+02:00","size":8808,"digest":"0453e8b97bf3b6cca4065712ec59f20343ad6131735b38547e865177a1c1c490","integrity":"sha256-BFPouXvztsykBlcS7FnyA0OtYTFzWzhUfoZRd6HBxJA="},"tinymce/langs/gl-1ff612222934f558870111f10934110c5656df3bb293c917e4eeceeb6605fcc5.js":{"logical_path":"tinymce/langs/gl.js","mtime":"2017-04-24T19:17:55+02:00","size":7066,"digest":"1ff612222934f558870111f10934110c5656df3bb293c917e4eeceeb6605fcc5","integrity":"sha256-H/YSIik09ViHARHxCTQRDFZW3zuyk8kX5O7O62YF/MU="},"tinymce/langs/he_IL-981f5250a4b8d404b37040ca5a35c30498cbeeb36e298d81bf1592b43fff7656.js":{"logical_path":"tinymce/langs/he_IL.js","mtime":"2017-04-24T19:17:55+02:00","size":16081,"digest":"981f5250a4b8d404b37040ca5a35c30498cbeeb36e298d81bf1592b43fff7656","integrity":"sha256-mB9SUKS41ASzcEDKWjXDBJjL7rNuKY2BvxWStD//dlY="},"tinymce/langs/hi_IN-695e0cdc22974fe45e0f35289f0249ddab87245165c9df765ec1b885ec55f0be.js":{"logical_path":"tinymce/langs/hi_IN.js","mtime":"2017-04-24T19:17:55+02:00","size":18458,"digest":"695e0cdc22974fe45e0f35289f0249ddab87245165c9df765ec1b885ec55f0be","integrity":"sha256-aV4M3CKXT+ReDzUonwJJ3auHJFFlyd92XsG4hexV8L4="},"tinymce/langs/hr-f77f1da2736d13f9a9a86ebf596f592fcc748f2975a0b9904b512d630f2c1a17.js":{"logical_path":"tinymce/langs/hr.js","mtime":"2017-04-24T19:17:55+02:00","size":7577,"digest":"f77f1da2736d13f9a9a86ebf596f592fcc748f2975a0b9904b512d630f2c1a17","integrity":"sha256-938donNtE/mpqG6/WW9ZL8x0jyl1oLmQS1EtYw8sGhc="},"tinymce/langs/hu_HU-1e22021a4f9c61919aa024041af555eac277bfc08ccb8c07fd329b87090a15e5.js":{"logical_path":"tinymce/langs/hu_HU.js","mtime":"2017-04-24T19:17:55+02:00","size":9410,"digest":"1e22021a4f9c61919aa024041af555eac277bfc08ccb8c07fd329b87090a15e5","integrity":"sha256-HiICGk+cYZGaoCQEGvVV6sJ3v8CMy4wH/TKbhwkKFeU="},"tinymce/langs/hy-0d384f3f82cd76793d3e7428a2140ea97f40a943f25ef99a2e3709a3e02b0930.js":{"logical_path":"tinymce/langs/hy.js","mtime":"2017-04-24T19:17:55+02:00","size":20375,"digest":"0d384f3f82cd76793d3e7428a2140ea97f40a943f25ef99a2e3709a3e02b0930","integrity":"sha256-DThPP4LNdnk9PnQoohQOqX9AqUPyXvmaLjcJo+ArCTA="},"tinymce/langs/id-e9fd018be745b5f14f4af47887420f98c590c607e01d57aca77ef5affe188523.js":{"logical_path":"tinymce/langs/id.js","mtime":"2017-04-24T19:17:55+02:00","size":7141,"digest":"e9fd018be745b5f14f4af47887420f98c590c607e01d57aca77ef5affe188523","integrity":"sha256-6f0Bi+dFtfFPSvR4h0IPmMWQxgfgHVesp371r/4YhSM="},"tinymce/langs/is_IS-c6e8c3e7b0e6b447faec3d8d258928f97c84558b29882c056513fb71cf237bfa.js":{"logical_path":"tinymce/langs/is_IS.js","mtime":"2017-04-24T19:17:55+02:00","size":7928,"digest":"c6e8c3e7b0e6b447faec3d8d258928f97c84558b29882c056513fb71cf237bfa","integrity":"sha256-xujD57DmtEf67D2NJYko+XyEVYspiCwFZRP7cc8je/o="},"tinymce/langs/it-25b5546d48c80ad666b600e5be3a05718b80645721b191785c1fafe1853f4a46.js":{"logical_path":"tinymce/langs/it.js","mtime":"2017-04-24T19:17:55+02:00","size":7598,"digest":"25b5546d48c80ad666b600e5be3a05718b80645721b191785c1fafe1853f4a46","integrity":"sha256-JbVUbUjICtZmtgDlvjoFcYuAZFchsZF4XB+v4YU/SkY="},"tinymce/langs/ja-80f0e7414030c32617ff651da1affa0bc85ee514fc9bc81f46edfd8ce0053ac0.js":{"logical_path":"tinymce/langs/ja.js","mtime":"2017-04-24T19:17:55+02:00","size":12290,"digest":"80f0e7414030c32617ff651da1affa0bc85ee514fc9bc81f46edfd8ce0053ac0","integrity":"sha256-gPDnQUAwwyYX/2Udoa/6C8he5RT8m8gfRu39jOAFOsA="},"tinymce/langs/ka_GE-3c6b82346a7070a8b6a15ae6e8faeecc5bfe63ad7e616b7de2e8ab8a75ec39c2.js":{"logical_path":"tinymce/langs/ka_GE.js","mtime":"2017-04-24T19:17:55+02:00","size":21284,"digest":"3c6b82346a7070a8b6a15ae6e8faeecc5bfe63ad7e616b7de2e8ab8a75ec39c2","integrity":"sha256-PGuCNGpwcKi2oVrm6PruzFv+Y61+YWt94uirinXsOcI="},"tinymce/langs/kab-3651d08aacd5bda15a04698f202bf616efbf13d3789aadd9ce4f93e430818c13.js":{"logical_path":"tinymce/langs/kab.js","mtime":"2017-04-24T19:17:55+02:00","size":7391,"digest":"3651d08aacd5bda15a04698f202bf616efbf13d3789aadd9ce4f93e430818c13","integrity":"sha256-NlHQiqzVvaFaBGmPICv2Fu+/E9N4mq3Zzk+T5DCBjBM="},"tinymce/langs/kk-0c1ba792ed9445c6512f310228f64d1cde7b5a98e0b212cca749dcb2d728fe86.js":{"logical_path":"tinymce/langs/kk.js","mtime":"2017-04-24T19:17:55+02:00","size":16681,"digest":"0c1ba792ed9445c6512f310228f64d1cde7b5a98e0b212cca749dcb2d728fe86","integrity":"sha256-DBunku2URcZRLzECKPZNHN57WpjgshLMp0ncstco/oY="},"tinymce/langs/km_KH-8bec84e4078db8c2a680260c073dfb486c85b61df62e14ca330d66d2ca2a85b5.js":{"logical_path":"tinymce/langs/km_KH.js","mtime":"2017-04-24T19:17:55+02:00","size":21396,"digest":"8bec84e4078db8c2a680260c073dfb486c85b61df62e14ca330d66d2ca2a85b5","integrity":"sha256-i+yE5AeNuMKmgCYMBz37SGyFth32LhTKMw1m0soqhbU="},"tinymce/langs/ko-ca535bfa388701fb020d24bdfb3f1e3aab127005b54e943cb1bd60b723c8194d.js":{"logical_path":"tinymce/langs/ko.js","mtime":"2017-04-24T19:17:55+02:00","size":10105,"digest":"ca535bfa388701fb020d24bdfb3f1e3aab127005b54e943cb1bd60b723c8194d","integrity":"sha256-ylNb+jiHAfsCDSS9+z8eOqsScAW1TpQ8sb1gtyPIGU0="},"tinymce/langs/ko_KR-daa3ae950d70260bb0901a5349034952247905523bbc2bcbe527701b6aad8e28.js":{"logical_path":"tinymce/langs/ko_KR.js","mtime":"2017-04-24T19:17:55+02:00","size":10005,"digest":"daa3ae950d70260bb0901a5349034952247905523bbc2bcbe527701b6aad8e28","integrity":"sha256-2qOulQ1wJguwkBpTSQNJUiR5BVI7vCvL5SdwG2qtjig="},"tinymce/langs/ku-95e2ffe4f0112df658f10327c26f2cdddedc2e2ed769767366ae22a465c14725.js":{"logical_path":"tinymce/langs/ku.js","mtime":"2017-04-24T19:17:55+02:00","size":18274,"digest":"95e2ffe4f0112df658f10327c26f2cdddedc2e2ed769767366ae22a465c14725","integrity":"sha256-leL/5PARLfZY8QMnwm8s3d7cLi7XaXZzZq4ipGXBRyU="},"tinymce/langs/ku_IQ-a212e8d41695989e56834facf72474e1934ef166c3fcaf7e255ef573a3c6e76c.js":{"logical_path":"tinymce/langs/ku_IQ.js","mtime":"2017-04-24T19:17:55+02:00","size":18364,"digest":"a212e8d41695989e56834facf72474e1934ef166c3fcaf7e255ef573a3c6e76c","integrity":"sha256-ohLo1BaVmJ5Wg0+s9yR04ZNO8WbD/K9+JV71c6PG52w="},"tinymce/langs/lb-94992279091f1a0be927d5d858d3724037d8d81ee6b63cc9ddde84af6124cc04.js":{"logical_path":"tinymce/langs/lb.js","mtime":"2017-04-24T19:17:55+02:00","size":7467,"digest":"94992279091f1a0be927d5d858d3724037d8d81ee6b63cc9ddde84af6124cc04","integrity":"sha256-lJkieQkfGgvpJ9XYWNNyQDfY2B7mtjzJ3d6Er2EkzAQ="},"tinymce/langs/lt-ae7cefbe2cb5420770b31eabf92605728135ab5d6a2d2cfca2d19809be67e6a8.js":{"logical_path":"tinymce/langs/lt.js","mtime":"2017-04-24T19:17:55+02:00","size":8899,"digest":"ae7cefbe2cb5420770b31eabf92605728135ab5d6a2d2cfca2d19809be67e6a8","integrity":"sha256-rnzvviy1Qgdwsx6r+SYFcoE1q11qLSz8otGYCb5n5qg="},"tinymce/langs/lv-e468ed0c78466d1fff9f4957645606d8aa683cb5dc35931e047df97b8e4f5433.js":{"logical_path":"tinymce/langs/lv.js","mtime":"2017-04-24T19:17:55+02:00","size":8282,"digest":"e468ed0c78466d1fff9f4957645606d8aa683cb5dc35931e047df97b8e4f5433","integrity":"sha256-5GjtDHhGbR//n0lXZFYG2KpoPLXcNZMeBH35e45PVDM="},"tinymce/langs/mk_MK-55aadb5d7c82c940cfcf42f24423ef0471294c9b02994a6b22e1b4173baa7ec6.js":{"logical_path":"tinymce/langs/mk_MK.js","mtime":"2017-04-24T19:17:55+02:00","size":18733,"digest":"55aadb5d7c82c940cfcf42f24423ef0471294c9b02994a6b22e1b4173baa7ec6","integrity":"sha256-VarbXXyCyUDPz0LyRCPvBHEpTJsCmUprIuG0FzuqfsY="},"tinymce/langs/ml-685de0808683c02274dcbe9f8de023a4d72a49b040e7526a99e3d5c786ff71ae.js":{"logical_path":"tinymce/langs/ml.js","mtime":"2017-04-24T19:17:55+02:00","size":7339,"digest":"685de0808683c02274dcbe9f8de023a4d72a49b040e7526a99e3d5c786ff71ae","integrity":"sha256-aF3ggIaDwCJ03L6fjeAjpNcqSbBA51JqmePVx4b/ca4="},"tinymce/langs/ml_IN-1ab433621d6257c7632718048bacc5ed98a302d33cf0438bbbb4200914e01aac.js":{"logical_path":"tinymce/langs/ml_IN.js","mtime":"2017-04-24T19:17:55+02:00","size":20019,"digest":"1ab433621d6257c7632718048bacc5ed98a302d33cf0438bbbb4200914e01aac","integrity":"sha256-GrQzYh1iV8djJxgEi6zF7ZijAtM88EOLu7QgCRTgGqw="},"tinymce/langs/mn_MN-b89f88cb9b0dd7c879e27532b2979c421c1e69648f65a4108a56060f1e1cb009.js":{"logical_path":"tinymce/langs/mn_MN.js","mtime":"2017-04-24T19:17:55+02:00","size":6877,"digest":"b89f88cb9b0dd7c879e27532b2979c421c1e69648f65a4108a56060f1e1cb009","integrity":"sha256-uJ+Iy5sN18h54nUyspecQhweaWSPZaQQilYGDx4csAk="},"tinymce/langs/nb_NO-602ee249e98a26ae24c1ee1311090c68a782050086a835f1e7bd46ebfe7879ef.js":{"logical_path":"tinymce/langs/nb_NO.js","mtime":"2017-04-24T19:17:55+02:00","size":7528,"digest":"602ee249e98a26ae24c1ee1311090c68a782050086a835f1e7bd46ebfe7879ef","integrity":"sha256-YC7iSemKJq4kwe4TEQkMaKeCBQCGqDXx571G6/54ee8="},"tinymce/langs/nl-9c77e9404a27fd7e4bd162ad44538b72d2725b7fee7be7ca3ff801cf217c4968.js":{"logical_path":"tinymce/langs/nl.js","mtime":"2017-04-24T19:17:55+02:00","size":7235,"digest":"9c77e9404a27fd7e4bd162ad44538b72d2725b7fee7be7ca3ff801cf217c4968","integrity":"sha256-nHfpQEon/X5L0WKtRFOLctJyW3/ue+fKP/gBzyF8SWg="},"tinymce/langs/pl-5cdd1586ec8fa67293f2175cd92edbd0392c4c77b24ed64cfdceccba8d99f152.js":{"logical_path":"tinymce/langs/pl.js","mtime":"2017-04-24T19:17:55+02:00","size":8129,"digest":"5cdd1586ec8fa67293f2175cd92edbd0392c4c77b24ed64cfdceccba8d99f152","integrity":"sha256-XN0VhuyPpnKT8hdc2S7b0DksTHeyTtZM/c7Muo2Z8VI="},"tinymce/langs/pt_BR-e3955318582d58bd241a62c3a81afe74e0ae7f31bdc92a562b75243701f114df.js":{"logical_path":"tinymce/langs/pt_BR.js","mtime":"2017-04-24T19:17:55+02:00","size":8002,"digest":"e3955318582d58bd241a62c3a81afe74e0ae7f31bdc92a562b75243701f114df","integrity":"sha256-45VTGFgtWL0kGmLDqBr+dOCufzG9ySpWK3UkNwHxFN8="},"tinymce/langs/pt_PT-1101d080ecd5da091c7ef70b23200adbd5136c5c32f0c79dae665a443d76c35d.js":{"logical_path":"tinymce/langs/pt_PT.js","mtime":"2017-04-24T19:17:55+02:00","size":8145,"digest":"1101d080ecd5da091c7ef70b23200adbd5136c5c32f0c79dae665a443d76c35d","integrity":"sha256-EQHQgOzV2gkcfvcLIyAK29UTbFwy8MedrmZaRD12w10="},"tinymce/langs/ro-484799d182031efab087d749b024014fd06ed06c1e7712b8bf87f3a4a965c2e4.js":{"logical_path":"tinymce/langs/ro.js","mtime":"2017-04-24T19:17:55+02:00","size":8275,"digest":"484799d182031efab087d749b024014fd06ed06c1e7712b8bf87f3a4a965c2e4","integrity":"sha256-SEeZ0YIDHvqwh9dJsCQBT9Bu0GwedxK4v4fzpKllwuQ="},"tinymce/langs/ru-bdd59cb662a7b4d61e770b07014d1791051312c87513ecc1891e80beba617171.js":{"logical_path":"tinymce/langs/ru.js","mtime":"2017-04-24T19:17:55+02:00","size":22290,"digest":"bdd59cb662a7b4d61e770b07014d1791051312c87513ecc1891e80beba617171","integrity":"sha256-vdWctmKntNYedwsHAU0XkQUTEsh1E+zBiR6AvrphcXE="},"tinymce/langs/ru_RU-9f18ef14f3493cc586cc0b4827fd9e1c2ed3d5790ce536d94f87e2d6aac2a688.js":{"logical_path":"tinymce/langs/ru_RU.js","mtime":"2017-04-24T19:17:55+02:00","size":4955,"digest":"9f18ef14f3493cc586cc0b4827fd9e1c2ed3d5790ce536d94f87e2d6aac2a688","integrity":"sha256-nxjvFPNJPMWGzAtIJ/2eHC7T1XkM5TbZT4fi1qrCpog="},"tinymce/langs/si_LK-5bfefe9b2fe82574d8ed839df18fd8ff65f1e1cd458b0a843cf1aadd1be704ea.js":{"logical_path":"tinymce/langs/si_LK.js","mtime":"2017-04-24T19:17:55+02:00","size":15856,"digest":"5bfefe9b2fe82574d8ed839df18fd8ff65f1e1cd458b0a843cf1aadd1be704ea","integrity":"sha256-W/7+my/oJXTY7YOd8Y/Y/2Xx4c1FiwqEPPGq3RvnBOo="},"tinymce/langs/sk-412fa7f982ad2733341203daa035c8ba10035262ca8f5f65e0a41507512209bd.js":{"logical_path":"tinymce/langs/sk.js","mtime":"2017-04-24T19:17:55+02:00","size":8958,"digest":"412fa7f982ad2733341203daa035c8ba10035262ca8f5f65e0a41507512209bd","integrity":"sha256-QS+n+YKtJzM0EgPaoDXIuhADUmLKj19l4KQVB1EiCb0="},"tinymce/langs/sl_SI-2bea4f3854a992ea840808019dc99467dc173b12454ea6016135234a741671d8.js":{"logical_path":"tinymce/langs/sl_SI.js","mtime":"2017-04-24T19:17:55+02:00","size":7039,"digest":"2bea4f3854a992ea840808019dc99467dc173b12454ea6016135234a741671d8","integrity":"sha256-K+pPOFSpkuqECAgBncmUZ9wXOxJFTqYBYTUjSnQWcdg="},"tinymce/langs/sr-e0b97453a0c1000b19f7ce37fcf86bcacbf9125d81076f60a77686820c7925c6.js":{"logical_path":"tinymce/langs/sr.js","mtime":"2017-04-24T19:17:55+02:00","size":6336,"digest":"e0b97453a0c1000b19f7ce37fcf86bcacbf9125d81076f60a77686820c7925c6","integrity":"sha256-4Ll0U6DBAAsZ9843/Phrysv5El2BB29gp3aGggx5JcY="},"tinymce/langs/sv_SE-fa561a7e49fdb42d5913337176fed6bc8a9997eb3ca8f20ecd9520d5391e17be.js":{"logical_path":"tinymce/langs/sv_SE.js","mtime":"2017-04-24T19:17:55+02:00","size":7496,"digest":"fa561a7e49fdb42d5913337176fed6bc8a9997eb3ca8f20ecd9520d5391e17be","integrity":"sha256-+lYafkn9tC1ZEzNxdv7WvIqZl+s8qPIOzZUg1TkeF74="},"tinymce/langs/ta-0fd0e62250fc1a3626ac2111c5adb4194a6a898888bb224414f6dc8adf53d385.js":{"logical_path":"tinymce/langs/ta.js","mtime":"2017-04-24T19:17:55+02:00","size":22617,"digest":"0fd0e62250fc1a3626ac2111c5adb4194a6a898888bb224414f6dc8adf53d385","integrity":"sha256-D9DmIlD8GjYmrCERxa20GUpqiYiIuyJEFPbcit9T04U="},"tinymce/langs/ta_IN-32303f65d2378e8202b17b0920b79277a2580872e3a6bd9409aeceef90867dd0.js":{"logical_path":"tinymce/langs/ta_IN.js","mtime":"2017-04-24T19:17:55+02:00","size":22620,"digest":"32303f65d2378e8202b17b0920b79277a2580872e3a6bd9409aeceef90867dd0","integrity":"sha256-MjA/ZdI3joICsXsJILeSd6JYCHLjpr2UCa7O75CGfdA="},"tinymce/langs/tg-1618248bf0aeda614a37ced9fd28b6623ae24f8453368bfb8c483ce820a3cb34.js":{"logical_path":"tinymce/langs/tg.js","mtime":"2017-04-24T19:17:55+02:00","size":18183,"digest":"1618248bf0aeda614a37ced9fd28b6623ae24f8453368bfb8c483ce820a3cb34","integrity":"sha256-Fhgki/Cu2mFKN87Z/Si2YjriT4RTNov7jEg86CCjyzQ="},"tinymce/langs/th_TH-5279a379afc886c2a31e22aba9d7ee7a8e3edf4c0785f39aaa20ccd03d46b19a.js":{"logical_path":"tinymce/langs/th_TH.js","mtime":"2017-04-24T19:17:55+02:00","size":17297,"digest":"5279a379afc886c2a31e22aba9d7ee7a8e3edf4c0785f39aaa20ccd03d46b19a","integrity":"sha256-Unmjea/IhsKjHiKrqdfueo4+30wHhfOaqiDM0D1GsZo="},"tinymce/langs/tr-3765d4a8923ef22864747d9c825c3e0af401e1356e75a5458bed837d486b7673.js":{"logical_path":"tinymce/langs/tr.js","mtime":"2017-04-24T19:17:55+02:00","size":8705,"digest":"3765d4a8923ef22864747d9c825c3e0af401e1356e75a5458bed837d486b7673","integrity":"sha256-N2XUqJI+8ihkdH2cglw+CvQB4TVudaVFi+2DfUhrdnM="},"tinymce/langs/tr_TR-5c93f80b89e5dd2eb6972f37bf50b76d7705c61f28120b836704a91fa5c14399.js":{"logical_path":"tinymce/langs/tr_TR.js","mtime":"2017-04-24T19:17:55+02:00","size":8141,"digest":"5c93f80b89e5dd2eb6972f37bf50b76d7705c61f28120b836704a91fa5c14399","integrity":"sha256-XJP4C4nl3S62ly83v1C3bXcFxh8oEguDZwSpH6XBQ5k="},"tinymce/langs/tt-22e302672df0a77de14688f58dbedf82de7a26e9089c9535a2a3cd1c0ccd7903.js":{"logical_path":"tinymce/langs/tt.js","mtime":"2017-04-24T19:17:55+02:00","size":19035,"digest":"22e302672df0a77de14688f58dbedf82de7a26e9089c9535a2a3cd1c0ccd7903","integrity":"sha256-IuMCZy3wp33hRoj1jb7fgt56JukInJU1oqPNHAzNeQM="},"tinymce/langs/ug-50232038bf7262c90be4f2919c74ff93792cdb82e6064d0f5c86f885b93271c5.js":{"logical_path":"tinymce/langs/ug.js","mtime":"2017-04-24T19:17:55+02:00","size":16888,"digest":"50232038bf7262c90be4f2919c74ff93792cdb82e6064d0f5c86f885b93271c5","integrity":"sha256-UCMgOL9yYskL5PKRnHT/k3ks24LmBk0PXIb4hbkyccU="},"tinymce/langs/uk-f6d7911714c422b178c0249df323cf7ec415a83195d751c7e4024590b1738c42.js":{"logical_path":"tinymce/langs/uk.js","mtime":"2017-04-24T19:17:55+02:00","size":22264,"digest":"f6d7911714c422b178c0249df323cf7ec415a83195d751c7e4024590b1738c42","integrity":"sha256-9teRFxTEIrF4wCSd8yPPfsQVqDGV11HH5AJFkLFzjEI="},"tinymce/langs/uk_UA-bd8cd7ca66228d85f8a4cadb651c49981f26e007fa2a952856c8c3d3c1baa66a.js":{"logical_path":"tinymce/langs/uk_UA.js","mtime":"2017-04-24T19:17:55+02:00","size":21691,"digest":"bd8cd7ca66228d85f8a4cadb651c49981f26e007fa2a952856c8c3d3c1baa66a","integrity":"sha256-vYzXymYijYX4pMrbZRxJmB8m4Af6KpUoVsjD08G6pmo="},"tinymce/langs/vi-6aa451047e4df911c92e10178e6a70147534e438c64df7a88eee37b4a440726e.js":{"logical_path":"tinymce/langs/vi.js","mtime":"2017-04-24T19:17:55+02:00","size":9901,"digest":"6aa451047e4df911c92e10178e6a70147534e438c64df7a88eee37b4a440726e","integrity":"sha256-aqRRBH5N+RHJLhAXjmpwFHU05DjGTfeoju43tKRAcm4="},"tinymce/langs/vi_VN-aea52c2e9397f8a657d54d50a42b3c5be0ca79480555a4fa1e0f5d785c5f6561.js":{"logical_path":"tinymce/langs/vi_VN.js","mtime":"2017-04-24T19:17:55+02:00","size":9899,"digest":"aea52c2e9397f8a657d54d50a42b3c5be0ca79480555a4fa1e0f5d785c5f6561","integrity":"sha256-rqUsLpOX+KZX1U1QpCs8W+DKeUgFVaT6Hg9deFxfZWE="},"tinymce/langs/zh_CN-8622ec46e2980b6f5baf3b745c6b0187dd2a54ddecbbf69a21f0b3e72f84f6dc.js":{"logical_path":"tinymce/langs/zh_CN.js","mtime":"2017-04-24T19:17:55+02:00","size":8483,"digest":"8622ec46e2980b6f5baf3b745c6b0187dd2a54ddecbbf69a21f0b3e72f84f6dc","integrity":"sha256-hiLsRuKYC29brzt0XGsBh90qVN3su/aaIfCz5y+E9tw="},"tinymce/langs/zh_TW-90723da3b889f2a4477d4aaf00ca3e75439998269b36b359ea4caa37e1defb4a.js":{"logical_path":"tinymce/langs/zh_TW.js","mtime":"2017-04-24T19:17:55+02:00","size":9379,"digest":"90723da3b889f2a4477d4aaf00ca3e75439998269b36b359ea4caa37e1defb4a","integrity":"sha256-kHI9o7iJ8qRHfUqvAMo+dUOZmCabNrNZ6kyqN+He+0o="},"tinymce/preinit-84328a53e798df12f891eb49871773fd9f925439c8630e9e22423a82ef9e6f89.js":{"logical_path":"tinymce/preinit.js","mtime":"2017-01-05T19:24:14+01:00","size":82,"digest":"84328a53e798df12f891eb49871773fd9f925439c8630e9e22423a82ef9e6f89","integrity":"sha256-hDKKU+eY3xL4ketJhxdz/Z+SVDnIYw6eIkI6gu+eb4k="},"tinymce/tinymce-6c5174912bf31a8ee031a9acb5d2b7d05f7bcd42e3ed0d26d7d217a5343eb2bf.js":{"logical_path":"tinymce/tinymce.js","mtime":"2017-01-05T19:24:14+01:00","size":1294513,"digest":"6c5174912bf31a8ee031a9acb5d2b7d05f7bcd42e3ed0d26d7d217a5343eb2bf","integrity":"sha256-bFF0kSvzGo7gMamstdK30F97zULj7Q0m19IXpTQ+sr8="},"tinymce/jquery.tinymce-275e24af4bf53bfb60f7fef218163106ad0648b8ad384ecfab9b4fd52f48603d.js":{"logical_path":"tinymce/jquery.tinymce.js","mtime":"2017-05-02T18:30:07+02:00","size":3592,"digest":"275e24af4bf53bfb60f7fef218163106ad0648b8ad384ecfab9b4fd52f48603d","integrity":"sha256-J14kr0v1O/tg9/7yGBYxBq0GSLitOE7Pq5tP1S9IYD0="},"tinymce/langs/readme-5a8b6a04d57b5c88e3fb7f2a870b8e2d3a48ec03ce6474206c41df78c155b2de.md":{"logical_path":"tinymce/langs/readme.md","mtime":"2017-05-06T15:41:53+02:00","size":151,"digest":"5a8b6a04d57b5c88e3fb7f2a870b8e2d3a48ec03ce6474206c41df78c155b2de","integrity":"sha256-WotqBNV7XIjj+38qhwuOLTpI7APOZHQgbEHfeMFVst4="},"tinymce/license-5fda611b8191f00121f161a93e7399cdb71789dba923e8ed09b50a1f78d32c5e.txt":{"logical_path":"tinymce/license.txt","mtime":"2017-05-02T18:30:07+02:00","size":26427,"digest":"5fda611b8191f00121f161a93e7399cdb71789dba923e8ed09b50a1f78d32c5e","integrity":"sha256-X9phG4GR8AEh8WGpPnOZzbcXidupI+jtCbUKH3jTLF4="},"tinymce/plugins/advlist/plugin-d0bd2b90c1aaf60ddbb048d955f7fbf76e303b5f3227f8e4dc83207548c3fc46.js":{"logical_path":"tinymce/plugins/advlist/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":2092,"digest":"d0bd2b90c1aaf60ddbb048d955f7fbf76e303b5f3227f8e4dc83207548c3fc46","integrity":"sha256-0L0rkMGq9g3bsEjZVff7924wO18yJ/jk3IMgdUjD/EY="},"tinymce/plugins/anchor/plugin-48c211e97cdf2fba4e8456ddc0464c301c61ff2d2751aa178d41c5eca38fbbe9.js":{"logical_path":"tinymce/plugins/anchor/plugin.js","mtime":"2017-01-05T19:24:14+01:00","size":958,"digest":"48c211e97cdf2fba4e8456ddc0464c301c61ff2d2751aa178d41c5eca38fbbe9","integrity":"sha256-SMIR6XzfL7pOhFbdwEZMMBxh/y0nUaoXjUHF7KOPu+k="},"tinymce/plugins/autolink/plugin-9d514baa6f3816a43008241db075d724fcb274632fad3db792e87e5feb6c5d0f.js":{"logical_path":"tinymce/plugins/autolink/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":2061,"digest":"9d514baa6f3816a43008241db075d724fcb274632fad3db792e87e5feb6c5d0f","integrity":"sha256-nVFLqm84FqQwCCQdsHXXJPyydGMvrT23kuh+X+tsXQ8="},"tinymce/plugins/autoresize/plugin-7cd05d5431f8713c948291ad40ef63eabe44908bd831d5675afacaca296a4d7b.js":{"logical_path":"tinymce/plugins/autoresize/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1904,"digest":"7cd05d5431f8713c948291ad40ef63eabe44908bd831d5675afacaca296a4d7b","integrity":"sha256-fNBdVDH4cTyUgpGtQO9j6r5EkIvYMdVnWvrKyilqTXs="},"tinymce/plugins/autosave/plugin-43448ce025b165ed1b509554cadf02cda4ed104ccfae6d0708379f02e981220f.js":{"logical_path":"tinymce/plugins/autosave/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":2188,"digest":"43448ce025b165ed1b509554cadf02cda4ed104ccfae6d0708379f02e981220f","integrity":"sha256-Q0SM4CWxZe0bUJVUyt8CzaTtEEzPrm0HCDefAumBIg8="},"tinymce/plugins/bbcode/plugin-dae2432b6477ca1acc3bd6ac7af33c379797c7f2dcf2c82513475d4c234d851d.js":{"logical_path":"tinymce/plugins/bbcode/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":3137,"digest":"dae2432b6477ca1acc3bd6ac7af33c379797c7f2dcf2c82513475d4c234d851d","integrity":"sha256-2uJDK2R3yhrMO9asevM8N5eXx/Lc8sglE0ddTCNNhR0="},"tinymce/plugins/charmap/plugin-ee3f9ed5d0135f19975a4609701b4b4546f00ab1afee9b74a38bb3d76ab94eca.js":{"logical_path":"tinymce/plugins/charmap/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":8200,"digest":"ee3f9ed5d0135f19975a4609701b4b4546f00ab1afee9b74a38bb3d76ab94eca","integrity":"sha256-7j+e1dATXxmXWkYJcBtLRUbwCrGv7pt0o4uz12q5Tso="},"tinymce/plugins/code/plugin-093b2519070297197c89cabd2b7bf7b7920786fa3ae5b055322fb16d51d113d4.js":{"logical_path":"tinymce/plugins/code/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":722,"digest":"093b2519070297197c89cabd2b7bf7b7920786fa3ae5b055322fb16d51d113d4","integrity":"sha256-CTslGQcClxl8icq9K3v3t5IHhvo65bBVMi+xbVHRE9Q="},"tinymce/plugins/codesample/css/prism-1988b66704b4d23e78c6c20c38a6856cbc1f0be96d6d60a3a0b12f4408f1057e.css":{"logical_path":"tinymce/plugins/codesample/css/prism.css","mtime":"2017-05-06T15:41:53+02:00","size":1776,"digest":"1988b66704b4d23e78c6c20c38a6856cbc1f0be96d6d60a3a0b12f4408f1057e","integrity":"sha256-GYi2ZwS00j54xsIMOKaFbLwfC+ltbWCjoLEvRAjxBX4="},"tinymce/plugins/codesample/plugin-edd0d2e7f821002843d7726182d9a8b1520fcabb753b95ee7956180337be23da.js":{"logical_path":"tinymce/plugins/codesample/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":20333,"digest":"edd0d2e7f821002843d7726182d9a8b1520fcabb753b95ee7956180337be23da","integrity":"sha256-7dDS5/ghAChD13JhgtmosVIPyrt1O5XueVYYAze+I9o="},"tinymce/plugins/colorpicker/plugin-526e08119d96ecdeeb21c1031cba4b471aba860fbc6ed0f8a010275088c00531.js":{"logical_path":"tinymce/plugins/colorpicker/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1223,"digest":"526e08119d96ecdeeb21c1031cba4b471aba860fbc6ed0f8a010275088c00531","integrity":"sha256-Um4IEZ2W7N7rIcEDHLpLRxq6hg+8btD4oBAnUIjABTE="},"tinymce/plugins/contextmenu/plugin-11ad7a2ff14cc47d12a3dd0170741590335e606b0efaa8dc77837409e54afa0a.js":{"logical_path":"tinymce/plugins/contextmenu/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1132,"digest":"11ad7a2ff14cc47d12a3dd0170741590335e606b0efaa8dc77837409e54afa0a","integrity":"sha256-Ea16L/FMxH0So90BcHQVkDNeYGsO+qjcd4N0CeVK+go="},"tinymce/plugins/directionality/plugin-6381fb028625726e50977d00f342fa1f60e39dc794e0ea1c7d9feff8846ab9fc.js":{"logical_path":"tinymce/plugins/directionality/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":727,"digest":"6381fb028625726e50977d00f342fa1f60e39dc794e0ea1c7d9feff8846ab9fc","integrity":"sha256-Y4H7AoYlcm5Ql30A80L6H2DjnceU4OocfZ/v+IRqufw="},"tinymce/plugins/emoticons/img/smiley-cool-bb0e93a050a32df7913e4026b3c88a176998e0e3e073ba06e9b73f6c24227c9c.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-cool.gif","mtime":"2017-05-06T15:41:53+02:00","size":354,"digest":"bb0e93a050a32df7913e4026b3c88a176998e0e3e073ba06e9b73f6c24227c9c","integrity":"sha256-uw6ToFCjLfeRPkAms8iKF2mY4OPgc7oG6bc/bCQifJw="},"tinymce/plugins/emoticons/img/smiley-cry-a0c5f3e7a682449c973c9d9f7c46342081c46920686d2353f57aff91ab907f68.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-cry.gif","mtime":"2017-05-06T15:41:53+02:00","size":329,"digest":"a0c5f3e7a682449c973c9d9f7c46342081c46920686d2353f57aff91ab907f68","integrity":"sha256-oMXz56aCRJyXPJ2ffEY0IIHEaSBobSNT9Xr/kauQf2g="},"tinymce/plugins/emoticons/img/smiley-embarassed-d3cafcb50b335672cb5e9f4600ea9ea261dac7828dd28844d4927c393a25618f.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-embarassed.gif","mtime":"2017-05-06T15:41:53+02:00","size":331,"digest":"d3cafcb50b335672cb5e9f4600ea9ea261dac7828dd28844d4927c393a25618f","integrity":"sha256-08r8tQszVnLLXp9GAOqeomHax4KN0ohE1JJ8OTolYY8="},"tinymce/plugins/emoticons/img/smiley-foot-in-mouth-03fe04d3ed533423ac81f05146584b0c451be3d4a30e76687ceef283ed07071f.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-foot-in-mouth.gif","mtime":"2017-05-06T15:41:53+02:00","size":342,"digest":"03fe04d3ed533423ac81f05146584b0c451be3d4a30e76687ceef283ed07071f","integrity":"sha256-A/4E0+1TNCOsgfBRRlhLDEUb49SjDnZofO7yg+0HBx8="},"tinymce/plugins/emoticons/img/smiley-frown-1b984bf98931dd1debb54461eb9d83e985f2b2999fe14bcb556d6c0921bc83b0.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-frown.gif","mtime":"2017-05-06T15:41:53+02:00","size":340,"digest":"1b984bf98931dd1debb54461eb9d83e985f2b2999fe14bcb556d6c0921bc83b0","integrity":"sha256-G5hL+Ykx3R3rtURh652D6YXyspmf4UvLVW1sCSG8g7A="},"tinymce/plugins/emoticons/img/smiley-innocent-8db353ef102196f2c6ddf5c4666446de955d7b14fc0957c806c9dbfb48fb0c29.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-innocent.gif","mtime":"2017-05-06T15:41:53+02:00","size":336,"digest":"8db353ef102196f2c6ddf5c4666446de955d7b14fc0957c806c9dbfb48fb0c29","integrity":"sha256-jbNT7xAhlvLG3fXEZmRG3pVdexT8CVfIBsnb+0j7DCk="},"tinymce/plugins/emoticons/img/smiley-kiss-3154c3665356c13ab10fefdbac1fe187fff978a0052037c99cdc4a97103413f2.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-kiss.gif","mtime":"2017-05-06T15:41:53+02:00","size":338,"digest":"3154c3665356c13ab10fefdbac1fe187fff978a0052037c99cdc4a97103413f2","integrity":"sha256-MVTDZlNWwTqxD+/brB/hh//5eKAFIDfJnNxKlxA0E/I="},"tinymce/plugins/emoticons/img/smiley-laughing-8f6adedcd091975ffead171867a6304d908bb6541a6ccb4919286ec6b7d4551e.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-laughing.gif","mtime":"2017-05-06T15:41:53+02:00","size":343,"digest":"8f6adedcd091975ffead171867a6304d908bb6541a6ccb4919286ec6b7d4551e","integrity":"sha256-j2re3NCRl1/+rRcYZ6YwTZCLtlQabMtJGShuxrfUVR4="},"tinymce/plugins/emoticons/img/smiley-money-mouth-f0b9f4f22e237f5dbc851f900fed8d7eca4c954ae6fbc606c0cd8be431d0ac80.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-money-mouth.gif","mtime":"2017-05-06T15:41:53+02:00","size":321,"digest":"f0b9f4f22e237f5dbc851f900fed8d7eca4c954ae6fbc606c0cd8be431d0ac80","integrity":"sha256-8Ln08i4jf128hR+QD+2NfspMlUrm+8YGwM2L5DHQrIA="},"tinymce/plugins/emoticons/img/smiley-sealed-9933b442636b6e537df7b564e2c3f7a2873526eea6b022a98eb1e468e5204c32.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-sealed.gif","mtime":"2017-05-06T15:41:53+02:00","size":323,"digest":"9933b442636b6e537df7b564e2c3f7a2873526eea6b022a98eb1e468e5204c32","integrity":"sha256-mTO0QmNrblN997Vk4sP3ooc1Ju6msCKpjrHkaOUgTDI="},"tinymce/plugins/emoticons/img/smiley-smile-fd89cd460ffcacb7e725e00c0275ef5b3924ce468248e5ff4fb43545571cfa65.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-smile.gif","mtime":"2017-05-06T15:41:53+02:00","size":344,"digest":"fd89cd460ffcacb7e725e00c0275ef5b3924ce468248e5ff4fb43545571cfa65","integrity":"sha256-/YnNRg/8rLfnJeAMAnXvWzkkzkaCSOX/T7Q1RVcc+mU="},"tinymce/plugins/emoticons/img/smiley-surprised-3871f356cb41976d7ae8a5f005e8739e4d014352a8adef9b33f773d81b6e6c01.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-surprised.gif","mtime":"2017-05-06T15:41:53+02:00","size":338,"digest":"3871f356cb41976d7ae8a5f005e8739e4d014352a8adef9b33f773d81b6e6c01","integrity":"sha256-OHHzVstBl2166KXwBehznk0BQ1Kore+bM/dz2BtubAE="},"tinymce/plugins/emoticons/img/smiley-tongue-out-5843c85667a8226dc43be83749fd9fbbc5d20b1577de2b763915d99815d37d47.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-tongue-out.gif","mtime":"2017-05-06T15:41:53+02:00","size":328,"digest":"5843c85667a8226dc43be83749fd9fbbc5d20b1577de2b763915d99815d37d47","integrity":"sha256-WEPIVmeoIm3EO+g3Sf2fu8XSCxV33it2ORXZmBXTfUc="},"tinymce/plugins/emoticons/img/smiley-undecided-d8b9bcbb433951ff3c4ca8dd959ac3844239b98e6d52218833e1485a91f67347.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-undecided.gif","mtime":"2017-05-06T15:41:53+02:00","size":337,"digest":"d8b9bcbb433951ff3c4ca8dd959ac3844239b98e6d52218833e1485a91f67347","integrity":"sha256-2Lm8u0M5Uf88TKjdlZrDhEI5uY5tUiGIM+FIWpH2c0c="},"tinymce/plugins/emoticons/img/smiley-wink-2af75ad7b1c08488505513503e34b15f40005e04a2a9568f698f0945d2d8ba1f.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-wink.gif","mtime":"2017-05-06T15:41:53+02:00","size":350,"digest":"2af75ad7b1c08488505513503e34b15f40005e04a2a9568f698f0945d2d8ba1f","integrity":"sha256-Kvda17HAhIhQVRNQPjSxX0AAXgSiqVaPaY8JRdLYuh8="},"tinymce/plugins/emoticons/img/smiley-yell-bba903fbcb46fce8c68b9e01863fd095b3b1d0e6aa72161f3a88d762a5f90a79.gif":{"logical_path":"tinymce/plugins/emoticons/img/smiley-yell.gif","mtime":"2017-05-06T15:41:53+02:00","size":336,"digest":"bba903fbcb46fce8c68b9e01863fd095b3b1d0e6aa72161f3a88d762a5f90a79","integrity":"sha256-u6kD+8tG/OjGi54Bhj/QlbOx0OaqchYfOojXYqX5Cnk="},"tinymce/plugins/emoticons/plugin-75971da62ade77af7e79b3a560c5ad5ac20ee5f88c7ba236e03902777fdec715.js":{"logical_path":"tinymce/plugins/emoticons/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":912,"digest":"75971da62ade77af7e79b3a560c5ad5ac20ee5f88c7ba236e03902777fdec715","integrity":"sha256-dZcdpired69+ebOlYMWtWsIO5fiMe6I24DkCd3/exxU="},"tinymce/plugins/example/dialog-5c61ad829a494e75c2234019c7941f6dd096ec693cf5a5538c0bf30485097841.html":{"logical_path":"tinymce/plugins/example/dialog.html","mtime":"2017-05-02T18:30:07+02:00","size":213,"digest":"5c61ad829a494e75c2234019c7941f6dd096ec693cf5a5538c0bf30485097841","integrity":"sha256-XGGtgppJTnXCI0AZx5QfbdCW7Gk89aVTjAvzBIUJeEE="},"tinymce/plugins/example/plugin-505b7ee82929e7338700605a4ca63d94dbe6ef2ce2d21104cc01c2adba829868.js":{"logical_path":"tinymce/plugins/example/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":659,"digest":"505b7ee82929e7338700605a4ca63d94dbe6ef2ce2d21104cc01c2adba829868","integrity":"sha256-UFt+6Ckp5zOHAGBaTKY9lNvm7yzi0hEEzAHCrbqCmGg="},"tinymce/plugins/example_dependency/plugin-9bb52c9d45c0f7e4d67c12f546c68095b2d5284aa84ab3a2c45f1d986f464653.js":{"logical_path":"tinymce/plugins/example_dependency/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":74,"digest":"9bb52c9d45c0f7e4d67c12f546c68095b2d5284aa84ab3a2c45f1d986f464653","integrity":"sha256-m7UsnUXA9+TWfBL1RsaAlbLVKEqoSrOixF8dmG9GRlM="},"tinymce/plugins/fullpage/plugin-6cd62d14e4225c1db1d9008a485143d8e8b7a7c699e2ceec16a8012b44875ef5.js":{"logical_path":"tinymce/plugins/fullpage/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":6309,"digest":"6cd62d14e4225c1db1d9008a485143d8e8b7a7c699e2ceec16a8012b44875ef5","integrity":"sha256-bNYtFOQiXB2x2QCKSFFD2Oi3p8aZ4s7sFqgBK0SHXvU="},"tinymce/plugins/fullscreen/plugin-972d5e04901e74c8c657ee88fb3cc245b94aeb005d54adeac00c07a0c5700f7a.js":{"logical_path":"tinymce/plugins/fullscreen/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1676,"digest":"972d5e04901e74c8c657ee88fb3cc245b94aeb005d54adeac00c07a0c5700f7a","integrity":"sha256-ly1eBJAedMjGV+6I+zzCRblK6wBdVK3qwAwHoMVwD3o="},"tinymce/plugins/hr/plugin-92558948637f4349e0f327350ddebdd225313e582f08aacf6cb5549d03fc9a8b.js":{"logical_path":"tinymce/plugins/hr/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":323,"digest":"92558948637f4349e0f327350ddebdd225313e582f08aacf6cb5549d03fc9a8b","integrity":"sha256-klWJSGN/Q0ng8yc1Dd690iUxPlgvCKrPbLVUnQP8mos="},"tinymce/plugins/image/plugin-1c01f4fb87c7523d1ae9bfd7018d883601b59c40edc79c552ef39e8374cb9313.js":{"logical_path":"tinymce/plugins/image/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":8205,"digest":"1c01f4fb87c7523d1ae9bfd7018d883601b59c40edc79c552ef39e8374cb9313","integrity":"sha256-HAH0+4fHUj0a6b/XAY2INgG1nEDtx5xVLvOeg3TLkxM="},"tinymce/plugins/imagetools/plugin-78f93669c67ad2579caa99f1069d5ac7f5dc97af9be40d7b55c036dbe650574f.js":{"logical_path":"tinymce/plugins/imagetools/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":30907,"digest":"78f93669c67ad2579caa99f1069d5ac7f5dc97af9be40d7b55c036dbe650574f","integrity":"sha256-ePk2acZ60lecqpnxBp1ax/Xcl6+b5A17VcA22+ZQV08="},"tinymce/plugins/importcss/plugin-31acbbaaa49b20377e4f5d5a830d9e09babddb9a1c5b7978b843098176e318b5.js":{"logical_path":"tinymce/plugins/importcss/plugin.js","mtime":"2017-01-05T19:24:14+01:00","size":2749,"digest":"31acbbaaa49b20377e4f5d5a830d9e09babddb9a1c5b7978b843098176e318b5","integrity":"sha256-May7qqSbIDd+T11agw2eCbq925ocW3l4uEMJgXbjGLU="},"tinymce/plugins/insertdatetime/plugin-923510af4de6343c5ea6b8e679dbaa87d27a7abdaf84ac1f0000ad5722787577.js":{"logical_path":"tinymce/plugins/insertdatetime/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1972,"digest":"923510af4de6343c5ea6b8e679dbaa87d27a7abdaf84ac1f0000ad5722787577","integrity":"sha256-kjUQr03mNDxeprjmeduqh9J6er2vhKwfAACtVyJ4dXc="},"tinymce/plugins/legacyoutput/plugin-ac8239571ea6699f14a76058ea9e53a2a5d9b7e84bed3446d7bd4137b8cdac9f.js":{"logical_path":"tinymce/plugins/legacyoutput/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":3264,"digest":"ac8239571ea6699f14a76058ea9e53a2a5d9b7e84bed3446d7bd4137b8cdac9f","integrity":"sha256-rII5Vx6maZ8Up2BY6p5ToqXZt+hL7TRG171BN7jNrJ8="},"tinymce/plugins/link/plugin-e38346a4005bc814b0117a2dae6eb04ea9a7a8865d658afce406a8394fec0577.js":{"logical_path":"tinymce/plugins/link/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":6995,"digest":"e38346a4005bc814b0117a2dae6eb04ea9a7a8865d658afce406a8394fec0577","integrity":"sha256-44NGpABbyBSwEXotrm6wTqmnqIZdZYr85AaoOU/sBXc="},"tinymce/plugins/lists/plugin-69b25b69974c739637d6459489642fc95bddc8dc564f2b482d7ec94f3082f935.js":{"logical_path":"tinymce/plugins/lists/plugin.js","mtime":"2017-01-05T19:24:14+01:00","size":10332,"digest":"69b25b69974c739637d6459489642fc95bddc8dc564f2b482d7ec94f3082f935","integrity":"sha256-abJbaZdMc5Y31kWUiWQvyVvdyNxWTytILX7JTzCC+TU="},"tinymce/plugins/media/plugin-deedd7c7d99c7401ab698f65a1e299819b487e52e662c7866f8700ba8d67a351.js":{"logical_path":"tinymce/plugins/media/plugin.js","mtime":"2017-01-05T19:24:14+01:00","size":16223,"digest":"deedd7c7d99c7401ab698f65a1e299819b487e52e662c7866f8700ba8d67a351","integrity":"sha256-3u3Xx9mcdAGraY9loeKZgZtIflLmYseGb4cAuo1no1E="},"tinymce/plugins/nonbreaking/plugin-4b15567cb04f551924ca87994514a09fef17c2c6ea3bb6d50e8ca65dc3243b93.js":{"logical_path":"tinymce/plugins/nonbreaking/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":656,"digest":"4b15567cb04f551924ca87994514a09fef17c2c6ea3bb6d50e8ca65dc3243b93","integrity":"sha256-SxVWfLBPVRkkyoeZRRSgn+8XwsbqO7bVDoymXcMkO5M="},"tinymce/plugins/noneditable/plugin-245b5d236dfea414326bdbcd601333f54d5c2b30a0133cbcbbbae329306b0df3.js":{"logical_path":"tinymce/plugins/noneditable/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1271,"digest":"245b5d236dfea414326bdbcd601333f54d5c2b30a0133cbcbbbae329306b0df3","integrity":"sha256-JFtdI23+pBQya9vNYBMz9U1cKzCgEzy8u7rjKTBrDfM="},"tinymce/plugins/pagebreak/plugin-4c8f35adfd6fb570639318219a4d2ad0e8850619f37ff322ad101683ec00829a.js":{"logical_path":"tinymce/plugins/pagebreak/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1231,"digest":"4c8f35adfd6fb570639318219a4d2ad0e8850619f37ff322ad101683ec00829a","integrity":"sha256-TI81rf1vtXBjkxghmk0q0OiFBhnzf/MirRAWg+wAgpo="},"tinymce/plugins/paste/plugin-f7d8cf6dd7bd24908d5c58c664a54cbe4838c542ec26e35f3c4b198f53f98291.js":{"logical_path":"tinymce/plugins/paste/plugin.js","mtime":"2017-01-05T19:24:14+01:00","size":17685,"digest":"f7d8cf6dd7bd24908d5c58c664a54cbe4838c542ec26e35f3c4b198f53f98291","integrity":"sha256-99jPbde9JJCNXFjGZKVMvkg4xULsJuNfPEsZj1P5gpE="},"tinymce/plugins/preview/plugin-d0b7e78697d7a21e237e170bbb0a9c95c40b8dc0118a5ccb6a8347eba1800ade.js":{"logical_path":"tinymce/plugins/preview/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1603,"digest":"d0b7e78697d7a21e237e170bbb0a9c95c40b8dc0118a5ccb6a8347eba1800ade","integrity":"sha256-0LfnhpfXoh4jfhcLuwqclcQLjcARilzLaoNH66GACt4="},"tinymce/plugins/print/plugin-07acb7cbdb293f598245755b4a5a142b9d7b78f6b7a6268e3a447b8941f64472.js":{"logical_path":"tinymce/plugins/print/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":294,"digest":"07acb7cbdb293f598245755b4a5a142b9d7b78f6b7a6268e3a447b8941f64472","integrity":"sha256-B6y3y9spP1mCRXVbSloUK517ePa3piaOOkR7iUH2RHI="},"tinymce/plugins/save/plugin-ef4b15573e862995e82aadd8ede1117ee36a05b335a74640804e24dbca5ebac1.js":{"logical_path":"tinymce/plugins/save/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1151,"digest":"ef4b15573e862995e82aadd8ede1117ee36a05b335a74640804e24dbca5ebac1","integrity":"sha256-70sVVz6GKZXoKq3Y7eERfuNqBbM1p0ZAgE4k28peusE="},"tinymce/plugins/searchreplace/plugin-e1f614dbe20b45955a82405a9aa38c415ab49288d74d0daf881db666eb5549c6.js":{"logical_path":"tinymce/plugins/searchreplace/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":6494,"digest":"e1f614dbe20b45955a82405a9aa38c415ab49288d74d0daf881db666eb5549c6","integrity":"sha256-4fYU2+ILRZVagkBamqOMQVq0kojXTQ2viB22ZutVScY="},"tinymce/plugins/spellchecker/plugin-8c198efb4ebcd3ae3f53b2906bed0265f883bd3fca5f8a30880aac630f4eb787.js":{"logical_path":"tinymce/plugins/spellchecker/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":10049,"digest":"8c198efb4ebcd3ae3f53b2906bed0265f883bd3fca5f8a30880aac630f4eb787","integrity":"sha256-jBmO+068064/U7KQa+0CZfiDvT/KX4owiAqsYw9Ot4c="},"tinymce/plugins/tabfocus/plugin-4b947a94b9cc31d699fed7bb19d2efd9b62fbbd75f0858040bca4ba6402113a0.js":{"logical_path":"tinymce/plugins/tabfocus/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1265,"digest":"4b947a94b9cc31d699fed7bb19d2efd9b62fbbd75f0858040bca4ba6402113a0","integrity":"sha256-S5R6lLnMMdaZ/te7GdLv2bYvu9dfCFgEC8pLpkAhE6A="},"tinymce/plugins/table/plugin-5f3b35988457fcc9d2c2c35601acb041b7b59246dc16d061433cf741cba9ca26.js":{"logical_path":"tinymce/plugins/table/plugin.js","mtime":"2017-01-05T19:24:14+01:00","size":46153,"digest":"5f3b35988457fcc9d2c2c35601acb041b7b59246dc16d061433cf741cba9ca26","integrity":"sha256-Xzs1mIRX/MnSwsNWAaywQbe1kkbcFtBhQzz3QcupyiY="},"tinymce/plugins/template/plugin-3a7a1a203ced83abdb7f36897c974eed07a876be4f54809e06ad5b17ec957222.js":{"logical_path":"tinymce/plugins/template/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":4521,"digest":"3a7a1a203ced83abdb7f36897c974eed07a876be4f54809e06ad5b17ec957222","integrity":"sha256-OnoaIDztg6vbfzaJfJdO7Qeodr5PVICeBq1bF+yVciI="},"tinymce/plugins/textcolor/plugin-d05a9d9a6fbdcca3f07c45e6ef1ba8913f48c68a68a871343cdce2075c0ef0b6.js":{"logical_path":"tinymce/plugins/textcolor/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":4146,"digest":"d05a9d9a6fbdcca3f07c45e6ef1ba8913f48c68a68a871343cdce2075c0ef0b6","integrity":"sha256-0Fqdmm+9zKPwfEXm7xuokT9IxopoqHE0PNziB1wO8LY="},"tinymce/plugins/textpattern/plugin-d630f2bc3205e400af41041eb224fe793ae950de5d5f4732f63e36f6819d3f35.js":{"logical_path":"tinymce/plugins/textpattern/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":2746,"digest":"d630f2bc3205e400af41041eb224fe793ae950de5d5f4732f63e36f6819d3f35","integrity":"sha256-1jDyvDIF5ACvQQQesiT+eTrpUN5dX0cy9j429oGdPzU="},"tinymce/plugins/toc/plugin-c20dc2987d4fcd8f859871ec0f2988f3c819c373d2fadad8c5b923b9b749d0ef.js":{"logical_path":"tinymce/plugins/toc/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":2772,"digest":"c20dc2987d4fcd8f859871ec0f2988f3c819c373d2fadad8c5b923b9b749d0ef","integrity":"sha256-wg3CmH1PzY+FmHHsDymI88gZw3PS+trYxbkjubdJ0O8="},"tinymce/plugins/visualblocks/css/visualblocks-e44e30ebe30e4d3763425a9ea38b558ff13106b8e16a30a74ae21b4c174b3417.css":{"logical_path":"tinymce/plugins/visualblocks/css/visualblocks.css","mtime":"2017-05-06T15:41:53+02:00","size":4767,"digest":"e44e30ebe30e4d3763425a9ea38b558ff13106b8e16a30a74ae21b4c174b3417","integrity":"sha256-5E4w6+MOTTdjQlqeo4tVj/ExBrjhajCnSuIbTBdLNBc="},"tinymce/plugins/visualblocks/plugin-6cdc811487cbbee106512812da68f1999fcb3db14f99c5cb4a070be578c9bb0a.js":{"logical_path":"tinymce/plugins/visualblocks/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1154,"digest":"6cdc811487cbbee106512812da68f1999fcb3db14f99c5cb4a070be578c9bb0a","integrity":"sha256-bNyBFIfLvuEGUSgS2mjxmZ/LPbFPmcXLSgcL5XjJuwo="},"tinymce/plugins/visualchars/plugin-0e8c1d7cba0b1471014fe3359a04ff4d4d981070777cdf31f4d95a732b83581f.js":{"logical_path":"tinymce/plugins/visualchars/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1179,"digest":"0e8c1d7cba0b1471014fe3359a04ff4d4d981070777cdf31f4d95a732b83581f","integrity":"sha256-DowdfLoLFHEBT+M1mgT/TU2YEHB3fN8x9NlacyuDWB8="},"tinymce/plugins/wordcount/plugin-d9ec660425815b227f5c3fbdc8b5d066a0530ec824ba37b47169aabd3f864ea7.js":{"logical_path":"tinymce/plugins/wordcount/plugin.js","mtime":"2017-01-05T19:24:14+01:00","size":12048,"digest":"d9ec660425815b227f5c3fbdc8b5d066a0530ec824ba37b47169aabd3f864ea7","integrity":"sha256-2exmBCWBWyJ/XD+9yLXQZqBTDsgkuje0cWmqvT+GTqc="},"tinymce/skins/lightgray/content.inline.min-5bb5c69d072a2d17d11e0c54bc81b6f863e5b5a126060d862970f0c22f5d49ec.css":{"logical_path":"tinymce/skins/lightgray/content.inline.min.css","mtime":"2017-05-02T18:30:07+02:00","size":2770,"digest":"5bb5c69d072a2d17d11e0c54bc81b6f863e5b5a126060d862970f0c22f5d49ec","integrity":"sha256-W7XGnQcqLRfRHgxUvIG2+GPltaEmBg2GKXDwwi9dSew="},"tinymce/skins/lightgray/content.min-92e6da84fb5c2dfcc35f34d311ca1914b19064ada45fa9a08ff2a68c0fc0e657.css":{"logical_path":"tinymce/skins/lightgray/content.min.css","mtime":"2017-05-02T18:30:07+02:00","size":3194,"digest":"92e6da84fb5c2dfcc35f34d311ca1914b19064ada45fa9a08ff2a68c0fc0e657","integrity":"sha256-kubahPtcLfzDXzTTEcoZFLGQZK2kX6mgj/KmjA/A5lc="},"tinymce/skins/lightgray/fonts/tinymce-small-a10fc4343d95b716c16d77463d475be5c079599ea67e1cd2bd3a94d5e7f508f9.eot":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce-small.eot","mtime":"2017-05-06T15:41:53+02:00","size":9492,"digest":"a10fc4343d95b716c16d77463d475be5c079599ea67e1cd2bd3a94d5e7f508f9","integrity":"sha256-oQ/END2VtxbBbXdGPUdb5cB5WZ6mfhzSvTqU1ef1CPk="},"tinymce/skins/lightgray/fonts/tinymce-small-e7773001446ab937e1d8d4bd5e8dbd9b31d112037353a14b319e36dd010ed8ee.svg":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce-small.svg","mtime":"2017-05-06T15:41:53+02:00","size":24727,"digest":"e7773001446ab937e1d8d4bd5e8dbd9b31d112037353a14b319e36dd010ed8ee","integrity":"sha256-53cwAURquTfh2NS9Xo29mzHREgNzU6FLMZ423QEO2O4="},"tinymce/skins/lightgray/fonts/tinymce-small-2f657502906d6f5c3fc8df3a82969114ebe030addfdc061c60c974b0f515fd09.ttf":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce-small.ttf","mtime":"2017-05-06T15:41:53+02:00","size":9304,"digest":"2f657502906d6f5c3fc8df3a82969114ebe030addfdc061c60c974b0f515fd09","integrity":"sha256-L2V1ApBtb1w/yN86gpaRFOvgMK3f3AYcYMl0sPUV/Qk="},"tinymce/skins/lightgray/fonts/tinymce-small-d3efbb678ca6de5632902bd93772746ba2f8e4e2322b953936e12694a183aa31.woff":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce-small.woff","mtime":"2017-05-06T15:41:53+02:00","size":9380,"digest":"d3efbb678ca6de5632902bd93772746ba2f8e4e2322b953936e12694a183aa31","integrity":"sha256-0++7Z4ym3lYykCvZN3J0a6L45OIyK5U5NuEmlKGDqjE="},"tinymce/skins/lightgray/fonts/tinymce-2e9c4a68fde992476e0db9e44128cb1f2e898f0de0b80f552a8acb52bb7ca0db.eot":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce.eot","mtime":"2017-05-06T15:41:53+02:00","size":17572,"digest":"2e9c4a68fde992476e0db9e44128cb1f2e898f0de0b80f552a8acb52bb7ca0db","integrity":"sha256-LpxKaP3pkkduDbnkQSjLHy6Jjw3guA9VKorLUrt8oNs="},"tinymce/skins/lightgray/fonts/tinymce-2094ddadc265c7f33570475fc78ef7adcdcb814e49060d17f5b4c4f8d1cb7ec6.svg":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce.svg","mtime":"2017-05-06T15:41:53+02:00","size":45991,"digest":"2094ddadc265c7f33570475fc78ef7adcdcb814e49060d17f5b4c4f8d1cb7ec6","integrity":"sha256-IJTdrcJlx/M1cEdfx473rc3LgU5JBg0X9bTE+NHLfsY="},"tinymce/skins/lightgray/fonts/tinymce-477ea2d46c1a975dd492af4c10235fabfd09069595779cce00ea0381ca9b4a20.ttf":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce.ttf","mtime":"2017-05-06T15:41:53+02:00","size":17408,"digest":"477ea2d46c1a975dd492af4c10235fabfd09069595779cce00ea0381ca9b4a20","integrity":"sha256-R36i1Gwal13Ukq9MECNfq/0JBpWVd5zOAOoDgcqbSiA="},"tinymce/skins/lightgray/fonts/tinymce-1ebc636bb24cbea637946ba8c22cbf4f35d8343ba9763045d2aee59e3714ae78.woff":{"logical_path":"tinymce/skins/lightgray/fonts/tinymce.woff","mtime":"2017-05-06T15:41:53+02:00","size":17484,"digest":"1ebc636bb24cbea637946ba8c22cbf4f35d8343ba9763045d2aee59e3714ae78","integrity":"sha256-Hrxja7JMvqY3lGuowiy/TzXYNDupdjBF0q7lnjcUrng="},"tinymce/skins/lightgray/img/anchor-2861666fd107d278d4449970615136d06d7f746be9bb19072cf9c8f30e565e1e.gif":{"logical_path":"tinymce/skins/lightgray/img/anchor.gif","mtime":"2017-05-06T15:41:53+02:00","size":53,"digest":"2861666fd107d278d4449970615136d06d7f746be9bb19072cf9c8f30e565e1e","integrity":"sha256-KGFmb9EH0njURJlwYVE20G1/dGvpuxkHLPnI8w5WXh4="},"tinymce/skins/lightgray/img/loader-eb7cfd3d959b2e09c170f532e29f8b825f9bc770b2279fde58e595617753e244.gif":{"logical_path":"tinymce/skins/lightgray/img/loader.gif","mtime":"2017-05-06T15:41:53+02:00","size":2608,"digest":"eb7cfd3d959b2e09c170f532e29f8b825f9bc770b2279fde58e595617753e244","integrity":"sha256-63z9PZWbLgnBcPUy4p+Lgl+bx3CyJ5/eWOWVYXdT4kQ="},"tinymce/skins/lightgray/img/object-e6a15e52bc4a17b085073ba8debd4708ead6ae3d4cbeb3880c65cb7afc489777.gif":{"logical_path":"tinymce/skins/lightgray/img/object.gif","mtime":"2017-05-06T15:41:53+02:00","size":152,"digest":"e6a15e52bc4a17b085073ba8debd4708ead6ae3d4cbeb3880c65cb7afc489777","integrity":"sha256-5qFeUrxKF7CFBzuo3r1HCOrWrj1MvrOIDGXLevxIl3c="},"tinymce/skins/lightgray/img/trans-9cf020d7c3bba7f5ab10cda54aabef934f906d4f9a3acf99e9e7dc6c98579635.gif":{"logical_path":"tinymce/skins/lightgray/img/trans.gif","mtime":"2017-05-06T15:41:53+02:00","size":43,"digest":"9cf020d7c3bba7f5ab10cda54aabef934f906d4f9a3acf99e9e7dc6c98579635","integrity":"sha256-nPAg18O7p/WrEM2lSqvvk0+QbU+aOs+Z6efcbJhXljU="},"tinymce/skins/lightgray/skin.ie7.min-f7e68049f5f1ba278870818429ef905d07846781701c40657d9d24ca6638cced.css":{"logical_path":"tinymce/skins/lightgray/skin.ie7.min.css","mtime":"2017-05-02T18:30:07+02:00","size":34904,"digest":"f7e68049f5f1ba278870818429ef905d07846781701c40657d9d24ca6638cced","integrity":"sha256-9+aASfXxuieIcIGEKe+QXQeEZ4FwHEBlfZ0kymY4zO0="},"tinymce/skins/lightgray/skin.min-6d81e56f6d40695f114abe4db834ccb7bf7d89cfa07c10c2cbaebb8066ace27b.css":{"logical_path":"tinymce/skins/lightgray/skin.min.css","mtime":"2017-05-02T18:30:07+02:00","size":38232,"digest":"6d81e56f6d40695f114abe4db834ccb7bf7d89cfa07c10c2cbaebb8066ace27b","integrity":"sha256-bYHlb21AaV8RSr5NuDTMt799ic+gfBDCy667gGas4ns="},"tinymce/themes/inlite/theme-95446aa7daedd3754400947ecc50a607971ef2068d093e7c9a889c5908ff6f40.js":{"logical_path":"tinymce/themes/inlite/theme.js","mtime":"2017-01-05T19:24:14+01:00","size":16382,"digest":"95446aa7daedd3754400947ecc50a607971ef2068d093e7c9a889c5908ff6f40","integrity":"sha256-lURqp9rt03VEAJR+zFCmB5ce8gaNCT58moicWQj/b0A="},"tinymce/themes/modern/theme-f0a3cccc241fa5d46bde8e19160e3f351368881a7c3cdb0c4ce84da11901064c.js":{"logical_path":"tinymce/themes/modern/theme.js","mtime":"2017-05-02T18:30:07+02:00","size":13155,"digest":"f0a3cccc241fa5d46bde8e19160e3f351368881a7c3cdb0c4ce84da11901064c","integrity":"sha256-8KPMzCQfpdRr3o4ZFg4/NRNoiBp8PNsMTOhNoRkBBkw="},"active_admin-f7ef723200f732c68bf56214e1c6ac931008f3de4eba9dcd29e140696b46f0a0.css":{"logical_path":"active_admin.css","mtime":"2017-05-04T21:49:46+02:00","size":79039,"digest":"f7ef723200f732c68bf56214e1c6ac931008f3de4eba9dcd29e140696b46f0a0","integrity":"sha256-9+9yMgD3MsaL9WIU4caskxAI895Oup3NKeFAaWtG8KA="},"active_admin-2b4f9b9e35d46bbace92d14d078b3568dcdbd0183e52827e5c44c54dc7c96266.js":{"logical_path":"active_admin.js","mtime":"2017-05-04T23:06:57+02:00","size":692870,"digest":"2b4f9b9e35d46bbace92d14d078b3568dcdbd0183e52827e5c44c54dc7c96266","integrity":"sha256-K0+bnjXUa7rOktFNB4s1aNzb0Bg+UoJ+XETFTcfJYmY="},"tinymce-8c0346bfe88f5c5405046ebd1cdbd1c7192d503d93623ffc00d2d7b430116b69.js":{"logical_path":"tinymce.js","mtime":"2017-05-04T23:06:57+02:00","size":971,"digest":"8c0346bfe88f5c5405046ebd1cdbd1c7192d503d93623ffc00d2d7b430116b69","integrity":"sha256-jANGv+iPXFQFBG69HNvRxxktUD2TYj/8ANLXtDARa2k="},"application-12922f8d27744fe5233d0c8f855c532cad64561e248ebaa05442fd6b59f73af2.css":{"logical_path":"application.css","mtime":"2017-05-04T23:06:57+02:00","size":174051,"digest":"12922f8d27744fe5233d0c8f855c532cad64561e248ebaa05442fd6b59f73af2","integrity":"sha256-EpIvjSd0T+UjPQyPhVxTLK1kVh4kjrqgVEL9a1n3OvI="},"brasil-0e293d8c9a86f8a98fea23013e9c365b32fd0022a1496309eeabcd97f7be1288.png":{"logical_path":"brasil.png","mtime":"2017-05-04T22:06:49+02:00","size":660,"digest":"0e293d8c9a86f8a98fea23013e9c365b32fd0022a1496309eeabcd97f7be1288","integrity":"sha256-Dik9jJqG+KmP6iMBPpw2WzL9ACKhSWMJ7qvNl/e+Eog="},"application-88a91754f1835c3e582224375aeeccd1d3dce637f71dded6ca23ce71a228d339.js":{"logical_path":"application.js","mtime":"2017-05-04T23:06:57+02:00","size":2376693,"digest":"88a91754f1835c3e582224375aeeccd1d3dce637f71dded6ca23ce71a228d339","integrity":"sha256-iKkXVPGDXD5YIiQ3Wu7M0dPc5jf3Hd7WyiPOcaIo0zk="},"tinymce/preinit-4eb7f4ac58f2f450d20185cf83ca1d8550d2a1419141bfe70eb5a2c4afe67349.js":{"logical_path":"tinymce/preinit.js","mtime":"2017-05-06T15:41:53+02:00","size":248,"digest":"4eb7f4ac58f2f450d20185cf83ca1d8550d2a1419141bfe70eb5a2c4afe67349","integrity":"sha256-Trf0rFjy9FDSAYXPg8odhVDSoUGRQb/nDrWixK/mc0k="},"tinymce/tinymce-d7f6811cb92d1e7638015669d3ec90175d4cb1309ecad56ff9d757b25fe18172.js":{"logical_path":"tinymce/tinymce.js","mtime":"2017-05-02T18:30:07+02:00","size":1299472,"digest":"d7f6811cb92d1e7638015669d3ec90175d4cb1309ecad56ff9d757b25fe18172","integrity":"sha256-1/aBHLktHnY4AVZp0+yQF11MsTCeytVv+ddXsl/hgXI="},"tinymce/plugins/anchor/plugin-f642e411a2a702256b0069e5baf65ef62d31c34e92e993123aad88e22ee295ce.js":{"logical_path":"tinymce/plugins/anchor/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":1189,"digest":"f642e411a2a702256b0069e5baf65ef62d31c34e92e993123aad88e22ee295ce","integrity":"sha256-9kLkEaKnAiVrAGnluvZe9i0xw06S6ZMSOq2I4i7ilc4="},"tinymce/plugins/importcss/plugin-5386dd0994914eaf7431876cb0b2d9cf505a8d91c0f8fd739c5166bd21f6376d.js":{"logical_path":"tinymce/plugins/importcss/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":2748,"digest":"5386dd0994914eaf7431876cb0b2d9cf505a8d91c0f8fd739c5166bd21f6376d","integrity":"sha256-U4bdCZSRTq90MYdssLLZz1BajZHA+P1znFFmvSH2N20="},"tinymce/plugins/lists/plugin-c56f1732e8069ebaca97437c3b99a69ed2663f558cd50a817ee721661673510c.js":{"logical_path":"tinymce/plugins/lists/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":14636,"digest":"c56f1732e8069ebaca97437c3b99a69ed2663f558cd50a817ee721661673510c","integrity":"sha256-xW8XMugGnrrKl0N8O5mmntJmP1WM1QqBfuchZhZzUQw="},"tinymce/plugins/media/plugin-f5341fd5503efcd25c050b419868be59073ba2e0bf58bf7a73877c052109e0de.js":{"logical_path":"tinymce/plugins/media/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":16453,"digest":"f5341fd5503efcd25c050b419868be59073ba2e0bf58bf7a73877c052109e0de","integrity":"sha256-9TQf1VA+/NJcBQtBmGi+WQc7ouC/WL96c4d8BSEJ4N4="},"tinymce/plugins/paste/plugin-524c40b866f13bbb8fea23d9b8529d00df10b94695e646bd4303eaff9f658e7c.js":{"logical_path":"tinymce/plugins/paste/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":18069,"digest":"524c40b866f13bbb8fea23d9b8529d00df10b94695e646bd4303eaff9f658e7c","integrity":"sha256-UkxAuGbxO7uP6iPZuFKdAN8QuUaV5ka9QwPq/59ljnw="},"tinymce/plugins/table/plugin-58e9f99c4c09431f853051ab6a87504487a9042e520c68e84d9adc59346659a6.js":{"logical_path":"tinymce/plugins/table/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":47127,"digest":"58e9f99c4c09431f853051ab6a87504487a9042e520c68e84d9adc59346659a6","integrity":"sha256-WOn5nEwJQx+FMFGraodQRIepBC5SDGjoTZrcWTRmWaY="},"tinymce/plugins/wordcount/plugin-649a9308c0183e56c3ba78002d7b480ecbba84ff30361c36bcea6ed07ea6be4f.js":{"logical_path":"tinymce/plugins/wordcount/plugin.js","mtime":"2017-05-02T18:30:07+02:00","size":12031,"digest":"649a9308c0183e56c3ba78002d7b480ecbba84ff30361c36bcea6ed07ea6be4f","integrity":"sha256-ZJqTCMAYPlbDungALXtIDsu6hP8wNhw2vOpu0H6mvk8="},"tinymce/themes/inlite/theme-a400085213d427d78d8a1e35089ae6cd00831e51d33a3342a198d1bc62851640.js":{"logical_path":"tinymce/themes/inlite/theme.js","mtime":"2017-05-02T18:30:07+02:00","size":16579,"digest":"a400085213d427d78d8a1e35089ae6cd00831e51d33a3342a198d1bc62851640","integrity":"sha256-pAAIUhPUJ9eNih41CJrmzQCDHlHTOjNCoZjRvGKFFkA="},"tinymce-4c729110e9fbc21457c0701ad636697126e92f7382d61a90a5d1417bce25d351.js":{"logical_path":"tinymce.js","mtime":"2017-05-04T23:44:41+02:00","size":971,"digest":"4c729110e9fbc21457c0701ad636697126e92f7382d61a90a5d1417bce25d351","integrity":"sha256-THKREOn7whRXwHAa1jZpcSbpL3OC1hqQpdFBe84l01E="},"application-bdfbc8eb22d736e3b643562e28b99fe04141f4cf95374182bef07145353c9d93.css":{"logical_path":"application.css","mtime":"2017-05-04T23:44:41+02:00","size":174069,"digest":"bdfbc8eb22d736e3b643562e28b99fe04141f4cf95374182bef07145353c9d93","integrity":"sha256-vfvI6yLXNuO2Q1YuKLmf4EFB9M+VN0GCvvBxRTU8nZM="},"application-903f24210c790f3469e1bc9eb1ce7ee154a7bf349807a3d86d0eda7deb1a8639.js":{"logical_path":"application.js","mtime":"2017-05-04T23:44:41+02:00","size":2376693,"digest":"903f24210c790f3469e1bc9eb1ce7ee154a7bf349807a3d86d0eda7deb1a8639","integrity":"sha256-kD8kIQx5DzRp4byesc5+4VSnvzSYB6PYbQ7afesahjk="},"tinymce-99a0778c7c535b32962fc89f8028c5c266e2635afaf1a4fef18fbea79c64417c.js":{"logical_path":"tinymce.js","mtime":"2017-05-05T00:03:37+02:00","size":971,"digest":"99a0778c7c535b32962fc89f8028c5c266e2635afaf1a4fef18fbea79c64417c","integrity":"sha256-maB3jHxTWzKWL8ifgCjFwmbiY1r68aT+8Y++p5xkQXw="},"application-c9233d317c4304011690c6ce879a873281e2d4c79930b7ea3cf28bb7c5839d24.css":{"logical_path":"application.css","mtime":"2017-05-05T00:03:37+02:00","size":174071,"digest":"c9233d317c4304011690c6ce879a873281e2d4c79930b7ea3cf28bb7c5839d24","integrity":"sha256-ySM9MXxDBAEWkMbOh5qHMoHi1MeZMLfqPPKLt8WDnSQ="},"application-d242f0ecb362deb18f1fb1143feba3afd81da98a6de3e41f805a9e99c6ba03dc.js":{"logical_path":"application.js","mtime":"2017-05-05T00:03:37+02:00","size":2376693,"digest":"d242f0ecb362deb18f1fb1143feba3afd81da98a6de3e41f805a9e99c6ba03dc","integrity":"sha256-0kLw7LNi3rGPH7EUP+ujr9gdqYpt4+QfgFqemca6A9w="},"tinymce-c09e1a38c74241759c70df0385e95b4c46d6cd0342bd271315c2457b25591aad.js":{"logical_path":"tinymce.js","mtime":"2017-05-06T15:41:53+02:00","size":971,"digest":"c09e1a38c74241759c70df0385e95b4c46d6cd0342bd271315c2457b25591aad","integrity":"sha256-wJ4aOMdCQXWccN8DhelbTEbWzQNCvScTFcJFeyVZGq0="},"application-74c16b3b8c70a0ee2d3bc48bb2acbb9925fc52b1cd41171d7cb5063cd119ba3a.css":{"logical_path":"application.css","mtime":"2017-05-06T15:41:53+02:00","size":174066,"digest":"74c16b3b8c70a0ee2d3bc48bb2acbb9925fc52b1cd41171d7cb5063cd119ba3a","integrity":"sha256-dMFrO4xwoO4tO8SLsqy7mSX8UrHNQRcdfLUGPNEZujo="},"application-5b7e43f757edc035a8a8704a7194315f37d111b86a354effc3df4fd3343fa018.js":{"logical_path":"application.js","mtime":"2017-05-05T00:07:11+02:00","size":2376693,"digest":"5b7e43f757edc035a8a8704a7194315f37d111b86a354effc3df4fd3343fa018","integrity":"sha256-W35D91ftwDWoqHBKcZQxXzfREbhqNU7/w99P0zQ/oBg="},"active_admin-23d58e148201d77c88712977540f99db82c21bece116faa407af2e3a099a9417.js":{"logical_path":"active_admin.js","mtime":"2017-05-06T15:41:53+02:00","size":692963,"digest":"23d58e148201d77c88712977540f99db82c21bece116faa407af2e3a099a9417","integrity":"sha256-I9WOFIIB13yIcSl3VA+Z24LCG+zhFvqkB68uOgmalBc="},"application-f22e563794b5c8c393d971168eb18deacfb064852fd91258978766d532fbb5a7.js":{"logical_path":"application.js","mtime":"2017-05-06T15:41:53+02:00","size":2720154,"digest":"f22e563794b5c8c393d971168eb18deacfb064852fd91258978766d532fbb5a7","integrity":"sha256-8i5WN5S1yMOT2XEWjrGN6s+wZIUv2RJYl4dm1TL7tac="},"tinymce/tinymce-0422648f7dd78a5e2c43b1fad74793a3d3b056cba25af436f1681a4dcba937e6.js":{"logical_path":"tinymce/tinymce.js","mtime":"2017-05-06T15:41:53+02:00","size":1642204,"digest":"0422648f7dd78a5e2c43b1fad74793a3d3b056cba25af436f1681a4dcba937e6","integrity":"sha256-BCJkj33Xil4sQ7H610eTo9OwVsuiWvQ28WgaTcupN+Y="},"tinymce/jquery.tinymce-4708a7ae12d4dd7d315d7475258257d344304f4256b535fc5c4c3ac4fa01986c.js":{"logical_path":"tinymce/jquery.tinymce.js","mtime":"2017-05-06T15:41:53+02:00","size":4228,"digest":"4708a7ae12d4dd7d315d7475258257d344304f4256b535fc5c4c3ac4fa01986c","integrity":"sha256-RwinrhLU3X0xXXR1JYJX00QwT0JWtTX8XEw6xPoBmGw="},"tinymce/license-47a9dcd2574891a5a465112fd9dfcebcc7e61844edec27fa936a64642008fe66.txt":{"logical_path":"tinymce/license.txt","mtime":"2017-05-06T15:41:53+02:00","size":26441,"digest":"47a9dcd2574891a5a465112fd9dfcebcc7e61844edec27fa936a64642008fe66","integrity":"sha256-R6nc0ldIkaWkZREv2d/OvMfmGETt7Cf6k2pkZCAI/mY="},"tinymce/plugins/advlist/plugin-a3bae9788cb831a5c87db458d3608696f5cdd9159f8c9af2a859e6cff3463327.js":{"logical_path":"tinymce/plugins/advlist/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":2973,"digest":"a3bae9788cb831a5c87db458d3608696f5cdd9159f8c9af2a859e6cff3463327","integrity":"sha256-o7rpeIy4MaXIfbRY02CGlvXN2RWfjJryqFnmz/NGMyc="},"tinymce/plugins/anchor/plugin-910353b28da9ffa1075fd37b1c95f1f05f0d6809e41a5e4250b33e1a3a7a86c8.js":{"logical_path":"tinymce/plugins/anchor/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":2110,"digest":"910353b28da9ffa1075fd37b1c95f1f05f0d6809e41a5e4250b33e1a3a7a86c8","integrity":"sha256-kQNTso2p/6EHX9N7HJXx8F8NaAnkGl5CULM+Gjp6hsg="},"tinymce/plugins/autolink/plugin-8dc80b03dea3552f0f39b5eb0558104bff82ae57ad3d8ecbbdf60123025e5493.js":{"logical_path":"tinymce/plugins/autolink/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":2982,"digest":"8dc80b03dea3552f0f39b5eb0558104bff82ae57ad3d8ecbbdf60123025e5493","integrity":"sha256-jcgLA96jVS8PObXrBVgQS/+CrletPY7LvfYBIwJeVJM="},"tinymce/plugins/autoresize/plugin-2e0a2856650e8fa09fba9a00fd18a9078e5ee436c6c47ead6ba6689fee74cafa.js":{"logical_path":"tinymce/plugins/autoresize/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":2916,"digest":"2e0a2856650e8fa09fba9a00fd18a9078e5ee436c6c47ead6ba6689fee74cafa","integrity":"sha256-LgooVmUOj6CfupoA/RipB45e5DbGxH6ta6Zon+50yvo="},"tinymce/plugins/autosave/plugin-55a285a6bc363cbf99b2638deccef1fda08941114407e360300617bd9e86dddc.js":{"logical_path":"tinymce/plugins/autosave/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":3219,"digest":"55a285a6bc363cbf99b2638deccef1fda08941114407e360300617bd9e86dddc","integrity":"sha256-VaKFprw2PL+ZsmON7M7x/aCJQRFEB+NgMAYXvZ6G3dw="},"tinymce/plugins/bbcode/plugin-3e2fdc6fa5b587ce568ca570974d0e910b6684e392a9ecaba02b5c6c15269080.js":{"logical_path":"tinymce/plugins/bbcode/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":3990,"digest":"3e2fdc6fa5b587ce568ca570974d0e910b6684e392a9ecaba02b5c6c15269080","integrity":"sha256-Pi/cb6W1h85WjKVwl00OkQtmhOOSqeyroCtcbBUmkIA="},"tinymce/plugins/charmap/plugin-f0c699e1edeacfaf2f1342019986c8c41653ae723c8befc205dee077de317ab8.js":{"logical_path":"tinymce/plugins/charmap/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":9144,"digest":"f0c699e1edeacfaf2f1342019986c8c41653ae723c8befc205dee077de317ab8","integrity":"sha256-8MaZ4e3qz68vE0IBmYbIxBZTrnI8i+/CBd7gd94xerg="},"tinymce/plugins/code/plugin-2c12bcd21813fa52b23a65c3080cc6f4ecb33be04ee058b6c460719724511372.js":{"logical_path":"tinymce/plugins/code/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":1656,"digest":"2c12bcd21813fa52b23a65c3080cc6f4ecb33be04ee058b6c460719724511372","integrity":"sha256-LBK80hgT+lKyOmXDCAzG9OyzO+BO4Fi2xGBxlyRRE3I="},"tinymce/plugins/codesample/plugin-a3591d2c33d0499eed106bbdc9d0aa698115456632cb806e8f44bdf270d8d6b8.js":{"logical_path":"tinymce/plugins/codesample/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":19950,"digest":"a3591d2c33d0499eed106bbdc9d0aa698115456632cb806e8f44bdf270d8d6b8","integrity":"sha256-o1kdLDPQSZ7tEGu9ydCqaYEVRWYyy4Buj0S98nDY1rg="},"tinymce/plugins/colorpicker/plugin-f4ea1ac5bfaaef5adef0789427a1ef1e3c07814ff9a7623953bfb1a79f9f502d.js":{"logical_path":"tinymce/plugins/colorpicker/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":2144,"digest":"f4ea1ac5bfaaef5adef0789427a1ef1e3c07814ff9a7623953bfb1a79f9f502d","integrity":"sha256-9Ooaxb+q71re8HiUJ6HvHjwHgU/5p2I5U7+xp5+fUC0="},"tinymce/plugins/contextmenu/plugin-f13279e7538cd4153798055dbc81d495831aa421056061b85496d304cdfcd280.js":{"logical_path":"tinymce/plugins/contextmenu/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":2213,"digest":"f13279e7538cd4153798055dbc81d495831aa421056061b85496d304cdfcd280","integrity":"sha256-8TJ551OM1BU3mAVdvIHUlYMapCEFYGG4VJbTBM380oA="},"tinymce/plugins/directionality/plugin-8b9d9e0d97d8cf5c20b4f74509a94cbd84c59b330d7badaad66ff2d0553479fd.js":{"logical_path":"tinymce/plugins/directionality/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":1653,"digest":"8b9d9e0d97d8cf5c20b4f74509a94cbd84c59b330d7badaad66ff2d0553479fd","integrity":"sha256-i52eDZfYz1wgtPdFCalMvYTFmzMNe62q1m/y0FU0ef0="},"tinymce/plugins/emoticons/plugin-4e4ed709e1a04969c1d82745d84b01eb7fdd36a19a3529452c81cc2ed4e6b58d.js":{"logical_path":"tinymce/plugins/emoticons/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":1838,"digest":"4e4ed709e1a04969c1d82745d84b01eb7fdd36a19a3529452c81cc2ed4e6b58d","integrity":"sha256-Tk7XCeGgSWnB2CdF2EsB63/dNqGaNSlFLIHMLtTmtY0="},"tinymce/plugins/fullpage/plugin-2184bd5db93788e2ead614801f7f96ed7aea38a25dd6f5f94a836807da12f4b7.js":{"logical_path":"tinymce/plugins/fullpage/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":7649,"digest":"2184bd5db93788e2ead614801f7f96ed7aea38a25dd6f5f94a836807da12f4b7","integrity":"sha256-IYS9Xbk3iOLq1hSAH3+W7XrqOKJd1vX5SoNoB9oS9Lc="},"tinymce/plugins/fullscreen/plugin-58355e469e27d887f7c5cedc4ab9c33268605171d0a6ef7539d7889bd6c22e95.js":{"logical_path":"tinymce/plugins/fullscreen/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":2611,"digest":"58355e469e27d887f7c5cedc4ab9c33268605171d0a6ef7539d7889bd6c22e95","integrity":"sha256-WDVeRp4n2If3xc7cSrnDMmhgUXHQpu91OdeIm9bCLpU="},"tinymce/plugins/help/img/logo-8b03dc4f83c4fea0b62c4f9866898c98e81057c55b3e3b8c1da3f5fdbf0086e9.png":{"logical_path":"tinymce/plugins/help/img/logo.png","mtime":"2017-05-06T15:41:53+02:00","size":23101,"digest":"8b03dc4f83c4fea0b62c4f9866898c98e81057c55b3e3b8c1da3f5fdbf0086e9","integrity":"sha256-iwPcT4PE/qC2LE+YZomMmOgQV8VbPjuMHaP1/b8Ahuk="},"tinymce/plugins/help/plugin-5be1acda091dc11d9811ab091a92ec48f5d71df3540968b6fc625df544521f1b.js":{"logical_path":"tinymce/plugins/help/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":12446,"digest":"5be1acda091dc11d9811ab091a92ec48f5d71df3540968b6fc625df544521f1b","integrity":"sha256-W+Gs2gkdwR2YEasJGpLsSPXXHfNUCWi2/GJd9URSHxs="},"tinymce/plugins/hr/plugin-7e54a59e7cc42e5dbcb208c5e1e171bfa1e07a12a4f2bc29eb924e3b56b2137e.js":{"logical_path":"tinymce/plugins/hr/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":1198,"digest":"7e54a59e7cc42e5dbcb208c5e1e171bfa1e07a12a4f2bc29eb924e3b56b2137e","integrity":"sha256-flSlnnzELl28sgjF4eFxv6HgehKk8rwp65JOO1ayE34="},"tinymce/plugins/image/plugin-a7fa27198aa75971d265a7784cb8909e4bcdba563fe901dd430c3a8f399b3025.js":{"logical_path":"tinymce/plugins/image/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":9257,"digest":"a7fa27198aa75971d265a7784cb8909e4bcdba563fe901dd430c3a8f399b3025","integrity":"sha256-p/onGYqnWXHSZad4TLiQnkvNulY/6QHdQww6jzmbMCU="},"tinymce/plugins/imagetools/plugin-6e2b61fcf7c452fea691fc5f7e9ddb7f9eb1b2e59f37baf2a5f01e303da86985.js":{"logical_path":"tinymce/plugins/imagetools/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":32795,"digest":"6e2b61fcf7c452fea691fc5f7e9ddb7f9eb1b2e59f37baf2a5f01e303da86985","integrity":"sha256-bith/PfEUv6mkfxffp3bf56xsuWfN7rypfAeMD2oaYU="},"tinymce/plugins/importcss/plugin-c9f390348b03c3c6311b5babcb935a60ba6fb23cf30013749dd3cda157b784b9.js":{"logical_path":"tinymce/plugins/importcss/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":3760,"digest":"c9f390348b03c3c6311b5babcb935a60ba6fb23cf30013749dd3cda157b784b9","integrity":"sha256-yfOQNIsDw8YxG1ury5NaYLpvsjzzABN0ndPNoVe3hLk="},"tinymce/plugins/insertdatetime/plugin-918c81e56c28ac5ecf1a7cf1441532a94637da84ae8119d69f5628a42dc1a70a.js":{"logical_path":"tinymce/plugins/insertdatetime/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":2904,"digest":"918c81e56c28ac5ecf1a7cf1441532a94637da84ae8119d69f5628a42dc1a70a","integrity":"sha256-kYyB5WworF7PGnzxRBUyqUY32oSugRnWn1YopC3Bpwo="},"tinymce/plugins/legacyoutput/plugin-367fc211a27027020d9cab6dec42bf1a86f428a507bb47530386439a9d581bd7.js":{"logical_path":"tinymce/plugins/legacyoutput/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":4184,"digest":"367fc211a27027020d9cab6dec42bf1a86f428a507bb47530386439a9d581bd7","integrity":"sha256-Nn/CEaJwJwINnKtt7EK/Gob0KKUHu0dTA4ZDmp1YG9c="},"tinymce/plugins/link/plugin-e7fcbdf4cba19f7049058191a9c6caab467844d60895b8a5fdaf68f22cc65ad5.js":{"logical_path":"tinymce/plugins/link/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":11097,"digest":"e7fcbdf4cba19f7049058191a9c6caab467844d60895b8a5fdaf68f22cc65ad5","integrity":"sha256-5/y99Muhn3BJBYGRqcbKq0Z4RNYIlbil/a9o8izGWtU="},"tinymce/plugins/lists/plugin-74933ea4fb2807d67d1d82a6a4efd7371ef095c04b41336b512660f21843e1e0.js":{"logical_path":"tinymce/plugins/lists/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":14962,"digest":"74933ea4fb2807d67d1d82a6a4efd7371ef095c04b41336b512660f21843e1e0","integrity":"sha256-dJM+pPsoB9Z9HYKmpO/XNx7wlcBLQTNrUSZg8hhD4eA="},"tinymce/plugins/media/plugin-5b4758de69f15a33a07cc4cddd1a896c9de832cdd120b901a7188e57f31cb570.js":{"logical_path":"tinymce/plugins/media/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":16814,"digest":"5b4758de69f15a33a07cc4cddd1a896c9de832cdd120b901a7188e57f31cb570","integrity":"sha256-W0dY3mnxWjOgfMTN3RqJbJ3oMs3RILkBpxiOV/MctXA="},"tinymce/plugins/nonbreaking/plugin-78123c195c1e249f3cd7ccc82f823ef4e2edf67bf61b818877acd85560a64907.js":{"logical_path":"tinymce/plugins/nonbreaking/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":1531,"digest":"78123c195c1e249f3cd7ccc82f823ef4e2edf67bf61b818877acd85560a64907","integrity":"sha256-eBI8GVweJJ8818zIL4I+9OLt9nv2G4GId6zYVWCmSQc="},"tinymce/plugins/noneditable/plugin-99b4ff9b08ba148764914357b4c626cf07ce5dae739ec678d43fd6f6c6461bc0.js":{"logical_path":"tinymce/plugins/noneditable/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":2191,"digest":"99b4ff9b08ba148764914357b4c626cf07ce5dae739ec678d43fd6f6c6461bc0","integrity":"sha256-mbT/mwi6FIdkkUNXtMYmzwfOXa5znsZ41D/W9sZGG8A="},"tinymce/plugins/pagebreak/plugin-ba3703ad8ce5ff341f209e6fa1ab0afdb66d66365dde2f322338d9382f8cabcb.js":{"logical_path":"tinymce/plugins/pagebreak/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":2152,"digest":"ba3703ad8ce5ff341f209e6fa1ab0afdb66d66365dde2f322338d9382f8cabcb","integrity":"sha256-ujcDrYzl/zQfIJ5voasK/bZtZjZd3i8yIzjZOC+Mq8s="},"tinymce/plugins/paste/plugin-5ea2f4e7612eb5648fdd2beacce9818c43afbe2797336e45f589cd023774dd1f.js":{"logical_path":"tinymce/plugins/paste/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":19990,"digest":"5ea2f4e7612eb5648fdd2beacce9818c43afbe2797336e45f589cd023774dd1f","integrity":"sha256-XqL052EutWSP3SvqzOmBjEOvvieXM25F9YnNAjd03R8="},"tinymce/plugins/preview/plugin-e860cbf6871633467a618d48ed0d0ce5f3e1ec8b7a40766f6aee480950822c55.js":{"logical_path":"tinymce/plugins/preview/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":2581,"digest":"e860cbf6871633467a618d48ed0d0ce5f3e1ec8b7a40766f6aee480950822c55","integrity":"sha256-6GDL9ocWM0Z6YY1I7Q0M5fPh7It6QHZvau5ICVCCLFU="},"tinymce/plugins/print/plugin-360588108f9b3c4d49e62b084a288f7b789d4555ff53eaedd793b7880d5b0799.js":{"logical_path":"tinymce/plugins/print/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":1169,"digest":"360588108f9b3c4d49e62b084a288f7b789d4555ff53eaedd793b7880d5b0799","integrity":"sha256-NgWIEI+bPE1J5isISiiPe3idRVX/U+rt15O3iA1bB5k="},"tinymce/plugins/save/plugin-18a4bdbbb2894ce2f3badb7a901ce2b21f18c9cbe54c1c346245ea3092f1d230.js":{"logical_path":"tinymce/plugins/save/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":2202,"digest":"18a4bdbbb2894ce2f3badb7a901ce2b21f18c9cbe54c1c346245ea3092f1d230","integrity":"sha256-GKS9u7KJTOLzutt6kBzish8YycvlTBw0YkXqMJLx0jA="},"tinymce/plugins/searchreplace/plugin-3dad9365a33b45d286959d6c7dae648e67c1e721a446205bf188136a4b9535d6.js":{"logical_path":"tinymce/plugins/searchreplace/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":7469,"digest":"3dad9365a33b45d286959d6c7dae648e67c1e721a446205bf188136a4b9535d6","integrity":"sha256-Pa2TZaM7RdKGlZ1sfa5kjmfB5yGkRiBb8YgTakuVNdY="},"tinymce/plugins/spellchecker/plugin-60aa63b171fe9d7ca87cea6be839a0ad9564774a80746413ad41b7665f9cec5b.js":{"logical_path":"tinymce/plugins/spellchecker/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":10068,"digest":"60aa63b171fe9d7ca87cea6be839a0ad9564774a80746413ad41b7665f9cec5b","integrity":"sha256-YKpjsXH+nXyofOpr6DmgrZVkd0qAdGQTrUG3Zl+c7Fs="},"tinymce/plugins/tabfocus/plugin-c004f18acdee65bc533bf582e05017cb72a1c78e235e6a6301d7f8cb218f059e.js":{"logical_path":"tinymce/plugins/tabfocus/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":2368,"digest":"c004f18acdee65bc533bf582e05017cb72a1c78e235e6a6301d7f8cb218f059e","integrity":"sha256-wATxis3uZbxTO/WC4FAXy3Khx44jXmpjAdf4yyGPBZ4="},"tinymce/plugins/table/plugin-efc0df279cc09409c65205bccfb16b14cac7284dbee694a9470169d1d20da8a6.js":{"logical_path":"tinymce/plugins/table/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":47627,"digest":"efc0df279cc09409c65205bccfb16b14cac7284dbee694a9470169d1d20da8a6","integrity":"sha256-78DfJ5zAlAnGUgW8z7FrFMrHKE2+5pSpRwFp0dINqKY="},"tinymce/plugins/template/plugin-4ee9d732d38b4420d0ff96f56f348ac9ae4293315ebff83ce441237f2eb991bf.js":{"logical_path":"tinymce/plugins/template/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":5588,"digest":"4ee9d732d38b4420d0ff96f56f348ac9ae4293315ebff83ce441237f2eb991bf","integrity":"sha256-TunXMtOLRCDQ/5b1bzSKya5CkzFev/g85EEjfy65kb8="},"tinymce/plugins/textcolor/plugin-7f993a50c7d5ca5af4a2117aecbafa820fc5c669bae6916509bc392b21ec10d7.js":{"logical_path":"tinymce/plugins/textcolor/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":5169,"digest":"7f993a50c7d5ca5af4a2117aecbafa820fc5c669bae6916509bc392b21ec10d7","integrity":"sha256-f5k6UMfVylr0ohF67Lr6gg/Fxmm65pFlCbw5KyHsENc="},"tinymce/plugins/textpattern/plugin-3abf3b59885a2b30139e25377c6ebf369e77178752ded63a8ae3a04bba7dabeb.js":{"logical_path":"tinymce/plugins/textpattern/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":4951,"digest":"3abf3b59885a2b30139e25377c6ebf369e77178752ded63a8ae3a04bba7dabeb","integrity":"sha256-Or87WYhaKzATniU3fG6/Np53F4dS3tY6iuOgS7p9q+s="},"tinymce/plugins/toc/plugin-24e4d24233ae96b5d80a1add45fed792c0be45c2ffb266957112465cd45ed0b7.js":{"logical_path":"tinymce/plugins/toc/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":3764,"digest":"24e4d24233ae96b5d80a1add45fed792c0be45c2ffb266957112465cd45ed0b7","integrity":"sha256-JOTSQjOulrXYChrdRf7XksC+RcL/smaVcRJGXNRe0Lc="},"tinymce/plugins/visualblocks/plugin-d65e950bb619d5c52a4fb236da31bb0ecc492e7477e7b0841a2ac06b6faeea26.js":{"logical_path":"tinymce/plugins/visualblocks/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":2029,"digest":"d65e950bb619d5c52a4fb236da31bb0ecc492e7477e7b0841a2ac06b6faeea26","integrity":"sha256-1l6VC7YZ1cUqT7I22jG7DsxJLnR357CEGirAa2+u6iY="},"tinymce/plugins/visualchars/plugin-d56ff99b2792abbb690ebafe6d70e6c4487a7f5cf2788cb1f3fa4ea62d8b70a2.js":{"logical_path":"tinymce/plugins/visualchars/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":8944,"digest":"d56ff99b2792abbb690ebafe6d70e6c4487a7f5cf2788cb1f3fa4ea62d8b70a2","integrity":"sha256-1W/5myeSq7tpDrr+bXDmxEh6f1zyeIyx8/pOpi2LcKI="},"tinymce/plugins/wordcount/plugin-450b905dc9037e85dcfa8ea5236a008d84406ced3e06462cc9813de86853b40c.js":{"logical_path":"tinymce/plugins/wordcount/plugin.js","mtime":"2017-05-06T15:41:53+02:00","size":12127,"digest":"450b905dc9037e85dcfa8ea5236a008d84406ced3e06462cc9813de86853b40c","integrity":"sha256-RQuQXckDfoXc+o6lI2oAjYRAbO0+BkYsyYE96GhTtAw="},"tinymce/skins/lightgray/content.inline.min-9930897d36862d7382a4daf86a17df91d9a5892c6b5939af7db04e7184ee7908.css":{"logical_path":"tinymce/skins/lightgray/content.inline.min.css","mtime":"2017-05-06T15:41:53+02:00","size":3074,"digest":"9930897d36862d7382a4daf86a17df91d9a5892c6b5939af7db04e7184ee7908","integrity":"sha256-mTCJfTaGLXOCpNr4ahffkdmliSxrWTmvfbBOcYTueQg="},"tinymce/skins/lightgray/content.min-ba763c80bdbabea34fe6634a43b1181ea131498a892903d742579d91cc3d658e.css":{"logical_path":"tinymce/skins/lightgray/content.min.css","mtime":"2017-05-06T15:41:53+02:00","size":3498,"digest":"ba763c80bdbabea34fe6634a43b1181ea131498a892903d742579d91cc3d658e","integrity":"sha256-unY8gL26vqNP5mNKQ7EYHqExSYqJKQPXQledkcw9ZY4="},"tinymce/skins/lightgray/skin.min-48be1dca174d1fa8e98ccc23d4d6741ea268cb2b20a4b8a7fb365e3c175bd769.css":{"logical_path":"tinymce/skins/lightgray/skin.min.css","mtime":"2017-05-06T15:41:53+02:00","size":39404,"digest":"48be1dca174d1fa8e98ccc23d4d6741ea268cb2b20a4b8a7fb365e3c175bd769","integrity":"sha256-SL4dyhdNH6jpjMwj1NZ0HqJoyysgpLin+zZePBdb12k="},"tinymce/themes/inlite/theme-24ec9fa4b7330913ca96f683fcfcdcdfa43714f91e8bba74bfbdfdf01cb63324.js":{"logical_path":"tinymce/themes/inlite/theme.js","mtime":"2017-05-06T15:41:53+02:00","size":17028,"digest":"24ec9fa4b7330913ca96f683fcfcdcdfa43714f91e8bba74bfbdfdf01cb63324","integrity":"sha256-JOyfpLczCRPKlvaD/Pzc36Q3FPkei7p0v7398By2MyQ="},"tinymce/themes/modern/theme-4547e25369b8acbbc7101f29494cfd7d289c31d221eb99d0b9d5f340ef3af240.js":{"logical_path":"tinymce/themes/modern/theme.js","mtime":"2017-05-06T15:41:53+02:00","size":14213,"digest":"4547e25369b8acbbc7101f29494cfd7d289c31d221eb99d0b9d5f340ef3af240","integrity":"sha256-RUfiU2m4rLvHEB8pSUz9fSicMdIh65nQudXzQO868kA="}},"assets":{"active_admin.css":"active_admin-f7ef723200f732c68bf56214e1c6ac931008f3de4eba9dcd29e140696b46f0a0.css","active_admin/nested_menu_arrow.gif":"active_admin/nested_menu_arrow-15084d93c65c1964d7077700ea748bd2d70cfa2d4c19707c58a9c64e232dd442.gif","active_admin/nested_menu_arrow_dark.gif":"active_admin/nested_menu_arrow_dark-7c43b8e0a5f8823875f49a093c9d7a6b374f885b6f9cc248ae9cd7e6e9b29034.gif","active_admin/datepicker/datepicker-input-icon.png":"active_admin/datepicker/datepicker-input-icon-d9c2bb73769af777c8a71720d29741f3a499aebd5a043e9a119bd0d9597aed47.png","active_admin/orderable.png":"active_admin/orderable-29374dbb55b0012d78a37c614d573bb3474f0779849b478a147d0f1845ca6617.png","active_admin/print.css":"active_admin/print-87c5ffc1d869a919123bcc1dc5ec51b20bc79fd9aeab9eed77e3438c6acd4f68.css","active_admin.js":"active_admin-23d58e148201d77c88712977540f99db82c21bece116faa407af2e3a099a9417.js","layers-2x.png":"layers-2x-066daca850d8ffbef007af00b06eac0015728dee279c51f3cb6c716df7c42edf.png","layers.png":"layers-1dbbe9d028e292f36fcba8f8b3a28d5e8932754fc2215b9ac69e4cdecf5107c6.png","marker-icon-2x.png":"marker-icon-2x-2d77a2e4c2f08bbac41808324ef946b9a2fe61b6150480d011b72b379c3b238d.png","marker-icon.png":"marker-icon-574c3a5cca85f4114085b6841596d62f00d7c892c7b03f28cbfa301deb1dc437.png","marker-shadow.png":"marker-shadow-264f5c640339f042dd729062cfc04c17f8ea0f29882b538e3848ed8f10edb4da.png","tinymce.js":"tinymce-c09e1a38c74241759c70df0385e95b4c46d6cd0342bd271315c2457b25591aad.js","application.css":"application-74c16b3b8c70a0ee2d3bc48bb2acbb9925fc52b1cd41171d7cb5063cd119ba3a.css","jquery-ui/ui-icons_444444_256x240.png":"jquery-ui/ui-icons_444444_256x240-31d988765b4e6f56553c29588c500381dc3e6f0aa2980c8212202e5644aefd5d.png","jquery-ui/ui-icons_555555_256x240.png":"jquery-ui/ui-icons_555555_256x240-32175261daee76c82bb0edf0eea16a56421866fbc31e94f3c1d570aa114502f5.png","jquery-ui/ui-icons_ffffff_256x240.png":"jquery-ui/ui-icons_ffffff_256x240-350df1b7131037de20e83c5c0f3a41a770d2ac48b5762ea772b3f4a8a7b9d47a.png","jquery-ui/ui-icons_777620_256x240.png":"jquery-ui/ui-icons_777620_256x240-0b020fc6e696d88d296e7bb1f61f1eb2ad827848e2c7382a4c3e0999e702dd9b.png","jquery-ui/ui-icons_cc0000_256x240.png":"jquery-ui/ui-icons_cc0000_256x240-40985a64b4d5dd213fba27fcd862a1bd1b337a97674f6ff0b9ec20abcee4bc69.png","jquery-ui/ui-icons_777777_256x240.png":"jquery-ui/ui-icons_777777_256x240-faf32007ae120c302213557626e660dd10e711c5dd4f1113d35f26dc05b78d2f.png","font-awesome/fontawesome-webfont.eot":"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot","font-awesome/fontawesome-webfont.woff2":"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2","font-awesome/fontawesome-webfont.woff":"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff","font-awesome/fontawesome-webfont.ttf":"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf","font-awesome/fontawesome-webfont.svg":"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg","markers-soft.png":"markers-soft-e78784e4ed70aaffddd73c315fab590233cc4e7b72388d7dd47a14796fc7c739.png","markers-shadow.png":"markers-shadow-8703a2262710f5e3d29e65d2acdf90d6512e159e119d27b8234731d8a6208a20.png","markers-soft@2x.png":"markers-soft@2x-c1e77253a8bfbe30cec24885d7046f443b76ebb66f4c961f77083b03f4a5cbaf.png","markers-shadow@2x.png":"markers-shadow@2x-b21a536be27313fb504f69f5899ff0b1245b276571769ac08d6c32c35676e47a.png","france.png":"france-f4341a7ec8331161a9c8d5298f808014c3fc9c799b5a29ed95eb56a7f3ccd0df.png","quebec.png":"quebec-776d563b6a4ac4312cae9f0bfe630c20711346e8dbddd41040998eba79f4b588.png","belgique.png":"belgique-3b8b772a522de2cbae7714b35a956faf2c394419b532a14bba982fed3f341091.png","suisse.png":"suisse-58d067f1c3fcdc4000fa13e95896cd5369a2b91aafd314475aa5e29da0b543d1.png","modernizr.js":"modernizr-654222debe8018b12f1993ceddff30dc163a7d5008d79869c399d6d167321f97.js","agendadescommuns.png":"agendadescommuns-cd40e342024be0587f8e7a0e3902d32cf67009d349b67c00f687e0499fde9ff6.png","alert.png":"alert-762ace9479328243a44061346b64c4d6b997e963c68dfc6bddd9e4d241192906.png","baby_gnu_adl.png":"baby_gnu_adl-232caf355c30740d5d9b30491887cd546b8849b33ca9bdb6cc71f8a47ea61815.png","baby_gnu_adl.svg":"baby_gnu_adl-97251005d3225cf1d58b8c497d6b7905dbc9560cc8acd50118fcce60d0a2679e.svg","communs.png":"communs-cd40e342024be0587f8e7a0e3902d32cf67009d349b67c00f687e0499fde9ff6.png","lef-small.png":"lef-small-160cf5b883add60c9c0f4361bd8425c75f6fb23b0e551a0b941fa0491c70e0c9.png","lef.png":"lef-9fcdd7ddd4d40de29c3809b59688c668b85f5628e219d4cd8a8810b72a64533b.png","priorite-logiciel-libre-je-soutiens-april_2_m.png":"priorite-logiciel-libre-je-soutiens-april_2_m-6442e454e96ed45cc1ebc40673a6c50bd286b9c28ea6a8b58572e94f7d6459fc.png","team.png":"team-cb04c7a311f7160c4eb6a281eae68be84f26991dde5d415bb4e205e6726ae275.png","application.js":"application-f22e563794b5c8c393d971168eb18deacfb064852fd91258978766d532fbb5a7.js","markers-matte.png":"markers-matte-497826545a90e09a240504d14530eba45823b19fd44175e09e27c47cd822ddb9.png","markers-matte@2x.png":"markers-matte@2x-948fc8c4426f04f60964ed20394247f45b0b60e575d02398b9b6810e7a29a823.png","markers-plain.png":"markers-plain-cf233423aa44e75ac0031e77b8ba571cd3331010517e1197e63fb7b06856c1ff.png","tinymce/plugins/emoticons/img/smiley-cool.gif":"tinymce/plugins/emoticons/img/smiley-cool-bb0e93a050a32df7913e4026b3c88a176998e0e3e073ba06e9b73f6c24227c9c.gif","tinymce/plugins/emoticons/img/smiley-cry.gif":"tinymce/plugins/emoticons/img/smiley-cry-a0c5f3e7a682449c973c9d9f7c46342081c46920686d2353f57aff91ab907f68.gif","tinymce/plugins/emoticons/img/smiley-embarassed.gif":"tinymce/plugins/emoticons/img/smiley-embarassed-d3cafcb50b335672cb5e9f4600ea9ea261dac7828dd28844d4927c393a25618f.gif","tinymce/plugins/emoticons/img/smiley-foot-in-mouth.gif":"tinymce/plugins/emoticons/img/smiley-foot-in-mouth-03fe04d3ed533423ac81f05146584b0c451be3d4a30e76687ceef283ed07071f.gif","tinymce/plugins/emoticons/img/smiley-frown.gif":"tinymce/plugins/emoticons/img/smiley-frown-1b984bf98931dd1debb54461eb9d83e985f2b2999fe14bcb556d6c0921bc83b0.gif","tinymce/plugins/emoticons/img/smiley-innocent.gif":"tinymce/plugins/emoticons/img/smiley-innocent-8db353ef102196f2c6ddf5c4666446de955d7b14fc0957c806c9dbfb48fb0c29.gif","tinymce/plugins/emoticons/img/smiley-kiss.gif":"tinymce/plugins/emoticons/img/smiley-kiss-3154c3665356c13ab10fefdbac1fe187fff978a0052037c99cdc4a97103413f2.gif","tinymce/plugins/emoticons/img/smiley-laughing.gif":"tinymce/plugins/emoticons/img/smiley-laughing-8f6adedcd091975ffead171867a6304d908bb6541a6ccb4919286ec6b7d4551e.gif","tinymce/plugins/emoticons/img/smiley-money-mouth.gif":"tinymce/plugins/emoticons/img/smiley-money-mouth-f0b9f4f22e237f5dbc851f900fed8d7eca4c954ae6fbc606c0cd8be431d0ac80.gif","tinymce/plugins/emoticons/img/smiley-sealed.gif":"tinymce/plugins/emoticons/img/smiley-sealed-9933b442636b6e537df7b564e2c3f7a2873526eea6b022a98eb1e468e5204c32.gif","tinymce/plugins/emoticons/img/smiley-smile.gif":"tinymce/plugins/emoticons/img/smiley-smile-fd89cd460ffcacb7e725e00c0275ef5b3924ce468248e5ff4fb43545571cfa65.gif","tinymce/plugins/emoticons/img/smiley-surprised.gif":"tinymce/plugins/emoticons/img/smiley-surprised-3871f356cb41976d7ae8a5f005e8739e4d014352a8adef9b33f773d81b6e6c01.gif","tinymce/plugins/emoticons/img/smiley-tongue-out.gif":"tinymce/plugins/emoticons/img/smiley-tongue-out-5843c85667a8226dc43be83749fd9fbbc5d20b1577de2b763915d99815d37d47.gif","tinymce/plugins/emoticons/img/smiley-undecided.gif":"tinymce/plugins/emoticons/img/smiley-undecided-d8b9bcbb433951ff3c4ca8dd959ac3844239b98e6d52218833e1485a91f67347.gif","tinymce/plugins/emoticons/img/smiley-wink.gif":"tinymce/plugins/emoticons/img/smiley-wink-2af75ad7b1c08488505513503e34b15f40005e04a2a9568f698f0945d2d8ba1f.gif","tinymce/plugins/emoticons/img/smiley-yell.gif":"tinymce/plugins/emoticons/img/smiley-yell-bba903fbcb46fce8c68b9e01863fd095b3b1d0e6aa72161f3a88d762a5f90a79.gif","tinymce/skins/lightgray/img/anchor.gif":"tinymce/skins/lightgray/img/anchor-2861666fd107d278d4449970615136d06d7f746be9bb19072cf9c8f30e565e1e.gif","tinymce/skins/lightgray/img/loader.gif":"tinymce/skins/lightgray/img/loader-eb7cfd3d959b2e09c170f532e29f8b825f9bc770b2279fde58e595617753e244.gif","tinymce/skins/lightgray/img/object.gif":"tinymce/skins/lightgray/img/object-e6a15e52bc4a17b085073ba8debd4708ead6ae3d4cbeb3880c65cb7afc489777.gif","tinymce/skins/lightgray/img/trans.gif":"tinymce/skins/lightgray/img/trans-9cf020d7c3bba7f5ab10cda54aabef934f906d4f9a3acf99e9e7dc6c98579635.gif","jquery-ui/ui-bg_flat_0_aaaaaa_40x100.png":"jquery-ui/ui-bg_flat_0_aaaaaa_40x100-ae65a7ae22c4c23115948fdeb5c05c9137dbd13ca2d426b3c4c3c4183451e410.png","tinymce/jquery.tinymce.js":"tinymce/jquery.tinymce-4708a7ae12d4dd7d315d7475258257d344304f4256b535fc5c4c3ac4fa01986c.js","tinymce/langs/readme.md":"tinymce/langs/readme-5a8b6a04d57b5c88e3fb7f2a870b8e2d3a48ec03ce6474206c41df78c155b2de.md","tinymce/license.txt":"tinymce/license-47a9dcd2574891a5a465112fd9dfcebcc7e61844edec27fa936a64642008fe66.txt","tinymce/plugins/advlist/plugin.js":"tinymce/plugins/advlist/plugin-a3bae9788cb831a5c87db458d3608696f5cdd9159f8c9af2a859e6cff3463327.js","tinymce/plugins/anchor/plugin.js":"tinymce/plugins/anchor/plugin-910353b28da9ffa1075fd37b1c95f1f05f0d6809e41a5e4250b33e1a3a7a86c8.js","tinymce/plugins/autolink/plugin.js":"tinymce/plugins/autolink/plugin-8dc80b03dea3552f0f39b5eb0558104bff82ae57ad3d8ecbbdf60123025e5493.js","tinymce/plugins/autoresize/plugin.js":"tinymce/plugins/autoresize/plugin-2e0a2856650e8fa09fba9a00fd18a9078e5ee436c6c47ead6ba6689fee74cafa.js","tinymce/plugins/autosave/plugin.js":"tinymce/plugins/autosave/plugin-55a285a6bc363cbf99b2638deccef1fda08941114407e360300617bd9e86dddc.js","tinymce/plugins/bbcode/plugin.js":"tinymce/plugins/bbcode/plugin-3e2fdc6fa5b587ce568ca570974d0e910b6684e392a9ecaba02b5c6c15269080.js","tinymce/plugins/charmap/plugin.js":"tinymce/plugins/charmap/plugin-f0c699e1edeacfaf2f1342019986c8c41653ae723c8befc205dee077de317ab8.js","tinymce/plugins/code/plugin.js":"tinymce/plugins/code/plugin-2c12bcd21813fa52b23a65c3080cc6f4ecb33be04ee058b6c460719724511372.js","tinymce/plugins/codesample/css/prism.css":"tinymce/plugins/codesample/css/prism-1988b66704b4d23e78c6c20c38a6856cbc1f0be96d6d60a3a0b12f4408f1057e.css","tinymce/plugins/codesample/plugin.dev.js":"tinymce/plugins/codesample/plugin.dev.js","tinymce/plugins/codesample/plugin.js":"tinymce/plugins/codesample/plugin-a3591d2c33d0499eed106bbdc9d0aa698115456632cb806e8f44bdf270d8d6b8.js","tinymce/plugins/colorpicker/plugin.js":"tinymce/plugins/colorpicker/plugin-f4ea1ac5bfaaef5adef0789427a1ef1e3c07814ff9a7623953bfb1a79f9f502d.js","tinymce/plugins/contextmenu/plugin.js":"tinymce/plugins/contextmenu/plugin-f13279e7538cd4153798055dbc81d495831aa421056061b85496d304cdfcd280.js","tinymce/plugins/directionality/plugin.js":"tinymce/plugins/directionality/plugin-8b9d9e0d97d8cf5c20b4f74509a94cbd84c59b330d7badaad66ff2d0553479fd.js","tinymce/plugins/emoticons/plugin.js":"tinymce/plugins/emoticons/plugin-4e4ed709e1a04969c1d82745d84b01eb7fdd36a19a3529452c81cc2ed4e6b58d.js","tinymce/plugins/example/dialog.html":"tinymce/plugins/example/dialog-5c61ad829a494e75c2234019c7941f6dd096ec693cf5a5538c0bf30485097841.html","tinymce/plugins/example/plugin.js":"tinymce/plugins/example/plugin-505b7ee82929e7338700605a4ca63d94dbe6ef2ce2d21104cc01c2adba829868.js","tinymce/plugins/example_dependency/plugin.js":"tinymce/plugins/example_dependency/plugin-9bb52c9d45c0f7e4d67c12f546c68095b2d5284aa84ab3a2c45f1d986f464653.js","tinymce/plugins/fullpage/plugin.js":"tinymce/plugins/fullpage/plugin-2184bd5db93788e2ead614801f7f96ed7aea38a25dd6f5f94a836807da12f4b7.js","tinymce/plugins/fullscreen/plugin.js":"tinymce/plugins/fullscreen/plugin-58355e469e27d887f7c5cedc4ab9c33268605171d0a6ef7539d7889bd6c22e95.js","tinymce/plugins/hr/plugin.js":"tinymce/plugins/hr/plugin-7e54a59e7cc42e5dbcb208c5e1e171bfa1e07a12a4f2bc29eb924e3b56b2137e.js","tinymce/plugins/image/plugin.js":"tinymce/plugins/image/plugin-a7fa27198aa75971d265a7784cb8909e4bcdba563fe901dd430c3a8f399b3025.js","tinymce/plugins/imagetools/plugin.js":"tinymce/plugins/imagetools/plugin-6e2b61fcf7c452fea691fc5f7e9ddb7f9eb1b2e59f37baf2a5f01e303da86985.js","tinymce/plugins/importcss/plugin.js":"tinymce/plugins/importcss/plugin-c9f390348b03c3c6311b5babcb935a60ba6fb23cf30013749dd3cda157b784b9.js","tinymce/plugins/insertdatetime/plugin.js":"tinymce/plugins/insertdatetime/plugin-918c81e56c28ac5ecf1a7cf1441532a94637da84ae8119d69f5628a42dc1a70a.js","tinymce/plugins/layer/plugin.js":"tinymce/plugins/layer/plugin.js","tinymce/plugins/legacyoutput/plugin.js":"tinymce/plugins/legacyoutput/plugin-367fc211a27027020d9cab6dec42bf1a86f428a507bb47530386439a9d581bd7.js","tinymce/plugins/link/plugin.js":"tinymce/plugins/link/plugin-e7fcbdf4cba19f7049058191a9c6caab467844d60895b8a5fdaf68f22cc65ad5.js","tinymce/plugins/lists/plugin.js":"tinymce/plugins/lists/plugin-74933ea4fb2807d67d1d82a6a4efd7371ef095c04b41336b512660f21843e1e0.js","tinymce/plugins/media/plugin.js":"tinymce/plugins/media/plugin-5b4758de69f15a33a07cc4cddd1a896c9de832cdd120b901a7188e57f31cb570.js","tinymce/plugins/nonbreaking/plugin.js":"tinymce/plugins/nonbreaking/plugin-78123c195c1e249f3cd7ccc82f823ef4e2edf67bf61b818877acd85560a64907.js","tinymce/plugins/noneditable/plugin.js":"tinymce/plugins/noneditable/plugin-99b4ff9b08ba148764914357b4c626cf07ce5dae739ec678d43fd6f6c6461bc0.js","tinymce/plugins/pagebreak/plugin.js":"tinymce/plugins/pagebreak/plugin-ba3703ad8ce5ff341f209e6fa1ab0afdb66d66365dde2f322338d9382f8cabcb.js","tinymce/plugins/paste/plugin.dev.js":"tinymce/plugins/paste/plugin.dev.js","tinymce/plugins/paste/plugin.js":"tinymce/plugins/paste/plugin-5ea2f4e7612eb5648fdd2beacce9818c43afbe2797336e45f589cd023774dd1f.js","tinymce/plugins/preview/plugin.js":"tinymce/plugins/preview/plugin-e860cbf6871633467a618d48ed0d0ce5f3e1ec8b7a40766f6aee480950822c55.js","tinymce/plugins/print/plugin.js":"tinymce/plugins/print/plugin-360588108f9b3c4d49e62b084a288f7b789d4555ff53eaedd793b7880d5b0799.js","tinymce/plugins/save/plugin.js":"tinymce/plugins/save/plugin-18a4bdbbb2894ce2f3badb7a901ce2b21f18c9cbe54c1c346245ea3092f1d230.js","tinymce/plugins/searchreplace/plugin.js":"tinymce/plugins/searchreplace/plugin-3dad9365a33b45d286959d6c7dae648e67c1e721a446205bf188136a4b9535d6.js","tinymce/plugins/spellchecker/plugin.dev.js":"tinymce/plugins/spellchecker/plugin.dev.js","tinymce/plugins/spellchecker/plugin.js":"tinymce/plugins/spellchecker/plugin-60aa63b171fe9d7ca87cea6be839a0ad9564774a80746413ad41b7665f9cec5b.js","tinymce/plugins/tabfocus/plugin.js":"tinymce/plugins/tabfocus/plugin-c004f18acdee65bc533bf582e05017cb72a1c78e235e6a6301d7f8cb218f059e.js","tinymce/plugins/table/plugin.dev.js":"tinymce/plugins/table/plugin.dev.js","tinymce/plugins/table/plugin.js":"tinymce/plugins/table/plugin-efc0df279cc09409c65205bccfb16b14cac7284dbee694a9470169d1d20da8a6.js","tinymce/plugins/template/plugin.js":"tinymce/plugins/template/plugin-4ee9d732d38b4420d0ff96f56f348ac9ae4293315ebff83ce441237f2eb991bf.js","tinymce/plugins/textcolor/plugin.js":"tinymce/plugins/textcolor/plugin-7f993a50c7d5ca5af4a2117aecbafa820fc5c669bae6916509bc392b21ec10d7.js","tinymce/plugins/textpattern/plugin.js":"tinymce/plugins/textpattern/plugin-3abf3b59885a2b30139e25377c6ebf369e77178752ded63a8ae3a04bba7dabeb.js","tinymce/plugins/toc/plugin.js":"tinymce/plugins/toc/plugin-24e4d24233ae96b5d80a1add45fed792c0be45c2ffb266957112465cd45ed0b7.js","tinymce/plugins/visualblocks/css/visualblocks.css":"tinymce/plugins/visualblocks/css/visualblocks-e44e30ebe30e4d3763425a9ea38b558ff13106b8e16a30a74ae21b4c174b3417.css","tinymce/plugins/visualblocks/plugin.js":"tinymce/plugins/visualblocks/plugin-d65e950bb619d5c52a4fb236da31bb0ecc492e7477e7b0841a2ac06b6faeea26.js","tinymce/plugins/visualchars/plugin.js":"tinymce/plugins/visualchars/plugin-d56ff99b2792abbb690ebafe6d70e6c4487a7f5cf2788cb1f3fa4ea62d8b70a2.js","tinymce/plugins/wordcount/plugin.js":"tinymce/plugins/wordcount/plugin-450b905dc9037e85dcfa8ea5236a008d84406ced3e06462cc9813de86853b40c.js","tinymce/skins/lightgray/AbsoluteLayout.less":"tinymce/skins/lightgray/AbsoluteLayout.less","tinymce/skins/lightgray/Animations.less":"tinymce/skins/lightgray/Animations.less","tinymce/skins/lightgray/Arrows.less":"tinymce/skins/lightgray/Arrows.less","tinymce/skins/lightgray/Button.less":"tinymce/skins/lightgray/Button.less","tinymce/skins/lightgray/ButtonGroup.less":"tinymce/skins/lightgray/ButtonGroup.less","tinymce/skins/lightgray/Checkbox.less":"tinymce/skins/lightgray/Checkbox.less","tinymce/skins/lightgray/ColorBox.less":"tinymce/skins/lightgray/ColorBox.less","tinymce/skins/lightgray/ColorButton.less":"tinymce/skins/lightgray/ColorButton.less","tinymce/skins/lightgray/ColorPicker.less":"tinymce/skins/lightgray/ColorPicker.less","tinymce/skins/lightgray/ComboBox.less":"tinymce/skins/lightgray/ComboBox.less","tinymce/skins/lightgray/Container.less":"tinymce/skins/lightgray/Container.less","tinymce/skins/lightgray/Content.Inline.less":"tinymce/skins/lightgray/Content.Inline.less","tinymce/skins/lightgray/Content.Objects.less":"tinymce/skins/lightgray/Content.Objects.less","tinymce/skins/lightgray/Content.less":"tinymce/skins/lightgray/Content.less","tinymce/skins/lightgray/CropRect.less":"tinymce/skins/lightgray/CropRect.less","tinymce/skins/lightgray/FieldSet.less":"tinymce/skins/lightgray/FieldSet.less","tinymce/skins/lightgray/FitLayout.less":"tinymce/skins/lightgray/FitLayout.less","tinymce/skins/lightgray/FloatPanel.less":"tinymce/skins/lightgray/FloatPanel.less","tinymce/skins/lightgray/FlowLayout.less":"tinymce/skins/lightgray/FlowLayout.less","tinymce/skins/lightgray/Icons.Ie7.less":"tinymce/skins/lightgray/Icons.Ie7.less","tinymce/skins/lightgray/Icons.less":"tinymce/skins/lightgray/Icons.less","tinymce/skins/lightgray/Iframe.less":"tinymce/skins/lightgray/Iframe.less","tinymce/skins/lightgray/ImagePanel.less":"tinymce/skins/lightgray/ImagePanel.less","tinymce/skins/lightgray/InfoBox.less":"tinymce/skins/lightgray/InfoBox.less","tinymce/skins/lightgray/Label.less":"tinymce/skins/lightgray/Label.less","tinymce/skins/lightgray/ListBox.less":"tinymce/skins/lightgray/ListBox.less","tinymce/skins/lightgray/Menu.less":"tinymce/skins/lightgray/Menu.less","tinymce/skins/lightgray/MenuBar.less":"tinymce/skins/lightgray/MenuBar.less","tinymce/skins/lightgray/MenuButton.less":"tinymce/skins/lightgray/MenuButton.less","tinymce/skins/lightgray/MenuItem.less":"tinymce/skins/lightgray/MenuItem.less","tinymce/skins/lightgray/Mixins.less":"tinymce/skins/lightgray/Mixins.less","tinymce/skins/lightgray/Notification.less":"tinymce/skins/lightgray/Notification.less","tinymce/skins/lightgray/Panel.less":"tinymce/skins/lightgray/Panel.less","tinymce/skins/lightgray/Path.less":"tinymce/skins/lightgray/Path.less","tinymce/skins/lightgray/Progress.less":"tinymce/skins/lightgray/Progress.less","tinymce/skins/lightgray/Radio.less":"tinymce/skins/lightgray/Radio.less","tinymce/skins/lightgray/Reset.less":"tinymce/skins/lightgray/Reset.less","tinymce/skins/lightgray/ResizeHandle.less":"tinymce/skins/lightgray/ResizeHandle.less","tinymce/skins/lightgray/Scrollable.less":"tinymce/skins/lightgray/Scrollable.less","tinymce/skins/lightgray/SelectBox.less":"tinymce/skins/lightgray/SelectBox.less","tinymce/skins/lightgray/Sidebar.less":"tinymce/skins/lightgray/Sidebar.less","tinymce/skins/lightgray/Slider.less":"tinymce/skins/lightgray/Slider.less","tinymce/skins/lightgray/Spacer.less":"tinymce/skins/lightgray/Spacer.less","tinymce/skins/lightgray/SplitButton.less":"tinymce/skins/lightgray/SplitButton.less","tinymce/skins/lightgray/StackLayout.less":"tinymce/skins/lightgray/StackLayout.less","tinymce/skins/lightgray/TabPanel.less":"tinymce/skins/lightgray/TabPanel.less","tinymce/skins/lightgray/TextBox.less":"tinymce/skins/lightgray/TextBox.less","tinymce/skins/lightgray/Throbber.less":"tinymce/skins/lightgray/Throbber.less","tinymce/skins/lightgray/TinyMCE.less":"tinymce/skins/lightgray/TinyMCE.less","tinymce/skins/lightgray/ToolTip.less":"tinymce/skins/lightgray/ToolTip.less","tinymce/skins/lightgray/Variables.less":"tinymce/skins/lightgray/Variables.less","tinymce/skins/lightgray/Window.less":"tinymce/skins/lightgray/Window.less","tinymce/skins/lightgray/content.inline.min.css":"tinymce/skins/lightgray/content.inline.min-9930897d36862d7382a4daf86a17df91d9a5892c6b5939af7db04e7184ee7908.css","tinymce/skins/lightgray/content.min.css":"tinymce/skins/lightgray/content.min-ba763c80bdbabea34fe6634a43b1181ea131498a892903d742579d91cc3d658e.css","tinymce/skins/lightgray/fonts/tinymce-small.eot":"tinymce/skins/lightgray/fonts/tinymce-small-a10fc4343d95b716c16d77463d475be5c079599ea67e1cd2bd3a94d5e7f508f9.eot","tinymce/skins/lightgray/fonts/tinymce-small.svg":"tinymce/skins/lightgray/fonts/tinymce-small-e7773001446ab937e1d8d4bd5e8dbd9b31d112037353a14b319e36dd010ed8ee.svg","tinymce/skins/lightgray/fonts/tinymce-small.ttf":"tinymce/skins/lightgray/fonts/tinymce-small-2f657502906d6f5c3fc8df3a82969114ebe030addfdc061c60c974b0f515fd09.ttf","tinymce/skins/lightgray/fonts/tinymce-small.woff":"tinymce/skins/lightgray/fonts/tinymce-small-d3efbb678ca6de5632902bd93772746ba2f8e4e2322b953936e12694a183aa31.woff","tinymce/skins/lightgray/fonts/tinymce.eot":"tinymce/skins/lightgray/fonts/tinymce-2e9c4a68fde992476e0db9e44128cb1f2e898f0de0b80f552a8acb52bb7ca0db.eot","tinymce/skins/lightgray/fonts/tinymce.svg":"tinymce/skins/lightgray/fonts/tinymce-2094ddadc265c7f33570475fc78ef7adcdcb814e49060d17f5b4c4f8d1cb7ec6.svg","tinymce/skins/lightgray/fonts/tinymce.ttf":"tinymce/skins/lightgray/fonts/tinymce-477ea2d46c1a975dd492af4c10235fabfd09069595779cce00ea0381ca9b4a20.ttf","tinymce/skins/lightgray/fonts/tinymce.woff":"tinymce/skins/lightgray/fonts/tinymce-1ebc636bb24cbea637946ba8c22cbf4f35d8343ba9763045d2aee59e3714ae78.woff","tinymce/skins/lightgray/skin.dev.less":"tinymce/skins/lightgray/skin.dev.less","tinymce/skins/lightgray/skin.ie7.dev.less":"tinymce/skins/lightgray/skin.ie7.dev.less","tinymce/skins/lightgray/skin.ie7.less":"tinymce/skins/lightgray/skin.ie7.less","tinymce/skins/lightgray/skin.ie7.min.css":"tinymce/skins/lightgray/skin.ie7.min-f7e68049f5f1ba278870818429ef905d07846781701c40657d9d24ca6638cced.css","tinymce/skins/lightgray/skin.less":"tinymce/skins/lightgray/skin.less","tinymce/skins/lightgray/skin.min.css":"tinymce/skins/lightgray/skin.min-48be1dca174d1fa8e98ccc23d4d6741ea268cb2b20a4b8a7fb365e3c175bd769.css","tinymce/themes/inlite/theme.js":"tinymce/themes/inlite/theme-24ec9fa4b7330913ca96f683fcfcdcdfa43714f91e8bba74bfbdfdf01cb63324.js","tinymce/themes/modern/theme.js":"tinymce/themes/modern/theme-4547e25369b8acbbc7101f29494cfd7d289c31d221eb99d0b9d5f340ef3af240.js","tinymce/tinymce.js":"tinymce/tinymce-0422648f7dd78a5e2c43b1fad74793a3d3b056cba25af436f1681a4dcba937e6.js","tinymce/langs/ar.js":"tinymce/langs/ar-e47a394dbc461d20aa547fa0c2027a9dad45fe55e18adb0da309045be6ed4109.js","tinymce/langs/ar_SA.js":"tinymce/langs/ar_SA-24b62c76e99e114ae44480a67edbacf74f9fed0ff7afbeacce4966f1bc80333b.js","tinymce/langs/az.js":"tinymce/langs/az-d40cecd6eb423f910f528ae98dcdaba4c2449802621759437174cf8c8c0d5b25.js","tinymce/langs/be.js":"tinymce/langs/be-42e2884c0f2394afa1a17e31e702660eeea0d84618bbd18155cb0313c6eb5f69.js","tinymce/langs/bg_BG.js":"tinymce/langs/bg_BG-2fac9d785519d2791d42881fcc08c6a82e841575785690259d7f64e1b88d7db3.js","tinymce/langs/bn_BD.js":"tinymce/langs/bn_BD-ef48a9094445dfa624af0c35902f60b7949b30585b5e9bc760a225fe2c07cbd3.js","tinymce/langs/bs.js":"tinymce/langs/bs-eb66c6d6910a30b950d7a0e784027ed288e6e5a2c6db7741da3359f2067e2e0e.js","tinymce/langs/ca.js":"tinymce/langs/ca-77ab49d6420318ed7f5fd51b6856bc396c393095bd78ea91dad83e38e5859637.js","tinymce/langs/cs.js":"tinymce/langs/cs-3d7ecd619895e3e4c7e1db06f6526682ef88f22f6e8b50d7b45ed0ae7c206714.js","tinymce/langs/cs_CZ.js":"tinymce/langs/cs_CZ-4b0778d233e200dea350f8361129da2844e23d1c0f2d524aeffa6d34e581368d.js","tinymce/langs/cy.js":"tinymce/langs/cy-a847ff54657ccf76eec362cc14fbc63adb4c67f9b1de023b29d817aba4fec062.js","tinymce/langs/da.js":"tinymce/langs/da-a87f3ae1c442c3bb26b81569687e98072d038269360361ec9728f00d6b17c282.js","tinymce/langs/de.js":"tinymce/langs/de-a10c8f6f1e53da776e7026dffd54ea8ba527492b767e5b54ae5c3974f6953311.js","tinymce/langs/de_AT.js":"tinymce/langs/de_AT-a32eec12ce12b06fc2c8919d2372242e9596712c96dc9bcfff1fc8b7dc458627.js","tinymce/langs/dv.js":"tinymce/langs/dv-182756bf33409a8b76bc684d0a2ab86881718c360d1f1fb3fbc609ce3f5e3f49.js","tinymce/langs/el.js":"tinymce/langs/el-6bbdbf3ccb2b2f22f961eb6749b43fe401c84fd6d89cd3f76a538dc2d06bb071.js","tinymce/langs/en_CA.js":"tinymce/langs/en_CA-1a9457da814b0a1f15687a00f3ae4b38da0301445b52c29a423a38c943d9a431.js","tinymce/langs/en_GB.js":"tinymce/langs/en_GB-a0f7752ff9ddf3ed3d2cd24fee04fe585bca0babc4ce655560c923ad386c0c07.js","tinymce/langs/eo.js":"tinymce/langs/eo-cbac4d7ebcb0679845b852d9354e74586e78cf13eef82de1400cf6b465e203cd.js","tinymce/langs/es.js":"tinymce/langs/es-133cb5bd627c2a299544586bf365859b5a1c96c57d18c90e7853048434a809b6.js","tinymce/langs/es_MX.js":"tinymce/langs/es_MX-352fcdff567919ff09a2e19c56d8059d339bffdbd999bcc82aa6d8340c19bbb9.js","tinymce/langs/et.js":"tinymce/langs/et-2cfc3da0ff39a37f0bd3c896d49604028f231ff0e7d8ebbc30dbfd4b87125f06.js","tinymce/langs/eu.js":"tinymce/langs/eu-8698ae4de236fcd490d0f45d485dbd33d8e9de6eb3db51191e1b4f8ea96a4d06.js","tinymce/langs/fa.js":"tinymce/langs/fa-7eff96595e93d4b0df484dd90c14b7b412966157ed8293f54429e9418882bdb2.js","tinymce/langs/fa_IR.js":"tinymce/langs/fa_IR-2f9d33f16718ae9c1f3642905b58434ed2662fb66448c4d115b8491aa68e7904.js","tinymce/langs/fi.js":"tinymce/langs/fi-6ca2a93d045067a86e8ea973d0b89368054b15eb9b9625bf1ca871608a5cb77c.js","tinymce/langs/fo.js":"tinymce/langs/fo-340609cecd5571e4eacb8fe7bd1343c8553d96d12610fb77d9a812dc6d3635fd.js","tinymce/langs/fr_CH.js":"tinymce/langs/fr_CH-e0f43c0f20727368ff0767f3bf099bc23eed9fe3e81f8bbe514381e786526928.js","tinymce/langs/fr_FR.js":"tinymce/langs/fr_FR-2702de7be93bd1e0d7120ae3c9e637061565186c66886f155ffca0663df25b4c.js","tinymce/langs/ga.js":"tinymce/langs/ga-d2a3de6f28723d75b03f7f42fd3aedfd045d473425ee38f02350b56035383af1.js","tinymce/langs/gd.js":"tinymce/langs/gd-0453e8b97bf3b6cca4065712ec59f20343ad6131735b38547e865177a1c1c490.js","tinymce/langs/gl.js":"tinymce/langs/gl-1ff612222934f558870111f10934110c5656df3bb293c917e4eeceeb6605fcc5.js","tinymce/langs/he_IL.js":"tinymce/langs/he_IL-981f5250a4b8d404b37040ca5a35c30498cbeeb36e298d81bf1592b43fff7656.js","tinymce/langs/hi_IN.js":"tinymce/langs/hi_IN-695e0cdc22974fe45e0f35289f0249ddab87245165c9df765ec1b885ec55f0be.js","tinymce/langs/hr.js":"tinymce/langs/hr-f77f1da2736d13f9a9a86ebf596f592fcc748f2975a0b9904b512d630f2c1a17.js","tinymce/langs/hu_HU.js":"tinymce/langs/hu_HU-1e22021a4f9c61919aa024041af555eac277bfc08ccb8c07fd329b87090a15e5.js","tinymce/langs/hy.js":"tinymce/langs/hy-0d384f3f82cd76793d3e7428a2140ea97f40a943f25ef99a2e3709a3e02b0930.js","tinymce/langs/id.js":"tinymce/langs/id-e9fd018be745b5f14f4af47887420f98c590c607e01d57aca77ef5affe188523.js","tinymce/langs/is_IS.js":"tinymce/langs/is_IS-c6e8c3e7b0e6b447faec3d8d258928f97c84558b29882c056513fb71cf237bfa.js","tinymce/langs/it.js":"tinymce/langs/it-25b5546d48c80ad666b600e5be3a05718b80645721b191785c1fafe1853f4a46.js","tinymce/langs/ja.js":"tinymce/langs/ja-80f0e7414030c32617ff651da1affa0bc85ee514fc9bc81f46edfd8ce0053ac0.js","tinymce/langs/ka_GE.js":"tinymce/langs/ka_GE-3c6b82346a7070a8b6a15ae6e8faeecc5bfe63ad7e616b7de2e8ab8a75ec39c2.js","tinymce/langs/kab.js":"tinymce/langs/kab-3651d08aacd5bda15a04698f202bf616efbf13d3789aadd9ce4f93e430818c13.js","tinymce/langs/kk.js":"tinymce/langs/kk-0c1ba792ed9445c6512f310228f64d1cde7b5a98e0b212cca749dcb2d728fe86.js","tinymce/langs/km_KH.js":"tinymce/langs/km_KH-8bec84e4078db8c2a680260c073dfb486c85b61df62e14ca330d66d2ca2a85b5.js","tinymce/langs/ko.js":"tinymce/langs/ko-ca535bfa388701fb020d24bdfb3f1e3aab127005b54e943cb1bd60b723c8194d.js","tinymce/langs/ko_KR.js":"tinymce/langs/ko_KR-daa3ae950d70260bb0901a5349034952247905523bbc2bcbe527701b6aad8e28.js","tinymce/langs/ku.js":"tinymce/langs/ku-95e2ffe4f0112df658f10327c26f2cdddedc2e2ed769767366ae22a465c14725.js","tinymce/langs/ku_IQ.js":"tinymce/langs/ku_IQ-a212e8d41695989e56834facf72474e1934ef166c3fcaf7e255ef573a3c6e76c.js","tinymce/langs/lb.js":"tinymce/langs/lb-94992279091f1a0be927d5d858d3724037d8d81ee6b63cc9ddde84af6124cc04.js","tinymce/langs/lt.js":"tinymce/langs/lt-ae7cefbe2cb5420770b31eabf92605728135ab5d6a2d2cfca2d19809be67e6a8.js","tinymce/langs/lv.js":"tinymce/langs/lv-e468ed0c78466d1fff9f4957645606d8aa683cb5dc35931e047df97b8e4f5433.js","tinymce/langs/mk_MK.js":"tinymce/langs/mk_MK-55aadb5d7c82c940cfcf42f24423ef0471294c9b02994a6b22e1b4173baa7ec6.js","tinymce/langs/ml.js":"tinymce/langs/ml-685de0808683c02274dcbe9f8de023a4d72a49b040e7526a99e3d5c786ff71ae.js","tinymce/langs/ml_IN.js":"tinymce/langs/ml_IN-1ab433621d6257c7632718048bacc5ed98a302d33cf0438bbbb4200914e01aac.js","tinymce/langs/mn_MN.js":"tinymce/langs/mn_MN-b89f88cb9b0dd7c879e27532b2979c421c1e69648f65a4108a56060f1e1cb009.js","tinymce/langs/nb_NO.js":"tinymce/langs/nb_NO-602ee249e98a26ae24c1ee1311090c68a782050086a835f1e7bd46ebfe7879ef.js","tinymce/langs/nl.js":"tinymce/langs/nl-9c77e9404a27fd7e4bd162ad44538b72d2725b7fee7be7ca3ff801cf217c4968.js","tinymce/langs/pl.js":"tinymce/langs/pl-5cdd1586ec8fa67293f2175cd92edbd0392c4c77b24ed64cfdceccba8d99f152.js","tinymce/langs/pt_BR.js":"tinymce/langs/pt_BR-e3955318582d58bd241a62c3a81afe74e0ae7f31bdc92a562b75243701f114df.js","tinymce/langs/pt_PT.js":"tinymce/langs/pt_PT-1101d080ecd5da091c7ef70b23200adbd5136c5c32f0c79dae665a443d76c35d.js","tinymce/langs/ro.js":"tinymce/langs/ro-484799d182031efab087d749b024014fd06ed06c1e7712b8bf87f3a4a965c2e4.js","tinymce/langs/ru.js":"tinymce/langs/ru-bdd59cb662a7b4d61e770b07014d1791051312c87513ecc1891e80beba617171.js","tinymce/langs/ru_RU.js":"tinymce/langs/ru_RU-9f18ef14f3493cc586cc0b4827fd9e1c2ed3d5790ce536d94f87e2d6aac2a688.js","tinymce/langs/si_LK.js":"tinymce/langs/si_LK-5bfefe9b2fe82574d8ed839df18fd8ff65f1e1cd458b0a843cf1aadd1be704ea.js","tinymce/langs/sk.js":"tinymce/langs/sk-412fa7f982ad2733341203daa035c8ba10035262ca8f5f65e0a41507512209bd.js","tinymce/langs/sl_SI.js":"tinymce/langs/sl_SI-2bea4f3854a992ea840808019dc99467dc173b12454ea6016135234a741671d8.js","tinymce/langs/sr.js":"tinymce/langs/sr-e0b97453a0c1000b19f7ce37fcf86bcacbf9125d81076f60a77686820c7925c6.js","tinymce/langs/sv_SE.js":"tinymce/langs/sv_SE-fa561a7e49fdb42d5913337176fed6bc8a9997eb3ca8f20ecd9520d5391e17be.js","tinymce/langs/ta.js":"tinymce/langs/ta-0fd0e62250fc1a3626ac2111c5adb4194a6a898888bb224414f6dc8adf53d385.js","tinymce/langs/ta_IN.js":"tinymce/langs/ta_IN-32303f65d2378e8202b17b0920b79277a2580872e3a6bd9409aeceef90867dd0.js","tinymce/langs/tg.js":"tinymce/langs/tg-1618248bf0aeda614a37ced9fd28b6623ae24f8453368bfb8c483ce820a3cb34.js","tinymce/langs/th_TH.js":"tinymce/langs/th_TH-5279a379afc886c2a31e22aba9d7ee7a8e3edf4c0785f39aaa20ccd03d46b19a.js","tinymce/langs/tr.js":"tinymce/langs/tr-3765d4a8923ef22864747d9c825c3e0af401e1356e75a5458bed837d486b7673.js","tinymce/langs/tr_TR.js":"tinymce/langs/tr_TR-5c93f80b89e5dd2eb6972f37bf50b76d7705c61f28120b836704a91fa5c14399.js","tinymce/langs/tt.js":"tinymce/langs/tt-22e302672df0a77de14688f58dbedf82de7a26e9089c9535a2a3cd1c0ccd7903.js","tinymce/langs/ug.js":"tinymce/langs/ug-50232038bf7262c90be4f2919c74ff93792cdb82e6064d0f5c86f885b93271c5.js","tinymce/langs/uk.js":"tinymce/langs/uk-f6d7911714c422b178c0249df323cf7ec415a83195d751c7e4024590b1738c42.js","tinymce/langs/uk_UA.js":"tinymce/langs/uk_UA-bd8cd7ca66228d85f8a4cadb651c49981f26e007fa2a952856c8c3d3c1baa66a.js","tinymce/langs/vi.js":"tinymce/langs/vi-6aa451047e4df911c92e10178e6a70147534e438c64df7a88eee37b4a440726e.js","tinymce/langs/vi_VN.js":"tinymce/langs/vi_VN-aea52c2e9397f8a657d54d50a42b3c5be0ca79480555a4fa1e0f5d785c5f6561.js","tinymce/langs/zh_CN.js":"tinymce/langs/zh_CN-8622ec46e2980b6f5baf3b745c6b0187dd2a54ddecbbf69a21f0b3e72f84f6dc.js","tinymce/langs/zh_TW.js":"tinymce/langs/zh_TW-90723da3b889f2a4477d4aaf00ca3e75439998269b36b359ea4caa37e1defb4a.js","leaflet/dist/images/layers.png":"leaflet/dist/images/layers-1dbbe9d028e292f36fcba8f8b3a28d5e8932754fc2215b9ac69e4cdecf5107c6.png","leaflet/dist/images/layers-2x.png":"leaflet/dist/images/layers-2x-066daca850d8ffbef007af00b06eac0015728dee279c51f3cb6c716df7c42edf.png","leaflet/dist/images/marker-icon.png":"leaflet/dist/images/marker-icon-574c3a5cca85f4114085b6841596d62f00d7c892c7b03f28cbfa301deb1dc437.png","leaflet/dist/images/marker-icon-2x.png":"leaflet/dist/images/marker-icon-2x-2d77a2e4c2f08bbac41808324ef946b9a2fe61b6150480d011b72b379c3b238d.png","leaflet/dist/images/marker-shadow.png":"leaflet/dist/images/marker-shadow-264f5c640339f042dd729062cfc04c17f8ea0f29882b538e3848ed8f10edb4da.png","tinymce/preinit.js":"tinymce/preinit-4eb7f4ac58f2f450d20185cf83ca1d8550d2a1419141bfe70eb5a2c4afe67349.js","brasil.png":"brasil-0e293d8c9a86f8a98fea23013e9c365b32fd0022a1496309eeabcd97f7be1288.png","tinymce/plugins/help/img/logo.png":"tinymce/plugins/help/img/logo-8b03dc4f83c4fea0b62c4f9866898c98e81057c55b3e3b8c1da3f5fdbf0086e9.png","tinymce/plugins/help/plugin.js":"tinymce/plugins/help/plugin-5be1acda091dc11d9811ab091a92ec48f5d71df3540968b6fc625df544521f1b.js"}}
\ No newline at end of file
diff --git a/public/assets/active_admin-23d58e148201d77c88712977540f99db82c21bece116faa407af2e3a099a9417.js b/public/assets/active_admin-23d58e148201d77c88712977540f99db82c21bece116faa407af2e3a099a9417.js
new file mode 100644
index 00000000..3847468e
--- /dev/null
+++ b/public/assets/active_admin-23d58e148201d77c88712977540f99db82c21bece116faa407af2e3a099a9417.js
@@ -0,0 +1,23385 @@
+/*!
+ * jQuery JavaScript Library v1.12.4
+ * http://jquery.com/
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2016-05-20T17:17Z
+ */
+
+
+(function( global, factory ) {
+
+ if ( typeof module === "object" && typeof module.exports === "object" ) {
+ // For CommonJS and CommonJS-like environments where a proper `window`
+ // is present, execute the factory and get jQuery.
+ // For environments that do not have a `window` with a `document`
+ // (such as Node.js), expose a factory as module.exports.
+ // This accentuates the need for the creation of a real `window`.
+ // e.g. var jQuery = require("jquery")(window);
+ // See ticket #14549 for more info.
+ module.exports = global.document ?
+ factory( global, true ) :
+ function( w ) {
+ if ( !w.document ) {
+ throw new Error( "jQuery requires a window with a document" );
+ }
+ return factory( w );
+ };
+ } else {
+ factory( global );
+ }
+
+// Pass this if window is not defined yet
+}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
+
+// Support: Firefox 18+
+// Can't be in strict mode, several libs including ASP.NET trace
+// the stack via arguments.caller.callee and Firefox dies if
+// you try to trace through "use strict" call chains. (#13335)
+//"use strict";
+var deletedIds = [];
+
+var document = window.document;
+
+var slice = deletedIds.slice;
+
+var concat = deletedIds.concat;
+
+var push = deletedIds.push;
+
+var indexOf = deletedIds.indexOf;
+
+var class2type = {};
+
+var toString = class2type.toString;
+
+var hasOwn = class2type.hasOwnProperty;
+
+var support = {};
+
+
+
+var
+ version = "1.12.4",
+
+ // Define a local copy of jQuery
+ jQuery = function( selector, context ) {
+
+ // The jQuery object is actually just the init constructor 'enhanced'
+ // Need init if jQuery is called (just allow error to be thrown if not included)
+ return new jQuery.fn.init( selector, context );
+ },
+
+ // Support: Android<4.1, IE<9
+ // Make sure we trim BOM and NBSP
+ rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
+
+ // Matches dashed string for camelizing
+ rmsPrefix = /^-ms-/,
+ rdashAlpha = /-([\da-z])/gi,
+
+ // Used by jQuery.camelCase as callback to replace()
+ fcamelCase = function( all, letter ) {
+ return letter.toUpperCase();
+ };
+
+jQuery.fn = jQuery.prototype = {
+
+ // The current version of jQuery being used
+ jquery: version,
+
+ constructor: jQuery,
+
+ // Start with an empty selector
+ selector: "",
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ toArray: function() {
+ return slice.call( this );
+ },
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num != null ?
+
+ // Return just the one element from the set
+ ( num < 0 ? this[ num + this.length ] : this[ num ] ) :
+
+ // Return all the elements in a clean array
+ slice.call( this );
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems ) {
+
+ // Build a new jQuery matched element set
+ var ret = jQuery.merge( this.constructor(), elems );
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+ ret.context = this.context;
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Execute a callback for every element in the matched set.
+ each: function( callback ) {
+ return jQuery.each( this, callback );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map( this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ } ) );
+ },
+
+ slice: function() {
+ return this.pushStack( slice.apply( this, arguments ) );
+ },
+
+ first: function() {
+ return this.eq( 0 );
+ },
+
+ last: function() {
+ return this.eq( -1 );
+ },
+
+ eq: function( i ) {
+ var len = this.length,
+ j = +i + ( i < 0 ? len : 0 );
+ return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor();
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: push,
+ sort: deletedIds.sort,
+ splice: deletedIds.splice
+};
+
+jQuery.extend = jQuery.fn.extend = function() {
+ var src, copyIsArray, copy, name, options, clone,
+ target = arguments[ 0 ] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+
+ // skip the boolean and the target
+ target = arguments[ i ] || {};
+ i++;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
+ target = {};
+ }
+
+ // extend jQuery itself if only one argument is passed
+ if ( i === length ) {
+ target = this;
+ i--;
+ }
+
+ for ( ; i < length; i++ ) {
+
+ // Only deal with non-null/undefined values
+ if ( ( options = arguments[ i ] ) != null ) {
+
+ // Extend the base object
+ for ( name in options ) {
+ src = target[ name ];
+ copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
+ ( copyIsArray = jQuery.isArray( copy ) ) ) ) {
+
+ if ( copyIsArray ) {
+ copyIsArray = false;
+ clone = src && jQuery.isArray( src ) ? src : [];
+
+ } else {
+ clone = src && jQuery.isPlainObject( src ) ? src : {};
+ }
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend( {
+
+ // Unique for each copy of jQuery on the page
+ expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
+
+ // Assume jQuery is ready without the ready module
+ isReady: true,
+
+ error: function( msg ) {
+ throw new Error( msg );
+ },
+
+ noop: function() {},
+
+ // See test/unit/core.js for details concerning isFunction.
+ // Since version 1.3, DOM methods and functions like alert
+ // aren't supported. They return false on IE (#2968).
+ isFunction: function( obj ) {
+ return jQuery.type( obj ) === "function";
+ },
+
+ isArray: Array.isArray || function( obj ) {
+ return jQuery.type( obj ) === "array";
+ },
+
+ isWindow: function( obj ) {
+ /* jshint eqeqeq: false */
+ return obj != null && obj == obj.window;
+ },
+
+ isNumeric: function( obj ) {
+
+ // parseFloat NaNs numeric-cast false positives (null|true|false|"")
+ // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
+ // subtraction forces infinities to NaN
+ // adding 1 corrects loss of precision from parseFloat (#15100)
+ var realStringObj = obj && obj.toString();
+ return !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0;
+ },
+
+ isEmptyObject: function( obj ) {
+ var name;
+ for ( name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ isPlainObject: function( obj ) {
+ var key;
+
+ // Must be an Object.
+ // Because of IE, we also have to check the presence of the constructor property.
+ // Make sure that DOM nodes and window objects don't pass through, as well
+ if ( !obj || jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ try {
+
+ // Not own constructor property must be Object
+ if ( obj.constructor &&
+ !hasOwn.call( obj, "constructor" ) &&
+ !hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
+ return false;
+ }
+ } catch ( e ) {
+
+ // IE8,9 Will throw exceptions on certain host objects #9897
+ return false;
+ }
+
+ // Support: IE<9
+ // Handle iteration over inherited properties before own properties.
+ if ( !support.ownFirst ) {
+ for ( key in obj ) {
+ return hasOwn.call( obj, key );
+ }
+ }
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own.
+ for ( key in obj ) {}
+
+ return key === undefined || hasOwn.call( obj, key );
+ },
+
+ type: function( obj ) {
+ if ( obj == null ) {
+ return obj + "";
+ }
+ return typeof obj === "object" || typeof obj === "function" ?
+ class2type[ toString.call( obj ) ] || "object" :
+ typeof obj;
+ },
+
+ // Workarounds based on findings by Jim Driscoll
+ // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+ globalEval: function( data ) {
+ if ( data && jQuery.trim( data ) ) {
+
+ // We use execScript on Internet Explorer
+ // We use an anonymous function so that context is window
+ // rather than jQuery in Firefox
+ ( window.execScript || function( data ) {
+ window[ "eval" ].call( window, data ); // jscs:ignore requireDotNotation
+ } )( data );
+ }
+ },
+
+ // Convert dashed to camelCase; used by the css and data modules
+ // Microsoft forgot to hump their vendor prefix (#9572)
+ camelCase: function( string ) {
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+ },
+
+ each: function( obj, callback ) {
+ var length, i = 0;
+
+ if ( isArrayLike( obj ) ) {
+ length = obj.length;
+ for ( ; i < length; i++ ) {
+ if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
+ break;
+ }
+ }
+ }
+
+ return obj;
+ },
+
+ // Support: Android<4.1, IE<9
+ trim: function( text ) {
+ return text == null ?
+ "" :
+ ( text + "" ).replace( rtrim, "" );
+ },
+
+ // results is for internal usage only
+ makeArray: function( arr, results ) {
+ var ret = results || [];
+
+ if ( arr != null ) {
+ if ( isArrayLike( Object( arr ) ) ) {
+ jQuery.merge( ret,
+ typeof arr === "string" ?
+ [ arr ] : arr
+ );
+ } else {
+ push.call( ret, arr );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, arr, i ) {
+ var len;
+
+ if ( arr ) {
+ if ( indexOf ) {
+ return indexOf.call( arr, elem, i );
+ }
+
+ len = arr.length;
+ i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
+
+ for ( ; i < len; i++ ) {
+
+ // Skip accessing in sparse arrays
+ if ( i in arr && arr[ i ] === elem ) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ },
+
+ merge: function( first, second ) {
+ var len = +second.length,
+ j = 0,
+ i = first.length;
+
+ while ( j < len ) {
+ first[ i++ ] = second[ j++ ];
+ }
+
+ // Support: IE<9
+ // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists)
+ if ( len !== len ) {
+ while ( second[ j ] !== undefined ) {
+ first[ i++ ] = second[ j++ ];
+ }
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, invert ) {
+ var callbackInverse,
+ matches = [],
+ i = 0,
+ length = elems.length,
+ callbackExpect = !invert;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( ; i < length; i++ ) {
+ callbackInverse = !callback( elems[ i ], i );
+ if ( callbackInverse !== callbackExpect ) {
+ matches.push( elems[ i ] );
+ }
+ }
+
+ return matches;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var length, value,
+ i = 0,
+ ret = [];
+
+ // Go through the array, translating each of the items to their new values
+ if ( isArrayLike( elems ) ) {
+ length = elems.length;
+ for ( ; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret.push( value );
+ }
+ }
+
+ // Go through every key on the object,
+ } else {
+ for ( i in elems ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret.push( value );
+ }
+ }
+ }
+
+ // Flatten any nested arrays
+ return concat.apply( [], ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ // Bind a function to a context, optionally partially applying any
+ // arguments.
+ proxy: function( fn, context ) {
+ var args, proxy, tmp;
+
+ if ( typeof context === "string" ) {
+ tmp = fn[ context ];
+ context = fn;
+ fn = tmp;
+ }
+
+ // Quick check to determine if target is callable, in the spec
+ // this throws a TypeError, but we will just return undefined.
+ if ( !jQuery.isFunction( fn ) ) {
+ return undefined;
+ }
+
+ // Simulated bind
+ args = slice.call( arguments, 2 );
+ proxy = function() {
+ return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
+ };
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+ return proxy;
+ },
+
+ now: function() {
+ return +( new Date() );
+ },
+
+ // jQuery.support is not used in Core but other projects attach their
+ // properties to it so it needs to exist.
+ support: support
+} );
+
+// JSHint would error on this code due to the Symbol not being defined in ES5.
+// Defining this global in .jshintrc would create a danger of using the global
+// unguarded in another place, it seems safer to just disable JSHint for these
+// three lines.
+/* jshint ignore: start */
+if ( typeof Symbol === "function" ) {
+ jQuery.fn[ Symbol.iterator ] = deletedIds[ Symbol.iterator ];
+}
+/* jshint ignore: end */
+
+// Populate the class2type map
+jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
+function( i, name ) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+} );
+
+function isArrayLike( obj ) {
+
+ // Support: iOS 8.2 (not reproducible in simulator)
+ // `in` check used to prevent JIT error (gh-2145)
+ // hasOwn isn't used here due to false negatives
+ // regarding Nodelist length in IE
+ var length = !!obj && "length" in obj && obj.length,
+ type = jQuery.type( obj );
+
+ if ( type === "function" || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ return type === "array" || length === 0 ||
+ typeof length === "number" && length > 0 && ( length - 1 ) in obj;
+}
+var Sizzle =
+/*!
+ * Sizzle CSS Selector Engine v2.2.1
+ * http://sizzlejs.com/
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2015-10-17
+ */
+(function( window ) {
+
+var i,
+ support,
+ Expr,
+ getText,
+ isXML,
+ tokenize,
+ compile,
+ select,
+ outermostContext,
+ sortInput,
+ hasDuplicate,
+
+ // Local document vars
+ setDocument,
+ document,
+ docElem,
+ documentIsHTML,
+ rbuggyQSA,
+ rbuggyMatches,
+ matches,
+ contains,
+
+ // Instance-specific data
+ expando = "sizzle" + 1 * new Date(),
+ preferredDoc = window.document,
+ dirruns = 0,
+ done = 0,
+ classCache = createCache(),
+ tokenCache = createCache(),
+ compilerCache = createCache(),
+ sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ }
+ return 0;
+ },
+
+ // General-purpose constants
+ MAX_NEGATIVE = 1 << 31,
+
+ // Instance methods
+ hasOwn = ({}).hasOwnProperty,
+ arr = [],
+ pop = arr.pop,
+ push_native = arr.push,
+ push = arr.push,
+ slice = arr.slice,
+ // Use a stripped-down indexOf as it's faster than native
+ // http://jsperf.com/thor-indexof-vs-for/5
+ indexOf = function( list, elem ) {
+ var i = 0,
+ len = list.length;
+ for ( ; i < len; i++ ) {
+ if ( list[i] === elem ) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
+
+ // Regular expressions
+
+ // http://www.w3.org/TR/css3-selectors/#whitespace
+ whitespace = "[\\x20\\t\\r\\n\\f]",
+
+ // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+ identifier = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
+
+ // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
+ attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
+ // Operator (capture 2)
+ "*([*^$|!~]?=)" + whitespace +
+ // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
+ "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
+ "*\\]",
+
+ pseudos = ":(" + identifier + ")(?:\\((" +
+ // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
+ // 1. quoted (capture 3; capture 4 or capture 5)
+ "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
+ // 2. simple (capture 6)
+ "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
+ // 3. anything else (capture 2)
+ ".*" +
+ ")\\)|)",
+
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rwhitespace = new RegExp( whitespace + "+", "g" ),
+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+
+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+ rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
+
+ rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
+
+ rpseudo = new RegExp( pseudos ),
+ ridentifier = new RegExp( "^" + identifier + "$" ),
+
+ matchExpr = {
+ "ID": new RegExp( "^#(" + identifier + ")" ),
+ "CLASS": new RegExp( "^\\.(" + identifier + ")" ),
+ "TAG": new RegExp( "^(" + identifier + "|[*])" ),
+ "ATTR": new RegExp( "^" + attributes ),
+ "PSEUDO": new RegExp( "^" + pseudos ),
+ "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
+ "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+ "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+ "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
+ // For use in libraries implementing .is()
+ // We use this for POS matching in `select`
+ "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
+ whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+ },
+
+ rinputs = /^(?:input|select|textarea|button)$/i,
+ rheader = /^h\d$/i,
+
+ rnative = /^[^{]+\{\s*\[native \w/,
+
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
+ rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+ rsibling = /[+~]/,
+ rescape = /'|\\/g,
+
+ // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+ runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
+ funescape = function( _, escaped, escapedWhitespace ) {
+ var high = "0x" + escaped - 0x10000;
+ // NaN means non-codepoint
+ // Support: Firefox<24
+ // Workaround erroneous numeric interpretation of +"0x"
+ return high !== high || escapedWhitespace ?
+ escaped :
+ high < 0 ?
+ // BMP codepoint
+ String.fromCharCode( high + 0x10000 ) :
+ // Supplemental Plane codepoint (surrogate pair)
+ String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+ },
+
+ // Used for iframes
+ // See setDocument()
+ // Removing the function wrapper causes a "Permission Denied"
+ // error in IE
+ unloadHandler = function() {
+ setDocument();
+ };
+
+// Optimize for push.apply( _, NodeList )
+try {
+ push.apply(
+ (arr = slice.call( preferredDoc.childNodes )),
+ preferredDoc.childNodes
+ );
+ // Support: Android<4.0
+ // Detect silently failing push.apply
+ arr[ preferredDoc.childNodes.length ].nodeType;
+} catch ( e ) {
+ push = { apply: arr.length ?
+
+ // Leverage slice if possible
+ function( target, els ) {
+ push_native.apply( target, slice.call(els) );
+ } :
+
+ // Support: IE<9
+ // Otherwise append directly
+ function( target, els ) {
+ var j = target.length,
+ i = 0;
+ // Can't trust NodeList.length
+ while ( (target[j++] = els[i++]) ) {}
+ target.length = j - 1;
+ }
+ };
+}
+
+function Sizzle( selector, context, results, seed ) {
+ var m, i, elem, nid, nidselect, match, groups, newSelector,
+ newContext = context && context.ownerDocument,
+
+ // nodeType defaults to 9, since context defaults to document
+ nodeType = context ? context.nodeType : 9;
+
+ results = results || [];
+
+ // Return early from calls with invalid selector or context
+ if ( typeof selector !== "string" || !selector ||
+ nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
+
+ return results;
+ }
+
+ // Try to shortcut find operations (as opposed to filters) in HTML documents
+ if ( !seed ) {
+
+ if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
+ setDocument( context );
+ }
+ context = context || document;
+
+ if ( documentIsHTML ) {
+
+ // If the selector is sufficiently simple, try using a "get*By*" DOM method
+ // (excepting DocumentFragment context, where the methods don't exist)
+ if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
+
+ // ID selector
+ if ( (m = match[1]) ) {
+
+ // Document context
+ if ( nodeType === 9 ) {
+ if ( (elem = context.getElementById( m )) ) {
+
+ // Support: IE, Opera, Webkit
+ // TODO: identify versions
+ // getElementById can match elements by name instead of ID
+ if ( elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ } else {
+ return results;
+ }
+
+ // Element context
+ } else {
+
+ // Support: IE, Opera, Webkit
+ // TODO: identify versions
+ // getElementById can match elements by name instead of ID
+ if ( newContext && (elem = newContext.getElementById( m )) &&
+ contains( context, elem ) &&
+ elem.id === m ) {
+
+ results.push( elem );
+ return results;
+ }
+ }
+
+ // Type selector
+ } else if ( match[2] ) {
+ push.apply( results, context.getElementsByTagName( selector ) );
+ return results;
+
+ // Class selector
+ } else if ( (m = match[3]) && support.getElementsByClassName &&
+ context.getElementsByClassName ) {
+
+ push.apply( results, context.getElementsByClassName( m ) );
+ return results;
+ }
+ }
+
+ // Take advantage of querySelectorAll
+ if ( support.qsa &&
+ !compilerCache[ selector + " " ] &&
+ (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
+
+ if ( nodeType !== 1 ) {
+ newContext = context;
+ newSelector = selector;
+
+ // qSA looks outside Element context, which is not what we want
+ // Thanks to Andrew Dupont for this workaround technique
+ // Support: IE <=8
+ // Exclude object elements
+ } else if ( context.nodeName.toLowerCase() !== "object" ) {
+
+ // Capture the context ID, setting it first if necessary
+ if ( (nid = context.getAttribute( "id" )) ) {
+ nid = nid.replace( rescape, "\\$&" );
+ } else {
+ context.setAttribute( "id", (nid = expando) );
+ }
+
+ // Prefix every selector in the list
+ groups = tokenize( selector );
+ i = groups.length;
+ nidselect = ridentifier.test( nid ) ? "#" + nid : "[id='" + nid + "']";
+ while ( i-- ) {
+ groups[i] = nidselect + " " + toSelector( groups[i] );
+ }
+ newSelector = groups.join( "," );
+
+ // Expand context for sibling selectors
+ newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
+ context;
+ }
+
+ if ( newSelector ) {
+ try {
+ push.apply( results,
+ newContext.querySelectorAll( newSelector )
+ );
+ return results;
+ } catch ( qsaError ) {
+ } finally {
+ if ( nid === expando ) {
+ context.removeAttribute( "id" );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // All others
+ return select( selector.replace( rtrim, "$1" ), context, results, seed );
+}
+
+/**
+ * Create key-value caches of limited size
+ * @returns {function(string, object)} Returns the Object data after storing it on itself with
+ * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ * deleting the oldest entry
+ */
+function createCache() {
+ var keys = [];
+
+ function cache( key, value ) {
+ // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+ if ( keys.push( key + " " ) > Expr.cacheLength ) {
+ // Only keep the most recent entries
+ delete cache[ keys.shift() ];
+ }
+ return (cache[ key + " " ] = value);
+ }
+ return cache;
+}
+
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+ fn[ expando ] = true;
+ return fn;
+}
+
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created div and expects a boolean result
+ */
+function assert( fn ) {
+ var div = document.createElement("div");
+
+ try {
+ return !!fn( div );
+ } catch (e) {
+ return false;
+ } finally {
+ // Remove from its parent by default
+ if ( div.parentNode ) {
+ div.parentNode.removeChild( div );
+ }
+ // release memory in IE
+ div = null;
+ }
+}
+
+/**
+ * Adds the same handler for all of the specified attrs
+ * @param {String} attrs Pipe-separated list of attributes
+ * @param {Function} handler The method that will be applied
+ */
+function addHandle( attrs, handler ) {
+ var arr = attrs.split("|"),
+ i = arr.length;
+
+ while ( i-- ) {
+ Expr.attrHandle[ arr[i] ] = handler;
+ }
+}
+
+/**
+ * Checks document order of two siblings
+ * @param {Element} a
+ * @param {Element} b
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
+ */
+function siblingCheck( a, b ) {
+ var cur = b && a,
+ diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
+ ( ~b.sourceIndex || MAX_NEGATIVE ) -
+ ( ~a.sourceIndex || MAX_NEGATIVE );
+
+ // Use IE sourceIndex if available on both nodes
+ if ( diff ) {
+ return diff;
+ }
+
+ // Check if b follows a
+ if ( cur ) {
+ while ( (cur = cur.nextSibling) ) {
+ if ( cur === b ) {
+ return -1;
+ }
+ }
+ }
+
+ return a ? 1 : -1;
+}
+
+/**
+ * Returns a function to use in pseudos for input types
+ * @param {String} type
+ */
+function createInputPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for buttons
+ * @param {String} type
+ */
+function createButtonPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for positionals
+ * @param {Function} fn
+ */
+function createPositionalPseudo( fn ) {
+ return markFunction(function( argument ) {
+ argument = +argument;
+ return markFunction(function( seed, matches ) {
+ var j,
+ matchIndexes = fn( [], seed.length, argument ),
+ i = matchIndexes.length;
+
+ // Match elements found at the specified indexes
+ while ( i-- ) {
+ if ( seed[ (j = matchIndexes[i]) ] ) {
+ seed[j] = !(matches[j] = seed[j]);
+ }
+ }
+ });
+ });
+}
+
+/**
+ * Checks a node for validity as a Sizzle context
+ * @param {Element|Object=} context
+ * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
+ */
+function testContext( context ) {
+ return context && typeof context.getElementsByTagName !== "undefined" && context;
+}
+
+// Expose support vars for convenience
+support = Sizzle.support = {};
+
+/**
+ * Detects XML nodes
+ * @param {Element|Object} elem An element or a document
+ * @returns {Boolean} True iff elem is a non-HTML XML node
+ */
+isXML = Sizzle.isXML = function( elem ) {
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+/**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+setDocument = Sizzle.setDocument = function( node ) {
+ var hasCompare, parent,
+ doc = node ? node.ownerDocument || node : preferredDoc;
+
+ // Return early if doc is invalid or already selected
+ if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
+ return document;
+ }
+
+ // Update global variables
+ document = doc;
+ docElem = document.documentElement;
+ documentIsHTML = !isXML( document );
+
+ // Support: IE 9-11, Edge
+ // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
+ if ( (parent = document.defaultView) && parent.top !== parent ) {
+ // Support: IE 11
+ if ( parent.addEventListener ) {
+ parent.addEventListener( "unload", unloadHandler, false );
+
+ // Support: IE 9 - 10 only
+ } else if ( parent.attachEvent ) {
+ parent.attachEvent( "onunload", unloadHandler );
+ }
+ }
+
+ /* Attributes
+ ---------------------------------------------------------------------- */
+
+ // Support: IE<8
+ // Verify that getAttribute really returns attributes and not properties
+ // (excepting IE8 booleans)
+ support.attributes = assert(function( div ) {
+ div.className = "i";
+ return !div.getAttribute("className");
+ });
+
+ /* getElement(s)By*
+ ---------------------------------------------------------------------- */
+
+ // Check if getElementsByTagName("*") returns only elements
+ support.getElementsByTagName = assert(function( div ) {
+ div.appendChild( document.createComment("") );
+ return !div.getElementsByTagName("*").length;
+ });
+
+ // Support: IE<9
+ support.getElementsByClassName = rnative.test( document.getElementsByClassName );
+
+ // Support: IE<10
+ // Check if getElementById returns elements by name
+ // The broken getElementById methods don't pick up programatically-set names,
+ // so use a roundabout getElementsByName test
+ support.getById = assert(function( div ) {
+ docElem.appendChild( div ).id = expando;
+ return !document.getElementsByName || !document.getElementsByName( expando ).length;
+ });
+
+ // ID find and filter
+ if ( support.getById ) {
+ Expr.find["ID"] = function( id, context ) {
+ if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
+ var m = context.getElementById( id );
+ return m ? [ m ] : [];
+ }
+ };
+ Expr.filter["ID"] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ return elem.getAttribute("id") === attrId;
+ };
+ };
+ } else {
+ // Support: IE6/7
+ // getElementById is not reliable as a find shortcut
+ delete Expr.find["ID"];
+
+ Expr.filter["ID"] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ var node = typeof elem.getAttributeNode !== "undefined" &&
+ elem.getAttributeNode("id");
+ return node && node.value === attrId;
+ };
+ };
+ }
+
+ // Tag
+ Expr.find["TAG"] = support.getElementsByTagName ?
+ function( tag, context ) {
+ if ( typeof context.getElementsByTagName !== "undefined" ) {
+ return context.getElementsByTagName( tag );
+
+ // DocumentFragment nodes don't have gEBTN
+ } else if ( support.qsa ) {
+ return context.querySelectorAll( tag );
+ }
+ } :
+
+ function( tag, context ) {
+ var elem,
+ tmp = [],
+ i = 0,
+ // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
+ results = context.getElementsByTagName( tag );
+
+ // Filter out possible comments
+ if ( tag === "*" ) {
+ while ( (elem = results[i++]) ) {
+ if ( elem.nodeType === 1 ) {
+ tmp.push( elem );
+ }
+ }
+
+ return tmp;
+ }
+ return results;
+ };
+
+ // Class
+ Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
+ if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
+ return context.getElementsByClassName( className );
+ }
+ };
+
+ /* QSA/matchesSelector
+ ---------------------------------------------------------------------- */
+
+ // QSA and matchesSelector support
+
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+ rbuggyMatches = [];
+
+ // qSa(:focus) reports false when true (Chrome 21)
+ // We allow this because of a bug in IE8/9 that throws an error
+ // whenever `document.activeElement` is accessed on an iframe
+ // So, we allow :focus to pass through QSA all the time to avoid the IE error
+ // See http://bugs.jquery.com/ticket/13378
+ rbuggyQSA = [];
+
+ if ( (support.qsa = rnative.test( document.querySelectorAll )) ) {
+ // Build QSA regex
+ // Regex strategy adopted from Diego Perini
+ assert(function( div ) {
+ // Select is set to empty string on purpose
+ // This is to test IE's treatment of not explicitly
+ // setting a boolean content attribute,
+ // since its presence should be enough
+ // http://bugs.jquery.com/ticket/12359
+ docElem.appendChild( div ).innerHTML = "" +
+ "";
+
+ // Support: IE8, Opera 11-12.16
+ // Nothing should be selected when empty strings follow ^= or $= or *=
+ // The test attribute must be unknown in Opera but "safe" for WinRT
+ // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
+ if ( div.querySelectorAll("[msallowcapture^='']").length ) {
+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
+ }
+
+ // Support: IE8
+ // Boolean attributes and "value" are not treated correctly
+ if ( !div.querySelectorAll("[selected]").length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
+ }
+
+ // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
+ if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
+ rbuggyQSA.push("~=");
+ }
+
+ // Webkit/Opera - :checked should return selected option elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ // IE8 throws error here and will not see later tests
+ if ( !div.querySelectorAll(":checked").length ) {
+ rbuggyQSA.push(":checked");
+ }
+
+ // Support: Safari 8+, iOS 8+
+ // https://bugs.webkit.org/show_bug.cgi?id=136851
+ // In-page `selector#id sibing-combinator selector` fails
+ if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) {
+ rbuggyQSA.push(".#.+[+~]");
+ }
+ });
+
+ assert(function( div ) {
+ // Support: Windows 8 Native Apps
+ // The type and name attributes are restricted during .innerHTML assignment
+ var input = document.createElement("input");
+ input.setAttribute( "type", "hidden" );
+ div.appendChild( input ).setAttribute( "name", "D" );
+
+ // Support: IE8
+ // Enforce case-sensitivity of name attribute
+ if ( div.querySelectorAll("[name=d]").length ) {
+ rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
+ }
+
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+ // IE8 throws error here and will not see later tests
+ if ( !div.querySelectorAll(":enabled").length ) {
+ rbuggyQSA.push( ":enabled", ":disabled" );
+ }
+
+ // Opera 10-11 does not throw on post-comma invalid pseudos
+ div.querySelectorAll("*,:x");
+ rbuggyQSA.push(",.*:");
+ });
+ }
+
+ if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
+ docElem.webkitMatchesSelector ||
+ docElem.mozMatchesSelector ||
+ docElem.oMatchesSelector ||
+ docElem.msMatchesSelector) )) ) {
+
+ assert(function( div ) {
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9)
+ support.disconnectedMatch = matches.call( div, "div" );
+
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ matches.call( div, "[s!='']:x" );
+ rbuggyMatches.push( "!=", pseudos );
+ });
+ }
+
+ rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
+ rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
+
+ /* Contains
+ ---------------------------------------------------------------------- */
+ hasCompare = rnative.test( docElem.compareDocumentPosition );
+
+ // Element contains another
+ // Purposefully self-exclusive
+ // As in, an element does not contain itself
+ contains = hasCompare || rnative.test( docElem.contains ) ?
+ function( a, b ) {
+ var adown = a.nodeType === 9 ? a.documentElement : a,
+ bup = b && b.parentNode;
+ return a === bup || !!( bup && bup.nodeType === 1 && (
+ adown.contains ?
+ adown.contains( bup ) :
+ a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+ ));
+ } :
+ function( a, b ) {
+ if ( b ) {
+ while ( (b = b.parentNode) ) {
+ if ( b === a ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+ /* Sorting
+ ---------------------------------------------------------------------- */
+
+ // Document order sorting
+ sortOrder = hasCompare ?
+ function( a, b ) {
+
+ // Flag for duplicate removal
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ // Sort on method existence if only one input has compareDocumentPosition
+ var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
+ if ( compare ) {
+ return compare;
+ }
+
+ // Calculate position if both inputs belong to the same document
+ compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
+ a.compareDocumentPosition( b ) :
+
+ // Otherwise we know they are disconnected
+ 1;
+
+ // Disconnected nodes
+ if ( compare & 1 ||
+ (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
+
+ // Choose the first element that is related to our preferred document
+ if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
+ return -1;
+ }
+ if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
+ return 1;
+ }
+
+ // Maintain original order
+ return sortInput ?
+ ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+ 0;
+ }
+
+ return compare & 4 ? -1 : 1;
+ } :
+ function( a, b ) {
+ // Exit early if the nodes are identical
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ var cur,
+ i = 0,
+ aup = a.parentNode,
+ bup = b.parentNode,
+ ap = [ a ],
+ bp = [ b ];
+
+ // Parentless nodes are either documents or disconnected
+ if ( !aup || !bup ) {
+ return a === document ? -1 :
+ b === document ? 1 :
+ aup ? -1 :
+ bup ? 1 :
+ sortInput ?
+ ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+ 0;
+
+ // If the nodes are siblings, we can do a quick check
+ } else if ( aup === bup ) {
+ return siblingCheck( a, b );
+ }
+
+ // Otherwise we need full lists of their ancestors for comparison
+ cur = a;
+ while ( (cur = cur.parentNode) ) {
+ ap.unshift( cur );
+ }
+ cur = b;
+ while ( (cur = cur.parentNode) ) {
+ bp.unshift( cur );
+ }
+
+ // Walk down the tree looking for a discrepancy
+ while ( ap[i] === bp[i] ) {
+ i++;
+ }
+
+ return i ?
+ // Do a sibling check if the nodes have a common ancestor
+ siblingCheck( ap[i], bp[i] ) :
+
+ // Otherwise nodes in our document sort first
+ ap[i] === preferredDoc ? -1 :
+ bp[i] === preferredDoc ? 1 :
+ 0;
+ };
+
+ return document;
+};
+
+Sizzle.matches = function( expr, elements ) {
+ return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+ // Set document vars if needed
+ if ( ( elem.ownerDocument || elem ) !== document ) {
+ setDocument( elem );
+ }
+
+ // Make sure that attribute selectors are quoted
+ expr = expr.replace( rattributeQuotes, "='$1']" );
+
+ if ( support.matchesSelector && documentIsHTML &&
+ !compilerCache[ expr + " " ] &&
+ ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
+ ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
+
+ try {
+ var ret = matches.call( elem, expr );
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if ( ret || support.disconnectedMatch ||
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9
+ elem.document && elem.document.nodeType !== 11 ) {
+ return ret;
+ }
+ } catch (e) {}
+ }
+
+ return Sizzle( expr, document, null, [ elem ] ).length > 0;
+};
+
+Sizzle.contains = function( context, elem ) {
+ // Set document vars if needed
+ if ( ( context.ownerDocument || context ) !== document ) {
+ setDocument( context );
+ }
+ return contains( context, elem );
+};
+
+Sizzle.attr = function( elem, name ) {
+ // Set document vars if needed
+ if ( ( elem.ownerDocument || elem ) !== document ) {
+ setDocument( elem );
+ }
+
+ var fn = Expr.attrHandle[ name.toLowerCase() ],
+ // Don't get fooled by Object.prototype properties (jQuery #13807)
+ val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
+ fn( elem, name, !documentIsHTML ) :
+ undefined;
+
+ return val !== undefined ?
+ val :
+ support.attributes || !documentIsHTML ?
+ elem.getAttribute( name ) :
+ (val = elem.getAttributeNode(name)) && val.specified ?
+ val.value :
+ null;
+};
+
+Sizzle.error = function( msg ) {
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Document sorting and removing duplicates
+ * @param {ArrayLike} results
+ */
+Sizzle.uniqueSort = function( results ) {
+ var elem,
+ duplicates = [],
+ j = 0,
+ i = 0;
+
+ // Unless we *know* we can detect duplicates, assume their presence
+ hasDuplicate = !support.detectDuplicates;
+ sortInput = !support.sortStable && results.slice( 0 );
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ while ( (elem = results[i++]) ) {
+ if ( elem === results[ i ] ) {
+ j = duplicates.push( i );
+ }
+ }
+ while ( j-- ) {
+ results.splice( duplicates[ j ], 1 );
+ }
+ }
+
+ // Clear input after sorting to release objects
+ // See https://github.com/jquery/sizzle/pull/225
+ sortInput = null;
+
+ return results;
+};
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+ var node,
+ ret = "",
+ i = 0,
+ nodeType = elem.nodeType;
+
+ if ( !nodeType ) {
+ // If no nodeType, this is expected to be an array
+ while ( (node = elem[i++]) ) {
+ // Do not traverse comment nodes
+ ret += getText( node );
+ }
+ } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+ // Use textContent for elements
+ // innerText usage removed for consistency of new lines (jQuery #11153)
+ if ( typeof elem.textContent === "string" ) {
+ return elem.textContent;
+ } else {
+ // Traverse its children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+ // Do not include comment or processing instruction nodes
+
+ return ret;
+};
+
+Expr = Sizzle.selectors = {
+
+ // Can be adjusted by the user
+ cacheLength: 50,
+
+ createPseudo: markFunction,
+
+ match: matchExpr,
+
+ attrHandle: {},
+
+ find: {},
+
+ relative: {
+ ">": { dir: "parentNode", first: true },
+ " ": { dir: "parentNode" },
+ "+": { dir: "previousSibling", first: true },
+ "~": { dir: "previousSibling" }
+ },
+
+ preFilter: {
+ "ATTR": function( match ) {
+ match[1] = match[1].replace( runescape, funescape );
+
+ // Move the given value to match[3] whether quoted or unquoted
+ match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
+
+ if ( match[2] === "~=" ) {
+ match[3] = " " + match[3] + " ";
+ }
+
+ return match.slice( 0, 4 );
+ },
+
+ "CHILD": function( match ) {
+ /* matches from matchExpr["CHILD"]
+ 1 type (only|nth|...)
+ 2 what (child|of-type)
+ 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+ 4 xn-component of xn+y argument ([+-]?\d*n|)
+ 5 sign of xn-component
+ 6 x of xn-component
+ 7 sign of y-component
+ 8 y of y-component
+ */
+ match[1] = match[1].toLowerCase();
+
+ if ( match[1].slice( 0, 3 ) === "nth" ) {
+ // nth-* requires argument
+ if ( !match[3] ) {
+ Sizzle.error( match[0] );
+ }
+
+ // numeric x and y parameters for Expr.filter.CHILD
+ // remember that false/true cast respectively to 0/1
+ match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
+ match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
+
+ // other types prohibit arguments
+ } else if ( match[3] ) {
+ Sizzle.error( match[0] );
+ }
+
+ return match;
+ },
+
+ "PSEUDO": function( match ) {
+ var excess,
+ unquoted = !match[6] && match[2];
+
+ if ( matchExpr["CHILD"].test( match[0] ) ) {
+ return null;
+ }
+
+ // Accept quoted arguments as-is
+ if ( match[3] ) {
+ match[2] = match[4] || match[5] || "";
+
+ // Strip excess characters from unquoted arguments
+ } else if ( unquoted && rpseudo.test( unquoted ) &&
+ // Get excess from tokenize (recursively)
+ (excess = tokenize( unquoted, true )) &&
+ // advance to the next closing parenthesis
+ (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+
+ // excess is a negative index
+ match[0] = match[0].slice( 0, excess );
+ match[2] = unquoted.slice( 0, excess );
+ }
+
+ // Return only captures needed by the pseudo filter method (type and argument)
+ return match.slice( 0, 3 );
+ }
+ },
+
+ filter: {
+
+ "TAG": function( nodeNameSelector ) {
+ var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
+ return nodeNameSelector === "*" ?
+ function() { return true; } :
+ function( elem ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+ };
+ },
+
+ "CLASS": function( className ) {
+ var pattern = classCache[ className + " " ];
+
+ return pattern ||
+ (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
+ classCache( className, function( elem ) {
+ return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
+ });
+ },
+
+ "ATTR": function( name, operator, check ) {
+ return function( elem ) {
+ var result = Sizzle.attr( elem, name );
+
+ if ( result == null ) {
+ return operator === "!=";
+ }
+ if ( !operator ) {
+ return true;
+ }
+
+ result += "";
+
+ return operator === "=" ? result === check :
+ operator === "!=" ? result !== check :
+ operator === "^=" ? check && result.indexOf( check ) === 0 :
+ operator === "*=" ? check && result.indexOf( check ) > -1 :
+ operator === "$=" ? check && result.slice( -check.length ) === check :
+ operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
+ operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
+ false;
+ };
+ },
+
+ "CHILD": function( type, what, argument, first, last ) {
+ var simple = type.slice( 0, 3 ) !== "nth",
+ forward = type.slice( -4 ) !== "last",
+ ofType = what === "of-type";
+
+ return first === 1 && last === 0 ?
+
+ // Shortcut for :nth-*(n)
+ function( elem ) {
+ return !!elem.parentNode;
+ } :
+
+ function( elem, context, xml ) {
+ var cache, uniqueCache, outerCache, node, nodeIndex, start,
+ dir = simple !== forward ? "nextSibling" : "previousSibling",
+ parent = elem.parentNode,
+ name = ofType && elem.nodeName.toLowerCase(),
+ useCache = !xml && !ofType,
+ diff = false;
+
+ if ( parent ) {
+
+ // :(first|last|only)-(child|of-type)
+ if ( simple ) {
+ while ( dir ) {
+ node = elem;
+ while ( (node = node[ dir ]) ) {
+ if ( ofType ?
+ node.nodeName.toLowerCase() === name :
+ node.nodeType === 1 ) {
+
+ return false;
+ }
+ }
+ // Reverse direction for :only-* (if we haven't yet done so)
+ start = dir = type === "only" && !start && "nextSibling";
+ }
+ return true;
+ }
+
+ start = [ forward ? parent.firstChild : parent.lastChild ];
+
+ // non-xml :nth-child(...) stores cache data on `parent`
+ if ( forward && useCache ) {
+
+ // Seek `elem` from a previously-cached index
+
+ // ...in a gzip-friendly way
+ node = parent;
+ outerCache = node[ expando ] || (node[ expando ] = {});
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ node.uniqueID ] ||
+ (outerCache[ node.uniqueID ] = {});
+
+ cache = uniqueCache[ type ] || [];
+ nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
+ diff = nodeIndex && cache[ 2 ];
+ node = nodeIndex && parent.childNodes[ nodeIndex ];
+
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+
+ // Fallback to seeking `elem` from the start
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ // When found, cache indexes on `parent` and break
+ if ( node.nodeType === 1 && ++diff && node === elem ) {
+ uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
+ break;
+ }
+ }
+
+ } else {
+ // Use previously-cached element index if available
+ if ( useCache ) {
+ // ...in a gzip-friendly way
+ node = elem;
+ outerCache = node[ expando ] || (node[ expando ] = {});
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ node.uniqueID ] ||
+ (outerCache[ node.uniqueID ] = {});
+
+ cache = uniqueCache[ type ] || [];
+ nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
+ diff = nodeIndex;
+ }
+
+ // xml :nth-child(...)
+ // or :nth-last-child(...) or :nth(-last)?-of-type(...)
+ if ( diff === false ) {
+ // Use the same loop as above to seek `elem` from the start
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ if ( ( ofType ?
+ node.nodeName.toLowerCase() === name :
+ node.nodeType === 1 ) &&
+ ++diff ) {
+
+ // Cache the index of each encountered element
+ if ( useCache ) {
+ outerCache = node[ expando ] || (node[ expando ] = {});
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ node.uniqueID ] ||
+ (outerCache[ node.uniqueID ] = {});
+
+ uniqueCache[ type ] = [ dirruns, diff ];
+ }
+
+ if ( node === elem ) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Incorporate the offset, then check against cycle size
+ diff -= last;
+ return diff === first || ( diff % first === 0 && diff / first >= 0 );
+ }
+ };
+ },
+
+ "PSEUDO": function( pseudo, argument ) {
+ // pseudo-class names are case-insensitive
+ // http://www.w3.org/TR/selectors/#pseudo-classes
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+ // Remember that setFilters inherits from pseudos
+ var args,
+ fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+ Sizzle.error( "unsupported pseudo: " + pseudo );
+
+ // The user may use createPseudo to indicate that
+ // arguments are needed to create the filter function
+ // just as Sizzle does
+ if ( fn[ expando ] ) {
+ return fn( argument );
+ }
+
+ // But maintain support for old signatures
+ if ( fn.length > 1 ) {
+ args = [ pseudo, pseudo, "", argument ];
+ return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+ markFunction(function( seed, matches ) {
+ var idx,
+ matched = fn( seed, argument ),
+ i = matched.length;
+ while ( i-- ) {
+ idx = indexOf( seed, matched[i] );
+ seed[ idx ] = !( matches[ idx ] = matched[i] );
+ }
+ }) :
+ function( elem ) {
+ return fn( elem, 0, args );
+ };
+ }
+
+ return fn;
+ }
+ },
+
+ pseudos: {
+ // Potentially complex pseudos
+ "not": markFunction(function( selector ) {
+ // Trim the selector passed to compile
+ // to avoid treating leading and trailing
+ // spaces as combinators
+ var input = [],
+ results = [],
+ matcher = compile( selector.replace( rtrim, "$1" ) );
+
+ return matcher[ expando ] ?
+ markFunction(function( seed, matches, context, xml ) {
+ var elem,
+ unmatched = matcher( seed, null, xml, [] ),
+ i = seed.length;
+
+ // Match elements unmatched by `matcher`
+ while ( i-- ) {
+ if ( (elem = unmatched[i]) ) {
+ seed[i] = !(matches[i] = elem);
+ }
+ }
+ }) :
+ function( elem, context, xml ) {
+ input[0] = elem;
+ matcher( input, null, xml, results );
+ // Don't keep the element (issue #299)
+ input[0] = null;
+ return !results.pop();
+ };
+ }),
+
+ "has": markFunction(function( selector ) {
+ return function( elem ) {
+ return Sizzle( selector, elem ).length > 0;
+ };
+ }),
+
+ "contains": markFunction(function( text ) {
+ text = text.replace( runescape, funescape );
+ return function( elem ) {
+ return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
+ };
+ }),
+
+ // "Whether an element is represented by a :lang() selector
+ // is based solely on the element's language value
+ // being equal to the identifier C,
+ // or beginning with the identifier C immediately followed by "-".
+ // The matching of C against the element's language value is performed case-insensitively.
+ // The identifier C does not have to be a valid language name."
+ // http://www.w3.org/TR/selectors/#lang-pseudo
+ "lang": markFunction( function( lang ) {
+ // lang value must be a valid identifier
+ if ( !ridentifier.test(lang || "") ) {
+ Sizzle.error( "unsupported lang: " + lang );
+ }
+ lang = lang.replace( runescape, funescape ).toLowerCase();
+ return function( elem ) {
+ var elemLang;
+ do {
+ if ( (elemLang = documentIsHTML ?
+ elem.lang :
+ elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
+
+ elemLang = elemLang.toLowerCase();
+ return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
+ }
+ } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
+ return false;
+ };
+ }),
+
+ // Miscellaneous
+ "target": function( elem ) {
+ var hash = window.location && window.location.hash;
+ return hash && hash.slice( 1 ) === elem.id;
+ },
+
+ "root": function( elem ) {
+ return elem === docElem;
+ },
+
+ "focus": function( elem ) {
+ return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+ },
+
+ // Boolean properties
+ "enabled": function( elem ) {
+ return elem.disabled === false;
+ },
+
+ "disabled": function( elem ) {
+ return elem.disabled === true;
+ },
+
+ "checked": function( elem ) {
+ // In CSS3, :checked should return both checked and selected elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ var nodeName = elem.nodeName.toLowerCase();
+ return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+ },
+
+ "selected": function( elem ) {
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ // Contents
+ "empty": function( elem ) {
+ // http://www.w3.org/TR/selectors/#empty-pseudo
+ // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
+ // but not by others (comment: 8; processing instruction: 7; etc.)
+ // nodeType < 6 works because attributes (2) do not appear as children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ if ( elem.nodeType < 6 ) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ "parent": function( elem ) {
+ return !Expr.pseudos["empty"]( elem );
+ },
+
+ // Element/input types
+ "header": function( elem ) {
+ return rheader.test( elem.nodeName );
+ },
+
+ "input": function( elem ) {
+ return rinputs.test( elem.nodeName );
+ },
+
+ "button": function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === "button" || name === "button";
+ },
+
+ "text": function( elem ) {
+ var attr;
+ return elem.nodeName.toLowerCase() === "input" &&
+ elem.type === "text" &&
+
+ // Support: IE<8
+ // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
+ ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
+ },
+
+ // Position-in-collection
+ "first": createPositionalPseudo(function() {
+ return [ 0 ];
+ }),
+
+ "last": createPositionalPseudo(function( matchIndexes, length ) {
+ return [ length - 1 ];
+ }),
+
+ "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ return [ argument < 0 ? argument + length : argument ];
+ }),
+
+ "even": createPositionalPseudo(function( matchIndexes, length ) {
+ var i = 0;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "odd": createPositionalPseudo(function( matchIndexes, length ) {
+ var i = 1;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; --i >= 0; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; ++i < length; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ })
+ }
+};
+
+Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+// Add button/input type pseudos
+for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
+ Expr.pseudos[ i ] = createInputPseudo( i );
+}
+for ( i in { submit: true, reset: true } ) {
+ Expr.pseudos[ i ] = createButtonPseudo( i );
+}
+
+// Easy API for creating new setFilters
+function setFilters() {}
+setFilters.prototype = Expr.filters = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
+ var matched, match, tokens, type,
+ soFar, groups, preFilters,
+ cached = tokenCache[ selector + " " ];
+
+ if ( cached ) {
+ return parseOnly ? 0 : cached.slice( 0 );
+ }
+
+ soFar = selector;
+ groups = [];
+ preFilters = Expr.preFilter;
+
+ while ( soFar ) {
+
+ // Comma and first run
+ if ( !matched || (match = rcomma.exec( soFar )) ) {
+ if ( match ) {
+ // Don't consume trailing commas as valid
+ soFar = soFar.slice( match[0].length ) || soFar;
+ }
+ groups.push( (tokens = []) );
+ }
+
+ matched = false;
+
+ // Combinators
+ if ( (match = rcombinators.exec( soFar )) ) {
+ matched = match.shift();
+ tokens.push({
+ value: matched,
+ // Cast descendant combinators to space
+ type: match[0].replace( rtrim, " " )
+ });
+ soFar = soFar.slice( matched.length );
+ }
+
+ // Filters
+ for ( type in Expr.filter ) {
+ if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
+ (match = preFilters[ type ]( match ))) ) {
+ matched = match.shift();
+ tokens.push({
+ value: matched,
+ type: type,
+ matches: match
+ });
+ soFar = soFar.slice( matched.length );
+ }
+ }
+
+ if ( !matched ) {
+ break;
+ }
+ }
+
+ // Return the length of the invalid excess
+ // if we're just parsing
+ // Otherwise, throw an error or return tokens
+ return parseOnly ?
+ soFar.length :
+ soFar ?
+ Sizzle.error( selector ) :
+ // Cache the tokens
+ tokenCache( selector, groups ).slice( 0 );
+};
+
+function toSelector( tokens ) {
+ var i = 0,
+ len = tokens.length,
+ selector = "";
+ for ( ; i < len; i++ ) {
+ selector += tokens[i].value;
+ }
+ return selector;
+}
+
+function addCombinator( matcher, combinator, base ) {
+ var dir = combinator.dir,
+ checkNonElements = base && dir === "parentNode",
+ doneName = done++;
+
+ return combinator.first ?
+ // Check against closest ancestor/preceding element
+ function( elem, context, xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ return matcher( elem, context, xml );
+ }
+ }
+ } :
+
+ // Check against all ancestor/preceding elements
+ function( elem, context, xml ) {
+ var oldCache, uniqueCache, outerCache,
+ newCache = [ dirruns, doneName ];
+
+ // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
+ if ( xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ if ( matcher( elem, context, xml ) ) {
+ return true;
+ }
+ }
+ }
+ } else {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ outerCache = elem[ expando ] || (elem[ expando ] = {});
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});
+
+ if ( (oldCache = uniqueCache[ dir ]) &&
+ oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
+
+ // Assign to newCache so results back-propagate to previous elements
+ return (newCache[ 2 ] = oldCache[ 2 ]);
+ } else {
+ // Reuse newcache so results back-propagate to previous elements
+ uniqueCache[ dir ] = newCache;
+
+ // A match means we're done; a fail means we have to keep checking
+ if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ };
+}
+
+function elementMatcher( matchers ) {
+ return matchers.length > 1 ?
+ function( elem, context, xml ) {
+ var i = matchers.length;
+ while ( i-- ) {
+ if ( !matchers[i]( elem, context, xml ) ) {
+ return false;
+ }
+ }
+ return true;
+ } :
+ matchers[0];
+}
+
+function multipleContexts( selector, contexts, results ) {
+ var i = 0,
+ len = contexts.length;
+ for ( ; i < len; i++ ) {
+ Sizzle( selector, contexts[i], results );
+ }
+ return results;
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+ var elem,
+ newUnmatched = [],
+ i = 0,
+ len = unmatched.length,
+ mapped = map != null;
+
+ for ( ; i < len; i++ ) {
+ if ( (elem = unmatched[i]) ) {
+ if ( !filter || filter( elem, context, xml ) ) {
+ newUnmatched.push( elem );
+ if ( mapped ) {
+ map.push( i );
+ }
+ }
+ }
+ }
+
+ return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+ if ( postFilter && !postFilter[ expando ] ) {
+ postFilter = setMatcher( postFilter );
+ }
+ if ( postFinder && !postFinder[ expando ] ) {
+ postFinder = setMatcher( postFinder, postSelector );
+ }
+ return markFunction(function( seed, results, context, xml ) {
+ var temp, i, elem,
+ preMap = [],
+ postMap = [],
+ preexisting = results.length,
+
+ // Get initial elements from seed or context
+ elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
+
+ // Prefilter to get matcher input, preserving a map for seed-results synchronization
+ matcherIn = preFilter && ( seed || !selector ) ?
+ condense( elems, preMap, preFilter, context, xml ) :
+ elems,
+
+ matcherOut = matcher ?
+ // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+ postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+ // ...intermediate processing is necessary
+ [] :
+
+ // ...otherwise use results directly
+ results :
+ matcherIn;
+
+ // Find primary matches
+ if ( matcher ) {
+ matcher( matcherIn, matcherOut, context, xml );
+ }
+
+ // Apply postFilter
+ if ( postFilter ) {
+ temp = condense( matcherOut, postMap );
+ postFilter( temp, [], context, xml );
+
+ // Un-match failing elements by moving them back to matcherIn
+ i = temp.length;
+ while ( i-- ) {
+ if ( (elem = temp[i]) ) {
+ matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
+ }
+ }
+ }
+
+ if ( seed ) {
+ if ( postFinder || preFilter ) {
+ if ( postFinder ) {
+ // Get the final matcherOut by condensing this intermediate into postFinder contexts
+ temp = [];
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) ) {
+ // Restore matcherIn since elem is not yet a final match
+ temp.push( (matcherIn[i] = elem) );
+ }
+ }
+ postFinder( null, (matcherOut = []), temp, xml );
+ }
+
+ // Move matched elements from seed to results to keep them synchronized
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) &&
+ (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {
+
+ seed[temp] = !(results[temp] = elem);
+ }
+ }
+ }
+
+ // Add elements to results, through postFinder if defined
+ } else {
+ matcherOut = condense(
+ matcherOut === results ?
+ matcherOut.splice( preexisting, matcherOut.length ) :
+ matcherOut
+ );
+ if ( postFinder ) {
+ postFinder( null, results, matcherOut, xml );
+ } else {
+ push.apply( results, matcherOut );
+ }
+ }
+ });
+}
+
+function matcherFromTokens( tokens ) {
+ var checkContext, matcher, j,
+ len = tokens.length,
+ leadingRelative = Expr.relative[ tokens[0].type ],
+ implicitRelative = leadingRelative || Expr.relative[" "],
+ i = leadingRelative ? 1 : 0,
+
+ // The foundational matcher ensures that elements are reachable from top-level context(s)
+ matchContext = addCombinator( function( elem ) {
+ return elem === checkContext;
+ }, implicitRelative, true ),
+ matchAnyContext = addCombinator( function( elem ) {
+ return indexOf( checkContext, elem ) > -1;
+ }, implicitRelative, true ),
+ matchers = [ function( elem, context, xml ) {
+ var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+ (checkContext = context).nodeType ?
+ matchContext( elem, context, xml ) :
+ matchAnyContext( elem, context, xml ) );
+ // Avoid hanging onto element (issue #299)
+ checkContext = null;
+ return ret;
+ } ];
+
+ for ( ; i < len; i++ ) {
+ if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
+ matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
+ } else {
+ matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
+
+ // Return special upon seeing a positional matcher
+ if ( matcher[ expando ] ) {
+ // Find the next relative operator (if any) for proper handling
+ j = ++i;
+ for ( ; j < len; j++ ) {
+ if ( Expr.relative[ tokens[j].type ] ) {
+ break;
+ }
+ }
+ return setMatcher(
+ i > 1 && elementMatcher( matchers ),
+ i > 1 && toSelector(
+ // If the preceding token was a descendant combinator, insert an implicit any-element `*`
+ tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
+ ).replace( rtrim, "$1" ),
+ matcher,
+ i < j && matcherFromTokens( tokens.slice( i, j ) ),
+ j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
+ j < len && toSelector( tokens )
+ );
+ }
+ matchers.push( matcher );
+ }
+ }
+
+ return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+ var bySet = setMatchers.length > 0,
+ byElement = elementMatchers.length > 0,
+ superMatcher = function( seed, context, xml, results, outermost ) {
+ var elem, j, matcher,
+ matchedCount = 0,
+ i = "0",
+ unmatched = seed && [],
+ setMatched = [],
+ contextBackup = outermostContext,
+ // We must always have either seed elements or outermost context
+ elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
+ // Use integer dirruns iff this is the outermost matcher
+ dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
+ len = elems.length;
+
+ if ( outermost ) {
+ outermostContext = context === document || context || outermost;
+ }
+
+ // Add elements passing elementMatchers directly to results
+ // Support: IE<9, Safari
+ // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id
+ for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
+ if ( byElement && elem ) {
+ j = 0;
+ if ( !context && elem.ownerDocument !== document ) {
+ setDocument( elem );
+ xml = !documentIsHTML;
+ }
+ while ( (matcher = elementMatchers[j++]) ) {
+ if ( matcher( elem, context || document, xml) ) {
+ results.push( elem );
+ break;
+ }
+ }
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ }
+ }
+
+ // Track unmatched elements for set filters
+ if ( bySet ) {
+ // They will have gone through all possible matchers
+ if ( (elem = !matcher && elem) ) {
+ matchedCount--;
+ }
+
+ // Lengthen the array for every element, matched or not
+ if ( seed ) {
+ unmatched.push( elem );
+ }
+ }
+ }
+
+ // `i` is now the count of elements visited above, and adding it to `matchedCount`
+ // makes the latter nonnegative.
+ matchedCount += i;
+
+ // Apply set filters to unmatched elements
+ // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
+ // equals `i`), unless we didn't visit _any_ elements in the above loop because we have
+ // no element matchers and no seed.
+ // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
+ // case, which will result in a "00" `matchedCount` that differs from `i` but is also
+ // numerically zero.
+ if ( bySet && i !== matchedCount ) {
+ j = 0;
+ while ( (matcher = setMatchers[j++]) ) {
+ matcher( unmatched, setMatched, context, xml );
+ }
+
+ if ( seed ) {
+ // Reintegrate element matches to eliminate the need for sorting
+ if ( matchedCount > 0 ) {
+ while ( i-- ) {
+ if ( !(unmatched[i] || setMatched[i]) ) {
+ setMatched[i] = pop.call( results );
+ }
+ }
+ }
+
+ // Discard index placeholder values to get only actual matches
+ setMatched = condense( setMatched );
+ }
+
+ // Add matches to results
+ push.apply( results, setMatched );
+
+ // Seedless set matches succeeding multiple successful matchers stipulate sorting
+ if ( outermost && !seed && setMatched.length > 0 &&
+ ( matchedCount + setMatchers.length ) > 1 ) {
+
+ Sizzle.uniqueSort( results );
+ }
+ }
+
+ // Override manipulation of globals by nested matchers
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ outermostContext = contextBackup;
+ }
+
+ return unmatched;
+ };
+
+ return bySet ?
+ markFunction( superMatcher ) :
+ superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
+ var i,
+ setMatchers = [],
+ elementMatchers = [],
+ cached = compilerCache[ selector + " " ];
+
+ if ( !cached ) {
+ // Generate a function of recursive functions that can be used to check each element
+ if ( !match ) {
+ match = tokenize( selector );
+ }
+ i = match.length;
+ while ( i-- ) {
+ cached = matcherFromTokens( match[i] );
+ if ( cached[ expando ] ) {
+ setMatchers.push( cached );
+ } else {
+ elementMatchers.push( cached );
+ }
+ }
+
+ // Cache the compiled function
+ cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+
+ // Save selector and tokenization
+ cached.selector = selector;
+ }
+ return cached;
+};
+
+/**
+ * A low-level selection function that works with Sizzle's compiled
+ * selector functions
+ * @param {String|Function} selector A selector or a pre-compiled
+ * selector function built with Sizzle.compile
+ * @param {Element} context
+ * @param {Array} [results]
+ * @param {Array} [seed] A set of elements to match against
+ */
+select = Sizzle.select = function( selector, context, results, seed ) {
+ var i, tokens, token, type, find,
+ compiled = typeof selector === "function" && selector,
+ match = !seed && tokenize( (selector = compiled.selector || selector) );
+
+ results = results || [];
+
+ // Try to minimize operations if there is only one selector in the list and no seed
+ // (the latter of which guarantees us context)
+ if ( match.length === 1 ) {
+
+ // Reduce context if the leading compound selector is an ID
+ tokens = match[0] = match[0].slice( 0 );
+ if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+ support.getById && context.nodeType === 9 && documentIsHTML &&
+ Expr.relative[ tokens[1].type ] ) {
+
+ context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
+ if ( !context ) {
+ return results;
+
+ // Precompiled matchers will still verify ancestry, so step up a level
+ } else if ( compiled ) {
+ context = context.parentNode;
+ }
+
+ selector = selector.slice( tokens.shift().value.length );
+ }
+
+ // Fetch a seed set for right-to-left matching
+ i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
+ while ( i-- ) {
+ token = tokens[i];
+
+ // Abort if we hit a combinator
+ if ( Expr.relative[ (type = token.type) ] ) {
+ break;
+ }
+ if ( (find = Expr.find[ type ]) ) {
+ // Search, expanding context for leading sibling combinators
+ if ( (seed = find(
+ token.matches[0].replace( runescape, funescape ),
+ rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
+ )) ) {
+
+ // If seed is empty or no tokens remain, we can return early
+ tokens.splice( i, 1 );
+ selector = seed.length && toSelector( tokens );
+ if ( !selector ) {
+ push.apply( results, seed );
+ return results;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ // Compile and execute a filtering function if one is not provided
+ // Provide `match` to avoid retokenization if we modified the selector above
+ ( compiled || compile( selector, match ) )(
+ seed,
+ context,
+ !documentIsHTML,
+ results,
+ !context || rsibling.test( selector ) && testContext( context.parentNode ) || context
+ );
+ return results;
+};
+
+// One-time assignments
+
+// Sort stability
+support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
+
+// Support: Chrome 14-35+
+// Always assume duplicates if they aren't passed to the comparison function
+support.detectDuplicates = !!hasDuplicate;
+
+// Initialize against the default document
+setDocument();
+
+// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
+// Detached nodes confoundingly follow *each other*
+support.sortDetached = assert(function( div1 ) {
+ // Should return 1, but returns 4 (following)
+ return div1.compareDocumentPosition( document.createElement("div") ) & 1;
+});
+
+// Support: IE<8
+// Prevent attribute/property "interpolation"
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !assert(function( div ) {
+ div.innerHTML = "";
+ return div.firstChild.getAttribute("href") === "#" ;
+}) ) {
+ addHandle( "type|href|height|width", function( elem, name, isXML ) {
+ if ( !isXML ) {
+ return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
+ }
+ });
+}
+
+// Support: IE<9
+// Use defaultValue in place of getAttribute("value")
+if ( !support.attributes || !assert(function( div ) {
+ div.innerHTML = "";
+ div.firstChild.setAttribute( "value", "" );
+ return div.firstChild.getAttribute( "value" ) === "";
+}) ) {
+ addHandle( "value", function( elem, name, isXML ) {
+ if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
+ return elem.defaultValue;
+ }
+ });
+}
+
+// Support: IE<9
+// Use getAttributeNode to fetch booleans when getAttribute lies
+if ( !assert(function( div ) {
+ return div.getAttribute("disabled") == null;
+}) ) {
+ addHandle( booleans, function( elem, name, isXML ) {
+ var val;
+ if ( !isXML ) {
+ return elem[ name ] === true ? name.toLowerCase() :
+ (val = elem.getAttributeNode( name )) && val.specified ?
+ val.value :
+ null;
+ }
+ });
+}
+
+return Sizzle;
+
+})( window );
+
+
+
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[ ":" ] = jQuery.expr.pseudos;
+jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+
+var dir = function( elem, dir, until ) {
+ var matched = [],
+ truncate = until !== undefined;
+
+ while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {
+ if ( elem.nodeType === 1 ) {
+ if ( truncate && jQuery( elem ).is( until ) ) {
+ break;
+ }
+ matched.push( elem );
+ }
+ }
+ return matched;
+};
+
+
+var siblings = function( n, elem ) {
+ var matched = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ matched.push( n );
+ }
+ }
+
+ return matched;
+};
+
+
+var rneedsContext = jQuery.expr.match.needsContext;
+
+var rsingleTag = ( /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/ );
+
+
+
+var risSimple = /^.[^:#\[\.,]*$/;
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, not ) {
+ if ( jQuery.isFunction( qualifier ) ) {
+ return jQuery.grep( elements, function( elem, i ) {
+ /* jshint -W018 */
+ return !!qualifier.call( elem, i, elem ) !== not;
+ } );
+
+ }
+
+ if ( qualifier.nodeType ) {
+ return jQuery.grep( elements, function( elem ) {
+ return ( elem === qualifier ) !== not;
+ } );
+
+ }
+
+ if ( typeof qualifier === "string" ) {
+ if ( risSimple.test( qualifier ) ) {
+ return jQuery.filter( qualifier, elements, not );
+ }
+
+ qualifier = jQuery.filter( qualifier, elements );
+ }
+
+ return jQuery.grep( elements, function( elem ) {
+ return ( jQuery.inArray( elem, qualifier ) > -1 ) !== not;
+ } );
+}
+
+jQuery.filter = function( expr, elems, not ) {
+ var elem = elems[ 0 ];
+
+ if ( not ) {
+ expr = ":not(" + expr + ")";
+ }
+
+ return elems.length === 1 && elem.nodeType === 1 ?
+ jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
+ jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
+ return elem.nodeType === 1;
+ } ) );
+};
+
+jQuery.fn.extend( {
+ find: function( selector ) {
+ var i,
+ ret = [],
+ self = this,
+ len = self.length;
+
+ if ( typeof selector !== "string" ) {
+ return this.pushStack( jQuery( selector ).filter( function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( self[ i ], this ) ) {
+ return true;
+ }
+ }
+ } ) );
+ }
+
+ for ( i = 0; i < len; i++ ) {
+ jQuery.find( selector, self[ i ], ret );
+ }
+
+ // Needed because $( selector, context ) becomes $( context ).find( selector )
+ ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
+ ret.selector = this.selector ? this.selector + " " + selector : selector;
+ return ret;
+ },
+ filter: function( selector ) {
+ return this.pushStack( winnow( this, selector || [], false ) );
+ },
+ not: function( selector ) {
+ return this.pushStack( winnow( this, selector || [], true ) );
+ },
+ is: function( selector ) {
+ return !!winnow(
+ this,
+
+ // If this is a positional/relative selector, check membership in the returned set
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
+ typeof selector === "string" && rneedsContext.test( selector ) ?
+ jQuery( selector ) :
+ selector || [],
+ false
+ ).length;
+ }
+} );
+
+
+// Initialize a jQuery object
+
+
+// A central reference to the root jQuery(document)
+var rootjQuery,
+
+ // A simple way to check for HTML strings
+ // Prioritize #id over to avoid XSS via location.hash (#9521)
+ // Strict HTML recognition (#11290: must start with <)
+ rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
+
+ init = jQuery.fn.init = function( selector, context, root ) {
+ var match, elem;
+
+ // HANDLE: $(""), $(null), $(undefined), $(false)
+ if ( !selector ) {
+ return this;
+ }
+
+ // init accepts an alternate rootjQuery
+ // so migrate can support jQuery.sub (gh-2101)
+ root = root || rootjQuery;
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ if ( selector.charAt( 0 ) === "<" &&
+ selector.charAt( selector.length - 1 ) === ">" &&
+ selector.length >= 3 ) {
+
+ // Assume that strings that start and end with <> are HTML and skip the regex check
+ match = [ null, selector, null ];
+
+ } else {
+ match = rquickExpr.exec( selector );
+ }
+
+ // Match html or make sure no context is specified for #id
+ if ( match && ( match[ 1 ] || !context ) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[ 1 ] ) {
+ context = context instanceof jQuery ? context[ 0 ] : context;
+
+ // scripts is true for back-compat
+ // Intentionally let the error be thrown if parseHTML is not present
+ jQuery.merge( this, jQuery.parseHTML(
+ match[ 1 ],
+ context && context.nodeType ? context.ownerDocument || context : document,
+ true
+ ) );
+
+ // HANDLE: $(html, props)
+ if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {
+ for ( match in context ) {
+
+ // Properties of context are called as methods if possible
+ if ( jQuery.isFunction( this[ match ] ) ) {
+ this[ match ]( context[ match ] );
+
+ // ...and otherwise set as attributes
+ } else {
+ this.attr( match, context[ match ] );
+ }
+ }
+ }
+
+ return this;
+
+ // HANDLE: $(#id)
+ } else {
+ elem = document.getElementById( match[ 2 ] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id !== match[ 2 ] ) {
+ return rootjQuery.find( selector );
+ }
+
+ // Otherwise, we inject the element directly into the jQuery object
+ this.length = 1;
+ this[ 0 ] = elem;
+ }
+
+ this.context = document;
+ this.selector = selector;
+ return this;
+ }
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return ( context || root ).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return this.constructor( context ).find( selector );
+ }
+
+ // HANDLE: $(DOMElement)
+ } else if ( selector.nodeType ) {
+ this.context = this[ 0 ] = selector;
+ this.length = 1;
+ return this;
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) ) {
+ return typeof root.ready !== "undefined" ?
+ root.ready( selector ) :
+
+ // Execute immediately if ready is not present
+ selector( jQuery );
+ }
+
+ if ( selector.selector !== undefined ) {
+ this.selector = selector.selector;
+ this.context = selector.context;
+ }
+
+ return jQuery.makeArray( selector, this );
+ };
+
+// Give the init function the jQuery prototype for later instantiation
+init.prototype = jQuery.fn;
+
+// Initialize central reference
+rootjQuery = jQuery( document );
+
+
+var rparentsprev = /^(?:parents|prev(?:Until|All))/,
+
+ // methods guaranteed to produce a unique set when starting from a unique set
+ guaranteedUnique = {
+ children: true,
+ contents: true,
+ next: true,
+ prev: true
+ };
+
+jQuery.fn.extend( {
+ has: function( target ) {
+ var i,
+ targets = jQuery( target, this ),
+ len = targets.length;
+
+ return this.filter( function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( this, targets[ i ] ) ) {
+ return true;
+ }
+ }
+ } );
+ },
+
+ closest: function( selectors, context ) {
+ var cur,
+ i = 0,
+ l = this.length,
+ matched = [],
+ pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
+ jQuery( selectors, context || this.context ) :
+ 0;
+
+ for ( ; i < l; i++ ) {
+ for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {
+
+ // Always skip document fragments
+ if ( cur.nodeType < 11 && ( pos ?
+ pos.index( cur ) > -1 :
+
+ // Don't pass non-elements to Sizzle
+ cur.nodeType === 1 &&
+ jQuery.find.matchesSelector( cur, selectors ) ) ) {
+
+ matched.push( cur );
+ break;
+ }
+ }
+ }
+
+ return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );
+ },
+
+ // Determine the position of an element within
+ // the matched set of elements
+ index: function( elem ) {
+
+ // No argument, return index in parent
+ if ( !elem ) {
+ return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
+ }
+
+ // index in selector
+ if ( typeof elem === "string" ) {
+ return jQuery.inArray( this[ 0 ], jQuery( elem ) );
+ }
+
+ // Locate the position of the desired element
+ return jQuery.inArray(
+
+ // If it receives a jQuery object, the first element is used
+ elem.jquery ? elem[ 0 ] : elem, this );
+ },
+
+ add: function( selector, context ) {
+ return this.pushStack(
+ jQuery.uniqueSort(
+ jQuery.merge( this.get(), jQuery( selector, context ) )
+ )
+ );
+ },
+
+ addBack: function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter( selector )
+ );
+ }
+} );
+
+function sibling( cur, dir ) {
+ do {
+ cur = cur[ dir ];
+ } while ( cur && cur.nodeType !== 1 );
+
+ return cur;
+}
+
+jQuery.each( {
+ parent: function( elem ) {
+ var parent = elem.parentNode;
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+ parents: function( elem ) {
+ return dir( elem, "parentNode" );
+ },
+ parentsUntil: function( elem, i, until ) {
+ return dir( elem, "parentNode", until );
+ },
+ next: function( elem ) {
+ return sibling( elem, "nextSibling" );
+ },
+ prev: function( elem ) {
+ return sibling( elem, "previousSibling" );
+ },
+ nextAll: function( elem ) {
+ return dir( elem, "nextSibling" );
+ },
+ prevAll: function( elem ) {
+ return dir( elem, "previousSibling" );
+ },
+ nextUntil: function( elem, i, until ) {
+ return dir( elem, "nextSibling", until );
+ },
+ prevUntil: function( elem, i, until ) {
+ return dir( elem, "previousSibling", until );
+ },
+ siblings: function( elem ) {
+ return siblings( ( elem.parentNode || {} ).firstChild, elem );
+ },
+ children: function( elem ) {
+ return siblings( elem.firstChild );
+ },
+ contents: function( elem ) {
+ return jQuery.nodeName( elem, "iframe" ) ?
+ elem.contentDocument || elem.contentWindow.document :
+ jQuery.merge( [], elem.childNodes );
+ }
+}, function( name, fn ) {
+ jQuery.fn[ name ] = function( until, selector ) {
+ var ret = jQuery.map( this, fn, until );
+
+ if ( name.slice( -5 ) !== "Until" ) {
+ selector = until;
+ }
+
+ if ( selector && typeof selector === "string" ) {
+ ret = jQuery.filter( selector, ret );
+ }
+
+ if ( this.length > 1 ) {
+
+ // Remove duplicates
+ if ( !guaranteedUnique[ name ] ) {
+ ret = jQuery.uniqueSort( ret );
+ }
+
+ // Reverse order for parents* and prev-derivatives
+ if ( rparentsprev.test( name ) ) {
+ ret = ret.reverse();
+ }
+ }
+
+ return this.pushStack( ret );
+ };
+} );
+var rnotwhite = ( /\S+/g );
+
+
+
+// Convert String-formatted options into Object-formatted ones
+function createOptions( options ) {
+ var object = {};
+ jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
+ object[ flag ] = true;
+ } );
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * options: an optional list of space-separated options that will change how
+ * the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ * once: will ensure the callback list can only be fired once (like a Deferred)
+ *
+ * memory: will keep track of previous values and will call any callback added
+ * after the list has been fired right away with the latest "memorized"
+ * values (like a Deferred)
+ *
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
+ *
+ * stopOnFalse: interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+ // Convert options from String-formatted to Object-formatted if needed
+ // (we check in cache first)
+ options = typeof options === "string" ?
+ createOptions( options ) :
+ jQuery.extend( {}, options );
+
+ var // Flag to know if list is currently firing
+ firing,
+
+ // Last fire value for non-forgettable lists
+ memory,
+
+ // Flag to know if list was already fired
+ fired,
+
+ // Flag to prevent firing
+ locked,
+
+ // Actual callback list
+ list = [],
+
+ // Queue of execution data for repeatable lists
+ queue = [],
+
+ // Index of currently firing callback (modified by add/remove as needed)
+ firingIndex = -1,
+
+ // Fire callbacks
+ fire = function() {
+
+ // Enforce single-firing
+ locked = options.once;
+
+ // Execute callbacks for all pending executions,
+ // respecting firingIndex overrides and runtime changes
+ fired = firing = true;
+ for ( ; queue.length; firingIndex = -1 ) {
+ memory = queue.shift();
+ while ( ++firingIndex < list.length ) {
+
+ // Run callback and check for early termination
+ if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
+ options.stopOnFalse ) {
+
+ // Jump to end and forget the data so .add doesn't re-fire
+ firingIndex = list.length;
+ memory = false;
+ }
+ }
+ }
+
+ // Forget the data if we're done with it
+ if ( !options.memory ) {
+ memory = false;
+ }
+
+ firing = false;
+
+ // Clean up if we're done firing for good
+ if ( locked ) {
+
+ // Keep an empty list if we have data for future add calls
+ if ( memory ) {
+ list = [];
+
+ // Otherwise, this object is spent
+ } else {
+ list = "";
+ }
+ }
+ },
+
+ // Actual Callbacks object
+ self = {
+
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+
+ // If we have memory from a past run, we should fire after adding
+ if ( memory && !firing ) {
+ firingIndex = list.length - 1;
+ queue.push( memory );
+ }
+
+ ( function add( args ) {
+ jQuery.each( args, function( _, arg ) {
+ if ( jQuery.isFunction( arg ) ) {
+ if ( !options.unique || !self.has( arg ) ) {
+ list.push( arg );
+ }
+ } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {
+
+ // Inspect recursively
+ add( arg );
+ }
+ } );
+ } )( arguments );
+
+ if ( memory && !firing ) {
+ fire();
+ }
+ }
+ return this;
+ },
+
+ // Remove a callback from the list
+ remove: function() {
+ jQuery.each( arguments, function( _, arg ) {
+ var index;
+ while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+ list.splice( index, 1 );
+
+ // Handle firing indexes
+ if ( index <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ } );
+ return this;
+ },
+
+ // Check if a given callback is in the list.
+ // If no argument is given, return whether or not list has callbacks attached.
+ has: function( fn ) {
+ return fn ?
+ jQuery.inArray( fn, list ) > -1 :
+ list.length > 0;
+ },
+
+ // Remove all callbacks from the list
+ empty: function() {
+ if ( list ) {
+ list = [];
+ }
+ return this;
+ },
+
+ // Disable .fire and .add
+ // Abort any current/pending executions
+ // Clear all callbacks and values
+ disable: function() {
+ locked = queue = [];
+ list = memory = "";
+ return this;
+ },
+ disabled: function() {
+ return !list;
+ },
+
+ // Disable .fire
+ // Also disable .add unless we have memory (since it would have no effect)
+ // Abort any pending executions
+ lock: function() {
+ locked = true;
+ if ( !memory ) {
+ self.disable();
+ }
+ return this;
+ },
+ locked: function() {
+ return !!locked;
+ },
+
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ if ( !locked ) {
+ args = args || [];
+ args = [ context, args.slice ? args.slice() : args ];
+ queue.push( args );
+ if ( !firing ) {
+ fire();
+ }
+ }
+ return this;
+ },
+
+ // Call all the callbacks with the given arguments
+ fire: function() {
+ self.fireWith( this, arguments );
+ return this;
+ },
+
+ // To know if the callbacks have already been called at least once
+ fired: function() {
+ return !!fired;
+ }
+ };
+
+ return self;
+};
+
+
+jQuery.extend( {
+
+ Deferred: function( func ) {
+ var tuples = [
+
+ // action, add listener, listener list, final state
+ [ "resolve", "done", jQuery.Callbacks( "once memory" ), "resolved" ],
+ [ "reject", "fail", jQuery.Callbacks( "once memory" ), "rejected" ],
+ [ "notify", "progress", jQuery.Callbacks( "memory" ) ]
+ ],
+ state = "pending",
+ promise = {
+ state: function() {
+ return state;
+ },
+ always: function() {
+ deferred.done( arguments ).fail( arguments );
+ return this;
+ },
+ then: function( /* fnDone, fnFail, fnProgress */ ) {
+ var fns = arguments;
+ return jQuery.Deferred( function( newDefer ) {
+ jQuery.each( tuples, function( i, tuple ) {
+ var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
+
+ // deferred[ done | fail | progress ] for forwarding actions to newDefer
+ deferred[ tuple[ 1 ] ]( function() {
+ var returned = fn && fn.apply( this, arguments );
+ if ( returned && jQuery.isFunction( returned.promise ) ) {
+ returned.promise()
+ .progress( newDefer.notify )
+ .done( newDefer.resolve )
+ .fail( newDefer.reject );
+ } else {
+ newDefer[ tuple[ 0 ] + "With" ](
+ this === promise ? newDefer.promise() : this,
+ fn ? [ returned ] : arguments
+ );
+ }
+ } );
+ } );
+ fns = null;
+ } ).promise();
+ },
+
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ return obj != null ? jQuery.extend( obj, promise ) : promise;
+ }
+ },
+ deferred = {};
+
+ // Keep pipe for back-compat
+ promise.pipe = promise.then;
+
+ // Add list-specific methods
+ jQuery.each( tuples, function( i, tuple ) {
+ var list = tuple[ 2 ],
+ stateString = tuple[ 3 ];
+
+ // promise[ done | fail | progress ] = list.add
+ promise[ tuple[ 1 ] ] = list.add;
+
+ // Handle state
+ if ( stateString ) {
+ list.add( function() {
+
+ // state = [ resolved | rejected ]
+ state = stateString;
+
+ // [ reject_list | resolve_list ].disable; progress_list.lock
+ }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+ }
+
+ // deferred[ resolve | reject | notify ]
+ deferred[ tuple[ 0 ] ] = function() {
+ deferred[ tuple[ 0 ] + "With" ]( this === deferred ? promise : this, arguments );
+ return this;
+ };
+ deferred[ tuple[ 0 ] + "With" ] = list.fireWith;
+ } );
+
+ // Make the deferred a promise
+ promise.promise( deferred );
+
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+
+ // All done!
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( subordinate /* , ..., subordinateN */ ) {
+ var i = 0,
+ resolveValues = slice.call( arguments ),
+ length = resolveValues.length,
+
+ // the count of uncompleted subordinates
+ remaining = length !== 1 ||
+ ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+ // the master Deferred.
+ // If resolveValues consist of only a single Deferred, just use that.
+ deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+
+ // Update function for both resolve and progress values
+ updateFunc = function( i, contexts, values ) {
+ return function( value ) {
+ contexts[ i ] = this;
+ values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
+ if ( values === progressValues ) {
+ deferred.notifyWith( contexts, values );
+
+ } else if ( !( --remaining ) ) {
+ deferred.resolveWith( contexts, values );
+ }
+ };
+ },
+
+ progressValues, progressContexts, resolveContexts;
+
+ // add listeners to Deferred subordinates; treat others as resolved
+ if ( length > 1 ) {
+ progressValues = new Array( length );
+ progressContexts = new Array( length );
+ resolveContexts = new Array( length );
+ for ( ; i < length; i++ ) {
+ if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
+ resolveValues[ i ].promise()
+ .progress( updateFunc( i, progressContexts, progressValues ) )
+ .done( updateFunc( i, resolveContexts, resolveValues ) )
+ .fail( deferred.reject );
+ } else {
+ --remaining;
+ }
+ }
+ }
+
+ // if we're not waiting on anything, resolve the master
+ if ( !remaining ) {
+ deferred.resolveWith( resolveContexts, resolveValues );
+ }
+
+ return deferred.promise();
+ }
+} );
+
+
+// The deferred used on DOM ready
+var readyList;
+
+jQuery.fn.ready = function( fn ) {
+
+ // Add the callback
+ jQuery.ready.promise().done( fn );
+
+ return this;
+};
+
+jQuery.extend( {
+
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
+
+ // Hold (or release) the ready event
+ holdReady: function( hold ) {
+ if ( hold ) {
+ jQuery.readyWait++;
+ } else {
+ jQuery.ready( true );
+ }
+ },
+
+ // Handle when the DOM is ready
+ ready: function( wait ) {
+
+ // Abort if there are pending holds or we're already ready
+ if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+ return;
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.resolveWith( document, [ jQuery ] );
+
+ // Trigger any bound ready events
+ if ( jQuery.fn.triggerHandler ) {
+ jQuery( document ).triggerHandler( "ready" );
+ jQuery( document ).off( "ready" );
+ }
+ }
+} );
+
+/**
+ * Clean-up method for dom ready events
+ */
+function detach() {
+ if ( document.addEventListener ) {
+ document.removeEventListener( "DOMContentLoaded", completed );
+ window.removeEventListener( "load", completed );
+
+ } else {
+ document.detachEvent( "onreadystatechange", completed );
+ window.detachEvent( "onload", completed );
+ }
+}
+
+/**
+ * The ready event handler and self cleanup method
+ */
+function completed() {
+
+ // readyState === "complete" is good enough for us to call the dom ready in oldIE
+ if ( document.addEventListener ||
+ window.event.type === "load" ||
+ document.readyState === "complete" ) {
+
+ detach();
+ jQuery.ready();
+ }
+}
+
+jQuery.ready.promise = function( obj ) {
+ if ( !readyList ) {
+
+ readyList = jQuery.Deferred();
+
+ // Catch cases where $(document).ready() is called
+ // after the browser event has already occurred.
+ // Support: IE6-10
+ // Older IE sometimes signals "interactive" too soon
+ if ( document.readyState === "complete" ||
+ ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {
+
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ window.setTimeout( jQuery.ready );
+
+ // Standards-based browsers support DOMContentLoaded
+ } else if ( document.addEventListener ) {
+
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", completed );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", completed );
+
+ // If IE event model is used
+ } else {
+
+ // Ensure firing before onload, maybe late but safe also for iframes
+ document.attachEvent( "onreadystatechange", completed );
+
+ // A fallback to window.onload, that will always work
+ window.attachEvent( "onload", completed );
+
+ // If IE and not a frame
+ // continually check to see if the document is ready
+ var top = false;
+
+ try {
+ top = window.frameElement == null && document.documentElement;
+ } catch ( e ) {}
+
+ if ( top && top.doScroll ) {
+ ( function doScrollCheck() {
+ if ( !jQuery.isReady ) {
+
+ try {
+
+ // Use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ top.doScroll( "left" );
+ } catch ( e ) {
+ return window.setTimeout( doScrollCheck, 50 );
+ }
+
+ // detach all dom ready events
+ detach();
+
+ // and execute any waiting functions
+ jQuery.ready();
+ }
+ } )();
+ }
+ }
+ }
+ return readyList.promise( obj );
+};
+
+// Kick off the DOM ready check even if the user does not
+jQuery.ready.promise();
+
+
+
+
+// Support: IE<9
+// Iteration over object's inherited properties before its own
+var i;
+for ( i in jQuery( support ) ) {
+ break;
+}
+support.ownFirst = i === "0";
+
+// Note: most support tests are defined in their respective modules.
+// false until the test is run
+support.inlineBlockNeedsLayout = false;
+
+// Execute ASAP in case we need to set body.style.zoom
+jQuery( function() {
+
+ // Minified: var a,b,c,d
+ var val, div, body, container;
+
+ body = document.getElementsByTagName( "body" )[ 0 ];
+ if ( !body || !body.style ) {
+
+ // Return for frameset docs that don't have a body
+ return;
+ }
+
+ // Setup
+ div = document.createElement( "div" );
+ container = document.createElement( "div" );
+ container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
+ body.appendChild( container ).appendChild( div );
+
+ if ( typeof div.style.zoom !== "undefined" ) {
+
+ // Support: IE<8
+ // Check if natively block-level elements act like inline-block
+ // elements when setting their display to 'inline' and giving
+ // them layout
+ div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1";
+
+ support.inlineBlockNeedsLayout = val = div.offsetWidth === 3;
+ if ( val ) {
+
+ // Prevent IE 6 from affecting layout for positioned elements #11048
+ // Prevent IE from shrinking the body in IE 7 mode #12869
+ // Support: IE<8
+ body.style.zoom = 1;
+ }
+ }
+
+ body.removeChild( container );
+} );
+
+
+( function() {
+ var div = document.createElement( "div" );
+
+ // Support: IE<9
+ support.deleteExpando = true;
+ try {
+ delete div.test;
+ } catch ( e ) {
+ support.deleteExpando = false;
+ }
+
+ // Null elements to avoid leaks in IE.
+ div = null;
+} )();
+var acceptData = function( elem ) {
+ var noData = jQuery.noData[ ( elem.nodeName + " " ).toLowerCase() ],
+ nodeType = +elem.nodeType || 1;
+
+ // Do not set data on non-element DOM nodes because it will not be cleared (#8335).
+ return nodeType !== 1 && nodeType !== 9 ?
+ false :
+
+ // Nodes accept data unless otherwise specified; rejection can be conditional
+ !noData || noData !== true && elem.getAttribute( "classid" ) === noData;
+};
+
+
+
+
+var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
+ rmultiDash = /([A-Z])/g;
+
+function dataAttr( elem, key, data ) {
+
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+
+ var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+
+ data = elem.getAttribute( name );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = data === "true" ? true :
+ data === "false" ? false :
+ data === "null" ? null :
+
+ // Only convert to a number if it doesn't change the string
+ +data + "" === data ? +data :
+ rbrace.test( data ) ? jQuery.parseJSON( data ) :
+ data;
+ } catch ( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ jQuery.data( elem, key, data );
+
+ } else {
+ data = undefined;
+ }
+ }
+
+ return data;
+}
+
+// checks a cache object for emptiness
+function isEmptyDataObject( obj ) {
+ var name;
+ for ( name in obj ) {
+
+ // if the public data object is empty, the private is still empty
+ if ( name === "data" && jQuery.isEmptyObject( obj[ name ] ) ) {
+ continue;
+ }
+ if ( name !== "toJSON" ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+function internalData( elem, name, data, pvt /* Internal Use Only */ ) {
+ if ( !acceptData( elem ) ) {
+ return;
+ }
+
+ var ret, thisCache,
+ internalKey = jQuery.expando,
+
+ // We have to handle DOM nodes and JS objects differently because IE6-7
+ // can't GC object references properly across the DOM-JS boundary
+ isNode = elem.nodeType,
+
+ // Only DOM nodes need the global jQuery cache; JS object data is
+ // attached directly to the object so GC can occur automatically
+ cache = isNode ? jQuery.cache : elem,
+
+ // Only defining an ID for JS objects if its cache already exists allows
+ // the code to shortcut on the same path as a DOM node with no cache
+ id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
+
+ // Avoid doing any more work than we need to when trying to get data on an
+ // object that has no data at all
+ if ( ( !id || !cache[ id ] || ( !pvt && !cache[ id ].data ) ) &&
+ data === undefined && typeof name === "string" ) {
+ return;
+ }
+
+ if ( !id ) {
+
+ // Only DOM nodes need a new unique ID for each element since their data
+ // ends up in the global cache
+ if ( isNode ) {
+ id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++;
+ } else {
+ id = internalKey;
+ }
+ }
+
+ if ( !cache[ id ] ) {
+
+ // Avoid exposing jQuery metadata on plain JS objects when the object
+ // is serialized using JSON.stringify
+ cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
+ }
+
+ // An object can be passed to jQuery.data instead of a key/value pair; this gets
+ // shallow copied over onto the existing cache
+ if ( typeof name === "object" || typeof name === "function" ) {
+ if ( pvt ) {
+ cache[ id ] = jQuery.extend( cache[ id ], name );
+ } else {
+ cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+ }
+ }
+
+ thisCache = cache[ id ];
+
+ // jQuery data() is stored in a separate object inside the object's internal data
+ // cache in order to avoid key collisions between internal data and user-defined
+ // data.
+ if ( !pvt ) {
+ if ( !thisCache.data ) {
+ thisCache.data = {};
+ }
+
+ thisCache = thisCache.data;
+ }
+
+ if ( data !== undefined ) {
+ thisCache[ jQuery.camelCase( name ) ] = data;
+ }
+
+ // Check for both converted-to-camel and non-converted data property names
+ // If a data property was specified
+ if ( typeof name === "string" ) {
+
+ // First Try to find as-is property data
+ ret = thisCache[ name ];
+
+ // Test for null|undefined property data
+ if ( ret == null ) {
+
+ // Try to find the camelCased property
+ ret = thisCache[ jQuery.camelCase( name ) ];
+ }
+ } else {
+ ret = thisCache;
+ }
+
+ return ret;
+}
+
+function internalRemoveData( elem, name, pvt ) {
+ if ( !acceptData( elem ) ) {
+ return;
+ }
+
+ var thisCache, i,
+ isNode = elem.nodeType,
+
+ // See jQuery.data for more information
+ cache = isNode ? jQuery.cache : elem,
+ id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+ // If there is already no cache entry for this object, there is no
+ // purpose in continuing
+ if ( !cache[ id ] ) {
+ return;
+ }
+
+ if ( name ) {
+
+ thisCache = pvt ? cache[ id ] : cache[ id ].data;
+
+ if ( thisCache ) {
+
+ // Support array or space separated string names for data keys
+ if ( !jQuery.isArray( name ) ) {
+
+ // try the string as a key before any manipulation
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+
+ // split the camel cased version by spaces unless a key with the spaces exists
+ name = jQuery.camelCase( name );
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+ name = name.split( " " );
+ }
+ }
+ } else {
+
+ // If "name" is an array of keys...
+ // When data is initially created, via ("key", "val") signature,
+ // keys will be converted to camelCase.
+ // Since there is no way to tell _how_ a key was added, remove
+ // both plain key and camelCase key. #12786
+ // This will only penalize the array argument path.
+ name = name.concat( jQuery.map( name, jQuery.camelCase ) );
+ }
+
+ i = name.length;
+ while ( i-- ) {
+ delete thisCache[ name[ i ] ];
+ }
+
+ // If there is no data left in the cache, we want to continue
+ // and let the cache object itself get destroyed
+ if ( pvt ? !isEmptyDataObject( thisCache ) : !jQuery.isEmptyObject( thisCache ) ) {
+ return;
+ }
+ }
+ }
+
+ // See jQuery.data for more information
+ if ( !pvt ) {
+ delete cache[ id ].data;
+
+ // Don't destroy the parent cache unless the internal data object
+ // had been the only thing left in it
+ if ( !isEmptyDataObject( cache[ id ] ) ) {
+ return;
+ }
+ }
+
+ // Destroy the cache
+ if ( isNode ) {
+ jQuery.cleanData( [ elem ], true );
+
+ // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
+ /* jshint eqeqeq: false */
+ } else if ( support.deleteExpando || cache != cache.window ) {
+ /* jshint eqeqeq: true */
+ delete cache[ id ];
+
+ // When all else fails, undefined
+ } else {
+ cache[ id ] = undefined;
+ }
+}
+
+jQuery.extend( {
+ cache: {},
+
+ // The following elements (space-suffixed to avoid Object.prototype collisions)
+ // throw uncatchable exceptions if you attempt to set expando properties
+ noData: {
+ "applet ": true,
+ "embed ": true,
+
+ // ...but Flash objects (which have this classid) *can* handle expandos
+ "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
+ },
+
+ hasData: function( elem ) {
+ elem = elem.nodeType ? jQuery.cache[ elem[ jQuery.expando ] ] : elem[ jQuery.expando ];
+ return !!elem && !isEmptyDataObject( elem );
+ },
+
+ data: function( elem, name, data ) {
+ return internalData( elem, name, data );
+ },
+
+ removeData: function( elem, name ) {
+ return internalRemoveData( elem, name );
+ },
+
+ // For internal use only.
+ _data: function( elem, name, data ) {
+ return internalData( elem, name, data, true );
+ },
+
+ _removeData: function( elem, name ) {
+ return internalRemoveData( elem, name, true );
+ }
+} );
+
+jQuery.fn.extend( {
+ data: function( key, value ) {
+ var i, name, data,
+ elem = this[ 0 ],
+ attrs = elem && elem.attributes;
+
+ // Special expections of .data basically thwart jQuery.access,
+ // so implement the relevant behavior ourselves
+
+ // Gets all values
+ if ( key === undefined ) {
+ if ( this.length ) {
+ data = jQuery.data( elem );
+
+ if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+ i = attrs.length;
+ while ( i-- ) {
+
+ // Support: IE11+
+ // The attrs elements can be null (#14894)
+ if ( attrs[ i ] ) {
+ name = attrs[ i ].name;
+ if ( name.indexOf( "data-" ) === 0 ) {
+ name = jQuery.camelCase( name.slice( 5 ) );
+ dataAttr( elem, name, data[ name ] );
+ }
+ }
+ }
+ jQuery._data( elem, "parsedAttrs", true );
+ }
+ }
+
+ return data;
+ }
+
+ // Sets multiple values
+ if ( typeof key === "object" ) {
+ return this.each( function() {
+ jQuery.data( this, key );
+ } );
+ }
+
+ return arguments.length > 1 ?
+
+ // Sets one value
+ this.each( function() {
+ jQuery.data( this, key, value );
+ } ) :
+
+ // Gets one value
+ // Try to fetch any internally stored data first
+ elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined;
+ },
+
+ removeData: function( key ) {
+ return this.each( function() {
+ jQuery.removeData( this, key );
+ } );
+ }
+} );
+
+
+jQuery.extend( {
+ queue: function( elem, type, data ) {
+ var queue;
+
+ if ( elem ) {
+ type = ( type || "fx" ) + "queue";
+ queue = jQuery._data( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( data ) {
+ if ( !queue || jQuery.isArray( data ) ) {
+ queue = jQuery._data( elem, type, jQuery.makeArray( data ) );
+ } else {
+ queue.push( data );
+ }
+ }
+ return queue || [];
+ }
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ startLength = queue.length,
+ fn = queue.shift(),
+ hooks = jQuery._queueHooks( elem, type ),
+ next = function() {
+ jQuery.dequeue( elem, type );
+ };
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ startLength--;
+ }
+
+ if ( fn ) {
+
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift( "inprogress" );
+ }
+
+ // clear up the last queue stop function
+ delete hooks.stop;
+ fn.call( elem, next, hooks );
+ }
+
+ if ( !startLength && hooks ) {
+ hooks.empty.fire();
+ }
+ },
+
+ // not intended for public consumption - generates a queueHooks object,
+ // or returns the current one
+ _queueHooks: function( elem, type ) {
+ var key = type + "queueHooks";
+ return jQuery._data( elem, key ) || jQuery._data( elem, key, {
+ empty: jQuery.Callbacks( "once memory" ).add( function() {
+ jQuery._removeData( elem, type + "queue" );
+ jQuery._removeData( elem, key );
+ } )
+ } );
+ }
+} );
+
+jQuery.fn.extend( {
+ queue: function( type, data ) {
+ var setter = 2;
+
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ setter--;
+ }
+
+ if ( arguments.length < setter ) {
+ return jQuery.queue( this[ 0 ], type );
+ }
+
+ return data === undefined ?
+ this :
+ this.each( function() {
+ var queue = jQuery.queue( this, type, data );
+
+ // ensure a hooks for this queue
+ jQuery._queueHooks( this, type );
+
+ if ( type === "fx" && queue[ 0 ] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ } );
+ },
+ dequeue: function( type ) {
+ return this.each( function() {
+ jQuery.dequeue( this, type );
+ } );
+ },
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ },
+
+ // Get a promise resolved when queues of a certain type
+ // are emptied (fx is the type by default)
+ promise: function( type, obj ) {
+ var tmp,
+ count = 1,
+ defer = jQuery.Deferred(),
+ elements = this,
+ i = this.length,
+ resolve = function() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ };
+
+ if ( typeof type !== "string" ) {
+ obj = type;
+ type = undefined;
+ }
+ type = type || "fx";
+
+ while ( i-- ) {
+ tmp = jQuery._data( elements[ i ], type + "queueHooks" );
+ if ( tmp && tmp.empty ) {
+ count++;
+ tmp.empty.add( resolve );
+ }
+ }
+ resolve();
+ return defer.promise( obj );
+ }
+} );
+
+
+( function() {
+ var shrinkWrapBlocksVal;
+
+ support.shrinkWrapBlocks = function() {
+ if ( shrinkWrapBlocksVal != null ) {
+ return shrinkWrapBlocksVal;
+ }
+
+ // Will be changed later if needed.
+ shrinkWrapBlocksVal = false;
+
+ // Minified: var b,c,d
+ var div, body, container;
+
+ body = document.getElementsByTagName( "body" )[ 0 ];
+ if ( !body || !body.style ) {
+
+ // Test fired too early or in an unsupported environment, exit.
+ return;
+ }
+
+ // Setup
+ div = document.createElement( "div" );
+ container = document.createElement( "div" );
+ container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
+ body.appendChild( container ).appendChild( div );
+
+ // Support: IE6
+ // Check if elements with layout shrink-wrap their children
+ if ( typeof div.style.zoom !== "undefined" ) {
+
+ // Reset CSS: box-sizing; display; margin; border
+ div.style.cssText =
+
+ // Support: Firefox<29, Android 2.3
+ // Vendor-prefix box-sizing
+ "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
+ "box-sizing:content-box;display:block;margin:0;border:0;" +
+ "padding:1px;width:1px;zoom:1";
+ div.appendChild( document.createElement( "div" ) ).style.width = "5px";
+ shrinkWrapBlocksVal = div.offsetWidth !== 3;
+ }
+
+ body.removeChild( container );
+
+ return shrinkWrapBlocksVal;
+ };
+
+} )();
+var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source;
+
+var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );
+
+
+var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
+
+var isHidden = function( elem, el ) {
+
+ // isHidden might be called from jQuery#filter function;
+ // in that case, element will be second argument
+ elem = el || elem;
+ return jQuery.css( elem, "display" ) === "none" ||
+ !jQuery.contains( elem.ownerDocument, elem );
+ };
+
+
+
+function adjustCSS( elem, prop, valueParts, tween ) {
+ var adjusted,
+ scale = 1,
+ maxIterations = 20,
+ currentValue = tween ?
+ function() { return tween.cur(); } :
+ function() { return jQuery.css( elem, prop, "" ); },
+ initial = currentValue(),
+ unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+ // Starting value computation is required for potential unit mismatches
+ initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
+ rcssNum.exec( jQuery.css( elem, prop ) );
+
+ if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
+
+ // Trust units reported by jQuery.css
+ unit = unit || initialInUnit[ 3 ];
+
+ // Make sure we update the tween properties later on
+ valueParts = valueParts || [];
+
+ // Iteratively approximate from a nonzero starting point
+ initialInUnit = +initial || 1;
+
+ do {
+
+ // If previous iteration zeroed out, double until we get *something*.
+ // Use string for doubling so we don't accidentally see scale as unchanged below
+ scale = scale || ".5";
+
+ // Adjust and apply
+ initialInUnit = initialInUnit / scale;
+ jQuery.style( elem, prop, initialInUnit + unit );
+
+ // Update scale, tolerating zero or NaN from tween.cur()
+ // Break the loop if scale is unchanged or perfect, or if we've just had enough.
+ } while (
+ scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations
+ );
+ }
+
+ if ( valueParts ) {
+ initialInUnit = +initialInUnit || +initial || 0;
+
+ // Apply relative offset (+=/-=) if specified
+ adjusted = valueParts[ 1 ] ?
+ initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :
+ +valueParts[ 2 ];
+ if ( tween ) {
+ tween.unit = unit;
+ tween.start = initialInUnit;
+ tween.end = adjusted;
+ }
+ }
+ return adjusted;
+}
+
+
+// Multifunctional method to get and set values of a collection
+// The value/s can optionally be executed if it's a function
+var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
+ var i = 0,
+ length = elems.length,
+ bulk = key == null;
+
+ // Sets many values
+ if ( jQuery.type( key ) === "object" ) {
+ chainable = true;
+ for ( i in key ) {
+ access( elems, fn, i, key[ i ], true, emptyGet, raw );
+ }
+
+ // Sets one value
+ } else if ( value !== undefined ) {
+ chainable = true;
+
+ if ( !jQuery.isFunction( value ) ) {
+ raw = true;
+ }
+
+ if ( bulk ) {
+
+ // Bulk operations run against the entire set
+ if ( raw ) {
+ fn.call( elems, value );
+ fn = null;
+
+ // ...except when executing function values
+ } else {
+ bulk = fn;
+ fn = function( elem, key, value ) {
+ return bulk.call( jQuery( elem ), value );
+ };
+ }
+ }
+
+ if ( fn ) {
+ for ( ; i < length; i++ ) {
+ fn(
+ elems[ i ],
+ key,
+ raw ? value : value.call( elems[ i ], i, fn( elems[ i ], key ) )
+ );
+ }
+ }
+ }
+
+ return chainable ?
+ elems :
+
+ // Gets
+ bulk ?
+ fn.call( elems ) :
+ length ? fn( elems[ 0 ], key ) : emptyGet;
+};
+var rcheckableType = ( /^(?:checkbox|radio)$/i );
+
+var rtagName = ( /<([\w:-]+)/ );
+
+var rscriptType = ( /^$|\/(?:java|ecma)script/i );
+
+var rleadingWhitespace = ( /^\s+/ );
+
+var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|" +
+ "details|dialog|figcaption|figure|footer|header|hgroup|main|" +
+ "mark|meter|nav|output|picture|progress|section|summary|template|time|video";
+
+
+
+function createSafeFragment( document ) {
+ var list = nodeNames.split( "|" ),
+ safeFrag = document.createDocumentFragment();
+
+ if ( safeFrag.createElement ) {
+ while ( list.length ) {
+ safeFrag.createElement(
+ list.pop()
+ );
+ }
+ }
+ return safeFrag;
+}
+
+
+( function() {
+ var div = document.createElement( "div" ),
+ fragment = document.createDocumentFragment(),
+ input = document.createElement( "input" );
+
+ // Setup
+ div.innerHTML = "
a";
+
+ // IE strips leading whitespace when .innerHTML is used
+ support.leadingWhitespace = div.firstChild.nodeType === 3;
+
+ // Make sure that tbody elements aren't automatically inserted
+ // IE will insert them into empty tables
+ support.tbody = !div.getElementsByTagName( "tbody" ).length;
+
+ // Make sure that link elements get serialized correctly by innerHTML
+ // This requires a wrapper element in IE
+ support.htmlSerialize = !!div.getElementsByTagName( "link" ).length;
+
+ // Makes sure cloning an html5 element does not cause problems
+ // Where outerHTML is undefined, this still works
+ support.html5Clone =
+ document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav>";
+
+ // Check if a disconnected checkbox will retain its checked
+ // value of true after appended to the DOM (IE6/7)
+ input.type = "checkbox";
+ input.checked = true;
+ fragment.appendChild( input );
+ support.appendChecked = input.checked;
+
+ // Make sure textarea (and checkbox) defaultValue is properly cloned
+ // Support: IE6-IE11+
+ div.innerHTML = "";
+ support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
+
+ // #11217 - WebKit loses check when the name is after the checked attribute
+ fragment.appendChild( div );
+
+ // Support: Windows Web Apps (WWA)
+ // `name` and `type` must use .setAttribute for WWA (#14901)
+ input = document.createElement( "input" );
+ input.setAttribute( "type", "radio" );
+ input.setAttribute( "checked", "checked" );
+ input.setAttribute( "name", "t" );
+
+ div.appendChild( input );
+
+ // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
+ // old WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Support: IE<9
+ // Cloned elements keep attachEvent handlers, we use addEventListener on IE9+
+ support.noCloneEvent = !!div.addEventListener;
+
+ // Support: IE<9
+ // Since attributes and properties are the same in IE,
+ // cleanData must set properties to undefined rather than use removeAttribute
+ div[ jQuery.expando ] = 1;
+ support.attributes = !div.getAttribute( jQuery.expando );
+} )();
+
+
+// We have to close these tags to support XHTML (#13200)
+var wrapMap = {
+ option: [ 1, "" ],
+ legend: [ 1, "" ],
+ area: [ 1, "" ],
+
+ // Support: IE8
+ param: [ 1, "" ],
+ thead: [ 1, "
", "
" ],
+ tr: [ 2, "
", "
" ],
+ col: [ 2, "
", "
" ],
+ td: [ 3, "
", "
" ],
+
+ // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
+ // unless wrapped in a div with non-breaking characters in front of it.
+ _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
", "
" ]
+};
+
+// Support: IE8-IE9
+wrapMap.optgroup = wrapMap.option;
+
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+
+function getAll( context, tag ) {
+ var elems, elem,
+ i = 0,
+ found = typeof context.getElementsByTagName !== "undefined" ?
+ context.getElementsByTagName( tag || "*" ) :
+ typeof context.querySelectorAll !== "undefined" ?
+ context.querySelectorAll( tag || "*" ) :
+ undefined;
+
+ if ( !found ) {
+ for ( found = [], elems = context.childNodes || context;
+ ( elem = elems[ i ] ) != null;
+ i++
+ ) {
+ if ( !tag || jQuery.nodeName( elem, tag ) ) {
+ found.push( elem );
+ } else {
+ jQuery.merge( found, getAll( elem, tag ) );
+ }
+ }
+ }
+
+ return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
+ jQuery.merge( [ context ], found ) :
+ found;
+}
+
+
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+ var elem,
+ i = 0;
+ for ( ; ( elem = elems[ i ] ) != null; i++ ) {
+ jQuery._data(
+ elem,
+ "globalEval",
+ !refElements || jQuery._data( refElements[ i ], "globalEval" )
+ );
+ }
+}
+
+
+var rhtml = /<|?\w+;/,
+ rtbody = / from table fragments
+ if ( !support.tbody ) {
+
+ // String was a
, *may* have spurious
+ elem = tag === "table" && !rtbody.test( elem ) ?
+ tmp.firstChild :
+
+ // String was a bare or
+ wrap[ 1 ] === "
" && !rtbody.test( elem ) ?
+ tmp :
+ 0;
+
+ j = elem && elem.childNodes.length;
+ while ( j-- ) {
+ if ( jQuery.nodeName( ( tbody = elem.childNodes[ j ] ), "tbody" ) &&
+ !tbody.childNodes.length ) {
+
+ elem.removeChild( tbody );
+ }
+ }
+ }
+
+ jQuery.merge( nodes, tmp.childNodes );
+
+ // Fix #12392 for WebKit and IE > 9
+ tmp.textContent = "";
+
+ // Fix #12392 for oldIE
+ while ( tmp.firstChild ) {
+ tmp.removeChild( tmp.firstChild );
+ }
+
+ // Remember the top-level container for proper cleanup
+ tmp = safe.lastChild;
+ }
+ }
+ }
+
+ // Fix #11356: Clear elements from fragment
+ if ( tmp ) {
+ safe.removeChild( tmp );
+ }
+
+ // Reset defaultChecked for any radios and checkboxes
+ // about to be appended to the DOM in IE 6/7 (#8060)
+ if ( !support.appendChecked ) {
+ jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
+ }
+
+ i = 0;
+ while ( ( elem = nodes[ i++ ] ) ) {
+
+ // Skip elements already in the context collection (trac-4087)
+ if ( selection && jQuery.inArray( elem, selection ) > -1 ) {
+ if ( ignored ) {
+ ignored.push( elem );
+ }
+
+ continue;
+ }
+
+ contains = jQuery.contains( elem.ownerDocument, elem );
+
+ // Append to fragment
+ tmp = getAll( safe.appendChild( elem ), "script" );
+
+ // Preserve script evaluation history
+ if ( contains ) {
+ setGlobalEval( tmp );
+ }
+
+ // Capture executables
+ if ( scripts ) {
+ j = 0;
+ while ( ( elem = tmp[ j++ ] ) ) {
+ if ( rscriptType.test( elem.type || "" ) ) {
+ scripts.push( elem );
+ }
+ }
+ }
+ }
+
+ tmp = null;
+
+ return safe;
+}
+
+
+( function() {
+ var i, eventName,
+ div = document.createElement( "div" );
+
+ // Support: IE<9 (lack submit/change bubble), Firefox (lack focus(in | out) events)
+ for ( i in { submit: true, change: true, focusin: true } ) {
+ eventName = "on" + i;
+
+ if ( !( support[ i ] = eventName in window ) ) {
+
+ // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
+ div.setAttribute( eventName, "t" );
+ support[ i ] = div.attributes[ eventName ].expando === false;
+ }
+ }
+
+ // Null elements to avoid leaks in IE.
+ div = null;
+} )();
+
+
+var rformElems = /^(?:input|select|textarea)$/i,
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
+
+function returnTrue() {
+ return true;
+}
+
+function returnFalse() {
+ return false;
+}
+
+// Support: IE9
+// See #13393 for more info
+function safeActiveElement() {
+ try {
+ return document.activeElement;
+ } catch ( err ) { }
+}
+
+function on( elem, types, selector, data, fn, one ) {
+ var origFn, type;
+
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) {
+
+ // ( types-Object, data )
+ data = data || selector;
+ selector = undefined;
+ }
+ for ( type in types ) {
+ on( elem, type, selector, data, types[ type ], one );
+ }
+ return elem;
+ }
+
+ if ( data == null && fn == null ) {
+
+ // ( types, fn )
+ fn = selector;
+ data = selector = undefined;
+ } else if ( fn == null ) {
+ if ( typeof selector === "string" ) {
+
+ // ( types, selector, fn )
+ fn = data;
+ data = undefined;
+ } else {
+
+ // ( types, data, fn )
+ fn = data;
+ data = selector;
+ selector = undefined;
+ }
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ } else if ( !fn ) {
+ return elem;
+ }
+
+ if ( one === 1 ) {
+ origFn = fn;
+ fn = function( event ) {
+
+ // Can use an empty set, since event contains the info
+ jQuery().off( event );
+ return origFn.apply( this, arguments );
+ };
+
+ // Use same guid so caller can remove using origFn
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+ }
+ return elem.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ } );
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+ global: {},
+
+ add: function( elem, types, handler, data, selector ) {
+ var tmp, events, t, handleObjIn,
+ special, eventHandle, handleObj,
+ handlers, type, namespaces, origType,
+ elemData = jQuery._data( elem );
+
+ // Don't attach events to noData or text/comment nodes (but allow plain objects)
+ if ( !elemData ) {
+ return;
+ }
+
+ // Caller can pass in an object of custom data in lieu of the handler
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ selector = handleObjIn.selector;
+ }
+
+ // Make sure that the handler has a unique ID, used to find/remove it later
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure and main handler, if this is the first
+ if ( !( events = elemData.events ) ) {
+ events = elemData.events = {};
+ }
+ if ( !( eventHandle = elemData.handle ) ) {
+ eventHandle = elemData.handle = function( e ) {
+
+ // Discard the second event of a jQuery.event.trigger() and
+ // when an event is called after a page has unloaded
+ return typeof jQuery !== "undefined" &&
+ ( !e || jQuery.event.triggered !== e.type ) ?
+ jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
+ undefined;
+ };
+
+ // Add elem as a property of the handle fn to prevent a memory leak
+ // with IE non-native events
+ eventHandle.elem = elem;
+ }
+
+ // Handle multiple events separated by a space
+ types = ( types || "" ).match( rnotwhite ) || [ "" ];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[ t ] ) || [];
+ type = origType = tmp[ 1 ];
+ namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
+
+ // There *must* be a type, no attaching namespace-only handlers
+ if ( !type ) {
+ continue;
+ }
+
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
+
+ // If selector defined, determine special event api type, otherwise given type
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+
+ // Update special based on newly reset type
+ special = jQuery.event.special[ type ] || {};
+
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend( {
+ type: type,
+ origType: origType,
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+ namespace: namespaces.join( "." )
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ if ( !( handlers = events[ type ] ) ) {
+ handlers = events[ type ] = [];
+ handlers.delegateCount = 0;
+
+ // Only use addEventListener/attachEvent if the special events handler returns false
+ if ( !special.setup ||
+ special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+
+ // Bind the global event handler to the element
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle, false );
+
+ } else if ( elem.attachEvent ) {
+ elem.attachEvent( "on" + type, eventHandle );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
+
+ // Keep track of which events have ever been used, for event optimization
+ jQuery.event.global[ type ] = true;
+ }
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, selector, mappedTypes ) {
+ var j, handleObj, tmp,
+ origCount, t, events,
+ special, handlers, type,
+ namespaces, origType,
+ elemData = jQuery.hasData( elem ) && jQuery._data( elem );
+
+ if ( !elemData || !( events = elemData.events ) ) {
+ return;
+ }
+
+ // Once for each type.namespace in types; type may be omitted
+ types = ( types || "" ).match( rnotwhite ) || [ "" ];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[ t ] ) || [];
+ type = origType = tmp[ 1 ];
+ namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
+
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+ }
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+ handlers = events[ type ] || [];
+ tmp = tmp[ 2 ] &&
+ new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );
+
+ // Remove matching events
+ origCount = j = handlers.length;
+ while ( j-- ) {
+ handleObj = handlers[ j ];
+
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !tmp || tmp.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector ||
+ selector === "**" && handleObj.selector ) ) {
+ handlers.splice( j, 1 );
+
+ if ( handleObj.selector ) {
+ handlers.delegateCount--;
+ }
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+ }
+
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( origCount && !handlers.length ) {
+ if ( !special.teardown ||
+ special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ delete elemData.handle;
+
+ // removeData also checks for emptiness and clears the expando if empty
+ // so use it instead of delete
+ jQuery._removeData( elem, "events" );
+ }
+ },
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+ var handle, ontype, cur,
+ bubbleType, special, tmp, i,
+ eventPath = [ elem || document ],
+ type = hasOwn.call( event, "type" ) ? event.type : event,
+ namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];
+
+ cur = tmp = elem = elem || document;
+
+ // Don't do events on text and comment nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
+ }
+
+ if ( type.indexOf( "." ) > -1 ) {
+
+ // Namespaced trigger; create a regexp to match event type in handle()
+ namespaces = type.split( "." );
+ type = namespaces.shift();
+ namespaces.sort();
+ }
+ ontype = type.indexOf( ":" ) < 0 && "on" + type;
+
+ // Caller can pass in a jQuery.Event object, Object, or just an event type string
+ event = event[ jQuery.expando ] ?
+ event :
+ new jQuery.Event( type, typeof event === "object" && event );
+
+ // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
+ event.isTrigger = onlyHandlers ? 2 : 3;
+ event.namespace = namespaces.join( "." );
+ event.rnamespace = event.namespace ?
+ new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) :
+ null;
+
+ // Clean up the event in case it is being reused
+ event.result = undefined;
+ if ( !event.target ) {
+ event.target = elem;
+ }
+
+ // Clone any incoming data and prepend the event, creating the handler arg list
+ data = data == null ?
+ [ event ] :
+ jQuery.makeArray( data, [ event ] );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ if ( !rfocusMorph.test( bubbleType + type ) ) {
+ cur = cur.parentNode;
+ }
+ for ( ; cur; cur = cur.parentNode ) {
+ eventPath.push( cur );
+ tmp = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( tmp === ( elem.ownerDocument || document ) ) {
+ eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+ }
+ }
+
+ // Fire handlers on the event path
+ i = 0;
+ while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {
+
+ event.type = i > 1 ?
+ bubbleType :
+ special.bindType || type;
+
+ // jQuery handler
+ handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] &&
+ jQuery._data( cur, "handle" );
+
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+
+ // Native handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && handle.apply && acceptData( cur ) ) {
+ event.result = handle.apply( cur, data );
+ if ( event.result === false ) {
+ event.preventDefault();
+ }
+ }
+ }
+ event.type = type;
+
+ // If nobody prevented the default action, do it now
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+ if (
+ ( !special._default ||
+ special._default.apply( eventPath.pop(), data ) === false
+ ) && acceptData( elem )
+ ) {
+
+ // Call a native DOM method on the target with the same name name as the event.
+ // Can't use an .isFunction() check here because IE6/7 fails that test.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ tmp = elem[ ontype ];
+
+ if ( tmp ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+ try {
+ elem[ type ]();
+ } catch ( e ) {
+
+ // IE<9 dies on focus/blur to hidden element (#1486,#12518)
+ // only reproducible on winXP IE8 native, not IE9 in IE8 mode
+ }
+ jQuery.event.triggered = undefined;
+
+ if ( tmp ) {
+ elem[ ontype ] = tmp;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ dispatch: function( event ) {
+
+ // Make a writable jQuery.Event from the native event object
+ event = jQuery.event.fix( event );
+
+ var i, j, ret, matched, handleObj,
+ handlerQueue = [],
+ args = slice.call( arguments ),
+ handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
+ special = jQuery.event.special[ event.type ] || {};
+
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
+ args[ 0 ] = event;
+ event.delegateTarget = this;
+
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ return;
+ }
+
+ // Determine handlers
+ handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+ // Run delegates first; they may want to stop propagation beneath us
+ i = 0;
+ while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
+ event.currentTarget = matched.elem;
+
+ j = 0;
+ while ( ( handleObj = matched.handlers[ j++ ] ) &&
+ !event.isImmediatePropagationStopped() ) {
+
+ // Triggered event must either 1) have no namespace, or 2) have namespace(s)
+ // a subset or equal to those in the bound event (both can have no namespace).
+ if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) {
+
+ event.handleObj = handleObj;
+ event.data = handleObj.data;
+
+ ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
+ handleObj.handler ).apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ if ( ( event.result = ret ) === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+ }
+ }
+
+ // Call the postDispatch hook for the mapped type
+ if ( special.postDispatch ) {
+ special.postDispatch.call( this, event );
+ }
+
+ return event.result;
+ },
+
+ handlers: function( event, handlers ) {
+ var i, matches, sel, handleObj,
+ handlerQueue = [],
+ delegateCount = handlers.delegateCount,
+ cur = event.target;
+
+ // Support (at least): Chrome, IE9
+ // Find delegate handlers
+ // Black-hole SVG
"},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){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","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&&(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.findBestRelativePosition(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(){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,inForm:E,hide:B,focus:C,remove:D}}}),g("n",["s"],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",["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("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")()}();
diff --git a/public/assets/tinymce/themes/inlite/theme-24ec9fa4b7330913ca96f683fcfcdcdfa43714f91e8bba74bfbdfdf01cb63324.js.gz b/public/assets/tinymce/themes/inlite/theme-24ec9fa4b7330913ca96f683fcfcdcdfa43714f91e8bba74bfbdfdf01cb63324.js.gz
new file mode 100644
index 00000000..d6ef3fdc
Binary files /dev/null and b/public/assets/tinymce/themes/inlite/theme-24ec9fa4b7330913ca96f683fcfcdcdfa43714f91e8bba74bfbdfdf01cb63324.js.gz differ
diff --git a/public/assets/tinymce/themes/inlite/theme.js b/public/assets/tinymce/themes/inlite/theme.js
index 7bb9f676..bbd0a081 120000
--- a/public/assets/tinymce/themes/inlite/theme.js
+++ b/public/assets/tinymce/themes/inlite/theme.js
@@ -1 +1 @@
-theme-a400085213d427d78d8a1e35089ae6cd00831e51d33a3342a198d1bc62851640.js
\ No newline at end of file
+theme-24ec9fa4b7330913ca96f683fcfcdcdfa43714f91e8bba74bfbdfdf01cb63324.js
\ No newline at end of file
diff --git a/public/assets/tinymce/themes/inlite/theme.js.gz b/public/assets/tinymce/themes/inlite/theme.js.gz
index abc943c4..d393e4df 120000
--- a/public/assets/tinymce/themes/inlite/theme.js.gz
+++ b/public/assets/tinymce/themes/inlite/theme.js.gz
@@ -1 +1 @@
-theme-a400085213d427d78d8a1e35089ae6cd00831e51d33a3342a198d1bc62851640.js.gz
\ No newline at end of file
+theme-24ec9fa4b7330913ca96f683fcfcdcdfa43714f91e8bba74bfbdfdf01cb63324.js.gz
\ No newline at end of file
diff --git a/public/assets/tinymce/themes/modern/theme-4547e25369b8acbbc7101f29494cfd7d289c31d221eb99d0b9d5f340ef3af240.js b/public/assets/tinymce/themes/modern/theme-4547e25369b8acbbc7101f29494cfd7d289c31d221eb99d0b9d5f340ef3af240.js
new file mode 100644
index 00000000..e950b5d8
--- /dev/null
+++ b/public/assets/tinymce/themes/modern/theme-4547e25369b8acbbc7101f29494cfd7d289c31d221eb99d0b9d5f340ef3af240.js
@@ -0,0 +1 @@
+!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=0;c--)for(d=f.length-1;d>=0;d--)if(f[d].predicate(e[c]))return{toolbar:f[d],element:e[c]};return null};a.on("click keyup setContent ObjectResized",function(b){("setcontent"!==b.type||b.selection)&&c.setEditorTimeout(a,function(){var b;b=u(a.selection.getNode()),b?(t(),s(b)):t()})}),a.on("blur hide contextmenu",t),a.on("ObjectResizeStart",function(){var b=u(a.selection.getNode());b&&b.toolbar.panel&&b.toolbar.panel.hide()}),a.on("ResizeEditor ResizeWindow",q(!0)),a.on("nodeChange",q(!1)),a.on("remove",function(){b.each(n(),function(a){a.panel&&a.panel.remove()}),a.contextToolbars={}}),a.shortcuts.add("ctrl+shift+e > ctrl+shift+p","",function(){var b=u(a.selection.getNode());b&&b.toolbar.panel&&b.toolbar.panel.items()[0].focus()})};return{addContextualToolbars:m}}),g("h",["d"],function(a){var b={file:{title:"File",items:"newdocument"},edit:{title:"Edit",items:"undo redo | cut copy paste pastetext | selectall"},insert:{title:"Insert",items:"|"},view:{title:"View",items:"visualaid |"},format:{title:"Format",items:"bold italic underline strikethrough superscript subscript | formats | removeformat"},table:{title:"Table"},tools:{title:"Tools"}},c=function(a,b){var c;return"|"==b?{text:"|"}:c=a[b]},d=function(d,e,f){var g,h,i,j,k;if(k=a.makeMap((e.removed_menuitems||"").split(/[ ,]/)),e.menu?(h=e.menu[f],j=!0):h=b[f],h){g={text:h.title},i=[],a.each((h.items||"").split(/[ ,]/),function(a){var b=c(d,a);b&&!k[a]&&i.push(c(d,a))}),j||a.each(d,function(a){a.context==f&&("before"==a.separator&&i.push({text:"|"}),a.prependToContext?i.unshift(a):i.push(a),"after"==a.separator&&i.push({text:"|"}))});for(var l=0;l=11},k=function(a){return!(!j()||!a.sidebars)&&a.sidebars.length>0},l=function(b){var c=a.map(b.sidebars,function(a){var c=a.settings;return{type:"button",icon:c.icon,image:c.image,tooltip:c.tooltip,onclick:i(b,a.name,b.sidebars)}});return{type:"panel",name:"sidebar",layout:"stack",classes:"sidebar",items:[{type:"toolbar",layout:"stack",classes:"sidebar-toolbar",items:c}]}};return{hasSidebar:k,createSidebar:l}}),g("j",[],function(){var a=function(a){var b=function(){a._skinLoaded=!0,a.fire("SkinLoaded")};return function(){a.initialized?b():a.on("init",b)}};return{fireSkinLoaded:a}}),g("6",["b","c","d","e","f","g","h","9","i","j","k"],function(a,b,c,d,e,f,g,h,i,j,k){var l=a.DOM,m=function(a){return function(b){a.find("*").disabled("readonly"===b.mode)}},n=function(a){return{type:"panel",name:"iframe",layout:"stack",classes:"edit-area",border:a,html:""}},o=function(a){return{type:"panel",layout:"stack",classes:"edit-aria-container",border:"1 0 0 0",items:[n("0"),i.createSidebar(a)]}},p=function(a,c,p){var q,r,s,t=a.settings;return p.skinUiCss&&l.styleSheetLoader.load(p.skinUiCss,j.fireSkinLoaded(a)),q=c.panel=b.create({type:"panel",role:"application",classes:"tinymce",style:"visibility: hidden",layout:"stack",border:1,items:[t.menubar===!1?null:{type:"menubar",border:"0 0 1 0",items:g.createMenuButtons(a)},k.createToolbars(a,t.toolbar_items_size),i.hasSidebar(a)?o(a):n("1 0 0 0")]}),t.resize!==!1&&(r={type:"resizehandle",direction:t.resize,onResizeStart:function(){var b=a.getContentAreaContainer().firstChild;s={width:b.clientWidth,height:b.clientHeight}},onResize:function(b){"both"===t.resize?h.resizeTo(a,s.width+b.deltaX,s.height+b.deltaY):h.resizeTo(a,null,s.height+b.deltaY)}}),t.statusbar!==!1&&q.add({type:"panel",name:"statusbar",classes:"statusbar",layout:"flow",border:"1 0 0 0",ariaRoot:!0,items:[{type:"elementpath",editor:a},r]}),a.fire("BeforeRenderUI"),a.on("SwitchMode",m(q)),q.renderBefore(p.targetNode).reflow(),t.readonly&&a.setMode("readonly"),p.width&&l.setStyle(q.getEl(),"width",p.width),a.on("remove",function(){q.remove(),q=null}),d.addKeys(a,q),f.addContextualToolbars(a),e.setup(a),{iframeContainer:q.find("#iframe")[0].getEl(),editorContainer:q.getEl()}};return{render:p}}),g("l",["a"],function(a){return a("tinymce.ui.FloatPanel")}),g("7",["d","c","b","l","k","h","g","e","j"],function(a,b,c,d,e,f,g,h,i){var j=function(a,j,k){var l,m,n=a.settings,o=c.DOM;n.fixed_toolbar_container&&(m=o.select(n.fixed_toolbar_container)[0]);var p=function(){if(l&&l.moveRel&&l.visible()&&!l._fixed){var b=a.selection.getScrollContainer(),c=a.getBody(),d=0,e=0;if(b){var f=o.getPos(c),g=o.getPos(b);d=Math.max(0,g.x-f.x),e=Math.max(0,g.y-f.y)}l.fixed(!1).moveRel(c,a.rtl?["tr-br","br-tr"]:["tl-bl","bl-tl","tr-br"]).moveBy(d,e)}},q=function(){l&&(l.show(),p(),o.addClass(a.getBody(),"mce-edit-focus"))},r=function(){l&&(l.hide(),d.hideAll(),o.removeClass(a.getBody(),"mce-edit-focus"))},s=function(){return l?void(l.visible()||q()):(l=j.panel=b.create({type:m?"panel":"floatpanel",role:"application",classes:"tinymce tinymce-inline",layout:"flex",direction:"column",align:"stretch",autohide:!1,autofix:!0,fixed:!!m,border:1,items:[n.menubar===!1?null:{type:"menubar",border:"0 0 1 0",items:f.createMenuButtons(a)},e.createToolbars(a,n.toolbar_items_size)]}),a.fire("BeforeRenderUI"),l.renderTo(m||document.body).reflow(),h.addKeys(a,l),q(),g.addContextualToolbars(a),a.on("nodeChange",p),a.on("activate",q),a.on("deactivate",r),void a.nodeChanged())};return n.content_editable=!0,a.on("focus",function(){k.skinUiCss?o.styleSheetLoader.load(k.skinUiCss,s,s):s()}),a.on("blur hide",r),a.on("remove",function(){l&&(l.remove(),l=null)}),k.skinUiCss&&o.styleSheetLoader.load(k.skinUiCss,i.fireSkinLoaded(a)),{}};return{render:j}}),g("m",["a"],function(a){return a("tinymce.ui.Throbber")}),g("8",["m"],function(a){var b=function(b,c){var d;b.on("ProgressState",function(b){d=d||new a(c.panel.getEl("body")),b.state?d.show(b.time):d.hide()})};return{setup:b}}),g("0",["1","2","3","4","5","6","7","8","9"],function(a,b,c,d,e,f,g,h,i){var j=b.ThemeManager;e.appendTo(a.tinymce?a.tinymce:{});var k=function(a,b,d){var e=a.settings,i=e.skin!==!1&&(e.skin||"lightgray");if(i){var j=e.skin_url;j=j?a.documentBaseURI.toAbsolute(j):c.baseURL+"/skins/"+i,d.skinUiCss=j+"/skin.min.css",a.contentCSS.push(j+"/content"+(a.inline?".inline":"")+".min.css")}return h.setup(a,b),e.inline?g.render(a,b,d):f.render(a,b,d)};return j.add("modern",function(a){return{renderUI:function(b){return k(a,this,b)},resizeTo:function(b,c){return i.resizeTo(a,b,c)},resizeBy:function(b,c){return i.resizeBy(a,b,c)}}}),function(){}}),d("0")()}();
diff --git a/public/assets/tinymce/themes/modern/theme-4547e25369b8acbbc7101f29494cfd7d289c31d221eb99d0b9d5f340ef3af240.js.gz b/public/assets/tinymce/themes/modern/theme-4547e25369b8acbbc7101f29494cfd7d289c31d221eb99d0b9d5f340ef3af240.js.gz
new file mode 100644
index 00000000..c08e4c29
Binary files /dev/null and b/public/assets/tinymce/themes/modern/theme-4547e25369b8acbbc7101f29494cfd7d289c31d221eb99d0b9d5f340ef3af240.js.gz differ
diff --git a/public/assets/tinymce/themes/modern/theme.js b/public/assets/tinymce/themes/modern/theme.js
index b0f13f29..0d187059 120000
--- a/public/assets/tinymce/themes/modern/theme.js
+++ b/public/assets/tinymce/themes/modern/theme.js
@@ -1 +1 @@
-theme-f0a3cccc241fa5d46bde8e19160e3f351368881a7c3cdb0c4ce84da11901064c.js
\ No newline at end of file
+theme-4547e25369b8acbbc7101f29494cfd7d289c31d221eb99d0b9d5f340ef3af240.js
\ No newline at end of file
diff --git a/public/assets/tinymce/themes/modern/theme.js.gz b/public/assets/tinymce/themes/modern/theme.js.gz
index c6665d79..464c0830 120000
--- a/public/assets/tinymce/themes/modern/theme.js.gz
+++ b/public/assets/tinymce/themes/modern/theme.js.gz
@@ -1 +1 @@
-theme-f0a3cccc241fa5d46bde8e19160e3f351368881a7c3cdb0c4ce84da11901064c.js.gz
\ No newline at end of file
+theme-4547e25369b8acbbc7101f29494cfd7d289c31d221eb99d0b9d5f340ef3af240.js.gz
\ No newline at end of file
diff --git a/public/assets/tinymce/tinymce-0422648f7dd78a5e2c43b1fad74793a3d3b056cba25af436f1681a4dcba937e6.js b/public/assets/tinymce/tinymce-0422648f7dd78a5e2c43b1fad74793a3d3b056cba25af436f1681a4dcba937e6.js
new file mode 100644
index 00000000..1986dd98
--- /dev/null
+++ b/public/assets/tinymce/tinymce-0422648f7dd78a5e2c43b1fad74793a3d3b056cba25af436f1681a4dcba937e6.js
@@ -0,0 +1,54551 @@
+(function () {
+
+var defs = {}; // id -> {dependencies, definition, instance (possibly undefined)}
+
+// Used when there is no 'main' module.
+// The name is probably (hopefully) unique so minification removes for releases.
+var register_3795 = function (id) {
+ var module = dem(id);
+ var fragments = id.split('.');
+ var target = Function('return this;')();
+ for (var i = 0; i < fragments.length - 1; ++i) {
+ if (target[fragments[i]] === undefined)
+ target[fragments[i]] = {};
+ target = target[fragments[i]];
+ }
+ target[fragments[fragments.length - 1]] = module;
+};
+
+var instantiate = function (id) {
+ var actual = defs[id];
+ var dependencies = actual.deps;
+ var definition = actual.defn;
+ var len = dependencies.length;
+ var instances = new Array(len);
+ for (var i = 0; i < len; ++i)
+ instances[i] = dem(dependencies[i]);
+ var defResult = definition.apply(null, instances);
+ if (defResult === undefined)
+ throw 'module [' + id + '] returned undefined';
+ actual.instance = defResult;
+};
+
+var def = function (id, dependencies, definition) {
+ if (typeof id !== 'string')
+ throw 'module id must be a string';
+ else if (dependencies === undefined)
+ throw 'no dependencies for ' + id;
+ else if (definition === undefined)
+ throw 'no definition function for ' + id;
+ defs[id] = {
+ deps: dependencies,
+ defn: definition,
+ instance: undefined
+ };
+};
+
+var dem = function (id) {
+ var actual = defs[id];
+ if (actual === undefined)
+ throw 'module [' + id + '] was undefined';
+ else if (actual.instance === undefined)
+ instantiate(id);
+ return actual.instance;
+};
+
+var req = function (ids, callback) {
+ var len = ids.length;
+ var instances = new Array(len);
+ for (var i = 0; i < len; ++i)
+ instances.push(dem(ids[i]));
+ callback.apply(null, callback);
+};
+
+var ephox = {};
+
+ephox.bolt = {
+ module: {
+ api: {
+ define: def,
+ require: req,
+ demand: dem
+ }
+ }
+};
+
+var define = def;
+var require = req;
+var demand = dem;
+// this helps with minificiation when using a lot of global references
+var defineGlobal = function (id, ref) {
+ define(id, [], function () { return ref; });
+};
+/*jsc
+["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","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","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.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","tinymce.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","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.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","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","tinymce.core.undo.Fragments","tinymce.core.delete.BlockBoundaryDelete","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","tinymce.core.undo.Diff","tinymce.core.delete.BlockBoundary","tinymce.core.delete.MergeBlocks","ephox.katamari.api.Options","ephox.sugar.api.dom.Compare","ephox.sugar.api.node.Element","tinymce.core.delete.DeleteUtils","tinymce.core.caret.CaretUtils","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.caret.CaretFinder","tinymce.core.data.Binding","tinymce.core.init.InitContentBody","global!Object","global!setTimeout","ephox.katamari.api.Struct","ephox.sand.api.Node","ephox.sand.api.PlatformDetection","ephox.sugar.api.search.Selectors","global!console","ephox.sugar.api.node.Node","ephox.sugar.api.search.PredicateFind","ephox.sugar.api.search.Traverse","tinymce.core.dom.Empty","ephox.sugar.api.dom.Insert","ephox.sugar.api.dom.Remove","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.PlatformDetection","global!navigator","ephox.sugar.api.node.NodeTypes","ephox.katamari.api.Type","ephox.sugar.api.node.Body","ephox.sugar.impl.ClosestOrAncestor","ephox.sugar.alien.Recurse","ephox.sugar.api.search.SelectorExists","ephox.sugar.api.dom.InsertAll","ephox.katamari.api.Obj","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.LineWalker","tinymce.core.caret.LineUtils","tinymce.core.DragDropOverrides","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.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","ephox.katamari.api.Merger","global!Number","ephox.katamari.str.StrAppend","ephox.katamari.str.StringParts"]
+jsc*/
+/**
+ * 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
+ */
+
+/**
+ * Contains various tools for rect/position calculation.
+ *
+ * @class tinymce.geom.Rect
+ */
+define(
+ 'tinymce.core.geom.Rect',
+ [
+ ],
+ function () {
+ "use strict";
+
+ var min = Math.min, max = Math.max, round = Math.round;
+
+ /**
+ * 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;
+
+ x = targetRect.x;
+ y = targetRect.y;
+ w = rect.w;
+ h = rect.h;
+ targetW = targetRect.w;
+ targetH = targetRect.h;
+
+ rel = (rel || '').split('');
+
+ if (rel[0] === 'b') {
+ y += targetH;
+ }
+
+ if (rel[1] === 'r') {
+ x += targetW;
+ }
+
+ if (rel[0] === 'c') {
+ y += round(targetH / 2);
+ }
+
+ if (rel[1] === 'c') {
+ x += round(targetW / 2);
+ }
+
+ if (rel[3] === 'b') {
+ y -= h;
+ }
+
+ if (rel[4] === 'r') {
+ x -= w;
+ }
+
+ if (rel[3] === 'c') {
+ y -= round(h / 2);
+ }
+
+ if (rel[4] === 'c') {
+ x -= round(w / 2);
+ }
+
+ return create(x, y, w, h);
+ }
+
+ /**
+ * 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;
+
+ 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);
+ }
+
+ return {
+ inflate: inflate,
+ relativePosition: relativePosition,
+ findBestRelativePosition: findBestRelativePosition,
+ intersect: intersect,
+ clamp: clamp,
+ create: create,
+ fromClientRect: fromClientRect
+ };
+ }
+);
+
+/**
+ * Promise.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
+ *
+ * Promise polyfill under MIT license: https://github.com/taylorhakes/promise-polyfill
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/* eslint-disable */
+/* jshint ignore:start */
+
+/**
+ * Modifed to be a feature fill and wrapped as tinymce module.
+ */
+define(
+ 'tinymce.core.util.Promise',
+ [],
+ function () {
+ if (window.Promise) {
+ return window.Promise;
+ }
+
+ // Use polyfill for setImmediate for performance gains
+ var asap = Promise.immediateFn || (typeof setImmediate === 'function' && setImmediate) ||
+ function (fn) { setTimeout(fn, 1); };
+
+ // Polyfill for Function.prototype.bind
+ function bind(fn, thisArg) {
+ return function () {
+ fn.apply(thisArg, arguments);
+ };
+ }
+
+ var isArray = Array.isArray || function (value) { return Object.prototype.toString.call(value) === "[object Array]"; };
+
+ function Promise(fn) {
+ if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new');
+ if (typeof fn !== 'function') throw new TypeError('not a function');
+ this._state = null;
+ this._value = null;
+ this._deferreds = [];
+
+ doResolve(fn, bind(resolve, this), bind(reject, this));
+ }
+
+ function handle(deferred) {
+ var me = this;
+ if (this._state === null) {
+ this._deferreds.push(deferred);
+ return;
+ }
+ asap(function () {
+ var cb = me._state ? deferred.onFulfilled : deferred.onRejected;
+ if (cb === null) {
+ (me._state ? deferred.resolve : deferred.reject)(me._value);
+ return;
+ }
+ var ret;
+ try {
+ ret = cb(me._value);
+ }
+ catch (e) {
+ deferred.reject(e);
+ return;
+ }
+ deferred.resolve(ret);
+ });
+ }
+
+ function resolve(newValue) {
+ try { //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
+ if (newValue === this) throw new TypeError('A promise cannot be resolved with itself.');
+ if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
+ var then = newValue.then;
+ if (typeof then === 'function') {
+ doResolve(bind(then, newValue), bind(resolve, this), bind(reject, this));
+ return;
+ }
+ }
+ this._state = true;
+ this._value = newValue;
+ finale.call(this);
+ } catch (e) { reject.call(this, e); }
+ }
+
+ function reject(newValue) {
+ this._state = false;
+ this._value = newValue;
+ finale.call(this);
+ }
+
+ function finale() {
+ for (var i = 0, len = this._deferreds.length; i < len; i++) {
+ handle.call(this, this._deferreds[i]);
+ }
+ this._deferreds = null;
+ }
+
+ function Handler(onFulfilled, onRejected, resolve, reject) {
+ this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
+ this.onRejected = typeof onRejected === 'function' ? onRejected : null;
+ this.resolve = resolve;
+ this.reject = reject;
+ }
+
+ /**
+ * Take a potentially misbehaving resolver function and make sure
+ * onFulfilled and onRejected are only called once.
+ *
+ * Makes no guarantees about asynchrony.
+ */
+ function doResolve(fn, onFulfilled, onRejected) {
+ var done = false;
+ try {
+ fn(function (value) {
+ if (done) return;
+ done = true;
+ onFulfilled(value);
+ }, function (reason) {
+ if (done) return;
+ done = true;
+ onRejected(reason);
+ });
+ } catch (ex) {
+ if (done) return;
+ done = true;
+ onRejected(ex);
+ }
+ }
+
+ Promise.prototype['catch'] = function (onRejected) {
+ return this.then(null, onRejected);
+ };
+
+ Promise.prototype.then = function (onFulfilled, onRejected) {
+ var me = this;
+ return new Promise(function (resolve, reject) {
+ handle.call(me, new Handler(onFulfilled, onRejected, resolve, reject));
+ });
+ };
+
+ Promise.all = function () {
+ var args = Array.prototype.slice.call(arguments.length === 1 && isArray(arguments[0]) ? arguments[0] : arguments);
+
+ return new Promise(function (resolve, reject) {
+ if (args.length === 0) return resolve([]);
+ var remaining = args.length;
+ function res(i, val) {
+ try {
+ if (val && (typeof val === 'object' || typeof val === 'function')) {
+ var then = val.then;
+ if (typeof then === 'function') {
+ then.call(val, function (val) { res(i, val); }, reject);
+ return;
+ }
+ }
+ args[i] = val;
+ if (--remaining === 0) {
+ resolve(args);
+ }
+ } catch (ex) {
+ reject(ex);
+ }
+ }
+ for (var i = 0; i < args.length; i++) {
+ res(i, args[i]);
+ }
+ });
+ };
+
+ Promise.resolve = function (value) {
+ if (value && typeof value === 'object' && value.constructor === Promise) {
+ return value;
+ }
+
+ return new Promise(function (resolve) {
+ resolve(value);
+ });
+ };
+
+ Promise.reject = function (value) {
+ return new Promise(function (resolve, reject) {
+ reject(value);
+ });
+ };
+
+ Promise.race = function (values) {
+ return new Promise(function (resolve, reject) {
+ for (var i = 0, len = values.length; i < len; i++) {
+ values[i].then(resolve, reject);
+ }
+ });
+ };
+
+ return Promise;
+ }
+);
+
+/* jshint ignore:end */
+/* eslint-enable */
+/**
+ * Delay.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
+ */
+
+/**
+ * Utility class for working with delayed actions like setTimeout.
+ *
+ * @class tinymce.util.Delay
+ */
+define(
+ 'tinymce.core.util.Delay',
+ [
+ "tinymce.core.util.Promise"
+ ],
+ function (Promise) {
+ var requestAnimationFramePromise;
+
+ function requestAnimationFrame(callback, element) {
+ var i, requestAnimationFrameFunc = window.requestAnimationFrame, vendors = ['ms', 'moz', 'webkit'];
+
+ function featurefill(callback) {
+ window.setTimeout(callback, 0);
+ }
+
+ for (i = 0; i < vendors.length && !requestAnimationFrameFunc; i++) {
+ requestAnimationFrameFunc = window[vendors[i] + 'RequestAnimationFrame'];
+ }
+
+ if (!requestAnimationFrameFunc) {
+ requestAnimationFrameFunc = featurefill;
+ }
+
+ requestAnimationFrameFunc(callback, element);
+ }
+
+ function wrappedSetTimeout(callback, time) {
+ if (typeof time != 'number') {
+ time = 0;
+ }
+
+ return setTimeout(callback, time);
+ }
+
+ function wrappedSetInterval(callback, time) {
+ if (typeof time != 'number') {
+ time = 1; // IE 8 needs it to be > 0
+ }
+
+ return setInterval(callback, time);
+ }
+
+ function wrappedClearTimeout(id) {
+ return clearTimeout(id);
+ }
+
+ function wrappedClearInterval(id) {
+ return clearInterval(id);
+ }
+
+ function debounce(callback, time) {
+ var timer, func;
+
+ func = function () {
+ var args = arguments;
+
+ clearTimeout(timer);
+
+ timer = wrappedSetTimeout(function () {
+ callback.apply(this, args);
+ }, time);
+ };
+
+ func.stop = function () {
+ clearTimeout(timer);
+ };
+
+ return func;
+ }
+
+ return {
+ /**
+ * Requests an animation frame and fallbacks to a timeout on older browsers.
+ *
+ * @method requestAnimationFrame
+ * @param {function} callback Callback to execute when a new frame is available.
+ * @param {DOMElement} element Optional element to scope it to.
+ */
+ requestAnimationFrame: function (callback, element) {
+ if (requestAnimationFramePromise) {
+ requestAnimationFramePromise.then(callback);
+ return;
+ }
+
+ requestAnimationFramePromise = new Promise(function (resolve) {
+ if (!element) {
+ element = document.body;
+ }
+
+ requestAnimationFrame(resolve, element);
+ }).then(callback);
+ },
+
+ /**
+ * Sets a timer in ms and executes the specified callback when the timer runs out.
+ *
+ * @method setTimeout
+ * @param {function} callback Callback to execute when timer runs out.
+ * @param {Number} time Optional time to wait before the callback is executed, defaults to 0.
+ * @return {Number} Timeout id number.
+ */
+ setTimeout: wrappedSetTimeout,
+
+ /**
+ * Sets an interval timer in ms and executes the specified callback at every interval of that time.
+ *
+ * @method setInterval
+ * @param {function} callback Callback to execute when interval time runs out.
+ * @param {Number} time Optional time to wait before the callback is executed, defaults to 0.
+ * @return {Number} Timeout id number.
+ */
+ setInterval: wrappedSetInterval,
+
+ /**
+ * Sets an editor timeout it's similar to setTimeout except that it checks if the editor instance is
+ * still alive when the callback gets executed.
+ *
+ * @method setEditorTimeout
+ * @param {tinymce.Editor} editor Editor instance to check the removed state on.
+ * @param {function} callback Callback to execute when timer runs out.
+ * @param {Number} time Optional time to wait before the callback is executed, defaults to 0.
+ * @return {Number} Timeout id number.
+ */
+ setEditorTimeout: function (editor, callback, time) {
+ return wrappedSetTimeout(function () {
+ if (!editor.removed) {
+ callback();
+ }
+ }, time);
+ },
+
+ /**
+ * Sets an interval timer it's similar to setInterval except that it checks if the editor instance is
+ * still alive when the callback gets executed.
+ *
+ * @method setEditorInterval
+ * @param {function} callback Callback to execute when interval time runs out.
+ * @param {Number} time Optional time to wait before the callback is executed, defaults to 0.
+ * @return {Number} Timeout id number.
+ */
+ setEditorInterval: function (editor, callback, time) {
+ var timer;
+
+ timer = wrappedSetInterval(function () {
+ if (!editor.removed) {
+ callback();
+ } else {
+ clearInterval(timer);
+ }
+ }, time);
+
+ return timer;
+ },
+
+ /**
+ * Creates debounced callback function that only gets executed once within the specified time.
+ *
+ * @method debounce
+ * @param {function} callback Callback to execute when timer finishes.
+ * @param {Number} time Optional time to wait before the callback is executed, defaults to 0.
+ * @return {Function} debounced function callback.
+ */
+ debounce: debounce,
+
+ // Throttle needs to be debounce due to backwards compatibility.
+ throttle: debounce,
+
+ /**
+ * Clears an interval timer so it won't execute.
+ *
+ * @method clearInterval
+ * @param {Number} Interval timer id number.
+ */
+ clearInterval: wrappedClearInterval,
+
+ /**
+ * Clears an timeout timer so it won't execute.
+ *
+ * @method clearTimeout
+ * @param {Number} Timeout timer id number.
+ */
+ clearTimeout: wrappedClearTimeout
+ };
+ }
+);
+
+/**
+ * Env.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 various environment constants like browser versions etc.
+ * Normally you don't want to sniff specific browser versions but sometimes you have
+ * to when it's impossible to feature detect. So use this with care.
+ *
+ * @class tinymce.Env
+ * @static
+ */
+define(
+ 'tinymce.core.Env',
+ [
+ ],
+ function () {
+ var nav = navigator, userAgent = nav.userAgent;
+ var opera, webkit, ie, ie11, ie12, gecko, mac, iDevice, android, fileApi, phone, tablet, windowsPhone;
+
+ function matchMediaQuery(query) {
+ return "matchMedia" in window ? matchMedia(query).matches : false;
+ }
+
+ opera = window.opera && window.opera.buildNumber;
+ android = /Android/.test(userAgent);
+ webkit = /WebKit/.test(userAgent);
+ ie = !webkit && !opera && (/MSIE/gi).test(userAgent) && (/Explorer/gi).test(nav.appName);
+ ie = ie && /MSIE (\w+)\./.exec(userAgent)[1];
+ ie11 = userAgent.indexOf('Trident/') != -1 && (userAgent.indexOf('rv:') != -1 || nav.appName.indexOf('Netscape') != -1) ? 11 : false;
+ ie12 = (userAgent.indexOf('Edge/') != -1 && !ie && !ie11) ? 12 : false;
+ ie = ie || ie11 || ie12;
+ gecko = !webkit && !ie11 && /Gecko/.test(userAgent);
+ mac = userAgent.indexOf('Mac') != -1;
+ iDevice = /(iPad|iPhone)/.test(userAgent);
+ fileApi = "FormData" in window && "FileReader" in window && "URL" in window && !!URL.createObjectURL;
+ phone = matchMediaQuery("only screen and (max-device-width: 480px)") && (android || iDevice);
+ tablet = matchMediaQuery("only screen and (min-width: 800px)") && (android || iDevice);
+ windowsPhone = userAgent.indexOf('Windows Phone') != -1;
+
+ if (ie12) {
+ webkit = false;
+ }
+
+ // Is a iPad/iPhone and not on iOS5 sniff the WebKit version since older iOS WebKit versions
+ // says it has contentEditable support but there is no visible caret.
+ var contentEditable = !iDevice || fileApi || userAgent.match(/AppleWebKit\/(\d*)/)[1] >= 534;
+
+ return {
+ /**
+ * Constant that is true if the browser is Opera.
+ *
+ * @property opera
+ * @type Boolean
+ * @final
+ */
+ opera: opera,
+
+ /**
+ * Constant that is true if the browser is WebKit (Safari/Chrome).
+ *
+ * @property webKit
+ * @type Boolean
+ * @final
+ */
+ webkit: webkit,
+
+ /**
+ * Constant that is more than zero if the browser is IE.
+ *
+ * @property ie
+ * @type Boolean
+ * @final
+ */
+ ie: ie,
+
+ /**
+ * Constant that is true if the browser is Gecko.
+ *
+ * @property gecko
+ * @type Boolean
+ * @final
+ */
+ gecko: gecko,
+
+ /**
+ * Constant that is true if the os is Mac OS.
+ *
+ * @property mac
+ * @type Boolean
+ * @final
+ */
+ mac: mac,
+
+ /**
+ * Constant that is true if the os is iOS.
+ *
+ * @property iOS
+ * @type Boolean
+ * @final
+ */
+ iOS: iDevice,
+
+ /**
+ * Constant that is true if the os is android.
+ *
+ * @property android
+ * @type Boolean
+ * @final
+ */
+ android: android,
+
+ /**
+ * Constant that is true if the browser supports editing.
+ *
+ * @property contentEditable
+ * @type Boolean
+ * @final
+ */
+ contentEditable: contentEditable,
+
+ /**
+ * Transparent image data url.
+ *
+ * @property transparentSrc
+ * @type Boolean
+ * @final
+ */
+ transparentSrc: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
+
+ /**
+ * Returns true/false if the browser can or can't place the caret after a inline block like an image.
+ *
+ * @property noCaretAfter
+ * @type Boolean
+ * @final
+ */
+ caretAfter: ie != 8,
+
+ /**
+ * Constant that is true if the browser supports native DOM Ranges. IE 9+.
+ *
+ * @property range
+ * @type Boolean
+ */
+ range: window.getSelection && "Range" in window,
+
+ /**
+ * Returns the IE document mode for non IE browsers this will fake IE 10.
+ *
+ * @property documentMode
+ * @type Number
+ */
+ documentMode: ie && !ie12 ? (document.documentMode || 7) : 10,
+
+ /**
+ * Constant that is true if the browser has a modern file api.
+ *
+ * @property fileApi
+ * @type Boolean
+ */
+ fileApi: fileApi,
+
+ /**
+ * Constant that is true if the browser supports contentEditable=false regions.
+ *
+ * @property ceFalse
+ * @type Boolean
+ */
+ ceFalse: (ie === false || ie > 8),
+
+ /**
+ * Constant if CSP mode is possible or not. Meaning we can't use script urls for the iframe.
+ */
+ canHaveCSP: (ie === false || ie > 11),
+
+ desktop: !phone && !tablet,
+ windowsPhone: windowsPhone
+ };
+ }
+);
+
+/**
+ * EventUtils.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 loopfunc:true*/
+/*eslint no-loop-func:0 */
+
+/**
+ * This class wraps the browsers native event logic with more convenient methods.
+ *
+ * @class tinymce.dom.EventUtils
+ */
+define(
+ 'tinymce.core.dom.EventUtils',
+ [
+ "tinymce.core.util.Delay",
+ "tinymce.core.Env"
+ ],
+ function (Delay, Env) {
+ "use strict";
+
+ var eventExpandoPrefix = "mce-data-";
+ var mouseEventRe = /^(?:mouse|contextmenu)|click/;
+ var deprecated = {
+ keyLocation: 1, layerX: 1, layerY: 1, returnValue: 1,
+ webkitMovementX: 1, webkitMovementY: 1, keyIdentifier: 1
+ };
+
+ // Checks if it is our own isDefaultPrevented function
+ var hasIsDefaultPrevented = function (event) {
+ return event.isDefaultPrevented === returnTrue || event.isDefaultPrevented === returnFalse;
+ };
+
+ // Dummy function that gets replaced on the delegation state functions
+ var returnFalse = function () {
+ return false;
+ };
+
+ // Dummy function that gets replaced on the delegation state functions
+ var returnTrue = function () {
+ return true;
+ };
+
+ /**
+ * Binds a native event to a callback on the speified target.
+ */
+ function addEvent(target, name, callback, capture) {
+ if (target.addEventListener) {
+ target.addEventListener(name, callback, capture || false);
+ } else if (target.attachEvent) {
+ target.attachEvent('on' + name, callback);
+ }
+ }
+
+ /**
+ * Unbinds a native event callback on the specified target.
+ */
+ function removeEvent(target, name, callback, capture) {
+ if (target.removeEventListener) {
+ target.removeEventListener(name, callback, capture || false);
+ } else if (target.detachEvent) {
+ target.detachEvent('on' + name, callback);
+ }
+ }
+
+ /**
+ * Gets the event target based on shadow dom properties like path and deepPath.
+ */
+ function getTargetFromShadowDom(event, defaultTarget) {
+ var path, target = defaultTarget;
+
+ // When target element is inside Shadow DOM we need to take first element from path
+ // otherwise we'll get Shadow Root parent, not actual target element
+
+ // Normalize target for WebComponents v0 implementation (in Chrome)
+ path = event.path;
+ if (path && path.length > 0) {
+ target = path[0];
+ }
+
+ // Normalize target for WebComponents v1 implementation (standard)
+ if (event.deepPath) {
+ path = event.deepPath();
+ if (path && path.length > 0) {
+ target = path[0];
+ }
+ }
+
+ return target;
+ }
+
+ /**
+ * Normalizes a native event object or just adds the event specific methods on a custom event.
+ */
+ function fix(originalEvent, data) {
+ var name, event = data || {}, undef;
+
+ // Copy all properties from the original event
+ for (name in originalEvent) {
+ // layerX/layerY is deprecated in Chrome and produces a warning
+ if (!deprecated[name]) {
+ event[name] = originalEvent[name];
+ }
+ }
+
+ // Normalize target IE uses srcElement
+ if (!event.target) {
+ event.target = event.srcElement || document;
+ }
+
+ // Experimental shadow dom support
+ if (Env.experimentalShadowDom) {
+ event.target = getTargetFromShadowDom(originalEvent, event.target);
+ }
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if (originalEvent && mouseEventRe.test(originalEvent.type) && originalEvent.pageX === undef && originalEvent.clientX !== undef) {
+ var eventDoc = event.target.ownerDocument || document;
+ var doc = eventDoc.documentElement;
+ var body = eventDoc.body;
+
+ event.pageX = originalEvent.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) -
+ (doc && doc.clientLeft || body && body.clientLeft || 0);
+
+ event.pageY = originalEvent.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) -
+ (doc && doc.clientTop || body && body.clientTop || 0);
+ }
+
+ // Add preventDefault method
+ event.preventDefault = function () {
+ event.isDefaultPrevented = returnTrue;
+
+ // Execute preventDefault on the original event object
+ if (originalEvent) {
+ if (originalEvent.preventDefault) {
+ originalEvent.preventDefault();
+ } else {
+ originalEvent.returnValue = false; // IE
+ }
+ }
+ };
+
+ // Add stopPropagation
+ event.stopPropagation = function () {
+ event.isPropagationStopped = returnTrue;
+
+ // Execute stopPropagation on the original event object
+ if (originalEvent) {
+ if (originalEvent.stopPropagation) {
+ originalEvent.stopPropagation();
+ } else {
+ originalEvent.cancelBubble = true; // IE
+ }
+ }
+ };
+
+ // Add stopImmediatePropagation
+ event.stopImmediatePropagation = function () {
+ event.isImmediatePropagationStopped = returnTrue;
+ event.stopPropagation();
+ };
+
+ // Add event delegation states
+ if (hasIsDefaultPrevented(event) === false) {
+ event.isDefaultPrevented = returnFalse;
+ event.isPropagationStopped = returnFalse;
+ event.isImmediatePropagationStopped = returnFalse;
+ }
+
+ // Add missing metaKey for IE 8
+ if (typeof event.metaKey == 'undefined') {
+ event.metaKey = false;
+ }
+
+ return event;
+ }
+
+ /**
+ * Bind a DOMContentLoaded event across browsers and executes the callback once the page DOM is initialized.
+ * It will also set/check the domLoaded state of the event_utils instance so ready isn't called multiple times.
+ */
+ function bindOnReady(win, callback, eventUtils) {
+ var doc = win.document, event = { type: 'ready' };
+
+ if (eventUtils.domLoaded) {
+ callback(event);
+ return;
+ }
+
+ function isDocReady() {
+ // Check complete or interactive state if there is a body
+ // element on some iframes IE 8 will produce a null body
+ return doc.readyState === "complete" || (doc.readyState === "interactive" && doc.body);
+ }
+
+ // Gets called when the DOM is ready
+ function readyHandler() {
+ if (!eventUtils.domLoaded) {
+ eventUtils.domLoaded = true;
+ callback(event);
+ }
+ }
+
+ function waitForDomLoaded() {
+ if (isDocReady()) {
+ removeEvent(doc, "readystatechange", waitForDomLoaded);
+ readyHandler();
+ }
+ }
+
+ function tryScroll() {
+ try {
+ // If IE is used, use the trick by Diego Perini licensed under MIT by request to the author.
+ // http://javascript.nwbox.com/IEContentLoaded/
+ doc.documentElement.doScroll("left");
+ } catch (ex) {
+ Delay.setTimeout(tryScroll);
+ return;
+ }
+
+ readyHandler();
+ }
+
+ // Use W3C method (exclude IE 9,10 - readyState "interactive" became valid only in IE 11)
+ if (doc.addEventListener && !(Env.ie && Env.ie < 11)) {
+ if (isDocReady()) {
+ readyHandler();
+ } else {
+ addEvent(win, 'DOMContentLoaded', readyHandler);
+ }
+ } else {
+ // Use IE method
+ addEvent(doc, "readystatechange", waitForDomLoaded);
+
+ // Wait until we can scroll, when we can the DOM is initialized
+ if (doc.documentElement.doScroll && win.self === win.top) {
+ tryScroll();
+ }
+ }
+
+ // Fallback if any of the above methods should fail for some odd reason
+ addEvent(win, 'load', readyHandler);
+ }
+
+ /**
+ * This class enables you to bind/unbind native events to elements and normalize it's behavior across browsers.
+ */
+ function EventUtils() {
+ var self = this, events = {}, count, expando, hasFocusIn, hasMouseEnterLeave, mouseEnterLeave;
+
+ expando = eventExpandoPrefix + (+new Date()).toString(32);
+ hasMouseEnterLeave = "onmouseenter" in document.documentElement;
+ hasFocusIn = "onfocusin" in document.documentElement;
+ mouseEnterLeave = { mouseenter: 'mouseover', mouseleave: 'mouseout' };
+ count = 1;
+
+ // State if the DOMContentLoaded was executed or not
+ self.domLoaded = false;
+ self.events = events;
+
+ /**
+ * Executes all event handler callbacks for a specific event.
+ *
+ * @private
+ * @param {Event} evt Event object.
+ * @param {String} id Expando id value to look for.
+ */
+ function executeHandlers(evt, id) {
+ var callbackList, i, l, callback, container = events[id];
+
+ callbackList = container && container[evt.type];
+ if (callbackList) {
+ for (i = 0, l = callbackList.length; i < l; i++) {
+ callback = callbackList[i];
+
+ // Check if callback exists might be removed if a unbind is called inside the callback
+ if (callback && callback.func.call(callback.scope, evt) === false) {
+ evt.preventDefault();
+ }
+
+ // Should we stop propagation to immediate listeners
+ if (evt.isImmediatePropagationStopped()) {
+ return;
+ }
+ }
+ }
+ }
+
+ /**
+ * Binds a callback to an event on the specified target.
+ *
+ * @method bind
+ * @param {Object} target Target node/window or custom object.
+ * @param {String} names Name of the event to bind.
+ * @param {function} callback Callback function to execute when the event occurs.
+ * @param {Object} scope Scope to call the callback function on, defaults to target.
+ * @return {function} Callback function that got bound.
+ */
+ self.bind = function (target, names, callback, scope) {
+ var id, callbackList, i, name, fakeName, nativeHandler, capture, win = window;
+
+ // Native event handler function patches the event and executes the callbacks for the expando
+ function defaultNativeHandler(evt) {
+ executeHandlers(fix(evt || win.event), id);
+ }
+
+ // Don't bind to text nodes or comments
+ if (!target || target.nodeType === 3 || target.nodeType === 8) {
+ return;
+ }
+
+ // Create or get events id for the target
+ if (!target[expando]) {
+ id = count++;
+ target[expando] = id;
+ events[id] = {};
+ } else {
+ id = target[expando];
+ }
+
+ // Setup the specified scope or use the target as a default
+ scope = scope || target;
+
+ // Split names and bind each event, enables you to bind multiple events with one call
+ names = names.split(' ');
+ i = names.length;
+ while (i--) {
+ name = names[i];
+ nativeHandler = defaultNativeHandler;
+ fakeName = capture = false;
+
+ // Use ready instead of DOMContentLoaded
+ if (name === "DOMContentLoaded") {
+ name = "ready";
+ }
+
+ // DOM is already ready
+ if (self.domLoaded && name === "ready" && target.readyState == 'complete') {
+ callback.call(scope, fix({ type: name }));
+ continue;
+ }
+
+ // Handle mouseenter/mouseleaver
+ if (!hasMouseEnterLeave) {
+ fakeName = mouseEnterLeave[name];
+
+ if (fakeName) {
+ nativeHandler = function (evt) {
+ var current, related;
+
+ current = evt.currentTarget;
+ related = evt.relatedTarget;
+
+ // Check if related is inside the current target if it's not then the event should
+ // be ignored since it's a mouseover/mouseout inside the element
+ if (related && current.contains) {
+ // Use contains for performance
+ related = current.contains(related);
+ } else {
+ while (related && related !== current) {
+ related = related.parentNode;
+ }
+ }
+
+ // Fire fake event
+ if (!related) {
+ evt = fix(evt || win.event);
+ evt.type = evt.type === 'mouseout' ? 'mouseleave' : 'mouseenter';
+ evt.target = current;
+ executeHandlers(evt, id);
+ }
+ };
+ }
+ }
+
+ // Fake bubbling of focusin/focusout
+ if (!hasFocusIn && (name === "focusin" || name === "focusout")) {
+ capture = true;
+ fakeName = name === "focusin" ? "focus" : "blur";
+ nativeHandler = function (evt) {
+ evt = fix(evt || win.event);
+ evt.type = evt.type === 'focus' ? 'focusin' : 'focusout';
+ executeHandlers(evt, id);
+ };
+ }
+
+ // Setup callback list and bind native event
+ callbackList = events[id][name];
+ if (!callbackList) {
+ events[id][name] = callbackList = [{ func: callback, scope: scope }];
+ callbackList.fakeName = fakeName;
+ callbackList.capture = capture;
+ //callbackList.callback = callback;
+
+ // Add the nativeHandler to the callback list so that we can later unbind it
+ callbackList.nativeHandler = nativeHandler;
+
+ // Check if the target has native events support
+
+ if (name === "ready") {
+ bindOnReady(target, nativeHandler, self);
+ } else {
+ addEvent(target, fakeName || name, nativeHandler, capture);
+ }
+ } else {
+ if (name === "ready" && self.domLoaded) {
+ callback({ type: name });
+ } else {
+ // If it already has an native handler then just push the callback
+ callbackList.push({ func: callback, scope: scope });
+ }
+ }
+ }
+
+ target = callbackList = 0; // Clean memory for IE
+
+ return callback;
+ };
+
+ /**
+ * Unbinds the specified event by name, name and callback or all events on the target.
+ *
+ * @method unbind
+ * @param {Object} target Target node/window or custom object.
+ * @param {String} names Optional event name to unbind.
+ * @param {function} callback Optional callback function to unbind.
+ * @return {EventUtils} Event utils instance.
+ */
+ self.unbind = function (target, names, callback) {
+ var id, callbackList, i, ci, name, eventMap;
+
+ // Don't bind to text nodes or comments
+ if (!target || target.nodeType === 3 || target.nodeType === 8) {
+ return self;
+ }
+
+ // Unbind event or events if the target has the expando
+ id = target[expando];
+ if (id) {
+ eventMap = events[id];
+
+ // Specific callback
+ if (names) {
+ names = names.split(' ');
+ i = names.length;
+ while (i--) {
+ name = names[i];
+ callbackList = eventMap[name];
+
+ // Unbind the event if it exists in the map
+ if (callbackList) {
+ // Remove specified callback
+ if (callback) {
+ ci = callbackList.length;
+ while (ci--) {
+ if (callbackList[ci].func === callback) {
+ var nativeHandler = callbackList.nativeHandler;
+ var fakeName = callbackList.fakeName, capture = callbackList.capture;
+
+ // Clone callbackList since unbind inside a callback would otherwise break the handlers loop
+ callbackList = callbackList.slice(0, ci).concat(callbackList.slice(ci + 1));
+ callbackList.nativeHandler = nativeHandler;
+ callbackList.fakeName = fakeName;
+ callbackList.capture = capture;
+
+ eventMap[name] = callbackList;
+ }
+ }
+ }
+
+ // Remove all callbacks if there isn't a specified callback or there is no callbacks left
+ if (!callback || callbackList.length === 0) {
+ delete eventMap[name];
+ removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture);
+ }
+ }
+ }
+ } else {
+ // All events for a specific element
+ for (name in eventMap) {
+ callbackList = eventMap[name];
+ removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture);
+ }
+
+ eventMap = {};
+ }
+
+ // Check if object is empty, if it isn't then we won't remove the expando map
+ for (name in eventMap) {
+ return self;
+ }
+
+ // Delete event object
+ delete events[id];
+
+ // Remove expando from target
+ try {
+ // IE will fail here since it can't delete properties from window
+ delete target[expando];
+ } catch (ex) {
+ // IE will set it to null
+ target[expando] = null;
+ }
+ }
+
+ return self;
+ };
+
+ /**
+ * Fires the specified event on the specified target.
+ *
+ * @method fire
+ * @param {Object} target Target node/window or custom object.
+ * @param {String} name Event name to fire.
+ * @param {Object} args Optional arguments to send to the observers.
+ * @return {EventUtils} Event utils instance.
+ */
+ self.fire = function (target, name, args) {
+ var id;
+
+ // Don't bind to text nodes or comments
+ if (!target || target.nodeType === 3 || target.nodeType === 8) {
+ return self;
+ }
+
+ // Build event object by patching the args
+ args = fix(null, args);
+ args.type = name;
+ args.target = target;
+
+ do {
+ // Found an expando that means there is listeners to execute
+ id = target[expando];
+ if (id) {
+ executeHandlers(args, id);
+ }
+
+ // Walk up the DOM
+ target = target.parentNode || target.ownerDocument || target.defaultView || target.parentWindow;
+ } while (target && !args.isPropagationStopped());
+
+ return self;
+ };
+
+ /**
+ * Removes all bound event listeners for the specified target. This will also remove any bound
+ * listeners to child nodes within that target.
+ *
+ * @method clean
+ * @param {Object} target Target node/window object.
+ * @return {EventUtils} Event utils instance.
+ */
+ self.clean = function (target) {
+ var i, children, unbind = self.unbind;
+
+ // Don't bind to text nodes or comments
+ if (!target || target.nodeType === 3 || target.nodeType === 8) {
+ return self;
+ }
+
+ // Unbind any element on the specified target
+ if (target[expando]) {
+ unbind(target);
+ }
+
+ // Target doesn't have getElementsByTagName it's probably a window object then use it's document to find the children
+ if (!target.getElementsByTagName) {
+ target = target.document;
+ }
+
+ // Remove events from each child element
+ if (target && target.getElementsByTagName) {
+ unbind(target);
+
+ children = target.getElementsByTagName('*');
+ i = children.length;
+ while (i--) {
+ target = children[i];
+
+ if (target[expando]) {
+ unbind(target);
+ }
+ }
+ }
+
+ return self;
+ };
+
+ /**
+ * Destroys the event object. Call this on IE to remove memory leaks.
+ */
+ self.destroy = function () {
+ events = {};
+ };
+
+ // Legacy function for canceling events
+ self.cancel = function (e) {
+ if (e) {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ }
+
+ return false;
+ };
+ }
+
+ EventUtils.Event = new EventUtils();
+ EventUtils.Event.bind(window, 'ready', function () { });
+
+ return EventUtils;
+ }
+);
+
+/**
+ * Sizzle.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
+ *
+ * @ignore-file
+ */
+
+/*jshint bitwise:false, expr:true, noempty:false, sub:true, eqnull:true, latedef:false, maxlen:255 */
+/*eslint-disable */
+
+/**
+ * Sizzle CSS Selector Engine v@VERSION
+ * http://sizzlejs.com/
+ *
+ * Copyright 2008, 2014 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: @DATE
+ */
+define(
+ 'tinymce.core.dom.Sizzle',
+ [],
+ function () {
+ var i,
+ support,
+ Expr,
+ getText,
+ isXML,
+ tokenize,
+ compile,
+ select,
+ outermostContext,
+ sortInput,
+ hasDuplicate,
+
+ // Local document vars
+ setDocument,
+ document,
+ docElem,
+ documentIsHTML,
+ rbuggyQSA,
+ rbuggyMatches,
+ matches,
+ contains,
+
+ // Instance-specific data
+ expando = "sizzle" + -(new Date()),
+ preferredDoc = window.document,
+ dirruns = 0,
+ done = 0,
+ classCache = createCache(),
+ tokenCache = createCache(),
+ compilerCache = createCache(),
+ sortOrder = function (a, b) {
+ if (a === b) {
+ hasDuplicate = true;
+ }
+ return 0;
+ },
+
+ // General-purpose constants
+ strundefined = typeof undefined,
+ MAX_NEGATIVE = 1 << 31,
+
+ // Instance methods
+ hasOwn = ({}).hasOwnProperty,
+ arr = [],
+ pop = arr.pop,
+ push_native = arr.push,
+ push = arr.push,
+ slice = arr.slice,
+ // Use a stripped-down indexOf if we can't use a native one
+ indexOf = arr.indexOf || function (elem) {
+ var i = 0,
+ len = this.length;
+ for (; i < len; i++) {
+ if (this[i] === elem) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
+
+ // Regular expressions
+
+ // http://www.w3.org/TR/css3-selectors/#whitespace
+ whitespace = "[\\x20\\t\\r\\n\\f]",
+
+ // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+ identifier = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
+
+ // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
+ attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
+ // Operator (capture 2)
+ "*([*^$|!~]?=)" + whitespace +
+ // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
+ "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
+ "*\\]",
+
+ pseudos = ":(" + identifier + ")(?:\\((" +
+ // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
+ // 1. quoted (capture 3; capture 4 or capture 5)
+ "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
+ // 2. simple (capture 6)
+ "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
+ // 3. anything else (capture 2)
+ ".*" +
+ ")\\)|)",
+
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rtrim = new RegExp("^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g"),
+
+ rcomma = new RegExp("^" + whitespace + "*," + whitespace + "*"),
+ rcombinators = new RegExp("^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*"),
+
+ rattributeQuotes = new RegExp("=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g"),
+
+ rpseudo = new RegExp(pseudos),
+ ridentifier = new RegExp("^" + identifier + "$"),
+
+ matchExpr = {
+ "ID": new RegExp("^#(" + identifier + ")"),
+ "CLASS": new RegExp("^\\.(" + identifier + ")"),
+ "TAG": new RegExp("^(" + identifier + "|[*])"),
+ "ATTR": new RegExp("^" + attributes),
+ "PSEUDO": new RegExp("^" + pseudos),
+ "CHILD": new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
+ "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+ "*(\\d+)|))" + whitespace + "*\\)|)", "i"),
+ "bool": new RegExp("^(?:" + booleans + ")$", "i"),
+ // For use in libraries implementing .is()
+ // We use this for POS matching in `select`
+ "needsContext": new RegExp("^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
+ whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i")
+ },
+
+ rinputs = /^(?:input|select|textarea|button)$/i,
+ rheader = /^h\d$/i,
+
+ rnative = /^[^{]+\{\s*\[native \w/,
+
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
+ rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+ rsibling = /[+~]/,
+ rescape = /'|\\/g,
+
+ // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+ runescape = new RegExp("\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig"),
+ funescape = function (_, escaped, escapedWhitespace) {
+ var high = "0x" + escaped - 0x10000;
+ // NaN means non-codepoint
+ // Support: Firefox<24
+ // Workaround erroneous numeric interpretation of +"0x"
+ return high !== high || escapedWhitespace ?
+ escaped :
+ high < 0 ?
+ // BMP codepoint
+ String.fromCharCode(high + 0x10000) :
+ // Supplemental Plane codepoint (surrogate pair)
+ String.fromCharCode(high >> 10 | 0xD800, high & 0x3FF | 0xDC00);
+ };
+
+ // Optimize for push.apply( _, NodeList )
+ try {
+ push.apply(
+ (arr = slice.call(preferredDoc.childNodes)),
+ preferredDoc.childNodes
+ );
+ // Support: Android<4.0
+ // Detect silently failing push.apply
+ arr[preferredDoc.childNodes.length].nodeType;
+ } catch (e) {
+ push = {
+ apply: arr.length ?
+
+ // Leverage slice if possible
+ function (target, els) {
+ push_native.apply(target, slice.call(els));
+ } :
+
+ // Support: IE<9
+ // Otherwise append directly
+ function (target, els) {
+ var j = target.length,
+ i = 0;
+ // Can't trust NodeList.length
+ while ((target[j++] = els[i++])) { }
+ target.length = j - 1;
+ }
+ };
+ }
+
+ function Sizzle(selector, context, results, seed) {
+ var match, elem, m, nodeType,
+ // QSA vars
+ i, groups, old, nid, newContext, newSelector;
+
+ if ((context ? context.ownerDocument || context : preferredDoc) !== document) {
+ setDocument(context);
+ }
+
+ context = context || document;
+ results = results || [];
+
+ if (!selector || typeof selector !== "string") {
+ return results;
+ }
+
+ if ((nodeType = context.nodeType) !== 1 && nodeType !== 9) {
+ return [];
+ }
+
+ if (documentIsHTML && !seed) {
+
+ // Shortcuts
+ if ((match = rquickExpr.exec(selector))) {
+ // Speed-up: Sizzle("#ID")
+ if ((m = match[1])) {
+ if (nodeType === 9) {
+ elem = context.getElementById(m);
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document (jQuery #6963)
+ if (elem && elem.parentNode) {
+ // Handle the case where IE, Opera, and Webkit return items
+ // by name instead of ID
+ if (elem.id === m) {
+ results.push(elem);
+ return results;
+ }
+ } else {
+ return results;
+ }
+ } else {
+ // Context is not a document
+ if (context.ownerDocument && (elem = context.ownerDocument.getElementById(m)) &&
+ contains(context, elem) && elem.id === m) {
+ results.push(elem);
+ return results;
+ }
+ }
+
+ // Speed-up: Sizzle("TAG")
+ } else if (match[2]) {
+ push.apply(results, context.getElementsByTagName(selector));
+ return results;
+
+ // Speed-up: Sizzle(".CLASS")
+ } else if ((m = match[3]) && support.getElementsByClassName) {
+ push.apply(results, context.getElementsByClassName(m));
+ return results;
+ }
+ }
+
+ // QSA path
+ if (support.qsa && (!rbuggyQSA || !rbuggyQSA.test(selector))) {
+ nid = old = expando;
+ newContext = context;
+ newSelector = nodeType === 9 && selector;
+
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ if (nodeType === 1 && context.nodeName.toLowerCase() !== "object") {
+ groups = tokenize(selector);
+
+ if ((old = context.getAttribute("id"))) {
+ nid = old.replace(rescape, "\\$&");
+ } else {
+ context.setAttribute("id", nid);
+ }
+ nid = "[id='" + nid + "'] ";
+
+ i = groups.length;
+ while (i--) {
+ groups[i] = nid + toSelector(groups[i]);
+ }
+ newContext = rsibling.test(selector) && testContext(context.parentNode) || context;
+ newSelector = groups.join(",");
+ }
+
+ if (newSelector) {
+ try {
+ push.apply(results,
+ newContext.querySelectorAll(newSelector)
+ );
+ return results;
+ } catch (qsaError) {
+ } finally {
+ if (!old) {
+ context.removeAttribute("id");
+ }
+ }
+ }
+ }
+ }
+
+ // All others
+ return select(selector.replace(rtrim, "$1"), context, results, seed);
+ }
+
+ /**
+ * Create key-value caches of limited size
+ * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
+ * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ * deleting the oldest entry
+ */
+ function createCache() {
+ var keys = [];
+
+ function cache(key, value) {
+ // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+ if (keys.push(key + " ") > Expr.cacheLength) {
+ // Only keep the most recent entries
+ delete cache[keys.shift()];
+ }
+ return (cache[key + " "] = value);
+ }
+ return cache;
+ }
+
+ /**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+ function markFunction(fn) {
+ fn[expando] = true;
+ return fn;
+ }
+
+ /**
+ * Support testing using an element
+ * @param {Function} fn Passed the created div and expects a boolean result
+ */
+ function assert(fn) {
+ var div = document.createElement("div");
+
+ try {
+ return !!fn(div);
+ } catch (e) {
+ return false;
+ } finally {
+ // Remove from its parent by default
+ if (div.parentNode) {
+ div.parentNode.removeChild(div);
+ }
+ // release memory in IE
+ div = null;
+ }
+ }
+
+ /**
+ * Adds the same handler for all of the specified attrs
+ * @param {String} attrs Pipe-separated list of attributes
+ * @param {Function} handler The method that will be applied
+ */
+ function addHandle(attrs, handler) {
+ var arr = attrs.split("|"),
+ i = attrs.length;
+
+ while (i--) {
+ Expr.attrHandle[arr[i]] = handler;
+ }
+ }
+
+ /**
+ * Checks document order of two siblings
+ * @param {Element} a
+ * @param {Element} b
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
+ */
+ function siblingCheck(a, b) {
+ var cur = b && a,
+ diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
+ (~b.sourceIndex || MAX_NEGATIVE) -
+ (~a.sourceIndex || MAX_NEGATIVE);
+
+ // Use IE sourceIndex if available on both nodes
+ if (diff) {
+ return diff;
+ }
+
+ // Check if b follows a
+ if (cur) {
+ while ((cur = cur.nextSibling)) {
+ if (cur === b) {
+ return -1;
+ }
+ }
+ }
+
+ return a ? 1 : -1;
+ }
+
+ /**
+ * Returns a function to use in pseudos for input types
+ * @param {String} type
+ */
+ function createInputPseudo(type) {
+ return function (elem) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === type;
+ };
+ }
+
+ /**
+ * Returns a function to use in pseudos for buttons
+ * @param {String} type
+ */
+ function createButtonPseudo(type) {
+ return function (elem) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && elem.type === type;
+ };
+ }
+
+ /**
+ * Returns a function to use in pseudos for positionals
+ * @param {Function} fn
+ */
+ function createPositionalPseudo(fn) {
+ return markFunction(function (argument) {
+ argument = +argument;
+ return markFunction(function (seed, matches) {
+ var j,
+ matchIndexes = fn([], seed.length, argument),
+ i = matchIndexes.length;
+
+ // Match elements found at the specified indexes
+ while (i--) {
+ if (seed[(j = matchIndexes[i])]) {
+ seed[j] = !(matches[j] = seed[j]);
+ }
+ }
+ });
+ });
+ }
+
+ /**
+ * Checks a node for validity as a Sizzle context
+ * @param {Element|Object=} context
+ * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
+ */
+ function testContext(context) {
+ return context && typeof context.getElementsByTagName !== strundefined && context;
+ }
+
+ // Expose support vars for convenience
+ support = Sizzle.support = {};
+
+ /**
+ * Detects XML nodes
+ * @param {Element|Object} elem An element or a document
+ * @returns {Boolean} True iff elem is a non-HTML XML node
+ */
+ isXML = Sizzle.isXML = function (elem) {
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+ };
+
+ /**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+ setDocument = Sizzle.setDocument = function (node) {
+ var hasCompare,
+ doc = node ? node.ownerDocument || node : preferredDoc,
+ parent = doc.defaultView;
+
+ function getTop(win) {
+ // Edge throws a lovely Object expected if you try to get top on a detached reference see #2642
+ try {
+ return win.top;
+ } catch (ex) {
+ // Ignore
+ }
+
+ return null;
+ }
+
+ // If no document and documentElement is available, return
+ if (doc === document || doc.nodeType !== 9 || !doc.documentElement) {
+ return document;
+ }
+
+ // Set our document
+ document = doc;
+ docElem = doc.documentElement;
+
+ // Support tests
+ documentIsHTML = !isXML(doc);
+
+ // Support: IE>8
+ // If iframe document is assigned to "document" variable and if iframe has been reloaded,
+ // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
+ // IE6-8 do not support the defaultView property so parent will be undefined
+ if (parent && parent !== getTop(parent)) {
+ // IE11 does not have attachEvent, so all must suffer
+ if (parent.addEventListener) {
+ parent.addEventListener("unload", function () {
+ setDocument();
+ }, false);
+ } else if (parent.attachEvent) {
+ parent.attachEvent("onunload", function () {
+ setDocument();
+ });
+ }
+ }
+
+ /* Attributes
+ ---------------------------------------------------------------------- */
+
+ // Support: IE<8
+ // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
+ support.attributes = assert(function (div) {
+ div.className = "i";
+ return !div.getAttribute("className");
+ });
+
+ /* getElement(s)By*
+ ---------------------------------------------------------------------- */
+
+ // Check if getElementsByTagName("*") returns only elements
+ support.getElementsByTagName = assert(function (div) {
+ div.appendChild(doc.createComment(""));
+ return !div.getElementsByTagName("*").length;
+ });
+
+ // Support: IE<9
+ support.getElementsByClassName = rnative.test(doc.getElementsByClassName);
+
+ // Support: IE<10
+ // Check if getElementById returns elements by name
+ // The broken getElementById methods don't pick up programatically-set names,
+ // so use a roundabout getElementsByName test
+ support.getById = assert(function (div) {
+ docElem.appendChild(div).id = expando;
+ return !doc.getElementsByName || !doc.getElementsByName(expando).length;
+ });
+
+ // ID find and filter
+ if (support.getById) {
+ Expr.find["ID"] = function (id, context) {
+ if (typeof context.getElementById !== strundefined && documentIsHTML) {
+ var m = context.getElementById(id);
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ return m && m.parentNode ? [m] : [];
+ }
+ };
+ Expr.filter["ID"] = function (id) {
+ var attrId = id.replace(runescape, funescape);
+ return function (elem) {
+ return elem.getAttribute("id") === attrId;
+ };
+ };
+ } else {
+ // Support: IE6/7
+ // getElementById is not reliable as a find shortcut
+ delete Expr.find["ID"];
+
+ Expr.filter["ID"] = function (id) {
+ var attrId = id.replace(runescape, funescape);
+ return function (elem) {
+ var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
+ return node && node.value === attrId;
+ };
+ };
+ }
+
+ // Tag
+ Expr.find["TAG"] = support.getElementsByTagName ?
+ function (tag, context) {
+ if (typeof context.getElementsByTagName !== strundefined) {
+ return context.getElementsByTagName(tag);
+ }
+ } :
+ function (tag, context) {
+ var elem,
+ tmp = [],
+ i = 0,
+ results = context.getElementsByTagName(tag);
+
+ // Filter out possible comments
+ if (tag === "*") {
+ while ((elem = results[i++])) {
+ if (elem.nodeType === 1) {
+ tmp.push(elem);
+ }
+ }
+
+ return tmp;
+ }
+ return results;
+ };
+
+ // Class
+ Expr.find["CLASS"] = support.getElementsByClassName && function (className, context) {
+ if (documentIsHTML) {
+ return context.getElementsByClassName(className);
+ }
+ };
+
+ /* QSA/matchesSelector
+ ---------------------------------------------------------------------- */
+
+ // QSA and matchesSelector support
+
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+ rbuggyMatches = [];
+
+ // qSa(:focus) reports false when true (Chrome 21)
+ // We allow this because of a bug in IE8/9 that throws an error
+ // whenever `document.activeElement` is accessed on an iframe
+ // So, we allow :focus to pass through QSA all the time to avoid the IE error
+ // See http://bugs.jquery.com/ticket/13378
+ rbuggyQSA = [];
+
+ if ((support.qsa = rnative.test(doc.querySelectorAll))) {
+ // Build QSA regex
+ // Regex strategy adopted from Diego Perini
+ assert(function (div) {
+ // Select is set to empty string on purpose
+ // This is to test IE's treatment of not explicitly
+ // setting a boolean content attribute,
+ // since its presence should be enough
+ // http://bugs.jquery.com/ticket/12359
+ div.innerHTML = "";
+
+ // Support: IE8, Opera 11-12.16
+ // Nothing should be selected when empty strings follow ^= or $= or *=
+ // The test attribute must be unknown in Opera but "safe" for WinRT
+ // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
+ if (div.querySelectorAll("[msallowcapture^='']").length) {
+ rbuggyQSA.push("[*^$]=" + whitespace + "*(?:''|\"\")");
+ }
+
+ // Support: IE8
+ // Boolean attributes and "value" are not treated correctly
+ if (!div.querySelectorAll("[selected]").length) {
+ rbuggyQSA.push("\\[" + whitespace + "*(?:value|" + booleans + ")");
+ }
+
+ // Webkit/Opera - :checked should return selected option elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ // IE8 throws error here and will not see later tests
+ if (!div.querySelectorAll(":checked").length) {
+ rbuggyQSA.push(":checked");
+ }
+ });
+
+ assert(function (div) {
+ // Support: Windows 8 Native Apps
+ // The type and name attributes are restricted during .innerHTML assignment
+ var input = doc.createElement("input");
+ input.setAttribute("type", "hidden");
+ div.appendChild(input).setAttribute("name", "D");
+
+ // Support: IE8
+ // Enforce case-sensitivity of name attribute
+ if (div.querySelectorAll("[name=d]").length) {
+ rbuggyQSA.push("name" + whitespace + "*[*^$|!~]?=");
+ }
+
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+ // IE8 throws error here and will not see later tests
+ if (!div.querySelectorAll(":enabled").length) {
+ rbuggyQSA.push(":enabled", ":disabled");
+ }
+
+ // Opera 10-11 does not throw on post-comma invalid pseudos
+ div.querySelectorAll("*,:x");
+ rbuggyQSA.push(",.*:");
+ });
+ }
+
+ if ((support.matchesSelector = rnative.test((matches = docElem.matches ||
+ docElem.webkitMatchesSelector ||
+ docElem.mozMatchesSelector ||
+ docElem.oMatchesSelector ||
+ docElem.msMatchesSelector)))) {
+
+ assert(function (div) {
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9)
+ support.disconnectedMatch = matches.call(div, "div");
+
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ matches.call(div, "[s!='']:x");
+ rbuggyMatches.push("!=", pseudos);
+ });
+ }
+
+ rbuggyQSA = rbuggyQSA.length && new RegExp(rbuggyQSA.join("|"));
+ rbuggyMatches = rbuggyMatches.length && new RegExp(rbuggyMatches.join("|"));
+
+ /* Contains
+ ---------------------------------------------------------------------- */
+ hasCompare = rnative.test(docElem.compareDocumentPosition);
+
+ // Element contains another
+ // Purposefully does not implement inclusive descendent
+ // As in, an element does not contain itself
+ contains = hasCompare || rnative.test(docElem.contains) ?
+ function (a, b) {
+ var adown = a.nodeType === 9 ? a.documentElement : a,
+ bup = b && b.parentNode;
+ return a === bup || !!(bup && bup.nodeType === 1 && (
+ adown.contains ?
+ adown.contains(bup) :
+ a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16
+ ));
+ } :
+ function (a, b) {
+ if (b) {
+ while ((b = b.parentNode)) {
+ if (b === a) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+ /* Sorting
+ ---------------------------------------------------------------------- */
+
+ // Document order sorting
+ sortOrder = hasCompare ?
+ function (a, b) {
+
+ // Flag for duplicate removal
+ if (a === b) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ // Sort on method existence if only one input has compareDocumentPosition
+ var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
+ if (compare) {
+ return compare;
+ }
+
+ // Calculate position if both inputs belong to the same document
+ compare = (a.ownerDocument || a) === (b.ownerDocument || b) ?
+ a.compareDocumentPosition(b) :
+
+ // Otherwise we know they are disconnected
+ 1;
+
+ // Disconnected nodes
+ if (compare & 1 ||
+ (!support.sortDetached && b.compareDocumentPosition(a) === compare)) {
+
+ // Choose the first element that is related to our preferred document
+ if (a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a)) {
+ return -1;
+ }
+ if (b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b)) {
+ return 1;
+ }
+
+ // Maintain original order
+ return sortInput ?
+ (indexOf.call(sortInput, a) - indexOf.call(sortInput, b)) :
+ 0;
+ }
+
+ return compare & 4 ? -1 : 1;
+ } :
+ function (a, b) {
+ // Exit early if the nodes are identical
+ if (a === b) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ var cur,
+ i = 0,
+ aup = a.parentNode,
+ bup = b.parentNode,
+ ap = [a],
+ bp = [b];
+
+ // Parentless nodes are either documents or disconnected
+ if (!aup || !bup) {
+ return a === doc ? -1 :
+ b === doc ? 1 :
+ aup ? -1 :
+ bup ? 1 :
+ sortInput ?
+ (indexOf.call(sortInput, a) - indexOf.call(sortInput, b)) :
+ 0;
+
+ // If the nodes are siblings, we can do a quick check
+ } else if (aup === bup) {
+ return siblingCheck(a, b);
+ }
+
+ // Otherwise we need full lists of their ancestors for comparison
+ cur = a;
+ while ((cur = cur.parentNode)) {
+ ap.unshift(cur);
+ }
+ cur = b;
+ while ((cur = cur.parentNode)) {
+ bp.unshift(cur);
+ }
+
+ // Walk down the tree looking for a discrepancy
+ while (ap[i] === bp[i]) {
+ i++;
+ }
+
+ return i ?
+ // Do a sibling check if the nodes have a common ancestor
+ siblingCheck(ap[i], bp[i]) :
+
+ // Otherwise nodes in our document sort first
+ ap[i] === preferredDoc ? -1 :
+ bp[i] === preferredDoc ? 1 :
+ 0;
+ };
+
+ return doc;
+ };
+
+ Sizzle.matches = function (expr, elements) {
+ return Sizzle(expr, null, null, elements);
+ };
+
+ Sizzle.matchesSelector = function (elem, expr) {
+ // Set document vars if needed
+ if ((elem.ownerDocument || elem) !== document) {
+ setDocument(elem);
+ }
+
+ // Make sure that attribute selectors are quoted
+ expr = expr.replace(rattributeQuotes, "='$1']");
+
+ if (support.matchesSelector && documentIsHTML &&
+ (!rbuggyMatches || !rbuggyMatches.test(expr)) &&
+ (!rbuggyQSA || !rbuggyQSA.test(expr))) {
+
+ try {
+ var ret = matches.call(elem, expr);
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if (ret || support.disconnectedMatch ||
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9
+ elem.document && elem.document.nodeType !== 11) {
+ return ret;
+ }
+ } catch (e) { }
+ }
+
+ return Sizzle(expr, document, null, [elem]).length > 0;
+ };
+
+ Sizzle.contains = function (context, elem) {
+ // Set document vars if needed
+ if ((context.ownerDocument || context) !== document) {
+ setDocument(context);
+ }
+ return contains(context, elem);
+ };
+
+ Sizzle.attr = function (elem, name) {
+ // Set document vars if needed
+ if ((elem.ownerDocument || elem) !== document) {
+ setDocument(elem);
+ }
+
+ var fn = Expr.attrHandle[name.toLowerCase()],
+ // Don't get fooled by Object.prototype properties (jQuery #13807)
+ val = fn && hasOwn.call(Expr.attrHandle, name.toLowerCase()) ?
+ fn(elem, name, !documentIsHTML) :
+ undefined;
+
+ return val !== undefined ?
+ val :
+ support.attributes || !documentIsHTML ?
+ elem.getAttribute(name) :
+ (val = elem.getAttributeNode(name)) && val.specified ?
+ val.value :
+ null;
+ };
+
+ Sizzle.error = function (msg) {
+ throw new Error("Syntax error, unrecognized expression: " + msg);
+ };
+
+ /**
+ * Document sorting and removing duplicates
+ * @param {ArrayLike} results
+ */
+ Sizzle.uniqueSort = function (results) {
+ var elem,
+ duplicates = [],
+ j = 0,
+ i = 0;
+
+ // Unless we *know* we can detect duplicates, assume their presence
+ hasDuplicate = !support.detectDuplicates;
+ sortInput = !support.sortStable && results.slice(0);
+ results.sort(sortOrder);
+
+ if (hasDuplicate) {
+ while ((elem = results[i++])) {
+ if (elem === results[i]) {
+ j = duplicates.push(i);
+ }
+ }
+ while (j--) {
+ results.splice(duplicates[j], 1);
+ }
+ }
+
+ // Clear input after sorting to release objects
+ // See https://github.com/jquery/sizzle/pull/225
+ sortInput = null;
+
+ return results;
+ };
+
+ /**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+ getText = Sizzle.getText = function (elem) {
+ var node,
+ ret = "",
+ i = 0,
+ nodeType = elem.nodeType;
+
+ if (!nodeType) {
+ // If no nodeType, this is expected to be an array
+ while ((node = elem[i++])) {
+ // Do not traverse comment nodes
+ ret += getText(node);
+ }
+ } else if (nodeType === 1 || nodeType === 9 || nodeType === 11) {
+ // Use textContent for elements
+ // innerText usage removed for consistency of new lines (jQuery #11153)
+ if (typeof elem.textContent === "string") {
+ return elem.textContent;
+ } else {
+ // Traverse its children
+ for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
+ ret += getText(elem);
+ }
+ }
+ } else if (nodeType === 3 || nodeType === 4) {
+ return elem.nodeValue;
+ }
+ // Do not include comment or processing instruction nodes
+
+ return ret;
+ };
+
+ Expr = Sizzle.selectors = {
+
+ // Can be adjusted by the user
+ cacheLength: 50,
+
+ createPseudo: markFunction,
+
+ match: matchExpr,
+
+ attrHandle: {},
+
+ find: {},
+
+ relative: {
+ ">": { dir: "parentNode", first: true },
+ " ": { dir: "parentNode" },
+ "+": { dir: "previousSibling", first: true },
+ "~": { dir: "previousSibling" }
+ },
+
+ preFilter: {
+ "ATTR": function (match) {
+ match[1] = match[1].replace(runescape, funescape);
+
+ // Move the given value to match[3] whether quoted or unquoted
+ match[3] = (match[3] || match[4] || match[5] || "").replace(runescape, funescape);
+
+ if (match[2] === "~=") {
+ match[3] = " " + match[3] + " ";
+ }
+
+ return match.slice(0, 4);
+ },
+
+ "CHILD": function (match) {
+ /* matches from matchExpr["CHILD"]
+ 1 type (only|nth|...)
+ 2 what (child|of-type)
+ 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+ 4 xn-component of xn+y argument ([+-]?\d*n|)
+ 5 sign of xn-component
+ 6 x of xn-component
+ 7 sign of y-component
+ 8 y of y-component
+ */
+ match[1] = match[1].toLowerCase();
+
+ if (match[1].slice(0, 3) === "nth") {
+ // nth-* requires argument
+ if (!match[3]) {
+ Sizzle.error(match[0]);
+ }
+
+ // numeric x and y parameters for Expr.filter.CHILD
+ // remember that false/true cast respectively to 0/1
+ match[4] = +(match[4] ? match[5] + (match[6] || 1) : 2 * (match[3] === "even" || match[3] === "odd"));
+ match[5] = +((match[7] + match[8]) || match[3] === "odd");
+
+ // other types prohibit arguments
+ } else if (match[3]) {
+ Sizzle.error(match[0]);
+ }
+
+ return match;
+ },
+
+ "PSEUDO": function (match) {
+ var excess,
+ unquoted = !match[6] && match[2];
+
+ if (matchExpr["CHILD"].test(match[0])) {
+ return null;
+ }
+
+ // Accept quoted arguments as-is
+ if (match[3]) {
+ match[2] = match[4] || match[5] || "";
+
+ // Strip excess characters from unquoted arguments
+ } else if (unquoted && rpseudo.test(unquoted) &&
+ // Get excess from tokenize (recursively)
+ (excess = tokenize(unquoted, true)) &&
+ // advance to the next closing parenthesis
+ (excess = unquoted.indexOf(")", unquoted.length - excess) - unquoted.length)) {
+
+ // excess is a negative index
+ match[0] = match[0].slice(0, excess);
+ match[2] = unquoted.slice(0, excess);
+ }
+
+ // Return only captures needed by the pseudo filter method (type and argument)
+ return match.slice(0, 3);
+ }
+ },
+
+ filter: {
+
+ "TAG": function (nodeNameSelector) {
+ var nodeName = nodeNameSelector.replace(runescape, funescape).toLowerCase();
+ return nodeNameSelector === "*" ?
+ function () { return true; } :
+ function (elem) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+ };
+ },
+
+ "CLASS": function (className) {
+ var pattern = classCache[className + " "];
+
+ return pattern ||
+ (pattern = new RegExp("(^|" + whitespace + ")" + className + "(" + whitespace + "|$)")) &&
+ classCache(className, function (elem) {
+ return pattern.test(typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "");
+ });
+ },
+
+ "ATTR": function (name, operator, check) {
+ return function (elem) {
+ var result = Sizzle.attr(elem, name);
+
+ if (result == null) {
+ return operator === "!=";
+ }
+ if (!operator) {
+ return true;
+ }
+
+ result += "";
+
+ return operator === "=" ? result === check :
+ operator === "!=" ? result !== check :
+ operator === "^=" ? check && result.indexOf(check) === 0 :
+ operator === "*=" ? check && result.indexOf(check) > -1 :
+ operator === "$=" ? check && result.slice(-check.length) === check :
+ operator === "~=" ? (" " + result + " ").indexOf(check) > -1 :
+ operator === "|=" ? result === check || result.slice(0, check.length + 1) === check + "-" :
+ false;
+ };
+ },
+
+ "CHILD": function (type, what, argument, first, last) {
+ var simple = type.slice(0, 3) !== "nth",
+ forward = type.slice(-4) !== "last",
+ ofType = what === "of-type";
+
+ return first === 1 && last === 0 ?
+
+ // Shortcut for :nth-*(n)
+ function (elem) {
+ return !!elem.parentNode;
+ } :
+
+ function (elem, context, xml) {
+ var cache, outerCache, node, diff, nodeIndex, start,
+ dir = simple !== forward ? "nextSibling" : "previousSibling",
+ parent = elem.parentNode,
+ name = ofType && elem.nodeName.toLowerCase(),
+ useCache = !xml && !ofType;
+
+ if (parent) {
+
+ // :(first|last|only)-(child|of-type)
+ if (simple) {
+ while (dir) {
+ node = elem;
+ while ((node = node[dir])) {
+ if (ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1) {
+ return false;
+ }
+ }
+ // Reverse direction for :only-* (if we haven't yet done so)
+ start = dir = type === "only" && !start && "nextSibling";
+ }
+ return true;
+ }
+
+ start = [forward ? parent.firstChild : parent.lastChild];
+
+ // non-xml :nth-child(...) stores cache data on `parent`
+ if (forward && useCache) {
+ // Seek `elem` from a previously-cached index
+ outerCache = parent[expando] || (parent[expando] = {});
+ cache = outerCache[type] || [];
+ nodeIndex = cache[0] === dirruns && cache[1];
+ diff = cache[0] === dirruns && cache[2];
+ node = nodeIndex && parent.childNodes[nodeIndex];
+
+ while ((node = ++nodeIndex && node && node[dir] ||
+
+ // Fallback to seeking `elem` from the start
+ (diff = nodeIndex = 0) || start.pop())) {
+
+ // When found, cache indexes on `parent` and break
+ if (node.nodeType === 1 && ++diff && node === elem) {
+ outerCache[type] = [dirruns, nodeIndex, diff];
+ break;
+ }
+ }
+
+ // Use previously-cached element index if available
+ } else if (useCache && (cache = (elem[expando] || (elem[expando] = {}))[type]) && cache[0] === dirruns) {
+ diff = cache[1];
+
+ // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
+ } else {
+ // Use the same loop as above to seek `elem` from the start
+ while ((node = ++nodeIndex && node && node[dir] ||
+ (diff = nodeIndex = 0) || start.pop())) {
+
+ if ((ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1) && ++diff) {
+ // Cache the index of each encountered element
+ if (useCache) {
+ (node[expando] || (node[expando] = {}))[type] = [dirruns, diff];
+ }
+
+ if (node === elem) {
+ break;
+ }
+ }
+ }
+ }
+
+ // Incorporate the offset, then check against cycle size
+ diff -= last;
+ return diff === first || (diff % first === 0 && diff / first >= 0);
+ }
+ };
+ },
+
+ "PSEUDO": function (pseudo, argument) {
+ // pseudo-class names are case-insensitive
+ // http://www.w3.org/TR/selectors/#pseudo-classes
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+ // Remember that setFilters inherits from pseudos
+ var args,
+ fn = Expr.pseudos[pseudo] || Expr.setFilters[pseudo.toLowerCase()] ||
+ Sizzle.error("unsupported pseudo: " + pseudo);
+
+ // The user may use createPseudo to indicate that
+ // arguments are needed to create the filter function
+ // just as Sizzle does
+ if (fn[expando]) {
+ return fn(argument);
+ }
+
+ // But maintain support for old signatures
+ if (fn.length > 1) {
+ args = [pseudo, pseudo, "", argument];
+ return Expr.setFilters.hasOwnProperty(pseudo.toLowerCase()) ?
+ markFunction(function (seed, matches) {
+ var idx,
+ matched = fn(seed, argument),
+ i = matched.length;
+ while (i--) {
+ idx = indexOf.call(seed, matched[i]);
+ seed[idx] = !(matches[idx] = matched[i]);
+ }
+ }) :
+ function (elem) {
+ return fn(elem, 0, args);
+ };
+ }
+
+ return fn;
+ }
+ },
+
+ pseudos: {
+ // Potentially complex pseudos
+ "not": markFunction(function (selector) {
+ // Trim the selector passed to compile
+ // to avoid treating leading and trailing
+ // spaces as combinators
+ var input = [],
+ results = [],
+ matcher = compile(selector.replace(rtrim, "$1"));
+
+ return matcher[expando] ?
+ markFunction(function (seed, matches, context, xml) {
+ var elem,
+ unmatched = matcher(seed, null, xml, []),
+ i = seed.length;
+
+ // Match elements unmatched by `matcher`
+ while (i--) {
+ if ((elem = unmatched[i])) {
+ seed[i] = !(matches[i] = elem);
+ }
+ }
+ }) :
+ function (elem, context, xml) {
+ input[0] = elem;
+ matcher(input, null, xml, results);
+ return !results.pop();
+ };
+ }),
+
+ "has": markFunction(function (selector) {
+ return function (elem) {
+ return Sizzle(selector, elem).length > 0;
+ };
+ }),
+
+ "contains": markFunction(function (text) {
+ text = text.replace(runescape, funescape);
+ return function (elem) {
+ return (elem.textContent || elem.innerText || getText(elem)).indexOf(text) > -1;
+ };
+ }),
+
+ // "Whether an element is represented by a :lang() selector
+ // is based solely on the element's language value
+ // being equal to the identifier C,
+ // or beginning with the identifier C immediately followed by "-".
+ // The matching of C against the element's language value is performed case-insensitively.
+ // The identifier C does not have to be a valid language name."
+ // http://www.w3.org/TR/selectors/#lang-pseudo
+ "lang": markFunction(function (lang) {
+ // lang value must be a valid identifier
+ if (!ridentifier.test(lang || "")) {
+ Sizzle.error("unsupported lang: " + lang);
+ }
+ lang = lang.replace(runescape, funescape).toLowerCase();
+ return function (elem) {
+ var elemLang;
+ do {
+ if ((elemLang = documentIsHTML ?
+ elem.lang :
+ elem.getAttribute("xml:lang") || elem.getAttribute("lang"))) {
+
+ elemLang = elemLang.toLowerCase();
+ return elemLang === lang || elemLang.indexOf(lang + "-") === 0;
+ }
+ } while ((elem = elem.parentNode) && elem.nodeType === 1);
+ return false;
+ };
+ }),
+
+ // Miscellaneous
+ "target": function (elem) {
+ var hash = window.location && window.location.hash;
+ return hash && hash.slice(1) === elem.id;
+ },
+
+ "root": function (elem) {
+ return elem === docElem;
+ },
+
+ "focus": function (elem) {
+ return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+ },
+
+ // Boolean properties
+ "enabled": function (elem) {
+ return elem.disabled === false;
+ },
+
+ "disabled": function (elem) {
+ return elem.disabled === true;
+ },
+
+ "checked": function (elem) {
+ // In CSS3, :checked should return both checked and selected elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ var nodeName = elem.nodeName.toLowerCase();
+ return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+ },
+
+ "selected": function (elem) {
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if (elem.parentNode) {
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ // Contents
+ "empty": function (elem) {
+ // http://www.w3.org/TR/selectors/#empty-pseudo
+ // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
+ // but not by others (comment: 8; processing instruction: 7; etc.)
+ // nodeType < 6 works because attributes (2) do not appear as children
+ for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
+ if (elem.nodeType < 6) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ "parent": function (elem) {
+ return !Expr.pseudos["empty"](elem);
+ },
+
+ // Element/input types
+ "header": function (elem) {
+ return rheader.test(elem.nodeName);
+ },
+
+ "input": function (elem) {
+ return rinputs.test(elem.nodeName);
+ },
+
+ "button": function (elem) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === "button" || name === "button";
+ },
+
+ "text": function (elem) {
+ var attr;
+ return elem.nodeName.toLowerCase() === "input" &&
+ elem.type === "text" &&
+
+ // Support: IE<8
+ // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
+ ((attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text");
+ },
+
+ // Position-in-collection
+ "first": createPositionalPseudo(function () {
+ return [0];
+ }),
+
+ "last": createPositionalPseudo(function (matchIndexes, length) {
+ return [length - 1];
+ }),
+
+ "eq": createPositionalPseudo(function (matchIndexes, length, argument) {
+ return [argument < 0 ? argument + length : argument];
+ }),
+
+ "even": createPositionalPseudo(function (matchIndexes, length) {
+ var i = 0;
+ for (; i < length; i += 2) {
+ matchIndexes.push(i);
+ }
+ return matchIndexes;
+ }),
+
+ "odd": createPositionalPseudo(function (matchIndexes, length) {
+ var i = 1;
+ for (; i < length; i += 2) {
+ matchIndexes.push(i);
+ }
+ return matchIndexes;
+ }),
+
+ "lt": createPositionalPseudo(function (matchIndexes, length, argument) {
+ var i = argument < 0 ? argument + length : argument;
+ for (; --i >= 0;) {
+ matchIndexes.push(i);
+ }
+ return matchIndexes;
+ }),
+
+ "gt": createPositionalPseudo(function (matchIndexes, length, argument) {
+ var i = argument < 0 ? argument + length : argument;
+ for (; ++i < length;) {
+ matchIndexes.push(i);
+ }
+ return matchIndexes;
+ })
+ }
+ };
+
+ Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+ // Add button/input type pseudos
+ for (i in { radio: true, checkbox: true, file: true, password: true, image: true }) {
+ Expr.pseudos[i] = createInputPseudo(i);
+ }
+ for (i in { submit: true, reset: true }) {
+ Expr.pseudos[i] = createButtonPseudo(i);
+ }
+
+ // Easy API for creating new setFilters
+ function setFilters() { }
+ setFilters.prototype = Expr.filters = Expr.pseudos;
+ Expr.setFilters = new setFilters();
+
+ tokenize = Sizzle.tokenize = function (selector, parseOnly) {
+ var matched, match, tokens, type,
+ soFar, groups, preFilters,
+ cached = tokenCache[selector + " "];
+
+ if (cached) {
+ return parseOnly ? 0 : cached.slice(0);
+ }
+
+ soFar = selector;
+ groups = [];
+ preFilters = Expr.preFilter;
+
+ while (soFar) {
+
+ // Comma and first run
+ if (!matched || (match = rcomma.exec(soFar))) {
+ if (match) {
+ // Don't consume trailing commas as valid
+ soFar = soFar.slice(match[0].length) || soFar;
+ }
+ groups.push((tokens = []));
+ }
+
+ matched = false;
+
+ // Combinators
+ if ((match = rcombinators.exec(soFar))) {
+ matched = match.shift();
+ tokens.push({
+ value: matched,
+ // Cast descendant combinators to space
+ type: match[0].replace(rtrim, " ")
+ });
+ soFar = soFar.slice(matched.length);
+ }
+
+ // Filters
+ for (type in Expr.filter) {
+ if ((match = matchExpr[type].exec(soFar)) && (!preFilters[type] ||
+ (match = preFilters[type](match)))) {
+ matched = match.shift();
+ tokens.push({
+ value: matched,
+ type: type,
+ matches: match
+ });
+ soFar = soFar.slice(matched.length);
+ }
+ }
+
+ if (!matched) {
+ break;
+ }
+ }
+
+ // Return the length of the invalid excess
+ // if we're just parsing
+ // Otherwise, throw an error or return tokens
+ return parseOnly ?
+ soFar.length :
+ soFar ?
+ Sizzle.error(selector) :
+ // Cache the tokens
+ tokenCache(selector, groups).slice(0);
+ };
+
+ function toSelector(tokens) {
+ var i = 0,
+ len = tokens.length,
+ selector = "";
+ for (; i < len; i++) {
+ selector += tokens[i].value;
+ }
+ return selector;
+ }
+
+ function addCombinator(matcher, combinator, base) {
+ var dir = combinator.dir,
+ checkNonElements = base && dir === "parentNode",
+ doneName = done++;
+
+ return combinator.first ?
+ // Check against closest ancestor/preceding element
+ function (elem, context, xml) {
+ while ((elem = elem[dir])) {
+ if (elem.nodeType === 1 || checkNonElements) {
+ return matcher(elem, context, xml);
+ }
+ }
+ } :
+
+ // Check against all ancestor/preceding elements
+ function (elem, context, xml) {
+ var oldCache, outerCache,
+ newCache = [dirruns, doneName];
+
+ // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+ if (xml) {
+ while ((elem = elem[dir])) {
+ if (elem.nodeType === 1 || checkNonElements) {
+ if (matcher(elem, context, xml)) {
+ return true;
+ }
+ }
+ }
+ } else {
+ while ((elem = elem[dir])) {
+ if (elem.nodeType === 1 || checkNonElements) {
+ outerCache = elem[expando] || (elem[expando] = {});
+ if ((oldCache = outerCache[dir]) &&
+ oldCache[0] === dirruns && oldCache[1] === doneName) {
+
+ // Assign to newCache so results back-propagate to previous elements
+ return (newCache[2] = oldCache[2]);
+ } else {
+ // Reuse newcache so results back-propagate to previous elements
+ outerCache[dir] = newCache;
+
+ // A match means we're done; a fail means we have to keep checking
+ if ((newCache[2] = matcher(elem, context, xml))) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ };
+ }
+
+ function elementMatcher(matchers) {
+ return matchers.length > 1 ?
+ function (elem, context, xml) {
+ var i = matchers.length;
+ while (i--) {
+ if (!matchers[i](elem, context, xml)) {
+ return false;
+ }
+ }
+ return true;
+ } :
+ matchers[0];
+ }
+
+ function multipleContexts(selector, contexts, results) {
+ var i = 0,
+ len = contexts.length;
+ for (; i < len; i++) {
+ Sizzle(selector, contexts[i], results);
+ }
+ return results;
+ }
+
+ function condense(unmatched, map, filter, context, xml) {
+ var elem,
+ newUnmatched = [],
+ i = 0,
+ len = unmatched.length,
+ mapped = map != null;
+
+ for (; i < len; i++) {
+ if ((elem = unmatched[i])) {
+ if (!filter || filter(elem, context, xml)) {
+ newUnmatched.push(elem);
+ if (mapped) {
+ map.push(i);
+ }
+ }
+ }
+ }
+
+ return newUnmatched;
+ }
+
+ function setMatcher(preFilter, selector, matcher, postFilter, postFinder, postSelector) {
+ if (postFilter && !postFilter[expando]) {
+ postFilter = setMatcher(postFilter);
+ }
+ if (postFinder && !postFinder[expando]) {
+ postFinder = setMatcher(postFinder, postSelector);
+ }
+ return markFunction(function (seed, results, context, xml) {
+ var temp, i, elem,
+ preMap = [],
+ postMap = [],
+ preexisting = results.length,
+
+ // Get initial elements from seed or context
+ elems = seed || multipleContexts(selector || "*", context.nodeType ? [context] : context, []),
+
+ // Prefilter to get matcher input, preserving a map for seed-results synchronization
+ matcherIn = preFilter && (seed || !selector) ?
+ condense(elems, preMap, preFilter, context, xml) :
+ elems,
+
+ matcherOut = matcher ?
+ // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+ postFinder || (seed ? preFilter : preexisting || postFilter) ?
+
+ // ...intermediate processing is necessary
+ [] :
+
+ // ...otherwise use results directly
+ results :
+ matcherIn;
+
+ // Find primary matches
+ if (matcher) {
+ matcher(matcherIn, matcherOut, context, xml);
+ }
+
+ // Apply postFilter
+ if (postFilter) {
+ temp = condense(matcherOut, postMap);
+ postFilter(temp, [], context, xml);
+
+ // Un-match failing elements by moving them back to matcherIn
+ i = temp.length;
+ while (i--) {
+ if ((elem = temp[i])) {
+ matcherOut[postMap[i]] = !(matcherIn[postMap[i]] = elem);
+ }
+ }
+ }
+
+ if (seed) {
+ if (postFinder || preFilter) {
+ if (postFinder) {
+ // Get the final matcherOut by condensing this intermediate into postFinder contexts
+ temp = [];
+ i = matcherOut.length;
+ while (i--) {
+ if ((elem = matcherOut[i])) {
+ // Restore matcherIn since elem is not yet a final match
+ temp.push((matcherIn[i] = elem));
+ }
+ }
+ postFinder(null, (matcherOut = []), temp, xml);
+ }
+
+ // Move matched elements from seed to results to keep them synchronized
+ i = matcherOut.length;
+ while (i--) {
+ if ((elem = matcherOut[i]) &&
+ (temp = postFinder ? indexOf.call(seed, elem) : preMap[i]) > -1) {
+
+ seed[temp] = !(results[temp] = elem);
+ }
+ }
+ }
+
+ // Add elements to results, through postFinder if defined
+ } else {
+ matcherOut = condense(
+ matcherOut === results ?
+ matcherOut.splice(preexisting, matcherOut.length) :
+ matcherOut
+ );
+ if (postFinder) {
+ postFinder(null, results, matcherOut, xml);
+ } else {
+ push.apply(results, matcherOut);
+ }
+ }
+ });
+ }
+
+ function matcherFromTokens(tokens) {
+ var checkContext, matcher, j,
+ len = tokens.length,
+ leadingRelative = Expr.relative[tokens[0].type],
+ implicitRelative = leadingRelative || Expr.relative[" "],
+ i = leadingRelative ? 1 : 0,
+
+ // The foundational matcher ensures that elements are reachable from top-level context(s)
+ matchContext = addCombinator(function (elem) {
+ return elem === checkContext;
+ }, implicitRelative, true),
+ matchAnyContext = addCombinator(function (elem) {
+ return indexOf.call(checkContext, elem) > -1;
+ }, implicitRelative, true),
+ matchers = [function (elem, context, xml) {
+ return (!leadingRelative && (xml || context !== outermostContext)) || (
+ (checkContext = context).nodeType ?
+ matchContext(elem, context, xml) :
+ matchAnyContext(elem, context, xml));
+ }];
+
+ for (; i < len; i++) {
+ if ((matcher = Expr.relative[tokens[i].type])) {
+ matchers = [addCombinator(elementMatcher(matchers), matcher)];
+ } else {
+ matcher = Expr.filter[tokens[i].type].apply(null, tokens[i].matches);
+
+ // Return special upon seeing a positional matcher
+ if (matcher[expando]) {
+ // Find the next relative operator (if any) for proper handling
+ j = ++i;
+ for (; j < len; j++) {
+ if (Expr.relative[tokens[j].type]) {
+ break;
+ }
+ }
+ return setMatcher(
+ i > 1 && elementMatcher(matchers),
+ i > 1 && toSelector(
+ // If the preceding token was a descendant combinator, insert an implicit any-element `*`
+ tokens.slice(0, i - 1).concat({ value: tokens[i - 2].type === " " ? "*" : "" })
+ ).replace(rtrim, "$1"),
+ matcher,
+ i < j && matcherFromTokens(tokens.slice(i, j)),
+ j < len && matcherFromTokens((tokens = tokens.slice(j))),
+ j < len && toSelector(tokens)
+ );
+ }
+ matchers.push(matcher);
+ }
+ }
+
+ return elementMatcher(matchers);
+ }
+
+ function matcherFromGroupMatchers(elementMatchers, setMatchers) {
+ var bySet = setMatchers.length > 0,
+ byElement = elementMatchers.length > 0,
+ superMatcher = function (seed, context, xml, results, outermost) {
+ var elem, j, matcher,
+ matchedCount = 0,
+ i = "0",
+ unmatched = seed && [],
+ setMatched = [],
+ contextBackup = outermostContext,
+ // We must always have either seed elements or outermost context
+ elems = seed || byElement && Expr.find["TAG"]("*", outermost),
+ // Use integer dirruns iff this is the outermost matcher
+ dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
+ len = elems.length;
+
+ if (outermost) {
+ outermostContext = context !== document && context;
+ }
+
+ // Add elements passing elementMatchers directly to results
+ // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
+ // Support: IE<9, Safari
+ // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id
+ for (; i !== len && (elem = elems[i]) != null; i++) {
+ if (byElement && elem) {
+ j = 0;
+ while ((matcher = elementMatchers[j++])) {
+ if (matcher(elem, context, xml)) {
+ results.push(elem);
+ break;
+ }
+ }
+ if (outermost) {
+ dirruns = dirrunsUnique;
+ }
+ }
+
+ // Track unmatched elements for set filters
+ if (bySet) {
+ // They will have gone through all possible matchers
+ if ((elem = !matcher && elem)) {
+ matchedCount--;
+ }
+
+ // Lengthen the array for every element, matched or not
+ if (seed) {
+ unmatched.push(elem);
+ }
+ }
+ }
+
+ // Apply set filters to unmatched elements
+ matchedCount += i;
+ if (bySet && i !== matchedCount) {
+ j = 0;
+ while ((matcher = setMatchers[j++])) {
+ matcher(unmatched, setMatched, context, xml);
+ }
+
+ if (seed) {
+ // Reintegrate element matches to eliminate the need for sorting
+ if (matchedCount > 0) {
+ while (i--) {
+ if (!(unmatched[i] || setMatched[i])) {
+ setMatched[i] = pop.call(results);
+ }
+ }
+ }
+
+ // Discard index placeholder values to get only actual matches
+ setMatched = condense(setMatched);
+ }
+
+ // Add matches to results
+ push.apply(results, setMatched);
+
+ // Seedless set matches succeeding multiple successful matchers stipulate sorting
+ if (outermost && !seed && setMatched.length > 0 &&
+ (matchedCount + setMatchers.length) > 1) {
+
+ Sizzle.uniqueSort(results);
+ }
+ }
+
+ // Override manipulation of globals by nested matchers
+ if (outermost) {
+ dirruns = dirrunsUnique;
+ outermostContext = contextBackup;
+ }
+
+ return unmatched;
+ };
+
+ return bySet ?
+ markFunction(superMatcher) :
+ superMatcher;
+ }
+
+ compile = Sizzle.compile = function (selector, match /* Internal Use Only */) {
+ var i,
+ setMatchers = [],
+ elementMatchers = [],
+ cached = compilerCache[selector + " "];
+
+ if (!cached) {
+ // Generate a function of recursive functions that can be used to check each element
+ if (!match) {
+ match = tokenize(selector);
+ }
+ i = match.length;
+ while (i--) {
+ cached = matcherFromTokens(match[i]);
+ if (cached[expando]) {
+ setMatchers.push(cached);
+ } else {
+ elementMatchers.push(cached);
+ }
+ }
+
+ // Cache the compiled function
+ cached = compilerCache(selector, matcherFromGroupMatchers(elementMatchers, setMatchers));
+
+ // Save selector and tokenization
+ cached.selector = selector;
+ }
+ return cached;
+ };
+
+ /**
+ * A low-level selection function that works with Sizzle's compiled
+ * selector functions
+ * @param {String|Function} selector A selector or a pre-compiled
+ * selector function built with Sizzle.compile
+ * @param {Element} context
+ * @param {Array} [results]
+ * @param {Array} [seed] A set of elements to match against
+ */
+ select = Sizzle.select = function (selector, context, results, seed) {
+ var i, tokens, token, type, find,
+ compiled = typeof selector === "function" && selector,
+ match = !seed && tokenize((selector = compiled.selector || selector));
+
+ results = results || [];
+
+ // Try to minimize operations if there is no seed and only one group
+ if (match.length === 1) {
+
+ // Take a shortcut and set the context if the root selector is an ID
+ tokens = match[0] = match[0].slice(0);
+ if (tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+ support.getById && context.nodeType === 9 && documentIsHTML &&
+ Expr.relative[tokens[1].type]) {
+
+ context = (Expr.find["ID"](token.matches[0].replace(runescape, funescape), context) || [])[0];
+ if (!context) {
+ return results;
+
+ // Precompiled matchers will still verify ancestry, so step up a level
+ } else if (compiled) {
+ context = context.parentNode;
+ }
+
+ selector = selector.slice(tokens.shift().value.length);
+ }
+
+ // Fetch a seed set for right-to-left matching
+ i = matchExpr["needsContext"].test(selector) ? 0 : tokens.length;
+ while (i--) {
+ token = tokens[i];
+
+ // Abort if we hit a combinator
+ if (Expr.relative[(type = token.type)]) {
+ break;
+ }
+ if ((find = Expr.find[type])) {
+ // Search, expanding context for leading sibling combinators
+ if ((seed = find(
+ token.matches[0].replace(runescape, funescape),
+ rsibling.test(tokens[0].type) && testContext(context.parentNode) || context
+ ))) {
+
+ // If seed is empty or no tokens remain, we can return early
+ tokens.splice(i, 1);
+ selector = seed.length && toSelector(tokens);
+ if (!selector) {
+ push.apply(results, seed);
+ return results;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ // Compile and execute a filtering function if one is not provided
+ // Provide `match` to avoid retokenization if we modified the selector above
+ (compiled || compile(selector, match))(
+ seed,
+ context,
+ !documentIsHTML,
+ results,
+ rsibling.test(selector) && testContext(context.parentNode) || context
+ );
+ return results;
+ };
+
+ // One-time assignments
+
+ // Sort stability
+ support.sortStable = expando.split("").sort(sortOrder).join("") === expando;
+
+ // Support: Chrome 14-35+
+ // Always assume duplicates if they aren't passed to the comparison function
+ support.detectDuplicates = !!hasDuplicate;
+
+ // Initialize against the default document
+ setDocument();
+
+ // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
+ // Detached nodes confoundingly follow *each other*
+ support.sortDetached = assert(function (div1) {
+ // Should return 1, but returns 4 (following)
+ return div1.compareDocumentPosition(document.createElement("div")) & 1;
+ }
+ );
+
+ // Support: IE<8
+ // Prevent attribute/property "interpolation"
+ // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+ if (!assert(function (div) {
+ div.innerHTML = "";
+ return div.firstChild.getAttribute("href") === "#";
+ })) {
+ addHandle("type|href|height|width", function (elem, name, isXML) {
+ if (!isXML) {
+ return elem.getAttribute(name, name.toLowerCase() === "type" ? 1 : 2);
+ }
+ });
+ }
+
+ // Support: IE<9
+ // Use defaultValue in place of getAttribute("value")
+ if (!support.attributes || !assert(function (div) {
+ div.innerHTML = "";
+ div.firstChild.setAttribute("value", "");
+ return div.firstChild.getAttribute("value") === "";
+ })) {
+ addHandle("value", function (elem, name, isXML) {
+ if (!isXML && elem.nodeName.toLowerCase() === "input") {
+ return elem.defaultValue;
+ }
+ });
+ }
+
+ // Support: IE<9
+ // Use getAttributeNode to fetch booleans when getAttribute lies
+ if (!assert(function (div) {
+ return div.getAttribute("disabled") == null;
+ })) {
+ addHandle(booleans, function (elem, name, isXML) {
+ var val;
+ if (!isXML) {
+ return elem[name] === true ? name.toLowerCase() :
+ (val = elem.getAttributeNode(name)) && val.specified ?
+ val.value :
+ null;
+ }
+ });
+ }
+
+ // EXPOSE
+ return Sizzle;
+ }
+);
+
+/*eslint-enable */
+
+/**
+ * Arr.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
+ */
+
+/**
+ * Array utility class.
+ *
+ * @private
+ * @class tinymce.util.Arr
+ */
+define(
+ 'tinymce.core.util.Arr',
+ [
+ ],
+ function () {
+ var isArray = Array.isArray || function (obj) {
+ return Object.prototype.toString.call(obj) === "[object Array]";
+ };
+
+ function toArray(obj) {
+ var array = obj, i, l;
+
+ if (!isArray(obj)) {
+ array = [];
+ for (i = 0, l = obj.length; i < l; i++) {
+ array[i] = obj[i];
+ }
+ }
+
+ return array;
+ }
+
+ function each(o, cb, s) {
+ var n, l;
+
+ if (!o) {
+ return 0;
+ }
+
+ s = s || o;
+
+ if (o.length !== undefined) {
+ // Indexed arrays, needed for Safari
+ for (n = 0, l = o.length; n < l; n++) {
+ if (cb.call(s, o[n], n, o) === false) {
+ return 0;
+ }
+ }
+ } else {
+ // Hashtables
+ for (n in o) {
+ if (o.hasOwnProperty(n)) {
+ if (cb.call(s, o[n], n, o) === false) {
+ return 0;
+ }
+ }
+ }
+ }
+
+ return 1;
+ }
+
+ function map(array, callback) {
+ var out = [];
+
+ each(array, function (item, index) {
+ out.push(callback(item, index, array));
+ });
+
+ return out;
+ }
+
+ function filter(a, f) {
+ var o = [];
+
+ each(a, function (v, index) {
+ if (!f || f(v, index, a)) {
+ o.push(v);
+ }
+ });
+
+ return o;
+ }
+
+ function indexOf(a, v) {
+ var i, l;
+
+ if (a) {
+ for (i = 0, l = a.length; i < l; i++) {
+ if (a[i] === v) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ }
+
+ function reduce(collection, iteratee, accumulator, thisArg) {
+ var i = 0;
+
+ if (arguments.length < 3) {
+ accumulator = collection[0];
+ }
+
+ for (; i < collection.length; i++) {
+ accumulator = iteratee.call(thisArg, accumulator, collection[i], i);
+ }
+
+ return accumulator;
+ }
+
+ function findIndex(array, predicate, thisArg) {
+ var i, l;
+
+ for (i = 0, l = array.length; i < l; i++) {
+ if (predicate.call(thisArg, array[i], i, array)) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ function find(array, predicate, thisArg) {
+ var idx = findIndex(array, predicate, thisArg);
+
+ if (idx !== -1) {
+ return array[idx];
+ }
+
+ return undefined;
+ }
+
+ function last(collection) {
+ return collection[collection.length - 1];
+ }
+
+ return {
+ isArray: isArray,
+ toArray: toArray,
+ each: each,
+ map: map,
+ filter: filter,
+ indexOf: indexOf,
+ reduce: reduce,
+ findIndex: findIndex,
+ find: find,
+ last: last
+ };
+ }
+);
+/**
+ * Tools.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 various utlity functions. These are also exposed
+ * directly on the tinymce namespace.
+ *
+ * @class tinymce.util.Tools
+ */
+define(
+ 'tinymce.core.util.Tools',
+ [
+ "tinymce.core.Env",
+ "tinymce.core.util.Arr"
+ ],
+ function (Env, Arr) {
+ /**
+ * Removes whitespace from the beginning and end of a string.
+ *
+ * @method trim
+ * @param {String} s String to remove whitespace from.
+ * @return {String} New string with removed whitespace.
+ */
+ var whiteSpaceRegExp = /^\s*|\s*$/g;
+
+ function trim(str) {
+ return (str === null || str === undefined) ? '' : ("" + str).replace(whiteSpaceRegExp, '');
+ }
+
+ /**
+ * Checks if a object is of a specific type for example an array.
+ *
+ * @method is
+ * @param {Object} obj Object to check type of.
+ * @param {string} type Optional type to check for.
+ * @return {Boolean} true/false if the object is of the specified type.
+ */
+ function is(obj, type) {
+ if (!type) {
+ return obj !== undefined;
+ }
+
+ if (type == 'array' && Arr.isArray(obj)) {
+ return true;
+ }
+
+ return typeof obj == type;
+ }
+
+ /**
+ * Makes a name/object map out of an array with names.
+ *
+ * @method makeMap
+ * @param {Array/String} items Items to make map out of.
+ * @param {String} delim Optional delimiter to split string by.
+ * @param {Object} map Optional map to add items to.
+ * @return {Object} Name/value map of items.
+ */
+ function makeMap(items, delim, map) {
+ var i;
+
+ items = items || [];
+ delim = delim || ',';
+
+ if (typeof items == "string") {
+ items = items.split(delim);
+ }
+
+ map = map || {};
+
+ i = items.length;
+ while (i--) {
+ map[items[i]] = {};
+ }
+
+ return map;
+ }
+
+ /**
+ * JavaScript does not protect hasOwnProperty method, so it is possible to overwrite it. This is
+ * object independent version.
+ *
+ * @param {Object} obj
+ * @param {String} prop
+ * @returns {Boolean}
+ */
+ function hasOwnProperty(obj, prop) {
+ return Object.prototype.hasOwnProperty.call(obj, prop);
+ }
+
+ /**
+ * Creates a class, subclass or static singleton.
+ * More details on this method can be found in the Wiki.
+ *
+ * @method create
+ * @param {String} s Class name, inheritance and prefix.
+ * @param {Object} p Collection of methods to add to the class.
+ * @param {Object} root Optional root object defaults to the global window object.
+ * @example
+ * // Creates a basic class
+ * tinymce.create('tinymce.somepackage.SomeClass', {
+ * SomeClass: function() {
+ * // Class constructor
+ * },
+ *
+ * method: function() {
+ * // Some method
+ * }
+ * });
+ *
+ * // Creates a basic subclass class
+ * tinymce.create('tinymce.somepackage.SomeSubClass:tinymce.somepackage.SomeClass', {
+ * SomeSubClass: function() {
+ * // Class constructor
+ * this.parent(); // Call parent constructor
+ * },
+ *
+ * method: function() {
+ * // Some method
+ * this.parent(); // Call parent method
+ * },
+ *
+ * 'static': {
+ * staticMethod: function() {
+ * // Static method
+ * }
+ * }
+ * });
+ *
+ * // Creates a singleton/static class
+ * tinymce.create('static tinymce.somepackage.SomeSingletonClass', {
+ * method: function() {
+ * // Some method
+ * }
+ * });
+ */
+ function create(s, p, root) {
+ var self = this, sp, ns, cn, scn, c, de = 0;
+
+ // Parse : :
+ s = /^((static) )?([\w.]+)(:([\w.]+))?/.exec(s);
+ cn = s[3].match(/(^|\.)(\w+)$/i)[2]; // Class name
+
+ // Create namespace for new class
+ ns = self.createNS(s[3].replace(/\.\w+$/, ''), root);
+
+ // Class already exists
+ if (ns[cn]) {
+ return;
+ }
+
+ // Make pure static class
+ if (s[2] == 'static') {
+ ns[cn] = p;
+
+ if (this.onCreate) {
+ this.onCreate(s[2], s[3], ns[cn]);
+ }
+
+ return;
+ }
+
+ // Create default constructor
+ if (!p[cn]) {
+ p[cn] = function () { };
+ de = 1;
+ }
+
+ // Add constructor and methods
+ ns[cn] = p[cn];
+ self.extend(ns[cn].prototype, p);
+
+ // Extend
+ if (s[5]) {
+ sp = self.resolve(s[5]).prototype;
+ scn = s[5].match(/\.(\w+)$/i)[1]; // Class name
+
+ // Extend constructor
+ c = ns[cn];
+ if (de) {
+ // Add passthrough constructor
+ ns[cn] = function () {
+ return sp[scn].apply(this, arguments);
+ };
+ } else {
+ // Add inherit constructor
+ ns[cn] = function () {
+ this.parent = sp[scn];
+ return c.apply(this, arguments);
+ };
+ }
+ ns[cn].prototype[cn] = ns[cn];
+
+ // Add super methods
+ self.each(sp, function (f, n) {
+ ns[cn].prototype[n] = sp[n];
+ });
+
+ // Add overridden methods
+ self.each(p, function (f, n) {
+ // Extend methods if needed
+ if (sp[n]) {
+ ns[cn].prototype[n] = function () {
+ this.parent = sp[n];
+ return f.apply(this, arguments);
+ };
+ } else {
+ if (n != cn) {
+ ns[cn].prototype[n] = f;
+ }
+ }
+ });
+ }
+
+ // Add static methods
+ /*jshint sub:true*/
+ /*eslint dot-notation:0*/
+ self.each(p['static'], function (f, n) {
+ ns[cn][n] = f;
+ });
+ }
+
+ function extend(obj, ext) {
+ var i, l, name, args = arguments, value;
+
+ for (i = 1, l = args.length; i < l; i++) {
+ ext = args[i];
+ for (name in ext) {
+ if (ext.hasOwnProperty(name)) {
+ value = ext[name];
+
+ if (value !== undefined) {
+ obj[name] = value;
+ }
+ }
+ }
+ }
+
+ return obj;
+ }
+
+ /**
+ * Executed the specified function for each item in a object tree.
+ *
+ * @method walk
+ * @param {Object} o Object tree to walk though.
+ * @param {function} f Function to call for each item.
+ * @param {String} n Optional name of collection inside the objects to walk for example childNodes.
+ * @param {String} s Optional scope to execute the function in.
+ */
+ function walk(o, f, n, s) {
+ s = s || this;
+
+ if (o) {
+ if (n) {
+ o = o[n];
+ }
+
+ Arr.each(o, function (o, i) {
+ if (f.call(s, o, i, n) === false) {
+ return false;
+ }
+
+ walk(o, f, n, s);
+ });
+ }
+ }
+
+ /**
+ * Creates a namespace on a specific object.
+ *
+ * @method createNS
+ * @param {String} n Namespace to create for example a.b.c.d.
+ * @param {Object} o Optional object to add namespace to, defaults to window.
+ * @return {Object} New namespace object the last item in path.
+ * @example
+ * // Create some namespace
+ * tinymce.createNS('tinymce.somepackage.subpackage');
+ *
+ * // Add a singleton
+ * var tinymce.somepackage.subpackage.SomeSingleton = {
+ * method: function() {
+ * // Some method
+ * }
+ * };
+ */
+ function createNS(n, o) {
+ var i, v;
+
+ o = o || window;
+
+ n = n.split('.');
+ for (i = 0; i < n.length; i++) {
+ v = n[i];
+
+ if (!o[v]) {
+ o[v] = {};
+ }
+
+ o = o[v];
+ }
+
+ return o;
+ }
+
+ /**
+ * Resolves a string and returns the object from a specific structure.
+ *
+ * @method resolve
+ * @param {String} n Path to resolve for example a.b.c.d.
+ * @param {Object} o Optional object to search though, defaults to window.
+ * @return {Object} Last object in path or null if it couldn't be resolved.
+ * @example
+ * // Resolve a path into an object reference
+ * var obj = tinymce.resolve('a.b.c.d');
+ */
+ function resolve(n, o) {
+ var i, l;
+
+ o = o || window;
+
+ n = n.split('.');
+ for (i = 0, l = n.length; i < l; i++) {
+ o = o[n[i]];
+
+ if (!o) {
+ break;
+ }
+ }
+
+ return o;
+ }
+
+ /**
+ * Splits a string but removes the whitespace before and after each value.
+ *
+ * @method explode
+ * @param {string} s String to split.
+ * @param {string} d Delimiter to split by.
+ * @example
+ * // Split a string into an array with a,b,c
+ * var arr = tinymce.explode('a, b, c');
+ */
+ function explode(s, d) {
+ if (!s || is(s, 'array')) {
+ return s;
+ }
+
+ return Arr.map(s.split(d || ','), trim);
+ }
+
+ function _addCacheSuffix(url) {
+ var cacheSuffix = Env.cacheSuffix;
+
+ if (cacheSuffix) {
+ url += (url.indexOf('?') === -1 ? '?' : '&') + cacheSuffix;
+ }
+
+ return url;
+ }
+
+ return {
+ trim: trim,
+
+ /**
+ * Returns true/false if the object is an array or not.
+ *
+ * @method isArray
+ * @param {Object} obj Object to check.
+ * @return {boolean} true/false state if the object is an array or not.
+ */
+ isArray: Arr.isArray,
+
+ is: is,
+
+ /**
+ * Converts the specified object into a real JavaScript array.
+ *
+ * @method toArray
+ * @param {Object} obj Object to convert into array.
+ * @return {Array} Array object based in input.
+ */
+ toArray: Arr.toArray,
+ makeMap: makeMap,
+
+ /**
+ * Performs an iteration of all items in a collection such as an object or array. This method will execure the
+ * callback function for each item in the collection, if the callback returns false the iteration will terminate.
+ * The callback has the following format: cb(value, key_or_index).
+ *
+ * @method each
+ * @param {Object} o Collection to iterate.
+ * @param {function} cb Callback function to execute for each item.
+ * @param {Object} s Optional scope to execute the callback in.
+ * @example
+ * // Iterate an array
+ * tinymce.each([1,2,3], function(v, i) {
+ * console.debug("Value: " + v + ", Index: " + i);
+ * });
+ *
+ * // Iterate an object
+ * tinymce.each({a: 1, b: 2, c: 3], function(v, k) {
+ * console.debug("Value: " + v + ", Key: " + k);
+ * });
+ */
+ each: Arr.each,
+
+ /**
+ * Creates a new array by the return value of each iteration function call. This enables you to convert
+ * one array list into another.
+ *
+ * @method map
+ * @param {Array} array Array of items to iterate.
+ * @param {function} callback Function to call for each item. It's return value will be the new value.
+ * @return {Array} Array with new values based on function return values.
+ */
+ map: Arr.map,
+
+ /**
+ * Filters out items from the input array by calling the specified function for each item.
+ * If the function returns false the item will be excluded if it returns true it will be included.
+ *
+ * @method grep
+ * @param {Array} a Array of items to loop though.
+ * @param {function} f Function to call for each item. Include/exclude depends on it's return value.
+ * @return {Array} New array with values imported and filtered based in input.
+ * @example
+ * // Filter out some items, this will return an array with 4 and 5
+ * var items = tinymce.grep([1,2,3,4,5], function(v) {return v > 3;});
+ */
+ grep: Arr.filter,
+
+ /**
+ * Returns an index of the item or -1 if item is not present in the array.
+ *
+ * @method inArray
+ * @param {any} item Item to search for.
+ * @param {Array} arr Array to search in.
+ * @return {Number} index of the item or -1 if item was not found.
+ */
+ inArray: Arr.indexOf,
+
+ hasOwn: hasOwnProperty,
+
+ extend: extend,
+ create: create,
+ walk: walk,
+ createNS: createNS,
+ resolve: resolve,
+ explode: explode,
+ _addCacheSuffix: _addCacheSuffix
+ };
+ }
+);
+/**
+ * DomQuery.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 mimics most of the jQuery API:
+ *
+ * This is whats currently implemented:
+ * - Utility functions
+ * - DOM traversial
+ * - DOM manipulation
+ * - Event binding
+ *
+ * This is not currently implemented:
+ * - Dimension
+ * - Ajax
+ * - Animation
+ * - Advanced chaining
+ *
+ * @example
+ * var $ = tinymce.dom.DomQuery;
+ * $('p').attr('attr', 'value').addClass('class');
+ *
+ * @class tinymce.dom.DomQuery
+ */
+define(
+ 'tinymce.core.dom.DomQuery',
+ [
+ "tinymce.core.dom.EventUtils",
+ "tinymce.core.dom.Sizzle",
+ "tinymce.core.util.Tools",
+ "tinymce.core.Env"
+ ],
+ function (EventUtils, Sizzle, Tools, Env) {
+ var doc = document, push = Array.prototype.push, slice = Array.prototype.slice;
+ var rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/;
+ var Event = EventUtils.Event, undef;
+ var skipUniques = Tools.makeMap('children,contents,next,prev');
+
+ function isDefined(obj) {
+ return typeof obj !== 'undefined';
+ }
+
+ function isString(obj) {
+ return typeof obj === 'string';
+ }
+
+ function isWindow(obj) {
+ return obj && obj == obj.window;
+ }
+
+ function createFragment(html, fragDoc) {
+ var frag, node, container;
+
+ fragDoc = fragDoc || doc;
+ container = fragDoc.createElement('div');
+ frag = fragDoc.createDocumentFragment();
+ container.innerHTML = html;
+
+ while ((node = container.firstChild)) {
+ frag.appendChild(node);
+ }
+
+ return frag;
+ }
+
+ function domManipulate(targetNodes, sourceItem, callback, reverse) {
+ var i;
+
+ if (isString(sourceItem)) {
+ sourceItem = createFragment(sourceItem, getElementDocument(targetNodes[0]));
+ } else if (sourceItem.length && !sourceItem.nodeType) {
+ sourceItem = DomQuery.makeArray(sourceItem);
+
+ if (reverse) {
+ for (i = sourceItem.length - 1; i >= 0; i--) {
+ domManipulate(targetNodes, sourceItem[i], callback, reverse);
+ }
+ } else {
+ for (i = 0; i < sourceItem.length; i++) {
+ domManipulate(targetNodes, sourceItem[i], callback, reverse);
+ }
+ }
+
+ return targetNodes;
+ }
+
+ if (sourceItem.nodeType) {
+ i = targetNodes.length;
+ while (i--) {
+ callback.call(targetNodes[i], sourceItem);
+ }
+ }
+
+ return targetNodes;
+ }
+
+ function hasClass(node, className) {
+ return node && className && (' ' + node.className + ' ').indexOf(' ' + className + ' ') !== -1;
+ }
+
+ function wrap(elements, wrapper, all) {
+ var lastParent, newWrapper;
+
+ wrapper = DomQuery(wrapper)[0];
+
+ elements.each(function () {
+ var self = this;
+
+ if (!all || lastParent != self.parentNode) {
+ lastParent = self.parentNode;
+ newWrapper = wrapper.cloneNode(false);
+ self.parentNode.insertBefore(newWrapper, self);
+ newWrapper.appendChild(self);
+ } else {
+ newWrapper.appendChild(self);
+ }
+ });
+
+ return elements;
+ }
+
+ var numericCssMap = Tools.makeMap('fillOpacity fontWeight lineHeight opacity orphans widows zIndex zoom', ' ');
+ var booleanMap = Tools.makeMap('checked compact declare defer disabled ismap multiple nohref noshade nowrap readonly selected', ' ');
+ var propFix = {
+ 'for': 'htmlFor',
+ 'class': 'className',
+ 'readonly': 'readOnly'
+ };
+ var cssFix = {
+ 'float': 'cssFloat'
+ };
+
+ var attrHooks = {}, cssHooks = {};
+
+ function DomQuery(selector, context) {
+ /*eslint new-cap:0 */
+ return new DomQuery.fn.init(selector, context);
+ }
+
+ function inArray(item, array) {
+ var i;
+
+ if (array.indexOf) {
+ return array.indexOf(item);
+ }
+
+ i = array.length;
+ while (i--) {
+ if (array[i] === item) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ var whiteSpaceRegExp = /^\s*|\s*$/g;
+
+ function trim(str) {
+ return (str === null || str === undef) ? '' : ("" + str).replace(whiteSpaceRegExp, '');
+ }
+
+ function each(obj, callback) {
+ var length, key, i, undef, value;
+
+ if (obj) {
+ length = obj.length;
+
+ if (length === undef) {
+ // Loop object items
+ for (key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ value = obj[key];
+ if (callback.call(value, key, value) === false) {
+ break;
+ }
+ }
+ }
+ } else {
+ // Loop array items
+ for (i = 0; i < length; i++) {
+ value = obj[i];
+ if (callback.call(value, i, value) === false) {
+ break;
+ }
+ }
+ }
+ }
+
+ return obj;
+ }
+
+ function grep(array, callback) {
+ var out = [];
+
+ each(array, function (i, item) {
+ if (callback(item, i)) {
+ out.push(item);
+ }
+ });
+
+ return out;
+ }
+
+ function getElementDocument(element) {
+ if (!element) {
+ return doc;
+ }
+
+ if (element.nodeType == 9) {
+ return element;
+ }
+
+ return element.ownerDocument;
+ }
+
+ DomQuery.fn = DomQuery.prototype = {
+ constructor: DomQuery,
+
+ /**
+ * Selector for the current set.
+ *
+ * @property selector
+ * @type String
+ */
+ selector: "",
+
+ /**
+ * Context used to create the set.
+ *
+ * @property context
+ * @type Element
+ */
+ context: null,
+
+ /**
+ * Number of items in the current set.
+ *
+ * @property length
+ * @type Number
+ */
+ length: 0,
+
+ /**
+ * Constructs a new DomQuery instance with the specified selector or context.
+ *
+ * @constructor
+ * @method init
+ * @param {String/Array/DomQuery} selector Optional CSS selector/Array or array like object or HTML string.
+ * @param {Document/Element} context Optional context to search in.
+ */
+ init: function (selector, context) {
+ var self = this, match, node;
+
+ if (!selector) {
+ return self;
+ }
+
+ if (selector.nodeType) {
+ self.context = self[0] = selector;
+ self.length = 1;
+
+ return self;
+ }
+
+ if (context && context.nodeType) {
+ self.context = context;
+ } else {
+ if (context) {
+ return DomQuery(selector).attr(context);
+ }
+
+ self.context = context = document;
+ }
+
+ if (isString(selector)) {
+ self.selector = selector;
+
+ if (selector.charAt(0) === "<" && selector.charAt(selector.length - 1) === ">" && selector.length >= 3) {
+ match = [null, selector, null];
+ } else {
+ match = rquickExpr.exec(selector);
+ }
+
+ if (match) {
+ if (match[1]) {
+ node = createFragment(selector, getElementDocument(context)).firstChild;
+
+ while (node) {
+ push.call(self, node);
+ node = node.nextSibling;
+ }
+ } else {
+ node = getElementDocument(context).getElementById(match[2]);
+
+ if (!node) {
+ return self;
+ }
+
+ if (node.id !== match[2]) {
+ return self.find(selector);
+ }
+
+ self.length = 1;
+ self[0] = node;
+ }
+ } else {
+ return DomQuery(context).find(selector);
+ }
+ } else {
+ this.add(selector, false);
+ }
+
+ return self;
+ },
+
+ /**
+ * Converts the current set to an array.
+ *
+ * @method toArray
+ * @return {Array} Array of all nodes in set.
+ */
+ toArray: function () {
+ return Tools.toArray(this);
+ },
+
+ /**
+ * Adds new nodes to the set.
+ *
+ * @method add
+ * @param {Array/tinymce.core.dom.DomQuery} items Array of all nodes to add to set.
+ * @param {Boolean} sort Optional sort flag that enables sorting of elements.
+ * @return {tinymce.dom.DomQuery} New instance with nodes added.
+ */
+ add: function (items, sort) {
+ var self = this, nodes, i;
+
+ if (isString(items)) {
+ return self.add(DomQuery(items));
+ }
+
+ if (sort !== false) {
+ nodes = DomQuery.unique(self.toArray().concat(DomQuery.makeArray(items)));
+ self.length = nodes.length;
+ for (i = 0; i < nodes.length; i++) {
+ self[i] = nodes[i];
+ }
+ } else {
+ push.apply(self, DomQuery.makeArray(items));
+ }
+
+ return self;
+ },
+
+ /**
+ * Sets/gets attributes on the elements in the current set.
+ *
+ * @method attr
+ * @param {String/Object} name Name of attribute to get or an object with attributes to set.
+ * @param {String} value Optional value to set.
+ * @return {tinymce.dom.DomQuery/String} Current set or the specified attribute when only the name is specified.
+ */
+ attr: function (name, value) {
+ var self = this, hook;
+
+ if (typeof name === "object") {
+ each(name, function (name, value) {
+ self.attr(name, value);
+ });
+ } else if (isDefined(value)) {
+ this.each(function () {
+ var hook;
+
+ if (this.nodeType === 1) {
+ hook = attrHooks[name];
+ if (hook && hook.set) {
+ hook.set(this, value);
+ return;
+ }
+
+ if (value === null) {
+ this.removeAttribute(name, 2);
+ } else {
+ this.setAttribute(name, value, 2);
+ }
+ }
+ });
+ } else {
+ if (self[0] && self[0].nodeType === 1) {
+ hook = attrHooks[name];
+ if (hook && hook.get) {
+ return hook.get(self[0], name);
+ }
+
+ if (booleanMap[name]) {
+ return self.prop(name) ? name : undef;
+ }
+
+ value = self[0].getAttribute(name, 2);
+
+ if (value === null) {
+ value = undef;
+ }
+ }
+
+ return value;
+ }
+
+ return self;
+ },
+
+ /**
+ * Removes attributse on the elements in the current set.
+ *
+ * @method removeAttr
+ * @param {String/Object} name Name of attribute to remove.
+ * @return {tinymce.dom.DomQuery/String} Current set.
+ */
+ removeAttr: function (name) {
+ return this.attr(name, null);
+ },
+
+ /**
+ * Sets/gets properties on the elements in the current set.
+ *
+ * @method attr
+ * @param {String/Object} name Name of property to get or an object with properties to set.
+ * @param {String} value Optional value to set.
+ * @return {tinymce.dom.DomQuery/String} Current set or the specified property when only the name is specified.
+ */
+ prop: function (name, value) {
+ var self = this;
+
+ name = propFix[name] || name;
+
+ if (typeof name === "object") {
+ each(name, function (name, value) {
+ self.prop(name, value);
+ });
+ } else if (isDefined(value)) {
+ this.each(function () {
+ if (this.nodeType == 1) {
+ this[name] = value;
+ }
+ });
+ } else {
+ if (self[0] && self[0].nodeType && name in self[0]) {
+ return self[0][name];
+ }
+
+ return value;
+ }
+
+ return self;
+ },
+
+ /**
+ * Sets/gets styles on the elements in the current set.
+ *
+ * @method css
+ * @param {String/Object} name Name of style to get or an object with styles to set.
+ * @param {String} value Optional value to set.
+ * @return {tinymce.dom.DomQuery/String} Current set or the specified style when only the name is specified.
+ */
+ css: function (name, value) {
+ var self = this, elm, hook;
+
+ function camel(name) {
+ return name.replace(/-(\D)/g, function (a, b) {
+ return b.toUpperCase();
+ });
+ }
+
+ function dashed(name) {
+ return name.replace(/[A-Z]/g, function (a) {
+ return '-' + a;
+ });
+ }
+
+ if (typeof name === "object") {
+ each(name, function (name, value) {
+ self.css(name, value);
+ });
+ } else {
+ if (isDefined(value)) {
+ name = camel(name);
+
+ // Default px suffix on these
+ if (typeof value === 'number' && !numericCssMap[name]) {
+ value += 'px';
+ }
+
+ self.each(function () {
+ var style = this.style;
+
+ hook = cssHooks[name];
+ if (hook && hook.set) {
+ hook.set(this, value);
+ return;
+ }
+
+ try {
+ this.style[cssFix[name] || name] = value;
+ } catch (ex) {
+ // Ignore
+ }
+
+ if (value === null || value === '') {
+ if (style.removeProperty) {
+ style.removeProperty(dashed(name));
+ } else {
+ style.removeAttribute(name);
+ }
+ }
+ });
+ } else {
+ elm = self[0];
+
+ hook = cssHooks[name];
+ if (hook && hook.get) {
+ return hook.get(elm);
+ }
+
+ if (elm.ownerDocument.defaultView) {
+ try {
+ return elm.ownerDocument.defaultView.getComputedStyle(elm, null).getPropertyValue(dashed(name));
+ } catch (ex) {
+ return undef;
+ }
+ } else if (elm.currentStyle) {
+ return elm.currentStyle[camel(name)];
+ }
+ }
+ }
+
+ return self;
+ },
+
+ /**
+ * Removes all nodes in set from the document.
+ *
+ * @method remove
+ * @return {tinymce.dom.DomQuery} Current set with the removed nodes.
+ */
+ remove: function () {
+ var self = this, node, i = this.length;
+
+ while (i--) {
+ node = self[i];
+ Event.clean(node);
+
+ if (node.parentNode) {
+ node.parentNode.removeChild(node);
+ }
+ }
+
+ return this;
+ },
+
+ /**
+ * Empties all elements in set.
+ *
+ * @method empty
+ * @return {tinymce.dom.DomQuery} Current set with the empty nodes.
+ */
+ empty: function () {
+ var self = this, node, i = this.length;
+
+ while (i--) {
+ node = self[i];
+ while (node.firstChild) {
+ node.removeChild(node.firstChild);
+ }
+ }
+
+ return this;
+ },
+
+ /**
+ * Sets or gets the HTML of the current set or first set node.
+ *
+ * @method html
+ * @param {String} value Optional innerHTML value to set on each element.
+ * @return {tinymce.dom.DomQuery/String} Current set or the innerHTML of the first element.
+ */
+ html: function (value) {
+ var self = this, i;
+
+ if (isDefined(value)) {
+ i = self.length;
+
+ try {
+ while (i--) {
+ self[i].innerHTML = value;
+ }
+ } catch (ex) {
+ // Workaround for "Unknown runtime error" when DIV is added to P on IE
+ DomQuery(self[i]).empty().append(value);
+ }
+
+ return self;
+ }
+
+ return self[0] ? self[0].innerHTML : '';
+ },
+
+ /**
+ * Sets or gets the text of the current set or first set node.
+ *
+ * @method text
+ * @param {String} value Optional innerText value to set on each element.
+ * @return {tinymce.dom.DomQuery/String} Current set or the innerText of the first element.
+ */
+ text: function (value) {
+ var self = this, i;
+
+ if (isDefined(value)) {
+ i = self.length;
+ while (i--) {
+ if ("innerText" in self[i]) {
+ self[i].innerText = value;
+ } else {
+ self[0].textContent = value;
+ }
+ }
+
+ return self;
+ }
+
+ return self[0] ? (self[0].innerText || self[0].textContent) : '';
+ },
+
+ /**
+ * Appends the specified node/html or node set to the current set nodes.
+ *
+ * @method append
+ * @param {String/Element/Array/tinymce.dom.DomQuery} content Content to append to each element in set.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ append: function () {
+ return domManipulate(this, arguments, function (node) {
+ // Either element or Shadow Root
+ if (this.nodeType === 1 || (this.host && this.host.nodeType === 1)) {
+ this.appendChild(node);
+ }
+ });
+ },
+
+ /**
+ * Prepends the specified node/html or node set to the current set nodes.
+ *
+ * @method prepend
+ * @param {String/Element/Array/tinymce.dom.DomQuery} content Content to prepend to each element in set.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ prepend: function () {
+ return domManipulate(this, arguments, function (node) {
+ // Either element or Shadow Root
+ if (this.nodeType === 1 || (this.host && this.host.nodeType === 1)) {
+ this.insertBefore(node, this.firstChild);
+ }
+ }, true);
+ },
+
+ /**
+ * Adds the specified elements before current set nodes.
+ *
+ * @method before
+ * @param {String/Element/Array/tinymce.dom.DomQuery} content Content to add before to each element in set.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ before: function () {
+ var self = this;
+
+ if (self[0] && self[0].parentNode) {
+ return domManipulate(self, arguments, function (node) {
+ this.parentNode.insertBefore(node, this);
+ });
+ }
+
+ return self;
+ },
+
+ /**
+ * Adds the specified elements after current set nodes.
+ *
+ * @method after
+ * @param {String/Element/Array/tinymce.dom.DomQuery} content Content to add after to each element in set.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ after: function () {
+ var self = this;
+
+ if (self[0] && self[0].parentNode) {
+ return domManipulate(self, arguments, function (node) {
+ this.parentNode.insertBefore(node, this.nextSibling);
+ }, true);
+ }
+
+ return self;
+ },
+
+ /**
+ * Appends the specified set nodes to the specified selector/instance.
+ *
+ * @method appendTo
+ * @param {String/Element/Array/tinymce.dom.DomQuery} val Item to append the current set to.
+ * @return {tinymce.dom.DomQuery} Current set with the appended nodes.
+ */
+ appendTo: function (val) {
+ DomQuery(val).append(this);
+
+ return this;
+ },
+
+ /**
+ * Prepends the specified set nodes to the specified selector/instance.
+ *
+ * @method prependTo
+ * @param {String/Element/Array/tinymce.dom.DomQuery} val Item to prepend the current set to.
+ * @return {tinymce.dom.DomQuery} Current set with the prepended nodes.
+ */
+ prependTo: function (val) {
+ DomQuery(val).prepend(this);
+
+ return this;
+ },
+
+ /**
+ * Replaces the nodes in set with the specified content.
+ *
+ * @method replaceWith
+ * @param {String/Element/Array/tinymce.dom.DomQuery} content Content to replace nodes with.
+ * @return {tinymce.dom.DomQuery} Set with replaced nodes.
+ */
+ replaceWith: function (content) {
+ return this.before(content).remove();
+ },
+
+ /**
+ * Wraps all elements in set with the specified wrapper.
+ *
+ * @method wrap
+ * @param {String/Element/Array/tinymce.dom.DomQuery} content Content to wrap nodes with.
+ * @return {tinymce.dom.DomQuery} Set with wrapped nodes.
+ */
+ wrap: function (content) {
+ return wrap(this, content);
+ },
+
+ /**
+ * Wraps all nodes in set with the specified wrapper. If the nodes are siblings all of them
+ * will be wrapped in the same wrapper.
+ *
+ * @method wrapAll
+ * @param {String/Element/Array/tinymce.dom.DomQuery} content Content to wrap nodes with.
+ * @return {tinymce.dom.DomQuery} Set with wrapped nodes.
+ */
+ wrapAll: function (content) {
+ return wrap(this, content, true);
+ },
+
+ /**
+ * Wraps all elements inner contents in set with the specified wrapper.
+ *
+ * @method wrapInner
+ * @param {String/Element/Array/tinymce.dom.DomQuery} content Content to wrap nodes with.
+ * @return {tinymce.dom.DomQuery} Set with wrapped nodes.
+ */
+ wrapInner: function (content) {
+ this.each(function () {
+ DomQuery(this).contents().wrapAll(content);
+ });
+
+ return this;
+ },
+
+ /**
+ * Unwraps all elements by removing the parent element of each item in set.
+ *
+ * @method unwrap
+ * @return {tinymce.dom.DomQuery} Set with unwrapped nodes.
+ */
+ unwrap: function () {
+ return this.parent().each(function () {
+ DomQuery(this).replaceWith(this.childNodes);
+ });
+ },
+
+ /**
+ * Clones all nodes in set.
+ *
+ * @method clone
+ * @return {tinymce.dom.DomQuery} Set with cloned nodes.
+ */
+ clone: function () {
+ var result = [];
+
+ this.each(function () {
+ result.push(this.cloneNode(true));
+ });
+
+ return DomQuery(result);
+ },
+
+ /**
+ * Adds the specified class name to the current set elements.
+ *
+ * @method addClass
+ * @param {String} className Class name to add.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ addClass: function (className) {
+ return this.toggleClass(className, true);
+ },
+
+ /**
+ * Removes the specified class name to the current set elements.
+ *
+ * @method removeClass
+ * @param {String} className Class name to remove.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ removeClass: function (className) {
+ return this.toggleClass(className, false);
+ },
+
+ /**
+ * Toggles the specified class name on the current set elements.
+ *
+ * @method toggleClass
+ * @param {String} className Class name to add/remove.
+ * @param {Boolean} state Optional state to toggle on/off.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ toggleClass: function (className, state) {
+ var self = this;
+
+ // Functions are not supported
+ if (typeof className != 'string') {
+ return self;
+ }
+
+ if (className.indexOf(' ') !== -1) {
+ each(className.split(' '), function () {
+ self.toggleClass(this, state);
+ });
+ } else {
+ self.each(function (index, node) {
+ var existingClassName, classState;
+
+ classState = hasClass(node, className);
+ if (classState !== state) {
+ existingClassName = node.className;
+
+ if (classState) {
+ node.className = trim((" " + existingClassName + " ").replace(' ' + className + ' ', ' '));
+ } else {
+ node.className += existingClassName ? ' ' + className : className;
+ }
+ }
+ });
+ }
+
+ return self;
+ },
+
+ /**
+ * Returns true/false if the first item in set has the specified class.
+ *
+ * @method hasClass
+ * @param {String} className Class name to check for.
+ * @return {Boolean} True/false if the set has the specified class.
+ */
+ hasClass: function (className) {
+ return hasClass(this[0], className);
+ },
+
+ /**
+ * Executes the callback function for each item DomQuery collection. If you return false in the
+ * callback it will break the loop.
+ *
+ * @method each
+ * @param {function} callback Callback function to execute for each item.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ each: function (callback) {
+ return each(this, callback);
+ },
+
+ /**
+ * Binds an event with callback function to the elements in set.
+ *
+ * @method on
+ * @param {String} name Name of the event to bind.
+ * @param {function} callback Callback function to execute when the event occurs.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ on: function (name, callback) {
+ return this.each(function () {
+ Event.bind(this, name, callback);
+ });
+ },
+
+ /**
+ * Unbinds an event with callback function to the elements in set.
+ *
+ * @method off
+ * @param {String} name Optional name of the event to bind.
+ * @param {function} callback Optional callback function to execute when the event occurs.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ off: function (name, callback) {
+ return this.each(function () {
+ Event.unbind(this, name, callback);
+ });
+ },
+
+ /**
+ * Triggers the specified event by name or event object.
+ *
+ * @method trigger
+ * @param {String/Object} name Name of the event to trigger or event object.
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ trigger: function (name) {
+ return this.each(function () {
+ if (typeof name == 'object') {
+ Event.fire(this, name.type, name);
+ } else {
+ Event.fire(this, name);
+ }
+ });
+ },
+
+ /**
+ * Shows all elements in set.
+ *
+ * @method show
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ show: function () {
+ return this.css('display', '');
+ },
+
+ /**
+ * Hides all elements in set.
+ *
+ * @method hide
+ * @return {tinymce.dom.DomQuery} Current set.
+ */
+ hide: function () {
+ return this.css('display', 'none');
+ },
+
+ /**
+ * Slices the current set.
+ *
+ * @method slice
+ * @param {Number} start Start index to slice at.
+ * @param {Number} end Optional end index to end slice at.
+ * @return {tinymce.dom.DomQuery} Sliced set.
+ */
+ slice: function () {
+ return new DomQuery(slice.apply(this, arguments));
+ },
+
+ /**
+ * Makes the set equal to the specified index.
+ *
+ * @method eq
+ * @param {Number} index Index to set it equal to.
+ * @return {tinymce.dom.DomQuery} Single item set.
+ */
+ eq: function (index) {
+ return index === -1 ? this.slice(index) : this.slice(index, +index + 1);
+ },
+
+ /**
+ * Makes the set equal to first element in set.
+ *
+ * @method first
+ * @return {tinymce.dom.DomQuery} Single item set.
+ */
+ first: function () {
+ return this.eq(0);
+ },
+
+ /**
+ * Makes the set equal to last element in set.
+ *
+ * @method last
+ * @return {tinymce.dom.DomQuery} Single item set.
+ */
+ last: function () {
+ return this.eq(-1);
+ },
+
+ /**
+ * Finds elements by the specified selector for each element in set.
+ *
+ * @method find
+ * @param {String} selector Selector to find elements by.
+ * @return {tinymce.dom.DomQuery} Set with matches elements.
+ */
+ find: function (selector) {
+ var i, l, ret = [];
+
+ for (i = 0, l = this.length; i < l; i++) {
+ DomQuery.find(selector, this[i], ret);
+ }
+
+ return DomQuery(ret);
+ },
+
+ /**
+ * Filters the current set with the specified selector.
+ *
+ * @method filter
+ * @param {String/function} selector Selector to filter elements by.
+ * @return {tinymce.dom.DomQuery} Set with filtered elements.
+ */
+ filter: function (selector) {
+ if (typeof selector == 'function') {
+ return DomQuery(grep(this.toArray(), function (item, i) {
+ return selector(i, item);
+ }));
+ }
+
+ return DomQuery(DomQuery.filter(selector, this.toArray()));
+ },
+
+ /**
+ * Gets the current node or any parent matching the specified selector.
+ *
+ * @method closest
+ * @param {String/Element/tinymce.dom.DomQuery} selector Selector or element to find.
+ * @return {tinymce.dom.DomQuery} Set with closest elements.
+ */
+ closest: function (selector) {
+ var result = [];
+
+ if (selector instanceof DomQuery) {
+ selector = selector[0];
+ }
+
+ this.each(function (i, node) {
+ while (node) {
+ if (typeof selector == 'string' && DomQuery(node).is(selector)) {
+ result.push(node);
+ break;
+ } else if (node == selector) {
+ result.push(node);
+ break;
+ }
+
+ node = node.parentNode;
+ }
+ });
+
+ return DomQuery(result);
+ },
+
+ /**
+ * Returns the offset of the first element in set or sets the top/left css properties of all elements in set.
+ *
+ * @method offset
+ * @param {Object} offset Optional offset object to set on each item.
+ * @return {Object/tinymce.dom.DomQuery} Returns the first element offset or the current set if you specified an offset.
+ */
+ offset: function (offset) {
+ var elm, doc, docElm;
+ var x = 0, y = 0, pos;
+
+ if (!offset) {
+ elm = this[0];
+
+ if (elm) {
+ doc = elm.ownerDocument;
+ docElm = doc.documentElement;
+
+ if (elm.getBoundingClientRect) {
+ pos = elm.getBoundingClientRect();
+ x = pos.left + (docElm.scrollLeft || doc.body.scrollLeft) - docElm.clientLeft;
+ y = pos.top + (docElm.scrollTop || doc.body.scrollTop) - docElm.clientTop;
+ }
+ }
+
+ return {
+ left: x,
+ top: y
+ };
+ }
+
+ return this.css(offset);
+ },
+
+ push: push,
+ sort: [].sort,
+ splice: [].splice
+ };
+
+ // Static members
+ Tools.extend(DomQuery, {
+ /**
+ * Extends the specified object with one or more objects.
+ *
+ * @static
+ * @method extend
+ * @param {Object} target Target object to extend with new items.
+ * @param {Object..} object Object to extend the target with.
+ * @return {Object} Extended input object.
+ */
+ extend: Tools.extend,
+
+ /**
+ * Creates an array out of an array like object.
+ *
+ * @static
+ * @method makeArray
+ * @param {Object} object Object to convert to array.
+ * @return {Array} Array produced from object.
+ */
+ makeArray: function (object) {
+ if (isWindow(object) || object.nodeType) {
+ return [object];
+ }
+
+ return Tools.toArray(object);
+ },
+
+ /**
+ * Returns the index of the specified item inside the array.
+ *
+ * @static
+ * @method inArray
+ * @param {Object} item Item to look for.
+ * @param {Array} array Array to look for item in.
+ * @return {Number} Index of the item or -1.
+ */
+ inArray: inArray,
+
+ /**
+ * Returns true/false if the specified object is an array or not.
+ *
+ * @static
+ * @method isArray
+ * @param {Object} array Object to check if it's an array or not.
+ * @return {Boolean} True/false if the object is an array.
+ */
+ isArray: Tools.isArray,
+
+ /**
+ * Executes the callback function for each item in array/object. If you return false in the
+ * callback it will break the loop.
+ *
+ * @static
+ * @method each
+ * @param {Object} obj Object to iterate.
+ * @param {function} callback Callback function to execute for each item.
+ */
+ each: each,
+
+ /**
+ * Removes whitespace from the beginning and end of a string.
+ *
+ * @static
+ * @method trim
+ * @param {String} str String to remove whitespace from.
+ * @return {String} New string with removed whitespace.
+ */
+ trim: trim,
+
+ /**
+ * Filters out items from the input array by calling the specified function for each item.
+ * If the function returns false the item will be excluded if it returns true it will be included.
+ *
+ * @static
+ * @method grep
+ * @param {Array} array Array of items to loop though.
+ * @param {function} callback Function to call for each item. Include/exclude depends on it's return value.
+ * @return {Array} New array with values imported and filtered based in input.
+ * @example
+ * // Filter out some items, this will return an array with 4 and 5
+ * var items = DomQuery.grep([1, 2, 3, 4, 5], function(v) {return v > 3;});
+ */
+ grep: grep,
+
+ // Sizzle
+ find: Sizzle,
+ expr: Sizzle.selectors,
+ unique: Sizzle.uniqueSort,
+ text: Sizzle.getText,
+ contains: Sizzle.contains,
+ filter: function (expr, elems, not) {
+ var i = elems.length;
+
+ if (not) {
+ expr = ":not(" + expr + ")";
+ }
+
+ while (i--) {
+ if (elems[i].nodeType != 1) {
+ elems.splice(i, 1);
+ }
+ }
+
+ if (elems.length === 1) {
+ elems = DomQuery.find.matchesSelector(elems[0], expr) ? [elems[0]] : [];
+ } else {
+ elems = DomQuery.find.matches(expr, elems);
+ }
+
+ return elems;
+ }
+ });
+
+ function dir(el, prop, until) {
+ var matched = [], cur = el[prop];
+
+ if (typeof until != 'string' && until instanceof DomQuery) {
+ until = until[0];
+ }
+
+ while (cur && cur.nodeType !== 9) {
+ if (until !== undefined) {
+ if (cur === until) {
+ break;
+ }
+
+ if (typeof until == 'string' && DomQuery(cur).is(until)) {
+ break;
+ }
+ }
+
+ if (cur.nodeType === 1) {
+ matched.push(cur);
+ }
+
+ cur = cur[prop];
+ }
+
+ return matched;
+ }
+
+ function sibling(node, siblingName, nodeType, until) {
+ var result = [];
+
+ if (until instanceof DomQuery) {
+ until = until[0];
+ }
+
+ for (; node; node = node[siblingName]) {
+ if (nodeType && node.nodeType !== nodeType) {
+ continue;
+ }
+
+ if (until !== undefined) {
+ if (node === until) {
+ break;
+ }
+
+ if (typeof until == 'string' && DomQuery(node).is(until)) {
+ break;
+ }
+ }
+
+ result.push(node);
+ }
+
+ return result;
+ }
+
+ function firstSibling(node, siblingName, nodeType) {
+ for (node = node[siblingName]; node; node = node[siblingName]) {
+ if (node.nodeType == nodeType) {
+ return node;
+ }
+ }
+
+ return null;
+ }
+
+ each({
+ /**
+ * Returns a new collection with the parent of each item in current collection matching the optional selector.
+ *
+ * @method parent
+ * @param {Element/tinymce.dom.DomQuery} node Node to match parents against.
+ * @return {tinymce.dom.DomQuery} New DomQuery instance with all matching parents.
+ */
+ parent: function (node) {
+ var parent = node.parentNode;
+
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+
+ /**
+ * Returns a new collection with the all the parents of each item in current collection matching the optional selector.
+ *
+ * @method parents
+ * @param {Element/tinymce.dom.DomQuery} node Node to match parents against.
+ * @return {tinymce.dom.DomQuery} New DomQuery instance with all matching parents.
+ */
+ parents: function (node) {
+ return dir(node, "parentNode");
+ },
+
+ /**
+ * Returns a new collection with next sibling of each item in current collection matching the optional selector.
+ *
+ * @method next
+ * @param {Element/tinymce.dom.DomQuery} node Node to match the next element against.
+ * @return {tinymce.dom.DomQuery} New DomQuery instance with all matching elements.
+ */
+ next: function (node) {
+ return firstSibling(node, 'nextSibling', 1);
+ },
+
+ /**
+ * Returns a new collection with previous sibling of each item in current collection matching the optional selector.
+ *
+ * @method prev
+ * @param {Element/tinymce.dom.DomQuery} node Node to match the previous element against.
+ * @return {tinymce.dom.DomQuery} New DomQuery instance with all matching elements.
+ */
+ prev: function (node) {
+ return firstSibling(node, 'previousSibling', 1);
+ },
+
+ /**
+ * Returns all child elements matching the optional selector.
+ *
+ * @method children
+ * @param {Element/tinymce.dom.DomQuery} node Node to match the elements against.
+ * @return {tinymce.dom.DomQuery} New DomQuery instance with all matching elements.
+ */
+ children: function (node) {
+ return sibling(node.firstChild, 'nextSibling', 1);
+ },
+
+ /**
+ * Returns all child nodes matching the optional selector.
+ *
+ * @method contents
+ * @param {Element/tinymce.dom.DomQuery} node Node to get the contents of.
+ * @return {tinymce.dom.DomQuery} New DomQuery instance with all matching elements.
+ */
+ contents: function (node) {
+ return Tools.toArray((node.nodeName === "iframe" ? node.contentDocument || node.contentWindow.document : node).childNodes);
+ }
+ }, function (name, fn) {
+ DomQuery.fn[name] = function (selector) {
+ var self = this, result = [];
+
+ self.each(function () {
+ var nodes = fn.call(result, this, selector, result);
+
+ if (nodes) {
+ if (DomQuery.isArray(nodes)) {
+ result.push.apply(result, nodes);
+ } else {
+ result.push(nodes);
+ }
+ }
+ });
+
+ // If traversing on multiple elements we might get the same elements twice
+ if (this.length > 1) {
+ if (!skipUniques[name]) {
+ result = DomQuery.unique(result);
+ }
+
+ if (name.indexOf('parents') === 0) {
+ result = result.reverse();
+ }
+ }
+
+ result = DomQuery(result);
+
+ if (selector) {
+ return result.filter(selector);
+ }
+
+ return result;
+ };
+ });
+
+ each({
+ /**
+ * Returns a new collection with the all the parents until the matching selector/element
+ * of each item in current collection matching the optional selector.
+ *
+ * @method parentsUntil
+ * @param {Element/tinymce.dom.DomQuery} node Node to find parent of.
+ * @param {String/Element/tinymce.dom.DomQuery} until Until the matching selector or element.
+ * @return {tinymce.dom.DomQuery} New DomQuery instance with all matching parents.
+ */
+ parentsUntil: function (node, until) {
+ return dir(node, "parentNode", until);
+ },
+
+ /**
+ * Returns a new collection with all next siblings of each item in current collection matching the optional selector.
+ *
+ * @method nextUntil
+ * @param {Element/tinymce.dom.DomQuery} node Node to find next siblings on.
+ * @param {String/Element/tinymce.dom.DomQuery} until Until the matching selector or element.
+ * @return {tinymce.dom.DomQuery} New DomQuery instance with all matching elements.
+ */
+ nextUntil: function (node, until) {
+ return sibling(node, 'nextSibling', 1, until).slice(1);
+ },
+
+ /**
+ * Returns a new collection with all previous siblings of each item in current collection matching the optional selector.
+ *
+ * @method prevUntil
+ * @param {Element/tinymce.dom.DomQuery} node Node to find previous siblings on.
+ * @param {String/Element/tinymce.dom.DomQuery} until Until the matching selector or element.
+ * @return {tinymce.dom.DomQuery} New DomQuery instance with all matching elements.
+ */
+ prevUntil: function (node, until) {
+ return sibling(node, 'previousSibling', 1, until).slice(1);
+ }
+ }, function (name, fn) {
+ DomQuery.fn[name] = function (selector, filter) {
+ var self = this, result = [];
+
+ self.each(function () {
+ var nodes = fn.call(result, this, selector, result);
+
+ if (nodes) {
+ if (DomQuery.isArray(nodes)) {
+ result.push.apply(result, nodes);
+ } else {
+ result.push(nodes);
+ }
+ }
+ });
+
+ // If traversing on multiple elements we might get the same elements twice
+ if (this.length > 1) {
+ result = DomQuery.unique(result);
+
+ if (name.indexOf('parents') === 0 || name === 'prevUntil') {
+ result = result.reverse();
+ }
+ }
+
+ result = DomQuery(result);
+
+ if (filter) {
+ return result.filter(filter);
+ }
+
+ return result;
+ };
+ });
+
+ /**
+ * Returns true/false if the current set items matches the selector.
+ *
+ * @method is
+ * @param {String} selector Selector to match the elements against.
+ * @return {Boolean} True/false if the current set matches the selector.
+ */
+ DomQuery.fn.is = function (selector) {
+ return !!selector && this.filter(selector).length > 0;
+ };
+
+ DomQuery.fn.init.prototype = DomQuery.fn;
+
+ DomQuery.overrideDefaults = function (callback) {
+ var defaults;
+
+ function sub(selector, context) {
+ defaults = defaults || callback();
+
+ if (arguments.length === 0) {
+ selector = defaults.element;
+ }
+
+ if (!context) {
+ context = defaults.context;
+ }
+
+ return new sub.fn.init(selector, context);
+ }
+
+ DomQuery.extend(sub, this);
+
+ return sub;
+ };
+
+ function appendHooks(targetHooks, prop, hooks) {
+ each(hooks, function (name, func) {
+ targetHooks[name] = targetHooks[name] || {};
+ targetHooks[name][prop] = func;
+ });
+ }
+
+ if (Env.ie && Env.ie < 8) {
+ appendHooks(attrHooks, 'get', {
+ maxlength: function (elm) {
+ var value = elm.maxLength;
+
+ if (value === 0x7fffffff) {
+ return undef;
+ }
+
+ return value;
+ },
+
+ size: function (elm) {
+ var value = elm.size;
+
+ if (value === 20) {
+ return undef;
+ }
+
+ return value;
+ },
+
+ 'class': function (elm) {
+ return elm.className;
+ },
+
+ style: function (elm) {
+ var value = elm.style.cssText;
+
+ if (value.length === 0) {
+ return undef;
+ }
+
+ return value;
+ }
+ });
+
+ appendHooks(attrHooks, 'set', {
+ 'class': function (elm, value) {
+ elm.className = value;
+ },
+
+ style: function (elm, value) {
+ elm.style.cssText = value;
+ }
+ });
+ }
+
+ if (Env.ie && Env.ie < 9) {
+ /*jshint sub:true */
+ /*eslint dot-notation: 0*/
+ cssFix['float'] = 'styleFloat';
+
+ appendHooks(cssHooks, 'set', {
+ opacity: function (elm, value) {
+ var style = elm.style;
+
+ if (value === null || value === '') {
+ style.removeAttribute('filter');
+ } else {
+ style.zoom = 1;
+ style.filter = 'alpha(opacity=' + (value * 100) + ')';
+ }
+ }
+ });
+ }
+
+ DomQuery.attrHooks = attrHooks;
+ DomQuery.cssHooks = cssHooks;
+
+ return DomQuery;
+ }
+);
+
+/**
+ * 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 _
+ function encode(str) {
+ isEncoded = true;
+
+ return encodingLookup[str];
+ }
+
+ // Decodes the specified string by replacing all _ 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
+ // 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 = {
+ '\"': '"', // Needs to be escaped since the YUI compressor would otherwise break the code
+ "'": ''',
+ '<': '<',
+ '>': '>',
+ '&': '&',
+ '\u0060': '`'
+ };
+
+ // Reverse lookup table for raw entities
+ reverseEntities = {
+ '<': '<',
+ '>': '>',
+ '&': '&',
+ '"': '"',
+ ''': "'"
+ };
+
+ // 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) {
+ return baseEntities[chr] || entities[chr] || '' + chr.charCodeAt(0) + ';' || chr;
+ });
+ }
+
+ 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;
+ }
+);
+
+/**
+ * Range.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
+ */
+
+/**
+ * Old IE Range.
+ *
+ * @private
+ * @class tinymce.dom.Range
+ */
+define(
+ 'tinymce.core.dom.Range',
+ [
+ "tinymce.core.util.Tools"
+ ],
+ function (Tools) {
+ // Range constructor
+ function Range(dom) {
+ var self = this,
+ doc = dom.doc,
+ EXTRACT = 0,
+ CLONE = 1,
+ DELETE = 2,
+ TRUE = true,
+ FALSE = false,
+ START_OFFSET = 'startOffset',
+ START_CONTAINER = 'startContainer',
+ END_CONTAINER = 'endContainer',
+ END_OFFSET = 'endOffset',
+ extend = Tools.extend,
+ nodeIndex = dom.nodeIndex;
+
+ function createDocumentFragment() {
+ return doc.createDocumentFragment();
+ }
+
+ function setStart(n, o) {
+ _setEndPoint(TRUE, n, o);
+ }
+
+ function setEnd(n, o) {
+ _setEndPoint(FALSE, n, o);
+ }
+
+ function setStartBefore(n) {
+ setStart(n.parentNode, nodeIndex(n));
+ }
+
+ function setStartAfter(n) {
+ setStart(n.parentNode, nodeIndex(n) + 1);
+ }
+
+ function setEndBefore(n) {
+ setEnd(n.parentNode, nodeIndex(n));
+ }
+
+ function setEndAfter(n) {
+ setEnd(n.parentNode, nodeIndex(n) + 1);
+ }
+
+ function collapse(ts) {
+ if (ts) {
+ self[END_CONTAINER] = self[START_CONTAINER];
+ self[END_OFFSET] = self[START_OFFSET];
+ } else {
+ self[START_CONTAINER] = self[END_CONTAINER];
+ self[START_OFFSET] = self[END_OFFSET];
+ }
+
+ self.collapsed = TRUE;
+ }
+
+ function selectNode(n) {
+ setStartBefore(n);
+ setEndAfter(n);
+ }
+
+ function selectNodeContents(n) {
+ setStart(n, 0);
+ setEnd(n, n.nodeType === 1 ? n.childNodes.length : n.nodeValue.length);
+ }
+
+ function compareBoundaryPoints(h, r) {
+ var sc = self[START_CONTAINER], so = self[START_OFFSET], ec = self[END_CONTAINER], eo = self[END_OFFSET],
+ rsc = r.startContainer, rso = r.startOffset, rec = r.endContainer, reo = r.endOffset;
+
+ // Check START_TO_START
+ if (h === 0) {
+ return _compareBoundaryPoints(sc, so, rsc, rso);
+ }
+
+ // Check START_TO_END
+ if (h === 1) {
+ return _compareBoundaryPoints(ec, eo, rsc, rso);
+ }
+
+ // Check END_TO_END
+ if (h === 2) {
+ return _compareBoundaryPoints(ec, eo, rec, reo);
+ }
+
+ // Check END_TO_START
+ if (h === 3) {
+ return _compareBoundaryPoints(sc, so, rec, reo);
+ }
+ }
+
+ function deleteContents() {
+ _traverse(DELETE);
+ }
+
+ function extractContents() {
+ return _traverse(EXTRACT);
+ }
+
+ function cloneContents() {
+ return _traverse(CLONE);
+ }
+
+ function insertNode(n) {
+ var startContainer = this[START_CONTAINER],
+ startOffset = this[START_OFFSET], nn, o;
+
+ // Node is TEXT_NODE or CDATA
+ if ((startContainer.nodeType === 3 || startContainer.nodeType === 4) && startContainer.nodeValue) {
+ if (!startOffset) {
+ // At the start of text
+ startContainer.parentNode.insertBefore(n, startContainer);
+ } else if (startOffset >= startContainer.nodeValue.length) {
+ // At the end of text
+ dom.insertAfter(n, startContainer);
+ } else {
+ // Middle, need to split
+ nn = startContainer.splitText(startOffset);
+ startContainer.parentNode.insertBefore(n, nn);
+ }
+ } else {
+ // Insert element node
+ if (startContainer.childNodes.length > 0) {
+ o = startContainer.childNodes[startOffset];
+ }
+
+ if (o) {
+ startContainer.insertBefore(n, o);
+ } else {
+ if (startContainer.nodeType == 3) {
+ dom.insertAfter(n, startContainer);
+ } else {
+ startContainer.appendChild(n);
+ }
+ }
+ }
+ }
+
+ function surroundContents(n) {
+ var f = self.extractContents();
+
+ self.insertNode(n);
+ n.appendChild(f);
+ self.selectNode(n);
+ }
+
+ function cloneRange() {
+ return extend(new Range(dom), {
+ startContainer: self[START_CONTAINER],
+ startOffset: self[START_OFFSET],
+ endContainer: self[END_CONTAINER],
+ endOffset: self[END_OFFSET],
+ collapsed: self.collapsed,
+ commonAncestorContainer: self.commonAncestorContainer
+ });
+ }
+
+ // Private methods
+
+ function _getSelectedNode(container, offset) {
+ var child;
+
+ // TEXT_NODE
+ if (container.nodeType == 3) {
+ return container;
+ }
+
+ if (offset < 0) {
+ return container;
+ }
+
+ child = container.firstChild;
+ while (child && offset > 0) {
+ --offset;
+ child = child.nextSibling;
+ }
+
+ if (child) {
+ return child;
+ }
+
+ return container;
+ }
+
+ function _isCollapsed() {
+ return (self[START_CONTAINER] == self[END_CONTAINER] && self[START_OFFSET] == self[END_OFFSET]);
+ }
+
+ function _compareBoundaryPoints(containerA, offsetA, containerB, offsetB) {
+ var c, offsetC, n, cmnRoot, childA, childB;
+
+ // In the first case the boundary-points have the same container. A is before B
+ // if its offset is less than the offset of B, A is equal to B if its offset is
+ // equal to the offset of B, and A is after B if its offset is greater than the
+ // offset of B.
+ if (containerA == containerB) {
+ if (offsetA == offsetB) {
+ return 0; // equal
+ }
+
+ if (offsetA < offsetB) {
+ return -1; // before
+ }
+
+ return 1; // after
+ }
+
+ // In the second case a child node C of the container of A is an ancestor
+ // container of B. In this case, A is before B if the offset of A is less than or
+ // equal to the index of the child node C and A is after B otherwise.
+ c = containerB;
+ while (c && c.parentNode != containerA) {
+ c = c.parentNode;
+ }
+
+ if (c) {
+ offsetC = 0;
+ n = containerA.firstChild;
+
+ while (n != c && offsetC < offsetA) {
+ offsetC++;
+ n = n.nextSibling;
+ }
+
+ if (offsetA <= offsetC) {
+ return -1; // before
+ }
+
+ return 1; // after
+ }
+
+ // In the third case a child node C of the container of B is an ancestor container
+ // of A. In this case, A is before B if the index of the child node C is less than
+ // the offset of B and A is after B otherwise.
+ c = containerA;
+ while (c && c.parentNode != containerB) {
+ c = c.parentNode;
+ }
+
+ if (c) {
+ offsetC = 0;
+ n = containerB.firstChild;
+
+ while (n != c && offsetC < offsetB) {
+ offsetC++;
+ n = n.nextSibling;
+ }
+
+ if (offsetC < offsetB) {
+ return -1; // before
+ }
+
+ return 1; // after
+ }
+
+ // In the fourth case, none of three other cases hold: the containers of A and B
+ // are siblings or descendants of sibling nodes. In this case, A is before B if
+ // the container of A is before the container of B in a pre-order traversal of the
+ // Ranges' context tree and A is after B otherwise.
+ cmnRoot = dom.findCommonAncestor(containerA, containerB);
+ childA = containerA;
+
+ while (childA && childA.parentNode != cmnRoot) {
+ childA = childA.parentNode;
+ }
+
+ if (!childA) {
+ childA = cmnRoot;
+ }
+
+ childB = containerB;
+ while (childB && childB.parentNode != cmnRoot) {
+ childB = childB.parentNode;
+ }
+
+ if (!childB) {
+ childB = cmnRoot;
+ }
+
+ if (childA == childB) {
+ return 0; // equal
+ }
+
+ n = cmnRoot.firstChild;
+ while (n) {
+ if (n == childA) {
+ return -1; // before
+ }
+
+ if (n == childB) {
+ return 1; // after
+ }
+
+ n = n.nextSibling;
+ }
+ }
+
+ function _setEndPoint(st, n, o) {
+ var ec, sc;
+
+ if (st) {
+ self[START_CONTAINER] = n;
+ self[START_OFFSET] = o;
+ } else {
+ self[END_CONTAINER] = n;
+ self[END_OFFSET] = o;
+ }
+
+ // If one boundary-point of a Range is set to have a root container
+ // other than the current one for the Range, the Range is collapsed to
+ // the new position. This enforces the restriction that both boundary-
+ // points of a Range must have the same root container.
+ ec = self[END_CONTAINER];
+ while (ec.parentNode) {
+ ec = ec.parentNode;
+ }
+
+ sc = self[START_CONTAINER];
+ while (sc.parentNode) {
+ sc = sc.parentNode;
+ }
+
+ if (sc == ec) {
+ // The start position of a Range is guaranteed to never be after the
+ // end position. To enforce this restriction, if the start is set to
+ // be at a position after the end, the Range is collapsed to that
+ // position.
+ if (_compareBoundaryPoints(self[START_CONTAINER], self[START_OFFSET], self[END_CONTAINER], self[END_OFFSET]) > 0) {
+ self.collapse(st);
+ }
+ } else {
+ self.collapse(st);
+ }
+
+ self.collapsed = _isCollapsed();
+ self.commonAncestorContainer = dom.findCommonAncestor(self[START_CONTAINER], self[END_CONTAINER]);
+ }
+
+ function _traverse(how) {
+ var c, endContainerDepth = 0, startContainerDepth = 0, p, depthDiff, startNode, endNode, sp, ep;
+
+ if (self[START_CONTAINER] == self[END_CONTAINER]) {
+ return _traverseSameContainer(how);
+ }
+
+ for (c = self[END_CONTAINER], p = c.parentNode; p; c = p, p = p.parentNode) {
+ if (p == self[START_CONTAINER]) {
+ return _traverseCommonStartContainer(c, how);
+ }
+
+ ++endContainerDepth;
+ }
+
+ for (c = self[START_CONTAINER], p = c.parentNode; p; c = p, p = p.parentNode) {
+ if (p == self[END_CONTAINER]) {
+ return _traverseCommonEndContainer(c, how);
+ }
+
+ ++startContainerDepth;
+ }
+
+ depthDiff = startContainerDepth - endContainerDepth;
+
+ startNode = self[START_CONTAINER];
+ while (depthDiff > 0) {
+ startNode = startNode.parentNode;
+ depthDiff--;
+ }
+
+ endNode = self[END_CONTAINER];
+ while (depthDiff < 0) {
+ endNode = endNode.parentNode;
+ depthDiff++;
+ }
+
+ // ascend the ancestor hierarchy until we have a common parent.
+ for (sp = startNode.parentNode, ep = endNode.parentNode; sp != ep; sp = sp.parentNode, ep = ep.parentNode) {
+ startNode = sp;
+ endNode = ep;
+ }
+
+ return _traverseCommonAncestors(startNode, endNode, how);
+ }
+
+ function _traverseSameContainer(how) {
+ var frag, s, sub, n, cnt, sibling, xferNode, start, len;
+
+ if (how != DELETE) {
+ frag = createDocumentFragment();
+ }
+
+ // If selection is empty, just return the fragment
+ if (self[START_OFFSET] == self[END_OFFSET]) {
+ return frag;
+ }
+
+ // Text node needs special case handling
+ if (self[START_CONTAINER].nodeType == 3) { // TEXT_NODE
+ // get the substring
+ s = self[START_CONTAINER].nodeValue;
+ sub = s.substring(self[START_OFFSET], self[END_OFFSET]);
+
+ // set the original text node to its new value
+ if (how != CLONE) {
+ n = self[START_CONTAINER];
+ start = self[START_OFFSET];
+ len = self[END_OFFSET] - self[START_OFFSET];
+
+ if (start === 0 && len >= n.nodeValue.length - 1) {
+ n.parentNode.removeChild(n);
+ } else {
+ n.deleteData(start, len);
+ }
+
+ // Nothing is partially selected, so collapse to start point
+ self.collapse(TRUE);
+ }
+
+ if (how == DELETE) {
+ return;
+ }
+
+ if (sub.length > 0) {
+ frag.appendChild(doc.createTextNode(sub));
+ }
+
+ return frag;
+ }
+
+ // Copy nodes between the start/end offsets.
+ n = _getSelectedNode(self[START_CONTAINER], self[START_OFFSET]);
+ cnt = self[END_OFFSET] - self[START_OFFSET];
+
+ while (n && cnt > 0) {
+ sibling = n.nextSibling;
+ xferNode = _traverseFullySelected(n, how);
+
+ if (frag) {
+ frag.appendChild(xferNode);
+ }
+
+ --cnt;
+ n = sibling;
+ }
+
+ // Nothing is partially selected, so collapse to start point
+ if (how != CLONE) {
+ self.collapse(TRUE);
+ }
+
+ return frag;
+ }
+
+ function _traverseCommonStartContainer(endAncestor, how) {
+ var frag, n, endIdx, cnt, sibling, xferNode;
+
+ if (how != DELETE) {
+ frag = createDocumentFragment();
+ }
+
+ n = _traverseRightBoundary(endAncestor, how);
+
+ if (frag) {
+ frag.appendChild(n);
+ }
+
+ endIdx = nodeIndex(endAncestor);
+ cnt = endIdx - self[START_OFFSET];
+
+ if (cnt <= 0) {
+ // Collapse to just before the endAncestor, which
+ // is partially selected.
+ if (how != CLONE) {
+ self.setEndBefore(endAncestor);
+ self.collapse(FALSE);
+ }
+
+ return frag;
+ }
+
+ n = endAncestor.previousSibling;
+ while (cnt > 0) {
+ sibling = n.previousSibling;
+ xferNode = _traverseFullySelected(n, how);
+
+ if (frag) {
+ frag.insertBefore(xferNode, frag.firstChild);
+ }
+
+ --cnt;
+ n = sibling;
+ }
+
+ // Collapse to just before the endAncestor, which
+ // is partially selected.
+ if (how != CLONE) {
+ self.setEndBefore(endAncestor);
+ self.collapse(FALSE);
+ }
+
+ return frag;
+ }
+
+ function _traverseCommonEndContainer(startAncestor, how) {
+ var frag, startIdx, n, cnt, sibling, xferNode;
+
+ if (how != DELETE) {
+ frag = createDocumentFragment();
+ }
+
+ n = _traverseLeftBoundary(startAncestor, how);
+ if (frag) {
+ frag.appendChild(n);
+ }
+
+ startIdx = nodeIndex(startAncestor);
+ ++startIdx; // Because we already traversed it
+
+ cnt = self[END_OFFSET] - startIdx;
+ n = startAncestor.nextSibling;
+ while (n && cnt > 0) {
+ sibling = n.nextSibling;
+ xferNode = _traverseFullySelected(n, how);
+
+ if (frag) {
+ frag.appendChild(xferNode);
+ }
+
+ --cnt;
+ n = sibling;
+ }
+
+ if (how != CLONE) {
+ self.setStartAfter(startAncestor);
+ self.collapse(TRUE);
+ }
+
+ return frag;
+ }
+
+ function _traverseCommonAncestors(startAncestor, endAncestor, how) {
+ var n, frag, startOffset, endOffset, cnt, sibling, nextSibling;
+
+ if (how != DELETE) {
+ frag = createDocumentFragment();
+ }
+
+ n = _traverseLeftBoundary(startAncestor, how);
+ if (frag) {
+ frag.appendChild(n);
+ }
+
+ startOffset = nodeIndex(startAncestor);
+ endOffset = nodeIndex(endAncestor);
+ ++startOffset;
+
+ cnt = endOffset - startOffset;
+ sibling = startAncestor.nextSibling;
+
+ while (cnt > 0) {
+ nextSibling = sibling.nextSibling;
+ n = _traverseFullySelected(sibling, how);
+
+ if (frag) {
+ frag.appendChild(n);
+ }
+
+ sibling = nextSibling;
+ --cnt;
+ }
+
+ n = _traverseRightBoundary(endAncestor, how);
+
+ if (frag) {
+ frag.appendChild(n);
+ }
+
+ if (how != CLONE) {
+ self.setStartAfter(startAncestor);
+ self.collapse(TRUE);
+ }
+
+ return frag;
+ }
+
+ function _traverseRightBoundary(root, how) {
+ var next = _getSelectedNode(self[END_CONTAINER], self[END_OFFSET] - 1), parent, clonedParent;
+ var prevSibling, clonedChild, clonedGrandParent, isFullySelected = next != self[END_CONTAINER];
+
+ if (next == root) {
+ return _traverseNode(next, isFullySelected, FALSE, how);
+ }
+
+ parent = next.parentNode;
+ clonedParent = _traverseNode(parent, FALSE, FALSE, how);
+
+ while (parent) {
+ while (next) {
+ prevSibling = next.previousSibling;
+ clonedChild = _traverseNode(next, isFullySelected, FALSE, how);
+
+ if (how != DELETE) {
+ clonedParent.insertBefore(clonedChild, clonedParent.firstChild);
+ }
+
+ isFullySelected = TRUE;
+ next = prevSibling;
+ }
+
+ if (parent == root) {
+ return clonedParent;
+ }
+
+ next = parent.previousSibling;
+ parent = parent.parentNode;
+
+ clonedGrandParent = _traverseNode(parent, FALSE, FALSE, how);
+
+ if (how != DELETE) {
+ clonedGrandParent.appendChild(clonedParent);
+ }
+
+ clonedParent = clonedGrandParent;
+ }
+ }
+
+ function _traverseLeftBoundary(root, how) {
+ var next = _getSelectedNode(self[START_CONTAINER], self[START_OFFSET]), isFullySelected = next != self[START_CONTAINER];
+ var parent, clonedParent, nextSibling, clonedChild, clonedGrandParent;
+
+ if (next == root) {
+ return _traverseNode(next, isFullySelected, TRUE, how);
+ }
+
+ parent = next.parentNode;
+ clonedParent = _traverseNode(parent, FALSE, TRUE, how);
+
+ while (parent) {
+ while (next) {
+ nextSibling = next.nextSibling;
+ clonedChild = _traverseNode(next, isFullySelected, TRUE, how);
+
+ if (how != DELETE) {
+ clonedParent.appendChild(clonedChild);
+ }
+
+ isFullySelected = TRUE;
+ next = nextSibling;
+ }
+
+ if (parent == root) {
+ return clonedParent;
+ }
+
+ next = parent.nextSibling;
+ parent = parent.parentNode;
+
+ clonedGrandParent = _traverseNode(parent, FALSE, TRUE, how);
+
+ if (how != DELETE) {
+ clonedGrandParent.appendChild(clonedParent);
+ }
+
+ clonedParent = clonedGrandParent;
+ }
+ }
+
+ function _traverseNode(n, isFullySelected, isLeft, how) {
+ var txtValue, newNodeValue, oldNodeValue, offset, newNode;
+
+ if (isFullySelected) {
+ return _traverseFullySelected(n, how);
+ }
+
+ // TEXT_NODE
+ if (n.nodeType == 3) {
+ txtValue = n.nodeValue;
+
+ if (isLeft) {
+ offset = self[START_OFFSET];
+ newNodeValue = txtValue.substring(offset);
+ oldNodeValue = txtValue.substring(0, offset);
+ } else {
+ offset = self[END_OFFSET];
+ newNodeValue = txtValue.substring(0, offset);
+ oldNodeValue = txtValue.substring(offset);
+ }
+
+ if (how != CLONE) {
+ n.nodeValue = oldNodeValue;
+ }
+
+ if (how == DELETE) {
+ return;
+ }
+
+ newNode = dom.clone(n, FALSE);
+ newNode.nodeValue = newNodeValue;
+
+ return newNode;
+ }
+
+ if (how == DELETE) {
+ return;
+ }
+
+ return dom.clone(n, FALSE);
+ }
+
+ function _traverseFullySelected(n, how) {
+ if (how != DELETE) {
+ return how == CLONE ? dom.clone(n, TRUE) : n;
+ }
+
+ n.parentNode.removeChild(n);
+ }
+
+ function toStringIE() {
+ return dom.create('body', null, cloneContents()).outerText;
+ }
+
+ extend(self, {
+ // Initial states
+ startContainer: doc,
+ startOffset: 0,
+ endContainer: doc,
+ endOffset: 0,
+ collapsed: TRUE,
+ commonAncestorContainer: doc,
+
+ // Range constants
+ START_TO_START: 0,
+ START_TO_END: 1,
+ END_TO_END: 2,
+ END_TO_START: 3,
+
+ // Public methods
+ setStart: setStart,
+ setEnd: setEnd,
+ setStartBefore: setStartBefore,
+ setStartAfter: setStartAfter,
+ setEndBefore: setEndBefore,
+ setEndAfter: setEndAfter,
+ collapse: collapse,
+ selectNode: selectNode,
+ selectNodeContents: selectNodeContents,
+ compareBoundaryPoints: compareBoundaryPoints,
+ deleteContents: deleteContents,
+ extractContents: extractContents,
+ cloneContents: cloneContents,
+ insertNode: insertNode,
+ surroundContents: surroundContents,
+ cloneRange: cloneRange,
+ toStringIE: toStringIE
+ });
+
+ return self;
+ }
+
+ // Older IE versions doesn't let you override toString by it's constructor so we have to stick it in the prototype
+ Range.prototype.toString = function () {
+ return this.toStringIE();
+ };
+
+ return Range;
+ }
+);
+
+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
+ };
+ }
+);
+
+defineGlobal("global!Object", Object);
+define(
+ 'ephox.katamari.api.Option',
+
+ [
+ 'ephox.katamari.api.Fun',
+ 'global!Object'
+ ],
+
+ function (Fun, Object) {
+
+ var never = Fun.never;
+ var always = Fun.always;
+
+ /**
+ Option objects support the following methods:
+
+ fold :: this Option a -> ((() -> b, a -> b)) -> Option b
+
+ is :: this Option a -> a -> Boolean
+
+ isSome :: this Option a -> () -> Boolean
+
+ isNone :: this Option a -> () -> Boolean
+
+ getOr :: this Option a -> a -> a
+
+ getOrThunk :: this Option a -> (() -> a) -> a
+
+ getOrDie :: this Option a -> String -> a
+
+ or :: this Option a -> Option a -> Option a
+ - if some: return self
+ - if none: return opt
+
+ orThunk :: this Option a -> (() -> Option a) -> Option a
+ - Same as "or", but uses a thunk instead of a value
+
+ map :: this Option a -> (a -> b) -> Option b
+ - "fmap" operation on the Option Functor.
+ - same as 'each'
+
+ ap :: this Option a -> Option (a -> b) -> Option b
+ - "apply" operation on the Option Apply/Applicative.
+ - Equivalent to <*> in Haskell/PureScript.
+
+ each :: this Option a -> (a -> b) -> Option b
+ - same as 'map'
+
+ bind :: this Option a -> (a -> Option b) -> Option b
+ - "bind"/"flatMap" operation on the Option Bind/Monad.
+ - Equivalent to >>= in Haskell/PureScript; flatMap in Scala.
+
+ flatten :: {this Option (Option a))} -> () -> Option a
+ - "flatten"/"join" operation on the Option Monad.
+
+ exists :: this Option a -> (a -> Boolean) -> Boolean
+
+ forall :: this Option a -> (a -> Boolean) -> Boolean
+
+ filter :: this Option a -> (a -> Boolean) -> Option a
+
+ equals :: this Option a -> Option a -> Boolean
+
+ equals_ :: this Option a -> (Option a, a -> Boolean) -> Boolean
+
+ toArray :: this Option a -> () -> [a]
+
+ */
+
+ var none = function () { return NONE; };
+
+ var NONE = (function () {
+ var eq = function (o) {
+ return o.isNone();
+ };
+
+ // inlined from peanut, maybe a micro-optimisation?
+ var call = function (thunk) { return thunk(); };
+ var id = function (n) { return n; };
+ var noop = function () { };
+
+ var me = {
+ fold: function (n, s) { return n(); },
+ is: never,
+ isSome: never,
+ isNone: always,
+ getOr: id,
+ getOrThunk: call,
+ getOrDie: function (msg) {
+ throw new Error(msg || 'error: getOrDie called on none.');
+ },
+ or: id,
+ orThunk: call,
+ map: none,
+ ap: none,
+ each: noop,
+ bind: none,
+ flatten: none,
+ exists: never,
+ forall: always,
+ filter: none,
+ equals: eq,
+ equals_: eq,
+ toArray: function () { return []; },
+ toString: Fun.constant("none()")
+ };
+ if (Object.freeze) Object.freeze(me);
+ return me;
+ })();
+
+
+ /** some :: a -> Option a */
+ var some = function (a) {
+
+ // inlined from peanut, maybe a micro-optimisation?
+ var constant_a = function () { return a; };
+
+ var self = function () {
+ // can't Fun.constant this one
+ return me;
+ };
+
+ var map = function (f) {
+ return some(f(a));
+ };
+
+ var bind = function (f) {
+ return f(a);
+ };
+
+ var me = {
+ fold: function (n, s) { return s(a); },
+ is: function (v) { return a === v; },
+ isSome: always,
+ isNone: never,
+ getOr: constant_a,
+ getOrThunk: constant_a,
+ getOrDie: constant_a,
+ or: self,
+ orThunk: self,
+ map: map,
+ ap: function (optfab) {
+ return optfab.fold(none, function(fab) {
+ return some(fab(a));
+ });
+ },
+ each: function (f) {
+ f(a);
+ },
+ bind: bind,
+ flatten: constant_a,
+ exists: bind,
+ forall: bind,
+ filter: function (f) {
+ return f(a) ? me : NONE;
+ },
+ equals: function (o) {
+ return o.is(a);
+ },
+ equals_: function (o, elementEq) {
+ return o.fold(
+ never,
+ function (b) { return elementEq(a, b); }
+ );
+ },
+ toArray: function () {
+ return [a];
+ },
+ toString: function () {
+ return 'some(' + a + ')';
+ }
+ };
+ return me;
+ };
+
+ /** from :: undefined|null|a -> Option a */
+ var from = function (value) {
+ return value === null || value === undefined ? NONE : some(value);
+ };
+
+ return {
+ some: some,
+ none: none,
+ from: from
+ };
+ }
+);
+
+defineGlobal("global!String", String);
+define(
+ 'ephox.katamari.api.Arr',
+
+ [
+ 'ephox.katamari.api.Option',
+ 'global!Array',
+ 'global!Error',
+ 'global!String'
+ ],
+
+ function (Option, Array, Error, String) {
+ // Use the native Array.indexOf if it is available (IE9+) otherwise fall back to manual iteration
+ // https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
+ var rawIndexOf = (function () {
+ var pIndexOf = Array.prototype.indexOf;
+
+ var fastIndex = function (xs, x) { return pIndexOf.call(xs, x); };
+
+ var slowIndex = function(xs, x) { return slowIndexOf(xs, x); };
+
+ return pIndexOf === undefined ? slowIndex : fastIndex;
+ })();
+
+ var indexOf = function (xs, x) {
+ // The rawIndexOf method does not wrap up in an option. This is for performance reasons.
+ var r = rawIndexOf(xs, x);
+ return r === -1 ? Option.none() : Option.some(r);
+ };
+
+ var contains = function (xs, x) {
+ return rawIndexOf(xs, x) > -1;
+ };
+
+ // Using findIndex is likely less optimal in Chrome (dynamic return type instead of bool)
+ // but if we need that micro-optimisation we can inline it later.
+ var exists = function (xs, pred) {
+ return findIndex(xs, pred).isSome();
+ };
+
+ var range = function (num, f) {
+ var r = [];
+ for (var i = 0; i < num; i++) {
+ r.push(f(i));
+ }
+ return r;
+ };
+
+ // It's a total micro optimisation, but these do make some difference.
+ // Particularly for browsers other than Chrome.
+ // - length caching
+ // http://jsperf.com/browser-diet-jquery-each-vs-for-loop/69
+ // - not using push
+ // http://jsperf.com/array-direct-assignment-vs-push/2
+
+ var chunk = function (array, size) {
+ var r = [];
+ for (var i = 0; i < array.length; i += size) {
+ var s = array.slice(i, i + size);
+ r.push(s);
+ }
+ return r;
+ };
+
+ var map = function(xs, f) {
+ // pre-allocating array size when it's guaranteed to be known
+ // http://jsperf.com/push-allocated-vs-dynamic/22
+ var len = xs.length;
+ var r = new Array(len);
+ for (var i = 0; i < len; i++) {
+ var x = xs[i];
+ r[i] = f(x, i, xs);
+ }
+ return r;
+ };
+
+ // Unwound implementing other functions in terms of each.
+ // The code size is roughly the same, and it should allow for better optimisation.
+ var each = function(xs, f) {
+ for (var i = 0, len = xs.length; i < len; i++) {
+ var x = xs[i];
+ f(x, i, xs);
+ }
+ };
+
+ var eachr = function (xs, f) {
+ for (var i = xs.length - 1; i >= 0; i--) {
+ var x = xs[i];
+ f(x, i, xs);
+ }
+ };
+
+ var partition = function(xs, pred) {
+ var pass = [];
+ var fail = [];
+ for (var i = 0, len = xs.length; i < len; i++) {
+ var x = xs[i];
+ var arr = pred(x, i, xs) ? pass : fail;
+ arr.push(x);
+ }
+ return { pass: pass, fail: fail };
+ };
+
+ var filter = function(xs, pred) {
+ var r = [];
+ for (var i = 0, len = xs.length; i < len; i++) {
+ var x = xs[i];
+ if (pred(x, i, xs)) {
+ r.push(x);
+ }
+ }
+ return r;
+ };
+
+ /*
+ * Groups an array into contiguous arrays of like elements. Whether an element is like or not depends on f.
+ *
+ * f is a function that derives a value from an element - e.g. true or false, or a string.
+ * Elements are like if this function generates the same value for them (according to ===).
+ *
+ *
+ * Order of the elements is preserved. Arr.flatten() on the result will return the original list, as with Haskell groupBy function.
+ * For a good explanation, see the group function (which is a special case of groupBy)
+ * http://hackage.haskell.org/package/base-4.7.0.0/docs/Data-List.html#v:group
+ */
+ var groupBy = function (xs, f) {
+ if (xs.length === 0) {
+ return [];
+ } else {
+ var wasType = f(xs[0]); // initial case for matching
+ var r = [];
+ var group = [];
+
+ for (var i = 0, len = xs.length; i < len; i++) {
+ var x = xs[i];
+ var type = f(x);
+ if (type !== wasType) {
+ r.push(group);
+ group = [];
+ }
+ wasType = type;
+ group.push(x);
+ }
+ if (group.length !== 0) {
+ r.push(group);
+ }
+ return r;
+ }
+ };
+
+ var foldr = function (xs, f, acc) {
+ eachr(xs, function (x) {
+ acc = f(acc, x);
+ });
+ return acc;
+ };
+
+ var foldl = function (xs, f, acc) {
+ each(xs, function (x) {
+ acc = f(acc, x);
+ });
+ return acc;
+ };
+
+ var find = function (xs, pred) {
+ for (var i = 0, len = xs.length; i < len; i++) {
+ var x = xs[i];
+ if (pred(x, i, xs)) {
+ return Option.some(x);
+ }
+ }
+ return Option.none();
+ };
+
+ var findIndex = function (xs, pred) {
+ for (var i = 0, len = xs.length; i < len; i++) {
+ var x = xs[i];
+ if (pred(x, i, xs)) {
+ return Option.some(i);
+ }
+ }
+
+ return Option.none();
+ };
+
+ var slowIndexOf = function (xs, x) {
+ for (var i = 0, len = xs.length; i < len; ++i) {
+ if (xs[i] === x) {
+ return i;
+ }
+ }
+
+ return -1;
+ };
+
+ var push = Array.prototype.push;
+ var flatten = function (xs) {
+ // Note, this is possible because push supports multiple arguments:
+ // http://jsperf.com/concat-push/6
+ // Note that in the past, concat() would silently work (very slowly) for array-like objects.
+ // With this change it will throw an error.
+ var r = [];
+ for (var i = 0, len = xs.length; i < len; ++i) {
+ // Ensure that each value is an array itself
+ if (! Array.prototype.isPrototypeOf(xs[i])) throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
+ push.apply(r, xs[i]);
+ }
+ return r;
+ };
+
+ var bind = function (xs, f) {
+ var output = map(xs, f);
+ return flatten(output);
+ };
+
+ var forall = function (xs, pred) {
+ for (var i = 0, len = xs.length; i < len; ++i) {
+ var x = xs[i];
+ if (pred(x, i, xs) !== true) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ var equal = function (a1, a2) {
+ return a1.length === a2.length && forall(a1, function (x, i) {
+ return x === a2[i];
+ });
+ };
+
+ var slice = Array.prototype.slice;
+ var reverse = function (xs) {
+ var r = slice.call(xs, 0);
+ r.reverse();
+ return r;
+ };
+
+ var difference = function (a1, a2) {
+ return filter(a1, function (x) {
+ return !contains(a2, x);
+ });
+ };
+
+ var mapToObject = function(xs, f) {
+ var r = {};
+ for (var i = 0, len = xs.length; i < len; i++) {
+ var x = xs[i];
+ r[String(x)] = f(x, i);
+ }
+ return r;
+ };
+
+ var pure = function(x) {
+ return [x];
+ };
+
+ var sort = function (xs, comparator) {
+ var copy = slice.call(xs, 0);
+ copy.sort(comparator);
+ return copy;
+ };
+
+ return {
+ map: map,
+ each: each,
+ eachr: eachr,
+ partition: partition,
+ filter: filter,
+ groupBy: groupBy,
+ indexOf: indexOf,
+ foldr: foldr,
+ foldl: foldl,
+ find: find,
+ findIndex: findIndex,
+ flatten: flatten,
+ bind: bind,
+ forall: forall,
+ exists: exists,
+ contains: contains,
+ equal: equal,
+ reverse: reverse,
+ chunk: chunk,
+ difference: difference,
+ mapToObject: mapToObject,
+ pure: pure,
+ sort: sort,
+ range: range
+ };
+ }
+);
+defineGlobal("global!setTimeout", setTimeout);
+define(
+ 'ephox.katamari.api.LazyValue',
+
+ [
+ 'ephox.katamari.api.Arr',
+ 'ephox.katamari.api.Option',
+ 'global!setTimeout'
+ ],
+
+ function (Arr, Option, setTimeout) {
+ var nu = function (baseFn) {
+ var data = Option.none();
+ var callbacks = [];
+
+ /** map :: this LazyValue a -> (a -> b) -> LazyValue b */
+ var map = function (f) {
+ return nu(function (nCallback) {
+ get(function (data) {
+ nCallback(f(data));
+ });
+ });
+ };
+
+ var get = function (nCallback) {
+ if (isReady()) call(nCallback);
+ else callbacks.push(nCallback);
+ };
+
+ var set = function (x) {
+ data = Option.some(x);
+ run(callbacks);
+ callbacks = [];
+ };
+
+ var isReady = function () {
+ return data.isSome();
+ };
+
+ var run = function (cbs) {
+ Arr.each(cbs, call);
+ };
+
+ var call = function(cb) {
+ data.each(function(x) {
+ setTimeout(function() {
+ cb(x);
+ }, 0);
+ });
+ };
+
+ // Lazy values cache the value and kick off immediately
+ baseFn(set);
+
+ return {
+ get: get,
+ map: map,
+ isReady: isReady
+ };
+ };
+
+ var pure = function (a) {
+ return nu(function (callback) {
+ callback(a);
+ });
+ };
+
+ return {
+ nu: nu,
+ pure: pure
+ };
+ }
+);
+define(
+ 'ephox.katamari.async.Bounce',
+
+ [
+ 'global!Array',
+ 'global!setTimeout'
+ ],
+
+ function (Array, setTimeout) {
+
+ var bounce = function(f) {
+ return function() {
+ var args = Array.prototype.slice.call(arguments);
+ var me = this;
+ setTimeout(function() {
+ f.apply(me, args);
+ }, 0);
+ };
+ };
+
+ return {
+ bounce: bounce
+ };
+ }
+);
+
+define(
+ 'ephox.katamari.api.Future',
+
+ [
+ 'ephox.katamari.api.LazyValue',
+ 'ephox.katamari.async.Bounce'
+ ],
+
+ /** A future value that is evaluated on demand. The base function is re-evaluated each time 'get' is called. */
+ function (LazyValue, Bounce) {
+ var nu = function (baseFn) {
+ var get = function(callback) {
+ baseFn(Bounce.bounce(callback));
+ };
+
+ /** map :: this Future a -> (a -> b) -> Future b */
+ var map = function (fab) {
+ return nu(function (callback) {
+ get(function (a) {
+ var value = fab(a);
+ callback(value);
+ });
+ });
+ };
+
+ /** bind :: this Future a -> (a -> Future b) -> Future b */
+ var bind = function (aFutureB) {
+ return nu(function (callback) {
+ get(function (a) {
+ aFutureB(a).get(callback);
+ });
+ });
+ };
+
+ /** anonBind :: this Future a -> Future b -> Future b
+ * Returns a future, which evaluates the first future, ignores the result, then evaluates the second.
+ */
+ var anonBind = function (futureB) {
+ return nu(function (callback) {
+ get(function (a) {
+ futureB.get(callback);
+ });
+ });
+ };
+
+ var toLazy = function () {
+ return LazyValue.nu(get);
+ };
+
+ return {
+ map: map,
+ bind: bind,
+ anonBind: anonBind,
+ toLazy: toLazy,
+ get: get
+ };
+
+ };
+
+ /** a -> Future a */
+ var pure = function (a) {
+ return nu(function (callback) {
+ callback(a);
+ });
+ };
+
+ return {
+ nu: nu,
+ pure: pure
+ };
+ }
+);
+
+define(
+ 'ephox.katamari.async.AsyncValues',
+
+ [
+ 'ephox.katamari.api.Arr'
+ ],
+
+ function (Arr) {
+ /*
+ * NOTE: an `asyncValue` must have a `get` function which gets given a callback and calls
+ * that callback with a value once it is ready
+ *
+ * e.g
+ * {
+ * get: function (callback) { callback(10); }
+ * }
+ */
+ var par = function (asyncValues, nu) {
+ return nu(function(callback) {
+ var r = [];
+ var count = 0;
+
+ var cb = function(i) {
+ return function(value) {
+ r[i] = value;
+ count++;
+ if (count >= asyncValues.length) {
+ callback(r);
+ }
+ };
+ };
+
+ if (asyncValues.length === 0) {
+ callback([]);
+ } else {
+ Arr.each(asyncValues, function(asyncValue, i) {
+ asyncValue.get(cb(i));
+ });
+ }
+ });
+ };
+
+ return {
+ par: par
+ };
+ }
+);
+define(
+ 'ephox.katamari.api.Futures',
+
+ [
+ 'ephox.katamari.api.Arr',
+ 'ephox.katamari.api.Future',
+ 'ephox.katamari.async.AsyncValues'
+ ],
+
+ function (Arr, Future, AsyncValues) {
+ /** par :: [Future a] -> Future [a] */
+ var par = function(futures) {
+ return AsyncValues.par(futures, Future.nu);
+ };
+
+ /** mapM :: [a] -> (a -> Future b) -> Future [b] */
+ var mapM = function(array, fn) {
+ var futures = Arr.map(array, fn);
+ return par(futures);
+ };
+
+ /** Kleisli composition of two functions: a -> Future b.
+ * Note the order of arguments: g is invoked first, then the result passed to f.
+ * This is in line with f . g = \x -> f (g a)
+ *
+ * compose :: ((b -> Future c), (a -> Future b)) -> a -> Future c
+ */
+ var compose = function (f, g) {
+ return function (a) {
+ return g(a).bind(f);
+ };
+ };
+
+ return {
+ par: par,
+ mapM: mapM,
+ compose: compose
+ };
+ }
+);
+define(
+ 'ephox.katamari.api.Result',
+
+ [
+ 'ephox.katamari.api.Fun',
+ 'ephox.katamari.api.Option'
+ ],
+
+ function (Fun, Option) {
+ /* The type signatures for Result
+ * is :: this Result a -> a -> Bool
+ * or :: this Result a -> Result a -> Result a
+ * orThunk :: this Result a -> (_ -> Result a) -> Result a
+ * map :: this Result a -> (a -> b) -> Result b
+ * each :: this Result a -> (a -> _) -> _
+ * bind :: this Result a -> (a -> Result b) -> Result b
+ * fold :: this Result a -> (_ -> b, a -> b) -> b
+ * exists :: this Result a -> (a -> Bool) -> Bool
+ * forall :: this Result a -> (a -> Bool) -> Bool
+ * toOption :: this Result a -> Option a
+ * isValue :: this Result a -> Bool
+ * isError :: this Result a -> Bool
+ * getOr :: this Result a -> a -> a
+ * getOrThunk :: this Result a -> (_ -> a) -> a
+ * getOrDie :: this Result a -> a (or throws error)
+ */
+
+ var value = function (o) {
+ var is = function (v) {
+ return o === v;
+ };
+
+ var or = function (opt) {
+ return value(o);
+ };
+
+ var orThunk = function (f) {
+ return value(o);
+ };
+
+ var map = function (f) {
+ return value(f(o));
+ };
+
+ var each = function (f) {
+ f(o);
+ };
+
+ var bind = function (f) {
+ return f(o);
+ };
+
+ var fold = function (_, onValue) {
+ return onValue(o);
+ };
+
+ var exists = function (f) {
+ return f(o);
+ };
+
+ var forall = function (f) {
+ return f(o);
+ };
+
+ var toOption = function () {
+ return Option.some(o);
+ };
+
+ return {
+ is: is,
+ isValue: Fun.constant(true),
+ isError: Fun.constant(false),
+ getOr: Fun.constant(o),
+ getOrThunk: Fun.constant(o),
+ getOrDie: Fun.constant(o),
+ or: or,
+ orThunk: orThunk,
+ fold: fold,
+ map: map,
+ each: each,
+ bind: bind,
+ exists: exists,
+ forall: forall,
+ toOption: toOption
+ };
+ };
+
+ var error = function (message) {
+ var getOrThunk = function (f) {
+ return f();
+ };
+
+ var getOrDie = function () {
+ return Fun.die(message)();
+ };
+
+ var or = function (opt) {
+ return opt;
+ };
+
+ var orThunk = function (f) {
+ return f();
+ };
+
+ var map = function (f) {
+ return error(message);
+ };
+
+ var bind = function (f) {
+ return error(message);
+ };
+
+ var fold = function (onError, _) {
+ return onError(message);
+ };
+
+ return {
+ is: Fun.constant(false),
+ isValue: Fun.constant(false),
+ isError: Fun.constant(true),
+ getOr: Fun.identity,
+ getOrThunk: getOrThunk,
+ getOrDie: getOrDie,
+ or: or,
+ orThunk: orThunk,
+ fold: fold,
+ map: map,
+ each: Fun.noop,
+ bind: bind,
+ exists: Fun.constant(false),
+ forall: Fun.constant(true),
+ toOption: Option.none
+ };
+ };
+
+ return {
+ value: value,
+ error: error
+ };
+ }
+);
+
+/**
+ * StyleSheetLoader.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 loading of external stylesheets and fires events when these are loaded.
+ *
+ * @class tinymce.dom.StyleSheetLoader
+ * @private
+ */
+define(
+ 'tinymce.core.dom.StyleSheetLoader',
+ [
+ 'ephox.katamari.api.Arr',
+ 'ephox.katamari.api.Fun',
+ 'ephox.katamari.api.Future',
+ 'ephox.katamari.api.Futures',
+ 'ephox.katamari.api.Result',
+ 'tinymce.core.util.Delay',
+ 'tinymce.core.util.Tools'
+ ],
+ function (Arr, Fun, Future, Futures, Result, Delay, Tools) {
+ "use strict";
+
+ return function (document, settings) {
+ var idCount = 0, loadedStates = {}, maxLoadTime;
+
+ settings = settings || {};
+ maxLoadTime = settings.maxLoadTime || 5000;
+
+ function appendToHead(node) {
+ document.getElementsByTagName('head')[0].appendChild(node);
+ }
+
+ /**
+ * Loads the specified css style sheet file and call the loadedCallback once it's finished loading.
+ *
+ * @method load
+ * @param {String} url Url to be loaded.
+ * @param {Function} loadedCallback Callback to be executed when loaded.
+ * @param {Function} errorCallback Callback to be executed when failed loading.
+ */
+ function load(url, loadedCallback, errorCallback) {
+ var link, style, startTime, state;
+
+ function passed() {
+ var callbacks = state.passed, i = callbacks.length;
+
+ while (i--) {
+ callbacks[i]();
+ }
+
+ state.status = 2;
+ state.passed = [];
+ state.failed = [];
+ }
+
+ function failed() {
+ var callbacks = state.failed, i = callbacks.length;
+
+ while (i--) {
+ callbacks[i]();
+ }
+
+ state.status = 3;
+ state.passed = [];
+ state.failed = [];
+ }
+
+ // Sniffs for older WebKit versions that have the link.onload but a broken one
+ function isOldWebKit() {
+ var webKitChunks = navigator.userAgent.match(/WebKit\/(\d*)/);
+ return !!(webKitChunks && webKitChunks[1] < 536);
+ }
+
+ // Calls the waitCallback until the test returns true or the timeout occurs
+ function wait(testCallback, waitCallback) {
+ if (!testCallback()) {
+ // Wait for timeout
+ if ((new Date().getTime()) - startTime < maxLoadTime) {
+ Delay.setTimeout(waitCallback);
+ } else {
+ failed();
+ }
+ }
+ }
+
+ // Workaround for WebKit that doesn't properly support the onload event for link elements
+ // Or WebKit that fires the onload event before the StyleSheet is added to the document
+ function waitForWebKitLinkLoaded() {
+ wait(function () {
+ var styleSheets = document.styleSheets, styleSheet, i = styleSheets.length, owner;
+
+ while (i--) {
+ styleSheet = styleSheets[i];
+ owner = styleSheet.ownerNode ? styleSheet.ownerNode : styleSheet.owningElement;
+ if (owner && owner.id === link.id) {
+ passed();
+ return true;
+ }
+ }
+ }, waitForWebKitLinkLoaded);
+ }
+
+ // Workaround for older Geckos that doesn't have any onload event for StyleSheets
+ function waitForGeckoLinkLoaded() {
+ wait(function () {
+ try {
+ // Accessing the cssRules will throw an exception until the CSS file is loaded
+ var cssRules = style.sheet.cssRules;
+ passed();
+ return !!cssRules;
+ } catch (ex) {
+ // Ignore
+ }
+ }, waitForGeckoLinkLoaded);
+ }
+
+ url = Tools._addCacheSuffix(url);
+
+ if (!loadedStates[url]) {
+ state = {
+ passed: [],
+ failed: []
+ };
+
+ loadedStates[url] = state;
+ } else {
+ state = loadedStates[url];
+ }
+
+ if (loadedCallback) {
+ state.passed.push(loadedCallback);
+ }
+
+ if (errorCallback) {
+ state.failed.push(errorCallback);
+ }
+
+ // Is loading wait for it to pass
+ if (state.status == 1) {
+ return;
+ }
+
+ // Has finished loading and was success
+ if (state.status == 2) {
+ passed();
+ return;
+ }
+
+ // Has finished loading and was a failure
+ if (state.status == 3) {
+ failed();
+ return;
+ }
+
+ // Start loading
+ state.status = 1;
+ link = document.createElement('link');
+ link.rel = 'stylesheet';
+ link.type = 'text/css';
+ link.id = 'u' + (idCount++);
+ link.async = false;
+ link.defer = false;
+ startTime = new Date().getTime();
+
+ // Feature detect onload on link element and sniff older webkits since it has an broken onload event
+ if ("onload" in link && !isOldWebKit()) {
+ link.onload = waitForWebKitLinkLoaded;
+ link.onerror = failed;
+ } else {
+ // Sniff for old Firefox that doesn't support the onload event on link elements
+ // TODO: Remove this in the future when everyone uses modern browsers
+ if (navigator.userAgent.indexOf("Firefox") > 0) {
+ style = document.createElement('style');
+ style.textContent = '@import "' + url + '"';
+ waitForGeckoLinkLoaded();
+ appendToHead(style);
+ return;
+ }
+
+ // Use the id owner on older webkits
+ waitForWebKitLinkLoaded();
+ }
+
+ appendToHead(link);
+ link.href = url;
+ }
+
+ var loadF = function (url) {
+ return Future.nu(function (resolve) {
+ load(
+ url,
+ Fun.compose(resolve, Fun.constant(Result.value(url))),
+ Fun.compose(resolve, Fun.constant(Result.error(url)))
+ );
+ });
+ };
+
+ var unbox = function (result) {
+ return result.fold(Fun.identity, Fun.identity);
+ };
+
+ var loadAll = function (urls, success, failure) {
+ Futures.par(Arr.map(urls, loadF)).get(function (result) {
+ var parts = Arr.partition(result, function (r) {
+ return r.isValue();
+ });
+
+ if (parts.fail.length > 0) {
+ failure(parts.fail.map(unbox));
+ } else {
+ success(parts.pass.map(unbox));
+ }
+ });
+ };
+
+ return {
+ load: load,
+ loadAll: loadAll
+ };
+ };
+ }
+);
+
+/**
+ * Schema.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
+ */
+
+/**
+ * Schema validator class.
+ *
+ * @class tinymce.html.Schema
+ * @example
+ * if (tinymce.activeEditor.schema.isValidChild('p', 'span'))
+ * alert('span is valid child of p.');
+ *
+ * if (tinymce.activeEditor.schema.getElementRule('p'))
+ * alert('P is a valid element.');
+ *
+ * @class tinymce.html.Schema
+ * @version 3.4
+ */
+define(
+ 'tinymce.core.html.Schema',
+ [
+ "tinymce.core.util.Tools"
+ ],
+ function (Tools) {
+ var mapCache = {}, dummyObj = {};
+ var makeMap = Tools.makeMap, each = Tools.each, extend = Tools.extend, explode = Tools.explode, inArray = Tools.inArray;
+
+ function split(items, delim) {
+ items = Tools.trim(items);
+ return items ? items.split(delim || ' ') : [];
+ }
+
+ /**
+ * Builds a schema lookup table
+ *
+ * @private
+ * @param {String} type html4, html5 or html5-strict schema type.
+ * @return {Object} Schema lookup table.
+ */
+ function compileSchema(type) {
+ var schema = {}, globalAttributes, blockContent;
+ var phrasingContent, flowContent, html4BlockContent, html4PhrasingContent;
+
+ function add(name, attributes, children) {
+ var ni, attributesOrder, element;
+
+ function arrayToMap(array, obj) {
+ var map = {}, i, l;
+
+ for (i = 0, l = array.length; i < l; i++) {
+ map[array[i]] = obj || {};
+ }
+
+ return map;
+ }
+
+ children = children || [];
+ attributes = attributes || "";
+
+ if (typeof children === "string") {
+ children = split(children);
+ }
+
+ name = split(name);
+ ni = name.length;
+ while (ni--) {
+ attributesOrder = split([globalAttributes, attributes].join(' '));
+
+ element = {
+ attributes: arrayToMap(attributesOrder),
+ attributesOrder: attributesOrder,
+ children: arrayToMap(children, dummyObj)
+ };
+
+ schema[name[ni]] = element;
+ }
+ }
+
+ function addAttrs(name, attributes) {
+ var ni, schemaItem, i, l;
+
+ name = split(name);
+ ni = name.length;
+ attributes = split(attributes);
+ while (ni--) {
+ schemaItem = schema[name[ni]];
+ for (i = 0, l = attributes.length; i < l; i++) {
+ schemaItem.attributes[attributes[i]] = {};
+ schemaItem.attributesOrder.push(attributes[i]);
+ }
+ }
+ }
+
+ // Use cached schema
+ if (mapCache[type]) {
+ return mapCache[type];
+ }
+
+ // Attributes present on all elements
+ globalAttributes = "id accesskey class dir lang style tabindex title role";
+
+ // Event attributes can be opt-in/opt-out
+ /*eventAttributes = split("onabort onblur oncancel oncanplay oncanplaythrough onchange onclick onclose oncontextmenu oncuechange " +
+ "ondblclick ondrag ondragend ondragenter ondragleave ondragover ondragstart ondrop ondurationchange onemptied onended " +
+ "onerror onfocus oninput oninvalid onkeydown onkeypress onkeyup onload onloadeddata onloadedmetadata onloadstart " +
+ "onmousedown onmousemove onmouseout onmouseover onmouseup onmousewheel onpause onplay onplaying onprogress onratechange " +
+ "onreset onscroll onseeked onseeking onseeking onselect onshow onstalled onsubmit onsuspend ontimeupdate onvolumechange " +
+ "onwaiting"
+ );*/
+
+ // Block content elements
+ blockContent =
+ "address blockquote div dl fieldset form h1 h2 h3 h4 h5 h6 hr menu ol p pre table ul";
+
+ // Phrasing content elements from the HTML5 spec (inline)
+ phrasingContent =
+ "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"
+ ;
+
+ // Add HTML5 items to globalAttributes, blockContent, phrasingContent
+ if (type != "html4") {
+ globalAttributes += " contenteditable contextmenu draggable dropzone " +
+ "hidden spellcheck translate";
+ blockContent += " article aside details dialog figure header footer hgroup section nav";
+ phrasingContent += " audio canvas command datalist mark meter output picture " +
+ "progress time wbr video ruby bdi keygen";
+ }
+
+ // Add HTML4 elements unless it's html5-strict
+ if (type != "html5-strict") {
+ globalAttributes += " xml:lang";
+
+ html4PhrasingContent = "acronym applet basefont big font strike tt";
+ phrasingContent = [phrasingContent, html4PhrasingContent].join(' ');
+
+ each(split(html4PhrasingContent), function (name) {
+ add(name, "", phrasingContent);
+ });
+
+ html4BlockContent = "center dir isindex noframes";
+ blockContent = [blockContent, html4BlockContent].join(' ');
+
+ // Flow content elements from the HTML5 spec (block+inline)
+ flowContent = [blockContent, phrasingContent].join(' ');
+
+ each(split(html4BlockContent), function (name) {
+ add(name, "", flowContent);
+ });
+ }
+
+ // Flow content elements from the HTML5 spec (block+inline)
+ flowContent = flowContent || [blockContent, phrasingContent].join(" ");
+
+ // HTML4 base schema TODO: Move HTML5 specific attributes to HTML5 specific if statement
+ // Schema items , ,
+ add("html", "manifest", "head body");
+ add("head", "", "base command link meta noscript script style title");
+ add("title hr noscript br");
+ add("base", "href target");
+ add("link", "href rel media hreflang type sizes hreflang");
+ add("meta", "name http-equiv content charset");
+ add("style", "media type scoped");
+ add("script", "src async defer type charset");
+ add("body", "onafterprint onbeforeprint onbeforeunload onblur onerror onfocus " +
+ "onhashchange onload onmessage onoffline ononline onpagehide onpageshow " +
+ "onpopstate onresize onscroll onstorage onunload", flowContent);
+ add("address dt dd div caption", "", flowContent);
+ add("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", "", phrasingContent);
+ add("blockquote", "cite", flowContent);
+ add("ol", "reversed start type", "li");
+ add("ul", "", "li");
+ add("li", "value", flowContent);
+ add("dl", "", "dt dd");
+ add("a", "href target rel media hreflang type", phrasingContent);
+ add("q", "cite", phrasingContent);
+ add("ins del", "cite datetime", flowContent);
+ add("img", "src sizes srcset alt usemap ismap width height");
+ add("iframe", "src name width height", flowContent);
+ add("embed", "src type width height");
+ add("object", "data type typemustmatch name usemap form width height", [flowContent, "param"].join(' '));
+ add("param", "name value");
+ add("map", "name", [flowContent, "area"].join(' '));
+ add("area", "alt coords shape href target rel media hreflang type");
+ add("table", "border", "caption colgroup thead tfoot tbody tr" + (type == "html4" ? " col" : ""));
+ add("colgroup", "span", "col");
+ add("col", "span");
+ add("tbody thead tfoot", "", "tr");
+ add("tr", "", "td th");
+ add("td", "colspan rowspan headers", flowContent);
+ add("th", "colspan rowspan headers scope abbr", flowContent);
+ add("form", "accept-charset action autocomplete enctype method name novalidate target", flowContent);
+ add("fieldset", "disabled form name", [flowContent, "legend"].join(' '));
+ add("label", "form for", phrasingContent);
+ add("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"
+ );
+ add("button", "disabled form formaction formenctype formmethod formnovalidate formtarget name type value",
+ type == "html4" ? flowContent : phrasingContent);
+ add("select", "disabled form multiple name required size", "option optgroup");
+ add("optgroup", "disabled label", "option");
+ add("option", "disabled label selected value");
+ add("textarea", "cols dirname disabled form maxlength name readonly required rows wrap");
+ add("menu", "type label", [flowContent, "li"].join(' '));
+ add("noscript", "", flowContent);
+
+ // Extend with HTML5 elements
+ if (type != "html4") {
+ add("wbr");
+ add("ruby", "", [phrasingContent, "rt rp"].join(' '));
+ add("figcaption", "", flowContent);
+ add("mark rt rp summary bdi", "", phrasingContent);
+ add("canvas", "width height", flowContent);
+ add("video", "src crossorigin poster preload autoplay mediagroup loop " +
+ "muted controls width height buffered", [flowContent, "track source"].join(' '));
+ add("audio", "src crossorigin preload autoplay mediagroup loop muted controls " +
+ "buffered volume", [flowContent, "track source"].join(' '));
+ add("picture", "", "img source");
+ add("source", "src srcset type media sizes");
+ add("track", "kind src srclang label default");
+ add("datalist", "", [phrasingContent, "option"].join(' '));
+ add("article section nav aside header footer", "", flowContent);
+ add("hgroup", "", "h1 h2 h3 h4 h5 h6");
+ add("figure", "", [flowContent, "figcaption"].join(' '));
+ add("time", "datetime", phrasingContent);
+ add("dialog", "open", flowContent);
+ add("command", "type label icon disabled checked radiogroup command");
+ add("output", "for form name", phrasingContent);
+ add("progress", "value max", phrasingContent);
+ add("meter", "value min max low high optimum", phrasingContent);
+ add("details", "open", [flowContent, "summary"].join(' '));
+ add("keygen", "autofocus challenge disabled form keytype name");
+ }
+
+ // Extend with HTML4 attributes unless it's html5-strict
+ if (type != "html5-strict") {
+ addAttrs("script", "language xml:space");
+ addAttrs("style", "xml:space");
+ addAttrs("object", "declare classid code codebase codetype archive standby align border hspace vspace");
+ addAttrs("embed", "align name hspace vspace");
+ addAttrs("param", "valuetype type");
+ addAttrs("a", "charset name rev shape coords");
+ addAttrs("br", "clear");
+ addAttrs("applet", "codebase archive code object alt name width height align hspace vspace");
+ addAttrs("img", "name longdesc align border hspace vspace");
+ addAttrs("iframe", "longdesc frameborder marginwidth marginheight scrolling align");
+ addAttrs("font basefont", "size color face");
+ addAttrs("input", "usemap align");
+ addAttrs("select", "onchange");
+ addAttrs("textarea");
+ addAttrs("h1 h2 h3 h4 h5 h6 div p legend caption", "align");
+ addAttrs("ul", "type compact");
+ addAttrs("li", "type");
+ addAttrs("ol dl menu dir", "compact");
+ addAttrs("pre", "width xml:space");
+ addAttrs("hr", "align noshade size width");
+ addAttrs("isindex", "prompt");
+ addAttrs("table", "summary width frame rules cellspacing cellpadding align bgcolor");
+ addAttrs("col", "width align char charoff valign");
+ addAttrs("colgroup", "width align char charoff valign");
+ addAttrs("thead", "align char charoff valign");
+ addAttrs("tr", "align char charoff valign bgcolor");
+ addAttrs("th", "axis align char charoff valign nowrap bgcolor width height");
+ addAttrs("form", "accept");
+ addAttrs("td", "abbr axis scope align char charoff valign nowrap bgcolor width height");
+ addAttrs("tfoot", "align char charoff valign");
+ addAttrs("tbody", "align char charoff valign");
+ addAttrs("area", "nohref");
+ addAttrs("body", "background bgcolor text link vlink alink");
+ }
+
+ // Extend with HTML5 attributes unless it's html4
+ if (type != "html4") {
+ addAttrs("input button select textarea", "autofocus");
+ addAttrs("input textarea", "placeholder");
+ addAttrs("a", "download");
+ addAttrs("link script img", "crossorigin");
+ addAttrs("iframe", "sandbox seamless allowfullscreen"); // Excluded: srcdoc
+ }
+
+ // Special: iframe, ruby, video, audio, label
+
+ // Delete children of the same name from it's parent
+ // For example: form can't have a child of the name form
+ each(split('a form meter progress dfn'), function (name) {
+ if (schema[name]) {
+ delete schema[name].children[name];
+ }
+ });
+
+ // Delete header, footer, sectioning and heading content descendants
+ /*each('dt th address', function(name) {
+ delete schema[name].children[name];
+ });*/
+
+ // Caption can't have tables
+ delete schema.caption.children.table;
+
+ // Delete scripts by default due to possible XSS
+ delete schema.script;
+
+ // TODO: LI:s can only have value if parent is OL
+
+ // TODO: Handle transparent elements
+ // a ins del canvas map
+
+ mapCache[type] = schema;
+
+ return schema;
+ }
+
+ function compileElementMap(value, mode) {
+ var styles;
+
+ if (value) {
+ styles = {};
+
+ if (typeof value == 'string') {
+ value = {
+ '*': value
+ };
+ }
+
+ // Convert styles into a rule list
+ each(value, function (value, key) {
+ styles[key] = styles[key.toUpperCase()] = mode == 'map' ? makeMap(value, /[, ]/) : explode(value, /[, ]/);
+ });
+ }
+
+ return styles;
+ }
+
+ /**
+ * Constructs a new Schema instance.
+ *
+ * @constructor
+ * @method Schema
+ * @param {Object} settings Name/value settings object.
+ */
+ return function (settings) {
+ var self = this, elements = {}, children = {}, patternElements = [], validStyles, invalidStyles, schemaItems;
+ var whiteSpaceElementsMap, selfClosingElementsMap, shortEndedElementsMap, boolAttrMap, validClasses;
+ var blockElementsMap, nonEmptyElementsMap, moveCaretBeforeOnEnterElementsMap, textBlockElementsMap, textInlineElementsMap;
+ var customElementsMap = {}, specialElements = {};
+
+ // Creates an lookup table map object for the specified option or the default value
+ function createLookupTable(option, defaultValue, extendWith) {
+ var value = settings[option];
+
+ if (!value) {
+ // Get cached default map or make it if needed
+ value = mapCache[option];
+
+ if (!value) {
+ value = makeMap(defaultValue, ' ', makeMap(defaultValue.toUpperCase(), ' '));
+ value = extend(value, extendWith);
+
+ mapCache[option] = value;
+ }
+ } else {
+ // Create custom map
+ value = makeMap(value, /[, ]/, makeMap(value.toUpperCase(), /[, ]/));
+ }
+
+ return value;
+ }
+
+ settings = settings || {};
+ schemaItems = compileSchema(settings.schema);
+
+ // Allow all elements and attributes if verify_html is set to false
+ if (settings.verify_html === false) {
+ settings.valid_elements = '*[*]';
+ }
+
+ validStyles = compileElementMap(settings.valid_styles);
+ invalidStyles = compileElementMap(settings.invalid_styles, 'map');
+ validClasses = compileElementMap(settings.valid_classes, 'map');
+
+ // Setup map objects
+ whiteSpaceElementsMap = createLookupTable(
+ 'whitespace_elements',
+ 'pre script noscript style textarea video audio iframe object code'
+ );
+ selfClosingElementsMap = createLookupTable('self_closing_elements', 'colgroup dd dt li option p td tfoot th thead tr');
+ shortEndedElementsMap = createLookupTable('short_ended_elements', 'area base basefont br col frame hr img input isindex link ' +
+ 'meta param embed source wbr track');
+ boolAttrMap = createLookupTable('boolean_attributes', 'checked compact declare defer disabled ismap multiple nohref noresize ' +
+ 'noshade nowrap readonly selected autoplay loop controls');
+ nonEmptyElementsMap = createLookupTable('non_empty_elements', 'td th iframe video audio object ' +
+ 'script pre code', shortEndedElementsMap);
+ moveCaretBeforeOnEnterElementsMap = createLookupTable('move_caret_before_on_enter_elements', 'table', nonEmptyElementsMap);
+ textBlockElementsMap = createLookupTable('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');
+ blockElementsMap = createLookupTable('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', textBlockElementsMap);
+ textInlineElementsMap = createLookupTable('text_inline_elements', 'span strong b em i font strike u var cite ' +
+ 'dfn code mark q sup sub samp');
+
+ each((settings.special || 'script noscript style textarea').split(' '), function (name) {
+ specialElements[name] = new RegExp('<\/' + name + '[^>]*>', 'gi');
+ });
+
+ // Converts a wildcard expression string to a regexp for example *a will become /.*a/.
+ function patternToRegExp(str) {
+ return new RegExp('^' + str.replace(/([?+*])/g, '.$1') + '$');
+ }
+
+ // Parses the specified valid_elements string and adds to the current rules
+ // This function is a bit hard to read since it's heavily optimized for speed
+ function addValidElements(validElements) {
+ var ei, el, ai, al, matches, element, attr, attrData, elementName, attrName, attrType, attributes, attributesOrder,
+ prefix, outputName, globalAttributes, globalAttributesOrder, key, value,
+ elementRuleRegExp = /^([#+\-])?([^\[!\/]+)(?:\/([^\[!]+))?(?:(!?)\[([^\]]+)\])?$/,
+ attrRuleRegExp = /^([!\-])?(\w+::\w+|[^=:<]+)?(?:([=:<])(.*))?$/,
+ hasPatternsRegExp = /[*?+]/;
+
+ if (validElements) {
+ // Split valid elements into an array with rules
+ validElements = split(validElements, ',');
+
+ if (elements['@']) {
+ globalAttributes = elements['@'].attributes;
+ globalAttributesOrder = elements['@'].attributesOrder;
+ }
+
+ // Loop all rules
+ for (ei = 0, el = validElements.length; ei < el; ei++) {
+ // Parse element rule
+ matches = elementRuleRegExp.exec(validElements[ei]);
+ if (matches) {
+ // Setup local names for matches
+ prefix = matches[1];
+ elementName = matches[2];
+ outputName = matches[3];
+ attrData = matches[5];
+
+ // Create new attributes and attributesOrder
+ attributes = {};
+ attributesOrder = [];
+
+ // Create the new element
+ element = {
+ attributes: attributes,
+ attributesOrder: attributesOrder
+ };
+
+ // Padd empty elements prefix
+ if (prefix === '#') {
+ element.paddEmpty = true;
+ }
+
+ // Remove empty elements prefix
+ if (prefix === '-') {
+ element.removeEmpty = true;
+ }
+
+ if (matches[4] === '!') {
+ element.removeEmptyAttrs = true;
+ }
+
+ // Copy attributes from global rule into current rule
+ if (globalAttributes) {
+ for (key in globalAttributes) {
+ attributes[key] = globalAttributes[key];
+ }
+
+ attributesOrder.push.apply(attributesOrder, globalAttributesOrder);
+ }
+
+ // Attributes defined
+ if (attrData) {
+ attrData = split(attrData, '|');
+ for (ai = 0, al = attrData.length; ai < al; ai++) {
+ matches = attrRuleRegExp.exec(attrData[ai]);
+ if (matches) {
+ attr = {};
+ attrType = matches[1];
+ attrName = matches[2].replace(/::/g, ':');
+ prefix = matches[3];
+ value = matches[4];
+
+ // Required
+ if (attrType === '!') {
+ element.attributesRequired = element.attributesRequired || [];
+ element.attributesRequired.push(attrName);
+ attr.required = true;
+ }
+
+ // Denied from global
+ if (attrType === '-') {
+ delete attributes[attrName];
+ attributesOrder.splice(inArray(attributesOrder, attrName), 1);
+ continue;
+ }
+
+ // Default value
+ if (prefix) {
+ // Default value
+ if (prefix === '=') {
+ element.attributesDefault = element.attributesDefault || [];
+ element.attributesDefault.push({ name: attrName, value: value });
+ attr.defaultValue = value;
+ }
+
+ // Forced value
+ if (prefix === ':') {
+ element.attributesForced = element.attributesForced || [];
+ element.attributesForced.push({ name: attrName, value: value });
+ attr.forcedValue = value;
+ }
+
+ // Required values
+ if (prefix === '<') {
+ attr.validValues = makeMap(value, '?');
+ }
+ }
+
+ // Check for attribute patterns
+ if (hasPatternsRegExp.test(attrName)) {
+ element.attributePatterns = element.attributePatterns || [];
+ attr.pattern = patternToRegExp(attrName);
+ element.attributePatterns.push(attr);
+ } else {
+ // Add attribute to order list if it doesn't already exist
+ if (!attributes[attrName]) {
+ attributesOrder.push(attrName);
+ }
+
+ attributes[attrName] = attr;
+ }
+ }
+ }
+ }
+
+ // Global rule, store away these for later usage
+ if (!globalAttributes && elementName == '@') {
+ globalAttributes = attributes;
+ globalAttributesOrder = attributesOrder;
+ }
+
+ // Handle substitute elements such as b/strong
+ if (outputName) {
+ element.outputName = elementName;
+ elements[outputName] = element;
+ }
+
+ // Add pattern or exact element
+ if (hasPatternsRegExp.test(elementName)) {
+ element.pattern = patternToRegExp(elementName);
+ patternElements.push(element);
+ } else {
+ elements[elementName] = element;
+ }
+ }
+ }
+ }
+ }
+
+ function setValidElements(validElements) {
+ elements = {};
+ patternElements = [];
+
+ addValidElements(validElements);
+
+ each(schemaItems, function (element, name) {
+ children[name] = element.children;
+ });
+ }
+
+ // Adds custom non HTML elements to the schema
+ function addCustomElements(customElements) {
+ var customElementRegExp = /^(~)?(.+)$/;
+
+ if (customElements) {
+ // Flush cached items since we are altering the default maps
+ mapCache.text_block_elements = mapCache.block_elements = null;
+
+ each(split(customElements, ','), function (rule) {
+ var matches = customElementRegExp.exec(rule),
+ inline = matches[1] === '~',
+ cloneName = inline ? 'span' : 'div',
+ name = matches[2];
+
+ children[name] = children[cloneName];
+ customElementsMap[name] = cloneName;
+
+ // If it's not marked as inline then add it to valid block elements
+ if (!inline) {
+ blockElementsMap[name.toUpperCase()] = {};
+ blockElementsMap[name] = {};
+ }
+
+ // Add elements clone if needed
+ if (!elements[name]) {
+ var customRule = elements[cloneName];
+
+ customRule = extend({}, customRule);
+ delete customRule.removeEmptyAttrs;
+ delete customRule.removeEmpty;
+
+ elements[name] = customRule;
+ }
+
+ // Add custom elements at span/div positions
+ each(children, function (element, elmName) {
+ if (element[cloneName]) {
+ children[elmName] = element = extend({}, children[elmName]);
+ element[name] = element[cloneName];
+ }
+ });
+ });
+ }
+ }
+
+ // Adds valid children to the schema object
+ function addValidChildren(validChildren) {
+ var childRuleRegExp = /^([+\-]?)(\w+)\[([^\]]+)\]$/;
+
+ // Invalidate the schema cache if the schema is mutated
+ mapCache[settings.schema] = null;
+
+ if (validChildren) {
+ each(split(validChildren, ','), function (rule) {
+ var matches = childRuleRegExp.exec(rule), parent, prefix;
+
+ if (matches) {
+ prefix = matches[1];
+
+ // Add/remove items from default
+ if (prefix) {
+ parent = children[matches[2]];
+ } else {
+ parent = children[matches[2]] = { '#comment': {} };
+ }
+
+ parent = children[matches[2]];
+
+ each(split(matches[3], '|'), function (child) {
+ if (prefix === '-') {
+ delete parent[child];
+ } else {
+ parent[child] = {};
+ }
+ });
+ }
+ });
+ }
+ }
+
+ function getElementRule(name) {
+ var element = elements[name], i;
+
+ // Exact match found
+ if (element) {
+ return element;
+ }
+
+ // No exact match then try the patterns
+ i = patternElements.length;
+ while (i--) {
+ element = patternElements[i];
+
+ if (element.pattern.test(name)) {
+ return element;
+ }
+ }
+ }
+
+ if (!settings.valid_elements) {
+ // No valid elements defined then clone the elements from the schema spec
+ each(schemaItems, function (element, name) {
+ elements[name] = {
+ attributes: element.attributes,
+ attributesOrder: element.attributesOrder
+ };
+
+ children[name] = element.children;
+ });
+
+ // Switch these on HTML4
+ if (settings.schema != "html5") {
+ each(split('strong/b em/i'), function (item) {
+ item = split(item, '/');
+ elements[item[1]].outputName = item[0];
+ });
+ }
+
+ // Add default alt attribute for images, removed since alt="" is treated as presentational.
+ // elements.img.attributesDefault = [{name: 'alt', value: ''}];
+
+ // Remove these if they are empty by default
+ each(split('ol ul sub sup blockquote span font a table tbody tr strong em b i'), function (name) {
+ if (elements[name]) {
+ elements[name].removeEmpty = true;
+ }
+ });
+
+ // Padd these by default
+ each(split('p h1 h2 h3 h4 h5 h6 th td pre div address caption'), function (name) {
+ elements[name].paddEmpty = true;
+ });
+
+ // Remove these if they have no attributes
+ each(split('span'), function (name) {
+ elements[name].removeEmptyAttrs = true;
+ });
+
+ // Remove these by default
+ // TODO: Reenable in 4.1
+ /*each(split('script style'), function(name) {
+ delete elements[name];
+ });*/
+ } else {
+ setValidElements(settings.valid_elements);
+ }
+
+ addCustomElements(settings.custom_elements);
+ addValidChildren(settings.valid_children);
+ addValidElements(settings.extended_valid_elements);
+
+ // Todo: Remove this when we fix list handling to be valid
+ addValidChildren('+ol[ul|ol],+ul[ul|ol]');
+
+
+ // Some elements are not valid by themselves - require parents
+ each({
+ 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 (parents, item) {
+ if (elements[item]) {
+ elements[item].parentsRequired = split(parents);
+ }
+ });
+
+
+ // Delete invalid elements
+ if (settings.invalid_elements) {
+ each(explode(settings.invalid_elements), function (item) {
+ if (elements[item]) {
+ delete elements[item];
+ }
+ });
+ }
+
+ // If the user didn't allow span only allow internal spans
+ if (!getElementRule('span')) {
+ addValidElements('span[!data-mce-type|*]');
+ }
+
+ /**
+ * Name/value map object with valid parents and children to those parents.
+ *
+ * @example
+ * children = {
+ * div:{p:{}, h1:{}}
+ * };
+ * @field children
+ * @type Object
+ */
+ self.children = children;
+
+ /**
+ * Name/value map object with valid styles for each element.
+ *
+ * @method getValidStyles
+ * @type Object
+ */
+ self.getValidStyles = function () {
+ return validStyles;
+ };
+
+ /**
+ * Name/value map object with valid styles for each element.
+ *
+ * @method getInvalidStyles
+ * @type Object
+ */
+ self.getInvalidStyles = function () {
+ return invalidStyles;
+ };
+
+ /**
+ * Name/value map object with valid classes for each element.
+ *
+ * @method getValidClasses
+ * @type Object
+ */
+ self.getValidClasses = function () {
+ return validClasses;
+ };
+
+ /**
+ * Returns a map with boolean attributes.
+ *
+ * @method getBoolAttrs
+ * @return {Object} Name/value lookup map for boolean attributes.
+ */
+ self.getBoolAttrs = function () {
+ return boolAttrMap;
+ };
+
+ /**
+ * Returns a map with block elements.
+ *
+ * @method getBlockElements
+ * @return {Object} Name/value lookup map for block elements.
+ */
+ self.getBlockElements = function () {
+ return blockElementsMap;
+ };
+
+ /**
+ * Returns a map with text block elements. Such as: p,h1-h6,div,address
+ *
+ * @method getTextBlockElements
+ * @return {Object} Name/value lookup map for block elements.
+ */
+ self.getTextBlockElements = function () {
+ return textBlockElementsMap;
+ };
+
+ /**
+ * Returns a map of inline text format nodes for example strong/span or ins.
+ *
+ * @method getTextInlineElements
+ * @return {Object} Name/value lookup map for text format elements.
+ */
+ self.getTextInlineElements = function () {
+ return textInlineElementsMap;
+ };
+
+ /**
+ * Returns a map with short ended elements such as BR or IMG.
+ *
+ * @method getShortEndedElements
+ * @return {Object} Name/value lookup map for short ended elements.
+ */
+ self.getShortEndedElements = function () {
+ return shortEndedElementsMap;
+ };
+
+ /**
+ * Returns a map with self closing tags such as
.
+ *
+ * @method getSelfClosingElements
+ * @return {Object} Name/value lookup map for self closing tags elements.
+ */
+ self.getSelfClosingElements = function () {
+ return selfClosingElementsMap;
+ };
+
+ /**
+ * Returns a map with elements that should be treated as contents regardless if it has text
+ * content in them or not such as TD, VIDEO or IMG.
+ *
+ * @method getNonEmptyElements
+ * @return {Object} Name/value lookup map for non empty elements.
+ */
+ self.getNonEmptyElements = function () {
+ return nonEmptyElementsMap;
+ };
+
+ /**
+ * Returns a map with elements that the caret should be moved in front of after enter is
+ * pressed
+ *
+ * @method getMoveCaretBeforeOnEnterElements
+ * @return {Object} Name/value lookup map for elements to place the caret in front of.
+ */
+ self.getMoveCaretBeforeOnEnterElements = function () {
+ return moveCaretBeforeOnEnterElementsMap;
+ };
+
+ /**
+ * Returns a map with elements where white space is to be preserved like PRE or SCRIPT.
+ *
+ * @method getWhiteSpaceElements
+ * @return {Object} Name/value lookup map for white space elements.
+ */
+ self.getWhiteSpaceElements = function () {
+ return whiteSpaceElementsMap;
+ };
+
+ /**
+ * Returns a map with special elements. These are elements that needs to be parsed
+ * in a special way such as script, style, textarea etc. The map object values
+ * are regexps used to find the end of the element.
+ *
+ * @method getSpecialElements
+ * @return {Object} Name/value lookup map for special elements.
+ */
+ self.getSpecialElements = function () {
+ return specialElements;
+ };
+
+ /**
+ * Returns true/false if the specified element and it's child is valid or not
+ * according to the schema.
+ *
+ * @method isValidChild
+ * @param {String} name Element name to check for.
+ * @param {String} child Element child to verify.
+ * @return {Boolean} True/false if the element is a valid child of the specified parent.
+ */
+ self.isValidChild = function (name, child) {
+ var parent = children[name.toLowerCase()];
+
+ return !!(parent && parent[child.toLowerCase()]);
+ };
+
+ /**
+ * Returns true/false if the specified element name and optional attribute is
+ * valid according to the schema.
+ *
+ * @method isValid
+ * @param {String} name Name of element to check.
+ * @param {String} attr Optional attribute name to check for.
+ * @return {Boolean} True/false if the element and attribute is valid.
+ */
+ self.isValid = function (name, attr) {
+ var attrPatterns, i, rule = getElementRule(name);
+
+ // Check if it's a valid element
+ if (rule) {
+ if (attr) {
+ // Check if attribute name exists
+ if (rule.attributes[attr]) {
+ return true;
+ }
+
+ // Check if attribute matches a regexp pattern
+ attrPatterns = rule.attributePatterns;
+ if (attrPatterns) {
+ i = attrPatterns.length;
+ while (i--) {
+ if (attrPatterns[i].pattern.test(name)) {
+ return true;
+ }
+ }
+ }
+ } else {
+ return true;
+ }
+ }
+
+ // No match
+ return false;
+ };
+
+ /**
+ * Returns true/false if the specified element is valid or not
+ * according to the schema.
+ *
+ * @method getElementRule
+ * @param {String} name Element name to check for.
+ * @return {Object} Element object or undefined if the element isn't valid.
+ */
+ self.getElementRule = getElementRule;
+
+ /**
+ * Returns an map object of all custom elements.
+ *
+ * @method getCustomElements
+ * @return {Object} Name/value map object of all custom elements.
+ */
+ self.getCustomElements = function () {
+ return customElementsMap;
+ };
+
+ /**
+ * Parses a valid elements string and adds it to the schema. The valid elements
+ * format is for example "element[attr=default|otherattr]".
+ * Existing rules will be replaced with the ones specified, so this extends the schema.
+ *
+ * @method addValidElements
+ * @param {String} valid_elements String in the valid elements format to be parsed.
+ */
+ self.addValidElements = addValidElements;
+
+ /**
+ * Parses a valid elements string and sets it to the schema. The valid elements
+ * format is for example "element[attr=default|otherattr]".
+ * Existing rules will be replaced with the ones specified, so this extends the schema.
+ *
+ * @method setValidElements
+ * @param {String} valid_elements String in the valid elements format to be parsed.
+ */
+ self.setValidElements = setValidElements;
+
+ /**
+ * Adds custom non HTML elements to the schema.
+ *
+ * @method addCustomElements
+ * @param {String} custom_elements Comma separated list of custom elements to add.
+ */
+ self.addCustomElements = addCustomElements;
+
+ /**
+ * Parses a valid children string and adds them to the schema structure. The valid children
+ * format is for example: "element[child1|child2]".
+ *
+ * @method addValidChildren
+ * @param {String} valid_children Valid children elements string to parse
+ */
+ self.addValidChildren = addValidChildren;
+
+ self.elements = elements;
+ };
+ }
+);
+
+/**
+ * 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
+ */
+
+/**
+ * Utility class for various DOM manipulation and retrieval functions.
+ *
+ * @class tinymce.dom.DOMUtils
+ * @example
+ * // Add a class to an element by id in the page
+ * tinymce.DOM.addClass('someid', 'someclass');
+ *
+ * // Add a class to an element by id inside the editor
+ * tinymce.activeEditor.dom.addClass('someid', 'someclass');
+ */
+define(
+ 'tinymce.core.dom.DOMUtils',
+ [
+ 'tinymce.core.dom.DomQuery',
+ 'tinymce.core.dom.EventUtils',
+ 'tinymce.core.dom.Range',
+ 'tinymce.core.dom.Sizzle',
+ 'tinymce.core.dom.StyleSheetLoader',
+ 'tinymce.core.dom.TreeWalker',
+ 'tinymce.core.Env',
+ 'tinymce.core.html.Entities',
+ 'tinymce.core.html.Schema',
+ 'tinymce.core.html.Styles',
+ 'tinymce.core.util.Tools'
+ ],
+ function (DomQuery, EventUtils, Range, Sizzle, StyleSheetLoader, TreeWalker, Env, Entities, Schema, Styles, Tools) {
+ // Shorten names
+ var each = Tools.each, is = Tools.is, grep = Tools.grep, trim = Tools.trim;
+ var isIE = Env.ie;
+ var simpleSelectorRe = /^([a-z0-9],?)+$/i;
+ var whiteSpaceRegExp = /^[ \t\r\n]*$/;
+
+ function setupAttrHooks(domUtils, settings) {
+ var attrHooks = {}, keepValues = settings.keep_values, keepUrlHook;
+
+ keepUrlHook = {
+ set: function ($elm, value, name) {
+ if (settings.url_converter) {
+ value = settings.url_converter.call(settings.url_converter_scope || domUtils, value, name, $elm[0]);
+ }
+
+ $elm.attr('data-mce-' + name, value).attr(name, value);
+ },
+
+ get: function ($elm, name) {
+ return $elm.attr('data-mce-' + name) || $elm.attr(name);
+ }
+ };
+
+ attrHooks = {
+ style: {
+ set: function ($elm, value) {
+ if (value !== null && typeof value === 'object') {
+ $elm.css(value);
+ return;
+ }
+
+ if (keepValues) {
+ $elm.attr('data-mce-style', value);
+ }
+
+ $elm.attr('style', value);
+ },
+
+ get: function ($elm) {
+ var value = $elm.attr('data-mce-style') || $elm.attr('style');
+
+ value = domUtils.serializeStyle(domUtils.parseStyle(value), $elm[0].nodeName);
+
+ return value;
+ }
+ }
+ };
+
+ if (keepValues) {
+ attrHooks.href = attrHooks.src = keepUrlHook;
+ }
+
+ return attrHooks;
+ }
+
+ function updateInternalStyleAttr(domUtils, $elm) {
+ var value = $elm.attr('style');
+
+ value = domUtils.serializeStyle(domUtils.parseStyle(value), $elm[0].nodeName);
+
+ if (!value) {
+ value = null;
+ }
+
+ $elm.attr('data-mce-style', value);
+ }
+
+ function nodeIndex(node, normalized) {
+ var idx = 0, lastNodeType, nodeType;
+
+ if (node) {
+ for (lastNodeType = node.nodeType, node = node.previousSibling; node; node = node.previousSibling) {
+ nodeType = node.nodeType;
+
+ // Normalize text nodes
+ if (normalized && nodeType == 3) {
+ if (nodeType == lastNodeType || !node.nodeValue.length) {
+ continue;
+ }
+ }
+ idx++;
+ lastNodeType = nodeType;
+ }
+ }
+
+ return idx;
+ }
+
+ /**
+ * Constructs a new DOMUtils instance. Consult the Wiki for more details on settings etc for this class.
+ *
+ * @constructor
+ * @method DOMUtils
+ * @param {Document} doc Document reference to bind the utility class to.
+ * @param {settings} settings Optional settings collection.
+ */
+ function DOMUtils(doc, settings) {
+ var self = this, blockElementsMap;
+
+ self.doc = doc;
+ self.win = window;
+ self.files = {};
+ self.counter = 0;
+ self.stdMode = !isIE || doc.documentMode >= 8;
+ self.boxModel = !isIE || doc.compatMode == "CSS1Compat" || self.stdMode;
+ self.styleSheetLoader = new StyleSheetLoader(doc);
+ self.boundEvents = [];
+ self.settings = settings = settings || {};
+ self.schema = settings.schema ? settings.schema : new Schema({});
+ self.styles = new Styles({
+ url_converter: settings.url_converter,
+ url_converter_scope: settings.url_converter_scope
+ }, settings.schema);
+
+ self.fixDoc(doc);
+ self.events = settings.ownEvents ? new EventUtils(settings.proxy) : EventUtils.Event;
+ self.attrHooks = setupAttrHooks(self, settings);
+ blockElementsMap = settings.schema ? settings.schema.getBlockElements() : {};
+ self.$ = DomQuery.overrideDefaults(function () {
+ return {
+ context: doc,
+ element: self.getRoot()
+ };
+ });
+
+ /**
+ * Returns true/false if the specified element is a block element or not.
+ *
+ * @method isBlock
+ * @param {Node/String} node Element/Node to check.
+ * @return {Boolean} True/False state if the node is a block element or not.
+ */
+ self.isBlock = function (node) {
+ // Fix for #5446
+ if (!node) {
+ return false;
+ }
+
+ // This function is called in module pattern style since it might be executed with the wrong this scope
+ var type = node.nodeType;
+
+ // If it's a node then check the type and use the nodeName
+ if (type) {
+ return !!(type === 1 && blockElementsMap[node.nodeName]);
+ }
+
+ return !!blockElementsMap[node];
+ };
+ }
+
+ DOMUtils.prototype = {
+ $$: function (elm) {
+ if (typeof elm == 'string') {
+ elm = this.get(elm);
+ }
+
+ return this.$(elm);
+ },
+
+ root: null,
+
+ fixDoc: function (doc) {
+ var settings = this.settings, name;
+
+ if (isIE && settings.schema) {
+ // Add missing HTML 4/5 elements to IE
+ ('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 (name) {
+ doc.createElement(name);
+ });
+
+ // Create all custom elements
+ for (name in settings.schema.getCustomElements()) {
+ doc.createElement(name);
+ }
+ }
+ },
+
+ clone: function (node, deep) {
+ var self = this, clone, doc;
+
+ // TODO: Add feature detection here in the future
+ if (!isIE || node.nodeType !== 1 || deep) {
+ return node.cloneNode(deep);
+ }
+
+ doc = self.doc;
+
+ // Make a HTML5 safe shallow copy
+ if (!deep) {
+ clone = doc.createElement(node.nodeName);
+
+ // Copy attribs
+ each(self.getAttribs(node), function (attr) {
+ self.setAttrib(clone, attr.nodeName, self.getAttrib(node, attr.nodeName));
+ });
+
+ return clone;
+ }
+
+ return clone.firstChild;
+ },
+
+ /**
+ * Returns the root node of the document. This is normally the body but might be a DIV. Parents like getParent will not
+ * go above the point of this root node.
+ *
+ * @method getRoot
+ * @return {Element} Root element for the utility class.
+ */
+ getRoot: function () {
+ var self = this;
+
+ return self.settings.root_element || self.doc.body;
+ },
+
+ /**
+ * Returns the viewport of the window.
+ *
+ * @method getViewPort
+ * @param {Window} win Optional window to get viewport of.
+ * @return {Object} Viewport object with fields x, y, w and h.
+ */
+ getViewPort: function (win) {
+ var doc, rootElm;
+
+ win = !win ? this.win : win;
+ doc = win.document;
+ rootElm = this.boxModel ? doc.documentElement : doc.body;
+
+ // Returns viewport size excluding scrollbars
+ return {
+ x: win.pageXOffset || rootElm.scrollLeft,
+ y: win.pageYOffset || rootElm.scrollTop,
+ w: win.innerWidth || rootElm.clientWidth,
+ h: win.innerHeight || rootElm.clientHeight
+ };
+ },
+
+ /**
+ * Returns the rectangle for a specific element.
+ *
+ * @method getRect
+ * @param {Element/String} elm Element object or element ID to get rectangle from.
+ * @return {object} Rectangle for specified element object with x, y, w, h fields.
+ */
+ getRect: function (elm) {
+ var self = this, pos, size;
+
+ elm = self.get(elm);
+ pos = self.getPos(elm);
+ size = self.getSize(elm);
+
+ return {
+ x: pos.x, y: pos.y,
+ w: size.w, h: size.h
+ };
+ },
+
+ /**
+ * Returns the size dimensions of the specified element.
+ *
+ * @method getSize
+ * @param {Element/String} elm Element object or element ID to get rectangle from.
+ * @return {object} Rectangle for specified element object with w, h fields.
+ */
+ getSize: function (elm) {
+ var self = this, w, h;
+
+ elm = self.get(elm);
+ w = self.getStyle(elm, 'width');
+ h = self.getStyle(elm, 'height');
+
+ // Non pixel value, then force offset/clientWidth
+ if (w.indexOf('px') === -1) {
+ w = 0;
+ }
+
+ // Non pixel value, then force offset/clientWidth
+ if (h.indexOf('px') === -1) {
+ h = 0;
+ }
+
+ return {
+ w: parseInt(w, 10) || elm.offsetWidth || elm.clientWidth,
+ h: parseInt(h, 10) || elm.offsetHeight || elm.clientHeight
+ };
+ },
+
+ /**
+ * Returns a node by the specified selector function. This function will
+ * loop through all parent nodes and call the specified function for each node.
+ * If the function then returns true indicating that it has found what it was looking for, the loop execution will then end
+ * and the node it found will be returned.
+ *
+ * @method getParent
+ * @param {Node/String} node DOM node to search parents on or ID string.
+ * @param {function} selector Selection function or CSS selector to execute on each node.
+ * @param {Node} root Optional root element, never go beyond this point.
+ * @return {Node} DOM Node or null if it wasn't found.
+ */
+ getParent: function (node, selector, root) {
+ return this.getParents(node, selector, root, false);
+ },
+
+ /**
+ * Returns a node list of all parents matching the specified selector function or pattern.
+ * If the function then returns true indicating that it has found what it was looking for and that node will be collected.
+ *
+ * @method getParents
+ * @param {Node/String} node DOM node to search parents on or ID string.
+ * @param {function} selector Selection function to execute on each node or CSS pattern.
+ * @param {Node} root Optional root element, never go beyond this point.
+ * @return {Array} Array of nodes or null if it wasn't found.
+ */
+ getParents: function (node, selector, root, collect) {
+ var self = this, selectorVal, result = [];
+
+ node = self.get(node);
+ collect = collect === undefined;
+
+ // Default root on inline mode
+ root = root || (self.getRoot().nodeName != 'BODY' ? self.getRoot().parentNode : null);
+
+ // Wrap node name as func
+ if (is(selector, 'string')) {
+ selectorVal = selector;
+
+ if (selector === '*') {
+ selector = function (node) {
+ return node.nodeType == 1;
+ };
+ } else {
+ selector = function (node) {
+ return self.is(node, selectorVal);
+ };
+ }
+ }
+
+ while (node) {
+ if (node == root || !node.nodeType || node.nodeType === 9) {
+ break;
+ }
+
+ if (!selector || selector(node)) {
+ if (collect) {
+ result.push(node);
+ } else {
+ return node;
+ }
+ }
+
+ node = node.parentNode;
+ }
+
+ return collect ? result : null;
+ },
+
+ /**
+ * Returns the specified element by ID or the input element if it isn't a string.
+ *
+ * @method get
+ * @param {String/Element} n Element id to look for or element to just pass though.
+ * @return {Element} Element matching the specified id or null if it wasn't found.
+ */
+ get: function (elm) {
+ var name;
+
+ if (elm && this.doc && typeof elm == 'string') {
+ name = elm;
+ elm = this.doc.getElementById(elm);
+
+ // IE and Opera returns meta elements when they match the specified input ID, but getElementsByName seems to do the trick
+ if (elm && elm.id !== name) {
+ return this.doc.getElementsByName(name)[1];
+ }
+ }
+
+ return elm;
+ },
+
+ /**
+ * Returns the next node that matches selector or function
+ *
+ * @method getNext
+ * @param {Node} node Node to find siblings from.
+ * @param {String/function} selector Selector CSS expression or function.
+ * @return {Node} Next node item matching the selector or null if it wasn't found.
+ */
+ getNext: function (node, selector) {
+ return this._findSib(node, selector, 'nextSibling');
+ },
+
+ /**
+ * Returns the previous node that matches selector or function
+ *
+ * @method getPrev
+ * @param {Node} node Node to find siblings from.
+ * @param {String/function} selector Selector CSS expression or function.
+ * @return {Node} Previous node item matching the selector or null if it wasn't found.
+ */
+ getPrev: function (node, selector) {
+ return this._findSib(node, selector, 'previousSibling');
+ },
+
+ // #ifndef jquery
+
+ /**
+ * Selects specific elements by a CSS level 3 pattern. For example "div#a1 p.test".
+ * This function is optimized for the most common patterns needed in TinyMCE but it also performs well enough
+ * on more complex patterns.
+ *
+ * @method select
+ * @param {String} selector CSS level 3 pattern to select/find elements by.
+ * @param {Object} scope Optional root element/scope element to search in.
+ * @return {Array} Array with all matched elements.
+ * @example
+ * // Adds a class to all paragraphs in the currently active editor
+ * tinymce.activeEditor.dom.addClass(tinymce.activeEditor.dom.select('p'), 'someclass');
+ *
+ * // Adds a class to all spans that have the test class in the currently active editor
+ * tinymce.activeEditor.dom.addClass(tinymce.activeEditor.dom.select('span.test'), 'someclass')
+ */
+ select: function (selector, scope) {
+ var self = this;
+
+ /*eslint new-cap:0 */
+ return Sizzle(selector, self.get(scope) || self.settings.root_element || self.doc, []);
+ },
+
+ /**
+ * Returns true/false if the specified element matches the specified css pattern.
+ *
+ * @method is
+ * @param {Node/NodeList} elm DOM node to match or an array of nodes to match.
+ * @param {String} selector CSS pattern to match the element against.
+ */
+ is: function (elm, selector) {
+ var i;
+
+ if (!elm) {
+ return false;
+ }
+
+ // If it isn't an array then try to do some simple selectors instead of Sizzle for to boost performance
+ if (elm.length === undefined) {
+ // Simple all selector
+ if (selector === '*') {
+ return elm.nodeType == 1;
+ }
+
+ // Simple selector just elements
+ if (simpleSelectorRe.test(selector)) {
+ selector = selector.toLowerCase().split(/,/);
+ elm = elm.nodeName.toLowerCase();
+
+ for (i = selector.length - 1; i >= 0; i--) {
+ if (selector[i] == elm) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+
+ // Is non element
+ if (elm.nodeType && elm.nodeType != 1) {
+ return false;
+ }
+
+ var elms = elm.nodeType ? [elm] : elm;
+
+ /*eslint new-cap:0 */
+ return Sizzle(selector, elms[0].ownerDocument || elms[0], null, elms).length > 0;
+ },
+
+ // #endif
+
+ /**
+ * Adds the specified element to another element or elements.
+ *
+ * @method add
+ * @param {String/Element/Array} parentElm Element id string, DOM node element or array of ids or elements to add to.
+ * @param {String/Element} name Name of new element to add or existing element to add.
+ * @param {Object} attrs Optional object collection with arguments to add to the new element(s).
+ * @param {String} html Optional inner HTML contents to add for each element.
+ * @param {Boolean} create Optional flag if the element should be created or added.
+ * @return {Element/Array} Element that got created, or an array of created elements if multiple input elements
+ * were passed in.
+ * @example
+ * // Adds a new paragraph to the end of the active editor
+ * tinymce.activeEditor.dom.add(tinymce.activeEditor.getBody(), 'p', {title: 'my title'}, 'Some content');
+ */
+ add: function (parentElm, name, attrs, html, create) {
+ var self = this;
+
+ return this.run(parentElm, function (parentElm) {
+ var newElm;
+
+ newElm = is(name, 'string') ? self.doc.createElement(name) : name;
+ self.setAttribs(newElm, attrs);
+
+ if (html) {
+ if (html.nodeType) {
+ newElm.appendChild(html);
+ } else {
+ self.setHTML(newElm, html);
+ }
+ }
+
+ return !create ? parentElm.appendChild(newElm) : newElm;
+ });
+ },
+
+ /**
+ * Creates a new element.
+ *
+ * @method create
+ * @param {String} name Name of new element.
+ * @param {Object} attrs Optional object name/value collection with element attributes.
+ * @param {String} html Optional HTML string to set as inner HTML of the element.
+ * @return {Element} HTML DOM node element that got created.
+ * @example
+ * // Adds an element where the caret/selection is in the active editor
+ * var el = tinymce.activeEditor.dom.create('div', {id: 'test', 'class': 'myclass'}, 'some content');
+ * tinymce.activeEditor.selection.setNode(el);
+ */
+ create: function (name, attrs, html) {
+ return this.add(this.doc.createElement(name), name, attrs, html, 1);
+ },
+
+ /**
+ * Creates HTML string for element. The element will be closed unless an empty inner HTML string is passed in.
+ *
+ * @method createHTML
+ * @param {String} name Name of new element.
+ * @param {Object} attrs Optional object name/value collection with element attributes.
+ * @param {String} html Optional HTML string to set as inner HTML of the element.
+ * @return {String} String with new HTML element, for example: test.
+ * @example
+ * // Creates a html chunk and inserts it at the current selection/caret location
+ * tinymce.activeEditor.selection.setContent(tinymce.activeEditor.dom.createHTML('a', {href: 'test.html'}, 'some line'));
+ */
+ createHTML: function (name, attrs, html) {
+ var outHtml = '', key;
+
+ outHtml += '<' + name;
+
+ for (key in attrs) {
+ if (attrs.hasOwnProperty(key) && attrs[key] !== null && typeof attrs[key] != 'undefined') {
+ outHtml += ' ' + key + '="' + this.encode(attrs[key]) + '"';
+ }
+ }
+
+ // A call to tinymce.is doesn't work for some odd reason on IE9 possible bug inside their JS runtime
+ if (typeof html != "undefined") {
+ return outHtml + '>' + html + '' + name + '>';
+ }
+
+ return outHtml + ' />';
+ },
+
+ /**
+ * Creates a document fragment out of the specified HTML string.
+ *
+ * @method createFragment
+ * @param {String} html Html string to create fragment from.
+ * @return {DocumentFragment} Document fragment node.
+ */
+ createFragment: function (html) {
+ var frag, node, doc = this.doc, container;
+
+ container = doc.createElement("div");
+ frag = doc.createDocumentFragment();
+
+ if (html) {
+ container.innerHTML = html;
+ }
+
+ while ((node = container.firstChild)) {
+ frag.appendChild(node);
+ }
+
+ return frag;
+ },
+
+ /**
+ * Removes/deletes the specified element(s) from the DOM.
+ *
+ * @method remove
+ * @param {String/Element/Array} node ID of element or DOM element object or array containing multiple elements/ids.
+ * @param {Boolean} keepChildren Optional state to keep children or not. If set to true all children will be
+ * placed at the location of the removed element.
+ * @return {Element/Array} HTML DOM element that got removed, or an array of removed elements if multiple input elements
+ * were passed in.
+ * @example
+ * // Removes all paragraphs in the active editor
+ * tinymce.activeEditor.dom.remove(tinymce.activeEditor.dom.select('p'));
+ *
+ * // Removes an element by id in the document
+ * tinymce.DOM.remove('mydiv');
+ */
+ remove: function (node, keepChildren) {
+ node = this.$$(node);
+
+ if (keepChildren) {
+ node.each(function () {
+ var child;
+
+ while ((child = this.firstChild)) {
+ if (child.nodeType == 3 && child.data.length === 0) {
+ this.removeChild(child);
+ } else {
+ this.parentNode.insertBefore(child, this);
+ }
+ }
+ }).remove();
+ } else {
+ node.remove();
+ }
+
+ return node.length > 1 ? node.toArray() : node[0];
+ },
+
+ /**
+ * Sets the CSS style value on a HTML element. The name can be a camelcase string
+ * or the CSS style name like background-color.
+ *
+ * @method setStyle
+ * @param {String/Element/Array} elm HTML element/Array of elements to set CSS style value on.
+ * @param {String} name Name of the style value to set.
+ * @param {String} value Value to set on the style.
+ * @example
+ * // Sets a style value on all paragraphs in the currently active editor
+ * tinymce.activeEditor.dom.setStyle(tinymce.activeEditor.dom.select('p'), 'background-color', 'red');
+ *
+ * // Sets a style value to an element by id in the current document
+ * tinymce.DOM.setStyle('mydiv', 'background-color', 'red');
+ */
+ setStyle: function (elm, name, value) {
+ elm = this.$$(elm).css(name, value);
+
+ if (this.settings.update_styles) {
+ updateInternalStyleAttr(this, elm);
+ }
+ },
+
+ /**
+ * Returns the current style or runtime/computed value of an element.
+ *
+ * @method getStyle
+ * @param {String/Element} elm HTML element or element id string to get style from.
+ * @param {String} name Style name to return.
+ * @param {Boolean} computed Computed style.
+ * @return {String} Current style or computed style value of an element.
+ */
+ getStyle: function (elm, name, computed) {
+ elm = this.$$(elm);
+
+ if (computed) {
+ return elm.css(name);
+ }
+
+ // Camelcase it, if needed
+ name = name.replace(/-(\D)/g, function (a, b) {
+ return b.toUpperCase();
+ });
+
+ if (name == 'float') {
+ name = Env.ie && Env.ie < 12 ? 'styleFloat' : 'cssFloat';
+ }
+
+ return elm[0] && elm[0].style ? elm[0].style[name] : undefined;
+ },
+
+ /**
+ * Sets multiple styles on the specified element(s).
+ *
+ * @method setStyles
+ * @param {Element/String/Array} elm DOM element, element id string or array of elements/ids to set styles on.
+ * @param {Object} styles Name/Value collection of style items to add to the element(s).
+ * @example
+ * // Sets styles on all paragraphs in the currently active editor
+ * tinymce.activeEditor.dom.setStyles(tinymce.activeEditor.dom.select('p'), {'background-color': 'red', 'color': 'green'});
+ *
+ * // Sets styles to an element by id in the current document
+ * tinymce.DOM.setStyles('mydiv', {'background-color': 'red', 'color': 'green'});
+ */
+ setStyles: function (elm, styles) {
+ elm = this.$$(elm).css(styles);
+
+ if (this.settings.update_styles) {
+ updateInternalStyleAttr(this, elm);
+ }
+ },
+
+ /**
+ * Removes all attributes from an element or elements.
+ *
+ * @method removeAllAttribs
+ * @param {Element/String/Array} e DOM element, element id string or array of elements/ids to remove attributes from.
+ */
+ removeAllAttribs: function (e) {
+ return this.run(e, function (e) {
+ var i, attrs = e.attributes;
+ for (i = attrs.length - 1; i >= 0; i--) {
+ e.removeAttributeNode(attrs.item(i));
+ }
+ });
+ },
+
+ /**
+ * Sets the specified attribute of an element or elements.
+ *
+ * @method setAttrib
+ * @param {Element/String/Array} elm DOM element, element id string or array of elements/ids to set attribute on.
+ * @param {String} name Name of attribute to set.
+ * @param {String} value Value to set on the attribute - if this value is falsy like null, 0 or '' it will remove
+ * the attribute instead.
+ * @example
+ * // Sets class attribute on all paragraphs in the active editor
+ * tinymce.activeEditor.dom.setAttrib(tinymce.activeEditor.dom.select('p'), 'class', 'myclass');
+ *
+ * // Sets class attribute on a specific element in the current page
+ * tinymce.dom.setAttrib('mydiv', 'class', 'myclass');
+ */
+ setAttrib: function (elm, name, value) {
+ var self = this, originalValue, hook, settings = self.settings;
+
+ if (value === '') {
+ value = null;
+ }
+
+ elm = self.$$(elm);
+ originalValue = elm.attr(name);
+
+ if (!elm.length) {
+ return;
+ }
+
+ hook = self.attrHooks[name];
+ if (hook && hook.set) {
+ hook.set(elm, value, name);
+ } else {
+ elm.attr(name, value);
+ }
+
+ if (originalValue != value && settings.onSetAttrib) {
+ settings.onSetAttrib({
+ attrElm: elm,
+ attrName: name,
+ attrValue: value
+ });
+ }
+ },
+
+ /**
+ * Sets two or more specified attributes of an element or elements.
+ *
+ * @method setAttribs
+ * @param {Element/String/Array} elm DOM element, element id string or array of elements/ids to set attributes on.
+ * @param {Object} attrs Name/Value collection of attribute items to add to the element(s).
+ * @example
+ * // Sets class and title attributes on all paragraphs in the active editor
+ * tinymce.activeEditor.dom.setAttribs(tinymce.activeEditor.dom.select('p'), {'class': 'myclass', title: 'some title'});
+ *
+ * // Sets class and title attributes on a specific element in the current page
+ * tinymce.DOM.setAttribs('mydiv', {'class': 'myclass', title: 'some title'});
+ */
+ setAttribs: function (elm, attrs) {
+ var self = this;
+
+ self.$$(elm).each(function (i, node) {
+ each(attrs, function (value, name) {
+ self.setAttrib(node, name, value);
+ });
+ });
+ },
+
+ /**
+ * Returns the specified attribute by name.
+ *
+ * @method getAttrib
+ * @param {String/Element} elm Element string id or DOM element to get attribute from.
+ * @param {String} name Name of attribute to get.
+ * @param {String} defaultVal Optional default value to return if the attribute didn't exist.
+ * @return {String} Attribute value string, default value or null if the attribute wasn't found.
+ */
+ getAttrib: function (elm, name, defaultVal) {
+ var self = this, hook, value;
+
+ elm = self.$$(elm);
+
+ if (elm.length) {
+ hook = self.attrHooks[name];
+
+ if (hook && hook.get) {
+ value = hook.get(elm, name);
+ } else {
+ value = elm.attr(name);
+ }
+ }
+
+ if (typeof value == 'undefined') {
+ value = defaultVal || '';
+ }
+
+ return value;
+ },
+
+ /**
+ * Returns the absolute x, y position of a node. The position will be returned in an object with x, y fields.
+ *
+ * @method getPos
+ * @param {Element/String} elm HTML element or element id to get x, y position from.
+ * @param {Element} rootElm Optional root element to stop calculations at.
+ * @return {object} Absolute position of the specified element object with x, y fields.
+ */
+ getPos: function (elm, rootElm) {
+ var self = this, x = 0, y = 0, offsetParent, doc = self.doc, body = doc.body, pos;
+
+ elm = self.get(elm);
+ rootElm = rootElm || body;
+
+ if (elm) {
+ // Use getBoundingClientRect if it exists since it's faster than looping offset nodes
+ // Fallback to offsetParent calculations if the body isn't static better since it stops at the body root
+ if (rootElm === body && elm.getBoundingClientRect && DomQuery(body).css('position') === 'static') {
+ pos = elm.getBoundingClientRect();
+ rootElm = self.boxModel ? doc.documentElement : body;
+
+ // Add scroll offsets from documentElement or body since IE with the wrong box model will use d.body and so do WebKit
+ // Also remove the body/documentelement clientTop/clientLeft on IE 6, 7 since they offset the position
+ x = pos.left + (doc.documentElement.scrollLeft || body.scrollLeft) - rootElm.clientLeft;
+ y = pos.top + (doc.documentElement.scrollTop || body.scrollTop) - rootElm.clientTop;
+
+ return { x: x, y: y };
+ }
+
+ offsetParent = elm;
+ while (offsetParent && offsetParent != rootElm && offsetParent.nodeType) {
+ x += offsetParent.offsetLeft || 0;
+ y += offsetParent.offsetTop || 0;
+ offsetParent = offsetParent.offsetParent;
+ }
+
+ offsetParent = elm.parentNode;
+ while (offsetParent && offsetParent != rootElm && offsetParent.nodeType) {
+ x -= offsetParent.scrollLeft || 0;
+ y -= offsetParent.scrollTop || 0;
+ offsetParent = offsetParent.parentNode;
+ }
+ }
+
+ return { x: x, y: y };
+ },
+
+ /**
+ * 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 parseStyle
+ * @param {String} cssText Style value to parse, for example: border:1px solid red;.
+ * @return {Object} Object representation of that style, for example: {border: '1px solid red'}
+ */
+ parseStyle: function (cssText) {
+ return this.styles.parse(cssText);
+ },
+
+ /**
+ * Serializes the specified style object into a string.
+ *
+ * @method serializeStyle
+ * @param {Object} styles Object to serialize as string, for example: {border: '1px solid red'}
+ * @param {String} name Optional element name.
+ * @return {String} String representation of the style object, for example: border: 1px solid red.
+ */
+ serializeStyle: function (styles, name) {
+ return this.styles.serialize(styles, name);
+ },
+
+ /**
+ * Adds a style element at the top of the document with the specified cssText content.
+ *
+ * @method addStyle
+ * @param {String} cssText CSS Text style to add to top of head of document.
+ */
+ addStyle: function (cssText) {
+ var self = this, doc = self.doc, head, styleElm;
+
+ // Prevent inline from loading the same styles twice
+ if (self !== DOMUtils.DOM && doc === document) {
+ var addedStyles = DOMUtils.DOM.addedStyles;
+
+ addedStyles = addedStyles || [];
+ if (addedStyles[cssText]) {
+ return;
+ }
+
+ addedStyles[cssText] = true;
+ DOMUtils.DOM.addedStyles = addedStyles;
+ }
+
+ // Create style element if needed
+ styleElm = doc.getElementById('mceDefaultStyles');
+ if (!styleElm) {
+ styleElm = doc.createElement('style');
+ styleElm.id = 'mceDefaultStyles';
+ styleElm.type = 'text/css';
+
+ head = doc.getElementsByTagName('head')[0];
+ if (head.firstChild) {
+ head.insertBefore(styleElm, head.firstChild);
+ } else {
+ head.appendChild(styleElm);
+ }
+ }
+
+ // Append style data to old or new style element
+ if (styleElm.styleSheet) {
+ styleElm.styleSheet.cssText += cssText;
+ } else {
+ styleElm.appendChild(doc.createTextNode(cssText));
+ }
+ },
+
+ /**
+ * Imports/loads the specified CSS file into the document bound to the class.
+ *
+ * @method loadCSS
+ * @param {String} url URL to CSS file to load.
+ * @example
+ * // Loads a CSS file dynamically into the current document
+ * tinymce.DOM.loadCSS('somepath/some.css');
+ *
+ * // Loads a CSS file into the currently active editor instance
+ * tinymce.activeEditor.dom.loadCSS('somepath/some.css');
+ *
+ * // Loads a CSS file into an editor instance by id
+ * tinymce.get('someid').dom.loadCSS('somepath/some.css');
+ *
+ * // Loads multiple CSS files into the current document
+ * tinymce.DOM.loadCSS('somepath/some.css,somepath/someother.css');
+ */
+ loadCSS: function (url) {
+ var self = this, doc = self.doc, head;
+
+ // Prevent inline from loading the same CSS file twice
+ if (self !== DOMUtils.DOM && doc === document) {
+ DOMUtils.DOM.loadCSS(url);
+ return;
+ }
+
+ if (!url) {
+ url = '';
+ }
+
+ head = doc.getElementsByTagName('head')[0];
+
+ each(url.split(','), function (url) {
+ var link;
+
+ url = Tools._addCacheSuffix(url);
+
+ if (self.files[url]) {
+ return;
+ }
+
+ self.files[url] = true;
+ link = self.create('link', { rel: 'stylesheet', href: url });
+
+ // IE 8 has a bug where dynamically loading stylesheets would produce a 1 item remaining bug
+ // This fix seems to resolve that issue by recalcing the document once a stylesheet finishes loading
+ // It's ugly but it seems to work fine.
+ if (isIE && doc.documentMode && doc.recalc) {
+ link.onload = function () {
+ if (doc.recalc) {
+ doc.recalc();
+ }
+
+ link.onload = null;
+ };
+ }
+
+ head.appendChild(link);
+ });
+ },
+
+ /**
+ * Adds a class to the specified element or elements.
+ *
+ * @method addClass
+ * @param {String/Element/Array} elm Element ID string or DOM element or array with elements or IDs.
+ * @param {String} cls Class name to add to each element.
+ * @return {String/Array} String with new class value or array with new class values for all elements.
+ * @example
+ * // Adds a class to all paragraphs in the active editor
+ * tinymce.activeEditor.dom.addClass(tinymce.activeEditor.dom.select('p'), 'myclass');
+ *
+ * // Adds a class to a specific element in the current page
+ * tinymce.DOM.addClass('mydiv', 'myclass');
+ */
+ addClass: function (elm, cls) {
+ this.$$(elm).addClass(cls);
+ },
+
+ /**
+ * Removes a class from the specified element or elements.
+ *
+ * @method removeClass
+ * @param {String/Element/Array} elm Element ID string or DOM element or array with elements or IDs.
+ * @param {String} cls Class name to remove from each element.
+ * @return {String/Array} String of remaining class name(s), or an array of strings if multiple input elements
+ * were passed in.
+ * @example
+ * // Removes a class from all paragraphs in the active editor
+ * tinymce.activeEditor.dom.removeClass(tinymce.activeEditor.dom.select('p'), 'myclass');
+ *
+ * // Removes a class from a specific element in the current page
+ * tinymce.DOM.removeClass('mydiv', 'myclass');
+ */
+ removeClass: function (elm, cls) {
+ this.toggleClass(elm, cls, false);
+ },
+
+ /**
+ * Returns true if the specified element has the specified class.
+ *
+ * @method hasClass
+ * @param {String/Element} elm HTML element or element id string to check CSS class on.
+ * @param {String} cls CSS class to check for.
+ * @return {Boolean} true/false if the specified element has the specified class.
+ */
+ hasClass: function (elm, cls) {
+ return this.$$(elm).hasClass(cls);
+ },
+
+ /**
+ * Toggles the specified class on/off.
+ *
+ * @method toggleClass
+ * @param {Element} elm Element to toggle class on.
+ * @param {[type]} cls Class to toggle on/off.
+ * @param {[type]} state Optional state to set.
+ */
+ toggleClass: function (elm, cls, state) {
+ this.$$(elm).toggleClass(cls, state).each(function () {
+ if (this.className === '') {
+ DomQuery(this).attr('class', null);
+ }
+ });
+ },
+
+ /**
+ * Shows the specified element(s) by ID by setting the "display" style.
+ *
+ * @method show
+ * @param {String/Element/Array} elm ID of DOM element or DOM element or array with elements or IDs to show.
+ */
+ show: function (elm) {
+ this.$$(elm).show();
+ },
+
+ /**
+ * Hides the specified element(s) by ID by setting the "display" style.
+ *
+ * @method hide
+ * @param {String/Element/Array} elm ID of DOM element or DOM element or array with elements or IDs to hide.
+ * @example
+ * // Hides an element by id in the document
+ * tinymce.DOM.hide('myid');
+ */
+ hide: function (elm) {
+ this.$$(elm).hide();
+ },
+
+ /**
+ * Returns true/false if the element is hidden or not by checking the "display" style.
+ *
+ * @method isHidden
+ * @param {String/Element} elm Id or element to check display state on.
+ * @return {Boolean} true/false if the element is hidden or not.
+ */
+ isHidden: function (elm) {
+ return this.$$(elm).css('display') == 'none';
+ },
+
+ /**
+ * Returns a unique id. This can be useful when generating elements on the fly.
+ * This method will not check if the element already exists.
+ *
+ * @method uniqueId
+ * @param {String} prefix Optional prefix to add in front of all ids - defaults to "mce_".
+ * @return {String} Unique id.
+ */
+ uniqueId: function (prefix) {
+ return (!prefix ? 'mce_' : prefix) + (this.counter++);
+ },
+
+ /**
+ * Sets the specified HTML content inside the element or elements. The HTML will first be processed. This means
+ * URLs will get converted, hex color values fixed etc. Check processHTML for details.
+ *
+ * @method setHTML
+ * @param {Element/String/Array} elm DOM element, element id string or array of elements/ids to set HTML inside of.
+ * @param {String} html HTML content to set as inner HTML of the element.
+ * @example
+ * // Sets the inner HTML of all paragraphs in the active editor
+ * tinymce.activeEditor.dom.setHTML(tinymce.activeEditor.dom.select('p'), 'some inner html');
+ *
+ * // Sets the inner HTML of an element by id in the document
+ * tinymce.DOM.setHTML('mydiv', 'some inner html');
+ */
+ setHTML: function (elm, html) {
+ elm = this.$$(elm);
+
+ if (isIE) {
+ elm.each(function (i, target) {
+ if (target.canHaveHTML === false) {
+ return;
+ }
+
+ // Remove all child nodes, IE keeps empty text nodes in DOM
+ while (target.firstChild) {
+ target.removeChild(target.firstChild);
+ }
+
+ try {
+ // IE will remove comments from the beginning
+ // unless you padd the contents with something
+ target.innerHTML = ' ' + html;
+ target.removeChild(target.firstChild);
+ } catch (ex) {
+ // IE sometimes produces an unknown runtime error on innerHTML if it's a div inside a p
+ DomQuery('').html(' ' + html).contents().slice(1).appendTo(target);
+ }
+
+ return html;
+ });
+ } else {
+ elm.html(html);
+ }
+ },
+
+ /**
+ * Returns the outer HTML of an element.
+ *
+ * @method getOuterHTML
+ * @param {String/Element} elm Element ID or element object to get outer HTML from.
+ * @return {String} Outer HTML string.
+ * @example
+ * tinymce.DOM.getOuterHTML(editorElement);
+ * tinymce.activeEditor.getOuterHTML(tinymce.activeEditor.getBody());
+ */
+ getOuterHTML: function (elm) {
+ elm = this.get(elm);
+
+ // Older FF doesn't have outerHTML 3.6 is still used by some orgaizations
+ return elm.nodeType == 1 && "outerHTML" in elm ? elm.outerHTML : DomQuery('').append(DomQuery(elm).clone()).html();
+ },
+
+ /**
+ * Sets the specified outer HTML on an element or elements.
+ *
+ * @method setOuterHTML
+ * @param {Element/String/Array} elm DOM element, element id string or array of elements/ids to set outer HTML on.
+ * @param {Object} html HTML code to set as outer value for the element.
+ * @example
+ * // Sets the outer HTML of all paragraphs in the active editor
+ * tinymce.activeEditor.dom.setOuterHTML(tinymce.activeEditor.dom.select('p'), '
some html
');
+ *
+ * // Sets the outer HTML of an element by id in the document
+ * tinymce.DOM.setOuterHTML('mydiv', '
some html
');
+ */
+ setOuterHTML: function (elm, html) {
+ var self = this;
+
+ self.$$(elm).each(function () {
+ try {
+ // Older FF doesn't have outerHTML 3.6 is still used by some organizations
+ if ("outerHTML" in this) {
+ this.outerHTML = html;
+ return;
+ }
+ } catch (ex) {
+ // Ignore
+ }
+
+ // OuterHTML for IE it sometimes produces an "unknown runtime error"
+ self.remove(DomQuery(this).html(html), true);
+ });
+ },
+
+ /**
+ * Entity decodes a string. This method decodes any HTML entities, such as å.
+ *
+ * @method decode
+ * @param {String} s String to decode entities on.
+ * @return {String} Entity decoded string.
+ */
+ decode: Entities.decode,
+
+ /**
+ * Entity encodes a string. This method encodes the most common entities, such as <>"&.
+ *
+ * @method encode
+ * @param {String} text String to encode with entities.
+ * @return {String} Entity encoded string.
+ */
+ encode: Entities.encodeAllRaw,
+
+ /**
+ * Inserts an element after the reference element.
+ *
+ * @method insertAfter
+ * @param {Element} node Element to insert after the reference.
+ * @param {Element/String/Array} referenceNode Reference element, element id or array of elements to insert after.
+ * @return {Element/Array} Element that got added or an array with elements.
+ */
+ insertAfter: function (node, referenceNode) {
+ referenceNode = this.get(referenceNode);
+
+ return this.run(node, function (node) {
+ var parent, nextSibling;
+
+ parent = referenceNode.parentNode;
+ nextSibling = referenceNode.nextSibling;
+
+ if (nextSibling) {
+ parent.insertBefore(node, nextSibling);
+ } else {
+ parent.appendChild(node);
+ }
+
+ return node;
+ });
+ },
+
+ /**
+ * Replaces the specified element or elements with the new element specified. The new element will
+ * be cloned if multiple input elements are passed in.
+ *
+ * @method replace
+ * @param {Element} newElm New element to replace old ones with.
+ * @param {Element/String/Array} oldElm Element DOM node, element id or array of elements or ids to replace.
+ * @param {Boolean} keepChildren Optional keep children state, if set to true child nodes from the old object will be added
+ * to new ones.
+ */
+ replace: function (newElm, oldElm, keepChildren) {
+ var self = this;
+
+ return self.run(oldElm, function (oldElm) {
+ if (is(oldElm, 'array')) {
+ newElm = newElm.cloneNode(true);
+ }
+
+ if (keepChildren) {
+ each(grep(oldElm.childNodes), function (node) {
+ newElm.appendChild(node);
+ });
+ }
+
+ return oldElm.parentNode.replaceChild(newElm, oldElm);
+ });
+ },
+
+ /**
+ * Renames the specified element and keeps its attributes and children.
+ *
+ * @method rename
+ * @param {Element} elm Element to rename.
+ * @param {String} name Name of the new element.
+ * @return {Element} New element or the old element if it needed renaming.
+ */
+ rename: function (elm, name) {
+ var self = this, newElm;
+
+ if (elm.nodeName != name.toUpperCase()) {
+ // Rename block element
+ newElm = self.create(name);
+
+ // Copy attribs to new block
+ each(self.getAttribs(elm), function (attrNode) {
+ self.setAttrib(newElm, attrNode.nodeName, self.getAttrib(elm, attrNode.nodeName));
+ });
+
+ // Replace block
+ self.replace(newElm, elm, 1);
+ }
+
+ return newElm || elm;
+ },
+
+ /**
+ * Find the common ancestor of two elements. This is a shorter method than using the DOM Range logic.
+ *
+ * @method findCommonAncestor
+ * @param {Element} a Element to find common ancestor of.
+ * @param {Element} b Element to find common ancestor of.
+ * @return {Element} Common ancestor element of the two input elements.
+ */
+ findCommonAncestor: function (a, b) {
+ var ps = a, pe;
+
+ while (ps) {
+ pe = b;
+
+ while (pe && ps != pe) {
+ pe = pe.parentNode;
+ }
+
+ if (ps == pe) {
+ break;
+ }
+
+ ps = ps.parentNode;
+ }
+
+ if (!ps && a.ownerDocument) {
+ return a.ownerDocument.documentElement;
+ }
+
+ return ps;
+ },
+
+ /**
+ * Parses the specified RGB color value and returns a hex version of that color.
+ *
+ * @method toHex
+ * @param {String} rgbVal RGB string value like rgb(1,2,3)
+ * @return {String} Hex version of that RGB value like #FF00FF.
+ */
+ toHex: function (rgbVal) {
+ return this.styles.toHex(Tools.trim(rgbVal));
+ },
+
+ /**
+ * Executes the specified function on the element by id or dom element node or array of elements/id.
+ *
+ * @method run
+ * @param {String/Element/Array} elm ID or DOM element object or array with ids or elements.
+ * @param {function} func Function to execute for each item.
+ * @param {Object} scope Optional scope to execute the function in.
+ * @return {Object/Array} Single object, or an array of objects if multiple input elements were passed in.
+ */
+ run: function (elm, func, scope) {
+ var self = this, result;
+
+ if (typeof elm === 'string') {
+ elm = self.get(elm);
+ }
+
+ if (!elm) {
+ return false;
+ }
+
+ scope = scope || this;
+ if (!elm.nodeType && (elm.length || elm.length === 0)) {
+ result = [];
+
+ each(elm, function (elm, i) {
+ if (elm) {
+ if (typeof elm == 'string') {
+ elm = self.get(elm);
+ }
+
+ result.push(func.call(scope, elm, i));
+ }
+ });
+
+ return result;
+ }
+
+ return func.call(scope, elm);
+ },
+
+ /**
+ * Returns a NodeList with attributes for the element.
+ *
+ * @method getAttribs
+ * @param {HTMLElement/string} elm Element node or string id to get attributes from.
+ * @return {NodeList} NodeList with attributes.
+ */
+ getAttribs: function (elm) {
+ var attrs;
+
+ elm = this.get(elm);
+
+ if (!elm) {
+ return [];
+ }
+
+ if (isIE) {
+ attrs = [];
+
+ // Object will throw exception in IE
+ if (elm.nodeName == 'OBJECT') {
+ return elm.attributes;
+ }
+
+ // IE doesn't keep the selected attribute if you clone option elements
+ if (elm.nodeName === 'OPTION' && this.getAttrib(elm, 'selected')) {
+ attrs.push({ specified: 1, nodeName: 'selected' });
+ }
+
+ // It's crazy that this is faster in IE but it's because it returns all attributes all the time
+ var attrRegExp = /<\/?[\w:\-]+ ?|=[\"][^\"]+\"|=\'[^\']+\'|=[\w\-]+|>/gi;
+ elm.cloneNode(false).outerHTML.replace(attrRegExp, '').replace(/[\w:\-]+/gi, function (a) {
+ attrs.push({ specified: 1, nodeName: a });
+ });
+
+ return attrs;
+ }
+
+ return elm.attributes;
+ },
+
+ /**
+ * Returns true/false if the specified node is to be considered empty or not.
+ *
+ * @example
+ * tinymce.DOM.isEmpty(node, {img: true});
+ * @method isEmpty
+ * @param {Object} elements Optional name/value object with elements that are automatically treated as non-empty elements.
+ * @return {Boolean} true/false if the node is empty or not.
+ */
+ isEmpty: function (node, elements) {
+ var self = this, i, attributes, type, whitespace, walker, name, brCount = 0;
+
+ node = node.firstChild;
+ if (node) {
+ walker = new TreeWalker(node, node.parentNode);
+ elements = elements || (self.schema ? self.schema.getNonEmptyElements() : null);
+ whitespace = self.schema ? self.schema.getWhiteSpaceElements() : {};
+
+ do {
+ type = node.nodeType;
+
+ if (type === 1) {
+ // Ignore bogus elements
+ var bogusVal = node.getAttribute('data-mce-bogus');
+ if (bogusVal) {
+ node = walker.next(bogusVal === 'all');
+ continue;
+ }
+
+ // Keep empty elements like
+ name = node.nodeName.toLowerCase();
+ if (elements && elements[name]) {
+ // Ignore single BR elements in blocks like
or
+ if (name === 'br') {
+ brCount++;
+ node = walker.next();
+ continue;
+ }
+
+ return false;
+ }
+
+ // Keep elements with data-bookmark attributes or name attribute like
+ attributes = self.getAttribs(node);
+ i = attributes.length;
+ while (i--) {
+ name = attributes[i].nodeName;
+ if (name === "name" || name === 'data-mce-bookmark') {
+ return false;
+ }
+ }
+ }
+
+ // Keep comment nodes
+ if (type == 8) {
+ return false;
+ }
+
+ // Keep non whitespace text nodes
+ if (type === 3 && !whiteSpaceRegExp.test(node.nodeValue)) {
+ return false;
+ }
+
+ // Keep whitespace preserve elements
+ if (type === 3 && node.parentNode && whitespace[node.parentNode.nodeName] && whiteSpaceRegExp.test(node.nodeValue)) {
+ return false;
+ }
+
+ node = walker.next();
+ } while (node);
+ }
+
+ return brCount <= 1;
+ },
+
+ /**
+ * Creates a new DOM Range object. This will use the native DOM Range API if it's
+ * available. If it's not, it will fall back to the custom TinyMCE implementation.
+ *
+ * @method createRng
+ * @return {DOMRange} DOM Range object.
+ * @example
+ * var rng = tinymce.DOM.createRng();
+ * alert(rng.startContainer + "," + rng.startOffset);
+ */
+ createRng: function () {
+ var doc = this.doc;
+
+ return doc.createRange ? doc.createRange() : new Range(this);
+ },
+
+ /**
+ * Returns the index of the specified node within its parent.
+ *
+ * @method nodeIndex
+ * @param {Node} node Node to look for.
+ * @param {boolean} normalized Optional true/false state if the index is what it would be after a normalization.
+ * @return {Number} Index of the specified node.
+ */
+ nodeIndex: nodeIndex,
+
+ /**
+ * Splits an element into two new elements and places the specified split
+ * element or elements between the new ones. For example splitting the paragraph at the bold element in
+ * this example
abcabc123
would produce
abc
abc
123
.
+ *
+ * @method split
+ * @param {Element} parentElm Parent element to split.
+ * @param {Element} splitElm Element to split at.
+ * @param {Element} replacementElm Optional replacement element to replace the split element with.
+ * @return {Element} Returns the split element or the replacement element if that is specified.
+ */
+ split: function (parentElm, splitElm, replacementElm) {
+ var self = this, r = self.createRng(), bef, aft, pa;
+
+ // W3C valid browsers tend to leave empty nodes to the left/right side of the contents - this makes sense
+ // but we don't want that in our code since it serves no purpose for the end user
+ // For example splitting this html at the bold element:
+ //
text 1CHOPtext 2
+ // would produce:
+ //
text 1
CHOP
text 2
+ // this function will then trim off empty edges and produce:
+ //
text 1
CHOP
text 2
+ function trimNode(node) {
+ var i, children = node.childNodes, type = node.nodeType;
+
+ function surroundedBySpans(node) {
+ var previousIsSpan = node.previousSibling && node.previousSibling.nodeName == 'SPAN';
+ var nextIsSpan = node.nextSibling && node.nextSibling.nodeName == 'SPAN';
+ return previousIsSpan && nextIsSpan;
+ }
+
+ if (type == 1 && node.getAttribute('data-mce-type') == 'bookmark') {
+ return;
+ }
+
+ for (i = children.length - 1; i >= 0; i--) {
+ trimNode(children[i]);
+ }
+
+ if (type != 9) {
+ // Keep non whitespace text nodes
+ if (type == 3 && node.nodeValue.length > 0) {
+ // If parent element isn't a block or there isn't any useful contents for example "
"
+ // Also keep text nodes with only spaces if surrounded by spans.
+ // eg. "
ab
" should keep space between a and b
+ var trimmedLength = trim(node.nodeValue).length;
+ if (!self.isBlock(node.parentNode) || trimmedLength > 0 || trimmedLength === 0 && surroundedBySpans(node)) {
+ return;
+ }
+ } else if (type == 1) {
+ // If the only child is a bookmark then move it up
+ children = node.childNodes;
+
+ // TODO fix this complex if
+ if (children.length == 1 && children[0] && children[0].nodeType == 1 &&
+ children[0].getAttribute('data-mce-type') == 'bookmark') {
+ node.parentNode.insertBefore(children[0], node);
+ }
+
+ // Keep non empty elements or img, hr etc
+ if (children.length || /^(br|hr|input|img)$/i.test(node.nodeName)) {
+ return;
+ }
+ }
+
+ self.remove(node);
+ }
+
+ return node;
+ }
+
+ if (parentElm && splitElm) {
+ // Get before chunk
+ r.setStart(parentElm.parentNode, self.nodeIndex(parentElm));
+ r.setEnd(splitElm.parentNode, self.nodeIndex(splitElm));
+ bef = r.extractContents();
+
+ // Get after chunk
+ r = self.createRng();
+ r.setStart(splitElm.parentNode, self.nodeIndex(splitElm) + 1);
+ r.setEnd(parentElm.parentNode, self.nodeIndex(parentElm) + 1);
+ aft = r.extractContents();
+
+ // Insert before chunk
+ pa = parentElm.parentNode;
+ pa.insertBefore(trimNode(bef), parentElm);
+
+ // Insert middle chunk
+ if (replacementElm) {
+ pa.insertBefore(replacementElm, parentElm);
+ //pa.replaceChild(replacementElm, splitElm);
+ } else {
+ pa.insertBefore(splitElm, parentElm);
+ }
+
+ // Insert after chunk
+ pa.insertBefore(trimNode(aft), parentElm);
+ self.remove(parentElm);
+
+ return replacementElm || splitElm;
+ }
+ },
+
+ /**
+ * Adds an event handler to the specified object.
+ *
+ * @method bind
+ * @param {Element/Document/Window/Array} target Target element to bind events to.
+ * handler to or an array of elements/ids/documents.
+ * @param {String} name Name of event handler to add, for example: click.
+ * @param {function} func Function to execute when the event occurs.
+ * @param {Object} scope Optional scope to execute the function in.
+ * @return {function} Function callback handler the same as the one passed in.
+ */
+ bind: function (target, name, func, scope) {
+ var self = this;
+
+ if (Tools.isArray(target)) {
+ var i = target.length;
+
+ while (i--) {
+ target[i] = self.bind(target[i], name, func, scope);
+ }
+
+ return target;
+ }
+
+ // Collect all window/document events bound by editor instance
+ if (self.settings.collect && (target === self.doc || target === self.win)) {
+ self.boundEvents.push([target, name, func, scope]);
+ }
+
+ return self.events.bind(target, name, func, scope || self);
+ },
+
+ /**
+ * Removes the specified event handler by name and function from an element or collection of elements.
+ *
+ * @method unbind
+ * @param {Element/Document/Window/Array} target Target element to unbind events on.
+ * @param {String} name Event handler name, for example: "click"
+ * @param {function} func Function to remove.
+ * @return {bool/Array} Bool state of true if the handler was removed, or an array of states if multiple input elements
+ * were passed in.
+ */
+ unbind: function (target, name, func) {
+ var self = this, i;
+
+ if (Tools.isArray(target)) {
+ i = target.length;
+
+ while (i--) {
+ target[i] = self.unbind(target[i], name, func);
+ }
+
+ return target;
+ }
+
+ // Remove any bound events matching the input
+ if (self.boundEvents && (target === self.doc || target === self.win)) {
+ i = self.boundEvents.length;
+
+ while (i--) {
+ var item = self.boundEvents[i];
+
+ if (target == item[0] && (!name || name == item[1]) && (!func || func == item[2])) {
+ this.events.unbind(item[0], item[1], item[2]);
+ }
+ }
+ }
+
+ return this.events.unbind(target, name, func);
+ },
+
+ /**
+ * Fires the specified event name with object on target.
+ *
+ * @method fire
+ * @param {Node/Document/Window} target Target element or object to fire event on.
+ * @param {String} name Name of the event to fire.
+ * @param {Object} evt Event object to send.
+ * @return {Event} Event object.
+ */
+ fire: function (target, name, evt) {
+ return this.events.fire(target, name, evt);
+ },
+
+ // Returns the content editable state of a node
+ getContentEditable: function (node) {
+ var contentEditable;
+
+ // Check type
+ if (!node || node.nodeType != 1) {
+ return null;
+ }
+
+ // Check for fake content editable
+ contentEditable = node.getAttribute("data-mce-contenteditable");
+ if (contentEditable && contentEditable !== "inherit") {
+ return contentEditable;
+ }
+
+ // Check for real content editable
+ return node.contentEditable !== "inherit" ? node.contentEditable : null;
+ },
+
+ getContentEditableParent: function (node) {
+ var root = this.getRoot(), state = null;
+
+ for (; node && node !== root; node = node.parentNode) {
+ state = this.getContentEditable(node);
+
+ if (state !== null) {
+ break;
+ }
+ }
+
+ return state;
+ },
+
+ /**
+ * Destroys all internal references to the DOM to solve IE leak issues.
+ *
+ * @method destroy
+ */
+ destroy: function () {
+ var self = this;
+
+ // Unbind all events bound to window/document by editor instance
+ if (self.boundEvents) {
+ var i = self.boundEvents.length;
+
+ while (i--) {
+ var item = self.boundEvents[i];
+ this.events.unbind(item[0], item[1], item[2]);
+ }
+
+ self.boundEvents = null;
+ }
+
+ // Restore sizzle document to window.document
+ // Since the current document might be removed producing "Permission denied" on IE see #6325
+ if (Sizzle.setDocument) {
+ Sizzle.setDocument();
+ }
+
+ self.win = self.doc = self.root = self.events = self.frag = null;
+ },
+
+ isChildOf: function (node, parent) {
+ while (node) {
+ if (parent === node) {
+ return true;
+ }
+
+ node = node.parentNode;
+ }
+
+ return false;
+ },
+
+ // #ifdef debug
+
+ dumpRng: function (r) {
+ return (
+ 'startContainer: ' + r.startContainer.nodeName +
+ ', startOffset: ' + r.startOffset +
+ ', endContainer: ' + r.endContainer.nodeName +
+ ', endOffset: ' + r.endOffset
+ );
+ },
+
+ // #endif
+
+ _findSib: function (node, selector, name) {
+ var self = this, func = selector;
+
+ if (node) {
+ // If expression make a function of it using is
+ if (typeof func == 'string') {
+ func = function (node) {
+ return self.is(node, selector);
+ };
+ }
+
+ // Loop all siblings
+ for (node = node[name]; node; node = node[name]) {
+ if (func(node)) {
+ return node;
+ }
+ }
+ }
+
+ return null;
+ }
+ };
+
+ /**
+ * Instance of DOMUtils for the current document.
+ *
+ * @static
+ * @property DOM
+ * @type tinymce.dom.DOMUtils
+ * @example
+ * // Example of how to add a class to some element by id
+ * tinymce.DOM.addClass('someid', 'someclass');
+ */
+ DOMUtils.DOM = new DOMUtils(document);
+ DOMUtils.nodeIndex = nodeIndex;
+
+ return DOMUtils;
+ }
+);
+
+/**
+ * ScriptLoader.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
+ */
+
+/*globals console*/
+
+/**
+ * This class handles asynchronous/synchronous loading of JavaScript files it will execute callbacks
+ * when various items gets loaded. This class is useful to load external JavaScript files.
+ *
+ * @class tinymce.dom.ScriptLoader
+ * @example
+ * // Load a script from a specific URL using the global script loader
+ * tinymce.ScriptLoader.load('somescript.js');
+ *
+ * // Load a script using a unique instance of the script loader
+ * var scriptLoader = new tinymce.dom.ScriptLoader();
+ *
+ * scriptLoader.load('somescript.js');
+ *
+ * // Load multiple scripts
+ * var scriptLoader = new tinymce.dom.ScriptLoader();
+ *
+ * scriptLoader.add('somescript1.js');
+ * scriptLoader.add('somescript2.js');
+ * scriptLoader.add('somescript3.js');
+ *
+ * scriptLoader.loadQueue(function() {
+ * alert('All scripts are now loaded.');
+ * });
+ */
+define(
+ 'tinymce.core.dom.ScriptLoader',
+ [
+ "tinymce.core.dom.DOMUtils",
+ "tinymce.core.util.Tools"
+ ],
+ function (DOMUtils, Tools) {
+ var DOM = DOMUtils.DOM;
+ var each = Tools.each, grep = Tools.grep;
+
+ var isFunction = function (f) {
+ return typeof f === 'function';
+ };
+
+ function ScriptLoader() {
+ var QUEUED = 0,
+ LOADING = 1,
+ LOADED = 2,
+ FAILED = 3,
+ states = {},
+ queue = [],
+ scriptLoadedCallbacks = {},
+ queueLoadedCallbacks = [],
+ loading = 0,
+ undef;
+
+ /**
+ * Loads a specific script directly without adding it to the load queue.
+ *
+ * @method load
+ * @param {String} url Absolute URL to script to add.
+ * @param {function} callback Optional success callback function when the script loaded successfully.
+ * @param {function} callback Optional failure callback function when the script failed to load.
+ */
+ function loadScript(url, success, failure) {
+ var dom = DOM, elm, id;
+
+ // Execute callback when script is loaded
+ function done() {
+ dom.remove(id);
+
+ if (elm) {
+ elm.onreadystatechange = elm.onload = elm = null;
+ }
+
+ success();
+ }
+
+ function error() {
+ /*eslint no-console:0 */
+
+ // We can't mark it as done if there is a load error since
+ // A) We don't want to produce 404 errors on the server and
+ // B) the onerror event won't fire on all browsers.
+ // done();
+
+ if (isFunction(failure)) {
+ failure();
+ } else {
+ // Report the error so it's easier for people to spot loading errors
+ if (typeof console !== "undefined" && console.log) {
+ console.log("Failed to load script: " + url);
+ }
+ }
+ }
+
+ id = dom.uniqueId();
+
+ // Create new script element
+ elm = document.createElement('script');
+ elm.id = id;
+ elm.type = 'text/javascript';
+ elm.src = Tools._addCacheSuffix(url);
+
+ // Seems that onreadystatechange works better on IE 10 onload seems to fire incorrectly
+ if ("onreadystatechange" in elm) {
+ elm.onreadystatechange = function () {
+ if (/loaded|complete/.test(elm.readyState)) {
+ done();
+ }
+ };
+ } else {
+ elm.onload = done;
+ }
+
+ // Add onerror event will get fired on some browsers but not all of them
+ elm.onerror = error;
+
+ // Add script to document
+ (document.getElementsByTagName('head')[0] || document.body).appendChild(elm);
+ }
+
+ /**
+ * Returns true/false if a script has been loaded or not.
+ *
+ * @method isDone
+ * @param {String} url URL to check for.
+ * @return {Boolean} true/false if the URL is loaded.
+ */
+ this.isDone = function (url) {
+ return states[url] == LOADED;
+ };
+
+ /**
+ * Marks a specific script to be loaded. This can be useful if a script got loaded outside
+ * the script loader or to skip it from loading some script.
+ *
+ * @method markDone
+ * @param {string} url Absolute URL to the script to mark as loaded.
+ */
+ this.markDone = function (url) {
+ states[url] = LOADED;
+ };
+
+ /**
+ * Adds a specific script to the load queue of the script loader.
+ *
+ * @method add
+ * @param {String} url Absolute URL to script to add.
+ * @param {function} success Optional success callback function to execute when the script loades successfully.
+ * @param {Object} scope Optional scope to execute callback in.
+ * @param {function} failure Optional failure callback function to execute when the script failed to load.
+ */
+ this.add = this.load = function (url, success, scope, failure) {
+ var state = states[url];
+
+ // Add url to load queue
+ if (state == undef) {
+ queue.push(url);
+ states[url] = QUEUED;
+ }
+
+ if (success) {
+ // Store away callback for later execution
+ if (!scriptLoadedCallbacks[url]) {
+ scriptLoadedCallbacks[url] = [];
+ }
+
+ scriptLoadedCallbacks[url].push({
+ success: success,
+ failure: failure,
+ scope: scope || this
+ });
+ }
+ };
+
+ this.remove = function (url) {
+ delete states[url];
+ delete scriptLoadedCallbacks[url];
+ };
+
+ /**
+ * Starts the loading of the queue.
+ *
+ * @method loadQueue
+ * @param {function} success Optional callback to execute when all queued items are loaded.
+ * @param {function} failure Optional callback to execute when queued items failed to load.
+ * @param {Object} scope Optional scope to execute the callback in.
+ */
+ this.loadQueue = function (success, scope, failure) {
+ this.loadScripts(queue, success, scope, failure);
+ };
+
+ /**
+ * Loads the specified queue of files and executes the callback ones they are loaded.
+ * This method is generally not used outside this class but it might be useful in some scenarios.
+ *
+ * @method loadScripts
+ * @param {Array} scripts Array of queue items to load.
+ * @param {function} callback Optional callback to execute when scripts is loaded successfully.
+ * @param {Object} scope Optional scope to execute callback in.
+ * @param {function} callback Optional callback to execute if scripts failed to load.
+ */
+ this.loadScripts = function (scripts, success, scope, failure) {
+ var loadScripts, failures = [];
+
+ function execCallbacks(name, url) {
+ // Execute URL callback functions
+ each(scriptLoadedCallbacks[url], function (callback) {
+ if (isFunction(callback[name])) {
+ callback[name].call(callback.scope);
+ }
+ });
+
+ scriptLoadedCallbacks[url] = undef;
+ }
+
+ queueLoadedCallbacks.push({
+ success: success,
+ failure: failure,
+ scope: scope || this
+ });
+
+ loadScripts = function () {
+ var loadingScripts = grep(scripts);
+
+ // Current scripts has been handled
+ scripts.length = 0;
+
+ // Load scripts that needs to be loaded
+ each(loadingScripts, function (url) {
+ // Script is already loaded then execute script callbacks directly
+ if (states[url] === LOADED) {
+ execCallbacks('success', url);
+ return;
+ }
+
+ if (states[url] === FAILED) {
+ execCallbacks('failure', url);
+ return;
+ }
+
+ // Is script not loading then start loading it
+ if (states[url] !== LOADING) {
+ states[url] = LOADING;
+ loading++;
+
+ loadScript(url, function () {
+ states[url] = LOADED;
+ loading--;
+
+ execCallbacks('success', url);
+
+ // Load more scripts if they where added by the recently loaded script
+ loadScripts();
+ }, function () {
+ states[url] = FAILED;
+ loading--;
+
+ failures.push(url);
+ execCallbacks('failure', url);
+
+ // Load more scripts if they where added by the recently loaded script
+ loadScripts();
+ });
+ }
+ });
+
+ // No scripts are currently loading then execute all pending queue loaded callbacks
+ if (!loading) {
+ each(queueLoadedCallbacks, function (callback) {
+ if (failures.length === 0) {
+ if (isFunction(callback.success)) {
+ callback.success.call(callback.scope);
+ }
+ } else {
+ if (isFunction(callback.failure)) {
+ callback.failure.call(callback.scope, failures);
+ }
+ }
+ });
+
+ queueLoadedCallbacks.length = 0;
+ }
+ };
+
+ loadScripts();
+ };
+ }
+
+ ScriptLoader.ScriptLoader = new ScriptLoader();
+
+ return ScriptLoader;
+ }
+);
+
+/**
+ * AddOnManager.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 loading of themes/plugins or other add-ons and their language packs.
+ *
+ * @class tinymce.AddOnManager
+ */
+define(
+ 'tinymce.core.AddOnManager',
+ [
+ "tinymce.core.dom.ScriptLoader",
+ "tinymce.core.util.Tools"
+ ],
+ function (ScriptLoader, Tools) {
+ var each = Tools.each;
+
+ function AddOnManager() {
+ var self = this;
+
+ self.items = [];
+ self.urls = {};
+ self.lookup = {};
+ }
+
+ AddOnManager.prototype = {
+ /**
+ * Returns the specified add on by the short name.
+ *
+ * @method get
+ * @param {String} name Add-on to look for.
+ * @return {tinymce.Theme/tinymce.Plugin} Theme or plugin add-on instance or undefined.
+ */
+ get: function (name) {
+ if (this.lookup[name]) {
+ return this.lookup[name].instance;
+ }
+
+ return undefined;
+ },
+
+ dependencies: function (name) {
+ var result;
+
+ if (this.lookup[name]) {
+ result = this.lookup[name].dependencies;
+ }
+
+ return result || [];
+ },
+
+ /**
+ * Loads a language pack for the specified add-on.
+ *
+ * @method requireLangPack
+ * @param {String} name Short name of the add-on.
+ * @param {String} languages Optional comma or space separated list of languages to check if it matches the name.
+ */
+ requireLangPack: function (name, languages) {
+ var language = AddOnManager.language;
+
+ if (language && AddOnManager.languageLoad !== false) {
+ if (languages) {
+ languages = ',' + languages + ',';
+
+ // Load short form sv.js or long form sv_SE.js
+ if (languages.indexOf(',' + language.substr(0, 2) + ',') != -1) {
+ language = language.substr(0, 2);
+ } else if (languages.indexOf(',' + language + ',') == -1) {
+ return;
+ }
+ }
+
+ ScriptLoader.ScriptLoader.add(this.urls[name] + '/langs/' + language + '.js');
+ }
+ },
+
+ /**
+ * Adds a instance of the add-on by it's short name.
+ *
+ * @method add
+ * @param {String} id Short name/id for the add-on.
+ * @param {tinymce.Theme/tinymce.Plugin} addOn Theme or plugin to add.
+ * @return {tinymce.Theme/tinymce.Plugin} The same theme or plugin instance that got passed in.
+ * @example
+ * // Create a simple plugin
+ * tinymce.create('tinymce.plugins.TestPlugin', {
+ * TestPlugin: function(ed, url) {
+ * ed.on('click', function(e) {
+ * ed.windowManager.alert('Hello World!');
+ * });
+ * }
+ * });
+ *
+ * // Register plugin using the add method
+ * tinymce.PluginManager.add('test', tinymce.plugins.TestPlugin);
+ *
+ * // Initialize TinyMCE
+ * tinymce.init({
+ * ...
+ * plugins: '-test' // Init the plugin but don't try to load it
+ * });
+ */
+ add: function (id, addOn, dependencies) {
+ this.items.push(addOn);
+ this.lookup[id] = { instance: addOn, dependencies: dependencies };
+
+ return addOn;
+ },
+
+ remove: function (name) {
+ delete this.urls[name];
+ delete this.lookup[name];
+ },
+
+ createUrl: function (baseUrl, dep) {
+ if (typeof dep === "object") {
+ return dep;
+ }
+
+ return { prefix: baseUrl.prefix, resource: dep, suffix: baseUrl.suffix };
+ },
+
+ /**
+ * Add a set of components that will make up the add-on. Using the url of the add-on name as the base url.
+ * This should be used in development mode. A new compressor/javascript munger process will ensure that the
+ * components are put together into the plugin.js file and compressed correctly.
+ *
+ * @method addComponents
+ * @param {String} pluginName name of the plugin to load scripts from (will be used to get the base url for the plugins).
+ * @param {Array} scripts Array containing the names of the scripts to load.
+ */
+ addComponents: function (pluginName, scripts) {
+ var pluginUrl = this.urls[pluginName];
+
+ each(scripts, function (script) {
+ ScriptLoader.ScriptLoader.add(pluginUrl + "/" + script);
+ });
+ },
+
+ /**
+ * Loads an add-on from a specific url.
+ *
+ * @method load
+ * @param {String} name Short name of the add-on that gets loaded.
+ * @param {String} addOnUrl URL to the add-on that will get loaded.
+ * @param {function} success Optional success callback to execute when an add-on is loaded.
+ * @param {Object} scope Optional scope to execute the callback in.
+ * @param {function} failure Optional failure callback to execute when an add-on failed to load.
+ * @example
+ * // Loads a plugin from an external URL
+ * tinymce.PluginManager.load('myplugin', '/some/dir/someplugin/plugin.js');
+ *
+ * // Initialize TinyMCE
+ * tinymce.init({
+ * ...
+ * plugins: '-myplugin' // Don't try to load it again
+ * });
+ */
+ load: function (name, addOnUrl, success, scope, failure) {
+ var self = this, url = addOnUrl;
+
+ function loadDependencies() {
+ var dependencies = self.dependencies(name);
+
+ each(dependencies, function (dep) {
+ var newUrl = self.createUrl(addOnUrl, dep);
+
+ self.load(newUrl.resource, newUrl, undefined, undefined);
+ });
+
+ if (success) {
+ if (scope) {
+ success.call(scope);
+ } else {
+ success.call(ScriptLoader);
+ }
+ }
+ }
+
+ if (self.urls[name]) {
+ return;
+ }
+
+ if (typeof addOnUrl === "object") {
+ url = addOnUrl.prefix + addOnUrl.resource + addOnUrl.suffix;
+ }
+
+ if (url.indexOf('/') !== 0 && url.indexOf('://') == -1) {
+ url = AddOnManager.baseURL + '/' + url;
+ }
+
+ self.urls[name] = url.substring(0, url.lastIndexOf('/'));
+
+ if (self.lookup[name]) {
+ loadDependencies();
+ } else {
+ ScriptLoader.ScriptLoader.add(url, loadDependencies, scope, failure);
+ }
+ }
+ };
+
+ AddOnManager.PluginManager = new AddOnManager();
+ AddOnManager.ThemeManager = new AddOnManager();
+
+ return AddOnManager;
+ }
+);
+
+/**
+ * TinyMCE theme class.
+ *
+ * @class tinymce.Theme
+ */
+
+/**
+ * This method is responsible for rendering/generating the overall user interface with toolbars, buttons, iframe containers etc.
+ *
+ * @method renderUI
+ * @param {Object} obj Object parameter containing the targetNode DOM node that will be replaced visually with an editor instance.
+ * @return {Object} an object with items like iframeContainer, editorContainer, sizeContainer, deltaWidth, deltaHeight.
+ */
+
+/**
+ * Plugin base class, this is a pseudo class that describes how a plugin is to be created for TinyMCE. The methods below are all optional.
+ *
+ * @class tinymce.Plugin
+ * @example
+ * tinymce.PluginManager.add('example', function(editor, url) {
+ * // Add a button that opens a window
+ * editor.addButton('example', {
+ * text: 'My button',
+ * icon: false,
+ * onclick: function() {
+ * // Open window
+ * editor.windowManager.open({
+ * title: 'Example plugin',
+ * body: [
+ * {type: 'textbox', name: 'title', label: 'Title'}
+ * ],
+ * onsubmit: function(e) {
+ * // Insert content when the window form is submitted
+ * editor.insertContent('Title: ' + e.data.title);
+ * }
+ * });
+ * }
+ * });
+ *
+ * // Adds a menu item to the tools menu
+ * editor.addMenuItem('example', {
+ * text: 'Example plugin',
+ * context: 'tools',
+ * onclick: function() {
+ * // Open window with a specific url
+ * editor.windowManager.open({
+ * title: 'TinyMCE site',
+ * url: 'http://www.tinymce.com',
+ * width: 800,
+ * height: 600,
+ * buttons: [{
+ * text: 'Close',
+ * onclick: 'close'
+ * }]
+ * });
+ * }
+ * });
+ * });
+ */
+
+/**
+ * NodeType.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 various node validation functions.
+ *
+ * @private
+ * @class tinymce.dom.NodeType
+ */
+define(
+ 'tinymce.core.dom.NodeType',
+ [
+ ],
+ function () {
+ function isNodeType(type) {
+ return function (node) {
+ return !!node && node.nodeType == type;
+ };
+ }
+
+ var isElement = isNodeType(1);
+
+ function matchNodeNames(names) {
+ names = names.toLowerCase().split(' ');
+
+ return function (node) {
+ var i, name;
+
+ if (node && node.nodeType) {
+ name = node.nodeName.toLowerCase();
+
+ for (i = 0; i < names.length; i++) {
+ if (name === names[i]) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ };
+ }
+
+ function matchStyleValues(name, values) {
+ values = values.toLowerCase().split(' ');
+
+ return function (node) {
+ var i, cssValue;
+
+ if (isElement(node)) {
+ for (i = 0; i < values.length; i++) {
+ cssValue = node.ownerDocument.defaultView.getComputedStyle(node, null).getPropertyValue(name);
+ if (cssValue === values[i]) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ };
+ }
+
+ function hasPropValue(propName, propValue) {
+ return function (node) {
+ return isElement(node) && node[propName] === propValue;
+ };
+ }
+
+ function hasAttribute(attrName, attrValue) {
+ return function (node) {
+ return isElement(node) && node.hasAttribute(attrName);
+ };
+ }
+
+ function hasAttributeValue(attrName, attrValue) {
+ return function (node) {
+ return isElement(node) && node.getAttribute(attrName) === attrValue;
+ };
+ }
+
+ function isBogus(node) {
+ return isElement(node) && node.hasAttribute('data-mce-bogus');
+ }
+
+ function hasContentEditableState(value) {
+ return function (node) {
+ if (isElement(node)) {
+ if (node.contentEditable === value) {
+ return true;
+ }
+
+ if (node.getAttribute('data-mce-contenteditable') === value) {
+ return true;
+ }
+ }
+
+ return false;
+ };
+ }
+
+ return {
+ isText: isNodeType(3),
+ isElement: isElement,
+ isComment: isNodeType(8),
+ isBr: matchNodeNames('br'),
+ isContentEditableTrue: hasContentEditableState('true'),
+ isContentEditableFalse: hasContentEditableState('false'),
+ matchNodeNames: matchNodeNames,
+ hasPropValue: hasPropValue,
+ hasAttribute: hasAttribute,
+ hasAttributeValue: hasAttributeValue,
+ matchStyleValues: matchStyleValues,
+ isBogus: isBogus
+ };
+ }
+);
+/**
+ * Zwsp.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
+ */
+
+/**
+ * Utility functions for working with zero width space
+ * characters used as character containers etc.
+ *
+ * @private
+ * @class tinymce.text.Zwsp
+ * @example
+ * var isZwsp = Zwsp.isZwsp('\uFEFF');
+ * var abc = Zwsp.trim('a\uFEFFc');
+ */
+define(
+ 'tinymce.core.text.Zwsp',
+ [
+ ],
+ function () {
+ // This is technically not a ZWSP but a ZWNBSP or a BYTE ORDER MARK it used to be a ZWSP
+ var ZWSP = '\uFEFF';
+
+ var isZwsp = function (chr) {
+ return chr === ZWSP;
+ };
+
+ var trim = function (text) {
+ return text.replace(new RegExp(ZWSP, 'g'), '');
+ };
+
+ return {
+ isZwsp: isZwsp,
+ ZWSP: ZWSP,
+ trim: trim
+ };
+ }
+);
+/**
+ * CaretContainer.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 caret containers. A caret container is a node that
+ * holds the caret for positional purposes.
+ *
+ * @private
+ * @class tinymce.caret.CaretContainer
+ */
+define(
+ 'tinymce.core.caret.CaretContainer',
+ [
+ "tinymce.core.dom.NodeType",
+ "tinymce.core.text.Zwsp"
+ ],
+ function (NodeType, Zwsp) {
+ var isElement = NodeType.isElement,
+ isText = NodeType.isText;
+
+ function isCaretContainerBlock(node) {
+ if (isText(node)) {
+ node = node.parentNode;
+ }
+
+ return isElement(node) && node.hasAttribute('data-mce-caret');
+ }
+
+ function isCaretContainerInline(node) {
+ return isText(node) && Zwsp.isZwsp(node.data);
+ }
+
+ function isCaretContainer(node) {
+ return isCaretContainerBlock(node) || isCaretContainerInline(node);
+ }
+
+ var hasContent = function (node) {
+ return node.firstChild !== node.lastChild || !NodeType.isBr(node.firstChild);
+ };
+
+ function insertInline(node, before) {
+ var doc, sibling, textNode, parentNode;
+
+ doc = node.ownerDocument;
+ textNode = doc.createTextNode(Zwsp.ZWSP);
+ parentNode = node.parentNode;
+
+ if (!before) {
+ sibling = node.nextSibling;
+ if (isText(sibling)) {
+ if (isCaretContainer(sibling)) {
+ return sibling;
+ }
+
+ if (startsWithCaretContainer(sibling)) {
+ sibling.splitText(1);
+ return sibling;
+ }
+ }
+
+ if (node.nextSibling) {
+ parentNode.insertBefore(textNode, node.nextSibling);
+ } else {
+ parentNode.appendChild(textNode);
+ }
+ } else {
+ sibling = node.previousSibling;
+ if (isText(sibling)) {
+ if (isCaretContainer(sibling)) {
+ return sibling;
+ }
+
+ if (endsWithCaretContainer(sibling)) {
+ return sibling.splitText(sibling.data.length - 1);
+ }
+ }
+
+ parentNode.insertBefore(textNode, node);
+ }
+
+ return textNode;
+ }
+
+ var prependInline = function (node) {
+ if (NodeType.isText(node)) {
+ var data = node.data;
+ if (data.length > 0 && data.charAt(0) !== Zwsp.ZWSP) {
+ node.insertData(0, Zwsp.ZWSP);
+ }
+ return node;
+ } else {
+ return null;
+ }
+ };
+
+ var appendInline = function (node) {
+ if (NodeType.isText(node)) {
+ var data = node.data;
+ if (data.length > 0 && data.charAt(data.length - 1) !== Zwsp.ZWSP) {
+ node.insertData(data.length, Zwsp.ZWSP);
+ }
+ return node;
+ } else {
+ return null;
+ }
+ };
+
+ var isBeforeInline = function (pos) {
+ return pos && NodeType.isText(pos.container()) && pos.container().data.charAt(pos.offset()) === Zwsp.ZWSP;
+ };
+
+ var isAfterInline = function (pos) {
+ return pos && NodeType.isText(pos.container()) && pos.container().data.charAt(pos.offset() - 1) === Zwsp.ZWSP;
+ };
+
+ function createBogusBr() {
+ var br = document.createElement('br');
+ br.setAttribute('data-mce-bogus', '1');
+ return br;
+ }
+
+ function insertBlock(blockName, node, before) {
+ var doc, blockNode, parentNode;
+
+ doc = node.ownerDocument;
+ blockNode = doc.createElement(blockName);
+ blockNode.setAttribute('data-mce-caret', before ? 'before' : 'after');
+ blockNode.setAttribute('data-mce-bogus', 'all');
+ blockNode.appendChild(createBogusBr());
+ parentNode = node.parentNode;
+
+ if (!before) {
+ if (node.nextSibling) {
+ parentNode.insertBefore(blockNode, node.nextSibling);
+ } else {
+ parentNode.appendChild(blockNode);
+ }
+ } else {
+ parentNode.insertBefore(blockNode, node);
+ }
+
+ return blockNode;
+ }
+
+ function startsWithCaretContainer(node) {
+ return isText(node) && node.data[0] == Zwsp.ZWSP;
+ }
+
+ function endsWithCaretContainer(node) {
+ return isText(node) && node.data[node.data.length - 1] == Zwsp.ZWSP;
+ }
+
+ function trimBogusBr(elm) {
+ var brs = elm.getElementsByTagName('br');
+ var lastBr = brs[brs.length - 1];
+ if (NodeType.isBogus(lastBr)) {
+ lastBr.parentNode.removeChild(lastBr);
+ }
+ }
+
+ function showCaretContainerBlock(caretContainer) {
+ if (caretContainer && caretContainer.hasAttribute('data-mce-caret')) {
+ trimBogusBr(caretContainer);
+ caretContainer.removeAttribute('data-mce-caret');
+ caretContainer.removeAttribute('data-mce-bogus');
+ caretContainer.removeAttribute('style');
+ caretContainer.removeAttribute('_moz_abspos');
+ return caretContainer;
+ }
+
+ return null;
+ }
+
+ return {
+ isCaretContainer: isCaretContainer,
+ isCaretContainerBlock: isCaretContainerBlock,
+ isCaretContainerInline: isCaretContainerInline,
+ showCaretContainerBlock: showCaretContainerBlock,
+ insertInline: insertInline,
+ prependInline: prependInline,
+ appendInline: appendInline,
+ isBeforeInline: isBeforeInline,
+ isAfterInline: isAfterInline,
+ insertBlock: insertBlock,
+ hasContent: hasContent,
+ startsWithCaretContainer: startsWithCaretContainer,
+ endsWithCaretContainer: endsWithCaretContainer
+ };
+ }
+);
+/**
+ * RangeUtils.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 a few utility methods for ranges.
+ *
+ * @class tinymce.dom.RangeUtils
+ */
+define(
+ 'tinymce.core.dom.RangeUtils',
+ [
+ "tinymce.core.util.Tools",
+ "tinymce.core.dom.TreeWalker",
+ "tinymce.core.dom.NodeType",
+ "tinymce.core.dom.Range",
+ "tinymce.core.caret.CaretContainer"
+ ],
+ function (Tools, TreeWalker, NodeType, Range, CaretContainer) {
+ var each = Tools.each,
+ isContentEditableTrue = NodeType.isContentEditableTrue,
+ isContentEditableFalse = NodeType.isContentEditableFalse,
+ isCaretContainer = CaretContainer.isCaretContainer;
+
+ function hasCeProperty(node) {
+ return isContentEditableTrue(node) || isContentEditableFalse(node);
+ }
+
+ function getEndChild(container, index) {
+ var childNodes = container.childNodes;
+
+ index--;
+
+ if (index > childNodes.length - 1) {
+ index = childNodes.length - 1;
+ } else if (index < 0) {
+ index = 0;
+ }
+
+ return childNodes[index] || container;
+ }
+
+ function findParent(node, rootNode, predicate) {
+ while (node && node !== rootNode) {
+ if (predicate(node)) {
+ return node;
+ }
+
+ node = node.parentNode;
+ }
+
+ return null;
+ }
+
+ function hasParent(node, rootNode, predicate) {
+ return findParent(node, rootNode, predicate) !== null;
+ }
+
+ function hasParentWithName(node, rootNode, name) {
+ return hasParent(node, rootNode, function (node) {
+ return node.nodeName === name;
+ });
+ }
+
+ function isFormatterCaret(node) {
+ return node.id === '_mce_caret';
+ }
+
+ function isCeFalseCaretContainer(node, rootNode) {
+ return isCaretContainer(node) && hasParent(node, rootNode, isFormatterCaret) === false;
+ }
+
+ function RangeUtils(dom) {
+ /**
+ * Walks the specified range like object and executes the callback for each sibling collection it finds.
+ *
+ * @private
+ * @method walk
+ * @param {Object} rng Range like object.
+ * @param {function} callback Callback function to execute for each sibling collection.
+ */
+ this.walk = function (rng, callback) {
+ var startContainer = rng.startContainer,
+ startOffset = rng.startOffset,
+ endContainer = rng.endContainer,
+ endOffset = rng.endOffset,
+ ancestor, startPoint,
+ endPoint, node, parent, siblings, nodes;
+
+ // Handle table cell selection the table plugin enables
+ // you to fake select table cells and perform formatting actions on them
+ nodes = dom.select('td[data-mce-selected],th[data-mce-selected]');
+ if (nodes.length > 0) {
+ each(nodes, function (node) {
+ callback([node]);
+ });
+
+ return;
+ }
+
+ /**
+ * Excludes start/end text node if they are out side the range
+ *
+ * @private
+ * @param {Array} nodes Nodes to exclude items from.
+ * @return {Array} Array with nodes excluding the start/end container if needed.
+ */
+ function exclude(nodes) {
+ var node;
+
+ // First node is excluded
+ node = nodes[0];
+ if (node.nodeType === 3 && node === startContainer && startOffset >= node.nodeValue.length) {
+ nodes.splice(0, 1);
+ }
+
+ // Last node is excluded
+ node = nodes[nodes.length - 1];
+ if (endOffset === 0 && nodes.length > 0 && node === endContainer && node.nodeType === 3) {
+ nodes.splice(nodes.length - 1, 1);
+ }
+
+ return nodes;
+ }
+
+ /**
+ * Collects siblings
+ *
+ * @private
+ * @param {Node} node Node to collect siblings from.
+ * @param {String} name Name of the sibling to check for.
+ * @param {Node} endNode
+ * @return {Array} Array of collected siblings.
+ */
+ function collectSiblings(node, name, endNode) {
+ var siblings = [];
+
+ for (; node && node != endNode; node = node[name]) {
+ siblings.push(node);
+ }
+
+ return siblings;
+ }
+
+ /**
+ * Find an end point this is the node just before the common ancestor root.
+ *
+ * @private
+ * @param {Node} node Node to start at.
+ * @param {Node} root Root/ancestor element to stop just before.
+ * @return {Node} Node just before the root element.
+ */
+ function findEndPoint(node, root) {
+ do {
+ if (node.parentNode == root) {
+ return node;
+ }
+
+ node = node.parentNode;
+ } while (node);
+ }
+
+ function walkBoundary(startNode, endNode, next) {
+ var siblingName = next ? 'nextSibling' : 'previousSibling';
+
+ for (node = startNode, parent = node.parentNode; node && node != endNode; node = parent) {
+ parent = node.parentNode;
+ siblings = collectSiblings(node == startNode ? node : node[siblingName], siblingName);
+
+ if (siblings.length) {
+ if (!next) {
+ siblings.reverse();
+ }
+
+ callback(exclude(siblings));
+ }
+ }
+ }
+
+ // If index based start position then resolve it
+ if (startContainer.nodeType == 1 && startContainer.hasChildNodes()) {
+ startContainer = startContainer.childNodes[startOffset];
+ }
+
+ // If index based end position then resolve it
+ if (endContainer.nodeType == 1 && endContainer.hasChildNodes()) {
+ endContainer = getEndChild(endContainer, endOffset);
+ }
+
+ // Same container
+ if (startContainer == endContainer) {
+ return callback(exclude([startContainer]));
+ }
+
+ // Find common ancestor and end points
+ ancestor = dom.findCommonAncestor(startContainer, endContainer);
+
+ // Process left side
+ for (node = startContainer; node; node = node.parentNode) {
+ if (node === endContainer) {
+ return walkBoundary(startContainer, ancestor, true);
+ }
+
+ if (node === ancestor) {
+ break;
+ }
+ }
+
+ // Process right side
+ for (node = endContainer; node; node = node.parentNode) {
+ if (node === startContainer) {
+ return walkBoundary(endContainer, ancestor);
+ }
+
+ if (node === ancestor) {
+ break;
+ }
+ }
+
+ // Find start/end point
+ startPoint = findEndPoint(startContainer, ancestor) || startContainer;
+ endPoint = findEndPoint(endContainer, ancestor) || endContainer;
+
+ // Walk left leaf
+ walkBoundary(startContainer, startPoint, true);
+
+ // Walk the middle from start to end point
+ siblings = collectSiblings(
+ startPoint == startContainer ? startPoint : startPoint.nextSibling,
+ 'nextSibling',
+ endPoint == endContainer ? endPoint.nextSibling : endPoint
+ );
+
+ if (siblings.length) {
+ callback(exclude(siblings));
+ }
+
+ // Walk right leaf
+ walkBoundary(endContainer, endPoint);
+ };
+
+ /**
+ * Splits the specified range at it's start/end points.
+ *
+ * @private
+ * @param {Range/RangeObject} rng Range to split.
+ * @return {Object} Range position object.
+ */
+ this.split = function (rng) {
+ var startContainer = rng.startContainer,
+ startOffset = rng.startOffset,
+ endContainer = rng.endContainer,
+ endOffset = rng.endOffset;
+
+ function splitText(node, offset) {
+ return node.splitText(offset);
+ }
+
+ // Handle single text node
+ if (startContainer == endContainer && startContainer.nodeType == 3) {
+ if (startOffset > 0 && startOffset < startContainer.nodeValue.length) {
+ endContainer = splitText(startContainer, startOffset);
+ startContainer = endContainer.previousSibling;
+
+ if (endOffset > startOffset) {
+ endOffset = endOffset - startOffset;
+ startContainer = endContainer = splitText(endContainer, endOffset).previousSibling;
+ endOffset = endContainer.nodeValue.length;
+ startOffset = 0;
+ } else {
+ endOffset = 0;
+ }
+ }
+ } else {
+ // Split startContainer text node if needed
+ if (startContainer.nodeType == 3 && startOffset > 0 && startOffset < startContainer.nodeValue.length) {
+ startContainer = splitText(startContainer, startOffset);
+ startOffset = 0;
+ }
+
+ // Split endContainer text node if needed
+ if (endContainer.nodeType == 3 && endOffset > 0 && endOffset < endContainer.nodeValue.length) {
+ endContainer = splitText(endContainer, endOffset).previousSibling;
+ endOffset = endContainer.nodeValue.length;
+ }
+ }
+
+ return {
+ startContainer: startContainer,
+ startOffset: startOffset,
+ endContainer: endContainer,
+ endOffset: endOffset
+ };
+ };
+
+ /**
+ * Normalizes the specified range by finding the closest best suitable caret location.
+ *
+ * @private
+ * @param {Range} rng Range to normalize.
+ * @return {Boolean} True/false if the specified range was normalized or not.
+ */
+ this.normalize = function (rng) {
+ var normalized = false, collapsed;
+
+ function normalizeEndPoint(start) {
+ var container, offset, walker, body = dom.getRoot(), node, nonEmptyElementsMap;
+ var directionLeft, isAfterNode;
+
+ function isTableCell(node) {
+ return node && /^(TD|TH|CAPTION)$/.test(node.nodeName);
+ }
+
+ function hasBrBeforeAfter(node, left) {
+ var walker = new TreeWalker(node, dom.getParent(node.parentNode, dom.isBlock) || body);
+
+ while ((node = walker[left ? 'prev' : 'next']())) {
+ if (node.nodeName === "BR") {
+ return true;
+ }
+ }
+ }
+
+ function hasContentEditableFalseParent(node) {
+ while (node && node != body) {
+ if (isContentEditableFalse(node)) {
+ return true;
+ }
+
+ node = node.parentNode;
+ }
+
+ return false;
+ }
+
+ function isPrevNode(node, name) {
+ return node.previousSibling && node.previousSibling.nodeName == name;
+ }
+
+ // Walks the dom left/right to find a suitable text node to move the endpoint into
+ // It will only walk within the current parent block or body and will stop if it hits a block or a BR/IMG
+ function findTextNodeRelative(left, startNode) {
+ var walker, lastInlineElement, parentBlockContainer;
+
+ startNode = startNode || container;
+ parentBlockContainer = dom.getParent(startNode.parentNode, dom.isBlock) || body;
+
+ // Lean left before the BR element if it's the only BR within a block element. Gecko bug: #6680
+ // This:
|
becomes
|
+ if (left && startNode.nodeName == 'BR' && isAfterNode && dom.isEmpty(parentBlockContainer)) {
+ container = startNode.parentNode;
+ offset = dom.nodeIndex(startNode);
+ normalized = true;
+ return;
+ }
+
+ // Walk left until we hit a text node we can move to or a block/br/img
+ walker = new TreeWalker(startNode, parentBlockContainer);
+ while ((node = walker[left ? 'prev' : 'next']())) {
+ // Break if we hit a non content editable node
+ if (dom.getContentEditableParent(node) === "false" || isCeFalseCaretContainer(node, dom.getRoot())) {
+ return;
+ }
+
+ // Found text node that has a length
+ if (node.nodeType === 3 && node.nodeValue.length > 0) {
+ if (hasParentWithName(node, body, 'A') === false) {
+ container = node;
+ offset = left ? node.nodeValue.length : 0;
+ normalized = true;
+ }
+
+ return;
+ }
+
+ // Break if we find a block or a BR/IMG/INPUT etc
+ if (dom.isBlock(node) || nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
+ return;
+ }
+
+ lastInlineElement = node;
+ }
+
+ // Only fetch the last inline element when in caret mode for now
+ if (collapsed && lastInlineElement) {
+ container = lastInlineElement;
+ normalized = true;
+ offset = 0;
+ }
+ }
+
+ container = rng[(start ? 'start' : 'end') + 'Container'];
+ offset = rng[(start ? 'start' : 'end') + 'Offset'];
+ isAfterNode = container.nodeType == 1 && offset === container.childNodes.length;
+ nonEmptyElementsMap = dom.schema.getNonEmptyElements();
+ directionLeft = start;
+
+ if (isCaretContainer(container)) {
+ return;
+ }
+
+ if (container.nodeType == 1 && offset > container.childNodes.length - 1) {
+ directionLeft = false;
+ }
+
+ // If the container is a document move it to the body element
+ if (container.nodeType === 9) {
+ container = dom.getRoot();
+ offset = 0;
+ }
+
+ // If the container is body try move it into the closest text node or position
+ if (container === body) {
+ // If start is before/after a image, table etc
+ if (directionLeft) {
+ node = container.childNodes[offset > 0 ? offset - 1 : 0];
+ if (node) {
+ if (isCaretContainer(node)) {
+ return;
+ }
+
+ if (nonEmptyElementsMap[node.nodeName] || node.nodeName == "TABLE") {
+ return;
+ }
+ }
+ }
+
+ // Resolve the index
+ if (container.hasChildNodes()) {
+ offset = Math.min(!directionLeft && offset > 0 ? offset - 1 : offset, container.childNodes.length - 1);
+ container = container.childNodes[offset];
+ offset = 0;
+
+ // Don't normalize non collapsed selections like
[a
]
+ if (!collapsed && container === body.lastChild && container.nodeName === 'TABLE') {
+ return;
+ }
+
+ if (hasContentEditableFalseParent(container) || isCaretContainer(container)) {
+ return;
+ }
+
+ // Don't walk into elements that doesn't have any child nodes like a IMG
+ if (container.hasChildNodes() && !/TABLE/.test(container.nodeName)) {
+ // Walk the DOM to find a text node to place the caret at or a BR
+ node = container;
+ walker = new TreeWalker(container, body);
+
+ do {
+ if (isContentEditableFalse(node) || isCaretContainer(node)) {
+ normalized = false;
+ break;
+ }
+
+ // Found a text node use that position
+ if (node.nodeType === 3 && node.nodeValue.length > 0) {
+ offset = directionLeft ? 0 : node.nodeValue.length;
+ container = node;
+ normalized = true;
+ break;
+ }
+
+ // Found a BR/IMG element that we can place the caret before
+ if (nonEmptyElementsMap[node.nodeName.toLowerCase()] && !isTableCell(node)) {
+ offset = dom.nodeIndex(node);
+ container = node.parentNode;
+
+ // Put caret after image when moving the end point
+ if (node.nodeName == "IMG" && !directionLeft) {
+ offset++;
+ }
+
+ normalized = true;
+ break;
+ }
+ } while ((node = (directionLeft ? walker.next() : walker.prev())));
+ }
+ }
+ }
+
+ // Lean the caret to the left if possible
+ if (collapsed) {
+ // So this: x|x
+ // Becomes: x|x
+ // Seems that only gecko has issues with this
+ if (container.nodeType === 3 && offset === 0) {
+ findTextNodeRelative(true);
+ }
+
+ // Lean left into empty inline elements when the caret is before a BR
+ // So this: |
+ // Becomes: |
+ // Seems that only gecko has issues with this.
+ // Special edge case for
bug on IE 8 #6178
+ DOMUtils.DOM.setHTML(elm, html);
+ }
+ };
+
+ return funcs;
+ }
+);
+/**
+ * BoxUtils.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
+ */
+
+/**
+ * Utility class for box parsing and measuring.
+ *
+ * @private
+ * @class tinymce.ui.BoxUtils
+ */
+define(
+ 'tinymce.core.ui.BoxUtils',
+ [
+ ],
+ function () {
+ "use strict";
+
+ return {
+ /**
+ * Parses the specified box value. A box value contains 1-4 properties in clockwise order.
+ *
+ * @method parseBox
+ * @param {String/Number} value Box value "0 1 2 3" or "0" etc.
+ * @return {Object} Object with top/right/bottom/left properties.
+ * @private
+ */
+ parseBox: function (value) {
+ var len, radix = 10;
+
+ if (!value) {
+ return;
+ }
+
+ if (typeof value === "number") {
+ value = value || 0;
+
+ return {
+ top: value,
+ left: value,
+ bottom: value,
+ right: value
+ };
+ }
+
+ value = value.split(' ');
+ len = value.length;
+
+ if (len === 1) {
+ value[1] = value[2] = value[3] = value[0];
+ } else if (len === 2) {
+ value[2] = value[0];
+ value[3] = value[1];
+ } else if (len === 3) {
+ value[3] = value[1];
+ }
+
+ return {
+ top: parseInt(value[0], radix) || 0,
+ right: parseInt(value[1], radix) || 0,
+ bottom: parseInt(value[2], radix) || 0,
+ left: parseInt(value[3], radix) || 0
+ };
+ },
+
+ measureBox: function (elm, prefix) {
+ function getStyle(name) {
+ var defaultView = document.defaultView;
+
+ if (defaultView) {
+ // Remove camelcase
+ name = name.replace(/[A-Z]/g, function (a) {
+ return '-' + a;
+ });
+
+ return defaultView.getComputedStyle(elm, null).getPropertyValue(name);
+ }
+
+ return elm.currentStyle[name];
+ }
+
+ function getSide(name) {
+ var val = parseFloat(getStyle(name), 10);
+
+ return isNaN(val) ? 0 : val;
+ }
+
+ return {
+ top: getSide(prefix + "TopWidth"),
+ right: getSide(prefix + "RightWidth"),
+ bottom: getSide(prefix + "BottomWidth"),
+ left: getSide(prefix + "LeftWidth")
+ };
+ }
+ };
+ }
+);
+
+/**
+ * ClassList.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 adding and removal of classes.
+ *
+ * @private
+ * @class tinymce.ui.ClassList
+ */
+define(
+ 'tinymce.core.ui.ClassList',
+ [
+ "tinymce.core.util.Tools"
+ ],
+ function (Tools) {
+ "use strict";
+
+ function noop() {
+ }
+
+ /**
+ * Constructs a new class list the specified onchange
+ * callback will be executed when the class list gets modifed.
+ *
+ * @constructor ClassList
+ * @param {function} onchange Onchange callback to be executed.
+ */
+ function ClassList(onchange) {
+ this.cls = [];
+ this.cls._map = {};
+ this.onchange = onchange || noop;
+ this.prefix = '';
+ }
+
+ Tools.extend(ClassList.prototype, {
+ /**
+ * Adds a new class to the class list.
+ *
+ * @method add
+ * @param {String} cls Class to be added.
+ * @return {tinymce.ui.ClassList} Current class list instance.
+ */
+ add: function (cls) {
+ if (cls && !this.contains(cls)) {
+ this.cls._map[cls] = true;
+ this.cls.push(cls);
+ this._change();
+ }
+
+ return this;
+ },
+
+ /**
+ * Removes the specified class from the class list.
+ *
+ * @method remove
+ * @param {String} cls Class to be removed.
+ * @return {tinymce.ui.ClassList} Current class list instance.
+ */
+ remove: function (cls) {
+ if (this.contains(cls)) {
+ for (var i = 0; i < this.cls.length; i++) {
+ if (this.cls[i] === cls) {
+ break;
+ }
+ }
+
+ this.cls.splice(i, 1);
+ delete this.cls._map[cls];
+ this._change();
+ }
+
+ return this;
+ },
+
+ /**
+ * Toggles a class in the class list.
+ *
+ * @method toggle
+ * @param {String} cls Class to be added/removed.
+ * @param {Boolean} state Optional state if it should be added/removed.
+ * @return {tinymce.ui.ClassList} Current class list instance.
+ */
+ toggle: function (cls, state) {
+ var curState = this.contains(cls);
+
+ if (curState !== state) {
+ if (curState) {
+ this.remove(cls);
+ } else {
+ this.add(cls);
+ }
+
+ this._change();
+ }
+
+ return this;
+ },
+
+ /**
+ * Returns true if the class list has the specified class.
+ *
+ * @method contains
+ * @param {String} cls Class to look for.
+ * @return {Boolean} true/false if the class exists or not.
+ */
+ contains: function (cls) {
+ return !!this.cls._map[cls];
+ },
+
+ /**
+ * Returns a space separated list of classes.
+ *
+ * @method toString
+ * @return {String} Space separated list of classes.
+ */
+
+ _change: function () {
+ delete this.clsValue;
+ this.onchange.call(this);
+ }
+ });
+
+ // IE 8 compatibility
+ ClassList.prototype.toString = function () {
+ var value;
+
+ if (this.clsValue) {
+ return this.clsValue;
+ }
+
+ value = '';
+ for (var i = 0; i < this.cls.length; i++) {
+ if (i > 0) {
+ value += ' ';
+ }
+
+ value += this.prefix + this.cls[i];
+ }
+
+ return value;
+ };
+
+ return ClassList;
+ }
+);
+/**
+ * ReflowQueue.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 automatically reflow controls on the next animation frame within a few milliseconds on older browsers.
+ * If the user manually reflows then the automatic reflow will be cancelled. This class is used internally when various control states
+ * changes that triggers a reflow.
+ *
+ * @class tinymce.ui.ReflowQueue
+ * @static
+ */
+define(
+ 'tinymce.core.ui.ReflowQueue',
+ [
+ "tinymce.core.util.Delay"
+ ],
+ function (Delay) {
+ var dirtyCtrls = {}, animationFrameRequested;
+
+ return {
+ /**
+ * Adds a control to the next automatic reflow call. This is the control that had a state
+ * change for example if the control was hidden/shown.
+ *
+ * @method add
+ * @param {tinymce.ui.Control} ctrl Control to add to queue.
+ */
+ add: function (ctrl) {
+ var parent = ctrl.parent();
+
+ if (parent) {
+ if (!parent._layout || parent._layout.isNative()) {
+ return;
+ }
+
+ if (!dirtyCtrls[parent._id]) {
+ dirtyCtrls[parent._id] = parent;
+ }
+
+ if (!animationFrameRequested) {
+ animationFrameRequested = true;
+
+ Delay.requestAnimationFrame(function () {
+ var id, ctrl;
+
+ animationFrameRequested = false;
+
+ for (id in dirtyCtrls) {
+ ctrl = dirtyCtrls[id];
+
+ if (ctrl.state.get('rendered')) {
+ ctrl.reflow();
+ }
+ }
+
+ dirtyCtrls = {};
+ }, document.body);
+ }
+ }
+ },
+
+ /**
+ * Removes the specified control from the automatic reflow. This will happen when for example the user
+ * manually triggers a reflow.
+ *
+ * @method remove
+ * @param {tinymce.ui.Control} ctrl Control to remove from queue.
+ */
+ remove: function (ctrl) {
+ if (dirtyCtrls[ctrl._id]) {
+ delete dirtyCtrls[ctrl._id];
+ }
+ }
+ };
+ }
+);
+
+/**
+ * Control.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 consistent-this:0 */
+
+/**
+ * This is the base class for all controls and containers. All UI control instances inherit
+ * from this one as it has the base logic needed by all of them.
+ *
+ * @class tinymce.ui.Control
+ */
+define(
+ 'tinymce.core.ui.Control',
+ [
+ "tinymce.core.util.Class",
+ "tinymce.core.util.Tools",
+ "tinymce.core.util.EventDispatcher",
+ "tinymce.core.data.ObservableObject",
+ "tinymce.core.ui.Collection",
+ "tinymce.core.ui.DomUtils",
+ "tinymce.core.dom.DomQuery",
+ "tinymce.core.ui.BoxUtils",
+ "tinymce.core.ui.ClassList",
+ "tinymce.core.ui.ReflowQueue"
+ ],
+ function (Class, Tools, EventDispatcher, ObservableObject, Collection, DomUtils, $, BoxUtils, ClassList, ReflowQueue) {
+ "use strict";
+
+ var hasMouseWheelEventSupport = "onmousewheel" in document;
+ var hasWheelEventSupport = false;
+ var classPrefix = "mce-";
+ var Control, idCounter = 0;
+
+ var proto = {
+ Statics: {
+ classPrefix: classPrefix
+ },
+
+ isRtl: function () {
+ return Control.rtl;
+ },
+
+ /**
+ * Class/id prefix to use for all controls.
+ *
+ * @final
+ * @field {String} classPrefix
+ */
+ classPrefix: classPrefix,
+
+ /**
+ * Constructs a new control instance with the specified settings.
+ *
+ * @constructor
+ * @param {Object} settings Name/value object with settings.
+ * @setting {String} style Style CSS properties to add.
+ * @setting {String} border Border box values example: 1 1 1 1
+ * @setting {String} padding Padding box values example: 1 1 1 1
+ * @setting {String} margin Margin box values example: 1 1 1 1
+ * @setting {Number} minWidth Minimal width for the control.
+ * @setting {Number} minHeight Minimal height for the control.
+ * @setting {String} classes Space separated list of classes to add.
+ * @setting {String} role WAI-ARIA role to use for control.
+ * @setting {Boolean} hidden Is the control hidden by default.
+ * @setting {Boolean} disabled Is the control disabled by default.
+ * @setting {String} name Name of the control instance.
+ */
+ init: function (settings) {
+ var self = this, classes, defaultClasses;
+
+ function applyClasses(classes) {
+ var i;
+
+ classes = classes.split(' ');
+ for (i = 0; i < classes.length; i++) {
+ self.classes.add(classes[i]);
+ }
+ }
+
+ self.settings = settings = Tools.extend({}, self.Defaults, settings);
+
+ // Initial states
+ self._id = settings.id || ('mceu_' + (idCounter++));
+ self._aria = { role: settings.role };
+ self._elmCache = {};
+ self.$ = $;
+
+ self.state = new ObservableObject({
+ visible: true,
+ active: false,
+ disabled: false,
+ value: ''
+ });
+
+ self.data = new ObservableObject(settings.data);
+
+ self.classes = new ClassList(function () {
+ if (self.state.get('rendered')) {
+ self.getEl().className = this.toString();
+ }
+ });
+ self.classes.prefix = self.classPrefix;
+
+ // Setup classes
+ classes = settings.classes;
+ if (classes) {
+ if (self.Defaults) {
+ defaultClasses = self.Defaults.classes;
+
+ if (defaultClasses && classes != defaultClasses) {
+ applyClasses(defaultClasses);
+ }
+ }
+
+ applyClasses(classes);
+ }
+
+ Tools.each('title text name visible disabled active value'.split(' '), function (name) {
+ if (name in settings) {
+ self[name](settings[name]);
+ }
+ });
+
+ self.on('click', function () {
+ if (self.disabled()) {
+ return false;
+ }
+ });
+
+ /**
+ * Name/value object with settings for the current control.
+ *
+ * @field {Object} settings
+ */
+ self.settings = settings;
+
+ self.borderBox = BoxUtils.parseBox(settings.border);
+ self.paddingBox = BoxUtils.parseBox(settings.padding);
+ self.marginBox = BoxUtils.parseBox(settings.margin);
+
+ if (settings.hidden) {
+ self.hide();
+ }
+ },
+
+ // Will generate getter/setter methods for these properties
+ Properties: 'parent,name',
+
+ /**
+ * Returns the root element to render controls into.
+ *
+ * @method getContainerElm
+ * @return {Element} HTML DOM element to render into.
+ */
+ getContainerElm: function () {
+ return DomUtils.getContainer();
+ },
+
+ /**
+ * Returns a control instance for the current DOM element.
+ *
+ * @method getParentCtrl
+ * @param {Element} elm HTML dom element to get parent control from.
+ * @return {tinymce.ui.Control} Control instance or undefined.
+ */
+ getParentCtrl: function (elm) {
+ var ctrl, lookup = this.getRoot().controlIdLookup;
+
+ while (elm && lookup) {
+ ctrl = lookup[elm.id];
+ if (ctrl) {
+ break;
+ }
+
+ elm = elm.parentNode;
+ }
+
+ return ctrl;
+ },
+
+ /**
+ * Initializes the current controls layout rect.
+ * This will be executed by the layout managers to determine the
+ * default minWidth/minHeight etc.
+ *
+ * @method initLayoutRect
+ * @return {Object} Layout rect instance.
+ */
+ initLayoutRect: function () {
+ var self = this, settings = self.settings, borderBox, layoutRect;
+ var elm = self.getEl(), width, height, minWidth, minHeight, autoResize;
+ var startMinWidth, startMinHeight, initialSize;
+
+ // Measure the current element
+ borderBox = self.borderBox = self.borderBox || BoxUtils.measureBox(elm, 'border');
+ self.paddingBox = self.paddingBox || BoxUtils.measureBox(elm, 'padding');
+ self.marginBox = self.marginBox || BoxUtils.measureBox(elm, 'margin');
+ initialSize = DomUtils.getSize(elm);
+
+ // Setup minWidth/minHeight and width/height
+ startMinWidth = settings.minWidth;
+ startMinHeight = settings.minHeight;
+ minWidth = startMinWidth || initialSize.width;
+ minHeight = startMinHeight || initialSize.height;
+ width = settings.width;
+ height = settings.height;
+ autoResize = settings.autoResize;
+ autoResize = typeof autoResize != "undefined" ? autoResize : !width && !height;
+
+ width = width || minWidth;
+ height = height || minHeight;
+
+ var deltaW = borderBox.left + borderBox.right;
+ var deltaH = borderBox.top + borderBox.bottom;
+
+ var maxW = settings.maxWidth || 0xFFFF;
+ var maxH = settings.maxHeight || 0xFFFF;
+
+ // Setup initial layout rect
+ self._layoutRect = layoutRect = {
+ x: settings.x || 0,
+ y: settings.y || 0,
+ w: width,
+ h: height,
+ deltaW: deltaW,
+ deltaH: deltaH,
+ contentW: width - deltaW,
+ contentH: height - deltaH,
+ innerW: width - deltaW,
+ innerH: height - deltaH,
+ startMinWidth: startMinWidth || 0,
+ startMinHeight: startMinHeight || 0,
+ minW: Math.min(minWidth, maxW),
+ minH: Math.min(minHeight, maxH),
+ maxW: maxW,
+ maxH: maxH,
+ autoResize: autoResize,
+ scrollW: 0
+ };
+
+ self._lastLayoutRect = {};
+
+ return layoutRect;
+ },
+
+ /**
+ * Getter/setter for the current layout rect.
+ *
+ * @method layoutRect
+ * @param {Object} [newRect] Optional new layout rect.
+ * @return {tinymce.ui.Control/Object} Current control or rect object.
+ */
+ layoutRect: function (newRect) {
+ var self = this, curRect = self._layoutRect, lastLayoutRect, size, deltaWidth, deltaHeight, undef, repaintControls;
+
+ // Initialize default layout rect
+ if (!curRect) {
+ curRect = self.initLayoutRect();
+ }
+
+ // Set new rect values
+ if (newRect) {
+ // Calc deltas between inner and outer sizes
+ deltaWidth = curRect.deltaW;
+ deltaHeight = curRect.deltaH;
+
+ // Set x position
+ if (newRect.x !== undef) {
+ curRect.x = newRect.x;
+ }
+
+ // Set y position
+ if (newRect.y !== undef) {
+ curRect.y = newRect.y;
+ }
+
+ // Set minW
+ if (newRect.minW !== undef) {
+ curRect.minW = newRect.minW;
+ }
+
+ // Set minH
+ if (newRect.minH !== undef) {
+ curRect.minH = newRect.minH;
+ }
+
+ // Set new width and calculate inner width
+ size = newRect.w;
+ if (size !== undef) {
+ size = size < curRect.minW ? curRect.minW : size;
+ size = size > curRect.maxW ? curRect.maxW : size;
+ curRect.w = size;
+ curRect.innerW = size - deltaWidth;
+ }
+
+ // Set new height and calculate inner height
+ size = newRect.h;
+ if (size !== undef) {
+ size = size < curRect.minH ? curRect.minH : size;
+ size = size > curRect.maxH ? curRect.maxH : size;
+ curRect.h = size;
+ curRect.innerH = size - deltaHeight;
+ }
+
+ // Set new inner width and calculate width
+ size = newRect.innerW;
+ if (size !== undef) {
+ size = size < curRect.minW - deltaWidth ? curRect.minW - deltaWidth : size;
+ size = size > curRect.maxW - deltaWidth ? curRect.maxW - deltaWidth : size;
+ curRect.innerW = size;
+ curRect.w = size + deltaWidth;
+ }
+
+ // Set new height and calculate inner height
+ size = newRect.innerH;
+ if (size !== undef) {
+ size = size < curRect.minH - deltaHeight ? curRect.minH - deltaHeight : size;
+ size = size > curRect.maxH - deltaHeight ? curRect.maxH - deltaHeight : size;
+ curRect.innerH = size;
+ curRect.h = size + deltaHeight;
+ }
+
+ // Set new contentW
+ if (newRect.contentW !== undef) {
+ curRect.contentW = newRect.contentW;
+ }
+
+ // Set new contentH
+ if (newRect.contentH !== undef) {
+ curRect.contentH = newRect.contentH;
+ }
+
+ // Compare last layout rect with the current one to see if we need to repaint or not
+ lastLayoutRect = self._lastLayoutRect;
+ if (lastLayoutRect.x !== curRect.x || lastLayoutRect.y !== curRect.y ||
+ lastLayoutRect.w !== curRect.w || lastLayoutRect.h !== curRect.h) {
+ repaintControls = Control.repaintControls;
+
+ if (repaintControls) {
+ if (repaintControls.map && !repaintControls.map[self._id]) {
+ repaintControls.push(self);
+ repaintControls.map[self._id] = true;
+ }
+ }
+
+ lastLayoutRect.x = curRect.x;
+ lastLayoutRect.y = curRect.y;
+ lastLayoutRect.w = curRect.w;
+ lastLayoutRect.h = curRect.h;
+ }
+
+ return self;
+ }
+
+ return curRect;
+ },
+
+ /**
+ * Repaints the control after a layout operation.
+ *
+ * @method repaint
+ */
+ repaint: function () {
+ var self = this, style, bodyStyle, bodyElm, rect, borderBox;
+ var borderW, borderH, lastRepaintRect, round, value;
+
+ // Use Math.round on all values on IE < 9
+ round = !document.createRange ? Math.round : function (value) {
+ return value;
+ };
+
+ style = self.getEl().style;
+ rect = self._layoutRect;
+ lastRepaintRect = self._lastRepaintRect || {};
+
+ borderBox = self.borderBox;
+ borderW = borderBox.left + borderBox.right;
+ borderH = borderBox.top + borderBox.bottom;
+
+ if (rect.x !== lastRepaintRect.x) {
+ style.left = round(rect.x) + 'px';
+ lastRepaintRect.x = rect.x;
+ }
+
+ if (rect.y !== lastRepaintRect.y) {
+ style.top = round(rect.y) + 'px';
+ lastRepaintRect.y = rect.y;
+ }
+
+ if (rect.w !== lastRepaintRect.w) {
+ value = round(rect.w - borderW);
+ style.width = (value >= 0 ? value : 0) + 'px';
+ lastRepaintRect.w = rect.w;
+ }
+
+ if (rect.h !== lastRepaintRect.h) {
+ value = round(rect.h - borderH);
+ style.height = (value >= 0 ? value : 0) + 'px';
+ lastRepaintRect.h = rect.h;
+ }
+
+ // Update body if needed
+ if (self._hasBody && rect.innerW !== lastRepaintRect.innerW) {
+ value = round(rect.innerW);
+
+ bodyElm = self.getEl('body');
+ if (bodyElm) {
+ bodyStyle = bodyElm.style;
+ bodyStyle.width = (value >= 0 ? value : 0) + 'px';
+ }
+
+ lastRepaintRect.innerW = rect.innerW;
+ }
+
+ if (self._hasBody && rect.innerH !== lastRepaintRect.innerH) {
+ value = round(rect.innerH);
+
+ bodyElm = bodyElm || self.getEl('body');
+ if (bodyElm) {
+ bodyStyle = bodyStyle || bodyElm.style;
+ bodyStyle.height = (value >= 0 ? value : 0) + 'px';
+ }
+
+ lastRepaintRect.innerH = rect.innerH;
+ }
+
+ self._lastRepaintRect = lastRepaintRect;
+ self.fire('repaint', {}, false);
+ },
+
+ /**
+ * Updates the controls layout rect by re-measuing it.
+ */
+ updateLayoutRect: function () {
+ var self = this;
+
+ self.parent()._lastRect = null;
+
+ DomUtils.css(self.getEl(), { width: '', height: '' });
+
+ self._layoutRect = self._lastRepaintRect = self._lastLayoutRect = null;
+ self.initLayoutRect();
+ },
+
+ /**
+ * Binds a callback to the specified event. This event can both be
+ * native browser events like "click" or custom ones like PostRender.
+ *
+ * The callback function will be passed a DOM event like object that enables yout do stop propagation.
+ *
+ * @method on
+ * @param {String} name Name of the event to bind. For example "click".
+ * @param {String/function} callback Callback function to execute ones the event occurs.
+ * @return {tinymce.ui.Control} Current control object.
+ */
+ on: function (name, callback) {
+ var self = this;
+
+ function resolveCallbackName(name) {
+ var callback, scope;
+
+ if (typeof name != 'string') {
+ return name;
+ }
+
+ return function (e) {
+ if (!callback) {
+ self.parentsAndSelf().each(function (ctrl) {
+ var callbacks = ctrl.settings.callbacks;
+
+ if (callbacks && (callback = callbacks[name])) {
+ scope = ctrl;
+ return false;
+ }
+ });
+ }
+
+ if (!callback) {
+ e.action = name;
+ this.fire('execute', e);
+ return;
+ }
+
+ return callback.call(scope, e);
+ };
+ }
+
+ getEventDispatcher(self).on(name, resolveCallbackName(callback));
+
+ return self;
+ },
+
+ /**
+ * Unbinds the specified event and optionally a specific callback. If you omit the name
+ * parameter all event handlers will be removed. If you omit the callback all event handles
+ * by the specified name will be removed.
+ *
+ * @method off
+ * @param {String} [name] Name for the event to unbind.
+ * @param {function} [callback] Callback function to unbind.
+ * @return {tinymce.ui.Control} Current control object.
+ */
+ off: function (name, callback) {
+ getEventDispatcher(this).off(name, callback);
+ return this;
+ },
+
+ /**
+ * Fires the specified event by name and arguments on the control. This will execute all
+ * bound event handlers.
+ *
+ * @method fire
+ * @param {String} name Name of the event to fire.
+ * @param {Object} [args] Arguments to pass to the event.
+ * @param {Boolean} [bubble] Value to control bubbling. Defaults to true.
+ * @return {Object} Current arguments object.
+ */
+ fire: function (name, args, bubble) {
+ var self = this;
+
+ args = args || {};
+
+ if (!args.control) {
+ args.control = self;
+ }
+
+ args = getEventDispatcher(self).fire(name, args);
+
+ // Bubble event up to parents
+ if (bubble !== false && self.parent) {
+ var parent = self.parent();
+ while (parent && !args.isPropagationStopped()) {
+ parent.fire(name, args, false);
+ parent = parent.parent();
+ }
+ }
+
+ return args;
+ },
+
+ /**
+ * Returns true/false if the specified event has any listeners.
+ *
+ * @method hasEventListeners
+ * @param {String} name Name of the event to check for.
+ * @return {Boolean} True/false state if the event has listeners.
+ */
+ hasEventListeners: function (name) {
+ return getEventDispatcher(this).has(name);
+ },
+
+ /**
+ * Returns a control collection with all parent controls.
+ *
+ * @method parents
+ * @param {String} selector Optional selector expression to find parents.
+ * @return {tinymce.ui.Collection} Collection with all parent controls.
+ */
+ parents: function (selector) {
+ var self = this, ctrl, parents = new Collection();
+
+ // Add each parent to collection
+ for (ctrl = self.parent(); ctrl; ctrl = ctrl.parent()) {
+ parents.add(ctrl);
+ }
+
+ // Filter away everything that doesn't match the selector
+ if (selector) {
+ parents = parents.filter(selector);
+ }
+
+ return parents;
+ },
+
+ /**
+ * Returns the current control and it's parents.
+ *
+ * @method parentsAndSelf
+ * @param {String} selector Optional selector expression to find parents.
+ * @return {tinymce.ui.Collection} Collection with all parent controls.
+ */
+ parentsAndSelf: function (selector) {
+ return new Collection(this).add(this.parents(selector));
+ },
+
+ /**
+ * Returns the control next to the current control.
+ *
+ * @method next
+ * @return {tinymce.ui.Control} Next control instance.
+ */
+ next: function () {
+ var parentControls = this.parent().items();
+
+ return parentControls[parentControls.indexOf(this) + 1];
+ },
+
+ /**
+ * Returns the control previous to the current control.
+ *
+ * @method prev
+ * @return {tinymce.ui.Control} Previous control instance.
+ */
+ prev: function () {
+ var parentControls = this.parent().items();
+
+ return parentControls[parentControls.indexOf(this) - 1];
+ },
+
+ /**
+ * Sets the inner HTML of the control element.
+ *
+ * @method innerHtml
+ * @param {String} html Html string to set as inner html.
+ * @return {tinymce.ui.Control} Current control object.
+ */
+ innerHtml: function (html) {
+ this.$el.html(html);
+ return this;
+ },
+
+ /**
+ * Returns the control DOM element or sub element.
+ *
+ * @method getEl
+ * @param {String} [suffix] Suffix to get element by.
+ * @return {Element} HTML DOM element for the current control or it's children.
+ */
+ getEl: function (suffix) {
+ var id = suffix ? this._id + '-' + suffix : this._id;
+
+ if (!this._elmCache[id]) {
+ this._elmCache[id] = $('#' + id)[0];
+ }
+
+ return this._elmCache[id];
+ },
+
+ /**
+ * Sets the visible state to true.
+ *
+ * @method show
+ * @return {tinymce.ui.Control} Current control instance.
+ */
+ show: function () {
+ return this.visible(true);
+ },
+
+ /**
+ * Sets the visible state to false.
+ *
+ * @method hide
+ * @return {tinymce.ui.Control} Current control instance.
+ */
+ hide: function () {
+ return this.visible(false);
+ },
+
+ /**
+ * Focuses the current control.
+ *
+ * @method focus
+ * @return {tinymce.ui.Control} Current control instance.
+ */
+ focus: function () {
+ try {
+ this.getEl().focus();
+ } catch (ex) {
+ // Ignore IE error
+ }
+
+ return this;
+ },
+
+ /**
+ * Blurs the current control.
+ *
+ * @method blur
+ * @return {tinymce.ui.Control} Current control instance.
+ */
+ blur: function () {
+ this.getEl().blur();
+
+ return this;
+ },
+
+ /**
+ * Sets the specified aria property.
+ *
+ * @method aria
+ * @param {String} name Name of the aria property to set.
+ * @param {String} value Value of the aria property.
+ * @return {tinymce.ui.Control} Current control instance.
+ */
+ aria: function (name, value) {
+ var self = this, elm = self.getEl(self.ariaTarget);
+
+ if (typeof value === "undefined") {
+ return self._aria[name];
+ }
+
+ self._aria[name] = value;
+
+ if (self.state.get('rendered')) {
+ elm.setAttribute(name == 'role' ? name : 'aria-' + name, value);
+ }
+
+ return self;
+ },
+
+ /**
+ * Encodes the specified string with HTML entities. It will also
+ * translate the string to different languages.
+ *
+ * @method encode
+ * @param {String/Object/Array} text Text to entity encode.
+ * @param {Boolean} [translate=true] False if the contents shouldn't be translated.
+ * @return {String} Encoded and possible traslated string.
+ */
+ encode: function (text, translate) {
+ if (translate !== false) {
+ text = this.translate(text);
+ }
+
+ return (text || '').replace(/[&<>"]/g, function (match) {
+ return '' + match.charCodeAt(0) + ';';
+ });
+ },
+
+ /**
+ * Returns the translated string.
+ *
+ * @method translate
+ * @param {String} text Text to translate.
+ * @return {String} Translated string or the same as the input.
+ */
+ translate: function (text) {
+ return Control.translate ? Control.translate(text) : text;
+ },
+
+ /**
+ * Adds items before the current control.
+ *
+ * @method before
+ * @param {Array/tinymce.ui.Collection} items Array of items to prepend before this control.
+ * @return {tinymce.ui.Control} Current control instance.
+ */
+ before: function (items) {
+ var self = this, parent = self.parent();
+
+ if (parent) {
+ parent.insert(items, parent.items().indexOf(self), true);
+ }
+
+ return self;
+ },
+
+ /**
+ * Adds items after the current control.
+ *
+ * @method after
+ * @param {Array/tinymce.ui.Collection} items Array of items to append after this control.
+ * @return {tinymce.ui.Control} Current control instance.
+ */
+ after: function (items) {
+ var self = this, parent = self.parent();
+
+ if (parent) {
+ parent.insert(items, parent.items().indexOf(self));
+ }
+
+ return self;
+ },
+
+ /**
+ * Removes the current control from DOM and from UI collections.
+ *
+ * @method remove
+ * @return {tinymce.ui.Control} Current control instance.
+ */
+ remove: function () {
+ var self = this, elm = self.getEl(), parent = self.parent(), newItems, i;
+
+ if (self.items) {
+ var controls = self.items().toArray();
+ i = controls.length;
+ while (i--) {
+ controls[i].remove();
+ }
+ }
+
+ if (parent && parent.items) {
+ newItems = [];
+
+ parent.items().each(function (item) {
+ if (item !== self) {
+ newItems.push(item);
+ }
+ });
+
+ parent.items().set(newItems);
+ parent._lastRect = null;
+ }
+
+ if (self._eventsRoot && self._eventsRoot == self) {
+ $(elm).off();
+ }
+
+ var lookup = self.getRoot().controlIdLookup;
+ if (lookup) {
+ delete lookup[self._id];
+ }
+
+ if (elm && elm.parentNode) {
+ elm.parentNode.removeChild(elm);
+ }
+
+ self.state.set('rendered', false);
+ self.state.destroy();
+
+ self.fire('remove');
+
+ return self;
+ },
+
+ /**
+ * Renders the control before the specified element.
+ *
+ * @method renderBefore
+ * @param {Element} elm Element to render before.
+ * @return {tinymce.ui.Control} Current control instance.
+ */
+ renderBefore: function (elm) {
+ $(elm).before(this.renderHtml());
+ this.postRender();
+ return this;
+ },
+
+ /**
+ * Renders the control to the specified element.
+ *
+ * @method renderBefore
+ * @param {Element} elm Element to render to.
+ * @return {tinymce.ui.Control} Current control instance.
+ */
+ renderTo: function (elm) {
+ $(elm || this.getContainerElm()).append(this.renderHtml());
+ this.postRender();
+ return this;
+ },
+
+ preRender: function () {
+ },
+
+ render: function () {
+ },
+
+ renderHtml: function () {
+ return '
';
+ },
+
+ /**
+ * Post render method. Called after the control has been rendered to the target.
+ *
+ * @method postRender
+ * @return {tinymce.ui.Control} Current control instance.
+ */
+ postRender: function () {
+ var self = this, settings = self.settings, elm, box, parent, name, parentEventsRoot;
+
+ self.$el = $(self.getEl());
+ self.state.set('rendered', true);
+
+ // Bind on settings
+ for (name in settings) {
+ if (name.indexOf("on") === 0) {
+ self.on(name.substr(2), settings[name]);
+ }
+ }
+
+ if (self._eventsRoot) {
+ for (parent = self.parent(); !parentEventsRoot && parent; parent = parent.parent()) {
+ parentEventsRoot = parent._eventsRoot;
+ }
+
+ if (parentEventsRoot) {
+ for (name in parentEventsRoot._nativeEvents) {
+ self._nativeEvents[name] = true;
+ }
+ }
+ }
+
+ bindPendingEvents(self);
+
+ if (settings.style) {
+ elm = self.getEl();
+ if (elm) {
+ elm.setAttribute('style', settings.style);
+ elm.style.cssText = settings.style;
+ }
+ }
+
+ if (self.settings.border) {
+ box = self.borderBox;
+ self.$el.css({
+ 'border-top-width': box.top,
+ 'border-right-width': box.right,
+ 'border-bottom-width': box.bottom,
+ 'border-left-width': box.left
+ });
+ }
+
+ // Add instance to lookup
+ var root = self.getRoot();
+ if (!root.controlIdLookup) {
+ root.controlIdLookup = {};
+ }
+
+ root.controlIdLookup[self._id] = self;
+
+ for (var key in self._aria) {
+ self.aria(key, self._aria[key]);
+ }
+
+ if (self.state.get('visible') === false) {
+ self.getEl().style.display = 'none';
+ }
+
+ self.bindStates();
+
+ self.state.on('change:visible', function (e) {
+ var state = e.value, parentCtrl;
+
+ if (self.state.get('rendered')) {
+ self.getEl().style.display = state === false ? 'none' : '';
+
+ // Need to force a reflow here on IE 8
+ self.getEl().getBoundingClientRect();
+ }
+
+ // Parent container needs to reflow
+ parentCtrl = self.parent();
+ if (parentCtrl) {
+ parentCtrl._lastRect = null;
+ }
+
+ self.fire(state ? 'show' : 'hide');
+
+ ReflowQueue.add(self);
+ });
+
+ self.fire('postrender', {}, false);
+ },
+
+ bindStates: function () {
+ },
+
+ /**
+ * Scrolls the current control into view.
+ *
+ * @method scrollIntoView
+ * @param {String} align Alignment in view top|center|bottom.
+ * @return {tinymce.ui.Control} Current control instance.
+ */
+ scrollIntoView: function (align) {
+ function getOffset(elm, rootElm) {
+ var x, y, parent = elm;
+
+ x = y = 0;
+ while (parent && parent != rootElm && parent.nodeType) {
+ x += parent.offsetLeft || 0;
+ y += parent.offsetTop || 0;
+ parent = parent.offsetParent;
+ }
+
+ return { x: x, y: y };
+ }
+
+ var elm = this.getEl(), parentElm = elm.parentNode;
+ var x, y, width, height, parentWidth, parentHeight;
+ var pos = getOffset(elm, parentElm);
+
+ x = pos.x;
+ y = pos.y;
+ width = elm.offsetWidth;
+ height = elm.offsetHeight;
+ parentWidth = parentElm.clientWidth;
+ parentHeight = parentElm.clientHeight;
+
+ if (align == "end") {
+ x -= parentWidth - width;
+ y -= parentHeight - height;
+ } else if (align == "center") {
+ x -= (parentWidth / 2) - (width / 2);
+ y -= (parentHeight / 2) - (height / 2);
+ }
+
+ parentElm.scrollLeft = x;
+ parentElm.scrollTop = y;
+
+ return this;
+ },
+
+ getRoot: function () {
+ var ctrl = this, rootControl, parents = [];
+
+ while (ctrl) {
+ if (ctrl.rootControl) {
+ rootControl = ctrl.rootControl;
+ break;
+ }
+
+ parents.push(ctrl);
+ rootControl = ctrl;
+ ctrl = ctrl.parent();
+ }
+
+ if (!rootControl) {
+ rootControl = this;
+ }
+
+ var i = parents.length;
+ while (i--) {
+ parents[i].rootControl = rootControl;
+ }
+
+ return rootControl;
+ },
+
+ /**
+ * Reflows the current control and it's parents.
+ * This should be used after you for example append children to the current control so
+ * that the layout managers know that they need to reposition everything.
+ *
+ * @example
+ * container.append({type: 'button', text: 'My button'}).reflow();
+ *
+ * @method reflow
+ * @return {tinymce.ui.Control} Current control instance.
+ */
+ reflow: function () {
+ ReflowQueue.remove(this);
+
+ var parent = this.parent();
+ if (parent && parent._layout && !parent._layout.isNative()) {
+ parent.reflow();
+ }
+
+ return this;
+ }
+
+ /**
+ * Sets/gets the parent container for the control.
+ *
+ * @method parent
+ * @param {tinymce.ui.Container} parent Optional parent to set.
+ * @return {tinymce.ui.Control} Parent control or the current control on a set action.
+ */
+ // parent: function(parent) {} -- Generated
+
+ /**
+ * Sets/gets the text for the control.
+ *
+ * @method text
+ * @param {String} value Value to set to control.
+ * @return {String/tinymce.ui.Control} Current control on a set operation or current value on a get.
+ */
+ // text: function(value) {} -- Generated
+
+ /**
+ * Sets/gets the disabled state on the control.
+ *
+ * @method disabled
+ * @param {Boolean} state Value to set to control.
+ * @return {Boolean/tinymce.ui.Control} Current control on a set operation or current state on a get.
+ */
+ // disabled: function(state) {} -- Generated
+
+ /**
+ * Sets/gets the active for the control.
+ *
+ * @method active
+ * @param {Boolean} state Value to set to control.
+ * @return {Boolean/tinymce.ui.Control} Current control on a set operation or current state on a get.
+ */
+ // active: function(state) {} -- Generated
+
+ /**
+ * Sets/gets the name for the control.
+ *
+ * @method name
+ * @param {String} value Value to set to control.
+ * @return {String/tinymce.ui.Control} Current control on a set operation or current value on a get.
+ */
+ // name: function(value) {} -- Generated
+
+ /**
+ * Sets/gets the title for the control.
+ *
+ * @method title
+ * @param {String} value Value to set to control.
+ * @return {String/tinymce.ui.Control} Current control on a set operation or current value on a get.
+ */
+ // title: function(value) {} -- Generated
+
+ /**
+ * Sets/gets the visible for the control.
+ *
+ * @method visible
+ * @param {Boolean} state Value to set to control.
+ * @return {Boolean/tinymce.ui.Control} Current control on a set operation or current state on a get.
+ */
+ // visible: function(value) {} -- Generated
+ };
+
+ /**
+ * Setup state properties.
+ */
+ Tools.each('text title visible disabled active value'.split(' '), function (name) {
+ proto[name] = function (value) {
+ if (arguments.length === 0) {
+ return this.state.get(name);
+ }
+
+ if (typeof value != "undefined") {
+ this.state.set(name, value);
+ }
+
+ return this;
+ };
+ });
+
+ Control = Class.extend(proto);
+
+ function getEventDispatcher(obj) {
+ if (!obj._eventDispatcher) {
+ obj._eventDispatcher = new EventDispatcher({
+ scope: obj,
+ toggleEvent: function (name, state) {
+ if (state && EventDispatcher.isNative(name)) {
+ if (!obj._nativeEvents) {
+ obj._nativeEvents = {};
+ }
+
+ obj._nativeEvents[name] = true;
+
+ if (obj.state.get('rendered')) {
+ bindPendingEvents(obj);
+ }
+ }
+ }
+ });
+ }
+
+ return obj._eventDispatcher;
+ }
+
+ function bindPendingEvents(eventCtrl) {
+ var i, l, parents, eventRootCtrl, nativeEvents, name;
+
+ function delegate(e) {
+ var control = eventCtrl.getParentCtrl(e.target);
+
+ if (control) {
+ control.fire(e.type, e);
+ }
+ }
+
+ function mouseLeaveHandler() {
+ var ctrl = eventRootCtrl._lastHoverCtrl;
+
+ if (ctrl) {
+ ctrl.fire("mouseleave", { target: ctrl.getEl() });
+
+ ctrl.parents().each(function (ctrl) {
+ ctrl.fire("mouseleave", { target: ctrl.getEl() });
+ });
+
+ eventRootCtrl._lastHoverCtrl = null;
+ }
+ }
+
+ function mouseEnterHandler(e) {
+ var ctrl = eventCtrl.getParentCtrl(e.target), lastCtrl = eventRootCtrl._lastHoverCtrl, idx = 0, i, parents, lastParents;
+
+ // Over on a new control
+ if (ctrl !== lastCtrl) {
+ eventRootCtrl._lastHoverCtrl = ctrl;
+
+ parents = ctrl.parents().toArray().reverse();
+ parents.push(ctrl);
+
+ if (lastCtrl) {
+ lastParents = lastCtrl.parents().toArray().reverse();
+ lastParents.push(lastCtrl);
+
+ for (idx = 0; idx < lastParents.length; idx++) {
+ if (parents[idx] !== lastParents[idx]) {
+ break;
+ }
+ }
+
+ for (i = lastParents.length - 1; i >= idx; i--) {
+ lastCtrl = lastParents[i];
+ lastCtrl.fire("mouseleave", {
+ target: lastCtrl.getEl()
+ });
+ }
+ }
+
+ for (i = idx; i < parents.length; i++) {
+ ctrl = parents[i];
+ ctrl.fire("mouseenter", {
+ target: ctrl.getEl()
+ });
+ }
+ }
+ }
+
+ function fixWheelEvent(e) {
+ e.preventDefault();
+
+ if (e.type == "mousewheel") {
+ e.deltaY = -1 / 40 * e.wheelDelta;
+
+ if (e.wheelDeltaX) {
+ e.deltaX = -1 / 40 * e.wheelDeltaX;
+ }
+ } else {
+ e.deltaX = 0;
+ e.deltaY = e.detail;
+ }
+
+ e = eventCtrl.fire("wheel", e);
+ }
+
+ nativeEvents = eventCtrl._nativeEvents;
+ if (nativeEvents) {
+ // Find event root element if it exists
+ parents = eventCtrl.parents().toArray();
+ parents.unshift(eventCtrl);
+ for (i = 0, l = parents.length; !eventRootCtrl && i < l; i++) {
+ eventRootCtrl = parents[i]._eventsRoot;
+ }
+
+ // Event root wasn't found the use the root control
+ if (!eventRootCtrl) {
+ eventRootCtrl = parents[parents.length - 1] || eventCtrl;
+ }
+
+ // Set the eventsRoot property on children that didn't have it
+ eventCtrl._eventsRoot = eventRootCtrl;
+ for (l = i, i = 0; i < l; i++) {
+ parents[i]._eventsRoot = eventRootCtrl;
+ }
+
+ var eventRootDelegates = eventRootCtrl._delegates;
+ if (!eventRootDelegates) {
+ eventRootDelegates = eventRootCtrl._delegates = {};
+ }
+
+ // Bind native event delegates
+ for (name in nativeEvents) {
+ if (!nativeEvents) {
+ return false;
+ }
+
+ if (name === "wheel" && !hasWheelEventSupport) {
+ if (hasMouseWheelEventSupport) {
+ $(eventCtrl.getEl()).on("mousewheel", fixWheelEvent);
+ } else {
+ $(eventCtrl.getEl()).on("DOMMouseScroll", fixWheelEvent);
+ }
+
+ continue;
+ }
+
+ // Special treatment for mousenter/mouseleave since these doesn't bubble
+ if (name === "mouseenter" || name === "mouseleave") {
+ // Fake mousenter/mouseleave
+ if (!eventRootCtrl._hasMouseEnter) {
+ $(eventRootCtrl.getEl()).on("mouseleave", mouseLeaveHandler).on("mouseover", mouseEnterHandler);
+ eventRootCtrl._hasMouseEnter = 1;
+ }
+ } else if (!eventRootDelegates[name]) {
+ $(eventRootCtrl.getEl()).on(name, delegate);
+ eventRootDelegates[name] = true;
+ }
+
+ // Remove the event once it's bound
+ nativeEvents[name] = false;
+ }
+ }
+ }
+
+ return Control;
+ }
+);
+
+/**
+ * Factory.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 factory for control instances. This enables you
+ * to create instances of controls without having to require the UI controls directly.
+ *
+ * It also allow you to override or add new control types.
+ *
+ * @class tinymce.ui.Factory
+ */
+define(
+ 'tinymce.core.ui.Factory',
+ [
+ ],
+ function () {
+ "use strict";
+
+ var types = {};
+
+ return {
+ /**
+ * Adds a new control instance type to the factory.
+ *
+ * @method add
+ * @param {String} type Type name for example "button".
+ * @param {function} typeClass Class type function.
+ */
+ add: function (type, typeClass) {
+ types[type.toLowerCase()] = typeClass;
+ },
+
+ /**
+ * Returns true/false if the specified type exists or not.
+ *
+ * @method has
+ * @param {String} type Type to look for.
+ * @return {Boolean} true/false if the control by name exists.
+ */
+ has: function (type) {
+ return !!types[type.toLowerCase()];
+ },
+
+ /**
+ * Creates a new control instance based on the settings provided. The instance created will be
+ * based on the specified type property it can also create whole structures of components out of
+ * the specified JSON object.
+ *
+ * @example
+ * tinymce.ui.Factory.create({
+ * type: 'button',
+ * text: 'Hello world!'
+ * });
+ *
+ * @method create
+ * @param {Object/String} settings Name/Value object with items used to create the type.
+ * @return {tinymce.ui.Control} Control instance based on the specified type.
+ */
+ create: function (type, settings) {
+ var ControlType;
+
+ // If string is specified then use it as the type
+ if (typeof type == 'string') {
+ settings = settings || {};
+ settings.type = type;
+ } else {
+ settings = type;
+ type = settings.type;
+ }
+
+ // Find control type
+ type = type.toLowerCase();
+ ControlType = types[type];
+
+ // #if debug
+
+ if (!ControlType) {
+ throw new Error("Could not find control by type: " + type);
+ }
+
+ // #endif
+
+ ControlType = new ControlType(settings);
+ ControlType.type = type; // Set the type on the instance, this will be used by the Selector engine
+
+ return ControlType;
+ }
+ };
+ }
+);
+/**
+ * KeyboardNavigation.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 keyboard navigation of controls and elements.
+ *
+ * @class tinymce.ui.KeyboardNavigation
+ */
+define(
+ 'tinymce.core.ui.KeyboardNavigation',
+ [
+ ],
+ function () {
+ "use strict";
+
+ var hasTabstopData = function (elm) {
+ return elm.getAttribute('data-mce-tabstop') ? true : false;
+ };
+
+ /**
+ * This class handles all keyboard navigation for WAI-ARIA support. Each root container
+ * gets an instance of this class.
+ *
+ * @constructor
+ */
+ return function (settings) {
+ var root = settings.root, focusedElement, focusedControl;
+
+ function isElement(node) {
+ return node && node.nodeType === 1;
+ }
+
+ try {
+ focusedElement = document.activeElement;
+ } catch (ex) {
+ // IE sometimes fails to return a proper element
+ focusedElement = document.body;
+ }
+
+ focusedControl = root.getParentCtrl(focusedElement);
+
+ /**
+ * Returns the currently focused elements wai aria role of the currently
+ * focused element or specified element.
+ *
+ * @private
+ * @param {Element} elm Optional element to get role from.
+ * @return {String} Role of specified element.
+ */
+ function getRole(elm) {
+ elm = elm || focusedElement;
+
+ if (isElement(elm)) {
+ return elm.getAttribute('role');
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the wai role of the parent element of the currently
+ * focused element or specified element.
+ *
+ * @private
+ * @param {Element} elm Optional element to get parent role from.
+ * @return {String} Role of the first parent that has a role.
+ */
+ function getParentRole(elm) {
+ var role, parent = elm || focusedElement;
+
+ while ((parent = parent.parentNode)) {
+ if ((role = getRole(parent))) {
+ return role;
+ }
+ }
+ }
+
+ /**
+ * Returns a wai aria property by name for example aria-selected.
+ *
+ * @private
+ * @param {String} name Name of the aria property to get for example "disabled".
+ * @return {String} Aria property value.
+ */
+ function getAriaProp(name) {
+ var elm = focusedElement;
+
+ if (isElement(elm)) {
+ return elm.getAttribute('aria-' + name);
+ }
+ }
+
+ /**
+ * Is the element a text input element or not.
+ *
+ * @private
+ * @param {Element} elm Element to check if it's an text input element or not.
+ * @return {Boolean} True/false if the element is a text element or not.
+ */
+ function isTextInputElement(elm) {
+ var tagName = elm.tagName.toUpperCase();
+
+ // Notice: since type can be "email" etc we don't check the type
+ // So all input elements gets treated as text input elements
+ return tagName == "INPUT" || tagName == "TEXTAREA" || tagName == "SELECT";
+ }
+
+ /**
+ * Returns true/false if the specified element can be focused or not.
+ *
+ * @private
+ * @param {Element} elm DOM element to check if it can be focused or not.
+ * @return {Boolean} True/false if the element can have focus.
+ */
+ function canFocus(elm) {
+ if (isTextInputElement(elm) && !elm.hidden) {
+ return true;
+ }
+
+ if (hasTabstopData(elm)) {
+ return true;
+ }
+
+ if (/^(button|menuitem|checkbox|tab|menuitemcheckbox|option|gridcell|slider)$/.test(getRole(elm))) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns an array of focusable visible elements within the specified container element.
+ *
+ * @private
+ * @param {Element} elm DOM element to find focusable elements within.
+ * @return {Array} Array of focusable elements.
+ */
+ function getFocusElements(elm) {
+ var elements = [];
+
+ function collect(elm) {
+ if (elm.nodeType != 1 || elm.style.display == 'none' || elm.disabled) {
+ return;
+ }
+
+ if (canFocus(elm)) {
+ elements.push(elm);
+ }
+
+ for (var i = 0; i < elm.childNodes.length; i++) {
+ collect(elm.childNodes[i]);
+ }
+ }
+
+ collect(elm || root.getEl());
+
+ return elements;
+ }
+
+ /**
+ * Returns the navigation root control for the specified control. The navigation root
+ * is the control that the keyboard navigation gets scoped to for example a menubar or toolbar group.
+ * It will look for parents of the specified target control or the currently focused control if this option is omitted.
+ *
+ * @private
+ * @param {tinymce.ui.Control} targetControl Optional target control to find root of.
+ * @return {tinymce.ui.Control} Navigation root control.
+ */
+ function getNavigationRoot(targetControl) {
+ var navigationRoot, controls;
+
+ targetControl = targetControl || focusedControl;
+ controls = targetControl.parents().toArray();
+ controls.unshift(targetControl);
+
+ for (var i = 0; i < controls.length; i++) {
+ navigationRoot = controls[i];
+
+ if (navigationRoot.settings.ariaRoot) {
+ break;
+ }
+ }
+
+ return navigationRoot;
+ }
+
+ /**
+ * Focuses the first item in the specified targetControl element or the last aria index if the
+ * navigation root has the ariaRemember option enabled.
+ *
+ * @private
+ * @param {tinymce.ui.Control} targetControl Target control to focus the first item in.
+ */
+ function focusFirst(targetControl) {
+ var navigationRoot = getNavigationRoot(targetControl);
+ var focusElements = getFocusElements(navigationRoot.getEl());
+
+ if (navigationRoot.settings.ariaRemember && "lastAriaIndex" in navigationRoot) {
+ moveFocusToIndex(navigationRoot.lastAriaIndex, focusElements);
+ } else {
+ moveFocusToIndex(0, focusElements);
+ }
+ }
+
+ /**
+ * Moves the focus to the specified index within the elements list.
+ * This will scope the index to the size of the element list if it changed.
+ *
+ * @private
+ * @param {Number} idx Specified index to move to.
+ * @param {Array} elements Array with dom elements to move focus within.
+ * @return {Number} Input index or a changed index if it was out of range.
+ */
+ function moveFocusToIndex(idx, elements) {
+ if (idx < 0) {
+ idx = elements.length - 1;
+ } else if (idx >= elements.length) {
+ idx = 0;
+ }
+
+ if (elements[idx]) {
+ elements[idx].focus();
+ }
+
+ return idx;
+ }
+
+ /**
+ * Moves the focus forwards or backwards.
+ *
+ * @private
+ * @param {Number} dir Direction to move in positive means forward, negative means backwards.
+ * @param {Array} elements Optional array of elements to move within defaults to the current navigation roots elements.
+ */
+ function moveFocus(dir, elements) {
+ var idx = -1, navigationRoot = getNavigationRoot();
+
+ elements = elements || getFocusElements(navigationRoot.getEl());
+
+ for (var i = 0; i < elements.length; i++) {
+ if (elements[i] === focusedElement) {
+ idx = i;
+ }
+ }
+
+ idx += dir;
+ navigationRoot.lastAriaIndex = moveFocusToIndex(idx, elements);
+ }
+
+ /**
+ * Moves the focus to the left this is called by the left key.
+ *
+ * @private
+ */
+ function left() {
+ var parentRole = getParentRole();
+
+ if (parentRole == "tablist") {
+ moveFocus(-1, getFocusElements(focusedElement.parentNode));
+ } else if (focusedControl.parent().submenu) {
+ cancel();
+ } else {
+ moveFocus(-1);
+ }
+ }
+
+ /**
+ * Moves the focus to the right this is called by the right key.
+ *
+ * @private
+ */
+ function right() {
+ var role = getRole(), parentRole = getParentRole();
+
+ if (parentRole == "tablist") {
+ moveFocus(1, getFocusElements(focusedElement.parentNode));
+ } else if (role == "menuitem" && parentRole == "menu" && getAriaProp('haspopup')) {
+ enter();
+ } else {
+ moveFocus(1);
+ }
+ }
+
+ /**
+ * Moves the focus to the up this is called by the up key.
+ *
+ * @private
+ */
+ function up() {
+ moveFocus(-1);
+ }
+
+ /**
+ * Moves the focus to the up this is called by the down key.
+ *
+ * @private
+ */
+ function down() {
+ var role = getRole(), parentRole = getParentRole();
+
+ if (role == "menuitem" && parentRole == "menubar") {
+ enter();
+ } else if (role == "button" && getAriaProp('haspopup')) {
+ enter({ key: 'down' });
+ } else {
+ moveFocus(1);
+ }
+ }
+
+ /**
+ * Moves the focus to the next item or previous item depending on shift key.
+ *
+ * @private
+ * @param {DOMEvent} e DOM event object.
+ */
+ function tab(e) {
+ var parentRole = getParentRole();
+
+ if (parentRole == "tablist") {
+ var elm = getFocusElements(focusedControl.getEl('body'))[0];
+
+ if (elm) {
+ elm.focus();
+ }
+ } else {
+ moveFocus(e.shiftKey ? -1 : 1);
+ }
+ }
+
+ /**
+ * Calls the cancel event on the currently focused control. This is normally done using the Esc key.
+ *
+ * @private
+ */
+ function cancel() {
+ focusedControl.fire('cancel');
+ }
+
+ /**
+ * Calls the click event on the currently focused control. This is normally done using the Enter/Space keys.
+ *
+ * @private
+ * @param {Object} aria Optional aria data to pass along with the enter event.
+ */
+ function enter(aria) {
+ aria = aria || {};
+ focusedControl.fire('click', { target: focusedElement, aria: aria });
+ }
+
+ root.on('keydown', function (e) {
+ function handleNonTabOrEscEvent(e, handler) {
+ // Ignore non tab keys for text elements
+ if (isTextInputElement(focusedElement) || hasTabstopData(focusedElement)) {
+ return;
+ }
+
+ if (getRole(focusedElement) === 'slider') {
+ return;
+ }
+
+ if (handler(e) !== false) {
+ e.preventDefault();
+ }
+ }
+
+ if (e.isDefaultPrevented()) {
+ return;
+ }
+
+ switch (e.keyCode) {
+ case 37: // DOM_VK_LEFT
+ handleNonTabOrEscEvent(e, left);
+ break;
+
+ case 39: // DOM_VK_RIGHT
+ handleNonTabOrEscEvent(e, right);
+ break;
+
+ case 38: // DOM_VK_UP
+ handleNonTabOrEscEvent(e, up);
+ break;
+
+ case 40: // DOM_VK_DOWN
+ handleNonTabOrEscEvent(e, down);
+ break;
+
+ case 27: // DOM_VK_ESCAPE
+ cancel();
+ break;
+
+ case 14: // DOM_VK_ENTER
+ case 13: // DOM_VK_RETURN
+ case 32: // DOM_VK_SPACE
+ handleNonTabOrEscEvent(e, enter);
+ break;
+
+ case 9: // DOM_VK_TAB
+ if (tab(e) !== false) {
+ e.preventDefault();
+ }
+ break;
+ }
+ });
+
+ root.on('focusin', function (e) {
+ focusedElement = e.target;
+ focusedControl = e.control;
+ });
+
+ return {
+ focusFirst: focusFirst
+ };
+ };
+ }
+);
+/**
+ * Container.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
+ */
+
+/**
+ * Container control. This is extended by all controls that can have
+ * children such as panels etc. You can also use this class directly as an
+ * generic container instance. The container doesn't have any specific role or style.
+ *
+ * @-x-less Container.less
+ * @class tinymce.ui.Container
+ * @extends tinymce.ui.Control
+ */
+define(
+ 'tinymce.core.ui.Container',
+ [
+ "tinymce.core.ui.Control",
+ "tinymce.core.ui.Collection",
+ "tinymce.core.ui.Selector",
+ "tinymce.core.ui.Factory",
+ "tinymce.core.ui.KeyboardNavigation",
+ "tinymce.core.util.Tools",
+ "tinymce.core.dom.DomQuery",
+ "tinymce.core.ui.ClassList",
+ "tinymce.core.ui.ReflowQueue"
+ ],
+ function (Control, Collection, Selector, Factory, KeyboardNavigation, Tools, $, ClassList, ReflowQueue) {
+ "use strict";
+
+ var selectorCache = {};
+
+ return Control.extend({
+ /**
+ * Constructs a new control instance with the specified settings.
+ *
+ * @constructor
+ * @param {Object} settings Name/value object with settings.
+ * @setting {Array} items Items to add to container in JSON format or control instances.
+ * @setting {String} layout Layout manager by name to use.
+ * @setting {Object} defaults Default settings to apply to all items.
+ */
+ init: function (settings) {
+ var self = this;
+
+ self._super(settings);
+ settings = self.settings;
+
+ if (settings.fixed) {
+ self.state.set('fixed', true);
+ }
+
+ self._items = new Collection();
+
+ if (self.isRtl()) {
+ self.classes.add('rtl');
+ }
+
+ self.bodyClasses = new ClassList(function () {
+ if (self.state.get('rendered')) {
+ self.getEl('body').className = this.toString();
+ }
+ });
+ self.bodyClasses.prefix = self.classPrefix;
+
+ self.classes.add('container');
+ self.bodyClasses.add('container-body');
+
+ if (settings.containerCls) {
+ self.classes.add(settings.containerCls);
+ }
+
+ self._layout = Factory.create((settings.layout || '') + 'layout');
+
+ if (self.settings.items) {
+ self.add(self.settings.items);
+ } else {
+ self.add(self.render());
+ }
+
+ // TODO: Fix this!
+ self._hasBody = true;
+ },
+
+ /**
+ * Returns a collection of child items that the container currently have.
+ *
+ * @method items
+ * @return {tinymce.ui.Collection} Control collection direct child controls.
+ */
+ items: function () {
+ return this._items;
+ },
+
+ /**
+ * Find child controls by selector.
+ *
+ * @method find
+ * @param {String} selector Selector CSS pattern to find children by.
+ * @return {tinymce.ui.Collection} Control collection with child controls.
+ */
+ find: function (selector) {
+ selector = selectorCache[selector] = selectorCache[selector] || new Selector(selector);
+
+ return selector.find(this);
+ },
+
+ /**
+ * Adds one or many items to the current container. This will create instances of
+ * the object representations if needed.
+ *
+ * @method add
+ * @param {Array/Object/tinymce.ui.Control} items Array or item that will be added to the container.
+ * @return {tinymce.ui.Collection} Current collection control.
+ */
+ add: function (items) {
+ var self = this;
+
+ self.items().add(self.create(items)).parent(self);
+
+ return self;
+ },
+
+ /**
+ * Focuses the current container instance. This will look
+ * for the first control in the container and focus that.
+ *
+ * @method focus
+ * @param {Boolean} keyboard Optional true/false if the focus was a keyboard focus or not.
+ * @return {tinymce.ui.Collection} Current instance.
+ */
+ focus: function (keyboard) {
+ var self = this, focusCtrl, keyboardNav, items;
+
+ if (keyboard) {
+ keyboardNav = self.keyboardNav || self.parents().eq(-1)[0].keyboardNav;
+
+ if (keyboardNav) {
+ keyboardNav.focusFirst(self);
+ return;
+ }
+ }
+
+ items = self.find('*');
+
+ // TODO: Figure out a better way to auto focus alert dialog buttons
+ if (self.statusbar) {
+ items.add(self.statusbar.items());
+ }
+
+ items.each(function (ctrl) {
+ if (ctrl.settings.autofocus) {
+ focusCtrl = null;
+ return false;
+ }
+
+ if (ctrl.canFocus) {
+ focusCtrl = focusCtrl || ctrl;
+ }
+ });
+
+ if (focusCtrl) {
+ focusCtrl.focus();
+ }
+
+ return self;
+ },
+
+ /**
+ * Replaces the specified child control with a new control.
+ *
+ * @method replace
+ * @param {tinymce.ui.Control} oldItem Old item to be replaced.
+ * @param {tinymce.ui.Control} newItem New item to be inserted.
+ */
+ replace: function (oldItem, newItem) {
+ var ctrlElm, items = this.items(), i = items.length;
+
+ // Replace the item in collection
+ while (i--) {
+ if (items[i] === oldItem) {
+ items[i] = newItem;
+ break;
+ }
+ }
+
+ if (i >= 0) {
+ // Remove new item from DOM
+ ctrlElm = newItem.getEl();
+ if (ctrlElm) {
+ ctrlElm.parentNode.removeChild(ctrlElm);
+ }
+
+ // Remove old item from DOM
+ ctrlElm = oldItem.getEl();
+ if (ctrlElm) {
+ ctrlElm.parentNode.removeChild(ctrlElm);
+ }
+ }
+
+ // Adopt the item
+ newItem.parent(this);
+ },
+
+ /**
+ * Creates the specified items. If any of the items is plain JSON style objects
+ * it will convert these into real tinymce.ui.Control instances.
+ *
+ * @method create
+ * @param {Array} items Array of items to convert into control instances.
+ * @return {Array} Array with control instances.
+ */
+ create: function (items) {
+ var self = this, settings, ctrlItems = [];
+
+ // Non array structure, then force it into an array
+ if (!Tools.isArray(items)) {
+ items = [items];
+ }
+
+ // Add default type to each child control
+ Tools.each(items, function (item) {
+ if (item) {
+ // Construct item if needed
+ if (!(item instanceof Control)) {
+ // Name only then convert it to an object
+ if (typeof item == "string") {
+ item = { type: item };
+ }
+
+ // Create control instance based on input settings and default settings
+ settings = Tools.extend({}, self.settings.defaults, item);
+ item.type = settings.type = settings.type || item.type || self.settings.defaultType ||
+ (settings.defaults ? settings.defaults.type : null);
+ item = Factory.create(settings);
+ }
+
+ ctrlItems.push(item);
+ }
+ });
+
+ return ctrlItems;
+ },
+
+ /**
+ * Renders new control instances.
+ *
+ * @private
+ */
+ renderNew: function () {
+ var self = this;
+
+ // Render any new items
+ self.items().each(function (ctrl, index) {
+ var containerElm;
+
+ ctrl.parent(self);
+
+ if (!ctrl.state.get('rendered')) {
+ containerElm = self.getEl('body');
+
+ // Insert or append the item
+ if (containerElm.hasChildNodes() && index <= containerElm.childNodes.length - 1) {
+ $(containerElm.childNodes[index]).before(ctrl.renderHtml());
+ } else {
+ $(containerElm).append(ctrl.renderHtml());
+ }
+
+ ctrl.postRender();
+ ReflowQueue.add(ctrl);
+ }
+ });
+
+ self._layout.applyClasses(self.items().filter(':visible'));
+ self._lastRect = null;
+
+ return self;
+ },
+
+ /**
+ * Appends new instances to the current container.
+ *
+ * @method append
+ * @param {Array/tinymce.ui.Collection} items Array if controls to append.
+ * @return {tinymce.ui.Container} Current container instance.
+ */
+ append: function (items) {
+ return this.add(items).renderNew();
+ },
+
+ /**
+ * Prepends new instances to the current container.
+ *
+ * @method prepend
+ * @param {Array/tinymce.ui.Collection} items Array if controls to prepend.
+ * @return {tinymce.ui.Container} Current container instance.
+ */
+ prepend: function (items) {
+ var self = this;
+
+ self.items().set(self.create(items).concat(self.items().toArray()));
+
+ return self.renderNew();
+ },
+
+ /**
+ * Inserts an control at a specific index.
+ *
+ * @method insert
+ * @param {Array/tinymce.ui.Collection} items Array if controls to insert.
+ * @param {Number} index Index to insert controls at.
+ * @param {Boolean} [before=false] Inserts controls before the index.
+ */
+ insert: function (items, index, before) {
+ var self = this, curItems, beforeItems, afterItems;
+
+ items = self.create(items);
+ curItems = self.items();
+
+ if (!before && index < curItems.length - 1) {
+ index += 1;
+ }
+
+ if (index >= 0 && index < curItems.length) {
+ beforeItems = curItems.slice(0, index).toArray();
+ afterItems = curItems.slice(index).toArray();
+ curItems.set(beforeItems.concat(items, afterItems));
+ }
+
+ return self.renderNew();
+ },
+
+ /**
+ * Populates the form fields from the specified JSON data object.
+ *
+ * Control items in the form that matches the data will have it's value set.
+ *
+ * @method fromJSON
+ * @param {Object} data JSON data object to set control values by.
+ * @return {tinymce.ui.Container} Current form instance.
+ */
+ fromJSON: function (data) {
+ var self = this;
+
+ for (var name in data) {
+ self.find('#' + name).value(data[name]);
+ }
+
+ return self;
+ },
+
+ /**
+ * Serializes the form into a JSON object by getting all items
+ * that has a name and a value.
+ *
+ * @method toJSON
+ * @return {Object} JSON object with form data.
+ */
+ toJSON: function () {
+ var self = this, data = {};
+
+ self.find('*').each(function (ctrl) {
+ var name = ctrl.name(), value = ctrl.value();
+
+ if (name && typeof value != "undefined") {
+ data[name] = value;
+ }
+ });
+
+ return data;
+ },
+
+ /**
+ * Renders the control as a HTML string.
+ *
+ * @method renderHtml
+ * @return {String} HTML representing the control.
+ */
+ renderHtml: function () {
+ var self = this, layout = self._layout, role = this.settings.role;
+
+ self.preRender();
+ layout.preRender(self);
+
+ return (
+ '
'
+ );
+ },
+
+ postRender: function () {
+ var self = this;
+
+ Delay.setTimeout(function () {
+ self.$el.addClass(self.classPrefix + 'in');
+ });
+
+ return self._super();
+ },
+
+ bindStates: function () {
+ var self = this;
+
+ self.state.on('change:text', function (e) {
+ self.getEl().childNodes[1].innerHTML = e.value;
+ });
+ if (self.progressBar) {
+ self.progressBar.bindStates();
+ }
+ 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;
+ }
+ });
+ }
+);
+/**
+ * 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.NotificationManager',
+ [
+ "tinymce.core.ui.Notification",
+ "tinymce.core.util.Delay",
+ "tinymce.core.util.Tools"
+ ],
+ function (Notification, Delay, Tools) {
+ return function (editor) {
+ var self = this, notifications = [];
+
+ function getLastNotification() {
+ if (notifications.length) {
+ return notifications[notifications.length - 1];
+ }
+ }
+
+ self.notifications = notifications;
+
+ function resizeWindowEvent() {
+ Delay.requestAnimationFrame(function () {
+ prePositionNotifications();
+ positionNotifications();
+ });
+ }
+
+ // 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);
+ }
+ }
+
+ 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');
+ }
+ }
+ }
+ }
+
+ editor.on('remove', function () {
+ var i = notifications.length;
+
+ while (i--) {
+ notifications[i].close();
+ }
+ });
+
+ editor.on('ResizeEditor', positionNotifications);
+ editor.on('ResizeWindow', resizeWindowEvent);
+
+ /**
+ * 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) {
+ return;
+ }
+
+ var notif;
+
+ editor.editorManager.setActive(editor);
+
+ var duplicate = findDuplicateMessage(notifications, args);
+
+ if (duplicate === null) {
+ notif = new Notification(args);
+ notifications.push(notif);
+
+ //If we have a timeout value
+ if (args.timeout > 0) {
+ notif.timer = setTimeout(function () {
+ notif.close();
+ }, args.timeout);
+ }
+
+ notif.on('close', function () {
+ var i = notifications.length;
+
+ if (notif.timer) {
+ editor.getWin().clearTimeout(notif.timer);
+ }
+
+ while (i--) {
+ if (notifications[i] === notif) {
+ notifications.splice(i, 1);
+ }
+ }
+
+ positionNotifications();
+ });
+
+ notif.renderTo();
+
+ positionNotifications();
+ } else {
+ notif = duplicate;
+ }
+
+ return notif;
+ };
+
+ /**
+ * Closes the top most notification.
+ *
+ * @method close
+ */
+ self.close = function () {
+ if (getLastNotification()) {
+ getLastNotification().close();
+ }
+ };
+
+ /**
+ * Returns the currently opened notification objects.
+ *
+ * @method getNotifications
+ * @return {Array} Array of the currently opened notifications.
+ */
+ self.getNotifications = function () {
+ return notifications;
+ };
+
+ editor.on('SkinLoaded', function () {
+ var serviceMessage = editor.settings.service_message;
+
+ if (serviceMessage) {
+ editor.notificationManager.open({
+ text: serviceMessage,
+ type: 'warning',
+ timeout: 0,
+ icon: ''
+ });
+ }
+ });
+
+ /**
+ * Finds any existing notification with the same properties as the new one.
+ * Returns either the found notification or null.
+ *
+ * @param {Notification[]} notificationArray - Array of current notifications
+ * @param {type: string, } newNotification - New notification object
+ * @returns {?Notification}
+ */
+ function findDuplicateMessage(notificationArray, newNotification) {
+ if (!isPlainTextNotification(newNotification)) {
+ return null;
+ }
+
+ var filteredNotifications = Tools.grep(notificationArray, function (notification) {
+ return isSameNotification(newNotification, notification);
+ });
+
+ return filteredNotifications.length === 0 ? null : filteredNotifications[0];
+ }
+
+ /**
+ * Checks if the passed in args object has the same
+ * type and text properties as the sent in notification.
+ *
+ * @param {type: string, text: string} a - New notification args object
+ * @param {Notification} b - Old notification
+ * @returns {boolean}
+ */
+ function isSameNotification(a, b) {
+ return a.type === b.settings.type && a.text === b.settings.text;
+ }
+
+ /**
+ * Checks that the notification does not have a progressBar
+ * or timeour property.
+ *
+ * @param {Notification} notification - Notification to check
+ * @returns {boolean}
+ */
+ function isPlainTextNotification(notification) {
+ return !notification.progressBar && !notification.timeout;
+ }
+
+ //self.positionNotifications = positionNotifications;
+ };
+ }
+);
+
+/**
+ * EditorObservable.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 mixin contains the event logic for the tinymce.Editor class.
+ *
+ * @mixin tinymce.EditorObservable
+ * @extends tinymce.util.Observable
+ */
+define(
+ 'tinymce.core.EditorObservable',
+ [
+ "tinymce.core.util.Observable",
+ "tinymce.core.dom.DOMUtils",
+ "tinymce.core.util.Tools"
+ ],
+ function (Observable, DOMUtils, Tools) {
+ var DOM = DOMUtils.DOM, customEventRootDelegates;
+
+ /**
+ * Returns the event target so for the specified event. Some events fire
+ * only on document, some fire on documentElement etc. This also handles the
+ * custom event root setting where it returns that element instead of the body.
+ *
+ * @private
+ * @param {tinymce.Editor} editor Editor instance to get event target from.
+ * @param {String} eventName Name of the event for example "click".
+ * @return {Element/Document} HTML Element or document target to bind on.
+ */
+ function getEventTarget(editor, eventName) {
+ if (eventName == 'selectionchange') {
+ return editor.getDoc();
+ }
+
+ // Need to bind mousedown/mouseup etc to document not body in iframe mode
+ // Since the user might click on the HTML element not the BODY
+ if (!editor.inline && /^mouse|touch|click|contextmenu|drop|dragover|dragend/.test(eventName)) {
+ return editor.getDoc().documentElement;
+ }
+
+ // Bind to event root instead of body if it's defined
+ if (editor.settings.event_root) {
+ if (!editor.eventRoot) {
+ editor.eventRoot = DOM.select(editor.settings.event_root)[0];
+ }
+
+ return editor.eventRoot;
+ }
+
+ return editor.getBody();
+ }
+
+ /**
+ * Binds a event delegate for the specified name this delegate will fire
+ * the event to the editor dispatcher.
+ *
+ * @private
+ * @param {tinymce.Editor} editor Editor instance to get event target from.
+ * @param {String} eventName Name of the event for example "click".
+ */
+ function bindEventDelegate(editor, eventName) {
+ var eventRootElm = getEventTarget(editor, eventName), delegate;
+
+ function isListening(editor) {
+ return !editor.hidden && !editor.readonly;
+ }
+
+ if (!editor.delegates) {
+ editor.delegates = {};
+ }
+
+ if (editor.delegates[eventName]) {
+ return;
+ }
+
+ if (editor.settings.event_root) {
+ if (!customEventRootDelegates) {
+ customEventRootDelegates = {};
+ editor.editorManager.on('removeEditor', function () {
+ var name;
+
+ if (!editor.editorManager.activeEditor) {
+ if (customEventRootDelegates) {
+ for (name in customEventRootDelegates) {
+ editor.dom.unbind(getEventTarget(editor, name));
+ }
+
+ customEventRootDelegates = null;
+ }
+ }
+ });
+ }
+
+ if (customEventRootDelegates[eventName]) {
+ return;
+ }
+
+ delegate = function (e) {
+ var target = e.target, editors = editor.editorManager.editors, i = editors.length;
+
+ while (i--) {
+ var body = editors[i].getBody();
+
+ if (body === target || DOM.isChildOf(target, body)) {
+ if (isListening(editors[i])) {
+ editors[i].fire(eventName, e);
+ }
+ }
+ }
+ };
+
+ customEventRootDelegates[eventName] = delegate;
+ DOM.bind(eventRootElm, eventName, delegate);
+ } else {
+ delegate = function (e) {
+ if (isListening(editor)) {
+ editor.fire(eventName, e);
+ }
+ };
+
+ DOM.bind(eventRootElm, eventName, delegate);
+ editor.delegates[eventName] = delegate;
+ }
+ }
+
+ var EditorObservable = {
+ /**
+ * Bind any pending event delegates. This gets executed after the target body/document is created.
+ *
+ * @private
+ */
+ bindPendingEventDelegates: function () {
+ var self = this;
+
+ Tools.each(self._pendingNativeEvents, function (name) {
+ bindEventDelegate(self, name);
+ });
+ },
+
+ /**
+ * Toggles a native event on/off this is called by the EventDispatcher when
+ * the first native event handler is added and when the last native event handler is removed.
+ *
+ * @private
+ */
+ toggleNativeEvent: function (name, state) {
+ var self = this;
+
+ // Never bind focus/blur since the FocusManager fakes those
+ if (name == "focus" || name == "blur") {
+ return;
+ }
+
+ if (state) {
+ if (self.initialized) {
+ bindEventDelegate(self, name);
+ } else {
+ if (!self._pendingNativeEvents) {
+ self._pendingNativeEvents = [name];
+ } else {
+ self._pendingNativeEvents.push(name);
+ }
+ }
+ } else if (self.initialized) {
+ self.dom.unbind(getEventTarget(self, name), name, self.delegates[name]);
+ delete self.delegates[name];
+ }
+ },
+
+ /**
+ * Unbinds all native event handlers that means delegates, custom events bound using the Events API etc.
+ *
+ * @private
+ */
+ unbindAllNativeEvents: function () {
+ var self = this, name;
+
+ if (self.delegates) {
+ for (name in self.delegates) {
+ self.dom.unbind(getEventTarget(self, name), name, self.delegates[name]);
+ }
+
+ delete self.delegates;
+ }
+
+ if (!self.inline) {
+ self.getBody().onload = null;
+ self.dom.unbind(self.getWin());
+ self.dom.unbind(self.getDoc());
+ }
+
+ self.dom.unbind(self.getBody());
+ self.dom.unbind(self.getContainer());
+ }
+ };
+
+ EditorObservable = Tools.extend({}, Observable, EditorObservable);
+
+ return EditorObservable;
+ }
+);
+
+/**
+ * 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);
+/**
+ * ErrorReporter.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
+ */
+
+/**
+ * Various error reporting helper functions.
+ *
+ * @class tinymce.ErrorReporter
+ * @private
+ */
+define(
+ 'tinymce.core.ErrorReporter',
+ [
+ "tinymce.core.AddOnManager"
+ ],
+ function (AddOnManager) {
+ var PluginManager = AddOnManager.PluginManager;
+
+ var resolvePluginName = function (targetUrl, suffix) {
+ for (var name in PluginManager.urls) {
+ var matchUrl = PluginManager.urls[name] + '/plugin' + suffix + '.js';
+ if (matchUrl === targetUrl) {
+ return name;
+ }
+ }
+
+ return null;
+ };
+
+ var pluginUrlToMessage = function (editor, url) {
+ var plugin = resolvePluginName(url, editor.suffix);
+ return plugin ?
+ 'Failed to load plugin: ' + plugin + ' from url ' + url :
+ 'Failed to load plugin url: ' + url;
+ };
+
+ var displayNotification = function (editor, message) {
+ editor.notificationManager.open({
+ type: 'error',
+ text: message
+ });
+ };
+
+ var displayError = function (editor, message) {
+ if (editor._skinLoaded) {
+ displayNotification(editor, message);
+ } else {
+ editor.on('SkinLoaded', function () {
+ displayNotification(editor, message);
+ });
+ }
+ };
+
+ var uploadError = function (editor, message) {
+ displayError(editor, 'Failed to upload image: ' + message);
+ };
+
+ var pluginLoadError = function (editor, url) {
+ displayError(editor, pluginUrlToMessage(editor, url));
+ };
+
+ var contentCssError = function (editor, urls) {
+ displayError(editor, 'Failed to load content css: ' + urls[0]);
+ };
+
+ var initError = function (message) {
+ var console = window.console;
+ if (console && !window.test) { // Skip test env
+ if (console.error) {
+ console.error.apply(console, arguments);
+ } else {
+ console.log.apply(console, arguments);
+ }
+ }
+ };
+
+ return {
+ pluginLoadError: pluginLoadError,
+ uploadError: uploadError,
+ displayError: displayError,
+ contentCssError: contentCssError,
+ initError: initError
+ };
+ }
+);
+/**
+ * CaretContainerInput.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 shows the invisble block that the caret is currently in when contents is added to that block.
+ */
+define(
+ 'tinymce.core.caret.CaretContainerInput',
+ [
+ 'ephox.katamari.api.Fun',
+ 'tinymce.core.caret.CaretContainer'
+ ],
+ function (Fun, CaretContainer) {
+ var findBlockCaretContainer = function (editor) {
+ return editor.dom.select('*[data-mce-caret]')[0];
+ };
+
+ var removeIeControlRect = function (editor) {
+ editor.selection.setRng(editor.selection.getRng());
+ };
+
+ var showBlockCaretContainer = function (editor, blockCaretContainer) {
+ if (blockCaretContainer.hasAttribute('data-mce-caret')) {
+ CaretContainer.showCaretContainerBlock(blockCaretContainer);
+ removeIeControlRect(editor);
+ editor.selection.scrollIntoView(blockCaretContainer);
+ }
+ };
+
+ var handleBlockContainer = function (editor, e) {
+ var blockCaretContainer = findBlockCaretContainer(editor);
+
+ if (!blockCaretContainer) {
+ return;
+ }
+
+ if (e.type === 'compositionstart') {
+ e.preventDefault();
+ e.stopPropagation();
+ showBlockCaretContainer(blockCaretContainer);
+ return;
+ }
+
+ if (CaretContainer.hasContent(blockCaretContainer)) {
+ showBlockCaretContainer(editor, blockCaretContainer);
+ }
+ };
+
+ var setup = function (editor) {
+ editor.on('keyup compositionstart', Fun.curry(handleBlockContainer, editor));
+ };
+
+ return {
+ setup: setup
+ };
+ }
+);
+/**
+ * Uploader.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
+ */
+
+/**
+ * Upload blobs or blob infos to the specified URL or handler.
+ *
+ * @private
+ * @class tinymce.file.Uploader
+ * @example
+ * var uploader = new Uploader({
+ * url: '/upload.php',
+ * basePath: '/base/path',
+ * credentials: true,
+ * handler: function(data, success, failure) {
+ * ...
+ * }
+ * });
+ *
+ * uploader.upload(blobInfos).then(function(result) {
+ * ...
+ * });
+ */
+define(
+ 'tinymce.core.file.Uploader',
+ [
+ "tinymce.core.util.Promise",
+ "tinymce.core.util.Tools",
+ "tinymce.core.util.Fun"
+ ],
+ function (Promise, Tools, Fun) {
+ return function (uploadStatus, settings) {
+ var pendingPromises = {};
+
+ function pathJoin(path1, path2) {
+ if (path1) {
+ return path1.replace(/\/$/, '') + '/' + path2.replace(/^\//, '');
+ }
+
+ 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);
+ };
+
+ xhr.onerror = function () {
+ failure("Image upload failed due to a XHR Transport error. Code: " + xhr.status);
+ };
+
+ xhr.onload = function () {
+ var json;
+
+ if (xhr.status != 200) {
+ 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);
+ }
+
+ function noUpload() {
+ return new Promise(function (resolve) {
+ resolve([]);
+ });
+ }
+
+ function handlerSuccess(blobInfo, url) {
+ return {
+ url: url,
+ blobInfo: blobInfo,
+ status: true
+ };
+ }
+
+ function handlerFailure(blobInfo, error) {
+ return {
+ url: '',
+ blobInfo: blobInfo,
+ status: false,
+ error: error
+ };
+ }
+
+ function resolvePending(blobUri, result) {
+ Tools.each(pendingPromises[blobUri], function (resolve) {
+ resolve(result);
+ });
+
+ delete pendingPromises[blobUri];
+ }
+
+ function uploadBlobInfo(blobInfo, handler, openNotification) {
+ uploadStatus.markPending(blobInfo.blobUri());
+
+ return new Promise(function (resolve) {
+ var notification, progress;
+
+ var noop = function () {
+ };
+
+ try {
+ var closeNotification = function () {
+ if (notification) {
+ notification.close();
+ progress = noop; // Once it's closed it's closed
+ }
+ };
+
+ var success = function (url) {
+ closeNotification();
+ uploadStatus.markUploaded(blobInfo.blobUri(), url);
+ resolvePending(blobInfo.blobUri(), handlerSuccess(blobInfo, url));
+ resolve(handlerSuccess(blobInfo, url));
+ };
+
+ var failure = function (error) {
+ closeNotification();
+ uploadStatus.removeFailed(blobInfo.blobUri());
+ resolvePending(blobInfo.blobUri(), handlerFailure(blobInfo, error));
+ resolve(handlerFailure(blobInfo, error));
+ };
+
+ progress = function (percent) {
+ if (percent < 0 || percent > 100) {
+ return;
+ }
+
+ if (!notification) {
+ notification = openNotification();
+ }
+
+ notification.progressBar.value(percent);
+ };
+
+ handler(blobInfo, success, failure, progress);
+ } catch (ex) {
+ resolve(handlerFailure(blobInfo, ex.message));
+ }
+ });
+ }
+
+ function isDefaultHandler(handler) {
+ return handler === defaultHandler;
+ }
+
+ function pendingUploadBlobInfo(blobInfo) {
+ var blobUri = blobInfo.blobUri();
+
+ return new Promise(function (resolve) {
+ pendingPromises[blobUri] = pendingPromises[blobUri] || [];
+ pendingPromises[blobUri].push(resolve);
+ });
+ }
+
+ function uploadBlobs(blobInfos, openNotification) {
+ blobInfos = Tools.grep(blobInfos, function (blobInfo) {
+ return !uploadStatus.isUploaded(blobInfo.blobUri());
+ });
+
+ return Promise.all(Tools.map(blobInfos, function (blobInfo) {
+ return uploadStatus.isPending(blobInfo.blobUri()) ?
+ pendingUploadBlobInfo(blobInfo) : uploadBlobInfo(blobInfo, settings.handler, openNotification);
+ }));
+ }
+
+ function upload(blobInfos, openNotification) {
+ return (!settings.url && isDefaultHandler(settings.handler)) ? noUpload() : uploadBlobs(blobInfos, openNotification);
+ }
+
+ settings = Tools.extend({
+ credentials: false,
+ // We are adding a notify argument to this (at the moment, until it doesn't work)
+ handler: defaultHandler
+ }, settings);
+
+ return {
+ upload: upload
+ };
+ };
+ }
+);
+/**
+ * Conversions.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
+ */
+
+/**
+ * Converts blob/uris back and forth.
+ *
+ * @private
+ * @class tinymce.file.Conversions
+ */
+define(
+ 'tinymce.core.file.Conversions',
+ [
+ "tinymce.core.util.Promise"
+ ],
+ function (Promise) {
+ function blobUriToBlob(url) {
+ return new Promise(function (resolve, reject) {
+
+ var rejectWithError = function () {
+ reject("Cannot convert " + url + " to Blob. Resource might not exist or is inaccessible.");
+ };
+
+ try {
+ var xhr = new XMLHttpRequest();
+
+ xhr.open('GET', url, true);
+ xhr.responseType = 'blob';
+
+ xhr.onload = function () {
+ if (this.status == 200) {
+ resolve(this.response);
+ } else {
+ // IE11 makes it into onload but responds with status 500
+ rejectWithError();
+ }
+ };
+
+ // Chrome fires an error event instead of the exception
+ // Also there seems to be no way to intercept the message that is logged to the console
+ xhr.onerror = rejectWithError;
+
+ xhr.send();
+ } catch (ex) {
+ rejectWithError();
+ }
+ });
+ }
+
+ function parseDataUri(uri) {
+ var type, matches;
+
+ uri = decodeURIComponent(uri).split(',');
+
+ matches = /data:([^;]+)/.exec(uri[0]);
+ if (matches) {
+ type = matches[1];
+ }
+
+ return {
+ type: type,
+ data: uri[1]
+ };
+ }
+
+ function dataUriToBlob(uri) {
+ return new Promise(function (resolve) {
+ var str, arr, i;
+
+ uri = parseDataUri(uri);
+
+ // Might throw error if data isn't proper base64
+ try {
+ str = atob(uri.data);
+ } catch (e) {
+ resolve(new Blob([]));
+ return;
+ }
+
+ arr = new Uint8Array(str.length);
+
+ for (i = 0; i < arr.length; i++) {
+ arr[i] = str.charCodeAt(i);
+ }
+
+ resolve(new Blob([arr], { type: uri.type }));
+ });
+ }
+
+ function uriToBlob(url) {
+ if (url.indexOf('blob:') === 0) {
+ return blobUriToBlob(url);
+ }
+
+ if (url.indexOf('data:') === 0) {
+ return dataUriToBlob(url);
+ }
+
+ return null;
+ }
+
+ function blobToDataUri(blob) {
+ return new Promise(function (resolve) {
+ var reader = new FileReader();
+
+ reader.onloadend = function () {
+ resolve(reader.result);
+ };
+
+ reader.readAsDataURL(blob);
+ });
+ }
+
+ return {
+ uriToBlob: uriToBlob,
+ blobToDataUri: blobToDataUri,
+ parseDataUri: parseDataUri
+ };
+ }
+);
+/**
+ * ImageScanner.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
+ */
+
+/**
+ * Finds images with data uris or blob uris. If data uris are found it will convert them into blob uris.
+ *
+ * @private
+ * @class tinymce.file.ImageScanner
+ */
+define(
+ 'tinymce.core.file.ImageScanner',
+ [
+ "tinymce.core.util.Promise",
+ "tinymce.core.util.Arr",
+ "tinymce.core.util.Fun",
+ "tinymce.core.file.Conversions",
+ "tinymce.core.Env"
+ ],
+ function (Promise, Arr, Fun, Conversions, Env) {
+ var count = 0;
+
+ var uniqueId = function (prefix) {
+ return (prefix || 'blobid') + (count++);
+ };
+
+ return function (uploadStatus, blobCache) {
+ var cachedPromises = {};
+
+ function findAll(elm, predicate) {
+ var images, promises;
+
+ function imageToBlobInfo(img, resolve, reject) {
+ var base64, blobInfo;
+
+ if (img.src.indexOf('blob:') === 0) {
+ blobInfo = blobCache.getByUri(img.src);
+
+ if (blobInfo) {
+ resolve({
+ image: img,
+ blobInfo: blobInfo
+ });
+ } else {
+ Conversions.uriToBlob(img.src).then(function (blob) {
+ Conversions.blobToDataUri(blob).then(function (dataUri) {
+ base64 = Conversions.parseDataUri(dataUri).data;
+ blobInfo = blobCache.create(uniqueId(), blob, base64);
+ blobCache.add(blobInfo);
+
+ resolve({
+ image: img,
+ blobInfo: blobInfo
+ });
+ });
+ }, function (err) {
+ reject(err);
+ });
+ }
+
+ return;
+ }
+
+ base64 = Conversions.parseDataUri(img.src).data;
+ blobInfo = blobCache.findFirst(function (cachedBlobInfo) {
+ return cachedBlobInfo.base64() === base64;
+ });
+
+ if (blobInfo) {
+ resolve({
+ image: img,
+ blobInfo: blobInfo
+ });
+ } else {
+ Conversions.uriToBlob(img.src).then(function (blob) {
+ blobInfo = blobCache.create(uniqueId(), blob, base64);
+ blobCache.add(blobInfo);
+
+ resolve({
+ image: img,
+ blobInfo: blobInfo
+ });
+ }, function (err) {
+ reject(err);
+ });
+ }
+ }
+
+ if (!predicate) {
+ predicate = Fun.constant(true);
+ }
+
+ images = Arr.filter(elm.getElementsByTagName('img'), function (img) {
+ var src = img.src;
+
+ if (!Env.fileApi) {
+ return false;
+ }
+
+ if (img.hasAttribute('data-mce-bogus')) {
+ return false;
+ }
+
+ if (img.hasAttribute('data-mce-placeholder')) {
+ return false;
+ }
+
+ if (!src || src == Env.transparentSrc) {
+ return false;
+ }
+
+ if (src.indexOf('blob:') === 0) {
+ return !uploadStatus.isUploaded(src);
+ }
+
+ if (src.indexOf('data:') === 0) {
+ return predicate(img);
+ }
+
+ return false;
+ });
+
+ promises = Arr.map(images, function (img) {
+ var newPromise;
+
+ if (cachedPromises[img.src]) {
+ // Since the cached promise will return the cached image
+ // We need to wrap it and resolve with the actual image
+ return new Promise(function (resolve) {
+ cachedPromises[img.src].then(function (imageInfo) {
+ if (typeof imageInfo === 'string') { // error apparently
+ return imageInfo;
+ }
+ resolve({
+ image: img,
+ blobInfo: imageInfo.blobInfo
+ });
+ });
+ });
+ }
+
+ newPromise = new Promise(function (resolve, reject) {
+ imageToBlobInfo(img, resolve, reject);
+ }).then(function (result) {
+ delete cachedPromises[result.image.src];
+ return result;
+ })['catch'](function (error) {
+ delete cachedPromises[img.src];
+ return error;
+ });
+
+ cachedPromises[img.src] = newPromise;
+
+ return newPromise;
+ });
+
+ return Promise.all(promises);
+ }
+
+ return {
+ findAll: findAll
+ };
+ };
+ }
+);
+/**
+ * Uuid.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
+ */
+
+/**
+ * Generates unique ids.
+ *
+ * @class tinymce.util.Uuid
+ * @private
+ */
+define(
+ 'tinymce.core.util.Uuid',
+ [
+ ],
+ function () {
+ var count = 0;
+
+ var seed = function () {
+ var rnd = function () {
+ return Math.round(Math.random() * 0xFFFFFFFF).toString(36);
+ };
+
+ var now = new Date().getTime();
+ return 's' + now.toString(36) + rnd() + rnd() + rnd();
+ };
+
+ var uuid = function (prefix) {
+ return prefix + (count++) + seed();
+ };
+
+ return {
+ uuid: uuid
+ };
+ }
+);
+
+defineGlobal("global!URL", URL);
+/**
+ * BlobCache.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
+ */
+
+/**
+ * Hold blob info objects where a blob has extra internal information.
+ *
+ * @private
+ * @class tinymce.file.BlobCache
+ */
+define(
+ 'tinymce.core.file.BlobCache',
+ [
+ 'tinymce.core.util.Arr',
+ 'tinymce.core.util.Fun',
+ 'tinymce.core.util.Uuid',
+ 'global!URL'
+ ],
+ function (Arr, Fun, Uuid, URL) {
+ return function () {
+ var cache = [], constant = Fun.constant;
+
+ function mimeToExt(mime) {
+ var mimes = {
+ 'image/jpeg': 'jpg',
+ 'image/jpg': 'jpg',
+ 'image/gif': 'gif',
+ 'image/png': 'png'
+ };
+
+ return mimes[mime.toLowerCase()] || 'dat';
+ }
+
+ function create(o, blob, base64, filename) {
+ return typeof o === 'object' ? toBlobInfo(o) : toBlobInfo({
+ id: o,
+ name: filename,
+ blob: blob,
+ base64: base64
+ });
+ }
+
+ function toBlobInfo(o) {
+ var id, name;
+
+ if (!o.blob || !o.base64) {
+ throw "blob and base64 representations of the image are required for BlobInfo to be created";
+ }
+
+ id = o.id || Uuid.uuid('blobid');
+ name = o.name || id;
+
+ return {
+ id: constant(id),
+ name: constant(name),
+ filename: constant(name + '.' + mimeToExt(o.blob.type)),
+ blob: constant(o.blob),
+ base64: constant(o.base64),
+ blobUri: constant(o.blobUri || URL.createObjectURL(o.blob)),
+ uri: constant(o.uri)
+ };
+ }
+
+ function add(blobInfo) {
+ if (!get(blobInfo.id())) {
+ cache.push(blobInfo);
+ }
+ }
+
+ function get(id) {
+ return findFirst(function (cachedBlobInfo) {
+ return cachedBlobInfo.id() === id;
+ });
+ }
+
+ function findFirst(predicate) {
+ return Arr.filter(cache, predicate)[0];
+ }
+
+ function getByUri(blobUri) {
+ return findFirst(function (blobInfo) {
+ return blobInfo.blobUri() == blobUri;
+ });
+ }
+
+ function removeByUri(blobUri) {
+ cache = Arr.filter(cache, function (blobInfo) {
+ if (blobInfo.blobUri() === blobUri) {
+ URL.revokeObjectURL(blobInfo.blobUri());
+ return false;
+ }
+
+ return true;
+ });
+ }
+
+ function destroy() {
+ Arr.each(cache, function (cachedBlobInfo) {
+ URL.revokeObjectURL(cachedBlobInfo.blobUri());
+ });
+
+ cache = [];
+ }
+
+ return {
+ create: create,
+ add: add,
+ get: get,
+ getByUri: getByUri,
+ findFirst: findFirst,
+ removeByUri: removeByUri,
+ destroy: destroy
+ };
+ };
+ }
+);
+/**
+ * UploadStatus.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
+ */
+
+/**
+ * Holds the current status of a blob uri, if it's pending or uploaded and what the result urls was.
+ *
+ * @private
+ * @class tinymce.file.UploadStatus
+ */
+define(
+ 'tinymce.core.file.UploadStatus',
+ [
+ ],
+ function () {
+ return function () {
+ var PENDING = 1, UPLOADED = 2;
+ var blobUriStatuses = {};
+
+ function createStatus(status, resultUri) {
+ return {
+ status: status,
+ resultUri: resultUri
+ };
+ }
+
+ function hasBlobUri(blobUri) {
+ return blobUri in blobUriStatuses;
+ }
+
+ function getResultUri(blobUri) {
+ var result = blobUriStatuses[blobUri];
+
+ return result ? result.resultUri : null;
+ }
+
+ function isPending(blobUri) {
+ return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === PENDING : false;
+ }
+
+ function isUploaded(blobUri) {
+ return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === UPLOADED : false;
+ }
+
+ function markPending(blobUri) {
+ blobUriStatuses[blobUri] = createStatus(PENDING, null);
+ }
+
+ function markUploaded(blobUri, resultUri) {
+ blobUriStatuses[blobUri] = createStatus(UPLOADED, resultUri);
+ }
+
+ function removeFailed(blobUri) {
+ delete blobUriStatuses[blobUri];
+ }
+
+ function destroy() {
+ blobUriStatuses = {};
+ }
+
+ return {
+ hasBlobUri: hasBlobUri,
+ getResultUri: getResultUri,
+ isPending: isPending,
+ isUploaded: isUploaded,
+ markPending: markPending,
+ markUploaded: markUploaded,
+ removeFailed: removeFailed,
+ destroy: destroy
+ };
+ };
+ }
+);
+/**
+ * EditorUpload.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 image uploads, updates undo stack and patches over various internal functions.
+ *
+ * @private
+ * @class tinymce.EditorUpload
+ */
+define(
+ 'tinymce.core.EditorUpload',
+ [
+ "tinymce.core.util.Arr",
+ "tinymce.core.file.Uploader",
+ "tinymce.core.file.ImageScanner",
+ "tinymce.core.file.BlobCache",
+ "tinymce.core.file.UploadStatus",
+ "tinymce.core.ErrorReporter"
+ ],
+ function (Arr, Uploader, ImageScanner, BlobCache, UploadStatus, ErrorReporter) {
+ return function (editor) {
+ var blobCache = new BlobCache(), uploader, imageScanner, settings = editor.settings;
+ var uploadStatus = new UploadStatus();
+
+ function aliveGuard(callback) {
+ return function (result) {
+ if (editor.selection) {
+ return callback(result);
+ }
+
+ return [];
+ };
+ }
+
+ function cacheInvalidator() {
+ return '?' + (new Date()).getTime();
+ }
+
+ // Replaces strings without regexps to avoid FF regexp to big issue
+ function replaceString(content, search, replace) {
+ var index = 0;
+
+ do {
+ index = content.indexOf(search, index);
+
+ if (index !== -1) {
+ content = content.substring(0, index) + replace + content.substr(index + search.length);
+ index += replace.length - search.length + 1;
+ }
+ } while (index !== -1);
+
+ return content;
+ }
+
+ function replaceImageUrl(content, targetUrl, replacementUrl) {
+ content = replaceString(content, 'src="' + targetUrl + '"', 'src="' + replacementUrl + '"');
+ content = replaceString(content, 'data-mce-src="' + targetUrl + '"', 'data-mce-src="' + replacementUrl + '"');
+
+ return content;
+ }
+
+ function replaceUrlInUndoStack(targetUrl, replacementUrl) {
+ Arr.each(editor.undoManager.data, function (level) {
+ if (level.type === 'fragmented') {
+ level.fragments = Arr.map(level.fragments, function (fragment) {
+ return replaceImageUrl(fragment, targetUrl, replacementUrl);
+ });
+ } else {
+ level.content = replaceImageUrl(level.content, targetUrl, replacementUrl);
+ }
+ });
+ }
+
+ function openNotification() {
+ return editor.notificationManager.open({
+ text: editor.translate('Image uploading...'),
+ type: 'info',
+ timeout: -1,
+ progressBar: true
+ });
+ }
+
+ function replaceImageUri(image, resultUri) {
+ blobCache.removeByUri(image.src);
+ replaceUrlInUndoStack(image.src, resultUri);
+
+ editor.$(image).attr({
+ src: settings.images_reuse_filename ? resultUri + cacheInvalidator() : resultUri,
+ 'data-mce-src': editor.convertURL(resultUri, 'src')
+ });
+ }
+
+ function uploadImages(callback) {
+ if (!uploader) {
+ uploader = new Uploader(uploadStatus, {
+ url: settings.images_upload_url,
+ basePath: settings.images_upload_base_path,
+ credentials: settings.images_upload_credentials,
+ handler: settings.images_upload_handler
+ });
+ }
+
+ return scanForImages().then(aliveGuard(function (imageInfos) {
+ var blobInfos;
+
+ blobInfos = Arr.map(imageInfos, function (imageInfo) {
+ return imageInfo.blobInfo;
+ });
+
+ return uploader.upload(blobInfos, openNotification).then(aliveGuard(function (result) {
+ var filteredResult = Arr.map(result, function (uploadInfo, index) {
+ var image = imageInfos[index].image;
+
+ if (uploadInfo.status && editor.settings.images_replace_blob_uris !== false) {
+ replaceImageUri(image, uploadInfo.url);
+ } else if (uploadInfo.error) {
+ ErrorReporter.uploadError(editor, uploadInfo.error);
+ }
+
+ return {
+ element: image,
+ status: uploadInfo.status
+ };
+ });
+
+ if (callback) {
+ callback(filteredResult);
+ }
+
+ return filteredResult;
+ }));
+ }));
+ }
+
+ function uploadImagesAuto(callback) {
+ if (settings.automatic_uploads !== false) {
+ return uploadImages(callback);
+ }
+ }
+
+ function isValidDataUriImage(imgElm) {
+ return settings.images_dataimg_filter ? settings.images_dataimg_filter(imgElm) : true;
+ }
+
+ function scanForImages() {
+ if (!imageScanner) {
+ imageScanner = new ImageScanner(uploadStatus, blobCache);
+ }
+
+ return imageScanner.findAll(editor.getBody(), isValidDataUriImage).then(aliveGuard(function (result) {
+ result = Arr.filter(result, function (resultItem) {
+ // ImageScanner internally converts images that it finds, but it may fail to do so if image source is inaccessible.
+ // In such case resultItem will contain appropriate text error message, instead of image data.
+ if (typeof resultItem === 'string') {
+ ErrorReporter.displayError(editor, resultItem);
+ return false;
+ }
+ return true;
+ });
+
+ Arr.each(result, function (resultItem) {
+ replaceUrlInUndoStack(resultItem.image.src, resultItem.blobInfo.blobUri());
+ resultItem.image.src = resultItem.blobInfo.blobUri();
+ resultItem.image.removeAttribute('data-mce-src');
+ });
+
+ return result;
+ }));
+ }
+
+ function destroy() {
+ blobCache.destroy();
+ uploadStatus.destroy();
+ imageScanner = uploader = null;
+ }
+
+ function replaceBlobUris(content) {
+ return content.replace(/src="(blob:[^"]+)"/g, function (match, blobUri) {
+ var resultUri = uploadStatus.getResultUri(blobUri);
+
+ if (resultUri) {
+ return 'src="' + resultUri + '"';
+ }
+
+ var blobInfo = blobCache.getByUri(blobUri);
+
+ if (!blobInfo) {
+ blobInfo = Arr.reduce(editor.editorManager.editors, function (result, editor) {
+ return result || editor.editorUpload && editor.editorUpload.blobCache.getByUri(blobUri);
+ }, null);
+ }
+
+ if (blobInfo) {
+ return 'src="data:' + blobInfo.blob().type + ';base64,' + blobInfo.base64() + '"';
+ }
+
+ return match;
+ });
+ }
+
+ editor.on('setContent', function () {
+ if (editor.settings.automatic_uploads !== false) {
+ uploadImagesAuto();
+ } else {
+ scanForImages();
+ }
+ });
+
+ editor.on('RawSaveContent', function (e) {
+ e.content = replaceBlobUris(e.content);
+ });
+
+ editor.on('getContent', function (e) {
+ if (e.source_view || e.format == 'raw') {
+ return;
+ }
+
+ e.content = replaceBlobUris(e.content);
+ });
+
+ editor.on('PostRender', function () {
+ editor.parser.addNodeFilter('img', function (images) {
+ Arr.each(images, function (img) {
+ var src = img.attr('src');
+
+ if (blobCache.getByUri(src)) {
+ return;
+ }
+
+ var resultUri = uploadStatus.getResultUri(src);
+ if (resultUri) {
+ img.attr('src', resultUri);
+ }
+ });
+ });
+ });
+
+ return {
+ blobCache: blobCache,
+ uploadImages: uploadImages,
+ uploadImagesAuto: uploadImagesAuto,
+ scanForImages: scanForImages,
+ destroy: destroy
+ };
+ };
+ }
+);
+/**
+ * ForceBlocks.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
+ */
+
+/**
+ * Makes sure that everything gets wrapped in paragraphs.
+ *
+ * @private
+ * @class tinymce.ForceBlocks
+ */
+define(
+ 'tinymce.core.ForceBlocks',
+ [
+ 'ephox.katamari.api.Fun'
+ ],
+ function (Fun) {
+ var addRootBlocks = function (editor) {
+ var settings = editor.settings, dom = editor.dom, selection = editor.selection;
+ var schema = editor.schema, blockElements = schema.getBlockElements();
+ var node = selection.getStart(), rootNode = editor.getBody(), rng;
+ var startContainer, startOffset, endContainer, endOffset, rootBlockNode;
+ var tempNode, offset = -0xFFFFFF, wrapped, restoreSelection;
+ var tmpRng, rootNodeName, forcedRootBlock;
+
+ forcedRootBlock = settings.forced_root_block;
+
+ if (!node || node.nodeType !== 1 || !forcedRootBlock) {
+ return;
+ }
+
+ // Check if node is wrapped in block
+ while (node && node !== rootNode) {
+ if (blockElements[node.nodeName]) {
+ return;
+ }
+
+ node = node.parentNode;
+ }
+
+ // Get current selection
+ rng = selection.getRng();
+ if (rng.setStart) {
+ startContainer = rng.startContainer;
+ startOffset = rng.startOffset;
+ endContainer = rng.endContainer;
+ endOffset = rng.endOffset;
+
+ try {
+ restoreSelection = editor.getDoc().activeElement === rootNode;
+ } catch (ex) {
+ // IE throws unspecified error here sometimes
+ }
+ } else {
+ // Force control range into text range
+ if (rng.item) {
+ node = rng.item(0);
+ rng = editor.getDoc().body.createTextRange();
+ rng.moveToElementText(node);
+ }
+
+ restoreSelection = rng.parentElement().ownerDocument === editor.getDoc();
+ tmpRng = rng.duplicate();
+ tmpRng.collapse(true);
+ startOffset = tmpRng.move('character', offset) * -1;
+
+ if (!tmpRng.collapsed) {
+ tmpRng = rng.duplicate();
+ tmpRng.collapse(false);
+ endOffset = (tmpRng.move('character', offset) * -1) - startOffset;
+ }
+ }
+
+ // Wrap non block elements and text nodes
+ node = rootNode.firstChild;
+ rootNodeName = rootNode.nodeName.toLowerCase();
+ while (node) {
+ // TODO: Break this up, too complex
+ if (((node.nodeType === 3 || (node.nodeType == 1 && !blockElements[node.nodeName]))) &&
+ schema.isValidChild(rootNodeName, forcedRootBlock.toLowerCase())) {
+ // Remove empty text nodes
+ if (node.nodeType === 3 && node.nodeValue.length === 0) {
+ tempNode = node;
+ node = node.nextSibling;
+ dom.remove(tempNode);
+ continue;
+ }
+
+ if (!rootBlockNode) {
+ rootBlockNode = dom.create(forcedRootBlock, editor.settings.forced_root_block_attrs);
+ node.parentNode.insertBefore(rootBlockNode, node);
+ wrapped = true;
+ }
+
+ tempNode = node;
+ node = node.nextSibling;
+ rootBlockNode.appendChild(tempNode);
+ } else {
+ rootBlockNode = null;
+ node = node.nextSibling;
+ }
+ }
+
+ if (wrapped && restoreSelection) {
+ if (rng.setStart) {
+ rng.setStart(startContainer, startOffset);
+ rng.setEnd(endContainer, endOffset);
+ selection.setRng(rng);
+ } else {
+ // Only select if the previous selection was inside the document to prevent auto focus in quirks mode
+ try {
+ rng = editor.getDoc().body.createTextRange();
+ rng.moveToElementText(rootNode);
+ rng.collapse(true);
+ rng.moveStart('character', startOffset);
+
+ if (endOffset > 0) {
+ rng.moveEnd('character', endOffset);
+ }
+
+ rng.select();
+ } catch (ex) {
+ // Ignore
+ }
+ }
+
+ editor.nodeChanged();
+ }
+ };
+
+ var setup = function (editor) {
+ if (editor.settings.forced_root_block) {
+ editor.on('NodeChange', Fun.curry(addRootBlocks, editor));
+ }
+ };
+
+ return {
+ setup: setup
+ };
+ }
+);
+define(
+ 'ephox.katamari.api.Merger',
+
+ [
+ 'ephox.katamari.api.Type',
+ 'global!Array',
+ 'global!Error'
+ ],
+
+ function (Type, Array, Error) {
+
+ var shallow = function (old, nu) {
+ return nu;
+ };
+
+ var deep = function (old, nu) {
+ var bothObjects = Type.isObject(old) && Type.isObject(nu);
+ return bothObjects ? deepMerge(old, nu) : nu;
+ };
+
+ var baseMerge = function (merger) {
+ return function() {
+ // Don't use array slice(arguments), makes the whole function unoptimisable on Chrome
+ var objects = new Array(arguments.length);
+ for (var i = 0; i < objects.length; i++) objects[i] = arguments[i];
+
+ if (objects.length === 0) throw new Error('Can\'t merge zero objects');
+
+ var ret = {};
+ for (var j = 0; j < objects.length; j++) {
+ var curObject = objects[j];
+ for (var key in curObject) if (curObject.hasOwnProperty(key)) {
+ ret[key] = merger(ret[key], curObject[key]);
+ }
+ }
+ return ret;
+ };
+ };
+
+ var deepMerge = baseMerge(deep);
+ var merge = baseMerge(shallow);
+
+ return {
+ deepMerge: deepMerge,
+ merge: merge
+ };
+ }
+);
+/**
+ * MatchKeys.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.MatchKeys',
+ [
+ 'ephox.katamari.api.Arr',
+ 'ephox.katamari.api.Fun',
+ 'ephox.katamari.api.Merger'
+ ],
+ function (Arr, Fun, Merger) {
+ var defaultPatterns = function (patterns) {
+ return Arr.map(patterns, function (pattern) {
+ return Merger.merge({
+ shiftKey: false,
+ altKey: false,
+ ctrlKey: false,
+ metaKey: false,
+ keyCode: 0,
+ action: Fun.noop
+ }, pattern);
+ });
+ };
+
+ var matchesEvent = function (pattern, evt) {
+ return (
+ evt.keyCode === pattern.keyCode &&
+ evt.shiftKey === pattern.shiftKey &&
+ evt.altKey === pattern.altKey &&
+ evt.ctrlKey === pattern.ctrlKey &&
+ evt.metaKey === pattern.metaKey
+ );
+ };
+
+ var match = function (patterns, evt) {
+ return Arr.bind(defaultPatterns(patterns), function (pattern) {
+ return matchesEvent(pattern, evt) ? [pattern] : [ ];
+ });
+ };
+
+ var action = function (f) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ return function () {
+ return f.apply(null, args);
+ };
+ };
+
+ return {
+ match: match,
+ action: action
+ };
+ }
+);
+/**
+ * ArrowKeys.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.ArrowKeys',
+ [
+ 'ephox.katamari.api.Arr',
+ 'ephox.katamari.api.Cell',
+ 'tinymce.core.keyboard.BoundarySelection',
+ 'tinymce.core.keyboard.MatchKeys',
+ 'tinymce.core.util.VK'
+ ],
+ function (Arr, Cell, BoundarySelection, MatchKeys, VK) {
+ var setup = function (editor, caret) {
+ editor.on('keydown', function (evt) {
+ var matches = MatchKeys.match([
+ { keyCode: VK.RIGHT, action: BoundarySelection.move(editor, caret, true) },
+ { keyCode: VK.LEFT, action: BoundarySelection.move(editor, caret, false) }
+ ], evt);
+
+ Arr.find(matches, function (pattern) {
+ return pattern.action();
+ }).each(function (_) {
+ evt.preventDefault();
+ });
+ });
+ };
+
+ return {
+ setup: setup
+ };
+ }
+);
+
+/**
+ * DeleteBackspaceKeys.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.DeleteBackspaceKeys',
+ [
+ 'ephox.katamari.api.Arr',
+ 'tinymce.core.delete.BlockBoundaryDelete',
+ 'tinymce.core.delete.BlockRangeDelete',
+ 'tinymce.core.delete.CefDelete',
+ 'tinymce.core.delete.InlineBoundaryDelete',
+ 'tinymce.core.keyboard.MatchKeys',
+ 'tinymce.core.util.VK'
+ ],
+ function (Arr, BlockBoundaryDelete, BlockRangeDelete, CefDelete, BoundaryDelete, MatchKeys, VK) {
+ var setupKeyDownHandler = function (editor, caret) {
+ editor.on('keydown', function (evt) {
+ var matches = MatchKeys.match([
+ { keyCode: VK.BACKSPACE, action: MatchKeys.action(BoundaryDelete.backspaceDelete, editor, caret, false) },
+ { keyCode: VK.DELETE, action: MatchKeys.action(BoundaryDelete.backspaceDelete, editor, caret, true) },
+ { keyCode: VK.BACKSPACE, action: MatchKeys.action(CefDelete.backspaceDelete, editor, false) },
+ { keyCode: VK.DELETE, action: MatchKeys.action(CefDelete.backspaceDelete, editor, true) },
+ { keyCode: VK.BACKSPACE, action: MatchKeys.action(BlockRangeDelete.backspaceDelete, editor, false) },
+ { keyCode: VK.DELETE, action: MatchKeys.action(BlockRangeDelete.backspaceDelete, editor, true) },
+ { keyCode: VK.BACKSPACE, action: MatchKeys.action(BlockBoundaryDelete.backspaceDelete, editor, false) },
+ { keyCode: VK.DELETE, action: MatchKeys.action(BlockBoundaryDelete.backspaceDelete, editor, true) }
+ ], evt);
+
+ Arr.find(matches, function (pattern) {
+ return pattern.action();
+ }).each(function (_) {
+ evt.preventDefault();
+ });
+ });
+ };
+
+ var setupKeyUpHandler = function (editor) {
+ editor.on('keyup', function (evt) {
+ var matches = MatchKeys.match([
+ { keyCode: VK.BACKSPACE, action: MatchKeys.action(CefDelete.paddEmptyElement, editor) },
+ { keyCode: VK.DELETE, action: MatchKeys.action(CefDelete.paddEmptyElement, editor) }
+ ], evt);
+
+ Arr.find(matches, function (pattern) {
+ return pattern.action();
+ });
+ });
+ };
+
+ var setup = function (editor, caret) {
+ setupKeyDownHandler(editor, caret);
+ setupKeyUpHandler(editor);
+ };
+
+ return {
+ setup: setup
+ };
+ }
+);
+
+/**
+ * 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
+ */
+
+/**
+ * Contains logic for handling the enter key to split/generate block elements.
+ */
+define(
+ 'tinymce.core.keyboard.EnterKey',
+ [
+ 'tinymce.core.caret.CaretContainer',
+ 'tinymce.core.dom.NodeType',
+ 'tinymce.core.dom.RangeUtils',
+ 'tinymce.core.dom.TreeWalker',
+ 'tinymce.core.Env',
+ 'tinymce.core.text.Zwsp',
+ 'tinymce.core.util.Tools'
+ ],
+ function (CaretContainer, NodeType, RangeUtils, TreeWalker, Env, Zwsp, Tools) {
+ var isIE = Env.ie && Env.ie < 11;
+
+ var isEmptyAnchor = function (elm) {
+ return elm && elm.nodeName === "A" && Tools.trim(Zwsp.trim(elm.innerText || elm.textContent)).length === 0;
+ };
+
+ var isTableCell = function (node) {
+ return node && /^(TD|TH|CAPTION)$/.test(node.nodeName);
+ };
+
+ var emptyBlock = function (elm) {
+ // BR is needed in empty blocks on non IE browsers
+ elm.innerHTML = !isIE ? ' ' : '';
+ };
+
+ // Returns true if the block can be split into two blocks or not
+ var canSplitBlock = function (dom, node) {
+ return node &&
+ dom.isBlock(node) &&
+ !/^(TD|TH|CAPTION|FORM)$/.test(node.nodeName) &&
+ !/^(fixed|absolute)/i.test(node.style.position) &&
+ dom.getContentEditable(node) !== "true";
+ };
+
+ // 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);
+ }
+ };
+
+ // Remove the first empty inline element of the block so this:
x
becomes this:
x
+ var trimInlineElementsOnLeftSideOfBlock = function (dom, nonEmptyElementsMap, block) {
+ var node = block, firstChilds = [], i;
+
+ if (!node) {
+ return;
+ }
+
+ // Find inner most first child ex:
*
+ while ((node = node.firstChild)) {
+ if (dom.isBlock(node)) {
+ return;
+ }
+
+ if (node.nodeType == 1 && !nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
+ firstChilds.push(node);
+ }
+ }
+
+ i = firstChilds.length;
+ while (i--) {
+ node = firstChilds[i];
+ if (!node.hasChildNodes() || (node.firstChild == node.lastChild && node.firstChild.nodeValue === '')) {
+ dom.remove(node);
+ } else {
+ if (isEmptyAnchor(node)) {
+ dom.remove(node);
+ }
+ }
+ }
+ };
+
+ var normalizeZwspOffset = function (start, container, offset) {
+ if (NodeType.isText(container) === false) {
+ return offset;
+ } if (start) {
+ return offset === 1 && container.data.charAt(offset - 1) === Zwsp.ZWSP ? 0 : offset;
+ } else {
+ return offset === container.data.length - 1 && container.data.charAt(offset) === Zwsp.ZWSP ? container.data.length : offset;
+ }
+ };
+
+ var includeZwspInRange = function (rng) {
+ var newRng = rng.cloneRange();
+ newRng.setStart(rng.startContainer, normalizeZwspOffset(true, rng.startContainer, rng.startOffset));
+ newRng.setEnd(rng.endContainer, normalizeZwspOffset(false, rng.endContainer, rng.endOffset));
+ return newRng;
+ };
+
+ var firstNonWhiteSpaceNodeSibling = function (node) {
+ while (node) {
+ if (node.nodeType === 1 || (node.nodeType === 3 && node.data && /[\r\n\s]/.test(node.data))) {
+ return node;
+ }
+
+ node = node.nextSibling;
+ }
+ };
+
+ 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();
+
+ function handleEnterKey(evt) {
+ var rng, tmpRng, editableRoot, container, offset, parentBlock, documentMode, shiftKey,
+ newBlock, fragment, containerBlock, parentBlockName, containerBlockName, newBlockName, isAfterLastNodeInContainer;
+
+ // 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;
+
+ if (!root) {
+ return;
+ }
+
+ // Old IE versions doesn't properly render blocks with br elements in them
+ // For example
wont be rendered correctly in a contentEditable area
+ // until you remove the br producing
+ if (Env.ie && Env.ie < 9 && parentBlock && parentBlock.firstChild) {
+ if (parentBlock.firstChild == parentBlock.lastChild && parentBlock.firstChild.tagName == 'BR') {
+ dom.remove(parentBlock.firstChild);
+ }
+ }
+
+ 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);
+ }
+ }
+
+ rng = dom.createRng();
+
+ // 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();
+ }
+
+ if (root.hasChildNodes()) {
+ walker = new TreeWalker(root, root);
+
+ while ((node = walker.current())) {
+ if (node.nodeType == 3) {
+ rng.setStart(node, 0);
+ rng.setEnd(node, 0);
+ break;
+ }
+
+ if (moveCaretBeforeOnEnterElementsMap[node.nodeName.toLowerCase()]) {
+ rng.setStartBefore(node);
+ rng.setEndBefore(node);
+ break;
+ }
+
+ lastNode = node;
+ node = walker.next();
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ function setForcedBlockAttrs(node) {
+ var forcedRootBlockName = settings.forced_root_block;
+
+ if (forcedRootBlockName && forcedRootBlockName.toLowerCase() === node.tagName.toLowerCase()) {
+ dom.setAttribs(node, settings.forced_root_block_attrs);
+ }
+ }
+
+ // 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();
+
+ if (name || parentBlockName == "TABLE") {
+ block = dom.create(name || newBlockName);
+ setForcedBlockAttrs(block);
+ } else {
+ block = parentBlock.cloneNode(false);
+ }
+
+ caretNode = block;
+
+ 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;
+ }
+
+ clonedNode = node.cloneNode(false);
+ dom.setAttrib(clonedNode, 'id', ''); // Remove ID since it needs to be document unique
+
+ if (block.hasChildNodes()) {
+ clonedNode.appendChild(block.firstChild);
+ block.appendChild(clonedNode);
+ } else {
+ caretNode = clonedNode;
+ block.appendChild(clonedNode);
+ }
+ }
+ } while ((node = node.parentNode) && node != editableRoot);
+ }
+
+ // BR is needed in empty blocks on non IE browsers
+ if (!isIE) {
+ caretNode.innerHTML = ' ';
+ }
+
+ return block;
+ }
+
+ // Returns true/false if the caret is at the start/end of the parent block element
+ function isCaretAtStartOrEndOfBlock(start) {
+ var walker, node, name, normalizedOffset;
+
+ normalizedOffset = normalizeZwspOffset(start, container, offset);
+
+ // 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;
+ }
+
+ // If after the last element in block node edge case for #5091
+ if (container.parentNode == parentBlock && isAfterLastNodeInContainer && !start) {
+ return true;
+ }
+
+ // If the caret if before the first element in parentBlock
+ if (start && container.nodeType == 1 && container == parentBlock.firstChild) {
+ return true;
+ }
+
+ // Caret can be before/after a table
+ if (container.nodeName === "TABLE" || (container.previousSibling && container.previousSibling.nodeName == "TABLE")) {
+ return (isAfterLastNodeInContainer && !start) || (!isAfterLastNodeInContainer && start);
+ }
+
+ // Walk the DOM and look for text nodes or non empty elements
+ walker = new TreeWalker(container, parentBlock);
+
+ // 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();
+ }
+ }
+
+ while ((node = walker.current())) {
+ if (node.nodeType === 1) {
+ // Ignore bogus elements
+ if (!node.getAttribute('data-mce-bogus')) {
+ // Keep empty elements like but not trailing br:s like
text|
+ name = node.nodeName.toLowerCase();
+ if (nonEmptyElementsMap[name] && name !== 'br') {
+ return false;
+ }
+ }
+ } else if (node.nodeType === 3 && !/^[ \t\r\n]*$/.test(node.nodeValue)) {
+ return false;
+ }
+
+ if (start) {
+ walker.prev();
+ } else {
+ walker.next();
+ }
+ }
+
+ 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();
+ } else {
+ rootBlockName = parentBlock.parentNode.nodeName.toLowerCase();
+ }
+
+ if (!parentBlock.hasChildNodes()) {
+ newBlock = dom.create(blockName);
+ setForcedBlockAttrs(newBlock);
+ parentBlock.appendChild(newBlock);
+ rng.setStart(newBlock, 0);
+ rng.setEnd(newBlock, 0);
+ return newBlock;
+ }
+
+ // Find parent that is the first child of parentBlock
+ node = container;
+ while (node.parentNode != parentBlock) {
+ node = node.parentNode;
+ }
+
+ // Loop left to find start node start wrapping at
+ while (node && !dom.isBlock(node)) {
+ startNode = node;
+ node = node.previousSibling;
+ }
+
+ 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;
+ }
+
+ // 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'];
+
+ // Find first/last element since there might be whitespace there
+ while (node) {
+ if (node.nodeType == 1) {
+ break;
+ }
+
+ node = node[first ? 'nextSibling' : 'previousSibling'];
+ }
+
+ return node === parentBlock;
+ }
+
+ function getContainerBlock() {
+ var containerBlockParent = containerBlock.parentNode;
+
+ if (/^(LI|DT|DD)$/.test(containerBlockParent.nodeName)) {
+ return containerBlockParent;
+ }
+
+ return containerBlock;
+ }
+
+ if (containerBlock == editor.getBody()) {
+ return;
+ }
+
+ // Check if we are in an nested list
+ var containerBlockParentName = containerBlock.parentNode.nodeName;
+ if (/^(OL|UL|LI)$/.test(containerBlockParentName)) {
+ newBlockName = 'LI';
+ }
+
+ newBlock = newBlockName ? createNewBlock(newBlockName) : dom.create('BR');
+
+ 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();
+
+ if (newBlockName == 'LI' && fragment.firstChild.nodeName == 'LI') {
+ newBlock = fragment.firstChild;
+ dom.insertAfter(fragment, containerBlock);
+ } else {
+ dom.insertAfter(fragment, containerBlock);
+ dom.insertAfter(newBlock, containerBlock);
+ }
+ }
+
+ dom.remove(parentBlock);
+ moveToCaretPosition(newBlock);
+ undoManager.add();
+ }
+
+ // Inserts a BR element if the forced_root_block option is set to false or empty string
+ function insertBr() {
+ editor.execCommand("InsertLineBreak", false, evt);
+ }
+
+ // 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]+/, '');
+ }
+
+ node = node.firstChild;
+ } while (node);
+ }
+
+ 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;
+ }
+
+ parent = parent.parentNode;
+ }
+
+ return parent !== root ? editableRoot : root;
+ }
+
+ // 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;
+
+ // 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
+
+ // 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');
+ }
+ }
+ }
+
+ 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();
+ }
+
+ // 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);
+ }
+
+ moveToCaretPosition(newBlock);
+ }
+
+ rng = selection.getRng(true);
+
+ // Event is blocked by some other handler for example the lists plugin
+ if (evt.isDefaultPrevented()) {
+ return;
+ }
+
+ // Delete any selected contents
+ if (!rng.collapsed) {
+ editor.execCommand('Delete');
+ return;
+ }
+
+ // 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;
+
+ // 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;
+ }
+ }
+
+ // Get editable root node, normally the body element but sometimes a div or span
+ editableRoot = getEditableRoot(container);
+
+ // If there is no editable root then enter is done inside a contentEditable false element
+ if (!editableRoot) {
+ return;
+ }
+
+ undoManager.beforeChange();
+
+ // If editable root isn't block nor the root of the editor
+ if (!dom.isBlock(editableRoot) && editableRoot != dom.getRoot()) {
+ if (!newBlockName || shiftKey) {
+ insertBr();
+ }
+
+ return;
+ }
+
+ // Wrap the current node and it's sibling in a default block if it's needed.
+ // for example this
text|text2
will become this
text|text2
+ // This won't happen if root blocks are disabled or the shiftKey is pressed
+ if ((newBlockName && !shiftKey) || (!newBlockName && shiftKey)) {
+ container = wrapSelfAndSiblingsInDefaultBlock(container, offset);
+ }
+
+ // Find parent block and setup empty block paddings
+ parentBlock = dom.getParent(container, dom.isBlock);
+ containerBlock = parentBlock ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
+
+ // Setup block names
+ parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : ''; // IE < 9 & HTML5
+ containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : ''; // IE < 9 & HTML5
+
+ // Enter inside block contained within a LI then split or insert before/after LI
+ if (containerBlockName == 'LI' && !evt.ctrlKey) {
+ parentBlock = containerBlock;
+ parentBlockName = containerBlockName;
+ }
+
+ if (editor.undoManager.typing) {
+ editor.undoManager.typing = false;
+ editor.undoManager.add();
+ }
+
+ // Handle enter in list item
+ if (/^(LI|DT|DD)$/.test(parentBlockName)) {
+ if (!newBlockName && shiftKey) {
+ insertBr();
+ return;
+ }
+
+ // Handle enter inside an empty list item
+ if (dom.isEmpty(parentBlock)) {
+ handleEmptyListItem();
+ return;
+ }
+ }
+
+ // 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;
+ }
+ }
+
+ // If parent block is root then never insert new blocks
+ if (newBlockName && parentBlock === editor.getBody()) {
+ return;
+ }
+
+ // Default block name if it's not configured
+ newBlockName = newBlockName || 'P';
+
+ // 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()) {
+ insertNewBlockAfter();
+ } else if (isCaretAtStartOrEndOfBlock(true)) {
+ // Insert new block before
+ newBlock = parentBlock.parentNode.insertBefore(createNewBlock(), parentBlock);
+ renderBlockOnIE(dom, selection, 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(parentBlock);
+
+ if (dom.isEmpty(parentBlock)) {
+ emptyBlock(parentBlock);
+ }
+
+ newBlock.normalize();
+
+ // New block might become empty if it's
a |
+ if (dom.isEmpty(newBlock)) {
+ dom.remove(newBlock);
+ insertNewBlockAfter();
+ } else {
+ moveToCaretPosition(newBlock);
+ }
+ }
+
+ dom.setAttrib(newBlock, 'id', ''); // Remove ID since it needs to be document unique
+
+ // Allow custom handling of new blocks
+ editor.fire('NewBlock', { newBlock: newBlock });
+
+ undoManager.typing = false;
+ undoManager.add();
+ }
+
+ editor.on('keydown', function (evt) {
+ if (evt.keyCode == 13) {
+ if (handleEnterKey(evt) !== false) {
+ evt.preventDefault();
+ }
+ }
+ });
+ };
+
+ return {
+ setup: setup
+ };
+ }
+);
+
+/**
+ * InsertSpace.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.InsertSpace',
+ [
+ 'ephox.katamari.api.Fun',
+ 'tinymce.core.caret.CaretPosition',
+ 'tinymce.core.dom.NodeType',
+ 'tinymce.core.keyboard.BoundaryLocation'
+ ],
+ function (Fun, CaretPosition, NodeType, BoundaryLocation) {
+ var isValidInsertPoint = function (location, caretPosition) {
+ return isAtStartOrEnd(location) && NodeType.isText(caretPosition.container());
+ };
+
+ var insertNbspAtPosition = function (editor, caretPosition) {
+ var container = caretPosition.container();
+ var offset = caretPosition.offset();
+
+ container.insertData(offset, '\u00a0');
+ editor.selection.setCursorLocation(container, offset + 1);
+ };
+
+ var insertAtLocation = function (editor, caretPosition, location) {
+ if (isValidInsertPoint(location, caretPosition)) {
+ insertNbspAtPosition(editor, caretPosition);
+ return true;
+ } else {
+ return false;
+ }
+ };
+
+ var insertAtCaret = function (editor) {
+ var caretPosition = CaretPosition.fromRangeStart(editor.selection.getRng());
+ var boundaryLocation = BoundaryLocation.readLocation(editor.getBody(), caretPosition);
+ return boundaryLocation.map(Fun.curry(insertAtLocation, editor, caretPosition)).getOr(false);
+ };
+
+ var isAtStartOrEnd = function (location) {
+ return location.fold(
+ Fun.constant(false), // Before
+ Fun.constant(true), // Start
+ Fun.constant(true), // End
+ Fun.constant(false) // After
+ );
+ };
+
+ var insertAtSelection = function (editor) {
+ return editor.selection.isCollapsed() ? insertAtCaret(editor) : false;
+ };
+
+ return {
+ insertAtSelection: insertAtSelection
+ };
+ }
+);
+
+/**
+ * SpaceKey.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.SpaceKey',
+ [
+ 'ephox.katamari.api.Arr',
+ 'tinymce.core.keyboard.InsertSpace',
+ 'tinymce.core.keyboard.MatchKeys',
+ 'tinymce.core.util.VK'
+ ],
+ function (Arr, InsertSpace, MatchKeys, VK) {
+ var setupKeyDownHandler = function (editor, caret) {
+ editor.on('keydown', function (evt) {
+ var matches = MatchKeys.match([
+ { keyCode: VK.SPACEBAR, action: MatchKeys.action(InsertSpace.insertAtSelection, editor) }
+ ], evt);
+
+ Arr.find(matches, function (pattern) {
+ return pattern.action();
+ }).each(function (_) {
+ evt.preventDefault();
+ });
+ });
+ };
+
+ var setup = function (editor) {
+ setupKeyDownHandler(editor);
+ };
+
+ return {
+ setup: setup
+ };
+ }
+);
+
+/**
+ * KeyboardOverrides.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.KeyboardOverrides',
+ [
+ 'tinymce.core.keyboard.ArrowKeys',
+ 'tinymce.core.keyboard.BoundarySelection',
+ 'tinymce.core.keyboard.DeleteBackspaceKeys',
+ 'tinymce.core.keyboard.EnterKey',
+ 'tinymce.core.keyboard.SpaceKey'
+ ],
+ function (ArrowKeys, BoundarySelection, DeleteBackspaceKeys, EnterKey, SpaceKey) {
+ var setup = function (editor) {
+ var caret = BoundarySelection.setupSelectedState(editor);
+
+ ArrowKeys.setup(editor, caret);
+ DeleteBackspaceKeys.setup(editor, caret);
+ EnterKey.setup(editor);
+ SpaceKey.setup(editor);
+ };
+
+ return {
+ setup: setup
+ };
+ }
+);
+/**
+ * NodeChange.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 nodechange event dispatching both manual and through selection change events.
+ *
+ * @class tinymce.NodeChange
+ * @private
+ */
+define(
+ 'tinymce.core.NodeChange',
+ [
+ "tinymce.core.dom.RangeUtils",
+ "tinymce.core.Env",
+ "tinymce.core.util.Delay"
+ ],
+ function (RangeUtils, Env, Delay) {
+ return function (editor) {
+ var lastRng, lastPath = [];
+
+ /**
+ * Returns true/false if the current element path has been changed or not.
+ *
+ * @private
+ * @return {Boolean} True if the element path is the same false if it's not.
+ */
+ function isSameElementPath(startElm) {
+ var i, currentPath;
+
+ currentPath = editor.$(startElm).parentsUntil(editor.getBody()).add(startElm);
+ if (currentPath.length === lastPath.length) {
+ for (i = currentPath.length; i >= 0; i--) {
+ if (currentPath[i] !== lastPath[i]) {
+ break;
+ }
+ }
+
+ if (i === -1) {
+ lastPath = currentPath;
+ return true;
+ }
+ }
+
+ lastPath = currentPath;
+
+ return false;
+ }
+
+ // Gecko doesn't support the "selectionchange" event
+ if (!('onselectionchange' in editor.getDoc())) {
+ editor.on('NodeChange Click MouseUp KeyUp Focus', function (e) {
+ var nativeRng, fakeRng;
+
+ // Since DOM Ranges mutate on modification
+ // of the DOM we need to clone it's contents
+ nativeRng = editor.selection.getRng();
+ fakeRng = {
+ startContainer: nativeRng.startContainer,
+ startOffset: nativeRng.startOffset,
+ endContainer: nativeRng.endContainer,
+ endOffset: nativeRng.endOffset
+ };
+
+ // Always treat nodechange as a selectionchange since applying
+ // formatting to the current range wouldn't update the range but it's parent
+ if (e.type == 'nodechange' || !RangeUtils.compareRanges(fakeRng, lastRng)) {
+ editor.fire('SelectionChange');
+ }
+
+ lastRng = fakeRng;
+ });
+ }
+
+ // IE has a bug where it fires a selectionchange on right click that has a range at the start of the body
+ // When the contextmenu event fires the selection is located at the right location
+ editor.on('contextmenu', function () {
+ editor.fire('SelectionChange');
+ });
+
+ // Selection change is delayed ~200ms on IE when you click inside the current range
+ editor.on('SelectionChange', function () {
+ var startElm = editor.selection.getStart(true);
+
+ // IE 8 will fire a selectionchange event with an incorrect selection
+ // when focusing out of table cells. Click inside cell -> toolbar = Invalid SelectionChange event
+ if (!Env.range && editor.selection.isCollapsed()) {
+ return;
+ }
+
+ if (!isSameElementPath(startElm) && editor.dom.isChildOf(startElm, editor.getBody())) {
+ editor.nodeChanged({ selectionChange: true });
+ }
+ });
+
+ // Fire an extra nodeChange on mouseup for compatibility reasons
+ editor.on('MouseUp', function (e) {
+ if (!e.isDefaultPrevented()) {
+ // Delay nodeChanged call for WebKit edge case issue where the range
+ // isn't updated until after you click outside a selected image
+ if (editor.selection.getNode().nodeName == 'IMG') {
+ Delay.setEditorTimeout(editor, function () {
+ editor.nodeChanged();
+ });
+ } else {
+ editor.nodeChanged();
+ }
+ }
+ });
+
+ /**
+ * Dispatches out a onNodeChange event to all observers. This method should be called when you
+ * need to update the UI states or element path etc.
+ *
+ * @method nodeChanged
+ * @param {Object} args Optional args to pass to NodeChange event handlers.
+ */
+ this.nodeChanged = function (args) {
+ var selection = editor.selection, node, parents, root;
+
+ // Fix for bug #1896577 it seems that this can not be fired while the editor is loading
+ if (editor.initialized && selection && !editor.settings.disable_nodechange && !editor.readonly) {
+ // Get start node
+ root = editor.getBody();
+ node = selection.getStart(true) || root;
+
+ // Make sure the node is within the editor root or is the editor root
+ if (node.ownerDocument != editor.getDoc() || !editor.dom.isChildOf(node, root)) {
+ node = root;
+ }
+
+ // Get parents and add them to object
+ parents = [];
+ editor.dom.getParent(node, function (node) {
+ if (node === root) {
+ return true;
+ }
+
+ parents.push(node);
+ });
+
+ args = args || {};
+ args.element = node;
+ args.parents = parents;
+
+ editor.fire('NodeChange', args);
+ }
+ };
+ };
+ }
+);
+
+/**
+ * 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;
+
+ 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 (isBlock(node)) {
+ caretContainerNode = CaretContainer.insertBlock('p', node, before);
+ clientRect = getAbsoluteClientRect(node, before);
+ DomQuery(caretContainerNode).css('top', clientRect.top);
+
+ $lastVisualCaret = DomQuery('').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
+ };
+ };
+ }
+);
+/**
+ * Dimensions.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 measures nodes and returns client rects. The client rects has an
+ * extra node property.
+ *
+ * @private
+ * @class tinymce.dom.Dimensions
+ */
+define(
+ 'tinymce.core.dom.Dimensions',
+ [
+ "tinymce.core.util.Arr",
+ "tinymce.core.dom.NodeType",
+ "tinymce.core.geom.ClientRect"
+ ],
+ function (Arr, NodeType, ClientRect) {
+
+ function getClientRects(node) {
+ function toArrayWithNode(clientRects) {
+ return Arr.map(clientRects, function (clientRect) {
+ clientRect = ClientRect.clone(clientRect);
+ clientRect.node = node;
+
+ return clientRect;
+ });
+ }
+
+ if (Arr.isArray(node)) {
+ return Arr.reduce(node, function (result, node) {
+ return result.concat(getClientRects(node));
+ }, []);
+ }
+
+ if (NodeType.isElement(node)) {
+ return toArrayWithNode(node.getClientRects());
+ }
+
+ if (NodeType.isText(node)) {
+ var rng = node.ownerDocument.createRange();
+
+ rng.setStart(node, 0);
+ rng.setEnd(node, node.data.length);
+
+ return toArrayWithNode(rng.getClientRects());
+ }
+ }
+
+ return {
+ /**
+ * Returns the client rects for a specific node.
+ *
+ * @method getClientRects
+ * @param {Array/DOMNode} node Node or array of nodes to get client rects on.
+ * @param {Array} Array of client rects with a extra node property.
+ */
+ getClientRects: getClientRects
+ };
+ }
+);
+/**
+ * LineWalker.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 lets you walk the document line by line
+ * returing nodes and client rects for each line.
+ *
+ * @private
+ * @class tinymce.caret.LineWalker
+ */
+define(
+ 'tinymce.core.caret.LineWalker',
+ [
+ "tinymce.core.util.Fun",
+ "tinymce.core.util.Arr",
+ "tinymce.core.dom.Dimensions",
+ "tinymce.core.caret.CaretCandidate",
+ "tinymce.core.caret.CaretUtils",
+ "tinymce.core.caret.CaretWalker",
+ "tinymce.core.caret.CaretPosition",
+ "tinymce.core.geom.ClientRect"
+ ],
+ function (Fun, Arr, Dimensions, CaretCandidate, CaretUtils, CaretWalker, CaretPosition, ClientRect) {
+ var curry = Fun.curry;
+
+ function findUntil(direction, rootNode, predicateFn, node) {
+ while ((node = CaretUtils.findNode(node, direction, CaretCandidate.isEditableCaretCandidate, rootNode))) {
+ if (predicateFn(node)) {
+ return;
+ }
+ }
+ }
+
+ function walkUntil(direction, isAboveFn, isBeflowFn, rootNode, predicateFn, caretPosition) {
+ var line = 0, node, result = [], targetClientRect;
+
+ function add(node) {
+ var i, clientRect, clientRects;
+
+ clientRects = Dimensions.getClientRects(node);
+ if (direction == -1) {
+ clientRects = clientRects.reverse();
+ }
+
+ for (i = 0; i < clientRects.length; i++) {
+ clientRect = clientRects[i];
+ if (isBeflowFn(clientRect, targetClientRect)) {
+ continue;
+ }
+
+ if (result.length > 0 && isAboveFn(clientRect, Arr.last(result))) {
+ line++;
+ }
+
+ clientRect.line = line;
+
+ if (predicateFn(clientRect)) {
+ return true;
+ }
+
+ result.push(clientRect);
+ }
+ }
+
+ targetClientRect = Arr.last(caretPosition.getClientRects());
+ if (!targetClientRect) {
+ return result;
+ }
+
+ node = caretPosition.getNode();
+ add(node);
+ findUntil(direction, rootNode, add, node);
+
+ return result;
+ }
+
+ function aboveLineNumber(lineNumber, clientRect) {
+ return clientRect.line > lineNumber;
+ }
+
+ function isLine(lineNumber, clientRect) {
+ return clientRect.line === lineNumber;
+ }
+
+ var upUntil = curry(walkUntil, -1, ClientRect.isAbove, ClientRect.isBelow);
+ var downUntil = curry(walkUntil, 1, ClientRect.isBelow, ClientRect.isAbove);
+
+ function positionsUntil(direction, rootNode, predicateFn, node) {
+ var caretWalker = new CaretWalker(rootNode), walkFn, isBelowFn, isAboveFn,
+ caretPosition, result = [], line = 0, clientRect, targetClientRect;
+
+ function getClientRect(caretPosition) {
+ if (direction == 1) {
+ return Arr.last(caretPosition.getClientRects());
+ }
+
+ return Arr.last(caretPosition.getClientRects());
+ }
+
+ if (direction == 1) {
+ walkFn = caretWalker.next;
+ isBelowFn = ClientRect.isBelow;
+ isAboveFn = ClientRect.isAbove;
+ caretPosition = CaretPosition.after(node);
+ } else {
+ walkFn = caretWalker.prev;
+ isBelowFn = ClientRect.isAbove;
+ isAboveFn = ClientRect.isBelow;
+ caretPosition = CaretPosition.before(node);
+ }
+
+ targetClientRect = getClientRect(caretPosition);
+
+ do {
+ if (!caretPosition.isVisible()) {
+ continue;
+ }
+
+ clientRect = getClientRect(caretPosition);
+
+ if (isAboveFn(clientRect, targetClientRect)) {
+ continue;
+ }
+
+ if (result.length > 0 && isBelowFn(clientRect, Arr.last(result))) {
+ line++;
+ }
+
+ clientRect = ClientRect.clone(clientRect);
+ clientRect.position = caretPosition;
+ clientRect.line = line;
+
+ if (predicateFn(clientRect)) {
+ return result;
+ }
+
+ result.push(clientRect);
+ } while ((caretPosition = walkFn(caretPosition)));
+
+ return result;
+ }
+
+ return {
+ upUntil: upUntil,
+ downUntil: downUntil,
+
+ /**
+ * Find client rects with line and caret position until the predicate returns true.
+ *
+ * @method positionsUntil
+ * @param {Number} direction Direction forward/backward 1/-1.
+ * @param {DOMNode} rootNode Root node to walk within.
+ * @param {function} predicateFn Gets the client rect as it's input.
+ * @param {DOMNode} node Node to start walking from.
+ * @return {Array} Array of client rects with line and position properties.
+ */
+ positionsUntil: positionsUntil,
+
+ isAboveLine: curry(aboveLineNumber),
+ isLine: curry(isLine)
+ };
+ }
+);
+/**
+ * LineUtils.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
+ */
+
+/**
+ * Utility functions for working with lines.
+ *
+ * @private
+ * @class tinymce.caret.LineUtils
+ */
+define(
+ 'tinymce.core.caret.LineUtils',
+ [
+ "tinymce.core.util.Fun",
+ "tinymce.core.util.Arr",
+ "tinymce.core.dom.NodeType",
+ "tinymce.core.dom.Dimensions",
+ "tinymce.core.geom.ClientRect",
+ "tinymce.core.caret.CaretUtils",
+ "tinymce.core.caret.CaretCandidate"
+ ],
+ function (Fun, Arr, NodeType, Dimensions, ClientRect, CaretUtils, CaretCandidate) {
+ var isContentEditableFalse = NodeType.isContentEditableFalse,
+ findNode = CaretUtils.findNode,
+ curry = Fun.curry;
+
+ function distanceToRectLeft(clientRect, clientX) {
+ return Math.abs(clientRect.left - clientX);
+ }
+
+ function distanceToRectRight(clientRect, clientX) {
+ return Math.abs(clientRect.right - clientX);
+ }
+
+ function findClosestClientRect(clientRects, clientX) {
+ function isInside(clientX, clientRect) {
+ return clientX >= clientRect.left && clientX <= clientRect.right;
+ }
+
+ return Arr.reduce(clientRects, function (oldClientRect, clientRect) {
+ var oldDistance, newDistance;
+
+ oldDistance = Math.min(distanceToRectLeft(oldClientRect, clientX), distanceToRectRight(oldClientRect, clientX));
+ newDistance = Math.min(distanceToRectLeft(clientRect, clientX), distanceToRectRight(clientRect, clientX));
+
+ if (isInside(clientX, clientRect)) {
+ return clientRect;
+ }
+
+ if (isInside(clientX, oldClientRect)) {
+ return oldClientRect;
+ }
+
+ // cE=false has higher priority
+ if (newDistance == oldDistance && isContentEditableFalse(clientRect.node)) {
+ return clientRect;
+ }
+
+ if (newDistance < oldDistance) {
+ return clientRect;
+ }
+
+ return oldClientRect;
+ });
+ }
+
+ function walkUntil(direction, rootNode, predicateFn, node) {
+ while ((node = findNode(node, direction, CaretCandidate.isEditableCaretCandidate, rootNode))) {
+ if (predicateFn(node)) {
+ return;
+ }
+ }
+ }
+
+ function findLineNodeRects(rootNode, targetNodeRect) {
+ var clientRects = [];
+
+ function collect(checkPosFn, node) {
+ var lineRects;
+
+ lineRects = Arr.filter(Dimensions.getClientRects(node), function (clientRect) {
+ return !checkPosFn(clientRect, targetNodeRect);
+ });
+
+ clientRects = clientRects.concat(lineRects);
+
+ return lineRects.length === 0;
+ }
+
+ clientRects.push(targetNodeRect);
+ walkUntil(-1, rootNode, curry(collect, ClientRect.isAbove), targetNodeRect.node);
+ walkUntil(1, rootNode, curry(collect, ClientRect.isBelow), targetNodeRect.node);
+
+ return clientRects;
+ }
+
+ function getContentEditableFalseChildren(rootNode) {
+ return Arr.filter(Arr.toArray(rootNode.getElementsByTagName('*')), isContentEditableFalse);
+ }
+
+ function caretInfo(clientRect, clientX) {
+ return {
+ node: clientRect.node,
+ before: distanceToRectLeft(clientRect, clientX) < distanceToRectRight(clientRect, clientX)
+ };
+ }
+
+ function closestCaret(rootNode, clientX, clientY) {
+ var contentEditableFalseNodeRects, closestNodeRect;
+
+ contentEditableFalseNodeRects = Dimensions.getClientRects(getContentEditableFalseChildren(rootNode));
+ contentEditableFalseNodeRects = Arr.filter(contentEditableFalseNodeRects, function (clientRect) {
+ return clientY >= clientRect.top && clientY <= clientRect.bottom;
+ });
+
+ closestNodeRect = findClosestClientRect(contentEditableFalseNodeRects, clientX);
+ if (closestNodeRect) {
+ closestNodeRect = findClosestClientRect(findLineNodeRects(rootNode, closestNodeRect), clientX);
+ if (closestNodeRect && isContentEditableFalse(closestNodeRect.node)) {
+ return caretInfo(closestNodeRect, clientX);
+ }
+ }
+
+ return null;
+ }
+
+ return {
+ findClosestClientRect: findClosestClientRect,
+ findLineNodeRects: findLineNodeRects,
+ closestCaret: closestCaret
+ };
+ }
+);
+/**
+ * MousePosition.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 calculates an absolute coordinate inside the editor body for both local and global mouse events.
+ *
+ * @private
+ * @class tinymce.dom.MousePosition
+ */
+define(
+ 'tinymce.core.dom.MousePosition',
+ [
+ ],
+ function () {
+ var getAbsolutePosition = function (elm) {
+ var doc, docElem, win, clientRect;
+
+ clientRect = elm.getBoundingClientRect();
+ doc = elm.ownerDocument;
+ docElem = doc.documentElement;
+ win = doc.defaultView;
+
+ return {
+ top: clientRect.top + win.pageYOffset - docElem.clientTop,
+ left: clientRect.left + win.pageXOffset - docElem.clientLeft
+ };
+ };
+
+ var getBodyPosition = function (editor) {
+ return editor.inline ? getAbsolutePosition(editor.getBody()) : { left: 0, top: 0 };
+ };
+
+ var getScrollPosition = function (editor) {
+ var body = editor.getBody();
+ return editor.inline ? { left: body.scrollLeft, top: body.scrollTop } : { left: 0, top: 0 };
+ };
+
+ var getBodyScroll = function (editor) {
+ var body = editor.getBody(), docElm = editor.getDoc().documentElement;
+ var inlineScroll = { left: body.scrollLeft, top: body.scrollTop };
+ var iframeScroll = { left: body.scrollLeft || docElm.scrollLeft, top: body.scrollTop || docElm.scrollTop };
+
+ return editor.inline ? inlineScroll : iframeScroll;
+ };
+
+ var getMousePosition = function (editor, event) {
+ if (event.target.ownerDocument !== editor.getDoc()) {
+ var iframePosition = getAbsolutePosition(editor.getContentAreaContainer());
+ var scrollPosition = getBodyScroll(editor);
+
+ return {
+ left: event.pageX - iframePosition.left + scrollPosition.left,
+ top: event.pageY - iframePosition.top + scrollPosition.top
+ };
+ }
+
+ return {
+ left: event.pageX,
+ top: event.pageY
+ };
+ };
+
+ var calculatePosition = function (bodyPosition, scrollPosition, mousePosition) {
+ return {
+ pageX: (mousePosition.left - bodyPosition.left) + scrollPosition.left,
+ pageY: (mousePosition.top - bodyPosition.top) + scrollPosition.top
+ };
+ };
+
+ var calc = function (editor, event) {
+ return calculatePosition(getBodyPosition(editor), getScrollPosition(editor), getMousePosition(editor, event));
+ };
+
+ return {
+ calc: calc
+ };
+ }
+);
+
+/**
+ * DragDropOverrides.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 overriding the drag/drop logic of the editor.
+ *
+ * @private
+ * @class tinymce.DragDropOverrides
+ */
+define(
+ 'tinymce.core.DragDropOverrides',
+ [
+ "tinymce.core.dom.NodeType",
+ "tinymce.core.util.Arr",
+ "tinymce.core.util.Fun",
+ "tinymce.core.util.Delay",
+ "tinymce.core.dom.DOMUtils",
+ "tinymce.core.dom.MousePosition"
+ ],
+ function (
+ NodeType, Arr, Fun, Delay, DOMUtils, MousePosition
+ ) {
+ var isContentEditableFalse = NodeType.isContentEditableFalse,
+ isContentEditableTrue = NodeType.isContentEditableTrue;
+
+ var isDraggable = function (rootElm, elm) {
+ return isContentEditableFalse(elm) && elm !== rootElm;
+ };
+
+ var isValidDropTarget = function (editor, targetElement, dragElement) {
+ if (targetElement === dragElement || editor.dom.isChildOf(targetElement, dragElement)) {
+ return false;
+ }
+
+ if (isContentEditableFalse(targetElement)) {
+ return false;
+ }
+
+ return true;
+ };
+
+ var cloneElement = function (elm) {
+ var cloneElm = elm.cloneNode(true);
+ cloneElm.removeAttribute('data-mce-selected');
+ return cloneElm;
+ };
+
+ var createGhost = function (editor, elm, width, height) {
+ var clonedElm = elm.cloneNode(true);
+
+ editor.dom.setStyles(clonedElm, { width: width, height: height });
+ editor.dom.setAttrib(clonedElm, 'data-mce-selected', null);
+
+ var ghostElm = editor.dom.create('div', {
+ 'class': 'mce-drag-container',
+ 'data-mce-bogus': 'all',
+ unselectable: 'on',
+ contenteditable: 'false'
+ });
+
+ editor.dom.setStyles(ghostElm, {
+ position: 'absolute',
+ opacity: 0.5,
+ overflow: 'hidden',
+ border: 0,
+ padding: 0,
+ margin: 0,
+ width: width,
+ height: height
+ });
+
+ editor.dom.setStyles(clonedElm, {
+ margin: 0,
+ boxSizing: 'border-box'
+ });
+
+ ghostElm.appendChild(clonedElm);
+
+ return ghostElm;
+ };
+
+ var appendGhostToBody = function (ghostElm, bodyElm) {
+ if (ghostElm.parentNode !== bodyElm) {
+ bodyElm.appendChild(ghostElm);
+ }
+ };
+
+ var moveGhost = function (ghostElm, position, width, height, maxX, maxY) {
+ var overflowX = 0, overflowY = 0;
+
+ ghostElm.style.left = position.pageX + 'px';
+ ghostElm.style.top = position.pageY + 'px';
+
+ if (position.pageX + width > maxX) {
+ overflowX = (position.pageX + width) - maxX;
+ }
+
+ if (position.pageY + height > maxY) {
+ overflowY = (position.pageY + height) - maxY;
+ }
+
+ ghostElm.style.width = (width - overflowX) + 'px';
+ ghostElm.style.height = (height - overflowY) + 'px';
+ };
+
+ var removeElement = function (elm) {
+ if (elm && elm.parentNode) {
+ elm.parentNode.removeChild(elm);
+ }
+ };
+
+ var isLeftMouseButtonPressed = function (e) {
+ return e.button === 0;
+ };
+
+ var hasDraggableElement = function (state) {
+ return state.element;
+ };
+
+ var applyRelPos = function (state, position) {
+ return {
+ pageX: position.pageX - state.relX,
+ pageY: position.pageY + 5
+ };
+ };
+
+ var start = function (state, editor) {
+ return function (e) {
+ if (isLeftMouseButtonPressed(e)) {
+ var ceElm = Arr.find(editor.dom.getParents(e.target), Fun.or(isContentEditableFalse, isContentEditableTrue));
+
+ if (isDraggable(editor.getBody(), ceElm)) {
+ var elmPos = editor.dom.getPos(ceElm);
+ var bodyElm = editor.getBody();
+ var docElm = editor.getDoc().documentElement;
+
+ state.element = ceElm;
+ state.screenX = e.screenX;
+ state.screenY = e.screenY;
+ state.maxX = (editor.inline ? bodyElm.scrollWidth : docElm.offsetWidth) - 2;
+ state.maxY = (editor.inline ? bodyElm.scrollHeight : docElm.offsetHeight) - 2;
+ state.relX = e.pageX - elmPos.x;
+ state.relY = e.pageY - elmPos.y;
+ state.width = ceElm.offsetWidth;
+ state.height = ceElm.offsetHeight;
+ state.ghost = createGhost(editor, ceElm, state.width, state.height);
+ }
+ }
+ };
+ };
+
+ var move = function (state, editor) {
+ // Reduces laggy drag behavior on Gecko
+ var throttledPlaceCaretAt = Delay.throttle(function (clientX, clientY) {
+ editor._selectionOverrides.hideFakeCaret();
+ editor.selection.placeCaretAt(clientX, clientY);
+ }, 0);
+
+ return function (e) {
+ var movement = Math.max(Math.abs(e.screenX - state.screenX), Math.abs(e.screenY - state.screenY));
+
+ if (hasDraggableElement(state) && !state.dragging && movement > 10) {
+ var args = editor.fire('dragstart', { target: state.element });
+ if (args.isDefaultPrevented()) {
+ return;
+ }
+
+ state.dragging = true;
+ editor.focus();
+ }
+
+ if (state.dragging) {
+ var targetPos = applyRelPos(state, MousePosition.calc(editor, e));
+
+ appendGhostToBody(state.ghost, editor.getBody());
+ moveGhost(state.ghost, targetPos, state.width, state.height, state.maxX, state.maxY);
+
+ throttledPlaceCaretAt(e.clientX, e.clientY);
+ }
+ };
+ };
+
+ // Returns the raw element instead of the fake cE=false element
+ var getRawTarget = function (selection) {
+ var rng = selection.getSel().getRangeAt(0);
+ var startContainer = rng.startContainer;
+ return startContainer.nodeType === 3 ? startContainer.parentNode : startContainer;
+ };
+
+ var drop = function (state, editor) {
+ return function (e) {
+ if (state.dragging) {
+ if (isValidDropTarget(editor, getRawTarget(editor.selection), state.element)) {
+ var targetClone = cloneElement(state.element);
+
+ var args = editor.fire('drop', {
+ targetClone: targetClone,
+ clientX: e.clientX,
+ clientY: e.clientY
+ });
+
+ if (!args.isDefaultPrevented()) {
+ targetClone = args.targetClone;
+
+ editor.undoManager.transact(function () {
+ removeElement(state.element);
+ editor.insertContent(editor.dom.getOuterHTML(targetClone));
+ editor._selectionOverrides.hideFakeCaret();
+ });
+ }
+ }
+ }
+
+ removeDragState(state);
+ };
+ };
+
+ var stop = function (state, editor) {
+ return function () {
+ removeDragState(state);
+ if (state.dragging) {
+ editor.fire('dragend');
+ }
+ };
+ };
+
+ var removeDragState = function (state) {
+ state.dragging = false;
+ state.element = null;
+ removeElement(state.ghost);
+ };
+
+ var bindFakeDragEvents = function (editor) {
+ var state = {}, pageDom, dragStartHandler, dragHandler, dropHandler, dragEndHandler, rootDocument;
+
+ pageDom = DOMUtils.DOM;
+ rootDocument = document;
+ dragStartHandler = start(state, editor);
+ dragHandler = move(state, editor);
+ dropHandler = drop(state, editor);
+ dragEndHandler = stop(state, editor);
+
+ editor.on('mousedown', dragStartHandler);
+ editor.on('mousemove', dragHandler);
+ editor.on('mouseup', dropHandler);
+
+ pageDom.bind(rootDocument, 'mousemove', dragHandler);
+ pageDom.bind(rootDocument, 'mouseup', dragEndHandler);
+
+ editor.on('remove', function () {
+ pageDom.unbind(rootDocument, 'mousemove', dragHandler);
+ pageDom.unbind(rootDocument, 'mouseup', dragEndHandler);
+ });
+ };
+
+ var blockIeDrop = function (editor) {
+ editor.on('drop', function (e) {
+ // FF doesn't pass out clientX/clientY for drop since this is for IE we just use null instead
+ var realTarget = typeof e.clientX !== 'undefined' ? editor.getDoc().elementFromPoint(e.clientX, e.clientY) : null;
+
+ if (isContentEditableFalse(realTarget) || isContentEditableFalse(editor.dom.getContentEditableParent(realTarget))) {
+ e.preventDefault();
+ }
+ });
+ };
+
+ var init = function (editor) {
+ bindFakeDragEvents(editor);
+ blockIeDrop(editor);
+ };
+
+ return {
+ init: init
+ };
+ }
+);
+
+/**
+ * SelectionOverrides.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 overriding the selection with keyboard/mouse
+ * around contentEditable=false regions.
+ *
+ * @example
+ * // Disable the default cE=false selection
+ * tinymce.activeEditor.on('ShowCaret BeforeObjectSelected', function(e) {
+ * e.preventDefault();
+ * });
+ *
+ * @private
+ * @class tinymce.SelectionOverrides
+ */
+define(
+ 'tinymce.core.SelectionOverrides',
+ [
+ "tinymce.core.Env",
+ "tinymce.core.caret.CaretWalker",
+ "tinymce.core.caret.CaretPosition",
+ "tinymce.core.caret.CaretContainer",
+ "tinymce.core.caret.CaretContainerRemove",
+ "tinymce.core.caret.CaretUtils",
+ "tinymce.core.caret.FakeCaret",
+ "tinymce.core.caret.LineWalker",
+ "tinymce.core.caret.LineUtils",
+ "tinymce.core.dom.NodeType",
+ "tinymce.core.dom.RangeUtils",
+ "tinymce.core.geom.ClientRect",
+ "tinymce.core.util.VK",
+ "tinymce.core.util.Fun",
+ "tinymce.core.util.Arr",
+ "tinymce.core.util.Delay",
+ "tinymce.core.DragDropOverrides"
+ ],
+ function (
+ Env, CaretWalker, CaretPosition, CaretContainer, CaretContainerRemove, CaretUtils, FakeCaret, LineWalker,
+ LineUtils, NodeType, RangeUtils, ClientRect, VK, Fun, Arr, Delay, DragDropOverrides
+) {
+ var curry = Fun.curry,
+ isContentEditableTrue = NodeType.isContentEditableTrue,
+ isContentEditableFalse = NodeType.isContentEditableFalse,
+ isAfterContentEditableFalse = CaretUtils.isAfterContentEditableFalse,
+ isBeforeContentEditableFalse = CaretUtils.isBeforeContentEditableFalse,
+ getSelectedNode = RangeUtils.getSelectedNode;
+
+ function getVisualCaretPosition(walkFn, caretPosition) {
+ while ((caretPosition = walkFn(caretPosition))) {
+ if (caretPosition.isVisible()) {
+ return caretPosition;
+ }
+ }
+
+ return caretPosition;
+ }
+
+ function SelectionOverrides(editor) {
+ var rootNode = editor.getBody(), caretWalker = new CaretWalker(rootNode);
+ var getNextVisualCaretPosition = curry(getVisualCaretPosition, caretWalker.next);
+ var getPrevVisualCaretPosition = curry(getVisualCaretPosition, caretWalker.prev),
+ fakeCaret = new FakeCaret(editor.getBody(), isBlock),
+ realSelectionId = 'sel-' + editor.dom.uniqueId(),
+ selectedContentEditableNode;
+
+ function isFakeSelectionElement(elm) {
+ return editor.dom.hasClass(elm, 'mce-offscreen-selection');
+ }
+
+ function getRealSelectionElement() {
+ var container = editor.dom.get(realSelectionId);
+ return container ? container.getElementsByTagName('*')[0] : container;
+ }
+
+ function isBlock(node) {
+ return editor.dom.isBlock(node);
+ }
+
+ function setRange(range) {
+ //console.log('setRange', range);
+ if (range) {
+ editor.selection.setRng(range);
+ }
+ }
+
+ function getRange() {
+ return editor.selection.getRng();
+ }
+
+ function scrollIntoView(node, alignToTop) {
+ editor.selection.scrollIntoView(node, alignToTop);
+ }
+
+ function showCaret(direction, node, before) {
+ var e;
+
+ e = editor.fire('ShowCaret', {
+ target: node,
+ direction: direction,
+ before: before
+ });
+
+ if (e.isDefaultPrevented()) {
+ return null;
+ }
+
+ scrollIntoView(node, direction === -1);
+
+ return fakeCaret.show(before, node);
+ }
+
+ function selectNode(node) {
+ var e;
+
+ e = editor.fire('BeforeObjectSelected', { target: node });
+ if (e.isDefaultPrevented()) {
+ return null;
+ }
+
+ return getNodeRange(node);
+ }
+
+ function getNodeRange(node) {
+ var rng = node.ownerDocument.createRange();
+
+ rng.selectNode(node);
+
+ return rng;
+ }
+
+ function isMoveInsideSameBlock(fromCaretPosition, toCaretPosition) {
+ var inSameBlock = CaretUtils.isInSameBlock(fromCaretPosition, toCaretPosition);
+
+ // Handle bogus BR
abc|
+ if (!inSameBlock && NodeType.isBr(fromCaretPosition.getNode())) {
+ return true;
+ }
+
+ return inSameBlock;
+ }
+
+ function getNormalizedRangeEndPoint(direction, range) {
+ range = CaretUtils.normalizeRange(direction, rootNode, range);
+
+ if (direction == -1) {
+ return CaretPosition.fromRangeStart(range);
+ }
+
+ return CaretPosition.fromRangeEnd(range);
+ }
+
+ function isRangeInCaretContainerBlock(range) {
+ return CaretContainer.isCaretContainerBlock(range.startContainer);
+ }
+
+ function moveToCeFalseHorizontally(direction, getNextPosFn, isBeforeContentEditableFalseFn, range) {
+ var node, caretPosition, peekCaretPosition, rangeIsInContainerBlock;
+
+ if (!range.collapsed) {
+ node = getSelectedNode(range);
+ if (isContentEditableFalse(node)) {
+ return showCaret(direction, node, direction == -1);
+ }
+ }
+
+ rangeIsInContainerBlock = isRangeInCaretContainerBlock(range);
+ caretPosition = getNormalizedRangeEndPoint(direction, range);
+
+ if (isBeforeContentEditableFalseFn(caretPosition)) {
+ return selectNode(caretPosition.getNode(direction == -1));
+ }
+
+ caretPosition = getNextPosFn(caretPosition);
+ if (!caretPosition) {
+ if (rangeIsInContainerBlock) {
+ return range;
+ }
+
+ return null;
+ }
+
+ if (isBeforeContentEditableFalseFn(caretPosition)) {
+ return showCaret(direction, caretPosition.getNode(direction == -1), direction == 1);
+ }
+
+ // Peek ahead for handling of ab|c -> abc|
+ peekCaretPosition = getNextPosFn(caretPosition);
+ if (isBeforeContentEditableFalseFn(peekCaretPosition)) {
+ if (isMoveInsideSameBlock(caretPosition, peekCaretPosition)) {
+ return showCaret(direction, peekCaretPosition.getNode(direction == -1), direction == 1);
+ }
+ }
+
+ if (rangeIsInContainerBlock) {
+ return renderRangeCaret(caretPosition.toRange());
+ }
+
+ return null;
+ }
+
+ function moveToCeFalseVertically(direction, walkerFn, range) {
+ var caretPosition, linePositions, nextLinePositions,
+ closestNextLineRect, caretClientRect, clientX,
+ dist1, dist2, contentEditableFalseNode;
+
+ contentEditableFalseNode = getSelectedNode(range);
+ caretPosition = getNormalizedRangeEndPoint(direction, range);
+ linePositions = walkerFn(rootNode, LineWalker.isAboveLine(1), caretPosition);
+ nextLinePositions = Arr.filter(linePositions, LineWalker.isLine(1));
+ caretClientRect = Arr.last(caretPosition.getClientRects());
+
+ if (isBeforeContentEditableFalse(caretPosition)) {
+ contentEditableFalseNode = caretPosition.getNode();
+ }
+
+ if (isAfterContentEditableFalse(caretPosition)) {
+ contentEditableFalseNode = caretPosition.getNode(true);
+ }
+
+ if (!caretClientRect) {
+ return null;
+ }
+
+ clientX = caretClientRect.left;
+
+ closestNextLineRect = LineUtils.findClosestClientRect(nextLinePositions, clientX);
+ if (closestNextLineRect) {
+ if (isContentEditableFalse(closestNextLineRect.node)) {
+ dist1 = Math.abs(clientX - closestNextLineRect.left);
+ dist2 = Math.abs(clientX - closestNextLineRect.right);
+
+ return showCaret(direction, closestNextLineRect.node, dist1 < dist2);
+ }
+ }
+
+ if (contentEditableFalseNode) {
+ var caretPositions = LineWalker.positionsUntil(direction, rootNode, LineWalker.isAboveLine(1), contentEditableFalseNode);
+
+ closestNextLineRect = LineUtils.findClosestClientRect(Arr.filter(caretPositions, LineWalker.isLine(1)), clientX);
+ if (closestNextLineRect) {
+ return renderRangeCaret(closestNextLineRect.position.toRange());
+ }
+
+ closestNextLineRect = Arr.last(Arr.filter(caretPositions, LineWalker.isLine(0)));
+ if (closestNextLineRect) {
+ return renderRangeCaret(closestNextLineRect.position.toRange());
+ }
+ }
+ }
+
+ function exitPreBlock(direction, range) {
+ var pre, caretPos, newBlock;
+
+ function createTextBlock() {
+ var textBlock = editor.dom.create(editor.settings.forced_root_block);
+
+ if (!Env.ie || Env.ie >= 11) {
+ textBlock.innerHTML = ' ';
+ }
+
+ return textBlock;
+ }
+
+ if (range.collapsed && editor.settings.forced_root_block) {
+ pre = editor.dom.getParent(range.startContainer, 'PRE');
+ if (!pre) {
+ return;
+ }
+
+ if (direction == 1) {
+ caretPos = getNextVisualCaretPosition(CaretPosition.fromRangeStart(range));
+ } else {
+ caretPos = getPrevVisualCaretPosition(CaretPosition.fromRangeStart(range));
+ }
+
+ if (!caretPos) {
+ newBlock = createTextBlock();
+
+ if (direction == 1) {
+ editor.$(pre).after(newBlock);
+ } else {
+ editor.$(pre).before(newBlock);
+ }
+
+ editor.selection.select(newBlock, true);
+ editor.selection.collapse();
+ }
+ }
+ }
+
+ function moveH(direction, getNextPosFn, isBeforeContentEditableFalseFn, range) {
+ var newRange;
+
+ newRange = moveToCeFalseHorizontally(direction, getNextPosFn, isBeforeContentEditableFalseFn, range);
+ if (newRange) {
+ return newRange;
+ }
+
+ newRange = exitPreBlock(direction, range);
+ if (newRange) {
+ return newRange;
+ }
+
+ return null;
+ }
+
+ function moveV(direction, walkerFn, range) {
+ var newRange;
+
+ newRange = moveToCeFalseVertically(direction, walkerFn, range);
+ if (newRange) {
+ return newRange;
+ }
+
+ newRange = exitPreBlock(direction, range);
+ if (newRange) {
+ return newRange;
+ }
+
+ return null;
+ }
+
+ function showBlockCaretContainer(blockCaretContainer) {
+ if (blockCaretContainer.hasAttribute('data-mce-caret')) {
+ CaretContainer.showCaretContainerBlock(blockCaretContainer);
+ setRange(getRange()); // Removes control rect on IE
+ scrollIntoView(blockCaretContainer[0]);
+ }
+ }
+
+ function renderCaretAtRange(range) {
+ var caretPosition, ceRoot;
+
+ range = CaretUtils.normalizeRange(1, rootNode, range);
+ caretPosition = CaretPosition.fromRangeStart(range);
+
+ if (isContentEditableFalse(caretPosition.getNode())) {
+ return showCaret(1, caretPosition.getNode(), !caretPosition.isAtEnd());
+ }
+
+ if (isContentEditableFalse(caretPosition.getNode(true))) {
+ return showCaret(1, caretPosition.getNode(true), false);
+ }
+
+ // TODO: Should render caret before/after depending on where you click on the page forces after now
+ ceRoot = editor.dom.getParent(caretPosition.getNode(), Fun.or(isContentEditableFalse, isContentEditableTrue));
+ if (isContentEditableFalse(ceRoot)) {
+ return showCaret(1, ceRoot, false);
+ }
+
+ return null;
+ }
+
+ function renderRangeCaret(range) {
+ var caretRange;
+
+ if (!range || !range.collapsed) {
+ return range;
+ }
+
+ caretRange = renderCaretAtRange(range);
+ if (caretRange) {
+ return caretRange;
+ }
+
+ return range;
+ }
+
+ function registerEvents() {
+ var right = curry(moveH, 1, getNextVisualCaretPosition, isBeforeContentEditableFalse);
+ var left = curry(moveH, -1, getPrevVisualCaretPosition, isAfterContentEditableFalse);
+ var up = curry(moveV, -1, LineWalker.upUntil);
+ var down = curry(moveV, 1, LineWalker.downUntil);
+
+ function override(evt, moveFn) {
+ if (evt.isDefaultPrevented() === false) {
+ var range = moveFn(getRange());
+
+ if (range) {
+ evt.preventDefault();
+ setRange(range);
+ }
+ }
+ }
+
+ function getContentEditableRoot(node) {
+ var root = editor.getBody();
+
+ while (node && node != root) {
+ if (isContentEditableTrue(node) || isContentEditableFalse(node)) {
+ return node;
+ }
+
+ node = node.parentNode;
+ }
+
+ return null;
+ }
+
+ 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);
+ }
+
+ // Some browsers (Chrome) lets you place the caret after a cE=false
+ // Make sure we render the caret container in this case
+ editor.on('mouseup', function () {
+ var range = getRange();
+
+ if (range.collapsed) {
+ setRange(renderCaretAtRange(range));
+ }
+ });
+
+ editor.on('click', function (e) {
+ var contentEditableRoot;
+
+ contentEditableRoot = getContentEditableRoot(e.target);
+ if (contentEditableRoot) {
+ // Prevent clicks on links in a cE=false element
+ if (isContentEditableFalse(contentEditableRoot)) {
+ e.preventDefault();
+ editor.focus();
+ }
+
+ // Removes fake selection if a cE=true is clicked within a cE=false like the toc title
+ if (isContentEditableTrue(contentEditableRoot)) {
+ if (editor.dom.isChildOf(contentEditableRoot, editor.selection.getNode())) {
+ removeContentEditableSelection();
+ }
+ }
+ }
+ });
+
+ editor.on('blur NewBlock', function () {
+ removeContentEditableSelection();
+ hideFakeCaret();
+ });
+
+ function handleTouchSelect(editor) {
+ var moved = false;
+
+ editor.on('touchstart', function () {
+ moved = false;
+ });
+
+ editor.on('touchmove', function () {
+ moved = true;
+ });
+
+ editor.on('touchend', function (e) {
+ var contentEditableRoot = getContentEditableRoot(e.target);
+
+ if (isContentEditableFalse(contentEditableRoot)) {
+ if (!moved) {
+ e.preventDefault();
+ setContentEditableSelection(selectNode(contentEditableRoot));
+ }
+ }
+ });
+ }
+
+ var hasNormalCaretPosition = function (elm) {
+ var caretWalker = new CaretWalker(elm);
+
+ if (!elm.firstChild) {
+ return false;
+ }
+
+ var startPos = CaretPosition.before(elm.firstChild);
+ var newPos = caretWalker.next(startPos);
+
+ return newPos && !isBeforeContentEditableFalse(newPos) && !isAfterContentEditableFalse(newPos);
+ };
+
+ var isInSameBlock = function (node1, node2) {
+ var block1 = editor.dom.getParent(node1, editor.dom.isBlock);
+ var block2 = editor.dom.getParent(node2, editor.dom.isBlock);
+ return block1 === block2;
+ };
+
+ var isContentKey = function (e) {
+ if (e.keyCode >= 112 && e.keyCode <= 123) {
+ return false;
+ }
+
+ return true;
+ };
+
+ // Checks if the target node is in a block and if that block has a caret position better than the
+ // suggested caretNode this is to prevent the caret from being sucked in towards a cE=false block if
+ // they are adjacent on the vertical axis
+ var hasBetterMouseTarget = function (targetNode, caretNode) {
+ var targetBlock = editor.dom.getParent(targetNode, editor.dom.isBlock);
+ var caretBlock = editor.dom.getParent(caretNode, editor.dom.isBlock);
+
+ return targetBlock && !isInSameBlock(targetBlock, caretBlock) && hasNormalCaretPosition(targetBlock);
+ };
+
+ handleTouchSelect(editor);
+
+ editor.on('mousedown', function (e) {
+ var contentEditableRoot;
+
+ contentEditableRoot = getContentEditableRoot(e.target);
+ if (contentEditableRoot) {
+ if (isContentEditableFalse(contentEditableRoot)) {
+ e.preventDefault();
+ setContentEditableSelection(selectNode(contentEditableRoot));
+ } else {
+ if (!isXYWithinRange(e.clientX, e.clientY, editor.selection.getRng())) {
+ editor.selection.placeCaretAt(e.clientX, e.clientY);
+ }
+ }
+ } else {
+ // Remove needs to be called here since the mousedown might alter the selection without calling selection.setRng
+ // and therefore not fire the AfterSetSelectionRange event.
+ removeContentEditableSelection();
+ hideFakeCaret();
+
+ var caretInfo = LineUtils.closestCaret(rootNode, e.clientX, e.clientY);
+ if (caretInfo) {
+ if (!hasBetterMouseTarget(e.target, caretInfo.node)) {
+ e.preventDefault();
+ editor.getBody().focus();
+ setRange(showCaret(1, caretInfo.node, caretInfo.before));
+ }
+ }
+ }
+ });
+
+ editor.on('keydown', function (e) {
+ if (VK.modifierPressed(e)) {
+ return;
+ }
+
+ switch (e.keyCode) {
+ case VK.RIGHT:
+ override(e, right);
+ break;
+
+ case VK.DOWN:
+ override(e, down);
+ break;
+
+ case VK.LEFT:
+ override(e, left);
+ break;
+
+ case VK.UP:
+ override(e, up);
+ break;
+
+ default:
+ if (isContentEditableFalse(editor.selection.getNode()) && isContentKey(e)) {
+ e.preventDefault();
+ }
+ break;
+ }
+ });
+
+ editor.on('getSelectionRange', function (e) {
+ var rng = e.range;
+
+ if (selectedContentEditableNode) {
+ if (!selectedContentEditableNode.parentNode) {
+ selectedContentEditableNode = null;
+ return;
+ }
+
+ rng = rng.cloneRange();
+ rng.selectNode(selectedContentEditableNode);
+ e.range = rng;
+ }
+ });
+
+ editor.on('setSelectionRange', function (e) {
+ var rng;
+
+ rng = setContentEditableSelection(e.range);
+ if (rng) {
+ e.range = rng;
+ }
+ });
+
+ editor.on('AfterSetSelectionRange', function (e) {
+ var rng = e.range;
+
+ if (!isRangeInCaretContainer(rng)) {
+ hideFakeCaret();
+ }
+
+ if (!isFakeSelectionElement(rng.startContainer.parentNode)) {
+ removeContentEditableSelection();
+ }
+ });
+
+ editor.on('focus', function () {
+ // Make sure we have a proper fake caret on focus
+ Delay.setEditorTimeout(editor, function () {
+ editor.selection.setRng(renderRangeCaret(editor.selection.getRng()));
+ }, 0);
+ });
+
+ editor.on('copy', function (e) {
+ var clipboardData = e.clipboardData;
+
+ // Make sure we get proper html/text for the fake cE=false selection
+ // Doesn't work at all on Edge since it doesn't have proper clipboardData support
+ if (!e.isDefaultPrevented() && e.clipboardData && !Env.ie) {
+ var realSelectionElement = getRealSelectionElement();
+ if (realSelectionElement) {
+ e.preventDefault();
+ clipboardData.clearData();
+ clipboardData.setData('text/html', realSelectionElement.outerHTML);
+ clipboardData.setData('text/plain', realSelectionElement.outerText);
+ }
+ }
+ });
+
+ DragDropOverrides.init(editor);
+ }
+
+ function addCss() {
+ var styles = editor.contentStyles, rootClass = '.mce-content-body';
+
+ styles.push(fakeCaret.getCss());
+ styles.push(
+ rootClass + ' .mce-offscreen-selection {' +
+ 'position: absolute;' +
+ 'left: -9999999999px;' +
+ 'max-width: 1000000px;' +
+ '}' +
+ rootClass + ' *[contentEditable=false] {' +
+ 'cursor: default;' +
+ '}' +
+ rootClass + ' *[contentEditable=true] {' +
+ 'cursor: text;' +
+ '}'
+ );
+ }
+
+ function isWithinCaretContainer(node) {
+ return (
+ CaretContainer.isCaretContainer(node) ||
+ CaretContainer.startsWithCaretContainer(node) ||
+ CaretContainer.endsWithCaretContainer(node)
+ );
+ }
+
+ function isRangeInCaretContainer(rng) {
+ return isWithinCaretContainer(rng.startContainer) || isWithinCaretContainer(rng.endContainer);
+ }
+
+ function setContentEditableSelection(range) {
+ var node, $ = editor.$, dom = editor.dom, $realSelectionContainer, sel,
+ startContainer, startOffset, endOffset, e, caretPosition, targetClone, origTargetClone;
+
+ if (!range) {
+ return null;
+ }
+
+ if (range.collapsed) {
+ if (!isRangeInCaretContainer(range)) {
+ caretPosition = getNormalizedRangeEndPoint(1, range);
+
+ if (isContentEditableFalse(caretPosition.getNode())) {
+ return showCaret(1, caretPosition.getNode(), !caretPosition.isAtEnd());
+ }
+
+ if (isContentEditableFalse(caretPosition.getNode(true))) {
+ return showCaret(1, caretPosition.getNode(true), false);
+ }
+ }
+
+ return null;
+ }
+
+ startContainer = range.startContainer;
+ startOffset = range.startOffset;
+ endOffset = range.endOffset;
+
+ // Normalizes [] to []
+ if (startContainer.nodeType == 3 && startOffset == 0 && isContentEditableFalse(startContainer.parentNode)) {
+ startContainer = startContainer.parentNode;
+ startOffset = dom.nodeIndex(startContainer);
+ startContainer = startContainer.parentNode;
+ }
+
+ if (startContainer.nodeType != 1) {
+ return null;
+ }
+
+ if (endOffset == startOffset + 1) {
+ node = startContainer.childNodes[startOffset];
+ }
+
+ if (!isContentEditableFalse(node)) {
+ return null;
+ }
+
+ targetClone = origTargetClone = node.cloneNode(true);
+ e = editor.fire('ObjectSelected', { target: node, targetClone: targetClone });
+ if (e.isDefaultPrevented()) {
+ return null;
+ }
+
+ targetClone = e.targetClone;
+ $realSelectionContainer = $('#' + realSelectionId);
+ if ($realSelectionContainer.length === 0) {
+ $realSelectionContainer = $(
+ ''
+ ).attr('id', realSelectionId);
+
+ $realSelectionContainer.appendTo(editor.getBody());
+ }
+
+ range = editor.dom.createRng();
+
+ // WHY is IE making things so hard! Copy on x produces: x
+ // This is a ridiculous hack where we place the selection from a block over the inline element
+ // so that just the inline element is copied as is and not converted.
+ if (targetClone === origTargetClone && Env.ie) {
+ $realSelectionContainer.empty().append('
\u00a0
').append(targetClone);
+ range.setStartAfter($realSelectionContainer[0].firstChild.firstChild);
+ range.setEndAfter(targetClone);
+ } else {
+ $realSelectionContainer.empty().append('\u00a0').append(targetClone).append('\u00a0');
+ range.setStart($realSelectionContainer[0].firstChild, 1);
+ range.setEnd($realSelectionContainer[0].lastChild, 0);
+ }
+
+ $realSelectionContainer.css({
+ top: dom.getPos(node, editor.getBody()).y
+ });
+
+ $realSelectionContainer[0].focus();
+ sel = editor.selection.getSel();
+ sel.removeAllRanges();
+ sel.addRange(range);
+
+ editor.$('*[data-mce-selected]').removeAttr('data-mce-selected');
+ node.setAttribute('data-mce-selected', 1);
+ selectedContentEditableNode = node;
+ hideFakeCaret();
+
+ return range;
+ }
+
+ function removeContentEditableSelection() {
+ if (selectedContentEditableNode) {
+ selectedContentEditableNode.removeAttribute('data-mce-selected');
+ editor.$('#' + realSelectionId).remove();
+ selectedContentEditableNode = null;
+ }
+ }
+
+ function destroy() {
+ fakeCaret.destroy();
+ selectedContentEditableNode = null;
+ }
+
+ function hideFakeCaret() {
+ fakeCaret.hide();
+ }
+
+ if (Env.ceFalse) {
+ registerEvents();
+ addCss();
+ }
+
+ return {
+ showBlockCaretContainer: showBlockCaretContainer,
+ hideFakeCaret: hideFakeCaret,
+ destroy: destroy
+ };
+ }
+
+ return SelectionOverrides;
+ }
+);
+
+/**
+ * NodePath.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 paths of nodes within an element.
+ *
+ * @private
+ * @class tinymce.dom.NodePath
+ */
+define(
+ 'tinymce.core.dom.NodePath',
+ [
+ "tinymce.core.dom.DOMUtils"
+ ],
+ function (DOMUtils) {
+ function create(rootNode, targetNode, normalized) {
+ var path = [];
+
+ for (; targetNode && targetNode != rootNode; targetNode = targetNode.parentNode) {
+ path.push(DOMUtils.nodeIndex(targetNode, normalized));
+ }
+
+ return path;
+ }
+
+ function resolve(rootNode, path) {
+ var i, node, children;
+
+ for (node = rootNode, i = path.length - 1; i >= 0; i--) {
+ children = node.childNodes;
+
+ if (path[i] > children.length - 1) {
+ return null;
+ }
+
+ node = children[path[i]];
+ }
+
+ return node;
+ }
+
+ return {
+ create: create,
+ resolve: resolve
+ };
+ }
+);
+/**
+ * Quirks.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
+ *
+ * @ignore-file
+ */
+
+/**
+ * This file includes fixes for various browser quirks it's made to make it easy to add/remove browser specific fixes.
+ *
+ * @private
+ * @class tinymce.util.Quirks
+ */
+define(
+ 'tinymce.core.util.Quirks',
+ [
+ "tinymce.core.util.VK",
+ "tinymce.core.dom.RangeUtils",
+ "tinymce.core.dom.TreeWalker",
+ "tinymce.core.dom.NodePath",
+ "tinymce.core.html.Node",
+ "tinymce.core.html.Entities",
+ "tinymce.core.Env",
+ "tinymce.core.util.Tools",
+ "tinymce.core.util.Delay",
+ "tinymce.core.caret.CaretContainer",
+ "tinymce.core.caret.CaretPosition",
+ "tinymce.core.caret.CaretWalker"
+ ],
+ function (VK, RangeUtils, TreeWalker, NodePath, Node, Entities, Env, Tools, Delay, CaretContainer, CaretPosition, CaretWalker) {
+ return function (editor) {
+ var each = Tools.each;
+ var BACKSPACE = VK.BACKSPACE, DELETE = VK.DELETE, dom = editor.dom, selection = editor.selection,
+ settings = editor.settings, parser = editor.parser, serializer = editor.serializer;
+ var isGecko = Env.gecko, isIE = Env.ie, isWebKit = Env.webkit;
+ var mceInternalUrlPrefix = 'data:text/mce-internal,';
+ var mceInternalDataType = isIE ? 'Text' : 'URL';
+
+ /**
+ * Executes a command with a specific state this can be to enable/disable browser editing features.
+ */
+ function setEditorCommandState(cmd, state) {
+ try {
+ editor.getDoc().execCommand(cmd, false, state);
+ } catch (ex) {
+ // Ignore
+ }
+ }
+
+ /**
+ * Returns current IE document mode.
+ */
+ function getDocumentMode() {
+ var documentMode = editor.getDoc().documentMode;
+
+ return documentMode ? documentMode : 6;
+ }
+
+ /**
+ * Returns true/false if the event is prevented or not.
+ *
+ * @private
+ * @param {Event} e Event object.
+ * @return {Boolean} true/false if the event is prevented or not.
+ */
+ function isDefaultPrevented(e) {
+ return e.isDefaultPrevented();
+ }
+
+ /**
+ * Sets Text/URL data on the event's dataTransfer object to a special data:text/mce-internal url.
+ * This is to workaround the inability to set custom contentType on IE and Safari.
+ * The editor's selected content is encoded into this url so drag and drop between editors will work.
+ *
+ * @private
+ * @param {DragEvent} e Event object
+ */
+ function setMceInternalContent(e) {
+ var selectionHtml, internalContent;
+
+ if (e.dataTransfer) {
+ if (editor.selection.isCollapsed() && e.target.tagName == 'IMG') {
+ selection.select(e.target);
+ }
+
+ selectionHtml = editor.selection.getContent();
+
+ // Safari/IE doesn't support custom dataTransfer items so we can only use URL and Text
+ if (selectionHtml.length > 0) {
+ internalContent = mceInternalUrlPrefix + escape(editor.id) + ',' + escape(selectionHtml);
+ e.dataTransfer.setData(mceInternalDataType, internalContent);
+ }
+ }
+ }
+
+ /**
+ * Gets content of special data:text/mce-internal url on the event's dataTransfer object.
+ * This is to workaround the inability to set custom contentType on IE and Safari.
+ * The editor's selected content is encoded into this url so drag and drop between editors will work.
+ *
+ * @private
+ * @param {DragEvent} e Event object
+ * @returns {String} mce-internal content
+ */
+ function getMceInternalContent(e) {
+ var internalContent;
+
+ if (e.dataTransfer) {
+ internalContent = e.dataTransfer.getData(mceInternalDataType);
+
+ if (internalContent && internalContent.indexOf(mceInternalUrlPrefix) >= 0) {
+ internalContent = internalContent.substr(mceInternalUrlPrefix.length).split(',');
+
+ return {
+ id: unescape(internalContent[0]),
+ html: unescape(internalContent[1])
+ };
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Inserts contents using the paste clipboard command if it's available if it isn't it will fallback
+ * to the core command.
+ *
+ * @private
+ * @param {String} content Content to insert at selection.
+ * @param {Boolean} internal State if the paste is to be considered internal or external.
+ */
+ function insertClipboardContents(content, internal) {
+ if (editor.queryCommandSupported('mceInsertClipboardContent')) {
+ editor.execCommand('mceInsertClipboardContent', false, { content: content, internal: internal });
+ } else {
+ editor.execCommand('mceInsertContent', false, content);
+ }
+ }
+
+ /**
+ * Makes sure that the editor body becomes empty when backspace or delete is pressed in empty editors.
+ *
+ * For example:
+ *
|
+ *
+ * Or:
+ *
|
+ *
+ * Or:
+ * []
+ */
+ function emptyEditorWhenDeleting() {
+ function serializeRng(rng) {
+ var body = dom.create("body");
+ var contents = rng.cloneContents();
+ body.appendChild(contents);
+ return selection.serializer.serialize(body, { format: 'html' });
+ }
+
+ function allContentsSelected(rng) {
+ if (!rng.setStart) {
+ if (rng.item) {
+ return false;
+ }
+
+ var bodyRng = rng.duplicate();
+ bodyRng.moveToElementText(editor.getBody());
+ return RangeUtils.compareRanges(rng, bodyRng);
+ }
+
+ var selection = serializeRng(rng);
+
+ var allRng = dom.createRng();
+ allRng.selectNode(editor.getBody());
+
+ var allSelection = serializeRng(allRng);
+ return selection === allSelection;
+ }
+
+ editor.on('keydown', function (e) {
+ var keyCode = e.keyCode, isCollapsed, body;
+
+ // Empty the editor if it's needed for example backspace at
|
+ if (!isDefaultPrevented(e) && (keyCode == DELETE || keyCode == BACKSPACE)) {
+ isCollapsed = editor.selection.isCollapsed();
+ body = editor.getBody();
+
+ // Selection is collapsed but the editor isn't empty
+ if (isCollapsed && !dom.isEmpty(body)) {
+ return;
+ }
+
+ // Selection isn't collapsed but not all the contents is selected
+ if (!isCollapsed && !allContentsSelected(editor.selection.getRng())) {
+ return;
+ }
+
+ // Manually empty the editor
+ e.preventDefault();
+ editor.setContent('');
+
+ if (body.firstChild && dom.isBlock(body.firstChild)) {
+ editor.selection.setCursorLocation(body.firstChild, 0);
+ } else {
+ editor.selection.setCursorLocation(body, 0);
+ }
+
+ editor.nodeChanged();
+ }
+ });
+ }
+
+ /**
+ * WebKit doesn't select all the nodes in the body when you press Ctrl+A.
+ * IE selects more than the contents [
a
] instead of
[a]
see bug #6438
+ * This selects the whole body so that backspace/delete logic will delete everything
+ */
+ function selectAll() {
+ editor.shortcuts.add('meta+a', null, 'SelectAll');
+ }
+
+ /**
+ * WebKit has a weird issue where it some times fails to properly convert keypresses to input method keystrokes.
+ * The IME on Mac doesn't initialize when it doesn't fire a proper focus event.
+ *
+ * This seems to happen when the user manages to click the documentElement element then the window doesn't get proper focus until
+ * you enter a character into the editor.
+ *
+ * It also happens when the first focus in made to the body.
+ *
+ * See: https://bugs.webkit.org/show_bug.cgi?id=83566
+ */
+ function inputMethodFocus() {
+ if (!editor.settings.content_editable) {
+ // Case 1 IME doesn't initialize if you focus the document
+ // Disabled since it was interferring with the cE=false logic
+ // Also coultn't reproduce the issue on Safari 9
+ /*dom.bind(editor.getDoc(), 'focusin', function() {
+ selection.setRng(selection.getRng());
+ });*/
+
+ // Case 2 IME doesn't initialize if you click the documentElement it also doesn't properly fire the focusin event
+ // Needs to be both down/up due to weird rendering bug on Chrome Windows
+ dom.bind(editor.getDoc(), 'mousedown mouseup', function (e) {
+ var rng;
+
+ if (e.target == editor.getDoc().documentElement) {
+ rng = selection.getRng();
+ editor.getBody().focus();
+
+ if (e.type == 'mousedown') {
+ if (CaretContainer.isCaretContainer(rng.startContainer)) {
+ return;
+ }
+
+ // Edge case for mousedown, drag select and mousedown again within selection on Chrome Windows to render caret
+ selection.placeCaretAt(e.clientX, e.clientY);
+ } else {
+ selection.setRng(rng);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Backspacing in FireFox/IE from a paragraph into a horizontal rule results in a floating text node because the
+ * browser just deletes the paragraph - the browser fails to merge the text node with a horizontal rule so it is
+ * left there. TinyMCE sees a floating text node and wraps it in a paragraph on the key up event (ForceBlocks.js
+ * addRootBlocks), meaning the action does nothing. With this code, FireFox/IE matche the behaviour of other
+ * browsers.
+ *
+ * It also fixes a bug on Firefox where it's impossible to delete HR elements.
+ */
+ function removeHrOnBackspace() {
+ editor.on('keydown', function (e) {
+ if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
+ // Check if there is any HR elements this is faster since getRng on IE 7 & 8 is slow
+ if (!editor.getBody().getElementsByTagName('hr').length) {
+ return;
+ }
+
+ if (selection.isCollapsed() && selection.getRng(true).startOffset === 0) {
+ var node = selection.getNode();
+ var previousSibling = node.previousSibling;
+
+ if (node.nodeName == 'HR') {
+ dom.remove(node);
+ e.preventDefault();
+ return;
+ }
+
+ if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === "hr") {
+ dom.remove(previousSibling);
+ e.preventDefault();
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Firefox 3.x has an issue where the body element won't get proper focus if you click out
+ * side it's rectangle.
+ */
+ function focusBody() {
+ // Fix for a focus bug in FF 3.x where the body element
+ // wouldn't get proper focus if the user clicked on the HTML element
+ if (!window.Range.prototype.getClientRects) { // Detect getClientRects got introduced in FF 4
+ editor.on('mousedown', function (e) {
+ if (!isDefaultPrevented(e) && e.target.nodeName === "HTML") {
+ var body = editor.getBody();
+
+ // Blur the body it's focused but not correctly focused
+ body.blur();
+
+ // Refocus the body after a little while
+ Delay.setEditorTimeout(editor, function () {
+ body.focus();
+ });
+ }
+ });
+ }
+ }
+
+ /**
+ * WebKit has a bug where it isn't possible to select image, hr or anchor elements
+ * by clicking on them so we need to fake that.
+ */
+ function selectControlElements() {
+ editor.on('click', function (e) {
+ var target = e.target;
+
+ // Workaround for bug, http://bugs.webkit.org/show_bug.cgi?id=12250
+ // WebKit can't even do simple things like selecting an image
+ // Needs to be the setBaseAndExtend or it will fail to select floated images
+ if (/^(IMG|HR)$/.test(target.nodeName) && dom.getContentEditableParent(target) !== "false") {
+ e.preventDefault();
+ editor.selection.select(target);
+ editor.nodeChanged();
+ }
+
+ if (target.nodeName == 'A' && dom.hasClass(target, 'mce-item-anchor')) {
+ e.preventDefault();
+ selection.select(target);
+ }
+ });
+ }
+
+ /**
+ * Fixes a Gecko bug where the style attribute gets added to the wrong element when deleting between two block elements.
+ *
+ * Fixes do backspace/delete on this:
+ *
bla[ck
r]ed
+ *
+ * Would become:
+ *
bla|ed
+ *
+ * Instead of:
+ *
bla|ed
+ */
+ function removeStylesWhenDeletingAcrossBlockElements() {
+ function getAttributeApplyFunction() {
+ var template = dom.getAttribs(selection.getStart().cloneNode(false));
+
+ return function () {
+ var target = selection.getStart();
+
+ if (target !== editor.getBody()) {
+ dom.setAttrib(target, "style", null);
+
+ each(template, function (attr) {
+ target.setAttributeNode(attr.cloneNode(true));
+ });
+ }
+ };
+ }
+
+ function isSelectionAcrossElements() {
+ return !selection.isCollapsed() &&
+ dom.getParent(selection.getStart(), dom.isBlock) != dom.getParent(selection.getEnd(), dom.isBlock);
+ }
+
+ editor.on('keypress', function (e) {
+ var applyAttributes;
+
+ if (!isDefaultPrevented(e) && (e.keyCode == 8 || e.keyCode == 46) && isSelectionAcrossElements()) {
+ applyAttributes = getAttributeApplyFunction();
+ editor.getDoc().execCommand('delete', false, null);
+ applyAttributes();
+ e.preventDefault();
+ return false;
+ }
+ });
+
+ dom.bind(editor.getDoc(), 'cut', function (e) {
+ var applyAttributes;
+
+ if (!isDefaultPrevented(e) && isSelectionAcrossElements()) {
+ applyAttributes = getAttributeApplyFunction();
+
+ Delay.setEditorTimeout(editor, function () {
+ applyAttributes();
+ });
+ }
+ });
+ }
+
+ /**
+ * Screen readers on IE needs to have the role application set on the body.
+ */
+ function ensureBodyHasRoleApplication() {
+ document.body.setAttribute("role", "application");
+ }
+
+ /**
+ * Backspacing into a table behaves differently depending upon browser type.
+ * Therefore, disable Backspace when cursor immediately follows a table.
+ */
+ function disableBackspaceIntoATable() {
+ editor.on('keydown', function (e) {
+ if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
+ if (selection.isCollapsed() && selection.getRng(true).startOffset === 0) {
+ var previousSibling = selection.getNode().previousSibling;
+ if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === "table") {
+ e.preventDefault();
+ return false;
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Old IE versions can't properly render BR elements in PRE tags white in contentEditable mode. So this
+ * logic adds a \n before the BR so that it will get rendered.
+ */
+ function addNewLinesBeforeBrInPre() {
+ // IE8+ rendering mode does the right thing with BR in PRE
+ if (getDocumentMode() > 7) {
+ return;
+ }
+
+ // Enable display: none in area and add a specific class that hides all BR elements in PRE to
+ // avoid the caret from getting stuck at the BR elements while pressing the right arrow key
+ setEditorCommandState('RespectVisibilityInDesign', true);
+ editor.contentStyles.push('.mceHideBrInPre pre br {display: none}');
+ dom.addClass(editor.getBody(), 'mceHideBrInPre');
+
+ // Adds a \n before all BR elements in PRE to get them visual
+ parser.addNodeFilter('pre', function (nodes) {
+ var i = nodes.length, brNodes, j, brElm, sibling;
+
+ while (i--) {
+ brNodes = nodes[i].getAll('br');
+ j = brNodes.length;
+ while (j--) {
+ brElm = brNodes[j];
+
+ // Add \n before BR in PRE elements on older IE:s so the new lines get rendered
+ sibling = brElm.prev;
+ if (sibling && sibling.type === 3 && sibling.value.charAt(sibling.value - 1) != '\n') {
+ sibling.value += '\n';
+ } else {
+ brElm.parent.insert(new Node('#text', 3), brElm, true).value = '\n';
+ }
+ }
+ }
+ });
+
+ // Removes any \n before BR elements in PRE since other browsers and in contentEditable=false mode they will be visible
+ serializer.addNodeFilter('pre', function (nodes) {
+ var i = nodes.length, brNodes, j, brElm, sibling;
+
+ while (i--) {
+ brNodes = nodes[i].getAll('br');
+ j = brNodes.length;
+ while (j--) {
+ brElm = brNodes[j];
+ sibling = brElm.prev;
+ if (sibling && sibling.type == 3) {
+ sibling.value = sibling.value.replace(/\r?\n$/, '');
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Moves style width/height to attribute width/height when the user resizes an image on IE.
+ */
+ function removePreSerializedStylesWhenSelectingControls() {
+ dom.bind(editor.getBody(), 'mouseup', function () {
+ var value, node = selection.getNode();
+
+ // Moved styles to attributes on IMG eements
+ if (node.nodeName == 'IMG') {
+ // Convert style width to width attribute
+ if ((value = dom.getStyle(node, 'width'))) {
+ dom.setAttrib(node, 'width', value.replace(/[^0-9%]+/g, ''));
+ dom.setStyle(node, 'width', '');
+ }
+
+ // Convert style height to height attribute
+ if ((value = dom.getStyle(node, 'height'))) {
+ dom.setAttrib(node, 'height', value.replace(/[^0-9%]+/g, ''));
+ dom.setStyle(node, 'height', '');
+ }
+ }
+ });
+ }
+
+ /**
+ * Removes a blockquote when backspace is pressed at the beginning of it.
+ *
+ * For example:
+ *
|x
+ *
+ * Becomes:
+ *
|x
+ */
+ function removeBlockQuoteOnBackSpace() {
+ // Add block quote deletion handler
+ editor.on('keydown', function (e) {
+ var rng, container, offset, root, parent;
+
+ if (isDefaultPrevented(e) || e.keyCode != VK.BACKSPACE) {
+ return;
+ }
+
+ rng = selection.getRng();
+ container = rng.startContainer;
+ offset = rng.startOffset;
+ root = dom.getRoot();
+ parent = container;
+
+ if (!rng.collapsed || offset !== 0) {
+ return;
+ }
+
+ while (parent && parent.parentNode && parent.parentNode.firstChild == parent && parent.parentNode != root) {
+ parent = parent.parentNode;
+ }
+
+ // Is the cursor at the beginning of a blockquote?
+ if (parent.tagName === 'BLOCKQUOTE') {
+ // Remove the blockquote
+ editor.formatter.toggle('blockquote', null, parent);
+
+ // Move the caret to the beginning of container
+ rng = dom.createRng();
+ rng.setStart(container, 0);
+ rng.setEnd(container, 0);
+ selection.setRng(rng);
+ }
+ });
+ }
+
+ /**
+ * Sets various Gecko editing options on mouse down and before a execCommand to disable inline table editing that is broken etc.
+ */
+ function setGeckoEditingOptions() {
+ function setOpts() {
+ refreshContentEditable();
+
+ setEditorCommandState("StyleWithCSS", false);
+ setEditorCommandState("enableInlineTableEditing", false);
+
+ if (!settings.object_resizing) {
+ setEditorCommandState("enableObjectResizing", false);
+ }
+ }
+
+ if (!settings.readonly) {
+ editor.on('BeforeExecCommand MouseDown', setOpts);
+ }
+ }
+
+ /**
+ * Fixes a gecko link bug, when a link is placed at the end of block elements there is
+ * no way to move the caret behind the link. This fix adds a bogus br element after the link.
+ *
+ * For example this:
+ *
+ */
+ function addBrAfterLastLinks() {
+ function fixLinks() {
+ each(dom.select('a'), function (node) {
+ var parentNode = node.parentNode, root = dom.getRoot();
+
+ if (parentNode.lastChild === node) {
+ while (parentNode && !dom.isBlock(parentNode)) {
+ if (parentNode.parentNode.lastChild !== parentNode || parentNode === root) {
+ return;
+ }
+
+ parentNode = parentNode.parentNode;
+ }
+
+ dom.add(parentNode, 'br', { 'data-mce-bogus': 1 });
+ }
+ });
+ }
+
+ editor.on('SetContent ExecCommand', function (e) {
+ if (e.type == "setcontent" || e.command === 'mceInsertLink') {
+ fixLinks();
+ }
+ });
+ }
+
+ /**
+ * WebKit will produce DIV elements here and there by default. But since TinyMCE uses paragraphs by
+ * default we want to change that behavior.
+ */
+ function setDefaultBlockType() {
+ if (settings.forced_root_block) {
+ editor.on('init', function () {
+ setEditorCommandState('DefaultParagraphSeparator', settings.forced_root_block);
+ });
+ }
+ }
+
+ /**
+ * Deletes the selected image on IE instead of navigating to previous page.
+ */
+ function deleteControlItemOnBackSpace() {
+ editor.on('keydown', function (e) {
+ var rng;
+
+ if (!isDefaultPrevented(e) && e.keyCode == BACKSPACE) {
+ rng = editor.getDoc().selection.createRange();
+ if (rng && rng.item) {
+ e.preventDefault();
+ editor.undoManager.beforeChange();
+ dom.remove(rng.item(0));
+ editor.undoManager.add();
+ }
+ }
+ });
+ }
+
+ /**
+ * IE10 doesn't properly render block elements with the right height until you add contents to them.
+ * This fixes that by adding a padding-right to all empty text block elements.
+ * See: https://connect.microsoft.com/IE/feedback/details/743881
+ */
+ function renderEmptyBlocksFix() {
+ var emptyBlocksCSS;
+
+ // IE10+
+ if (getDocumentMode() >= 10) {
+ emptyBlocksCSS = '';
+ each('p div h1 h2 h3 h4 h5 h6'.split(' '), function (name, i) {
+ emptyBlocksCSS += (i > 0 ? ',' : '') + name + ':empty';
+ });
+
+ editor.contentStyles.push(emptyBlocksCSS + '{padding-right: 1px !important}');
+ }
+ }
+
+ /**
+ * Old IE versions can't retain contents within noscript elements so this logic will store the contents
+ * as a attribute and the insert that value as it's raw text when the DOM is serialized.
+ */
+ function keepNoScriptContents() {
+ if (getDocumentMode() < 9) {
+ parser.addNodeFilter('noscript', function (nodes) {
+ var i = nodes.length, node, textNode;
+
+ while (i--) {
+ node = nodes[i];
+ textNode = node.firstChild;
+
+ if (textNode) {
+ node.attr('data-mce-innertext', textNode.value);
+ }
+ }
+ });
+
+ serializer.addNodeFilter('noscript', function (nodes) {
+ var i = nodes.length, node, textNode, value;
+
+ while (i--) {
+ node = nodes[i];
+ textNode = nodes[i].firstChild;
+
+ if (textNode) {
+ textNode.value = Entities.decode(textNode.value);
+ } else {
+ // Old IE can't retain noscript value so an attribute is used to store it
+ value = node.attributes.map['data-mce-innertext'];
+ if (value) {
+ node.attr('data-mce-innertext', null);
+ textNode = new Node('#text', 3);
+ textNode.value = value;
+ textNode.raw = true;
+ node.append(textNode);
+ }
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * IE has an issue where you can't select/move the caret by clicking outside the body if the document is in standards mode.
+ */
+ function fixCaretSelectionOfDocumentElementOnIe() {
+ var doc = dom.doc, body = doc.body, started, startRng, htmlElm;
+
+ // Return range from point or null if it failed
+ function rngFromPoint(x, y) {
+ var rng = body.createTextRange();
+
+ try {
+ rng.moveToPoint(x, y);
+ } catch (ex) {
+ // IE sometimes throws and exception, so lets just ignore it
+ rng = null;
+ }
+
+ return rng;
+ }
+
+ // Fires while the selection is changing
+ function selectionChange(e) {
+ var pointRng;
+
+ // Check if the button is down or not
+ if (e.button) {
+ // Create range from mouse position
+ pointRng = rngFromPoint(e.x, e.y);
+
+ if (pointRng) {
+ // Check if pointRange is before/after selection then change the endPoint
+ if (pointRng.compareEndPoints('StartToStart', startRng) > 0) {
+ pointRng.setEndPoint('StartToStart', startRng);
+ } else {
+ pointRng.setEndPoint('EndToEnd', startRng);
+ }
+
+ pointRng.select();
+ }
+ } else {
+ endSelection();
+ }
+ }
+
+ // Removes listeners
+ function endSelection() {
+ var rng = doc.selection.createRange();
+
+ // If the range is collapsed then use the last start range
+ if (startRng && !rng.item && rng.compareEndPoints('StartToEnd', rng) === 0) {
+ startRng.select();
+ }
+
+ dom.unbind(doc, 'mouseup', endSelection);
+ dom.unbind(doc, 'mousemove', selectionChange);
+ startRng = started = 0;
+ }
+
+ // Make HTML element unselectable since we are going to handle selection by hand
+ doc.documentElement.unselectable = true;
+
+ // Detect when user selects outside BODY
+ dom.bind(doc, 'mousedown contextmenu', function (e) {
+ if (e.target.nodeName === 'HTML') {
+ if (started) {
+ endSelection();
+ }
+
+ // Detect vertical scrollbar, since IE will fire a mousedown on the scrollbar and have target set as HTML
+ htmlElm = doc.documentElement;
+ if (htmlElm.scrollHeight > htmlElm.clientHeight) {
+ return;
+ }
+
+ started = 1;
+ // Setup start position
+ startRng = rngFromPoint(e.x, e.y);
+ if (startRng) {
+ // Listen for selection change events
+ dom.bind(doc, 'mouseup', endSelection);
+ dom.bind(doc, 'mousemove', selectionChange);
+
+ dom.getRoot().focus();
+ startRng.select();
+ }
+ }
+ });
+ }
+
+ /**
+ * Fixes selection issues where the caret can be placed between two inline elements like a|b
+ * this fix will lean the caret right into the closest inline element.
+ */
+ function normalizeSelection() {
+ // Normalize selection for example a|a becomes a|a except for Ctrl+A since it selects everything
+ editor.on('keyup focusin mouseup', function (e) {
+ if (e.keyCode != 65 || !VK.metaKeyPressed(e)) {
+ selection.normalize();
+ }
+ }, true);
+ }
+
+ /**
+ * Forces Gecko to render a broken image icon if it fails to load an image.
+ */
+ function showBrokenImageIcon() {
+ editor.contentStyles.push(
+ 'img:-moz-broken {' +
+ '-moz-force-broken-image-icon:1;' +
+ 'min-width:24px;' +
+ 'min-height:24px' +
+ '}'
+ );
+ }
+
+ /**
+ * iOS has a bug where it's impossible to type if the document has a touchstart event
+ * bound and the user touches the document while having the on screen keyboard visible.
+ *
+ * The touch event moves the focus to the parent document while having the caret inside the iframe
+ * this fix moves the focus back into the iframe document.
+ */
+ function restoreFocusOnKeyDown() {
+ if (!editor.inline) {
+ editor.on('keydown', function () {
+ if (document.activeElement == document.body) {
+ editor.getWin().focus();
+ }
+ });
+ }
+ }
+
+ /**
+ * IE 11 has an annoying issue where you can't move focus into the editor
+ * by clicking on the white area HTML element. We used to be able to to fix this with
+ * the fixCaretSelectionOfDocumentElementOnIe fix. But since M$ removed the selection
+ * object it's not possible anymore. So we need to hack in a ungly CSS to force the
+ * body to be at least 150px. If the user clicks the HTML element out side this 150px region
+ * we simply move the focus into the first paragraph. Not ideal since you loose the
+ * positioning of the caret but goot enough for most cases.
+ */
+ function bodyHeight() {
+ if (!editor.inline) {
+ editor.contentStyles.push('body {min-height: 150px}');
+ editor.on('click', function (e) {
+ var rng;
+
+ if (e.target.nodeName == 'HTML') {
+ // Edge seems to only need focus if we set the range
+ // the caret will become invisible and moved out of the iframe!!
+ if (Env.ie > 11) {
+ editor.getBody().focus();
+ return;
+ }
+
+ // Need to store away non collapsed ranges since the focus call will mess that up see #7382
+ rng = editor.selection.getRng();
+ editor.getBody().focus();
+ editor.selection.setRng(rng);
+ editor.selection.normalize();
+ editor.nodeChanged();
+ }
+ });
+ }
+ }
+
+ /**
+ * Firefox on Mac OS will move the browser back to the previous page if you press CMD+Left arrow.
+ * You might then loose all your work so we need to block that behavior and replace it with our own.
+ */
+ function blockCmdArrowNavigation() {
+ if (Env.mac) {
+ editor.on('keydown', function (e) {
+ if (VK.metaKeyPressed(e) && !e.shiftKey && (e.keyCode == 37 || e.keyCode == 39)) {
+ e.preventDefault();
+ editor.selection.getSel().modify('move', e.keyCode == 37 ? 'backward' : 'forward', 'lineboundary');
+ }
+ });
+ }
+ }
+
+ /**
+ * Disables the autolinking in IE 9+ this is then re-enabled by the autolink plugin.
+ */
+ function disableAutoUrlDetect() {
+ setEditorCommandState("AutoUrlDetect", false);
+ }
+
+ /**
+ * iOS 7.1 introduced two new bugs:
+ * 1) It's possible to open links within a contentEditable area by clicking on them.
+ * 2) If you hold down the finger it will display the link/image touch callout menu.
+ */
+ function tapLinksAndImages() {
+ editor.on('click', function (e) {
+ var elm = e.target;
+
+ do {
+ if (elm.tagName === 'A') {
+ e.preventDefault();
+ return;
+ }
+ } while ((elm = elm.parentNode));
+ });
+
+ editor.contentStyles.push('.mce-content-body {-webkit-touch-callout: none}');
+ }
+
+ /**
+ * iOS Safari and possible other browsers have a bug where it won't fire
+ * a click event when a contentEditable is focused. This function fakes click events
+ * by using touchstart/touchend and measuring the time and distance travelled.
+ */
+ /*
+ function touchClickEvent() {
+ editor.on('touchstart', function(e) {
+ var elm, time, startTouch, changedTouches;
+
+ elm = e.target;
+ time = new Date().getTime();
+ changedTouches = e.changedTouches;
+
+ if (!changedTouches || changedTouches.length > 1) {
+ return;
+ }
+
+ startTouch = changedTouches[0];
+
+ editor.once('touchend', function(e) {
+ var endTouch = e.changedTouches[0], args;
+
+ if (new Date().getTime() - time > 500) {
+ return;
+ }
+
+ if (Math.abs(startTouch.clientX - endTouch.clientX) > 5) {
+ return;
+ }
+
+ if (Math.abs(startTouch.clientY - endTouch.clientY) > 5) {
+ return;
+ }
+
+ args = {
+ target: elm
+ };
+
+ each('pageX pageY clientX clientY screenX screenY'.split(' '), function(key) {
+ args[key] = endTouch[key];
+ });
+
+ args = editor.fire('click', args);
+
+ if (!args.isDefaultPrevented()) {
+ // iOS WebKit can't place the caret properly once
+ // you bind touch events so we need to do this manually
+ // TODO: Expand to the closest word? Touble tap still works.
+ editor.selection.placeCaretAt(endTouch.clientX, endTouch.clientY);
+ editor.nodeChanged();
+ }
+ });
+ });
+ }
+ */
+
+ /**
+ * WebKit has a bug where it will allow forms to be submitted if they are inside a contentEditable element.
+ * For example this:
+ */
+ function blockFormSubmitInsideEditor() {
+ editor.on('init', function () {
+ editor.dom.bind(editor.getBody(), 'submit', function (e) {
+ e.preventDefault();
+ });
+ });
+ }
+
+ /**
+ * Sometimes WebKit/Blink generates BR elements with the Apple-interchange-newline class.
+ *
+ * Scenario:
+ * 1) Create a table 2x2.
+ * 2) Select and copy cells A2-B2.
+ * 3) Paste and it will add BR element to table cell.
+ */
+ function removeAppleInterchangeBrs() {
+ parser.addNodeFilter('br', function (nodes) {
+ var i = nodes.length;
+
+ while (i--) {
+ if (nodes[i].attr('class') == 'Apple-interchange-newline') {
+ nodes[i].remove();
+ }
+ }
+ });
+ }
+
+ /**
+ * IE cannot set custom contentType's on drag events, and also does not properly drag/drop between
+ * editors. This uses a special data:text/mce-internal URL to pass data when drag/drop between editors.
+ */
+ function ieInternalDragAndDrop() {
+ editor.on('dragstart', function (e) {
+ setMceInternalContent(e);
+ });
+
+ editor.on('drop', function (e) {
+ if (!isDefaultPrevented(e)) {
+ var internalContent = getMceInternalContent(e);
+
+ if (internalContent && internalContent.id != editor.id) {
+ e.preventDefault();
+
+ var rng = RangeUtils.getCaretRangeFromPoint(e.x, e.y, editor.getDoc());
+ selection.setRng(rng);
+ insertClipboardContents(internalContent.html, true);
+ }
+ }
+ });
+ }
+
+ function refreshContentEditable() {
+ // No-op since Mozilla seems to have fixed the caret repaint issues
+ }
+
+ function isHidden() {
+ var sel;
+
+ if (!isGecko) {
+ return 0;
+ }
+
+ // Weird, wheres that cursor selection?
+ sel = editor.selection.getSel();
+ return (!sel || !sel.rangeCount || sel.rangeCount === 0);
+ }
+
+ /**
+ * 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();
+ }
+ }
+ });
+ }
+
+ // All browsers
+ removeBlockQuoteOnBackSpace();
+ emptyEditorWhenDeleting();
+
+ // Windows phone will return a range like [body, 0] on mousedown so
+ // it will always normalize to the wrong location
+ if (!Env.windowsPhone) {
+ normalizeSelection();
+ }
+
+ // WebKit
+ if (isWebKit) {
+ emptyEditorOnDeleteEverything();
+ inputMethodFocus();
+ selectControlElements();
+ setDefaultBlockType();
+ blockFormSubmitInsideEditor();
+ disableBackspaceIntoATable();
+ removeAppleInterchangeBrs();
+
+ //touchClickEvent();
+
+ // iOS
+ if (Env.iOS) {
+ restoreFocusOnKeyDown();
+ bodyHeight();
+ tapLinksAndImages();
+ } else {
+ selectAll();
+ }
+ }
+
+ // IE
+ if (isIE && Env.ie < 11) {
+ removeHrOnBackspace();
+ ensureBodyHasRoleApplication();
+ addNewLinesBeforeBrInPre();
+ removePreSerializedStylesWhenSelectingControls();
+ deleteControlItemOnBackSpace();
+ renderEmptyBlocksFix();
+ keepNoScriptContents();
+ fixCaretSelectionOfDocumentElementOnIe();
+ }
+
+ if (Env.ie >= 11) {
+ bodyHeight();
+ disableBackspaceIntoATable();
+ }
+
+ if (Env.ie) {
+ selectAll();
+ disableAutoUrlDetect();
+ ieInternalDragAndDrop();
+ }
+
+ // Gecko
+ if (isGecko) {
+ emptyEditorOnDeleteEverything();
+ removeHrOnBackspace();
+ focusBody();
+ removeStylesWhenDeletingAcrossBlockElements();
+ setGeckoEditingOptions();
+ addBrAfterLastLinks();
+ showBrokenImageIcon();
+ blockCmdArrowNavigation();
+ disableBackspaceIntoATable();
+ }
+
+ return {
+ refreshContentEditable: refreshContentEditable,
+ isHidden: isHidden
+ };
+ };
+ }
+);
+
+/**
+ * InitContentBody.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.init.InitContentBody',
+ [
+ 'global!document',
+ 'global!window',
+ 'tinymce.core.caret.CaretContainerInput',
+ 'tinymce.core.dom.DOMUtils',
+ 'tinymce.core.dom.Selection',
+ 'tinymce.core.dom.Serializer',
+ 'tinymce.core.EditorUpload',
+ 'tinymce.core.ErrorReporter',
+ 'tinymce.core.ForceBlocks',
+ 'tinymce.core.Formatter',
+ 'tinymce.core.html.DomParser',
+ 'tinymce.core.html.Node',
+ 'tinymce.core.html.Schema',
+ 'tinymce.core.keyboard.KeyboardOverrides',
+ 'tinymce.core.NodeChange',
+ 'tinymce.core.SelectionOverrides',
+ 'tinymce.core.UndoManager',
+ 'tinymce.core.util.Delay',
+ 'tinymce.core.util.Quirks',
+ 'tinymce.core.util.Tools'
+ ],
+ function (
+ document, window, CaretContainerInput, DOMUtils, Selection, Serializer, EditorUpload, ErrorReporter, ForceBlocks, Formatter, DomParser, Node, Schema, KeyboardOverrides,
+ NodeChange, SelectionOverrides, UndoManager, Delay, Quirks, Tools
+ ) {
+ var DOM = DOMUtils.DOM;
+
+ var createParser = function (editor) {
+ var parser = new DomParser(editor.settings, editor.schema);
+
+ // Convert src and href into data-mce-src, data-mce-href and data-mce-style
+ parser.addAttributeFilter('src,href,style,tabindex', function (nodes, name) {
+ var i = nodes.length, node, dom = editor.dom, value, internalName;
+
+ while (i--) {
+ node = nodes[i];
+ value = node.attr(name);
+ internalName = 'data-mce-' + name;
+
+ // Add internal attribute if we need to we don't on a refresh of the document
+ if (!node.attributes.map[internalName]) {
+ // Don't duplicate these since they won't get modified by any browser
+ if (value.indexOf('data:') === 0 || value.indexOf('blob:') === 0) {
+ continue;
+ }
+
+ if (name === "style") {
+ value = dom.serializeStyle(dom.parseStyle(value), node.name);
+
+ if (!value.length) {
+ value = null;
+ }
+
+ node.attr(internalName, value);
+ node.attr(name, value);
+ } else if (name === "tabindex") {
+ node.attr(internalName, value);
+ node.attr(name, null);
+ } else {
+ node.attr(internalName, editor.convertURL(value, name, node.name));
+ }
+ }
+ }
+ });
+
+ // Keep scripts from executing
+ parser.addNodeFilter('script', function (nodes) {
+ var i = nodes.length, node, type;
+
+ while (i--) {
+ node = nodes[i];
+ type = node.attr('type') || 'no/type';
+ if (type.indexOf('mce-') !== 0) {
+ node.attr('type', 'mce-' + type);
+ }
+ }
+ });
+
+ parser.addNodeFilter('#cdata', function (nodes) {
+ var i = nodes.length, node;
+
+ while (i--) {
+ node = nodes[i];
+ node.type = 8;
+ node.name = '#comment';
+ node.value = '[CDATA[' + node.value + ']]';
+ }
+ });
+
+ parser.addNodeFilter('p,h1,h2,h3,h4,h5,h6,div', function (nodes) {
+ var i = nodes.length, node, nonEmptyElements = editor.schema.getNonEmptyElements();
+
+ while (i--) {
+ node = nodes[i];
+
+ if (node.isEmpty(nonEmptyElements) && node.getAll('br').length === 0) {
+ node.append(new Node('br', 1)).shortEnded = true;
+ }
+ }
+ });
+
+ return parser;
+ };
+
+ var autoFocus = function (editor) {
+ if (editor.settings.auto_focus) {
+ Delay.setEditorTimeout(editor, function () {
+ var focusEditor;
+
+ if (editor.settings.auto_focus === true) {
+ focusEditor = editor;
+ } else {
+ focusEditor = editor.editorManager.get(editor.settings.auto_focus);
+ }
+
+ if (!focusEditor.destroyed) {
+ focusEditor.focus();
+ }
+ }, 100);
+ }
+ };
+
+ var initEditor = function (editor) {
+ editor.bindPendingEventDelegates();
+ editor.initialized = true;
+ editor.fire('init');
+ editor.focus(true);
+ editor.nodeChanged({ initial: true });
+ editor.execCallback('init_instance_callback', editor);
+ autoFocus(editor);
+ };
+
+ var initContentBody = function (editor, skipWrite) {
+ var settings = editor.settings, targetElm = editor.getElement(), doc = editor.getDoc(), body, contentCssText;
+
+ // Restore visibility on target element
+ if (!settings.inline) {
+ editor.getElement().style.visibility = editor.orgVisibility;
+ }
+
+ // Setup iframe body
+ if (!skipWrite && !settings.content_editable) {
+ doc.open();
+ doc.write(editor.iframeHTML);
+ doc.close();
+ }
+
+ if (settings.content_editable) {
+ editor.on('remove', function () {
+ var bodyEl = this.getBody();
+
+ DOM.removeClass(bodyEl, 'mce-content-body');
+ DOM.removeClass(bodyEl, 'mce-edit-focus');
+ DOM.setAttrib(bodyEl, 'contentEditable', null);
+ });
+
+ DOM.addClass(targetElm, 'mce-content-body');
+ editor.contentDocument = doc = settings.content_document || document;
+ editor.contentWindow = settings.content_window || window;
+ editor.bodyElement = targetElm;
+
+ // Prevent leak in IE
+ settings.content_document = settings.content_window = null;
+
+ // TODO: Fix this
+ settings.root_name = targetElm.nodeName.toLowerCase();
+ }
+
+ // It will not steal focus while setting contentEditable
+ body = editor.getBody();
+ body.disabled = true;
+ editor.readonly = settings.readonly;
+
+ if (!editor.readonly) {
+ if (editor.inline && DOM.getStyle(body, 'position', true) === 'static') {
+ body.style.position = 'relative';
+ }
+
+ body.contentEditable = editor.getParam('content_editable_state', true);
+ }
+
+ body.disabled = false;
+
+ editor.editorUpload = new EditorUpload(editor);
+ editor.schema = new Schema(settings);
+ editor.dom = new DOMUtils(doc, {
+ keep_values: true,
+ url_converter: editor.convertURL,
+ url_converter_scope: editor,
+ hex_colors: settings.force_hex_style_colors,
+ class_filter: settings.class_filter,
+ update_styles: true,
+ root_element: editor.inline ? editor.getBody() : null,
+ collect: settings.content_editable,
+ schema: editor.schema,
+ onSetAttrib: function (e) {
+ editor.fire('SetAttrib', e);
+ }
+ });
+
+ editor.parser = createParser(editor);
+ editor.serializer = new Serializer(settings, editor);
+ editor.selection = new Selection(editor.dom, editor.getWin(), editor.serializer, editor);
+ editor.formatter = new Formatter(editor);
+ editor.undoManager = new UndoManager(editor);
+ editor._nodeChangeDispatcher = new NodeChange(editor);
+ editor._selectionOverrides = new SelectionOverrides(editor);
+
+ CaretContainerInput.setup(editor);
+ KeyboardOverrides.setup(editor);
+ ForceBlocks.setup(editor);
+
+ editor.fire('PreInit');
+
+ if (!settings.browser_spellcheck && !settings.gecko_spellcheck) {
+ doc.body.spellcheck = false; // Gecko
+ DOM.setAttrib(body, "spellcheck", "false");
+ }
+
+ editor.quirks = new Quirks(editor);
+ editor.fire('PostRender');
+
+ if (settings.directionality) {
+ body.dir = settings.directionality;
+ }
+
+ if (settings.nowrap) {
+ body.style.whiteSpace = "nowrap";
+ }
+
+ if (settings.protect) {
+ editor.on('BeforeSetContent', function (e) {
+ Tools.each(settings.protect, function (pattern) {
+ e.content = e.content.replace(pattern, function (str) {
+ return '';
+ });
+ });
+ });
+ }
+
+ editor.on('SetContent', function () {
+ editor.addVisual(editor.getBody());
+ });
+
+ // Remove empty contents
+ if (settings.padd_empty_editor) {
+ editor.on('PostProcess', function (e) {
+ e.content = e.content.replace(/^(
';
+
+ // We only need to override paths if we have to
+ // IE has a bug where it remove site absolute urls to relative ones if this is specified
+ if (settings.document_base_url != editor.documentBaseUrl) {
+ editor.iframeHTML += '';
+ }
+
+ // IE8 doesn't support carets behind images setting ie7_compat would force IE8+ to run in IE7 compat mode.
+ if (!Env.caretAfter && settings.ie7_compat) {
+ editor.iframeHTML += '';
+ }
+
+ editor.iframeHTML += '';
+
+ bodyId = settings.body_id || 'tinymce';
+ if (bodyId.indexOf('=') != -1) {
+ bodyId = editor.getParam('body_id', '', 'hash');
+ bodyId = bodyId[editor.id] || bodyId;
+ }
+
+ bodyClass = settings.body_class || '';
+ if (bodyClass.indexOf('=') != -1) {
+ bodyClass = editor.getParam('body_class', '', 'hash');
+ bodyClass = bodyClass[editor.id] || '';
+ }
+
+ if (settings.content_security_policy) {
+ editor.iframeHTML += '';
+ }
+
+ editor.iframeHTML += ' ';
+
+ var bodyUuid = Uuid.uuid('mce');
+
+ editor[bodyUuid] = function () {
+ InitContentBody.initContentBody(editor);
+ };
+
+ /*eslint no-script-url:0 */
+ var domainRelaxUrl = 'javascript:(function(){' +
+ 'document.open();document.domain="' + document.domain + '";' +
+ 'var ed = window.parent.tinymce.get("' + editor.id + '");document.write(ed.iframeHTML);' +
+ 'document.close();ed.' + bodyUuid + '(true);})()';
+
+ // Domain relaxing is required since the user has messed around with document.domain
+ if (document.domain != window.location.hostname) {
+ // Edge seems to be able to handle domain relaxing
+ if (Env.ie && Env.ie < 12) {
+ url = domainRelaxUrl;
+ }
+ }
+
+ // Create iframe
+ // TODO: ACC add the appropriate description on this.
+ var ifr = DOM.create('iframe', {
+ id: editor.id + "_ifr",
+ //src: url || 'javascript:""', // Workaround for HTTPS warning in IE6/7
+ frameBorder: '0',
+ allowTransparency: "true",
+ title: editor.editorManager.translate(
+ "Rich Text Area. Press ALT-F9 for menu. " +
+ "Press ALT-F10 for toolbar. Press ALT-0 for help"
+ ),
+ style: {
+ width: '100%',
+ height: o.height,
+ display: 'block' // Important for Gecko to render the iframe correctly
+ }
+ });
+
+ ifr.onload = function () {
+ ifr.onload = null;
+ editor.fire("load");
+ };
+
+ DOM.setAttrib(ifr, "src", url || 'javascript:""');
+
+ editor.contentAreaContainer = o.iframeContainer;
+ editor.iframeElement = ifr;
+
+ DOM.add(o.iframeContainer, ifr);
+
+ // Try accessing the document this will fail on IE when document.domain is set to the same as location.hostname
+ // Then we have to force domain relaxing using the domainRelaxUrl approach very ugly!!
+ if (Env.ie) {
+ try {
+ editor.getDoc();
+ } catch (e) {
+ ifr.src = url = domainRelaxUrl;
+ }
+ }
+
+ return url;
+ };
+
+ var init = function (editor) {
+ var settings = editor.settings, elm = editor.getElement();
+ var boxInfo, url;
+
+ editor.rtl = settings.rtl_ui || editor.editorManager.i18n.rtl;
+ editor.editorManager.i18n.setCode(settings.language);
+ settings.aria_label = settings.aria_label || DOM.getAttrib(elm, 'aria-label', editor.getLang('aria.rich_text_area'));
+
+ editor.fire('ScriptsLoaded');
+
+ initTheme(editor);
+ initPlugins(editor);
+ boxInfo = measueBox(editor);
+
+ // Load specified content CSS last
+ if (settings.content_css) {
+ Tools.each(Tools.explode(settings.content_css), function (u) {
+ editor.contentCSS.push(editor.documentBaseURI.toAbsolute(u));
+ });
+ }
+
+ // Load specified content CSS last
+ if (settings.content_style) {
+ editor.contentStyles.push(settings.content_style);
+ }
+
+ // Content editable mode ends here
+ if (settings.content_editable) {
+ return InitContentBody.initContentBody(editor);
+ }
+
+ url = createIframe(editor, boxInfo);
+
+ if (boxInfo.editorContainer) {
+ DOM.get(boxInfo.editorContainer).style.display = editor.orgDisplay;
+ editor.hidden = DOM.isHidden(boxInfo.editorContainer);
+ }
+
+ editor.getElement().style.display = 'none';
+ DOM.setAttrib(editor.id, 'aria-hidden', true);
+
+ if (!url) {
+ InitContentBody.initContentBody(editor);
+ }
+ };
+
+ return {
+ init: init
+ };
+ }
+);
+
+/**
+ * Render.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.init.Render',
+ [
+ 'global!window',
+ 'tinymce.core.dom.DOMUtils',
+ 'tinymce.core.dom.EventUtils',
+ 'tinymce.core.dom.ScriptLoader',
+ 'tinymce.core.Env',
+ 'tinymce.core.ErrorReporter',
+ 'tinymce.core.init.Init',
+ 'tinymce.core.NotificationManager',
+ 'tinymce.core.PluginManager',
+ 'tinymce.core.ThemeManager',
+ 'tinymce.core.util.Tools',
+ 'tinymce.core.WindowManager'
+ ],
+ function (window, DOMUtils, EventUtils, ScriptLoader, Env, ErrorReporter, Init, NotificationManager, PluginManager, ThemeManager, Tools, WindowManager) {
+ var DOM = DOMUtils.DOM;
+
+ var loadScripts = function (editor, suffix) {
+ var settings = editor.settings, scriptLoader = ScriptLoader.ScriptLoader;
+
+ if (settings.language && settings.language != 'en' && !settings.language_url) {
+ settings.language_url = editor.editorManager.baseURL + '/langs/' + settings.language + '.js';
+ }
+
+ if (settings.language_url) {
+ scriptLoader.add(settings.language_url);
+ }
+
+ if (settings.theme && typeof settings.theme != "function" &&
+ settings.theme.charAt(0) != '-' && !ThemeManager.urls[settings.theme]) {
+ var themeUrl = settings.theme_url;
+
+ if (themeUrl) {
+ themeUrl = editor.documentBaseURI.toAbsolute(themeUrl);
+ } else {
+ themeUrl = 'themes/' + settings.theme + '/theme' + suffix + '.js';
+ }
+
+ ThemeManager.load(settings.theme, themeUrl);
+ }
+
+ if (Tools.isArray(settings.plugins)) {
+ settings.plugins = settings.plugins.join(' ');
+ }
+
+ Tools.each(settings.external_plugins, function (url, name) {
+ PluginManager.load(name, url);
+ settings.plugins += ' ' + name;
+ });
+
+ Tools.each(settings.plugins.split(/[ ,]/), function (plugin) {
+ plugin = Tools.trim(plugin);
+
+ if (plugin && !PluginManager.urls[plugin]) {
+ if (plugin.charAt(0) === '-') {
+ plugin = plugin.substr(1, plugin.length);
+
+ var dependencies = PluginManager.dependencies(plugin);
+
+ Tools.each(dependencies, function (dep) {
+ var defaultSettings = {
+ prefix: 'plugins/',
+ resource: dep,
+ suffix: '/plugin' + suffix + '.js'
+ };
+
+ dep = PluginManager.createUrl(defaultSettings, dep);
+ PluginManager.load(dep.resource, dep);
+ });
+ } else {
+ PluginManager.load(plugin, {
+ prefix: 'plugins/',
+ resource: plugin,
+ suffix: '/plugin' + suffix + '.js'
+ });
+ }
+ }
+ });
+
+ scriptLoader.loadQueue(function () {
+ if (!editor.removed) {
+ Init.init(editor);
+ }
+ }, editor, function (urls) {
+ ErrorReporter.pluginLoadError(editor, urls[0]);
+
+ if (!editor.removed) {
+ Init.init(editor);
+ }
+ });
+ };
+
+ var render = function (editor) {
+ var settings = editor.settings, id = editor.id;
+
+ function readyHandler() {
+ DOM.unbind(window, 'ready', readyHandler);
+ editor.render();
+ }
+
+ // Page is not loaded yet, wait for it
+ if (!EventUtils.Event.domLoaded) {
+ DOM.bind(window, 'ready', readyHandler);
+ return;
+ }
+
+ // Element not found, then skip initialization
+ if (!editor.getElement()) {
+ return;
+ }
+
+ // No editable support old iOS versions etc
+ if (!Env.contentEditable) {
+ return;
+ }
+
+ // Hide target element early to prevent content flashing
+ if (!settings.inline) {
+ editor.orgVisibility = editor.getElement().style.visibility;
+ editor.getElement().style.visibility = 'hidden';
+ } else {
+ editor.inline = true;
+ }
+
+ var form = editor.getElement().form || DOM.getParent(id, 'form');
+ if (form) {
+ editor.formElement = form;
+
+ // Add hidden input for non input elements inside form elements
+ if (settings.hidden_input && !/TEXTAREA|INPUT/i.test(editor.getElement().nodeName)) {
+ DOM.insertAfter(DOM.create('input', { type: 'hidden', name: id }), id);
+ editor.hasHiddenInput = true;
+ }
+
+ // Pass submit/reset from form to editor instance
+ editor.formEventDelegate = function (e) {
+ editor.fire(e.type, e);
+ };
+
+ DOM.bind(form, 'submit reset', editor.formEventDelegate);
+
+ // Reset contents in editor when the form is reset
+ editor.on('reset', function () {
+ editor.setContent(editor.startContent, { format: 'raw' });
+ });
+
+ // Check page uses id="submit" or name="submit" for it's submit button
+ if (settings.submit_patch && !form.submit.nodeType && !form.submit.length && !form._mceOldSubmit) {
+ form._mceOldSubmit = form.submit;
+ form.submit = function () {
+ editor.editorManager.triggerSave();
+ editor.setDirty(false);
+
+ return form._mceOldSubmit(form);
+ };
+ }
+ }
+
+ editor.windowManager = new WindowManager(editor);
+ editor.notificationManager = new NotificationManager(editor);
+
+ if (settings.encoding === 'xml') {
+ editor.on('GetContent', function (e) {
+ if (e.save) {
+ e.content = DOM.encode(e.content);
+ }
+ });
+ }
+
+ if (settings.add_form_submit_trigger) {
+ editor.on('submit', function () {
+ if (editor.initialized) {
+ editor.save();
+ }
+ });
+ }
+
+ if (settings.add_unload_trigger) {
+ editor._beforeUnload = function () {
+ if (editor.initialized && !editor.destroyed && !editor.isHidden()) {
+ editor.save({ format: 'raw', no_events: true, set_dirty: false });
+ }
+ };
+
+ editor.editorManager.on('BeforeUnload', editor._beforeUnload);
+ }
+
+ editor.editorManager.add(editor);
+ loadScripts(editor, editor.suffix);
+ };
+
+ return {
+ render: render
+ };
+ }
+);
+
+/**
+ * Mode.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
+ */
+
+/**
+ * Mode switcher logic.
+ *
+ * @private
+ * @class tinymce.Mode
+ */
+define(
+ 'tinymce.core.Mode',
+ [
+ ],
+ function () {
+ function setEditorCommandState(editor, cmd, state) {
+ try {
+ editor.getDoc().execCommand(cmd, false, state);
+ } catch (ex) {
+ // Ignore
+ }
+ }
+
+ function clickBlocker(editor) {
+ var target, handler;
+
+ target = editor.getBody();
+
+ handler = function (e) {
+ if (editor.dom.getParents(e.target, 'a').length > 0) {
+ e.preventDefault();
+ }
+ };
+
+ editor.dom.bind(target, 'click', handler);
+
+ return {
+ unbind: function () {
+ editor.dom.unbind(target, 'click', handler);
+ }
+ };
+ }
+
+ function toggleReadOnly(editor, state) {
+ if (editor._clickBlocker) {
+ editor._clickBlocker.unbind();
+ editor._clickBlocker = null;
+ }
+
+ if (state) {
+ editor._clickBlocker = clickBlocker(editor);
+ editor.selection.controlSelection.hideResizeRect();
+ editor.readonly = true;
+ editor.getBody().contentEditable = false;
+ } else {
+ editor.readonly = false;
+ editor.getBody().contentEditable = true;
+ setEditorCommandState(editor, "StyleWithCSS", false);
+ setEditorCommandState(editor, "enableInlineTableEditing", false);
+ setEditorCommandState(editor, "enableObjectResizing", false);
+ editor.focus();
+ editor.nodeChanged();
+ }
+ }
+
+ function setMode(editor, mode) {
+ var currentMode = editor.readonly ? 'readonly' : 'design';
+
+ if (mode == currentMode) {
+ return;
+ }
+
+ if (editor.initialized) {
+ toggleReadOnly(editor, mode == 'readonly');
+ } else {
+ editor.on('init', function () {
+ toggleReadOnly(editor, mode == 'readonly');
+ });
+ }
+
+ // Event is NOT preventable
+ editor.fire('SwitchMode', { mode: mode });
+ }
+
+ return {
+ setMode: setMode
+ };
+ }
+);
+/**
+ * Sidebar.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 handle sidebar instances for the editor.
+ *
+ * @class tinymce.ui.Sidebar
+ * @private
+ */
+define(
+ 'tinymce.core.ui.Sidebar',
+ [
+ ],
+ function (
+ ) {
+ var add = function (editor, name, settings) {
+ var sidebars = editor.sidebars ? editor.sidebars : [];
+ sidebars.push({ name: name, settings: settings });
+ editor.sidebars = sidebars;
+ };
+
+ return {
+ add: add
+ };
+ }
+);
+
+/**
+ * Editor.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 scripturl:true */
+
+/**
+ * Include the base event class documentation.
+ *
+ * @include ../../../../../tools/docs/tinymce.Event.js
+ */
+
+/**
+ * This class contains the core logic for a TinyMCE editor.
+ *
+ * @class tinymce.Editor
+ * @mixes tinymce.util.Observable
+ * @example
+ * // Add a class to all paragraphs in the editor.
+ * tinymce.activeEditor.dom.addClass(tinymce.activeEditor.dom.select('p'), 'someclass');
+ *
+ * // Gets the current editors selection as text
+ * tinymce.activeEditor.selection.getContent({format: 'text'});
+ *
+ * // Creates a new editor instance
+ * var ed = new tinymce.Editor('textareaid', {
+ * some_setting: 1
+ * }, tinymce.EditorManager);
+ *
+ * ed.render();
+ */
+define(
+ 'tinymce.core.Editor',
+ [
+ 'tinymce.core.AddOnManager',
+ 'tinymce.core.dom.DomQuery',
+ 'tinymce.core.dom.DOMUtils',
+ 'tinymce.core.EditorCommands',
+ 'tinymce.core.EditorObservable',
+ 'tinymce.core.Env',
+ 'tinymce.core.html.Serializer',
+ 'tinymce.core.init.Render',
+ 'tinymce.core.Mode',
+ 'tinymce.core.Shortcuts',
+ 'tinymce.core.ui.Sidebar',
+ 'tinymce.core.util.Tools',
+ 'tinymce.core.util.URI',
+ 'tinymce.core.util.Uuid'
+ ],
+ function (
+ AddOnManager, DomQuery, DOMUtils, EditorCommands, EditorObservable, Env, Serializer, Render, Mode,
+ Shortcuts, Sidebar, Tools, URI, Uuid
+ ) {
+ // Shorten these names
+ var DOM = DOMUtils.DOM;
+ var extend = Tools.extend, each = Tools.each;
+ var trim = Tools.trim, resolve = Tools.resolve;
+ var isGecko = Env.gecko, ie = Env.ie;
+
+ /**
+ * Include Editor API docs.
+ *
+ * @include ../../../../../tools/docs/tinymce.Editor.js
+ */
+
+ /**
+ * Constructs a editor instance by id.
+ *
+ * @constructor
+ * @method Editor
+ * @param {String} id Unique id for the editor.
+ * @param {Object} settings Settings for the editor.
+ * @param {tinymce.EditorManager} editorManager EditorManager instance.
+ */
+ function Editor(id, settings, editorManager) {
+ var self = this, documentBaseUrl, baseUri, defaultSettings;
+
+ documentBaseUrl = self.documentBaseUrl = editorManager.documentBaseURL;
+ baseUri = editorManager.baseURI;
+ defaultSettings = editorManager.defaultSettings;
+
+ /**
+ * Name/value collection with editor settings.
+ *
+ * @property settings
+ * @type Object
+ * @example
+ * // Get the value of the theme setting
+ * tinymce.activeEditor.windowManager.alert("You are using the " + tinymce.activeEditor.settings.theme + " theme");
+ */
+ 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: '',
+ 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',
+ 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;
+ AddOnManager.language = settings.language || 'en';
+ AddOnManager.languageLoad = settings.language_load;
+ AddOnManager.baseURL = editorManager.baseURL;
+
+ /**
+ * Editor instance id, normally the same as the div/textarea that was replaced.
+ *
+ * @property id
+ * @type String
+ */
+ self.id = settings.id = id;
+
+ /**
+ * State to force the editor to return false on a isDirty call.
+ *
+ * @property isNotDirty
+ * @type Boolean
+ * @deprecated Use editor.setDirty instead.
+ */
+ self.setDirty(false);
+
+ /**
+ * Name/Value object containing plugin instances.
+ *
+ * @property plugins
+ * @type Object
+ * @example
+ * // Execute a method inside a plugin directly
+ * tinymce.activeEditor.plugins.someplugin.someMethod();
+ */
+ self.plugins = {};
+
+ /**
+ * URI object to document configured for the TinyMCE instance.
+ *
+ * @property documentBaseURI
+ * @type tinymce.util.URI
+ * @example
+ * // Get relative URL from the location of document_base_url
+ * tinymce.activeEditor.documentBaseURI.toRelative('/somedir/somefile.htm');
+ *
+ * // Get absolute URL from the location of document_base_url
+ * tinymce.activeEditor.documentBaseURI.toAbsolute('somefile.htm');
+ */
+ self.documentBaseURI = new URI(settings.document_base_url || documentBaseUrl, {
+ base_uri: baseUri
+ });
+
+ /**
+ * URI object to current document that holds the TinyMCE editor instance.
+ *
+ * @property baseURI
+ * @type tinymce.util.URI
+ * @example
+ * // Get relative URL from the location of the API
+ * tinymce.activeEditor.baseURI.toRelative('/somedir/somefile.htm');
+ *
+ * // Get absolute URL from the location of the API
+ * tinymce.activeEditor.baseURI.toAbsolute('somefile.htm');
+ */
+ self.baseURI = baseUri;
+
+ /**
+ * Array with CSS files to load into the iframe.
+ *
+ * @property contentCSS
+ * @type Array
+ */
+ self.contentCSS = [];
+
+ /**
+ * Array of CSS styles to add to head of document when the editor loads.
+ *
+ * @property contentStyles
+ * @type Array
+ */
+ self.contentStyles = [];
+
+ // Creates all events like onClick, onSetContent etc see Editor.Events.js for the actual logic
+ self.shortcuts = new Shortcuts(self);
+ self.loadedCSS = {};
+ self.editorCommands = new EditorCommands(self);
+ self.suffix = editorManager.suffix;
+ self.editorManager = editorManager;
+ self.inline = settings.inline;
+ self.settings.content_editable = self.inline;
+
+ if (settings.cache_suffix) {
+ Env.cacheSuffix = settings.cache_suffix.replace(/^[\?\&]+/, '');
+ }
+
+ if (settings.override_viewport === false) {
+ Env.overrideViewPort = false;
+ }
+
+ // Call setup
+ editorManager.fire('SetupEditor', self);
+ self.execCallback('setup', self);
+
+ /**
+ * Dom query instance with default scope to the editor document and default element is the body of the editor.
+ *
+ * @property $
+ * @type tinymce.dom.DomQuery
+ * @example
+ * tinymce.activeEditor.$('p').css('color', 'red');
+ * tinymce.activeEditor.$().append('
new
');
+ */
+ self.$ = DomQuery.overrideDefaults(function () {
+ return {
+ context: self.inline ? self.getBody() : self.getDoc(),
+ element: self.getBody()
+ };
+ });
+ }
+
+ Editor.prototype = {
+ /**
+ * Renders the editor/adds it to the page.
+ *
+ * @method render
+ */
+ render: function () {
+ Render.render(this);
+ },
+
+ /**
+ * Focuses/activates the editor. This will set this editor as the activeEditor in the tinymce collection
+ * it will also place DOM focus inside the editor.
+ *
+ * @method focus
+ * @param {Boolean} skipFocus Skip DOM focus. Just set is as the active editor.
+ */
+ focus: function (skipFocus) {
+ 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 (!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);
+ },
+
+ /**
+ * Executes a legacy callback. This method is useful to call old 2.x option callbacks.
+ * There new event model is a better way to add callback so this method might be removed in the future.
+ *
+ * @method execCallback
+ * @param {String} name Name of the callback to execute.
+ * @return {Object} Return value passed from callback function.
+ */
+ execCallback: function (name) {
+ var self = this, callback = self.settings[name], scope;
+
+ if (!callback) {
+ return;
+ }
+
+ // Look through lookup
+ if (self.callbackLookup && (scope = self.callbackLookup[name])) {
+ callback = scope.func;
+ scope = scope.scope;
+ }
+
+ if (typeof callback === 'string') {
+ scope = callback.replace(/\.\w+$/, '');
+ scope = scope ? resolve(scope) : 0;
+ callback = resolve(callback);
+ self.callbackLookup = self.callbackLookup || {};
+ self.callbackLookup[name] = { func: callback, scope: scope };
+ }
+
+ return callback.apply(scope || self, Array.prototype.slice.call(arguments, 1));
+ },
+
+ /**
+ * Translates the specified string by replacing variables with language pack items it will also check if there is
+ * a key matching the input.
+ *
+ * @method translate
+ * @param {String} text String to translate by the language pack data.
+ * @return {String} Translated string.
+ */
+ translate: function (text) {
+ var lang = this.settings.language || 'en', i18n = this.editorManager.i18n;
+
+ if (!text) {
+ return '';
+ }
+
+ text = i18n.data[lang + '.' + text] || text.replace(/\{\#([^\}]+)\}/g, function (a, b) {
+ return i18n.data[lang + '.' + b] || '{#' + b + '}';
+ });
+
+ return this.editorManager.translate(text);
+ },
+
+ /**
+ * Returns a language pack item by name/key.
+ *
+ * @method getLang
+ * @param {String} name Name/key to get from the language pack.
+ * @param {String} defaultVal Optional default value to retrieve.
+ */
+ getLang: function (name, defaultVal) {
+ return (
+ this.editorManager.i18n.data[(this.settings.language || 'en') + '.' + name] ||
+ (defaultVal !== undefined ? defaultVal : '{#' + name + '}')
+ );
+ },
+
+ /**
+ * Returns a configuration parameter by name.
+ *
+ * @method getParam
+ * @param {String} name Configruation parameter to retrieve.
+ * @param {String} defaultVal Optional default value to return.
+ * @param {String} type Optional type parameter.
+ * @return {String} Configuration parameter value or default value.
+ * @example
+ * // Returns a specific config value from the currently active editor
+ * var someval = tinymce.activeEditor.getParam('myvalue');
+ *
+ * // Returns a specific config value from a specific editor instance by id
+ * var someval2 = tinymce.get('my_editor').getParam('myvalue');
+ */
+ getParam: function (name, defaultVal, type) {
+ var value = name in this.settings ? this.settings[name] : defaultVal, output;
+
+ if (type === 'hash') {
+ output = {};
+
+ if (typeof value === 'string') {
+ each(value.indexOf('=') > 0 ? value.split(/[;,](?![^=;,]*(?:[;,]|$))/) : value.split(','), function (value) {
+ value = value.split('=');
+
+ if (value.length > 1) {
+ output[trim(value[0])] = trim(value[1]);
+ } else {
+ output[trim(value[0])] = trim(value);
+ }
+ });
+ } else {
+ output = value;
+ }
+
+ return output;
+ }
+
+ return value;
+ },
+
+ /**
+ * Dispatches out a onNodeChange event to all observers. This method should be called when you
+ * need to update the UI states or element path etc.
+ *
+ * @method nodeChanged
+ * @param {Object} args Optional args to pass to NodeChange event handlers.
+ */
+ nodeChanged: function (args) {
+ this._nodeChangeDispatcher.nodeChanged(args);
+ },
+
+ /**
+ * Adds a button that later gets created by the theme in the editors toolbars.
+ *
+ * @method addButton
+ * @param {String} name Button name to add.
+ * @param {Object} settings Settings object with title, cmd etc.
+ * @example
+ * // Adds a custom button to the editor that inserts contents when clicked
+ * tinymce.init({
+ * ...
+ *
+ * toolbar: 'example'
+ *
+ * setup: function(ed) {
+ * ed.addButton('example', {
+ * title: 'My title',
+ * image: '../js/tinymce/plugins/example/img/example.gif',
+ * onclick: function() {
+ * ed.insertContent('Hello world!!');
+ * }
+ * });
+ * }
+ * });
+ */
+ addButton: function (name, settings) {
+ var self = this;
+
+ if (settings.cmd) {
+ settings.onclick = function () {
+ self.execCommand(settings.cmd);
+ };
+ }
+
+ if (!settings.text && !settings.icon) {
+ settings.icon = name;
+ }
+
+ self.buttons = self.buttons || {};
+ settings.tooltip = settings.tooltip || settings.title;
+ self.buttons[name] = settings;
+ },
+
+ /**
+ * Adds a sidebar for the editor instance.
+ *
+ * @method addSidebar
+ * @param {String} name Sidebar name to add.
+ * @param {Object} settings Settings object with icon, onshow etc.
+ * @example
+ * // Adds a custom sidebar that when clicked logs the panel element
+ * tinymce.init({
+ * ...
+ * setup: function(ed) {
+ * ed.addSidebar('example', {
+ * tooltip: 'My sidebar',
+ * icon: 'my-side-bar',
+ * onshow: function(api) {
+ * console.log(api.element());
+ * }
+ * });
+ * }
+ * });
+ */
+ addSidebar: function (name, settings) {
+ return Sidebar.add(this, name, settings);
+ },
+
+ /**
+ * Adds a menu item to be used in the menus of the theme. There might be multiple instances
+ * of this menu item for example it might be used in the main menus of the theme but also in
+ * the context menu so make sure that it's self contained and supports multiple instances.
+ *
+ * @method addMenuItem
+ * @param {String} name Menu item name to add.
+ * @param {Object} settings Settings object with title, cmd etc.
+ * @example
+ * // Adds a custom menu item to the editor that inserts contents when clicked
+ * // The context option allows you to add the menu item to an existing default menu
+ * tinymce.init({
+ * ...
+ *
+ * setup: function(ed) {
+ * ed.addMenuItem('example', {
+ * text: 'My menu item',
+ * context: 'tools',
+ * onclick: function() {
+ * ed.insertContent('Hello world!!');
+ * }
+ * });
+ * }
+ * });
+ */
+ addMenuItem: function (name, settings) {
+ var self = this;
+
+ if (settings.cmd) {
+ settings.onclick = function () {
+ self.execCommand(settings.cmd);
+ };
+ }
+
+ self.menuItems = self.menuItems || {};
+ self.menuItems[name] = settings;
+ },
+
+ /**
+ * Adds a contextual toolbar to be rendered when the selector matches.
+ *
+ * @method addContextToolbar
+ * @param {function/string} predicate Predicate that needs to return true if provided strings get converted into CSS predicates.
+ * @param {String/Array} items String or array with items to add to the context toolbar.
+ */
+ addContextToolbar: function (predicate, items) {
+ var self = this, selector;
+
+ self.contextToolbars = self.contextToolbars || [];
+
+ // Convert selector to predicate
+ if (typeof predicate == "string") {
+ selector = predicate;
+ predicate = function (elm) {
+ return self.dom.is(elm, selector);
+ };
+ }
+
+ self.contextToolbars.push({
+ id: Uuid.uuid('mcet'),
+ predicate: predicate,
+ items: items
+ });
+ },
+
+ /**
+ * Adds a custom command to the editor, you can also override existing commands with this method.
+ * The command that you add can be executed with execCommand.
+ *
+ * @method addCommand
+ * @param {String} name Command name to add/override.
+ * @param {addCommandCallback} callback Function to execute when the command occurs.
+ * @param {Object} scope Optional scope to execute the function in.
+ * @example
+ * // Adds a custom command that later can be executed using execCommand
+ * tinymce.init({
+ * ...
+ *
+ * setup: function(ed) {
+ * // Register example command
+ * ed.addCommand('mycommand', function(ui, v) {
+ * ed.windowManager.alert('Hello world!! Selection: ' + ed.selection.getContent({format: 'text'}));
+ * });
+ * }
+ * });
+ */
+ addCommand: function (name, callback, scope) {
+ /**
+ * Callback function that gets called when a command is executed.
+ *
+ * @callback addCommandCallback
+ * @param {Boolean} ui Display UI state true/false.
+ * @param {Object} value Optional value for command.
+ * @return {Boolean} True/false state if the command was handled or not.
+ */
+ this.editorCommands.addCommand(name, callback, scope);
+ },
+
+ /**
+ * Adds a custom query state command to the editor, you can also override existing commands with this method.
+ * The command that you add can be executed with queryCommandState function.
+ *
+ * @method addQueryStateHandler
+ * @param {String} name Command name to add/override.
+ * @param {addQueryStateHandlerCallback} callback Function to execute when the command state retrieval occurs.
+ * @param {Object} scope Optional scope to execute the function in.
+ */
+ addQueryStateHandler: function (name, callback, scope) {
+ /**
+ * Callback function that gets called when a queryCommandState is executed.
+ *
+ * @callback addQueryStateHandlerCallback
+ * @return {Boolean} True/false state if the command is enabled or not like is it bold.
+ */
+ this.editorCommands.addQueryStateHandler(name, callback, scope);
+ },
+
+ /**
+ * Adds a custom query value command to the editor, you can also override existing commands with this method.
+ * The command that you add can be executed with queryCommandValue function.
+ *
+ * @method addQueryValueHandler
+ * @param {String} name Command name to add/override.
+ * @param {addQueryValueHandlerCallback} callback Function to execute when the command value retrieval occurs.
+ * @param {Object} scope Optional scope to execute the function in.
+ */
+ addQueryValueHandler: function (name, callback, scope) {
+ /**
+ * Callback function that gets called when a queryCommandValue is executed.
+ *
+ * @callback addQueryValueHandlerCallback
+ * @return {Object} Value of the command or undefined.
+ */
+ this.editorCommands.addQueryValueHandler(name, callback, scope);
+ },
+
+ /**
+ * Adds a keyboard shortcut for some command or function.
+ *
+ * @method addShortcut
+ * @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} sc Optional scope to execute the function in.
+ * @return {Boolean} true/false state if the shortcut was added or not.
+ */
+ addShortcut: function (pattern, desc, cmdFunc, scope) {
+ this.shortcuts.add(pattern, desc, cmdFunc, scope);
+ },
+
+ /**
+ * Executes a command on the current instance. These commands can be TinyMCE internal commands prefixed with "mce" or
+ * they can be build in browser commands such as "Bold". A compleate list of browser commands is available on MSDN or Mozilla.org.
+ * This function will dispatch the execCommand function on each plugin, theme or the execcommand_callback option if none of these
+ * return true it will handle the command as a internal browser command.
+ *
+ * @method execCommand
+ * @param {String} cmd Command name to execute, for example mceLink or Bold.
+ * @param {Boolean} ui True/false state if a UI (dialog) should be presented or not.
+ * @param {mixed} value Optional command value, this can be anything.
+ * @param {Object} args Optional arguments object.
+ */
+ execCommand: function (cmd, ui, value, args) {
+ return this.editorCommands.execCommand(cmd, ui, value, args);
+ },
+
+ /**
+ * Returns a command specific state, for example if bold is enabled or not.
+ *
+ * @method queryCommandState
+ * @param {string} cmd Command to query state from.
+ * @return {Boolean} Command specific state, for example if bold is enabled or not.
+ */
+ queryCommandState: function (cmd) {
+ return this.editorCommands.queryCommandState(cmd);
+ },
+
+ /**
+ * Returns a command specific value, for example the current font size.
+ *
+ * @method queryCommandValue
+ * @param {string} cmd Command to query value from.
+ * @return {Object} Command specific value, for example the current font size.
+ */
+ queryCommandValue: function (cmd) {
+ return this.editorCommands.queryCommandValue(cmd);
+ },
+
+ /**
+ * Returns true/false if the command is supported or not.
+ *
+ * @method queryCommandSupported
+ * @param {String} cmd Command that we check support for.
+ * @return {Boolean} true/false if the command is supported or not.
+ */
+ queryCommandSupported: function (cmd) {
+ return this.editorCommands.queryCommandSupported(cmd);
+ },
+
+ /**
+ * Shows the editor and hides any textarea/div that the editor is supposed to replace.
+ *
+ * @method show
+ */
+ show: function () {
+ var self = this;
+
+ if (self.hidden) {
+ self.hidden = false;
+
+ if (self.inline) {
+ self.getBody().contentEditable = true;
+ } else {
+ DOM.show(self.getContainer());
+ DOM.hide(self.id);
+ }
+
+ self.load();
+ self.fire('show');
+ }
+ },
+
+ /**
+ * Hides the editor and shows any textarea/div that the editor is supposed to replace.
+ *
+ * @method hide
+ */
+ hide: function () {
+ var self = this, doc = self.getDoc();
+
+ if (!self.hidden) {
+ // Fixed bug where IE has a blinking cursor left from the editor
+ if (ie && doc && !self.inline) {
+ doc.execCommand('SelectAll');
+ }
+
+ // We must save before we hide so Safari doesn't crash
+ self.save();
+
+ if (self.inline) {
+ self.getBody().contentEditable = false;
+
+ // Make sure the editor gets blurred
+ if (self == self.editorManager.focusedEditor) {
+ self.editorManager.focusedEditor = null;
+ }
+ } else {
+ DOM.hide(self.getContainer());
+ DOM.setStyle(self.id, 'display', self.orgDisplay);
+ }
+
+ self.hidden = true;
+ self.fire('hide');
+ }
+ },
+
+ /**
+ * Returns true/false if the editor is hidden or not.
+ *
+ * @method isHidden
+ * @return {Boolean} True/false if the editor is hidden or not.
+ */
+ isHidden: function () {
+ return !!this.hidden;
+ },
+
+ /**
+ * Sets the progress state, this will display a throbber/progess for the editor.
+ * This is ideal for asynchronous operations like an AJAX save call.
+ *
+ * @method setProgressState
+ * @param {Boolean} state Boolean state if the progress should be shown or hidden.
+ * @param {Number} time Optional time to wait before the progress gets shown.
+ * @return {Boolean} Same as the input state.
+ * @example
+ * // Show progress for the active editor
+ * tinymce.activeEditor.setProgressState(true);
+ *
+ * // Hide progress for the active editor
+ * tinymce.activeEditor.setProgressState(false);
+ *
+ * // Show progress after 3 seconds
+ * tinymce.activeEditor.setProgressState(true, 3000);
+ */
+ setProgressState: function (state, time) {
+ this.fire('ProgressState', { state: state, time: time });
+ },
+
+ /**
+ * Loads contents from the textarea or div element that got converted into an editor instance.
+ * This method will move the contents from that textarea or div into the editor by using setContent
+ * so all events etc that method has will get dispatched as well.
+ *
+ * @method load
+ * @param {Object} args Optional content object, this gets passed around through the whole load process.
+ * @return {String} HTML string that got set into the editor.
+ */
+ load: function (args) {
+ var self = this, elm = self.getElement(), html;
+
+ if (elm) {
+ args = args || {};
+ args.load = true;
+
+ html = self.setContent(elm.value !== undefined ? elm.value : elm.innerHTML, args);
+ args.element = elm;
+
+ if (!args.no_events) {
+ self.fire('LoadContent', args);
+ }
+
+ args.element = elm = null;
+
+ return html;
+ }
+ },
+
+ /**
+ * Saves the contents from a editor out to the textarea or div element that got converted into an editor instance.
+ * This method will move the HTML contents from the editor into that textarea or div by getContent
+ * so all events etc that method has will get dispatched as well.
+ *
+ * @method save
+ * @param {Object} args Optional content object, this gets passed around through the whole save process.
+ * @return {String} HTML string that got set into the textarea/div.
+ */
+ save: function (args) {
+ var self = this, elm = self.getElement(), html, form;
+
+ if (!elm || !self.initialized) {
+ return;
+ }
+
+ args = args || {};
+ args.save = true;
+
+ args.element = elm;
+ html = args.content = self.getContent(args);
+
+ if (!args.no_events) {
+ self.fire('SaveContent', args);
+ }
+
+ // Always run this internal event
+ if (args.format == 'raw') {
+ self.fire('RawSaveContent', args);
+ }
+
+ html = args.content;
+
+ if (!/TEXTAREA|INPUT/i.test(elm.nodeName)) {
+ // Update DIV element when not in inline mode
+ if (!self.inline) {
+ elm.innerHTML = html;
+ }
+
+ // Update hidden form element
+ if ((form = DOM.getParent(self.id, 'form'))) {
+ each(form.elements, function (elm) {
+ if (elm.name == self.id) {
+ elm.value = html;
+ return false;
+ }
+ });
+ }
+ } else {
+ elm.value = html;
+ }
+
+ args.element = elm = null;
+
+ if (args.set_dirty !== false) {
+ self.setDirty(false);
+ }
+
+ return html;
+ },
+
+ /**
+ * Sets the specified content to the editor instance, this will cleanup the content before it gets set using
+ * the different cleanup rules options.
+ *
+ * @method setContent
+ * @param {String} content Content to set to editor, normally HTML contents but can be other formats as well.
+ * @param {Object} args Optional content object, this gets passed around through the whole set process.
+ * @return {String} HTML string that got set into the editor.
+ * @example
+ * // Sets the HTML contents of the activeEditor editor
+ * tinymce.activeEditor.setContent('some html');
+ *
+ * // Sets the raw contents of the activeEditor editor
+ * tinymce.activeEditor.setContent('some html', {format: 'raw'});
+ *
+ * // Sets the content of a specific editor (my_editor in this example)
+ * tinymce.get('my_editor').setContent(data);
+ *
+ * // Sets the bbcode contents of the activeEditor editor if the bbcode plugin was added
+ * tinymce.activeEditor.setContent('[b]some[/b] html', {format: 'bbcode'});
+ */
+ setContent: function (content, args) {
+ var self = this, body = self.getBody(), forcedRootBlockName, padd;
+
+ // Setup args object
+ args = args || {};
+ args.format = args.format || 'html';
+ args.set = true;
+ args.content = content;
+
+ // Do preprocessing
+ if (!args.no_events) {
+ self.fire('BeforeSetContent', args);
+ }
+
+ content = args.content;
+
+ // Padd empty content in Gecko and Safari. Commands will otherwise fail on the content
+ // It will also be impossible to place the caret in the editor unless there is a BR element present
+ if (content.length === 0 || /^\s+$/.test(content)) {
+ padd = ie && ie < 11 ? '' : ' ';
+
+ // Todo: There is a lot more root elements that need special padding
+ // so separate this and add all of them at some point.
+ if (body.nodeName == 'TABLE') {
+ content = '