@thednp/shorty 2.0.0-alpha9 → 2.0.1

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/.eslintrc.cjs ADDED
@@ -0,0 +1,224 @@
1
+ module.exports = {
2
+ "env": {
3
+ "browser": true,
4
+ "es6": true
5
+ },
6
+ "extends": [
7
+ "plugin:@typescript-eslint/recommended",
8
+ "plugin:@typescript-eslint/recommended-requiring-type-checking",
9
+ ],
10
+ "parser": "@typescript-eslint/parser",
11
+ "parserOptions": {
12
+ "project": "tsconfig.json",
13
+ "sourceType": "module"
14
+ },
15
+ "plugins": [
16
+ "eslint-plugin-jsdoc",
17
+ "eslint-plugin-prefer-arrow",
18
+ // "eslint-plugin-react",
19
+ "@typescript-eslint",
20
+ "prettier"
21
+ ],
22
+ "root": true,
23
+ "rules": {
24
+ "prettier/prettier": "error",
25
+ "@typescript-eslint/adjacent-overload-signatures": "error",
26
+ "@typescript-eslint/array-type": [
27
+ "error",
28
+ {
29
+ "default": "array"
30
+ }
31
+ ],
32
+ "@typescript-eslint/ban-types": [
33
+ "error",
34
+ {
35
+ "types": {
36
+ "Object": {
37
+ "message": "Avoid using the `Object` type. Did you mean `object`?"
38
+ },
39
+ "Function": {
40
+ "message": "Avoid using the `Function` type. Prefer a specific function type, like `() => void`."
41
+ },
42
+ "Boolean": {
43
+ "message": "Avoid using the `Boolean` type. Did you mean `boolean`?"
44
+ },
45
+ "Number": {
46
+ "message": "Avoid using the `Number` type. Did you mean `number`?"
47
+ },
48
+ "String": {
49
+ "message": "Avoid using the `String` type. Did you mean `string`?"
50
+ },
51
+ "Symbol": {
52
+ "message": "Avoid using the `Symbol` type. Did you mean `symbol`?"
53
+ }
54
+ }
55
+ }
56
+ ],
57
+ "@typescript-eslint/consistent-type-assertions": "error",
58
+ "@typescript-eslint/dot-notation": "error",
59
+ "@typescript-eslint/explicit-function-return-type": "off",
60
+ "@typescript-eslint/explicit-module-boundary-types": "off",
61
+ "@typescript-eslint/indent": "off",
62
+ "@typescript-eslint/member-delimiter-style": [
63
+ "off",
64
+ {
65
+ "multiline": {
66
+ "delimiter": "none",
67
+ "requireLast": true
68
+ },
69
+ "singleline": {
70
+ "delimiter": "semi",
71
+ "requireLast": false
72
+ }
73
+ }
74
+ ],
75
+ "@typescript-eslint/naming-convention": "off", // error
76
+ "@typescript-eslint/no-empty-function": "error",
77
+ "@typescript-eslint/no-empty-interface": "error",
78
+ "@typescript-eslint/no-explicit-any": "off",
79
+ "@typescript-eslint/no-misused-new": "error",
80
+ "@typescript-eslint/no-namespace": "error",
81
+ "@typescript-eslint/no-parameter-properties": "off",
82
+ "@typescript-eslint/no-shadow": [
83
+ "error",
84
+ {
85
+ "hoist": "all"
86
+ }
87
+ ],
88
+ "@typescript-eslint/no-unused-expressions": "error",
89
+ "@typescript-eslint/no-use-before-define": "off",
90
+ "@typescript-eslint/no-var-requires": "error",
91
+ "@typescript-eslint/prefer-for-of": "error",
92
+ "@typescript-eslint/prefer-function-type": "error",
93
+ "@typescript-eslint/prefer-namespace-keyword": "error",
94
+ "@typescript-eslint/quotes": "off",
95
+ "@typescript-eslint/semi": [
96
+ "off",
97
+ null
98
+ ],
99
+ "@typescript-eslint/triple-slash-reference": [
100
+ "error",
101
+ {
102
+ "path": "always",
103
+ "types": "prefer-import",
104
+ "lib": "always"
105
+ }
106
+ ],
107
+ "@typescript-eslint/type-annotation-spacing": "off",
108
+ "@typescript-eslint/typedef": "off",
109
+ "@typescript-eslint/unified-signatures": "error",
110
+ "arrow-parens": [
111
+ "off",
112
+ "always"
113
+ ],
114
+ "brace-style": [
115
+ "off",
116
+ "off"
117
+ ],
118
+ "comma-dangle": "off",
119
+ "complexity": "off",
120
+ "constructor-super": "error",
121
+ "dot-notation": "off",
122
+ "eol-last": "off",
123
+ "eqeqeq": [
124
+ "error",
125
+ "smart"
126
+ ],
127
+ "guard-for-in": "error",
128
+ "id-denylist": [
129
+ "error",
130
+ "any",
131
+ "Number",
132
+ "number",
133
+ "String",
134
+ "string",
135
+ "Boolean",
136
+ "boolean",
137
+ "Undefined",
138
+ "undefined"
139
+ ],
140
+ "id-match": "error",
141
+ "indent": "off",
142
+ "jsdoc/check-alignment": "error",
143
+ "jsdoc/check-indentation": "error",
144
+ // "jsdoc/newline-after-description": "error",
145
+ "linebreak-style": "off",
146
+ "max-classes-per-file": [
147
+ "error",
148
+ 1
149
+ ],
150
+ "max-len": "off",
151
+ "new-parens": "off",
152
+ "newline-per-chained-call": "off",
153
+ "no-bitwise": "error",
154
+ "no-caller": "error",
155
+ "no-cond-assign": "error",
156
+ "no-console": "error",
157
+ "no-debugger": "error",
158
+ "no-empty": "error",
159
+ "no-empty-function": "off",
160
+ "no-eval": "error",
161
+ "no-extra-semi": "off",
162
+ "no-fallthrough": "off",
163
+ "no-invalid-this": "off",
164
+ "no-irregular-whitespace": "off",
165
+ "no-multiple-empty-lines": "off",
166
+ "no-new-wrappers": "error",
167
+ "no-shadow": "off",
168
+ "no-throw-literal": "error",
169
+ "no-trailing-spaces": "off",
170
+ "no-undef-init": "error",
171
+ "no-underscore-dangle": "off",
172
+ "no-unsafe-finally": "error",
173
+ "no-unused-expressions": "off",
174
+ "no-unused-labels": "error",
175
+ "no-use-before-define": "off",
176
+ "no-var": "error",
177
+ "object-shorthand": "error",
178
+ "one-var": [
179
+ "error",
180
+ "never"
181
+ ],
182
+ "padded-blocks": [
183
+ "off",
184
+ {
185
+ "blocks": "never"
186
+ },
187
+ {
188
+ "allowSingleLineBlocks": true
189
+ }
190
+ ],
191
+ "prefer-arrow/prefer-arrow-functions": "error",
192
+ "prefer-const": "error",
193
+ "quote-props": "off",
194
+ "quotes": "off",
195
+ "radix": "error",
196
+ // "react/jsx-curly-spacing": "off",
197
+ // "react/jsx-equals-spacing": "off",
198
+ // "react/jsx-tag-spacing": [
199
+ // "off",
200
+ // {
201
+ // "afterOpening": "allow",
202
+ // "closingSlash": "allow"
203
+ // }
204
+ // ],
205
+ // "react/jsx-wrap-multilines": "off",
206
+ "semi": "off",
207
+ "space-before-function-paren": "off",
208
+ "space-in-parens": [
209
+ "off",
210
+ "never"
211
+ ],
212
+ "spaced-comment": [
213
+ "error",
214
+ "always",
215
+ {
216
+ "markers": [
217
+ "/"
218
+ ]
219
+ }
220
+ ],
221
+ "use-isnan": "error",
222
+ "valid-typeof": "off"
223
+ }
224
+ };
package/.lgtm.yml ADDED
@@ -0,0 +1,8 @@
1
+ extraction:
2
+ typescript:
3
+ index:
4
+ exclude:
5
+ - coverage
6
+ - cypress
7
+ - experiments
8
+ - node_modules
@@ -0,0 +1,15 @@
1
+ {
2
+ "arrowParens": "avoid",
3
+ "bracketSpacing": true,
4
+ "endOfLine": "lf",
5
+ "bracketSameLine": false,
6
+ "jsxSingleQuote": false,
7
+ "printWidth": 100,
8
+ "proseWrap": "preserve",
9
+ "quoteProps": "as-needed",
10
+ "semi": true,
11
+ "singleQuote": true,
12
+ "tabWidth": 2,
13
+ "trailingComma": "all",
14
+ "useTabs": false
15
+ }
package/README.md CHANGED
@@ -5,11 +5,11 @@
5
5
  [![NPM Version](https://img.shields.io/npm/v/@thednp/shorty.svg)](https://www.npmjs.com/package/@thednp/shorty)
6
6
  [![NPM Downloads](https://img.shields.io/npm/dm/@thednp/shorty.svg)](http://npm-stat.com/charts.html?package=@thednp/shorty)
7
7
  [![jsDelivr hits (npm)](https://img.shields.io/jsdelivr/npm/hw/@thednp/shorty)](https://www.jsdelivr.com/package/npm/@thednp/shorty)
8
- [![typescript version](https://img.shields.io/badge/typescript-4.9.4-brightgreen)](https://www.typescriptlang.org/)
9
- [![eslint version](https://img.shields.io/badge/eslint-8.29.0-brightgreen)](https://github.com/eslint)
10
- [![prettier version](https://img.shields.io/badge/prettier-2.8.3-brightgreen)](https://prettier.io/)
11
- [![cypress version](https://img.shields.io/badge/cypress-12.4.1-brightgreen)](https://cypress.io/)
12
- [![vite version](https://img.shields.io/badge/vite-4.0.4-brightgreen)](https://github.com/vitejs)
8
+ [![typescript version](https://img.shields.io/badge/typescript-5.5.3-brightgreen)](https://www.typescriptlang.org/)
9
+ [![eslint version](https://img.shields.io/badge/eslint-8.57.0-brightgreen)](https://github.com/eslint)
10
+ [![prettier version](https://img.shields.io/badge/prettier-2.8.8-brightgreen)](https://prettier.io/)
11
+ [![cypress version](https://img.shields.io/badge/cypress-13.13.1-brightgreen)](https://cypress.io/)
12
+ [![vite version](https://img.shields.io/badge/vite-5.3.4-brightgreen)](https://github.com/vitejs)
13
13
 
14
14
 
15
15
  A small TypeScript library with various tools, all ESLint valid and featuring everything useful for creating light libraries or web components. If there is anything that is consistently repeating itself, **shorty** can help you save up to 50% of the code required, with little to no performance cost.
@@ -0,0 +1,46 @@
1
+ /// <reference types="cypress" />
2
+ // @ts-nocheck
3
+
4
+ // import SHORTY from '../../src/index';
5
+ import * as SHORTY from '../../src/index';
6
+
7
+ describe('Shorty Library Tests', () => {
8
+ before(() => {
9
+ cy.visit('cypress/test.html');
10
+ });
11
+
12
+ it('Test attr folder', () => {
13
+ const {
14
+ getAttribute,
15
+ setAttribute,
16
+ hasAttribute,
17
+ removeAttribute,
18
+ getAttributeNS,
19
+ setAttributeNS,
20
+ hasAttributeNS,
21
+ removeAttributeNS,
22
+ querySelector,
23
+ } = SHORTY;
24
+
25
+ cy
26
+ .get('.alert')
27
+ .should($element => {
28
+ const el = $element[0];
29
+ expect(getAttribute(el, 'class'), 'getAttribute').to.have.length.above(0);
30
+ setAttribute(el, 'data-att', 'momo');
31
+ expect(hasAttribute(el, 'data-att'), 'hasAttribute').to.be.true;
32
+ removeAttribute(el, 'data-att');
33
+ expect(hasAttribute(el, 'data-att'), 'hasAttribute').to.be.false;
34
+ });
35
+ cy.get('svg').should($svg => {
36
+ console.log(querySelector('svg'));
37
+ const svg = $svg[0] as HTMLElement;
38
+ const ns = 'http://www.w3.org/2000/svg';
39
+ expect(hasAttributeNS(ns, svg, 'transform'), 'hasAttributeNS').to.be.false;
40
+ setAttributeNS(ns, svg, 'transform', 'scale(0.99)');
41
+ expect(getAttributeNS(ns, svg, 'transform'), 'getAttributeNS').to.eq('scale(0.99)');
42
+ removeAttributeNS(ns, svg, 'transform');
43
+ expect(getAttributeNS(ns, svg, 'transform'), 'getAttributeNS').to.be.null;
44
+ });
45
+ });
46
+ });
@@ -0,0 +1,44 @@
1
+ /// <reference types="cypress" />
2
+ // @ts-nocheck
3
+
4
+ // import SHORTY from '../../src/index';
5
+ import * as SHORTY from '../../src/index';
6
+
7
+ describe('Shorty Library Tests', () => {
8
+ before(() => {
9
+ cy.visit('cypress/test.html');
10
+ });
11
+
12
+ it('Test boolean folder', () => {
13
+ const {
14
+ // these are impossible to test 100% of the branches
15
+ isApple,
16
+ isMobile,
17
+ isFirefox,
18
+ support3DTransform,
19
+ supportAnimation,
20
+ supportPassive,
21
+ supportTouch,
22
+ supportTransform,
23
+ supportTransition,
24
+ // querySelectorAll, getWindow
25
+ } = SHORTY;
26
+ cy
27
+ .window()
28
+ .then(() => {
29
+ expect(isApple, 'isApple').to.be.false;
30
+ expect(isMobile, 'isMobile').to.be.false;
31
+ if (Cypress.isBrowser('firefox')) {
32
+ expect(isFirefox, 'isFirefox').to.be.true;
33
+ } else {
34
+ expect(isFirefox, 'isFirefox').to.be.false;
35
+ }
36
+ expect(support3DTransform, 'support3DTransform').to.be.true;
37
+ expect(supportAnimation, 'supportAnimation').to.be.true;
38
+ expect(supportPassive, 'supportPassive').to.be.true;
39
+ expect(supportTouch, 'supportTouch').to.be.false;
40
+ expect(supportTransform, 'supportTransform').to.be.true;
41
+ expect(supportTransition, 'supportTransition').to.be.true;
42
+ });
43
+ });
44
+ });
@@ -0,0 +1,28 @@
1
+ /// <reference types="cypress" />
2
+ // @ts-nocheck
3
+
4
+ // import SHORTY from '../../src/index';
5
+ import * as SHORTY from '../../src/index';
6
+
7
+ describe('Shorty Library Tests', () => {
8
+ before(() => {
9
+ cy.visit('cypress/test.html');
10
+ });
11
+
12
+ it('Test class folder', () => {
13
+ const { addClass, hasClass, removeClass } = SHORTY;
14
+ cy
15
+ .get('.alert')
16
+ .then($alert => {
17
+ const alert = $alert[0];
18
+
19
+ addClass(alert, 'to-be-removed');
20
+ expect(hasClass(alert, 'to-be-removed')).to.be.true;
21
+ removeClass(alert, 'show');
22
+ expect(hasClass(alert, 'show')).to.be.false;
23
+ })
24
+ .wait(200)
25
+ .get('.alert')
26
+ .should('be.hidden');
27
+ });
28
+ });
@@ -0,0 +1,51 @@
1
+ /// <reference types="cypress" />
2
+ // @ts-nocheck
3
+
4
+ // import SHORTY from '../../src/index';
5
+ import * as SHORTY from '../../src/index';
6
+
7
+ describe('Shorty Library Tests', () => {
8
+ before(() => {
9
+ cy.visit('cypress/test.html');
10
+ });
11
+
12
+ it('Test event folder', () => {
13
+ const {
14
+ // on, off are called by one
15
+ one,
16
+ getElementsByClassName,
17
+ } = SHORTY;
18
+
19
+ cy
20
+ .get('.alert')
21
+ .should(($alert) => {
22
+
23
+ if ($alert[0]){
24
+ const [el] = $alert;
25
+ const [btn] = getElementsByClassName('btn-close', el);
26
+ const doc = btn.ownerDocument;
27
+ console.log(doc, btn)
28
+
29
+ one(el, 'click', function handle(e) {
30
+ const message = doc.createElement('p');
31
+ message.innerText += 'click fired for ' + (e.currentTarget as HTMLElement).tagName;
32
+ el.append(message);
33
+ // console.log(e.target, e.currentTarget);
34
+ });
35
+
36
+ one(btn, 'click', function handle(e) {
37
+ const message = doc.createElement('p');
38
+ message.innerText = 'click fired for ' + (e.target as HTMLElement).tagName;
39
+ el.append(message);
40
+ });
41
+ }
42
+ })
43
+ .get('.btn-close')
44
+ .click({ force: true })
45
+ .should(btn => {
46
+ expect(btn[0], 'event target').be.equal((btn[0].ownerDocument as Document).activeElement);
47
+ })
48
+ .get('.alert')
49
+ .should('contain', 'click fired for BUTTON');
50
+ });
51
+ });
@@ -0,0 +1,168 @@
1
+ /// <reference types="cypress" />
2
+ // @ts-nocheck
3
+
4
+ // import SHORTY from '../../src/index';
5
+ import * as SHORTY from '../../src/index';
6
+
7
+ import CustomElem from '../fixtures/custom-elem';
8
+
9
+ describe('Shorty Library Tests', () => {
10
+ before(() => {
11
+ cy.visit('cypress/test.html');
12
+ });
13
+
14
+ it('Test get folder', () => {
15
+ const {
16
+ getBoundingClientRect,
17
+ getDocument,
18
+ getDocumentBody,
19
+ getDocumentElement,
20
+ getDocumentHead,
21
+ getElementAnimationDelay,
22
+ getElementAnimationDuration,
23
+ getElementTransitionDelay,
24
+ getElementTransitionDuration,
25
+ getElementStyle,
26
+ getNodeScroll,
27
+ getParentNode,
28
+ getRectRelativeToOffsetParent,
29
+ getUID,
30
+ getWindow,
31
+ ObjectValues,
32
+ } = SHORTY;
33
+
34
+ cy
35
+ .get('.alert')
36
+ .should($element => {
37
+ const element = $element[0];
38
+ element.style.transform = 'scale(1.01)';
39
+ const win = getWindow(element);
40
+ const CE = new CustomElem();
41
+ CE.className = 'btn btn-outline-primary';
42
+ win.document.body.append(CE);
43
+
44
+ // we round values so all browsers return same values
45
+ let { x, y, top, left, right, bottom, width, height } = getBoundingClientRect(
46
+ element,
47
+ true,
48
+ );
49
+ expect(
50
+ ObjectValues([x, y, top, left, right, bottom, width, height]).map(Math.round),
51
+ 'getBoundingClientRect',
52
+ ).to.deep.equal([63, 87, 87, 63, 927, 204, 864, 117]);
53
+ element.style.transform = '';
54
+
55
+ expect(getWindow(), 'getWindow').to.be.instanceOf(Window); // root WINDOW
56
+ expect(getWindow(element.ownerDocument), 'getWindow(document)').to.be.instanceOf(
57
+ win.Window,
58
+ );
59
+ expect(getWindow(CE), 'getWindow(CustomElement)').to.be.instanceOf(win.Window);
60
+ expect(getWindow(CE.shadowRoot), 'getWindow(CustomElement.shadowRoot)').to.be.instanceOf(
61
+ win.Window,
62
+ );
63
+ expect(getWindow(win.top), 'getWindow(window)').to.be.instanceOf(win.top.Window);
64
+
65
+ expect(getDocument(), 'getDocument()').to.be.instanceOf(Document);
66
+ expect(getDocument(element), 'getDocument(node)').to.be.instanceOf(win.Document);
67
+ expect(getDocument(win.document), 'getDocument(document)').to.be.instanceOf(win.Document);
68
+ expect(getDocument(win), 'getDocument(window)').to.be.instanceOf(win.Document);
69
+
70
+ expect(getDocumentBody(element), 'getDocumentBody').to.be.instanceOf(win.HTMLBodyElement);
71
+ expect(getDocumentElement(element), 'getDocumentElement').to.be.instanceOf(
72
+ win.HTMLHtmlElement,
73
+ );
74
+ expect(getDocumentHead(element), 'getDocumentHead').to.be.instanceOf(win.HTMLHeadElement);
75
+
76
+ expect(getElementAnimationDelay(element), 'getElementAnimationDelay').to.equal(0);
77
+
78
+ expect(getElementAnimationDuration(element), 'getElementAnimationDuration').to.equal(0);
79
+
80
+ CE.style.animation = 'animate-me 1s ease 0.5s';
81
+ expect(getElementAnimationDelay(CE), 'getElementAnimationDelay - seconds').to.equal(500);
82
+
83
+ expect(getElementAnimationDuration(CE), 'getElementAnimationDuration - seconds').to.equal(
84
+ 1000,
85
+ );
86
+
87
+ CE.style.animation = 'animate-me 1200ms ease 400ms';
88
+ expect(getElementAnimationDelay(CE), 'getElementAnimationDelay - miliseconds').to.equal(
89
+ 400,
90
+ );
91
+
92
+ expect(
93
+ getElementAnimationDuration(CE),
94
+ 'getElementAnimationDuration - miliseconds',
95
+ ).to.equal(1200);
96
+
97
+ element.style.transition = 'opacity .145s linear .1s';
98
+ expect(getElementTransitionDelay(element), 'getElementTransitionDelay - seconds').to.equal(
99
+ 100,
100
+ );
101
+ expect(
102
+ getElementTransitionDuration(element),
103
+ 'getElementTransitionDuration - seconds',
104
+ ).to.equal(145);
105
+
106
+ element.style.transition = 'opacity 140ms linear 10ms';
107
+ expect(
108
+ getElementTransitionDelay(element),
109
+ 'getElementTransitionDelay- miliseconds',
110
+ ).to.equal(10);
111
+
112
+ expect(
113
+ getElementTransitionDuration(element),
114
+ 'getElementTransitionDuration- miliseconds',
115
+ ).to.equal(140);
116
+
117
+ element.style.transition = '';
118
+
119
+ expect(getElementStyle(element, 'color'), 'getElementStyle(color)').to.equal(
120
+ 'rgb(102, 77, 3)',
121
+ );
122
+
123
+ expect(getNodeScroll(win), 'getNodeScroll(window)').to.deep.equal({ x: 0, y: 0 });
124
+ expect(getNodeScroll(element), 'getNodeScroll(element)').to.deep.equal({ x: 0, y: 0 });
125
+ expect(
126
+ getNodeScroll(element.offsetParent as HTMLElement),
127
+ 'getNodeScroll(element.offsetParent)',
128
+ ).to.deep.equal({ x: 0, y: 0 });
129
+ expect(getNodeScroll(getDocumentBody(element)), 'getNodeScroll(body)').to.deep.equal({
130
+ x: 0,
131
+ y: 0,
132
+ });
133
+
134
+ expect(getParentNode(getDocumentElement()), 'getParentNode()').to.be.instanceOf(
135
+ HTMLHtmlElement,
136
+ ); // root HTML
137
+ expect(getParentNode(win), 'getParentNode(window)').to.be.instanceOf(win.HTMLHtmlElement);
138
+ expect(getParentNode(getDocumentBody(element)), 'getParentNode(body)').to.be.instanceOf(
139
+ win.HTMLHtmlElement,
140
+ );
141
+ expect(getParentNode(element), 'getParentNode(node)').to.have.class('container');
142
+ expect(getParentNode(CE), 'getParentNode(CustomElement)').to.be.instanceOf(
143
+ win.HTMLBodyElement,
144
+ );
145
+ expect(
146
+ getParentNode(CE.shadowRoot),
147
+ 'getParentNode(CustomElement.shadowRoot)',
148
+ ).to.be.instanceOf(CustomElem);
149
+
150
+ ({ x, y, width, height } = getRectRelativeToOffsetParent(
151
+ element,
152
+ getDocumentElement(win),
153
+ getNodeScroll(getDocumentElement(win)),
154
+ ));
155
+
156
+ expect(
157
+ [x, y, width, height].map(Math.round),
158
+ 'getRectRelativeToOffsetParent',
159
+ ).to.deep.equal([68, 88, 864, 117]);
160
+
161
+ expect(getUID(element), 'getUID()').to.eq(0);
162
+ expect(getUID(element, 'Alert'), 'getUID(key) - set & returns').to.eq(0);
163
+ expect(getUID(element, 'Alert'), 'getUID(key) - returns').to.eq(0);
164
+ expect(getUID(win, 'Alert'), 'getUID(key) - set & returns').to.eq(1);
165
+ expect(getUID(win, 'Alert'), 'getUID(key) - returns').to.eq(1);
166
+ });
167
+ });
168
+ });