Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 30127ba

Browse files
committedNov 2, 2024
feat: Add hello.js file and handler function
This commit adds a new file hello.js to the project, which contains a handler function that responds with a hello message and some event data. The function also parses the event data if it is a string. This change is necessary to handle incoming requests and provide a response.
1 parent cde6f6e commit 30127ba

File tree

7 files changed

+389
-25
lines changed

7 files changed

+389
-25
lines changed
 

‎.aws-sam/build.toml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# This file is auto generated by SAM CLI build command
2+
3+
[function_build_definitions.aa580c42-cdac-49be-a475-38fccb6c338e]
4+
codeuri = "/Users/umutc/code/magistum/aws-lambda-layer-php73/src"
5+
runtime = "provided.al2"
6+
architecture = "x86_64"
7+
handler = "index.handler"
8+
manifest_hash = ""
9+
packagetype = "Zip"
10+
functions = ["HelloPhp82"]
11+
12+
[function_build_definitions.aa580c42-cdac-49be-a475-38fccb6c338e.metadata]
13+
BuildMethod = "makefile"
14+
15+
[layer_build_definitions]

‎deploy.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
#!/bin/bash
22

3-
sam package --template-file template.yaml --output-template-file serverless-output.yaml --s3-bucket magistum-sam
4-
sam deploy --template-file serverless-output.yaml --stack-name magistum-serverless-php73 --capabilities CAPABILITY_IAM
3+
sam package --template-file template.yaml --output-template-file serverless-output.yaml --s3-bucket kalko-sam --profile kalko
4+
sam deploy --template-file serverless-output.yaml --stack-name kalko-serverless-nodejs --capabilities CAPABILITY_IAM --profile kalko

‎package.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "magistum-serverless",
3+
"version": "1.0.0",
4+
"description": "Magistum Serverless Node.js Functions",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "jest",
8+
"deploy": "sam deploy"
9+
},
10+
"dependencies": {},
11+
"devDependencies": {
12+
"jest": "^29.0.0"
13+
}
14+
}

‎src/array.js

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
const ArrayStats = require('./lib/ArrayStats');
2+
3+
exports.stats = async (event) => {
4+
const data = typeof event === 'string' ? JSON.parse(event) : event;
5+
const response = [];
6+
7+
try {
8+
for (const point of data.points) {
9+
const arrayStats = new ArrayStats(point.results);
10+
const stats = {
11+
_min: data.min,
12+
_max: data.max,
13+
mean: arrayStats.mean(),
14+
median: arrayStats.median(),
15+
mode: arrayStats.mode(),
16+
range: arrayStats.range(),
17+
standard_deviation: arrayStats.standardDeviation(),
18+
frequency: arrayStats.frequency(),
19+
min: arrayStats.min(),
20+
max: arrayStats.max(),
21+
maxGraphDataValue: 0,
22+
graphData: arrayStats.graphData(data.min, data.max)
23+
};
24+
25+
let maxGraphDataValue = Math.max(...stats.graphData.map(item => item.value));
26+
stats.maxGraphDataValue = maxGraphDataValue;
27+
28+
let x = null;
29+
if (maxGraphDataValue <= 0.0001) x = 10000;
30+
else if (maxGraphDataValue <= 0.001) x = 1000;
31+
else if (maxGraphDataValue <= 0.01) x = 100;
32+
else if (maxGraphDataValue <= 0.1) x = 10;
33+
34+
if (x) {
35+
stats.graphData = stats.graphData.map(item => ({
36+
...item,
37+
value: item.value * x
38+
}));
39+
}
40+
41+
delete point.results;
42+
point.stats = stats;
43+
}
44+
45+
response.push(...data.points);
46+
} catch (e) {
47+
console.error(e);
48+
}
49+
50+
return response;
51+
};
52+
53+
exports.info = async () => {
54+
return {
55+
NODE_VERSION: process.version,
56+
__dirname: __dirname
57+
};
58+
};
59+
60+
exports.itemAnalysis = async (event) => {
61+
const data = typeof event === 'string' ? JSON.parse(event) : event;
62+
63+
// Create matrix
64+
const matrix = {};
65+
data.esssr.forEach(id => {
66+
matrix[id] = {};
67+
data.question_ids.forEach(qId => {
68+
matrix[id][qId] = 0;
69+
});
70+
});
71+
72+
// Fill matrix
73+
data.esssrq.forEach(item => {
74+
matrix[item.esss_id_row_index][item.question_id] = 1;
75+
});
76+
77+
// Convert to array and sort by sum descending
78+
const matrixArray = Object.entries(matrix).map(([key, value]) => ({
79+
id: key,
80+
values: value,
81+
sum: Object.values(value).reduce((a, b) => a + b, 0)
82+
})).sort((a, b) => b.sum - a.sum);
83+
84+
// Get top and bottom 27%
85+
const count = Math.floor(matrixArray.length * 0.27);
86+
const top27 = matrixArray.slice(0, count);
87+
const bottom27 = matrixArray.slice(-count);
88+
89+
// Calculate statistics for each question
90+
const items = data.question_ids.map(qId => {
91+
const question = data.questions.find(q => q.id === qId);
92+
const columnTotal = matrixArray.map(row => row.values[qId]);
93+
const columnTop27 = top27.map(row => row.values[qId]);
94+
const columnBottom27 = bottom27.map(row => row.values[qId]);
95+
96+
const totalSum = columnTotal.reduce((a, b) => a + b, 0);
97+
const totalSumPersentage = (totalSum / matrixArray.length) * 100;
98+
const totalSumTop27 = columnTop27.reduce((a, b) => a + b, 0);
99+
const totalSumBottom27 = columnBottom27.reduce((a, b) => a + b, 0);
100+
const countTop27 = top27.length;
101+
const countBottom27 = bottom27.length;
102+
103+
const Pj = (totalSumTop27 + totalSumBottom27) / (countTop27 + countBottom27);
104+
const Sj2 = Pj * (1 - Pj);
105+
const SS = Math.sqrt(Sj2);
106+
const rjx = (totalSumTop27 - totalSumBottom27) / countTop27;
107+
108+
const arrayStats = new ArrayStats(columnTotal);
109+
110+
return {
111+
question_id: qId,
112+
question: question,
113+
data: {
114+
totalSum: {
115+
id: 'totalSum',
116+
title: 'Maddeyi toplam doğru cevaplayan öğrenci sayısı',
117+
value: totalSum
118+
},
119+
totalSumPersentage: {
120+
id: 'totalSumPersentage',
121+
title: 'Madde başarı yüzdesi',
122+
value: totalSumPersentage
123+
},
124+
totalSumTop27: {
125+
id: 'totalSumTop27',
126+
title: 'Maddeyi üst grupta doğru cevaplayan öğrenci sayısı',
127+
value: totalSumTop27
128+
},
129+
totalSumBottom27: {
130+
id: 'totalSumBottom27',
131+
title: 'Maddeyi alt grupta doğru cevaplayan öğrenci sayısı',
132+
value: totalSumBottom27
133+
},
134+
Pj: {
135+
id: 'Pj',
136+
title: 'Madde güçlük indeksi',
137+
value: Pj
138+
},
139+
Sj2: {
140+
id: 'Sj2',
141+
title: 'Madde varyansı',
142+
value: Sj2
143+
},
144+
rjx: {
145+
id: 'rjx',
146+
title: 'Madde ayırıcılık gücü',
147+
value: rjx
148+
},
149+
SS: {
150+
id: 'SS',
151+
title: 'Standart sapma',
152+
value: SS
153+
},
154+
ri: {
155+
id: 'ri',
156+
title: 'Madde güvenirlik indeksi',
157+
value: rjx * SS
158+
},
159+
stats: {
160+
_min: 0,
161+
_max: 1,
162+
mean: arrayStats.mean(),
163+
median: arrayStats.median(),
164+
mode: arrayStats.mode(),
165+
range: arrayStats.range(),
166+
variance: arrayStats.variance(),
167+
standard_deviation: arrayStats.standardDeviation(),
168+
frequency: arrayStats.frequency(),
169+
min: arrayStats.min(),
170+
max: arrayStats.max(),
171+
maxGraphDataValue: 1,
172+
graphData: arrayStats.graphData(0, 1)
173+
}
174+
}
175+
};
176+
});
177+
178+
// Calculate graph data categories
179+
const graphData = [
180+
{
181+
id: 1,
182+
name: '[Pj>0.90]',
183+
value: 0,
184+
desc: 'Eğer etkili bir öğretim varsa tercih edilir'
185+
},
186+
{
187+
id: 2,
188+
name: '[Pj>=0.60][rjx>=0.20]',
189+
value: 0,
190+
desc: 'Tipik iyi bir madde'
191+
},
192+
{
193+
id: 3,
194+
name: '[Pj>=0.60][rjx<0.20]',
195+
value: 0,
196+
desc: 'Üzerinde çalışılması gereken madde'
197+
},
198+
{
199+
id: 4,
200+
name: '[Pj<0.60][rjx>=0.20]',
201+
value: 0,
202+
desc: 'Zor fakat ayırt edici bir madde (Eğer yüksek standartlara sahipseniz bu soru iyidir)'
203+
},
204+
{
205+
id: 5,
206+
name: '[Pj<0.60][rjx<0.20]',
207+
value: 0,
208+
desc: 'Zor ve ayırt edici olmayan madde (Bu madde kullanılamaz)'
209+
}
210+
];
211+
212+
// Calculate Pj values and update graph data
213+
const Pj = [];
214+
items.forEach(item => {
215+
Pj.push(item.data.Pj.value);
216+
const pjValue = item.data.Pj.value;
217+
const rjxValue = item.data.rjx.value;
218+
219+
if (pjValue > 0.90) {
220+
graphData[0].value++;
221+
} else if (pjValue >= 0.60 && rjxValue >= 0.20) {
222+
graphData[1].value++;
223+
} else if (pjValue >= 0.60 && rjxValue < 0.20) {
224+
graphData[2].value++;
225+
} else if (pjValue < 0.60 && rjxValue >= 0.20) {
226+
graphData[3].value++;
227+
} else if (pjValue < 0.60 && rjxValue < 0.20) {
228+
graphData[4].value++;
229+
}
230+
});
231+
232+
return {
233+
PjAvg: Pj.reduce((a, b) => a + b, 0) / Pj.length,
234+
studentCount: data.esssr.length,
235+
questionCount: data.question_ids.length,
236+
graphData: graphData,
237+
items: items
238+
};
239+
};

‎src/hello.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
exports.handler = async (event) => {
2+
const response = {
3+
msg: `hello from Node.js ${process.version}`,
4+
eventData: event,
5+
data: typeof event === 'string' ? JSON.parse(event) : event
6+
};
7+
8+
return response;
9+
};

‎src/lib/ArrayStats.js

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
class ArrayStats {
2+
constructor(array) {
3+
if (!array || array.length === 0) {
4+
throw new Error("Array cannot be empty");
5+
}
6+
this.array = array.map(Number).sort((a, b) => b - a);
7+
}
8+
9+
mean() {
10+
return this.array.reduce((a, b) => a + b, 0) / this.array.length;
11+
}
12+
13+
median() {
14+
const mid = Math.floor(this.array.length / 2);
15+
return this.array.length % 2 !== 0
16+
? this.array[mid]
17+
: (this.array[mid - 1] + this.array[mid]) / 2;
18+
}
19+
20+
mode() {
21+
const frequency = {};
22+
let maxFreq = 0;
23+
let mode = null;
24+
25+
this.array.forEach(num => {
26+
frequency[num] = (frequency[num] || 0) + 1;
27+
if (frequency[num] > maxFreq) {
28+
maxFreq = frequency[num];
29+
mode = num;
30+
}
31+
});
32+
33+
return mode;
34+
}
35+
36+
range() {
37+
return Math.max(...this.array) - Math.min(...this.array);
38+
}
39+
40+
standardDeviation() {
41+
const mean = this.mean();
42+
const squareDiffs = this.array.map(value => {
43+
const diff = value - mean;
44+
return diff * diff;
45+
});
46+
const avgSquareDiff = squareDiffs.reduce((a, b) => a + b, 0) / this.array.length;
47+
return Math.sqrt(avgSquareDiff);
48+
}
49+
50+
frequency() {
51+
const freq = {};
52+
this.array.forEach(num => {
53+
freq[num] = (freq[num] || 0) + 1;
54+
});
55+
return freq;
56+
}
57+
58+
min() {
59+
return Math.min(...this.array);
60+
}
61+
62+
max() {
63+
return Math.max(...this.array);
64+
}
65+
66+
graphData(min = 0, max = 100) {
67+
const mean = this.mean();
68+
const stdDev = this.standardDeviation();
69+
const data = [];
70+
71+
for (let i = min; i <= max; i++) {
72+
data.push({
73+
name: i.toString(),
74+
value: this.densNormal(i, mean, stdDev)
75+
});
76+
}
77+
78+
return data;
79+
}
80+
81+
densNormal(x, mean, stdDev) {
82+
if (stdDev <= 0) return 0;
83+
const exp = Math.exp(-(Math.pow(x - mean, 2) / (2 * Math.pow(stdDev, 2))));
84+
return (1 / (stdDev * Math.sqrt(2 * Math.PI))) * exp;
85+
}
86+
87+
variance() {
88+
const mean = this.mean();
89+
const squareDiffs = this.array.map(value => {
90+
const diff = value - mean;
91+
return diff * diff;
92+
});
93+
return squareDiffs.reduce((a, b) => a + b, 0) / this.array.length;
94+
}
95+
}
96+
97+
module.exports = ArrayStats;

‎template.yaml

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,54 @@
11
AWSTemplateFormatVersion: 2010-09-09
2-
Description: Magistum Serverless PHP 7.3.1
2+
Description: Magistum Serverless Node.js
33
Transform: AWS::Serverless-2016-10-31
44
Resources:
5-
LayerPhp73:
6-
Properties:
7-
ContentUri: layer/php
8-
Type: AWS::Serverless::LayerVersion
9-
HelloPhp73:
5+
HelloFunction:
106
Type: AWS::Serverless::Function
117
Properties:
128
FunctionName: !Sub ${AWS::StackName}-hello
13-
Description: This is the hello world function from lambda php 7.3.1 layer
9+
Description: This is the hello world function
1410
CodeUri: src
15-
Runtime: provided
16-
Handler: hello.hello
11+
Runtime: nodejs18.x
12+
Handler: hello.handler
1713
MemorySize: 128
1814
Timeout: 4
1915
Tracing: Active
20-
Layers:
21-
- 'arn:aws:lambda:eu-central-1:303814004728:layer:aws-lambda-layer-php-7-3-1:6'
16+
2217
ArrayStats:
2318
Type: AWS::Serverless::Function
2419
Properties:
2520
FunctionName: !Sub ${AWS::StackName}-array-stats
2621
Description: This is the statistics function that calculates payload array.
2722
CodeUri: src
28-
Runtime: provided
23+
Runtime: nodejs18.x
2924
Handler: array.stats
3025
MemorySize: 128
3126
Timeout: 4
3227
Tracing: Active
33-
Layers:
34-
- 'arn:aws:lambda:eu-central-1:303814004728:layer:aws-lambda-layer-php-7-3-1:6'
28+
3529
ItemAnalysis:
3630
Type: AWS::Serverless::Function
3731
Properties:
3832
FunctionName: !Sub ${AWS::StackName}-item-analysis
3933
Description: This is the statistics function that calculates item analysis of payload object.
4034
CodeUri: src
41-
Runtime: provided
42-
Handler: array.item_analysis
35+
Runtime: nodejs18.x
36+
Handler: array.itemAnalysis
4337
MemorySize: 512
4438
Timeout: 16
4539
Tracing: Active
46-
Layers:
47-
- 'arn:aws:lambda:eu-central-1:303814004728:layer:aws-lambda-layer-php-7-3-1:6'
48-
# Layer local test - Ref: LayerPhp73
40+
4941
Info:
5042
Type: AWS::Serverless::Function
5143
Properties:
5244
FunctionName: !Sub ${AWS::StackName}-info
53-
Description: This is the statistics function that calculates payload array.
45+
Description: This is the info function that returns runtime information
5446
CodeUri: src
55-
Runtime: provided
47+
Runtime: nodejs18.x
5648
Handler: array.info
5749
MemorySize: 128
5850
Timeout: 4
5951
Tracing: Active
60-
Layers:
61-
- 'arn:aws:lambda:eu-central-1:303814004728:layer:aws-lambda-layer-php-7-3-1:6'
6252
Policies:
6353
- S3ReadPolicy:
6454
BucketName: magistum-sam

0 commit comments

Comments
 (0)
Please sign in to comment.