545 lines
21 KiB
JavaScript
545 lines
21 KiB
JavaScript
'use strict';
|
|
|
|
app.controller('teamInfoController', ['$scope', '$http', 'hoursResourcesConverter', 'cellHighligting', 'teamInfoService', function ($scope, $http, hoursResourcesConverter, cellHighligting, teamInfoService) {
|
|
var collapsedIcon = 'fa-plus-square',
|
|
nonCollapsedIcon = 'fa-minus-square';
|
|
|
|
var RowType = {
|
|
Vacations: 1,
|
|
Trainings: 2,
|
|
Team: 3,
|
|
ExpenditureCategory: 4
|
|
};
|
|
$scope.InternalData = null; //DAL data model
|
|
|
|
$scope.DisplayMode = { // Page Options
|
|
IsUOMHours: true, // display data in Hours
|
|
GroupCapacityByTeam: false, // do not group capacity by team
|
|
TotalsAs: 1, // Allocated/Capacity
|
|
CapacityView: false, // Planned
|
|
IsAvgMode: false // Totals average mode. SA. ENV-1046
|
|
};
|
|
|
|
$scope.DisplayData = {}; // UI data model
|
|
$scope.DisplayDataOrder = ["Vacations", "Trainings"];
|
|
$scope.$on('rebindTeamInfo', function (event, data) {
|
|
if (!data)
|
|
return;
|
|
|
|
$scope.InternalData = {
|
|
Vacations: data.Vacations || {},
|
|
Trainings: data.Trainings || {},
|
|
Header: data.Header || {}
|
|
};
|
|
|
|
initOptions(data.DisplayMode);
|
|
initRows();
|
|
});
|
|
$scope.$on('groupCapacityByTeamChanged', function (event, data) {
|
|
$scope.DisplayMode.GroupCapacityByTeam = data;
|
|
initRows();
|
|
});
|
|
$scope.$on('changeUOMMode', function (event, data) {
|
|
$scope.DisplayMode.IsUOMHours = data;
|
|
initRows();
|
|
});
|
|
$scope.$on('totalsAsChanged', function (event, data) {
|
|
$scope.DisplayMode.TotalsAs = data;
|
|
initRows();
|
|
});
|
|
$scope.$on('capacityViewChanged', function (event, data) {
|
|
$scope.DisplayMode.CapacityView = data;
|
|
initRows();
|
|
});
|
|
$scope.$on('expenditureCategoryValueChanged', function (event, data) {
|
|
if (!data)
|
|
return;
|
|
|
|
expenditureCategoryValueChanged(data.TeamId, data.ExpenditureCategoryId, data.WeekIndex);
|
|
});
|
|
$scope.$on('resourceValueChanged', function (event, data) {
|
|
if (!data)
|
|
return;
|
|
|
|
resourceValueChanged(data.TeamId, data.ExpenditureCategoryId, data.ResourceId, data.WeekIndex);
|
|
});
|
|
$scope.toggleExpCategoryRow = function (key, $event) {
|
|
if (!!$event && angular.isFunction($event.preventDefault))
|
|
$event.preventDefault();
|
|
|
|
$scope.DisplayData[key].IsCollapsed = !$scope.DisplayData[key].IsCollapsed;
|
|
};
|
|
|
|
$scope.isAvgMode = function () {
|
|
return $scope.DisplayMode.IsAvgMode && !$scope.DisplayMode.IsUOMHours;
|
|
}
|
|
|
|
// set page options with values received from outer scope
|
|
function initOptions(options) {
|
|
if (!options)
|
|
return;
|
|
|
|
var modes = Object.keys(options);
|
|
if (modes.indexOf('IsUOMHours') >= 0)
|
|
$scope.DisplayMode.IsUOMHours = options.IsUOMHours;
|
|
if (modes.indexOf('GroupCapacityByTeam') >= 0)
|
|
$scope.DisplayMode.GroupCapacityByTeam = options.GroupCapacityByTeam;
|
|
if (modes.indexOf('TotalsAs') >= 0)
|
|
$scope.DisplayMode.TotalsAs = options.TotalsAs;
|
|
if (modes.indexOf('CapacityView') >= 0)
|
|
$scope.DisplayMode.CapacityView = options.CapacityView;
|
|
if (modes.indexOf('IsAvgMode') >= 0)
|
|
$scope.DisplayMode.IsAvgMode = options.IsAvgMode;
|
|
}
|
|
//==========Start Convert data model to UI data model methods=============//
|
|
function initVacationsRow() {
|
|
return {
|
|
Name: "Vacations",
|
|
Type: RowType.Vacations,
|
|
Cells: new Array($scope.InternalData.Header.Weeks.length)
|
|
};
|
|
}
|
|
function initTrainingsRow() {
|
|
return {
|
|
Name: "Trainings",
|
|
Type: RowType.Trainings,
|
|
Cells: new Array($scope.InternalData.Header.Weeks.length)
|
|
};
|
|
}
|
|
function initTeamRow(id, name) {
|
|
return {
|
|
Id: id,
|
|
Name: name,
|
|
Type: RowType.Team,
|
|
Cells: new Array($scope.InternalData.Header.Weeks.length),
|
|
CSSClass: new Array($scope.InternalData.Header.Weeks.length)
|
|
};
|
|
}
|
|
function initExpCategoryRow(category, teamId) {
|
|
return {
|
|
Id: category.Id,
|
|
TeamId: teamId,
|
|
Name: category.Name,
|
|
Type: RowType.ExpenditureCategory,
|
|
IsCollapsed: true,
|
|
Cells: new Array($scope.InternalData.Header.Weeks.length),
|
|
Resources: [],
|
|
CSSClass: new Array($scope.InternalData.Header.Weeks.length)
|
|
};
|
|
}
|
|
function initResourceRow(resource, catId, teamId) {
|
|
return {
|
|
Id: resource.Id,
|
|
ExpCatId: catId,
|
|
TeamId: teamId,
|
|
Name: resource.Name,
|
|
Cells: new Array($scope.InternalData.Header.Weeks.length),
|
|
CSSClass: new Array($scope.InternalData.Header.Weeks.length)
|
|
};
|
|
}
|
|
function initRows() {
|
|
if (!$scope.InternalData)
|
|
return;
|
|
|
|
$scope.DisplayData = {
|
|
"Vacations": initVacationsRow(),
|
|
"Trainings": initTrainingsRow()
|
|
};
|
|
$scope.DisplayDataOrder = ["Vacations", "Trainings"];
|
|
|
|
var teams = teamInfoService.getAll();
|
|
if (!!teams) {
|
|
for (var teamId in teams) {
|
|
var team = teams[teamId];
|
|
if ($scope.DisplayMode.GroupCapacityByTeam === true) {
|
|
$scope.DisplayData[team.Id] = initTeamRow(team.Id, team.Name);
|
|
$scope.DisplayDataOrder.push(team.Id);
|
|
}
|
|
|
|
if (!team.ExpCategories)
|
|
continue;
|
|
|
|
for (var expCatId in team.ExpCategories) {
|
|
var ec = team.ExpCategories[expCatId];
|
|
var ecKey = $scope.DisplayMode.GroupCapacityByTeam === true ? team.Id + '-' + ec.Id : ec.Id;
|
|
var teamId = $scope.DisplayMode.GroupCapacityByTeam === true ? team.Id : null;
|
|
if (!$scope.DisplayData[ecKey]) {
|
|
$scope.DisplayData[ecKey] = initExpCategoryRow(ec, teamId);
|
|
$scope.DisplayDataOrder.push(ecKey);
|
|
}
|
|
if (!ec.Resources)
|
|
continue;
|
|
|
|
for (var resourceId in ec.Resources) {
|
|
var resource = initResourceRow(ec.Resources[resourceId], ec.Id, teamId);
|
|
$scope.DisplayData[ecKey].Resources.push(resource);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
initRowsData();
|
|
}
|
|
function initRowsData() {
|
|
if (!$scope.InternalData.Header.Months || !$scope.InternalData.Header.Weeks)
|
|
return;
|
|
|
|
for (var i in $scope.DisplayData) {
|
|
var fillCellFunction = undefined,
|
|
originalRow = $scope.DisplayData[i],
|
|
expCat = undefined,
|
|
team = undefined,
|
|
resource = undefined;
|
|
|
|
switch (originalRow.Type) {
|
|
case RowType.Vacations:
|
|
fillCellFunction = fillVacationCell;
|
|
break;
|
|
case RowType.Trainings:
|
|
fillCellFunction = fillTrainingCell;
|
|
break;
|
|
case RowType.Team:
|
|
fillCellFunction = fillTeamCell;
|
|
team = teamInfoService.getById(originalRow.Id);
|
|
break;
|
|
case RowType.ExpenditureCategory:
|
|
fillCellFunction = fillECTotalCell;
|
|
team = teamInfoService.getById(originalRow.TeamId);
|
|
if (team != null)
|
|
expCat = teamInfoService.getExpenditureCategoryInTeam(originalRow.TeamId, originalRow.Id);
|
|
break;
|
|
}
|
|
|
|
for (var mIndex in $scope.InternalData.Header.Months) {
|
|
var month = $scope.InternalData.Header.Months[mIndex];
|
|
if (!month.Childs)
|
|
continue;
|
|
|
|
for (var wIndex in month.Childs) {
|
|
if (fillCellFunction == undefined || typeof fillCellFunction !== 'function') {
|
|
updateTotalCell(originalRow, month.Childs[wIndex], month.SelfIndexInWeeks, [0, 0]);
|
|
} else {
|
|
fillCellFunction(month.Childs[wIndex], month.SelfIndexInWeeks, originalRow, team, expCat);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function fillVacationCell(wIndex, mIndex, originalRow) {
|
|
var week = $scope.InternalData.Header.Weeks[wIndex];
|
|
var value = 0;
|
|
|
|
for (var expCatId in $scope.InternalData.Vacations) {
|
|
var v = $scope.InternalData.Vacations[expCatId][week.Milliseconds] || 0;
|
|
if (!$scope.DisplayMode.IsUOMHours) {
|
|
value += hoursResourcesConverter.convertToResources(expCatId, v);
|
|
}
|
|
else {
|
|
value += v;
|
|
}
|
|
}
|
|
|
|
updateSimpleCell(originalRow, wIndex, mIndex, value);
|
|
}
|
|
function fillTrainingCell(wIndex, mIndex, originalRow) {
|
|
var week = $scope.InternalData.Header.Weeks[wIndex];
|
|
var value = 0;
|
|
|
|
for (var expCatId in $scope.InternalData.Trainings) {
|
|
var v = $scope.InternalData.Trainings[expCatId][week.Milliseconds] || 0;
|
|
if (!$scope.DisplayMode.IsUOMHours) {
|
|
value += hoursResourcesConverter.convertToResources(expCatId, v);
|
|
}
|
|
else {
|
|
value += v;
|
|
}
|
|
}
|
|
|
|
updateSimpleCell(originalRow, wIndex, mIndex, value);
|
|
}
|
|
function fillECTotalCell(wIndex, mIndex, originalRow, team, expCat) {
|
|
var week = $scope.InternalData.Header.Weeks[wIndex];
|
|
var values = {
|
|
Value1: 0,
|
|
Value2: 0
|
|
};
|
|
var resources = [];
|
|
if (!team) {
|
|
var teams = teamInfoService.getAll();
|
|
if (!!teams) {
|
|
for (var teamId in teams) {
|
|
var teamItem = teams[teamId];
|
|
for (var catKey in teamItem.ExpCategories) {
|
|
if (teamItem.ExpCategories[catKey].Id == originalRow.Id) {
|
|
values = getEcCellValue(teamItem.ExpCategories[catKey], week.Milliseconds, values);
|
|
for (var resourceId in teamItem.ExpCategories[catKey].Resources) {
|
|
resources.push(teamItem.ExpCategories[catKey].Resources[resourceId]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (!expCat) {
|
|
throw 'expCat for the team ' + team.Name + ' (' + team.Id + ') is not set';
|
|
} else {
|
|
values = getEcCellValue(expCat, week.Milliseconds);
|
|
for (var resourceId in expCat.Resources) {
|
|
resources.push(expCat.Resources[resourceId]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!$scope.DisplayMode.IsUOMHours) {
|
|
values.Value1 = hoursResourcesConverter.convertToResources(originalRow.Id, values.Value1);
|
|
values.Value2 = hoursResourcesConverter.convertToResources(originalRow.Id, values.Value2);
|
|
}
|
|
updateTotalCell(originalRow, wIndex, mIndex, values);
|
|
updateResourcesCell(originalRow, wIndex, mIndex, resources, week.Milliseconds);
|
|
}
|
|
function fillTeamCell(wIndex, mIndex, originalRow, team) {
|
|
if (team == null)
|
|
return;
|
|
|
|
var week = $scope.InternalData.Header.Weeks[wIndex];
|
|
var values = {
|
|
Value1: 0,
|
|
Value2: 0
|
|
};
|
|
|
|
for (var catKey in team.ExpCategories) {
|
|
values = getEcCellValue(team.ExpCategories[catKey], week.Milliseconds, values);
|
|
}
|
|
|
|
if (!$scope.DisplayMode.IsUOMHours) {
|
|
values.Value1 = hoursResourcesConverter.convertToResources(catKey, values.Value1);
|
|
values.Value2 = hoursResourcesConverter.convertToResources(catKey, values.Value2);
|
|
}
|
|
updateTotalCell(originalRow, wIndex, mIndex, values);
|
|
}
|
|
function updateSimpleCell(originalRow, weekIndex, monthIndex, newValue) {
|
|
if (!originalRow || !originalRow.Cells)
|
|
return;
|
|
|
|
if (originalRow.Cells[monthIndex] == undefined)
|
|
originalRow.Cells[monthIndex] = 0;
|
|
|
|
if (originalRow.Cells[weekIndex] == undefined)
|
|
originalRow.Cells[weekIndex] = 0;
|
|
|
|
// we should increase/decrease month total value by delta between new and old values
|
|
var totalsDelta = newValue;
|
|
var showAverageTotals = $scope.isAvgMode();
|
|
|
|
if (showAverageTotals) {
|
|
var monthIndexInMonthes = $scope.InternalData.Header.Weeks[weekIndex].ParentIndex;
|
|
var weekCountInThisMonth = $scope.InternalData.Header.Months[monthIndexInMonthes].Childs.length;
|
|
totalsDelta = totalsDelta / weekCountInThisMonth;
|
|
}
|
|
|
|
originalRow.Cells[monthIndex] += totalsDelta - originalRow.Cells[weekIndex];
|
|
originalRow.Cells[weekIndex] = newValue;
|
|
}
|
|
function updateResourceCell(expCatRow, originalRow, weekIndex, monthIndex, newValues) {
|
|
if (!originalRow || !originalRow.Cells)
|
|
return;
|
|
|
|
if (originalRow.Cells[monthIndex] == undefined)
|
|
originalRow.Cells[monthIndex] = { Value1: 0, Value2: 0 };
|
|
|
|
if (originalRow.Cells[weekIndex] == undefined)
|
|
originalRow.Cells[weekIndex] = { Value1: 0, Value2: 0 };
|
|
|
|
// we should to increase/decrease month total value by delta between new and old values
|
|
var totalsDelta = {}; // SA. ENV-1046
|
|
totalsDelta.Value1 = newValues.Value1 - originalRow.Cells[weekIndex].Value1;
|
|
totalsDelta.Value2 = newValues.Value2 - originalRow.Cells[weekIndex].Value2;
|
|
|
|
var showAverageTotals = $scope.isAvgMode();
|
|
|
|
if (showAverageTotals) {
|
|
var monthIndexInMonthes = $scope.InternalData.Header.Weeks[weekIndex].ParentIndex;
|
|
var weekCountInThisMonth = $scope.InternalData.Header.Months[monthIndexInMonthes].Childs.length;
|
|
totalsDelta.Value1 = totalsDelta.Value1 / weekCountInThisMonth;
|
|
totalsDelta.Value2 = totalsDelta.Value2 / weekCountInThisMonth;
|
|
}
|
|
|
|
originalRow.Cells[monthIndex].Value1 += totalsDelta.Value1;
|
|
originalRow.Cells[monthIndex].Value2 += totalsDelta.Value2;
|
|
originalRow.Cells[weekIndex] = newValues;
|
|
cellHighligting.setCellCssClasses(expCatRow, originalRow, weekIndex);
|
|
cellHighligting.setCellCssClasses(expCatRow, originalRow, monthIndex);
|
|
}
|
|
function updateResourcesCell(originalRow, weekIndex, monthIndex, resources, milliseconds) {
|
|
if (!originalRow || !originalRow.Resources)
|
|
return;
|
|
|
|
for (var resIndex = 0; resIndex < originalRow.Resources.length; resIndex++) {
|
|
var resRow = originalRow.Resources[resIndex];
|
|
for (var i = 0; i < resources.length; i++) {
|
|
if (resRow.Id == resources[i].Id) {
|
|
var values = getResourceCellValue(resources[i], milliseconds);
|
|
if (!$scope.DisplayMode.IsUOMHours) {
|
|
values.Value1 = hoursResourcesConverter.convertToResources(originalRow.Id, values.Value1);
|
|
values.Value2 = hoursResourcesConverter.convertToResources(originalRow.Id, values.Value2);
|
|
}
|
|
updateResourceCell(originalRow, resRow, weekIndex, monthIndex, values);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function updateTotalCell(originalRow, weekIndex, monthIndex, newValues) {
|
|
if (!originalRow || !originalRow.Cells)
|
|
return;
|
|
|
|
if (originalRow.Cells[monthIndex] == undefined)
|
|
originalRow.Cells[monthIndex] = { Value1: 0, Value2: 0 };
|
|
|
|
if (originalRow.Cells[weekIndex] == undefined)
|
|
originalRow.Cells[weekIndex] = { Value1: 0, Value2: 0 };
|
|
|
|
// we should increase/decrease month total value by delta between new and old values
|
|
var totalsDelta = {}; // SA. ENV-1046
|
|
totalsDelta.Value1 = newValues.Value1 - originalRow.Cells[weekIndex].Value1;
|
|
totalsDelta.Value2 = newValues.Value2 - originalRow.Cells[weekIndex].Value2;
|
|
|
|
var showAverageTotals = $scope.isAvgMode();
|
|
|
|
if (showAverageTotals) {
|
|
var monthIndexInMonthes = $scope.InternalData.Header.Weeks[weekIndex].ParentIndex;
|
|
var weekCountInThisMonth = $scope.InternalData.Header.Months[monthIndexInMonthes].Childs.length;
|
|
totalsDelta.Value1 = totalsDelta.Value1 / weekCountInThisMonth;
|
|
totalsDelta.Value2 = totalsDelta.Value2 / weekCountInThisMonth;
|
|
}
|
|
|
|
originalRow.Cells[monthIndex].Value1 += totalsDelta.Value1;
|
|
originalRow.Cells[monthIndex].Value2 += totalsDelta.Value2;
|
|
originalRow.Cells[weekIndex] = newValues;
|
|
cellHighligting.setCellCssClasses(originalRow, null, weekIndex);
|
|
cellHighligting.setCellCssClasses(originalRow, null, monthIndex);
|
|
}
|
|
// returns an object with values to display in Expenditure Category row (bottom part)
|
|
function getEcCellValue(expCat, index, values) {
|
|
if (!values) {
|
|
values = {
|
|
Value1: 0,
|
|
Value2: 0
|
|
};
|
|
}
|
|
if ($scope.DisplayMode.CapacityView) { // capacity = Actual
|
|
switch (parseInt($scope.DisplayMode.TotalsAs)) {
|
|
case 1:
|
|
//Allocated/Capacity
|
|
values.Value1 += expCat.AllocatedCapacity[index] || 0;
|
|
values.Value2 += expCat.ActualCapacityValues[index] || 0;
|
|
break;
|
|
case 2:
|
|
//Need/Capacity
|
|
values.Value1 += expCat.NeedCapacity[index] || 0;
|
|
values.Value2 += expCat.ActualCapacityValues[index] || 0;
|
|
break;
|
|
case 3:
|
|
//Allocated/Need
|
|
values.Value1 += expCat.AllocatedCapacity[index] || 0;
|
|
values.Value2 += expCat.NeedCapacity[index] || 0;
|
|
break;
|
|
}
|
|
} else { // capacity = Planned
|
|
switch (parseInt($scope.DisplayMode.TotalsAs)) {
|
|
case 1:
|
|
//Allocated/Capacity
|
|
values.Value1 += expCat.AllocatedCapacity[index] || 0;
|
|
values.Value2 += expCat.PlannedCapacityValues[index] || 0;
|
|
break;
|
|
case 2:
|
|
//Need/Capacity
|
|
values.Value1 += expCat.NeedCapacity[index] || 0;
|
|
values.Value2 += expCat.PlannedCapacityValues[index] || 0;
|
|
break;
|
|
case 3:
|
|
//Allocated/Need
|
|
values.Value1 += expCat.AllocatedCapacity[index] || 0;
|
|
values.Value2 += expCat.NeedCapacity[index] || 0;
|
|
break;
|
|
}
|
|
}
|
|
return values;
|
|
}
|
|
// returns an object with values to display in Resource row (bottom part)
|
|
function getResourceCellValue(resource, index) {
|
|
return {
|
|
Value1: resource.AllocatedCapacity[index] || 0,
|
|
Value2: resource.TotalCapacity[index] || 0
|
|
};
|
|
}
|
|
//==========End Convert data model to UI data model methods=============//
|
|
|
|
function expenditureCategoryValueChanged(teamId, expenditureCategoryId, weekIndex) {
|
|
if (!teamId || !expenditureCategoryId)
|
|
return;
|
|
|
|
var team = teamInfoService.getById(teamId);
|
|
if (!team)
|
|
return;
|
|
|
|
var expCategoryInTeam = teamInfoService.getExpenditureCategoryInTeam(teamId, expenditureCategoryId);
|
|
if (!expCategoryInTeam)
|
|
return;
|
|
|
|
var week = $scope.InternalData.Header.Weeks[weekIndex];
|
|
if (!week)
|
|
return;
|
|
|
|
var month = $scope.InternalData.Header.Months[week.ParentIndex];
|
|
if (!month)
|
|
return;
|
|
|
|
var ecKey = $scope.DisplayMode.GroupCapacityByTeam === true ? team.Id + '-' + expenditureCategoryId : expenditureCategoryId;
|
|
var originalRow = $scope.DisplayData[ecKey];
|
|
if (!originalRow)
|
|
return;
|
|
|
|
if ($scope.DisplayMode.GroupCapacityByTeam === true) {
|
|
fillECTotalCell(weekIndex, month.SelfIndexInWeeks, originalRow, team, expCategoryInTeam);
|
|
if (!!$scope.DisplayData[team.Id]) {
|
|
fillTeamCell(weekIndex, month.SelfIndexInWeeks, $scope.DisplayData[team.Id], team);
|
|
}
|
|
} else {
|
|
fillECTotalCell(weekIndex, month.SelfIndexInWeeks, originalRow);
|
|
}
|
|
}
|
|
function resourceValueChanged(teamId, expenditureCategoryId, resourceId, weekIndex) {
|
|
if (!teamId || !expenditureCategoryId || !resourceId)
|
|
return;
|
|
|
|
var team = teamInfoService.getById(teamId);
|
|
if (!team)
|
|
return;
|
|
|
|
var expCategoryInTeam = team.ExpCategories[expenditureCategoryId];
|
|
if (!expCategoryInTeam)
|
|
return;
|
|
|
|
var week = $scope.InternalData.Header.Weeks[weekIndex];
|
|
if (!week)
|
|
return;
|
|
|
|
var month = $scope.InternalData.Header.Months[week.ParentIndex];
|
|
if (!month)
|
|
return;
|
|
|
|
var ecKey = $scope.DisplayMode.GroupCapacityByTeam === true ? team.Id + '-' + expenditureCategoryId : expenditureCategoryId;
|
|
var originalRow = $scope.DisplayData[ecKey];
|
|
if (!originalRow)
|
|
return;
|
|
|
|
if ($scope.DisplayMode.GroupCapacityByTeam === true) {
|
|
fillECTotalCell(weekIndex, month.SelfIndexInWeeks, originalRow, team, expCategoryInTeam);
|
|
if (!!$scope.DisplayData[team.Id]) {
|
|
fillTeamCell(weekIndex, month.SelfIndexInWeeks, $scope.DisplayData[team.Id], team);
|
|
}
|
|
} else {
|
|
fillECTotalCell(weekIndex, month.SelfIndexInWeeks, originalRow);
|
|
}
|
|
}
|
|
}]); |