| 1 |
jQuery(function ($) { |
| 2 |
// Highlight the extensions submenu. |
| 3 |
|
| 4 |
if (typeof(Allex) === 'undefined') { |
| 5 |
if (location.protocol === 'https:') { |
| 6 |
alert("You are using HTTPS, but some files are loading via HTTP. Please check Settings -> General in your WordPress admin dashboard to make sure WordPress Address and Site Address are both HTTPS.\n\nAfter you have done this, make sure your cache is cleared. It may take some time for the change to take effect. If you don't have this option, look for Settings -> Local SSL and check '" + |
| 7 |
"Enable Upgrade All Connections to HTTPS'."); |
| 8 |
} |
| 9 |
else { |
| 10 |
alert("Cannot find Allex library. Please check your settings to ensure that it is available."); |
| 11 |
} |
| 12 |
return; |
| 13 |
} |
| 14 |
|
| 15 |
var allex = new Allex('upstream'); |
| 16 |
allex.highlight_submenu('admin.php?page=upstream_extensions'); |
| 17 |
|
| 18 |
window.upstream_reset_capabilities = function (event) { |
| 19 |
var $btn = $(event.target); |
| 20 |
var label = $btn.text(); |
| 21 |
var buttonSlug = $btn.data('slug'); |
| 22 |
|
| 23 |
if (!confirm(upstreamAdmin.MSG_CONFIRM_RESET_CAPABILITIES)) { |
| 24 |
return; |
| 25 |
} |
| 26 |
|
| 27 |
$.ajax({ |
| 28 |
url: ajaxurl, |
| 29 |
type: 'post', |
| 30 |
data: { |
| 31 |
action: 'upstream_admin_reset_capabilities', |
| 32 |
nonce: $btn.data('nonce'), |
| 33 |
role: buttonSlug |
| 34 |
}, |
| 35 |
beforeSend: function () { |
| 36 |
$btn.text(upstreamAdmin.LB_RESETTING); |
| 37 |
$btn.prop('disabled', true); |
| 38 |
}, |
| 39 |
error: function (response) { |
| 40 |
$msg = $('<span>' + upstreamAdmin.MSG_CAPABILITIES_ERROR + '</span>'); |
| 41 |
$msg.addClass('upstream_float_error'); |
| 42 |
|
| 43 |
$btn.after($msg); |
| 44 |
|
| 45 |
window.setTimeout(function () { |
| 46 |
$msg.fadeOut(); |
| 47 |
}, 4000); |
| 48 |
}, |
| 49 |
success: function (response) { |
| 50 |
$msg = $('<span class="allex-success-message">' + upstreamAdmin.MSG_CAPABILITIES_RESETED + '</span>'); |
| 51 |
$msg.addClass('upstream_float_success'); |
| 52 |
|
| 53 |
$btn.parent().append($msg); |
| 54 |
|
| 55 |
window.setTimeout(function () { |
| 56 |
$msg.fadeOut(); |
| 57 |
}, 4000); |
| 58 |
}, |
| 59 |
complete: function (jqXHR, textStatus) { |
| 60 |
if (textStatus !== 'success') { |
| 61 |
|
| 62 |
} |
| 63 |
|
| 64 |
$btn.text(label); |
| 65 |
$btn.prop('disabled', false); |
| 66 |
} |
| 67 |
}); |
| 68 |
}; |
| 69 |
|
| 70 |
window.upstream_refresh_projects_meta = function (event) { |
| 71 |
var $btn = $(event.target); |
| 72 |
var label = $btn.text(); |
| 73 |
|
| 74 |
if (!confirm(upstreamAdmin.MSG_CONFIRM_REFRESH_PROJECTS_META)) { |
| 75 |
return; |
| 76 |
} |
| 77 |
|
| 78 |
$.ajax({ |
| 79 |
url: ajaxurl, |
| 80 |
type: 'post', |
| 81 |
data: { |
| 82 |
action: 'upstream_admin_refresh_projects_meta', |
| 83 |
nonce: $btn.data('nonce') |
| 84 |
}, |
| 85 |
beforeSend: function () { |
| 86 |
$btn.text(upstreamAdmin.LB_REFRESHING); |
| 87 |
$btn.prop('disabled', true); |
| 88 |
}, |
| 89 |
error: function (response) { |
| 90 |
$msg = $('<span>' + upstreamAdmin.MSG_PROJECTS_META_ERROR + '</span>'); |
| 91 |
$msg.addClass('upstream_float_error'); |
| 92 |
|
| 93 |
$btn.after($msg); |
| 94 |
|
| 95 |
window.setTimeout(function () { |
| 96 |
$msg.fadeOut(); |
| 97 |
}, 4000); |
| 98 |
}, |
| 99 |
success: function (response) { |
| 100 |
$msg = $('<span class="allex-success-message">' + upstreamAdmin.MSG_PROJECTS_SUCCESS + '</span>'); |
| 101 |
$msg.addClass('upstream_float_success'); |
| 102 |
|
| 103 |
$btn.parent().append($msg); |
| 104 |
|
| 105 |
window.setTimeout(function () { |
| 106 |
$msg.fadeOut(); |
| 107 |
}, 4000); |
| 108 |
}, |
| 109 |
complete: function (jqXHR, textStatus) { |
| 110 |
if (textStatus !== 'success') { |
| 111 |
|
| 112 |
} |
| 113 |
|
| 114 |
$btn.text(label); |
| 115 |
$btn.prop('disabled', false); |
| 116 |
} |
| 117 |
}); |
| 118 |
}; |
| 119 |
|
| 120 |
|
| 121 |
window.upstream_import_file = function (event) { |
| 122 |
$('.upstream-option-subpanel').remove(); |
| 123 |
|
| 124 |
/** |
| 125 |
* Prepare the terminal for output the migration data. |
| 126 |
*/ |
| 127 |
var $fieldWrapper = $('.cmb2-id-perform-import .cmb-td'); |
| 128 |
var $importWrapper = $('<div>').addClass('upstream-option-subpanel'); |
| 129 |
var $btn = $(event.target); |
| 130 |
var promptString = ''; |
| 131 |
|
| 132 |
$fieldWrapper.append($importWrapper); |
| 133 |
|
| 134 |
/** |
| 135 |
* Initialize the terminal. |
| 136 |
*/ |
| 137 |
var terminal = $($importWrapper).terminal( |
| 138 |
function (command) { |
| 139 |
error('Please, just wait until the process finish.'); |
| 140 |
}, |
| 141 |
{ |
| 142 |
greetings: '======================================================\nUpStream - Import File\n======================================================', |
| 143 |
name: 'upstream_import_file', |
| 144 |
prompt: promptString |
| 145 |
} |
| 146 |
).disable(); |
| 147 |
|
| 148 |
var echo = function (text) { |
| 149 |
terminal.echo(promptString + text); |
| 150 |
}; |
| 151 |
|
| 152 |
var error = function (text) { |
| 153 |
terminal.error(text); |
| 154 |
}; |
| 155 |
|
| 156 |
$btn.prop('disabled', true); |
| 157 |
|
| 158 |
var call = function (args) { |
| 159 |
var data = args.data; |
| 160 |
data.action = args.action; |
| 161 |
data.nonce = $btn.data('nonce'); |
| 162 |
|
| 163 |
$.ajax({ |
| 164 |
url: ajaxurl, |
| 165 |
type: args.type, |
| 166 |
data: data, |
| 167 |
beforeSend: function () { |
| 168 |
if (typeof args.before !== 'undefined') { |
| 169 |
args.before(); |
| 170 |
} |
| 171 |
}, |
| 172 |
error: function (response) { |
| 173 |
error('Sorry, something is wrong...'); |
| 174 |
error(response.status + ' ' + response.statusText); |
| 175 |
}, |
| 176 |
success: function (response) { |
| 177 |
if (typeof args.after !== 'undefined') { |
| 178 |
args.after(response); |
| 179 |
} |
| 180 |
} |
| 181 |
}); |
| 182 |
}; |
| 183 |
|
| 184 |
var importData = function (i, total) { |
| 185 |
call({ |
| 186 |
action: 'upstream_admin_import_file_section', |
| 187 |
type: 'post', |
| 188 |
data: { |
| 189 |
fileId: $('#import_file_id').val(), |
| 190 |
lineNo: i |
| 191 |
}, |
| 192 |
before: function () { |
| 193 |
echo('Processing lines ' + i + ' to ' + (i+100 > total ? total : i+100) + '...This should take about 3 minutes.'); |
| 194 |
}, |
| 195 |
after: function (response) { |
| 196 |
response = JSON.parse(response); |
| 197 |
|
| 198 |
if (typeof response.success === 'undefined' || !response.success) { |
| 199 |
error(response.message + '\n'); |
| 200 |
$btn.prop('disabled', false); |
| 201 |
echo('End time:' + new Date()); |
| 202 |
} else { |
| 203 |
echo('Section loaded successfullly.\n'); |
| 204 |
|
| 205 |
if (i + 100 <= total) { |
| 206 |
importData(i + 100, total); |
| 207 |
} else { |
| 208 |
echo('\n\nDone.'); |
| 209 |
echo('End time:' + new Date()); |
| 210 |
} |
| 211 |
} |
| 212 |
} |
| 213 |
}); |
| 214 |
}; |
| 215 |
|
| 216 |
// Check how many projects with milestones we have |
| 217 |
call({ |
| 218 |
action: 'upstream_admin_import_file_prepare', |
| 219 |
type: 'get', |
| 220 |
data: { |
| 221 |
fileId: $('#import_file_id').val() |
| 222 |
}, |
| 223 |
before: function () { |
| 224 |
echo('Please wait... we are preparing the file for import.'); |
| 225 |
}, |
| 226 |
after: function (response) { |
| 227 |
response = JSON.parse(response); |
| 228 |
|
| 229 |
if ('total' in response) { |
| 230 |
echo('Found ' + response.total + ' items to import.\n'); |
| 231 |
echo(''); |
| 232 |
echo('Start time:' + new Date()); |
| 233 |
echo('Starting the import process...\n'); |
| 234 |
|
| 235 |
importData(0, response.total); |
| 236 |
} else { |
| 237 |
if ('error' in response) { |
| 238 |
echo(response.error); |
| 239 |
} else { |
| 240 |
echo('\nAn error occurred.'); |
| 241 |
} |
| 242 |
} |
| 243 |
} |
| 244 |
}); |
| 245 |
}; |
| 246 |
|
| 247 |
window.upstream_signup = function (btn) { |
| 248 |
var $btn = $(btn); |
| 249 |
|
| 250 |
$.ajax({ |
| 251 |
url: ajaxurl, |
| 252 |
type: 'post', |
| 253 |
data: { |
| 254 |
action: 'upstream_admin_signup', |
| 255 |
email: $('#upstream-pointer-email').val(), |
| 256 |
nonce: $btn.attr('data-nonce') |
| 257 |
}, |
| 258 |
}); |
| 259 |
|
| 260 |
// TODO: translate this |
| 261 |
$('#upstream-pointer-signup-box').html('Thank you for signing up! You will receive an email confirmation.'); |
| 262 |
}; |
| 263 |
|
| 264 |
window.upstream_cleanup_update_cache = function (event) { |
| 265 |
var $btn = $(event.target); |
| 266 |
var label = $btn.text(); |
| 267 |
|
| 268 |
if (!confirm(upstreamAdmin.MSG_CONFIRM_CLEANUP_UPDATE_CACHE)) { |
| 269 |
return; |
| 270 |
} |
| 271 |
|
| 272 |
$.ajax({ |
| 273 |
url: ajaxurl, |
| 274 |
type: 'post', |
| 275 |
data: { |
| 276 |
action: 'upstream_admin_cleanup_update_cache', |
| 277 |
nonce: $btn.data('nonce') |
| 278 |
}, |
| 279 |
beforeSend: function () { |
| 280 |
$btn.text(upstreamAdmin.LB_REFRESHING); |
| 281 |
$btn.prop('disabled', true); |
| 282 |
}, |
| 283 |
error: function (response) { |
| 284 |
$msg = $('<span>' + upstreamAdmin.MSG_CLEANUP_UPDATE_DATA_ERROR + '</span>'); |
| 285 |
$msg.addClass('upstream_float_error'); |
| 286 |
|
| 287 |
$btn.after($msg); |
| 288 |
|
| 289 |
window.setTimeout(function () { |
| 290 |
$msg.fadeOut(); |
| 291 |
}, 4000); |
| 292 |
}, |
| 293 |
success: function (response) { |
| 294 |
$msg = $('<span class="allex-success-message">' + upstreamAdmin.MSG_PROJECTS_SUCCESS + '</span>'); |
| 295 |
$msg.addClass('upstream_float_success'); |
| 296 |
|
| 297 |
$btn.parent().append($msg); |
| 298 |
|
| 299 |
window.setTimeout(function () { |
| 300 |
$msg.fadeOut(); |
| 301 |
}, 4000); |
| 302 |
}, |
| 303 |
complete: function (jqXHR, textStatus) { |
| 304 |
if (textStatus !== 'success') { |
| 305 |
|
| 306 |
} |
| 307 |
|
| 308 |
$btn.text(label); |
| 309 |
$btn.prop('disabled', false); |
| 310 |
} |
| 311 |
}); |
| 312 |
}; |
| 313 |
|
| 314 |
$("#_upstream_milestone_start_date").datepicker({ |
| 315 |
numberOfMonths: 2, |
| 316 |
dateFormat: 'yy-mm-dd', |
| 317 |
onSelect: function(selected) { |
| 318 |
$("#_upstream_milestone_end_date").datepicker("option","minDate", selected) |
| 319 |
} |
| 320 |
}); |
| 321 |
$("#_upstream_milestone_end_date").datepicker({ |
| 322 |
numberOfMonths: 2, |
| 323 |
dateFormat: 'yy-mm-dd', |
| 324 |
onSelect: function(selected) { |
| 325 |
$("#_upstream_milestone_start_date").datepicker("option","maxDate", selected) |
| 326 |
} |
| 327 |
}); |
| 328 |
|
| 329 |
|
| 330 |
$('.o-datepicker').datepicker({ |
| 331 |
todayBtn: 'linked', |
| 332 |
clearBtn: true, |
| 333 |
autoclose: true, |
| 334 |
keyboardNavigation: false, |
| 335 |
format: upstreamAdmin.datepickerDateFormat |
| 336 |
}).on('change', function (e) { |
| 337 |
var self = $(this); |
| 338 |
|
| 339 |
|
| 340 |
var value = self.datepicker('getDate'); |
| 341 |
|
| 342 |
if (value) { |
| 343 |
value = ((+new Date(value)) / 1000) - (60 * (new Date()).getTimezoneOffset()); |
| 344 |
} |
| 345 |
|
| 346 |
var hiddenField = $('#' + self.attr('id') + '_timestamp'); |
| 347 |
if (hiddenField.length > 0) { |
| 348 |
hiddenField.val(value); |
| 349 |
} |
| 350 |
}); |
| 351 |
|
| 352 |
$('.color-field').wpColorPicker(); |
| 353 |
|
| 354 |
window.upstream_migrate_milestones = function (event) { |
| 355 |
$('.upstream-option-subpanel').remove(); |
| 356 |
|
| 357 |
/** |
| 358 |
* Prepare the terminal for output the migration data. |
| 359 |
*/ |
| 360 |
var $fieldWrapper = $('.cmb2-id-migrate-milestones .cmb-td'); |
| 361 |
var $migrationWrapper = $('<div>').addClass('upstream-option-subpanel'); |
| 362 |
var $btn = $(event.target); |
| 363 |
var promptString = ''; |
| 364 |
|
| 365 |
$fieldWrapper.append($migrationWrapper); |
| 366 |
|
| 367 |
/** |
| 368 |
* Initialize the terminal. |
| 369 |
*/ |
| 370 |
var terminal = $($migrationWrapper).terminal( |
| 371 |
function (command) { |
| 372 |
error('Please, just wait until the process finish.'); |
| 373 |
}, |
| 374 |
{ |
| 375 |
greetings: '======================================================\nUpStream - Legacy Milestone Migration\n======================================================', |
| 376 |
name: 'upstream_milestone_migration', |
| 377 |
prompt: promptString |
| 378 |
} |
| 379 |
).disable(); |
| 380 |
|
| 381 |
var echo = function (text) { |
| 382 |
terminal.echo(promptString + text); |
| 383 |
}; |
| 384 |
|
| 385 |
var error = function (text) { |
| 386 |
terminal.error(text); |
| 387 |
}; |
| 388 |
|
| 389 |
$btn.prop('disabled', true); |
| 390 |
|
| 391 |
var call = function (args) { |
| 392 |
var data = args.data; |
| 393 |
data.action = args.action; |
| 394 |
data.nonce = $btn.data('nonce'); |
| 395 |
|
| 396 |
$.ajax({ |
| 397 |
url: ajaxurl, |
| 398 |
type: args.type, |
| 399 |
data: data, |
| 400 |
beforeSend: function () { |
| 401 |
if (typeof args.before !== 'undefined') { |
| 402 |
args.before(); |
| 403 |
} |
| 404 |
}, |
| 405 |
error: function (response) { |
| 406 |
error('Sorry, something is wrong...'); |
| 407 |
error(response.status + ' ' + response.statusText); |
| 408 |
}, |
| 409 |
success: function (response) { |
| 410 |
if (typeof args.after !== 'undefined') { |
| 411 |
args.after(response); |
| 412 |
} |
| 413 |
} |
| 414 |
}); |
| 415 |
}; |
| 416 |
|
| 417 |
var migrateProject = function (projects, i) { |
| 418 |
var project = projects[i]; |
| 419 |
|
| 420 |
call({ |
| 421 |
action: 'upstream_admin_migrate_milestones_for_project', |
| 422 |
type: 'post', |
| 423 |
data: { |
| 424 |
projectId: project.id |
| 425 |
}, |
| 426 |
before: function () { |
| 427 |
echo('[' + (i + 1) + '] Migrating milestones for ' + project.title); |
| 428 |
}, |
| 429 |
after: function (response) { |
| 430 |
response = JSON.parse(response); |
| 431 |
|
| 432 |
if (typeof response.success === 'undefined' || !response.success) { |
| 433 |
error('Error found while migrating the milestones for the project ' + project.title + '\n'); |
| 434 |
} else { |
| 435 |
echo('Success\n'); |
| 436 |
} |
| 437 |
|
| 438 |
// Call the migration for the next project, if exists. |
| 439 |
if (projects.length > i + 1) { |
| 440 |
migrateProject(projects, i + 1); |
| 441 |
} else { |
| 442 |
echo('\nDone.'); |
| 443 |
|
| 444 |
$btn.prop('disabled', false); |
| 445 |
} |
| 446 |
} |
| 447 |
}); |
| 448 |
}; |
| 449 |
|
| 450 |
// Check how many projects with milestones we have |
| 451 |
call({ |
| 452 |
action: 'upstream_admin_migrate_milestones_get_projects', |
| 453 |
type: 'get', |
| 454 |
data: {}, |
| 455 |
before: function () { |
| 456 |
echo('Please, wait... we are looking for legacy milestones on all projects'); |
| 457 |
}, |
| 458 |
after: function (response) { |
| 459 |
response = JSON.parse(response); |
| 460 |
|
| 461 |
if (response.length > 0) { |
| 462 |
echo(response.length + ' projects with legacy milestones found:\n'); |
| 463 |
var data; |
| 464 |
|
| 465 |
// Display the found projects |
| 466 |
for (var i = 0; i < response.length; i++) { |
| 467 |
data = response[i]; |
| 468 |
|
| 469 |
echo(' ' + (i + 1) + '. ' + data.id + ': ' + data.title + ' (' + data.count + ')'); |
| 470 |
} |
| 471 |
|
| 472 |
echo(''); |
| 473 |
echo('Starting the migration process for each project\n'); |
| 474 |
|
| 475 |
// Trigger the migration for each project |
| 476 |
migrateProject(response, 0); |
| 477 |
} else { |
| 478 |
echo('\nDone. No legacy milestones found.'); |
| 479 |
} |
| 480 |
} |
| 481 |
}); |
| 482 |
}; |
| 483 |
}); |
| 484 |
|
| 485 |
// Sortable |
| 486 |
jQuery(document).ready(function($) { |
| 487 |
if( $("#_upstream_project_milestones_repeat").length ) { |
| 488 |
$("#_upstream_project_milestones_repeat").sortable({ |
| 489 |
stop: function( event, ui ) { |
| 490 |
var idx = 1; |
| 491 |
$("#_upstream_project_milestones_repeat > .cmb-repeatable-grouping").each(function() { |
| 492 |
$(this).attr("idx", idx); |
| 493 |
$.ajax({ |
| 494 |
type: 'POST', |
| 495 |
url: ajaxurl, |
| 496 |
data: { |
| 497 |
action: 'upstream.milestone-edit.editmenuorder', |
| 498 |
post_id: $("#_upstream_project_milestones_" + $(this).attr("data-iterator") + "_id").val(), |
| 499 |
item_val: idx |
| 500 |
}, |
| 501 |
success: function (response) { |
| 502 |
console.log(response); |
| 503 |
} |
| 504 |
}); |
| 505 |
idx++; |
| 506 |
}); |
| 507 |
} |
| 508 |
}); |
| 509 |
} |
| 510 |
$(".task-status").on("change", function() { |
| 511 |
|
| 512 |
// RSD: to avoid this being called before anything was selected |
| 513 |
if (this.selectedIndex < 0) return; |
| 514 |
|
| 515 |
var taskId = $(this).val(); |
| 516 |
var curObj = $(this); |
| 517 |
var curPer = curObj.closest('.cmb2GridRow').find(".task-progress").val(); |
| 518 |
$.ajax({ |
| 519 |
type: 'POST', |
| 520 |
url: ajaxurl, |
| 521 |
data: { |
| 522 |
action: 'upstream.task-edit.gettaskpercent', |
| 523 |
task_id: taskId, |
| 524 |
cur_per: curPer |
| 525 |
}, |
| 526 |
success: function (response) { |
| 527 |
|
| 528 |
// RSD: gettaskpercent returns 0, but dropdown expects "" |
| 529 |
if (response == 0) response = ""; |
| 530 |
|
| 531 |
curObj.closest('.cmb2GridRow').find(".task-progress").val(response).change(); |
| 532 |
} |
| 533 |
}); |
| 534 |
}); |
| 535 |
$(".task-progress").on("click", function() { |
| 536 |
|
| 537 |
// RSD: removed because it was causing too many problems |
| 538 |
return; |
| 539 |
|
| 540 |
var taskPercent = $(this).val(); |
| 541 |
var curObj = $(this); |
| 542 |
$.ajax({ |
| 543 |
type: 'POST', |
| 544 |
url: ajaxurl, |
| 545 |
data: { |
| 546 |
action: 'upstream.task-edit.gettaskstatus', |
| 547 |
task_percent: taskPercent |
| 548 |
}, |
| 549 |
success: function (response) { |
| 550 |
if (response < 0) return; |
| 551 |
curObj.closest('.cmb2GridRow').find(".task-status").val(response).change(); |
| 552 |
} |
| 553 |
}); |
| 554 |
}); |
| 555 |
if( $('.cmb-row.up-o-select2-wrapper select.cmb2_select').length > 0 ) { |
| 556 |
$('.cmb-row.up-o-select2-wrapper select.cmb2_select').select2(); |
| 557 |
} |
| 558 |
var ActiveSelect2 = function(){ |
| 559 |
if( $('.cmb-row.is-new select.cmb2_select').length > 0 ) { |
| 560 |
$('.cmb-row.is-new select.cmb2_select').select2(); |
| 561 |
} |
| 562 |
}; |
| 563 |
$('#_upstream_project_milestones_repeat button, #_upstream_project_files_repeat button, #_upstream_project_tasks_repeat button, #_upstream_project_bugs_repeat button').on("click", function() { |
| 564 |
setTimeout(ActiveSelect2, 500); |
| 565 |
}); |
| 566 |
if( $("#_upstream_project_tasks_repeat").length ) { |
| 567 |
$("#_upstream_project_tasks_repeat").sortable(); |
| 568 |
} |
| 569 |
if( $("#_upstream_project_bugs_repeat").length ) { |
| 570 |
$("#_upstream_project_bugs_repeat").sortable(); |
| 571 |
} |
| 572 |
if( $("#post_type").val() == 'upst_milestone' ) { |
| 573 |
$("#post_type").parent().find("#normal-sortables").css("display", "none"); |
| 574 |
} |
| 575 |
|
| 576 |
/* Change the text color of any invalid license messages */ |
| 577 |
if ( $("#allex-addons-container").length ) { |
| 578 |
setTimeout(() => { |
| 579 |
$( "#allex-addons-container .allex-addon-license-status" ).each(function( index ) { |
| 580 |
if ( $(this).html() != "Activated" ) { |
| 581 |
$(this).css( 'color', '#dc6f8e' ); |
| 582 |
} |
| 583 |
}); |
| 584 |
}, 100); |
| 585 |
} |
| 586 |
|
| 587 |
}); |
| 588 |
|