@mavogel/awscdk-rootmail 0.1.10 → 0.1.11

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/.jsii CHANGED
@@ -14,7 +14,7 @@
14
14
  "@aws-sdk/client-ses": "^3.1146.0",
15
15
  "@aws-sdk/client-ssm": "^3.1146.0",
16
16
  "cdk-nag": "^3.0.1",
17
- "mailparser": "^3.9.34",
17
+ "mailparser": "^3.9.35",
18
18
  "uuid": "^14.0.2"
19
19
  },
20
20
  "dependencies": {
@@ -9620,6 +9620,6 @@
9620
9620
  "symbolId": "src/ses-receive:SESReceiveProps"
9621
9621
  }
9622
9622
  },
9623
- "version": "0.1.10",
9624
- "fingerprint": "3iQgrp/Q3YCvLBcFIlM9R3jAmqSe7PUyd1YE87h9qVo="
9623
+ "version": "0.1.11",
9624
+ "fingerprint": "A35Mzh9zc6iNnBMgqMgcmVc+ABej3IW3YJ+kDqnT30Y="
9625
9625
  }
package/lib/rootmail.js CHANGED
@@ -11,7 +11,7 @@ const ses_receive_1 = require("./ses-receive");
11
11
  * Rootmail construct
12
12
  */
13
13
  class Rootmail extends constructs_1.Construct {
14
- static [JSII_RTTI_SYMBOL_1] = { fqn: "@mavogel/awscdk-rootmail.Rootmail", version: "0.1.10" };
14
+ static [JSII_RTTI_SYMBOL_1] = { fqn: "@mavogel/awscdk-rootmail.Rootmail", version: "0.1.11" };
15
15
  /**
16
16
  * The name parameter in SSM to store the domain name server.
17
17
  */
@@ -11,7 +11,7 @@ const ses_receipt_ruleset_activation_1 = require("./ses-receipt-ruleset-activati
11
11
  * SES Receive construct
12
12
  */
13
13
  class SESReceive extends constructs_1.Construct {
14
- static [JSII_RTTI_SYMBOL_1] = { fqn: "@mavogel/awscdk-rootmail.SESReceive", version: "0.1.10" };
14
+ static [JSII_RTTI_SYMBOL_1] = { fqn: "@mavogel/awscdk-rootmail.SESReceive", version: "0.1.11" };
15
15
  constructor(scope, id, props) {
16
16
  super(scope, id);
17
17
  const filteredEmailSubjects = props.filteredEmailSubjects || [];
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zone-eu/mailsplit",
3
- "version": "5.4.19",
3
+ "version": "5.4.20",
4
4
  "description": "Split email messages into an object stream",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -15,8 +15,8 @@
15
15
  "author": "Andris Reinman",
16
16
  "license": "(MIT OR EUPL-1.1+)",
17
17
  "dependencies": {
18
- "libbase64": "1.3.1",
19
- "libmime": "5.4.6",
18
+ "libbase64": "1.3.2",
19
+ "libmime": "5.4.7",
20
20
  "libqp": "2.1.2"
21
21
  },
22
22
  "devDependencies": {
@@ -25,7 +25,7 @@
25
25
  "@types/grunt": "0.4.32",
26
26
  "@types/libmime": "5.3.0",
27
27
  "@types/libqp": "1.1.3",
28
- "@types/node": "26.6.3",
28
+ "@types/node": "26.6.4",
29
29
  "eslint": "8.29.0",
30
30
  "eslint-config-nodemailer": "1.2.0",
31
31
  "eslint-config-prettier": "9.1.0",
@@ -1,4 +1,4 @@
1
- # he [![Build status](https://travis-ci.org/mathiasbynens/he.svg?branch=master)](https://travis-ci.org/mathiasbynens/he) [![Code coverage status](https://codecov.io/github/mathiasbynens/he/coverage.svg?branch=master)](https://codecov.io/github/mathiasbynens/he?branch=master) [![Dependency status](https://gemnasium.com/mathiasbynens/he.svg)](https://gemnasium.com/mathiasbynens/he)
1
+ # he [![Test status](https://github.com/mathiasbynens/he/actions/workflows/test.yml/badge.svg)](https://github.com/mathiasbynens/he/actions/workflows/test.yml) [![he on npm](https://img.shields.io/npm/v/he)](https://www.npmjs.com/package/he)
2
2
 
3
3
  _he_ (for “HTML entities”) is a robust HTML entity encoder/decoder written in JavaScript. It supports [all standardized named character references as per HTML](https://html.spec.whatwg.org/multipage/syntax.html#named-character-references), handles [ambiguous ampersands](https://mathiasbynens.be/notes/ambiguous-ampersands) and other edge cases [just like a browser would](https://html.spec.whatwg.org/multipage/syntax.html#tokenizing-character-references), has an extensive test suite, and — contrary to many other JavaScript solutions — _he_ handles astral Unicode symbols just fine. [An online demo is available.](https://mothereff.in/html-entities)
4
4
 
@@ -10,58 +10,26 @@ Via [npm](https://www.npmjs.com/):
10
10
  npm install he
11
11
  ```
12
12
 
13
- Via [Bower](http://bower.io/):
14
-
15
- ```bash
16
- bower install he
17
- ```
18
-
19
- Via [Component](https://github.com/component/component):
20
-
21
- ```bash
22
- component install mathiasbynens/he
23
- ```
24
-
25
- In a browser:
26
-
27
- ```html
28
- <script src="he.js"></script>
29
- ```
30
-
31
- In [Node.js](https://nodejs.org/), [io.js](https://iojs.org/), [Narwhal](http://narwhaljs.org/), and [RingoJS](http://ringojs.org/):
13
+ _he_ is published as an ECMAScript module with named exports:
32
14
 
33
15
  ```js
34
- var he = require('he');
16
+ import { decode, encode, escape, unescape } from 'he';
17
+ // Or, to use the `he.*` style shown in the examples below:
18
+ import * as he from 'he';
35
19
  ```
36
20
 
37
- In [Rhino](http://www.mozilla.org/rhino/):
21
+ In a browser, using a `<script type="module">` and a path to the package’s `src/he.mjs`:
38
22
 
39
- ```js
40
- load('he.js');
23
+ ```html
24
+ <script type="module">
25
+ import * as he from './node_modules/he/src/he.mjs';
26
+ </script>
41
27
  ```
42
28
 
43
- Using an AMD loader like [RequireJS](http://requirejs.org/):
44
-
45
- ```js
46
- require(
47
- {
48
- 'paths': {
49
- 'he': 'path/to/he'
50
- }
51
- },
52
- ['he'],
53
- function(he) {
54
- console.log(he);
55
- }
56
- );
57
- ```
29
+ In CommonJS code on Node.js versions that support [`require(esm)`](https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require), `require('he')` returns the module namespace object, so `require('he').encode(…)` works as well.
58
30
 
59
31
  ## API
60
32
 
61
- ### `he.version`
62
-
63
- A string representing the semantic version number.
64
-
65
33
  ### `he.encode(text, options)`
66
34
 
67
35
  This function takes a string of text and encodes (by default) any symbols that aren’t printable ASCII symbols and `&`, `<`, `>`, `"`, `'`, and `` ` ``, replacing them with character references.
@@ -95,13 +63,13 @@ he.encode('foo © bar ≠ baz 𝌆 qux');
95
63
 
96
64
  // Passing an `options` object to `encode`, to explicitly disallow named references:
97
65
  he.encode('foo © bar ≠ baz 𝌆 qux', {
98
- 'useNamedReferences': false
66
+ useNamedReferences: false,
99
67
  });
100
68
  // → 'foo &#xA9; bar &#x2260; baz &#x1D306; qux'
101
69
 
102
70
  // Passing an `options` object to `encode`, to explicitly allow named references:
103
71
  he.encode('foo © bar ≠ baz 𝌆 qux', {
104
- 'useNamedReferences': true
72
+ useNamedReferences: true,
105
73
  });
106
74
  // → 'foo &copy; bar &ne; baz &#x1D306; qux'
107
75
  ```
@@ -117,20 +85,20 @@ he.encode('foo © bar ≠ baz 𝌆 qux');
117
85
 
118
86
  // Passing an `options` object to `encode`, to explicitly disable decimal escapes:
119
87
  he.encode('foo © bar ≠ baz 𝌆 qux', {
120
- 'decimal': false
88
+ decimal: false,
121
89
  });
122
90
  // → 'foo &#xA9; bar &#x2260; baz &#x1D306; qux'
123
91
 
124
92
  // Passing an `options` object to `encode`, to explicitly enable decimal escapes:
125
93
  he.encode('foo © bar ≠ baz 𝌆 qux', {
126
- 'decimal': true
94
+ decimal: true,
127
95
  });
128
96
  // → 'foo &#169; bar &#8800; baz &#119558; qux'
129
97
 
130
98
  // Passing an `options` object to `encode`, to explicitly allow named references and decimal escapes:
131
99
  he.encode('foo © bar ≠ baz 𝌆 qux', {
132
- 'useNamedReferences': true,
133
- 'decimal': true
100
+ useNamedReferences: true,
101
+ decimal: true,
134
102
  });
135
103
  // → 'foo &copy; bar &ne; baz &#119558; qux'
136
104
  ```
@@ -146,14 +114,14 @@ he.encode('foo © bar ≠ baz 𝌆 qux');
146
114
 
147
115
  // Passing an `options` object to `encode`, to explicitly encode all symbols:
148
116
  he.encode('foo © bar ≠ baz 𝌆 qux', {
149
- 'encodeEverything': true
117
+ encodeEverything: true,
150
118
  });
151
119
  // → '&#x66;&#x6F;&#x6F;&#x20;&#xA9;&#x20;&#x62;&#x61;&#x72;&#x20;&#x2260;&#x20;&#x62;&#x61;&#x7A;&#x20;&#x1D306;&#x20;&#x71;&#x75;&#x78;'
152
120
 
153
121
  // This setting can be combined with the `useNamedReferences` option:
154
122
  he.encode('foo © bar ≠ baz 𝌆 qux', {
155
- 'encodeEverything': true,
156
- 'useNamedReferences': true
123
+ encodeEverything: true,
124
+ useNamedReferences: true,
157
125
  });
158
126
  // → '&#x66;&#x6F;&#x6F;&#x20;&copy;&#x20;&#x62;&#x61;&#x72;&#x20;&ne;&#x20;&#x62;&#x61;&#x7A;&#x20;&#x1D306;&#x20;&#x71;&#x75;&#x78;'
159
127
  ```
@@ -169,13 +137,13 @@ he.encode('\x01');
169
137
 
170
138
  // Passing an `options` object to `encode`, to explicitly enable error-tolerant mode:
171
139
  he.encode('\x01', {
172
- 'strict': false
140
+ strict: false,
173
141
  });
174
142
  // → '&#x1;'
175
143
 
176
144
  // Passing an `options` object to `encode`, to explicitly enable strict mode:
177
145
  he.encode('\x01', {
178
- 'strict': true
146
+ strict: true,
179
147
  });
180
148
  // → Parse error
181
149
  ```
@@ -186,7 +154,7 @@ The default value for the `allowUnsafeSymbols` option is `false`. This means tha
186
154
 
187
155
  ```js
188
156
  he.encode('foo © and & ampersand', {
189
- 'allowUnsafeSymbols': true
157
+ allowUnsafeSymbols: true,
190
158
  });
191
159
  // → 'foo &#xA9; and & ampersand'
192
160
  ```
@@ -230,13 +198,13 @@ he.decode('foo&ampbar');
230
198
 
231
199
  // Passing an `options` object to `decode`, to explicitly assume an HTML text context:
232
200
  he.decode('foo&ampbar', {
233
- 'isAttributeValue': false
201
+ isAttributeValue: false,
234
202
  });
235
203
  // → 'foo&bar'
236
204
 
237
205
  // Passing an `options` object to `decode`, to explicitly assume an HTML attribute value context:
238
206
  he.decode('foo&ampbar', {
239
- 'isAttributeValue': true
207
+ isAttributeValue: true,
240
208
  });
241
209
  // → 'foo&ampbar'
242
210
  ```
@@ -252,13 +220,13 @@ he.decode('foo&ampbar');
252
220
 
253
221
  // Passing an `options` object to `decode`, to explicitly enable error-tolerant mode:
254
222
  he.decode('foo&ampbar', {
255
- 'strict': false
223
+ strict: false,
256
224
  });
257
225
  // → 'foo&bar'
258
226
 
259
227
  // Passing an `options` object to `decode`, to explicitly enable strict mode:
260
228
  he.decode('foo&ampbar', {
261
- 'strict': true
229
+ strict: true,
262
230
  });
263
231
  // → Parse error
264
232
  ```
@@ -342,27 +310,17 @@ See `he --help` for the full list of options.
342
310
 
343
311
  ## Support
344
312
 
345
- _he_ has been tested in at least:
346
-
347
- * Chrome 27-50
348
- * Firefox 3-45
349
- * Safari 4-9
350
- * Opera 10-12, 15–37
351
- * IE 6–11
352
- * Edge
353
- * Narwhal 0.3.2
354
- * Node.js v0.10, v0.12, v4, v5
355
- * PhantomJS 1.9.0
356
- * Rhino 1.7RC4
357
- * RingoJS 0.8-0.11
358
-
359
- ## Unit tests & code coverage
313
+ _he_ is an ES2022 module. It works in all modern browsers and in Node.js v22+. The CLI requires Node.js v22+.
360
314
 
361
- After cloning this repository, run `npm install` to install the dependencies needed for he development and testing. You may want to install Istanbul _globally_ using `npm install istanbul -g`.
315
+ ## Development
362
316
 
363
- Once that’s done, you can run the unit tests in Node using `npm test` or `node tests/tests.js`. To run the tests in Rhino, Ringo, Narwhal, and web browsers as well, use `grunt test`.
317
+ After cloning this repository, run `npm install` to install the development dependencies.
364
318
 
365
- To generate the code coverage report, use `grunt cover`.
319
+ - `npm test` runs the test suite using the built-in Node.js test runner.
320
+ - `npm run coverage` prints a code coverage report.
321
+ - `npm run build` regenerates `data/*.json` from `data/entities.json` and writes the generated `src/data.mjs` module, which `src/he.mjs` imports.
322
+ - `npm run fetch` downloads the latest `entities.json`, derives the invalid code points and character reference overrides from the HTML and Infra Standards, and rebuilds. If the relevant spec prose changes, `scripts/fetch-spec.mjs` fails with an explanation instead of writing data.
323
+ - `npm run format` formats the code using [Oxfmt](https://oxc.rs/docs/guide/usage/formatter); `npm run format:check` verifies formatting.
366
324
 
367
325
  ## Acknowledgements
368
326
 
@@ -370,9 +328,9 @@ Thanks to [Simon Pieters](https://simon.html5.org/) ([@zcorpan](https://twitter.
370
328
 
371
329
  ## Author
372
330
 
373
- | [![twitter/mathias](https://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") |
374
- |---|
375
- | [Mathias Bynens](https://mathiasbynens.be/) |
331
+ | [![twitter/mathias](https://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias 'Follow @mathias on Twitter') |
332
+ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
333
+ | [Mathias Bynens](https://mathiasbynens.be/) |
376
334
 
377
335
  ## License
378
336
 
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env node
2
+ import packageJson from '../package.json' with { type: 'json' };
3
+ import * as he from '../src/he.mjs';
4
+
5
+ const { version } = packageJson;
6
+
7
+ const strings = process.argv.slice(2);
8
+ const stdin = process.stdin;
9
+ const options = {};
10
+ const log = console.log;
11
+ let action;
12
+ let timeout;
13
+
14
+ const flags = new Map([
15
+ [
16
+ '--escape',
17
+ () => {
18
+ action = 'escape';
19
+ },
20
+ ],
21
+ [
22
+ '--encode',
23
+ () => {
24
+ action = 'encode';
25
+ },
26
+ ],
27
+ [
28
+ '--use-named-refs',
29
+ () => {
30
+ action = 'encode';
31
+ options.useNamedReferences = true;
32
+ },
33
+ ],
34
+ [
35
+ '--everything',
36
+ () => {
37
+ action = 'encode';
38
+ options.encodeEverything = true;
39
+ },
40
+ ],
41
+ [
42
+ '--allow-unsafe',
43
+ () => {
44
+ action = 'encode';
45
+ options.allowUnsafeSymbols = true;
46
+ },
47
+ ],
48
+ [
49
+ '--decimal',
50
+ () => {
51
+ action = 'encode';
52
+ options.decimal = true;
53
+ },
54
+ ],
55
+ [
56
+ '--decode',
57
+ () => {
58
+ action = 'decode';
59
+ },
60
+ ],
61
+ [
62
+ '--attribute',
63
+ () => {
64
+ action = 'decode';
65
+ options.isAttributeValue = true;
66
+ },
67
+ ],
68
+ [
69
+ '--strict',
70
+ () => {
71
+ action = 'decode';
72
+ options.strict = true;
73
+ },
74
+ ],
75
+ ]);
76
+
77
+ const main = () => {
78
+ const option = strings[0];
79
+ let count = 0;
80
+
81
+ if (/^(?:-h|--help|undefined)$/.test(option)) {
82
+ log('he v%s - https://mths.be/he', version);
83
+ log(
84
+ [
85
+ '\nUsage:\n',
86
+ '\the [--escape] string',
87
+ '\the [--encode] [--use-named-refs] [--everything] [--allow-unsafe] [--decimal] string',
88
+ '\the [--decode] [--attribute] [--strict] string',
89
+ '\the [-v | --version]',
90
+ '\the [-h | --help]',
91
+ '\nExamples:\n',
92
+ '\the --escape \\<img\\ src\\=\\\'x\\\'\\ onerror\\=\\"prompt\\(1\\)\\"\\>',
93
+ "\techo '&copy; &#x1D306;' | he --decode",
94
+ ].join('\n'),
95
+ );
96
+ return process.exit(option ? 0 : 1);
97
+ }
98
+
99
+ if (/^(?:-v|--version)$/.test(option)) {
100
+ log('v%s', version);
101
+ return process.exit(0);
102
+ }
103
+
104
+ for (const string of strings) {
105
+ // Process options.
106
+ const flag = flags.get(string);
107
+ if (flag) {
108
+ flag();
109
+ continue;
110
+ }
111
+ // Process string(s).
112
+ if (!action) {
113
+ log('Error: he requires at least one option and a string argument.');
114
+ log('Try `he --help` for more information.');
115
+ return process.exit(1);
116
+ }
117
+ try {
118
+ log(he[action](string, options));
119
+ count++;
120
+ } catch (error) {
121
+ log(`${error.message}\n`);
122
+ log('Error: failed to %s.', action);
123
+ log('If you think this is a bug in he, please report it:');
124
+ log('https://github.com/mathiasbynens/he/issues/new');
125
+ log('\nStack trace using he@%s:\n', version);
126
+ log(error.stack);
127
+ return process.exit(1);
128
+ }
129
+ }
130
+ if (!count) {
131
+ log('Error: he requires a string argument.');
132
+ log('Try `he --help` for more information.');
133
+ return process.exit(1);
134
+ }
135
+ // Exit with status 0 after the loop, in case multiple strings were passed in.
136
+ return process.exit(0);
137
+ };
138
+
139
+ if (stdin.isTTY) {
140
+ // Handle shell arguments.
141
+ main();
142
+ } else {
143
+ // Either the script is called from within a non-TTY context, or `stdin`
144
+ // content is being piped in.
145
+ if (!process.stdout.isTTY) {
146
+ // The script was called from a non-TTY context. This is a rather uncommon
147
+ // use case we don’t actively support. However, we don’t want the script
148
+ // to wait forever in such cases, so…
149
+ timeout = setTimeout(() => {
150
+ // …if no piped data arrived after a whole minute, handle shell
151
+ // arguments instead.
152
+ main();
153
+ }, 60_000);
154
+ }
155
+ let data = '';
156
+ stdin.on('data', (chunk) => {
157
+ clearTimeout(timeout);
158
+ data += chunk;
159
+ });
160
+ stdin.on('end', () => {
161
+ strings.push(data.trim());
162
+ main();
163
+ });
164
+ stdin.resume();
165
+ }
@@ -1,58 +1,58 @@
1
1
  {
2
- "name": "he",
3
- "version": "1.2.0",
4
- "description": "A robust HTML entities encoder/decoder with full Unicode support.",
5
- "homepage": "https://mths.be/he",
6
- "main": "he.js",
7
- "bin": "bin/he",
8
- "keywords": [
9
- "string",
10
- "entities",
11
- "entity",
12
- "html",
13
- "encode",
14
- "decode",
15
- "unicode"
16
- ],
17
- "license": "MIT",
18
- "author": {
19
- "name": "Mathias Bynens",
20
- "url": "https://mathiasbynens.be/"
21
- },
22
- "repository": {
23
- "type": "git",
24
- "url": "https://github.com/mathiasbynens/he.git"
25
- },
26
- "bugs": "https://github.com/mathiasbynens/he/issues",
27
- "files": [
28
- "LICENSE-MIT.txt",
29
- "he.js",
30
- "bin/",
31
- "man/"
32
- ],
33
- "directories": {
34
- "bin": "bin",
35
- "man": "man",
36
- "test": "tests"
37
- },
38
- "scripts": {
39
- "test": "node tests/tests.js",
40
- "build": "grunt build"
41
- },
42
- "devDependencies": {
43
- "codecov.io": "^0.1.6",
44
- "grunt": "^0.4.5",
45
- "grunt-cli": "^1.3.1",
46
- "grunt-shell": "^1.1.1",
47
- "grunt-template": "^0.2.3",
48
- "istanbul": "^0.4.2",
49
- "jsesc": "^1.0.0",
50
- "lodash": "^4.8.2",
51
- "qunit-extras": "^1.4.5",
52
- "qunitjs": "~1.11.0",
53
- "regenerate": "^1.2.1",
54
- "regexgen": "^1.3.0",
55
- "requirejs": "^2.1.22",
56
- "sort-object": "^3.0.2"
57
- }
2
+ "name": "he",
3
+ "version": "2.0.0",
4
+ "description": "A robust HTML entities encoder/decoder with full Unicode support.",
5
+ "keywords": [
6
+ "decode",
7
+ "encode",
8
+ "entities",
9
+ "entity",
10
+ "html",
11
+ "string",
12
+ "unicode"
13
+ ],
14
+ "homepage": "https://mths.be/he",
15
+ "bugs": "https://github.com/mathiasbynens/he/issues",
16
+ "license": "MIT",
17
+ "author": {
18
+ "name": "Mathias Bynens",
19
+ "url": "https://mathiasbynens.be/"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/mathiasbynens/he.git"
24
+ },
25
+ "man": "man/he.1",
26
+ "bin": {
27
+ "he": "bin/he.mjs"
28
+ },
29
+ "files": [
30
+ "LICENSE-MIT.txt",
31
+ "src/",
32
+ "bin/",
33
+ "man/"
34
+ ],
35
+ "type": "module",
36
+ "exports": {
37
+ ".": "./src/he.mjs",
38
+ "./package.json": "./package.json"
39
+ },
40
+ "scripts": {
41
+ "build": "node scripts/process-data.mjs && node scripts/build.mjs && oxfmt data src/data.mjs",
42
+ "fetch": "npm run fetch:entities && node scripts/fetch-spec.mjs && npm run build",
43
+ "fetch:entities": "curl --fail --silent --show-error --location https://html.spec.whatwg.org/entities.json --output data/entities.json && oxfmt data/entities.json",
44
+ "test": "node --test \"tests/**/*.test.mjs\"",
45
+ "coverage": "node --test --experimental-test-coverage --test-coverage-include=\"src/**\" \"tests/**/*.test.mjs\"",
46
+ "format": "oxfmt",
47
+ "format:check": "oxfmt --check"
48
+ },
49
+ "devDependencies": {
50
+ "jsesc": "^3.1.0",
51
+ "linkedom": "^0.18.13",
52
+ "oxfmt": "^0.71.0",
53
+ "regenerate": "^1.4.2"
54
+ },
55
+ "engines": {
56
+ "node": ">=22"
57
+ }
58
58
  }