This is what I've tried and it seems like I'm on the right path but I've been trying to tweak this algorithm for a while and I can't figure out what I'm doing wrong. Here is my code so far:
const getThem = async () => {
const format2 = 'YYYY/MM/DD';
const obj = {};
for (let i = 0; i < data.length; i++) {
for (let j = 0; j < data[i].tests.length; j++) {
for (let z = 0; z < channel.length; z++) {
if (data[i].tests[j] === channel[z].id) {
const dateTime = moment(channel[z].start).format(format2);
const dateTime2 = moment(channel[z].end).format(format2);
const dateList = getDateArray(new Date(dateTime), new Date(dateTime2));
if (Date.parse(dateTime) > Date.parse('2019-11-15') || Date.parse(dateTime) < Date.parse('2019-11-04')) {
break;
}
if (!channel[z].end) {
// eslint-disable-next-line operator-assignment
obj[dateTime] += (1 / data.length);
} else {
for (let k = 0; k < dateList.length; k++) {
if (!obj.hasOwnProperty(dateList[k])) {
obj[dateList[k]] = 1 / data.length;
} else {
obj[dateList[k]] += (1 / data.length);
}
}
}
}
}
}
}
setDates(Array.sort(Object.keys(obj)));
setValues(Object.values(obj));
};
Check my answer. The approach is simple. First we loop through all the testsResponse data and get the minimum and maximum dates then we iterate through each day from min to max date. For each current day we check the test ids in testsResponse data and then we filter the channels data from the tests array in channelsResponse data and then finally we take the % by the filtered channels data and total channels response data and push it in the results array. The only catch here is that it will push all the dates between minimum test.start and maximum test.end dates both inclusive. If you want to exclude the dates for which testIds is empty then just before the results.push() check if testIds.length is not 0. Here is the getThem():
// given channelsResponse & testsResponse
const getThem = () => {
// get min and max dates
let max='';
let min=new Date().toISOString();
testsResponse.forEach(test => {
min=test.start && min.localeCompare(test.start)>0?test.start:min;
max=test.end && max.localeCompare(test.end)<0?test.end:max;
});
min=new Date(min.substr(0,10)+'T00:00:00.000Z');
max=new Date(max.substr(0,10)+'T00:00:00.000Z');
let results = [];
// loop from min date to max date
for(var i=min; i<=max; i.setDate(i.getDate()+1)) {
let p=0;
let d=i.toISOString().substr(0,10);
// get test ids within the current date
const testIds = testsResponse.filter(t => d.localeCompare((t.start+'').substr(0,10))>=0 && d.localeCompare((t.end+'').substr(0,10))<=0).map(t => t.id);
// get channels where above test ids were found
const channels = channelsResponse.filter(c => c.tests.some(t => testIds.includes(t)));
// calculate %
p=Math.round(channels.length*100.0/channelsResponse.length);
// push data for current date to results
results.push({date: i.toISOString(), utilizationPercentage: p})
}
return results;
};
console.log(getThem());
// [{"date":"2019-11-04T00:00:00.000Z","utilizationPercentage":14},{"date":"2019-11-05T00:00:00.000Z","utilizationPercentage":86},{"date":"2019-11-06T00:00:00.000Z","utilizationPercentage":71},{"date":"2019-11-07T00:00:00.000Z","utilizationPercentage":43},{"date":"2019-11-08T00:00:00.000Z","utilizationPercentage":57},{"date":"2019-11-09T00:00:00.000Z","utilizationPercentage":29},{"date":"2019-11-10T00:00:00.000Z","utilizationPercentage":29},{"date":"2019-11-11T00:00:00.000Z","utilizationPercentage":57},{"date":"2019-11-12T00:00:00.000Z","utilizationPercentage":57},{"date":"2019-11-13T00:00:00.000Z","utilizationPercentage":57},{"date":"2019-11-14T00:00:00.000Z","utilizationPercentage":43},{"date":"2019-11-15T00:00:00.000Z","utilizationPercentage":43}]
Check the demo code here: https://ideone.com/L2rbVe
To avoid iteration over your inputs several times, getting a bad time complexity, I would suggest using Maps and Sets, so you can find related information efficiently.
I kept your function getDateArray. As you didn't provide its source, I reproduced it. But you may want to use your own:
const channelsResponse = [{id: 372,name: 'Channel 01',lab: 'Fullerton',tests: [3, 4, 7, 8],},{id: 373,name: 'Channel 02',lab: 'Fullerton',tests: [1, 2, 5, 6],},{id: 374,name: 'Beta Channel',lab: 'Fullerton',tests: [],},{id: 472,name: 'Channel 01',lab: 'Queens',tests: [9, 11, 12, 13],},{id: 473,name: 'Channel 02',lab: 'Queens',tests: [15, 17, 19],},{id: 474,name: 'Channel 03',lab: 'Queens',tests: [21, 22, 24, 25],},{id: 475,name: 'Channel 04',lab: 'Queens',tests: [26, 27, 28, 29, 30],},];
const testsResponse = [{id: 1,start: '2019-11-05T11:05:00Z',end: '2019-11-05T13:05:00Z',},{id: 2,start: '2019-11-06T11:05:00Z',end: '2019-11-06T13:05:00Z',},{id: 3,start: '2019-11-04T11:05:00Z',end: '2019-11-04T13:09:00Z',},{id: 4,start: '2019-11-04T17:00:00Z',end: '2019-11-05T09:32:00Z',},{id: 5,start: '2019-11-11T11:05:00Z',end: '2019-11-12T13:05:00Z',},{id: 6,start: '2019-11-12T14:05:00Z',end: '2019-11-15T13:05:00Z',},{id: 7,start: '2019-11-07T11:05:00Z',end: '2019-11-08T13:05:00Z',},{id: 8,start: '2019-11-08T15:05:00Z',end: '2019-11-08T15:35:00Z',},{id: 9,start: '2019-11-05T09:05:00Z',end: '2019-11-08T12:05:00Z',},{id: 11,start: '2019-11-08T12:35:00Z',end: '2019-11-08T13:35:00Z',},{id: 12,start: '2019-11-08T17:00:00Z',end: '2019-11-11T10:00:00Z',},{id: 13,start: '2019-11-11T12:00:00Z',end: null,},{id: 15},{id: 17,start: '2019-11-05T17:00:00Z',end: '2019-11-06T10:00:00Z',},{id: 19,start: '2019-11-06T12:00:00Z',end: '2019-11-06T13:22:00Z',},{id: 21,start: '2019-11-05T09:05:00Z',end: '2019-11-06T12:05:00Z',},{id: 22,start: '2019-11-08T12:35:00Z',end: '2019-11-08T13:35:00Z',},{id: 24,start: '2019-11-11T17:00:00Z',end: '2019-11-15T10:00:00Z',},{id: 25,start: '2019-11-15T12:00:00Z',},{id: 26,start: '2019-11-05T09:05:00Z',end: '2019-11-06T12:05:00Z',},{id: 27,start: '2019-11-07T12:35:00Z',end: '2019-11-07T13:35:00Z',},{id: 28,start: '2019-11-08T17:00:00Z',end: '2019-11-11T10:00:00Z',},{id: 29,start: '2019-11-12T12:00:00Z',end: '2019-11-12T14:00:00Z',},{id: 30,start: '2019-11-13T12:00:00Z',end: '2019-11-13T14:00:00Z',},];
function getDateArray(start, end) {
if (!start || !end) return [];
let date = new Date(start.slice(0,11) + "00:00:00Z");
let last = Date.parse(end.slice(0,11) + "00:00:00Z");
let dates = [date.toJSON()];
while (+date != last) {
date.setDate(date.getDate()+1);
dates.push(date.toJSON());
}
return dates; // array of date-strings
}
// Create two maps for faster retrieval
let mapTestToDates = new Map(testsResponse.map(( { id, start, end }) => [id, getDateArray(start, end)]));
let allDates = [...new Set([...mapTestToDates.values()].flat())].sort();
let mapDateToChannels = new Map(allDates.map(date => [date, new Set]));
// Main data collection loop
for (let channel of channelsResponse) {
for (let test of channel.tests) {
for (let date of mapTestToDates.get(test)) {
mapDateToChannels.get(date).add(channel);
}
}
}
// Finally calculate the percentages
let result = Array.from(mapDateToChannels.entries(), ([date, channels]) =>
({ date, utilizationPercentage: Math.round(channels.size * 100 / channelsResponse.length) })
);
console.log(result);
Related
I am a Javascript beginner, I have a personal project to use program to find all the possible & no repeat combinations form specific arrays
I suppose have 3 sets of products and 10 style in each set, like this array
[1,2,3,4..10,1,2,4...8,9,10]
①②③④⑤⑥⑦⑧⑨⑩
①②③④⑤⑥⑦⑧⑨⑩
①②③④⑤⑥⑦⑧⑨⑩
totaly array length = 30
I plan to randomly separate it into 5 children, but they can't repeat the same products style
OK result:
①②③④⑤⑥ ✔
②③④⑤⑥⑦ ✔
①②③⑧⑨⑩ ✔
④⑥⑦⑧⑨⑩ ✔
①⑤⑦⑧⑨⑩ ✔
Everyone can evenly assign products that are not duplicated
NG:
①②③④⑤⑥ ✔
①②③④⑤⑦ ✔
①②⑥⑧⑨⑩ ✔
③④⑤⑦⑧⑨ ✔
⑥⑦⑧⑨⑩⑩ ✘ (because number 10 repeated)
My solution is randomly to assign 5 sets of arrays, then use "new Set(myArray[i]).size;" check the value sum is 30 or not, Use [do..white], while sum is not 30 then repeat to do the random assign function until the result is not duplicated.
like this:
function splitArray() {
do {
var productArray = [1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10]; //Just for sample, actualy this array will be more then 30
var productPerChildArray = [];
for (var i = 0; i < 5; i++) {
GroupNum = [];
for (var v = 0; v < 6; v++) {
var selectNum = productArray[Math.floor(Math.random() * productArray.length)];
GroupNum.push(selectNum);
productArray = removeItemOnce(productArray, selectNum);
}
productPerChildArray.push(GroupNum);
}
} while (checkIfArrayIsUnique(productPerChildArray));
return productPerChildArray;
}
//---------check repeat or not----------
function checkIfArrayIsUnique(myArray) {
var countRight = 0;
for (var i = 0; i < myArray.length; i++) {
countRight += new Set(myArray[i]).size;
}
return (countRight != 5*6);
}
//----------update productArray status----------
function removeItemOnce(arr, value) {
var index = arr.indexOf(value);
if (index > -1) {
arr.splice(index, 1);
}
return arr;
}
console.log(splitArray());
Seems to solve the problem, but actualy productArray is not must 30, this solution will spend to much time to try the no repeat combination. Low efficiency
I believe they have a other solution to solve the problem better than my idea
Any help would be greatly appreciated.
My approach would be: just place the next number in an array that is selected randomly - of course, filter out those that already contain the next number.
// the beginning dataset
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// the size of the groups to be formed (must divide the
// size of beginning dataset without a remainder)
const ARR_LENGTH = 6
// creating the array that will be filled randomly
const getBaseArray = ({ data, arrLength }) => {
const num = parseInt(data.length / arrLength, 10)
return Array.from(Array(num), () => [])
}
// filter arrays that satisfy conditions
const conditions = ({ subArr, val }) => {
if (subArr.includes(val)) return false
if (ARR_LENGTH <= subArr.length) return false
return true
}
const getArraysFiltered = ({ val, arr }) => {
return arr
.map((e, i) => ({
origIdx: i,
subArr: e,
}))
.filter(({ subArr }) => conditions({ subArr, val }))
}
// select a random array from a list of arrays
const getRandomArrIdx = ({ arr }) => {
return Math.floor(Math.random() * arr.length)
}
// get the original array index from the filtered values
const getArrIdx = ({ val, arr }) => {
const filtered = getArraysFiltered({ val, arr })
if (!filtered.length) return -1
const randomArrIdx = getRandomArrIdx({ arr: filtered })
return filtered[randomArrIdx].origIdx
}
const getFinalArr = ({ data }) => {
// short circuit: if the data cannot be placed in
// arrays evenly, then it's a mistake (based on
// the current ruleset)
if (data.length % ARR_LENGTH) return [false]
// creating the array that will hold the numbers
const arr = getBaseArray({ data, arrLength: ARR_LENGTH })
let i = 0;
for (i; i < data.length; i++) {
const idx = getArrIdx({
val: data[i],
arr,
})
// if there's no place that the next number could be
// placed, then break (prematurely), so the algorithm
// can be restarted as early as possible
if (idx === -1) break;
arr[idx].push(data[i])
}
if (i < data.length) {
// restart algorithm if we couldn't place
// all the numbers in the dataset
return getFinalArr({ data })
} else {
return arr
}
}
// constructing the final array of arrays & logging them:
console.log('res', getFinalArr({ data }).join(' '))
console.log('res', getFinalArr({ data }).join(' '))
console.log('res', getFinalArr({ data }).join(' '))
console.log('res', getFinalArr({ data }).join(' '))
I don't know if it's more efficient, but I found this question interesting.
Now, the algorithm is
broken down into small logical steps that are
easy to follow
simple to tweak to needs
works with all sizes of data (if the groups to be made can be filled equally)
Hopefully this is not too specific of a question, but I'm hoping to get insight into how to work with nested Objects and Arrays without making a program that runs O(n)^2 or O(n)^3.
Below is a program I built to find the cheapest flight(s) from point A to point B, and if the flight is the same price, the one with the least amount of flights. You will see where I label the parts that are not efficient. How can I make these more efficient?
//returns an object with an array of IDs that will get you to a destination at the lowest cost. if same cost, then the least amount of flights flights
function leastExpensiveFlight(flightInfo, start, end) {
var numOfTimes = 1
var combinedValues = []
var minValue
var indexOfMinValue;
var numOfFlights = []
var minNumberOfFlights;
var startTimes = flightInfo.reduce((startTimes, f, index) => {
if (f[0] == start) {
startTimes[numOfTimes] = [f];
numOfTimes++
}
return startTimes
}, {})
//below is O(n)^2
//Gets the Flights where Location 1 = start
for (i = 0; i < Object.keys(startTimes).length; i++) {
for (j = 0; j < startTimes[Object.keys(startTimes)[i]].length; j++) {
flightInfo.forEach((f, ) => {
if (startTimes[Object.keys(startTimes)[i]][j] &&
f[0] === startTimes[Object.keys(startTimes)[i]][j][1] &&
startTimes[Object.keys(startTimes)[i]][j][1] <= end &&
f[1] <= end) {
if (!startTimes[Object.keys(startTimes)[i]].includes(f)) {
startTimes[Object.keys(startTimes)[i]].push(f)
}
}
})
}
}
//below is O(n)^3!!
//Finds trips that will get to the destination
Object.keys(startTimes).forEach((flights) => {
startTimes[flights].forEach((subFlights1, sFIndex1) => {
startTimes[flights].forEach((subFlights2, sFIndex2) => {
if (subFlights1[0] === subFlights2[0] &&
subFlights1[1] === subFlights2[1] &&
sFIndex1 != sFIndex2) {
if (subFlights1[2] >= subFlights2[2]) {
startTimes[flights].splice(sFIndex1, 1)
} else {
startTimes[flights].splice(sFIndex2, 1)
}
}
})
})
})
//below is O(n)^2
//Finds the trip with the minimum value and, if same price, least amount of flights
Object.keys(startTimes).forEach((flights, sTIndex) => {
startTimes[flights].forEach((subFlights, sFIndex) => {
if (sFIndex == 0) {
combinedValues[sTIndex] = subFlights[2]
numOfFlights.push(1)
} else {
combinedValues[sTIndex] += subFlights[2]
numOfFlights[sTIndex] += 1
}
if (sFIndex === startTimes[flights].length - 1 &&
((combinedValues[sTIndex] <= minValue) ||
!minValue)) {
if ((!minNumberOfFlights ||
minNumberOfFlights > numOfFlights[sTIndex])) {
minNumberOfFlights = numOfFlights[sTIndex]
}
if (combinedValues[sTIndex] === minValue &&
numOfFlights[sTIndex] === minNumberOfFlights ||
(combinedValues[sTIndex] < minValue &&
numOfFlights[sTIndex] >= minNumberOfFlights) ||
!minValue) {
minValue = combinedValues[sTIndex];
indexOfMinValue = sTIndex
}
}
})
})
return startTimes[Object.keys(startTimes)[indexOfMinValue]]
} //Big O is O(n)^3
//2D Array: data[0][0] = Location start,
// data[0][1] = Location end,
// data[0][2] = Price,
//
var data = [
[4, 5, 400],
[1, 2, 500],
[2, 3, 300],
[1, 3, 900],
[2, 3, 100],
[3, 4, 400]
]
//so from location 1 - location 3, the cheapest route would be: [1,2,500],[2,3,100]
console.log(JSON.stringify(leastExpensiveFlight(data, 1, 3)));
Your help is much appreciated. I am trying to get better at coding so I can go into my engineering department, but as you can see, I have a long way to go.
[EDIT]- Sorry, had an erroneous statement in there that I just fixed.
I'd approach this by first constructing a graph for each possible path between the start and end nodes. Make a function that, given a start node and a list of nodes already visited, can look through the data to find each path leading out of this node. For each path which has not been visited yet, if the path ends at the destination, push the whole result of the paths traveled to a finishedPaths array. Otherwise, recursively call the function so that it does the same process again, starting at the end node.
To reduce complexity, to identify whether a node has or hasn't been visited yet, use an object or Set (which have lookups in O(1) time, unlike Array.prototype.includes, which runs in O(n) time).
At the end, look through all the possible paths between the start and end, identify the ones with the lowest cost, and among those, find the one with the least number of paths.
function leastExpensiveFlight(data, start, end) {
const pathsByStartLoc = {};
for (const path of data) {
const start = path[0];
if (!pathsByStartLoc[start]) pathsByStartLoc[start] = [];
pathsByStartLoc[start].push(path);
}
const getAllPaths = (
start,
costSoFar = 0,
pathsSoFar = [],
finishedPaths = [],
visitedNodes = {}
) => {
if (!pathsByStartLoc[start]) return;
for (const path of pathsByStartLoc[start]) {
if (visitedNodes.hasOwnProperty(path[2])) continue;
if (path[1] === end) {
finishedPaths.push({ totalCost: costSoFar + path[2], paths: [...pathsSoFar, path] });
}
getAllPaths(
path[1],
costSoFar + path[2],
[...pathsSoFar, path],
finishedPaths, { ...visitedNodes, [path[0]]: true }
);
}
return finishedPaths;
};
const allPaths = getAllPaths(start);
const lowestCost = Math.min(...allPaths.map(({ totalCost }) => totalCost));
const lowestCostPaths = allPaths.filter(({ totalCost }) => totalCost === lowestCost);
return lowestCostPaths.reduce((a, item) => a.paths.length < item.paths.length ? a : item);
}
var data = [
[4, 5, 400],
[1, 2, 500],
[2, 3, 300],
[1, 3, 900],
[2, 3, 100],
[3, 4, 400]
]
//so from location 1 - location 3, the cheapest route would be: [1,2,500],[2,3,300]
console.log(leastExpensiveFlight(data, 1, 3));
I need to create an array, and it's elements just depending on the index. To make sense about my current problem, I want to return the dates of a selected day's week.
// With for
const getWeekDatesFor = day => {
const dayIndex = moment(day).format('E') - 1;
const dates = [];
for(let i = 0; i < 7; i++){
if(i < dayIndex){
const lessWith = dayIndex - i;
dates[i] = moment(day).subtract(lessWith, "d").format('YYYY-M-D')
} else {
const moreWith = i - dayIndex;
dates[i] = moment(day).add(moreWith, "d").format('YYYY-M-D')
}
}
return dates
}
// How I wanted to simplify (but returns empty array with 7 elements)
const getWeekDatesNew = day => {
const dayIndex = moment(day).format('E') - 1;
return Array(7).map((e, i) => {
if(i < dayIndex){
const lessWith = dayIndex - i;
return moment(day).subtract(lessWith, "d").format('YYYY-M-D')
} else {
const moreWith = i - dayIndex;
return moment(day).add(moreWith, "d").format('YYYY-M-D')
}
})
}
For loops are good, but I'm sure that with ES6 we have a simpler way to perform these actions: create an array where items depending on it's index. All I want to know what is the ES6 method of doing this.
Simplest way is to use combination of array.from and new array like so:
Array.from(new Array(5), (und, ind) => ind) // This returns [0,1,2,3,4]
und is undefined since the array is initiated with undefined values and needs to be filled.
So you can extend this with more complex evaluating :
Array.from(new Array(5), (und, ind) => {return some_data_based_on_ind})
There is also Array.fill method for simple fills:
Array(6).fill('somedata')
Just push into your data variable. I have used something similar using date-fns instead of moment
const daysOfWeek = () => {
const days = []
let startDate = dateFns.startOfWeek(new Date())
for (let i = 0; i < 7; i++) {
days.push(
<span key={i}>
{ dateFns.format(dateFns.addDays(startDate, i), 'dddd') }
</span>
)
}
return days
}
How can i do this in Ruby
var pCodePrice = {
'GR1': 3.11,
'SR1': 5,
'CF1': 11.23
};
var basket = ['GR1', 'SR1', 'GR1', 'GR1', 'CF1'];
var total = [];
for (i = 0, x = basket.length; i < x; i++) {
for (var prop in pCodePrice) {
if (basket[i] == prop) {
total.push(pCodePrice[prop])
}
}
}
This loops through the array and checks to see if the item matches the key of the hash in the inner loop, if so it pushes the value into a new array.
I just cant get it in Ruby,
Thanks
It's pretty simple in ruby using map.
pCodePrice = { 'GR1' => 3.11, 'SR1' => 5, 'CF1' => 11.23 }
=> {"GR1"=>3.11, "SR1"=>5, "CF1"=>11.23}
basket = ['GR1','SR1','GR1','GR1','CF1']
=> ["GR1", "SR1", "GR1", "GR1", "CF1"]
total = basket.map { |code| pCodePrice[code] }
=> [3.11, 5, 3.11, 3.11, 11.23]
I have an array of Date() objects in javascript and I want to count the number of events on each day.
Here is an example:
What I have is:
Array [ Date 2014-12-04T10:30:20.000Z, Date 2014-12-05T11:04:58.056Z, Date 2014-12-05T11:04:58.056Z, Date 2014-12-05T11:04:58.056Z ]
What I want is:
Array [{date: '2014-12-04', counts: 1}, {date: '2014-12-05', counts: 3}]
Thanks a lot!
Max
Basic answer:
var arr = [], // fill it with array with your data
results = {}, rarr = [], i, date;
for (i=0; i<arr.length; i++) {
// get the date
date = [arr[i].getFullYear(),arr[i].getMonth(),arr[i].getDate()].join("-");
results[date] = results[date] || 0;
results[date]++;
}
// you can always convert it into an array of objects, if you must
for (i in results) {
if (results.hasOwnProperty(i)) {
rarr.push({date:i,counts:results[i]});
}
}
These can be made much easier with lodash functions, and Array.forEach() in ES5
You much better off having a simple object with the keys as the date and the value as the count. I've added a simple pad function that prefixes a zero where the number is a single digit as per your output requirements.
function pad(n) {
return n.toString().length == 1 ? '0' + n : n;
}
function getCount(arr) {
var obj = {};
for (var i = 0, l = arr.length; i < l; i++) {
var thisDate = arr[i];
var day = pad(thisDate.getDate());
var month = pad(thisDate.getMonth() + 1);
var year = thisDate.getFullYear();
var key = [year, day, month].join('-');
obj[key] = obj[key] || 0;
obj[key]++;
}
return obj;
}
getCount(arr); // Object { 2014-04-12: 1, 2014-05-12: 3 }
DEMO
I came across the same issue and found this solution which uses Map()
`
calc = (obj) => {
const orders = []
const dates_map = new Map()
//iterate through all the objects inside the orders array
orders.forEach(order => {
// format and get the date
const date = new Date(order.created_at).toLocaleDateString('en-GB')
//check if the date key exists in the Map() and save it in a temp
const temp = dates_map.get(date) || false
// if it does not exist
if (temp) {
// clone the object
const previous = {...temp}
// increase counter
previous.count += 1
dates_map.set(date, previous)
}else{
//create new object to avoid overwriting
const result = {}
result.count = 1
dates_map.set(date, result)
}
})
console.log(dates_map)
}
And this is the output
Output: Map(3) {
'08/05/2021' => { count: 2 },
'09/05/2021' => { count: 1 },
'11/05/2021' => { count: 2,}
}
`