miolo 0.0.9 → 0.0.13
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/config/defaults.js +5 -2
- package/lib/logger/index.js +2 -2
- package/lib/server/index.js +11 -2
- package/lib/server/middleware/auth/passport.js +24 -17
- package/lib/server/middleware/{catcher.js → catcher/index.js} +14 -6
- package/lib/server/middleware/extra.js +34 -0
- package/package.json +1 -1
- package/src/config/defaults.js +6 -3
- package/src/logger/index.js +3 -3
- package/src/server/index.js +11 -2
- package/src/server/middleware/auth/passport.js +21 -20
- package/src/server/middleware/{catcher.js → catcher/index.js} +12 -6
- package/src/server/middleware/extra.js +18 -0
package/lib/config/defaults.js
CHANGED
|
@@ -198,7 +198,10 @@ module.exports = {
|
|
|
198
198
|
// // auth=> done(null, user) noauth=> done(null, false, {message: ''}) err=> done(error, null)
|
|
199
199
|
// url_login : '/login',
|
|
200
200
|
// url_logout: '/logout',
|
|
201
|
-
//
|
|
201
|
+
// url_login_redirect: undefined
|
|
202
|
+
// url_logout_redirect: '/'
|
|
202
203
|
//}
|
|
203
|
-
}
|
|
204
|
+
},
|
|
205
|
+
middlewares: [// (ctx) => {}
|
|
206
|
+
]
|
|
204
207
|
};
|
package/lib/logger/index.js
CHANGED
|
@@ -24,8 +24,8 @@ var init_logger = (config, emailer) => {
|
|
|
24
24
|
silly: _farrapaColors.gray,
|
|
25
25
|
debug: _farrapaColors.magenta,
|
|
26
26
|
verbose: _farrapaColors.cyan,
|
|
27
|
-
info: _farrapaColors.
|
|
28
|
-
warn: _farrapaColors.
|
|
27
|
+
info: _farrapaColors.yellow,
|
|
28
|
+
warn: _farrapaColors.red_light,
|
|
29
29
|
error: _farrapaColors.red
|
|
30
30
|
};
|
|
31
31
|
var myFormat = printf(info => {
|
package/lib/server/index.js
CHANGED
|
@@ -15,6 +15,8 @@ var _logger = require("../logger");
|
|
|
15
15
|
|
|
16
16
|
var _cron = require("./engines/cron");
|
|
17
17
|
|
|
18
|
+
var _conn = require("../db/conn");
|
|
19
|
+
|
|
18
20
|
var _context = require("./middleware/context");
|
|
19
21
|
|
|
20
22
|
var _body = require("./middleware/body");
|
|
@@ -23,7 +25,7 @@ var _catcher = require("./middleware/catcher");
|
|
|
23
25
|
|
|
24
26
|
var _static = require("./middleware/static");
|
|
25
27
|
|
|
26
|
-
var
|
|
28
|
+
var _extra = require("./middleware/extra");
|
|
27
29
|
|
|
28
30
|
var _request = require("./middleware/request");
|
|
29
31
|
|
|
@@ -112,7 +114,14 @@ function _miolo() {
|
|
|
112
114
|
} // Socket.io
|
|
113
115
|
// const io= init_socket(logger)
|
|
114
116
|
// io.attach(app)
|
|
115
|
-
//
|
|
117
|
+
// extra middlewares
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
var extra_middlewares = config === null || config === void 0 ? void 0 : config.middlewares;
|
|
121
|
+
|
|
122
|
+
if (extra_middlewares) {
|
|
123
|
+
(0, _extra.init_extra_middlewares)(app, extra_middlewares);
|
|
124
|
+
} // Middleware for html render
|
|
116
125
|
|
|
117
126
|
|
|
118
127
|
if (render == undefined || render.html != undefined) {
|
|
@@ -40,14 +40,16 @@ var init_passport_auth_middleware = (app, options) => {
|
|
|
40
40
|
local_auth_user,
|
|
41
41
|
url_login,
|
|
42
42
|
url_logout,
|
|
43
|
+
url_login_redirect,
|
|
43
44
|
url_logout_redirect
|
|
44
45
|
} = options; //const local_options = {}
|
|
46
|
+
// fallback funcs
|
|
45
47
|
|
|
46
48
|
var get_user_id_f = get_user_id || def_get_user_id;
|
|
47
49
|
var find_user_by_id_f = find_user_by_id || def_find_user_by_id;
|
|
48
50
|
var local_auth_user_f = local_auth_user || def_local_auth_user;
|
|
49
51
|
var url_login_f = url_login || '/login';
|
|
50
|
-
var url_logout_f = url_logout || '/logout';
|
|
52
|
+
var url_logout_f = url_logout || '/logout'; // init passport
|
|
51
53
|
|
|
52
54
|
var serialize_user = (user, done) => {
|
|
53
55
|
process.nextTick(function () {
|
|
@@ -68,20 +70,10 @@ var init_passport_auth_middleware = (app, options) => {
|
|
|
68
70
|
passport.deserializeUser(deserialize_user);
|
|
69
71
|
passport.use(local_strategy);
|
|
70
72
|
app.use(passport.initialize());
|
|
71
|
-
app.use(passport.session());
|
|
72
|
-
var login_router = new Router();
|
|
73
|
-
/*login_router.post(url_login_f, passport.authenticate('local', {
|
|
74
|
-
successRedirect: '/',
|
|
75
|
-
failureRedirect: '/', // /login
|
|
76
|
-
//failureMessage: true
|
|
77
|
-
}))*/
|
|
73
|
+
app.use(passport.session()); // handle auth routes
|
|
78
74
|
|
|
79
|
-
|
|
75
|
+
var handleLogIn = (ctx, next) => {
|
|
80
76
|
return passport.authenticate('local', function (err, user, info, status) {
|
|
81
|
-
// console.log('[PASS AUTH] Error', err)
|
|
82
|
-
// console.log('[PASS AUTH] User', user)
|
|
83
|
-
// console.log('[PASS AUTH] Info', info)
|
|
84
|
-
// console.log('[PASS AUTH] Status', status)
|
|
85
77
|
if (user === false) {
|
|
86
78
|
ctx.body = {
|
|
87
79
|
success: false,
|
|
@@ -97,14 +89,23 @@ var init_passport_auth_middleware = (app, options) => {
|
|
|
97
89
|
user: user,
|
|
98
90
|
authenticated: true
|
|
99
91
|
};
|
|
92
|
+
|
|
93
|
+
if (url_login_redirect != undefined) {
|
|
94
|
+
ctx.redirect(url_login_redirect);
|
|
95
|
+
}
|
|
96
|
+
|
|
100
97
|
return ctx.login(user);
|
|
101
98
|
}
|
|
102
99
|
})(ctx);
|
|
103
|
-
}
|
|
104
|
-
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
var handleLogOut = /*#__PURE__*/function () {
|
|
105
103
|
var _ref = _asyncToGenerator(function* (ctx) {
|
|
106
104
|
if (ctx.isAuthenticated()) {
|
|
107
105
|
ctx.logout();
|
|
106
|
+
ctx.body = {
|
|
107
|
+
success: true
|
|
108
|
+
};
|
|
108
109
|
|
|
109
110
|
if (url_logout_redirect != undefined) {
|
|
110
111
|
ctx.redirect(url_logout_redirect);
|
|
@@ -117,10 +118,16 @@ var init_passport_auth_middleware = (app, options) => {
|
|
|
117
118
|
}
|
|
118
119
|
});
|
|
119
120
|
|
|
120
|
-
return function (_x) {
|
|
121
|
+
return function handleLogOut(_x) {
|
|
121
122
|
return _ref.apply(this, arguments);
|
|
122
123
|
};
|
|
123
|
-
}()
|
|
124
|
+
}(); // Init the router
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
var login_router = new Router();
|
|
128
|
+
login_router.post(url_login_f, handleLogIn);
|
|
129
|
+
login_router.get(url_logout_f, handleLogOut);
|
|
130
|
+
login_router.post(url_logout_f, handleLogOut);
|
|
124
131
|
app.use(login_router.routes());
|
|
125
132
|
};
|
|
126
133
|
|
|
@@ -13,6 +13,8 @@ function _asyncToGenerator(fn) { return function () { var self = this, args = ar
|
|
|
13
13
|
* Middleware for catching errors thrown in routes
|
|
14
14
|
* @param ctx
|
|
15
15
|
*/
|
|
16
|
+
var _ONLY_WARN = [401];
|
|
17
|
+
|
|
16
18
|
function init_catcher_middleware(app, logger) {
|
|
17
19
|
function catcher_middleware(_x) {
|
|
18
20
|
return _catcher_middleware.apply(this, arguments);
|
|
@@ -20,18 +22,23 @@ function init_catcher_middleware(app, logger) {
|
|
|
20
22
|
|
|
21
23
|
function _catcher_middleware() {
|
|
22
24
|
_catcher_middleware = _asyncToGenerator(function* (err) {
|
|
23
|
-
if (!err) return;
|
|
24
|
-
|
|
25
|
+
if (!err) return; // Get HTML status code
|
|
26
|
+
|
|
25
27
|
var status = err.status || 400;
|
|
26
28
|
var type = this.accepts(['text', 'json', 'html']);
|
|
27
29
|
|
|
28
30
|
if (!type) {
|
|
29
31
|
status = 406;
|
|
30
32
|
err.message = 'Unsupported type';
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (typeof status != 'number') {
|
|
33
|
+
} else if (typeof status != 'number') {
|
|
34
34
|
status = 500;
|
|
35
|
+
} // Log the error depending on the status
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
if (_ONLY_WARN.indexOf(status) >= 0) {
|
|
39
|
+
logger.warn("".concat(this.method, " ").concat(this.url, " - ").concat(status, ": ").concat(err.message));
|
|
40
|
+
} else {
|
|
41
|
+
logger.error(err);
|
|
35
42
|
} // Nothing we can do here other than delegate to the app-level handler and log.
|
|
36
43
|
|
|
37
44
|
|
|
@@ -39,7 +46,8 @@ function init_catcher_middleware(app, logger) {
|
|
|
39
46
|
logger.debug('headers were already sent, returning early');
|
|
40
47
|
err.headerSent = true;
|
|
41
48
|
return;
|
|
42
|
-
}
|
|
49
|
+
} // Prepare response a bit
|
|
50
|
+
|
|
43
51
|
|
|
44
52
|
this.type = 'json';
|
|
45
53
|
this.status = status;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.init_extra_middlewares = void 0;
|
|
7
|
+
|
|
8
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
9
|
+
|
|
10
|
+
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
11
|
+
|
|
12
|
+
var init_extra_middlewares = (app, middlewares) => {
|
|
13
|
+
if (middlewares == undefined || middlewares.length == 0) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
middlewares.map(midw => {
|
|
18
|
+
function extra_middleware(_x, _x2) {
|
|
19
|
+
return _extra_middleware.apply(this, arguments);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function _extra_middleware() {
|
|
23
|
+
_extra_middleware = _asyncToGenerator(function* (ctx, next) {
|
|
24
|
+
midw(ctx);
|
|
25
|
+
yield next();
|
|
26
|
+
});
|
|
27
|
+
return _extra_middleware.apply(this, arguments);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
app.use(extra_middleware);
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
exports.init_extra_middlewares = init_extra_middlewares;
|
package/package.json
CHANGED
package/src/config/defaults.js
CHANGED
|
@@ -196,9 +196,12 @@ module.exports= {
|
|
|
196
196
|
// // auth=> done(null, user) noauth=> done(null, false, {message: ''}) err=> done(error, null)
|
|
197
197
|
// url_login : '/login',
|
|
198
198
|
// url_logout: '/logout',
|
|
199
|
-
//
|
|
199
|
+
// url_login_redirect: undefined
|
|
200
|
+
// url_logout_redirect: '/'
|
|
200
201
|
//}
|
|
201
|
-
}
|
|
202
|
-
|
|
202
|
+
},
|
|
203
|
+
middlewares: [
|
|
204
|
+
// (ctx) => {}
|
|
205
|
+
]
|
|
203
206
|
};
|
|
204
207
|
|
package/src/logger/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { red,
|
|
1
|
+
import { red, cyan, magenta, yellow, gray, red_light } from 'farrapa-colors'
|
|
2
2
|
/* https://github.com/winstonjs/winston/issues/925 */
|
|
3
3
|
/* https://github.com/winstonjs/winston/issues/287 */
|
|
4
4
|
const { createLogger, format, transports } = require('winston')
|
|
@@ -10,8 +10,8 @@ const init_logger = (config, emailer) => {
|
|
|
10
10
|
silly : gray,
|
|
11
11
|
debug : magenta,
|
|
12
12
|
verbose: cyan,
|
|
13
|
-
info :
|
|
14
|
-
warn :
|
|
13
|
+
info : yellow,
|
|
14
|
+
warn : red_light,
|
|
15
15
|
error : red
|
|
16
16
|
}
|
|
17
17
|
|
package/src/server/index.js
CHANGED
|
@@ -5,17 +5,19 @@ import { init_logger } from 'src/logger'
|
|
|
5
5
|
import { init_cron } from './engines/cron'
|
|
6
6
|
// import {init_socket} from './engines/socket'
|
|
7
7
|
|
|
8
|
+
import { init_db_connection } from 'src/db/conn'
|
|
9
|
+
|
|
8
10
|
import { init_context_middleware } from './middleware/context'
|
|
9
11
|
import { init_body_middleware } from './middleware/body'
|
|
10
12
|
import { init_catcher_middleware } from './middleware/catcher'
|
|
11
13
|
import { init_static_middleware } from './middleware/static'
|
|
12
|
-
|
|
13
|
-
import { init_db_connection } from 'src/db/conn'
|
|
14
|
+
import { init_extra_middlewares } from './middleware/extra'
|
|
14
15
|
|
|
15
16
|
import { init_request_middleware } from './middleware/request'
|
|
16
17
|
import { init_session_middleware } from './middleware/session'
|
|
17
18
|
import { init_route_robots } from './routes/robots'
|
|
18
19
|
import { init_route_catch_js_error} from './routes/catch_js_error'
|
|
20
|
+
|
|
19
21
|
import { init_route_html_render} from './routes/html_render'
|
|
20
22
|
|
|
21
23
|
async function miolo(sconfig, render, callback) {
|
|
@@ -34,6 +36,7 @@ async function miolo(sconfig, render, callback) {
|
|
|
34
36
|
|
|
35
37
|
// Assign miolo stuff to ctx
|
|
36
38
|
init_context_middleware(app, config, logger, emailer, conn)
|
|
39
|
+
|
|
37
40
|
// Compress and body parser
|
|
38
41
|
init_body_middleware(app)
|
|
39
42
|
|
|
@@ -82,6 +85,12 @@ async function miolo(sconfig, render, callback) {
|
|
|
82
85
|
// const io= init_socket(logger)
|
|
83
86
|
// io.attach(app)
|
|
84
87
|
|
|
88
|
+
// extra middlewares
|
|
89
|
+
const extra_middlewares= config?.middlewares
|
|
90
|
+
if (extra_middlewares) {
|
|
91
|
+
init_extra_middlewares(app, extra_middlewares)
|
|
92
|
+
}
|
|
93
|
+
|
|
85
94
|
// Middleware for html render
|
|
86
95
|
if (render==undefined || render.html!=undefined) {
|
|
87
96
|
init_route_html_render(app, render?.html)
|
|
@@ -25,18 +25,18 @@ const def_local_auth_user = (username, password, done) => {
|
|
|
25
25
|
|
|
26
26
|
const init_passport_auth_middleware = ( app, options ) => {
|
|
27
27
|
const {get_user_id, find_user_by_id, local_auth_user,
|
|
28
|
-
url_login, url_logout, url_logout_redirect} = options
|
|
28
|
+
url_login, url_logout, url_login_redirect, url_logout_redirect} = options
|
|
29
29
|
|
|
30
30
|
//const local_options = {}
|
|
31
31
|
|
|
32
|
+
// fallback funcs
|
|
32
33
|
const get_user_id_f = get_user_id || def_get_user_id
|
|
33
34
|
const find_user_by_id_f = find_user_by_id || def_find_user_by_id
|
|
34
35
|
const local_auth_user_f = local_auth_user || def_local_auth_user
|
|
35
36
|
const url_login_f = url_login || '/login'
|
|
36
37
|
const url_logout_f = url_logout || '/logout'
|
|
37
|
-
|
|
38
|
-
|
|
39
38
|
|
|
39
|
+
// init passport
|
|
40
40
|
const serialize_user = (user, done) => {
|
|
41
41
|
process.nextTick(function() {
|
|
42
42
|
get_user_id_f(user, done)
|
|
@@ -53,7 +53,6 @@ const init_passport_auth_middleware = ( app, options ) => {
|
|
|
53
53
|
(username, password, done) => {
|
|
54
54
|
local_auth_user_f(username, password, done)
|
|
55
55
|
})
|
|
56
|
-
|
|
57
56
|
|
|
58
57
|
passport.serializeUser(serialize_user)
|
|
59
58
|
passport.deserializeUser(deserialize_user)
|
|
@@ -61,22 +60,11 @@ const init_passport_auth_middleware = ( app, options ) => {
|
|
|
61
60
|
|
|
62
61
|
app.use(passport.initialize())
|
|
63
62
|
app.use(passport.session())
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const login_router = new Router()
|
|
67
|
-
/*login_router.post(url_login_f, passport.authenticate('local', {
|
|
68
|
-
successRedirect: '/',
|
|
69
|
-
failureRedirect: '/', // /login
|
|
70
|
-
//failureMessage: true
|
|
71
|
-
}))*/
|
|
72
63
|
|
|
73
|
-
login_router.post(url_login_f, function(ctx, next) {
|
|
74
64
|
|
|
65
|
+
// handle auth routes
|
|
66
|
+
const handleLogIn = (ctx, next) => {
|
|
75
67
|
return passport.authenticate('local', function(err, user, info, status) {
|
|
76
|
-
// console.log('[PASS AUTH] Error', err)
|
|
77
|
-
// console.log('[PASS AUTH] User', user)
|
|
78
|
-
// console.log('[PASS AUTH] Info', info)
|
|
79
|
-
// console.log('[PASS AUTH] Status', status)
|
|
80
68
|
if (user === false) {
|
|
81
69
|
ctx.body = {
|
|
82
70
|
success: false,
|
|
@@ -92,14 +80,21 @@ const init_passport_auth_middleware = ( app, options ) => {
|
|
|
92
80
|
user : user,
|
|
93
81
|
authenticated: true
|
|
94
82
|
}
|
|
83
|
+
if (url_login_redirect!=undefined) {
|
|
84
|
+
ctx.redirect(url_login_redirect)
|
|
85
|
+
}
|
|
86
|
+
|
|
95
87
|
return ctx.login(user)
|
|
96
88
|
}
|
|
97
89
|
})(ctx)
|
|
98
|
-
}
|
|
90
|
+
}
|
|
99
91
|
|
|
100
|
-
|
|
92
|
+
const handleLogOut = async (ctx) => {
|
|
101
93
|
if (ctx.isAuthenticated()) {
|
|
102
94
|
ctx.logout()
|
|
95
|
+
ctx.body = {
|
|
96
|
+
success: true
|
|
97
|
+
}
|
|
103
98
|
if (url_logout_redirect!=undefined) {
|
|
104
99
|
ctx.redirect(url_logout_redirect)
|
|
105
100
|
}
|
|
@@ -109,7 +104,13 @@ const init_passport_auth_middleware = ( app, options ) => {
|
|
|
109
104
|
}
|
|
110
105
|
ctx.throw(401)
|
|
111
106
|
}
|
|
112
|
-
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Init the router
|
|
110
|
+
const login_router = new Router()
|
|
111
|
+
login_router.post(url_login_f, handleLogIn)
|
|
112
|
+
login_router.get (url_logout_f, handleLogOut)
|
|
113
|
+
login_router.post(url_logout_f, handleLogOut)
|
|
113
114
|
|
|
114
115
|
app.use(login_router.routes())
|
|
115
116
|
}
|
|
@@ -3,24 +3,30 @@
|
|
|
3
3
|
* @param ctx
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
const _ONLY_WARN= [401]
|
|
7
|
+
|
|
6
8
|
function init_catcher_middleware(app, logger) {
|
|
7
9
|
|
|
8
10
|
async function catcher_middleware(err) {
|
|
9
11
|
|
|
10
12
|
if (!err) return
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
// Get HTML status code
|
|
14
15
|
let status = err.status || 400
|
|
15
|
-
|
|
16
16
|
const type = this.accepts(['text', 'json', 'html'])
|
|
17
17
|
if (!type) {
|
|
18
18
|
status = 406;
|
|
19
19
|
err.message = 'Unsupported type'
|
|
20
|
+
} else if (typeof status != 'number') {
|
|
21
|
+
status = 500
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
// Log the error depending on the status
|
|
25
|
+
|
|
26
|
+
if (_ONLY_WARN.indexOf(status)>=0) {
|
|
27
|
+
logger.warn(`${this.method} ${this.url} - ${status}: ${err.message}`)
|
|
28
|
+
} else {
|
|
29
|
+
logger.error(err)
|
|
24
30
|
}
|
|
25
31
|
|
|
26
32
|
// Nothing we can do here other than delegate to the app-level handler and log.
|
|
@@ -30,9 +36,9 @@ function init_catcher_middleware(app, logger) {
|
|
|
30
36
|
return
|
|
31
37
|
}
|
|
32
38
|
|
|
39
|
+
// Prepare response a bit
|
|
33
40
|
this.type = 'json'
|
|
34
41
|
this.status = status
|
|
35
|
-
|
|
36
42
|
this.body = JSON.stringify(this.body || '', null, 2)
|
|
37
43
|
this.length = Buffer.byteLength(this.body)
|
|
38
44
|
this.res.end(this.body)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
|
|
2
|
+
const init_extra_middlewares = ( app, middlewares ) => {
|
|
3
|
+
if (middlewares==undefined || middlewares.length==0) {
|
|
4
|
+
return
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
middlewares.map(midw => {
|
|
8
|
+
|
|
9
|
+
async function extra_middleware(ctx, next) {
|
|
10
|
+
midw(ctx)
|
|
11
|
+
await next()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
app.use(extra_middleware)
|
|
15
|
+
})
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export { init_extra_middlewares }
|