2023-08-24 12:27:42 +02:00
|
|
|
/**
|
|
|
|
* @jest-environment node
|
|
|
|
*/
|
2022-11-24 20:59:07 +01:00
|
|
|
import { ControllerMessenger } from '@metamask/base-controller';
|
|
|
|
import { TokenListController } from '@metamask/assets-controllers';
|
2023-08-24 12:27:42 +02:00
|
|
|
import { CHAIN_IDS } from '../../../shared/constants/network';
|
2021-03-16 22:00:08 +01:00
|
|
|
import PreferencesController from './preferences';
|
2017-12-19 00:49:55 +01:00
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
const NETWORK_CONFIGURATION_DATA = {
|
|
|
|
'test-networkConfigurationId-1': {
|
|
|
|
rpcUrl: 'https://testrpc.com',
|
|
|
|
chainId: CHAIN_IDS.GOERLI,
|
|
|
|
nickname: '0X5',
|
|
|
|
rpcPrefs: { blockExplorerUrl: 'https://etherscan.io' },
|
|
|
|
},
|
|
|
|
'test-networkConfigurationId-2': {
|
|
|
|
rpcUrl: 'http://localhost:8545',
|
|
|
|
chainId: '0x539',
|
|
|
|
ticker: 'ETH',
|
|
|
|
nickname: 'Localhost 8545',
|
|
|
|
rpcPrefs: {},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
describe('preferences controller', () => {
|
2021-02-04 19:15:23 +01:00
|
|
|
let preferencesController;
|
2022-08-10 03:26:25 +02:00
|
|
|
let tokenListController;
|
2017-12-19 00:49:55 +01:00
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
beforeEach(() => {
|
2022-08-10 03:26:25 +02:00
|
|
|
const tokenListMessenger = new ControllerMessenger().getRestricted({
|
|
|
|
name: 'TokenListController',
|
|
|
|
});
|
|
|
|
tokenListController = new TokenListController({
|
|
|
|
chainId: '1',
|
|
|
|
preventPollingOnNetworkRestart: false,
|
2023-08-24 12:27:42 +02:00
|
|
|
onNetworkStateChange: jest.fn(),
|
|
|
|
onPreferencesStateChange: jest.fn(),
|
2022-08-10 03:26:25 +02:00
|
|
|
messenger: tokenListMessenger,
|
|
|
|
});
|
2021-06-22 19:39:44 +02:00
|
|
|
|
2020-11-03 00:41:28 +01:00
|
|
|
preferencesController = new PreferencesController({
|
2021-12-08 22:36:53 +01:00
|
|
|
initLangCode: 'en_US',
|
2022-08-10 03:26:25 +02:00
|
|
|
tokenListController,
|
2023-08-24 12:27:42 +02:00
|
|
|
onInfuraIsBlocked: jest.fn(),
|
|
|
|
onInfuraIsUnblocked: jest.fn(),
|
|
|
|
networkConfigurations: NETWORK_CONFIGURATION_DATA,
|
2021-02-04 19:15:23 +01:00
|
|
|
});
|
|
|
|
});
|
Update address book state upon custom RPC chainId edit (#9493)
When the `chainId` for a custom RPC endpoint is edited, we now migrate
the corresponding address book entries to ensure they are not orphaned.
The address book entries are grouped by the `metamask.network` state,
which unfortunately was sometimes the `chainId`, and sometimes the
`networkId`. It was always the `networkId` for built-in Infura
networks, but for custom RPC endpoints it would be set to the user-set
`chainId` field, with a fallback to the `networkId` of the network.
A recent change will force users to enter valid `chainId`s on all
custom networks, which will be normalized to be hex-prefixed. As a
result, address book contacts will now be keyed by a different string.
The contact entries are now migrated when this edit takes place.
There are some edge cases where two separate entries share the same set
of contacts. For example, if two entries have the same `chainId`, or if
they had the same `networkId` and had no `chainId` set. When the
`chainId` is edited in such cases, the contacts are duplicated on both
networks. This is the best we can do, as we don't have any way to know
which network the contacts _should_ be on.
The `typed-message-manager` unit tests have also been updated as part
of this commit because the addition of `sinon.restore()` to the
preferences controller tests ended up clearing a test object in-between
individual tests in that file. The test object is now re-constructed
before each individual test.
2020-10-07 19:32:17 +02:00
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
describe('useBlockie', () => {
|
|
|
|
it('defaults useBlockie to false', () => {
|
|
|
|
expect(preferencesController.store.getState().useBlockie).toStrictEqual(
|
|
|
|
false,
|
|
|
|
);
|
2021-12-08 22:36:53 +01:00
|
|
|
});
|
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
it('setUseBlockie to true', () => {
|
2021-12-08 22:36:53 +01:00
|
|
|
preferencesController.setUseBlockie(true);
|
2023-08-24 12:27:42 +02:00
|
|
|
expect(preferencesController.store.getState().useBlockie).toStrictEqual(
|
|
|
|
true,
|
|
|
|
);
|
2021-12-08 22:36:53 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
describe('setCurrentLocale', () => {
|
|
|
|
it('checks the default currentLocale', () => {
|
2021-12-08 22:36:53 +01:00
|
|
|
const { currentLocale } = preferencesController.store.getState();
|
2023-08-24 12:27:42 +02:00
|
|
|
expect(currentLocale).toStrictEqual('en_US');
|
2021-12-08 22:36:53 +01:00
|
|
|
});
|
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
it('sets current locale in preferences controller', () => {
|
2021-12-08 22:36:53 +01:00
|
|
|
preferencesController.setCurrentLocale('ja');
|
|
|
|
const { currentLocale } = preferencesController.store.getState();
|
2023-08-24 12:27:42 +02:00
|
|
|
expect(currentLocale).toStrictEqual('ja');
|
2021-12-08 22:36:53 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
describe('setAddresses', () => {
|
|
|
|
it('should keep a map of addresses to names and addresses in the store', () => {
|
2021-02-04 19:15:23 +01:00
|
|
|
preferencesController.setAddresses(['0xda22le', '0x7e57e2']);
|
2018-04-19 05:33:51 +02:00
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
const { identities } = preferencesController.store.getState();
|
2023-08-24 12:27:42 +02:00
|
|
|
expect(identities).toStrictEqual({
|
2018-04-19 05:33:51 +02:00
|
|
|
'0xda22le': {
|
|
|
|
name: 'Account 1',
|
|
|
|
address: '0xda22le',
|
|
|
|
},
|
|
|
|
'0x7e57e2': {
|
|
|
|
name: 'Account 2',
|
|
|
|
address: '0x7e57e2',
|
|
|
|
},
|
2021-02-04 19:15:23 +01:00
|
|
|
});
|
|
|
|
});
|
2018-04-19 05:33:51 +02:00
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
it('should replace its list of addresses', () => {
|
2021-02-04 19:15:23 +01:00
|
|
|
preferencesController.setAddresses(['0xda22le', '0x7e57e2']);
|
|
|
|
preferencesController.setAddresses(['0xda22le77', '0x7e57e277']);
|
2018-04-19 05:33:51 +02:00
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
const { identities } = preferencesController.store.getState();
|
2023-08-24 12:27:42 +02:00
|
|
|
expect(identities).toStrictEqual({
|
2018-04-19 05:33:51 +02:00
|
|
|
'0xda22le77': {
|
|
|
|
name: 'Account 1',
|
|
|
|
address: '0xda22le77',
|
|
|
|
},
|
|
|
|
'0x7e57e277': {
|
|
|
|
name: 'Account 2',
|
|
|
|
address: '0x7e57e277',
|
|
|
|
},
|
2021-02-04 19:15:23 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2018-04-19 05:33:51 +02:00
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
describe('removeAddress', () => {
|
|
|
|
it('should remove an address from state', () => {
|
2021-02-04 19:15:23 +01:00
|
|
|
preferencesController.setAddresses(['0xda22le', '0x7e57e2']);
|
2018-07-16 22:08:19 +02:00
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
preferencesController.removeAddress('0xda22le');
|
2018-07-16 22:08:19 +02:00
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
expect(
|
2020-11-03 00:41:28 +01:00
|
|
|
preferencesController.store.getState().identities['0xda22le'],
|
2023-08-24 12:27:42 +02:00
|
|
|
).toStrictEqual(undefined);
|
2021-02-04 19:15:23 +01:00
|
|
|
});
|
2018-07-16 22:08:19 +02:00
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
it('should switch accounts if the selected address is removed', () => {
|
2021-02-04 19:15:23 +01:00
|
|
|
preferencesController.setAddresses(['0xda22le', '0x7e57e2']);
|
2018-07-16 22:08:19 +02:00
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
preferencesController.setSelectedAddress('0x7e57e2');
|
|
|
|
preferencesController.removeAddress('0x7e57e2');
|
2023-08-24 12:27:42 +02:00
|
|
|
expect(preferencesController.getSelectedAddress()).toStrictEqual(
|
|
|
|
'0xda22le',
|
|
|
|
);
|
2021-02-04 19:15:23 +01:00
|
|
|
});
|
|
|
|
});
|
2018-07-16 22:08:19 +02:00
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
describe('setAccountLabel', () => {
|
|
|
|
it('should update a label for the given account', () => {
|
2021-02-04 19:15:23 +01:00
|
|
|
preferencesController.setAddresses(['0xda22le', '0x7e57e2']);
|
2020-11-03 00:41:28 +01:00
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
expect(
|
2020-11-03 00:41:28 +01:00
|
|
|
preferencesController.store.getState().identities['0xda22le'],
|
2023-08-24 12:27:42 +02:00
|
|
|
).toStrictEqual({
|
|
|
|
name: 'Account 1',
|
|
|
|
address: '0xda22le',
|
|
|
|
});
|
2018-04-19 05:33:51 +02:00
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
preferencesController.setAccountLabel('0xda22le', 'Dazzle');
|
2023-08-24 12:27:42 +02:00
|
|
|
expect(
|
2020-11-03 00:41:28 +01:00
|
|
|
preferencesController.store.getState().identities['0xda22le'],
|
2023-08-24 12:27:42 +02:00
|
|
|
).toStrictEqual({
|
|
|
|
name: 'Dazzle',
|
|
|
|
address: '0xda22le',
|
|
|
|
});
|
2021-02-04 19:15:23 +01:00
|
|
|
});
|
|
|
|
});
|
2018-04-19 05:33:51 +02:00
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
describe('setPasswordForgotten', () => {
|
|
|
|
it('should default to false', () => {
|
|
|
|
expect(
|
2020-11-03 00:41:28 +01:00
|
|
|
preferencesController.store.getState().forgottenPassword,
|
2023-08-24 12:27:42 +02:00
|
|
|
).toStrictEqual(false);
|
|
|
|
});
|
2018-09-11 02:01:15 +02:00
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
it('should set the forgottenPassword property in state', () => {
|
2021-02-04 19:15:23 +01:00
|
|
|
preferencesController.setPasswordForgotten(true);
|
2023-08-24 12:27:42 +02:00
|
|
|
expect(
|
2020-11-03 00:41:28 +01:00
|
|
|
preferencesController.store.getState().forgottenPassword,
|
2023-08-24 12:27:42 +02:00
|
|
|
).toStrictEqual(true);
|
2021-02-04 19:15:23 +01:00
|
|
|
});
|
|
|
|
});
|
2018-09-11 02:01:15 +02:00
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
describe('setUsePhishDetect', () => {
|
|
|
|
it('should default to true', () => {
|
|
|
|
expect(
|
|
|
|
preferencesController.store.getState().usePhishDetect,
|
|
|
|
).toStrictEqual(true);
|
2021-02-04 19:15:23 +01:00
|
|
|
});
|
2020-02-27 07:29:41 +01:00
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
it('should set the usePhishDetect property in state', () => {
|
2021-02-04 19:15:23 +01:00
|
|
|
preferencesController.setUsePhishDetect(false);
|
2023-08-24 12:27:42 +02:00
|
|
|
expect(
|
2021-02-04 19:15:23 +01:00
|
|
|
preferencesController.store.getState().usePhishDetect,
|
2023-08-24 12:27:42 +02:00
|
|
|
).toStrictEqual(false);
|
2021-02-04 19:15:23 +01:00
|
|
|
});
|
|
|
|
});
|
2022-12-01 22:16:04 +01:00
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
describe('setUseMultiAccountBalanceChecker', () => {
|
|
|
|
it('should default to true', () => {
|
|
|
|
expect(
|
2022-12-01 22:16:04 +01:00
|
|
|
preferencesController.store.getState().useMultiAccountBalanceChecker,
|
2023-08-24 12:27:42 +02:00
|
|
|
).toStrictEqual(true);
|
|
|
|
});
|
2022-12-01 22:16:04 +01:00
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
it('should set the setUseMultiAccountBalanceChecker property in state', () => {
|
2022-12-01 22:16:04 +01:00
|
|
|
preferencesController.setUseMultiAccountBalanceChecker(false);
|
2023-08-24 12:27:42 +02:00
|
|
|
expect(
|
2022-12-01 22:16:04 +01:00
|
|
|
preferencesController.store.getState().useMultiAccountBalanceChecker,
|
2023-08-24 12:27:42 +02:00
|
|
|
).toStrictEqual(false);
|
2022-12-01 22:16:04 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
describe('setUseTokenDetection', () => {
|
|
|
|
it('should default to false', () => {
|
|
|
|
expect(
|
|
|
|
preferencesController.store.getState().useTokenDetection,
|
|
|
|
).toStrictEqual(false);
|
2021-07-16 01:08:16 +02:00
|
|
|
});
|
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
it('should set the useTokenDetection property in state', () => {
|
2021-09-16 19:07:23 +02:00
|
|
|
preferencesController.setUseTokenDetection(true);
|
2023-08-24 12:27:42 +02:00
|
|
|
expect(
|
2021-09-09 22:56:27 +02:00
|
|
|
preferencesController.store.getState().useTokenDetection,
|
2023-08-24 12:27:42 +02:00
|
|
|
).toStrictEqual(true);
|
2021-07-16 01:08:16 +02:00
|
|
|
});
|
|
|
|
});
|
2021-11-11 20:18:50 +01:00
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
describe('setUseNftDetection', () => {
|
|
|
|
it('should default to false', () => {
|
|
|
|
expect(
|
|
|
|
preferencesController.store.getState().useNftDetection,
|
|
|
|
).toStrictEqual(false);
|
2021-11-26 19:54:57 +01:00
|
|
|
});
|
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
it('should set the useNftDetection property in state', () => {
|
2021-12-01 05:12:27 +01:00
|
|
|
preferencesController.setOpenSeaEnabled(true);
|
2022-11-15 19:49:42 +01:00
|
|
|
preferencesController.setUseNftDetection(true);
|
2023-08-24 12:27:42 +02:00
|
|
|
expect(
|
2022-11-15 19:49:42 +01:00
|
|
|
preferencesController.store.getState().useNftDetection,
|
2023-08-24 12:27:42 +02:00
|
|
|
).toStrictEqual(true);
|
2021-11-26 19:54:57 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2023-08-04 19:28:37 +02:00
|
|
|
describe('setUse4ByteResolution', function () {
|
|
|
|
it('should default to true', function () {
|
2023-08-24 12:27:42 +02:00
|
|
|
expect(
|
|
|
|
preferencesController.store.getState().use4ByteResolution,
|
|
|
|
).toStrictEqual(true);
|
2023-08-04 19:28:37 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should set the use4ByteResolution property in state', function () {
|
|
|
|
preferencesController.setUse4ByteResolution(false);
|
2023-08-24 12:27:42 +02:00
|
|
|
expect(
|
2023-08-04 19:28:37 +02:00
|
|
|
preferencesController.store.getState().use4ByteResolution,
|
2023-08-24 12:27:42 +02:00
|
|
|
).toStrictEqual(false);
|
2023-08-04 19:28:37 +02:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
describe('setOpenSeaEnabled', () => {
|
|
|
|
it('should default to false', () => {
|
|
|
|
expect(
|
|
|
|
preferencesController.store.getState().openSeaEnabled,
|
|
|
|
).toStrictEqual(false);
|
2021-12-01 05:12:27 +01:00
|
|
|
});
|
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
it('should set the openSeaEnabled property in state', () => {
|
2021-12-01 05:12:27 +01:00
|
|
|
preferencesController.setOpenSeaEnabled(true);
|
2023-08-24 12:27:42 +02:00
|
|
|
expect(
|
|
|
|
preferencesController.store.getState().openSeaEnabled,
|
|
|
|
).toStrictEqual(true);
|
2021-12-01 05:12:27 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
describe('setAdvancedGasFee', () => {
|
|
|
|
it('should default to null', () => {
|
|
|
|
expect(
|
|
|
|
preferencesController.store.getState().advancedGasFee,
|
|
|
|
).toStrictEqual(null);
|
2021-11-11 20:18:50 +01:00
|
|
|
});
|
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
it('should set the setAdvancedGasFee property in state', () => {
|
2021-11-11 20:18:50 +01:00
|
|
|
preferencesController.setAdvancedGasFee({
|
|
|
|
maxBaseFee: '1.5',
|
|
|
|
priorityFee: '2',
|
|
|
|
});
|
2023-08-24 12:27:42 +02:00
|
|
|
expect(
|
2021-11-11 20:18:50 +01:00
|
|
|
preferencesController.store.getState().advancedGasFee.maxBaseFee,
|
2023-08-24 12:27:42 +02:00
|
|
|
).toStrictEqual('1.5');
|
|
|
|
expect(
|
2021-11-11 20:18:50 +01:00
|
|
|
preferencesController.store.getState().advancedGasFee.priorityFee,
|
2023-08-24 12:27:42 +02:00
|
|
|
).toStrictEqual('2');
|
2021-11-11 20:18:50 +01:00
|
|
|
});
|
|
|
|
});
|
2022-03-07 19:53:19 +01:00
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
describe('setTheme', () => {
|
|
|
|
it('should default to value "OS"', () => {
|
|
|
|
expect(preferencesController.store.getState().theme).toStrictEqual('os');
|
2022-03-07 19:53:19 +01:00
|
|
|
});
|
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
it('should set the setTheme property in state', () => {
|
2022-03-07 19:53:19 +01:00
|
|
|
preferencesController.setTheme('dark');
|
2023-08-24 12:27:42 +02:00
|
|
|
expect(preferencesController.store.getState().theme).toStrictEqual(
|
|
|
|
'dark',
|
|
|
|
);
|
2022-03-07 19:53:19 +01:00
|
|
|
});
|
|
|
|
});
|
2023-01-17 16:23:04 +01:00
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
describe('setUseCurrencyRateCheck', () => {
|
|
|
|
it('should default to false', () => {
|
|
|
|
expect(
|
|
|
|
preferencesController.store.getState().useCurrencyRateCheck,
|
|
|
|
).toStrictEqual(true);
|
2023-01-17 16:23:04 +01:00
|
|
|
});
|
|
|
|
|
2023-08-24 12:27:42 +02:00
|
|
|
it('should set the useCurrencyRateCheck property in state', () => {
|
2023-01-17 16:23:04 +01:00
|
|
|
preferencesController.setUseCurrencyRateCheck(false);
|
2023-08-24 12:27:42 +02:00
|
|
|
expect(
|
2023-01-17 16:23:04 +01:00
|
|
|
preferencesController.store.getState().useCurrencyRateCheck,
|
2023-08-24 12:27:42 +02:00
|
|
|
).toStrictEqual(false);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('setIncomingTransactionsPreferences', () => {
|
|
|
|
const addedNonTestNetworks = Object.keys(NETWORK_CONFIGURATION_DATA);
|
|
|
|
|
|
|
|
it('should have default value combined', () => {
|
|
|
|
const state = preferencesController.store.getState();
|
|
|
|
expect(state.incomingTransactionsPreferences).toStrictEqual({
|
|
|
|
[CHAIN_IDS.MAINNET]: true,
|
|
|
|
[CHAIN_IDS.LINEA_MAINNET]: true,
|
|
|
|
[NETWORK_CONFIGURATION_DATA[addedNonTestNetworks[0]].chainId]: true,
|
|
|
|
[NETWORK_CONFIGURATION_DATA[addedNonTestNetworks[1]].chainId]: true,
|
|
|
|
[CHAIN_IDS.GOERLI]: true,
|
|
|
|
[CHAIN_IDS.SEPOLIA]: true,
|
|
|
|
[CHAIN_IDS.LINEA_GOERLI]: true,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should update incomingTransactionsPreferences with given value set', () => {
|
|
|
|
preferencesController.setIncomingTransactionsPreferences(
|
|
|
|
[CHAIN_IDS.LINEA_MAINNET],
|
2023-01-17 16:23:04 +01:00
|
|
|
false,
|
|
|
|
);
|
2023-08-24 12:27:42 +02:00
|
|
|
const state = preferencesController.store.getState();
|
|
|
|
expect(state.incomingTransactionsPreferences).toStrictEqual({
|
|
|
|
[CHAIN_IDS.MAINNET]: true,
|
|
|
|
[CHAIN_IDS.LINEA_MAINNET]: false,
|
|
|
|
[NETWORK_CONFIGURATION_DATA[addedNonTestNetworks[0]].chainId]: true,
|
|
|
|
[NETWORK_CONFIGURATION_DATA[addedNonTestNetworks[1]].chainId]: true,
|
|
|
|
[CHAIN_IDS.GOERLI]: true,
|
|
|
|
[CHAIN_IDS.SEPOLIA]: true,
|
|
|
|
[CHAIN_IDS.LINEA_GOERLI]: true,
|
|
|
|
});
|
2023-01-17 16:23:04 +01:00
|
|
|
});
|
|
|
|
});
|
2021-02-04 19:15:23 +01:00
|
|
|
});
|