From 76d61c9349614010cb3ac768b3934b78fd1b50ef Mon Sep 17 00:00:00 2001 From: Dawid Sowa <119939994+dawidsowardx@users.noreply.github.com> Date: Tue, 10 Dec 2024 20:47:19 +0100 Subject: [PATCH] feat: remove `bowser`, add EnvironmentModule (#292) * test: add various user agents to `isMobile` unit test * feat: add environment module - remove bowser in favor of custom regex - use DI for `isMobile` and `isBrowser` * fix: extract `isTMA` to environment module --- examples/simple-dapp/src/main.ts | 6 + package-lock.json | 4 +- packages/dapp-toolkit/package.json | 1 - packages/dapp-toolkit/src/_types.ts | 2 + packages/dapp-toolkit/src/helpers/index.ts | 1 - .../dapp-toolkit/src/helpers/is-browser.ts | 2 - .../src/helpers/is-mobile.spec.ts | 12 - .../dapp-toolkit/src/helpers/is-mobile.ts | 6 - .../connect-button/connect-button.module.ts | 21 +- .../src/modules/connect-button/subjects.ts | 6 +- .../environment/environment.module.spec.ts | 609 ++++++++++++++++++ .../modules/environment/environment.module.ts | 35 + .../src/modules/environment/index.ts | 1 + packages/dapp-toolkit/src/modules/index.ts | 1 + .../storage/local-storage.module.spec.ts | 7 +- .../modules/storage/local-storage.module.ts | 26 +- .../connector-extension.module.ts | 10 +- .../radix-connect-relay/deep-link.module.ts | 26 +- .../radix-connect-relay/helpers/index.ts | 1 - .../radix-connect-relay/helpers/isTma.ts | 8 - .../radix-connect-relay.module.ts | 11 +- .../wallet-request/wallet-request-sdk.ts | 7 +- .../wallet-request/wallet-request.spec.ts | 10 +- .../modules/wallet-request/wallet-request.ts | 14 +- .../dapp-toolkit/src/radix-dapp-toolkit.ts | 11 +- 25 files changed, 758 insertions(+), 80 deletions(-) delete mode 100644 packages/dapp-toolkit/src/helpers/is-browser.ts delete mode 100644 packages/dapp-toolkit/src/helpers/is-mobile.spec.ts delete mode 100644 packages/dapp-toolkit/src/helpers/is-mobile.ts create mode 100644 packages/dapp-toolkit/src/modules/environment/environment.module.spec.ts create mode 100644 packages/dapp-toolkit/src/modules/environment/environment.module.ts create mode 100644 packages/dapp-toolkit/src/modules/environment/index.ts delete mode 100644 packages/dapp-toolkit/src/modules/wallet-request/transport/radix-connect-relay/helpers/isTma.ts diff --git a/examples/simple-dapp/src/main.ts b/examples/simple-dapp/src/main.ts index 7a2be7c0..ac64dda0 100644 --- a/examples/simple-dapp/src/main.ts +++ b/examples/simple-dapp/src/main.ts @@ -7,6 +7,7 @@ import { DataRequestBuilder, OneTimeDataRequestBuilder, LocalStorageModule, + EnvironmentModule, generateRolaChallenge, SubintentRequestBuilder, } from '@radixdlt/radix-dapp-toolkit' @@ -15,6 +16,11 @@ const dAppDefinitionAddress = import.meta.env.VITE_DAPP_DEFINITION_ADDRESS const networkId = RadixNetwork.Stokenet const storageModule = LocalStorageModule( `rdt:${dAppDefinitionAddress}:${networkId}`, + { + providers: { + environmentModule: EnvironmentModule(), + }, + }, ) const requestsStore = storageModule.getPartition('requests') const sessionStore = storageModule.getPartition('sessions') diff --git a/package-lock.json b/package-lock.json index 6ff2f2d4..ea450e0e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13868,7 +13868,8 @@ "node_modules/bowser": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", - "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", + "dev": true }, "node_modules/bplist-parser": { "version": "0.2.0", @@ -32303,7 +32304,6 @@ "@noble/curves": "^1.4.0", "base64url": "^3.0.1", "blakejs": "^1.2.1", - "bowser": "^2.11.0", "buffer": "^6.0.3", "immer": "^10.0.4", "lit": "^3.1.2", diff --git a/packages/dapp-toolkit/package.json b/packages/dapp-toolkit/package.json index bc53e3f3..735e78e2 100644 --- a/packages/dapp-toolkit/package.json +++ b/packages/dapp-toolkit/package.json @@ -63,7 +63,6 @@ "@noble/curves": "^1.4.0", "base64url": "^3.0.1", "blakejs": "^1.2.1", - "bowser": "^2.11.0", "buffer": "^6.0.3", "immer": "^10.0.4", "lit": "^3.1.2", diff --git a/packages/dapp-toolkit/src/_types.ts b/packages/dapp-toolkit/src/_types.ts index 844969b8..1450ebd4 100644 --- a/packages/dapp-toolkit/src/_types.ts +++ b/packages/dapp-toolkit/src/_types.ts @@ -24,6 +24,7 @@ import type { GatewayModule, WalletRequestModule, ConnectButtonModule, + EnvironmentModule, } from './modules' import { BuildableSubintentRequest } from './modules/wallet-request/pre-authorization-request/subintent-builder' @@ -32,6 +33,7 @@ export type Providers = { gatewayModule: GatewayModule stateModule: StateModule storageModule: StorageModule + environmentModule: EnvironmentModule walletRequestModule: WalletRequestModule } diff --git a/packages/dapp-toolkit/src/helpers/index.ts b/packages/dapp-toolkit/src/helpers/index.ts index 840c47ae..c6f679d5 100644 --- a/packages/dapp-toolkit/src/helpers/index.ts +++ b/packages/dapp-toolkit/src/helpers/index.ts @@ -1,6 +1,5 @@ export * from './exponential-backoff' export * from './fetch-wrapper' -export * from './is-mobile' export * from './logger' export * from './parse-json' export * from './remove-undefined' diff --git a/packages/dapp-toolkit/src/helpers/is-browser.ts b/packages/dapp-toolkit/src/helpers/is-browser.ts deleted file mode 100644 index 88de98f5..00000000 --- a/packages/dapp-toolkit/src/helpers/is-browser.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const isBrowser = () => - ![typeof window, typeof document].includes('undefined') diff --git a/packages/dapp-toolkit/src/helpers/is-mobile.spec.ts b/packages/dapp-toolkit/src/helpers/is-mobile.spec.ts deleted file mode 100644 index 555dc582..00000000 --- a/packages/dapp-toolkit/src/helpers/is-mobile.spec.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { describe, it, expect } from 'vitest' -import { isMobile } from './is-mobile' - -describe('isMobile', () => { - it('should return true if userAgent is mobile', () => { - ;[ - 'Mozilla/5.0 (iPad; CPU OS 13_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/126.0.0.0 Mobile/15E148 Safari/604.1', - ].forEach((userAgent) => { - expect(isMobile(userAgent)).toBe(true) - }) - }) -}) diff --git a/packages/dapp-toolkit/src/helpers/is-mobile.ts b/packages/dapp-toolkit/src/helpers/is-mobile.ts deleted file mode 100644 index 2fed9ea2..00000000 --- a/packages/dapp-toolkit/src/helpers/is-mobile.ts +++ /dev/null @@ -1,6 +0,0 @@ -import Bowser from 'bowser' - -export const isMobile = (userAgent: string = window.navigator.userAgent) => { - const parsed = Bowser.parse(userAgent) - return parsed.platform.type === 'mobile' || parsed.platform.type === 'tablet' -} diff --git a/packages/dapp-toolkit/src/modules/connect-button/connect-button.module.ts b/packages/dapp-toolkit/src/modules/connect-button/connect-button.module.ts index 3ea51ace..a5511166 100644 --- a/packages/dapp-toolkit/src/modules/connect-button/connect-button.module.ts +++ b/packages/dapp-toolkit/src/modules/connect-button/connect-button.module.ts @@ -21,7 +21,7 @@ import type { RequestItem, } from 'radix-connect-common' import { ConnectButtonSubjects } from './subjects' -import { isMobile, type Logger } from '../../helpers' +import { type Logger } from '../../helpers' import { ExplorerConfig } from '../../_types' import { transformWalletDataToConnectButton, @@ -30,8 +30,8 @@ import { import { GatewayModule, RadixNetworkConfigById } from '../gateway' import { StateModule } from '../state' import { ConnectButtonModuleOutput } from './types' -import { isBrowser } from '../../helpers/is-browser' import { ConnectButtonNoopModule } from './connect-button-noop.module' +import { EnvironmentModule } from '../environment' export type ConnectButtonModule = ReturnType @@ -47,6 +47,7 @@ export type ConnectButtonModuleInput = { providers: { stateModule: StateModule gatewayModule: GatewayModule + environmentModule: EnvironmentModule walletRequestModule: WalletRequestModule } } @@ -54,13 +55,17 @@ export type ConnectButtonModuleInput = { export const ConnectButtonModule = ( input: ConnectButtonModuleInput, ): ConnectButtonModuleOutput => { - if (!isBrowser()) { + if (!input.providers.environmentModule.isBrowser()) { return ConnectButtonNoopModule() } import('@radixdlt/connect-button') const logger = input?.logger?.getSubLogger({ name: 'ConnectButtonModule' }) - const subjects = input.subjects || ConnectButtonSubjects() + const subjects = + input.subjects || + ConnectButtonSubjects({ + providers: { environmentModule: input.providers.environmentModule }, + }) const dAppDefinitionAddress = input.dAppDefinitionAddress const { baseUrl, accountsPath, transactionPath, subintentPath } = input.explorer ?? { @@ -86,7 +91,7 @@ export const ConnectButtonModule = ( const subscriptions = new Subscription() - const onConnectButtonRender$ = fromEvent(window, 'onConnectButtonRender') + const onConnectButtonRender$ = fromEvent(input.providers.environmentModule.globalThis, 'onConnectButtonRender') subscriptions.add( onConnectButtonRender$ @@ -418,7 +423,11 @@ export const ConnectButtonModule = ( oneTime: false, }), ) - .map(() => isMobile() && subjects.showPopoverMenu.next(false)), + .map( + () => + input.providers.environmentModule.isMobile() && + subjects.showPopoverMenu.next(false), + ), ), ) .subscribe(), diff --git a/packages/dapp-toolkit/src/modules/connect-button/subjects.ts b/packages/dapp-toolkit/src/modules/connect-button/subjects.ts index 9b495e5e..8f26d07f 100644 --- a/packages/dapp-toolkit/src/modules/connect-button/subjects.ts +++ b/packages/dapp-toolkit/src/modules/connect-button/subjects.ts @@ -1,10 +1,10 @@ import type { Account, RadixButtonTheme, RequestItem } from 'radix-connect-common' import { BehaviorSubject, ReplaySubject, Subject } from 'rxjs' -import { isMobile } from '../../helpers' import { ConnectButtonStatus } from './types' +import { EnvironmentModule } from '../environment' export type ConnectButtonSubjects = ReturnType -export const ConnectButtonSubjects = () => ({ +export const ConnectButtonSubjects = (input: { providers: { environmentModule: EnvironmentModule }}) => ({ onConnect: new Subject<{ challenge: string } | undefined>(), onDisconnect: new Subject(), onUpdateSharedAccounts: new Subject(), @@ -16,7 +16,7 @@ export const ConnectButtonSubjects = () => ({ onShowPopover: new Subject(), status: new BehaviorSubject('default'), loggedInTimestamp: new BehaviorSubject(''), - isMobile: new BehaviorSubject(isMobile()), + isMobile: new BehaviorSubject(input.providers.environmentModule.isMobile()), isWalletLinked: new BehaviorSubject(false), showPopoverMenu: new BehaviorSubject(false), isExtensionAvailable: new BehaviorSubject(false), diff --git a/packages/dapp-toolkit/src/modules/environment/environment.module.spec.ts b/packages/dapp-toolkit/src/modules/environment/environment.module.spec.ts new file mode 100644 index 00000000..2a3a3d07 --- /dev/null +++ b/packages/dapp-toolkit/src/modules/environment/environment.module.spec.ts @@ -0,0 +1,609 @@ +import { describe, expect, it } from 'vitest' +import { EnvironmentModule } from './environment.module' + +describe('EnvironmentModule', () => { + const environmentModule = EnvironmentModule() + const isMobile = environmentModule.isMobile + describe('isMobile', () => { + it('should return true if userAgent is mobile', () => { + ;[ + 'Mozilla/5.0 (iPad; CPU OS 13_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/126.0.0.0 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPad; CPU OS 14_7_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/132.0 Mobile/15E148 Safari/605.1.15', + 'Mozilla/5.0 (iPad; CPU OS 17_7_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (Linux; Android 10; ONEPLUS A6003) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.102 Mobile Safari/537.36 EdgA/130.0.2849.68', + 'Mozilla/5.0 (Linux; Android 15) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.104 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 15; SM-A205U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.104 Mobile Safari/537.36', + 'Mozilla/5.0 (Android 13; Mobile; rv:133.0) Gecko/133.0 Firefox/133.0', + 'Mozilla/5.0 (Android 14; Mobile; rv:132.0) Gecko/132.0 Firefox/132.0', + 'Mozilla/5.0 (iPad; CPU OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/129.0.6668.69 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPad; CPU OS 17_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPad; CPU OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/129.0.6668.69 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPad; CPU OS 17_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPad; CPU OS 17_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/129.0.6668.46 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPad; CPU OS 18_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/130.0.6723.78 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPad; CPU OS 18_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/131.0.6778.73 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/129.0.6668.46 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.4 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/128.0.6613.92 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/128.0.6613.98 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/129.0.6668.69 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/130.0.6723.90 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Safari/605.1.15', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/131.0.6778.73 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5.1 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5.2 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/123.0.6312.52 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/128.0.6613.92 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/129.0.6668.46 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/124.0.6367.88 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/128.0.6613.98 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/129.0.6668.69 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/130.0.6723.90 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/79.0.3945.73 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_7_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_7_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.7.1 Mobile/20H30 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_7_10 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_7_10 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.7 Mobile/15E148 Safari/604.1 OPT/5.0.7', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_7_10 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.7.10 Mobile/20H350 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_7_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_7_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.7.2 Mobile/20H115 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_7_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_7_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_7_8 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_7_8 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.7 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_7_8 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.7.8 Mobile/20H343 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/128.0.6613.98 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/129.0.6668.69 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Mobile/21B74 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Mobile/15E148 Safari/604.1 Ddg/17.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1.1 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_1_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Mobile/15E148 Safari/604.1 OPT/5.1.0', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_1_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1.2 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_2_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.3 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.3.1 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/121.0.6167.138 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/124.0.6367.68 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/128.0.6613.98 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/129.0.6668.69 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 YaBrowser/24.7.7.783.10 SA/3 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Mobile/21E236 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/126.0.6478.153 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/127.0.6533.107 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/127.0.6533.77 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/128.0.6613.34 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/128.0.6613.92 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/128.0.6613.98 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/129.0.6668.46 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/129.0.6668.69 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/130.0.6723.37 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/130.0.6723.78 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) GSA/333.0.671582647 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) GSA/336.0.679286625 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) GSA/339.0.686111475 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) GSA/342.0.693598186 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/131.0.6778.73 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1 Ddg/17.5', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5.1 Mobile/21F90 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/113.0.5672.109 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/120.0.6099.144 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/123.0.6312.52 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/126.0.6478.153 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/127.0.6533.107 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/128.0.6613.98 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/129.0.6668.46 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/129.0.6668.69 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/130.0.6723.37 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/130.0.6723.78 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/130.0.6723.90 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) EdgiOS/128.0.2739.42 Version/17.0 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) EdgiOS/130.0.2849.80 Version/17.0 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) GSA/333.0.671582647 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) GSA/335.0.676534794 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) GSA/338.1.685896509 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) GSA/340.3.689937600 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Mobile/15E148 Safari/604.1 Ddg/17.6', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/131.0.6778.73 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/130.1 Mobile/15E148 Safari/605.1.15', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Safari/605.1.15', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/21G93 [FBAN/FBIOS;FBAV/482.1.0.47.106;FBBV/644413532;FBDV/iPhone14,7;FBMD/iPhone;FBSN/iOS;FBSV/17.6.1;FBSS/3;FBID/phone;FBLC/pl_PL;FBOP/5;FBRV/646501326;IABMV/1]', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Mobile/15E148 Safari/604.1 Ddg/17.6', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Mobile/15E148 Safari/604.1 OPT/5.0.7', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6.1 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6.1 Mobile/15E148 Safari/605.1.15 (Ecosia ios@10.1.2.1933)', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6.1 Mobile/15E148 Safari/605.1.15 (Ecosia ios@10.1.3.1951)', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6.1 Mobile/21G101 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6.1 Mobile/21G93 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/116.0.5845.177 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/129.0.6668.46 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/130.0.6723.90 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.7 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.7 Mobile/21H16 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_7_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.8 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_7_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.8.1 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/112.0.5615.167 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/120.0.6099.144 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/125.0.6422.80 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/126.0.6478.161 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/128.0.6613.98 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/129.0.6668.46 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/129.0.6668.69 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/130.0.6723.37 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/130.0.6723.90 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/130.1 Mobile/15E148 Safari/605.1.15', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) GSA/331.0.665236494 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Safari/605.1.15', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/22A3354 Instagram 351.0.1.35.98 (iPhone13,4; iOS 18_0; fr_FR; fr-FR; scale=3.00; 1284x2778; 647722782; IABMV/1)', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/22A3354 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/131.0.6778.73 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/22A3370 Instagram 355.0.0.34.91 (iPhone15,3; iOS 18_0_1; hr_HR; hr; scale=3.00; 1290x2796; 656616803; IABMV/1)', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1 Ddg/18.0', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1 OPT/5.0.0', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1 OPT/5.1.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0.1 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0.1 Mobile/22A3370 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/128.0.6613.98 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/129.0.6668.46 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/130.0.6723.90 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) EdgiOS/130.0.2849.80 Version/18.0 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/132.0 Mobile/15E148 Safari/605.1.15', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.1 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.1 Mobile/22B5054e Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.1 Mobile/22B83 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_1_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/131.0.6778.73 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/131.0.6778.73 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.1 Mobile/15E148 Safari/604.1 Ddg/18.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.1.1 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.1.1 Mobile/22B91 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/130.0.6723.78 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) EdgiOS/130.0.2849.68 Version/18.0 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.2 Mobile/15E148 Safari/604.1', + 'Mozilla/5.0 (Linux; Android 10; 5030D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.79 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; CLT-L29 Build/HUAWEICLT-L29; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/132.0.6834.14 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/485.2.0.68.111;]', + 'Mozilla/5.0 (Linux; Android 10; CPH1931 Build/QKQ1.200209.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.100 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; HRY-LX1T Build/HONORHRY-LX1T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Mobile Safari/537.36 Presearch (Tempest)', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.118 Mobile Safari/537.36 XiaoMi/MiuiBrowser/14.17.0-gn', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.118 Mobile Safari/537.36 XiaoMi/MiuiBrowser/14.18.0-gn', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.118 Mobile Safari/537.36 XiaoMi/MiuiBrowser/14.19.0-gn', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Mobile Safari/537.36 AlohaBrowser/6.3.2', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Mobile Safari/537.36 AlohaBrowser/6.4.0', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Mobile Safari/537.36 EdgA/126.0.0.0', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Mobile Safari/537.36 OPR/83.0.0.0', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Mobile Safari/537.36 Veera/1.3.5', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Mobile Safari/537.36 EdgA/127.0.0.0', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Mobile Safari/537.36 OPR/84.0.0.0', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 EdgA/127.0.0.0', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 OPR/84.0.0.0', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Mobile Safari/537.36 EdgA/128.0.0.0', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.127 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Mobile Safari/537.36 EdgA/129.0.0.0', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Mobile Safari/537.36 OPR/85.0.0.0', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.100 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.54 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Mobile Safari/537.36 EdgA/130.0.0.0', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.60 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/25.0 Chrome/121.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/26.0 Chrome/122.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/27.0 Chrome/125.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.88 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; M2007J20CG) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.40 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; moto z4 Build/QPFS30.130-15-11-23) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; moto z4 Build/QPFS30.130-15-11-23) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.100 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; Nokia 5.1 Plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; Redmi Note 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; Redmi Note 9S Build/QKQ1.191215.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/131.0.6778.46 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/490.0.0.63.82;IABMV/1;]', + 'Mozilla/5.0 (Linux; Android 10; Redmi Y3 Build/QKQ1.191008.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.148 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; Redmi Y3 Build/QKQ1.191008.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.102 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; SM-A015F Build/QP1A.190711.020) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.43 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; SM-A015F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.99 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; STK-L21 Build/HUAWEISTK-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.105 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; STK-L21 Build/HUAWEISTK-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; STK-L21 Build/HUAWEISTK-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.100 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; TECNO KD7 Build/QP1A.190711.020) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.99 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 10; YAL-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; 220333QAG) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; CPH1937 Build/RKQ1.200903.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; CPH1989 Build/RP1A.200720.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.58 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; CPH2113) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; Infinix X6812 Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.146 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/475.0.0.60.109;]', + 'Mozilla/5.0 (Linux; Android 11; Infinix X6812 Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.54 Mobile Safari/537.36[FBAN/EMA;FBLC/en_US;FBAV/407.0.0.12.116;]', + 'Mozilla/5.0 (Linux; Android 11; Infinix X6812 Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/130.0.6723.108 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/485.2.0.68.111;]', + 'Mozilla/5.0 (Linux; Android 11; Infinix X688B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.82 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; Infinix X689B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; Infinix X695) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.210 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.133 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.105 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.127 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.100 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.70 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.71 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.107 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.39 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; K) AppleWebKit/537.36 (KHTML, like Gecko) Stargon/6.1.5 Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.127 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.127 Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; K) Build/RZBS31.Q2-143-27-25) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.70 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; K) play Build/RPXS31.Q2-58-17-7-3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.107 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; K) power Build/RPES31.Q4U-47-35-12) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.81 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; K) power Build/RPES31.Q4U-47-35-12) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.107 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; Lenovo TB-J716F Build/RKQ1.201112.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.20 Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; LM-K510 Build/RKQ1.210420.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.88 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/452.0.0.45.110;]', + 'Mozilla/5.0 (Linux; Android 11; M2003J15SC Build/RP1A.200720.011;) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; M2003J15SC) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.85 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; M2007J20CG Build/RKQ1.200826.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.108 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; M2101K7BI Build/RP1A.200720.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; M2101K7BI Build/RP1A.200720.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.81 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; M2102J20SI Build/RKQ1.200826.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.88 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; moto e20 Build/RONS31.267-94-14) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.127 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; moto e20 Build/RONS31.267-94-14) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; moto g(20)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.210 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; moto g(9) play Build/RPXS31.Q2-58-17-7-3; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.100 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/479.1.0.76.109;]', + 'Mozilla/5.0 (Linux; Android 11; Motorola Defy) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.85 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; Redmi Note 7 Build/RQ3A.211001.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; Redmi Note 8 Pro Build/RP1A.200720.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; Redmi Note 8 Pro Build/RP1A.200720.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; SM-A125F Build/RP1A.200720.012; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.88 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/480.0.0.54.88;]', + 'Mozilla/5.0 (Linux; Android 11; TECNO KF6k) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.98 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; V2043 Build/RP1A.200720.012; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/127.0.6533.103 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/473.0.0.35.110;]', + 'Mozilla/5.0 (Linux; Android 11; V2043 Build/RP1A.200720.012; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.127 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/474.1.0.47.109;]', + 'Mozilla/5.0 (Linux; Android 11; V2146 Build/RP1A.200720.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.14 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; vivo 1901) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.101 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; vivo 1904; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/87.0.4280.141 Mobile Safari/537.36 VivoBrowser/12.9.0.4', + 'Mozilla/5.0 (Linux; Android 11; vivo 1918 Build/RP1A.200720.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.81 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11; vivo 1920 Build/RP1A.200720.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.127 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 11) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.146 Mobile DuckDuckGo/5 Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; CPH2473) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; Infinix X6516 Build/SP1A.210812.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/127.0.6533.103 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/474.1.0.47.109;]', + 'Mozilla/5.0 (Linux; Android 12; itel S665L Build/SP1A.210812.016; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/126.0.6478.186 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; K) Build/S2RI32.32-20-9-9-2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.128 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; M2007J17C Build/SKQ1.211006.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; M2007J20CG Build/SKQ1.211019.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.66 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/483.0.0.51.72;]', + 'Mozilla/5.0 (Linux; Android 12; M2007J20CG) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; M2007J20CI Build/SKQ1.211019.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.127 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; M2007J3SG Build/SKQ1.211006.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/130.0.6723.24 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/486.0.0.66.70;IABMV/1;]', + 'Mozilla/5.0 (Linux; Android 12; M2010J19SG Build/SKQ1.211202.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.100 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; M2010J19SI Build/SKQ1.211202.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.105 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; M2012K11AG Build/SKQ1.211006.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/127.0.6533.105 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; M2101K7AG Build/SKQ1.210908.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; M2101K7BNY) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; M2102J20SG Build/SKQ1.211006.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; M2102J20SG Build/SKQ1.211006.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.100 Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; Mi 10 Pro Build/XiaomiMi 10 Pro;) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/99.0.4844.88 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; Redmi Note 9 Build/SQ3A.220705.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.127 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; Redmi Note 9 Pro Build/SKQ1.211019.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.143 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; RMX2155 Build/SP1A.210812.016; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.146 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/475.0.0.60.109;]', + 'Mozilla/5.0 (Linux; Android 12; RMX2155 Build/SP1A.210812.016; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.66 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/483.0.0.51.72;IABMV/1;]', + 'Mozilla/5.0 (Linux; Android 12; RMX2155 Build/SP1A.210812.016; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/130.0.6723.24 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/486.0.0.66.70;IABMV/1;]', + 'Mozilla/5.0 (Linux; Android 12; RMX2161 Build/SP1A.210812.016) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; RMX2161 Build/SP1A.210812.016) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.38 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; SAMSUNG SM-A115M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/22.0 Chrome/111.0.5563.116 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; SM-A315G Build/SP1A.210812.016) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.128 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; SM-A715F Build/HUAWEISM-A715F;) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/99.0.4844.88 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; SM-G780G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.88 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; SM-G970F Build/SP1A.210812.016; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.148 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/476.1.0.47.109;]', + 'Mozilla/5.0 (Linux; Android 12; SM-M317F Build/SP1A.210812.016) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.127 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; SM-N970F Build/SP1A.210812.016; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/127.0.6533.143 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/466.0.0.39.109;]', + 'Mozilla/5.0 (Linux; Android 12; TECNO KI5k Build/SP1A.210812.016) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12; V2027 Build/SP1A.210812.003; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/127.0.6533.105 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/473.1.0.45.110;]', + 'Mozilla/5.0 (Linux; Android 12; V2027 Build/SP1A.210812.003) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 12) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; 2201116PI Build/TKQ1.221114.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; 2201117PG Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/130.0.6723.24 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/486.0.0.66.70;IABMV/1;]', + 'Mozilla/5.0 (Linux; Android 13; 2209116AG Build/TKQ1.221114.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.127 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; 23108RN04Y Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.70 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/478.0.0.47.115;]', + 'Mozilla/5.0 (Linux; Android 13; 23122PCD1G Build/TKQ1.221114.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.108 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; 23124RA7EO Build/TKQ1.221114.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.148 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/476.1.0.47.109;]', + 'Mozilla/5.0 (Linux; Android 13; Android_Device) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; CPH2159 Build/TP1A.220905.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; CPH2159 Build/TP1A.220905.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/130.0.6723.86 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; CPH2197 Build/TP1A.220905.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.51 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/482.0.0.51.80;]', + 'Mozilla/5.0 (Linux; Android 13; CPH2473 Build/TP1A.220905.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.127 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; CPH2591 Build/TP1A.220905.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; en; Infinix X6525B Build/SP1A.210812.016) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.129 HiBrowser/v2.24.1.3 UWS/ Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; en; Infinix X6711 Build/SP1A.210812.016) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.129 HiBrowser/v2.23.1.4 UWS/ Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; en; Infinix X678B Build/SP1A.210812.016) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.129 HiBrowser/v2.23.1.4 UWS/ Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; Infinix X6525 Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.134 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/481.0.0.61.80;]', + 'Mozilla/5.0 (Linux; Android 13; Infinix X6731B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.70 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; Infinix X6739 Build/TP1A.220624.014) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; Infinix X6815D Build/TP1A.220624.014) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; itel A666LN Build/TP1A.220624.014) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.5563.116 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.70 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.81 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.107 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.39 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.88 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.38 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.70 Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; M2101K6G Build/TKQ1.221013.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; M2101K6G Build/TKQ1.221013.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.88 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; M2101K6P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.159 Mobile Safari/537.36 OPR/82.2.4342.79546', + 'Mozilla/5.0 (Linux; Android 13; M2101K7BNY Build/TP1A.220624.014) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.58 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; M2101K9G Build/TKQ1.220829.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.127 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; M2103K19G Build/TP1A.220624.014;) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; moto e13 Build/TLAS33.105-285-4; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.146 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/482.0.0.51.80;]', + 'Mozilla/5.0 (Linux; Android 13; moto e13 Build/TLAS33.105-285-4; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/130.0.6723.24 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/486.0.0.66.70;IABMV/1;]', + 'Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; RMX3363) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Mobile Safari/537.36 Carbon', + 'Mozilla/5.0 (Linux; Android 13; RMX3624 Build/TP1A.220624.014) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.82 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; RMX3630 Build/TP1A.220905.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; RMX3760 Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.100 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/479.1.0.76.109;]', + 'Mozilla/5.0 (Linux; Android 13; RMX3830 Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.123 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/480.0.0.54.88;]', + 'Mozilla/5.0 (Linux; Android 13; SAMSUNG SM-A032M Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 SamsungBrowser/7.4 Chrome/129.0.6668.100 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; SAMSUNG SM-A127F) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/23.0 Chrome/115.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; SAMSUNG SM-A325F) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/23.0 Chrome/115.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; SM-A037F Build/TP1A.220624.014) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.70 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; SM-A326B Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.127 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/475.0.0.60.109;]', + 'Mozilla/5.0 (Linux; Android 13; SM-A515F Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.70 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/477.0.0.50.99;]', + 'Mozilla/5.0 (Linux; Android 13; SM-G781B Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.146 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/477.0.0.50.99;]', + 'Mozilla/5.0 (Linux; Android 13; SM-G781B Build/TP1A.220624.014) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; TECNO LH8n Build/TP1A.220624.014) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; V2025) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; V2037 Build/TP1A.220624.014) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; V2037 Build/TP1A.220624.014) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.82 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 13; V2146 Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/130.0.6723.107 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/483.0.0.51.72;IABMV/1;]', + 'Mozilla/5.0 (Linux; Android 14; 22041211AC Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.20 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; 22041211AC Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.38 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; 22041211AC Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.5 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; 22041211AC Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.2 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; 22041211AC Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.6834.14 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; 22041216C Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; 22041219NY Build/UP1A.231005.007; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/127.0.6533.103 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/473.1.0.45.110;]', + 'Mozilla/5.0 (Linux; Android 14; 22071212AG Build/UP1A.230905.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.82 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; 2211133G Build/UKQ1.230705.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.127 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; 23021RAA2Y Build/UKQ1.230917.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.134 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/481.0.0.61.80;]', + 'Mozilla/5.0 (Linux; Android 14; 23021RAA2Y Build/UKQ1.230917.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.100 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/484.0.0.63.83;IABMV/1;]', + 'Mozilla/5.0 (Linux; Android 14; 23049PCD8G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.192 Mobile Safari/537.36 OPR/74.2.3922.71802', + 'Mozilla/5.0 (Linux; Android 14; 23076PC4BI Build/UKQ1.230917.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.127 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; 23090RA98C Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; 2311DRK48G Build/UP1A.230905.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; 2311DRK48G Build/UP1A.230905.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.127 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; 23124RA7EO Build/UKQ1.231207.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.97 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/485.0.0.70.77;IABMV/1;]', + 'Mozilla/5.0 (Linux; Android 14; 2312DRA50G Build/UKQ1.231003.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.148 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/477.0.0.50.99;]', + 'Mozilla/5.0 (Linux; Android 14; 2312DRA50G Build/UKQ1.231003.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.81 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; 24066PC95I Build/UKQ1.240116.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; ASUS_AI2401_D Build/UKQ1.231003.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.88 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; CPH2581 Build/UKQ1.230924.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.127 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/475.0.0.60.109;]', + 'Mozilla/5.0 (Linux; Android 14; CPH2591 Build/UP1A.230620.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; en; A065 Build/SP1A.210812.016) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.129 HiBrowser/v2.23.1.4 UWS/ Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; en; Infinix X6833B Build/SP1A.210812.016) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.129 HiBrowser/v2.23.1.4 UWS/ Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; en; Infinix X6853 Build/SP1A.210812.016) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.129 HiBrowser/v2.22.3.5 UWS/ Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; en; RMX3710 Build/SP1A.210812.016) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.129 HiBrowser/v2.23.1.4 UWS/ Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; I2214 Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.128 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; I2214 Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.102 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; I2216 Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.127 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; I2219 Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; I2219 Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.100 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; I2220 Build/UP1A.231005.007_IN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; I2220 Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; I2220 Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; Infinix X678B Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.81 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; Infinix X6833B Build/UP1A.231005.007; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; Infinix X6833B Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; Infinix X6833B Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.107 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; Infinix X6850 Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.58 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.186 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.128 Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.38 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.5 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/131.0.6778.39 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; motorola edge 30 neo Build/U1SSMS34.31-64-4-6; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.146 Mobile Safari/537.36 Instagram 349.0.0.39.104 Android (34/14; 420dpi; 1080x2174; motorola; motorola edge 30 neo; miami; qcom; pt_BR; 642842387)', + 'Mozilla/5.0 (Linux; Android 14; MT2111 Build/UKQ1.230924.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.102 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; RMX3393 Build/UKQ1.230924.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.51 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/482.0.0.51.80;]', + 'Mozilla/5.0 (Linux; Android 14; RMX3710 Build/UKQ1.230924.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.105 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; RMX3780 Build/UKQ1.230924.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.134 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/481.0.0.61.80;]', + 'Mozilla/5.0 (Linux; Android 14; RMX3998 Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; SAMSUNG SM-A055F) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/22.0 Chrome/111.0.5563.116 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; SM-A245F Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.108 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; SM-A256B Build/UP1A.231005.007; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.81 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/478.0.0.47.115;]', + 'Mozilla/5.0 (Linux; Android 14; SM-A525F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Mobile Safari/537.36 Carbon', + 'Mozilla/5.0 (Linux; Android 14; SM-M236B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Mobile Safari/537.36 Carbon', + 'Mozilla/5.0 (Linux; Android 14; SM-S911B Build/UP1A.231005.007; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.148 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/476.1.0.47.109;]', + 'Mozilla/5.0 (Linux; Android 14; TECNO KJ7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; TECNO LH8n) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.56 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; TrebleDroid with GApps Build/UQ1A.240205.004) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/121.0.6167.164 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 14; V2310 Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.103 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 8.1.0; CPH1909) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 8.1.0; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 8.1.0; OPPO R11; Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.4280.141 Mobile Safari/537.36 Firefox-KiToBrowser/115.0', + 'Mozilla/5.0 (Linux; Android 9; AMN-LX9 Build/HUAWEIAMN-LX9; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/127.0.6533.103 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/474.1.0.47.109;]', + 'Mozilla/5.0 (Linux; Android 9; ASUS_X01AD Build/WW_Phone-202011271133) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.127 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 9; CPH2083 Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/127.0.6533.84 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 9; Infinix X650C Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.110 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 9; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.105 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 9; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 9; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.81 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 9; LG-H870 Build/PKQ1.190522.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.146 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/476.1.0.47.109;]', + 'Mozilla/5.0 (Linux; Android 9; Redmi 6A Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.81 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 9; Redmi 8A Pro Build/PKQ1.190319.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.122 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 9; Redmi Y2 Build/PKQ1.181203.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 9; vivo 1902 Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.146 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 9; vivo 1904) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.66 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; Android 9; VIVO Y17 Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.73 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; arm_64; Android 13; M2012K11AG) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.165 YaBrowser/24.7.8.165.00 SA/3 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; arm_64; Android 13; SM-A515F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.61 YaBrowser/24.7.9.61.00 SA/3 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; arm_64; Android 13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.142 YaBrowser/24.7.4.142.00 SA/3 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; arm_64; Android 14; SM-A057F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.124 YaBrowser/24.7.3.124.00 SA/3 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; arm_64; Android 14; SM-A057F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.22 YaBrowser/24.7.8.22.00 (beta) SA/3 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; arm_64; Android 14; SM-A057F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.46 YaBrowser/24.10.2.46.00 (beta) SA/3 Mobile Safari/537.36', + 'Mozilla/5.0 (Linux; U; Android 10; id-id; Redmi Note 9 Pro Build/QQ3A.200805.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/Mint Browser/3.9.3', + 'Mozilla/5.0 (Linux; U; Android 11; Redmi Note 8 Pro Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.146 Safari/537.36 OPR/84.0.2254.73823', + 'Mozilla/5.0 (Linux; U; Android 12; en-gb; SM-A125F Build/SP1A.210812.016) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.61 Mobile Safari/537.36 PHX/5.6', + 'Mozilla/5.0 (Linux; U; Android 12; M2102J20SG Build/SKQ1.211006.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.128 Mobile Safari/537.36 OPR/84.0.2254.73823', + 'Mozilla/5.0 (Linux; U; Android 12; Redmi Note 9 Pro Max Build/SKQ1.211019.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.146 Mobile Safari/537.36 OPR/84.0.2254.73823', + 'Mozilla/5.0 (Linux; U; Android 12; SM-M115F Build/SP1A.210812.016; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.81 Mobile Safari/537.36 OPR/83.1.2254.73239', + 'Mozilla/5.0 (Linux; U; Android 13; en-us; Redmi 10 Build/TP1A.220624.014) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4896.127 Mobile Safari/537.36 XiaoMi/MiuiBrowser/13.25.2.2-gn', + 'Mozilla/5.0 (Linux; U; Android 13; pt-pt; Redmi Note 11 Build/TKQ1.221114.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/112.0.5615.136 Mobile Safari/537.36 XiaoMi/MiuiBrowser/14.10.1.2-gn', + 'Mozilla/5.0 (Linux; U; Android 14; en-us; 23046PNC9C Build/UP1A.231005.007) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.119 Mobile Safari/537.36 XiaoMi/MiuiBrowser/18.6.60929', + 'Mozilla/5.0 (Linux; U; Android 8.1.0; SM-G610F Build/M1AJQ; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.127 Mobile Safari/537.36 OPR/47.2.2254.147957', + 'Mozilla/5.0 (Linux; U; Android 9; in-id; Infinix X650C Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Mobile Safari/537.36 PHX/10.6', + ].forEach((userAgent) => { + expect(isMobile(userAgent)).toBe(true) + }) + }) + + it('should return false if user agent is not mobile', () => { + ;[ + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 13.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6308.196 Safari/537.36 Edg/126.0.2282.70', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 OPR/112.0.0.0', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 YaBrowser/24.7.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Decentr Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Norton/127.0.0.0', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 OPR/113.0.0.0', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 OPR/113.0.0.0 (Edition std-1)', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 OPR/114.0.0.0', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 OPR/114.0.0.0 (Edition std-2)', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 YaBrowser/24.10.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.644 YaBrowser/24.10.4.644 (beta) Yowser/2.5 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 AVG/130.0.0.0', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0', + 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0', + 'Mozilla/5.0 (Windows NT 10.0; WOW64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6301.219 Safari/537.36', + 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.140', + 'Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36', + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36', + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36', + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36', + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36', + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:132.0) Gecko/20100101 Firefox/132.0', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0', + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:132.0) Gecko/20100101 Firefox/132.0', + 'Mozilla/5.0 (X11; Linux x86_64; rv:132.0) Gecko/20100101 Firefox/132.0', + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36', + 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:132.0) Gecko/20100101 Firefox/132.0', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36', + 'Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.1 Safari/605.1.15', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.1.1 Safari/605.1.15', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Safari/605.1.15', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:133.0) Gecko/20100101 Firefox/133.0', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 OPR/114.0.0.0', + 'Mozilla/5.0 (X11; Linux x86_64; rv:131.0) Gecko/20100101 Firefox/131.0', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0.1 Safari/605.1.15', + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36', + 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0', + 'Mozilla/5.0 (X11; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 YaBrowser/24.10.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:130.0) Gecko/20100101 Firefox/130.0', + 'Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36', + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36', + 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/119.0', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:131.0) Gecko/20100101 Firefox/131.0', + 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36', + 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:131.0) Gecko/20100101 Firefox/131.0', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Safari/605.1.15', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.95 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0', + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36', + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + ].forEach((userAgent) => { + expect(isMobile(userAgent)).toBe(false) + }) + }) + }) +}) diff --git a/packages/dapp-toolkit/src/modules/environment/environment.module.ts b/packages/dapp-toolkit/src/modules/environment/environment.module.ts new file mode 100644 index 00000000..d520c097 --- /dev/null +++ b/packages/dapp-toolkit/src/modules/environment/environment.module.ts @@ -0,0 +1,35 @@ +export type EnvironmentModule = ReturnType +export const EnvironmentModule = () => { + const isMobile = (userAgent: string) => { + const ua = userAgent.toLowerCase() + + return /(mobi|ipod|phone|blackberry|opera mini|fennec|minimo|symbian|psp|nintendo ds|archos|skyfire|puffin|blazer|bolt|gobrowser|iris|maemo|semc|teashark|uzard|ipad|tablet|(android(?!.*mobile))|(windows(?!.*phone)(.*touch))|kindle|playbook|silk|(puffin(?!.*(IP|AP|WP))))/.test( + ua, + ) + } + + const getNavigator = () => { + return typeof navigator !== 'undefined' ? navigator : undefined + } + + /** + * Checks if the provided object is a Telegram Mobile App (TMA) global object. + * + * @param maybeTgGlobalObject - The object to check. + * @returns `true` if the object has WebView initialization parameters, otherwise `false`. + */ + const isTMA = () => + Object.keys((globalThis as any)?.Telegram?.WebView?.initParams || {}) + .length > 0 + + return { + get globalThis() { + return globalThis + }, + isMobile: (userAgent?: string) => { + return isMobile(userAgent ?? getNavigator()?.userAgent ?? '') + }, + isTMA, + isBrowser: () => ![typeof window, typeof document].includes('undefined'), + } +} diff --git a/packages/dapp-toolkit/src/modules/environment/index.ts b/packages/dapp-toolkit/src/modules/environment/index.ts new file mode 100644 index 00000000..edd92c80 --- /dev/null +++ b/packages/dapp-toolkit/src/modules/environment/index.ts @@ -0,0 +1 @@ +export * from './environment.module' \ No newline at end of file diff --git a/packages/dapp-toolkit/src/modules/index.ts b/packages/dapp-toolkit/src/modules/index.ts index 075c0a7a..c7e2d8d4 100644 --- a/packages/dapp-toolkit/src/modules/index.ts +++ b/packages/dapp-toolkit/src/modules/index.ts @@ -1,5 +1,6 @@ export * from './connect-button' export * from './gateway' export * from './state' +export * from './environment' export * from './storage' export * from './wallet-request' diff --git a/packages/dapp-toolkit/src/modules/storage/local-storage.module.spec.ts b/packages/dapp-toolkit/src/modules/storage/local-storage.module.spec.ts index 23d5c36d..63534677 100644 --- a/packages/dapp-toolkit/src/modules/storage/local-storage.module.spec.ts +++ b/packages/dapp-toolkit/src/modules/storage/local-storage.module.spec.ts @@ -5,12 +5,17 @@ import { beforeEach, describe, expect, it } from 'vitest' import { LocalStorageModule, StorageModule } from './local-storage.module' import { ResultAsync } from 'neverthrow' +import { EnvironmentModule } from '../environment' describe('LocalStorageModule', () => { let storageModule: StorageModule beforeEach(() => { - storageModule = LocalStorageModule(`rdt:${crypto.randomUUID()}:1`) + storageModule = LocalStorageModule(`rdt:${crypto.randomUUID()}:1`, { + providers: { + environmentModule: EnvironmentModule(), + }, + }) }) it('should store and read data', async () => { diff --git a/packages/dapp-toolkit/src/modules/storage/local-storage.module.ts b/packages/dapp-toolkit/src/modules/storage/local-storage.module.ts index 61645765..d3703ae6 100644 --- a/packages/dapp-toolkit/src/modules/storage/local-storage.module.ts +++ b/packages/dapp-toolkit/src/modules/storage/local-storage.module.ts @@ -1,6 +1,7 @@ import { err, Ok, ok, Result, ResultAsync } from 'neverthrow' import { typedError, parseJSON, stringify } from '../../helpers' import { filter, fromEvent, map, merge, mergeMap, of } from 'rxjs' +import { EnvironmentModule } from '../environment' type NetworkId = number type PartitionKey = @@ -24,11 +25,18 @@ export type StorageModule = ReturnType< > export const LocalStorageModule = ( - key: `rdt:${dAppDefinitionAddress}:${NetworkId}`, - partitionKey?: PartitionKey, + storageKey: + | `rdt:${dAppDefinitionAddress}:${NetworkId}` + | `rdt:${dAppDefinitionAddress}:${NetworkId}${string}`, + { + providers, + }: { + providers: { + environmentModule: EnvironmentModule + } + }, ) => { - const storageKey = partitionKey ? `${key}:${partitionKey}` : key - + const _window = providers.environmentModule.globalThis const getDataAsync = (): Promise => new Promise((resolve, reject) => { try { @@ -71,7 +79,7 @@ export const LocalStorageModule = ( setDataAsync(serialized), typedError, ).map(() => { - window.dispatchEvent( + _window.dispatchEvent( new StorageEvent('storage', { key: storageKey, oldValue: JSON.stringify(items), @@ -97,7 +105,7 @@ export const LocalStorageModule = ( setDataAsync(serialized), typedError, ).map(() => { - window.dispatchEvent( + _window.dispatchEvent( new StorageEvent('storage', { key: storageKey, oldValue: JSON.stringify(data), @@ -120,7 +128,7 @@ export const LocalStorageModule = ( setDataAsync(serialized), typedError, ).map(() => { - window.dispatchEvent( + _window.dispatchEvent( new StorageEvent('storage', { key: storageKey, oldValue: JSON.stringify(oldValue), @@ -147,10 +155,10 @@ export const LocalStorageModule = ( ) const getPartition = (partitionKey: PartitionKey) => - LocalStorageModule(key, partitionKey) + LocalStorageModule(`${storageKey}:${partitionKey}`, { providers }) const storage$ = merge( - fromEvent(window, 'storage'), + fromEvent(providers.environmentModule.globalThis, 'storage'), of({ key: storageKey, newValue: null, oldValue: null }), ).pipe( filter((item) => item.key === storageKey), diff --git a/packages/dapp-toolkit/src/modules/wallet-request/transport/connector-extension/connector-extension.module.ts b/packages/dapp-toolkit/src/modules/wallet-request/transport/connector-extension/connector-extension.module.ts index 0bbf9cdd..132712cf 100644 --- a/packages/dapp-toolkit/src/modules/wallet-request/transport/connector-extension/connector-extension.module.ts +++ b/packages/dapp-toolkit/src/modules/wallet-request/transport/connector-extension/connector-extension.module.ts @@ -20,7 +20,7 @@ import { tap, timer, } from 'rxjs' -import { Logger, isMobile, unwrapObservable } from '../../../../helpers' +import { Logger, unwrapObservable } from '../../../../helpers' import { CallbackFns, IncomingMessage, @@ -35,6 +35,7 @@ import { SdkError } from '../../../../error' import { TransportProvider } from '../../../../_types' import { v4 as uuidV4 } from 'uuid' import type { RequestResolverModule } from '../../request-resolver/request-resolver.module' +import { EnvironmentModule } from '../../../environment' export type ConnectorExtensionModule = ReturnType< typeof ConnectorExtensionModule @@ -45,6 +46,7 @@ export const ConnectorExtensionModule = (input: { logger?: Logger extensionDetectionTime?: number providers: { + environmentModule: EnvironmentModule requestResolverModule: RequestResolverModule storageModule: StorageModule<{ sessionId?: string }> } @@ -95,7 +97,7 @@ export const ConnectorExtensionModule = (input: { method: 'outgoingMessageSubject', payload, }) - window.dispatchEvent( + input.providers.environmentModule.globalThis.dispatchEvent( new CustomEvent(eventType.outgoingMessage, { detail: payload, }), @@ -311,7 +313,7 @@ export const ConnectorExtensionModule = (input: { return { id: 'connector-extension' as const, - isSupported: () => !isMobile(), + isSupported: () => !input.providers.environmentModule.isMobile(), send: sendWalletInteraction, isAvailable$: extensionStatus$.pipe( map(({ isExtensionAvailable }) => isExtensionAvailable), @@ -320,7 +322,7 @@ export const ConnectorExtensionModule = (input: { map(({ isWalletLinked }) => isWalletLinked), ), showQrCode: () => { - window.dispatchEvent( + input.providers.environmentModule.globalThis.dispatchEvent( new CustomEvent(eventType.outgoingMessage, { detail: { discriminator: 'openPopup' }, }), diff --git a/packages/dapp-toolkit/src/modules/wallet-request/transport/radix-connect-relay/deep-link.module.ts b/packages/dapp-toolkit/src/modules/wallet-request/transport/radix-connect-relay/deep-link.module.ts index 57729e22..8f64e027 100644 --- a/packages/dapp-toolkit/src/modules/wallet-request/transport/radix-connect-relay/deep-link.module.ts +++ b/packages/dapp-toolkit/src/modules/wallet-request/transport/radix-connect-relay/deep-link.module.ts @@ -1,26 +1,20 @@ import { ResultAsync } from 'neverthrow' import { errAsync, okAsync } from 'neverthrow' -import { Logger, isMobile } from '../../../../helpers' -import Bowser from 'bowser' +import { Logger } from '../../../../helpers' import { SdkError } from '../../../../error' -import { isTMA } from './helpers' +import { EnvironmentModule } from '../../../environment' export type DeepLinkModule = ReturnType export const DeepLinkModule = (input: { logger?: Logger walletUrl: string + providers: { + environmentModule: EnvironmentModule + } }) => { const { walletUrl } = input - const userAgent = Bowser.parse(window.navigator.userAgent) - const { platform } = userAgent const logger = input?.logger?.getSubLogger({ name: 'DeepLinkModule' }) - const isTelegramMiniApp = isTMA(globalThis) - - logger?.debug({ - platform, - userAgent: window.navigator.userAgent, - userAgentParsed: userAgent, - }) + const isTelegramMiniApp = input.providers.environmentModule.isTMA() const deepLinkToWallet = ( values: Record, @@ -36,12 +30,14 @@ export const DeepLinkModule = (input: { data: { ...values }, }) - if (isMobile()) { + if (input.providers.environmentModule.isMobile()) { const deepLink = outboundUrl.toString() // Telegram Mini App does not support deep linking by changing location.href value - if (isTelegramMiniApp) globalThis.open(deepLink, '_blank') - else if (globalThis.location?.href) globalThis.location.href = deepLink + if (isTelegramMiniApp) + input.providers.environmentModule.globalThis.open(deepLink, '_blank') + else if (input.providers.environmentModule.globalThis.location?.href) + input.providers.environmentModule.globalThis.location.href = deepLink return okAsync(undefined) } diff --git a/packages/dapp-toolkit/src/modules/wallet-request/transport/radix-connect-relay/helpers/index.ts b/packages/dapp-toolkit/src/modules/wallet-request/transport/radix-connect-relay/helpers/index.ts index 502b20aa..4a0ecfb1 100644 --- a/packages/dapp-toolkit/src/modules/wallet-request/transport/radix-connect-relay/helpers/index.ts +++ b/packages/dapp-toolkit/src/modules/wallet-request/transport/radix-connect-relay/helpers/index.ts @@ -1,2 +1 @@ export * from './base64url' -export * from './isTma' diff --git a/packages/dapp-toolkit/src/modules/wallet-request/transport/radix-connect-relay/helpers/isTma.ts b/packages/dapp-toolkit/src/modules/wallet-request/transport/radix-connect-relay/helpers/isTma.ts deleted file mode 100644 index f2218c1e..00000000 --- a/packages/dapp-toolkit/src/modules/wallet-request/transport/radix-connect-relay/helpers/isTma.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Checks if the provided object is a Telegram Mobile App (TMA) global object. - * - * @param maybeTgGlobalObject - The object to check. - * @returns `true` if the object has WebView initialization parameters, otherwise `false`. - */ -export const isTMA = (globalObject: any) => - Object.keys(globalObject?.Telegram?.WebView?.initParams || {}).length > 0 diff --git a/packages/dapp-toolkit/src/modules/wallet-request/transport/radix-connect-relay/radix-connect-relay.module.ts b/packages/dapp-toolkit/src/modules/wallet-request/transport/radix-connect-relay/radix-connect-relay.module.ts index 3b56bc65..fe865ff6 100644 --- a/packages/dapp-toolkit/src/modules/wallet-request/transport/radix-connect-relay/radix-connect-relay.module.ts +++ b/packages/dapp-toolkit/src/modules/wallet-request/transport/radix-connect-relay/radix-connect-relay.module.ts @@ -7,7 +7,7 @@ import type { WalletInteraction, WalletInteractionResponse, } from '../../../../schemas' -import { Logger, isMobile, parseJSON } from '../../../../helpers' +import { Logger, parseJSON } from '../../../../helpers' import { SdkError } from '../../../../error' import { DeepLinkModule } from './deep-link.module' import { IdentityModule } from '../../identity/identity.module' @@ -20,6 +20,7 @@ import { import type { TransportProvider } from '../../../../_types' import { base64urlEncode } from './helpers/base64url' import type { RequestResolverModule } from '../../request-resolver/request-resolver.module' +import { EnvironmentModule } from '../../../environment' export type RadixConnectRelayModule = ReturnType export const RadixConnectRelayModule = (input: { @@ -30,6 +31,7 @@ export const RadixConnectRelayModule = (input: { providers: { storageModule: StorageModule requestResolverModule: RequestResolverModule + environmentModule: EnvironmentModule encryptionModule?: EncryptionModule identityModule?: IdentityModule sessionModule?: SessionModule @@ -47,6 +49,9 @@ export const RadixConnectRelayModule = (input: { DeepLinkModule({ logger, walletUrl, + providers: { + environmentModule: input.providers.environmentModule, + }, }) const identityModule = @@ -113,7 +118,7 @@ export const RadixConnectRelayModule = (input: { checkRelayLoop() } - if (isMobile()) { + if (input.providers.environmentModule.isMobile()) { checkRelayLoop() } @@ -222,7 +227,7 @@ export const RadixConnectRelayModule = (input: { return { id: 'radix-connect-relay' as const, - isSupported: () => isMobile(), + isSupported: () => input.providers.environmentModule.isMobile(), send: sendToWallet, disconnect: () => {}, destroy: () => { diff --git a/packages/dapp-toolkit/src/modules/wallet-request/wallet-request-sdk.ts b/packages/dapp-toolkit/src/modules/wallet-request/wallet-request-sdk.ts index a79732af..12e03a74 100644 --- a/packages/dapp-toolkit/src/modules/wallet-request/wallet-request-sdk.ts +++ b/packages/dapp-toolkit/src/modules/wallet-request/wallet-request-sdk.ts @@ -7,12 +7,12 @@ import { WalletInteractionItems, WalletInteraction, WalletInteractionFailureResponse, - WalletInteractionResponse, WalletInteractionSuccessResponse, } from '../../schemas' import { parse } from 'valibot' import { SdkError } from '../../error' import { v4 as uuidV4 } from 'uuid' +import { EnvironmentModule } from '../environment' export type WalletRequestSdkInput = { networkId: number @@ -25,6 +25,7 @@ export type WalletRequestSdkInput = { providers: { transports: TransportProvider[] interactionIdFactory?: () => string + environmentModule: EnvironmentModule } } export type WalletRequestSdk = ReturnType @@ -34,7 +35,9 @@ export const WalletRequestSdk = (input: WalletRequestSdkInput) => { version: 2, dAppDefinitionAddress: input.dAppDefinitionAddress, networkId: input.networkId, - origin: input.origin || window.location.origin, + origin: + input.origin || + input.providers.environmentModule.globalThis?.location?.origin || '', } as Metadata const interactionIdFactory = input.providers.interactionIdFactory ?? uuidV4 diff --git a/packages/dapp-toolkit/src/modules/wallet-request/wallet-request.spec.ts b/packages/dapp-toolkit/src/modules/wallet-request/wallet-request.spec.ts index c9c4c315..466bbfa7 100644 --- a/packages/dapp-toolkit/src/modules/wallet-request/wallet-request.spec.ts +++ b/packages/dapp-toolkit/src/modules/wallet-request/wallet-request.spec.ts @@ -17,9 +17,14 @@ import { delayAsync } from '../../test-helpers/delay-async' import { WalletRequestSdk } from './wallet-request-sdk' import { TransportProvider } from '../../_types' import { TestingTransportModule } from './transport/testing-transport/transport.testing-module' +import { EnvironmentModule } from '../environment' const createMockEnvironment = () => { - const storageModule = LocalStorageModule(`rdt:${crypto.randomUUID()}:1`) + const storageModule = LocalStorageModule(`rdt:${crypto.randomUUID()}:1`, { + providers: { + environmentModule: EnvironmentModule(), + }, + }) const gatewayModule = { pollTransactionStatus: (hash: string) => ResultAsync.fromSafePromise(delayAsync(2000)).map(() => @@ -76,6 +81,7 @@ describe('WalletRequestModule', () => { networkId: RadixNetwork.Stokenet, dAppDefinitionAddress: '', providers: { + environmentModule: EnvironmentModule(), stateModule: {} as any, storageModule, requestItemModule, @@ -173,11 +179,13 @@ describe('WalletRequestModule', () => { storageModule, requestItemModule, requestResolverModule, + environmentModule: EnvironmentModule(), gatewayModule, walletRequestSdk: WalletRequestSdk({ networkId: 2, dAppDefinitionAddress: '', providers: { + environmentModule: EnvironmentModule(), interactionIdFactory: () => interactionId, transports: [testingTransport], }, diff --git a/packages/dapp-toolkit/src/modules/wallet-request/wallet-request.ts b/packages/dapp-toolkit/src/modules/wallet-request/wallet-request.ts index 7973bedb..43e120fe 100644 --- a/packages/dapp-toolkit/src/modules/wallet-request/wallet-request.ts +++ b/packages/dapp-toolkit/src/modules/wallet-request/wallet-request.ts @@ -46,6 +46,7 @@ import { } from './request-resolver' import { RequestItemTypes } from 'radix-connect-common' import { PreauthorizationPollingModule } from './pre-authorization-request/preauthorization-polling-module' +import { EnvironmentModule } from '../environment' export type WalletRequestModule = ReturnType export const WalletRequestModule = (input: { @@ -59,6 +60,7 @@ export const WalletRequestModule = (input: { stateModule: StateModule storageModule: StorageModule gatewayModule: GatewayModule + environmentModule: EnvironmentModule transports?: TransportProvider[] dataRequestStateModule?: DataRequestStateModule requestItemModule?: RequestItemModule @@ -145,7 +147,11 @@ export const WalletRequestModule = (input: { const transports: TransportProvider[] = input.providers.transports ?? [ ConnectorExtensionModule({ logger, - providers: { storageModule, requestResolverModule }, + providers: { + storageModule, + requestResolverModule, + environmentModule: input.providers.environmentModule, + }, }), RadixConnectRelayModule({ logger, @@ -155,6 +161,7 @@ export const WalletRequestModule = (input: { providers: { storageModule, requestResolverModule, + environmentModule: input.providers.environmentModule, }, }), ] @@ -167,7 +174,10 @@ export const WalletRequestModule = (input: { origin: input.origin, dAppDefinitionAddress, requestInterceptor: input.requestInterceptor, - providers: { transports }, + providers: { + transports, + environmentModule: input.providers.environmentModule, + }, }) const cancelRequestControl = (id: string) => { diff --git a/packages/dapp-toolkit/src/radix-dapp-toolkit.ts b/packages/dapp-toolkit/src/radix-dapp-toolkit.ts index d68446c0..87bb5af4 100644 --- a/packages/dapp-toolkit/src/radix-dapp-toolkit.ts +++ b/packages/dapp-toolkit/src/radix-dapp-toolkit.ts @@ -18,6 +18,7 @@ import { ConnectButtonModule, generateGatewayApiConfig, } from './modules' +import { EnvironmentModule } from './modules/environment' export type RadixDappToolkit = { walletApi: WalletApi @@ -45,9 +46,15 @@ export const RadixDappToolkit = ( useCache = true, } = options || {} + const environmentModule = providers?.environmentModule ?? EnvironmentModule() + const storageModule = providers?.storageModule ?? - LocalStorageModule(`rdt:${dAppDefinitionAddress}:${networkId}`) + LocalStorageModule(`rdt:${dAppDefinitionAddress}:${networkId}`, { + providers: { + environmentModule, + }, + }) const stateModule = providers?.stateModule ?? @@ -83,6 +90,7 @@ export const RadixDappToolkit = ( stateModule, storageModule, gatewayModule, + environmentModule, }, }) @@ -96,6 +104,7 @@ export const RadixDappToolkit = ( dAppDefinitionAddress, providers: { stateModule, + environmentModule, walletRequestModule, gatewayModule, },