567 lines
22 KiB
C#
567 lines
22 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Linq.Expressions;
|
|
using System.Threading.Tasks;
|
|
using LCU.API.Internal.Operations.IncentiveApiLib.Extensions;
|
|
using LCU.API.Internal.Operations.IncentiveApiLib.Persistence;
|
|
using LCU.Library.Internal.IncentiveApiModels.Common;
|
|
using LCU.Library.Internal.IncentiveApiModels.Entities;
|
|
using LCU.Library.Internal.IncentiveApiModels.Enums;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace LCU.API.Internal.Operations.IncentiveApiLib.Repositories;
|
|
|
|
public class ActivityRepository : BaseRepository, IActivityRepository
|
|
{
|
|
public ActivityRepository(IApplicationDbContext context) : base(context)
|
|
{
|
|
}
|
|
|
|
public async Task<int> SaveActivityAsync(Activity activity)
|
|
{
|
|
await _context.Activities.AddAsync(activity);
|
|
return activity.Id;
|
|
}
|
|
|
|
public async Task SaveActivityRangeAsync(List<Activity> activities)
|
|
{
|
|
await _context.Activities.AddRangeAsync(activities);
|
|
}
|
|
|
|
public void UpdateActivityRangeAsync(List<Activity> activities)
|
|
{
|
|
var existing = activities.Where(x => _context.Activities.Contains(x));
|
|
_context.Activities.UpdateRange(activities);
|
|
}
|
|
|
|
public async Task<IReadOnlyCollection<Activity>> GetActivitiesAsync()
|
|
{
|
|
return await _context.Activities
|
|
.Include(activity => activity.Detail)
|
|
.Include(activity => activity.MetaData)
|
|
.OrderBy(t => t.Id)
|
|
.ToListAsync();
|
|
}
|
|
|
|
public async Task<PagedResult<Activity>> GetActivitiesAsync(int page, int limit)
|
|
{
|
|
var results = new PagedResult<Activity>();
|
|
var skip = (page - 1) * limit;
|
|
var activities = _context.Activities
|
|
.Include(activity => activity.Detail)
|
|
.Include(activity => activity.MetaData)
|
|
.OrderByDescending(t => t.Created);
|
|
|
|
|
|
results.Total = activities.Count();
|
|
results.Items = await activities.Skip(skip).Take(limit).ToListAsync();
|
|
return results;
|
|
}
|
|
|
|
public async Task<IReadOnlyCollection<Activity>> FindUnmatchedReferrals()
|
|
{
|
|
var activities = _context.Activities.Include(activity => activity.Detail).Include(activity => activity.MetaData);
|
|
IQueryable<Activity> querySet = activities
|
|
.Where(x => x.Type == ActivityType.Referral
|
|
&& x.State == ActivityState.PendingReferral)
|
|
.OrderByDescending(t => t.LastUpdated);
|
|
|
|
return await querySet.ToListAsync();
|
|
}
|
|
|
|
public async Task<IReadOnlyCollection<Activity>> FindPendingEStatementsReferrals()
|
|
{
|
|
var activities = _context.Activities.Include(activity => activity.Detail).Include(activity => activity.MetaData);
|
|
IQueryable<Activity> querySet = activities
|
|
.Where(x => x.Type == ActivityType.Referral
|
|
&& x.State == ActivityState.PendingReferral
|
|
&& x.Product == Product.eStatement
|
|
&& string.IsNullOrEmpty(x.Detail.AccountNumber))
|
|
.OrderByDescending(t => t.LastUpdated);
|
|
|
|
return await querySet.ToListAsync();
|
|
}
|
|
|
|
public async Task<Activity> FindUnmatchedSaleForReferral(Activity referral)
|
|
{
|
|
var activities = _context.Activities
|
|
.Include(activity => activity.Detail)
|
|
.Include(activity => activity.MetaData);
|
|
|
|
var matchOnMetaData = string.IsNullOrEmpty(referral.Detail.SubjectOrgNbr) && string.IsNullOrEmpty(referral.Detail.SubjectPersonNbr);
|
|
|
|
var matchedActivities = matchOnMetaData
|
|
? await activities.Where(MetaDataMatchPredicate(referral)).ToListAsync()
|
|
: await activities.Where(PersonDataMatchPredicate(referral)).ToListAsync();
|
|
|
|
if (matchOnMetaData && matchedActivities.Any())
|
|
{
|
|
matchedActivities = matchedActivities.Where(x =>
|
|
ListsContainMatchingItem(
|
|
x.MetaData.Where(e => e.MetaDataType == MetaDataType.Email).Select(e => e.MetaData).ToList(),
|
|
referral.MetaData.Where(r => r.MetaDataType == MetaDataType.Email).Select(e => e.MetaData).ToList()
|
|
)
|
|
||
|
|
ListsContainMatchingItem(
|
|
x.MetaData.Where(e => e.MetaDataType == MetaDataType.Phone).Select(e => e.MetaData).ToList(),
|
|
referral.MetaData.Where(r => r.MetaDataType == MetaDataType.Phone).Select(e => e.MetaData).ToList()
|
|
)
|
|
)
|
|
.ToList();
|
|
}
|
|
|
|
var matchingSaleActivityIds = matchedActivities.Select(x => x.Id);
|
|
var activityIDsAssociatedToStateChange = _context.ActivityStateChanges
|
|
.Where(change => matchingSaleActivityIds.Contains(change.ActivityMatchId))
|
|
.Select(x => x.ActivityMatchId);
|
|
var activityIDsNotAssociatedToStateChange = matchingSaleActivityIds.Except(activityIDsAssociatedToStateChange);
|
|
return matchedActivities.Where(x => activityIDsNotAssociatedToStateChange.Contains(x.Id))
|
|
.OrderByDescending(t => t.LastUpdated)
|
|
.FirstOrDefault();
|
|
}
|
|
|
|
public EStatementDeliveryMethod FindDeliveryMethodForEStatement(Activity referral, List<EStatementDeliveryMethod> deliveryMethods)
|
|
{
|
|
var matchedMethods = new List<EStatementDeliveryMethod>();
|
|
var nullReferralOrgNumber = "0";
|
|
|
|
var matchableDeliveryMethods = deliveryMethods.Where(x => x.ActivityDateTime.Date >= referral.SourceCreated.Date).ToList();
|
|
|
|
matchedMethods.AddRange(matchableDeliveryMethods.Where(x => x.PersonNumber == referral.Detail.SubjectPersonNbr
|
|
|| x.OrganizationNumber == (referral.Detail.SubjectOrgNbr ?? nullReferralOrgNumber)
|
|
&& x.OrganizationNumber != nullReferralOrgNumber
|
|
&& referral.Detail.SubjectOrgNbr != nullReferralOrgNumber));
|
|
|
|
matchedMethods.AddRange(matchableDeliveryMethods.Where(x =>
|
|
ListsContainMatchingItem(
|
|
x.MetaData.Where(e => e.MetaDataType == MetaDataType.Email).Select(e => e.MetaData).ToList(),
|
|
referral.MetaData.Where(r => r.MetaDataType == MetaDataType.Email).Select(e => e.MetaData).ToList()
|
|
)
|
|
||
|
|
ListsContainMatchingItem(
|
|
x.MetaData.Where(e => e.MetaDataType == MetaDataType.Phone).Select(e => e.MetaData).ToList(),
|
|
referral.MetaData.Where(r => r.MetaDataType == MetaDataType.Phone).Select(e => e.MetaData).ToList()
|
|
)
|
|
)
|
|
.ToList());
|
|
|
|
var matchedMethod = matchedMethods.OrderByDescending(a => a.ActivityDateTime).FirstOrDefault();
|
|
|
|
if (matchedMethod != null)
|
|
{
|
|
deliveryMethods.Remove(matchedMethod);
|
|
}
|
|
|
|
return matchedMethod;
|
|
}
|
|
|
|
private static Expression<Func<Activity, bool>> MetaDataMatchPredicate(Activity referral)
|
|
{
|
|
return x => (x.Type == ActivityType.Sale || x.Type == ActivityType.Other)
|
|
&& x.Product == referral.Product
|
|
&& x.MetaData != null && referral.MetaData != null
|
|
&& x.State == ActivityState.Accepted
|
|
&& x.SourceCreated.Date >= referral.SourceCreated.Date;
|
|
}
|
|
|
|
private static bool ListsContainMatchingItem(IReadOnlyList<string> list1, IReadOnlyList<string> list2)
|
|
{
|
|
if ((list1?.Any() ?? false) && (list2?.Any() ?? false))
|
|
{
|
|
return list1.Any(x => list2.Any(t => string.Equals(t, x, StringComparison.CurrentCultureIgnoreCase)));
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private static Expression<Func<Activity, bool>> PersonDataMatchPredicate(Activity referral)
|
|
{
|
|
return x => (x.Type == ActivityType.Sale || x.Type == ActivityType.Other)
|
|
&& x.Product == referral.Product
|
|
&& x.Detail.SubjectPersonNbr == referral.Detail.SubjectPersonNbr
|
|
&& x.Detail.SubjectOrgNbr == referral.Detail.SubjectOrgNbr
|
|
&& x.State == ActivityState.Accepted
|
|
&& x.SourceCreated.Date >= referral.SourceCreated.Date;
|
|
}
|
|
|
|
public async Task<Activity> FindDuplicateSaleAsync(Activity queryActivity)
|
|
{
|
|
if (queryActivity.Detail == null || queryActivity.Type != ActivityType.Sale)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var activities = _context.Activities
|
|
.Include(activity => activity.Detail)
|
|
.Include(activity => activity.MetaData);
|
|
|
|
IQueryable<Activity> querySet = activities
|
|
.Where(x => x.Id != queryActivity.Id
|
|
&& x.Product == queryActivity.Product
|
|
&& x.Type == queryActivity.Type
|
|
&& x.Detail.AccountNumber == queryActivity.Detail.AccountNumber
|
|
&& x.Detail.SubAccountNumber == queryActivity.Detail.SubAccountNumber
|
|
&& x.Detail.SubjectOrgNbr == queryActivity.Detail.SubjectOrgNbr
|
|
&& x.Detail.SubjectPersonNbr == queryActivity.Detail.SubjectPersonNbr
|
|
&& (
|
|
queryActivity.SourceId == null
|
|
|| x.SourceId == queryActivity.SourceId)
|
|
)
|
|
.OrderByDescending(t => t.LastUpdated);
|
|
|
|
return await querySet.FirstOrDefaultAsync();
|
|
}
|
|
|
|
public async Task<Activity> FindDuplicateReferralAsync(Activity queryActivity)
|
|
{
|
|
if (queryActivity.Detail == null || queryActivity.Type != ActivityType.Referral)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var activities = _context.Activities
|
|
.Include(activity => activity.Detail);
|
|
|
|
IQueryable<Activity> querySet = activities
|
|
.Where(x => x.Id != queryActivity.Id
|
|
&& x.Type == queryActivity.Type && x.Product == queryActivity.Product
|
|
&& x.Detail.SubjectPersonNbr != null && queryActivity.Detail.SubjectPersonNbr != null
|
|
&& x.Detail.SubjectOrgNbr != null && queryActivity.Detail.SubjectOrgNbr != null
|
|
&& x.Detail.SubjectPersonNbr == queryActivity.Detail.SubjectPersonNbr
|
|
&& x.Detail.SubjectOrgNbr == queryActivity.Detail.SubjectOrgNbr
|
|
)
|
|
.OrderByDescending(t => t.LastUpdated);
|
|
|
|
return await querySet.FirstOrDefaultAsync();
|
|
}
|
|
|
|
public async Task<Activity> FindActivityForStateUpdate(Activity queryActivity)
|
|
{
|
|
if (queryActivity.Detail == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var activities = _context.Activities
|
|
.Include(activity => activity.Detail)
|
|
.Include(activity => activity.MetaData);
|
|
|
|
IQueryable<Activity> querySet = activities
|
|
.Where(x => x.EmployeeEmail == queryActivity.EmployeeEmail
|
|
&& x.EmployeeId == queryActivity.EmployeeId
|
|
&& x.DepartmentId == queryActivity.DepartmentId
|
|
&& x.Product == queryActivity.Product
|
|
&& x.SourceCreated.Date == queryActivity.SourceCreated.Date
|
|
&& x.SourceSystem == queryActivity.SourceSystem
|
|
&& x.Type == queryActivity.Type
|
|
&& x.Detail.AccountNumber == queryActivity.Detail.AccountNumber
|
|
&& x.Detail.SubAccountNumber == queryActivity.Detail.SubAccountNumber
|
|
)
|
|
.OrderByDescending(t => t.LastUpdated);
|
|
|
|
var returnedItems = await querySet.ToListAsync();
|
|
Func<Activity, bool> activityStateCondition = x => x.State != queryActivity.State;
|
|
var returnItem = returnedItems.Count(activityStateCondition) > 1
|
|
? returnedItems.FirstOrDefault(activityStateCondition)
|
|
: returnedItems.FirstOrDefault();
|
|
|
|
return returnItem;
|
|
}
|
|
|
|
public async Task<Activity> FindActivityForDetailUpdate(Activity queryActivity)
|
|
{
|
|
if (queryActivity.Detail == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var returnedItems = await GetActivityForDetailUpdate(queryActivity);
|
|
|
|
if (returnedItems.Count == 0)
|
|
{
|
|
returnedItems = await GetActivityForDetailUpdate(queryActivity, false);
|
|
}
|
|
|
|
if (returnedItems.Count == 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
Func<Activity, bool> activityStatePredicate = x => x.State == ActivityState.Accepted;
|
|
var returnItem = returnedItems.Count(activityStatePredicate) >= 1
|
|
? returnedItems.FirstOrDefault(activityStatePredicate)
|
|
: returnedItems.FirstOrDefault();
|
|
|
|
return returnItem;
|
|
}
|
|
|
|
private async Task<List<Activity>> GetActivityForDetailUpdate(Activity queryActivity, bool filterOnSubAccountNumber = true)
|
|
{
|
|
var activities = _context.Activities
|
|
.Include(activity => activity.Detail)
|
|
.Include(activity => activity.MetaData);
|
|
|
|
IQueryable<Activity> querySet = activities
|
|
.Where(x => x.EmployeeEmail == queryActivity.EmployeeEmail
|
|
&& x.EmployeeId == queryActivity.EmployeeId
|
|
&& x.DepartmentId == queryActivity.DepartmentId
|
|
&& x.Product == queryActivity.Product
|
|
&& x.SourceSystem == queryActivity.SourceSystem
|
|
&& x.Type == queryActivity.Type
|
|
&& x.Detail.AccountNumber == queryActivity.Detail.AccountNumber
|
|
)
|
|
.OrderByDescending(t => t.LastUpdated);
|
|
|
|
if (filterOnSubAccountNumber)
|
|
{
|
|
return await querySet.Where(x => x.Detail.SubAccountNumber == queryActivity.Detail.SubAccountNumber).ToListAsync();
|
|
}
|
|
|
|
return await querySet.Where(x => x.State == ActivityState.Accepted).ToListAsync();
|
|
}
|
|
|
|
public async Task<PagedResult<Activity>> GetPagedFilteredActivities(ActivityFilter filter)
|
|
{
|
|
var results = new PagedResult<Activity>();
|
|
var skip = (filter.Page - 1) * filter.Limit;
|
|
var activities = _context.Activities.Include(activity => activity.Detail).Include(activity => activity.MetaData);
|
|
IQueryable<Activity> querySet = activities;
|
|
|
|
if (filter.Product != null && filter.Product.Any())
|
|
{
|
|
var products = filter.Product;
|
|
querySet = querySet.Where(x => products.Contains(x.Product));
|
|
}
|
|
|
|
if (filter.Type != null && filter.Type.Any())
|
|
{
|
|
var types = filter.Type;
|
|
querySet = querySet.Where(x => types.Contains(x.Type));
|
|
}
|
|
|
|
if (filter.State != null && filter.State.Any())
|
|
{
|
|
var states = filter.State;
|
|
querySet = querySet.Where(x => states.Contains(x.State));
|
|
}
|
|
|
|
if (filter.DateLow != null)
|
|
{
|
|
querySet = querySet.Where(x => x.Accepted.Date >= filter.DateLow);
|
|
}
|
|
|
|
if (filter.DateHigh != null)
|
|
{
|
|
querySet = querySet.Where(x => x.Accepted.Date <= filter.DateHigh);
|
|
}
|
|
|
|
if (filter.DepartmentId != 0)
|
|
{
|
|
querySet = querySet.Where(x => x.DepartmentId == filter.DepartmentId);
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(filter.EmployeeId))
|
|
{
|
|
querySet = querySet.Where(x => x.EmployeeId == filter.EmployeeId);
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(filter.Query))
|
|
{
|
|
var query = filter.Query.ToLower().Trim();
|
|
querySet = querySet.Where(x =>
|
|
x.Detail.MemberName.ToLower().Contains(query)
|
|
|| x.Detail.AccountNumber.ToLower().Contains(query)
|
|
|| x.Detail.SubjectPersonNbr.ToLower().Contains(query)
|
|
|| x.Detail.SubjectOrgNbr.ToLower().Contains(query)
|
|
|| x.SourceId.ToLower() == query
|
|
|| query == x.Id.ToString());
|
|
}
|
|
|
|
querySet = SortQuerySet(querySet, filter);
|
|
results.Total = querySet.Count();
|
|
results.Items = await querySet.Skip(skip).Take(filter.Limit).ToListAsync();
|
|
return results;
|
|
}
|
|
|
|
public async Task<List<Activity>> GetAllActivitiesWithPayoutsForEmployee(string employeeId)
|
|
{
|
|
return await _context.Activities.Include(activity => activity.ActivityPayouts).Where(x => x.EmployeeId == employeeId).ToListAsync();
|
|
}
|
|
|
|
private IQueryable<Activity> SortQuerySet(IQueryable<Activity> querySet, ActivityFilter filter)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(filter.SortBy))
|
|
{
|
|
return querySet
|
|
.OrderByDescending(t => t.Accepted);
|
|
}
|
|
|
|
if (filter.SortDescending.HasValue && filter.SortDescending.Value)
|
|
{
|
|
return (IQueryable<Activity>)querySet.OrderByDescending<Activity>(filter.SortBy);
|
|
}
|
|
|
|
return (IQueryable<Activity>)querySet.OrderBy<Activity>(filter.SortBy);
|
|
}
|
|
|
|
public async Task<Activity> GetActivityById(int activityId)
|
|
{
|
|
return await _context.Activities.FindAsync(activityId);
|
|
}
|
|
|
|
public async Task<ICollection<Activity>> FindEmployeeActivityByMonthRange(AppUser appUser, MonthRange monthRange)
|
|
{
|
|
return await _context.Activities
|
|
.Include(activity => activity.Detail)
|
|
.Include(activity => activity.MetaData)
|
|
.Where(x => x.Accepted.Date >= monthRange.StartTime.Date &&
|
|
x.Accepted.Date <= monthRange.EndTime.Date &&
|
|
appUser.EmployeeId == x.EmployeeId)
|
|
.ToListAsync();
|
|
}
|
|
|
|
public async Task<ICollection<Activity>> FindDepartmentActivityByMonthRange(int departmentId, MonthRange monthRange)
|
|
{
|
|
return await _context.Activities
|
|
.Include(activity => activity.Detail)
|
|
.Include(activity => activity.MetaData)
|
|
.Where(x => x.Accepted.Date >= monthRange.StartTime.Date &&
|
|
x.Accepted.Date <= monthRange.EndTime.Date &&
|
|
x.DepartmentId == departmentId)
|
|
.ToListAsync();
|
|
}
|
|
|
|
public async Task<Activity> GetActivityIncludingPayouts(int activityId)
|
|
{
|
|
return await _context.Activities
|
|
.Include(activity => activity.Detail)
|
|
.Include(activity => activity.MetaData)
|
|
.Include(activity => activity.ActivityPayouts)
|
|
.ThenInclude(payouts => payouts.PayoutLineItem)
|
|
.FirstOrDefaultAsync(x => x.Id == activityId);
|
|
}
|
|
|
|
public async Task<List<Activity>> GetActivitiesBySourceId(List<string> sourceIds)
|
|
{
|
|
return await _context.Activities.Where(x => sourceIds.Contains(x.SourceId)).ToListAsync();
|
|
}
|
|
|
|
public async Task<Activity> FindDuplicateReferralBySourceIdAsync(Activity queryActivity)
|
|
{
|
|
if (queryActivity.Detail == null || queryActivity.Type != ActivityType.Referral)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var activities = _context.Activities
|
|
.Include(activity => activity.Detail)
|
|
.Include(activity => activity.MetaData);
|
|
|
|
IQueryable<Activity> querySet = activities
|
|
.Where(x => x.Id != queryActivity.Id
|
|
&& x.Type == queryActivity.Type
|
|
&& x.Product == queryActivity.Product
|
|
&& x.SourceId == queryActivity.SourceId)
|
|
.OrderByDescending(t => t.LastUpdated);
|
|
|
|
return await querySet.FirstOrDefaultAsync();
|
|
}
|
|
|
|
public async Task<List<Activity>> FindById(
|
|
List<int> ids,
|
|
bool withDetail = true,
|
|
bool withTracking = true
|
|
)
|
|
{
|
|
if (!ids.Any())
|
|
{
|
|
return new List<Activity>();
|
|
}
|
|
|
|
var query = withTracking
|
|
? _context.Activities
|
|
: _context.Activities.AsNoTracking();
|
|
|
|
if (withDetail)
|
|
{
|
|
query = query.Include(activity => activity.Detail);
|
|
}
|
|
|
|
query = query.Where(activity => ids.Contains(activity.Id));
|
|
|
|
return await query.ToListAsync();
|
|
}
|
|
|
|
public async Task<List<Activity>> FindLatestBySourceId(
|
|
List<string> sourceIds,
|
|
bool withDetail = true,
|
|
bool withTracking = true
|
|
)
|
|
{
|
|
if (!sourceIds.Any())
|
|
{
|
|
return new List<Activity>();
|
|
}
|
|
|
|
var query = withTracking
|
|
? _context.Activities
|
|
: _context.Activities.AsNoTracking();
|
|
|
|
if (withDetail)
|
|
{
|
|
query = query.Include(activity => activity.Detail);
|
|
}
|
|
|
|
return (await query
|
|
.Where(activity => sourceIds.Contains(activity.SourceId))
|
|
.GroupBy(activity => activity.SourceId)
|
|
.Select(group => group.OrderBy(activity => activity.Created).FirstOrDefault())
|
|
.ToListAsync())
|
|
.Where(activity => activity != null)
|
|
.ToList();
|
|
}
|
|
|
|
public async Task<List<Activity>> FindGapInsuranceEligible(
|
|
MonthRange monthRange,
|
|
bool withTracking = true
|
|
)
|
|
{
|
|
var query = withTracking
|
|
? _context.Activities
|
|
: _context.Activities.AsNoTracking();
|
|
|
|
return await query
|
|
.Include(activity => activity.Detail)
|
|
.Where(activity =>
|
|
activity.Detail != null &&
|
|
activity.Detail.IsGapInsuranceEligible &&
|
|
activity.Accepted.Date >= monthRange.StartTime.Date &&
|
|
activity.Accepted.Date <= monthRange.EndTime.Date)
|
|
.ToListAsync();
|
|
}
|
|
|
|
public async Task<List<Activity>> GetFilteredActivities(
|
|
MonthRange monthRange,
|
|
Product product,
|
|
ActivityState activityState,
|
|
bool withTracking = true
|
|
)
|
|
{
|
|
var querySet = withTracking
|
|
? _context.Activities
|
|
: _context.Activities.AsNoTracking();
|
|
|
|
return await querySet
|
|
.Include(activity => activity.Detail)
|
|
.Where(
|
|
activity =>
|
|
activity.Accepted.Date >= monthRange.StartTime.Date &&
|
|
activity.Accepted.Date <= monthRange.EndTime.Date &&
|
|
activity.Product == product &&
|
|
activity.State == activityState
|
|
)
|
|
.ToListAsync();
|
|
}
|
|
}
|