eslint-plugin-react-redux
Advanced tools
Comparing version
@@ -1,5 +0,17 @@ | ||
module.exports = function (node) { | ||
return ( | ||
node.callee.name === 'connect' | ||
); | ||
module.exports = function (node, context) { | ||
if (node.callee.type === 'Identifier' && node.callee.name === 'connect') { | ||
const sourceCode = context.getSourceCode(); | ||
const scope = sourceCode.getScope(node); | ||
const variable = scope.variables.find(v => v.name === 'connect'); | ||
if (variable && variable.defs.length > 0) { | ||
const def = variable.defs[0]; | ||
if ( | ||
(def.node.type === 'ImportSpecifier' && def.parent.source.value === 'react-redux') || | ||
(def.node.type === 'VariableDeclarator' && def.node.init && def.node.init.callee && def.node.init.callee.name === 'require' && def.node.init.arguments[0].value === 'react-redux') | ||
) { | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
}; |
@@ -13,3 +13,3 @@ const isReactReduxConnect = require('../isReactReduxConnect'); | ||
CallExpression(node) { | ||
if (isReactReduxConnect(node)) { | ||
if (isReactReduxConnect(node, context)) { | ||
if (node.arguments.length < 2) { | ||
@@ -16,0 +16,0 @@ report(node); |
@@ -20,3 +20,3 @@ const isReactReduxConnect = require('../isReactReduxConnect'); | ||
CallExpression(node) { | ||
if (isReactReduxConnect(node)) { | ||
if (isReactReduxConnect(node, context)) { | ||
node.arguments.forEach((argument, i) => { | ||
@@ -23,0 +23,0 @@ if (argument.raw && argument.raw !== 'null') { |
@@ -43,3 +43,3 @@ const isReactReduxConnect = require('../isReactReduxConnect'); | ||
CallExpression(node) { | ||
if (isReactReduxConnect(node)) { | ||
if (isReactReduxConnect(node, context)) { | ||
const mapDispatchToProps = node.arguments && node.arguments[1]; | ||
@@ -46,0 +46,0 @@ if (mapDispatchToProps && ( |
@@ -74,3 +74,3 @@ const isReactReduxConnect = require('../isReactReduxConnect'); | ||
CallExpression(node) { | ||
if (isReactReduxConnect(node)) { | ||
if (isReactReduxConnect(node, context)) { | ||
const mapDispatchToProps = node.arguments && node.arguments[1]; | ||
@@ -77,0 +77,0 @@ if (mapDispatchToProps && ( |
@@ -37,3 +37,3 @@ const isReactReduxConnect = require('../isReactReduxConnect'); | ||
CallExpression(node) { | ||
if (isReactReduxConnect(node)) { | ||
if (isReactReduxConnect(node, context)) { | ||
const mapDispatchToProps = node.arguments && node.arguments[1]; | ||
@@ -40,0 +40,0 @@ if (mapDispatchToProps && ( |
@@ -69,3 +69,3 @@ const utils = require('../utils'); | ||
CallExpression(node) { | ||
if (isReactReduxConnect(node)) { | ||
if (isReactReduxConnect(node, context)) { | ||
const mapStateToProps = node.arguments && node.arguments[0]; | ||
@@ -72,0 +72,0 @@ if (mapStateToProps && mapStateToProps.body) { |
@@ -55,3 +55,3 @@ const utils = require('../utils'); | ||
CallExpression(node) { | ||
if (isReactReduxConnect(node)) { | ||
if (isReactReduxConnect(node, context)) { | ||
const mapStateToProps = node.arguments && node.arguments[0]; | ||
@@ -58,0 +58,0 @@ if (mapStateToProps && mapStateToProps.body) { |
@@ -43,3 +43,3 @@ const isReactReduxConnect = require('../isReactReduxConnect'); | ||
CallExpression(node) { | ||
if (isReactReduxConnect(node)) { | ||
if (isReactReduxConnect(node, context)) { | ||
const mapStateToProps = node.arguments && node.arguments[0]; | ||
@@ -46,0 +46,0 @@ if (mapStateToProps && ( |
@@ -86,3 +86,3 @@ const isReactReduxConnect = require('../isReactReduxConnect'); | ||
CallExpression(node) { | ||
if (isReactReduxConnect(node)) { | ||
if (isReactReduxConnect(node, context)) { | ||
const mapStateToProps = node.arguments && node.arguments[0]; | ||
@@ -89,0 +89,0 @@ if (mapStateToProps && ( |
@@ -36,3 +36,3 @@ 'use strict'; | ||
} else if (node.type === 'CallExpression') { | ||
if (isReactReduxConnect(node)) { | ||
if (isReactReduxConnect(node, context)) { | ||
const check = (mapToProps) => { | ||
@@ -89,2 +89,2 @@ if (mapToProps && mapToProps.body) { | ||
noUnusedPropTypesReact, | ||
], getPropNameFromReactRuleMessage, getPropNameFromReduxRuleMessage); | ||
], getPropNameFromReactRuleMessage, getPropNameFromReduxRuleMessage); |
@@ -15,3 +15,3 @@ const isReactReduxConnect = require('../isReactReduxConnect'); | ||
CallExpression(node) { | ||
if (isReactReduxConnect(node)) { | ||
if (isReactReduxConnect(node, context)) { | ||
const component = | ||
@@ -18,0 +18,0 @@ node.parent && |
{ | ||
"name": "eslint-plugin-react-redux", | ||
"version": "4.2.0", | ||
"version": "4.2.1", | ||
"description": "Enforcing best practices for react-redux", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -16,8 +16,8 @@ const rule = require('../../../lib/rules/connect-prefer-minimum-two-arguments'); | ||
...codeSamples, | ||
'connect(mapStateToProps, mapDispatchToProps, mergeProps, options)(Component)', | ||
'connect(mapStateToProps, mapDispatchToProps)(Component)', | ||
'connect({prop1, prop2}, {action1, action2})(Component)', | ||
`import { connect } from 'react-redux'; connect(mapStateToProps, mapDispatchToProps, mergeProps, options)(Component)`, | ||
`import { connect } from 'react-redux'; connect(mapStateToProps, mapDispatchToProps)(Component)`, | ||
`import { connect } from 'react-redux'; connect({prop1, prop2}, {action1, action2})(Component)`, | ||
], | ||
invalid: [{ | ||
code: 'connect(mapStateToProps)(Component)', | ||
code: `import { connect } from 'react-redux'; connect(mapStateToProps)(Component)`, | ||
errors: [ | ||
@@ -24,0 +24,0 @@ { |
@@ -16,9 +16,12 @@ const rule = require('../../../lib/rules/connect-prefer-named-arguments'); | ||
...codeSamples, | ||
'export default connect(null, mapDispatchToProps)(TodoApp)', | ||
'connect(mapStateToProps, mapDispatchToProps, mergeProps, options)(Component)', | ||
'connect(mapStateToProps, mapDispatchToProps)(Component)', | ||
'connect()(TodoApp)', | ||
`import { connect } from 'react-redux'; export default connect(null, mapDispatchToProps)(TodoApp)`, | ||
`import { connect } from 'react-redux'; connect(mapStateToProps, mapDispatchToProps, mergeProps, options)(Component)`, | ||
`import { connect } from 'react-redux'; connect(mapStateToProps, mapDispatchToProps)(Component)`, | ||
`import { connect } from 'react-redux'; connect()(TodoApp)`, | ||
'connect(() => {}, () => {}, mergeProps, options)(Component)', | ||
'connect({}, {})(Component)', | ||
'connect(state => state)(TodoApp)', | ||
], | ||
invalid: [{ | ||
code: 'connect(() => {}, () => {}, mergeProps, options)(Component)', | ||
code: `import { connect } from 'react-redux'; connect(() => {}, () => {}, mergeProps, options)(Component)`, | ||
errors: [ | ||
@@ -32,3 +35,3 @@ { | ||
}, { | ||
code: 'connect({}, {})(Component)', | ||
code: `import { connect } from 'react-redux'; connect({}, {})(Component)`, | ||
errors: [ | ||
@@ -42,3 +45,3 @@ { | ||
}, { | ||
code: 'connect(state => state)(TodoApp)', | ||
code: `import { connect } from 'react-redux'; connect(state => state)(TodoApp)`, | ||
errors: [ | ||
@@ -45,0 +48,0 @@ { |
@@ -21,7 +21,8 @@ const rule = require('../../../lib/rules/mapDispatchToProps-prefer-parameters-names'); | ||
'const mapDispatchToProps = {anAction: anAction}', | ||
'connect((state) => state, {anAction: anAction})(App)', | ||
'connect(null, null)(App)', | ||
'connect((state) => state, (dispatch, ownProps, moreArgs) => {})(App)', | ||
`import { connect } from 'react-redux'; connect((state) => state, {anAction: anAction})(App)`, | ||
`import { connect } from 'react-redux'; connect(null, null)(App)`, | ||
`import { connect } from 'react-redux'; connect((state) => state, (dispatch, ownProps, moreArgs) => {})(App)`, | ||
`import { connect } from './path/to/connect.js'; connect('something')`, | ||
`import { connect } from './path/to/connect.js'; connect((state) => state, (anyOtherName) => {})(App)`, | ||
'function mapDispatchToProps(dispatch, ownProps) {}', | ||
], | ||
@@ -52,3 +53,3 @@ invalid: [{ | ||
}, { | ||
code: 'connect((state) => state, (anyOtherName) => {})(App)', | ||
code: `import { connect } from 'react-redux'; connect((state) => state, (anyOtherName) => {})(App)`, | ||
errors: [ | ||
@@ -59,3 +60,10 @@ { | ||
], | ||
}, { | ||
code: `const { connect } = require('react-redux'); connect((state) => state, (anyOtherName) => {})(App)`, | ||
errors: [ | ||
{ | ||
message: 'mapDispatchToProps function parameter #0 should be named dispatch', | ||
}, | ||
], | ||
}], | ||
}); |
@@ -30,3 +30,4 @@ const rule = require('../../../lib/rules/mapDispatchToProps-prefer-shorthand'); | ||
'const mapDispatchToProps = {anAction: anAction}', | ||
`export default connect( | ||
`import { connect } from 'react-redux'; | ||
export default connect( | ||
state => ({ | ||
@@ -38,3 +39,3 @@ productsList: state.Products.productsList, | ||
`, | ||
'connect(null, null)(App)', | ||
`import { connect } from 'react-redux'; connect(null, null)(App)`, | ||
'function mapDispatchToProps () {return aThing}', | ||
@@ -41,0 +42,0 @@ ], |
@@ -20,3 +20,4 @@ const rule = require('../../../lib/rules/mapDispatchToProps-returns-object'); | ||
'const mapDispatchToProps = {anAction: anAction}', | ||
`export default connect( | ||
`import { connect } from 'react-redux'; | ||
export default connect( | ||
state => ({ | ||
@@ -46,3 +47,3 @@ productsList: state.Products.productsList, | ||
}`, | ||
'connect(null, null)(App)', | ||
`import { connect } from 'react-redux'; connect(null, null)(App)`, | ||
'function mapDispatchToProps () {return aThing}', | ||
@@ -68,3 +69,4 @@ `function mapDispatchToProps(dispatch) { | ||
}, { | ||
code: `export default connect( | ||
code: `import { connect } from 'react-redux'; | ||
export default connect( | ||
state => ({ | ||
@@ -82,3 +84,4 @@ productsList: state.Products.productsList, | ||
}, { | ||
code: `export default connect( | ||
code: `import { connect } from 'react-redux'; | ||
export default connect( | ||
state => ({ | ||
@@ -85,0 +88,0 @@ productsList: state.Products.productsList, |
@@ -32,7 +32,8 @@ | ||
'export default function observeStore(store) {return store;}', | ||
'export default connect(() => {})(Alert)', | ||
'export default connect(null, null)(Alert)', | ||
'connect((state) => ({isActive: state.isActive}), null)(App)', | ||
'connect(null, null)(App)', | ||
`connect( | ||
`import { connect } from 'react-redux'; export default connect(() => {})(Alert)`, | ||
`import { connect } from 'react-redux'; export default connect(null, null)(Alert)`, | ||
`import { connect } from 'react-redux'; connect((state) => ({isActive: state.isActive}), null)(App)`, | ||
`import { connect } from 'react-redux'; connect(null, null)(App)`, | ||
`import { connect } from 'react-redux'; | ||
connect( | ||
(state) => { | ||
@@ -46,3 +47,4 @@ return { | ||
`, | ||
`connect(function(state){ | ||
`import { connect } from 'react-redux'; | ||
connect(function(state){ | ||
return { | ||
@@ -63,3 +65,4 @@ isActive: state.isActive | ||
'const mapStateToProps = (state) => {isActive: state.isActive}', | ||
`const mapStateToProps = (state, ownProps) => {}; | ||
`import { connect } from 'react-redux'; | ||
const mapStateToProps = (state, ownProps) => {}; | ||
connect(mapStateToProps, null)(Alert);`, | ||
@@ -70,4 +73,4 @@ `const mapStateToProps = ({ header }) => ({ | ||
'const mapStateToProps = ({header}, ownProps) => {header};', | ||
'connect(({header}, ownProps) => {header})(App);', | ||
'connect(({header}, {ownProp1}) => {header, ownProp1})(App);', | ||
`import { connect } from 'react-redux'; connect(({header}, ownProps) => {header})(App);`, | ||
`import { connect } from 'react-redux'; connect(({header}, {ownProp1}) => {header, ownProp1})(App);`, | ||
], | ||
@@ -100,3 +103,4 @@ invalid: [{ | ||
}, { | ||
code: `export default connect( | ||
code: `import { connect } from 'react-redux'; | ||
export default connect( | ||
(state) => { | ||
@@ -119,3 +123,3 @@ return { | ||
}, { | ||
code: 'connect((state) => state, null)(App)', | ||
code: `import { connect } from 'react-redux'; connect((state) => state, null)(App)`, | ||
errors: [ | ||
@@ -127,3 +131,4 @@ { | ||
}, { | ||
code: `const mapStateToProps = (state, ownProps) => state; | ||
code: `import { connect } from 'react-redux'; | ||
const mapStateToProps = (state, ownProps) => state; | ||
connect(mapStateToProps, null)(Alert);`, | ||
@@ -143,3 +148,3 @@ errors: [ | ||
}, { | ||
code: 'connect((state) => ({...state}), null)(App)', | ||
code: `import { connect } from 'react-redux'; connect((state) => ({...state}), null)(App)`, | ||
errors: [ | ||
@@ -146,0 +151,0 @@ { |
@@ -53,6 +53,7 @@ | ||
`, | ||
'export default connect(null, null)(Alert)', | ||
'connect((state) => ({isActive: state.isActive}), null)(App)', | ||
'connect(null, null)(App)', | ||
`connect( | ||
`import { connect } from 'react-redux'; export default connect(null, null)(Alert)`, | ||
`import { connect } from 'react-redux'; connect((state) => ({isActive: state.isActive}), null)(App)`, | ||
`import { connect } from 'react-redux'; connect(null, null)(App)`, | ||
`import { connect } from 'react-redux'; | ||
connect( | ||
(state) => { | ||
@@ -66,3 +67,4 @@ return { | ||
`, | ||
`connect(function(state){ | ||
`import { connect } from 'react-redux'; | ||
connect(function(state){ | ||
return { | ||
@@ -82,3 +84,4 @@ isActive: state.isActive | ||
'const mapStateToProps = (state) => {set: [1, 2, 3, state.a]}', | ||
`const mapStateToProps = (state, ownProps) => {}; | ||
`import { connect } from 'react-redux'; | ||
const mapStateToProps = (state, ownProps) => {}; | ||
connect(mapStateToProps, null)(Alert);`, | ||
@@ -89,4 +92,4 @@ `const mapStateToProps = ({ header }) => ({ | ||
'const mapStateToProps = ({header}, ownProps) => {header};', | ||
'connect(({header}, ownProps) => {header})(App);', | ||
'connect(({header}, {ownProp1}) => {header, ownProp1})(App);', | ||
`import { connect } from 'react-redux'; connect(({header}, ownProps) => {header})(App);`, | ||
`import { connect } from 'react-redux'; connect(({header}, {ownProp1}) => {header, ownProp1})(App);`, | ||
`const mapStateToProps = ({header}, ownProps) => { | ||
@@ -99,3 +102,4 @@ return { | ||
};`, | ||
`const createConnectedToolbarItem = (icon, onClick) => { | ||
`import { connect } from 'react-redux'; | ||
const createConnectedToolbarItem = (icon, onClick) => { | ||
const mapStateToProps = { onClick } | ||
@@ -145,3 +149,4 @@ | ||
}, { | ||
code: `export default connect( | ||
code: `import { connect } from 'react-redux'; | ||
export default connect( | ||
(state) => { | ||
@@ -148,0 +153,0 @@ return { |
@@ -19,7 +19,7 @@ const rule = require('../../../lib/rules/mapStateToProps-prefer-parameters-names'); | ||
'const mapStateToProps = (state, ownProps, moreArgs) => {}', | ||
'connect((state) => state, null)(App)', | ||
`import { connect } from 'react-redux'; connect((state) => state, null)(App)`, | ||
'function mapStateToProps(state, ownProps) {}', | ||
'connect({state}, null)(App)', | ||
`import { connect } from 'react-redux'; connect({state}, null)(App)`, | ||
'const mapStateToProps = {}', | ||
'connect(null, null)(App)', | ||
`import { connect } from 'react-redux'; connect(null, null)(App)`, | ||
'const mapStateToProps = ({prop1, prop2}, ownProps) => {}', | ||
@@ -44,3 +44,3 @@ ], | ||
}, { | ||
code: 'connect(function(anyOtherName) {}, null)(App)', | ||
code: `import { connect } from 'react-redux'; connect(function(anyOtherName) {}, null)(App)`, | ||
errors: [ | ||
@@ -47,0 +47,0 @@ { |
@@ -25,9 +25,9 @@ const rule = require('../../../lib/rules/mapStateToProps-prefer-selectors'); | ||
'function mapStateToProps(state) { doSomethingElse(); return { x: xSelector(state) }; }', | ||
'connect((state) => ({ x: xSelector(state) }), {})(Comp)', | ||
`import { connect } from 'react-redux'; connect((state) => ({ x: xSelector(state) }), {})(Comp)`, | ||
'const mapStateToProps = () => ({ x: xSelector() })', | ||
'const mapStateToProps = function(state) { return { x: getX() }; }', | ||
'const mapStateToProps = function(state) { return { x: getX(state) }; }', | ||
'connect((state, ownProps) => ({ x: selector() }), {})(Comp)', | ||
'connect((state, ownProps) => ({ x: selector(state) }), {})(Comp)', | ||
'connect((state, ownProps) => ({ x: selector(state, ownProps) }), {})(Comp)', | ||
`import { connect } from 'react-redux'; connect((state, ownProps) => ({ x: selector() }), {})(Comp)`, | ||
`import { connect } from 'react-redux'; connect((state, ownProps) => ({ x: selector(state) }), {})(Comp)`, | ||
`import { connect } from 'react-redux'; connect((state, ownProps) => ({ x: selector(state, ownProps) }), {})(Comp)`, | ||
{ | ||
@@ -46,3 +46,3 @@ code: 'const mapStateToProps = (state) => ({ x: xSelector(state) })', | ||
{ | ||
code: 'connect((state) => ({ x: selector(state) }), {})(Comp)', | ||
code: `import { connect } from 'react-redux'; connect((state) => ({ x: selector(state) }), {})(Comp)`, | ||
options: [{ | ||
@@ -65,3 +65,3 @@ matching: '^selector$', | ||
{ | ||
code: 'connect(() => ({ x: selector(state) }), {})(Comp)', | ||
code: `import { connect } from 'react-redux'; connect(() => ({ x: selector(state) }), {})(Comp)`, | ||
options: [{ | ||
@@ -125,3 +125,3 @@ validateParams: false, | ||
}, { | ||
code: 'connect((state) => ({ x: state.x }), {})(Comp)', | ||
code: `import { connect } from 'react-redux'; connect((state) => ({ x: state.x }), {})(Comp)`, | ||
errors: [ | ||
@@ -149,3 +149,3 @@ { | ||
}, { | ||
code: 'connect((state) => ({ x: selectorr(state) }), {})(Comp)', | ||
code: `import { connect } from 'react-redux'; connect((state) => ({ x: selectorr(state) }), {})(Comp)`, | ||
options: [{ | ||
@@ -173,3 +173,3 @@ matching: '^selector$', | ||
}, { | ||
code: 'connect((state, ownProps) => ({ x: getX(state, notOwnProps) }), {})(Comp)', | ||
code: `import { connect } from 'react-redux'; connect((state, ownProps) => ({ x: getX(state, notOwnProps) }), {})(Comp)`, | ||
errors: [{ | ||
@@ -179,3 +179,3 @@ message: 'mapStateToProps "x"\'s selector "getX" parameter #1 should be "ownProps".', | ||
}, { | ||
code: 'connect((state2, ownProps) => ({ x: getX(state) }), {})(Comp)', | ||
code: `import { connect } from 'react-redux'; connect((state2, ownProps) => ({ x: getX(state) }), {})(Comp)`, | ||
errors: [{ | ||
@@ -185,3 +185,3 @@ message: 'mapStateToProps "x"\'s selector "getX" parameter #0 should be "state2".', | ||
}, { | ||
code: 'connect((state, ownProps2) => ({ x: getX(state, ownProps) }), {})(Comp)', | ||
code: `import { connect } from 'react-redux'; connect((state, ownProps2) => ({ x: getX(state, ownProps) }), {})(Comp)`, | ||
errors: [{ | ||
@@ -188,0 +188,0 @@ message: 'mapStateToProps "x"\'s selector "getX" parameter #1 should be "ownProps2".', |
@@ -36,2 +36,3 @@ | ||
import { connect } from 'react-redux'; | ||
export default connect(mapStateToProps)(MyComponent);`, | ||
@@ -54,2 +55,3 @@ | ||
import { connect } from 'react-redux'; | ||
export default connect(mapStateToProps)(MyComponent);`, | ||
@@ -71,2 +73,3 @@ | ||
import { connect } from 'react-redux'; | ||
export default connect(mapStateToProps)(MyComponent);`, | ||
@@ -88,2 +91,3 @@ | ||
import { connect } from 'react-redux'; | ||
export default connect(mapStateToProps)(MyComponent);`, | ||
@@ -104,2 +108,3 @@ `export const mapStateToProps = (state, {myProp}) => ({ | ||
import { connect } from 'react-redux'; | ||
export default connect(mapStateToProps)(MyComponent);`, | ||
@@ -140,2 +145,3 @@ `const selectorFoo = (state) => ({isFetching: false, name: 'Foo', isDeleting: false, deltedId: ''}); | ||
import { connect } from 'react-redux'; | ||
export default connect(mapStateToProps)(MyComponent);`, | ||
@@ -158,2 +164,3 @@ ], | ||
import { connect } from 'react-redux'; | ||
export default connect(mapStateToProps)(MyComponent);`, | ||
@@ -182,2 +189,3 @@ | ||
import { connect } from 'react-redux'; | ||
export default connect(mapStateToProps)(MyComponent);`, | ||
@@ -205,2 +213,3 @@ | ||
import { connect } from 'react-redux'; | ||
export default connect(mapStateToProps)(MyComponent);`, | ||
@@ -229,2 +238,3 @@ | ||
import { connect } from 'react-redux'; | ||
export default connect(mapStateToProps)(MyComponent);`, | ||
@@ -254,2 +264,3 @@ | ||
import { connect } from 'react-redux'; | ||
export default connect(mapStateToProps)(MyComponent);`, | ||
@@ -256,0 +267,0 @@ |
@@ -15,11 +15,15 @@ const rule = require('../../../lib/rules/prefer-separate-component-file'); | ||
...codeSamples, | ||
` import Component from './component'; | ||
`import { connect } from 'react-redux'; | ||
import Component from './component'; | ||
connect(mapStateToProps, mapDispatchToProps)(Component)`, | ||
`const Component = require('./component') | ||
connect(mapStateToProps, mapDispatchToProps)(Component)`, | ||
`import {Component} from './component'; | ||
connect(mapStateToProps, mapDispatchToProps)(Component)`, | ||
`import { connect } from 'react-redux'; | ||
const Component = require('./component') | ||
connect(mapStateToProps, mapDispatchToProps)(Component)`, | ||
`import { connect } from 'react-redux'; | ||
import {Component} from './component'; | ||
connect(mapStateToProps, mapDispatchToProps)(Component)`, | ||
], | ||
invalid: [{ | ||
code: `const Component = () => {}; | ||
code: `import { connect } from 'react-redux'; | ||
const Component = () => {}; | ||
connect(mapStateToProps, null)(Component)`, | ||
@@ -26,0 +30,0 @@ errors: [ |
96582
4.72%2243
2.47%