agentdev-webui 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/lib/agent-api.js +530 -0
- package/lib/auth.js +127 -0
- package/lib/config.js +53 -0
- package/lib/database.js +762 -0
- package/lib/device-flow.js +257 -0
- package/lib/email.js +420 -0
- package/lib/encryption.js +112 -0
- package/lib/github.js +339 -0
- package/lib/history.js +143 -0
- package/lib/pwa.js +107 -0
- package/lib/redis-logs.js +226 -0
- package/lib/routes.js +680 -0
- package/migrations/000_create_database.sql +33 -0
- package/migrations/001_create_agentdev_schema.sql +135 -0
- package/migrations/001_create_agentdev_schema.sql.old +100 -0
- package/migrations/001_create_agentdev_schema_fixed.sql +135 -0
- package/migrations/002_add_github_token.sql +17 -0
- package/migrations/003_add_agent_logs_table.sql +23 -0
- package/migrations/004_remove_oauth_columns.sql +11 -0
- package/migrations/005_add_projects.sql +44 -0
- package/migrations/006_project_github_token.sql +7 -0
- package/migrations/007_project_repositories.sql +12 -0
- package/migrations/008_add_notifications.sql +20 -0
- package/migrations/009_unified_oauth.sql +153 -0
- package/migrations/README.md +97 -0
- package/package.json +37 -0
- package/public/css/styles.css +1140 -0
- package/public/device.html +384 -0
- package/public/docs.html +862 -0
- package/public/docs.md +697 -0
- package/public/favicon.svg +5 -0
- package/public/index.html +271 -0
- package/public/js/app.js +2379 -0
- package/public/login.html +224 -0
- package/public/profile.html +394 -0
- package/public/register.html +392 -0
- package/public/reset-password.html +349 -0
- package/public/verify-email.html +177 -0
- package/server.js +1450 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
|
6
|
+
<meta name="theme-color" content="#1a1a2e">
|
|
7
|
+
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
8
|
+
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
9
|
+
<meta name="apple-mobile-web-app-title" content="Agent Dev">
|
|
10
|
+
<meta name="description" content="Multi-agent development workflow">
|
|
11
|
+
<meta property="og:title" content="Agent Dev">
|
|
12
|
+
<meta property="og:description" content="Multi-agent development workflow">
|
|
13
|
+
<meta property="og:type" content="website">
|
|
14
|
+
<meta property="og:image" content="/og-image.svg">
|
|
15
|
+
<meta property="og:image:width" content="1200">
|
|
16
|
+
<meta property="og:image:height" content="630">
|
|
17
|
+
<meta name="twitter:card" content="summary_large_image">
|
|
18
|
+
<meta name="twitter:title" content="Agent Dev">
|
|
19
|
+
<meta name="twitter:description" content="Multi-agent development workflow">
|
|
20
|
+
<meta name="twitter:image" content="/og-image.svg">
|
|
21
|
+
<link rel="manifest" href="/manifest.json">
|
|
22
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
|
23
|
+
<link rel="apple-touch-icon" href="/icon-192.png">
|
|
24
|
+
<link rel="stylesheet" href="/css/styles.css">
|
|
25
|
+
<title>Agent Dev</title>
|
|
26
|
+
</head>
|
|
27
|
+
<body>
|
|
28
|
+
<div class="offline-banner" id="offlineBanner">You are offline - reconnecting...</div>
|
|
29
|
+
<div class="header">
|
|
30
|
+
<h1>Agent Dev</h1>
|
|
31
|
+
<div class="status"><div class="status-dot" id="dot"></div><span id="statusTxt">Ready</span></div>
|
|
32
|
+
<div class="project-group">
|
|
33
|
+
<select id="projectSelector" class="project-selector" onchange="switchProject(this.value)" title="Select project">
|
|
34
|
+
<option value="">All Projects</option>
|
|
35
|
+
</select>
|
|
36
|
+
<button class="manage-projects-btn" onclick="openManageProjectsModal()" title="Add New Project">+</button>
|
|
37
|
+
<button class="manage-projects-btn" id="editProjectBtn" onclick="editCurrentProject()" title="Edit Selected Project" style="display:none;font-size:12px;">✎</button>
|
|
38
|
+
</div>
|
|
39
|
+
<div class="actions-group">
|
|
40
|
+
<div style="position:relative">
|
|
41
|
+
<button class="notification-bell" id="notificationBell" onclick="toggleNotificationPanel()" title="Notifications">
|
|
42
|
+
<svg viewBox="0 0 24 24"><path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.9 2 2 2zm6-6v-5c0-3.07-1.63-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.64 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2zm-2 1H8v-6c0-2.48 1.51-4.5 4-4.5s4 2.02 4 4.5v6z"/></svg>
|
|
43
|
+
<span class="badge" id="notificationBadge">0</span>
|
|
44
|
+
</button>
|
|
45
|
+
<div class="notification-panel" id="notificationPanel">
|
|
46
|
+
<div class="notification-panel-header">
|
|
47
|
+
<span>Notifications</span>
|
|
48
|
+
<button onclick="clearNotifications()" title="Mark all as read">Clear</button>
|
|
49
|
+
</div>
|
|
50
|
+
<div class="notification-panel-body" id="notificationPanelBody">
|
|
51
|
+
<div class="notification-empty">No notifications</div>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
<button class="logout-btn" onclick="window.location.href='/device'" title="Authorize Devices">
|
|
56
|
+
<svg viewBox="0 0 24 24" width="20" height="20"><path fill="currentColor" d="M17 1.01L7 1c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM17 19H7V5h10v14z"/></svg>
|
|
57
|
+
</button>
|
|
58
|
+
<button class="logout-btn" onclick="window.location.href='/profile'" title="Profile">
|
|
59
|
+
<svg viewBox="0 0 24 24" width="20" height="20"><path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/></svg>
|
|
60
|
+
</button>
|
|
61
|
+
<button class="logout-btn" id="logoutBtn" onclick="logout()" title="Logout">
|
|
62
|
+
<svg viewBox="0 0 24 24" width="20" height="20"><path fill="currentColor" d="M17 7l-1.41 1.41L18.17 11H8v2h10.17l-2.58 2.58L17 17l5-5zM4 5h8V3H4c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h8v-2H4V5z"/></svg>
|
|
63
|
+
</button>
|
|
64
|
+
</div>
|
|
65
|
+
<button class="hamburger" id="hamburger" onclick="toggleSidebar()">
|
|
66
|
+
<span></span><span></span><span></span>
|
|
67
|
+
</button>
|
|
68
|
+
</div>
|
|
69
|
+
<div class="controls">
|
|
70
|
+
<div class="view-toggle">
|
|
71
|
+
<button class="view-btn active" id="viewLogsBtn" onclick="switchView('logs')" title="Logs View">Logs</button>
|
|
72
|
+
<button class="view-btn" id="viewBoardBtn" onclick="switchView('board')" title="Board View">Board</button>
|
|
73
|
+
</div>
|
|
74
|
+
<button id="runBtn" onclick="run()">Run</button>
|
|
75
|
+
<button onclick="clearCurrentTab()">Clear</button>
|
|
76
|
+
<button id="stopBtn" onclick="stop()" disabled>Stop</button>
|
|
77
|
+
<button onclick="openCreateTicketModal()" class="btn-primary">+ Ticket</button>
|
|
78
|
+
<span class="agent-count" id="agentCount">Agents: 0</span>
|
|
79
|
+
</div>
|
|
80
|
+
<div class="mobile-sidebar-tabs" id="mobileSidebarTabs">
|
|
81
|
+
<div class="mobile-sidebar-tab active" data-tab="active" onclick="mobileSidebarTab('active')">Active</div>
|
|
82
|
+
<div class="mobile-sidebar-tab" data-tab="tickets" onclick="mobileSidebarTab('tickets')">Tickets <span id="mobileTodoCount" class="todo-count"></span></div>
|
|
83
|
+
<div class="mobile-sidebar-tab" data-tab="history" onclick="mobileSidebarTab('history')">History</div>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<!-- Create Ticket Modal -->
|
|
87
|
+
<div class="modal-overlay" id="createTicketModal">
|
|
88
|
+
<div class="modal">
|
|
89
|
+
<div class="modal-header">
|
|
90
|
+
<h2>Create Ticket</h2>
|
|
91
|
+
<button class="modal-close" onclick="closeCreateTicketModal()">×</button>
|
|
92
|
+
</div>
|
|
93
|
+
<div class="modal-body">
|
|
94
|
+
<div class="form-status" id="formStatus"></div>
|
|
95
|
+
<div class="form-group">
|
|
96
|
+
<label for="ticketRepo">Repository</label>
|
|
97
|
+
<select id="ticketRepo"></select>
|
|
98
|
+
</div>
|
|
99
|
+
<div class="form-group">
|
|
100
|
+
<label for="ticketDescription">Description</label>
|
|
101
|
+
<div class="textarea-wrapper">
|
|
102
|
+
<textarea id="ticketDescription" placeholder="Describe what you want to build or fix...
|
|
103
|
+
|
|
104
|
+
The first line will be used as the ticket title.
|
|
105
|
+
@claude will be automatically added."></textarea>
|
|
106
|
+
<button type="button" class="voice-btn" id="voiceBtn" onclick="toggleVoiceInput()" title="Voice input">
|
|
107
|
+
<svg viewBox="0 0 24 24"><path d="M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm-1-9c0-.55.45-1 1-1s1 .45 1 1v6c0 .55-.45 1-1 1s-1-.45-1-1V5zm6 6c0 2.76-2.24 5-5 5s-5-2.24-5-5H5c0 3.53 2.61 6.43 6 6.92V21h2v-3.08c3.39-.49 6-3.39 6-6.92h-2z"/></svg>
|
|
108
|
+
</button>
|
|
109
|
+
</div>
|
|
110
|
+
<div class="hint">First line = title. @claude auto-added. Tap mic for voice input.</div>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
<div class="modal-footer">
|
|
114
|
+
<button onclick="closeCreateTicketModal()">Cancel</button>
|
|
115
|
+
<button class="btn-primary" id="createTicketBtn" onclick="createTicket()">Create Ticket</button>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
<div class="main">
|
|
120
|
+
<div class="logs-container" id="logsContainer">
|
|
121
|
+
<div class="tabs" id="tabs">
|
|
122
|
+
<div class="tab active" data-tab="global" onclick="switchTab('global')">Global</div>
|
|
123
|
+
</div>
|
|
124
|
+
<div class="tab-content" id="tabContent">
|
|
125
|
+
<div class="logs-panel active" id="panel-global"></div>
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
<div class="board-container" id="boardContainer">
|
|
129
|
+
<div class="board" id="board"></div>
|
|
130
|
+
</div>
|
|
131
|
+
<div class="sidebar-overlay" id="sidebarOverlay" onclick="closeSidebar()"></div>
|
|
132
|
+
<div class="sidebar" id="sidebar">
|
|
133
|
+
<div class="sidebar-tabs">
|
|
134
|
+
<div class="sidebar-tab active" onclick="switchSidebarTab('active')">Active</div>
|
|
135
|
+
<div class="sidebar-tab" onclick="switchSidebarTab('tickets')">Tickets <span id="todoCount" class="todo-count"></span></div>
|
|
136
|
+
<div class="sidebar-tab" onclick="switchSidebarTab('history')">History</div>
|
|
137
|
+
</div>
|
|
138
|
+
<div class="sidebar-content">
|
|
139
|
+
<div class="agent-list active" id="agents"></div>
|
|
140
|
+
<div class="agent-list" id="agentsTodo"></div>
|
|
141
|
+
<div class="agent-list" id="agentsHistory"></div>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
<!-- Ticket Detail Panel -->
|
|
146
|
+
<div class="ticket-panel-overlay" id="ticketPanelOverlay" onclick="closeTicketPanel()"></div>
|
|
147
|
+
<div class="ticket-panel" id="ticketPanel">
|
|
148
|
+
<div class="ticket-panel-header">
|
|
149
|
+
<div class="ticket-panel-title" id="ticketPanelTitle"></div>
|
|
150
|
+
<button class="ticket-panel-close" onclick="closeTicketPanel()">×</button>
|
|
151
|
+
</div>
|
|
152
|
+
<div class="ticket-panel-body" id="ticketPanelBody"></div>
|
|
153
|
+
</div>
|
|
154
|
+
<div class="tooltip" id="tooltip"></div>
|
|
155
|
+
<button class="scroll-to-bottom" id="scrollToBottom" onclick="scrollToBottom()" title="Scroll to bottom">
|
|
156
|
+
<svg viewBox="0 0 24 24"><path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z"/></svg>
|
|
157
|
+
</button>
|
|
158
|
+
<div class="bottom-sheet" id="bottomSheet">
|
|
159
|
+
<div class="bottom-sheet-handle"></div>
|
|
160
|
+
<div class="bottom-sheet-content" id="bottomSheetContent"></div>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<!-- Add Comment Modal -->
|
|
164
|
+
<div class="modal-overlay" id="addCommentModal">
|
|
165
|
+
<div class="modal">
|
|
166
|
+
<div class="modal-header">
|
|
167
|
+
<h2>Add Comment to Ticket</h2>
|
|
168
|
+
<button class="modal-close" onclick="closeCommentModal()">×</button>
|
|
169
|
+
</div>
|
|
170
|
+
<div class="modal-body">
|
|
171
|
+
<div class="form-status" id="commentFormStatus"></div>
|
|
172
|
+
<div class="form-group">
|
|
173
|
+
<label>Ticket</label>
|
|
174
|
+
<div id="commentTicketInfo" style="color:#4ade80;font-size:14px;padding:8px 0;"></div>
|
|
175
|
+
</div>
|
|
176
|
+
<div class="form-group">
|
|
177
|
+
<label for="commentText">Comment</label>
|
|
178
|
+
<div class="textarea-wrapper">
|
|
179
|
+
<textarea id="commentText" placeholder="Write your comment here...
|
|
180
|
+
|
|
181
|
+
@claude will be automatically added to trigger the agent."></textarea>
|
|
182
|
+
<button type="button" class="voice-btn" id="commentVoiceBtn" onclick="toggleCommentVoiceInput()" title="Voice input">
|
|
183
|
+
<svg viewBox="0 0 24 24"><path d="M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm-1-9c0-.55.45-1 1-1s1 .45 1 1v6c0 .55-.45 1-1 1s-1-.45-1-1V5zm6 6c0 2.76-2.24 5-5 5s-5-2.24-5-5H5c0 3.53 2.61 6.43 6 6.92V21h2v-3.08c3.39-.49 6-3.39 6-6.92h-2z"/></svg>
|
|
184
|
+
</button>
|
|
185
|
+
</div>
|
|
186
|
+
<div class="hint">@claude will be auto-added. Use mic for voice input. Ctrl+Enter to submit.</div>
|
|
187
|
+
</div>
|
|
188
|
+
</div>
|
|
189
|
+
<div class="modal-footer">
|
|
190
|
+
<button onclick="closeCommentModal()">Cancel</button>
|
|
191
|
+
<button class="btn-primary" id="addCommentBtn" onclick="submitComment()">Add Comment</button>
|
|
192
|
+
</div>
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
<!-- Manage Projects Modal -->
|
|
196
|
+
<div class="modal-overlay" id="manageProjectsModal">
|
|
197
|
+
<div class="modal" style="max-width:500px;">
|
|
198
|
+
<div class="modal-header">
|
|
199
|
+
<h2 id="projectModalTitle">Add Project</h2>
|
|
200
|
+
<button class="modal-close" onclick="closeManageProjectsModal()">×</button>
|
|
201
|
+
</div>
|
|
202
|
+
<div class="modal-body">
|
|
203
|
+
<div class="form-status" id="projectFormStatus"></div>
|
|
204
|
+
<div class="form-group">
|
|
205
|
+
<label for="projectName">Name</label>
|
|
206
|
+
<input type="text" id="projectName" placeholder="My Project" style="width:100%;padding:8px;background:#16213e;border:1px solid #333;color:#fff;border-radius:4px;">
|
|
207
|
+
</div>
|
|
208
|
+
<div class="form-group">
|
|
209
|
+
<label for="projectOrg">GitHub Org</label>
|
|
210
|
+
<input type="text" id="projectOrg" placeholder="data-tamer" style="width:100%;padding:8px;background:#16213e;border:1px solid #333;color:#fff;border-radius:4px;">
|
|
211
|
+
</div>
|
|
212
|
+
<div class="form-group">
|
|
213
|
+
<label for="projectGithubToken">GitHub Token (optional)</label>
|
|
214
|
+
<input type="password" id="projectGithubToken" placeholder="ghp_... (leave empty to use profile default)" style="width:100%;padding:8px;background:#16213e;border:1px solid #333;color:#fff;border-radius:4px;font-family:monospace;font-size:12px;">
|
|
215
|
+
<div class="hint">Optional. Used for fetching repos/fields below. If empty, uses your profile token.</div>
|
|
216
|
+
</div>
|
|
217
|
+
<div class="form-group">
|
|
218
|
+
<label for="projectNumber">Project Number</label>
|
|
219
|
+
<input type="number" id="projectNumber" placeholder="1" style="width:100%;padding:8px;background:#16213e;border:1px solid #333;color:#fff;border-radius:4px;">
|
|
220
|
+
</div>
|
|
221
|
+
<div class="form-group">
|
|
222
|
+
<label>Project Board Fields</label>
|
|
223
|
+
<div style="display:flex;gap:8px;margin-bottom:8px;">
|
|
224
|
+
<button type="button" class="btn-fetch-repos" onclick="fetchProjectFields(this)">Fetch from GitHub</button>
|
|
225
|
+
<span id="fieldsFetchStatus" style="font-size:11px;color:#888;align-self:center;"></span>
|
|
226
|
+
</div>
|
|
227
|
+
<input type="hidden" id="projectGithubId">
|
|
228
|
+
<input type="hidden" id="projectStatusFieldId">
|
|
229
|
+
<div id="projectFieldsInfo" style="font-size:11px;color:#888;margin-bottom:8px;"></div>
|
|
230
|
+
<div class="hint" style="margin-bottom:8px;">Fill in Org + Project Number above, then click "Fetch from GitHub" to auto-detect the project ID, status field, and status columns.</div>
|
|
231
|
+
</div>
|
|
232
|
+
<div class="form-group">
|
|
233
|
+
<label>Status Columns</label>
|
|
234
|
+
<table id="statusOptionsTable" class="status-options-table">
|
|
235
|
+
<thead><tr><th style="width:30px;"></th><th>Map To</th><th>Column Name</th><th>ID</th><th style="width:30px;"></th></tr></thead>
|
|
236
|
+
<tbody id="statusOptionsBody">
|
|
237
|
+
<tr><td colspan="5" style="color:#666;text-align:center;padding:12px;">Click "Fetch from GitHub" to load columns</td></tr>
|
|
238
|
+
</tbody>
|
|
239
|
+
</table>
|
|
240
|
+
<div id="addColumnRow" style="display:none;margin-top:8px;gap:6px;align-items:center;">
|
|
241
|
+
<select id="addColMapTo" style="padding:4px;background:#16213e;border:1px solid #333;color:#eee;border-radius:4px;font-size:11px;">
|
|
242
|
+
<option value="">(skip)</option><option value="TODO">TODO</option><option value="IN_PROGRESS">IN_PROGRESS</option><option value="TEST">TEST</option><option value="DONE">DONE</option>
|
|
243
|
+
</select>
|
|
244
|
+
<input type="text" id="addColName" placeholder="Column name" style="flex:1;padding:4px 6px;background:#16213e;border:1px solid #333;color:#eee;border-radius:4px;font-size:11px;">
|
|
245
|
+
<input type="text" id="addColId" placeholder="Column ID" style="flex:1;padding:4px 6px;background:#16213e;border:1px solid #333;color:#eee;border-radius:4px;font-size:11px;font-family:monospace;">
|
|
246
|
+
<button type="button" id="confirmAddColBtn" class="btn-fetch-repos" style="padding:4px 10px;font-size:11px;min-height:auto;" onclick="confirmAddColumn()">Add</button>
|
|
247
|
+
<button type="button" id="cancelAddColBtn" style="padding:4px 8px;font-size:11px;background:#333;border:1px solid #555;color:#eee;border-radius:4px;cursor:pointer;" onclick="hideAddColumnRow()">Cancel</button>
|
|
248
|
+
</div>
|
|
249
|
+
<button type="button" class="btn-add-column" id="addColumnBtn" onclick="showAddColumnRow()">+ Add Column</button>
|
|
250
|
+
<div class="hint">Assign each GitHub column to a role: TODO, IN_PROGRESS, TEST, or DONE. Reorder with arrows, remove with ×.</div>
|
|
251
|
+
</div>
|
|
252
|
+
<div class="form-group">
|
|
253
|
+
<label for="projectRepositories">Repositories</label>
|
|
254
|
+
<div style="display:flex;gap:8px;margin-bottom:8px;">
|
|
255
|
+
<button type="button" class="btn-fetch-repos" onclick="fetchOrgRepos(this)">Fetch from Org</button>
|
|
256
|
+
<span id="repoFetchStatus" style="font-size:11px;color:#888;align-self:center;"></span>
|
|
257
|
+
</div>
|
|
258
|
+
<select id="projectRepositories" multiple size="8" class="repo-multiselect">
|
|
259
|
+
</select>
|
|
260
|
+
<div class="hint">Fill in the GitHub Org above, then click "Fetch from Org" to load repos. Ctrl/Cmd+click to select multiple.</div>
|
|
261
|
+
</div>
|
|
262
|
+
</div>
|
|
263
|
+
<div class="modal-footer">
|
|
264
|
+
<button onclick="closeManageProjectsModal()">Cancel</button>
|
|
265
|
+
<button class="btn-primary" id="projectSubmitBtn" onclick="submitProject()">Add Project</button>
|
|
266
|
+
</div>
|
|
267
|
+
</div>
|
|
268
|
+
</div>
|
|
269
|
+
<script src="/js/app.js"></script>
|
|
270
|
+
</body>
|
|
271
|
+
</html>
|