diff --git a/chrome/content/zotero/browser.js b/chrome/content/zotero/browser.js index e102bb44c..49ed27e37 100644 --- a/chrome/content/zotero/browser.js +++ b/chrome/content/zotero/browser.js @@ -117,6 +117,15 @@ var Zotero_Browser = new function() { * ID as the argument */ function scrapeThisPage(saveLocation) { + if (!Zotero.stateCheck()) { + Zotero_Browser.progress.changeHeadline(Zotero.getString("ingester.scrapeError")); + var desc = Zotero.getString("ingester.scrapeError.transactionInProgress.previousError") + + ' ' + Zotero.getString("general.restartFirefoxAndTryAgain"); + Zotero_Browser.progress.addDescription(desc); + Zotero_Browser.progress.show(); + Zotero_Browser.progress.startCloseTimer(8000); + return; + } _getTabObject(this.tabbrowser.selectedBrowser).translate(saveLocation); } diff --git a/chrome/content/zotero/overlay.js b/chrome/content/zotero/overlay.js index f9f5fbaff..c7a28a842 100644 --- a/chrome/content/zotero/overlay.js +++ b/chrome/content/zotero/overlay.js @@ -85,6 +85,7 @@ var ZoteroPane = new function() this.showAttachmentNotFoundDialog = showAttachmentNotFoundDialog; this.relinkAttachment = relinkAttachment; this.reportErrors = reportErrors; + this.displayErrorMessage = displayErrorMessage; const DEFAULT_ZPANE_HEIGHT = 300; const COLLECTIONS_HEIGHT = 125; // minimum height of the collections pane and toolbar @@ -467,6 +468,11 @@ var ZoteroPane = new function() */ function newItem(typeID, data) { + if (!Zotero.stateCheck()) { + this.displayErrorMessage(true); + return; + } + var item = new Zotero.Item(typeID); for (var i in data) @@ -704,6 +710,11 @@ var ZoteroPane = new function() function itemSelected() { + if (!Zotero.stateCheck()) { + this.displayErrorMessage(); + return; + } + if (this.itemsView && this.itemsView.selection.count == 1 && this.itemsView.selection.currentIndex != -1) { var item = this.itemsView._getItemAtRow(this.itemsView.selection.currentIndex); @@ -1453,15 +1464,23 @@ var ZoteroPane = new function() function setItemsPaneMessage(msg) { + var elem = document.getElementById('zotero-items-pane-message-box'); + while (elem.hasChildNodes()) { + elem.removeChild(elem.firstChild); + } + var msgParts = msg.split("\n\n"); + for (var i=0; i - + @@ -265,9 +265,7 @@ - - + @@ -352,6 +350,11 @@ break; } + // Set "Report Errors..." label via property rather than DTD entity, + // since we need to reference it in script elsewhere + document.getElementById('zotero-tb-actions-reportErrors').setAttribute('label', + Zotero.getString('errorReport.reportErrors')); + // Used for loading the changelog after upgrades if (Zotero.initialURL) { gBrowser.selectedTab = gBrowser.addTab(Zotero.initialURL); diff --git a/chrome/content/zotero/preferences/preferences.js b/chrome/content/zotero/preferences/preferences.js index fa9ebc7c3..e0bcb7ebf 100644 --- a/chrome/content/zotero/preferences/preferences.js +++ b/chrome/content/zotero/preferences/preferences.js @@ -68,7 +68,7 @@ function onDataDirUpdate(event) { + (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL); var index = ps.confirmEx(window, Zotero.getString('general.restartRequired'), - Zotero.getString('general.restartFirefox.singular'), + Zotero.getString('general.restartRequiredForChange'), buttonFlags, Zotero.getString('general.restartNow'), null, null, null, {}); diff --git a/chrome/content/zotero/xpcom/db.js b/chrome/content/zotero/xpcom/db.js index bed08da47..04d45c63f 100644 --- a/chrome/content/zotero/xpcom/db.js +++ b/chrome/content/zotero/xpcom/db.js @@ -403,6 +403,8 @@ Zotero.DBConnection.prototype.transactionInProgress = function () { /** * Safety function used on shutdown to make sure we're not stuck in the * middle of a transaction + * + * NOTE: No longer used */ Zotero.DBConnection.prototype.commitAllTransactions = function () { if (this.transactionInProgress()) { @@ -418,6 +420,23 @@ Zotero.DBConnection.prototype.commitAllTransactions = function () { } +/* + * Used on shutdown to rollback all open transactions + */ +Zotero.DBConnection.prototype.rollbackAllTransactions = function () { + if (this.transactionInProgress()) { + var level = this._transactionNestingLevel; + this._transactionNestingLevel = 0; + try { + this.rollbackTransaction(); + } + catch (e) {} + return level ? level : true; + } + return false; +} + + Zotero.DBConnection.prototype.tableExists = function (table) { return this._getDBConnection().tableExists(table); } @@ -530,7 +549,9 @@ Zotero.DBConnection.prototype.observe = function(subject, topic, data) { return; } - var level = this.commitAllTransactions(); + // NOTE: disabled + //var level = this.commitAllTransactions(); + var level = this.rollbackAllTransactions() if (level) { level = level === true ? '0' : level; this._debug("A transaction in DB '" + this._dbName + "' was still open! (level " + level + ")", 2); @@ -776,8 +797,8 @@ Zotero.DBConnection.prototype._getDBConnection = function () { // Register shutdown handler to call this.onShutdown() for DB backup var observerService = Components.classes["@mozilla.org/observer-service;1"] .getService(Components.interfaces.nsIObserverService); - observerService.addObserver(this, "xpcom-shutdown", false); + observerService = null; return this._connection; } diff --git a/chrome/content/zotero/xpcom/itemTreeView.js b/chrome/content/zotero/xpcom/itemTreeView.js index 3fcc4b5b5..c1b062e39 100644 --- a/chrome/content/zotero/xpcom/itemTreeView.js +++ b/chrome/content/zotero/xpcom/itemTreeView.js @@ -96,6 +96,24 @@ Zotero.ItemTreeView.prototype.setTree = function(treebox) // Generate the tree contents in a timer to allow message above to display var paneLoader = function(obj) { + // If a DB transaction is open, display error message and bail + if (!Zotero.stateCheck()) { + if (obj._ownerDocument.defaultView.ZoteroPane) { + obj._ownerDocument.defaultView.ZoteroPane.displayErrorMessage(); + /* + var reportErrorsStr = Zotero.getString('errorReport.reportErrors'); + var reportInstructions = + Zotero.getString('errorReport.reportInstructions', reportErrorsStr) + + var msg = Zotero.getString('general.errorHasOccurred') + ' ' + + Zotero.getString('general.restartFirefox') + '\n\n' + + reportInstructions; + obj._ownerDocument.defaultView.ZoteroPane.setItemsPaneMessage(msg); + */ + } + return; + } + obj.refresh(); // Add a keypress listener for expand/collapse diff --git a/chrome/content/zotero/xpcom/progressWindow.js b/chrome/content/zotero/xpcom/progressWindow.js index 27e9e43be..be889b17e 100644 --- a/chrome/content/zotero/xpcom/progressWindow.js +++ b/chrome/content/zotero/xpcom/progressWindow.js @@ -97,7 +97,7 @@ Zotero.ProgressWindowSet = new function() { for (var i=0; i<_progressWindows.length; i++) { // Pass |requireMouseOver| so that the window only closes // if the mouse was over it at some point - _progressWindows[i].instance.startCloseTimer(true); + _progressWindows[i].instance.startCloseTimer(null, true); } } } @@ -246,7 +246,7 @@ Zotero.ProgressWindow = function(_window){ } - function startCloseTimer(requireMouseOver) { + function startCloseTimer(ms, requireMouseOver) { if (_windowLoaded || _windowLoading) { if (requireMouseOver && !_mouseWasOver) { return; @@ -256,7 +256,11 @@ Zotero.ProgressWindow = function(_window){ _disableTimeout(); } - _timeoutID = _progressWindow.setTimeout(_timeout, 2500); + if (typeof ms != 'number') { + ms = 2500; + } + + _timeoutID = _progressWindow.setTimeout(_timeout, ms); } } diff --git a/chrome/content/zotero/xpcom/zotero.js b/chrome/content/zotero/xpcom/zotero.js index b5befecab..ae5410a1c 100644 --- a/chrome/content/zotero/xpcom/zotero.js +++ b/chrome/content/zotero/xpcom/zotero.js @@ -34,6 +34,7 @@ const ZOTERO_CONFIG = { var Zotero = new function(){ // Privileged (public) methods this.init = init; + this.stateCheck = stateCheck; //this.shutdown = shutdown; this.getProfileDirectory = getProfileDirectory; this.getZoteroDirectory = getZoteroDirectory; @@ -223,6 +224,17 @@ var Zotero = new function(){ } + function stateCheck() { + if (Zotero.DB.transactionInProgress()) { + this.initialized = false; + this.skipLoading = true; + return false; + } + + return true; + } + + /* function shutdown(subject, topic, data){ // Called twice otherwise, for some reason @@ -350,7 +362,7 @@ var Zotero = new function(){ } var index = ps.confirmEx(win, Zotero.getString('general.restartRequired'), - Zotero.getString('general.restartFirefox.singular'), + Zotero.getString('general.restartRequiredForChange'), buttonFlags, Zotero.getString('general.restartNow'), forceRestartNow ? null : Zotero.getString('general.restartLater'), diff --git a/chrome/locale/bg-BG/zotero/zotero.properties b/chrome/locale/bg-BG/zotero/zotero.properties index d4318fae6..e1388e2e5 100644 --- a/chrome/locale/bg-BG/zotero/zotero.properties +++ b/chrome/locale/bg-BG/zotero/zotero.properties @@ -1,7 +1,7 @@ general.dontShowWarningAgain=Don't show this warning again. general.locate=Locate... -general.restartFirefox.singular=Firefox must be restarted for the change to take effect. -general.restartFirefox.plural=Firefox must be restarted for the changes to take effect. +general.restartRequiredForChange=Firefox must be restarted for the change to take effect. +general.restartRequiredForChanges=Firefox must be restarted for the changes to take effect. general.restartNow=Restart now general.restartLater=Restart later diff --git a/chrome/locale/de-AT/zotero/zotero.properties b/chrome/locale/de-AT/zotero/zotero.properties index ec20f7a24..d9eac8adf 100644 --- a/chrome/locale/de-AT/zotero/zotero.properties +++ b/chrome/locale/de-AT/zotero/zotero.properties @@ -1,7 +1,7 @@ general.dontShowWarningAgain=Don't show this warning again. general.locate=Locate... -general.restartFirefox.singular=Firefox must be restarted for the change to take effect. -general.restartFirefox.plural=Firefox must be restarted for the changes to take effect. +general.restartRequiredForChange=Firefox must be restarted for the change to take effect. +general.restartRequiredForChanges=Firefox must be restarted for the changes to take effect. general.restartNow=Restart now general.restartLater=Restart later diff --git a/chrome/locale/de-CH/zotero/zotero.properties b/chrome/locale/de-CH/zotero/zotero.properties index 49fb0fdee..6054584cd 100644 --- a/chrome/locale/de-CH/zotero/zotero.properties +++ b/chrome/locale/de-CH/zotero/zotero.properties @@ -1,7 +1,7 @@ general.dontShowWarningAgain=Don't show this warning again. general.locate=Locate... -general.restartFirefox.singular=Firefox must be restarted for the change to take effect. -general.restartFirefox.plural=Firefox must be restarted for the changes to take effect. +general.restartRequiredForChange=Firefox must be restarted for the change to take effect. +general.restartRequiredForChanges=Firefox must be restarted for the changes to take effect. general.restartNow=Restart now general.restartLater=Restart later diff --git a/chrome/locale/de-DE/zotero/zotero.properties b/chrome/locale/de-DE/zotero/zotero.properties index 45ca6ddec..9d2b72025 100644 --- a/chrome/locale/de-DE/zotero/zotero.properties +++ b/chrome/locale/de-DE/zotero/zotero.properties @@ -1,7 +1,7 @@ general.dontShowWarningAgain=Don't show this warning again. general.locate=Locate... -general.restartFirefox.singular=Firefox must be restarted for the change to take effect. -general.restartFirefox.plural=Firefox must be restarted for the changes to take effect. +general.restartRequiredForChange=Firefox must be restarted for the change to take effect. +general.restartRequiredForChanges=Firefox must be restarted for the changes to take effect. general.restartNow=Restart now general.restartLater=Restart later diff --git a/chrome/locale/en-US/zotero/zotero.dtd b/chrome/locale/en-US/zotero/zotero.dtd index f5d6f6621..aced82d70 100644 --- a/chrome/locale/en-US/zotero/zotero.dtd +++ b/chrome/locale/en-US/zotero/zotero.dtd @@ -63,7 +63,6 @@ - diff --git a/chrome/locale/en-US/zotero/zotero.properties b/chrome/locale/en-US/zotero/zotero.properties index dcbb6f0bc..496c68009 100644 --- a/chrome/locale/en-US/zotero/zotero.properties +++ b/chrome/locale/en-US/zotero/zotero.properties @@ -2,14 +2,19 @@ general.error = Error general.dontShowWarningAgain = Don't show this warning again. general.locate = Locate... general.restartRequired = Restart Required -general.restartFirefox.singular = Firefox must be restarted for the change to take effect. -general.restartFirefox.plural = Firefox must be restarted for the changes to take effect. +general.restartRequiredForChange = Firefox must be restarted for the change to take effect. +general.restartRequiredForChanges = Firefox must be restarted for the changes to take effect. general.restartNow = Restart now general.restartLater = Restart later +general.errorHasOccurred = An error has occurred. +general.restartFirefox = Please restart Firefox. +general.restartFirefoxAndTryAgain = Please restart Firefox and try again. upgrade.failed = Upgrading of the Zotero database failed: upgrade.advanceMessage = Press %S to upgrade now. +errorReport.reportErrors = Report Errors... +errorReport.reportInstructions = You can report this error by selecting "%S" from the Actions (gear) menu. errorReport.followingErrors = The following errors have occurred: errorReport.advanceMessage = Press %S to send an error report to the Zotero developers. errorReport.stepsToReproduce = Steps to Reproduce: @@ -293,6 +298,7 @@ ingester.scrapeComplete = Item Saved ingester.scrapeError = Could Not Save Item ingester.scrapeErrorDescription = An error occurred while saving this item. Check %S for more information. ingester.scrapeErrorDescription.linkText = Known Translator Issues +ingester.scrapeError.transactionInProgress.previousError = The saving process failed due to a previous Zotero error. db.dbCorrupted = The Zotero database '%S' appears to have become corrupted. db.dbCorrupted.restart = Please restart Firefox to attempt an automatic restore from the last backup. diff --git a/chrome/locale/es-ES/zotero/zotero.properties b/chrome/locale/es-ES/zotero/zotero.properties index a2f33d014..01a8d84fa 100644 --- a/chrome/locale/es-ES/zotero/zotero.properties +++ b/chrome/locale/es-ES/zotero/zotero.properties @@ -1,7 +1,7 @@ general.dontShowWarningAgain=Don't show this warning again. general.locate=Locate... -general.restartFirefox.singular=Firefox must be restarted for the change to take effect. -general.restartFirefox.plural=Firefox must be restarted for the changes to take effect. +general.restartRequiredForChange=Firefox must be restarted for the change to take effect. +general.restartRequiredForChanges=Firefox must be restarted for the changes to take effect. general.restartNow=Restart now general.restartLater=Restart later diff --git a/chrome/locale/fr-FR/zotero/zotero.properties b/chrome/locale/fr-FR/zotero/zotero.properties index 7000c7ce0..de2dbe4ae 100644 --- a/chrome/locale/fr-FR/zotero/zotero.properties +++ b/chrome/locale/fr-FR/zotero/zotero.properties @@ -1,7 +1,7 @@ general.dontShowWarningAgain=Don't show this warning again. general.locate=Locate... -general.restartFirefox.singular=Firefox must be restarted for the change to take effect. -general.restartFirefox.plural=Firefox must be restarted for the changes to take effect. +general.restartRequiredForChange=Firefox must be restarted for the change to take effect. +general.restartRequiredForChanges=Firefox must be restarted for the changes to take effect. general.restartNow=Restart now general.restartLater=Restart later diff --git a/chrome/locale/it-IT/zotero/zotero.properties b/chrome/locale/it-IT/zotero/zotero.properties index 055e2fa1f..9ed4215ac 100644 --- a/chrome/locale/it-IT/zotero/zotero.properties +++ b/chrome/locale/it-IT/zotero/zotero.properties @@ -1,7 +1,7 @@ general.dontShowWarningAgain=Don't show this warning again. general.locate=Locate... -general.restartFirefox.singular=Firefox must be restarted for the change to take effect. -general.restartFirefox.plural=Firefox must be restarted for the changes to take effect. +general.restartRequiredForChange=Firefox must be restarted for the change to take effect. +general.restartRequiredForChanges=Firefox must be restarted for the changes to take effect. general.restartNow=Restart now general.restartLater=Restart later diff --git a/chrome/locale/ja-JP/zotero/zotero.properties b/chrome/locale/ja-JP/zotero/zotero.properties index ed43653c1..fdeb43327 100644 --- a/chrome/locale/ja-JP/zotero/zotero.properties +++ b/chrome/locale/ja-JP/zotero/zotero.properties @@ -1,7 +1,7 @@ general.dontShowWarningAgain=Don't show this warning again. general.locate=Locate... -general.restartFirefox.singular=Firefox must be restarted for the change to take effect. -general.restartFirefox.plural=Firefox must be restarted for the changes to take effect. +general.restartRequiredForChange=Firefox must be restarted for the change to take effect. +general.restartRequiredForChanges=Firefox must be restarted for the changes to take effect. general.restartNow=Restart now general.restartLater=Restart later diff --git a/chrome/locale/ko-KR/zotero/zotero.properties b/chrome/locale/ko-KR/zotero/zotero.properties index 455893be7..79fe42485 100644 --- a/chrome/locale/ko-KR/zotero/zotero.properties +++ b/chrome/locale/ko-KR/zotero/zotero.properties @@ -1,7 +1,7 @@ general.dontShowWarningAgain=Don't show this warning again. general.locate=Locate... -general.restartFirefox.singular=Firefox must be restarted for the change to take effect. -general.restartFirefox.plural=Firefox must be restarted for the changes to take effect. +general.restartRequiredForChange=Firefox must be restarted for the change to take effect. +general.restartRequiredForChanges=Firefox must be restarted for the changes to take effect. general.restartNow=Restart now general.restartLater=Restart later diff --git a/chrome/locale/nb-NO/zotero/zotero.properties b/chrome/locale/nb-NO/zotero/zotero.properties index 737d4d2d9..354c5c5a3 100644 --- a/chrome/locale/nb-NO/zotero/zotero.properties +++ b/chrome/locale/nb-NO/zotero/zotero.properties @@ -1,7 +1,7 @@ general.dontShowWarningAgain=Don't show this warning again. general.locate=Locate... -general.restartFirefox.singular=Firefox must be restarted for the change to take effect. -general.restartFirefox.plural=Firefox must be restarted for the changes to take effect. +general.restartRequiredForChange=Firefox must be restarted for the change to take effect. +general.restartRequiredForChanges=Firefox must be restarted for the changes to take effect. general.restartNow=Restart now general.restartLater=Restart later diff --git a/chrome/locale/nl-NL/zotero/zotero.properties b/chrome/locale/nl-NL/zotero/zotero.properties index 21d7a8ada..bb3a683a2 100644 --- a/chrome/locale/nl-NL/zotero/zotero.properties +++ b/chrome/locale/nl-NL/zotero/zotero.properties @@ -1,7 +1,7 @@ general.dontShowWarningAgain=Don't show this warning again. general.locate=Locate... -general.restartFirefox.singular=Firefox must be restarted for the change to take effect. -general.restartFirefox.plural=Firefox must be restarted for the changes to take effect. +general.restartRequiredForChange=Firefox must be restarted for the change to take effect. +general.restartRequiredForChanges=Firefox must be restarted for the changes to take effect. general.restartNow=Restart now general.restartLater=Restart later diff --git a/chrome/locale/pt-BR/zotero/zotero.properties b/chrome/locale/pt-BR/zotero/zotero.properties index d543726ac..64b0198c0 100644 --- a/chrome/locale/pt-BR/zotero/zotero.properties +++ b/chrome/locale/pt-BR/zotero/zotero.properties @@ -1,7 +1,7 @@ general.dontShowWarningAgain=Don't show this warning again. general.locate=Locate... -general.restartFirefox.singular=Firefox must be restarted for the change to take effect. -general.restartFirefox.plural=Firefox must be restarted for the changes to take effect. +general.restartRequiredForChange=Firefox must be restarted for the change to take effect. +general.restartRequiredForChanges=Firefox must be restarted for the changes to take effect. general.restartNow=Restart now general.restartLater=Restart later diff --git a/chrome/locale/sr-YU/zotero/zotero.properties b/chrome/locale/sr-YU/zotero/zotero.properties index 8c91b644d..4a0718d76 100644 --- a/chrome/locale/sr-YU/zotero/zotero.properties +++ b/chrome/locale/sr-YU/zotero/zotero.properties @@ -1,7 +1,7 @@ general.dontShowWarningAgain=Don't show this warning again. general.locate=Locate... -general.restartFirefox.singular=Firefox must be restarted for the change to take effect. -general.restartFirefox.plural=Firefox must be restarted for the changes to take effect. +general.restartRequiredForChange=Firefox must be restarted for the change to take effect. +general.restartRequiredForChanges=Firefox must be restarted for the changes to take effect. general.restartNow=Restart now general.restartLater=Restart later diff --git a/chrome/locale/tr-TR/zotero/zotero.properties b/chrome/locale/tr-TR/zotero/zotero.properties index 547da23db..edc1f11b3 100644 --- a/chrome/locale/tr-TR/zotero/zotero.properties +++ b/chrome/locale/tr-TR/zotero/zotero.properties @@ -1,7 +1,7 @@ general.dontShowWarningAgain=Don't show this warning again. general.locate=Locate... -general.restartFirefox.singular=Firefox must be restarted for the change to take effect. -general.restartFirefox.plural=Firefox must be restarted for the changes to take effect. +general.restartRequiredForChange=Firefox must be restarted for the change to take effect. +general.restartRequiredForChanges=Firefox must be restarted for the changes to take effect. general.restartNow=Restart now general.restartLater=Restart later diff --git a/chrome/locale/zh-CN/zotero/zotero.properties b/chrome/locale/zh-CN/zotero/zotero.properties index c07578ed3..de38ffc74 100644 --- a/chrome/locale/zh-CN/zotero/zotero.properties +++ b/chrome/locale/zh-CN/zotero/zotero.properties @@ -1,7 +1,7 @@ general.dontShowWarningAgain=Don't show this warning again. general.locate=Locate... -general.restartFirefox.singular=Firefox must be restarted for the change to take effect. -general.restartFirefox.plural=Firefox must be restarted for the changes to take effect. +general.restartRequiredForChange=Firefox must be restarted for the change to take effect. +general.restartRequiredForChanges=Firefox must be restarted for the changes to take effect. general.restartNow=Restart now general.restartLater=Restart later diff --git a/chrome/locale/zh-TW/zotero/zotero.properties b/chrome/locale/zh-TW/zotero/zotero.properties index 0150e3015..7e1c0569b 100644 --- a/chrome/locale/zh-TW/zotero/zotero.properties +++ b/chrome/locale/zh-TW/zotero/zotero.properties @@ -1,7 +1,7 @@ general.dontShowWarningAgain=Don't show this warning again. general.locate=Locate... -general.restartFirefox.singular=Firefox must be restarted for the change to take effect. -general.restartFirefox.plural=Firefox must be restarted for the changes to take effect. +general.restartRequiredForChange=Firefox must be restarted for the change to take effect. +general.restartRequiredForChanges=Firefox must be restarted for the changes to take effect. general.restartNow=Restart now general.restartLater=Restart later diff --git a/chrome/skin/default/zotero/errorReport.css b/chrome/skin/default/zotero/errorReport.css index 1a42fddeb..b999037e4 100644 --- a/chrome/skin/default/zotero/errorReport.css +++ b/chrome/skin/default/zotero/errorReport.css @@ -1,5 +1,5 @@ description { - margin-bottom: 1.5em; + margin: 0 0 1.5em; } /* Intro pane */ diff --git a/chrome/skin/default/zotero/overlay.css b/chrome/skin/default/zotero/overlay.css index b9ae5e1ab..0c2215e80 100644 --- a/chrome/skin/default/zotero/overlay.css +++ b/chrome/skin/default/zotero/overlay.css @@ -264,6 +264,10 @@ -moz-appearance: listbox; } +#zotero-items-pane-message-box description:not(:first-child) { + margin-top: .75em; +} + #zotero-annotate-tb-add {