koa3-cli 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.
@@ -0,0 +1,608 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Koa3 CLI 文档</title>
7
+ <!-- Prism.js 代码高亮 -->
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css">
9
+ <!-- 文档样式文件 - 修改 docs.css 来调整样式 -->
10
+ <link rel="stylesheet" href="/docs/docs.css">
11
+ </head>
12
+ <body>
13
+ <!-- 顶部导航栏 -->
14
+ <nav class="navbar">
15
+ <button class="menu-toggle" onclick="toggleSidebar()">☰</button>
16
+ <a href="#" class="navbar-brand" onclick="showHome(); return false;">Koa3 CLI</a>
17
+ <div style="margin-left: auto; display: flex; gap: 1rem; align-items: center;">
18
+ <a href="https://gitee.com/wangziwl/koa3-cli" target="_blank" style="color: #2c3e50; text-decoration: none; font-size: 0.9rem;">🔗 Gitee</a>
19
+ </div>
20
+ </nav>
21
+
22
+ <!-- 侧边栏 - 导航菜单由 docs-content.js 动态生成 -->
23
+ <aside class="sidebar" id="sidebar">
24
+ <!-- 导航菜单将在这里动态生成 -->
25
+ </aside>
26
+
27
+ <!-- 主内容区 -->
28
+ <main class="main">
29
+ <div class="content">
30
+ <!-- ============================================
31
+ 文档内容区域
32
+ 修改下面的内容来更新文档
33
+ ============================================ -->
34
+
35
+ <!-- 首页 -->
36
+ <div id="home" class="content-section active">
37
+ <div class="home">
38
+ <div class="hero">
39
+ <h1>Koa3 CLI</h1>
40
+ <p>基于 Koa3 的脚手架项目</p>
41
+ <p class="info-text">2025年4月28日,Node.js 生态圈迎来了一场重磅升级——Koa.js 3.0 正式发布!自2017年启动开发计划,历经8年长跑,由 Express 原班人马打造的经典轻量级 Web 框架,终于以全新姿态回归视野。Koa 3.0 不仅是一次版本号的跃迁,更是 Node.js 现代化进程的重要里程碑。</p>
42
+ <div style="margin: 1.5rem 0;">
43
+ <a href="https://gitee.com/wangziwl/koa3-cli" target="_blank" style="color: #3eaf7c; text-decoration: none; margin-right: 1rem;">🔗 Gitee 仓库</a>
44
+ </div>
45
+ <a href="#" class="action-button" onclick="showContent('getting-started'); return false;">快速开始 →</a>
46
+ </div>
47
+ <div class="features">
48
+ <div class="feature">
49
+ <h3>🚀 轻量高效</h3>
50
+ <p>基于 Koa3,性能优异,代码简洁</p>
51
+ </div>
52
+ <div class="feature">
53
+ <h3>📁 清晰结构</h3>
54
+ <p>规范统一,易于维护</p>
55
+ </div>
56
+ <div class="feature">
57
+ <h3>🔧 多环境配置</h3>
58
+ <p>支持 development/production 环境配置</p>
59
+ </div>
60
+ <div class="feature">
61
+ <h3>🏗️ MVC 架构</h3>
62
+ <p>Controller/Service/Model 分层清晰</p>
63
+ </div>
64
+ <div class="feature">
65
+ <h3>🔌 中间件支持</h3>
66
+ <p>灵活的中间件系统,易于扩展</p>
67
+ </div>
68
+ <div class="feature">
69
+ <h3>✅ 错误处理</h3>
70
+ <p>统一的错误处理机制</p>
71
+ </div>
72
+ </div>
73
+ </div>
74
+ </div>
75
+
76
+ <!-- 快速开始 -->
77
+ <div id="getting-started" class="content-section">
78
+ <h1>快速开始</h1>
79
+ <h2>安装依赖</h2>
80
+ <pre><code class="language-bash">npm install</code></pre>
81
+ <h2>启动项目</h2>
82
+ <h3>开发环境</h3>
83
+ <p>使用 nodemon 自动重启:</p>
84
+ <pre><code class="language-bash">npm run dev</code></pre>
85
+ <h3>生产环境</h3>
86
+ <pre><code class="language-bash">npm start</code></pre>
87
+ <h2>访问应用</h2>
88
+ <p>启动成功后,你可以访问:</p>
89
+ <ul>
90
+ <li><strong>首页</strong>: http://localhost:3000</li>
91
+ <li><strong>API 示例</strong>: http://localhost:3000/api/user</li>
92
+ <li><strong>文档</strong>: http://localhost:3000/index.html</li>
93
+ </ul>
94
+ <h2>环境配置</h2>
95
+ <p>项目支持多环境配置,通过 <code>NODE_ENV</code> 环境变量控制:</p>
96
+ <ul>
97
+ <li><code>development</code> 或 <code>local</code>: 加载 <code>config.local.js</code></li>
98
+ <li><code>production</code>: 加载 <code>config.prod.js</code></li>
99
+ <li>默认: 加载 <code>config.default.js</code></li>
100
+ </ul>
101
+ <p>可以通过 <code>.env</code> 文件配置环境变量(参考 <code>env.example</code>)。</p>
102
+ <h2>下一步</h2>
103
+ <ul>
104
+ <li>了解 <a href="#" onclick="showContent('project-structure'); return false;">项目结构</a></li>
105
+ <li>查看 <a href="#" onclick="showContent('configuration'); return false;">配置说明</a></li>
106
+ <li>阅读 <a href="#" onclick="showContent('development'); return false;">开发指南</a></li>
107
+ </ul>
108
+ </div>
109
+
110
+ <!-- 项目结构 -->
111
+ <div id="project-structure" class="content-section">
112
+ <h1>项目结构</h1>
113
+ <pre><code class="language-text">koa3-cli/
114
+ ├── app/ # 应用代码目录
115
+ │ ├── controller/ # 控制器目录
116
+ │ │ ├── home.js # 首页控制器
117
+ │ │ ├── user.js # 用户控制器
118
+ │ │ └── docs.js # 文档控制器
119
+ │ ├── service/ # 服务层目录
120
+ │ │ └── user.js # 用户服务
121
+ │ ├── model/ # 数据模型目录
122
+ │ │ └── user.js # 用户模型
123
+ │ ├── middleware/ # 中间件目录
124
+ │ │ ├── index.js # 中间件入口
125
+ │ │ └── auth.js # 认证中间件示例
126
+ │ ├── router.js # 路由配置
127
+ │ └── view/ # 视图模板目录(可选)
128
+ │ └── docs.ejs # 页面模板
129
+ ├── config/ # 配置文件目录
130
+ │ ├── config.default.js # 默认配置
131
+ │ ├── config.local.js # 本地开发配置
132
+ │ └── config.prod.js # 生产环境配置
133
+ ├── public/ # 静态资源目录
134
+ │ └── index.html # 首页
135
+ ├── app.js # 应用入口文件
136
+ ├── package.json # 项目配置
137
+ └── README.md # 项目说明</code></pre>
138
+ <h2>目录说明</h2>
139
+ <h3>app/</h3>
140
+ <p>应用代码目录,包含所有业务逻辑代码。</p>
141
+ <h4>controller/</h4>
142
+ <p>控制器目录,处理 HTTP 请求和响应。</p>
143
+ <pre><code class="language-javascript">// app/controller/user.js
144
+ class UserController {
145
+ async list(ctx) {
146
+ ctx.body = await userService.getUserList();
147
+ }
148
+ }</code></pre>
149
+ <h4>service/</h4>
150
+ <p>服务层目录,处理业务逻辑。</p>
151
+ <pre><code class="language-javascript">// app/service/user.js
152
+ class UserService {
153
+ async getUserList() {
154
+ return await userModel.findAll();
155
+ }
156
+ }</code></pre>
157
+ <h4>model/</h4>
158
+ <p>数据模型目录,处理数据访问。</p>
159
+ <pre><code class="language-javascript">// app/model/user.js
160
+ class UserModel {
161
+ async findAll() {
162
+ // 数据库查询逻辑
163
+ }
164
+ }</code></pre>
165
+ <h4>middleware/</h4>
166
+ <p>中间件目录,处理请求预处理和后处理。</p>
167
+ <pre><code class="language-javascript">// app/middleware/index.js
168
+ module.exports = async (ctx, next) => {
169
+ // 中间件逻辑
170
+ await next();
171
+ };</code></pre>
172
+ <h3>config/</h3>
173
+ <p>配置文件目录,包含不同环境的配置。</p>
174
+ <h3>public/</h3>
175
+ <p>静态资源目录,存放静态文件。</p>
176
+ </div>
177
+
178
+ <!-- 配置说明 -->
179
+ <div id="configuration" class="content-section">
180
+ <h1>配置说明</h1>
181
+ <h2>环境配置</h2>
182
+ <p>项目支持多环境配置,通过 <code>NODE_ENV</code> 环境变量控制:</p>
183
+ <ul>
184
+ <li><code>development</code> 或 <code>local</code>: 加载 <code>config.local.js</code></li>
185
+ <li><code>production</code>: 加载 <code>config.prod.js</code></li>
186
+ <li>默认: 加载 <code>config.default.js</code></li>
187
+ </ul>
188
+ <p>配置文件会按顺序加载,后面的配置会覆盖前面的配置。</p>
189
+ <h2>环境变量</h2>
190
+ <p>可以通过 <code>.env</code> 文件配置环境变量(参考 <code>env.example</code>):</p>
191
+ <pre><code class="language-env"># 运行环境
192
+ NODE_ENV=development
193
+
194
+ # 服务端口
195
+ PORT=3000
196
+
197
+ # 应用密钥(多个密钥用逗号分隔)
198
+ KEYS=your-secret-key-1,your-secret-key-2
199
+
200
+ # 数据库配置
201
+ DB_HOST=localhost
202
+ DB_PORT=3306
203
+ DB_USER=root
204
+ DB_PASSWORD=
205
+ DB_NAME=test
206
+
207
+ # Redis配置
208
+ REDIS_HOST=localhost
209
+ REDIS_PORT=6379
210
+ REDIS_PASSWORD=
211
+ REDIS_DB=0
212
+
213
+ # 日志级别
214
+ LOG_LEVEL=info</code></pre>
215
+ <h2>配置项说明</h2>
216
+ <h3>基础配置</h3>
217
+ <pre><code class="language-javascript">{
218
+ name: 'koa3-cli', // 应用名称
219
+ env: 'development', // 运行环境
220
+ port: 3000, // 服务端口
221
+ keys: ['secret-key'] // 应用密钥
222
+ }</code></pre>
223
+ <h3>静态资源配置</h3>
224
+ <pre><code class="language-javascript">static: {
225
+ enable: true, // 是否启用
226
+ dir: 'public', // 静态文件目录
227
+ options: {
228
+ maxAge: 365 * 24 * 60 * 60 * 1000, // 缓存时间
229
+ gzip: true // 是否启用 gzip
230
+ }
231
+ }</code></pre>
232
+ <h3>视图配置</h3>
233
+ <pre><code class="language-javascript">view: {
234
+ enable: true, // 是否启用
235
+ root: 'app/view', // 视图文件目录
236
+ options: {
237
+ extension: 'ejs', // 默认扩展名
238
+ map: {
239
+ html: 'ejs' // 文件扩展名映射
240
+ }
241
+ }
242
+ }</code></pre>
243
+ <h3>数据库配置</h3>
244
+ <pre><code class="language-javascript">database: {
245
+ client: 'mysql',
246
+ connection: {
247
+ host: 'localhost',
248
+ port: 3306,
249
+ user: 'root',
250
+ password: '',
251
+ database: 'test'
252
+ },
253
+ pool: {
254
+ min: 2,
255
+ max: 10
256
+ }
257
+ }</code></pre>
258
+ <h3>Redis配置</h3>
259
+ <pre><code class="language-javascript">redis: {
260
+ host: 'localhost',
261
+ port: 6379,
262
+ password: '',
263
+ db: 0
264
+ }</code></pre>
265
+ <h3>日志配置</h3>
266
+ <pre><code class="language-javascript">logger: {
267
+ level: 'info', // 日志级别: debug, info, warn, error
268
+ dir: 'logs' // 日志目录
269
+ }</code></pre>
270
+ </div>
271
+
272
+ <!-- 开发指南 -->
273
+ <div id="development" class="content-section">
274
+ <h1>开发指南</h1>
275
+ <h2>添加新的控制器</h2>
276
+ <p>1. 在 <code>app/controller/</code> 目录下创建控制器文件</p>
277
+ <pre><code class="language-javascript">// app/controller/product.js
278
+ const productService = require('../service/product');
279
+
280
+ class ProductController {
281
+ async list(ctx) {
282
+ try {
283
+ const products = await productService.getList();
284
+ ctx.body = products;
285
+ } catch (error) {
286
+ ctx.throw(500, error.message);
287
+ }
288
+ }
289
+
290
+ async detail(ctx) {
291
+ const { id } = ctx.params;
292
+ const product = await productService.getById(id);
293
+ if (!product) {
294
+ ctx.status = 404;
295
+ ctx.body = { message: 'Product not found' };
296
+ return;
297
+ }
298
+ ctx.body = product;
299
+ }
300
+ }
301
+
302
+ module.exports = new ProductController();</code></pre>
303
+ <p>2. 在 <code>app/router.js</code> 中注册路由</p>
304
+ <pre><code class="language-javascript">const productController = require('./controller/product');
305
+
306
+ router.get('/api/product', productController.list);
307
+ router.get('/api/product/:id', productController.detail);</code></pre>
308
+ <h2>添加新的服务</h2>
309
+ <p>在 <code>app/service/</code> 目录下创建服务文件,处理业务逻辑:</p>
310
+ <pre><code class="language-javascript">// app/service/product.js
311
+ const productModel = require('../model/product');
312
+
313
+ class ProductService {
314
+ async getList() {
315
+ return await productModel.findAll();
316
+ }
317
+
318
+ async getById(id) {
319
+ return await productModel.findById(id);
320
+ }
321
+
322
+ async create(productData) {
323
+ // 数据验证
324
+ if (!productData.name) {
325
+ throw new Error('Product name is required');
326
+ }
327
+ return await productModel.create(productData);
328
+ }
329
+ }
330
+
331
+ module.exports = new ProductService();</code></pre>
332
+ <h2>添加新的模型</h2>
333
+ <p>在 <code>app/model/</code> 目录下创建模型文件,处理数据访问:</p>
334
+ <pre><code class="language-javascript">// app/model/product.js
335
+ class ProductModel {
336
+ async findAll() {
337
+ // 数据库查询逻辑
338
+ // return await db.query('SELECT * FROM products');
339
+ }
340
+
341
+ async findById(id) {
342
+ // return await db.query('SELECT * FROM products WHERE id = ?', [id]);
343
+ }
344
+
345
+ async create(productData) {
346
+ // return await db.insert('products', productData);
347
+ }
348
+ }
349
+
350
+ module.exports = new ProductModel();</code></pre>
351
+ <h2>添加中间件</h2>
352
+ <p>在 <code>app/middleware/</code> 目录下创建中间件文件:</p>
353
+ <pre><code class="language-javascript">// app/middleware/logger.js
354
+ module.exports = async (ctx, next) => {
355
+ const start = Date.now();
356
+ await next();
357
+ const ms = Date.now() - start;
358
+ console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
359
+ };</code></pre>
360
+ <p>然后在 <code>app/middleware/index.js</code> 中引入使用:</p>
361
+ <pre><code class="language-javascript">const logger = require('./logger');
362
+
363
+ module.exports = async (ctx, next) => {
364
+ await logger(ctx, next);
365
+ // 其他中间件...
366
+ };</code></pre>
367
+ <h2>错误处理</h2>
368
+ <p>控制器中的错误会自动被错误处理中间件捕获:</p>
369
+ <pre><code class="language-javascript">// 抛出错误
370
+ ctx.throw(400, 'Bad Request');
371
+
372
+ // 或者
373
+ throw new Error('Something went wrong');</code></pre>
374
+ <p>错误会被统一处理并返回:</p>
375
+ <pre><code class="language-json">{
376
+ "success": false,
377
+ "message": "Error message",
378
+ "stack": "..." // 仅在开发环境显示
379
+ }</code></pre>
380
+ <h2>响应格式</h2>
381
+ <p>API 请求会自动统一响应格式:</p>
382
+ <pre><code class="language-json">{
383
+ "success": true,
384
+ "data": {
385
+ // 响应数据
386
+ }
387
+ }</code></pre>
388
+ <p>如果响应已经是 <code>{ success: true/false }</code> 格式,则不会再次包装。</p>
389
+ </div>
390
+
391
+ <!-- API 文档首页 -->
392
+ <div id="api-readme" class="content-section">
393
+ <h1>API 文档</h1>
394
+ <p>本文档描述了 Koa3 CLI 提供的所有 API 接口。</p>
395
+ <h2>基础信息</h2>
396
+ <ul>
397
+ <li><strong>Base URL</strong>: <code>http://localhost:3000</code></li>
398
+ <li><strong>Content-Type</strong>: <code>application/json</code></li>
399
+ </ul>
400
+ <h2>响应格式</h2>
401
+ <p>所有 API 响应都遵循统一的格式:</p>
402
+ <h3>成功响应</h3>
403
+ <pre><code class="language-json">{
404
+ "success": true,
405
+ "data": {
406
+ // 响应数据
407
+ }
408
+ }</code></pre>
409
+ <h3>错误响应</h3>
410
+ <pre><code class="language-json">{
411
+ "success": false,
412
+ "message": "错误信息",
413
+ "stack": "..." // 仅在开发环境显示
414
+ }</code></pre>
415
+ <h2>API 列表</h2>
416
+ <ul>
417
+ <li><a href="#" onclick="showContent('api-user'); return false;">用户接口</a> - 用户相关的 CRUD 操作</li>
418
+ </ul>
419
+ </div>
420
+
421
+ <!-- 用户接口 -->
422
+ <div id="api-user" class="content-section">
423
+ <h1>用户接口</h1>
424
+ <p>用户相关的 CRUD 操作接口。</p>
425
+ <h2>获取用户列表</h2>
426
+ <p>获取所有用户列表。</p>
427
+ <h3>请求</h3>
428
+ <pre><code class="language-http">GET /api/user</code></pre>
429
+ <h3>响应</h3>
430
+ <pre><code class="language-json">{
431
+ "success": true,
432
+ "data": [
433
+ {
434
+ "id": 1,
435
+ "name": "张三",
436
+ "email": "zhangsan@example.com",
437
+ "createdAt": "2024-01-01T00:00:00.000Z"
438
+ },
439
+ {
440
+ "id": 2,
441
+ "name": "李四",
442
+ "email": "lisi@example.com",
443
+ "createdAt": "2024-01-01T00:00:00.000Z"
444
+ }
445
+ ]
446
+ }</code></pre>
447
+ <h2>获取用户详情</h2>
448
+ <p>根据用户 ID 获取用户详情。</p>
449
+ <h3>请求</h3>
450
+ <pre><code class="language-http">GET /api/user/:id</code></pre>
451
+ <h3>路径参数</h3>
452
+ <table>
453
+ <thead>
454
+ <tr>
455
+ <th>参数</th>
456
+ <th>类型</th>
457
+ <th>说明</th>
458
+ </tr>
459
+ </thead>
460
+ <tbody>
461
+ <tr>
462
+ <td>id</td>
463
+ <td>number</td>
464
+ <td>用户ID</td>
465
+ </tr>
466
+ </tbody>
467
+ </table>
468
+ <h3>响应</h3>
469
+ <pre><code class="language-json">{
470
+ "success": true,
471
+ "data": {
472
+ "id": 1,
473
+ "name": "张三",
474
+ "email": "zhangsan@example.com",
475
+ "createdAt": "2024-01-01T00:00:00.000Z"
476
+ }
477
+ }</code></pre>
478
+ <h3>错误响应</h3>
479
+ <pre><code class="language-json">{
480
+ "success": false,
481
+ "message": "User not found"
482
+ }</code></pre>
483
+ <h2>创建用户</h2>
484
+ <p>创建新用户。</p>
485
+ <h3>请求</h3>
486
+ <pre><code class="language-http">POST /api/user
487
+ Content-Type: application/json</code></pre>
488
+ <h3>请求体</h3>
489
+ <pre><code class="language-json">{
490
+ "name": "张三",
491
+ "email": "zhangsan@example.com"
492
+ }</code></pre>
493
+ <h3>请求参数</h3>
494
+ <table>
495
+ <thead>
496
+ <tr>
497
+ <th>参数</th>
498
+ <th>类型</th>
499
+ <th>必填</th>
500
+ <th>说明</th>
501
+ </tr>
502
+ </thead>
503
+ <tbody>
504
+ <tr>
505
+ <td>name</td>
506
+ <td>string</td>
507
+ <td>是</td>
508
+ <td>用户姓名</td>
509
+ </tr>
510
+ <tr>
511
+ <td>email</td>
512
+ <td>string</td>
513
+ <td>是</td>
514
+ <td>用户邮箱</td>
515
+ </tr>
516
+ </tbody>
517
+ </table>
518
+ <h3>响应</h3>
519
+ <pre><code class="language-json">{
520
+ "success": true,
521
+ "data": {
522
+ "id": 1,
523
+ "name": "张三",
524
+ "email": "zhangsan@example.com",
525
+ "createdAt": "2024-01-01T00:00:00.000Z"
526
+ }
527
+ }</code></pre>
528
+ <h2>更新用户</h2>
529
+ <p>更新用户信息。</p>
530
+ <h3>请求</h3>
531
+ <pre><code class="language-http">PUT /api/user/:id
532
+ Content-Type: application/json</code></pre>
533
+ <h3>路径参数</h3>
534
+ <table>
535
+ <thead>
536
+ <tr>
537
+ <th>参数</th>
538
+ <th>类型</th>
539
+ <th>说明</th>
540
+ </tr>
541
+ </thead>
542
+ <tbody>
543
+ <tr>
544
+ <td>id</td>
545
+ <td>number</td>
546
+ <td>用户ID</td>
547
+ </tr>
548
+ </tbody>
549
+ </table>
550
+ <h3>请求体</h3>
551
+ <pre><code class="language-json">{
552
+ "name": "李四",
553
+ "email": "lisi@example.com"
554
+ }</code></pre>
555
+ <h3>响应</h3>
556
+ <pre><code class="language-json">{
557
+ "success": true,
558
+ "data": {
559
+ "id": 1,
560
+ "name": "李四",
561
+ "email": "lisi@example.com",
562
+ "createdAt": "2024-01-01T00:00:00.000Z",
563
+ "updatedAt": "2024-01-02T00:00:00.000Z"
564
+ }
565
+ }</code></pre>
566
+ <h2>删除用户</h2>
567
+ <p>删除指定用户。</p>
568
+ <h3>请求</h3>
569
+ <pre><code class="language-http">DELETE /api/user/:id</code></pre>
570
+ <h3>路径参数</h3>
571
+ <table>
572
+ <thead>
573
+ <tr>
574
+ <th>参数</th>
575
+ <th>类型</th>
576
+ <th>说明</th>
577
+ </tr>
578
+ </thead>
579
+ <tbody>
580
+ <tr>
581
+ <td>id</td>
582
+ <td>number</td>
583
+ <td>用户ID</td>
584
+ </tr>
585
+ </tbody>
586
+ </table>
587
+ <h3>响应</h3>
588
+ <pre><code class="language-http">204 No Content</code></pre>
589
+ <h3>错误响应</h3>
590
+ <pre><code class="language-json">{
591
+ "success": false,
592
+ "message": "User not found"
593
+ }</code></pre>
594
+ </div>
595
+ </div>
596
+ </main>
597
+
598
+ <!-- Prism.js 代码高亮库 -->
599
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js"></script>
600
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
601
+
602
+ <!-- 文档内容配置 - 修改 docs-content.js 来更新导航菜单 -->
603
+ <script src="/docs/docs-content.js"></script>
604
+
605
+ <!-- 文档逻辑文件 - 修改 docs.js 来调整交互行为 -->
606
+ <script src="/docs/docs.js"></script>
607
+ </body>
608
+ </html>