calendar-notes-plugin 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/extensions.json +4 -0
- package/.vscode/launch.json +20 -0
- package/.vscode/mcp.json +9 -0
- package/.vscode/tasks.json +42 -0
- package/backend/policies/RLS.sql +1 -0
- package/backend/policies/delete.sql +6 -0
- package/backend/policies/insert.sql +6 -0
- package/backend/policies/select.sql +4 -0
- package/backend/policies/update.sql +8 -0
- package/backend/table.sql +9 -0
- package/calendar-notes-plugin/.editorconfig +17 -0
- package/calendar-notes-plugin/.hintrc +5 -0
- package/calendar-notes-plugin/.vscode/extensions.json +4 -0
- package/calendar-notes-plugin/.vscode/launch.json +20 -0
- package/calendar-notes-plugin/.vscode/mcp.json +9 -0
- package/calendar-notes-plugin/.vscode/tasks.json +42 -0
- package/calendar-notes-plugin/README.md +226 -0
- package/calendar-notes-plugin/angular.json +74 -0
- package/calendar-notes-plugin/package-lock.json +8917 -0
- package/calendar-notes-plugin/package.json +52 -0
- package/calendar-notes-plugin/public/favicon.ico +0 -0
- package/calendar-notes-plugin/public/widget.js +75 -0
- package/calendar-notes-plugin/src/app/app.config.ts +12 -0
- package/calendar-notes-plugin/src/app/app.css +0 -0
- package/calendar-notes-plugin/src/app/app.html +1 -0
- package/calendar-notes-plugin/src/app/app.routes.server.ts +8 -0
- package/calendar-notes-plugin/src/app/app.routes.ts +3 -0
- package/calendar-notes-plugin/src/app/app.spec.ts +23 -0
- package/calendar-notes-plugin/src/app/app.ts +17 -0
- package/calendar-notes-plugin/src/app/components/calender/calendar.css +73 -0
- package/calendar-notes-plugin/src/app/components/calender/calendar.html +26 -0
- package/calendar-notes-plugin/src/app/components/calender/calendar.spec.ts +23 -0
- package/calendar-notes-plugin/src/app/components/calender/calendar.ts +155 -0
- package/calendar-notes-plugin/src/app/components/floating-button/floating-button.css +17 -0
- package/calendar-notes-plugin/src/app/components/floating-button/floating-button.html +3 -0
- package/calendar-notes-plugin/src/app/components/floating-button/floating-button.spec.ts +23 -0
- package/calendar-notes-plugin/src/app/components/floating-button/floating-button.ts +25 -0
- package/calendar-notes-plugin/src/app/components/notes/notes.css +251 -0
- package/calendar-notes-plugin/src/app/components/notes/notes.html +107 -0
- package/calendar-notes-plugin/src/app/components/notes/notes.spec.ts +23 -0
- package/calendar-notes-plugin/src/app/components/notes/notes.ts +328 -0
- package/calendar-notes-plugin/src/app/components/panel/panel.css +28 -0
- package/calendar-notes-plugin/src/app/components/panel/panel.html +16 -0
- package/calendar-notes-plugin/src/app/components/panel/panel.spec.ts +23 -0
- package/calendar-notes-plugin/src/app/components/panel/panel.ts +46 -0
- package/calendar-notes-plugin/src/app/components/widget/widget.css +18 -0
- package/calendar-notes-plugin/src/app/components/widget/widget.html +17 -0
- package/calendar-notes-plugin/src/app/components/widget/widget.spec.ts +23 -0
- package/calendar-notes-plugin/src/app/components/widget/widget.ts +23 -0
- package/calendar-notes-plugin/src/app/services/api.spec.ts +16 -0
- package/calendar-notes-plugin/src/app/services/api.ts +39 -0
- package/calendar-notes-plugin/src/app/services/notification.spec.ts +16 -0
- package/calendar-notes-plugin/src/app/services/notification.ts +116 -0
- package/calendar-notes-plugin/src/backend/database/policies/delete.sql +6 -0
- package/calendar-notes-plugin/src/backend/database/policies/insert.sql +6 -0
- package/calendar-notes-plugin/src/backend/database/policies/select.sql +6 -0
- package/calendar-notes-plugin/src/backend/database/policies/update.sql +6 -0
- package/calendar-notes-plugin/src/backend/database/table.sql +13 -0
- package/calendar-notes-plugin/src/index.html +13 -0
- package/calendar-notes-plugin/src/main.ts +34 -0
- package/calendar-notes-plugin/src/styles.css +1 -0
- package/calendar-notes-plugin/tsconfig.app.json +17 -0
- package/calendar-notes-plugin/tsconfig.json +33 -0
- package/calendar-notes-plugin/tsconfig.spec.json +15 -0
- package/calendar-notes-plugin-1.0.0.tgz +0 -0
- package/package.json +29 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"configurations": [
|
|
5
|
+
{
|
|
6
|
+
"name": "ng serve",
|
|
7
|
+
"type": "chrome",
|
|
8
|
+
"request": "launch",
|
|
9
|
+
"preLaunchTask": "npm: start",
|
|
10
|
+
"url": "http://localhost:4200/"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "ng test",
|
|
14
|
+
"type": "chrome",
|
|
15
|
+
"request": "launch",
|
|
16
|
+
"preLaunchTask": "npm: test",
|
|
17
|
+
"url": "http://localhost:9876/debug.html"
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
package/.vscode/mcp.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"tasks": [
|
|
5
|
+
{
|
|
6
|
+
"type": "npm",
|
|
7
|
+
"script": "start",
|
|
8
|
+
"isBackground": true,
|
|
9
|
+
"problemMatcher": {
|
|
10
|
+
"owner": "typescript",
|
|
11
|
+
"pattern": "$tsc",
|
|
12
|
+
"background": {
|
|
13
|
+
"activeOnStart": true,
|
|
14
|
+
"beginsPattern": {
|
|
15
|
+
"regexp": "Changes detected"
|
|
16
|
+
},
|
|
17
|
+
"endsPattern": {
|
|
18
|
+
"regexp": "bundle generation (complete|failed)"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"type": "npm",
|
|
25
|
+
"script": "test",
|
|
26
|
+
"isBackground": true,
|
|
27
|
+
"problemMatcher": {
|
|
28
|
+
"owner": "typescript",
|
|
29
|
+
"pattern": "$tsc",
|
|
30
|
+
"background": {
|
|
31
|
+
"activeOnStart": true,
|
|
32
|
+
"beginsPattern": {
|
|
33
|
+
"regexp": "Changes detected"
|
|
34
|
+
},
|
|
35
|
+
"endsPattern": {
|
|
36
|
+
"regexp": "bundle generation (complete|failed)"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
alter table notes enable row level security;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Editor configuration, see https://editorconfig.org
|
|
2
|
+
root = true
|
|
3
|
+
|
|
4
|
+
[*]
|
|
5
|
+
charset = utf-8
|
|
6
|
+
indent_style = space
|
|
7
|
+
indent_size = 2
|
|
8
|
+
insert_final_newline = true
|
|
9
|
+
trim_trailing_whitespace = true
|
|
10
|
+
|
|
11
|
+
[*.ts]
|
|
12
|
+
quote_type = single
|
|
13
|
+
ij_typescript_use_double_quotes = false
|
|
14
|
+
|
|
15
|
+
[*.md]
|
|
16
|
+
max_line_length = off
|
|
17
|
+
trim_trailing_whitespace = false
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"configurations": [
|
|
5
|
+
{
|
|
6
|
+
"name": "ng serve",
|
|
7
|
+
"type": "chrome",
|
|
8
|
+
"request": "launch",
|
|
9
|
+
"preLaunchTask": "npm: start",
|
|
10
|
+
"url": "http://localhost:4200/"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "ng test",
|
|
14
|
+
"type": "chrome",
|
|
15
|
+
"request": "launch",
|
|
16
|
+
"preLaunchTask": "npm: test",
|
|
17
|
+
"url": "http://localhost:9876/debug.html"
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"tasks": [
|
|
5
|
+
{
|
|
6
|
+
"type": "npm",
|
|
7
|
+
"script": "start",
|
|
8
|
+
"isBackground": true,
|
|
9
|
+
"problemMatcher": {
|
|
10
|
+
"owner": "typescript",
|
|
11
|
+
"pattern": "$tsc",
|
|
12
|
+
"background": {
|
|
13
|
+
"activeOnStart": true,
|
|
14
|
+
"beginsPattern": {
|
|
15
|
+
"regexp": "Changes detected"
|
|
16
|
+
},
|
|
17
|
+
"endsPattern": {
|
|
18
|
+
"regexp": "bundle generation (complete|failed)"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"type": "npm",
|
|
25
|
+
"script": "test",
|
|
26
|
+
"isBackground": true,
|
|
27
|
+
"problemMatcher": {
|
|
28
|
+
"owner": "typescript",
|
|
29
|
+
"pattern": "$tsc",
|
|
30
|
+
"background": {
|
|
31
|
+
"activeOnStart": true,
|
|
32
|
+
"beginsPattern": {
|
|
33
|
+
"regexp": "Changes detected"
|
|
34
|
+
},
|
|
35
|
+
"endsPattern": {
|
|
36
|
+
"regexp": "bundle generation (complete|failed)"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
📅 Calendar Notes Widget
|
|
2
|
+
A lightweight embeddable calendar + personal notes widget that can be integrated into any website.
|
|
3
|
+
Users can:
|
|
4
|
+
• 📅 View a calendar
|
|
5
|
+
• 📝 Create personal notes for specific dates
|
|
6
|
+
• 🔔 Set reminders
|
|
7
|
+
• ☁️ Store notes securely in Supabase
|
|
8
|
+
• 🔐 Keep notes private per user
|
|
9
|
+
The widget is designed to be embedded via a simple script tag and integrated with the host website's authentication system.
|
|
10
|
+
________________________________________
|
|
11
|
+
✨ Features
|
|
12
|
+
• 📆 Interactive calendar
|
|
13
|
+
• 📝 Add / update / delete notes
|
|
14
|
+
• 🔔 Reminder support
|
|
15
|
+
• ☁️ Supabase database storage
|
|
16
|
+
• 🔐 User-based note isolation
|
|
17
|
+
• ⚡ Lightweight embeddable widget
|
|
18
|
+
• 🔌 Easy integration with existing websites
|
|
19
|
+
• 🧩 Works with any framework (Angular, React, Vue, Vanilla JS)
|
|
20
|
+
________________________________________
|
|
21
|
+
📦 Installation
|
|
22
|
+
CDN (Recommended)
|
|
23
|
+
Add the widget script to your website.
|
|
24
|
+
<script src="http://localhost:4200/widget.js"></script>
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
⚡ Quick Start
|
|
30
|
+
1. Include the widget script.
|
|
31
|
+
<script src="widget.js"></script>
|
|
32
|
+
2. Configure the widget.
|
|
33
|
+
window.CalendarNotesConfig = {
|
|
34
|
+
loadNotes: async () => { },
|
|
35
|
+
saveNote: async (note) => { },
|
|
36
|
+
updateNote: async (note) => { },
|
|
37
|
+
deleteNote: async (id) => { }
|
|
38
|
+
};
|
|
39
|
+
3. The widget will automatically load on the page.
|
|
40
|
+
________________________________________
|
|
41
|
+
🔌 Host Website Integration
|
|
42
|
+
The host website must provide four functions to interact with the database.
|
|
43
|
+
These functions allow the widget to remain backend-agnostic.
|
|
44
|
+
Example configuration:
|
|
45
|
+
window.CalendarNotesConfig = {
|
|
46
|
+
|
|
47
|
+
loadNotes: async () => {
|
|
48
|
+
if (!window.currentUserId) return [];
|
|
49
|
+
const { data } =
|
|
50
|
+
await supabaseService.getNotes(window.currentUserId);
|
|
51
|
+
return data || [];
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
saveNote: async (note) => {
|
|
55
|
+
note.user_id = window.currentUserId;
|
|
56
|
+
const { data } =
|
|
57
|
+
await supabaseService.saveNote([note]);
|
|
58
|
+
return data?.[0];
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
updateNote: async (note) => {
|
|
62
|
+
const { data } =
|
|
63
|
+
await supabaseService.updateNote(note.id, note);
|
|
64
|
+
return data?.[0];
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
deleteNote: async (id) => {
|
|
70
|
+
await supabaseService.deleteNote(id);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
};
|
|
74
|
+
________________________________________
|
|
75
|
+
🔐 User Authentication Integration
|
|
76
|
+
When a user logs in, the host website must notify the plugin.
|
|
77
|
+
Example:
|
|
78
|
+
window.currentUserId = userId;
|
|
79
|
+
|
|
80
|
+
window.postMessage(
|
|
81
|
+
{ type: "USER_LOGIN", userId: userId },
|
|
82
|
+
"*"
|
|
83
|
+
);
|
|
84
|
+
This allows the widget to load user-specific notes.
|
|
85
|
+
________________________________________
|
|
86
|
+
☁️ Supabase Integration
|
|
87
|
+
The widget does not directly access Supabase.
|
|
88
|
+
Instead, the host website handles Supabase communication.
|
|
89
|
+
Example Supabase service:
|
|
90
|
+
const { data } = await supabase
|
|
91
|
+
.from("notes")
|
|
92
|
+
.select("*")
|
|
93
|
+
.eq("user_id", userId);
|
|
94
|
+
________________________________________
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
🗄 Database Schema
|
|
98
|
+
Create a notes table in Supabase.
|
|
99
|
+
|
|
100
|
+
Column Type Description
|
|
101
|
+
id uuid Primary key
|
|
102
|
+
user_id uuid User ID
|
|
103
|
+
title text Note title
|
|
104
|
+
content text Note content
|
|
105
|
+
note_date date Note date
|
|
106
|
+
reminder_at timestamp Reminder time
|
|
107
|
+
created_at timestamp Created time
|
|
108
|
+
________________________________________
|
|
109
|
+
🔒 Row Level Security Policies
|
|
110
|
+
Enable Row Level Security.
|
|
111
|
+
|
|
112
|
+
Policy example:
|
|
113
|
+
Select policy
|
|
114
|
+
CREATE POLICY "Users can view their notes"
|
|
115
|
+
ON notes
|
|
116
|
+
FOR SELECT
|
|
117
|
+
|
|
118
|
+
Insert policy
|
|
119
|
+
CREATE POLICY "Users can insert notes"
|
|
120
|
+
ON notes
|
|
121
|
+
FOR INSERT
|
|
122
|
+
WITH CHECK (auth.uid() = user_id);
|
|
123
|
+
|
|
124
|
+
Update policy
|
|
125
|
+
CREATE POLICY "Users can update their notes"
|
|
126
|
+
ON notes
|
|
127
|
+
FOR UPDATE
|
|
128
|
+
USING (auth.uid() = user_id);
|
|
129
|
+
|
|
130
|
+
Delete policy
|
|
131
|
+
CREATE POLICY "Users can delete their notes"
|
|
132
|
+
ON notes
|
|
133
|
+
FOR DELETE
|
|
134
|
+
USING (auth.uid() = user_id);
|
|
135
|
+
________________________________________
|
|
136
|
+
📡 API Reference
|
|
137
|
+
The plugin expects the following configuration API.
|
|
138
|
+
loadNotes()
|
|
139
|
+
Fetch notes for the logged-in user.
|
|
140
|
+
Returns:
|
|
141
|
+
Array<Note>
|
|
142
|
+
________________________________________
|
|
143
|
+
saveNote(note)
|
|
144
|
+
Create a new note.
|
|
145
|
+
Example note:
|
|
146
|
+
{
|
|
147
|
+
title: "Exam preparation",
|
|
148
|
+
content: "Study chapter 3",
|
|
149
|
+
note_date: "2026-03-14"
|
|
150
|
+
}
|
|
151
|
+
Returns:
|
|
152
|
+
Note
|
|
153
|
+
________________________________________
|
|
154
|
+
updateNote(note)
|
|
155
|
+
Update an existing note.
|
|
156
|
+
Requires:
|
|
157
|
+
note.id
|
|
158
|
+
________________________________________
|
|
159
|
+
deleteNote(id)
|
|
160
|
+
Delete a note.
|
|
161
|
+
Parameter:
|
|
162
|
+
noteId
|
|
163
|
+
________________________________________
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
📄 Note Object Structure
|
|
168
|
+
{
|
|
169
|
+
id: string
|
|
170
|
+
user_id: string
|
|
171
|
+
title: string
|
|
172
|
+
content?: string
|
|
173
|
+
note_date: string
|
|
174
|
+
reminder_at?: string
|
|
175
|
+
}
|
|
176
|
+
________________________________________
|
|
177
|
+
💡 Usage Example
|
|
178
|
+
Example login integration.
|
|
179
|
+
async login() {
|
|
180
|
+
|
|
181
|
+
const { data } =
|
|
182
|
+
await supabase.auth.signInWithPassword({
|
|
183
|
+
email,
|
|
184
|
+
password
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const userId = data.user.id;
|
|
188
|
+
|
|
189
|
+
window.currentUserId = userId;
|
|
190
|
+
|
|
191
|
+
window.postMessage({
|
|
192
|
+
type: "USER_LOGIN",
|
|
193
|
+
userId: userId
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
}
|
|
197
|
+
________________________________________
|
|
198
|
+
🛠 Troubleshooting
|
|
199
|
+
Notes not loading
|
|
200
|
+
Check:
|
|
201
|
+
CalendarNotesConfig.loadNotes
|
|
202
|
+
________________________________________
|
|
203
|
+
Notes not saving
|
|
204
|
+
Verify:
|
|
205
|
+
currentUserId is set
|
|
206
|
+
________________________________________
|
|
207
|
+
Supabase permission errors
|
|
208
|
+
Check:
|
|
209
|
+
Row Level Security policies
|
|
210
|
+
________________________________________
|
|
211
|
+
❓ FAQ
|
|
212
|
+
Does the plugin require Supabase?
|
|
213
|
+
No.
|
|
214
|
+
You can connect it to any backend as long as the required functions are implemented.
|
|
215
|
+
________________________________________
|
|
216
|
+
Can multiple users use the plugin?
|
|
217
|
+
Yes.
|
|
218
|
+
Each user's notes are isolated using user_id.
|
|
219
|
+
________________________________________
|
|
220
|
+
Can this plugin work with React or Vue?
|
|
221
|
+
Yes.
|
|
222
|
+
It works with any framework because it uses a simple script tag.
|
|
223
|
+
________________________________________
|
|
224
|
+
👨💻 Author
|
|
225
|
+
Developed by Vidunaya Technologies
|
|
226
|
+
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"cli": {
|
|
5
|
+
"packageManager": "npm"
|
|
6
|
+
},
|
|
7
|
+
"newProjectRoot": "projects",
|
|
8
|
+
"projects": {
|
|
9
|
+
"notes_plugin": {
|
|
10
|
+
"projectType": "application",
|
|
11
|
+
"schematics": {},
|
|
12
|
+
"root": "",
|
|
13
|
+
"sourceRoot": "src",
|
|
14
|
+
"prefix": "app",
|
|
15
|
+
"architect": {
|
|
16
|
+
"build": {
|
|
17
|
+
"builder": "@angular/build:application",
|
|
18
|
+
"options": {
|
|
19
|
+
"browser": "src/main.ts",
|
|
20
|
+
"tsConfig": "tsconfig.app.json",
|
|
21
|
+
"assets": [
|
|
22
|
+
{
|
|
23
|
+
"glob": "**/*",
|
|
24
|
+
"input": "public"
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"styles": [
|
|
28
|
+
"src/styles.css"
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
},
|
|
32
|
+
"configurations": {
|
|
33
|
+
"production": {
|
|
34
|
+
"budgets": [
|
|
35
|
+
{
|
|
36
|
+
"type": "initial",
|
|
37
|
+
"maximumWarning": "500kB",
|
|
38
|
+
"maximumError": "1MB"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"type": "anyComponentStyle",
|
|
42
|
+
"maximumWarning": "4kB",
|
|
43
|
+
"maximumError": "8kB"
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"outputHashing": "none"
|
|
47
|
+
},
|
|
48
|
+
"development": {
|
|
49
|
+
"optimization": true,
|
|
50
|
+
"extractLicenses": false,
|
|
51
|
+
"sourceMap": false
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"defaultConfiguration": "production"
|
|
55
|
+
},
|
|
56
|
+
"serve": {
|
|
57
|
+
"builder": "@angular/build:dev-server",
|
|
58
|
+
"configurations": {
|
|
59
|
+
"production": {
|
|
60
|
+
"buildTarget": "notes_plugin:build:production"
|
|
61
|
+
},
|
|
62
|
+
"development": {
|
|
63
|
+
"buildTarget": "notes_plugin:build:development"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"defaultConfiguration": "development"
|
|
67
|
+
},
|
|
68
|
+
"test": {
|
|
69
|
+
"builder": "@angular/build:unit-test"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|