600 lines
28 KiB
Plaintext
600 lines
28 KiB
Plaintext
@model Disco.Web.Areas.Config.Models.UserFlag.ShowModel
|
|
@using Disco.Services.Interop.ActiveDirectory;
|
|
@using Disco.Services.Users.UserFlags;
|
|
@using Disco.Web.Areas.Config.Models.Shared;
|
|
@{
|
|
Authorization.Require(Claims.Config.UserFlag.Show);
|
|
|
|
ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "User Flags", MVC.Config.UserFlag.Index(null), Model.UserFlag.ToString());
|
|
|
|
var canConfig = Authorization.Has(Claims.Config.UserFlag.Configure);
|
|
var canDelete = Authorization.Has(Claims.Config.UserFlag.Delete);
|
|
var canBulkAssignment = Authorization.HasAll(Claims.User.Actions.AddFlags, Claims.User.Actions.RemoveFlags, Claims.User.ShowFlagAssignments);
|
|
var canShowUsers = Model.CurrentAssignmentCount > 0 && Authorization.HasAll(Claims.User.Search, Claims.User.ShowFlagAssignments);
|
|
var canExportCurrent = Model.CurrentAssignmentCount > 0 && Authorization.Has(Claims.Config.UserFlag.Export);
|
|
var canExportAll = Model.TotalAssignmentCount > 0 && Authorization.Has(Claims.Config.UserFlag.Export);
|
|
|
|
var hideAdvanced =
|
|
Model.UserFlag.UserDevicesLinkedGroup == null &&
|
|
Model.UserFlag.UsersLinkedGroup == null &&
|
|
Model.UserFlag.OnAssignmentExpression == null &&
|
|
Model.UserFlag.OnUnassignmentExpression == null;
|
|
|
|
Html.BundleDeferred("~/ClientScripts/Modules/Disco-PropertyChangeHelpers");
|
|
}
|
|
<div id="Config_UserFlags_Show" class="form@(hideAdvanced ? " Config_HideAdvanced" : null)" style="width: 550px">
|
|
<table>
|
|
<tr>
|
|
<th style="width: 150px">
|
|
Id:
|
|
</th>
|
|
<td>
|
|
@Html.DisplayFor(model => model.UserFlag.Id)
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th>
|
|
Name:
|
|
</th>
|
|
<td>
|
|
@if (canConfig)
|
|
{@Html.EditorFor(model => model.UserFlag.Name)
|
|
@AjaxHelpers.AjaxSave()
|
|
@AjaxHelpers.AjaxLoader()
|
|
<script type="text/javascript">
|
|
$(function () {
|
|
document.DiscoFunctions.PropertyChangeHelper(
|
|
$('#UserFlag_Name'),
|
|
'Invalid Name',
|
|
'@(Url.Action(MVC.API.UserFlag.UpdateName(Model.UserFlag.Id)))',
|
|
'FlagName'
|
|
);
|
|
});
|
|
</script>
|
|
}
|
|
else
|
|
{
|
|
@Model.UserFlag.Name
|
|
}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th>
|
|
Description:
|
|
</th>
|
|
<td>
|
|
@if (canConfig)
|
|
{@Html.EditorFor(model => model.UserFlag.Description)
|
|
@AjaxHelpers.AjaxSave()
|
|
@AjaxHelpers.AjaxLoader()
|
|
<script type="text/javascript">
|
|
$(function () {
|
|
document.DiscoFunctions.PropertyChangeHelper(
|
|
$('#UserFlag_Description'),
|
|
'Invalid Description',
|
|
'@(Url.Action(MVC.API.UserFlag.UpdateDescription(Model.UserFlag.Id)))',
|
|
'Description'
|
|
);
|
|
});
|
|
</script>
|
|
}
|
|
else
|
|
{
|
|
<pre>
|
|
@if (string.IsNullOrEmpty(Model.UserFlag.Description))
|
|
{
|
|
<text><None></text>
|
|
}
|
|
else
|
|
{
|
|
@Model.UserFlag.Description.ToHtmlComment()
|
|
}
|
|
</pre>
|
|
}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th>
|
|
Statistics:
|
|
</th>
|
|
<td>
|
|
<div><strong>@Model.CurrentAssignmentCount user@(Model.CurrentAssignmentCount != 1 ? "s" : null) currently assigned</strong></div>
|
|
<div>@Model.TotalAssignmentCount total user historical assignment@(Model.TotalAssignmentCount != 1 ? "s" : null)</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th>
|
|
Icon:
|
|
</th>
|
|
<td>
|
|
<i id="Config_UserFlags_Icon" data-icon="@(Model.UserFlag.Icon)" data-colour="@(Model.UserFlag.IconColour)" class="fa fa-@(Model.UserFlag.Icon) fa-4x d-@(Model.UserFlag.IconColour)"></i>
|
|
@if (canConfig)
|
|
{
|
|
<div>
|
|
<a id="Config_UserFlags_Icon_Update" href="#" class="button small">Update</a>
|
|
<div id="Config_UserFlags_Icon_Update_Dialog" class="dialog" title="User Flag Icon">
|
|
<div>
|
|
<div class="colours">
|
|
@foreach (var colour in Model.ThemeColours)
|
|
{
|
|
<i data-colour="@(colour.Key)" class="fa fa-square d-@(colour.Key)" title="@colour.Value"></i>
|
|
}
|
|
</div>
|
|
<div class="icons">
|
|
@foreach (var icon in Model.Icons)
|
|
{
|
|
<i data-icon="@(icon.Key)" class="fa fa-@(icon.Key)" title="@icon.Value"></i>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
(function () {
|
|
var dialog, icon, colours, icons;
|
|
|
|
function showDialog() {
|
|
if (!dialog) {
|
|
dialog = $('#Config_UserFlags_Icon_Update_Dialog').dialog({
|
|
resizable: false,
|
|
modal: true,
|
|
autoOpen: false,
|
|
width: 1000,
|
|
buttons: {
|
|
"Save": save,
|
|
Cancel: cancel
|
|
}
|
|
});
|
|
|
|
colours = dialog.find('.colours');
|
|
icons = dialog.find('.icons');
|
|
|
|
colours.on('click', 'i', selectColour);
|
|
icons.on('click', 'i', selectIcon);
|
|
}
|
|
|
|
colours.find('i[data-colour="' + icon.attr('data-colour') + '"]').each(selectColour);
|
|
icons.find('i[data-icon="' + icon.attr('data-icon') + '"]').each(selectIcon);
|
|
|
|
dialog.dialog('open');
|
|
|
|
return false;
|
|
}
|
|
|
|
function selectColour() {
|
|
var $this = $(this),
|
|
colourCode = $this.attr('data-colour'),
|
|
previousColourCode = icons.attr('data-colour');
|
|
|
|
|
|
colours.find('i').removeClass('selected fa-check-square').addClass('fa-square');
|
|
$this.removeClass('fa-square').addClass('fa-check-square selected');
|
|
|
|
if (previousColourCode)
|
|
icons.removeClass('d-' + previousColourCode);
|
|
icons.attr('data-colour', colourCode)
|
|
icons.addClass('d-' + colourCode);
|
|
}
|
|
function selectIcon() {
|
|
var $this = $(this),
|
|
iconCode = $this.attr('data-icon');
|
|
|
|
icons.find('i').removeClass('selected');
|
|
$this.addClass('selected');
|
|
}
|
|
|
|
function save() {
|
|
var url = '@(Url.Action(MVC.API.UserFlag.UpdateIconAndColour(id: Model.UserFlag.Id, redirect: true)))',
|
|
data = {
|
|
Icon: icons.find('i.selected').attr('data-icon'),
|
|
IconColour: colours.find('i.selected').attr('data-colour')
|
|
};
|
|
window.location.href = url + '&' + $.param(data);
|
|
|
|
dialog.dialog("disable");
|
|
dialog.dialog("option", "buttons", null);
|
|
}
|
|
|
|
function cancel() {
|
|
$(this).dialog("close");
|
|
}
|
|
|
|
$(function () {
|
|
icon = $('#Config_UserFlags_Icon');
|
|
$('#Config_UserFlags_Icon_Update').click(showDialog);
|
|
});
|
|
}());
|
|
</script>
|
|
</div>
|
|
}
|
|
</td>
|
|
</tr>
|
|
@if (hideAdvanced)
|
|
{
|
|
<tr>
|
|
<td colspan="2" style="text-align: right;">
|
|
<button id="Config_HideAdvanced_Show" class="button small">Show Advanced Options</button>
|
|
<script>
|
|
$(function () {
|
|
$('#Config_HideAdvanced_Show').click(function () {
|
|
var $this = $(this);
|
|
$this.closest('.Config_HideAdvanced').removeClass('Config_HideAdvanced');
|
|
$this.closest('tr').remove();
|
|
});
|
|
});
|
|
</script>
|
|
</td>
|
|
</tr>
|
|
}
|
|
<tr class="Config_HideAdvanced_Item">
|
|
<th>
|
|
On Assignment<br />Expression:
|
|
</th>
|
|
<td>
|
|
@if (canConfig)
|
|
{
|
|
@Html.EditorFor(model => model.UserFlag.OnAssignmentExpression)
|
|
@AjaxHelpers.AjaxRemove()
|
|
@AjaxHelpers.AjaxSave()
|
|
@AjaxHelpers.AjaxLoader()
|
|
<script type="text/javascript">
|
|
$(function () {
|
|
var field = $('#UserFlag_OnAssignmentExpression');
|
|
var fieldRemove = field.next('.ajaxRemove');
|
|
var fieldOriginalWidth, fieldOriginalHeight;
|
|
|
|
document.DiscoFunctions.PropertyChangeHelper(
|
|
field,
|
|
'None',
|
|
'@Url.Action(MVC.API.UserFlag.UpdateOnAssignmentExpression(Model.UserFlag.Id))',
|
|
'OnAssignmentExpression'
|
|
);
|
|
|
|
field.focus(function () {
|
|
fieldOriginalWidth = field.width();
|
|
fieldOriginalHeight = field.height();
|
|
field.css('overflow', 'visible').animate({ width: field.parent().width() - 42, height: 75 }, 200);
|
|
}).blur(function () {
|
|
field.css('overflow', 'hidden').animate({ width: fieldOriginalWidth, height: fieldOriginalHeight }, 200);
|
|
}).change(function () {
|
|
if (!!field.val()) {
|
|
fieldRemove.show();
|
|
} else {
|
|
fieldRemove.hide();
|
|
}
|
|
}).attr('placeholder', 'None').attr('spellcheck', 'false');
|
|
|
|
fieldRemove.click(function () {
|
|
field.val('').change();
|
|
});
|
|
|
|
if (!!field.val()) {
|
|
fieldRemove.show();
|
|
} else {
|
|
fieldRemove.hide();
|
|
}
|
|
});
|
|
</script>
|
|
}
|
|
else
|
|
{
|
|
if (string.IsNullOrWhiteSpace(Model.UserFlag.OnAssignmentExpression))
|
|
{
|
|
<span class="smallMessage"><None Specified></span>
|
|
}
|
|
else
|
|
{
|
|
<div class="code">
|
|
@Model.UserFlag.OnAssignmentExpression
|
|
</div>
|
|
}
|
|
}
|
|
<div class="info-box">
|
|
<p class="fa-p">
|
|
<i class="fa fa-fw fa-info-circle"></i>This expression will be evaluated whenever the user flag is assigned to a user. The output of the expression will be shown with the flag assignment.
|
|
</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr class="Config_HideAdvanced_Item">
|
|
<th>
|
|
On Unassignment<br />Expression:
|
|
</th>
|
|
<td>
|
|
@if (canConfig)
|
|
{
|
|
@Html.EditorFor(model => model.UserFlag.OnUnassignmentExpression)
|
|
@AjaxHelpers.AjaxRemove()
|
|
@AjaxHelpers.AjaxSave()
|
|
@AjaxHelpers.AjaxLoader()
|
|
<script type="text/javascript">
|
|
$(function () {
|
|
var field = $('#UserFlag_OnUnassignmentExpression');
|
|
var fieldRemove = field.next('.ajaxRemove');
|
|
var fieldOriginalWidth, fieldOriginalHeight;
|
|
|
|
document.DiscoFunctions.PropertyChangeHelper(
|
|
field,
|
|
'None',
|
|
'@Url.Action(MVC.API.UserFlag.UpdateOnUnassignmentExpression(Model.UserFlag.Id))',
|
|
'OnUnassignmentExpression'
|
|
);
|
|
|
|
field.focus(function () {
|
|
fieldOriginalWidth = field.width();
|
|
fieldOriginalHeight = field.height();
|
|
field.css('overflow', 'visible').animate({ width: field.parent().width() - 42, height: 75 }, 200);
|
|
}).blur(function () {
|
|
field.css('overflow', 'hidden').animate({ width: fieldOriginalWidth, height: fieldOriginalHeight }, 200);
|
|
}).change(function () {
|
|
if (!!field.val()) {
|
|
fieldRemove.show();
|
|
} else {
|
|
fieldRemove.hide();
|
|
}
|
|
}).attr('placeholder', 'None').attr('spellcheck', 'false');
|
|
|
|
fieldRemove.click(function () {
|
|
field.val('').change();
|
|
});
|
|
|
|
if (!!field.val()) {
|
|
fieldRemove.show();
|
|
} else {
|
|
fieldRemove.hide();
|
|
}
|
|
});
|
|
</script>
|
|
}
|
|
else
|
|
{
|
|
if (string.IsNullOrWhiteSpace(Model.UserFlag.OnUnassignmentExpression))
|
|
{
|
|
<span class="smallMessage"><None Specified></span>
|
|
}
|
|
else
|
|
{
|
|
<div class="code">
|
|
@Model.UserFlag.OnUnassignmentExpression
|
|
</div>
|
|
}
|
|
}
|
|
<div class="info-box">
|
|
<p class="fa-p">
|
|
<i class="fa fa-fw fa-info-circle"></i>This expression will be evaluated whenever the user flag is removed from a user. The output of the expression will be shown with the flag assignment.
|
|
</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr class="Config_HideAdvanced_Item">
|
|
<th>
|
|
Linked Groups:
|
|
</th>
|
|
<td>
|
|
<div>
|
|
@Html.Partial(MVC.Config.Shared.Views.LinkedGroupInstance, new LinkedGroupModel()
|
|
{
|
|
CanConfigure = canConfig,
|
|
CategoryDescription = UserFlagUsersManagedGroup.GetCategoryDescription(Model.UserFlag),
|
|
Description = UserFlagUsersManagedGroup.GetDescription(Model.UserFlag),
|
|
ManagedGroup = Model.UsersLinkedGroup,
|
|
IncludeFilterBeginDate = true,
|
|
UpdateUrl = Url.Action(MVC.API.UserFlag.UpdateAssignedUsersLinkedGroup(Model.UserFlag.Id, redirect: true))
|
|
})
|
|
@Html.Partial(MVC.Config.Shared.Views.LinkedGroupInstance, new LinkedGroupModel()
|
|
{
|
|
CanConfigure = canConfig,
|
|
CategoryDescription = UserFlagUserDevicesManagedGroup.GetCategoryDescription(Model.UserFlag),
|
|
Description = UserFlagUserDevicesManagedGroup.GetDescription(Model.UserFlag),
|
|
ManagedGroup = Model.UserDevicesLinkedGroup,
|
|
IncludeFilterBeginDate = true,
|
|
UpdateUrl = Url.Action(MVC.API.UserFlag.UpdateAssignedUserDevicesLinkedGroup(Model.UserFlag.Id, redirect: true))
|
|
})
|
|
@if (canConfig)
|
|
{
|
|
@Html.Partial(MVC.Config.Shared.Views.LinkedGroupShared)
|
|
}
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
@if (canBulkAssignment || canDelete || canShowUsers || canExportCurrent || canExportAll)
|
|
{
|
|
<div class="actionBar">
|
|
@if (canExportCurrent)
|
|
{
|
|
@Html.ActionLinkButton("Export Current Assignments", MVC.Config.UserFlag.Export(null, Model.UserFlag.Id, true), "Config_UserFlags_Actions_ExportCurrent_Button")
|
|
}
|
|
@if (canExportAll)
|
|
{
|
|
@Html.ActionLinkButton("Export All Assignments", MVC.Config.UserFlag.Export(null, Model.UserFlag.Id, false), "Config_UserFlags_Actions_ExportAll_Button")
|
|
}
|
|
@if (canBulkAssignment)
|
|
{
|
|
<a href="#" id="Config_UserFlags_BulkAssign_Button" class="button">Bulk Assign Users</a>
|
|
<div id="Config_UserFlags_BulkAssign_ModeDialog" class="dialog" title="Bulk Assign User Mode">
|
|
<p>
|
|
Select the mode used to assign users:
|
|
</p>
|
|
<div>
|
|
<div class="add">
|
|
<h5><i class="fa fa-plus fa-fw"></i>Add</h5>
|
|
<p>
|
|
Specified users will have this flag <strong>added</strong>. Users who already have this flag will be skipped.
|
|
</p>
|
|
</div>
|
|
<div class="override">
|
|
<h5><i class="fa fa-repeat fa-fw"></i>Override</h5>
|
|
<p>
|
|
Specified users will have this flag <strong>added</strong>. Specified users which already have this flag will be skipped.
|
|
Users who already have this flag but are not specified will have the flag <strong>removed</strong>.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="Config_UserFlags_BulkAssign_AssignDialog" class="dialog" title="Bulk Assign Users">
|
|
<div class="brief">
|
|
<div>
|
|
Enter multiple <strong>User Ids</strong> separated by <code><new line></code>, commas (<code>,</code>) or semicolons (<code>;</code>).
|
|
</div>
|
|
<div class="examples clearfix">
|
|
<h4>Examples:</h4>
|
|
<div class="code example1">
|
|
user6<br />
|
|
smi0099<br />
|
|
@(ActiveDirectory.Context.PrimaryDomain.NetBiosName)\rsmith
|
|
</div>
|
|
<div class="code">user6,smi0099,@(ActiveDirectory.Context.PrimaryDomain.NetBiosName)\rsmith</div>
|
|
<div class="code">user6;smi0099;@(ActiveDirectory.Context.PrimaryDomain.NetBiosName)\rsmith</div>
|
|
</div>
|
|
</div>
|
|
<div class="loading">
|
|
<h4><i class="fa fa-lg fa-cog fa-spin" title="Please Wait"></i>Loading current assignments...</h4>
|
|
</div>
|
|
<form action="#" method="post">
|
|
<textarea id="Config_UserFlags_BulkAssign_AssignDialog_UserIds" name="UserIds"></textarea>
|
|
<h4>Comments:</h4>
|
|
<textarea id="Config_UserFlags_BulkAssign_AssignDialog_Comments" name="Comments"></textarea>
|
|
</form>
|
|
</div>
|
|
<script>
|
|
$(function () {
|
|
var modeDialog, assignDialog, assignUserIds;
|
|
|
|
function showModeDialog() {
|
|
if (!modeDialog) {
|
|
modeDialog = $('#Config_UserFlags_BulkAssign_ModeDialog').dialog({
|
|
resizable: false,
|
|
modal: true,
|
|
autoOpen: false,
|
|
width: 400,
|
|
buttons: {
|
|
Cancel: function () {
|
|
$(this).dialog('close');
|
|
}
|
|
}
|
|
});
|
|
|
|
modeDialog.find('.add').click(function () {
|
|
modeDialog.dialog('close');
|
|
showAssignDialog('Add');
|
|
});
|
|
modeDialog.find('.override').click(function () {
|
|
modeDialog.dialog('close');
|
|
showAssignDialog('Override');
|
|
});
|
|
}
|
|
modeDialog.dialog('open');
|
|
}
|
|
function showAssignDialog(mode) {
|
|
if (!assignDialog) {
|
|
assignDialog = $('#Config_UserFlags_BulkAssign_AssignDialog').dialog({
|
|
resizable: false,
|
|
modal: true,
|
|
autoOpen: false,
|
|
width: 460
|
|
});
|
|
|
|
assignUserIds = $('#Config_UserFlags_BulkAssign_AssignDialog_UserIds');
|
|
}
|
|
|
|
assignDialog.removeClass('loading');
|
|
|
|
var buttons = {};
|
|
buttons[mode + " User Flags"] = function () {
|
|
$(this).find('form').submit();
|
|
$(this).dialog("disable");
|
|
}
|
|
buttons['Cancel'] = function () {
|
|
$(this).dialog('close');
|
|
}
|
|
assignDialog.dialog('option', 'buttons', buttons);
|
|
assignDialog.dialog('option', 'title', 'Bulk Assign Users: ' + mode);
|
|
|
|
if (mode == "Override") {
|
|
assignUserIds.closest('form').attr('action', '@(Url.Action(MVC.API.UserFlag.BulkAssignUsers(Model.UserFlag.Id, true)))');
|
|
|
|
assignDialog.addClass('loading');
|
|
$.getJSON('@Url.Action(MVC.API.UserFlag.AssignedUsers(Model.UserFlag.Id))', function (response, result) {
|
|
assignDialog.removeClass('loading');
|
|
|
|
if (result != 'success') {
|
|
alert('Unable to load current assignments:\n' + response);
|
|
assignDialog.dialog('close');
|
|
} else {
|
|
if (!!response) {
|
|
assignUserIds.val(response.join('\n'));
|
|
} else {
|
|
assignUserIds.val('');
|
|
}
|
|
}
|
|
});
|
|
}
|
|
else // Assume Add
|
|
{
|
|
assignUserIds.closest('form').attr('action', '@(Url.Action(MVC.API.UserFlag.BulkAssignUsers(Model.UserFlag.Id, false)))');
|
|
}
|
|
|
|
assignDialog.dialog('open');
|
|
}
|
|
|
|
$('#Config_UserFlags_BulkAssign_Button').click(function () {
|
|
showModeDialog();
|
|
return false;
|
|
});
|
|
});
|
|
</script>
|
|
}
|
|
@if (canDelete)
|
|
{
|
|
@Html.ActionLinkButton("Delete", MVC.API.UserFlag.Delete(Model.UserFlag.Id, true), "Config_UserFlags_Actions_Delete_Button")
|
|
<div id="Config_UserFlags_Actions_Delete_Dialog" title="Delete this User Flag?">
|
|
<p>
|
|
<i class="fa fa-exclamation-triangle fa-lg warning"></i>
|
|
This item will be permanently deleted and cannot be recovered.<br />
|
|
<br />
|
|
@if (Model.CurrentAssignmentCount > 0)
|
|
{
|
|
<strong>@Model.CurrentAssignmentCount user@(Model.CurrentAssignmentCount != 1 ? "s are" : " is") currently assigned</strong>
|
|
<br />
|
|
<br />
|
|
}
|
|
Are you sure?
|
|
</p>
|
|
</div>
|
|
<script type="text/javascript">
|
|
$(function () {
|
|
var button = $('#Config_UserFlags_Actions_Delete_Button');
|
|
var buttonDialog = $('#Config_UserFlags_Actions_Delete_Dialog');
|
|
var buttonLink = button.attr('href');
|
|
button.attr('href', '#');
|
|
button.click(function () {
|
|
buttonDialog.dialog('open');
|
|
return false;
|
|
});
|
|
buttonDialog.dialog({
|
|
resizable: false,
|
|
modal: true,
|
|
autoOpen: false,
|
|
buttons: {
|
|
"Delete": function () {
|
|
var $this = $(this);
|
|
$this.dialog("disable");
|
|
$this.dialog("option", "buttons", null);
|
|
window.location.href = buttonLink;
|
|
},
|
|
Cancel: function () {
|
|
$(this).dialog("close");
|
|
}
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
}
|
|
@if (canShowUsers)
|
|
{
|
|
@Html.ActionLinkButton(string.Format("Show {0} user{1}", Model.CurrentAssignmentCount, (Model.CurrentAssignmentCount == 1 ? null : "s")), MVC.Search.Query(Model.UserFlag.Id.ToString(), "UserFlag"), "Config_UserFlags_Actions_ShowUsers_Button")
|
|
}
|
|
</div>
|
|
} |