apps::get()   F
last analyzed

Complexity

Conditions 57
Paths 1

Size

Total Lines 426
Code Lines 333

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 394
CRAP Score 57

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 57
eloc 333
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 426
ccs 394
cts 395
cp 0.9975
crap 57
rs 3.3333

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
}