├── .eslintignore
├── app
├── public
│ └── 绩效考核统计表 (1).xlsx
├── controller
│ ├── home.js
│ ├── simple.js
│ ├── complex.js
│ └── import.js
├── router.js
├── view
│ └── home.tpl
└── extend
│ └── helper.js
├── .eslintrc
├── config
├── plugin.js
└── config.default.js
├── .gitignore
├── .travis.yml
├── appveyor.yml
├── .autod.conf.js
├── test
└── app
│ └── controller
│ └── home.test.js
├── README.md
├── README.zh-CN.md
└── package.json
/.eslintignore:
--------------------------------------------------------------------------------
1 | coverage
2 |
--------------------------------------------------------------------------------
/app/public/绩效考核统计表 (1).xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wuwei9536/egg-exceljs/HEAD/app/public/绩效考核统计表 (1).xlsx
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "eslint-config-egg",
3 | "rules": {
4 | "linebreak-style": [0 ,"error", "windows"]
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/config/plugin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // had enabled by egg
4 | // exports.static = true;
5 | exports.nunjucks = {
6 | enable: true,
7 | package: 'egg-view-nunjucks',
8 | };
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | logs/
2 | npm-debug.log
3 | yarn-error.log
4 | node_modules/
5 | package-lock.json
6 | yarn.lock
7 | coverage/
8 | .idea/
9 | run/
10 | .DS_Store
11 | *.sw*
12 | *.un~
13 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 | node_js:
4 | - '8'
5 | install:
6 | - npm i npminstall && npminstall
7 | script:
8 | - npm run ci
9 | after_script:
10 | - npminstall codecov && codecov
11 |
--------------------------------------------------------------------------------
/app/controller/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class HomeController extends Controller {
6 | async index() {
7 | // this.ctx.body = 'hi, egg';
8 | await this.ctx.render('home.tpl', {});
9 | }
10 | }
11 |
12 | module.exports = HomeController;
13 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | environment:
2 | matrix:
3 | - nodejs_version: '8'
4 |
5 | install:
6 | - ps: Install-Product node $env:nodejs_version
7 | - npm i npminstall && node_modules\.bin\npminstall
8 |
9 | test_script:
10 | - node --version
11 | - npm --version
12 | - npm run test
13 |
14 | build: off
15 |
--------------------------------------------------------------------------------
/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @param {Egg.Application} app - egg application
5 | */
6 | module.exports = app => {
7 | const { router, controller } = app;
8 | router.get('/', controller.home.index);
9 | router.get('/simple', controller.simple.excel);
10 | router.get('/complex', controller.complex.excel);
11 | router.post('/import', controller.import.index);
12 | };
13 |
--------------------------------------------------------------------------------
/.autod.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | write: true,
5 | prefix: '^',
6 | plugin: 'autod-egg',
7 | test: [
8 | 'test',
9 | 'benchmark',
10 | ],
11 | dep: [
12 | 'egg',
13 | 'egg-scripts',
14 | ],
15 | devdep: [
16 | 'egg-ci',
17 | 'egg-bin',
18 | 'egg-mock',
19 | 'autod',
20 | 'autod-egg',
21 | 'eslint',
22 | 'eslint-config-egg',
23 | 'webstorm-disable-index',
24 | ],
25 | exclude: [
26 | './test/fixtures',
27 | './dist',
28 | ],
29 | };
30 |
31 |
--------------------------------------------------------------------------------
/test/app/controller/home.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { app, assert } = require('egg-mock/bootstrap');
4 |
5 | describe('test/app/controller/home.test.js', () => {
6 |
7 | it('should assert', function* () {
8 | const pkg = require('../../../package.json');
9 | assert(app.config.keys.startsWith(pkg.name));
10 |
11 | // const ctx = app.mockContext({});
12 | // yield ctx.service.xx();
13 | });
14 |
15 | it('should GET /', () => {
16 | return app.httpRequest()
17 | .get('/')
18 | .expect('hi, egg')
19 | .expect(200);
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # eggjs-exceljs
2 |
3 |
4 |
5 | ## QuickStart
6 |
7 |
8 |
9 | see [egg docs][egg] for more detail.
10 |
11 | ### Development
12 |
13 | ```bash
14 | $ npm i
15 | $ npm run dev
16 | $ open http://localhost:7001/
17 | ```
18 |
19 | ### Deploy
20 |
21 | ```bash
22 | $ npm start
23 | $ npm stop
24 | ```
25 |
26 | ### npm scripts
27 |
28 | - Use `npm run lint` to check code style.
29 | - Use `npm test` to run unit test.
30 | - Use `npm run autod` to auto detect dependencies upgrade, see [autod](https://www.npmjs.com/package/autod) for more detail.
31 |
32 |
33 | [egg]: https://eggjs.org
--------------------------------------------------------------------------------
/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | # eggjs-exceljs
2 |
3 |
4 |
5 | ## 快速入门
6 |
7 |
8 |
9 | 如需进一步了解,参见 [egg 文档][egg]。
10 |
11 | ### 本地开发
12 |
13 | ```bash
14 | $ npm i
15 | $ npm run dev
16 | $ open http://localhost:7001/
17 | ```
18 |
19 | ### 部署
20 |
21 | ```bash
22 | $ npm start
23 | $ npm stop
24 | ```
25 |
26 | ### 单元测试
27 |
28 | - [egg-bin] 内置了 [mocha], [thunk-mocha], [power-assert], [istanbul] 等框架,让你可以专注于写单元测试,无需理会配套工具。
29 | - 断言库非常推荐使用 [power-assert]。
30 | - 具体参见 [egg 文档 - 单元测试](https://eggjs.org/zh-cn/core/unittest)。
31 |
32 | ### 内置指令
33 |
34 | - 使用 `npm run lint` 来做代码风格检查。
35 | - 使用 `npm test` 来执行单元测试。
36 | - 使用 `npm run autod` 来自动检测依赖更新,详细参见 [autod](https://www.npmjs.com/package/autod) 。
37 |
38 |
39 | [egg]: https://eggjs.org
40 |
--------------------------------------------------------------------------------
/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | // const path = require('path');
3 | module.exports = appInfo => {
4 | const config = exports = {};
5 |
6 | config.security = {
7 | csrf: { enable: false },
8 | };
9 | config.multipart = {
10 | mode: 'file',
11 | fileExtensions: [
12 | '.xlsx',
13 | ],
14 | };
15 |
16 | config.view = {
17 | // root: [
18 | // path.join(appInfo.baseDir, 'app/view'),
19 | // ].join(','),
20 | defaultViewEngine: 'nunjucks',
21 | };
22 |
23 | // use for cookie sign key, should change to your own and keep security
24 | config.keys = appInfo.name + '_1548729941824_4568';
25 |
26 | // add your config here
27 | config.middleware = [];
28 |
29 | return config;
30 | };
31 |
--------------------------------------------------------------------------------
/app/controller/simple.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /* eslint-disable*/
3 | //一级表头适用
4 | exports.excel = async ctx => {
5 | // 请求数据地址
6 | let url = 'https://www.easy-mock.com/mock/5c46cad124390d27ad616890/api-node/selectRateList';
7 | // 请求数据参数
8 | let param = {
9 | dataType: 'json',
10 | // data: {
11 | // }
12 | };
13 |
14 | // t:title k:key w:width ==>表头
15 | let headers = [[
16 | { t: '姓名', k: 'userName', w: 20 },
17 | { t: '所属部门', k: 'deptName' },
18 | { t: '自评分', k: 'selfRate' },
19 | { t: 'learder评分', k: 'leaderRate' },
20 | { t: '绩效结果', k: 'rateResult' },
21 | ]];
22 |
23 | await ctx.helper.excelNew(url, param, headers, '绩效考核统计表', function (res) {
24 | //数据二次处理函数
25 | });
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/app/view/home.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 | 基于eggjs导入导出excel表格
4 |
5 |
6 | 基于eggjs导入导出excel表格
7 |
8 | {# 导出 #}
9 |
10 |
11 | {# 导入 #}
12 |
13 |
14 |
15 | {# fetch 方式 #}
16 |
17 |
18 | {# #}
19 |
20 |
21 |
22 | {# form表单提交方式 #}
23 |
28 | {# #}
29 |
30 |
31 |
48 |
49 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eggjs-exceljs",
3 | "version": "1.0.0",
4 | "description": "",
5 | "private": true,
6 | "dependencies": {
7 | "egg": "^2.2.1",
8 | "egg-scripts": "^2.5.0",
9 | "egg-view-nunjucks": "^2.2.0",
10 | "exceljs": "^1.7.0"
11 | },
12 | "devDependencies": {
13 | "autod": "^3.0.1",
14 | "autod-egg": "^1.0.0",
15 | "egg-bin": "^4.3.5",
16 | "egg-ci": "^1.8.0",
17 | "egg-mock": "^3.14.0",
18 | "eslint": "^4.11.0",
19 | "eslint-config-egg": "^6.0.0",
20 | "webstorm-disable-index": "^1.2.0"
21 | },
22 | "engines": {
23 | "node": ">=8.9.0"
24 | },
25 | "scripts": {
26 | "start": "egg-scripts start --daemon --title=egg-server-eggjs-exceljs",
27 | "stop": "egg-scripts stop --title=egg-server-eggjs-exceljs",
28 | "dev": "egg-bin dev",
29 | "debug": "egg-bin debug",
30 | "test": "npm run lint -- --fix && npm run test-local",
31 | "test-local": "egg-bin test",
32 | "cov": "egg-bin cov",
33 | "lint": "eslint .",
34 | "ci": "npm run lint && npm run cov",
35 | "autod": "autod"
36 | },
37 | "ci": {
38 | "version": "8"
39 | },
40 | "repository": {
41 | "type": "git",
42 | "url": ""
43 | },
44 | "author": "wien",
45 | "license": "MIT"
46 | }
47 |
--------------------------------------------------------------------------------
/app/controller/complex.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /* eslint-disable*/
3 | const Controller = require('egg').Controller;
4 |
5 | class ComplexController extends Controller {
6 | async excel(ctx) {
7 | // let req = ctx.helper.data(['strBeginTime', 'strEndTime', 'deptId']);
8 | // req.deptId = req.deptId || ctx.session.user.deptId;
9 |
10 | let headers = [[
11 | { t: '单位名称', f: 'deptName', w: 20, m1: 'A1', m2: 'A3', totalRowText: '合计' },
12 | { t: '办理身份证证件', m1: 'B1', m2: 'M1' },
13 | { t: '临时身份证证件', m1: 'N1', m2: 'O1' },
14 | { t: '总计', m1: 'P1', m2: 'R2' }
15 | ], [
16 | { t: '申领', m1: 'B2', m2: 'D2' },
17 | { t: '换领', m1: 'E2', m2: 'G2' },
18 | { t: '补领', m1: 'H2', m2: 'J2' },
19 | { t: '小计', m1: 'K2', m2: 'M2' },
20 | { t: '临时身份证', m1: 'N2', m2: 'O2' }
21 | ], [
22 | { t: '本地人数', f: 'slbdCount', totalRow: true },
23 | { t: '异地人数', f: 'slydCount', totalRow: true },
24 | { t: '金额', f: 'slJe', totalRow: true },
25 | { t: '本地人数', f: 'hlbdCount', totalRow: true },
26 | { t: '异地人数', f: 'hlydCount', totalRow: true },
27 | { t: '金额', f: 'hlJe', totalRow: true },
28 | { t: '本地人数', f: 'blbdCount', totalRow: true },
29 | { t: '异地人数', f: 'blydCount', totalRow: true },
30 | { t: '金额', f: 'blJe', totalRow: true },
31 | { t: '本地人数', f: 'xj_bdrs', totalRow: true },
32 | { t: '异地人数', f: 'xj_ydrs', totalRow: true },
33 | { t: '金额', f: 'xj_je', totalRow: true },
34 | { t: '人数', f: 'lsCount', totalRow: true },
35 | { t: '金额', f: 'lsJe', totalRow: true },
36 | { t: '本地人数', f: 'hj_bdrs', totalRow: true },
37 | { t: '异地人数', f: 'hj_ydrs', totalRow: true },
38 | { t: '金额', f: 'hj_je', totalRow: true }
39 | ]];
40 | await ctx.helper.excelNewComplex('https://www.baidu.com', 'req', headers, '身份证受理统计', function (res) {
41 | for (let i = 0, len = res.data.length; i < len; i++) {
42 | let r = res.data[i];
43 | r.xj_bdrs = r.slbdCount + r.hlbdCount + r.blbdCount;
44 | r.xj_ydrs = r.slydCount + r.hlydCount + r.blydCount;
45 | r.xj_je = r.slJe + r.hlJe + r.blJe;
46 | r.hj_bdrs = r.slbdCount + r.hlbdCount + r.blbdCount + r.lsCount;
47 | r.hj_ydrs = r.slydCount + r.hlydCount + r.blydCount;
48 | r.hj_je = r.slJe + r.hlJe + r.blJe + r.lsJe;
49 | }
50 | return res;
51 | });
52 | }
53 | }
54 |
55 | module.exports = ComplexController;
--------------------------------------------------------------------------------
/app/controller/import.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /* eslint-disable*/
3 | const Controller = require('egg').Controller;
4 | const Excel = require('exceljs');
5 | // const fs = require('fs');
6 | // const path = require('path');
7 |
8 | class submitController extends Controller {
9 | //适用于简单表格的导入,所以一般导入要先下载固定格式的excel表格才能正确解析
10 | async index() {
11 | const { ctx } = this;
12 | const file = ctx.request.files[0];
13 |
14 | // fs.exists(path.resolve(__dirname, '../public/绩效考核统计表 (1).xlsx') //绝对路径
15 | // , (exists) => {
16 | // console.log(exists ? 'it\'s there' : 'no passwd!');
17 | // });
18 |
19 | let dataArray = [];//最后得到的Json对象数组
20 | let workbook = new Excel.Workbook();
21 | await workbook.xlsx.readFile(file.filepath) //绝对路径
22 | .then(function () {
23 | let worksheet = workbook.getWorksheet(1);
24 | dataArray = changeRowsToDict(worksheet);
25 | console.log(JSON.stringify(dataArray));
26 | ctx.body = dataArray;
27 | // console.log('异步');
28 | });
29 |
30 | // console.log('同步');
31 |
32 | /* 将所有的行数据转换为json */
33 | function changeRowsToDict(worksheet) {
34 | let dataArray = [];
35 | let keys = [];
36 | worksheet.eachRow(function (row, rowNumber) {
37 | if (rowNumber == 1) {
38 | keys = row.values;
39 | }
40 | else {
41 | // method1 ===============
42 | // let rowDict = cellValueToDict(keys, row.values);
43 | // dataArray.push(rowDict);
44 | // method2 ===============
45 | let rowDict = cellValueToDict2(keys, row);
46 | dataArray.push(rowDict);
47 | }
48 | });
49 | return dataArray;
50 | }
51 |
52 | /* keys: {id,name,phone}, rowValue:每一行的值数组, 执行次数3次 */
53 | function cellValueToDict(keys, rowValue) {
54 | let rowDict = {};
55 | keys.forEach((value, index) => {
56 | rowDict[value] = rowValue[index];
57 | });
58 | return rowDict;
59 | }
60 |
61 | /* keys: {id,name,phone}, rowValue:每一行的值数组, 执行次数3次 */
62 | function cellValueToDict2(keys, row) {
63 | let data = {};
64 | row.eachCell({ includeEmpty: true }, function (cell, colNumber) {
65 | let value = cell.value;
66 | // if (typeof value == "object") value = value.text;
67 | data[keys[colNumber]] = value;
68 | });
69 | return data;
70 | }
71 | }
72 | }
73 |
74 | module.exports = submitController;
75 |
--------------------------------------------------------------------------------
/app/extend/helper.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable*/
2 | //simple
3 | /**
4 | * 请求接口得到数据并生成excel
5 | * 支持数据自定义 func
6 | * 支持数据字典
7 | * 支持日期
8 | * @param {string} url 接口地址:相对地址或者http开头完整地址
9 | * @param {object} param 请求数据参数
10 | * @param {Array} headers excel标题栏
11 | * @param {string} name 文件名称
12 | * @param {function} func 数据自定义函数
13 | */
14 |
15 | //complex
16 | /**
17 | * 请求接口得到数据并生成excel
18 | * 支持复杂表头(m1:合并单元格左上坐标;m2:合并单元格右下坐标)
19 | * 支持合计行 totalRowText totalRow
20 | * 支持数据自定义 func
21 | * 支持数据字典
22 | * 支持日期
23 | */
24 |
25 | const Excel = require('exceljs');
26 | module.exports = {
27 | //simple
28 | async excelNew(url, param, headers, name, func) {
29 | let columns = [];//exceljs要求的columns
30 | let titleRows = headers.length;//标题栏行数
31 |
32 | //处理表头
33 | for (let i = 0; i < titleRows; i++) {
34 | let row = headers[i];
35 | for (let j = 0, rlen = row.length; j < rlen; j++) {
36 | let col = row[j];
37 | let { k, t, w = 15 } = col;
38 | if (!k) continue;//不存在k则跳过
39 | col.style = { alignment: { vertical: 'middle', horizontal: 'center' } };
40 | col.header = t;
41 | col.key = k;
42 | col.width = w;
43 | columns.push(col);
44 | }
45 | }
46 |
47 | //请求并处理数据
48 | let result = await this.ctx.curl(url, param);
49 | // if(func) result = func(result);
50 |
51 | //生成excel 这一部门语法需看下exceljs
52 | let workbook = new Excel.Workbook();
53 | let sheet = workbook.addWorksheet('绩效考核统计表', { views: [{ xSplit: 1, ySplit: 1 }] });
54 | sheet.columns = columns;
55 | sheet.addRows(result.data.data)
56 |
57 | //处理样式、日期、字典项
58 | let that = this;
59 | sheet.eachRow(function (row, rowNumber) {
60 | //设置行高
61 | row.height = 25;
62 |
63 | row.eachCell({ includeEmpty: true }, function (cell, colNumber) {
64 | //设置边框 黑色 细实线
65 | let top = left = bottom = right = { style: 'thin', color: { argb: '000000' } };
66 | cell.border = { top, left, bottom, right };
67 |
68 | //设置标题部分为粗体
69 | if (rowNumber <= titleRows) { cell.font = { bold: true }; return; }
70 |
71 | //处理数据项里面的日期和字典
72 | let { type, dict } = columns[colNumber - 1];
73 | if (type && (cell.value || cell.value == 0)) return;//非日期、字典或值为空的直接返回
74 | switch (type) {
75 | case 'date': cell.value = that.parseDate(cell.value); break;
76 | case 'dict': cell.value = that.parseDict(cell.value.toString(), dict); break;
77 | }
78 |
79 | });
80 | });
81 |
82 | this.ctx.set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
83 | this.ctx.set('Content-Disposition', "attachment;filename*=UTF-8' '" + encodeURIComponent(name) + '.xlsx');
84 | this.ctx.body = await workbook.xlsx.writeBuffer();
85 | },
86 |
87 | // ------------------------------------------------------------------------------------------------------------------------
88 |
89 | //complex
90 | async excelNewComplex(url, req, headers, name, func) {
91 | let columns = [];//exceljs要求的columns
92 | let hjRow = {};//合计行
93 | let titleRows = headers.length;//标题栏行数
94 |
95 | //处理表头
96 | for (let i = 0; i < titleRows; i++) {
97 | let row = headers[i];
98 | for (let j = 0, rlen = row.length; j < rlen; j++) {
99 | let col = row[j];
100 | let { f, t, w = 15 } = col;
101 | if (!f) continue;//不存在f则跳过
102 |
103 | if (col.totalRow) hjRow[f] = true;
104 | if (col.totalRowText) hjRow[f] = col.totalRowText;
105 | col.style = { alignment: { vertical: 'middle', horizontal: 'center' } };
106 | col.header = t;
107 | col.key = f;
108 | col.width = w;
109 | columns.push(col);
110 | }
111 | }
112 |
113 | // const result = await this.post(url, req);//请求数据
114 | // let result = await this.ctx.curl(url);
115 | // let data = result.data;
116 | // if (func) data = func(data);
117 | let data = { "data": [] } //需要在这边自己适配数据,这边为空
118 |
119 | //处理合计行
120 | if (JSON.stringify(hjRow) != "{}") {
121 | let tr = {};
122 | for (let i = 0, len = data.data.length; i < len; i++) {
123 | let item = data.data[i];
124 | for (let key in item) {
125 | if (hjRow[key] === true) {
126 | tr[key] = (tr[key] || 0) + item[key];
127 | continue;
128 | }
129 | tr[key] = hjRow[key] || '';
130 | }
131 | }
132 | data.data.push(tr);
133 | }
134 |
135 | let workbook = new Excel.Workbook();
136 | let sheet = workbook.addWorksheet('My Sheet', { views: [{ xSplit: 1, ySplit: 1 }] });
137 | sheet.columns = columns;
138 | sheet.addRows(data.data);
139 |
140 | //处理复杂表头
141 | if (titleRows > 1) {
142 | for (let i = 1; i < titleRows; i++) sheet.spliceRows(1, 0, []);//头部插入空行
143 |
144 | for (let i = 0; i < titleRows; i++) {
145 | let row = headers[i];
146 | for (let j = 0, rlen = row.length; j < rlen; j++) {
147 | let col = row[j];
148 | if (!col.m1) continue;
149 |
150 | sheet.getCell(col.m1).value = col.t;
151 | sheet.mergeCells(col.m1 + ":" + col.m2);
152 | }
153 | }
154 | }
155 |
156 | //处理样式、日期、字典项
157 | let that = this;
158 | sheet.eachRow(function (row, rowNumber) {
159 | //设置行高
160 | row.height = 25;
161 |
162 | row.eachCell({ includeEmpty: true }, function (cell, colNumber) {
163 | //设置边框 黑色 细实线
164 | let top = left = bottom = right = { style: 'thin', color: { argb: '000000' } };
165 | cell.border = { top, left, bottom, right };
166 |
167 | //设置标题部分为粗体
168 | if (rowNumber <= titleRows) { cell.font = { bold: true }; return; }
169 |
170 | //处理数据项里面的日期和字典
171 | let { type, dict } = columns[colNumber - 1];
172 | if (type && (cell.value || cell.value == 0)) return;//非日期、字典或值为空的直接返回
173 | switch (type) {
174 | case 'date': cell.value = that.parseDate(cell.value); break;
175 | case 'dict': cell.value = that.parseDict(cell.value.toString(), dict); break;
176 | }
177 |
178 | });
179 | });
180 |
181 | this.ctx.set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
182 | this.ctx.set('Content-Disposition', "attachment;filename*=UTF-8" + encodeURIComponent(name) + '.xlsx');
183 | this.ctx.body = await workbook.xlsx.writeBuffer();
184 | },
185 | };
186 |
187 |
--------------------------------------------------------------------------------