From ecd1ad362884e6f94af9124a7aff3fe89a370ecb Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Fri, 4 Dec 2015 17:37:26 +0000 Subject: [PATCH] Common method to show split series warning, used for edit popup & drag and drop. Now (tries) to indicate the date the split will occur. --- calendar/js/app.js | 111 +++++++++++----------------- calendar/js/et2_widget_event.js | 50 +++++++++++++ calendar/js/et2_widget_timegrid.js | 27 +++---- calendar/lang/egw_de.lang | 2 +- calendar/lang/egw_en.lang | 2 +- calendar/lang/egw_es-es.lang | 2 +- calendar/lang/egw_fi.lang | 2 +- calendar/lang/egw_fr.lang | 2 +- calendar/lang/egw_it.lang | 2 +- calendar/lang/egw_ru.lang | 2 +- calendar/lang/egw_sk.lang | 2 +- calendar/templates/default/edit.xet | 2 +- 12 files changed, 112 insertions(+), 94 deletions(-) diff --git a/calendar/js/app.js b/calendar/js/app.js index b6e9a1dcb8..4dce8f3c37 100644 --- a/calendar/js/app.js +++ b/calendar/js/app.js @@ -813,70 +813,35 @@ app.classes.calendar = AppJS.extend( } else { - egw().json( - 'calendar.calendar_uiforms.ajax_moveEvent', - [ - dialog_button == 'exception' ? widget.options.value.app_id : widget.options.value.id, - widget.options.value.owner, - widget.options.value.start, - widget.options.value.owner, - widget.options.value.duration, - dialog_button == 'series' ? widget.options.value.start : null - ], - // Remove loading spinner - function() {if(widget && widget.div) widget.div.removeClass('loading');} - ).sendRequest(true); - } - }, - - /** - * This function tries to recognise the type of dropped event, and sends relative request to server accordingly - * -ATM we have three different requests: - * -1. Event part of series - * -2. Single Event (Normall Cal Event) - * -3. Integrated Infolog Event - * - * @param {string} _id dragged event id - * @param {array} _date array of date,hour, and minute of dropped cell - * @param {string} _duration description - * @param {string} _eventFlag Flag to distinguish whether the event is Whole Day, Series, or Single - * - S represents Series - * - WD represents Whole Day - * - WDS represents Whole Day Series (recurrent whole day event) - * - '' represents Single - */ - dropEvent : function(_id, _date, _duration, _eventFlag) - { - var eventId = _id.substring(_id.lastIndexOf("drag_")+5,_id.lastIndexOf("_O")); - var calOwner = _id.substring(_id.lastIndexOf("_O")+2,_id.lastIndexOf("_C")); - var eventOwner = _id.substring(_id.lastIndexOf("_C")+2,_id.lastIndexOf("")); - var date = this.cal_dnd_tZone_converter(_date); - - if (_eventFlag == 'S') - { - et2_dialog.show_dialog(function(_button_id) + var _send = function() { + egw().json( + 'calendar.calendar_uiforms.ajax_moveEvent', + [ + dialog_button == 'exception' ? widget.options.value.app_id : widget.options.value.id, + widget.options.value.owner, + widget.options.value.start, + widget.options.value.owner, + widget.options.value.duration, + dialog_button == 'series' ? widget.options.value.start : null + ], + // Remove loading spinner + function() {if(widget && widget.div) widget.div.removeClass('loading');} + ).sendRequest(true); + } + if(dialog_button == 'series' && widget.options.value.recur_type) { - if (_button_id == et2_dialog.OK_BUTTON) - { - egw().json('calendar.calendar_uiforms.ajax_moveEvent', [eventId, calOwner, date, eventOwner, _duration]).sendRequest(); - } - },this.egw.lang("Do you really want to change the start of this series? If you do, the original series will be terminated as of today and a new series for the future reflecting your changes will be created."), - this.egw.lang("This event is part of a series"), {}, et2_dialog.BUTTONS_OK_CANCEL , et2_dialog.WARNING_MESSAGE); - } - else - { - //Get infologID if in case if it's an integrated infolog event - var infolog_id = eventId.split('infolog')[1]; - - if (infolog_id) - { - // If it is an integrated infolog event we need to edit infolog entry - egw().json('stylite_infolog_calendar_integration::ajax_moveInfologEvent', [infolog_id, date,_duration]).sendRequest(); + widget.series_split_prompt(function(_button_id) + { + if (_button_id == et2_dialog.OK_BUTTON) + { + _send(); + } + } + ); } else { - //Edit calendar event - egw().json('calendar.calendar_uiforms.ajax_moveEvent',[eventId, calOwner, date, eventOwner, _duration]).sendRequest(); + _send(); } } }, @@ -1431,30 +1396,38 @@ app.classes.calendar = AppJS.extend( { var content = this.et2.getArrayMgr('content').data; var start_date = this.et2.getWidgetById('start').get_value(); + var end_date = this.et2.getWidgetById('end').get_value(); var whole_day = this.et2.getWidgetById('whole_day'); + var duration = ''+this.et2.getWidgetById('duration').get_value(); var is_whole_day = whole_day && whole_day.get_value() == whole_day.options.selected_value; var button = _button; var that = this; + + var instance_date = window.location.search.match(/date=(\d{4}-\d{2}-\d{2}(?:.+Z)?)/); + if(instance_date && instance_date.length && instance_date[1]) + { + instance_date = new Date(unescape(instance_date[1])); + instance_date.setUTCMinutes(instance_date.getUTCMinutes() +instance_date.getTimezoneOffset()); + } if (typeof content != 'undefined' && content.id != null && typeof content.recur_type != 'undefined' && content.recur_type != null && content.recur_type != 0 ) { - if (content.start != start_date || content.whole_day != is_whole_day) + if (content.start != start_date || + content.whole_day != is_whole_day || + (duration && ''+content.duration != duration || !duration && end_date != content.end_date) + ) { - et2_dialog.show_dialog(function(_button_id) + et2_calendar_event.series_split_prompt( + content, instance_date, function(_button_id) { if (_button_id == et2_dialog.OK_BUTTON) { that.et2._inst.submit(button); } - else - { - return false; - } - }, - this.egw.lang("Do you really want to change the start of this series? If you do, the original series will be terminated as of today and a new series for the future reflecting your changes will be created."), - this.egw.lang("This event is part of a series"), {}, et2_dialog.BUTTONS_OK_CANCEL , et2_dialog.WARNING_MESSAGE); + } + ); } else { diff --git a/calendar/js/et2_widget_event.js b/calendar/js/et2_widget_event.js index a565edd2bb..98dd372aea 100644 --- a/calendar/js/et2_widget_event.js +++ b/calendar/js/et2_widget_event.js @@ -591,6 +591,16 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM], et2_calendar_event.recur_prompt(this.options.value,callback); }, + /** + * Show the series split prompt for this event + * + * @param {function} callback + */ + series_split_prompt: function(callback) + { + et2_calendar_event.series_split_prompt(this.options.value,this.options.value.recur_date, callback); + }, + /** * Link the actions to the DOM nodes / widget bits. * @@ -710,6 +720,46 @@ et2_calendar_event.recur_prompt = function(event_data, callback) } }; +/** + * Split series prompt + * + * If the event is recurring and the user adjusts the time or duration, we may need + * to split the series, ending the current one and creating a new one with the changes. + * This prompts the user if they really want to do that. + * + * @param {Object} event_data - Event information + * @param {string} event_data.id - Unique ID for the event, possibly with a timestamp + * @param {string|Date} instance_date - The date of the edited instance of the event + * @param {Function} [callback] - Callback is called with the button (ok or cancel) and the event data. + * + * @augments {et2_calendar_event} + */ +et2_calendar_event.series_split_prompt = function(event_data, instance_date, callback) +{ + var egw = this.egw ? (typeof this.egw == 'function' ? this.egw() : this.egw) : (window.opener || window).egw; + var that = this; + + if(typeof instance_date == 'string') + { + instance_date = new Date(instance_date); + } + + // Check for modifying a series that started before today + var tempDate = new Date(); + var today = new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate(),tempDate.getHours(),-tempDate.getTimezoneOffset(),tempDate.getSeconds()); + var termination_date = instance_date < today ? egw.lang('today') : date(egw.preference('dateformat'),instance_date); + + if(parseInt(event_data.recur_type)) + { + et2_dialog.show_dialog( + function(button_id) {callback.call(that, button_id, event_data);}, + (!event_data.is_private ? event_data['title'] : egw.lang('private')) + "\n" + + egw.lang("Do you really want to change the start of this series? If you do, the original series will be terminated as of %1 and a new series for the future reflecting your changes will be created.", termination_date), + egw.lang("This event is part of a series"), {}, et2_dialog.BUTTONS_OK_CANCEL , et2_dialog.WARNING_MESSAGE + ); + } +}; + et2_calendar_event.drag_helper = function(event,ui) { ui.helper.width(ui.width()); }; diff --git a/calendar/js/et2_widget_timegrid.js b/calendar/js/et2_widget_timegrid.js index bb4f43c9f0..21c7f46a07 100644 --- a/calendar/js/et2_widget_timegrid.js +++ b/calendar/js/et2_widget_timegrid.js @@ -251,6 +251,7 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz event_widget.options.value.duration = e.data.duration; } $j(this).trigger(e); + event_widget._update(event_widget.options.value); // That cleared the resize handles, so remove for re-creation... if($j(this).resizable('instance')) @@ -456,24 +457,18 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz }; // Check for modifying a series that started before today - var tempDate = new Date(); - var today = new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate(),0,-tempDate.getTimezoneOffset(),0); - if (event_widget.options.value.recur_type && today >= new Date(event_widget.options.value.start)) + if (event_widget.options.value.recur_type) { - et2_dialog.show_dialog(function(_button_id) + event_widget.series_split_prompt(function(_button_id) { + if (_button_id === et2_dialog.OK_BUTTON) { - if (_button_id == et2_dialog.OK_BUTTON) - { - _send(event_widget.options.value.recur_date); - - } - else - { - loading.remove(); - } - }, - egw.lang("Do you really want to change the start of this series? If you do, the original series will be terminated as of today and a new series for the future reflecting your changes will be created."), - egw.lang("This event is part of a series"), {}, et2_dialog.BUTTONS_OK_CANCEL , et2_dialog.WARNING_MESSAGE); + _send(event_widget.options.value.recur_date); + } + else + { + loading.remove(); + } + }); } else { diff --git a/calendar/lang/egw_de.lang b/calendar/lang/egw_de.lang index 272c77e7e2..2c9bbc7a18 100644 --- a/calendar/lang/egw_de.lang +++ b/calendar/lang/egw_de.lang @@ -160,7 +160,7 @@ display status of events calendar de Status von Terminen anzeigen displayed view calendar de Ansicht displays this calendar view on the home page (page you get when you enter egroupware or click on the home page icon)? calendar de Zeigt diese Ansicht auf der Startseite (Seite die Sie bekommen wenn Sie EGroupware starten oder das Home Icon anklicken)? do not include events of group members calendar de Zeige nicht die Termine der Gruppenmitglieder -do you really want to change the start of this series? if you do, the original series will be terminated as of today and a new series for the future reflecting your changes will be created. calendar de Wollen Sie wirklich den Beginn dieses Serientermins ändern? Wenn Sie das tun, so wird die bestehende Serie heute beendet und für die Zukunft ein neuer Wiederholungstermin mit Ihren Änderungen erzeugt. +do you really want to change the start of this series? if you do, the original series will be terminated as of %1 and a new series for the future reflecting your changes will be created. calendar de Wollen Sie wirklich den Beginn dieses Serientermins ändern? Wenn Sie das tun, so wird die bestehende Serie %1 beendet und für die Zukunft ein neuer Wiederholungstermin mit Ihren Änderungen erzeugt. do you want a weekview with or without weekend? calendar de Möchten Sie eine Wochenansicht mit oder ohne Wochenende? do you want non-egroupware participants of events you created to be automatically notified about new or changed appointments? calendar de Sollen Teilnehmer, die keine EGroupware Benutzer sind, automatisch über Änderungen an von Ihnen angelegten Terminen benachrichtigt werden? do you want to be notified about changes of appointments you modified? calendar de Wollen Sie auch über eigene Änderungen Benachrichtigt werden? diff --git a/calendar/lang/egw_en.lang b/calendar/lang/egw_en.lang index 538584a8a2..5fca7bb510 100644 --- a/calendar/lang/egw_en.lang +++ b/calendar/lang/egw_en.lang @@ -160,7 +160,7 @@ display status of events calendar en Display status of events displayed view calendar en Displayed view displays this calendar view on the home page (page you get when you enter egroupware or click on the home page icon)? calendar en Displays this calendar view on the home page, the page you get when you enter EGroupware or click on the home page icon? do not include events of group members calendar en Do not include events of group members -do you really want to change the start of this series? if you do, the original series will be terminated as of today and a new series for the future reflecting your changes will be created. calendar en Do you really want to change the start of this series? If you do, the original series will be terminated as of today and a new series for the future reflecting your changes will be created. +do you really want to change the start of this series? if you do, the original series will be terminated as of %1 and a new series for the future reflecting your changes will be created. calendar en Do you really want to change the start of this series? If you do, the original series will be terminated as of %1 and a new series for the future reflecting your changes will be created. do you want a weekview with or without weekend? calendar en Do you want a weekview with or without weekend? do you want non-egroupware participants of events you created to be automatically notified about new or changed appointments? calendar en Do you want non-EGroupware participants of events you created to be automatically notified about new or changed appointments? do you want to be notified about changes of appointments you modified? calendar en Do you want to be notified about changes of appointments you modified? diff --git a/calendar/lang/egw_es-es.lang b/calendar/lang/egw_es-es.lang index 459ec37ca7..6a62ea99fa 100644 --- a/calendar/lang/egw_es-es.lang +++ b/calendar/lang/egw_es-es.lang @@ -151,7 +151,7 @@ display in header calendar es-es Mostar en encabezado display status of events calendar es-es Mostrar estado de los eventos displayed view calendar es-es Vista mostrada do not include events of group members calendar es-es No incluir los eventos de los miembros del grupo -do you really want to change the start of this series? if you do, the original series will be terminated as of today and a new series for the future reflecting your changes will be created. calendar es-es ¿Realmente desea cambiar el principio de la serie? Si lo hace, la serie original terminará hoy y se creará otra serie nueva para el futuro reflejando los cambios. +do you really want to change the start of this series? if you do, the original series will be terminated as of %1 and a new series for the future reflecting your changes will be created. calendar es-es ¿Realmente desea cambiar el principio de la serie? Si lo hace, la serie original terminará %1 y se creará otra serie nueva para el futuro reflejando los cambios. do you want a weekview with or without weekend? calendar es-es ¿Desea una vista de la semana con o sin fin de semana? do you want to be notified about changes of appointments you modified? calendar es-es ¿Desea recibir notificaciones de los cambios en las citas que ha modificado? do you want to be notified about new or changed appointments? you are not notified about changes you made yourself.
you can limit the notifications to certain changes only. each item includes all notifications listed above. all modifications include changes of title, description, participants, but no participant responses. if the owner of an event requested any notifcations, he will always get participant responses like acceptions or rejections too. calendar es-es ¿Desea que se le notifiquen citas nuevas o modificadas? Se le notificará de los cambios que haga usted mismo.
Puede limitar las notificaciones para sólo ciertos cambios. Cada elemento incluye toda la notificación listada encima. Todas las modificaciones incluyen cambios de título, participantes, pero no las respuestas de los participantes. Si el dueño de un evento solicitó alguna notificación, siempre obtendrá las respuestas de aceptación o rechazo del participante. diff --git a/calendar/lang/egw_fi.lang b/calendar/lang/egw_fi.lang index db921706b4..d59b22a479 100644 --- a/calendar/lang/egw_fi.lang +++ b/calendar/lang/egw_fi.lang @@ -141,7 +141,7 @@ display status of events calendar fi Näytä tapahtumien tila displayed view calendar fi Valittu näkymä displays this calendar view on the home page (page you get when you enter egroupware or click on the home page icon)? calendar fi Näytä kalenteri Etusivulla do not include events of group members calendar fi Ei ryhmänjäsenten tapahtumia -do you really want to change the start of this series? if you do, the original series will be terminated as of today and a new series for the future reflecting your changes will be created. calendar fi Haluatko varmasti muuttaa tapahtuman aloitusajankohtaa? Jos muutat, alkuperäinen tapahtumasarja päättyy tähän päivään ja luodaan uusi sarja muutoksineen. +do you really want to change the start of this series? if you do, the original series will be terminated as of %1 and a new series for the future reflecting your changes will be created. calendar fi Haluatko varmasti muuttaa tapahtuman aloitusajankohtaa? Jos muutat, alkuperäinen tapahtumasarja päättyy %1 päivään ja luodaan uusi sarja muutoksineen. do you want a weekview with or without weekend? calendar fi Haluatko viikkonäkymän viikonlopun kanssa vai ilman? do you want non-egroupware participants of events you created to be automatically notified about new or changed appointments? calendar fi Lähetetäänkö huomautusviesti EGroupwaren ulkopuolisille käyttäjille merkintään tehtävistä muutoksista ja uusista merkinnöistä? do you want to be notified about changes of appointments you modified? calendar fi Haluatko, että sinua huomautetaan tapahtumista, joita itse muokkasit? diff --git a/calendar/lang/egw_fr.lang b/calendar/lang/egw_fr.lang index fe148265a5..1e282d8ea5 100644 --- a/calendar/lang/egw_fr.lang +++ b/calendar/lang/egw_fr.lang @@ -158,7 +158,7 @@ display status of events calendar fr Afficher le statut des événements displayed view calendar fr Vue affichée displays this calendar view on the home page (page you get when you enter egroupware or click on the home page icon)? calendar fr Afficher cette vue de calendrier dans l'accueil, la page par défaut lors de l'entrée dans eGrouware ou bien lorsque vous cliquer sur l'icône Accueil ? do not include events of group members calendar fr Ne pas inclure les événements des membres du groupe. -do you really want to change the start of this series? if you do, the original series will be terminated as of today and a new series for the future reflecting your changes will be created. calendar fr Confirmez-vous vouloir changer le début de cette série ? Si oui, la série d'origine sera terminée à aujourd'hui et une nouvelle série sera créée dans le futur pour prendre en compte vos changements. +do you really want to change the start of this series? if you do, the original series will be terminated as of %1 and a new series for the future reflecting your changes will be created. calendar fr Confirmez-vous vouloir changer le début de cette série ? Si oui, la série d'origine sera terminée à %1 et une nouvelle série sera créée dans le futur pour prendre en compte vos changements. do you want a weekview with or without weekend? calendar fr Voulez-vous voir les semaines avec ou sans week-end ? do you want non-egroupware participants of events you created to be automatically notified about new or changed appointments? calendar fr Souhaitez-vous que des participants non issus de eGroupware soient automatiquement notifiés des rendez-vous créés ou modifié ? do you want to be notified about changes of appointments you modified? calendar fr Souhaitez-vous être notifié des changements sur les rendez-vous que vous modifiez ? diff --git a/calendar/lang/egw_it.lang b/calendar/lang/egw_it.lang index f062be6bbf..3707a02f31 100644 --- a/calendar/lang/egw_it.lang +++ b/calendar/lang/egw_it.lang @@ -159,7 +159,7 @@ display status of events calendar it Visualizza lo stato degli eventi displayed view calendar it Vista mostrata displays this calendar view on the home page (page you get when you enter egroupware or click on the home page icon)? calendar it Mostra questa visualizzazione dell'agenda nella home page (la pagina che compare cliccando sull'immagine "home") do not include events of group members calendar it Non includere eventi di membri del gruppo -do you really want to change the start of this series? if you do, the original series will be terminated as of today and a new series for the future reflecting your changes will be created. calendar it Confermi di voler modificare l'inizio di questa serie? Se confermi allora la serie originale terminerà da oggi e verrà creata una nuova serie nel futuro, che riflette queste modifiche. +do you really want to change the start of this series? if you do, the original series will be terminated as of %1 and a new series for the future reflecting your changes will be created. calendar it Confermi di voler modificare l'inizio di questa serie? Se confermi allora la serie originale terminerà da %1 e verrà creata una nuova serie nel futuro, che riflette queste modifiche. do you want a weekview with or without weekend? calendar it Vuoi una vista settimanale con o senza weekend? do you want non-egroupware participants of events you created to be automatically notified about new or changed appointments? calendar it Vuoi notificare a partecipanti che non sono utenti di Egroupware circa i nuovi eventi oppure le modifiche degli appuntamenti? do you want to be notified about changes of appointments you modified? calendar it Vuoi ricevere notifiche sui cambiamenti in appuntamenti creati da te? diff --git a/calendar/lang/egw_ru.lang b/calendar/lang/egw_ru.lang index c985f1e8a4..fa7d1efa9f 100644 --- a/calendar/lang/egw_ru.lang +++ b/calendar/lang/egw_ru.lang @@ -148,7 +148,7 @@ display status of events calendar ru Показать статус событи displayed view calendar ru Показывать обзор displays this calendar view on the home page (page you get when you enter egroupware or click on the home page icon)? calendar ru Показывать этот обзор Календаря на домашней странице (на которую Вы попадаете, когда входите в EGroupware или нажимаете на значок домашней страницы) ? do not include events of group members calendar ru Не включать события членов группы -do you really want to change the start of this series? if you do, the original series will be terminated as of today and a new series for the future reflecting your changes will be created. calendar ru Вы действительно хотите изменить начало этой серии? Если да, то исходная серия будет завершена сегодня и новая серия для будущих изменений будет создана. +do you really want to change the start of this series? if you do, the original series will be terminated as of %1 and a new series for the future reflecting your changes will be created. calendar ru Вы действительно хотите изменить начало этой серии? Если да, то исходная серия будет завершена %1 и новая серия для будущих изменений будет создана. do you want a weekview with or without weekend? calendar ru Необходим ли обзор за полную неделю (7 дней) или только рабочую (5 дней) do you want non-egroupware participants of events you created to be automatically notified about new or changed appointments? calendar ru Хотите автоматически уведомлять участников событий, не являющихся пользователями EGroupware, о новых событиях или об изменениях событий ? do you want to be notified about changes of appointments you modified? calendar ru Хотите получать уведомления об изменениях событий, которые Вы произвели ? diff --git a/calendar/lang/egw_sk.lang b/calendar/lang/egw_sk.lang index 7ff809e7c1..6b16f08990 100644 --- a/calendar/lang/egw_sk.lang +++ b/calendar/lang/egw_sk.lang @@ -159,7 +159,7 @@ display status of events calendar sk Zobraziť stav udalostí displayed view calendar sk zobrazený pohľad displays this calendar view on the home page (page you get when you enter egroupware or click on the home page icon)? calendar sk Zobraziť tento pohľad kalendára na domovskej stránke - tej, ktorá sa zobrazí keď otvoríte EGroupware alebo kliknete na ikonu Domov? do not include events of group members calendar sk Nezahrnúť udalosti členov skupiny -do you really want to change the start of this series? if you do, the original series will be terminated as of today and a new series for the future reflecting your changes will be created. calendar sk Naozaj si želáte zmeniť začiatok tejto série? Ak to urobíte, pôvodná séria bude dneškom ukončená a bude vytvorená nová séria pre budúcnosť, v ktorej budú zohľadnené vaše zmeny. +do you really want to change the start of this series? if you do, the original series will be terminated as of %1 and a new series for the future reflecting your changes will be created. calendar sk Naozaj si želáte zmeniť začiatok tejto série? Ak to urobíte, pôvodná séria bude %1 ukončená a bude vytvorená nová séria pre budúcnosť, v ktorej budú zohľadnené vaše zmeny. do you want a weekview with or without weekend? calendar sk Želáte si týždenný pohľad s víkendom alebo bez? do you want non-egroupware participants of events you created to be automatically notified about new or changed appointments? calendar sk Chcete, aby účastníci mimo EGroupware, pri udalostiach ktoré ste vytvorili, boli automaticky upozornení na zmeny alebo nové udalosti? do you want to be notified about changes of appointments you modified? calendar sk Chcete dostávať upozornenia na zmeny tých udalostí, ktoré ste upravili? diff --git a/calendar/templates/default/edit.xet b/calendar/templates/default/edit.xet index 9c50306165..c556227920 100644 --- a/calendar/templates/default/edit.xet +++ b/calendar/templates/default/edit.xet @@ -176,7 +176,7 @@ - +