mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
* Move .eslintrc (yaml) to .eslintrc.js (js) * Add Prettier setup to ESLint * Run Prettier on @kbn/build * Update style guide with Prettier
This commit is contained in:
parent
421a594f12
commit
f5b3b46170
20 changed files with 134 additions and 66 deletions
10
.eslintrc
10
.eslintrc
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
extends:
|
||||
- '@elastic/eslint-config-kibana'
|
||||
- '@elastic/eslint-config-kibana/jest'
|
||||
|
||||
settings:
|
||||
import/resolver:
|
||||
'@elastic/eslint-import-resolver-kibana':
|
||||
rootPackageName: 'kibana'
|
||||
kibanaPath: .
|
33
.eslintrc.js
Normal file
33
.eslintrc.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
module.exports = {
|
||||
extends: [
|
||||
'@elastic/eslint-config-kibana',
|
||||
'@elastic/eslint-config-kibana/jest',
|
||||
],
|
||||
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
'@elastic/eslint-import-resolver-kibana': {
|
||||
rootPackageName: 'kibana',
|
||||
kibanaPath: '.',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
overrides: [
|
||||
// Enable Prettier
|
||||
{
|
||||
files: [
|
||||
'.eslintrc.js',
|
||||
'packages/kbn-build/**/*.js',
|
||||
],
|
||||
plugins: [
|
||||
'prettier',
|
||||
],
|
||||
rules: Object.assign(
|
||||
{ 'prettier/prettier': 'error' },
|
||||
require('eslint-config-prettier').rules,
|
||||
require('eslint-config-prettier/react').rules,
|
||||
),
|
||||
},
|
||||
]
|
||||
}
|
4
.prettierrc
Normal file
4
.prettierrc
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5"
|
||||
}
|
|
@ -74,13 +74,13 @@
|
|||
"url": "https://github.com/elastic/kibana.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"@kbn/babel-preset": "link:packages/kbn-babel-preset",
|
||||
"@elastic/datemath": "4.0.2",
|
||||
"@elastic/eui": "0.0.18",
|
||||
"@elastic/filesaver": "1.1.2",
|
||||
"@elastic/numeral": "2.3.0",
|
||||
"@elastic/test-subj-selector": "0.2.1",
|
||||
"@elastic/ui-ace": "0.2.3",
|
||||
"@kbn/babel-preset": "link:packages/kbn-babel-preset",
|
||||
"JSONStream": "1.1.1",
|
||||
"accept-language-parser": "1.2.0",
|
||||
"angular": "1.6.5",
|
||||
|
@ -233,12 +233,14 @@
|
|||
"enzyme-adapter-react-16": "^1.1.1",
|
||||
"enzyme-to-json": "3.1.4",
|
||||
"eslint": "4.14.0",
|
||||
"eslint-config-prettier": "^2.9.0",
|
||||
"eslint-plugin-babel": "4.1.2",
|
||||
"eslint-plugin-import": "2.8.0",
|
||||
"eslint-plugin-jest": "^21.6.2",
|
||||
"eslint-plugin-mocha": "4.11.0",
|
||||
"eslint-plugin-no-unsanitized": "^2.0.2",
|
||||
"eslint-plugin-prefer-object-spread": "1.2.1",
|
||||
"eslint-plugin-prettier": "^2.6.0",
|
||||
"eslint-plugin-react": "7.5.1",
|
||||
"event-stream": "3.3.2",
|
||||
"expect.js": "0.3.1",
|
||||
|
@ -287,6 +289,7 @@
|
|||
"nock": "8.0.0",
|
||||
"node-sass": "4.5.3",
|
||||
"pixelmatch": "4.0.2",
|
||||
"prettier": "^1.10.2",
|
||||
"proxyquire": "1.7.10",
|
||||
"sass-loader": "6.0.6",
|
||||
"simple-git": "1.37.0",
|
||||
|
|
|
@ -45,8 +45,8 @@ export async function run(argv) {
|
|||
|
||||
const options = getopts(argv, {
|
||||
alias: {
|
||||
h: 'help'
|
||||
}
|
||||
h: 'help',
|
||||
},
|
||||
});
|
||||
|
||||
const args = options._;
|
||||
|
|
|
@ -11,8 +11,8 @@ import { getProjects } from '../../utils/projects';
|
|||
// and more integration-y, as we're trying to not add very slow tests to our
|
||||
// Jest unit tests.
|
||||
|
||||
describe('kbn-build production', function () {
|
||||
it('builds and copies projects for production', async function () {
|
||||
describe('kbn-build production', function() {
|
||||
it('builds and copies projects for production', async function() {
|
||||
this.timeout(60 * 1000);
|
||||
|
||||
const tmpDir = tempy.directory();
|
||||
|
@ -26,7 +26,7 @@ describe('kbn-build production', function () {
|
|||
cwd: fixturesPath,
|
||||
parents: true,
|
||||
nodir: true,
|
||||
dot: true
|
||||
dot: true,
|
||||
});
|
||||
|
||||
const projects = await getProjects(tmpDir, ['./packages/*']);
|
||||
|
@ -34,14 +34,14 @@ describe('kbn-build production', function () {
|
|||
for (const project of projects.values()) {
|
||||
// This will both install dependencies and generate `yarn.lock` files
|
||||
await project.installDependencies({
|
||||
extraArgs: ['--silent', '--no-progress']
|
||||
extraArgs: ['--silent', '--no-progress'],
|
||||
});
|
||||
}
|
||||
|
||||
await buildProductionProjects({ kibanaRoot: tmpDir, buildRoot });
|
||||
|
||||
const files = await globby(['**/*', '!**/node_modules/**'], {
|
||||
cwd: buildRoot
|
||||
cwd: buildRoot,
|
||||
});
|
||||
|
||||
expect(files).to.eql([
|
||||
|
@ -52,7 +52,7 @@ describe('kbn-build production', function () {
|
|||
'packages/foo/package.json',
|
||||
'packages/foo/src/index.js',
|
||||
'packages/foo/target/index.js',
|
||||
'packages/foo/yarn.lock'
|
||||
'packages/foo/yarn.lock',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,18 +6,18 @@ import { getProjectPaths } from '../config';
|
|||
import {
|
||||
getProjects,
|
||||
buildProjectGraph,
|
||||
topologicallyBatchProjects
|
||||
topologicallyBatchProjects,
|
||||
} from '../utils/projects';
|
||||
import {
|
||||
createProductionPackageJson,
|
||||
writePackageJson
|
||||
writePackageJson,
|
||||
} from '../utils/package_json';
|
||||
import { isDirectory } from '../utils/fs';
|
||||
|
||||
export async function buildProductionProjects({ kibanaRoot, buildRoot }) {
|
||||
const projectPaths = getProjectPaths(kibanaRoot, {
|
||||
'skip-kibana': true,
|
||||
'skip-kibana-extra': true
|
||||
'skip-kibana-extra': true,
|
||||
});
|
||||
|
||||
const projects = await getProductionProjects(kibanaRoot, projectPaths);
|
||||
|
@ -81,7 +81,7 @@ async function copyToBuild(project, kibanaRoot, buildRoot) {
|
|||
cwd: project.path,
|
||||
parents: true,
|
||||
nodir: true,
|
||||
dot: true
|
||||
dot: true,
|
||||
});
|
||||
|
||||
const packageJson = project.json;
|
||||
|
|
|
@ -16,7 +16,7 @@ function generateColors() {
|
|||
export function spawn(command, args, opts) {
|
||||
return execa(command, args, {
|
||||
...opts,
|
||||
stdio: 'inherit'
|
||||
stdio: 'inherit',
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -25,14 +25,14 @@ const nextColor = generateColors();
|
|||
export function spawnStreaming(command, args, opts, { prefix }) {
|
||||
const spawned = execa(command, args, {
|
||||
...opts,
|
||||
stdio: ['ignore', 'pipe', 'pipe']
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
});
|
||||
|
||||
const color = nextColor();
|
||||
const prefixedStdout = logTransformer({ tag: `${color.bold(prefix)}:` });
|
||||
const prefixedStderr = logTransformer({
|
||||
tag: `${logSymbols.error} ${color.bold(prefix)}:`,
|
||||
mergeMultiline: true
|
||||
mergeMultiline: true,
|
||||
});
|
||||
|
||||
spawned.stdout.pipe(prefixedStdout).pipe(process.stdout);
|
||||
|
|
|
@ -12,7 +12,7 @@ export function writePackageJson(path, json) {
|
|||
|
||||
export const createProductionPackageJson = pkgJson => ({
|
||||
...pkgJson,
|
||||
dependencies: transformDependencies(pkgJson.dependencies)
|
||||
dependencies: transformDependencies(pkgJson.dependencies),
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,7 +4,7 @@ import chalk from 'chalk';
|
|||
import {
|
||||
installInDir,
|
||||
runScriptInPackage,
|
||||
runScriptInPackageStreaming
|
||||
runScriptInPackageStreaming,
|
||||
} from './scripts';
|
||||
import { readPackageJson } from './package_json';
|
||||
import { CliError } from './errors';
|
||||
|
@ -27,7 +27,7 @@ export class Project {
|
|||
|
||||
this.allDependencies = {
|
||||
...(this.json.devDependencies || {}),
|
||||
...(this.json.dependencies || {})
|
||||
...(this.json.dependencies || {}),
|
||||
};
|
||||
|
||||
this.scripts = this.json.scripts || {};
|
||||
|
@ -53,7 +53,7 @@ export class Project {
|
|||
const meta = {
|
||||
package: `${this.name} (${this.packageJsonLocation})`,
|
||||
expected: `"${project.name}": "${expectedVersionInPackageJson}"`,
|
||||
actual: `"${project.name}": "${versionInPackageJson}"`
|
||||
actual: `"${project.name}": "${versionInPackageJson}"`,
|
||||
};
|
||||
|
||||
if (versionInPackageJson.startsWith(PREFIX)) {
|
||||
|
|
|
@ -9,7 +9,7 @@ const createProjectWith = (fields, path = '') =>
|
|||
{
|
||||
name: 'kibana',
|
||||
version: '1.0.0',
|
||||
...fields
|
||||
...fields,
|
||||
},
|
||||
join(rootPath, path)
|
||||
);
|
||||
|
@ -25,11 +25,11 @@ describe('fromPath', () => {
|
|||
test('fields', async () => {
|
||||
const kibana = createProjectWith({
|
||||
scripts: {
|
||||
test: 'jest'
|
||||
test: 'jest',
|
||||
},
|
||||
dependencies: {
|
||||
foo: '1.2.3'
|
||||
}
|
||||
foo: '1.2.3',
|
||||
},
|
||||
});
|
||||
|
||||
expect(kibana.name).toBe('kibana');
|
||||
|
@ -45,13 +45,13 @@ describe('#ensureValidProjectDependency', () => {
|
|||
test('valid link: version', async () => {
|
||||
const root = createProjectWith({
|
||||
dependencies: {
|
||||
foo: 'link:packages/foo'
|
||||
}
|
||||
foo: 'link:packages/foo',
|
||||
},
|
||||
});
|
||||
|
||||
const foo = createProjectWith(
|
||||
{
|
||||
name: 'foo'
|
||||
name: 'foo',
|
||||
},
|
||||
'packages/foo'
|
||||
);
|
||||
|
@ -63,15 +63,15 @@ describe('#ensureValidProjectDependency', () => {
|
|||
const root = createProjectWith(
|
||||
{
|
||||
dependencies: {
|
||||
foo: 'link:wrong/path'
|
||||
}
|
||||
foo: 'link:wrong/path',
|
||||
},
|
||||
},
|
||||
rootPath
|
||||
);
|
||||
|
||||
const foo = createProjectWith(
|
||||
{
|
||||
name: 'foo'
|
||||
name: 'foo',
|
||||
},
|
||||
'packages/foo'
|
||||
);
|
||||
|
@ -85,15 +85,15 @@ describe('#ensureValidProjectDependency', () => {
|
|||
const root = createProjectWith(
|
||||
{
|
||||
dependencies: {
|
||||
foo: '1.0.0'
|
||||
}
|
||||
foo: '1.0.0',
|
||||
},
|
||||
},
|
||||
rootPath
|
||||
);
|
||||
|
||||
const foo = createProjectWith(
|
||||
{
|
||||
name: 'foo'
|
||||
name: 'foo',
|
||||
},
|
||||
'packages/foo'
|
||||
);
|
||||
|
|
|
@ -19,7 +19,7 @@ export async function getProjects(rootPath, projectsPaths) {
|
|||
|
||||
// Do not match ** against multiple filenames
|
||||
// (This is only specified because we currently don't have a need for it.)
|
||||
noglobstar: true
|
||||
noglobstar: true,
|
||||
};
|
||||
const projects = new Map();
|
||||
|
||||
|
@ -36,7 +36,7 @@ export async function getProjects(rootPath, projectsPaths) {
|
|||
`There are multiple projects with the same name [${project.name}]`,
|
||||
{
|
||||
name: project.name,
|
||||
paths: [project.path, projects.get(project.name).path]
|
||||
paths: [project.path, projects.get(project.name).path],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import { resolve } from 'path';
|
|||
import {
|
||||
getProjects,
|
||||
buildProjectGraph,
|
||||
topologicallyBatchProjects
|
||||
topologicallyBatchProjects,
|
||||
} from './projects';
|
||||
|
||||
const rootPath = resolve(`${__dirname}/__fixtures__/kibana`);
|
||||
|
@ -53,7 +53,7 @@ describe('#buildProjectGraph', () => {
|
|||
const projects = await getProjects(rootPath, [
|
||||
'.',
|
||||
'packages/*',
|
||||
'../plugins/*'
|
||||
'../plugins/*',
|
||||
]);
|
||||
const graph = buildProjectGraph(projects);
|
||||
|
||||
|
@ -71,7 +71,7 @@ describe('#topologicallyBatchProjects', () => {
|
|||
const projects = await getProjects(rootPath, [
|
||||
'.',
|
||||
'packages/*',
|
||||
'../plugins/*'
|
||||
'../plugins/*',
|
||||
]);
|
||||
const graph = buildProjectGraph(projects);
|
||||
|
||||
|
|
|
@ -9,13 +9,13 @@ export function installInDir(directory, extraArgs = []) {
|
|||
'install',
|
||||
'--non-interactive',
|
||||
'--mutex file',
|
||||
...extraArgs
|
||||
...extraArgs,
|
||||
];
|
||||
|
||||
// We pass the mutex flag to ensure only one instance of yarn runs at any
|
||||
// given time (e.g. to avoid conflicts).
|
||||
return spawn(yarnPath, options, {
|
||||
cwd: directory
|
||||
cwd: directory,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ export function installInDir(directory, extraArgs = []) {
|
|||
*/
|
||||
export function runScriptInPackage(script, args, pkg) {
|
||||
const execOpts = {
|
||||
cwd: pkg.path
|
||||
cwd: pkg.path,
|
||||
};
|
||||
|
||||
return spawn(yarnPath, ['run', script, ...args], execOpts);
|
||||
|
@ -35,10 +35,10 @@ export function runScriptInPackage(script, args, pkg) {
|
|||
*/
|
||||
export function runScriptInPackageStreaming(script, args, pkg) {
|
||||
const execOpts = {
|
||||
cwd: pkg.path
|
||||
cwd: pkg.path,
|
||||
};
|
||||
|
||||
return spawnStreaming(yarnPath, ['run', script, ...args], execOpts, {
|
||||
prefix: pkg.name
|
||||
prefix: pkg.name,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ const path = require('path');
|
|||
|
||||
module.exports = {
|
||||
entry: {
|
||||
index: './src/index.js'
|
||||
index: './src/index.js',
|
||||
},
|
||||
target: 'node',
|
||||
|
||||
|
@ -18,8 +18,8 @@ module.exports = {
|
|||
test: /\.js$/,
|
||||
exclude: /(node_modules)/,
|
||||
use: {
|
||||
loader: 'babel-loader'
|
||||
}
|
||||
loader: 'babel-loader',
|
||||
},
|
||||
},
|
||||
// Removing an unnecessary require from
|
||||
// https://github.com/ForbesLindesay/spawn-sync/blob/8ba6d1bd032917ff5f0cf68508b91bb628d16336/index.js#L3
|
||||
|
@ -33,16 +33,16 @@ module.exports = {
|
|||
options: {
|
||||
search: ` || require('./lib/spawn-sync')`,
|
||||
replace: '',
|
||||
strict: true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
strict: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
node: {
|
||||
// Don't replace built-in globals
|
||||
__filename: false,
|
||||
__dirname: false
|
||||
}
|
||||
__dirname: false,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
|
||||
root: true
|
||||
extends: '../../../../.eslintrc'
|
||||
extends: '../../../../.eslintrc.js'
|
||||
|
||||
rules:
|
||||
block-scoped-var: off
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
|
||||
root: true
|
||||
extends: '../../../../.eslintrc'
|
||||
extends: '../../../../.eslintrc.js'
|
||||
|
||||
rules:
|
||||
block-scoped-var: off
|
||||
|
|
|
@ -6,6 +6,15 @@ This JavaScript guide forked from the [node style guide](https://github.com/feli
|
|||
licensed under the [CC BY-SA 3.0](http://creativecommons.org/licenses/by-sa/3.0/)
|
||||
license.
|
||||
|
||||
## Prettier
|
||||
|
||||
We are gradually moving the Kibana code base over to Prettier.
|
||||
|
||||
Prettier is set up to run with ESLint, and to add new code paths to Prettier,
|
||||
see `.eslintrc.js` in the root of the Kibana repo. This also means that if you
|
||||
get ESLint errors related to Prettier, run `node scripts/eslint --fix` from the
|
||||
root of the Kibana repo to fix these.
|
||||
|
||||
## 2 Spaces for indention
|
||||
|
||||
Use 2 spaces for indenting your code and swear an oath to never mix tabs and
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
extends: '../.eslintrc'
|
||||
extends: '../.eslintrc.js'
|
||||
|
||||
rules:
|
||||
no-var: 0
|
29
yarn.lock
29
yarn.lock
|
@ -3667,6 +3667,12 @@ escope@^3.6.0:
|
|||
esrecurse "^4.1.0"
|
||||
estraverse "^4.1.1"
|
||||
|
||||
eslint-config-prettier@^2.9.0:
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-2.9.0.tgz#5ecd65174d486c22dff389fe036febf502d468a3"
|
||||
dependencies:
|
||||
get-stdin "^5.0.1"
|
||||
|
||||
eslint-import-resolver-node@^0.3.0, eslint-import-resolver-node@^0.3.1:
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a"
|
||||
|
@ -3736,6 +3742,13 @@ eslint-plugin-prefer-object-spread@1.2.1:
|
|||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-prefer-object-spread/-/eslint-plugin-prefer-object-spread-1.2.1.tgz#27fb91853690cceb3ae6101d9c8aecc6a67a402c"
|
||||
|
||||
eslint-plugin-prettier@^2.6.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.0.tgz#33e4e228bdb06142d03c560ce04ec23f6c767dd7"
|
||||
dependencies:
|
||||
fast-diff "^1.1.1"
|
||||
jest-docblock "^21.0.0"
|
||||
|
||||
eslint-plugin-react@7.5.1:
|
||||
version "7.5.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.5.1.tgz#52e56e8d80c810de158859ef07b880d2f56ee30b"
|
||||
|
@ -4175,6 +4188,10 @@ fast-deep-equal@^1.0.0:
|
|||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff"
|
||||
|
||||
fast-diff@^1.1.1:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154"
|
||||
|
||||
fast-json-stable-stringify@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
|
||||
|
@ -4616,6 +4633,10 @@ get-stdin@^4.0.1:
|
|||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
|
||||
|
||||
get-stdin@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398"
|
||||
|
||||
get-stream@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
|
||||
|
@ -6331,6 +6352,10 @@ jest-diff@^22.0.6:
|
|||
jest-get-type "^22.0.6"
|
||||
pretty-format "^22.0.6"
|
||||
|
||||
jest-docblock@^21.0.0:
|
||||
version "21.2.0"
|
||||
resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414"
|
||||
|
||||
jest-docblock@^22.0.6:
|
||||
version "22.0.6"
|
||||
resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-22.0.6.tgz#f187fb2c67eec0999e569d563092125283084f9e"
|
||||
|
@ -9185,6 +9210,10 @@ preserve@^0.2.0:
|
|||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
|
||||
|
||||
prettier@^1.10.2:
|
||||
version "1.10.2"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.10.2.tgz#1af8356d1842276a99a5b5529c82dd9e9ad3cc93"
|
||||
|
||||
pretty-bytes@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue