eslint-plugin-no-jquery 2.7.0 → 3.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.
Files changed (50) hide show
  1. package/README.md +2 -2
  2. package/README.md.template +1 -1
  3. package/package.json +12 -9
  4. package/src/.eslintrc.js +17 -0
  5. package/src/all-methods.js +2 -1
  6. package/src/index.js +4 -1
  7. package/src/rules/no-ajax-events.js +26 -28
  8. package/src/rules/no-ajax.js +1 -1
  9. package/src/rules/no-and-self.js +1 -3
  10. package/src/rules/no-animate-toggle.js +3 -3
  11. package/src/rules/no-animate.js +28 -30
  12. package/src/rules/no-append-html.js +18 -20
  13. package/src/rules/no-class-state.js +16 -18
  14. package/src/rules/no-class.js +1 -1
  15. package/src/rules/no-constructor-attributes.js +21 -23
  16. package/src/rules/no-data.js +1 -1
  17. package/src/rules/no-deferred.js +2 -2
  18. package/src/rules/no-error.js +1 -3
  19. package/src/rules/no-escape-selector.js +1 -3
  20. package/src/rules/no-event-shorthand.js +3 -3
  21. package/src/rules/no-extend.js +28 -26
  22. package/src/rules/no-fade.js +1 -1
  23. package/src/rules/no-fx-interval.js +13 -15
  24. package/src/rules/no-global-selector.js +39 -41
  25. package/src/rules/no-is-array.js +1 -3
  26. package/src/rules/no-is-function.js +1 -1
  27. package/src/rules/no-jquery-constructor.js +13 -15
  28. package/src/rules/no-load-shorthand.js +17 -19
  29. package/src/rules/no-noop.js +1 -3
  30. package/src/rules/no-now.js +1 -3
  31. package/src/rules/no-on-ready.js +29 -34
  32. package/src/rules/no-other-methods.js +19 -21
  33. package/src/rules/no-other-utils.js +18 -20
  34. package/src/rules/no-parse-html-literal.js +60 -67
  35. package/src/rules/no-parse-json.js +1 -3
  36. package/src/rules/no-parse-xml.js +1 -1
  37. package/src/rules/no-prop.js +1 -1
  38. package/src/rules/no-proxy.js +1 -1
  39. package/src/rules/no-ready-shorthand.js +1 -1
  40. package/src/rules/no-ready.js +9 -11
  41. package/src/rules/no-serialize.js +1 -1
  42. package/src/rules/no-size.js +1 -3
  43. package/src/rules/no-sizzle.js +5 -5
  44. package/src/rules/no-slide.js +1 -1
  45. package/src/rules/no-unique.js +1 -3
  46. package/src/rules/no-visibility.js +1 -1
  47. package/src/rules/no-wrap.js +1 -1
  48. package/src/rules/variable-pattern.js +4 -4
  49. package/src/utils.js +107 -117
  50. package/Changelog.md +0 -359
@@ -28,61 +28,59 @@ module.exports = {
28
28
  ]
29
29
  },
30
30
 
31
- create: function ( context ) {
32
- return {
33
- 'CallExpression:exit': function ( node ) {
34
- if (
35
- node.callee.type !== 'Identifier' ||
31
+ create: ( context ) => ( {
32
+ 'CallExpression:exit': ( node ) => {
33
+ if (
34
+ node.callee.type !== 'Identifier' ||
36
35
  !utils.isjQueryConstructor( context, node.callee.name ) ||
37
36
  !node.arguments[ 0 ] ||
38
37
  node.arguments[ 0 ].type !== 'Literal'
39
- ) {
40
- return;
41
- }
42
- const value = node.arguments[ 0 ].value;
43
- const allowIds = context.options[ 0 ] && context.options[ 0 ].allowIds;
44
- if (
45
- typeof value !== 'string' ||
38
+ ) {
39
+ return;
40
+ }
41
+ const value = node.arguments[ 0 ].value;
42
+ const allowIds = context.options[ 0 ] && context.options[ 0 ].allowIds;
43
+ if (
44
+ typeof value !== 'string' ||
46
45
  !value ||
47
46
  value === '#' ||
48
47
  ( allowIds && idPattern.test( value.trim() ) )
49
- ) {
50
- return;
51
- }
48
+ ) {
49
+ return;
50
+ }
52
51
 
53
- // Simple HTML check (copied from jQuery)
54
- if (
55
- value[ 0 ] === '<' &&
52
+ // Simple HTML check (copied from jQuery)
53
+ if (
54
+ value[ 0 ] === '<' &&
56
55
  value[ value.length - 1 ] === '>' &&
57
56
  value.length >= 3
58
- ) {
59
- return;
60
- }
61
- if ( rquickExpr.exec( value ) ) {
62
- return;
63
- }
57
+ ) {
58
+ return;
59
+ }
60
+ if ( rquickExpr.exec( value ) ) {
61
+ return;
62
+ }
64
63
 
65
- const selectorContext = node.arguments[ 1 ];
66
- if ( selectorContext ) {
67
- if (
68
- selectorContext.type !== 'Literal' &&
64
+ const selectorContext = node.arguments[ 1 ];
65
+ if ( selectorContext ) {
66
+ if (
67
+ selectorContext.type !== 'Literal' &&
69
68
  !(
70
69
  selectorContext.type === 'Identifier' &&
71
70
  selectorContext.name === 'undefined'
72
71
  )
73
- ) {
74
- return;
75
- }
76
- if ( selectorContext.value === '#' ) {
77
- return;
78
- }
72
+ ) {
73
+ return;
74
+ }
75
+ if ( selectorContext.value === '#' ) {
76
+ return;
79
77
  }
80
-
81
- context.report( {
82
- node: node,
83
- message: 'Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.'
84
- } );
85
78
  }
86
- };
87
- }
79
+
80
+ context.report( {
81
+ node,
82
+ message: 'Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.'
83
+ } );
84
+ }
85
+ } )
88
86
  };
@@ -7,8 +7,6 @@ module.exports = utils.createUtilMethodRule(
7
7
  'Prefer `Array.isArray` to `$.isArray`',
8
8
  {
9
9
  fixable: 'code',
10
- fix: function ( node, context, fixer ) {
11
- return fixer.replaceText( node.callee, 'Array.isArray' );
12
- }
10
+ fix: ( node, context, fixer ) => fixer.replaceText( node.callee, 'Array.isArray' )
13
11
  }
14
12
  );
@@ -7,7 +7,7 @@ module.exports = utils.createUtilMethodRule(
7
7
  'Prefer `typeof` to `$.isFunction`',
8
8
  {
9
9
  fixable: 'code',
10
- fix: function ( node, context, fixer ) {
10
+ fix: ( node, context, fixer ) => {
11
11
  const calleeRange = node.callee.range;
12
12
  return [
13
13
  fixer.replaceTextRange( [ calleeRange[ 0 ], calleeRange[ 1 ] + 1 ], 'typeof ' ),
@@ -11,21 +11,19 @@ module.exports = {
11
11
  schema: []
12
12
  },
13
13
 
14
- create: function ( context ) {
15
- return {
16
- 'CallExpression:exit': function ( node ) {
17
- if (
18
- node.callee.type !== 'Identifier' ||
14
+ create: ( context ) => ( {
15
+ 'CallExpression:exit': ( node ) => {
16
+ if (
17
+ node.callee.type !== 'Identifier' ||
19
18
  !utils.isjQueryConstructor( context, node.callee.name )
20
- ) {
21
- return;
22
- }
23
-
24
- context.report( {
25
- node: node,
26
- message: 'The jQuery constructor is not allowed'
27
- } );
19
+ ) {
20
+ return;
28
21
  }
29
- };
30
- }
22
+
23
+ context.report( {
24
+ node,
25
+ message: 'The jQuery constructor is not allowed'
26
+ } );
27
+ }
28
+ } )
31
29
  };
@@ -12,28 +12,26 @@ module.exports = {
12
12
  schema: []
13
13
  },
14
14
 
15
- create: function ( context ) {
16
- return {
17
- 'CallExpression:exit': function ( node ) {
18
- if ( !(
19
- node.callee.type === 'MemberExpression' &&
15
+ create: ( context ) => ( {
16
+ 'CallExpression:exit': ( node ) => {
17
+ if ( !(
18
+ node.callee.type === 'MemberExpression' &&
20
19
  !utils.isjQueryConstructor( context, node.callee.object.name ) &&
21
20
  node.callee.property.name === 'load' && (
22
- node.arguments.length === 0 ||
21
+ node.arguments.length === 0 ||
23
22
  utils.isFunction( node.arguments[ 0 ] )
24
- )
25
- ) ) {
26
- return;
27
- }
23
+ )
24
+ ) ) {
25
+ return;
26
+ }
28
27
 
29
- if ( utils.isjQuery( context, node.callee ) ) {
30
- context.report( {
31
- node: node,
32
- message: 'Prefer .on or .trigger to .load',
33
- fix: utils.eventShorthandFixer.bind( this, node, context )
34
- } );
35
- }
28
+ if ( utils.isjQuery( context, node.callee ) ) {
29
+ context.report( {
30
+ node,
31
+ message: 'Prefer .on or .trigger to .load',
32
+ fix: utils.eventShorthandFixer.bind( this, node, context )
33
+ } );
36
34
  }
37
- };
38
- }
35
+ }
36
+ } )
39
37
  };
@@ -7,8 +7,6 @@ module.exports = utils.createUtilPropertyRule(
7
7
  'Prefer `function(){}` to `$.noop`',
8
8
  {
9
9
  fixable: 'code',
10
- fix: function ( node, context, fixer ) {
11
- return fixer.replaceText( node, '(function(){})' );
12
- }
10
+ fix: ( node, context, fixer ) => fixer.replaceText( node, '(function(){})' )
13
11
  }
14
12
  );
@@ -7,8 +7,6 @@ module.exports = utils.createUtilMethodRule(
7
7
  'Prefer `Date.now` to `$.now`',
8
8
  {
9
9
  fixable: 'code',
10
- fix: function ( node, context, fixer ) {
11
- return fixer.replaceText( node.callee, 'Date.now' );
12
- }
10
+ fix: ( node, context, fixer ) => fixer.replaceText( node.callee, 'Date.now' )
13
11
  }
14
12
  );
@@ -12,41 +12,36 @@ module.exports = {
12
12
  schema: []
13
13
  },
14
14
 
15
- create: function ( context ) {
16
- return {
17
- 'CallExpression:exit': function ( node ) {
18
- if (
19
- node.callee.type !== 'MemberExpression' ||
15
+ create: ( context ) => ( {
16
+ 'CallExpression:exit': ( node ) => {
17
+ if (
18
+ node.callee.type !== 'MemberExpression' ||
20
19
  node.callee.property.name !== 'on'
21
- ) {
22
- return;
23
- }
24
- const arg = node.arguments[ 0 ];
25
- if ( !arg || arg.value !== 'ready' ) {
26
- return;
27
- }
20
+ ) {
21
+ return;
22
+ }
23
+ const arg = node.arguments[ 0 ];
24
+ if ( !arg || arg.value !== 'ready' ) {
25
+ return;
26
+ }
28
27
 
29
- if ( utils.isjQuery( context, node.callee ) ) {
30
- context.report( {
31
- node: node,
32
- message: '.on("ready") is not allowed',
33
- fix: function ( fixer ) {
34
- if ( node.arguments.length > 1 ) {
35
- return [
36
- fixer.replaceText( node.callee.property, 'ready' ),
37
- fixer.replaceTextRange(
38
- [
39
- node.arguments[ 0 ].range[ 0 ],
40
- node.arguments[ 1 ].range[ 0 ]
41
- ],
42
- ''
43
- )
44
- ];
45
- }
46
- }
47
- } );
48
- }
28
+ if ( utils.isjQuery( context, node.callee ) ) {
29
+ context.report( {
30
+ node,
31
+ message: '.on("ready") is not allowed',
32
+ fix: ( fixer ) => ( node.arguments.length > 1 ) ?
33
+ [
34
+ fixer.replaceText( node.callee.property, 'ready' ),
35
+ fixer.replaceTextRange(
36
+ [
37
+ node.arguments[ 0 ].range[ 0 ],
38
+ node.arguments[ 1 ].range[ 0 ]
39
+ ],
40
+ ''
41
+ )
42
+ ] : null
43
+ } );
49
44
  }
50
- };
51
- }
45
+ }
46
+ } )
52
47
  };
@@ -94,28 +94,26 @@ module.exports = {
94
94
  schema: []
95
95
  },
96
96
 
97
- create: function ( context ) {
98
- return {
99
- 'CallExpression:exit': function ( node ) {
100
- if ( node.callee.type !== 'MemberExpression' ) {
101
- return;
102
- }
103
- const name = node.callee.property.name;
104
- if (
105
- !name ||
97
+ create: ( context ) => ( {
98
+ 'CallExpression:exit': ( node ) => {
99
+ if ( node.callee.type !== 'MemberExpression' ) {
100
+ return;
101
+ }
102
+ const name = node.callee.property.name;
103
+ if (
104
+ !name ||
106
105
  methodsWithRules.includes( name ) ||
107
106
  utils.isjQueryConstructor( context, node.callee.object.name )
108
- ) {
109
- return;
110
- }
111
- if ( utils.isjQuery( context, node.callee ) ) {
112
- context.report( {
113
- node: node,
114
- message: '.{{name}} is not allowed',
115
- data: { name: name }
116
- } );
117
- }
107
+ ) {
108
+ return;
109
+ }
110
+ if ( utils.isjQuery( context, node.callee ) ) {
111
+ context.report( {
112
+ node,
113
+ message: '.{{name}} is not allowed',
114
+ data: { name }
115
+ } );
118
116
  }
119
- };
120
- }
117
+ }
118
+ } )
121
119
  };
@@ -62,27 +62,25 @@ module.exports = {
62
62
  schema: []
63
63
  },
64
64
 
65
- create: function ( context ) {
66
- return {
67
- 'CallExpression:exit': function ( node ) {
68
- if ( node.callee.type !== 'MemberExpression' ) {
69
- return;
70
- }
71
- const name = node.callee.property.name;
72
- if (
73
- !name ||
65
+ create: ( context ) => ( {
66
+ 'CallExpression:exit': ( node ) => {
67
+ if ( node.callee.type !== 'MemberExpression' ) {
68
+ return;
69
+ }
70
+ const name = node.callee.property.name;
71
+ if (
72
+ !name ||
74
73
  utilsWithRules.includes( name ) ||
75
74
  !utils.isjQueryConstructor( context, node.callee.object.name )
76
- ) {
77
- return;
78
- }
79
-
80
- context.report( {
81
- node: node,
82
- message: '$.{{name}} is not allowed',
83
- data: { name: name }
84
- } );
75
+ ) {
76
+ return;
85
77
  }
86
- };
87
- }
78
+
79
+ context.report( {
80
+ node,
81
+ message: '$.{{name}} is not allowed',
82
+ data: { name }
83
+ } );
84
+ }
85
+ } )
88
86
  };
@@ -56,89 +56,82 @@ module.exports = {
56
56
  ]
57
57
  },
58
58
 
59
- create: function ( context ) {
60
- return {
61
- 'CallExpression:exit': function ( node ) {
62
- let allowSingle,
63
- message = 'Prefer DOM building to parsing HTML literals';
59
+ create: ( context ) => ( {
60
+ 'CallExpression:exit': ( node ) => {
61
+ let allowSingle,
62
+ message = 'Prefer DOM building to parsing HTML literals';
64
63
 
65
- if ( node.callee.type === 'Identifier' ) {
66
- if ( !(
67
- utils.isjQueryConstructor( context, node.callee.name ) &&
64
+ if ( node.callee.type === 'Identifier' ) {
65
+ if ( !(
66
+ utils.isjQueryConstructor( context, node.callee.name ) &&
68
67
  node.arguments[ 0 ] &&
69
68
  (
70
69
  node.arguments[ 0 ].type === 'Literal' ||
71
70
  node.arguments[ 0 ].type === 'BinaryExpression'
72
71
  )
73
- ) ) {
74
- return;
75
- }
76
- allowSingle = true;
77
- } else if ( node.callee.type === 'MemberExpression' ) {
78
- if (
79
- utils.isjQueryConstructor( context, node.callee.object.name ) &&
72
+ ) ) {
73
+ return;
74
+ }
75
+ allowSingle = true;
76
+ } else if ( node.callee.type === 'MemberExpression' ) {
77
+ if (
78
+ utils.isjQueryConstructor( context, node.callee.object.name ) &&
80
79
  node.callee.property.name === 'parseHTML'
81
- ) {
82
- allowSingle = false;
83
- } else if (
84
- [ 'html', 'append', 'add' ].includes( node.callee.property.name ) &&
80
+ ) {
81
+ allowSingle = false;
82
+ } else if (
83
+ [ 'html', 'append', 'add' ].includes( node.callee.property.name ) &&
85
84
  utils.isjQuery( context, node )
86
- ) {
87
- allowSingle = true;
88
- } else {
89
- return;
90
- }
85
+ ) {
86
+ allowSingle = true;
91
87
  } else {
92
88
  return;
93
89
  }
90
+ } else {
91
+ return;
92
+ }
94
93
 
95
- let expectedTag;
96
- const arg = node.arguments[ 0 ];
97
- if ( allowSingle ) {
98
- const value = arg && allLiteral( arg ) && joinLiterals( arg );
99
- if ( !( typeof value === 'string' && value ) || !rquickExpr.exec( value ) ) {
100
- // Empty or non-string, or non-HTML
101
- return;
102
- }
103
- let match;
104
- if ( ( match = rsingleTag.exec( value ) ) ) {
105
- // Single tag
106
- const singleTagStyle = ( context.options[ 0 ] && context.options[ 0 ].singleTagStyle ) || 'minimal';
107
- if ( singleTagStyle === 'minimal' ) {
108
- if ( !rsingleTagMinimal.exec( value ) ) {
109
- expectedTag = '<' + match[ 1 ] + '>';
110
- message = 'Single tag must use the format: ' + expectedTag;
111
- } else {
112
- return;
113
- }
114
- } else if ( singleTagStyle === 'self-closing' ) {
115
- if ( !rsingleTagSelfClosing.exec( value ) ) {
116
- expectedTag = '<' + match[ 1 ] + '/>';
117
- message = 'Single tag must use the format: ' + expectedTag;
118
- } else {
119
- return;
120
- }
94
+ let expectedTag;
95
+ const arg = node.arguments[ 0 ];
96
+ if ( allowSingle ) {
97
+ const value = arg && allLiteral( arg ) && joinLiterals( arg );
98
+ if ( !( typeof value === 'string' && value ) || !rquickExpr.exec( value ) ) {
99
+ // Empty or non-string, or non-HTML
100
+ return;
101
+ }
102
+ let match;
103
+ if ( ( match = rsingleTag.exec( value ) ) ) {
104
+ // Single tag
105
+ const singleTagStyle = ( context.options[ 0 ] && context.options[ 0 ].singleTagStyle ) || 'minimal';
106
+ if ( singleTagStyle === 'minimal' ) {
107
+ if ( !rsingleTagMinimal.exec( value ) ) {
108
+ expectedTag = '<' + match[ 1 ] + '>';
109
+ message = 'Single tag must use the format: ' + expectedTag;
121
110
  } else {
122
- // singleTagStyle === 'any'
123
111
  return;
124
112
  }
125
- }
126
- } else if ( !( arg && allLiteral( arg ) ) ) {
127
- // Non literals passed to $.parseHTML
128
- return;
129
- }
130
-
131
- context.report( {
132
- node: node,
133
- message: message,
134
- fix: function ( fixer ) {
135
- if ( expectedTag ) {
136
- return fixer.replaceText( arg, '"' + expectedTag + '"' );
113
+ } else if ( singleTagStyle === 'self-closing' ) {
114
+ if ( !rsingleTagSelfClosing.exec( value ) ) {
115
+ expectedTag = '<' + match[ 1 ] + '/>';
116
+ message = 'Single tag must use the format: ' + expectedTag;
117
+ } else {
118
+ return;
137
119
  }
138
- return null;
120
+ } else {
121
+ // singleTagStyle === 'any'
122
+ return;
139
123
  }
140
- } );
124
+ }
125
+ } else if ( !( arg && allLiteral( arg ) ) ) {
126
+ // Non literals passed to $.parseHTML
127
+ return;
141
128
  }
142
- };
143
- }
129
+
130
+ context.report( {
131
+ node,
132
+ message,
133
+ fix: ( fixer ) => expectedTag ? fixer.replaceText( arg, '"' + expectedTag + '"' ) : null
134
+ } );
135
+ }
136
+ } )
144
137
  };
@@ -7,8 +7,6 @@ module.exports = utils.createUtilMethodRule(
7
7
  'Prefer `JSON.parse` to `$.parseJSON`',
8
8
  {
9
9
  fixable: 'code',
10
- fix: function ( node, context, fixer ) {
11
- return fixer.replaceText( node.callee, 'JSON.parse' );
12
- }
10
+ fix: ( node, context, fixer ) => fixer.replaceText( node.callee, 'JSON.parse' )
13
11
  }
14
12
  );
@@ -7,7 +7,7 @@ module.exports = utils.createUtilMethodRule(
7
7
  'Prefer `DOMParser#parseFromString` to `$.parseXML`',
8
8
  {
9
9
  fixable: 'code',
10
- fix: function ( node, context, fixer ) {
10
+ fix: ( node, context, fixer ) => {
11
11
  if ( node.arguments.length ) {
12
12
  return [
13
13
  fixer.replaceText( node.callee, '( new window.DOMParser() ).parseFromString' ),
@@ -6,5 +6,5 @@ module.exports = utils.createCollectionOrUtilMethodRule(
6
6
  [ 'prop', 'removeProp' ],
7
7
  ( node ) => node === true ?
8
8
  'Prefer direct property access' :
9
- `Prefer direct property access to .${node.callee.property.name}/$.${node.callee.property.name}`
9
+ `Prefer direct property access to .${ node.callee.property.name }/$.${ node.callee.property.name }`
10
10
  );
@@ -7,7 +7,7 @@ module.exports = utils.createUtilMethodRule(
7
7
  'Prefer `Function#bind` to `$.proxy`',
8
8
  {
9
9
  fixable: 'code',
10
- fix: function ( node, context, fixer ) {
10
+ fix: ( node, context, fixer ) => {
11
11
  if (
12
12
  node.arguments.length >= 2 &&
13
13
  node.arguments[ 1 ].type !== 'Literal'
@@ -7,7 +7,7 @@ module.exports = utils.createCollectionMethodRule(
7
7
  'Prefer `$()` to `.ready`',
8
8
  {
9
9
  fixable: 'code',
10
- fix: function ( node, context, fixer ) {
10
+ fix: ( node, context, fixer ) => {
11
11
  if ( node.parent.type === 'ExpressionStatement' ) {
12
12
  return fixer.replaceText( node.callee, '$' );
13
13
  }
@@ -30,16 +30,14 @@ module.exports = {
30
30
  schema: []
31
31
  },
32
32
 
33
- create: function ( context ) {
34
- return {
35
- 'CallExpression:exit': function ( node ) {
36
- if ( isDirect( context, node ) || isChained( context, node ) ) {
37
- context.report( {
38
- node: node,
39
- message: '.ready is not allowed'
40
- } );
41
- }
33
+ create: ( context ) => ( {
34
+ 'CallExpression:exit': ( node ) => {
35
+ if ( isDirect( context, node ) || isChained( context, node ) ) {
36
+ context.report( {
37
+ node,
38
+ message: '.ready is not allowed'
39
+ } );
42
40
  }
43
- };
44
- }
41
+ }
42
+ } )
45
43
  };
@@ -6,5 +6,5 @@ module.exports = utils.createCollectionMethodRule(
6
6
  [ 'serialize', 'serializeArray' ],
7
7
  ( node ) => node === true ?
8
8
  'Prefer `FormData` or `URLSearchParams`' :
9
- `Prefer FormData or URLSearchParams to .${node.callee.property.name}`
9
+ `Prefer FormData or URLSearchParams to .${ node.callee.property.name }`
10
10
  );
@@ -7,8 +7,6 @@ module.exports = utils.createCollectionMethodRule(
7
7
  'Prefer `.length` to `.size`',
8
8
  {
9
9
  fixable: 'code',
10
- fix: function ( node, context, fixer ) {
11
- return fixer.replaceTextRange( [ node.callee.property.range[ 0 ], node.range[ 1 ] ], 'length' );
12
- }
10
+ fix: ( node, context, fixer ) => fixer.replaceTextRange( [ node.callee.property.range[ 0 ], node.range[ 1 ] ], 'length' )
13
11
  }
14
12
  );