@maz-ui/eslint-config 4.0.0-beta.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 LouisMazel
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,164 @@
1
+ # @maz-ui/eslint-config
2
+
3
+ Reusable ESLint configuration for JavaScript/TypeScript projects.
4
+
5
+ ## Features
6
+
7
+ - 🚀 **Based on @antfu/eslint-config** - Modern and performant configuration
8
+ - 🛡️ **Strict TypeScript** - Full TypeScript support
9
+ - 🎨 **Tailwind CSS** - Rules for Tailwind CSS (with Tailwind CSS plugin)
10
+ - 🔍 **SonarJS** - Code quality with SonarJS (with SonarJS plugin)
11
+ - ⚙️ **Configurable** - Flexible and extensible options
12
+ - 📦 **Production ready** - Optimized for production environments
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ pnpm add -D @maz-ui/eslint-config eslint
18
+ ```
19
+
20
+ ## Basic usage
21
+
22
+ ```js
23
+ // eslint.config.js
24
+ import { defineConfig } from '@maz-ui/eslint-config'
25
+
26
+ export default defineConfig()
27
+ ```
28
+
29
+ ## Custom configuration
30
+
31
+ ```js
32
+ // eslint.config.js
33
+ import { defineConfig } from '@maz-ui/eslint-config'
34
+
35
+ export default defineConfig({
36
+ // Environment (affects console rules)
37
+ env: 'production', // 'development' | 'production'
38
+
39
+ // Enable/disable plugins
40
+ typescript: true,
41
+ tailwindcss: true,
42
+ sonarjs: true,
43
+ formatters: true,
44
+
45
+ // Files to ignore
46
+ ignores: ['custom-dist/**'],
47
+
48
+ // Custom rules
49
+ rules: {
50
+ 'no-console': 'error',
51
+ 'prefer-const': 'warn'
52
+ }
53
+ })
54
+ ```
55
+
56
+ ## Available options
57
+
58
+ ```typescript
59
+ interface MazESLintOptions {
60
+ typescript?: boolean // TypeScript support (default: true)
61
+ tailwindcss?: boolean // Tailwind CSS rules (default: true)
62
+ sonarjs?: boolean // SonarJS rules (default: true)
63
+ formatters?: boolean // Formatters support (default: true)
64
+ env?: 'development' | 'production' // Environment (default: 'development')
65
+ ignores?: string[] // Files to ignore
66
+ rules?: Record<string, any> // Custom ESLint rules
67
+ }
68
+ ```
69
+
70
+ ## Advanced usage
71
+
72
+ ### Selective rule imports
73
+
74
+ ```js
75
+ import { baseRules, sonarjsRules, tailwindcssRules } from '@maz-ui/eslint-config'
76
+
77
+ export default [
78
+ {
79
+ rules: {
80
+ ...baseRules,
81
+ ...sonarjsRules,
82
+ // Your custom rules
83
+ }
84
+ }
85
+ ]
86
+ ```
87
+
88
+ ### Example for Vue project
89
+
90
+ ```js
91
+ // eslint.config.js
92
+ import { defineConfig } from '@maz-ui/eslint-config'
93
+
94
+ export default defineConfig({
95
+ env: 'production',
96
+ rules: {
97
+ 'vue/custom-event-name-casing': ['error', 'kebab-case'],
98
+ 'vue/no-undef-components': ['error', {
99
+ ignorePatterns: ['RouterView', 'RouterLink']
100
+ }]
101
+ }
102
+ })
103
+ ```
104
+
105
+ ## Included rules
106
+
107
+ ### Base (JavaScript/TypeScript)
108
+
109
+ - Console management by environment
110
+ - Code quality rules
111
+ - Optimized TypeScript support
112
+
113
+ ### SonarJS
114
+
115
+ - Limited cognitive complexity
116
+ - Duplicate code detection
117
+ - Security best practices
118
+
119
+ ### Tailwind CSS
120
+
121
+ - Consistent class ordering
122
+ - Contradictory class detection
123
+ - Valid Tailwind syntax
124
+
125
+ ## Compatibility
126
+
127
+ - **ESLint** ^9.0.0
128
+ - **Node.js** >=18.0.0
129
+ - **TypeScript** ^5.0.0
130
+
131
+ ## Usage examples
132
+
133
+ ### Simple JavaScript project
134
+
135
+ ```js
136
+ export default defineConfig({
137
+ typescript: false,
138
+ tailwindcss: false
139
+ })
140
+ ```
141
+
142
+ ### Project with Tailwind
143
+
144
+ ```js
145
+ export default defineConfig({
146
+ tailwindcss: true,
147
+ rules: {
148
+ 'tailwindcss/classnames-order': 'error'
149
+ }
150
+ })
151
+ ```
152
+
153
+ ### Production project
154
+
155
+ ```js
156
+ export default defineConfig({
157
+ env: 'production',
158
+ sonarjs: true,
159
+ rules: {
160
+ 'no-console': 'error',
161
+ 'no-debugger': 'error'
162
+ }
163
+ })
164
+ ```
@@ -0,0 +1,106 @@
1
+ import { antfu, OptionsConfig, Rules, TypedFlatConfigItem } from '@antfu/eslint-config';
2
+ import { Linter } from 'eslint';
3
+
4
+ type MazESLintUserConfig = TypedFlatConfigItem | TypedFlatConfigItem[] | Linter.Config | Linter.Config[];
5
+ interface MazESLintOptions extends OptionsConfig {
6
+ /**
7
+ * Enable Tailwind CSS support
8
+ * @default true
9
+ */
10
+ tailwindcss?: boolean;
11
+ /**
12
+ * Enable SonarJS rules for code quality
13
+ * @default true
14
+ */
15
+ sonarjs?: boolean;
16
+ /**
17
+ * Enable Vue Accessibility plugin
18
+ * @default false
19
+ */
20
+ vueAccessibility?: boolean;
21
+ /**
22
+ * Environment (affects console warnings/errors)
23
+ * @default 'development'
24
+ */
25
+ env?: 'development' | 'production';
26
+ /**
27
+ * Files to ignore
28
+ * @default ['**\/*.md', 'dist/**', 'node_modules/**']
29
+ */
30
+ ignores?: string[];
31
+ /**
32
+ * Additional rules to merge
33
+ */
34
+ rules?: Partial<Rules>;
35
+ }
36
+ type MazESLintConfig = ReturnType<typeof antfu>;
37
+
38
+ /**
39
+ * Base ESLint rules for JavaScript/TypeScript projects
40
+ * Optimized for code quality and consistency
41
+ */
42
+ declare function baseRules(isProduction: boolean): Partial<Rules>;
43
+
44
+ /**
45
+ * SonarJS rules configuration
46
+ * Focused on code quality and maintainability
47
+ */
48
+ declare const sonarjsRules: {
49
+ readonly 'sonarjs/no-duplicate-string': "off";
50
+ readonly 'sonarjs/class-name': "off";
51
+ readonly 'sonarjs/no-nested-conditional': "off";
52
+ readonly 'sonarjs/sonar-no-unused-vars': "off";
53
+ readonly 'sonarjs/cognitive-complexity': readonly ["error", 20];
54
+ readonly 'sonarjs/no-identical-functions': "error";
55
+ readonly 'sonarjs/no-collapsible-if': "error";
56
+ readonly 'sonarjs/prefer-immediate-return': "error";
57
+ readonly 'sonarjs/prefer-object-literal': "error";
58
+ readonly 'sonarjs/prefer-single-boolean-return': "error";
59
+ };
60
+ /**
61
+ * SonarJS rules for test files
62
+ */
63
+ declare const sonarjsTestRules: {
64
+ readonly 'sonarjs/no-nested-functions': "off";
65
+ readonly 'sonarjs/cognitive-complexity': "off";
66
+ readonly 'sonarjs/no-hardcoded-credentials': "off";
67
+ readonly 'sonarjs/no-duplicate-string': "off";
68
+ };
69
+
70
+ /**
71
+ * Tailwind CSS ESLint rules configuration
72
+ */
73
+ declare const tailwindcssRules: {
74
+ readonly 'tailwindcss/no-custom-classname': "off";
75
+ readonly 'tailwindcss/classnames-order': "warn";
76
+ readonly 'tailwindcss/no-contradicting-classname': "error";
77
+ readonly 'tailwindcss/enforces-negative-arbitrary-values': "error";
78
+ readonly 'tailwindcss/enforces-shorthand': "warn";
79
+ };
80
+
81
+ declare const vueRules: {
82
+ 'vue/custom-event-name-casing': ["error", "kebab-case"];
83
+ };
84
+
85
+ /**
86
+ * Create ESLint configuration for Maz-UI and JavaScript/TypeScript projects
87
+ *
88
+ * @param options Configuration options
89
+ * @returns ESLint flat config array
90
+ *
91
+ * @example
92
+ * ```js
93
+ * import { defineConfig } from '@maz-ui/eslint-config'
94
+ *
95
+ * export default defineConfig({
96
+ * env: 'production',
97
+ * rules: {
98
+ * 'no-console': 'error'
99
+ * }
100
+ * })
101
+ * ```
102
+ */
103
+ declare function defineConfig(options?: MazESLintOptions, ...userConfigs: MazESLintUserConfig[]): MazESLintConfig;
104
+
105
+ export { baseRules, defineConfig, sonarjsRules, sonarjsTestRules, tailwindcssRules, vueRules };
106
+ export type { MazESLintConfig, MazESLintOptions };
@@ -0,0 +1,106 @@
1
+ import { antfu, OptionsConfig, Rules, TypedFlatConfigItem } from '@antfu/eslint-config';
2
+ import { Linter } from 'eslint';
3
+
4
+ type MazESLintUserConfig = TypedFlatConfigItem | TypedFlatConfigItem[] | Linter.Config | Linter.Config[];
5
+ interface MazESLintOptions extends OptionsConfig {
6
+ /**
7
+ * Enable Tailwind CSS support
8
+ * @default true
9
+ */
10
+ tailwindcss?: boolean;
11
+ /**
12
+ * Enable SonarJS rules for code quality
13
+ * @default true
14
+ */
15
+ sonarjs?: boolean;
16
+ /**
17
+ * Enable Vue Accessibility plugin
18
+ * @default false
19
+ */
20
+ vueAccessibility?: boolean;
21
+ /**
22
+ * Environment (affects console warnings/errors)
23
+ * @default 'development'
24
+ */
25
+ env?: 'development' | 'production';
26
+ /**
27
+ * Files to ignore
28
+ * @default ['**\/*.md', 'dist/**', 'node_modules/**']
29
+ */
30
+ ignores?: string[];
31
+ /**
32
+ * Additional rules to merge
33
+ */
34
+ rules?: Partial<Rules>;
35
+ }
36
+ type MazESLintConfig = ReturnType<typeof antfu>;
37
+
38
+ /**
39
+ * Base ESLint rules for JavaScript/TypeScript projects
40
+ * Optimized for code quality and consistency
41
+ */
42
+ declare function baseRules(isProduction: boolean): Partial<Rules>;
43
+
44
+ /**
45
+ * SonarJS rules configuration
46
+ * Focused on code quality and maintainability
47
+ */
48
+ declare const sonarjsRules: {
49
+ readonly 'sonarjs/no-duplicate-string': "off";
50
+ readonly 'sonarjs/class-name': "off";
51
+ readonly 'sonarjs/no-nested-conditional': "off";
52
+ readonly 'sonarjs/sonar-no-unused-vars': "off";
53
+ readonly 'sonarjs/cognitive-complexity': readonly ["error", 20];
54
+ readonly 'sonarjs/no-identical-functions': "error";
55
+ readonly 'sonarjs/no-collapsible-if': "error";
56
+ readonly 'sonarjs/prefer-immediate-return': "error";
57
+ readonly 'sonarjs/prefer-object-literal': "error";
58
+ readonly 'sonarjs/prefer-single-boolean-return': "error";
59
+ };
60
+ /**
61
+ * SonarJS rules for test files
62
+ */
63
+ declare const sonarjsTestRules: {
64
+ readonly 'sonarjs/no-nested-functions': "off";
65
+ readonly 'sonarjs/cognitive-complexity': "off";
66
+ readonly 'sonarjs/no-hardcoded-credentials': "off";
67
+ readonly 'sonarjs/no-duplicate-string': "off";
68
+ };
69
+
70
+ /**
71
+ * Tailwind CSS ESLint rules configuration
72
+ */
73
+ declare const tailwindcssRules: {
74
+ readonly 'tailwindcss/no-custom-classname': "off";
75
+ readonly 'tailwindcss/classnames-order': "warn";
76
+ readonly 'tailwindcss/no-contradicting-classname': "error";
77
+ readonly 'tailwindcss/enforces-negative-arbitrary-values': "error";
78
+ readonly 'tailwindcss/enforces-shorthand': "warn";
79
+ };
80
+
81
+ declare const vueRules: {
82
+ 'vue/custom-event-name-casing': ["error", "kebab-case"];
83
+ };
84
+
85
+ /**
86
+ * Create ESLint configuration for Maz-UI and JavaScript/TypeScript projects
87
+ *
88
+ * @param options Configuration options
89
+ * @returns ESLint flat config array
90
+ *
91
+ * @example
92
+ * ```js
93
+ * import { defineConfig } from '@maz-ui/eslint-config'
94
+ *
95
+ * export default defineConfig({
96
+ * env: 'production',
97
+ * rules: {
98
+ * 'no-console': 'error'
99
+ * }
100
+ * })
101
+ * ```
102
+ */
103
+ declare function defineConfig(options?: MazESLintOptions, ...userConfigs: MazESLintUserConfig[]): MazESLintConfig;
104
+
105
+ export { baseRules, defineConfig, sonarjsRules, sonarjsTestRules, tailwindcssRules, vueRules };
106
+ export type { MazESLintConfig, MazESLintOptions };
package/dist/index.mjs ADDED
@@ -0,0 +1,151 @@
1
+ import antfu from '@antfu/eslint-config';
2
+ import sonarjs from 'eslint-plugin-sonarjs';
3
+ import tailwind from 'eslint-plugin-tailwindcss';
4
+ import vueA11y from 'eslint-plugin-vuejs-accessibility';
5
+
6
+ function baseRules(isProduction) {
7
+ return {
8
+ // Console warnings in development, errors in production
9
+ "no-console": [isProduction ? "error" : "warn"],
10
+ // Code quality
11
+ "prefer-regex-literals": "off",
12
+ "require-await": "error",
13
+ // Import/export
14
+ "node/prefer-global/process": "off",
15
+ // Disable overly strict rules
16
+ "no-unused-vars": "off",
17
+ // Handled by TypeScript
18
+ "ts/no-unused-vars": ["error", {
19
+ argsIgnorePattern: "^_",
20
+ varsIgnorePattern: "^_"
21
+ }],
22
+ // Allow reasonable complexity
23
+ "complexity": ["error", { max: 20 }],
24
+ "max-depth": ["error", { max: 4 }],
25
+ "max-nested-callbacks": ["error", { max: 3 }]
26
+ };
27
+ }
28
+
29
+ const markdown = {
30
+ ignores: ["**/*.md"],
31
+ rules: {
32
+ "ts/no-unused-vars": "off",
33
+ "sonarjs/unused-import": "off"
34
+ }
35
+ };
36
+
37
+ const sonarjsRules = {
38
+ // Disable overly strict SonarJS rules
39
+ "sonarjs/no-duplicate-string": "off",
40
+ "sonarjs/class-name": "off",
41
+ "sonarjs/no-nested-conditional": "off",
42
+ "sonarjs/sonar-no-unused-vars": "off",
43
+ "sonarjs/cognitive-complexity": ["error", 20],
44
+ // Keep useful SonarJS rules
45
+ "sonarjs/no-identical-functions": "error",
46
+ "sonarjs/no-collapsible-if": "error",
47
+ "sonarjs/prefer-immediate-return": "error",
48
+ "sonarjs/prefer-object-literal": "error",
49
+ "sonarjs/prefer-single-boolean-return": "error"
50
+ };
51
+ const sonarjsTestRules = {
52
+ "sonarjs/no-nested-functions": "off",
53
+ "sonarjs/cognitive-complexity": "off",
54
+ "sonarjs/no-hardcoded-credentials": "off",
55
+ "sonarjs/no-duplicate-string": "off"
56
+ };
57
+
58
+ const tailwindcssRules = {
59
+ // Allow custom class names (useful for component libraries)
60
+ "tailwindcss/no-custom-classname": "off",
61
+ // Enforce consistent class ordering
62
+ "tailwindcss/classnames-order": "warn",
63
+ // Prevent contradicting classes
64
+ "tailwindcss/no-contradicting-classname": "error",
65
+ // Enforce valid Tailwind syntax
66
+ "tailwindcss/enforces-negative-arbitrary-values": "error",
67
+ "tailwindcss/enforces-shorthand": "warn"
68
+ };
69
+
70
+ const testRules = {
71
+ "max-nested-callbacks": "off"
72
+ };
73
+
74
+ const vueRules = {
75
+ "vue/custom-event-name-casing": ["error", "kebab-case"]
76
+ };
77
+
78
+ const defaultOptions = {
79
+ formatters: true,
80
+ typescript: true,
81
+ sonarjs: true,
82
+ tailwindcss: false,
83
+ ignores: ["dist/**", "node_modules/**"],
84
+ rules: {}
85
+ };
86
+ function defineConfig(options = {}, ...userConfigs) {
87
+ const opts = { ...defaultOptions, ...options };
88
+ const env = opts.env || process.env.NODE_ENV || "production";
89
+ let allRules = {
90
+ ...baseRules(env === "production"),
91
+ ...opts.rules
92
+ };
93
+ if (opts.vue || opts.formatters) {
94
+ allRules = {
95
+ ...allRules,
96
+ ...vueRules
97
+ };
98
+ }
99
+ const additionalConfigs = [];
100
+ if (opts.sonarjs) {
101
+ additionalConfigs.push(sonarjs.configs.recommended);
102
+ additionalConfigs.push({
103
+ rules: {
104
+ ...sonarjs.configs.recommended.rules
105
+ }
106
+ });
107
+ additionalConfigs.push({
108
+ files: ["**/*.spec.ts", "**/*.test.ts", "**/*.spec.js", "**/*.test.js"],
109
+ rules: sonarjsTestRules
110
+ });
111
+ }
112
+ if (opts.vueAccessibility) {
113
+ const vueA11yConfigs = vueA11y.configs["flat/recommended"];
114
+ const configsArray = Array.isArray(vueA11yConfigs) ? vueA11yConfigs : [vueA11yConfigs];
115
+ const fixedConfigs = configsArray.map((config) => {
116
+ if (config && config.languageOptions && config.languageOptions.globals) {
117
+ const fixedGlobals = { ...config.languageOptions.globals };
118
+ if ("AudioWorkletGlobalScope " in fixedGlobals) {
119
+ fixedGlobals.AudioWorkletGlobalScope = fixedGlobals["AudioWorkletGlobalScope "];
120
+ delete fixedGlobals["AudioWorkletGlobalScope "];
121
+ }
122
+ return {
123
+ ...config,
124
+ languageOptions: {
125
+ ...config.languageOptions,
126
+ globals: fixedGlobals
127
+ }
128
+ };
129
+ }
130
+ return config;
131
+ });
132
+ additionalConfigs.push(...fixedConfigs);
133
+ }
134
+ if (opts.tailwindcss) {
135
+ additionalConfigs.push(...tailwind.configs["flat/recommended"]);
136
+ additionalConfigs.push({
137
+ rules: tailwindcssRules
138
+ });
139
+ }
140
+ additionalConfigs.push({
141
+ files: ["**/*.spec.ts", "**/*.test.ts", "**/*.spec.js", "**/*.test.js"],
142
+ rules: testRules
143
+ });
144
+ return antfu({
145
+ formatters: opts.formatters,
146
+ ...opts,
147
+ rules: allRules
148
+ }, ...additionalConfigs, ...userConfigs, markdown);
149
+ }
150
+
151
+ export { baseRules, defineConfig, sonarjsRules, sonarjsTestRules, tailwindcssRules, vueRules };
package/package.json ADDED
@@ -0,0 +1,85 @@
1
+ {
2
+ "name": "@maz-ui/eslint-config",
3
+ "type": "module",
4
+ "version": "4.0.0-beta.0",
5
+ "description": "ESLint configuration for JavaScript/TypeScript projects",
6
+ "author": "Louis Mazel <me@loicmazuel.com>",
7
+ "license": "MIT",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/LouisMazel/maz-ui.git"
11
+ },
12
+ "bugs": "https://github.com/LouisMazel/maz-ui/issues",
13
+ "keywords": [
14
+ "eslint",
15
+ "eslint-config",
16
+ "javascript",
17
+ "typescript",
18
+ "code-quality",
19
+ "maz-ui"
20
+ ],
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/index.d.ts",
27
+ "import": "./dist/index.mjs"
28
+ },
29
+ "./*": "./*"
30
+ },
31
+ "main": "./dist/index.mjs",
32
+ "types": "./dist/index.d.ts",
33
+ "files": [
34
+ "LICENSE",
35
+ "README.md",
36
+ "dist"
37
+ ],
38
+ "engines": {
39
+ "node": ">=18.0.0"
40
+ },
41
+ "scripts": {
42
+ "build": "unbuild",
43
+ "dev": "unbuild --stub",
44
+ "typecheck": "tsc --noEmit --skipLibCheck",
45
+ "lint": "eslint .",
46
+ "lint:fix": "eslint . --fix",
47
+ "pre-commit": "lint-staged"
48
+ },
49
+ "peerDependencies": {
50
+ "eslint-plugin-format": "^1.0.1",
51
+ "eslint-plugin-sonarjs": "^3.0.2",
52
+ "eslint-plugin-tailwindcss": "^3.18.0",
53
+ "eslint-plugin-vuejs-accessibility": "^2.4.0"
54
+ },
55
+ "peerDependenciesMeta": {
56
+ "eslint-plugin-format": {
57
+ "optional": true
58
+ },
59
+ "eslint-plugin-sonarjs": {
60
+ "optional": true
61
+ },
62
+ "eslint-plugin-tailwindcss": {
63
+ "optional": true
64
+ },
65
+ "eslint-plugin-vuejs-accessibility": {
66
+ "optional": true
67
+ }
68
+ },
69
+ "dependencies": {
70
+ "@antfu/eslint-config": "^4.14.1"
71
+ },
72
+ "devDependencies": {
73
+ "@types/eslint-plugin-tailwindcss": "^3.17.0",
74
+ "eslint": "^9.29.0",
75
+ "eslint-plugin-format": "^1.0.1",
76
+ "typescript": "^5.8.3",
77
+ "unbuild": "^3.5.0"
78
+ },
79
+ "lint-staged": {
80
+ "*.{js,jsx,ts,tsx,mjs,mts,cjs,md}": [
81
+ "eslint --fix"
82
+ ]
83
+ },
84
+ "gitHead": "9ef7beb4feeee0b0cb44e7df8af7115d5d5ef334"
85
+ }