apps   F
last analyzed

Complexity

Total Complexity 60

Size/Duplication

Total Lines 473
Duplicated Lines 0 %

Test Coverage

Coverage 99.77%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 368
c 1
b 0
f 0
dl 0
loc 473
ccs 431
cts 432
cp 0.9977
rs 3.6
wmc 60

2 Methods

Rating   Name   Duplication   Size   Complexity  
A getApp() 0 37 3
F get() 0 426 57

How to fix   Complexity   

Complex Class

Complex classes like apps often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use apps, and based on these observations, apply Extract Interface, too.

1
<?php
2
declare(strict_types = 1);
3
namespace hexydec\agentzero;
4
5
class apps {
6
7
	/**
8
	 * Generates a configuration array for matching apps
9
	 * 
10
	 * @return array<string,props> An array with keys representing the string to match, and values a props object defining how to generate the match and which properties to set
11
	 */
12 52
	public static function get() : array {
13 1
		$fn = [
14 1
			'appslash' => function (string $value, int $i, array $tokens, string $match) : array {
15 52
				if (\mb_stripos($value, 'AppleWebKit') === false && !\str_contains($value, '://') && !\str_starts_with($value, 'appid/')) {
16 27
					$parts = \explode('/', $value, 4);
17 27
					$offset = isset($parts[2]) && !\is_numeric($parts[1]) ? 1 : 0;
18 27
					$app = \str_replace('GooglePlayStore ', '', $parts[0 + $offset]);
19 27
					if (\mb_stripos($app, \rtrim($match, '/')) !== false) { // check the match is before the slash
20 27
						return [
21 27
							'app' => self::getApp($app),
22 27
							'appname' => \trim($app, '[]'),
23 27
							'appversion' => $parts[1 + $offset] ?? null
24 27
						];
25
					}
26
				}
27 41
				return [];
28 1
			},
29 1
		];
30 3
		return [
31 3
			'com.google.' => new props('start', function (string $value) : array {
32 1
				$parts = \explode('/', $value, 3);
33 1
				return [
34 1
					'type' => 'human',
35 1
					'app' => self::getApp($parts[0]),
36 1
					'appname' => $parts[0],
37 1
					'appversion' => $parts[1] ?? null
38 1
				];
39 3
			}),
40 3
			'OcIdWebView' => new props('exact', function (string $value) : array {
41 1
				$data = [
42 1
					'app' => 'Google App Web View',
43 1
					'appname' => $value
44 1
				];
45 1
				return $data;
46 3
			}),
47 3
			'Instagram' => new props('any', function (string $value, int $i, array $tokens) : array {
48 8
				$parts = \explode(' ', $value, 4);
49 8
				$data = [
50 8
					'type' => 'human',
51 8
					'app' => 'Instagram',
52 8
					'appname' => 'Instagram',
53 8
					'appversion' => $parts[1] ?? null,
54 8
					'platform' => empty($parts[2]) ? null : platforms::getPlatform($parts[2])
55 8
				];
56 8
				foreach (\array_slice($tokens, $i + 1) AS $key => $item) {
57 8
					$ipad = null;
58 8
					if (($ipados = \str_starts_with($item, 'iPadOS')) || \str_starts_with($item, 'iOS ')) {
59 2
						$data['kernel'] = 'Linux';
60 2
						$data['platform'] = 'iOS';
61 2
						$data['platformversion'] = \str_replace('_', '.', \mb_substr($item, $ipados ? 7 : 4));
62 2
						$data['density'] = \floatval(\mb_substr($item, 6));
63 8
					} elseif (($iphone = \str_starts_with($item, 'iPhone')) || ($ipad = \str_starts_with($item, 'iPad')) || \str_starts_with($item, 'iPod')) {
64 2
						$data['vendor'] = 'Apple';
65 2
						$data['category'] = $ipad ? 'tablet' : 'mobile';
66 2
						$data['device'] = $iphone ? 'iPhone' : ($ipad ? 'iPad' : 'iPod');
67 2
						$data['model'] = \str_replace(',', '.', \mb_substr($item, $iphone ? 6 : 4));
68 2
						$data['architecture'] = 'Arm';
69 2
						$data['bits'] = 64;
70 8
					} elseif (\str_starts_with($item, 'scale=')) {
71 2
						$data['density'] = \floatval(\mb_substr($item, 6));
72 8
					} elseif (\str_ends_with($item, 'dpi')) {
73 7
						$data['dpi'] = \intval(\mb_substr($item, 0, -3));
74 8
					} elseif (\str_contains($item, 'x') && \strspn($item, '0123456789x') === \strlen($item)) {
75 8
						list($data['width'], $data['height']) = \array_map('intval', \explode('x', $item, 2));
76
77
						// get device when the UA string starts with "Instagram"
78 8
						if ($i === 0 && !isset($data['vendor'])) {
79 1
							$device = [
80 1
								\trim(\mb_strstr($tokens[$key + 2] ?? '', '/') ?: $tokens[$key + 2] ?? '', '/ '), // sometimes the vendor name has a / with the correct name after
81 1
								$tokens[$key + 3] ?? null
82 1
							];
83
84
							// remove duplicated name
85 1
							if ($device[1] !== null && \mb_stripos($device[1], $device[0]) === 0) {
86 1
								unset($device[0]);
87
							}
88 1
							$data = \array_merge($data, devices::getDevice(\implode(' ', \array_filter($device))));
89 1
							break;
90
						}
91
					}
92
				}
93 8
				return $data;
94 3
			}),
95 3
			'imoAndroid/' => new props('start', fn (string $value, int $i, array $tokens) : array => \array_merge(
96 3
				isset($tokens[$i + 3]) ? devices::getDevice($tokens[$i + 3]) : [],
97 3
				[
98 3
					'app' => 'imo',
99 3
					'appname' => 'imoAndroid',
100 3
					'appversion' => ($ver = \mb_strstr($value, '/')) === false ? $value : \ltrim($ver, '/'),
101 3
					'platform' => 'Android',
102 3
					'platformversion' => $tokens[$i + 1] ?? null,
103 3
					'cpu' => $tokens[$i + 11] ?? null,
104 3
					'vendor' => isset($tokens[$i + 4]) ? devices::getVendor($tokens[$i + 4]) : null
105 3
				]
106 3
			)),
107 3
			'GSA/' => new props('any', $fn['appslash']),
108 3
			'DuckDuckGo/' => new props('start', $fn['appslash']),
109 3
			'FlipboardProxy/' => new props('start', $fn['appslash']),
110 3
			'Emacs/' => new props('start', $fn['appslash']),
111 3
			'AndroidDownloadManager/' => new props('start', $fn['appslash']),
112 3
			'Zoom ' => new props('start', fn (string $value) : array => [
113 2
				'app' => 'Zoom',
114 2
				'appname' => 'Zoom',
115 2
				'appversion' => \mb_substr($value, 5)
116 2
			]),
117 3
			'Reddit/' => new props('start', function (string $value, int $i, array $tokens) : array {
118 1
				$os = !empty($tokens[$i+2]) ? \explode('/', $tokens[$i+2], 2) : null;
119 1
				$parts = !empty($os[1]) ? \explode(' ', $os[1], 3) : null;
120 1
				return [
121 1
					'type' => 'human',
122 1
					'app' => 'Reddit',
123 1
					'appname' => 'Reddit',
124 1
					'appversion' => $value === 'Reddit/Version' ? (\mb_strstr($tokens[$i+1], '/', true) ?: null) : \mb_substr($value, 7),
125 1
					'platform' => $parts[0] ?? null,
126 1
					'platformversion' => $tokens[$i+3] ?? null
127 1
				];
128 3
			}),
129 3
			'Pinterest for ' => new props('start', fn (string $value) : array => [
130 1
				'type' => 'human',
131 1
				'app' => 'Pinterest',
132 1
				'appname' => 'Pinterest',
133 1
				'appversion' => \explode('/', $value, 3)[1],
134 1
				'platform' => \mb_substr($value, 14, \mb_strpos($value, '/') - 14)
135 1
			]),
136 3
			'OculusBrowser/' => new props('start', $fn['appslash']),
137 3
			'BaiduBrowser/' => new props('start', $fn['appslash']),
138 3
			'bdhonorbrowser/' => new props('start', $fn['appslash']),
139 3
			'YaBrowser/' => new props('start', $fn['appslash']),
140 3
			'YaApp_iOS/' => new props('start', $fn['appslash']),
141 3
			'YaApp_Android/' => new props('start', $fn['appslash']),
142 3
			'choqok/' => new props('start', $fn['appslash']),
143 3
			'Quora ' => new props('start', fn (string $value) : array => [
144 1
				'type' => 'human',
145 1
				'app' => 'Quora',
146 1
				'appname' => 'Quora',
147 1
				'appversion' => \explode(' ', $value, 3)[1]
148 1
			]),
149 3
			'AmazonKidsBrowser/' => new props('start', $fn['appslash']),
150 3
			'whisper/' => new props('start', $fn['appslash']),
151 3
			'Teams/' => new props('start', $fn['appslash']),
152 3
			'Viber/' => new props('start', $fn['appslash']),
153 3
			'MXPlayer/' => new props('start', fn (string $value) : array => [
154 1
				'app' => 'MXPlayer',
155 1
				'appname' => 'MXPlayer',
156 1
				'appversion' => \explode('/', $value, 3)[1] ?: null
157 1
			]),
158 3
			'Todoist-Android/' => new props('start', fn (string $value) : array => [
159 1
				'type' => 'human',
160 1
				'platform' => 'Android',
161 1
				'app' => 'Todoist',
162 1
				'appname' => 'Todoist-Android',
163 1
				'appversion' => \explode('/', $value, 3)[1] ?: null
164 1
			]),
165 3
			'Trello for Android/' => new props('start', fn (string $value) : array => [
166 1
				'type' => 'human',
167 1
				'platform' => 'Android',
168 1
				'app' => 'Trello',
169 1
				'appname' => 'Trello for Android',
170 1
				'appversion' => \explode('/', $value, 3)[1] ?: null
171 1
			]),
172 3
			'iPad PurpleMashApp' => new props('start', fn (string $value) : array => [
0 ignored issues
show
Unused Code introduced by
The parameter $value is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

172
			'iPad PurpleMashApp' => new props('start', fn (/** @scrutinizer ignore-unused */ string $value) : array => [

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
173 1
				'type' => 'human',
174 1
				'platform' => 'iOS',
175 1
				'vendor' => 'Apple',
176 1
				'device' => 'iPad',
177 1
				'app' => 'Purple Mash',
178 1
				'appname' => 'PurpleMashApp'
179 1
			]),
180 3
			'Instapaper for Android ' => new props('start', fn (string $value) : array => [
181 1
				'type' => 'human',
182 1
				'platform' => 'Android',
183 1
				'app' => 'Instapaper',
184 1
				'appname' => 'Instapaper',
185 1
				'appversion' => \mb_substr($value, \mb_strrpos($value, ' ') + 1)
186 1
			]),
187 3
			'Instapaper' => new props('start', fn (string $value, int $i, array $tokens, string $match) => \array_merge([
188 3
				'type' => 'human'
189 3
			], $fn['appslash']($value, $i, $tokens, $match))),
190 3
			'Player/LG' => new props('start', function (string $value, int $i, array $tokens) : ?array {
191 1
				if (\str_starts_with($tokens[$i+1], 'Player ')) {
192 1
					$parts = \explode(' ', $tokens[$i+1]);
193 1
					$device = $i === 1 ? \explode('/', $tokens[0]) : null;
194 1
					return [
195 1
						'type' => 'human',
196 1
						'vendor' => 'LG',
197 1
						'device' => $device[0] ?? null,
198 1
						'model' => $device[1] ?? null,
199 1
						'app' => 'LG Player',
200 1
						'appname' => 'LG Player',
201 1
						'appversion' => $parts[1] ?? null,
202 1
						'platform' => $parts[3] ?? null,
203 1
						'platformversion' => $parts[4] ?? null
204 1
					];
205
				}
206
				return null;
207 3
			}),
208 3
			'RobloxApp/' => new props('any', $fn['appslash']),
209 3
			'Nexo/' => new props('start', $fn['appslash']),
210 3
			'nu.nl/' => new props('any', fn (string $value) : array => [
211 1
				'app' => 'nu.nl',
212 1
				'appname' => 'nu.nl',
213 1
				'appversion' => \mb_substr($value, 6)
214 1
			]),
215 3
			'Sanoma/app' => new props('exact', fn () : array => [
216 1
				'type' => 'human',
217 1
				'app' => 'Sanoma',
218 1
				'appname' => 'Sanoma'
219 1
			]),
220 3
			'Google Web Preview' => new props('start', $fn['appslash']),
221 3
			'MicroMessenger/' => new props('start', $fn['appslash']),
222 3
			'MicroMessenger Weixin QQ' => new props('start', fn () : array => [
223 2
				'app' => 'WeChat',
224 2
				'appname' => 'MicroMessenger'
225 2
			]),
226 3
			'weibo' => new props('any', function (string $value) : array {
227 1
				$data = [
228 1
					'type' => 'human',
229 1
					'app' => 'Weibo',
230 1
					'appname' => 'Weibo'
231 1
				];
232 1
				if (\str_contains($value, '__')) {
233 1
					$parts = \explode('__', $value);
234 1
					$data = \array_merge($data, devices::getDevice($parts[0]), [
235 1
						'appname' => $parts[1],
236 1
						'appversion' => $parts[2] ?? null,
237 1
						'platform' => isset($parts[3]) ? platforms::getPlatform($parts[3]) : null,
238 1
						'platformversion' => isset($parts[4]) ? \substr($parts[4], \strcspn($parts[4], '0123456789.')) : null
239 1
					]);
240
				} else {
241 1
					$parts = \explode('_', $value);
242 1
					foreach ($parts AS $i => $item) {
243 1
						if (\mb_stripos($item, 'Weibo') !== false) {
244 1
							$data['appname'] = $item;
245 1
							$data['appversion'] = $parts[$i + (\strspn($parts[$i + 1] ?? '', '0123456789', 0, 1) === 1 ? 1 : 2)] ?? null;
246 1
							break;
247
						}
248
					}
249
				}
250 1
				return $data;
251 3
			}),
252
253
			// special parser for Facebook app because it is completely different to any other
254 3
			'FBAN/' => new props('any', function (string $value) : array {
255 4
				$map = [
256 4
					'FBAN/MessengerLiteForiOS' => [
257 4
						'type' => 'human',
258 4
						'app' => 'Facebook Messenger',
259 4
						'appname' => 'MessengerLiteForiOS',
260 4
						'platform' => 'iOS'
261 4
					],
262 4
					'FBAN/FB4A' => [
263 4
						'type' => 'human',
264 4
						'app' => 'Facebook',
265 4
						'appname' => 'FB4A',
266 4
						'platform' => 'Android'
267 4
					],
268 4
					'FBAN/FBIOS' => [
269 4
						'type' => 'human',
270 4
						'app' => 'Facebook',
271 4
						'appname' => 'FBIOS',
272 4
						'platform' => 'iOS'
273 4
					],
274 4
					'FBAN/FB4FireTV' => [
275 4
						'type' => 'human',
276 4
						'category' => 'tv',
277 4
						'app' => 'Facebook',
278 4
						'appname' => 'FB4FireTV',
279 4
						'platform' => 'Android'
280 4
					],
281 4
					'FBAN/MessengerDesktop' => [
282 4
						'type' => 'human',
283 4
						'category' => 'desktop',
284 4
						'app' => 'Facebook Messenger',
285 4
						'appname' => 'MessengerDesktop'
286 4
					],
287 4
					'FacebookCanvasDesktop FBAN/GamesWindowsDesktopApp' => [
288 4
						'type' => 'human',
289 4
						'platform' => 'Windows',
290 4
						'category' => 'desktop',
291 4
						'app' => 'Facebook Gamesroom',
292 4
						'appname' => 'GamesWindowsDesktopApp'
293 4
					]
294 4
				];
295 4
				return \array_merge([
296 4
					'type' => 'human',
297 4
					'app' => 'Facebook',
298 4
					'appname' => \explode('/', $value, 2)[1]
299 4
				], $map[$value] ?? []);
300 3
			}),
301 3
			'FB_IAB/' => new props('start', fn (string $value) : array => [
302 8
				'type' => 'human',
303 8
				'app' => 'Facebook',
304 8
				'appname' => \mb_substr($value, 7)
305 8
			]),
306 3
			'FBPN/' => new props('start', fn (string $value) : array => [
307 2
				'type' => 'human',
308 2
				'app' => 'Facebook',
309 2
				'appname' => \mb_substr($value, 5)
310 2
			]),
311 3
			'FBAV/' => new props('start', fn (string $value) : array => [
312 9
				'type' => 'human',
313 9
				'app' => 'Facebook',
314 9
				'appname' => 'Facebook',
315 9
				'appversion' => \mb_substr($value, 5)
316 9
			]),
317 3
			'FBMF/' => new props('start', fn (string $value) : array => [
318 2
				'type' => 'human',
319 2
				'app' => 'Facebook',
320 2
				'appname' => 'Facebook',
321 2
				'vendor' => devices::getVendor(\mb_substr($value, 5))
322 2
			]),
323 3
			'FBDV/' => new props('start', fn (string $value) : array => \array_merge(
324 3
				devices::getDevice(\mb_substr($value, 5))),
325 3
				[
0 ignored issues
show
Unused Code introduced by
The call to hexydec\agentzero\props::__construct() has too many arguments starting with array('type' => 'human',...appname' => 'Facebook'). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

325
			'FBDV/' => /** @scrutinizer ignore-call */ new props('start', fn (string $value) : array => \array_merge(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
326 3
					'type' => 'human',
327 3
					'app' => 'Facebook',
328 3
					'appname' => 'Facebook'
329 3
				]
330 3
			),
331 3
			'FBMD/' => new props('start', fn (string $value) : array => [
332 3
				'type' => 'human',
333 3
				'app' => 'Facebook',
334 3
				'appname' => 'Facebook',
335 3
				'model' => \mb_substr($value, 5)
336 3
			]),
337 3
			'FBDM/' => new props('start', function (string $value) : array {
338 1
				$data = [
339 1
					'type' => 'human',
340 1
					'app' => 'Facebook',
341 1
					'appname' => 'Facebook'
342 1
				];
343 1
				foreach (\explode(',', \trim(\mb_substr($value, 5), '{}')) AS $item) {
344 1
					$parts = \explode('=', $item);
345 1
					if (!empty($parts[1])) {
346 1
						if (\is_numeric($parts[1])) {
347 1
							$parts[1] = \str_contains($parts[1], '.') ? \floatval($parts[1]) : \intval($parts[1]);
348
						}
349 1
						$data[$parts[0]] = $parts[1];
350
					}
351
				}
352 1
				return $data;
353 3
			}),
354 3
			'FBSN/' => new props('start', fn (string $value) : array => [
355 3
				'type' => 'human',
356 3
				'app' => 'Facebook',
357 3
				'appname' => 'Facebook',
358 3
				'platform' => \mb_substr($value, 5)
359 3
			]),
360 3
			'FBSV' => new props('start', fn (string $value) : array => [
361 3
				'type' => 'human',
362 3
				'app' => 'Facebook',
363 3
				'appname' => 'Facebook',
364 3
				'platformversion' => \mb_substr($value, 5)
365 3
			]),
366 3
			'isDarkMode/' => new props('start', function (string $value) : array {
367 1
				$mode = \mb_substr($value, 11);
368 1
				return [
369 1
					'darkmode' => \in_array($mode, ['0', '1'], true) ? \boolval($mode) : null
370 1
				];
371 3
			}),
372 3
			'dark-mode' => new props('exact', ['darkmode' => true]),
373 3
			'AppTheme/' => new props('start', fn (string $value) : array => [
374 2
				'darkmode' => \mb_substr($value, 9) === 'dark'
375 2
			]),
376 3
			'Microsoft Office' => new props('start', function (string $value, int $i, array $tokens) : array {
377 1
				$data = [
378 1
					'type' => 'human'
379 1
				];
380 1
				if (\str_contains($value, '/')) {
381 1
					foreach (\array_slice($tokens, $i + 1) AS $item) {
382 1
						if (\str_starts_with($item, 'Microsoft ')) {
383 1
							$parts = \explode(' ', $item);
384 1
							$data['app'] = $parts[0].' '.$parts[1];
385 1
							$data['appname'] = $parts[0].' '.$parts[1];
386 1
							if (isset($parts[2])) {
387 1
								$data['appversion'] = $parts[2];
388
							}
389 1
							break;
390
						}
391
					}
392 1
					if (!isset($data['app'])) {
393 1
						$parts = \explode('/', $value, 2);
394 1
						$data['app'] = $parts[0];
395 1
						$data['appname'] = $parts[0];
396 1
						if (!isset($data['appversion'])) {
397 1
							$data['appversion'] = $parts[1];
398
						}
399
					}
400
				} else {
401 1
					$parts = \explode(' ', $value);
402 1
					$data['app'] = \rtrim($parts[0].' '.($parts[1] ?? '').' '.($parts[2] ?? ''));
403 1
					$data['appname'] = $value;
404 1
					$data['appversion'] = $parts[3] ?? null;
405
				}
406 1
				return $data;
407 3
			}),
408
409
			// TikTok
410 3
			'AppName/' => new props('start', function (string $value) : array {
411 2
				$map = [
412 2
					'AppName/musical_ly' => 'TikTok',
413 2
					'AppName/aweme' => 'Douyin'
414 2
				];
415 2
				return [
416 2
					'app' => $map[$value] ?? \mb_substr($value, 8),
417 2
					'appname' => \mb_substr($value, 8)
418 2
				];
419 3
			}),
420 3
			'app_version/' => new props('start', fn(string $value) : array => [
421 3
				'appversion' => \mb_substr($value, 12)
422 3
			]),
423 3
			'AppVersion/' => new props('any', fn(string $value) : array => [
424 2
				'appversion' => \explode('/', $value, 2)[1]
425 2
			]),
426 3
			'musical_ly' => new props('start', fn(string $value) : array => [
427 2
				'app' => 'TikTok',
428 2
				'appname' => 'musical_ly',
429 2
				'appversion' => \str_replace('_', '.', \mb_substr(\explode(' ', $value, 2)[0], 11))
430 2
			]),
431 3
			'Android App' => new props('any', [
432 3
				'type' => 'human',
433 3
				'platform' => 'Android'
434 3
			]),
435
				
436
			// generic
437 3
			'App' => new props('any', $fn['appslash'])
438 3
		];
439
	}
440
441 27
	public static function getApp(string $value) : string {
442 27
		$map = [
443 27
			'YaApp_iOS' => 'Yandex',
444 27
			'YaApp_Android' => 'Yandex',
445 27
			'YaSearchApp' => 'Yandex',
446 27
			'YaBrowser' => 'Yandex',
447 27
			'YaSearchBrowser' => 'Yandex',
448 27
			'LinkedInApp' => 'LinkedIn',
449 27
			'[LinkedInApp]' => 'LinkedIn',
450 27
			'GoogleApp' => 'Google',
451 27
			'com.zhiliaoapp.musically' => 'TikTok',
452 27
			'com.google.android.apps.searchlite' => 'Google',
453 27
			'com.google.android.googlequicksearchbox' => 'Google',
454 27
			'com.google.android.gms' => 'Google',
455 27
			'com.google.GoogleMobile' => 'Google',
456 27
			'com.google.Maps' => 'Google Maps',
457 27
			'com.google.photos' => 'Google Photos',
458 27
			'com.google.ios.youtube' => 'YouTube',
459 27
			'com.google.android.youtube' => 'YouTube',
460 27
			'AlohaBrowserApp' => 'Aloha',
461 27
			'OculusBrowser' => 'Oculus Browser',
462 27
			'AndroidDownloadManager' => 'Android Download Manager',
463 27
			'imoAndroid' => 'imo',
464 27
			'MicroMessenger' => 'WeChat',
465 27
			'GSA' => 'Google',
466 27
			'baiduboxapp' => 'Baidu',
467 27
			'lite baiduboxapp' => 'Baidu',
468 27
			'baidubrowser' => 'Baidu',
469 27
			'bdhonorbrowser' => 'Baidu',
470 27
			'RobloxApp' => 'Roblox'
471 27
		];
472 27
		if (isset($map[$value])) {
473 13
			return $map[$value];
474 17
		} elseif (($pos = \mb_strrpos($value, '.')) !== false) {
475 3
			return \mb_substr($value, $pos + 1);
476
		}
477 16
		return $value;
478
	}
479
}