2015-07-20 22:41:24 +03:00
|
|
|
/* ----------------------------------------------------------------------------
|
|
|
|
* Easy!Appointments - Open Source Web Scheduler
|
2015-10-05 01:31:06 +03:00
|
|
|
*
|
2015-07-20 22:41:24 +03:00
|
|
|
* @package EasyAppointments
|
|
|
|
* @author A.Tselegidis <alextselegidis@gmail.com>
|
|
|
|
* @copyright Copyright (c) 2013 - 2015, Alex Tselegidis
|
2015-10-05 01:31:06 +03:00
|
|
|
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
|
2015-07-20 22:41:24 +03:00
|
|
|
* @link http://easyappointments.org
|
|
|
|
* @since v1.0.0
|
|
|
|
* ---------------------------------------------------------------------------- */
|
|
|
|
|
2013-05-08 17:31:17 +03:00
|
|
|
/**
|
2013-06-13 19:25:34 +03:00
|
|
|
* This file contains the General Functions javascript namespace.
|
2015-10-05 01:31:06 +03:00
|
|
|
* It contains functions that apply both on the front and back
|
2013-05-08 17:31:17 +03:00
|
|
|
* end of the application.
|
2015-10-05 01:31:06 +03:00
|
|
|
*
|
2013-06-13 19:25:34 +03:00
|
|
|
* @namespace GeneralFunctions
|
2013-05-08 17:31:17 +03:00
|
|
|
*/
|
2013-06-13 19:25:34 +03:00
|
|
|
var GeneralFunctions = {
|
2013-09-23 18:42:36 +03:00
|
|
|
/**
|
|
|
|
* General Functions Constants
|
|
|
|
*/
|
2013-12-20 19:44:44 +02:00
|
|
|
EXCEPTIONS_TITLE: EALang['unexpected_issues'],
|
|
|
|
EXCEPTIONS_MESSAGE: EALang['unexpected_issues_message'],
|
|
|
|
WARNINGS_TITLE: EALang['unexpected_warnings'],
|
|
|
|
WARNINGS_MESSAGE: EALang['unexpected_warnings_message'],
|
2015-10-05 01:31:06 +03:00
|
|
|
|
2013-06-13 19:25:34 +03:00
|
|
|
/**
|
|
|
|
* This functions displays a message box in
|
|
|
|
* the admin array. It is usefull when user
|
|
|
|
* decisions or verifications are needed.
|
2015-10-05 01:31:06 +03:00
|
|
|
*
|
2013-06-13 19:25:34 +03:00
|
|
|
* @param {string} title The title of the message box.
|
|
|
|
* @param {string} message The message of the dialog.
|
2015-10-05 01:31:06 +03:00
|
|
|
* @param {array} messageButtons Contains the dialog
|
2013-06-13 19:25:34 +03:00
|
|
|
* buttons along with their functions.
|
|
|
|
*/
|
|
|
|
displayMessageBox: function(title, message, messageButtons) {
|
|
|
|
// Check arguments integrity.
|
2015-04-26 17:20:16 +03:00
|
|
|
if (title == undefined || title == '') {
|
|
|
|
title = '<No Title Given>';
|
2015-10-05 01:31:06 +03:00
|
|
|
}
|
2013-05-08 17:31:17 +03:00
|
|
|
|
2015-04-26 17:20:16 +03:00
|
|
|
if (message == undefined || message == '') {
|
|
|
|
message = '<No Message Given>';
|
2015-10-05 01:31:06 +03:00
|
|
|
}
|
2013-05-08 17:31:17 +03:00
|
|
|
|
2013-06-13 19:25:34 +03:00
|
|
|
if (messageButtons == undefined) {
|
2013-12-19 18:28:19 +02:00
|
|
|
messageButtons = {};
|
2013-12-20 19:44:44 +02:00
|
|
|
messageButtons[EALang['close']] = function() {
|
2015-04-26 17:20:16 +03:00
|
|
|
$('#message_box').dialog('close');
|
2013-06-13 19:25:34 +03:00
|
|
|
};
|
|
|
|
}
|
2013-05-08 17:31:17 +03:00
|
|
|
|
2013-06-13 19:25:34 +03:00
|
|
|
// Destroy previous dialog instances.
|
2015-04-26 17:20:16 +03:00
|
|
|
$('#message_box').dialog('destroy');
|
|
|
|
$('#message_box').remove();
|
2013-06-03 17:42:19 +03:00
|
|
|
|
2013-06-13 19:25:34 +03:00
|
|
|
// Create the html of the message box.
|
2015-04-26 17:20:16 +03:00
|
|
|
$('body').append(
|
|
|
|
'<div id="message_box" title="' + title + '">' +
|
|
|
|
'<p>' + message + '</p>' +
|
|
|
|
'</div>'
|
2015-10-05 01:31:06 +03:00
|
|
|
);
|
2013-06-10 18:51:23 +03:00
|
|
|
|
2015-04-26 17:20:16 +03:00
|
|
|
$("#message_box").dialog({
|
2013-07-06 03:00:04 +03:00
|
|
|
autoOpen: false,
|
|
|
|
modal: true,
|
2015-04-26 17:20:16 +03:00
|
|
|
resize: 'auto',
|
|
|
|
width: 'auto',
|
|
|
|
height: 'auto',
|
2013-07-06 03:00:04 +03:00
|
|
|
resizable: false,
|
|
|
|
buttons: messageButtons,
|
2013-12-29 15:57:09 +02:00
|
|
|
closeOnEscape: true
|
2013-06-13 19:25:34 +03:00
|
|
|
});
|
|
|
|
|
2015-10-05 01:31:06 +03:00
|
|
|
$('#message_box').dialog('open');
|
|
|
|
$('.ui-dialog .ui-dialog-buttonset button').addClass('btn btn-default');
|
2015-04-26 17:20:16 +03:00
|
|
|
$('#message_box .ui-dialog-titlebar-close').hide();
|
2013-06-13 19:25:34 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method centers a DOM element vertically and horizontally
|
|
|
|
* on the page.
|
2015-10-05 01:31:06 +03:00
|
|
|
*
|
|
|
|
* @param {object} elementHandle The object that is going to be
|
2013-06-13 19:25:34 +03:00
|
|
|
* centered.
|
|
|
|
*/
|
|
|
|
centerElementOnPage: function(elementHandle) {
|
|
|
|
// Center main frame vertical middle
|
|
|
|
$(window).resize(function() {
|
|
|
|
var elementLeft = ($(window).width() - elementHandle.outerWidth()) / 2;
|
|
|
|
var elementTop = ($(window).height() - elementHandle.outerHeight()) / 2;
|
|
|
|
elementTop = (elementTop > 0 ) ? elementTop : 20;
|
|
|
|
|
|
|
|
elementHandle.css({
|
2013-07-06 03:00:04 +03:00
|
|
|
position: 'absolute',
|
|
|
|
left: elementLeft,
|
|
|
|
top: elementTop
|
2015-10-05 01:31:06 +03:00
|
|
|
});
|
2013-06-13 19:25:34 +03:00
|
|
|
});
|
|
|
|
$(window).resize();
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
2015-10-05 01:31:06 +03:00
|
|
|
* This function retrieves a parameter from a "GET" formed url.
|
|
|
|
*
|
2013-06-13 19:25:34 +03:00
|
|
|
* @link http://www.netlobo.com/url_query_string_javascript.html
|
2015-10-05 01:31:06 +03:00
|
|
|
*
|
2013-06-13 19:25:34 +03:00
|
|
|
* @param {string} url The selected url.
|
|
|
|
* @param {string} name The parameter name.
|
2015-10-05 01:31:06 +03:00
|
|
|
* @returns {String} Returns the parameter value.
|
2013-06-13 19:25:34 +03:00
|
|
|
*/
|
|
|
|
getUrlParameter: function(url, parameterName) {
|
2015-04-26 17:20:16 +03:00
|
|
|
parameterName = parameterName.replace(/[\[]/,'\\\[').replace(/[\]]/,'\\\]');
|
|
|
|
var regexS = '[\\#&]' + parameterName + '=([^&#]*)';
|
2013-06-13 19:25:34 +03:00
|
|
|
var regex = new RegExp( regexS );
|
|
|
|
var results = regex.exec( url );
|
|
|
|
if( results == null )
|
2015-04-26 17:20:16 +03:00
|
|
|
return '';
|
2013-06-13 19:25:34 +03:00
|
|
|
else
|
|
|
|
return results[1];
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function creates a RFC 3339 date string. This string is needed
|
|
|
|
* by the Google Calendar API in order to pass dates as parameters.
|
2015-10-05 01:31:06 +03:00
|
|
|
*
|
2013-06-13 19:25:34 +03:00
|
|
|
* @param {date} dt The given date that will be transformed
|
|
|
|
* @returns {String} Returns the transformed string.
|
|
|
|
*/
|
|
|
|
ISODateString: function(dt){
|
2015-04-26 17:20:16 +03:00
|
|
|
function pad(n) { return n<10 ? '0'+n : n; }
|
2013-06-13 19:25:34 +03:00
|
|
|
|
|
|
|
return dt.getUTCFullYear()+'-'
|
|
|
|
+ pad(dt.getUTCMonth()+1)+'-'
|
|
|
|
+ pad(dt.getUTCDate())+'T'
|
|
|
|
+ pad(dt.getUTCHours())+':'
|
|
|
|
+ pad(dt.getUTCMinutes())+':'
|
2013-06-24 09:04:30 +03:00
|
|
|
+ pad(dt.getUTCSeconds())+'Z';
|
2013-06-18 19:06:34 +03:00
|
|
|
},
|
2015-10-05 01:31:06 +03:00
|
|
|
|
2013-06-18 19:06:34 +03:00
|
|
|
/**
|
2015-10-05 01:31:06 +03:00
|
|
|
* This method creates and returns an exact copy of the provided object.
|
2013-06-18 19:06:34 +03:00
|
|
|
* It is very usefull whenever changes need to be made to an object without
|
|
|
|
* modyfing the original data.
|
2015-10-05 01:31:06 +03:00
|
|
|
*
|
2013-06-18 19:06:34 +03:00
|
|
|
* @link http://stackoverflow.com/questions/728360/most-elegant-way-to-clone-a-javascript-object
|
2015-10-05 01:31:06 +03:00
|
|
|
*
|
2013-06-18 19:06:34 +03:00
|
|
|
* @param {object} originalObject Object to be copied.
|
|
|
|
* @returns {object} Returns an exact copy of the provided element.
|
|
|
|
*/
|
|
|
|
clone: function(originalObject) {
|
|
|
|
// Handle the 3 simple types, and null or undefined
|
2015-10-05 01:31:06 +03:00
|
|
|
if (null == originalObject || 'object' != typeof originalObject)
|
2013-06-18 19:06:34 +03:00
|
|
|
return originalObject;
|
|
|
|
|
|
|
|
// Handle Date
|
|
|
|
if (originalObject instanceof Date) {
|
|
|
|
var copy = new Date();
|
|
|
|
copy.setTime(originalObject.getTime());
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle Array
|
|
|
|
if (originalObject instanceof Array) {
|
|
|
|
var copy = [];
|
|
|
|
for (var i = 0, len = originalObject.length; i < len; i++) {
|
|
|
|
copy[i] = GeneralFunctions.clone(originalObject[i]);
|
|
|
|
}
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle Object
|
|
|
|
if (originalObject instanceof Object) {
|
|
|
|
var copy = {};
|
|
|
|
for (var attr in originalObject) {
|
2015-10-05 01:31:06 +03:00
|
|
|
if (originalObject.hasOwnProperty(attr))
|
2013-06-18 19:06:34 +03:00
|
|
|
copy[attr] = GeneralFunctions.clone(originalObject[attr]);
|
|
|
|
}
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
2015-04-26 17:20:16 +03:00
|
|
|
throw new Error('Unable to copy obj! Its type isn\'t supported.');
|
2013-06-29 00:54:12 +03:00
|
|
|
},
|
2015-10-05 01:31:06 +03:00
|
|
|
|
2013-06-29 00:54:12 +03:00
|
|
|
/**
|
|
|
|
* This method validates an email address. If the address is not on the proper
|
|
|
|
* form then the result is FALSE.
|
2015-10-05 01:31:06 +03:00
|
|
|
*
|
2015-10-11 23:30:18 +03:00
|
|
|
* @link http://stackoverflow.com/a/46181
|
|
|
|
*
|
2013-06-29 00:54:12 +03:00
|
|
|
* @param {string} email The email address to be checked.
|
|
|
|
* @returns {bool} Returns the validation result.
|
|
|
|
*/
|
2015-10-11 23:30:18 +03:00
|
|
|
validateEmail: function (email) {
|
|
|
|
var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
|
|
|
return re.test(email);
|
2013-07-02 20:18:19 +03:00
|
|
|
},
|
2015-10-05 01:31:06 +03:00
|
|
|
|
2013-07-02 20:18:19 +03:00
|
|
|
/**
|
|
|
|
* This method returns the exception html display for javascript ajax calls.
|
|
|
|
* It uses the Bootstrap collapse module to show exception messages when the
|
|
|
|
* user opens the "Details" collapse component.
|
2015-10-05 01:31:06 +03:00
|
|
|
*
|
2013-07-02 20:18:19 +03:00
|
|
|
* @param {array} exceptions Contains the exceptions to be displayed.
|
2014-01-04 19:25:21 +02:00
|
|
|
* @returns {string} Returns the html markup for the exceptions.
|
2013-07-02 20:18:19 +03:00
|
|
|
*/
|
|
|
|
exceptionsToHtml: function(exceptions) {
|
2015-10-05 01:31:06 +03:00
|
|
|
var html =
|
|
|
|
'<div class="accordion" id="error-accordion">' +
|
|
|
|
'<div class="accordion-group">' +
|
2013-07-02 20:18:19 +03:00
|
|
|
'<div class="accordion-heading">' +
|
|
|
|
'<a class="accordion-toggle" data-toggle="collapse" ' +
|
2015-10-05 01:31:06 +03:00
|
|
|
'data-parent="#error-accordion" href="#error-technical">' +
|
|
|
|
EALang['details'] +
|
2013-07-02 20:18:19 +03:00
|
|
|
'</a>' +
|
|
|
|
'</div>';
|
2015-10-05 01:31:06 +03:00
|
|
|
|
2013-07-02 20:18:19 +03:00
|
|
|
$.each(exceptions, function(index, exception) {
|
|
|
|
html +=
|
|
|
|
'<div id="error-technical" class="accordion-body collapse">' +
|
2015-10-05 01:31:06 +03:00
|
|
|
'<div class="accordion-inner">' +
|
2013-07-02 20:18:19 +03:00
|
|
|
'<pre>' + exception['message'] + '</pre>' +
|
|
|
|
'</div>' +
|
|
|
|
'</div>';
|
|
|
|
});
|
2015-10-05 01:31:06 +03:00
|
|
|
|
2013-07-02 20:18:19 +03:00
|
|
|
html += '</div></div>';
|
2015-10-05 01:31:06 +03:00
|
|
|
|
2013-07-02 20:18:19 +03:00
|
|
|
return html;
|
|
|
|
},
|
2015-10-05 01:31:06 +03:00
|
|
|
|
2013-07-02 20:18:19 +03:00
|
|
|
/**
|
|
|
|
* This method parse the json encoded strings that are fetched by ajax calls.
|
2015-10-05 01:31:06 +03:00
|
|
|
*
|
2013-07-02 20:18:19 +03:00
|
|
|
* @param {array} exceptions Exception array returned by an ajax call.
|
2014-01-04 19:25:21 +02:00
|
|
|
* @returns {array} Returns the parsed js objects.
|
2013-07-02 20:18:19 +03:00
|
|
|
*/
|
|
|
|
parseExceptions: function(exceptions) {
|
|
|
|
var parsedExceptions = new Array();
|
2015-10-05 01:31:06 +03:00
|
|
|
|
2013-07-02 20:18:19 +03:00
|
|
|
$.each(exceptions, function(index, exception) {
|
2015-04-26 17:20:16 +03:00
|
|
|
parsedExceptions.push($.parseJSON(exception));
|
2013-07-02 20:18:19 +03:00
|
|
|
});
|
2015-10-05 01:31:06 +03:00
|
|
|
|
2013-07-02 20:18:19 +03:00
|
|
|
return parsedExceptions;
|
2013-09-18 19:36:29 +03:00
|
|
|
},
|
2015-10-05 01:31:06 +03:00
|
|
|
|
2013-09-18 19:36:29 +03:00
|
|
|
/**
|
|
|
|
* Makes the first letter of the string upper case.
|
2015-10-05 01:31:06 +03:00
|
|
|
*
|
2013-09-18 19:36:29 +03:00
|
|
|
* @param {string} str The string to be converted.
|
|
|
|
* @returns {string} Returns the capitalized string.
|
|
|
|
*/
|
|
|
|
ucaseFirstLetter: function(str){
|
|
|
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
2013-09-23 18:42:36 +03:00
|
|
|
},
|
2015-10-05 01:31:06 +03:00
|
|
|
|
2013-09-23 18:42:36 +03:00
|
|
|
/**
|
|
|
|
* All backend js code has the same way of dislaying exceptions that are raised on the
|
2015-10-05 01:31:06 +03:00
|
|
|
* server during an ajax call.
|
|
|
|
*
|
|
|
|
* @param {object} response Contains the server response. If exceptions or warnings are
|
2013-09-23 18:42:36 +03:00
|
|
|
* found, user friendly messages are going to be displayed to the user.
|
|
|
|
* @returns {bool} Returns whether the the ajax callback should continue the execution or
|
|
|
|
* stop, due to critical server exceptions.
|
|
|
|
*/
|
|
|
|
handleAjaxExceptions: function(response) {
|
|
|
|
if (response.exceptions) {
|
|
|
|
response.exceptions = GeneralFunctions.parseExceptions(response.exceptions);
|
|
|
|
GeneralFunctions.displayMessageBox(GeneralFunctions.EXCEPTIONS_TITLE, GeneralFunctions.EXCEPTIONS_MESSAGE);
|
|
|
|
$('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (response.warnings) {
|
|
|
|
response.warnings = GeneralFunctions.parseExceptions(response.warnings);
|
|
|
|
GeneralFunctions.displayMessageBox(GeneralFunctions.WARNINGS_TITLE, GeneralFunctions.WARNINGS_MESSAGE);
|
|
|
|
$('#message_box').append(GeneralFunctions.exceptionsToHtml(response.warnings));
|
|
|
|
}
|
2015-10-05 01:31:06 +03:00
|
|
|
|
2013-09-23 18:42:36 +03:00
|
|
|
return true;
|
2013-12-23 18:55:42 +02:00
|
|
|
},
|
2015-10-05 01:31:06 +03:00
|
|
|
|
2013-12-23 18:55:42 +02:00
|
|
|
/**
|
|
|
|
* Enables the language selection functionality. Must be called on every page has a
|
|
|
|
* language selection button. This method requires the global variable 'availableLanguages'
|
|
|
|
* to be initialized before the execution.
|
2015-10-05 01:31:06 +03:00
|
|
|
*
|
2013-12-23 18:55:42 +02:00
|
|
|
* @param {object} $element Selected element button for the language selection.
|
|
|
|
*/
|
|
|
|
enableLanguageSelection: function($element) {
|
|
|
|
// Select Language
|
|
|
|
var html = '<ul id="language-list">';
|
|
|
|
$.each(availableLanguages, function() {
|
2015-10-05 01:31:06 +03:00
|
|
|
html += '<li class="language" data-language="' + this + '">'
|
2013-12-23 18:55:42 +02:00
|
|
|
+ GeneralFunctions.ucaseFirstLetter(this) + '</li>';
|
|
|
|
});
|
|
|
|
html += '</ul>';
|
2015-10-05 01:31:06 +03:00
|
|
|
|
2013-12-23 18:55:42 +02:00
|
|
|
$element.popover({
|
|
|
|
'placement': 'top',
|
|
|
|
'title': 'Select Language',
|
|
|
|
'content': html,
|
|
|
|
'html': true,
|
|
|
|
'container': 'body',
|
|
|
|
'trigger': 'manual'
|
|
|
|
});
|
2015-10-05 01:31:06 +03:00
|
|
|
|
2013-12-23 18:55:42 +02:00
|
|
|
$element.click(function() {
|
|
|
|
if ($('#language-list').length == 0) {
|
|
|
|
$(this).popover('show');
|
|
|
|
} else {
|
|
|
|
$(this).popover('hide');
|
|
|
|
}
|
2015-10-06 01:20:55 +03:00
|
|
|
|
|
|
|
$(this).toggleClass('active');
|
2013-12-23 18:55:42 +02:00
|
|
|
});
|
2015-10-05 01:31:06 +03:00
|
|
|
|
2013-12-23 18:55:42 +02:00
|
|
|
$(document).on('click', 'li.language', function() {
|
|
|
|
// Change language with ajax call and refresh page.
|
2015-05-20 23:26:11 +03:00
|
|
|
var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_change_language';
|
2015-10-05 01:31:06 +03:00
|
|
|
var postData = {
|
2015-05-28 00:42:40 +03:00
|
|
|
'csrfToken': GlobalVariables.csrfToken,
|
|
|
|
'language': $(this).attr('data-language'),
|
|
|
|
};
|
2013-12-23 18:55:42 +02:00
|
|
|
$.post(postUrl, postData, function(response) {
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
console.log('Change Language Response', response);
|
|
|
|
////////////////////////////////////////////////////
|
2015-10-05 01:31:06 +03:00
|
|
|
|
2013-12-23 18:55:42 +02:00
|
|
|
if (!GeneralFunctions.handleAjaxExceptions(response)) return;
|
|
|
|
document.location.reload(true);
|
2015-10-05 01:31:06 +03:00
|
|
|
|
2015-10-09 00:12:59 +03:00
|
|
|
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
|
2013-12-23 18:55:42 +02:00
|
|
|
});
|
2015-10-09 00:12:59 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Use this method for common error handling between
|
|
|
|
*
|
|
|
|
* @param {object} jqxhr
|
|
|
|
* @param {string} textStatus
|
|
|
|
* @param {object} errorThrown
|
|
|
|
*/
|
|
|
|
ajaxFailureHandler: function(jqxhr, textStatus, errorThrown) {
|
|
|
|
var exceptions = [
|
|
|
|
{
|
|
|
|
message: 'AJAX Error: ' + textStatus
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
|
|
|
console.log('AJAX Failure Handler:', jqxhr, textStatus, errorThrown);
|
|
|
|
GeneralFunctions.displayMessageBox(GeneralFunctions.EXCEPTIONS_TITLE,
|
|
|
|
GeneralFunctions.EXCEPTIONS_MESSAGE);
|
|
|
|
$('#message_box').append(GeneralFunctions.exceptionsToHtml(exceptions));
|
2015-11-28 13:55:03 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Escape JS HTML string values for XSS prevention.
|
|
|
|
*
|
|
|
|
* @param {string} str String to be escaped.
|
|
|
|
* @returns {string} Returns the escaped string.
|
|
|
|
*/
|
|
|
|
escapeHtml: function(str) {
|
|
|
|
return $('<div/>').text(str).html();
|
2013-06-13 19:25:34 +03:00
|
|
|
}
|
2015-10-05 01:31:06 +03:00
|
|
|
};
|