diff --git a/Jakefile.js b/Jakefile.js index b68e869aae..1544ccec0a 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -795,7 +795,7 @@ compileFile( /*prereqs*/[builtLocalDirectory, tscFile, tsserverLibraryFile].concat(libraryTargets).concat(servicesSources).concat(harnessSources), /*prefixes*/[], /*useBuiltCompiler:*/ true, - /*opts*/ { types: ["node", "mocha", "chai"], lib: "es6" }); + /*opts*/ { types: ["node", "mocha"], lib: "es6" }); var internalTests = "internal/"; diff --git a/package-lock.json b/package-lock.json index 6c44ab023b..5dc35c5bb2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "integrity": "sha1-z6I7xYQPkQTOMqZedNt+epdLvuE=", "dev": true, "requires": { - "acorn": "5.1.2", + "acorn": "5.2.1", "css": "2.2.1", "normalize-path": "2.1.1", "source-map": "0.5.7", @@ -18,9 +18,9 @@ }, "dependencies": { "acorn": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz", - "integrity": "sha512-o96FZLJBPY1lvTuJylGA9Bk3t/GKPPJG8H0ydQQl01crzwJgspa4AEIq/pVTXigmK0PHVQhiAtn8WMBLL9D2WA==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.2.1.tgz", + "integrity": "sha512-jG0u7c4Ly+3QkkW18V+NRDN+4bWHdln30NL1ZL2AvFZZmQe/BfopYCtghCKKVBUSetZ4QKcyA0pY6/4Gw8Pv8w==", "dev": true } } @@ -42,13 +42,13 @@ "dev": true, "requires": { "@types/insert-module-globals": "7.0.0", - "@types/node": "8.0.46" + "@types/node": "8.0.54" } }, "@types/chai": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.0.4.tgz", - "integrity": "sha512-cvU0HomQ7/aGDQJZsbtJXqBQ7w4J4TqLB0Z/h8mKrpRjfeZEvTbygkfJEb7fWdmwpIeDeFmIVwAEqS0OYuUv3Q==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.0.7.tgz", + "integrity": "sha512-OsFOcyJH0SViMMHzDKZdapG8sfoH7qcpYgKhgyw9xn5MgkCvAplkf0FUaRFB+HTrVH6gQ/GU7sbIUDM1usVEUA==", "dev": true }, "@types/colors": { @@ -58,9 +58,9 @@ "dev": true }, "@types/convert-source-map": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@types/convert-source-map/-/convert-source-map-1.5.0.tgz", - "integrity": "sha512-4OHKJEw70U59CN24TLRxU3W+B/9GPp0P6g+eNIsObZLAIqw6NTEBorkjIpei4xsvUCx+YzFwUtt4MBZbfSLvbQ==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@types/convert-source-map/-/convert-source-map-1.5.1.tgz", + "integrity": "sha512-laiDIXqqthjJlyAMYAXOtN3N8+UlbM+KvZi4BaY5ZOekmVkBs/UxfK5O0HWeJVG2eW8F+Mu2ww13fTX+kY1FlQ==", "dev": true }, "@types/del": { @@ -72,6 +72,12 @@ "@types/glob": "5.0.33" } }, + "@types/events": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-1.1.0.tgz", + "integrity": "sha512-y3bR98mzYOo0pAZuiLari+cQyiKk3UXRuT45h1RjhfeCzqkjaVsfZJNaxdgtk7/3tzOm1ozLTqEqMP3VbI48jw==", + "dev": true + }, "@types/glob": { "version": "5.0.33", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-5.0.33.tgz", @@ -79,56 +85,56 @@ "dev": true, "requires": { "@types/minimatch": "3.0.1", - "@types/node": "8.0.46" + "@types/node": "8.0.54" } }, "@types/gulp": { - "version": "3.8.33", - "resolved": "https://registry.npmjs.org/@types/gulp/-/gulp-3.8.33.tgz", - "integrity": "sha512-3UpA2pkKO40cNPe/8bxMQFWSASR9Jx67JfN9Z2Cf6ogfDMwXgEHm2XjKmuLYEtrp1IHYApOWlYMLYNgtTJgSAw==", + "version": "3.8.35", + "resolved": "https://registry.npmjs.org/@types/gulp/-/gulp-3.8.35.tgz", + "integrity": "sha512-h9clNJu8X6+zW74ZLa5zhh5HP0LxnvlelVXdXby6pM/DDEj/gKqmmFXKwjzvupZKlMpof02jr6c3JokPbHXQgg==", "dev": true, "requires": { - "@types/node": "8.0.46", - "@types/orchestrator": "0.3.0", + "@types/node": "8.0.54", + "@types/orchestrator": "0.3.2", "@types/vinyl": "2.0.1" } }, "@types/gulp-concat": { - "version": "0.0.31", - "resolved": "https://registry.npmjs.org/@types/gulp-concat/-/gulp-concat-0.0.31.tgz", - "integrity": "sha512-F14zRcKn15HC59RXRlHpcxj79WoLjkJBJBPfN0NBZOgkRCfDZYVu8rs0Y/CH4CJGUbbc/nHczD2LmepDS+ARaA==", + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/gulp-concat/-/gulp-concat-0.0.32.tgz", + "integrity": "sha512-CUCFADlITzzBfBa2bdGzhKtvBr4eFh+evb+4igVbvPoO5RyPfHifmyQlZl6lM7q19+OKncRlFXDU7B4X9Ayo2g==", "dev": true, "requires": { - "@types/node": "8.0.46" + "@types/node": "8.0.54" } }, "@types/gulp-help": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/@types/gulp-help/-/gulp-help-0.0.33.tgz", - "integrity": "sha1-ZejGUSQQkiVTf6OQA8S6UfT9GsU=", + "version": "0.0.34", + "resolved": "https://registry.npmjs.org/@types/gulp-help/-/gulp-help-0.0.34.tgz", + "integrity": "sha512-MkW7psZznxxJg2MBk2P2qHE+T8jEZVFz3FG/qGjUYazkyJt7hBJWx5Nuewmay5RVNtUvSWPrdZLr/WTXY3T/6A==", "dev": true, "requires": { - "@types/gulp": "3.8.33", - "@types/node": "8.0.46", - "@types/orchestrator": "0.3.0" + "@types/gulp": "3.8.35", + "@types/node": "8.0.54", + "@types/orchestrator": "0.3.2" } }, "@types/gulp-newer": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/@types/gulp-newer/-/gulp-newer-0.0.30.tgz", - "integrity": "sha1-bqn7oVsFdr5CTpl31IlCAEZKFR4=", + "version": "0.0.31", + "resolved": "https://registry.npmjs.org/@types/gulp-newer/-/gulp-newer-0.0.31.tgz", + "integrity": "sha512-e7J/Zv5Wd7CC0WpuA2syWVitgwrkG0u221e41w7r07XUR6hMH6kHPkq9tUrusHkbeW8QbuLbis5fODOwQCyggQ==", "dev": true, "requires": { - "@types/node": "8.0.46" + "@types/node": "8.0.54" } }, "@types/gulp-sourcemaps": { - "version": "0.0.31", - "resolved": "https://registry.npmjs.org/@types/gulp-sourcemaps/-/gulp-sourcemaps-0.0.31.tgz", - "integrity": "sha512-kJD1byVNx+sdQlaBzZpSGeFH/4l99TXTY4XSGW+aRk27eOnVyk6VknXJpsb1Jk5E4ThKxZ8GYy6ais7MtprK1w==", + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/gulp-sourcemaps/-/gulp-sourcemaps-0.0.32.tgz", + "integrity": "sha512-+7BAmptW2bxyJnJcCEuie7vLoop3FwWgCdBMzyv7MYXED/HeNMeQuX7uPCkp4vfU1TTu4CYFH0IckNPvo0VePA==", "dev": true, "requires": { - "@types/node": "8.0.46" + "@types/node": "8.0.54" } }, "@types/insert-module-globals": { @@ -137,16 +143,16 @@ "integrity": "sha512-zudCJPwluh1VUDB6Gl/OQdRp+fYy3+47huJB/JMQubMS2p+sH18MCVK4WUz3FqaWLB12yh5ELxVR/+tqwlm/qA==", "dev": true, "requires": { - "@types/node": "8.0.46" + "@types/node": "8.0.54" } }, "@types/merge2": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@types/merge2/-/merge2-1.1.2.tgz", - "integrity": "sha512-Xy54xPmFQ8oAx0S3ku46i/zXE4dvfxl5M8n4p2M62IwxPau8IpobiRtL4jkrUzX6Kgeyb34BHOh0i70SDjKHeA==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@types/merge2/-/merge2-1.1.4.tgz", + "integrity": "sha512-GjaXY4OultxbaOOk7lCLO7xvEcFpdjExC605YmfI6X29vhHKpJfMWKCDZd3x+BITrZaXKg97DgV/SdGVSwdzxA==", "dev": true, "requires": { - "@types/node": "8.0.46" + "@types/node": "8.0.54" } }, "@types/minimatch": { @@ -162,58 +168,53 @@ "dev": true }, "@types/mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha512-XA4vNO6GCBz8Smq0hqSRo4yRWMqr4FPQrWjhJt6nKskzly4/p87SfuJMFYGRyYb6jo2WNIQU2FDBsY5r1BibUA==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-0.5.2.tgz", + "integrity": "sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg==", "dev": true, "requires": { - "@types/node": "8.0.46" + "@types/node": "8.0.54" } }, "@types/mocha": { - "version": "2.2.43", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.43.tgz", - "integrity": "sha512-xNlAmH+lRJdUMXClMTI9Y0pRqIojdxfm7DHsIxoB2iTzu3fnPmSMEN8SsSx0cdwV36d02PWCWaDUoZPDSln+xw==", + "version": "2.2.44", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.44.tgz", + "integrity": "sha512-k2tWTQU8G4+iSMvqKi0Q9IIsWAp/n8xzdZS4Q4YVIltApoMA00wFBFdlJnmoaK1/z7B0Cy0yPe6GgXteSmdUNw==", "dev": true }, "@types/node": { - "version": "8.0.46", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.46.tgz", - "integrity": "sha512-rRkP4kb5JYIfAoRKaDbcdPZBcTNOgzSApyzhPN9e6rhViSJAWQGlSXIX5gc75iR02jikhpzy3usu31wMHllfFw==", - "dev": true - }, - "@types/orchestrator": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@types/orchestrator/-/orchestrator-0.3.0.tgz", - "integrity": "sha1-v4ShaZyTMNT+ic2BJj6PwJ+zKXg=", + "version": "8.0.54", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.54.tgz", + "integrity": "sha512-qetMdTv3Ytz9u9ESLdcYs45LPI0mczYZIbC184n7kY0jczOqPNQsabBfVCh+na3B2shAfvC459JqHV771A8Rxg==", "dev": true, "requires": { - "@types/node": "8.0.46", - "@types/q": "0.0.37" - }, - "dependencies": { - "@types/q": { - "version": "0.0.37", - "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.37.tgz", - "integrity": "sha512-vjFGX1zMTMz/kUp3xgfJcxMVLkMWVMrdlyc0RwVyve1y9jxwqNaT8wTcv6M51ylq2a/zn5lm8g7qPSoIS4uvZQ==", - "dev": true - } + "@types/events": "1.1.0" + } + }, + "@types/orchestrator": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@types/orchestrator/-/orchestrator-0.3.2.tgz", + "integrity": "sha512-cKB4yTX0wGaRCSkdHDX2fkGQbMAA8UOshC2U7DQky1CE5o+5q2iQQ8VkbPbE/88uaTtsusvBPMcCX7dgmjxBhQ==", + "dev": true, + "requires": { + "@types/node": "8.0.54", + "@types/q": "1.0.6" } }, "@types/q": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/q/-/q-1.0.5.tgz", - "integrity": "sha512-sudQPADzmQjXYS1fS2TxbWA/N/vbbfaO4Y7luPaAEyRWZVXC8jHwKV8KgNDbT7IHQaONNZWy9BYsodxY7IyDXQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.0.6.tgz", + "integrity": "sha512-LSx7jkcXoXWB+kkfwG5zc9Okbgn51BrjLMtKwbmnqfQlCGttTnTxvDVwQanHxkK6CLKb9yEfxQ1ID6pqDpeURw==", "dev": true }, "@types/run-sequence": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/run-sequence/-/run-sequence-0.0.29.tgz", - "integrity": "sha1-atD3ODE24TklMi5p/EHbd7MLIHU=", + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/run-sequence/-/run-sequence-0.0.30.tgz", + "integrity": "sha512-XwGr1b4yCGUILKeBkzmeWcxmGHQ0vFFFpA6D6y1yLO6gKmYorF+PHqdU5KG+nWt38OvtrkDptmrSmlHX/XtpLw==", "dev": true, "requires": { - "@types/gulp": "3.8.33", - "@types/node": "8.0.46" + "@types/gulp": "3.8.35", + "@types/node": "8.0.54" } }, "@types/through2": { @@ -222,7 +223,7 @@ "integrity": "sha1-H/LoihAN+1sUDnu5h5HxGUQA0TE=", "dev": true, "requires": { - "@types/node": "8.0.46" + "@types/node": "8.0.54" } }, "@types/vinyl": { @@ -231,16 +232,26 @@ "integrity": "sha512-Joudabfn2ZofU2usW04y8OLmN75u7ZQkW0MCT3AnoBf5oUBp5iQ3Pgfz9+y1RdWkzhCPZo9/wBJ7FMWW2JrY0g==", "dev": true, "requires": { - "@types/node": "8.0.46" + "@types/node": "8.0.54" } }, "@types/xml2js": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.0.tgz", - "integrity": "sha512-3gw0UqFMq7PsfMDwsawD0/L48soXfzOEh0NSAWVO99IZXnhx9LD3nOldHIpGYzZBsrS9NV2vaRFvEdWe+UweXQ==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.2.tgz", + "integrity": "sha512-8aKUBSj3oGcnuiBmDLm3BIk09RYg01mz9HlQ2u4aS17oJ25DxjQrEUVGFSBVNOfM45pQW4OjcBPplq6r/exJdA==", "dev": true, "requires": { - "@types/node": "8.0.46" + "@types/node": "8.0.54" + } + }, + "JSONStream": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz", + "integrity": "sha1-cH92HgHa6eFvG8+TcDt4xwlmV5o=", + "dev": true, + "requires": { + "jsonparse": "1.3.1", + "through": "2.3.8" } }, "abbrev": { @@ -351,9 +362,9 @@ "dev": true }, "array-slice": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.0.0.tgz", - "integrity": "sha1-5zA08A3MH0CHYAj9IP6ud71LfC8=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", "dev": true }, "array-union": { @@ -384,9 +395,9 @@ "dev": true }, "asn1.js": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.1.tgz", - "integrity": "sha1-SLokC0WpKA6UdImQull9IWYX/UA=", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.2.tgz", + "integrity": "sha512-b/OsSjvWEo8Pi8H0zsDd2P6Uqo2TK2pH8gNLSJtNLM2Db0v2QaAZ0pBQJXVjAn4gBuugeVDr7s63ZogpUIwWDg==", "dev": true, "requires": { "bn.js": "4.11.8", @@ -498,9 +509,9 @@ "integrity": "sha1-+GzWzvT1MAyOY+B6TVEvZfv/RTE=", "dev": true, "requires": { + "JSONStream": "1.3.1", "combine-source-map": "0.7.2", "defined": "1.0.0", - "JSONStream": "1.3.1", "through2": "2.0.3", "umd": "3.0.1" } @@ -526,6 +537,7 @@ "integrity": "sha512-gKfOsNQv/toWz+60nSPfYzuwSEdzvV2WdxrVPUbPD/qui44rAkB3t3muNtmmGYHqrG56FGwX9SUEQmzNLAeS7g==", "dev": true, "requires": { + "JSONStream": "1.3.1", "assert": "1.4.1", "browser-pack": "6.0.2", "browser-resolve": "1.11.2", @@ -535,7 +547,7 @@ "concat-stream": "1.5.2", "console-browserify": "1.1.0", "constants-browserify": "1.0.0", - "crypto-browserify": "3.11.1", + "crypto-browserify": "3.12.0", "defined": "1.0.0", "deps-sort": "2.0.0", "domain-browser": "1.1.7", @@ -547,7 +559,6 @@ "https-browserify": "1.0.0", "inherits": "2.0.3", "insert-module-globals": "7.0.1", - "JSONStream": "1.3.1", "labeled-stream-splicer": "2.0.0", "module-deps": "4.1.1", "os-browserify": "0.3.0", @@ -573,35 +584,12 @@ "util": "0.10.3", "vm-browserify": "0.0.4", "xtend": "4.0.1" - }, - "dependencies": { - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "dev": true, - "requires": { - "pako": "1.0.6" - } - }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", - "dev": true - }, - "pako": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", - "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", - "dev": true - } } }, "browserify-aes": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.0.8.tgz", - "integrity": "sha512-WYCMOT/PtGTlpOKFht0YJFYcPy6pLCR98CtWfzK13zoynLlBMvAdEMSRGmgnJCw2M2j/5qxBkinZQFobieM8dQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.1.1.tgz", + "integrity": "sha512-UGnTYAnB2a3YuYKIRy1/4FB2HdM866E0qC46JXvVTYKlBlZlnvfpSfY6OKfXZAkv70eJ2a1SqzpAo5CRhZGDFg==", "dev": true, "requires": { "buffer-xor": "1.0.3", @@ -618,7 +606,7 @@ "integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=", "dev": true, "requires": { - "browserify-aes": "1.0.8", + "browserify-aes": "1.1.1", "browserify-des": "1.0.0", "evp_bytestokey": "1.0.3" } @@ -659,6 +647,15 @@ "parse-asn1": "5.1.0" } }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "1.0.6" + } + }, "buffer": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.0.8.tgz", @@ -737,7 +734,7 @@ "deep-eql": "3.0.1", "get-func-name": "2.0.0", "pathval": "1.1.0", - "type-detect": "4.0.3" + "type-detect": "4.0.5" } }, "chalk": { @@ -791,9 +788,9 @@ } }, "clone": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz", - "integrity": "sha1-Jgt6meux7f4kdTgXX3gyQ8sZ0Uk=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.3.tgz", + "integrity": "sha1-KY1+IjFmD0DAA8LtMUDezz9TCF8=", "dev": true }, "clone-buffer": { @@ -820,9 +817,9 @@ } }, "color-convert": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz", - "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", + "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", "dev": true, "requires": { "color-name": "1.1.3" @@ -930,9 +927,9 @@ "dev": true }, "convert-source-map": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz", - "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", + "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", "dev": true }, "core-util-is": { @@ -978,9 +975,9 @@ } }, "crypto-browserify": { - "version": "3.11.1", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.11.1.tgz", - "integrity": "sha512-Na7ZlwCOqoaW5RwUK1WpXws2kv8mNhWdTlzob0UXulk6G9BDbyiJaGTYBIX61Ozn9l1EPPJpICZb4DaOpT9NlQ==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "dev": true, "requires": { "browserify-cipher": "1.0.0", @@ -992,7 +989,8 @@ "inherits": "2.0.3", "pbkdf2": "3.0.14", "public-encrypt": "4.0.0", - "randombytes": "2.0.5" + "randombytes": "2.0.5", + "randomfill": "1.0.3" } }, "css": { @@ -1033,7 +1031,7 @@ "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "dev": true, "requires": { - "es5-ext": "0.10.31" + "es5-ext": "0.10.37" } }, "date-now": { @@ -1080,7 +1078,7 @@ "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", "dev": true, "requires": { - "type-detect": "4.0.3" + "type-detect": "4.0.5" } }, "deep-is": { @@ -1095,7 +1093,7 @@ "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", "dev": true, "requires": { - "clone": "1.0.2" + "clone": "1.0.3" } }, "defined": { @@ -1162,13 +1160,21 @@ "dev": true }, "detective": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/detective/-/detective-4.5.0.tgz", - "integrity": "sha1-blqMaybmx6JUsca210kNmOyR7dE=", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.0.tgz", + "integrity": "sha512-4mBqSEdMfBpRAo/DQZnTcAXenpiSIJmVKbCMSotS+SFWWcrP/CKM6iBRPdTiEO+wZhlfEsoZlGqpG6ycl5vTqw==", "dev": true, "requires": { - "acorn": "4.0.13", + "acorn": "5.2.1", "defined": "1.0.0" + }, + "dependencies": { + "acorn": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.2.1.tgz", + "integrity": "sha512-jG0u7c4Ly+3QkkW18V+NRDN+4bWHdln30NL1ZL2AvFZZmQe/BfopYCtghCKKVBUSetZ4QKcyA0pY6/4Gw8Pv8w==", + "dev": true + } } }, "diff": { @@ -1271,23 +1277,23 @@ } }, "es5-ext": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.31.tgz", - "integrity": "sha1-e7k4yVp/G59ygJLcCcQe3MOY7v4=", + "version": "0.10.37", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.37.tgz", + "integrity": "sha1-DudB0Ui4AGm6J9AgOTdWryV978M=", "dev": true, "requires": { - "es6-iterator": "2.0.1", + "es6-iterator": "2.0.3", "es6-symbol": "3.1.1" } }, "es6-iterator": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", - "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", "dev": true, "requires": { "d": "1.0.0", - "es5-ext": "0.10.31", + "es5-ext": "0.10.37", "es6-symbol": "3.1.1" } }, @@ -1304,7 +1310,7 @@ "dev": true, "requires": { "d": "1.0.0", - "es5-ext": "0.10.31" + "es5-ext": "0.10.37" } }, "es6-weak-map": { @@ -1314,8 +1320,8 @@ "dev": true, "requires": { "d": "1.0.0", - "es5-ext": "0.10.31", - "es6-iterator": "2.0.1", + "es5-ext": "0.10.37", + "es6-iterator": "2.0.3", "es6-symbol": "3.1.1" } }, @@ -1375,7 +1381,7 @@ "dev": true, "requires": { "d": "1.0.0", - "es5-ext": "0.10.31" + "es5-ext": "0.10.37" } }, "events": { @@ -1755,7 +1761,7 @@ "dev": true, "requires": { "homedir-polyfill": "1.0.1", - "ini": "1.3.4", + "ini": "1.3.5", "is-windows": "0.2.0", "which": "1.3.0" } @@ -1861,7 +1867,7 @@ "chalk": "1.1.3", "deprecated": "0.0.1", "gulp-util": "3.0.8", - "interpret": "1.0.4", + "interpret": "1.1.0", "liftoff": "2.3.0", "minimist": "1.2.0", "orchestrator": "0.3.8", @@ -2099,40 +2105,6 @@ "concat-with-sourcemaps": "1.0.4", "through2": "2.0.3", "vinyl": "2.1.0" - }, - "dependencies": { - "clone": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", - "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=", - "dev": true - }, - "clone-stats": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", - "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", - "dev": true - }, - "replace-ext": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", - "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", - "dev": true - }, - "vinyl": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.1.0.tgz", - "integrity": "sha1-Ah+cLPlR1rk5lDyJ617lrdT9kkw=", - "dev": true, - "requires": { - "clone": "2.1.1", - "clone-buffer": "1.0.0", - "clone-stats": "1.0.0", - "cloneable-readable": "1.0.0", - "remove-trailing-separator": "1.1.0", - "replace-ext": "1.0.0" - } - } } }, "gulp-help": { @@ -2209,7 +2181,7 @@ "@gulp-sourcemaps/identity-map": "1.0.1", "@gulp-sourcemaps/map-sources": "1.0.0", "acorn": "4.0.13", - "convert-source-map": "1.5.0", + "convert-source-map": "1.5.1", "css": "2.2.1", "debug-fabulous": "0.2.1", "detect-newline": "2.1.0", @@ -2232,7 +2204,7 @@ "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", "dev": true, "requires": { - "clone": "1.0.2", + "clone": "1.0.3", "clone-stats": "0.0.1", "replace-ext": "0.0.1" } @@ -2240,9 +2212,9 @@ } }, "gulp-typescript": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/gulp-typescript/-/gulp-typescript-3.2.2.tgz", - "integrity": "sha1-t+Xh08s193LlPmBAJmAYJuK+d/w=", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/gulp-typescript/-/gulp-typescript-3.2.3.tgz", + "integrity": "sha512-Np2sJXgtDUwIAoMtlJ9uXsVmpu1FWXlKZw164hLuo56uJa7qo5W2KZ0yAYiYH/HUsaz5L0O2toMOcLIokpFCPg==", "dev": true, "requires": { "gulp-util": "3.0.8", @@ -2326,7 +2298,7 @@ "integrity": "sha1-uG/zSdgBzrVuHZ59x7vLS33uYAw=", "dev": true, "requires": { - "convert-source-map": "1.5.0", + "convert-source-map": "1.5.1", "graceful-fs": "4.1.11", "strip-bom": "2.0.0", "through2": "2.0.3", @@ -2404,7 +2376,7 @@ "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", "dev": true, "requires": { - "clone": "1.0.2", + "clone": "1.0.3", "clone-stats": "0.0.1", "replace-ext": "0.0.1" } @@ -2467,6 +2439,17 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", "dev": true + }, + "vinyl": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", + "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", + "dev": true, + "requires": { + "clone": "1.0.3", + "clone-stats": "0.0.1", + "replace-ext": "0.0.1" + } } } }, @@ -2480,9 +2463,9 @@ } }, "handlebars": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.10.tgz", - "integrity": "sha1-PTDHGLCaPZbyPqTMH0A8TTup/08=", + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", + "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", "dev": true, "requires": { "async": "1.5.2", @@ -2642,9 +2625,9 @@ "dev": true }, "ini": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", - "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=", + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true }, "inline-source-map": { @@ -2662,10 +2645,10 @@ "integrity": "sha1-wDv04BywhtW15azorQr+eInWOMM=", "dev": true, "requires": { + "JSONStream": "1.3.1", "combine-source-map": "0.7.2", "concat-stream": "1.5.2", - "is-buffer": "1.1.5", - "JSONStream": "1.3.1", + "is-buffer": "1.1.6", "lexical-scope": "1.2.0", "process": "0.11.10", "through2": "2.0.3", @@ -2673,9 +2656,9 @@ } }, "interpret": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.4.tgz", - "integrity": "sha1-ggzdWIuGj/sZGoCVBtbJyPISsbA=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", "dev": true }, "is-absolute": { @@ -2695,9 +2678,9 @@ "dev": true }, "is-buffer": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", - "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, "is-builtin-module": { @@ -2775,13 +2758,13 @@ "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", "dev": true, "requires": { - "is-path-inside": "1.0.0" + "is-path-inside": "1.0.1" } }, "is-path-inside": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", - "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "dev": true, "requires": { "path-is-inside": "1.0.2" @@ -2896,7 +2879,7 @@ "escodegen": "1.8.1", "esprima": "2.7.3", "glob": "5.0.15", - "handlebars": "4.0.10", + "handlebars": "4.0.11", "js-yaml": "3.10.0", "mkdirp": "0.5.1", "nopt": "3.0.6", @@ -3020,16 +3003,6 @@ "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", "dev": true }, - "JSONStream": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz", - "integrity": "sha1-cH92HgHa6eFvG8+TcDt4xwlmV5o=", - "dev": true, - "requires": { - "jsonparse": "1.3.1", - "through": "2.3.8" - } - }, "kew": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", @@ -3042,7 +3015,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.5" + "is-buffer": "1.1.6" } }, "labeled-stream-splicer": { @@ -3454,7 +3427,7 @@ "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", "dev": true, "requires": { - "es5-ext": "0.10.31" + "es5-ext": "0.10.37" } }, "make-error": { @@ -3504,7 +3477,7 @@ "dev": true, "requires": { "d": "1.0.0", - "es5-ext": "0.10.31", + "es5-ext": "0.10.37", "es6-weak-map": "2.0.2", "event-emitter": "0.3.5", "is-promise": "2.1.0", @@ -3668,14 +3641,14 @@ "integrity": "sha1-IyFYM/HaE/1gbMuAh7RIUty4If0=", "dev": true, "requires": { + "JSONStream": "1.3.1", "browser-resolve": "1.11.2", "cached-path-relative": "1.0.1", "concat-stream": "1.5.2", "defined": "1.0.0", - "detective": "4.5.0", + "detective": "4.7.0", "duplexer2": "0.1.4", "inherits": "2.0.3", - "JSONStream": "1.3.1", "parents": "1.0.1", "readable-stream": "2.3.3", "resolve": "1.1.7", @@ -3802,7 +3775,7 @@ "dev": true, "requires": { "array-each": "1.0.1", - "array-slice": "1.0.0", + "array-slice": "1.1.0", "for-own": "1.0.0", "isobject": "3.0.1" }, @@ -3915,6 +3888,12 @@ "integrity": "sha1-/VZamvjrRHO6abbtijQ1LLVS8SY=", "dev": true }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", @@ -3927,6 +3906,12 @@ "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", "dev": true }, + "pako": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", + "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", + "dev": true + }, "parents": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", @@ -3942,8 +3927,8 @@ "integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=", "dev": true, "requires": { - "asn1.js": "4.9.1", - "browserify-aes": "1.0.8", + "asn1.js": "4.9.2", + "browserify-aes": "1.1.1", "create-hash": "1.1.3", "evp_bytestokey": "1.0.3", "pbkdf2": "3.0.14" @@ -4204,7 +4189,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.5" + "is-buffer": "1.1.6" } } } @@ -4215,7 +4200,7 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "1.1.5" + "is-buffer": "1.1.6" } } } @@ -4229,6 +4214,16 @@ "safe-buffer": "5.1.1" } }, + "randomfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.3.tgz", + "integrity": "sha512-YL6GrhrWoic0Eq8rXVbMptH7dAxCs0J+mh5Y0euNekPPYaxEmdVGim6GdoxoRzKW2yJoU8tueifS7mYxvcFDEQ==", + "dev": true, + "requires": { + "randombytes": "2.0.5", + "safe-buffer": "5.1.1" + } + }, "read-only-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", @@ -4515,12 +4510,20 @@ } }, "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.0.tgz", + "integrity": "sha512-vUoN3I7fHQe0R/SJLKRdKYuEdRGogsviXFkHHo17AWaTGv17VLnxw+CFXvqy+y4ORZ3doWLQcxRYfwKrsd/H7Q==", "dev": true, "requires": { - "source-map": "0.5.7" + "source-map": "0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } } }, "source-map-url": { @@ -4811,7 +4814,7 @@ "integrity": "sha1-YcxHp2wavTGV8UUn+XjViulMUgQ=", "dev": true, "requires": { - "es5-ext": "0.10.31", + "es5-ext": "0.10.37", "next-tick": "1.0.0" } }, @@ -4849,7 +4852,7 @@ "dev": true, "requires": { "arrify": "1.0.1", - "chalk": "2.2.0", + "chalk": "2.3.0", "diff": "3.3.1", "make-error": "1.3.0", "minimist": "1.2.0", @@ -4866,13 +4869,13 @@ "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", "dev": true, "requires": { - "color-convert": "1.9.0" + "color-convert": "1.9.1" } }, "chalk": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.2.0.tgz", - "integrity": "sha512-0BMM/2hG3ZaoPfR6F+h/oWpZtsh3b/s62TjSM6MGCJWEbJDN1acqCXvyhhZsDSVFklpebUoQ5O1kKC7lOzrn9g==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", "dev": true, "requires": { "ansi-styles": "3.2.0", @@ -4886,6 +4889,15 @@ "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", "dev": true }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "0.5.7" + } + }, "supports-color": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", @@ -4938,15 +4950,15 @@ "requires": { "babel-code-frame": "6.26.0", "builtin-modules": "1.1.1", - "chalk": "2.2.0", + "chalk": "2.3.0", "commander": "2.11.0", "diff": "3.3.1", "glob": "7.1.2", "minimatch": "3.0.4", - "resolve": "1.4.0", + "resolve": "1.5.0", "semver": "5.4.1", "tslib": "1.8.0", - "tsutils": "2.12.1" + "tsutils": "2.13.0" }, "dependencies": { "ansi-styles": { @@ -4955,13 +4967,13 @@ "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", "dev": true, "requires": { - "color-convert": "1.9.0" + "color-convert": "1.9.1" } }, "chalk": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.2.0.tgz", - "integrity": "sha512-0BMM/2hG3ZaoPfR6F+h/oWpZtsh3b/s62TjSM6MGCJWEbJDN1acqCXvyhhZsDSVFklpebUoQ5O1kKC7lOzrn9g==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", "dev": true, "requires": { "ansi-styles": "3.2.0", @@ -4976,9 +4988,9 @@ "dev": true }, "resolve": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz", - "integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", + "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", "dev": true, "requires": { "path-parse": "1.0.5" @@ -5002,9 +5014,9 @@ } }, "tsutils": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.12.1.tgz", - "integrity": "sha1-9Nlc4zkciXHkblTEzw7bCiHdWyQ=", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.13.0.tgz", + "integrity": "sha512-FuWzNJbMsp3gcZMbI3b5DomhW4Ia41vMxjN63nKWI0t7f+I3UmHfRl0TrXJTwI2LUduDG+eR1Mksp3pvtlyCFQ==", "dev": true, "requires": { "tslib": "1.8.0" @@ -5026,9 +5038,9 @@ } }, "type-detect": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.3.tgz", - "integrity": "sha1-Dj8mcLRAmbC0bChNE2p+9Jx0wuo=", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.5.tgz", + "integrity": "sha512-N9IvkQslUGYGC24RkJk1ba99foK6TkwC2FHAEBlQFBP0RxQZS8ZpJuAZcwiY/w9ZJHFQb1aOXBI60OdxhTrwEQ==", "dev": true }, "typedarray": { @@ -5038,9 +5050,9 @@ "dev": true }, "typescript": { - "version": "2.7.0-dev.20171020", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.7.0-dev.20171020.tgz", - "integrity": "sha512-Sy1F2YVw7nj2pcMP2bE6YK5dviaY2WRJb12t27EUiW4wkD8GiaZ0sgNBdTKRcvTNFJ8KXjwnl+Ysi5+J5BlcHw==", + "version": "2.7.0-dev.20171203", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.7.0-dev.20171203.tgz", + "integrity": "sha512-FyhV7OvieIXzjktOb9YmixEIR8olL8IrnonCmJQWGnj8Wt6eoQQKQlkXWPy8mpwEaSIXw/nQO0NpGQ+nWokhRw==", "dev": true }, "uglify-js": { @@ -5165,14 +5177,37 @@ } }, "vinyl": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", - "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.1.0.tgz", + "integrity": "sha1-Ah+cLPlR1rk5lDyJ617lrdT9kkw=", "dev": true, "requires": { - "clone": "1.0.2", - "clone-stats": "0.0.1", - "replace-ext": "0.0.1" + "clone": "2.1.1", + "clone-buffer": "1.0.0", + "clone-stats": "1.0.0", + "cloneable-readable": "1.0.0", + "remove-trailing-separator": "1.1.0", + "replace-ext": "1.0.0" + }, + "dependencies": { + "clone": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", + "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=", + "dev": true + }, + "clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", + "dev": true + }, + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true + } } }, "vinyl-fs": { diff --git a/package.json b/package.json index e329db05d8..b3c76e6d51 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ }, "devDependencies": { "@types/browserify": "latest", - "@types/chai": "latest", "@types/colors": "latest", "@types/convert-source-map": "latest", "@types/del": "latest", @@ -53,7 +52,6 @@ "xml2js": "^0.4.19", "browser-resolve": "^1.11.2", "browserify": "latest", - "chai": "latest", "convert-source-map": "latest", "del": "latest", "gulp": "3.X", diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 71b5e1afbf..4eab97f28b 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -749,6 +749,10 @@ namespace ts { return expr1.kind === SyntaxKind.TypeOfExpression && isNarrowableOperand((expr1).expression) && expr2.kind === SyntaxKind.StringLiteral; } + function isNarrowableInOperands(left: Expression, right: Expression) { + return left.kind === SyntaxKind.StringLiteral && isNarrowingExpression(right); + } + function isNarrowingBinaryExpression(expr: BinaryExpression) { switch (expr.operatorToken.kind) { case SyntaxKind.EqualsToken: @@ -761,6 +765,8 @@ namespace ts { isNarrowingTypeofOperands(expr.right, expr.left) || isNarrowingTypeofOperands(expr.left, expr.right); case SyntaxKind.InstanceOfKeyword: return isNarrowableOperand(expr.left); + case SyntaxKind.InKeyword: + return isNarrowableInOperands(expr.left, expr.right); case SyntaxKind.CommaToken: return isNarrowingExpression(expr.right); } diff --git a/src/compiler/builder.ts b/src/compiler/builder.ts index 34ca1bdf0e..7e44a9608f 100644 --- a/src/compiler/builder.ts +++ b/src/compiler/builder.ts @@ -468,9 +468,9 @@ namespace ts { } function getReferencedByPaths(referencedFilePath: Path) { - return mapDefinedIter(references.entries(), ([filePath, referencesInFile]) => + return arrayFrom(mapDefinedIterator(references.entries(), ([filePath, referencesInFile]) => referencesInFile.has(referencedFilePath) ? filePath as Path : undefined - ); + )); } function getFilesAffectedByUpdatedShape(program: Program, sourceFile: SourceFile): ReadonlyArray { @@ -504,7 +504,7 @@ namespace ts { } // Return array of values that needs emit - return flatMapIter(seenFileNamesMap.values(), value => value); + return arrayFrom(mapDefinedIterator(seenFileNamesMap.values(), value => value)); } } } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2ab67120e4..269c55145e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -210,7 +210,18 @@ namespace ts { getEmitResolver, getExportsOfModule: getExportsOfModuleAsArray, getExportsAndPropertiesOfModule, - getSymbolWalker: createGetSymbolWalker(getRestTypeOfSignature, getReturnTypeOfSignature, getBaseTypes, resolveStructuredTypeMembers, getTypeOfSymbol, getResolvedSymbol, getIndexTypeOfStructuredType, getConstraintFromTypeParameter, getFirstIdentifier), + getSymbolWalker: createGetSymbolWalker( + getRestTypeOfSignature, + getTypePredicateOfSignature, + getReturnTypeOfSignature, + getBaseTypes, + resolveStructuredTypeMembers, + getTypeOfSymbol, + getResolvedSymbol, + getIndexTypeOfStructuredType, + getConstraintFromTypeParameter, + getFirstIdentifier, + ), getAmbientModules, getAllAttributesTypeFromJsxOpeningLikeElement: node => { node = getParseTreeNode(node, isJsxOpeningLikeElement); @@ -312,10 +323,12 @@ namespace ts { markerSubType.constraint = markerSuperType; const markerOtherType = createType(TypeFlags.TypeParameter); - const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); - const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, unknownType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); - const resolvingSignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); - const silentNeverSignature = createSignature(undefined, undefined, undefined, emptyArray, silentNeverType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); + const noTypePredicate = createIdentifierTypePredicate("<>", 0, anyType); + + const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); + const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, unknownType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); + const resolvingSignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); + const silentNeverSignature = createSignature(undefined, undefined, undefined, emptyArray, silentNeverType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); const enumNumberIndexInfo = createIndexInfo(stringType, /*isReadonly*/ true); const jsObjectLiteralIndexInfo = createIndexInfo(anyType, /*isReadonly*/ false); @@ -1007,7 +1020,7 @@ namespace ts { // It's an external module. First see if the module has an export default and if the local // name of that export default matches. - if (result = moduleExports.get("default" as __String)) { + if (result = moduleExports.get(InternalSymbolName.Default)) { const localSymbol = getLocalSymbolForExportDefault(result); if (localSymbol && (result.flags & meaning) && localSymbol.escapedName === name) { break loop; @@ -1461,8 +1474,8 @@ namespace ts { else { const exportValue = moduleSymbol.exports.get("export=" as __String); exportDefaultSymbol = exportValue - ? getPropertyOfType(getTypeOfSymbol(exportValue), "default" as __String) - : resolveSymbol(moduleSymbol.exports.get("default" as __String), dontResolveAlias); + ? getPropertyOfType(getTypeOfSymbol(exportValue), InternalSymbolName.Default) + : resolveSymbol(moduleSymbol.exports.get(InternalSymbolName.Default), dontResolveAlias); } if (!exportDefaultSymbol && !allowSyntheticDefaultImports) { @@ -1551,7 +1564,7 @@ namespace ts { symbolFromVariable = resolveSymbol(symbolFromVariable, dontResolveAlias); let symbolFromModule = getExportOfModule(targetSymbol, name.escapedText, dontResolveAlias); // If the export member we're looking for is default, and there is no real default but allowSyntheticDefaultImports is on, return the entire module as the default - if (!symbolFromModule && allowSyntheticDefaultImports && name.escapedText === "default") { + if (!symbolFromModule && allowSyntheticDefaultImports && name.escapedText === InternalSymbolName.Default) { symbolFromModule = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || resolveSymbol(moduleSymbol, dontResolveAlias); } const symbol = symbolFromModule && symbolFromVariable ? @@ -1938,7 +1951,7 @@ namespace ts { function extendExportSymbols(target: SymbolTable, source: SymbolTable | undefined, lookupTable?: ExportCollisionTrackerTable, exportNode?: ExportDeclaration) { if (!source) return; source.forEach((sourceSymbol, id) => { - if (id === "default") return; + if (id === InternalSymbolName.Default) return; const targetSymbol = target.get(id); if (!targetSymbol) { @@ -2926,8 +2939,8 @@ namespace ts { parameters.unshift(thisParameter); } let returnTypeNode: TypeNode; - if (signature.typePredicate) { - const typePredicate = signature.typePredicate; + const typePredicate = getTypePredicateOfSignature(signature); + if (typePredicate) { const parameterName = typePredicate.kind === TypePredicateKind.Identifier ? setEmitFlags(createIdentifier((typePredicate).parameterName), EmitFlags.NoAsciiEscaping) : createThisTypeNode(); @@ -3208,7 +3221,7 @@ namespace ts { * ensuring that any names written with literals use element accesses. */ function appendPropertyOrElementAccessForSymbol(symbol: Symbol, writer: SymbolWriter): void { - const symbolName = symbol.escapedName === "default" ? "default" : getNameOfSymbolAsWritten(symbol); + const symbolName = symbol.escapedName === InternalSymbolName.Default ? InternalSymbolName.Default : getNameOfSymbolAsWritten(symbol); const firstChar = symbolName.charCodeAt(0); const needsElementAccess = !isIdentifierStart(firstChar, languageVersion); @@ -3887,8 +3900,9 @@ namespace ts { } writeSpace(writer); - if (signature.typePredicate) { - buildTypePredicateDisplay(signature.typePredicate, writer, enclosingDeclaration, flags, symbolStack); + const typePredicate = getTypePredicateOfSignature(signature); + if (typePredicate) { + buildTypePredicateDisplay(typePredicate, writer, enclosingDeclaration, flags, symbolStack); } else { buildTypeDisplay(returnType, writer, enclosingDeclaration, flags, symbolStack); @@ -5783,15 +5797,24 @@ namespace ts { resolveObjectTypeMembers(type, source, typeParameters, typeArguments); } - function createSignature(declaration: SignatureDeclaration, typeParameters: TypeParameter[], thisParameter: Symbol | undefined, parameters: Symbol[], - resolvedReturnType: Type, typePredicate: TypePredicate, minArgumentCount: number, hasRestParameter: boolean, hasLiteralTypes: boolean): Signature { + function createSignature( + declaration: SignatureDeclaration, + typeParameters: TypeParameter[], + thisParameter: Symbol | undefined, + parameters: Symbol[], + resolvedReturnType: Type | undefined, + resolvedTypePredicate: TypePredicate | undefined, + minArgumentCount: number, + hasRestParameter: boolean, + hasLiteralTypes: boolean, + ): Signature { const sig = new Signature(checker); sig.declaration = declaration; sig.typeParameters = typeParameters; sig.parameters = parameters; sig.thisParameter = thisParameter; sig.resolvedReturnType = resolvedReturnType; - sig.typePredicate = typePredicate; + sig.resolvedTypePredicate = resolvedTypePredicate; sig.minArgumentCount = minArgumentCount; sig.hasRestParameter = hasRestParameter; sig.hasLiteralTypes = hasLiteralTypes; @@ -5799,15 +5822,15 @@ namespace ts { } function cloneSignature(sig: Signature): Signature { - return createSignature(sig.declaration, sig.typeParameters, sig.thisParameter, sig.parameters, sig.resolvedReturnType, - sig.typePredicate, sig.minArgumentCount, sig.hasRestParameter, sig.hasLiteralTypes); + return createSignature(sig.declaration, sig.typeParameters, sig.thisParameter, sig.parameters, /*resolvedReturnType*/ undefined, + /*resolvedTypePredicate*/ undefined, sig.minArgumentCount, sig.hasRestParameter, sig.hasLiteralTypes); } function getDefaultConstructSignatures(classType: InterfaceType): Signature[] { const baseConstructorType = getBaseConstructorTypeOfClass(classType); const baseSignatures = getSignaturesOfType(baseConstructorType, SignatureKind.Construct); if (baseSignatures.length === 0) { - return [createSignature(undefined, classType.localTypeParameters, undefined, emptyArray, classType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false)]; + return [createSignature(undefined, classType.localTypeParameters, undefined, emptyArray, classType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false)]; } const baseTypeNode = getBaseTypeNodeOfClass(classType); const isJavaScript = isInJavaScriptFile(baseTypeNode); @@ -5817,7 +5840,7 @@ namespace ts { for (const baseSig of baseSignatures) { const minTypeArgumentCount = getMinTypeArgumentCount(baseSig.typeParameters); const typeParamCount = length(baseSig.typeParameters); - if (isJavaScript || (typeArgCount >= minTypeArgumentCount && typeArgCount <= typeParamCount)) { + if (isJavaScript || typeArgCount >= minTypeArgumentCount && typeArgCount <= typeParamCount) { const sig = typeParamCount ? createSignatureInstantiation(baseSig, fillMissingTypeArguments(typeArguments, baseSig.typeParameters, minTypeArgumentCount, isJavaScript)) : cloneSignature(baseSig); sig.typeParameters = classType.localTypeParameters; sig.resolvedReturnType = classType; @@ -5877,13 +5900,13 @@ namespace ts { let s = signature; // Union the result types when more than one signature matches if (unionSignatures.length > 1) { - s = cloneSignature(signature); + let thisParameter = signature.thisParameter; if (forEach(unionSignatures, sig => sig.thisParameter)) { const thisType = getUnionType(map(unionSignatures, sig => getTypeOfSymbol(sig.thisParameter) || anyType), /*subtypeReduction*/ true); - s.thisParameter = createSymbolWithType(signature.thisParameter, thisType); + thisParameter = createSymbolWithType(signature.thisParameter, thisType); } - // Clear resolved return type we possibly got from cloneSignature - s.resolvedReturnType = undefined; + s = cloneSignature(signature); + s.thisParameter = thisParameter; s.unionSignatures = unionSignatures; } (result || (result = [])).push(s); @@ -6434,14 +6457,13 @@ namespace ts { function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: __String): Symbol { let props: Symbol[]; - const types = containingType.types; const isUnion = containingType.flags & TypeFlags.Union; const excludeModifiers = isUnion ? ModifierFlags.NonPublicAccessibilityModifier : 0; // Flags we want to propagate to the result if they exist in all source symbols let commonFlags = isUnion ? SymbolFlags.None : SymbolFlags.Optional; let syntheticFlag = CheckFlags.SyntheticMethod; let checkFlags = 0; - for (const current of types) { + for (const current of containingType.types) { const type = getApparentType(current); if (type !== unknownType) { const prop = getPropertyOfType(type, name); @@ -6674,22 +6696,26 @@ namespace ts { function createTypePredicateFromTypePredicateNode(node: TypePredicateNode): IdentifierTypePredicate | ThisTypePredicate { const { parameterName } = node; + const type = getTypeFromTypeNode(node.type); if (parameterName.kind === SyntaxKind.Identifier) { - return { - kind: TypePredicateKind.Identifier, - parameterName: parameterName ? parameterName.escapedText : undefined, - parameterIndex: parameterName ? getTypePredicateParameterIndex((node.parent as SignatureDeclaration).parameters, parameterName) : undefined, - type: getTypeFromTypeNode(node.type) - } as IdentifierTypePredicate; + return createIdentifierTypePredicate( + parameterName && parameterName.escapedText as string, // TODO: GH#18217 + parameterName && getTypePredicateParameterIndex((node.parent as SignatureDeclaration).parameters, parameterName), + type); } else { - return { - kind: TypePredicateKind.This, - type: getTypeFromTypeNode(node.type) - }; + return createThisTypePredicate(type); } } + function createIdentifierTypePredicate(parameterName: string | undefined, parameterIndex: number | undefined, type: Type): IdentifierTypePredicate { + return { kind: TypePredicateKind.Identifier, parameterName, parameterIndex, type }; + } + + function createThisTypePredicate(type: Type): ThisTypePredicate { + return { kind: TypePredicateKind.This, type }; + } + /** * Gets the minimum number of type arguments needed to satisfy all non-optional type * parameters. @@ -6805,11 +6831,8 @@ namespace ts { : undefined; const typeParameters = classType ? classType.localTypeParameters : getTypeParametersFromDeclaration(declaration); const returnType = getSignatureReturnTypeFromDeclaration(declaration, isJSConstructSignature, classType); - const typePredicate = declaration.type && declaration.type.kind === SyntaxKind.TypePredicate ? - createTypePredicateFromTypePredicateNode(declaration.type as TypePredicateNode) : - undefined; const hasRestLikeParameter = hasRestParameter(declaration) || isInJavaScriptFile(declaration) && maybeAddJsSyntheticRestParameter(declaration, parameters); - links.resolvedSignature = createSignature(declaration, typeParameters, thisParameter, parameters, returnType, typePredicate, minArgumentCount, hasRestLikeParameter, hasLiteralTypes); + links.resolvedSignature = createSignature(declaration, typeParameters, thisParameter, parameters, returnType, /*resolvedTypePredicate*/ undefined, minArgumentCount, hasRestLikeParameter, hasLiteralTypes); } return links.resolvedSignature; } @@ -6946,6 +6969,30 @@ namespace ts { } } + function signatureHasTypePredicate(signature: Signature): boolean { + return getTypePredicateOfSignature(signature) !== undefined; + } + + function getTypePredicateOfSignature(signature: Signature): TypePredicate | undefined { + if (!signature.resolvedTypePredicate) { + if (signature.target) { + const targetTypePredicate = getTypePredicateOfSignature(signature.target); + signature.resolvedTypePredicate = targetTypePredicate ? instantiateTypePredicate(targetTypePredicate, signature.mapper) : noTypePredicate; + } + else if (signature.unionSignatures) { + signature.resolvedTypePredicate = getUnionTypePredicate(signature.unionSignatures) || noTypePredicate; + } + else { + const declaration = signature.declaration; + signature.resolvedTypePredicate = declaration && declaration.type && declaration.type.kind === SyntaxKind.TypePredicate ? + createTypePredicateFromTypePredicateNode(declaration.type as TypePredicateNode) : + noTypePredicate; + } + Debug.assert(!!signature.resolvedTypePredicate); + } + return signature.resolvedTypePredicate === noTypePredicate ? undefined : signature.resolvedTypePredicate; + } + function getReturnTypeOfSignature(signature: Signature): Type { if (!signature.resolvedReturnType) { if (!pushTypeResolution(signature, TypeSystemPropertyName.ResolvedReturnType)) { @@ -7824,6 +7871,42 @@ namespace ts { return getUnionTypeFromSortedList(typeSet, aliasSymbol, aliasTypeArguments); } + function getUnionTypePredicate(signatures: ReadonlyArray): TypePredicate { + let first: TypePredicate | undefined; + const types: Type[] = []; + for (const sig of signatures) { + const pred = getTypePredicateOfSignature(sig); + if (!pred) { + continue; + } + + if (first) { + if (!typePredicateKindsMatch(first, pred)) { + // No common type predicate. + return undefined; + } + } + else { + first = pred; + } + types.push(pred.type); + } + if (!first) { + // No union signatures had a type predicate. + return undefined; + } + const unionType = getUnionType(types); + return isIdentifierTypePredicate(first) + ? createIdentifierTypePredicate(first.parameterName, first.parameterIndex, unionType) + : createThisTypePredicate(unionType); + } + + function typePredicateKindsMatch(a: TypePredicate, b: TypePredicate): boolean { + return isIdentifierTypePredicate(a) + ? isIdentifierTypePredicate(b) && a.parameterIndex === b.parameterIndex + : !isIdentifierTypePredicate(b); + } + // This function assumes the constituent type list is sorted and deduplicated. function getUnionTypeFromSortedList(types: Type[], aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { if (types.length === 0) { @@ -8574,7 +8657,7 @@ namespace ts { return result; } - function cloneTypePredicate(predicate: TypePredicate, mapper: TypeMapper): ThisTypePredicate | IdentifierTypePredicate { + function instantiateTypePredicate(predicate: TypePredicate, mapper: TypeMapper): ThisTypePredicate | IdentifierTypePredicate { if (isIdentifierTypePredicate(predicate)) { return { kind: TypePredicateKind.Identifier, @@ -8593,7 +8676,6 @@ namespace ts { function instantiateSignature(signature: Signature, mapper: TypeMapper, eraseTypeParameters?: boolean): Signature { let freshTypeParameters: TypeParameter[]; - let freshTypePredicate: TypePredicate; if (signature.typeParameters && !eraseTypeParameters) { // First create a fresh set of type parameters, then include a mapping from the old to the // new type parameters in the mapper function. Finally store this mapper in the new type @@ -8604,15 +8686,17 @@ namespace ts { tp.mapper = mapper; } } - if (signature.typePredicate) { - freshTypePredicate = cloneTypePredicate(signature.typePredicate, mapper); - } + // Don't compute resolvedReturnType and resolvedTypePredicate now, + // because using `mapper` now could trigger inferences to become fixed. (See `createInferenceContext`.) + // See GH#17600. const result = createSignature(signature.declaration, freshTypeParameters, signature.thisParameter && instantiateSymbol(signature.thisParameter, mapper), instantiateList(signature.parameters, mapper, instantiateSymbol), /*resolvedReturnType*/ undefined, - freshTypePredicate, - signature.minArgumentCount, signature.hasRestParameter, signature.hasLiteralTypes); + /*resolvedTypePredicate*/ undefined, + signature.minArgumentCount, + signature.hasRestParameter, + signature.hasLiteralTypes); result.target = signature; result.mapper = mapper; return result; @@ -9006,7 +9090,7 @@ namespace ts { // with respect to T. const sourceSig = callbackCheck ? undefined : getSingleCallSignature(getNonNullableType(sourceType)); const targetSig = callbackCheck ? undefined : getSingleCallSignature(getNonNullableType(targetType)); - const callbacks = sourceSig && targetSig && !sourceSig.typePredicate && !targetSig.typePredicate && + const callbacks = sourceSig && targetSig && !signatureHasTypePredicate(sourceSig) && !signatureHasTypePredicate(targetSig) && (getFalsyFlags(sourceType) & TypeFlags.Nullable) === (getFalsyFlags(targetType) & TypeFlags.Nullable); const related = callbacks ? compareSignaturesRelated(targetSig, sourceSig, strictVariance ? CallbackCheck.Strict : CallbackCheck.Bivariant, /*ignoreReturnTypes*/ false, reportErrors, errorReporter, compareTypes) : @@ -9030,11 +9114,13 @@ namespace ts { const sourceReturnType = getReturnTypeOfSignature(source); // The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions - if (target.typePredicate) { - if (source.typePredicate) { - result &= compareTypePredicateRelatedTo(source.typePredicate, target.typePredicate, source.declaration, target.declaration, reportErrors, errorReporter, compareTypes); + const targetTypePredicate = getTypePredicateOfSignature(target); + if (targetTypePredicate) { + const sourceTypePredicate = getTypePredicateOfSignature(source); + if (sourceTypePredicate) { + result &= compareTypePredicateRelatedTo(sourceTypePredicate, targetTypePredicate, source.declaration, target.declaration, reportErrors, errorReporter, compareTypes); } - else if (isIdentifierTypePredicate(target.typePredicate)) { + else if (isIdentifierTypePredicate(targetTypePredicate)) { if (reportErrors) { errorReporter(Diagnostics.Signature_0_must_be_a_type_predicate, signatureToString(source)); } @@ -10579,11 +10665,20 @@ namespace ts { result &= related; } if (!ignoreReturnTypes) { - result &= compareTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); + const sourceTypePredicate = getTypePredicateOfSignature(source); + const targetTypePredicate = getTypePredicateOfSignature(target); + result &= sourceTypePredicate !== undefined || targetTypePredicate !== undefined + ? compareTypePredicatesIdentical(sourceTypePredicate, targetTypePredicate, compareTypes) + // If they're both type predicates their return types will both be `boolean`, so no need to compare those. + : compareTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); } return result; } + function compareTypePredicatesIdentical(source: TypePredicate | undefined, target: TypePredicate | undefined, compareTypes: (s: Type, t: Type) => Ternary): Ternary { + return source === undefined || target === undefined || !typePredicateKindsMatch(source, target) ? Ternary.False : compareTypes(source.type, target.type); + } + function isRestParameterIndex(signature: Signature, parameterIndex: number) { return signature.hasRestParameter && parameterIndex >= signature.parameters.length - 1; } @@ -11448,8 +11543,10 @@ namespace ts { function inferFromSignature(source: Signature, target: Signature) { forEachMatchingParameterType(source, target, inferFromContravariantTypes); - if (source.typePredicate && target.typePredicate && source.typePredicate.kind === target.typePredicate.kind) { - inferFromTypes(source.typePredicate.type, target.typePredicate.type); + const sourceTypePredicate = getTypePredicateOfSignature(source); + const targetTypePredicate = getTypePredicateOfSignature(target); + if (sourceTypePredicate && targetTypePredicate && sourceTypePredicate.kind === targetTypePredicate.kind) { + inferFromTypes(sourceTypePredicate.type, targetTypePredicate.type); } else { inferFromTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); @@ -12264,10 +12361,7 @@ namespace ts { const funcType = checkNonNullExpression(node.expression); if (funcType !== silentNeverType) { const apparentType = getApparentType(funcType); - if (apparentType !== unknownType) { - const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call); - return !!forEach(callSignatures, sig => sig.typePredicate); - } + return apparentType !== unknownType && some(getSignaturesOfType(apparentType, SignatureKind.Call), signatureHasTypePredicate); } } return false; @@ -12628,6 +12722,22 @@ namespace ts { return type; } + function isTypePresencePossible(type: Type, propName: __String, assumeTrue: boolean) { + const prop = getPropertyOfType(type, propName); + if (prop) { + return (prop.flags & SymbolFlags.Optional) ? true : assumeTrue; + } + return !assumeTrue; + } + + function narrowByInKeyword(type: Type, literal: LiteralExpression, assumeTrue: boolean) { + if ((type.flags & (TypeFlags.Union | TypeFlags.Object)) || (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType)) { + const propName = escapeLeadingUnderscores(literal.text); + return filterType(type, t => isTypePresencePossible(t, propName, /* assumeTrue */ assumeTrue)); + } + return type; + } + function narrowTypeByBinaryExpression(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { switch (expr.operatorToken.kind) { case SyntaxKind.EqualsToken: @@ -12663,6 +12773,12 @@ namespace ts { break; case SyntaxKind.InstanceOfKeyword: return narrowTypeByInstanceof(type, expr, assumeTrue); + case SyntaxKind.InKeyword: + const target = getReferenceCandidate(expr.right); + if (expr.left.kind === SyntaxKind.StringLiteral && isMatchingReference(reference, target)) { + return narrowByInKeyword(type, expr.left, assumeTrue); + } + break; case SyntaxKind.CommaToken: return narrowType(type, expr.right, assumeTrue); } @@ -12840,7 +12956,7 @@ namespace ts { return type; } const signature = getResolvedSignature(callExpression); - const predicate = signature.typePredicate; + const predicate = getTypePredicateOfSignature(signature); if (!predicate) { return type; } @@ -14251,8 +14367,6 @@ namespace ts { let result: Signature; if (signatureList) { result = cloneSignature(signatureList[0]); - // Clear resolved return type we possibly got from cloneSignature - result.resolvedReturnType = undefined; result.unionSignatures = signatureList; } return result; @@ -19305,7 +19419,7 @@ namespace ts { return; } - const typePredicate = getSignatureFromDeclaration(parent).typePredicate; + const typePredicate = getTypePredicateOfSignature(getSignatureFromDeclaration(parent)); if (!typePredicate) { return; } @@ -22915,6 +23029,7 @@ namespace ts { case SyntaxKind.PlusToken: return left + right; case SyntaxKind.MinusToken: return left - right; case SyntaxKind.PercentToken: return left % right; + case SyntaxKind.AsteriskAsteriskToken: return left ** right; } } break; diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 48c1b84dba..ec2eff50c3 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -191,6 +191,19 @@ namespace ts { return undefined; } + export function firstDefinedIterator(iter: Iterator, callback: (element: T) => U | undefined): U | undefined { + while (true) { + const { value, done } = iter.next(); + if (done) { + return undefined; + } + const result = callback(value); + if (result !== undefined) { + return result; + } + } + } + /** * Iterates through the parent chain of a node and performs the callback on each parent until the callback * returns a truthy value, then returns that value. @@ -474,22 +487,32 @@ namespace ts { return result; } - export function flatMapIter(iter: Iterator, mapfn: (x: T) => U | U[] | undefined): U[] { - const result: U[] = []; - while (true) { - const { value, done } = iter.next(); - if (done) break; - const res = mapfn(value); - if (res) { - if (isArray(res)) { - result.push(...res); - } - else { - result.push(res); - } - } + export function flatMapIterator(iter: Iterator, mapfn: (x: T) => U[] | Iterator | undefined): Iterator { + const first = iter.next(); + if (first.done) { + return emptyIterator; + } + let currentIter = getIterator(first.value); + return { + next() { + while (true) { + const currentRes = currentIter.next(); + if (!currentRes.done) { + return currentRes; + } + const iterRes = iter.next(); + if (iterRes.done) { + return iterRes; + } + currentIter = getIterator(iterRes.value); + } + }, + }; + + function getIterator(x: T): Iterator { + const res = mapfn(x); + return res === undefined ? emptyIterator : isArray(res) ? arrayIterator(res) : res; } - return result; } /** @@ -537,17 +560,34 @@ namespace ts { return result; } - export function mapDefinedIter(iter: Iterator, mapFn: (x: T) => U | undefined): U[] { - const result: U[] = []; - while (true) { - const { value, done } = iter.next(); - if (done) break; - const res = mapFn(value); - if (res !== undefined) { - result.push(res); + export function mapDefinedIterator(iter: Iterator, mapFn: (x: T) => U | undefined): Iterator { + return { + next() { + while (true) { + const res = iter.next(); + if (res.done) { + return res; + } + const value = mapFn(res.value); + if (value !== undefined) { + return { value, done: false }; + } + } } - } - return result; + }; + } + + export const emptyIterator: Iterator = { next: () => ({ value: undefined as never, done: true }) }; + + export function singleIterator(value: T): Iterator { + let done = false; + return { + next() { + const wasDone = done; + done = true; + return wasDone ? { value: undefined as never, done: true } : { value, done: false }; + } + }; } /** @@ -1360,7 +1400,7 @@ namespace ts { /** * Tests whether a value is an array. */ - export function isArray(value: any): value is ReadonlyArray { + export function isArray(value: any): value is ReadonlyArray<{}> { return Array.isArray ? Array.isArray(value) : value instanceof Array; } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index faf0acb163..fab7583d90 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2828,6 +2828,10 @@ "category": "Message", "code": 6030 }, + "Starting compilation in watch mode...": { + "category": "Message", + "code": 6031 + }, "File change detected. Starting incremental compilation...": { "category": "Message", "code": 6032 diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index b0633ef4d5..1cc11acd32 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -64,9 +64,9 @@ namespace ts { return { fileName: resolved.path, packageId: resolved.packageId }; } - function createResolvedModuleWithFailedLookupLocations(resolved: Resolved | undefined, isExternalLibraryImport: boolean, failedLookupLocations: string[]): ResolvedModuleWithFailedLookupLocations { + function createResolvedModuleWithFailedLookupLocations(resolved: Resolved | undefined, originalPath: string | undefined, isExternalLibraryImport: boolean, failedLookupLocations: string[]): ResolvedModuleWithFailedLookupLocations { return { - resolvedModule: resolved && { resolvedFileName: resolved.path, extension: resolved.extension, isExternalLibraryImport, packageId: resolved.packageId }, + resolvedModule: resolved && { resolvedFileName: resolved.path, originalPath, extension: resolved.extension, isExternalLibraryImport, packageId: resolved.packageId }, failedLookupLocations }; } @@ -732,12 +732,12 @@ namespace ts { const result = jsOnly ? tryResolve(Extensions.JavaScript) : (tryResolve(Extensions.TypeScript) || tryResolve(Extensions.JavaScript)); if (result && result.value) { - const { resolved, isExternalLibraryImport } = result.value; - return createResolvedModuleWithFailedLookupLocations(resolved, isExternalLibraryImport, failedLookupLocations); + const { resolved, originalPath, isExternalLibraryImport } = result.value; + return createResolvedModuleWithFailedLookupLocations(resolved, originalPath, isExternalLibraryImport, failedLookupLocations); } return { resolvedModule: undefined, failedLookupLocations }; - function tryResolve(extensions: Extensions): SearchResult<{ resolved: Resolved, isExternalLibraryImport: boolean }> { + function tryResolve(extensions: Extensions): SearchResult<{ resolved: Resolved, originalPath?: string, isExternalLibraryImport: boolean }> { const loader: ResolutionKindSpecificLoader = (extensions, candidate, failedLookupLocations, onlyRecordFailures, state) => nodeLoadModuleByRelativeName(extensions, candidate, failedLookupLocations, onlyRecordFailures, state, /*considerPackageJson*/ true); const resolved = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loader, failedLookupLocations, state); if (resolved) { @@ -752,11 +752,17 @@ namespace ts { if (!resolved) return undefined; let resolvedValue = resolved.value; - if (!compilerOptions.preserveSymlinks) { - resolvedValue = resolvedValue && { ...resolved.value, path: realPath(resolved.value.path, host, traceEnabled), extension: resolved.value.extension }; + let originalPath: string | undefined; + if (!compilerOptions.preserveSymlinks && resolvedValue) { + originalPath = resolvedValue.path; + const path = realPath(resolved.value.path, host, traceEnabled); + if (path === originalPath) { + originalPath = undefined; + } + resolvedValue = { ...resolvedValue, path }; } // For node_modules lookups, get the real path so that multiple accesses to an `npm link`-ed module do not create duplicate files. - return { value: resolvedValue && { resolved: resolvedValue, isExternalLibraryImport: true } }; + return { value: resolvedValue && { resolved: resolvedValue, originalPath, isExternalLibraryImport: true } }; } else { const { path: candidate, parts } = normalizePathAndParts(combinePaths(containingDirectory, moduleName)); @@ -1115,7 +1121,8 @@ namespace ts { const containingDirectory = getDirectoryPath(containingFile); const resolved = tryResolve(Extensions.TypeScript) || tryResolve(Extensions.JavaScript); - return createResolvedModuleWithFailedLookupLocations(resolved && resolved.value, /*isExternalLibraryImport*/ false, failedLookupLocations); + // No originalPath because classic resolution doesn't resolve realPath + return createResolvedModuleWithFailedLookupLocations(resolved && resolved.value, /*originalPath*/ undefined, /*isExternalLibraryImport*/ false, failedLookupLocations); function tryResolve(extensions: Extensions): SearchResult { const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFileNoPackageId, failedLookupLocations, state); @@ -1162,7 +1169,7 @@ namespace ts { const state: ModuleResolutionState = { compilerOptions, host, traceEnabled }; const failedLookupLocations: string[] = []; const resolved = loadModuleFromNodeModulesOneLevel(Extensions.DtsOnly, moduleName, globalCache, failedLookupLocations, state); - return createResolvedModuleWithFailedLookupLocations(resolved, /*isExternalLibraryImport*/ true, failedLookupLocations); + return createResolvedModuleWithFailedLookupLocations(resolved, /*originalPath*/ undefined, /*isExternalLibraryImport*/ true, failedLookupLocations); } /** diff --git a/src/compiler/symbolWalker.ts b/src/compiler/symbolWalker.ts index 4af313e389..fed5f15f79 100644 --- a/src/compiler/symbolWalker.ts +++ b/src/compiler/symbolWalker.ts @@ -2,6 +2,7 @@ namespace ts { export function createGetSymbolWalker( getRestTypeOfSignature: (sig: Signature) => Type, + getTypePredicateOfSignature: (sig: Signature) => TypePredicate | undefined, getReturnTypeOfSignature: (sig: Signature) => Type, getBaseTypes: (type: Type) => Type[], resolveStructuredTypeMembers: (type: ObjectType) => ResolvedType, @@ -117,8 +118,9 @@ namespace ts { } function visitSignature(signature: Signature): void { - if (signature.typePredicate) { - visitType(signature.typePredicate.type); + const typePredicate = getTypePredicateOfSignature(signature); + if (typePredicate) { + visitType(typePredicate.type); } forEach(signature.typeParameters, visitType); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index af92654c0a..0c9747f483 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2478,7 +2478,7 @@ namespace ts { // Stores a mapping 'external module reference text' -> 'resolved file name' | undefined // It is used to resolve module names in the checker. // Content of this field should never be used directly - use getResolvedModuleFileName/setResolvedModuleFileName functions instead - /* @internal */ resolvedModules: Map; + /* @internal */ resolvedModules: Map; /* @internal */ resolvedTypeReferenceDirectiveNames: Map; /* @internal */ imports: ReadonlyArray; // Identifier only if `declare global` @@ -2791,7 +2791,17 @@ namespace ts { /* @internal */ createPromiseType(type: Type): Type; /* @internal */ createAnonymousType(symbol: Symbol, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo, numberIndexInfo: IndexInfo): Type; - /* @internal */ createSignature(declaration: SignatureDeclaration, typeParameters: TypeParameter[], thisParameter: Symbol | undefined, parameters: Symbol[], resolvedReturnType: Type, typePredicate: TypePredicate, minArgumentCount: number, hasRestParameter: boolean, hasLiteralTypes: boolean): Signature; + /* @internal */ createSignature( + declaration: SignatureDeclaration, + typeParameters: TypeParameter[], + thisParameter: Symbol | undefined, + parameters: Symbol[], + resolvedReturnType: Type, + typePredicate: TypePredicate | undefined, + minArgumentCount: number, + hasRestParameter: boolean, + hasLiteralTypes: boolean, + ): Signature; /* @internal */ createSymbol(flags: SymbolFlags, name: __String): TransientSymbol; /* @internal */ createIndexInfo(type: Type, isReadonly: boolean, declaration?: SignatureDeclaration): IndexInfo; /* @internal */ isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, shouldComputeAliasToMarkVisible: boolean): SymbolAccessibilityResult; @@ -3638,7 +3648,13 @@ namespace ts { /* @internal */ thisParameter?: Symbol; // symbol of this-type parameter /* @internal */ - resolvedReturnType: Type; // Resolved return type + // See comment in `instantiateSignature` for why these are set lazily. + resolvedReturnType: Type | undefined; // Lazily set by `getReturnTypeOfSignature`. + /* @internal */ + // Lazily set by `getTypePredicateOfSignature`. + // `undefined` indicates a type predicate that has not yet been computed. + // Uses a special `noTypePredicate` sentinel value to indicate that there is no type predicate. This looks like a TypePredicate at runtime to avoid polymorphism. + resolvedTypePredicate: TypePredicate | undefined; /* @internal */ minArgumentCount: number; // Number of non-optional parameters /* @internal */ @@ -3658,8 +3674,6 @@ namespace ts { /* @internal */ isolatedSignatureType?: ObjectType; // A manufactured type that just contains the signature for purposes of signature comparison /* @internal */ - typePredicate?: TypePredicate; - /* @internal */ instantiations?: Map; // Generic signature instantiation cache } @@ -4229,6 +4243,8 @@ namespace ts { * If changing this, remember to change `moduleResolutionIsEqualTo`. */ export interface ResolvedModuleFull extends ResolvedModule { + /* @internal */ + readonly originalPath?: string; /** * Extension of resolvedFileName. This must match what's at the end of resolvedFileName. * This is optional for backwards-compatibility, but will be added if not provided. diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 0e62c2d8ce..eac101c028 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -101,6 +101,7 @@ namespace ts { return oldResolution.isExternalLibraryImport === newResolution.isExternalLibraryImport && oldResolution.extension === newResolution.extension && oldResolution.resolvedFileName === newResolution.resolvedFileName && + oldResolution.originalPath === newResolution.originalPath && packageIdIsEqual(oldResolution.packageId, newResolution.packageId); } @@ -3696,6 +3697,10 @@ namespace ts { export function typeHasCallOrConstructSignatures(type: Type, checker: TypeChecker) { return checker.getSignaturesOfType(type, SignatureKind.Call).length !== 0 || checker.getSignaturesOfType(type, SignatureKind.Construct).length !== 0; } + + export function forSomeAncestorDirectory(directory: string, callback: (directory: string) => boolean): boolean { + return !!forEachAncestorDirectory(directory, d => callback(d) ? true : undefined); + } } namespace ts { diff --git a/src/compiler/watch.ts b/src/compiler/watch.ts index a9e5fab202..35692531d0 100644 --- a/src/compiler/watch.ts +++ b/src/compiler/watch.ts @@ -302,6 +302,8 @@ namespace ts { // There is no extra check needed since we can just rely on the program to decide emit const builder = createBuilder({ getCanonicalFileName, computeHash }); + clearHostScreen(); + reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.Starting_compilation_in_watch_mode)); synchronizeProgram(); // Update the wild card directory watch @@ -492,10 +494,14 @@ namespace ts { scheduleProgramUpdate(); } - function updateProgram() { + function clearHostScreen() { if (watchingHost.system.clearScreen) { watchingHost.system.clearScreen(); } + } + + function updateProgram() { + clearHostScreen(); timerToUpdateProgram = undefined; reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation)); diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 5886619402..f5cd0c1967 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -27,6 +27,7 @@ namespace FourSlash { // The contents of the file (with markers, etc stripped out) content: string; fileName: string; + symlinks?: string[]; version: number; // File-specific options (name/value pairs) fileOptions: Harness.TestCaseParser.CompilerSettings; @@ -106,15 +107,16 @@ namespace FourSlash { // Name of testcase metadata including ts.CompilerOptions properties that will be used by globalOptions // To add additional option, add property into the testOptMetadataNames, refer the property in either globalMetadataNames or fileMetadataNames // Add cases into convertGlobalOptionsToCompilationsSettings function for the compiler to acknowledge such option from meta data - const metadataOptionNames = { - baselineFile: "BaselineFile", - emitThisFile: "emitThisFile", // This flag is used for testing getEmitOutput feature. It allows test-cases to indicate what file to be output in multiple files project - fileName: "Filename", - resolveReference: "ResolveReference", // This flag is used to specify entry file for resolve file references. The flag is only allow once per test file - }; + const enum MetadataOptionNames { + baselineFile = "BaselineFile", + emitThisFile = "emitThisFile", // This flag is used for testing getEmitOutput feature. It allows test-cases to indicate what file to be output in multiple files project + fileName = "Filename", + resolveReference = "ResolveReference", // This flag is used to specify entry file for resolve file references. The flag is only allow once per test file + symlink = "Symlink", + } // List of allowed metadata names - const fileMetadataNames = [metadataOptionNames.fileName, metadataOptionNames.emitThisFile, metadataOptionNames.resolveReference]; + const fileMetadataNames = [MetadataOptionNames.fileName, MetadataOptionNames.emitThisFile, MetadataOptionNames.resolveReference, MetadataOptionNames.symlink]; function convertGlobalOptionsToCompilerOptions(globalOptions: Harness.TestCaseParser.CompilerSettings): ts.CompilerOptions { const settings: ts.CompilerOptions = { target: ts.ScriptTarget.ES5 }; @@ -281,7 +283,7 @@ namespace FourSlash { configFileName = file.fileName; } - if (!startResolveFileRef && file.fileOptions[metadataOptionNames.resolveReference] === "true") { + if (!startResolveFileRef && file.fileOptions[MetadataOptionNames.resolveReference] === "true") { startResolveFileRef = file; } else if (startResolveFileRef) { @@ -295,7 +297,7 @@ namespace FourSlash { const host = new Utils.MockParseConfigHost(baseDir, /*ignoreCase*/ false, this.inputFiles); const configJsonObj = ts.parseConfigFileTextToJson(configFileName, this.inputFiles.get(configFileName)); - assert.isTrue(configJsonObj.config !== undefined); + assert(configJsonObj.config !== undefined); const { options, errors } = ts.parseJsonConfigFileContent(configJsonObj.config, host, baseDir); @@ -354,6 +356,10 @@ namespace FourSlash { Harness.Compiler.getDefaultLibrarySourceFile().text, /*isRootFile*/ false); } + for (const file of testData.files) { + ts.forEach(file.symlinks, link => this.languageServiceAdapterHost.addSymlink(link, file.fileName)); + } + this.formatCodeSettings = { baseIndentSize: 0, indentSize: 4, @@ -437,7 +443,7 @@ namespace FourSlash { public goToEachMarker(action: () => void) { const markers = this.getMarkers(); - assert(markers.length); + assert(markers.length !== 0); for (const marker of markers) { this.goToMarker(marker); action(); @@ -446,7 +452,7 @@ namespace FourSlash { public goToEachRange(action: () => void) { const ranges = this.getRanges(); - assert(ranges.length); + assert(ranges.length !== 0); for (const range of ranges) { this.goToRangeStart(range); action(); @@ -653,7 +659,7 @@ namespace FourSlash { this.verifyGoToXPlain(arg0, endMarkerNames, getDefs); } else if (ts.isArray(arg0)) { - const pairs: ReadonlyArray<[string | string[], string | string[]]> = arg0; + const pairs = arg0 as ReadonlyArray<[string | string[], string | string[]]>; for (const [start, end] of pairs) { this.verifyGoToXPlain(start, end, getDefs); } @@ -793,7 +799,7 @@ namespace FourSlash { } const entries = this.getCompletionListAtCaret().entries; - assert.isTrue(items.length <= entries.length, `Amount of expected items in completion list [ ${items.length} ] is greater than actual number of items in list [ ${entries.length} ]`); + assert(items.length <= entries.length, `Amount of expected items in completion list [ ${items.length} ] is greater than actual number of items in list [ ${entries.length} ]`); ts.zipWith(entries, items, (entry, item) => { assert.equal(entry.name, item, `Unexpected item in completion list`); }); @@ -947,7 +953,7 @@ namespace FourSlash { public verifyCompletionEntryDetails(entryName: string, expectedText: string, expectedDocumentation?: string, kind?: string, tags?: ts.JSDocTagInfo[]) { const details = this.getCompletionEntryDetails(entryName); - assert(details, "no completion entry available"); + assert.isDefined(details, "no completion entry available"); assert.equal(ts.displayPartsToString(details.displayParts), expectedText, this.assertionMessageAtLastKnownMarker("completion entry details text")); @@ -1082,7 +1088,7 @@ namespace FourSlash { public verifyRangesReferenceEachOther(ranges?: Range[]) { ranges = ranges || this.getRanges(); - assert(ranges.length); + assert(ranges.length !== 0); for (const range of ranges) { this.verifyReferencesOf(range, ranges); } @@ -1368,7 +1374,6 @@ Actual: ${stringify(fullActual)}`); public verifyCurrentParameterIsVariable(isVariable: boolean) { const signature = this.getActiveSignatureHelpItem(); - assert.isOk(signature); assert.equal(isVariable, signature.isVariadic); } @@ -1563,7 +1568,7 @@ Actual: ${stringify(fullActual)}`); } public baselineCurrentFileBreakpointLocations() { - let baselineFile = this.testData.globalOptions[metadataOptionNames.baselineFile]; + let baselineFile = this.testData.globalOptions[MetadataOptionNames.baselineFile]; if (!baselineFile) { baselineFile = this.activeFile.fileName.replace(this.basePath + "/breakpointValidation", "bpSpan"); baselineFile = baselineFile.replace(ts.Extension.Ts, ".baseline"); @@ -1582,7 +1587,7 @@ Actual: ${stringify(fullActual)}`); const allFourSlashFiles = this.testData.files; for (const file of allFourSlashFiles) { - if (file.fileOptions[metadataOptionNames.emitThisFile] === "true") { + if (file.fileOptions[MetadataOptionNames.emitThisFile] === "true") { // Find a file with the flag emitThisFile turned on emitFiles.push(file); } @@ -1594,7 +1599,7 @@ Actual: ${stringify(fullActual)}`); } Harness.Baseline.runBaseline( - this.testData.globalOptions[metadataOptionNames.baselineFile], + this.testData.globalOptions[MetadataOptionNames.baselineFile], () => { let resultString = ""; // Loop through all the emittedFiles and emit them one by one @@ -1634,7 +1639,7 @@ Actual: ${stringify(fullActual)}`); } public baselineQuickInfo() { - let baselineFile = this.testData.globalOptions[metadataOptionNames.baselineFile]; + let baselineFile = this.testData.globalOptions[MetadataOptionNames.baselineFile]; if (!baselineFile) { baselineFile = ts.getBaseFileName(this.activeFile.fileName).replace(ts.Extension.Ts, ".baseline"); } @@ -2019,7 +2024,7 @@ Actual: ${stringify(fullActual)}`); const implementations = this.languageService.getImplementationAtPosition(this.activeFile.fileName, this.currentCaretPosition); if (negative) { - assert.isTrue(implementations && implementations.length > 0, "Expected at least one implementation but got 0"); + assert(implementations && implementations.length > 0, "Expected at least one implementation but got 0"); } else { assert.isUndefined(implementations, "Expected implementation list to be empty but implementations returned"); @@ -2244,7 +2249,7 @@ Actual: ${stringify(fullActual)}`); public baselineCurrentFileNameOrDottedNameSpans() { Harness.Baseline.runBaseline( - this.testData.globalOptions[metadataOptionNames.baselineFile], + this.testData.globalOptions[MetadataOptionNames.baselineFile], () => { return this.baselineCurrentFileLocations(pos => this.getNameOrDottedNameSpan(pos)); @@ -2472,7 +2477,7 @@ Actual: ${stringify(fullActual)}`); } private verifyNewContent(options: FourSlashInterface.NewContentOptions) { - if (options.newFileContent) { + if (options.newFileContent !== undefined) { assert(!options.newRangeContent); this.verifyCurrentFileContent(options.newFileContent); } @@ -3110,7 +3115,7 @@ Actual: ${stringify(fullActual)}`); if (spanIndex !== undefined) { const span = this.getTextSpanForRangeAtIndex(spanIndex); - assert.isTrue(TestState.textSpansEqual(span, item.replacementSpan), this.assertionMessageAtLastKnownMarker(stringify(span) + " does not equal " + stringify(item.replacementSpan) + " replacement span for " + entryId)); + assert(TestState.textSpansEqual(span, item.replacementSpan), this.assertionMessageAtLastKnownMarker(stringify(span) + " does not equal " + stringify(item.replacementSpan) + " replacement span for " + entryId)); } assert.equal(item.hasAction, hasAction); @@ -3270,12 +3275,21 @@ ${code} // Stuff related to the subfile we're parsing let currentFileContent: string = undefined; let currentFileName = fileName; + let currentFileSymlinks: string[] | undefined; let currentFileOptions: { [s: string]: string } = {}; - function resetLocalData() { + function nextFile() { + const file = parseFileContent(currentFileContent, currentFileName, markerPositions, markers, ranges); + file.fileOptions = currentFileOptions; + file.symlinks = currentFileSymlinks; + + // Store result file + files.push(file); + currentFileContent = undefined; currentFileOptions = {}; currentFileName = fileName; + currentFileSymlinks = undefined; } for (let line of lines) { @@ -3304,8 +3318,7 @@ ${code} const match = optionRegex.exec(line.substr(2)); if (match) { const [key, value] = match.slice(1); - const fileMetadataNamesIndex = fileMetadataNames.indexOf(key); - if (fileMetadataNamesIndex === -1) { + if (!ts.contains(fileMetadataNames, key)) { // Check if the match is already existed in the global options if (globalOptions[key] !== undefined) { throw new Error(`Global option '${key}' already exists`); @@ -3313,24 +3326,22 @@ ${code} globalOptions[key] = value; } else { - if (fileMetadataNamesIndex === fileMetadataNames.indexOf(metadataOptionNames.fileName)) { - // Found an @FileName directive, if this is not the first then create a new subfile - if (currentFileContent) { - const file = parseFileContent(currentFileContent, currentFileName, markerPositions, markers, ranges); - file.fileOptions = currentFileOptions; + switch (key) { + case MetadataOptionNames.fileName: + // Found an @FileName directive, if this is not the first then create a new subfile + if (currentFileContent) { + nextFile(); + } - // Store result file - files.push(file); - - resetLocalData(); - } - - currentFileName = ts.isRootedDiskPath(value) ? value : basePath + "/" + value; - currentFileOptions[key] = value; - } - else { - // Add other fileMetadata flag - currentFileOptions[key] = value; + currentFileName = ts.isRootedDiskPath(value) ? value : basePath + "/" + value; + currentFileOptions[key] = value; + break; + case MetadataOptionNames.symlink: + currentFileSymlinks = ts.append(currentFileSymlinks, value); + break; + default: + // Add other fileMetadata flag + currentFileOptions[key] = value; } } } @@ -3342,13 +3353,7 @@ ${code} else { // Empty line or code line, terminate current subfile if there is one if (currentFileContent) { - const file = parseFileContent(currentFileContent, currentFileName, markerPositions, markers, ranges); - file.fileOptions = currentFileOptions; - - // Store result file - files.push(file); - - resetLocalData(); + nextFile(); } } } @@ -3383,7 +3388,7 @@ ${code} function getNonFileNameOptionInObject(optionObject: { [s: string]: string }): string { for (const option in optionObject) { - if (option !== metadataOptionNames.fileName) { + if (option !== MetadataOptionNames.fileName) { return option; } } diff --git a/src/harness/harness.ts b/src/harness/harness.ts index f4a58352b1..0b361f8db3 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -23,18 +23,60 @@ /// /// /// -/// - // Block scoped definitions work poorly for global variables, temporarily enable var /* tslint:disable:no-var-keyword */ -// this will work in the browser via browserify -var _chai: typeof chai = require("chai"); -var assert: typeof _chai.assert = _chai.assert; -// chai's builtin `assert.isFalse` is featureful but slow - we don't use those features, -// so we'll just overwrite it as an alterative to migrating a bunch of code off of chai -assert.isFalse = (expr, msg) => { if (expr as any as boolean !== false) throw new Error(msg); }; +function assert(expr: boolean, msg?: string | (() => string)): void { + if (!expr) { + throw new Error(typeof msg === "string" ? msg : msg()); + } +} +namespace assert { + export function isFalse(expr: boolean, msg = "Expected value to be false."): void { + assert(!expr, msg); + } + export function equal(a: T, b: T, msg = "Expected values to be equal."): void { + assert(a === b, msg); + } + export function notEqual(a: T, b: T, msg = "Expected values to not be equal."): void { + assert(a !== b, msg); + } + export function isDefined(x: {} | null | undefined, msg = "Expected value to be defined."): void { + assert(x !== undefined && x !== null, msg); + } + export function isUndefined(x: {} | null | undefined, msg = "Expected value to be undefined."): void { + assert(x === undefined, msg); + } + export function deepEqual(a: T, b: T, msg?: string): void { + assert(isDeepEqual(a, b), msg || (() => `Expected values to be deeply equal:\nExpected:\n${JSON.stringify(a, undefined, 4)}\nActual:\n${JSON.stringify(b, undefined, 4)}`)); + } + export function lengthOf(a: ReadonlyArray<{}>, length: number, msg = "Expected length to match."): void { + assert(a.length === length, msg); + } + export function throws(cb: () => void, msg = "Expected callback to throw"): void { + let threw = false; + try { + cb(); + } + catch { + threw = true; + } + assert(threw, msg); + } + + function isDeepEqual(a: T, b: T): boolean { + if (a === b) { + return true; + } + if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) { + return false; + } + const aKeys = Object.keys(a).sort(); + const bKeys = Object.keys(b).sort(); + return aKeys.length === bKeys.length && aKeys.every((key, i) => bKeys[i] === key && isDeepEqual((a as any)[key], (b as any)[key])); + } +} declare var __dirname: string; // Node-specific var global: NodeJS.Global = Function("return this").call(undefined); @@ -347,8 +389,8 @@ namespace Utils { return; } - assert(array1, "array1"); - assert(array2, "array2"); + assert(!!array1, "array1"); + assert(!!array2, "array2"); assert.equal(array1.length, array2.length, "array1.length !== array2.length"); @@ -371,8 +413,8 @@ namespace Utils { return; } - assert(node1, "node1"); - assert(node2, "node2"); + assert(!!node1, "node1"); + assert(!!node2, "node2"); assert.equal(node1.pos, node2.pos, "node1.pos !== node2.pos"); assert.equal(node1.end, node2.end, "node1.end !== node2.end"); assert.equal(node1.kind, node2.kind, "node1.kind !== node2.kind"); @@ -402,8 +444,8 @@ namespace Utils { return; } - assert(array1, "array1"); - assert(array2, "array2"); + assert(!!array1, "array1"); + assert(!!array2, "array2"); assert.equal(array1.pos, array2.pos, "array1.pos !== array2.pos"); assert.equal(array1.end, array2.end, "array1.end !== array2.end"); assert.equal(array1.length, array2.length, "array1.length !== array2.length"); @@ -1259,7 +1301,7 @@ namespace Harness { function findResultCodeFile(fileName: string) { const sourceFile = result.program.getSourceFile(fileName); - assert(sourceFile, "Program has no source file with name '" + fileName + "'"); + assert.isDefined(sourceFile, "Program has no source file with name '" + fileName + "'"); // Is this file going to be emitted separately let sourceFileName: string; const outFile = options.outFile || options.out; @@ -1942,7 +1984,7 @@ namespace Harness { const data = testUnitData[i]; if (ts.getBaseFileName(data.name).toLowerCase() === "tsconfig.json") { const configJson = ts.parseJsonText(data.name, data.content); - assert.isTrue(configJson.endOfFileToken !== undefined); + assert(configJson.endOfFileToken !== undefined); let baseDir = ts.normalizePath(ts.getDirectoryPath(data.name)); if (rootDir) { baseDir = ts.getNormalizedAbsolutePath(baseDir, rootDir); diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index d4b5a9c2a1..59c3a0f829 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -122,7 +122,7 @@ namespace Harness.LanguageService { getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo; } - export class LanguageServiceAdapterHost { + export abstract class LanguageServiceAdapterHost { public typesRegistry: ts.Map | undefined; protected virtualFileSystem: Utils.VirtualFileSystem = new Utils.VirtualFileSystem(virtualFileSystemRoot, /*useCaseSensitiveFilenames*/false); @@ -166,6 +166,8 @@ namespace Harness.LanguageService { throw new Error("No script with name '" + fileName + "'"); } + public abstract addSymlink(from: string, target: string): void; + public openFile(_fileName: string, _content?: string, _scriptKindName?: string): void { /*overridden*/ } /** @@ -174,14 +176,15 @@ namespace Harness.LanguageService { */ public positionToLineAndCharacter(fileName: string, position: number): ts.LineAndCharacter { const script: ScriptInfo = this.getScriptInfo(fileName); - assert.isOk(script); - + assert(!!script); return ts.computeLineAndCharacterOfPosition(script.getLineMap(), position); } } /// Native adapter - class NativeLanguageServiceHost extends LanguageServiceAdapterHost implements ts.LanguageServiceHost { + class NativeLanguageServiceHost extends LanguageServiceAdapterHost implements ts.LanguageServiceHost, LanguageServiceAdapterHost { + symlinks = ts.createMap(); + isKnownTypesPackageName(name: string): boolean { return this.typesRegistry && this.typesRegistry.has(name); } @@ -212,13 +215,16 @@ namespace Harness.LanguageService { } directoryExists(dirName: string): boolean { + if (ts.forEachEntry(this.symlinks, (_, key) => ts.forSomeAncestorDirectory(key, ancestor => ancestor === dirName))) { + return true; + } + const fileEntry = this.virtualFileSystem.traversePath(dirName); return fileEntry && fileEntry.isDirectory(); } fileExists(fileName: string): boolean { - const script = this.getScriptSnapshot(fileName); - return script !== undefined; + return this.symlinks.has(fileName) || this.getScriptSnapshot(fileName) !== undefined; } readDirectory(path: string, extensions?: ReadonlyArray, exclude?: ReadonlyArray, include?: ReadonlyArray, depth?: number): string[] { return ts.matchFiles(path, extensions, exclude, include, @@ -228,9 +234,19 @@ namespace Harness.LanguageService { (p) => this.virtualFileSystem.getAccessibleFileSystemEntries(p)); } readFile(path: string): string | undefined { + const target = this.symlinks.get(path); + if (target !== undefined) { + return this.readFile(target); + } + const snapshot = this.getScriptSnapshot(path); return snapshot.getText(0, snapshot.getLength()); } + addSymlink(from: string, target: string) { this.symlinks.set(from, target); } + realpath(path: string): string { + const target = this.symlinks.get(path); + return target === undefined ? path : target; + } getTypeRootsVersion() { return 0; } @@ -246,7 +262,7 @@ namespace Harness.LanguageService { constructor(cancellationToken?: ts.HostCancellationToken, options?: ts.CompilerOptions) { this.host = new NativeLanguageServiceHost(cancellationToken, options); } - getHost() { return this.host; } + getHost(): LanguageServiceAdapterHost { return this.host; } getLanguageService(): ts.LanguageService { return ts.createLanguageService(this.host); } getClassifier(): ts.Classifier { return ts.createClassifier(); } getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { return ts.preProcessFile(fileContents, /* readImportFiles */ true, ts.hasJavaScriptFileExtension(fileName)); } @@ -259,6 +275,8 @@ namespace Harness.LanguageService { public getModuleResolutionsForFile: (fileName: string) => string; public getTypeReferenceDirectiveResolutionsForFile: (fileName: string) => string; + addSymlink() { return ts.notImplemented(); } + constructor(preprocessToResolve: boolean, cancellationToken?: ts.HostCancellationToken, options?: ts.CompilerOptions) { super(cancellationToken, options); this.nativeHost = new NativeLanguageServiceHost(cancellationToken, options); @@ -360,7 +378,7 @@ namespace Harness.LanguageService { classification: parseInt(result[i + 1]) }; - assert.isTrue(t.length > 0, "Result length should be greater than 0, got :" + t.length); + assert(t.length > 0, "Result length should be greater than 0, got :" + t.length); position += t.length; } const finalLexState = parseInt(result[result.length - 1]); diff --git a/src/harness/sourceMapRecorder.ts b/src/harness/sourceMapRecorder.ts index 606d4e67ac..5ab8407067 100644 --- a/src/harness/sourceMapRecorder.ts +++ b/src/harness/sourceMapRecorder.ts @@ -285,10 +285,10 @@ namespace Harness.SourceMapRecorder { } export function recordNewSourceFileSpan(sourceMapSpan: ts.SourceMapSpan, newSourceFileCode: string) { - assert.isTrue(spansOnSingleLine.length === 0 || spansOnSingleLine[0].sourceMapSpan.emittedLine !== sourceMapSpan.emittedLine, "new file source map span should be on new line. We currently handle only that scenario"); + assert(spansOnSingleLine.length === 0 || spansOnSingleLine[0].sourceMapSpan.emittedLine !== sourceMapSpan.emittedLine, "new file source map span should be on new line. We currently handle only that scenario"); recordSourceMapSpan(sourceMapSpan); - assert.isTrue(spansOnSingleLine.length === 1); + assert(spansOnSingleLine.length === 1); sourceMapRecorder.WriteLine("-------------------------------------------------------------------"); sourceMapRecorder.WriteLine("emittedFile:" + jsFile.fileName); sourceMapRecorder.WriteLine("sourceFile:" + sourceMapSources[spansOnSingleLine[0].sourceMapSpan.sourceIndex]); @@ -331,7 +331,7 @@ namespace Harness.SourceMapRecorder { function getMarkerId(markerIndex: number) { let markerId = ""; if (spanMarkerContinues) { - assert.isTrue(markerIndex === 0); + assert(markerIndex === 0); markerId = "1->"; } else { diff --git a/src/harness/tsconfig.json b/src/harness/tsconfig.json index db38b95ba6..7353f3f7ef 100644 --- a/src/harness/tsconfig.json +++ b/src/harness/tsconfig.json @@ -5,7 +5,7 @@ "outFile": "../../built/local/run.js", "declaration": false, "types": [ - "node", "mocha", "chai" + "node", "mocha" ], "lib": [ "es6", diff --git a/src/harness/unittests/commandLineParsing.ts b/src/harness/unittests/commandLineParsing.ts index 82c2af7f64..5f0cc2acc7 100644 --- a/src/harness/unittests/commandLineParsing.ts +++ b/src/harness/unittests/commandLineParsing.ts @@ -12,7 +12,7 @@ namespace ts { const parsedErrors = parsed.errors; const expectedErrors = expectedParsedCommandLine.errors; - assert.isTrue(parsedErrors.length === expectedErrors.length, `Expected error: ${JSON.stringify(expectedErrors)}. Actual error: ${JSON.stringify(parsedErrors)}.`); + assert(parsedErrors.length === expectedErrors.length, `Expected error: ${JSON.stringify(expectedErrors)}. Actual error: ${JSON.stringify(parsedErrors)}.`); for (let i = 0; i < parsedErrors.length; i++) { const parsedError = parsedErrors[i]; const expectedError = expectedErrors[i]; @@ -23,7 +23,7 @@ namespace ts { const parsedFileNames = parsed.fileNames; const expectedFileNames = expectedParsedCommandLine.fileNames; - assert.isTrue(parsedFileNames.length === expectedFileNames.length, `Expected fileNames: [${JSON.stringify(expectedFileNames)}]. Actual fileNames: [${JSON.stringify(parsedFileNames)}].`); + assert(parsedFileNames.length === expectedFileNames.length, `Expected fileNames: [${JSON.stringify(expectedFileNames)}]. Actual fileNames: [${JSON.stringify(parsedFileNames)}].`); for (let i = 0; i < parsedFileNames.length; i++) { const parsedFileName = parsedFileNames[i]; const expectedFileName = expectedFileNames[i]; diff --git a/src/harness/unittests/compileOnSave.ts b/src/harness/unittests/compileOnSave.ts index a64d7bdd2a..808e03a068 100644 --- a/src/harness/unittests/compileOnSave.ts +++ b/src/harness/unittests/compileOnSave.ts @@ -25,7 +25,7 @@ namespace ts.projectSystem { const actualResultSingleProjectFileNameList = actualResultSingleProject.fileNames.sort(); const expectedResultSingleProjectFileNameList = map(expectedResultSingleProject.files, f => f.path).sort(); - assert.isTrue( + assert( arrayIsEqualTo(actualResultSingleProjectFileNameList, expectedResultSingleProjectFileNameList), `For project ${actualResultSingleProject.projectFileName}, the actual result is ${actualResultSingleProjectFileNameList}, while expected ${expectedResultSingleProjectFileNameList}`); } @@ -563,7 +563,7 @@ namespace ts.projectSystem { session.executeCommand(compileFileRequest); const expectedEmittedFileName = "/a/b/f1.js"; - assert.isTrue(host.fileExists(expectedEmittedFileName)); + assert(host.fileExists(expectedEmittedFileName)); assert.equal(host.readFile(expectedEmittedFileName), `"use strict";\r\nexports.__esModule = true;\r\nfunction Foo() { return 10; }\r\nexports.Foo = Foo;\r\n`); }); @@ -600,11 +600,11 @@ namespace ts.projectSystem { session.executeCommand(emitRequest); const expectedOutFileName = "/a/b/dist.js"; - assert.isTrue(host.fileExists(expectedOutFileName)); + assert(host.fileExists(expectedOutFileName)); const outFileContent = host.readFile(expectedOutFileName); - assert.isTrue(outFileContent.indexOf(file1.content) !== -1); - assert.isTrue(outFileContent.indexOf(file2.content) === -1); - assert.isTrue(outFileContent.indexOf(file3.content) === -1); + assert(outFileContent.indexOf(file1.content) !== -1); + assert(outFileContent.indexOf(file2.content) === -1); + assert(outFileContent.indexOf(file3.content) === -1); }); it("should use project root as current directory so that compile on save results in correct file mapping", () => { @@ -634,19 +634,19 @@ namespace ts.projectSystem { // Verify js file const expectedOutFileName = "/root/TypeScriptProject3/TypeScriptProject3/" + outFileName; - assert.isTrue(host.fileExists(expectedOutFileName)); + assert(host.fileExists(expectedOutFileName)); const outFileContent = host.readFile(expectedOutFileName); verifyContentHasString(outFileContent, file1.content); verifyContentHasString(outFileContent, `//# ${"sourceMappingURL"}=${outFileName}.map`); // Sometimes tools can sometimes see this line as a source mapping url comment, so we obfuscate it a little // Verify map file const expectedMapFileName = expectedOutFileName + ".map"; - assert.isTrue(host.fileExists(expectedMapFileName)); + assert(host.fileExists(expectedMapFileName)); const mapFileContent = host.readFile(expectedMapFileName); verifyContentHasString(mapFileContent, `"sources":["${inputFileName}"]`); function verifyContentHasString(content: string, str: string) { - assert.isTrue(stringContains(content, str), `Expected "${content}" to have "${str}"`); + assert(stringContains(content, str), `Expected "${content}" to have "${str}"`); } }); }); diff --git a/src/harness/unittests/configurationExtension.ts b/src/harness/unittests/configurationExtension.ts index 5a1b155fbc..ebe5b63105 100644 --- a/src/harness/unittests/configurationExtension.ts +++ b/src/harness/unittests/configurationExtension.ts @@ -113,7 +113,7 @@ namespace ts { const caseSensitiveHost = new Utils.MockParseConfigHost(caseSensitiveBasePath, /*useCaseSensitiveFileNames*/ true, testContents); function verifyDiagnostics(actual: Diagnostic[], expected: {code: number, category: DiagnosticCategory, messageText: string}[]) { - assert.isTrue(expected.length === actual.length, `Expected error: ${JSON.stringify(expected)}. Actual error: ${JSON.stringify(actual)}.`); + assert(expected.length === actual.length, `Expected error: ${JSON.stringify(expected)}. Actual error: ${JSON.stringify(actual)}.`); for (let i = 0; i < actual.length; i++) { const actualError = actual[i]; const expectedError = expected[i]; diff --git a/src/harness/unittests/convertCompilerOptionsFromJson.ts b/src/harness/unittests/convertCompilerOptionsFromJson.ts index 2a8f1fe3a8..9f5ca179ef 100644 --- a/src/harness/unittests/convertCompilerOptionsFromJson.ts +++ b/src/harness/unittests/convertCompilerOptionsFromJson.ts @@ -16,7 +16,7 @@ namespace ts { assert.equal(parsedCompilerOptions, expectedCompilerOptions); const expectedErrors = expectedResult.errors; - assert.isTrue(expectedResult.errors.length === actualErrors.length, `Expected error: ${JSON.stringify(expectedResult.errors)}. Actual error: ${JSON.stringify(actualErrors)}.`); + assert(expectedResult.errors.length === actualErrors.length, `Expected error: ${JSON.stringify(expectedResult.errors)}. Actual error: ${JSON.stringify(actualErrors)}.`); for (let i = 0; i < actualErrors.length; i++) { const actualError = actualErrors[i]; const expectedError = expectedErrors[i]; @@ -42,15 +42,15 @@ namespace ts { const actualErrors = filter(actualParseErrors, error => error.code !== Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code); const expectedErrors = expectedResult.errors; - assert.isTrue(expectedResult.errors.length === actualErrors.length, `Expected error: ${JSON.stringify(expectedResult.errors)}. Actual error: ${JSON.stringify(actualErrors)}.`); + assert(expectedResult.errors.length === actualErrors.length, `Expected error: ${JSON.stringify(expectedResult.errors)}. Actual error: ${JSON.stringify(actualErrors)}.`); for (let i = 0; i < actualErrors.length; i++) { const actualError = actualErrors[i]; const expectedError = expectedErrors[i]; assert.equal(actualError.code, expectedError.code, `Expected error-code: ${JSON.stringify(expectedError.code)}. Actual error-code: ${JSON.stringify(actualError.code)}.`); assert.equal(actualError.category, expectedError.category, `Expected error-category: ${JSON.stringify(expectedError.category)}. Actual error-category: ${JSON.stringify(actualError.category)}.`); - assert(actualError.file); - assert(actualError.start); - assert(actualError.length); + assert.isDefined(actualError.file); + assert(actualError.start > 0); + assert(actualError.length > 0); } } diff --git a/src/harness/unittests/convertTypeAcquisitionFromJson.ts b/src/harness/unittests/convertTypeAcquisitionFromJson.ts index be1ada10a9..ddeec6b986 100644 --- a/src/harness/unittests/convertTypeAcquisitionFromJson.ts +++ b/src/harness/unittests/convertTypeAcquisitionFromJson.ts @@ -17,16 +17,16 @@ namespace ts { function verifyErrors(actualErrors: Diagnostic[], expectedResult: ExpectedResult, hasLocation?: boolean) { const expectedErrors = expectedResult.errors; - assert.isTrue(expectedResult.errors.length === actualErrors.length, `Expected error: ${JSON.stringify(expectedResult.errors)}. Actual error: ${JSON.stringify(actualErrors)}.`); + assert(expectedResult.errors.length === actualErrors.length, `Expected error: ${JSON.stringify(expectedResult.errors)}. Actual error: ${JSON.stringify(actualErrors)}.`); for (let i = 0; i < actualErrors.length; i++) { const actualError = actualErrors[i]; const expectedError = expectedErrors[i]; assert.equal(actualError.code, expectedError.code, `Expected error-code: ${JSON.stringify(expectedError.code)}. Actual error-code: ${JSON.stringify(actualError.code)}.`); assert.equal(actualError.category, expectedError.category, `Expected error-category: ${JSON.stringify(expectedError.category)}. Actual error-category: ${JSON.stringify(actualError.category)}.`); if (hasLocation) { - assert(actualError.file); - assert(actualError.start); - assert(actualError.length); + assert.isDefined(actualError.file); + assert(actualError.start > 0); + assert(actualError.length > 0); } } } diff --git a/src/harness/unittests/extractRanges.ts b/src/harness/unittests/extractRanges.ts index 493c9639c3..08bae357f0 100644 --- a/src/harness/unittests/extractRanges.ts +++ b/src/harness/unittests/extractRanges.ts @@ -39,7 +39,7 @@ namespace ts { assert.equal(end, expectedRange.end, "incorrect end of range"); } else { - assert.isTrue(!result.targetRange, `expected range to extract to be undefined`); + assert(!result.targetRange, `expected range to extract to be undefined`); } } diff --git a/src/harness/unittests/hostNewLineSupport.ts b/src/harness/unittests/hostNewLineSupport.ts index 95a05f101f..ac5031ed56 100644 --- a/src/harness/unittests/hostNewLineSupport.ts +++ b/src/harness/unittests/hostNewLineSupport.ts @@ -47,7 +47,7 @@ namespace ts { assert(!result.emitSkipped, "emit was skipped"); assert(result.outputFiles.length === 1, "a number of files other than 1 was output"); assert(result.outputFiles[0].name === "input.js", `Expected output file name input.js, but got ${result.outputFiles[0].name}`); - assert(result.outputFiles[0].text.match(options.newLine === NewLineKind.CarriageReturnLineFeed ? /\r\n/ : /[^\r]\n/), "expected to find appropriate newlines"); + assert.isDefined(result.outputFiles[0].text.match(options.newLine === NewLineKind.CarriageReturnLineFeed ? /\r\n/ : /[^\r]\n/), "expected to find appropriate newlines"); assert(!result.outputFiles[0].text.match(options.newLine === NewLineKind.CarriageReturnLineFeed ? /[^\r]\n/ : /\r\n/), "expected not to find inappropriate newlines"); } diff --git a/src/harness/unittests/incrementalParser.ts b/src/harness/unittests/incrementalParser.ts index c71b89d3da..2facc4aa15 100644 --- a/src/harness/unittests/incrementalParser.ts +++ b/src/harness/unittests/incrementalParser.ts @@ -66,7 +66,7 @@ namespace ts { assertSameDiagnostics(newTree, incrementalNewTree); // There should be no reused nodes between two trees that are fully parsed. - assert.isTrue(reusedElements(oldTree, newTree) === 0); + assert(reusedElements(oldTree, newTree) === 0); assert.equal(newTree.fileName, incrementalNewTree.fileName, "newTree.fileName !== incrementalNewTree.fileName"); assert.equal(newTree.text, incrementalNewTree.text, "newTree.text !== incrementalNewTree.text"); diff --git a/src/harness/unittests/jsDocParsing.ts b/src/harness/unittests/jsDocParsing.ts index b7215f5ea3..51647c4636 100644 --- a/src/harness/unittests/jsDocParsing.ts +++ b/src/harness/unittests/jsDocParsing.ts @@ -7,7 +7,7 @@ namespace ts { function parsesCorrectly(name: string, content: string) { it(name, () => { const typeAndDiagnostics = ts.parseJSDocTypeExpressionForTests(content); - assert.isTrue(typeAndDiagnostics && typeAndDiagnostics.diagnostics.length === 0, "no errors issued"); + assert(typeAndDiagnostics && typeAndDiagnostics.diagnostics.length === 0, "no errors issued"); Harness.Baseline.runBaseline("JSDocParsing/TypeExpressions.parsesCorrectly." + name + ".json", () => Utils.sourceFileToJSON(typeAndDiagnostics.jsDocTypeExpression.type)); @@ -17,7 +17,7 @@ namespace ts { function parsesIncorrectly(name: string, content: string) { it(name, () => { const type = ts.parseJSDocTypeExpressionForTests(content); - assert.isTrue(!type || type.diagnostics.length > 0); + assert(!type || type.diagnostics.length > 0); }); } @@ -106,7 +106,7 @@ namespace ts { function parsesIncorrectly(name: string, content: string) { it(name, () => { const type = parseIsolatedJSDocComment(content); - assert.isTrue(!type || type.diagnostics.length > 0); + assert(!type || type.diagnostics.length > 0); }); } diff --git a/src/harness/unittests/languageService.ts b/src/harness/unittests/languageService.ts index 1407a51861..2760df63c8 100644 --- a/src/harness/unittests/languageService.ts +++ b/src/harness/unittests/languageService.ts @@ -40,12 +40,9 @@ export function Component(x: Config): any;` getDefaultLibFileName(options) { return ts.getDefaultLibFilePath(options); }, - fileExists: noop as any, - readFile: noop as any, - readDirectory: noop as any, }); const definitions = languageService.getDefinitionAtPosition("foo.ts", 160); // 160 is the latter `vueTemplateHtml` position - expect(definitions).to.exist; // tslint:disable-line no-unused-expression + assert.isDefined(definitions); }); }); } \ No newline at end of file diff --git a/src/harness/unittests/moduleResolution.ts b/src/harness/unittests/moduleResolution.ts index de79ba06cf..1c18ac273a 100644 --- a/src/harness/unittests/moduleResolution.ts +++ b/src/harness/unittests/moduleResolution.ts @@ -4,9 +4,9 @@ namespace ts { export function checkResolvedModule(expected: ResolvedModuleFull, actual: ResolvedModuleFull): boolean { if (!expected === !actual) { if (expected) { - assert.isTrue(expected.resolvedFileName === actual.resolvedFileName, `'resolvedFileName': expected '${expected.resolvedFileName}' to be equal to '${actual.resolvedFileName}'`); - assert.isTrue(expected.extension === actual.extension, `'ext': expected '${expected.extension}' to be equal to '${actual.extension}'`); - assert.isTrue(expected.isExternalLibraryImport === actual.isExternalLibraryImport, `'isExternalLibraryImport': expected '${expected.isExternalLibraryImport}' to be equal to '${actual.isExternalLibraryImport}'`); + assert(expected.resolvedFileName === actual.resolvedFileName, `'resolvedFileName': expected '${expected.resolvedFileName}' to be equal to '${actual.resolvedFileName}'`); + assert(expected.extension === actual.extension, `'ext': expected '${expected.extension}' to be equal to '${actual.extension}'`); + assert(expected.isExternalLibraryImport === actual.isExternalLibraryImport, `'isExternalLibraryImport': expected '${expected.isExternalLibraryImport}' to be equal to '${actual.isExternalLibraryImport}'`); } return true; } @@ -14,7 +14,7 @@ namespace ts { } export function checkResolvedModuleWithFailedLookupLocations(actual: ResolvedModuleWithFailedLookupLocations, expectedResolvedModule: ResolvedModuleFull, expectedFailedLookupLocations: string[]): void { - assert.isTrue(actual.resolvedModule !== undefined, "module should be resolved"); + assert(actual.resolvedModule !== undefined, "module should be resolved"); checkResolvedModule(actual.resolvedModule, expectedResolvedModule); assert.deepEqual(actual.failedLookupLocations, expectedFailedLookupLocations); } @@ -58,7 +58,7 @@ namespace ts { realpath, directoryExists: path => directories.has(path), fileExists: path => { - assert.isTrue(directories.has(getDirectoryPath(path)), `'fileExists' '${path}' request in non-existing directory`); + assert(directories.has(getDirectoryPath(path)), `'fileExists' '${path}' request in non-existing directory`); return map.has(path); } }; @@ -313,7 +313,7 @@ namespace ts { const host = createModuleResolutionHost(/*hasDirectoryExists*/ true, { name: realFileName, symlinks: [symlinkFileName] }); const resolution = nodeModuleNameResolver("linked", "/app/app.ts", { preserveSymlinks }, host); const resolvedFileName = preserveSymlinks ? symlinkFileName : realFileName; - checkResolvedModule(resolution.resolvedModule, { resolvedFileName, isExternalLibraryImport: true, extension: Extension.Dts }); + checkResolvedModule(resolution.resolvedModule, createResolvedModule(resolvedFileName, /*isExternalLibraryImport*/ true)); }); } }); @@ -338,7 +338,7 @@ namespace ts { const path = normalizePath(combinePaths(currentDirectory, fileName)); return files.has(path); }, - readFile: notImplemented + readFile: notImplemented, }; const program = createProgram(rootFiles, options, host); @@ -351,7 +351,7 @@ namespace ts { // try to get file using a relative name for (const relativeFileName of relativeNamesToCheck) { - assert.isTrue(program.getSourceFile(relativeFileName) !== undefined, `expected to get file by relative name, got undefined`); + assert(program.getSourceFile(relativeFileName) !== undefined, `expected to get file by relative name, got undefined`); } } @@ -426,7 +426,7 @@ export = C; const path = getCanonicalFileName(normalizePath(combinePaths(currentDirectory, fileName))); return files.has(path); }, - readFile: notImplemented + readFile: notImplemented, }; const program = createProgram(rootFiles, options, host); const diagnostics = sortAndDeduplicateDiagnostics([...program.getSemanticDiagnostics(), ...program.getOptionsDiagnostics()]); @@ -1067,14 +1067,14 @@ import b = require("./moduleB"); readFile: fileName => { const file = sourceFiles.get(fileName); return file && file.text; - } + }, }; const program1 = createProgram(names, {}, compilerHost); const diagnostics1 = program1.getFileProcessingDiagnostics().getDiagnostics(); assert.equal(diagnostics1.length, 1, "expected one diagnostic"); createProgram(names, {}, compilerHost, program1); - assert.isTrue(program1.structureIsReused === StructureIsReused.Completely); + assert(program1.structureIsReused === StructureIsReused.Completely); const diagnostics2 = program1.getFileProcessingDiagnostics().getDiagnostics(); assert.equal(diagnostics2.length, 1, "expected one diagnostic"); assert.equal(diagnostics1[0].messageText, diagnostics2[0].messageText, "expected one diagnostic"); diff --git a/src/harness/unittests/programMissingFiles.ts b/src/harness/unittests/programMissingFiles.ts index ce8abc232e..e6e2b9af71 100644 --- a/src/harness/unittests/programMissingFiles.ts +++ b/src/harness/unittests/programMissingFiles.ts @@ -6,10 +6,10 @@ namespace ts { const map = arrayToSet(expected) as Map; for (const missing of missingPaths) { const value = map.get(missing); - assert.isTrue(value, `${missing} to be ${value === undefined ? "not present" : "present only once"}, in actual: ${missingPaths} expected: ${expected}`); + assert(value, `${missing} to be ${value === undefined ? "not present" : "present only once"}, in actual: ${missingPaths} expected: ${expected}`); map.set(missing, false); } - const notFound = mapDefinedIter(map.keys(), k => map.get(k) === true ? k : undefined); + const notFound = arrayFrom(mapDefinedIterator(map.keys(), k => map.get(k) === true ? k : undefined)); assert.equal(notFound.length, 0, `Not found ${notFound} in actual: ${missingPaths} expected: ${expected}`); } diff --git a/src/harness/unittests/projectErrors.ts b/src/harness/unittests/projectErrors.ts index dae465a3ef..d146b3af08 100644 --- a/src/harness/unittests/projectErrors.ts +++ b/src/harness/unittests/projectErrors.ts @@ -5,7 +5,7 @@ namespace ts.projectSystem { describe("Project errors", () => { function checkProjectErrors(projectFiles: server.ProjectFilesWithTSDiagnostics, expectedErrors: ReadonlyArray): void { - assert.isTrue(projectFiles !== undefined, "missing project files"); + assert(projectFiles !== undefined, "missing project files"); checkProjectErrorsWorker(projectFiles.projectErrors, expectedErrors); } @@ -15,7 +15,7 @@ namespace ts.projectSystem { for (let i = 0; i < errors.length; i++) { const actualMessage = flattenDiagnosticMessageText(errors[i].messageText, "\n"); const expectedMessage = expectedErrors[i]; - assert.isTrue(actualMessage.indexOf(expectedMessage) === 0, `error message does not match, expected ${actualMessage} to start with ${expectedMessage}`); + assert(actualMessage.indexOf(expectedMessage) === 0, `error message does not match, expected ${actualMessage} to start with ${expectedMessage}`); } } } @@ -24,7 +24,7 @@ namespace ts.projectSystem { assert.equal(errors ? errors.length : 0, expectedErrors.length, `expected ${expectedErrors.length} error in the list`); if (expectedErrors.length) { zipWith(errors, expectedErrors, ({ message: actualMessage }, expectedMessage) => { - assert.isTrue(startsWith(actualMessage, actualMessage), `error message does not match, expected ${actualMessage} to start with ${expectedMessage}`); + assert(startsWith(actualMessage, actualMessage), `error message does not match, expected ${actualMessage} to start with ${expectedMessage}`); }); } } @@ -137,13 +137,13 @@ namespace ts.projectSystem { { projectService.checkNumberOfProjects({ configuredProjects: 1 }); const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f); - assert.isTrue(configuredProject !== undefined, "should find configured project"); + assert(configuredProject !== undefined, "should find configured project"); checkProjectErrors(configuredProject, []); const projectErrors = configuredProjectAt(projectService, 0).getAllProjectErrors(); checkProjectErrorsWorker(projectErrors, [ "'{' expected." ]); - assert.isNotNull(projectErrors[0].file); + assert.isDefined(projectErrors[0].file); assert.equal(projectErrors[0].file.fileName, corruptedConfig.path); } // fix config and trigger watcher @@ -151,7 +151,7 @@ namespace ts.projectSystem { { projectService.checkNumberOfProjects({ configuredProjects: 1 }); const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f); - assert.isTrue(configuredProject !== undefined, "should find configured project"); + assert(configuredProject !== undefined, "should find configured project"); checkProjectErrors(configuredProject, []); const projectErrors = configuredProjectAt(projectService, 0).getAllProjectErrors(); checkProjectErrorsWorker(projectErrors, []); @@ -182,7 +182,7 @@ namespace ts.projectSystem { { projectService.checkNumberOfProjects({ configuredProjects: 1 }); const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f); - assert.isTrue(configuredProject !== undefined, "should find configured project"); + assert(configuredProject !== undefined, "should find configured project"); checkProjectErrors(configuredProject, []); const projectErrors = configuredProjectAt(projectService, 0).getAllProjectErrors(); checkProjectErrorsWorker(projectErrors, []); @@ -192,13 +192,13 @@ namespace ts.projectSystem { { projectService.checkNumberOfProjects({ configuredProjects: 1 }); const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f); - assert.isTrue(configuredProject !== undefined, "should find configured project"); + assert(configuredProject !== undefined, "should find configured project"); checkProjectErrors(configuredProject, []); const projectErrors = configuredProjectAt(projectService, 0).getAllProjectErrors(); checkProjectErrorsWorker(projectErrors, [ "'{' expected." ]); - assert.isNotNull(projectErrors[0].file); + assert.isDefined(projectErrors[0].file); assert.equal(projectErrors[0].file.fileName, corruptedConfig.path); } }); diff --git a/src/harness/unittests/reuseProgramStructure.ts b/src/harness/unittests/reuseProgramStructure.ts index fdccc8a779..45fe7383c3 100644 --- a/src/harness/unittests/reuseProgramStructure.ts +++ b/src/harness/unittests/reuseProgramStructure.ts @@ -193,14 +193,14 @@ namespace ts { function checkCache(caption: string, program: Program, fileName: string, expectedContent: Map, getCache: (f: SourceFile) => Map, entryChecker: (expected: T, original: T) => boolean): void { const file = program.getSourceFile(fileName); - assert.isTrue(file !== undefined, `cannot find file ${fileName}`); + assert(file !== undefined, `cannot find file ${fileName}`); const cache = getCache(file); if (expectedContent === undefined) { - assert.isTrue(cache === undefined, `expected ${caption} to be undefined`); + assert(cache === undefined, `expected ${caption} to be undefined`); } else { - assert.isTrue(cache !== undefined, `expected ${caption} to be set`); - assert.isTrue(mapsAreEqual(expectedContent, cache, entryChecker), `contents of ${caption} did not match the expected contents.`); + assert(cache !== undefined, `expected ${caption} to be set`); + assert(mapsAreEqual(expectedContent, cache, entryChecker), `contents of ${caption} did not match the expected contents.`); } } @@ -329,7 +329,7 @@ namespace ts { const options: CompilerOptions = { target, noLib: true }; const program1 = newProgram(files, ["a.ts"], options); - assert.notDeepEqual(emptyArray, program1.getMissingFilePaths()); + assert(program1.getMissingFilePaths().length !== 0); const program2 = updateProgram(program1, ["a.ts"], options, noop); assert.deepEqual(program1.getMissingFilePaths(), program2.getMissingFilePaths()); @@ -341,11 +341,11 @@ namespace ts { const options: CompilerOptions = { target, noLib: true }; const program1 = newProgram(files, ["a.ts"], options); - assert.notDeepEqual(emptyArray, program1.getMissingFilePaths()); + assert(program1.getMissingFilePaths().length !== 0); const newTexts: NamedSourceText[] = files.concat([{ name: "non-existing-file.ts", text: SourceText.New("", "", `var x = 1`) }]); const program2 = updateProgram(program1, ["a.ts"], options, noop, newTexts); - assert.deepEqual(emptyArray, program2.getMissingFilePaths()); + assert.lengthOf(program2.getMissingFilePaths(), 0); assert.equal(StructureIsReused.Not, program1.structureIsReused); }); @@ -826,12 +826,12 @@ namespace ts { updateProgramText(files, root, "const x = 1;"); }); assert.equal(program1.structureIsReused, StructureIsReused.Completely); - assert.deepEqual(program2.getSemanticDiagnostics(), emptyArray); + assert.lengthOf(program2.getSemanticDiagnostics(), 0); }); it("Target changes -> redirect broken", () => { const program1 = createRedirectProgram(); - assert.deepEqual(program1.getSemanticDiagnostics(), emptyArray); + assert.lengthOf(program1.getSemanticDiagnostics(), 0); const program2 = updateRedirectProgram(program1, files => { updateProgramText(files, axIndex, "export default class X { private x: number; private y: number; }"); @@ -860,7 +860,7 @@ namespace ts { updateProgramText(files, bxPackage, JSON.stringify({ name: "x", version: "1.2.3" })); }); assert.equal(program1.structureIsReused, StructureIsReused.Not); - assert.deepEqual(program2.getSemanticDiagnostics(), []); + assert.lengthOf(program2.getSemanticDiagnostics(), 0); }); }); }); @@ -888,7 +888,7 @@ namespace ts { /*hasInvalidatedResolution*/ returnFalse, /*hasChangedAutomaticTypeDirectiveNames*/ false ); - assert.isTrue(actual); + assert(actual); } function duplicate(options: CompilerOptions): CompilerOptions; diff --git a/src/harness/unittests/services/colorization.ts b/src/harness/unittests/services/colorization.ts index 17d4132e9e..b03285d333 100644 --- a/src/harness/unittests/services/colorization.ts +++ b/src/harness/unittests/services/colorization.ts @@ -50,7 +50,7 @@ describe("Colorization", () => { const actualEntry = getEntryAtPosition(result, actualEntryPosition); - assert(actualEntry, "Could not find classification entry for '" + expectedEntry.value + "' at position: " + actualEntryPosition); + assert.isDefined(actualEntry, "Could not find classification entry for '" + expectedEntry.value + "' at position: " + actualEntryPosition); assert.equal(actualEntry.classification, expectedEntry.classification, "Classification class does not match expected. Expected: " + ts.TokenClass[expectedEntry.classification] + ", Actual: " + ts.TokenClass[actualEntry.classification]); assert.equal(actualEntry.length, expectedEntry.value.length, "Classification length does not match expected. Expected: " + ts.TokenClass[expectedEntry.value.length] + ", Actual: " + ts.TokenClass[actualEntry.length]); } diff --git a/src/harness/unittests/services/patternMatcher.ts b/src/harness/unittests/services/patternMatcher.ts index fef382e8a3..62946afde3 100644 --- a/src/harness/unittests/services/patternMatcher.ts +++ b/src/harness/unittests/services/patternMatcher.ts @@ -140,25 +140,25 @@ describe("PatternMatcher", () => { it("PreferCaseSensitiveCamelCaseMatchToLongPattern1", () => { const match = getFirstMatch("FogBar", "FBB"); - assert.isTrue(match === undefined); + assert(match === undefined); }); it("PreferCaseSensitiveCamelCaseMatchToLongPattern2", () => { const match = getFirstMatch("FogBar", "FoooB"); - assert.isTrue(match === undefined); + assert(match === undefined); }); it("CamelCaseMatchPartiallyUnmatched", () => { const match = getFirstMatch("FogBarBaz", "FZ"); - assert.isTrue(match === undefined); + assert(match === undefined); }); it("CamelCaseMatchCompletelyUnmatched", () => { const match = getFirstMatch("FogBarBaz", "ZZ"); - assert.isTrue(match === undefined); + assert(match === undefined); }); it("TwoUppercaseCharacters", () => { @@ -220,7 +220,7 @@ describe("PatternMatcher", () => { it("PreferCaseSensitiveMiddleUnderscore3", () => { const match = getFirstMatch("Fog_Bar", "F__B"); - assert.isTrue(undefined === match); + assert(undefined === match); }); it("PreferCaseSensitiveMiddleUnderscore4", () => { @@ -264,25 +264,25 @@ describe("PatternMatcher", () => { it("AllLowerPattern1", () => { const match = getFirstMatch("FogBarChangedEventArgs", "changedeventargs"); - assert.isTrue(undefined !== match); + assert(undefined !== match); }); it("AllLowerPattern2", () => { const match = getFirstMatch("FogBarChangedEventArgs", "changedeventarrrgh"); - assert.isTrue(undefined === match); + assert(undefined === match); }); it("AllLowerPattern3", () => { const match = getFirstMatch("ABCDEFGH", "bcd"); - assert.isTrue(undefined !== match); + assert(undefined !== match); }); it("AllLowerPattern4", () => { const match = getFirstMatch("AbcdefghijEfgHij", "efghij"); - assert.isTrue(undefined === match); + assert(undefined === match); }); }); @@ -370,13 +370,13 @@ describe("PatternMatcher", () => { it("BlankPattern", () => { const matches = getAllMatches("AddMetadataReference", ""); - assert.isTrue(matches === undefined); + assert(matches === undefined); }); it("WhitespaceOnlyPattern", () => { const matches = getAllMatches("AddMetadataReference", " "); - assert.isTrue(matches === undefined); + assert(matches === undefined); }); it("EachWordSeparately1", () => { @@ -403,13 +403,13 @@ describe("PatternMatcher", () => { it("MixedCasing", () => { const matches = getAllMatches("AddMetadataReference", "mEta"); - assert.isTrue(matches === undefined); + assert(matches === undefined); }); it("MixedCasing2", () => { const matches = getAllMatches("AddMetadataReference", "Data"); - assert.isTrue(matches === undefined); + assert(matches === undefined); }); it("AsteriskSplit", () => { @@ -421,7 +421,7 @@ describe("PatternMatcher", () => { it("LowercaseSubstring1", () => { const matches = getAllMatches("Operator", "a"); - assert.isTrue(matches === undefined); + assert(matches === undefined); }); it("LowercaseSubstring2", () => { @@ -441,7 +441,7 @@ describe("PatternMatcher", () => { it("DottedPattern2", () => { const match = getFirstMatchForDottedPattern("Foo.Bar.Baz", "Quux", "C.Q"); - assert.isTrue(match === undefined); + assert(match === undefined); }); it("DottedPattern3", () => { @@ -464,13 +464,13 @@ describe("PatternMatcher", () => { it("DottedPattern6", () => { const match = getFirstMatchForDottedPattern("Foo.Bar.Baz", "Quux", "F.F.B.B.Quux"); - assert.isTrue(match === undefined); + assert(match === undefined); }); it("DottedPattern7", () => { let match = getFirstMatch("UIElement", "UIElement"); match = getFirstMatch("GetKeyword", "UIElement"); - assert.isTrue(match === undefined); + assert(match === undefined); }); }); @@ -508,8 +508,8 @@ describe("PatternMatcher", () => { } function assertInRange(val: number, low: number, high: number) { - assert.isTrue(val >= low); - assert.isTrue(val <= high); + assert(val >= low); + assert(val <= high); } function verifyBreakIntoCharacterSpans(original: string, ...parts: string[]): void { @@ -521,6 +521,6 @@ describe("PatternMatcher", () => { } function assertContainsKind(kind: ts.PatternMatchKind, results: ts.PatternMatch[]) { - assert.isTrue(ts.forEach(results, r => r.kind === kind)); + assert(ts.forEach(results, r => r.kind === kind)); } }); diff --git a/src/harness/unittests/services/preProcessFile.ts b/src/harness/unittests/services/preProcessFile.ts index 1e13bc3e34..acbb8edd67 100644 --- a/src/harness/unittests/services/preProcessFile.ts +++ b/src/harness/unittests/services/preProcessFile.ts @@ -18,7 +18,7 @@ describe("PreProcessFile:", () => { return; } if (!expected) { - assert.isTrue(false, `Expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`); + assert(false, `Expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`); } assert.equal(actual.length, expected.length, `[${kind}] Actual array's length does not match expected length. Expected files: ${JSON.stringify(expected)}, actual files: ${JSON.stringify(actual)}`); diff --git a/src/harness/unittests/session.ts b/src/harness/unittests/session.ts index 5cde1e9d2e..9912294d1d 100644 --- a/src/harness/unittests/session.ts +++ b/src/harness/unittests/session.ts @@ -1,7 +1,5 @@ /// -const expect: typeof _chai.expect = _chai.expect; - namespace ts.server { let lastWrittenToHost: string; const mockHost: ServerHost = { @@ -82,7 +80,7 @@ namespace ts.server { } }; - expect(() => session.executeCommand(req)).to.throw(); + assert.throws(() => session.executeCommand(req)); }); it("should output an error response when a command does not exist", () => { const req: protocol.Request = { @@ -101,7 +99,7 @@ namespace ts.server { request_seq: 0, success: false }; - expect(lastSent).to.deep.equal(expected); + assert.deepEqual(lastSent, expected); }); it("should return a tuple containing the response and if a response is required on success", () => { const req: protocol.ConfigureRequest = { @@ -116,17 +114,18 @@ namespace ts.server { } }; - expect(session.executeCommand(req)).to.deep.equal({ + assert.deepEqual(session.executeCommand(req), { responseRequired: false }); - expect(lastSent).to.deep.equal({ + const expected: protocol.Response = { command: CommandNames.Configure, type: "response", success: true, request_seq: 0, seq: 0, body: undefined - }); + }; + assert.deepEqual(lastSent, expected); }); it("should handle literal types in request", () => { const configureRequest: protocol.ConfigureRequest = { @@ -297,14 +296,15 @@ namespace ts.server { session.onMessage(JSON.stringify(req)); - expect(lastSent).to.deep.equal({ + const expected: protocol.ConfigureResponse = { command: CommandNames.Configure, type: "response", success: true, request_seq: 0, seq: 0, body: undefined - }); + }; + assert.deepEqual(lastSent, expected); }); }); @@ -316,9 +316,9 @@ namespace ts.server { const resultMsg = `Content-Length: ${len}\r\n\r\n${strmsg}\n`; session.send = Session.prototype.send; - assert(session.send); - expect(session.send(msg)).to.not.exist; // tslint:disable-line no-unused-expression - expect(lastWrittenToHost).to.equal(resultMsg); + assert.isDefined(session.send); + session.send(msg); + assert.equal(lastWrittenToHost, resultMsg); }); }); @@ -335,11 +335,7 @@ namespace ts.server { session.addProtocolHandler(command, () => result); - expect(session.executeCommand({ - command, - seq: 0, - type: "request" - })).to.deep.equal(result); + assert.deepEqual(session.executeCommand({ command, seq: 0, type: "request" }), result); }); it("throws when a duplicate handler is passed", () => { const respBody = { @@ -353,8 +349,7 @@ namespace ts.server { session.addProtocolHandler(command, () => resp); - expect(() => session.addProtocolHandler(command, () => resp)) - .to.throw(`Protocol handler already exists for command "${command}"`); + assert.throws(() => session.addProtocolHandler(command, () => resp), `Protocol handler already exists for command "${command}"`); }); }); @@ -367,12 +362,13 @@ namespace ts.server { session.event(info, evt); - expect(lastSent).to.deep.equal({ + const expected: protocol.Event = { type: "event", seq: 0, event: evt, body: info - }); + }; + assert.deepEqual(lastSent, expected); }); }); @@ -387,14 +383,15 @@ namespace ts.server { session.output(body, command, /*reqSeq*/ 0); - expect(lastSent).to.deep.equal({ + const expected: protocol.Response = { seq: 0, request_seq: 0, type: "response", command, body, success: true - }); + }; + assert.deepEqual(lastSent, expected); }); }); }); @@ -455,14 +452,16 @@ namespace ts.server { session.onMessage(JSON.stringify(request)); const lastSent = session.lastSent as protocol.Response; - expect(lastSent).to.contain({ + assert.deepEqual({ ...lastSent, message: undefined }, { + request_seq: 0, seq: 0, type: "response", command, - success: false + success: false, + message: undefined, }); - expect(lastSent.message).has.string("myMessage").and.has.string("f1"); + assert(ts.stringContains(lastSent.message, "myMessage") && ts.stringContains(lastSent.message, "f1")); }); }); @@ -502,23 +501,24 @@ namespace ts.server { session.output(body, command, /*reqSeq*/ 0); - expect(session.lastSent).to.deep.equal({ + const expected: protocol.Response = { seq: 0, request_seq: 0, type: "response", command, body, success: true - }); + }; + assert.deepEqual(session.lastSent, expected); }); it("can add and respond to new protocol handlers", () => { const session = new TestSession(); - expect(session.executeCommand({ + assert.deepEqual(session.executeCommand({ seq: 0, type: "request", command: session.customHandler - })).to.deep.equal({ + }), { response: undefined, responseRequired: true }); @@ -528,8 +528,7 @@ namespace ts.server { new class extends TestSession { constructor() { super(); - assert(this.projectService); - expect(this.projectService).to.be.instanceOf(ProjectService); + assert(this.projectService instanceof ProjectService); } }(); }); @@ -653,9 +652,9 @@ namespace ts.server { // Add an event handler cli.on("testevent", (eventinfo) => { - expect(eventinfo).to.equal(toEvent); + assert.equal(eventinfo, toEvent); responses++; - expect(responses).to.equal(1); + assert.equal(responses, 1); }); // Trigger said event from the server @@ -665,8 +664,8 @@ namespace ts.server { cli.execute("echo", toEcho, (resp) => { assert(resp.success, resp.message); responses++; - expect(responses).to.equal(2); - expect(resp.body).to.deep.equal(toEcho); + assert.equal(responses, 2); + assert.deepEqual(resp.body, toEcho); }); // Queue a configure command @@ -678,7 +677,7 @@ namespace ts.server { }, (resp) => { assert(resp.success, resp.message); responses++; - expect(responses).to.equal(3); + assert.equal(responses, 3); done(); }); diff --git a/src/harness/unittests/textStorage.ts b/src/harness/unittests/textStorage.ts index aa8231aa31..78a736487c 100644 --- a/src/harness/unittests/textStorage.ts +++ b/src/harness/unittests/textStorage.ts @@ -33,20 +33,20 @@ namespace ts.textStorage { for (let offset = 0; offset < end - start; offset++) { const pos1 = ts1.lineOffsetToPosition(line + 1, offset + 1); const pos2 = ts2.lineOffsetToPosition(line + 1, offset + 1); - assert.isTrue(pos1 === pos2, `lineOffsetToPosition ${line + 1}-${offset + 1}: expected ${pos1} to equal ${pos2}`); + assert(pos1 === pos2, `lineOffsetToPosition ${line + 1}-${offset + 1}: expected ${pos1} to equal ${pos2}`); } const {start: start1, length: length1 } = ts1.lineToTextSpan(line); const {start: start2, length: length2 } = ts2.lineToTextSpan(line); - assert.isTrue(start1 === start2, `lineToTextSpan ${line}::start:: expected ${start1} to equal ${start2}`); - assert.isTrue(length1 === length2, `lineToTextSpan ${line}::length:: expected ${length1} to equal ${length2}`); + assert(start1 === start2, `lineToTextSpan ${line}::start:: expected ${start1} to equal ${start2}`); + assert(length1 === length2, `lineToTextSpan ${line}::length:: expected ${length1} to equal ${length2}`); } for (let pos = 0; pos < f.content.length; pos++) { const { line: line1, offset: offset1 } = ts1.positionToLineOffset(pos); const { line: line2, offset: offset2 } = ts2.positionToLineOffset(pos); - assert.isTrue(line1 === line2, `positionToLineOffset ${pos}::line:: expected ${line1} to equal ${line2}`); - assert.isTrue(offset1 === offset2, `positionToLineOffset ${pos}::offset:: expected ${offset1} to equal ${offset2}`); + assert(line1 === line2, `positionToLineOffset ${pos}::line:: expected ${line1} to equal ${line2}`); + assert(offset1 === offset2, `positionToLineOffset ${pos}::offset:: expected ${offset1} to equal ${offset2}`); } }); @@ -55,16 +55,16 @@ namespace ts.textStorage { const ts1 = new server.TextStorage(host, server.asNormalizedPath(f.path)); ts1.getSnapshot(); - assert.isTrue(!ts1.hasScriptVersionCache_TestOnly(), "should not have script version cache - 1"); + assert(!ts1.hasScriptVersionCache_TestOnly(), "should not have script version cache - 1"); ts1.edit(0, 5, " "); - assert.isTrue(ts1.hasScriptVersionCache_TestOnly(), "have script version cache - 1"); + assert(ts1.hasScriptVersionCache_TestOnly(), "have script version cache - 1"); ts1.useText(); - assert.isTrue(!ts1.hasScriptVersionCache_TestOnly(), "should not have script version cache - 2"); + assert(!ts1.hasScriptVersionCache_TestOnly(), "should not have script version cache - 2"); ts1.getLineInfo(0); - assert.isTrue(ts1.hasScriptVersionCache_TestOnly(), "have script version cache - 2"); + assert(ts1.hasScriptVersionCache_TestOnly(), "have script version cache - 2"); }); }); } diff --git a/src/harness/unittests/tscWatchMode.ts b/src/harness/unittests/tscWatchMode.ts index 8087d038b7..bab45765a9 100644 --- a/src/harness/unittests/tscWatchMode.ts +++ b/src/harness/unittests/tscWatchMode.ts @@ -80,20 +80,47 @@ namespace ts.tscWatch { checkOutputDoesNotContain(host, expectedNonAffectedFiles); } - function checkOutputErrors(host: WatchedSystem, errors: ReadonlyArray, isInitial?: true, skipWaiting?: true) { + enum ExpectedOutputErrorsPosition { + BeforeCompilationStarts, + AfterCompilationStarting, + AfterFileChangeDetected + } + + function checkOutputErrors( + host: WatchedSystem, + errors: ReadonlyArray, + errorsPosition: ExpectedOutputErrorsPosition, + skipWaiting?: true + ) { const outputs = host.getOutput(); - const expectedOutputCount = (isInitial ? 0 : 1) + errors.length + (skipWaiting ? 0 : 1); + const expectedOutputCount = errors.length + (skipWaiting ? 0 : 1) + 1; assert.equal(outputs.length, expectedOutputCount, "Outputs = " + outputs.toString()); - let index = 0; - if (!isInitial) { - assertWatchDiagnosticAt(host, index, Diagnostics.File_change_detected_Starting_incremental_compilation); - index++; + let index: number; + + switch (errorsPosition) { + case ExpectedOutputErrorsPosition.AfterCompilationStarting: + assertWatchDiagnosticAt(host, 0, Diagnostics.Starting_compilation_in_watch_mode); + index = 1; + break; + case ExpectedOutputErrorsPosition.AfterFileChangeDetected: + assertWatchDiagnosticAt(host, 0, Diagnostics.File_change_detected_Starting_incremental_compilation); + index = 1; + break; + case ExpectedOutputErrorsPosition.BeforeCompilationStarts: + assertWatchDiagnosticAt(host, errors.length, Diagnostics.Starting_compilation_in_watch_mode); + index = 0; + break; } + forEach(errors, error => { assertDiagnosticAt(host, index, error); index++; }); if (!skipWaiting) { + if (errorsPosition === ExpectedOutputErrorsPosition.BeforeCompilationStarts) { + assertWatchDiagnosticAt(host, index, ts.Diagnostics.Starting_compilation_in_watch_mode); + index += 1; + } assertWatchDiagnosticAt(host, index, Diagnostics.Compilation_complete_Watching_for_file_changes); } host.clearOutput(); @@ -106,7 +133,7 @@ namespace ts.tscWatch { function assertWatchDiagnosticAt(host: WatchedSystem, outputAt: number, diagnosticMessage: DiagnosticMessage) { const output = host.getOutput()[outputAt]; - assert.isTrue(endsWith(output, getWatchDiagnosticWithoutDate(host, diagnosticMessage)), "outputs[" + outputAt + "] is " + output); + assert(endsWith(output, getWatchDiagnosticWithoutDate(host, diagnosticMessage)), "outputs[" + outputAt + "] is " + output); } function getWatchDiagnosticWithoutDate(host: WatchedSystem, diagnosticMessage: DiagnosticMessage) { @@ -333,13 +360,13 @@ namespace ts.tscWatch { checkOutputErrors(host, [ getDiagnosticOfFileFromProgram(watch(), file1.path, file1.content.indexOf(commonFile2Name), commonFile2Name.length, Diagnostics.File_0_not_found, commonFile2.path), getDiagnosticOfFileFromProgram(watch(), file1.path, file1.content.indexOf("y"), 1, Diagnostics.Cannot_find_name_0, "y") - ], /*isInitial*/ true); + ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); host.reloadFS([file1, commonFile2, libFile]); host.runQueuedTimeoutCallbacks(); checkProgramRootFiles(watch(), [file1.path]); checkProgramActualFiles(watch(), [file1.path, libFile.path, commonFile2.path]); - checkOutputErrors(host, emptyArray); + checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); }); it("should reflect change in config file", () => { @@ -667,7 +694,7 @@ namespace ts.tscWatch { const watch = createWatchModeWithConfigFile(config.path, host); checkProgramActualFiles(watch(), [file1.path, file2.path, libFile.path]); - checkOutputErrors(host, emptyArray, /*isInitial*/ true); + checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); host.reloadFS([file1, file2, libFile]); host.checkTimeoutQueueLengthAndRun(1); @@ -675,7 +702,7 @@ namespace ts.tscWatch { assert.equal(host.exitCode, ExitStatus.DiagnosticsPresent_OutputsSkipped); checkOutputErrors(host, [ getDiagnosticWithoutFile(Diagnostics.File_0_not_found, config.path) - ], /*isInitial*/ undefined, /*skipWaiting*/ true); + ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected, /*skipWaiting*/ true); }); it("Proper errors: document is not contained in project", () => { @@ -778,7 +805,7 @@ namespace ts.tscWatch { }; const host = createWatchedSystem([moduleFile, file1, libFile]); const watch = createWatchModeWithoutConfigFile([file1.path], host); - checkOutputErrors(host, emptyArray, /*isInitial*/ true); + checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); const moduleFileOldPath = moduleFile.path; const moduleFileNewPath = "/a/b/moduleFile1.ts"; @@ -787,12 +814,12 @@ namespace ts.tscWatch { host.runQueuedTimeoutCallbacks(); checkOutputErrors(host, [ getDiagnosticModuleNotFoundOfFile(watch(), file1, "./moduleFile") - ]); + ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); moduleFile.path = moduleFileOldPath; host.reloadFS([moduleFile, file1, libFile]); host.runQueuedTimeoutCallbacks(); - checkOutputErrors(host, emptyArray); + checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); }); it("rename a module file and rename back should restore the states for configured projects", () => { @@ -810,7 +837,7 @@ namespace ts.tscWatch { }; const host = createWatchedSystem([moduleFile, file1, configFile, libFile]); const watch = createWatchModeWithConfigFile(configFile.path, host); - checkOutputErrors(host, emptyArray, /*isInitial*/ true); + checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); const moduleFileOldPath = moduleFile.path; const moduleFileNewPath = "/a/b/moduleFile1.ts"; @@ -819,12 +846,12 @@ namespace ts.tscWatch { host.runQueuedTimeoutCallbacks(); checkOutputErrors(host, [ getDiagnosticModuleNotFoundOfFile(watch(), file1, "./moduleFile") - ]); + ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); moduleFile.path = moduleFileOldPath; host.reloadFS([moduleFile, file1, configFile, libFile]); host.runQueuedTimeoutCallbacks(); - checkOutputErrors(host, emptyArray); + checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); }); it("types should load from config file path if config exists", () => { @@ -863,11 +890,11 @@ namespace ts.tscWatch { checkOutputErrors(host, [ getDiagnosticModuleNotFoundOfFile(watch(), file1, "./moduleFile") - ], /*isInitial*/ true); + ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); host.reloadFS([file1, moduleFile, libFile]); host.runQueuedTimeoutCallbacks(); - checkOutputErrors(host, emptyArray); + checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); }); it("Configure file diagnostics events are generated when the config file has errors", () => { @@ -890,7 +917,7 @@ namespace ts.tscWatch { checkOutputErrors(host, [ getUnknownCompilerOption(watch(), configFile, "foo"), getUnknownCompilerOption(watch(), configFile, "allowJS") - ], /*isInitial*/ true); + ], /*errorsPosition*/ ExpectedOutputErrorsPosition.BeforeCompilationStarts); }); it("If config file doesnt have errors, they are not reported", () => { @@ -907,7 +934,7 @@ namespace ts.tscWatch { const host = createWatchedSystem([file, configFile, libFile]); createWatchModeWithConfigFile(configFile.path, host); - checkOutputErrors(host, emptyArray, /*isInitial*/ true); + checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); }); it("Reports errors when the config file changes", () => { @@ -924,7 +951,7 @@ namespace ts.tscWatch { const host = createWatchedSystem([file, configFile, libFile]); const watch = createWatchModeWithConfigFile(configFile.path, host); - checkOutputErrors(host, emptyArray, /*isInitial*/ true); + checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); configFile.content = `{ "compilerOptions": { @@ -935,14 +962,14 @@ namespace ts.tscWatch { host.runQueuedTimeoutCallbacks(); checkOutputErrors(host, [ getUnknownCompilerOption(watch(), configFile, "haha") - ]); + ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); configFile.content = `{ "compilerOptions": {} }`; host.reloadFS([file, configFile, libFile]); host.runQueuedTimeoutCallbacks(); - checkOutputErrors(host, emptyArray); + checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); }); it("non-existing directories listed in config file input array should be tolerated without crashing the server", () => { @@ -1030,13 +1057,13 @@ namespace ts.tscWatch { getDiagnosticOfFile(watch().getCompilerOptions().configFile, configFile.content.indexOf('"declaration"'), '"declaration"'.length, Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration") ]; const intialErrors = errors(); - checkOutputErrors(host, intialErrors, /*isInitial*/ true); + checkOutputErrors(host, intialErrors, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); configFile.content = configFileContentWithoutCommentLine; host.reloadFS(files); host.runQueuedTimeoutCallbacks(); const nowErrors = errors(); - checkOutputErrors(host, nowErrors); + checkOutputErrors(host, nowErrors, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); assert.equal(nowErrors[0].start, intialErrors[0].start - configFileContentComment.length); assert.equal(nowErrors[1].start, intialErrors[1].start - configFileContentComment.length); }); @@ -1516,11 +1543,11 @@ namespace ts.tscWatch { function verifyEmittedFiles(host: WatchedSystem, emittedFiles: EmittedFile[]) { for (const { path, content, shouldBeWritten } of emittedFiles) { if (shouldBeWritten) { - assert.isTrue(host.fileExists(path), `Expected file ${path} to be present`); + assert(host.fileExists(path), `Expected file ${path} to be present`); assert.equal(host.readFile(path), content, `Contents of file ${path} do not match`); } else { - assert.isNotTrue(host.fileExists(path), `Expected file ${path} to be absent`); + assert(!host.fileExists(path), `Expected file ${path} to be absent`); } } } @@ -1667,7 +1694,7 @@ namespace ts.tscWatch { const cannotFindFoo = getDiagnosticOfFileFromProgram(watch(), imported.path, imported.content.indexOf("foo"), "foo".length, Diagnostics.Cannot_find_name_0, "foo"); // ensure that imported file was found - checkOutputErrors(host, [f1IsNotModule, cannotFindFoo], /*isInitial*/ true); + checkOutputErrors(host, [f1IsNotModule, cannotFindFoo], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); const originalFileExists = host.fileExists; { @@ -1687,7 +1714,7 @@ namespace ts.tscWatch { f1IsNotModule, getDiagnosticOfFileFromProgram(watch(), root.path, newContent.indexOf("var x") + "var ".length, "x".length, Diagnostics.Type_0_is_not_assignable_to_type_1, 1, "string"), cannotFindFoo - ]); + ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); } { let fileExistsIsCalled = false; @@ -1696,7 +1723,7 @@ namespace ts.tscWatch { return false; } fileExistsIsCalled = true; - assert.isTrue(fileName.indexOf("/f2.") !== -1); + assert(fileName.indexOf("/f2.") !== -1); return originalFileExists.call(host, fileName); }; @@ -1709,9 +1736,9 @@ namespace ts.tscWatch { // ensure file has correct number of errors after edit checkOutputErrors(host, [ getDiagnosticModuleNotFoundOfFile(watch(), root, "f2") - ]); + ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); - assert.isTrue(fileExistsIsCalled); + assert(fileExistsIsCalled); } { let fileExistsCalled = false; @@ -1720,7 +1747,7 @@ namespace ts.tscWatch { return false; } fileExistsCalled = true; - assert.isTrue(fileName.indexOf("/f1.") !== -1); + assert(fileName.indexOf("/f1.") !== -1); return originalFileExists.call(host, fileName); }; @@ -1730,8 +1757,8 @@ namespace ts.tscWatch { host.reloadFS(files); host.runQueuedTimeoutCallbacks(); - checkOutputErrors(host, [f1IsNotModule, cannotFindFoo]); - assert.isTrue(fileExistsCalled); + checkOutputErrors(host, [f1IsNotModule, cannotFindFoo], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + assert(fileExistsCalled); } }); @@ -1764,18 +1791,18 @@ namespace ts.tscWatch { const watch = createWatchModeWithoutConfigFile([root.path], host, { module: ModuleKind.AMD }); - assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called"); + assert(fileExistsCalledForBar, "'fileExists' should be called"); checkOutputErrors(host, [ getDiagnosticModuleNotFoundOfFile(watch(), root, "bar") - ], /*isInitial*/ true); + ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); fileExistsCalledForBar = false; root.content = `import {y} from "bar"`; host.reloadFS(files.concat(imported)); host.runQueuedTimeoutCallbacks(); - assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called."); - checkOutputErrors(host, emptyArray); + checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + assert(fileExistsCalledForBar, "'fileExists' should be called."); }); it("should compile correctly when resolved module goes missing and then comes back (module is not part of the root)", () => { @@ -1806,22 +1833,22 @@ namespace ts.tscWatch { const watch = createWatchModeWithoutConfigFile([root.path], host, { module: ModuleKind.AMD }); - assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called"); - checkOutputErrors(host, emptyArray, /*isInitial*/ true); + assert(fileExistsCalledForBar, "'fileExists' should be called"); + checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); fileExistsCalledForBar = false; host.reloadFS(files); host.runQueuedTimeoutCallbacks(); - assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called."); + assert(fileExistsCalledForBar, "'fileExists' should be called."); checkOutputErrors(host, [ getDiagnosticModuleNotFoundOfFile(watch(), root, "bar") - ]); + ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); fileExistsCalledForBar = false; host.reloadFS(filesWithImported); host.checkTimeoutQueueLengthAndRun(1); - assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called."); - checkOutputErrors(host, emptyArray); + checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + assert(fileExistsCalledForBar, "'fileExists' should be called."); }); it("works when module resolution changes to ambient module", () => { @@ -1857,11 +1884,11 @@ declare module "fs" { checkOutputErrors(host, [ getDiagnosticModuleNotFoundOfFile(watch(), root, "fs") - ], /*isInitial*/ true); + ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); host.reloadFS(filesWithNodeType); host.runQueuedTimeoutCallbacks(); - checkOutputErrors(host, emptyArray); + checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); }); it("works when included file with ambient module changes", () => { @@ -1899,12 +1926,12 @@ declare module "fs" { checkOutputErrors(host, [ getDiagnosticModuleNotFoundOfFile(watch(), root, "fs") - ], /*isInitial*/ true); + ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); file.content += fileContentWithFS; host.reloadFS(files); host.runQueuedTimeoutCallbacks(); - checkOutputErrors(host, emptyArray); + checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); }); it("works when reusing program with files from external library", () => { @@ -1939,7 +1966,7 @@ declare module "fs" { const host = createWatchedSystem(programFiles.concat(configFile), { currentDirectory: "/a/b/projects/myProject/" }); const watch = createWatchModeWithConfigFile(configFile.path, host); checkProgramActualFiles(watch(), programFiles.map(f => f.path)); - checkOutputErrors(host, emptyArray, /*isInitial*/ true); + checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); const expectedFiles: ExpectedFile[] = [ createExpectedEmittedFile(file1), createExpectedEmittedFile(file2), @@ -1958,7 +1985,7 @@ declare module "fs" { host.reloadFS(programFiles.concat(configFile)); host.runQueuedTimeoutCallbacks(); checkProgramActualFiles(watch(), programFiles.map(f => f.path)); - checkOutputErrors(host, emptyArray); + checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); verifyExpectedFiles(expectedFiles); @@ -2023,13 +2050,13 @@ declare module "fs" { checkProgramActualFiles(watch(), mapDefined(files, f => f === configFile ? undefined : f.path)); const outputFile1 = changeExtension((outputFolder + getBaseFileName(file1.path)), ".js"); - assert.isTrue(host.fileExists(outputFile1)); + assert(host.fileExists(outputFile1)); assert.equal(host.readFile(outputFile1), file1.content + host.newLine); }); }); describe("tsc-watch console clearing", () => { - it("doesn't clear the console when it starts", () => { + it("clears the console when it starts", () => { const file = { path: "f.ts", content: "" @@ -2039,7 +2066,7 @@ declare module "fs" { createWatchModeWithoutConfigFile([file.path], host); host.runQueuedTimeoutCallbacks(); - host.checkScreenClears(0); + host.checkScreenClears(1); }); it("clears the console on recompile", () => { @@ -2057,7 +2084,7 @@ declare module "fs" { host.reloadFS([modifiedFile]); host.runQueuedTimeoutCallbacks(); - host.checkScreenClears(1); + host.checkScreenClears(2); }); }); } diff --git a/src/harness/unittests/tsconfigParsing.ts b/src/harness/unittests/tsconfigParsing.ts index 8d56360bba..0f03b5630b 100644 --- a/src/harness/unittests/tsconfigParsing.ts +++ b/src/harness/unittests/tsconfigParsing.ts @@ -11,20 +11,20 @@ namespace ts { function assertParseError(jsonText: string) { const parsed = ts.parseConfigFileTextToJson("/apath/tsconfig.json", jsonText); assert.deepEqual(parsed.config, {}); - assert.isTrue(undefined !== parsed.error); + assert(undefined !== parsed.error); } function assertParseErrorWithExcludesKeyword(jsonText: string) { { const parsed = ts.parseConfigFileTextToJson("/apath/tsconfig.json", jsonText); const parsedCommand = ts.parseJsonConfigFileContent(parsed.config, ts.sys, "tests/cases/unittests"); - assert.isTrue(parsedCommand.errors && parsedCommand.errors.length === 1 && + assert(parsedCommand.errors && parsedCommand.errors.length === 1 && parsedCommand.errors[0].code === ts.Diagnostics.Unknown_option_excludes_Did_you_mean_exclude.code); } { const parsed = ts.parseJsonText("/apath/tsconfig.json", jsonText); const parsedCommand = ts.parseJsonSourceFileConfigFileContent(parsed, ts.sys, "tests/cases/unittests"); - assert.isTrue(parsedCommand.errors && parsedCommand.errors.length === 1 && + assert(parsedCommand.errors && parsedCommand.errors.length === 1 && parsedCommand.errors[0].code === ts.Diagnostics.Unknown_option_excludes_Did_you_mean_exclude.code); } } @@ -44,26 +44,26 @@ namespace ts { function assertParseFileList(jsonText: string, configFileName: string, basePath: string, allFileList: string[], expectedFileList: string[]) { { const parsed = getParsedCommandJson(jsonText, configFileName, basePath, allFileList); - assert.isTrue(arrayIsEqualTo(parsed.fileNames.sort(), expectedFileList.sort())); + assert(arrayIsEqualTo(parsed.fileNames.sort(), expectedFileList.sort())); } { const parsed = getParsedCommandJsonNode(jsonText, configFileName, basePath, allFileList); - assert.isTrue(arrayIsEqualTo(parsed.fileNames.sort(), expectedFileList.sort())); + assert(arrayIsEqualTo(parsed.fileNames.sort(), expectedFileList.sort())); } } function assertParseFileDiagnostics(jsonText: string, configFileName: string, basePath: string, allFileList: string[], expectedDiagnosticCode: number, noLocation?: boolean) { { const parsed = getParsedCommandJson(jsonText, configFileName, basePath, allFileList); - assert.isTrue(parsed.errors.length >= 0); - assert.isTrue(parsed.errors.filter(e => e.code === expectedDiagnosticCode).length > 0, `Expected error code ${expectedDiagnosticCode} to be in ${JSON.stringify(parsed.errors)}`); + assert(parsed.errors.length >= 0); + assert(parsed.errors.filter(e => e.code === expectedDiagnosticCode).length > 0, `Expected error code ${expectedDiagnosticCode} to be in ${JSON.stringify(parsed.errors)}`); } { const parsed = getParsedCommandJsonNode(jsonText, configFileName, basePath, allFileList); - assert.isTrue(parsed.errors.length >= 0); - assert.isTrue(parsed.errors.filter(e => e.code === expectedDiagnosticCode).length > 0, `Expected error code ${expectedDiagnosticCode} to be in ${JSON.stringify(parsed.errors)}`); + assert(parsed.errors.length >= 0); + assert(parsed.errors.filter(e => e.code === expectedDiagnosticCode).length > 0, `Expected error code ${expectedDiagnosticCode} to be in ${JSON.stringify(parsed.errors)}`); if (!noLocation) { - assert.isTrue(parsed.errors.filter(e => e.code === expectedDiagnosticCode && e.file && e.start && e.length).length > 0, `Expected error code ${expectedDiagnosticCode} to be in ${JSON.stringify(parsed.errors)} with location information`); + assert(parsed.errors.filter(e => e.code === expectedDiagnosticCode && e.file && e.start && e.length).length > 0, `Expected error code ${expectedDiagnosticCode} to be in ${JSON.stringify(parsed.errors)} with location information`); } } } @@ -241,7 +241,7 @@ namespace ts { }, files: ["file1.ts"] }; - assert.isTrue(diagnostics.length === 2); + assert(diagnostics.length === 2); assert.equal(JSON.stringify(configJsonObject), JSON.stringify(expectedResult)); }); diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index 8e0dfe36c2..39dde23b28 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -468,12 +468,12 @@ namespace ts.projectSystem { assert.equal(outputs[index], server.formatMessage(expectedEvent, nullLogger, Utils.byteLength, session.host.newLine)); if (isMostRecent) { - assert.strictEqual(events.length, index + 1, JSON.stringify(events)); - assert.strictEqual(outputs.length, index + 1, JSON.stringify(outputs)); + assert.equal(events.length, index + 1, JSON.stringify(events)); + assert.equal(outputs.length, index + 1, JSON.stringify(outputs)); } } - describe("tsserverProjectSystem", () => { + describe("tsserverProjectSystem general functionality", () => { const commonFile1: FileOrFolder = { path: "/a/b/commonFile1.ts", content: "let x = 1" @@ -572,8 +572,8 @@ namespace ts.projectSystem { const projectService = createProjectService(host); const { configFileName, configFileErrors } = projectService.openClientFile(file1.path); - assert(configFileName, "should find config file"); - assert.isTrue(!configFileErrors || configFileErrors.length === 0, `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`); + assert.isDefined(configFileName, "should find config file"); + assert(!configFileErrors || configFileErrors.length === 0, `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`); checkNumberOfInferredProjects(projectService, 0); checkNumberOfConfiguredProjects(projectService, 1); @@ -612,8 +612,8 @@ namespace ts.projectSystem { const projectService = createProjectService(host); const { configFileName, configFileErrors } = projectService.openClientFile(file1.path); - assert(configFileName, "should find config file"); - assert.isTrue(!configFileErrors || configFileErrors.length === 0, `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`); + assert.isDefined(configFileName, "should find config file"); + assert(!configFileErrors || configFileErrors.length === 0, `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`); checkNumberOfInferredProjects(projectService, 0); checkNumberOfConfiguredProjects(projectService, 1); @@ -821,7 +821,7 @@ namespace ts.projectSystem { host.reloadFS([file1, commonFile2, libFile]); host.runQueuedTimeoutCallbacks(); checkNumberOfInferredProjects(projectService, 1); - assert.strictEqual(projectService.inferredProjects[0], project, "Inferred project should be same"); + assert.equal(projectService.inferredProjects[0], project, "Inferred project should be same"); checkProjectRootFiles(project, [file1.path]); checkProjectActualFiles(project, [file1.path, libFile.path, commonFile2.path]); diags = session.executeCommand(getErrRequest).response as server.protocol.Diagnostic[]; @@ -1024,11 +1024,11 @@ namespace ts.projectSystem { projectService.openExternalProject({ rootFiles: toExternalFiles([file1.path]), options: {}, projectFileName: proj1name }); const proj1 = projectService.findProject(proj1name); - assert.isTrue(proj1.languageServiceEnabled); + assert(proj1.languageServiceEnabled); projectService.openExternalProject({ rootFiles: toExternalFiles([file2.path]), options: {}, projectFileName: proj2name }); const proj2 = projectService.findProject(proj2name); - assert.isTrue(proj2.languageServiceEnabled); + assert(proj2.languageServiceEnabled); projectService.openExternalProject({ rootFiles: toExternalFiles([file3.path]), options: {}, projectFileName: proj3name }); const proj3 = projectService.findProject(proj3name); @@ -1100,18 +1100,18 @@ namespace ts.projectSystem { projectService.openClientFile(file1.path); checkNumberOfConfiguredProjects(projectService, 1); const project = projectService.configuredProjects.get(configFile.path); - assert.isTrue(project.hasOpenRef()); // file1 + assert(project.hasOpenRef()); // file1 projectService.closeClientFile(file1.path); checkNumberOfConfiguredProjects(projectService, 1); - assert.strictEqual(projectService.configuredProjects.get(configFile.path), project); + assert.equal(projectService.configuredProjects.get(configFile.path), project); assert.isFalse(project.hasOpenRef()); // No open files assert.isFalse(project.isClosed()); projectService.openClientFile(file2.path); checkNumberOfConfiguredProjects(projectService, 1); - assert.strictEqual(projectService.configuredProjects.get(configFile.path), project); - assert.isTrue(project.hasOpenRef()); // file2 + assert.equal(projectService.configuredProjects.get(configFile.path), project); + assert(project.hasOpenRef()); // file2 assert.isFalse(project.isClosed()); }); @@ -1134,18 +1134,18 @@ namespace ts.projectSystem { projectService.openClientFile(file1.path); checkNumberOfConfiguredProjects(projectService, 1); const project = projectService.configuredProjects.get(configFile.path); - assert.isTrue(project.hasOpenRef()); // file1 + assert(project.hasOpenRef()); // file1 projectService.closeClientFile(file1.path); checkNumberOfConfiguredProjects(projectService, 1); - assert.strictEqual(projectService.configuredProjects.get(configFile.path), project); + assert.equal(projectService.configuredProjects.get(configFile.path), project); assert.isFalse(project.hasOpenRef()); // No files assert.isFalse(project.isClosed()); projectService.openClientFile(libFile.path); checkNumberOfConfiguredProjects(projectService, 0); assert.isFalse(project.hasOpenRef()); // No files + project closed - assert.isTrue(project.isClosed()); + assert(project.isClosed()); }); it("should not close external project with no open files", () => { @@ -1233,28 +1233,28 @@ namespace ts.projectSystem { // open client file - should not lead to creation of inferred project projectService.openClientFile(file1.path, file1.content); checkNumberOfProjects(projectService, { configuredProjects: 2 }); - assert.strictEqual(projectService.configuredProjects.get(config1.path), proj1); - assert.strictEqual(projectService.configuredProjects.get(config2.path), proj2); + assert.equal(projectService.configuredProjects.get(config1.path), proj1); + assert.equal(projectService.configuredProjects.get(config2.path), proj2); projectService.openClientFile(file3.path, file3.content); checkNumberOfProjects(projectService, { configuredProjects: 2, inferredProjects: 1 }); - assert.strictEqual(projectService.configuredProjects.get(config1.path), proj1); - assert.strictEqual(projectService.configuredProjects.get(config2.path), proj2); + assert.equal(projectService.configuredProjects.get(config1.path), proj1); + assert.equal(projectService.configuredProjects.get(config2.path), proj2); projectService.closeExternalProject(externalProjectName); // open file 'file1' from configured project keeps project alive checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 1 }); - assert.strictEqual(projectService.configuredProjects.get(config1.path), proj1); + assert.equal(projectService.configuredProjects.get(config1.path), proj1); assert.isUndefined(projectService.configuredProjects.get(config2.path)); projectService.closeClientFile(file3.path); checkNumberOfProjects(projectService, { configuredProjects: 1 }); - assert.strictEqual(projectService.configuredProjects.get(config1.path), proj1); + assert.equal(projectService.configuredProjects.get(config1.path), proj1); assert.isUndefined(projectService.configuredProjects.get(config2.path)); projectService.closeClientFile(file1.path); checkNumberOfProjects(projectService, { configuredProjects: 1 }); - assert.strictEqual(projectService.configuredProjects.get(config1.path), proj1); + assert.equal(projectService.configuredProjects.get(config1.path), proj1); assert.isUndefined(projectService.configuredProjects.get(config2.path)); projectService.openClientFile(file2.path, file2.content); @@ -1286,14 +1286,14 @@ namespace ts.projectSystem { const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 2, { includeExternalModuleExports: false }); // should contain completions for string - assert.isTrue(completions1.entries.some(e => e.name === "charAt"), "should contain 'charAt'"); + assert(completions1.entries.some(e => e.name === "charAt"), "should contain 'charAt'"); assert.isFalse(completions1.entries.some(e => e.name === "toExponential"), "should not contain 'toExponential'"); service.closeClientFile(f2.path); const completions2 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 2, { includeExternalModuleExports: false }); // should contain completions for string assert.isFalse(completions2.entries.some(e => e.name === "charAt"), "should not contain 'charAt'"); - assert.isTrue(completions2.entries.some(e => e.name === "toExponential"), "should contain 'toExponential'"); + assert(completions2.entries.some(e => e.name === "toExponential"), "should contain 'toExponential'"); }); it("clear mixed content file after closing", () => { @@ -1317,7 +1317,7 @@ namespace ts.projectSystem { checkProjectActualFiles(service.externalProjects[0], [f1.path, f2.path, libFile.path]); const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 0, { includeExternalModuleExports: false }); - assert.isTrue(completions1.entries.some(e => e.name === "somelongname"), "should contain 'somelongname'"); + assert(completions1.entries.some(e => e.name === "somelongname"), "should contain 'somelongname'"); service.closeClientFile(f2.path); const completions2 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 0, { includeExternalModuleExports: false }); @@ -1387,16 +1387,16 @@ namespace ts.projectSystem { }); checkNumberOfProjects(projectService, { configuredProjects: 1 }); - assert.strictEqual(projectService.configuredProjects.get(configFile.path), project); + assert.equal(projectService.configuredProjects.get(configFile.path), project); projectService.closeExternalProject(externalProjectName); // configured project is alive since file is still open checkNumberOfProjects(projectService, { configuredProjects: 1 }); - assert.strictEqual(projectService.configuredProjects.get(configFile.path), project); + assert.equal(projectService.configuredProjects.get(configFile.path), project); projectService.closeClientFile(file1.path); checkNumberOfProjects(projectService, { configuredProjects: 1 }); - assert.strictEqual(projectService.configuredProjects.get(configFile.path), project); + assert.equal(projectService.configuredProjects.get(configFile.path), project); projectService.openClientFile(file2.path); checkNumberOfProjects(projectService, { inferredProjects: 1 }); @@ -1910,7 +1910,7 @@ namespace ts.projectSystem { // The configured project should now be updated to include html file checkNumberOfProjects(projectService, { configuredProjects: 1 }); - assert.strictEqual(configuredProjectAt(projectService, 0), configuredProj, "Same configured project should be updated"); + assert.equal(configuredProjectAt(projectService, 0), configuredProj, "Same configured project should be updated"); checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path, config.path]); // Open HTML file @@ -2176,18 +2176,18 @@ namespace ts.projectSystem { projectService.openClientFile(file2.path); checkNumberOfProjects(projectService, { configuredProjects: 1 }); const project1 = projectService.configuredProjects.get(tsconfig1.path); - assert.isTrue(project1.hasOpenRef(), "Has open ref count in project1 - 1"); // file2 + assert(project1.hasOpenRef(), "Has open ref count in project1 - 1"); // file2 assert.equal(project1.getScriptInfo(file2.path).containingProjects.length, 1, "containing projects count"); assert.isFalse(project1.isClosed()); projectService.openClientFile(file1.path); checkNumberOfProjects(projectService, { configuredProjects: 2 }); - assert.isTrue(project1.hasOpenRef(), "Has open ref count in project1 - 2"); // file2 - assert.strictEqual(projectService.configuredProjects.get(tsconfig1.path), project1); + assert(project1.hasOpenRef(), "Has open ref count in project1 - 2"); // file2 + assert.equal(projectService.configuredProjects.get(tsconfig1.path), project1); assert.isFalse(project1.isClosed()); const project2 = projectService.configuredProjects.get(tsconfig2.path); - assert.isTrue(project2.hasOpenRef(), "Has open ref count in project2 - 2"); // file1 + assert(project2.hasOpenRef(), "Has open ref count in project2 - 2"); // file1 assert.isFalse(project2.isClosed()); assert.equal(project1.getScriptInfo(file1.path).containingProjects.length, 2, `${file1.path} containing projects count`); @@ -2196,9 +2196,9 @@ namespace ts.projectSystem { projectService.closeClientFile(file2.path); checkNumberOfProjects(projectService, { configuredProjects: 2 }); assert.isFalse(project1.hasOpenRef(), "Has open ref count in project1 - 3"); // No files - assert.isTrue(project2.hasOpenRef(), "Has open ref count in project2 - 3"); // file1 - assert.strictEqual(projectService.configuredProjects.get(tsconfig1.path), project1); - assert.strictEqual(projectService.configuredProjects.get(tsconfig2.path), project2); + assert(project2.hasOpenRef(), "Has open ref count in project2 - 3"); // file1 + assert.equal(projectService.configuredProjects.get(tsconfig1.path), project1); + assert.equal(projectService.configuredProjects.get(tsconfig2.path), project2); assert.isFalse(project1.isClosed()); assert.isFalse(project2.isClosed()); @@ -2206,18 +2206,18 @@ namespace ts.projectSystem { checkNumberOfProjects(projectService, { configuredProjects: 2 }); assert.isFalse(project1.hasOpenRef(), "Has open ref count in project1 - 4"); // No files assert.isFalse(project2.hasOpenRef(), "Has open ref count in project2 - 4"); // No files - assert.strictEqual(projectService.configuredProjects.get(tsconfig1.path), project1); - assert.strictEqual(projectService.configuredProjects.get(tsconfig2.path), project2); + assert.equal(projectService.configuredProjects.get(tsconfig1.path), project1); + assert.equal(projectService.configuredProjects.get(tsconfig2.path), project2); assert.isFalse(project1.isClosed()); assert.isFalse(project2.isClosed()); projectService.openClientFile(file2.path); checkNumberOfProjects(projectService, { configuredProjects: 1 }); - assert.strictEqual(projectService.configuredProjects.get(tsconfig1.path), project1); + assert.equal(projectService.configuredProjects.get(tsconfig1.path), project1); assert.isUndefined(projectService.configuredProjects.get(tsconfig2.path)); - assert.isTrue(project1.hasOpenRef(), "Has open ref count in project1 - 5"); // file2 + assert(project1.hasOpenRef(), "Has open ref count in project1 - 5"); // file2 assert.isFalse(project1.isClosed()); - assert.isTrue(project2.isClosed()); + assert(project2.isClosed()); }); it("Open ref of configured project when open file gets added to the project as part of configured file update", () => { @@ -2255,7 +2255,7 @@ namespace ts.projectSystem { checkOpenFiles(projectService, files); checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 2 }); const configProject1 = projectService.configuredProjects.get(configFile.path); - assert.isTrue(configProject1.hasOpenRef()); // file1 and file3 + assert(configProject1.hasOpenRef()); // file1 and file3 checkProjectActualFiles(configProject1, [file1.path, file3.path, configFile.path]); const inferredProject1 = projectService.inferredProjects[0]; checkProjectActualFiles(inferredProject1, [file2.path]); @@ -2272,7 +2272,7 @@ namespace ts.projectSystem { checkNumberOfInferredProjects(projectService, 1); const inferredProject3 = projectService.inferredProjects[0]; checkProjectActualFiles(inferredProject3, [file4.path]); - assert.strictEqual(inferredProject3, inferredProject2); + assert.equal(inferredProject3, inferredProject2); projectService.closeClientFile(file1.path); projectService.closeClientFile(file2.path); @@ -2298,7 +2298,7 @@ namespace ts.projectSystem { checkNumberOfInferredProjects(projectService, 1); const inferredProject5 = projectService.inferredProjects[0]; checkProjectActualFiles(inferredProject4, [file4.path]); - assert.strictEqual(inferredProject5, inferredProject4); + assert.equal(inferredProject5, inferredProject4); const file5: FileOrFolder = { path: "/file5.ts", @@ -2307,13 +2307,13 @@ namespace ts.projectSystem { host.reloadFS(files.concat(configFile, file5)); projectService.openClientFile(file5.path); verifyScriptInfosAreUndefined([file1, file2, file3]); - assert.strictEqual(projectService.getScriptInfoForPath(file4.path as Path), find(infos, info => info.path === file4.path)); + assert.equal(projectService.getScriptInfoForPath(file4.path as Path), find(infos, info => info.path === file4.path)); assert.isDefined(projectService.getScriptInfoForPath(file5.path as Path)); checkOpenFiles(projectService, [file4, file5]); checkNumberOfConfiguredProjects(projectService, 0); function verifyScriptInfos() { - infos.forEach(info => assert.strictEqual(projectService.getScriptInfoForPath(info.path), info)); + infos.forEach(info => assert.equal(projectService.getScriptInfoForPath(info.path), info)); } function verifyScriptInfosAreUndefined(files: FileOrFolder[]) { @@ -2325,7 +2325,7 @@ namespace ts.projectSystem { function verifyConfiguredProjectStateAfterUpdate(hasOpenRef: boolean) { checkNumberOfConfiguredProjects(projectService, 1); const configProject2 = projectService.configuredProjects.get(configFile.path); - assert.strictEqual(configProject2, configProject1); + assert.equal(configProject2, configProject1); checkProjectActualFiles(configProject2, [file1.path, file2.path, file3.path, configFile.path]); assert.equal(configProject2.hasOpenRef(), hasOpenRef); } @@ -2364,7 +2364,7 @@ namespace ts.projectSystem { checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 1 }); const configuredProject = projectService.configuredProjects.get(configFile.path); - assert.isTrue(configuredProject.hasOpenRef()); // file1 and file3 + assert(configuredProject.hasOpenRef()); // file1 and file3 checkProjectActualFiles(configuredProject, [file1.path, file3.path, configFile.path]); const inferredProject1 = projectService.inferredProjects[0]; checkProjectActualFiles(inferredProject1, [file2.path]); @@ -2376,23 +2376,23 @@ namespace ts.projectSystem { configFile.content = "{}"; host.reloadFS(files.concat(configFile)); // Time out is not yet run so there is project update pending - assert.isTrue(configuredProject.hasOpenRef()); // Pending update and file2 might get into the project + assert(configuredProject.hasOpenRef()); // Pending update and file2 might get into the project projectService.openClientFile(file4.path); checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 2 }); - assert.strictEqual(projectService.configuredProjects.get(configFile.path), configuredProject); - assert.isTrue(configuredProject.hasOpenRef()); // Pending update and F2 might get into the project - assert.strictEqual(projectService.inferredProjects[0], inferredProject1); + assert.equal(projectService.configuredProjects.get(configFile.path), configuredProject); + assert(configuredProject.hasOpenRef()); // Pending update and F2 might get into the project + assert.equal(projectService.inferredProjects[0], inferredProject1); const inferredProject2 = projectService.inferredProjects[1]; checkProjectActualFiles(inferredProject2, [file4.path]); host.runQueuedTimeoutCallbacks(); checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 1 }); - assert.strictEqual(projectService.configuredProjects.get(configFile.path), configuredProject); - assert.isTrue(configuredProject.hasOpenRef()); // file2 + assert.equal(projectService.configuredProjects.get(configFile.path), configuredProject); + assert(configuredProject.hasOpenRef()); // file2 checkProjectActualFiles(configuredProject, [file1.path, file2.path, file3.path, configFile.path]); - assert.strictEqual(projectService.inferredProjects[0], inferredProject2); + assert.equal(projectService.inferredProjects[0], inferredProject2); checkProjectActualFiles(inferredProject2, [file4.path]); }); @@ -2427,7 +2427,7 @@ namespace ts.projectSystem { options: {} }); service.checkNumberOfProjects({ externalProjects: 1 }); - assert.isTrue(service.externalProjects[0].languageServiceEnabled, "language service should be enabled"); + assert(service.externalProjects[0].languageServiceEnabled, "language service should be enabled"); service.openExternalProject({ projectFileName, @@ -2464,12 +2464,12 @@ namespace ts.projectSystem { projectService.openClientFile(f1.path); projectService.checkNumberOfProjects({ configuredProjects: 1 }); const project = projectService.configuredProjects.get(config.path); - assert.isTrue(project.hasOpenRef()); // f1 + assert(project.hasOpenRef()); // f1 assert.isFalse(project.isClosed()); projectService.closeClientFile(f1.path); projectService.checkNumberOfProjects({ configuredProjects: 1 }); - assert.strictEqual(projectService.configuredProjects.get(config.path), project); + assert.equal(projectService.configuredProjects.get(config.path), project); assert.isFalse(project.hasOpenRef()); // No files assert.isFalse(project.isClosed()); @@ -2488,7 +2488,7 @@ namespace ts.projectSystem { projectService.openClientFile(f4.path); projectService.checkNumberOfProjects({ inferredProjects: 1 }); assert.isFalse(project.hasOpenRef()); // No files - assert.isTrue(project.isClosed()); + assert(project.isClosed()); for (const f of [f1, f2, f3]) { // All the script infos should not be present since the project is closed and orphan script infos are collected @@ -2540,7 +2540,7 @@ namespace ts.projectSystem { checkNumberOfProjects(projectService, { configuredProjects: 1 }); const project = configuredProjectAt(projectService, 0); assert.isFalse(project.languageServiceEnabled, "Language service enabled"); - assert.isTrue(!!lastEvent, "should receive event"); + assert(!!lastEvent, "should receive event"); assert.equal(lastEvent.data.project, project, "project name"); assert.equal(lastEvent.data.project.getProjectName(), config.path, "config path"); assert.isFalse(lastEvent.data.languageServiceEnabled, "Language service state"); @@ -2548,9 +2548,9 @@ namespace ts.projectSystem { host.reloadFS([f1, f2, configWithExclude]); host.checkTimeoutQueueLengthAndRun(2); checkNumberOfProjects(projectService, { configuredProjects: 1 }); - assert.isTrue(project.languageServiceEnabled, "Language service enabled"); + assert(project.languageServiceEnabled, "Language service enabled"); assert.equal(lastEvent.data.project, project, "project"); - assert.isTrue(lastEvent.data.languageServiceEnabled, "Language service state"); + assert(lastEvent.data.languageServiceEnabled, "Language service state"); }); it("syntactic features work even if language service is disabled", () => { @@ -2592,7 +2592,7 @@ namespace ts.projectSystem { checkNumberOfProjects(projectService, { configuredProjects: 1 }); const project = configuredProjectAt(projectService, 0); assert.isFalse(project.languageServiceEnabled, "Language service enabled"); - assert.isTrue(!!lastEvent, "should receive event"); + assert(!!lastEvent, "should receive event"); assert.equal(lastEvent.data.project, project, "project name"); assert.isFalse(lastEvent.data.languageServiceEnabled, "Language service state"); @@ -2747,7 +2747,7 @@ namespace ts.projectSystem { host.runQueuedTimeoutCallbacks(); watchedRecursiveDirectories.pop(); checkNumberOfProjects(projectService, { configuredProjects: 1 }); - assert.strictEqual(projectService.configuredProjects.get(configFile.path), project); + assert.equal(projectService.configuredProjects.get(configFile.path), project); checkProjectActualFiles(project, mapDefined(files, file => file === file2a ? undefined : file.path)); checkWatchedFiles(host, mapDefined(files, file => file === file1 ? undefined : file.path)); checkWatchedDirectories(host, [], /*recursive*/ false); @@ -2756,7 +2756,7 @@ namespace ts.projectSystem { // On next file open the files file2a should be closed and not watched any more projectService.openClientFile(file2.path); checkNumberOfProjects(projectService, { configuredProjects: 1 }); - assert.strictEqual(projectService.configuredProjects.get(configFile.path), project); + assert.equal(projectService.configuredProjects.get(configFile.path), project); checkProjectActualFiles(project, mapDefined(files, file => file === file2a ? undefined : file.path)); checkWatchedFiles(host, [libFile.path, configFile.path]); checkWatchedDirectories(host, [], /*recursive*/ false); @@ -2806,7 +2806,7 @@ namespace ts.projectSystem { }); - describe("Proper errors", () => { + describe("tsserverProjectSystem Proper errors", () => { it("document is not contained in project", () => { const file1 = { path: "/a/b/app.ts", @@ -2960,7 +2960,7 @@ namespace ts.projectSystem { }); }); - describe("autoDiscovery", () => { + describe("tsserverProjectSystem autoDiscovery", () => { it("does not depend on extension", () => { const file1 = { path: "/a/b/app.html", @@ -2979,11 +2979,11 @@ namespace ts.projectSystem { }); projectService.checkNumberOfProjects({ externalProjects: 1 }); const typeAcquisition = projectService.externalProjects[0].getTypeAcquisition(); - assert.isTrue(typeAcquisition.enable, "Typine acquisition should be enabled"); + assert(typeAcquisition.enable, "Typine acquisition should be enabled"); }); }); - describe("extra resolution pass in lshost", () => { + describe("tsserverProjectSystem extra resolution pass in lshost", () => { it("can load typings that are proper modules", () => { const file1 = { path: "/a/b/app.js", @@ -3025,7 +3025,7 @@ namespace ts.projectSystem { }); }); - describe("navigate-to for javascript project", () => { + describe("tsserverProjectSystem navigate-to for javascript project", () => { function containsNavToItem(items: protocol.NavtoItem[], itemName: string, itemKind: string) { return find(items, item => item.name === itemName && item.kind === itemKind) !== undefined; } @@ -3050,11 +3050,11 @@ namespace ts.projectSystem { const localFunctionNavToRequst = makeSessionRequest(CommandNames.Navto, { searchValue: "foo", file: file1.path, projectFileName: configFile.path }); const items2 = session.executeCommand(localFunctionNavToRequst).response as protocol.NavtoItem[]; - assert.isTrue(containsNavToItem(items2, "foo", "function"), `Cannot find function symbol "foo".`); + assert(containsNavToItem(items2, "foo", "function"), `Cannot find function symbol "foo".`); }); }); - describe("external projects", () => { + describe("tsserverProjectSystem external projects", () => { it("correctly handling add/remove tsconfig - 1", () => { const f1 = { path: "/a/b/app.ts", @@ -3264,23 +3264,23 @@ namespace ts.projectSystem { projectService.openClientFile(f.path); projectService.checkNumberOfProjects({ configuredProjects: 1 }); const project = projectService.configuredProjects.get(config.path); - assert.isTrue(project.hasOpenRef()); // f + assert(project.hasOpenRef()); // f projectService.closeClientFile(f.path); projectService.checkNumberOfProjects({ configuredProjects: 1 }); - assert.strictEqual(projectService.configuredProjects.get(config.path), project); + assert.equal(projectService.configuredProjects.get(config.path), project); assert.isFalse(project.hasOpenRef()); // No files assert.isFalse(project.isClosed()); projectService.openClientFile(f.path); projectService.checkNumberOfProjects({ configuredProjects: 1 }); - assert.strictEqual(projectService.configuredProjects.get(config.path), project); - assert.isTrue(project.hasOpenRef()); // f + assert.equal(projectService.configuredProjects.get(config.path), project); + assert(project.hasOpenRef()); // f assert.isFalse(project.isClosed()); }); }); - describe("prefer typings to js", () => { + describe("tsserverProjectSystem prefer typings to js", () => { it("during second resolution pass", () => { const typingsCacheLocation = "/a/typings"; const f1 = { @@ -3308,7 +3308,7 @@ namespace ts.projectSystem { }); }); - describe("format settings", () => { + describe("tsserverProjectSystem format settings", () => { it("can be set globally", () => { const f1 = { path: "/a/b/app.ts", @@ -3349,7 +3349,7 @@ namespace ts.projectSystem { }); }); - describe("watching @types", () => { + describe("tsserverProjectSystem watching @types", () => { it("works correctly when typings are added or removed", () => { const f1 = { path: "/a/b/app.ts", @@ -3395,7 +3395,7 @@ namespace ts.projectSystem { }); }); - describe("Open-file", () => { + describe("tsserverProjectSystem Open-file", () => { it("can be reloaded with empty content", () => { const f = { path: "/a/b/app.ts", @@ -3470,7 +3470,7 @@ namespace ts.projectSystem { }); }); - describe("Language service", () => { + describe("tsserverProjectSystem Language service", () => { it("should work correctly on case-sensitive file systems", () => { const lib = { path: "/a/Lib/lib.d.ts", @@ -3488,7 +3488,7 @@ namespace ts.projectSystem { }); }); - describe("rename a module file and rename back", () => { + describe("tsserverProjectSystem rename a module file and rename back", () => { it("should restore the states for inferred projects", () => { const moduleFile = { path: "/a/b/moduleFile.ts", @@ -3623,7 +3623,7 @@ namespace ts.projectSystem { }); }); - describe("add the missing module file for inferred project", () => { + describe("tsserverProjectSystem add the missing module file for inferred project", () => { it("should remove the `module not found` error", () => { const moduleFile = { path: "/a/b/moduleFile.ts", @@ -3729,7 +3729,7 @@ namespace ts.projectSystem { }); }); - describe("Configure file diagnostics events", () => { + describe("tsserverProjectSystem Configure file diagnostics events", () => { it("are generated when the config file has errors", () => { const file = { @@ -3845,7 +3845,7 @@ namespace ts.projectSystem { }); }); - describe("skipLibCheck", () => { + describe("tsserverProjectSystem skipLibCheck", () => { it("should be turned on for js-only inferred projects", () => { const file1 = { path: "/a/b/file1.js", @@ -3872,16 +3872,16 @@ namespace ts.projectSystem { { file: file2.path } ); let errorResult = session.executeCommand(file2GetErrRequest).response; - assert.isTrue(errorResult.length === 0); + assert(errorResult.length === 0); const closeFileRequest = makeSessionRequest(CommandNames.Close, { file: file1.path }); session.executeCommand(closeFileRequest); errorResult = session.executeCommand(file2GetErrRequest).response; - assert.isTrue(errorResult.length !== 0); + assert(errorResult.length !== 0); openFilesForSession([file1], session); errorResult = session.executeCommand(file2GetErrRequest).response; - assert.isTrue(errorResult.length === 0); + assert(errorResult.length === 0); }); it("should be turned on for js-only external projects", () => { @@ -3917,7 +3917,7 @@ namespace ts.projectSystem { { file: dTsFile.path } ); const errorResult = session.executeCommand(dTsFileGetErrRequest).response; - assert.isTrue(errorResult.length === 0); + assert(errorResult.length === 0); }); it("should be turned on for js-only external projects with skipLibCheck=false", () => { @@ -3953,7 +3953,7 @@ namespace ts.projectSystem { { file: dTsFile.path } ); const errorResult = session.executeCommand(dTsFileGetErrRequest).response; - assert.isTrue(errorResult.length === 0); + assert(errorResult.length === 0); }); it("should not report bind errors for declaration files with skipLibCheck=true", () => { @@ -3984,14 +3984,14 @@ namespace ts.projectSystem { { file: dTsFile1.path } ); const error1Result = session.executeCommand(dTsFile1GetErrRequest).response; - assert.isTrue(error1Result.length === 0); + assert(error1Result.length === 0); const dTsFile2GetErrRequest = makeSessionRequest( CommandNames.SemanticDiagnosticsSync, { file: dTsFile2.path } ); const error2Result = session.executeCommand(dTsFile2GetErrRequest).response; - assert.isTrue(error2Result.length === 0); + assert(error2Result.length === 0); }); it("should report semanitc errors for loose JS files with '// @ts-check' and skipLibCheck=true", () => { @@ -4012,7 +4012,7 @@ namespace ts.projectSystem { { file: jsFile.path } ); const errorResult = session.executeCommand(getErrRequest).response; - assert.isTrue(errorResult.length === 1); + assert(errorResult.length === 1); assert.equal(errorResult[0].code, Diagnostics.Operator_0_cannot_be_applied_to_types_1_and_2.code); }); @@ -4039,7 +4039,7 @@ namespace ts.projectSystem { { file: jsFile.path } ); const errorResult = session.executeCommand(getErrRequest).response; - assert.isTrue(errorResult.length === 1); + assert(errorResult.length === 1); assert.equal(errorResult[0].code, Diagnostics.Operator_0_cannot_be_applied_to_types_1_and_2.code); }); @@ -4068,12 +4068,12 @@ namespace ts.projectSystem { { file: jsFile.path } ); const errorResult = session.executeCommand(getErrRequest).response; - assert.isTrue(errorResult.length === 1); + assert(errorResult.length === 1); assert.equal(errorResult[0].code, Diagnostics.Operator_0_cannot_be_applied_to_types_1_and_2.code); }); }); - describe("non-existing directories listed in config file input array", () => { + describe("tsserverProjectSystem non-existing directories listed in config file input array", () => { it("should be tolerated without crashing the server", () => { const configFile = { path: "/a/b/tsconfig.json", @@ -4096,7 +4096,7 @@ namespace ts.projectSystem { checkNumberOfInferredProjects(projectService, 1); const inferredProject = projectService.inferredProjects[0]; - assert.isTrue(inferredProject.containsFile(file1.path)); + assert(inferredProject.containsFile(file1.path)); }); it("should be able to handle @types if input file list is empty", () => { @@ -4128,7 +4128,7 @@ namespace ts.projectSystem { }); }); - describe("reload", () => { + describe("tsserverProjectSystem reload", () => { it("should work with temp file", () => { const f1 = { path: "/a/b/app.ts", @@ -4236,7 +4236,7 @@ namespace ts.projectSystem { arguments: { file: f1.path } }); checkScriptInfoAndProjects(0, f1.content, "contents of closed file"); - assert.strictEqual(info.getSnapshot(), snap); + assert.equal(info.getSnapshot(), snap); // reload from temp file session.executeCommandSeq({ @@ -4244,7 +4244,7 @@ namespace ts.projectSystem { arguments: { file: f1.path, tmpfile: tmp.path } }); checkScriptInfoAndProjects(0, tmp.content, "contents of temp file"); - assert.notStrictEqual(info.getSnapshot(), snap); + assert.notEqual(info.getSnapshot(), snap); // reload from own file session.executeCommandSeq({ @@ -4252,11 +4252,11 @@ namespace ts.projectSystem { arguments: { file: f1.path } }); checkScriptInfoAndProjects(0, f1.content, "contents of closed file"); - assert.notStrictEqual(info.getSnapshot(), snap); + assert.notEqual(info.getSnapshot(), snap); function checkScriptInfoAndProjects(inferredProjects: number, contentsOfInfo: string, captionForContents: string) { checkNumberOfProjects(projectService, { inferredProjects }); - assert.strictEqual(projectService.getScriptInfo(f1.path), info); + assert.equal(projectService.getScriptInfo(f1.path), info); checkScriptInfoContents(contentsOfInfo, captionForContents); } @@ -4267,7 +4267,7 @@ namespace ts.projectSystem { }); }); - describe("Inferred projects", () => { + describe("tsserverProjectSystem Inferred projects", () => { it("should support files without extensions", () => { const f = { path: "/a/compile", @@ -4495,7 +4495,7 @@ namespace ts.projectSystem { }); }); - describe("No overwrite emit error", () => { + describe("tsserverProjectSystem No overwrite emit error", () => { it("for inferred project", () => { const f1 = { path: "/a/b/f1.js", @@ -4515,7 +4515,7 @@ namespace ts.projectSystem { seq: 2, arguments: { projectFileName: projectName } }).response as ReadonlyArray; - assert.isTrue(diags.length === 0); + assert(diags.length === 0); session.executeCommand({ type: "request", @@ -4529,7 +4529,7 @@ namespace ts.projectSystem { seq: 4, arguments: { projectFileName: projectName } }).response as ReadonlyArray; - assert.isTrue(diagsAfterUpdate.length === 0); + assert(diagsAfterUpdate.length === 0); }); it("for external project", () => { @@ -4556,7 +4556,7 @@ namespace ts.projectSystem { seq: 2, arguments: { projectFileName } }).response as ReadonlyArray; - assert.isTrue(diags.length === 0); + assert(diags.length === 0); session.executeCommand({ type: "request", @@ -4574,11 +4574,11 @@ namespace ts.projectSystem { seq: 4, arguments: { projectFileName } }).response as ReadonlyArray; - assert.isTrue(diagsAfterUpdate.length === 0); + assert(diagsAfterUpdate.length === 0); }); }); - describe("emit with outFile or out setting", () => { + describe("tsserverProjectSystem emit with outFile or out setting", () => { function test(opts: CompilerOptions, expectedUsesOutFile: boolean) { const f1 = { path: "/a/a.ts", @@ -4626,7 +4626,7 @@ namespace ts.projectSystem { }); }); - describe("import helpers", () => { + describe("tsserverProjectSystem import helpers", () => { it("should not crash in tsserver", () => { const f1 = { path: "/a/app.ts", @@ -4643,7 +4643,7 @@ namespace ts.projectSystem { }); }); - describe("searching for config file", () => { + describe("tsserverProjectSystem searching for config file", () => { it("should stop at projectRootPath if given", () => { const f1 = { path: "/a/file1.ts", @@ -4735,7 +4735,7 @@ namespace ts.projectSystem { }); }); - describe("cancellationToken", () => { + describe("tsserverProjectSystem cancellationToken", () => { // Disable sourcemap support for the duration of the test, as sourcemapping the errors generated during this test is slow and not something we care to test let oldPrepare: ts.AnyFunction; before(() => { @@ -4758,7 +4758,7 @@ namespace ts.projectSystem { isCancellationRequested: () => false, setRequest: requestId => { if (expectedRequestId === undefined) { - assert.isTrue(false, "unexpected call"); + assert(false, "unexpected call"); } assert.equal(requestId, expectedRequestId); }, @@ -4998,7 +4998,7 @@ namespace ts.projectSystem { }); }); - describe("occurence highlight on string", () => { + describe("tsserverProjectSystem occurence highlight on string", () => { it("should be marked if only on string values", () => { const file1: FileOrFolder = { path: "/a/b/file1.ts", @@ -5017,7 +5017,7 @@ namespace ts.projectSystem { ); const highlightResponse = session.executeCommand(highlightRequest).response as protocol.OccurrencesResponseItem[]; const firstOccurence = highlightResponse[0]; - assert.isTrue(firstOccurence.isInString, "Highlights should be marked with isInString"); + assert(firstOccurence.isInString, "Highlights should be marked with isInString"); } { @@ -5026,7 +5026,7 @@ namespace ts.projectSystem { { file: file1.path, line: 3, offset: 13 } ); const highlightResponse = session.executeCommand(highlightRequest).response as protocol.OccurrencesResponseItem[]; - assert.isTrue(highlightResponse.length === 2); + assert(highlightResponse.length === 2); const firstOccurence = highlightResponse[0]; assert.isUndefined(firstOccurence.isInString, "Highlights should not be marked with isInString if on property name"); } @@ -5037,14 +5037,14 @@ namespace ts.projectSystem { { file: file1.path, line: 4, offset: 14 } ); const highlightResponse = session.executeCommand(highlightRequest).response as protocol.OccurrencesResponseItem[]; - assert.isTrue(highlightResponse.length === 2); + assert(highlightResponse.length === 2); const firstOccurence = highlightResponse[0]; assert.isUndefined(firstOccurence.isInString, "Highlights should not be marked with isInString if on indexer"); } }); }); - describe("maxNodeModuleJsDepth for inferred projects", () => { + describe("tsserverProjectSystem maxNodeModuleJsDepth for inferred projects", () => { it("should be set to 2 if the project has js root files", () => { const file1: FileOrFolder = { path: "/a/b/file1.js", @@ -5061,13 +5061,13 @@ namespace ts.projectSystem { let project = projectService.inferredProjects[0]; let options = project.getCompilationSettings(); - assert.isTrue(options.maxNodeModuleJsDepth === 2); + assert(options.maxNodeModuleJsDepth === 2); // Assert the option sticks projectService.setCompilerOptionsForInferredProjects({ target: ScriptTarget.ES2016 }); project = projectService.inferredProjects[0]; options = project.getCompilationSettings(); - assert.isTrue(options.maxNodeModuleJsDepth === 2); + assert(options.maxNodeModuleJsDepth === 2); }); it("should return to normal state when all js root files are removed from project", () => { @@ -5090,7 +5090,7 @@ namespace ts.projectSystem { projectService.openClientFile(file2.path); project = projectService.inferredProjects[0]; - assert.isTrue(project.getCompilationSettings().maxNodeModuleJsDepth === 2); + assert(project.getCompilationSettings().maxNodeModuleJsDepth === 2); projectService.closeClientFile(file2.path); project = projectService.inferredProjects[0]; @@ -5098,7 +5098,7 @@ namespace ts.projectSystem { }); }); - describe("Options Diagnostic locations reported correctly with changes in configFile contents", () => { + describe("tsserverProjectSystem Options Diagnostic locations reported correctly with changes in configFile contents", () => { it("when options change", () => { const file = { path: "/a/b/app.ts", @@ -5134,7 +5134,7 @@ namespace ts.projectSystem { seq: 2, arguments: { file: configFile.path, projectFileName: projectName, includeLinePosition: true } }).response as ReadonlyArray; - assert.isTrue(diags.length === 2); + assert(diags.length === 2); configFile.content = configFileContentWithoutCommentLine; host.reloadFS([file, configFile]); @@ -5145,7 +5145,7 @@ namespace ts.projectSystem { seq: 2, arguments: { file: configFile.path, projectFileName: projectName, includeLinePosition: true } }).response as ReadonlyArray; - assert.isTrue(diagsAfterEdit.length === 2); + assert(diagsAfterEdit.length === 2); verifyDiagnostic(diags[0], diagsAfterEdit[0]); verifyDiagnostic(diags[1], diagsAfterEdit[1]); @@ -5162,7 +5162,7 @@ namespace ts.projectSystem { }); }); - describe("refactors", () => { + describe("tsserverProjectSystem refactors", () => { it("use formatting options", () => { const file = { path: "/a.ts", @@ -5218,7 +5218,7 @@ namespace ts.projectSystem { }); }); - describe("CachingFileSystemInformation", () => { + describe("tsserverProjectSystem CachingFileSystemInformation", () => { enum CalledMapsWithSingleArg { fileExists = "fileExists", directoryExists = "directoryExists", @@ -5271,7 +5271,7 @@ namespace ts.projectSystem { function verifyCalledOn(callback: CalledMaps, name: string) { const calledMap = calledMaps[callback]; const result = calledMap.get(name); - assert.isTrue(result && !!result.length, `${callback} should be called with name: ${name}: ${arrayFrom(calledMap.keys())}`); + assert(result && !!result.length, `${callback} should be called with name: ${name}: ${arrayFrom(calledMap.keys())}`); } function verifyNoCall(callback: CalledMaps) { @@ -5283,7 +5283,7 @@ namespace ts.projectSystem { const calledMap = calledMaps[callback]; ts.TestFSWithWatch.verifyMapSize(callback, calledMap, arrayFrom(expectedKeys.keys())); expectedKeys.forEach((called, name) => { - assert.isTrue(calledMap.has(name), `${callback} is expected to contain ${name}, actual keys: ${arrayFrom(calledMap.keys())}`); + assert(calledMap.has(name), `${callback} is expected to contain ${name}, actual keys: ${arrayFrom(calledMap.keys())}`); assert.equal(calledMap.get(name).length, called, `${callback} is expected to be called ${called} times with ${name}. Actual entry: ${calledMap.get(name)}`); }); } @@ -5356,10 +5356,10 @@ namespace ts.projectSystem { try { // trigger synchronization to make sure that LSHost will try to find 'f2' module on disk verifyImportedDiagnostics(); - assert.isTrue(false, `should not find file '${imported.path}'`); + assert(false, `should not find file '${imported.path}'`); } catch (e) { - assert.isTrue(e.message.indexOf(`Could not find file: '${imported.path}'.`) === 0); + assert(e.message.indexOf(`Could not find file: '${imported.path}'.`) === 0); } const f2Lookups = getLocationsForModuleLookup("f2"); callsTrackingHost.verifyCalledOnEachEntryNTimes(CalledMapsWithSingleArg.fileExists, f2Lookups, 1); @@ -5544,7 +5544,7 @@ namespace ts.projectSystem { callsTrackingHost.verifyNoHostCallsExceptFileExistsOnce(["/a/b/models/tsconfig.json", "/a/b/models/jsconfig.json"]); checkNumberOfConfiguredProjects(projectService, 1); - assert.strictEqual(projectService.configuredProjects.get(tsconfigFile.path), project); + assert.equal(projectService.configuredProjects.get(tsconfigFile.path), project); }); describe("WatchDirectories for config file with", () => { @@ -5631,7 +5631,7 @@ namespace ts.projectSystem { callsTrackingHost.verifyNoCall(CalledMapsWithFiveArgs.readDirectory); checkNumberOfConfiguredProjects(projectService, 1); - assert.strictEqual(projectService.configuredProjects.get(canonicalConfigPath), project); + assert.equal(projectService.configuredProjects.get(canonicalConfigPath), project); verifyProjectAndWatchedDirectories(); callsTrackingHost.clear(); @@ -5640,7 +5640,7 @@ namespace ts.projectSystem { assert.equal(configFile2, configFileName); checkNumberOfConfiguredProjects(projectService, 1); - assert.strictEqual(projectService.configuredProjects.get(canonicalConfigPath), project); + assert.equal(projectService.configuredProjects.get(canonicalConfigPath), project); verifyProjectAndWatchedDirectories(); callsTrackingHost.verifyNoHostCalls(); @@ -5835,14 +5835,14 @@ namespace ts.projectSystem { }); }); - describe("ProjectsChangedInBackground", () => { + describe("tsserverProjectSystem ProjectsChangedInBackground", () => { function verifyFiles(caption: string, actual: ReadonlyArray, expected: ReadonlyArray) { assert.equal(actual.length, expected.length, `Incorrect number of ${caption}. Actual: ${actual} Expected: ${expected}`); const seen = createMap(); forEach(actual, f => { assert.isFalse(seen.has(f), `${caption}: Found duplicate ${f}. Actual: ${actual} Expected: ${expected}`); seen.set(f, true); - assert.isTrue(contains(expected, f), `${caption}: Expected not to contain ${f}. Actual: ${actual} Expected: ${expected}`); + assert(contains(expected, f), `${caption}: Expected not to contain ${f}. Actual: ${actual} Expected: ${expected}`); }); } @@ -6313,7 +6313,7 @@ namespace ts.projectSystem { else { // file2 addition wont be detected projectFiles.pop(); - assert.isTrue(host.fileExists(file2.path)); + assert(host.fileExists(file2.path)); } verifyProject(); @@ -6380,7 +6380,7 @@ namespace ts.projectSystem { assert.equal(projectChangedEvents.length, expectedEvents.length, `Incorrect number of events Actual: ${eventsToString(projectChangedEvents)} Expected: ${eventsToString(expectedEvents)}`); forEach(projectChangedEvents, (actualEvent, i) => { const expectedEvent = expectedEvents[i]; - assert.strictEqual(actualEvent.eventName, expectedEvent.eventName); + assert.equal(actualEvent.eventName, expectedEvent.eventName); verifyFiles("openFiles", actualEvent.data.openFiles, expectedEvent.data.openFiles); }); @@ -6431,7 +6431,7 @@ namespace ts.projectSystem { }); }); - describe("Watched recursive directories with windows style file system", () => { + describe("tsserverProjectSystem Watched recursive directories with windows style file system", () => { function verifyWatchedDirectories(useProjectAtRoot: boolean) { const root = useProjectAtRoot ? "c:/" : "c:/myfolder/allproject/"; const configFile: FileOrFolder = { diff --git a/src/harness/unittests/typingsInstaller.ts b/src/harness/unittests/typingsInstaller.ts index d0038902ae..adf99094f7 100644 --- a/src/harness/unittests/typingsInstaller.ts +++ b/src/harness/unittests/typingsInstaller.ts @@ -292,7 +292,7 @@ namespace ts.projectSystem { typeAcquisition: { enable: true, include: ["jquery"] } }); - assert.isTrue(enqueueIsCalled, "expected enqueueIsCalled to be true"); + assert(enqueueIsCalled, "expected enqueueIsCalled to be true"); installer.installAll(/*expectedCount*/ 1); // auto is set in type acquisition - use it even if project contains only .ts files @@ -598,7 +598,7 @@ namespace ts.projectSystem { installer.executePendingCommands(); // expected all typings file to exist for (const f of typingFiles) { - assert.isTrue(host.fileExists(f.path), `expected file ${f.path} to exist`); + assert(host.fileExists(f.path), `expected file ${f.path} to exist`); } host.checkTimeoutQueueLengthAndRun(2); checkNumberOfProjects(projectService, { externalProjects: 1 }); @@ -934,8 +934,8 @@ namespace ts.projectSystem { installer.installAll(/*expectedCount*/1); - assert.isTrue(host.fileExists(node.path), "typings for 'node' should be created"); - assert.isTrue(host.fileExists(commander.path), "typings for 'commander' should be created"); + assert(host.fileExists(node.path), "typings for 'node' should be created"); + assert(host.fileExists(commander.path), "typings for 'commander' should be created"); checkProjectActualFiles(service.inferredProjects[0], [file.path, node.path, commander.path]); }); @@ -1076,7 +1076,7 @@ namespace ts.projectSystem { projectService.openClientFile(f1.path); installer.checkPendingCommands(/*expectedCount*/ 0); - assert.isTrue(messages.indexOf("Package name '; say ‘Hello from TypeScript!’ #' contains non URI safe characters") > 0, "should find package with invalid name"); + assert(messages.indexOf("Package name '; say ‘Hello from TypeScript!’ #' contains non URI safe characters") > 0, "should find package with invalid name"); }); }); @@ -1225,7 +1225,7 @@ namespace ts.projectSystem { installer.installAll(/*expectedCount*/ 1); - assert.isTrue(seenTelemetryEvent); + assert(seenTelemetryEvent); host.checkTimeoutQueueLengthAndRun(2); checkNumberOfProjects(projectService, { inferredProjects: 1 }); checkProjectActualFiles(projectService.inferredProjects[0], [f1.path, commander.path]); @@ -1276,10 +1276,10 @@ namespace ts.projectSystem { installer.installAll(/*expectedCount*/ 1); - assert.isTrue(!!beginEvent); - assert.isTrue(!!endEvent); - assert.isTrue(beginEvent.eventId === endEvent.eventId); - assert.isTrue(endEvent.installSuccess); + assert(!!beginEvent); + assert(!!endEvent); + assert(beginEvent.eventId === endEvent.eventId); + assert(endEvent.installSuccess); host.checkTimeoutQueueLengthAndRun(2); checkNumberOfProjects(projectService, { inferredProjects: 1 }); checkProjectActualFiles(projectService.inferredProjects[0], [f1.path, commander.path]); @@ -1322,9 +1322,9 @@ namespace ts.projectSystem { installer.installAll(/*expectedCount*/ 1); - assert.isTrue(!!beginEvent); - assert.isTrue(!!endEvent); - assert.isTrue(beginEvent.eventId === endEvent.eventId); + assert(!!beginEvent); + assert(!!endEvent); + assert(beginEvent.eventId === endEvent.eventId); assert.isFalse(endEvent.installSuccess); checkNumberOfProjects(projectService, { inferredProjects: 1 }); checkProjectActualFiles(projectService.inferredProjects[0], [f1.path]); diff --git a/src/harness/unittests/versionCache.ts b/src/harness/unittests/versionCache.ts index bbd23f25da..60b478d486 100644 --- a/src/harness/unittests/versionCache.ts +++ b/src/harness/unittests/versionCache.ts @@ -34,7 +34,7 @@ var p:Point=new Point(); var q:Point=p;`; const { lines } = server.LineIndex.linesFromText(testContent); - assert.isTrue(lines.length > 0, "Failed to initialize test text. Expected text to have at least one line"); + assert(lines.length > 0, "Failed to initialize test text. Expected text to have at least one line"); const lineIndex = new server.LineIndex(); lineIndex.load(lines); @@ -94,7 +94,7 @@ that was purple at the tips and grew 1cm per day`; ({ lines, lineMap } = server.LineIndex.linesFromText(testContent)); - assert.isTrue(lines.length > 0, "Failed to initialize test text. Expected text to have at least one line"); + assert(lines.length > 0, "Failed to initialize test text. Expected text to have at least one line"); const lineIndex = new server.LineIndex(); lineIndex.load(lines); @@ -203,10 +203,10 @@ and grew 1cm per day`; const testFileName = "src/compiler/scanner.ts"; testContent = Harness.IO.readFile(testFileName); const totalChars = testContent.length; - assert.isTrue(totalChars > 0, "Failed to read test file."); + assert(totalChars > 0, "Failed to read test file."); ({ lines, lineMap } = server.LineIndex.linesFromText(testContent)); - assert.isTrue(lines.length > 0, "Failed to initialize test text. Expected text to have at least one line"); + assert(lines.length > 0, "Failed to initialize test text. Expected text to have at least one line"); lineIndex = new server.LineIndex(); lineIndex.load(lines); diff --git a/src/harness/virtualFileSystemWithWatch.ts b/src/harness/virtualFileSystemWithWatch.ts index 581b86c042..3cf480ead8 100644 --- a/src/harness/virtualFileSystemWithWatch.ts +++ b/src/harness/virtualFileSystemWithWatch.ts @@ -139,7 +139,7 @@ interface Array {}` function checkMapKeys(caption: string, map: Map, expectedKeys: ReadonlyArray) { verifyMapSize(caption, map, expectedKeys); for (const name of expectedKeys) { - assert.isTrue(map.has(name), `${caption} is expected to contain ${name}, actual keys: ${arrayFrom(map.keys())}`); + assert(map.has(name), `${caption} is expected to contain ${name}, actual keys: ${arrayFrom(map.keys())}`); } } @@ -168,7 +168,7 @@ interface Array {}` mapSeen.set(f, true); } } - assert.equal(mapExpected.size, 0, `Output has missing ${JSON.stringify(flatMapIter(mapExpected.keys(), key => key))} in ${JSON.stringify(host.getOutput())}`); + assert.equal(mapExpected.size, 0, `Output has missing ${JSON.stringify(arrayFrom(mapExpected.keys()))} in ${JSON.stringify(host.getOutput())}`); } export function checkOutputDoesNotContain(host: TestServerHost, expectedToBeAbsent: string[] | ReadonlyArray) { @@ -241,7 +241,7 @@ interface Array {}` ignoreWatchInvokedWithTriggerAsFileCreate: boolean; } - export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost { + export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, ModuleResolutionHost { args: string[] = []; private readonly output: string[] = []; diff --git a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl index 88817c1298..23d85fb19e 100644 --- a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -856,49 +856,55 @@ - - + + - + - - + + + + + - - + + + + + - - + + + + + - + - - - @@ -1528,10 +1534,13 @@ - - + + + + + @@ -1942,31 +1951,37 @@ - - + + - + - - + + + + + - - + + + + + @@ -2338,37 +2353,49 @@ - - + + + + + - - + + + + + - - + + + + + - - + + + + + @@ -2446,10 +2473,13 @@ - - + + + + + @@ -3715,28 +3745,37 @@ - - + + + + + - - + + + + + - - + + + + + @@ -3751,10 +3790,13 @@ - - + + + + + @@ -3901,37 +3943,49 @@ - - + + + + + - - + + + + + - - + + + + + - - + + + + + @@ -4462,10 +4516,13 @@ - - + + + + + @@ -5374,10 +5431,13 @@ - - + + + + + @@ -5827,10 +5887,13 @@ - - + + + + + @@ -6250,10 +6313,13 @@ - - + + + + + @@ -6365,12 +6431,9 @@ - + - - - - + @@ -6554,6 +6617,9 @@ + + + @@ -7322,12 +7388,9 @@ - + - - - diff --git a/src/server/session.ts b/src/server/session.ts index a6b627bde3..744563cf32 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -1571,15 +1571,15 @@ namespace ts.server { } } - private applyCodeActionCommand(commandName: string, requestSeq: number, args: protocol.ApplyCodeActionCommandRequestArgs): void { + private applyCodeActionCommand(args: protocol.ApplyCodeActionCommandRequestArgs): {} { const commands = args.command as CodeActionCommand | CodeActionCommand[]; // They should be sending back the command we sent them. for (const command of toArray(commands)) { const { project } = this.getFileAndProject(command); - const output = (success: boolean, message: string) => this.doOutput({}, commandName, requestSeq, success, message); project.getLanguageService().applyCodeActionCommand(command).then( - result => { output(/*success*/ true, result.successMessage); }, - error => { output(/*success*/ false, error); }); + _result => { /* TODO: GH#20447 report success message? */ }, + _error => { /* TODO: GH#20447 report errors */ }); } + return {}; } private getStartAndEndPosition(args: protocol.FileRangeRequestArgs, scriptInfo: ScriptInfo) { @@ -1709,17 +1709,17 @@ namespace ts.server { }, [CommandNames.OpenExternalProject]: (request: protocol.OpenExternalProjectRequest) => { this.projectService.openExternalProject(request.arguments, /*suppressRefreshOfInferredProjects*/ false); - // TODO: report errors + // TODO: GH#20447 report errors return this.requiredResponse(/*response*/ true); }, [CommandNames.OpenExternalProjects]: (request: protocol.OpenExternalProjectsRequest) => { this.projectService.openExternalProjects(request.arguments.projects); - // TODO: report errors + // TODO: GH#20447 report errors return this.requiredResponse(/*response*/ true); }, [CommandNames.CloseExternalProject]: (request: protocol.CloseExternalProjectRequest) => { this.projectService.closeExternalProject(request.arguments.projectFileName); - // TODO: report errors + // TODO: GH#20447 report errors return this.requiredResponse(/*response*/ true); }, [CommandNames.SynchronizeProjectList]: (request: protocol.SynchronizeProjectListRequest) => { @@ -1961,8 +1961,7 @@ namespace ts.server { return this.requiredResponse(this.getCodeFixes(request.arguments, /*simplifiedResult*/ false)); }, [CommandNames.ApplyCodeActionCommand]: (request: protocol.ApplyCodeActionCommandRequest) => { - this.applyCodeActionCommand(request.command, request.seq, request.arguments); - return this.notRequired(); // Response will come asynchronously. + return this.requiredResponse(this.applyCodeActionCommand(request.arguments)); }, [CommandNames.GetSupportedCodeFixes]: () => { return this.requiredResponse(this.getSupportedCodeFixes()); diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts index 19bd592b7a..1e18267929 100644 --- a/src/services/codefixes/fixAddMissingMember.ts +++ b/src/services/codefixes/fixAddMissingMember.ts @@ -62,7 +62,6 @@ namespace ts.codefix { } const classDeclarationSourceFile = getSourceFileOfNode(classDeclaration); - const classOpenBrace = getOpenBraceOfClassLike(classDeclaration, classDeclarationSourceFile); return isInJavaScriptFile(classDeclarationSourceFile) ? getActionsForAddMissingMemberInJavaScriptFile(classDeclaration, makeStatic) : @@ -154,7 +153,7 @@ namespace ts.codefix { typeNode, /*initializer*/ undefined); const propertyChangeTracker = textChanges.ChangeTracker.fromContext(context); - propertyChangeTracker.insertNodeAfter(classDeclarationSourceFile, classOpenBrace, property, { suffix: context.newLineCharacter }); + propertyChangeTracker.insertNodeAtClassStart(classDeclarationSourceFile, classDeclaration, property, context.newLineCharacter); const diag = makeStatic ? Diagnostics.Declare_static_property_0 : Diagnostics.Declare_property_0; actions = append(actions, { @@ -180,7 +179,7 @@ namespace ts.codefix { typeNode); const indexSignatureChangeTracker = textChanges.ChangeTracker.fromContext(context); - indexSignatureChangeTracker.insertNodeAfter(classDeclarationSourceFile, classOpenBrace, indexSignature, { suffix: context.newLineCharacter }); + indexSignatureChangeTracker.insertNodeAtClassStart(classDeclarationSourceFile, classDeclaration, indexSignature, context.newLineCharacter); actions.push({ description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_signature_for_property_0), [tokenName]), @@ -197,7 +196,7 @@ namespace ts.codefix { const methodDeclaration = createMethodFromCallExpression(callExpression, tokenName, includeTypeScriptSyntax, makeStatic); const methodDeclarationChangeTracker = textChanges.ChangeTracker.fromContext(context); - methodDeclarationChangeTracker.insertNodeAfter(classDeclarationSourceFile, classOpenBrace, methodDeclaration, { suffix: context.newLineCharacter }); + methodDeclarationChangeTracker.insertNodeAtClassStart(classDeclarationSourceFile, classDeclaration, methodDeclaration, context.newLineCharacter); const diag = makeStatic ? Diagnostics.Declare_static_method_0 : Diagnostics.Declare_method_0; return { description: formatStringFromArgs(getLocaleSpecificMessage(diag), [tokenName]), diff --git a/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts b/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts index 24f44a877b..d61adfee47 100644 --- a/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts +++ b/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts @@ -12,7 +12,7 @@ namespace ts.codefix { const changeTracker = textChanges.ChangeTracker.fromContext(context); const superCall = createStatement(createCall(createSuper(), /*typeArguments*/ undefined, /*argumentsArray*/ emptyArray)); - changeTracker.insertNodeAfter(sourceFile, getOpenBrace(token.parent, sourceFile), superCall, { suffix: context.newLineCharacter }); + changeTracker.insertNodeAtConstructorStart(sourceFile, token.parent, superCall, context.newLineCharacter); return [{ description: getLocaleSpecificMessage(Diagnostics.Add_missing_super_call), diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 7bf057a03d..e786a77c6b 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -32,6 +32,7 @@ namespace ts.codefix { interface ImportCodeFixContext extends SymbolAndTokenContext { host: LanguageServiceHost; + program: Program; checker: TypeChecker; compilerOptions: CompilerOptions; getCanonicalFileName: GetCanonicalFileName; @@ -161,15 +162,17 @@ namespace ts.codefix { function convertToImportCodeFixContext(context: CodeFixContext): ImportCodeFixContext { const useCaseSensitiveFileNames = context.host.useCaseSensitiveFileNames ? context.host.useCaseSensitiveFileNames() : false; - const checker = context.program.getTypeChecker(); + const { program } = context; + const checker = program.getTypeChecker(); const symbolToken = getTokenAtPosition(context.sourceFile, context.span.start, /*includeJsDocComment*/ false); return { host: context.host, newLineCharacter: context.newLineCharacter, formatContext: context.formatContext, sourceFile: context.sourceFile, + program, checker, - compilerOptions: context.program.getCompilerOptions(), + compilerOptions: program.getCompilerOptions(), cachedImportDeclarations: [], getCanonicalFileName: createGetCanonicalFileName(useCaseSensitiveFileNames), symbolName: symbolToken.getText(), @@ -309,6 +312,7 @@ namespace ts.codefix { } export function getModuleSpecifiersForNewImport( + program: Program, sourceFile: SourceFile, moduleSymbols: ReadonlyArray, options: CompilerOptions, @@ -316,68 +320,79 @@ namespace ts.codefix { host: LanguageServiceHost, ): string[] { const { baseUrl, paths, rootDirs } = options; - const choicesForEachExportingModule = mapIterator(arrayIterator(moduleSymbols), moduleSymbol => { - const moduleFileName = moduleSymbol.valueDeclaration.getSourceFile().fileName; - const sourceDirectory = getDirectoryPath(sourceFile.fileName); - const global = tryGetModuleNameFromAmbientModule(moduleSymbol) - || tryGetModuleNameFromTypeRoots(options, host, getCanonicalFileName, moduleFileName) - || tryGetModuleNameAsNodeModule(options, moduleFileName, host, getCanonicalFileName, sourceDirectory) - || rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName); - if (global) { - return [global]; - } - - const relativePath = removeExtensionAndIndexPostFix(getRelativePath(moduleFileName, sourceDirectory, getCanonicalFileName), options); - if (!baseUrl) { - return [relativePath]; - } - - const relativeToBaseUrl = getRelativePathIfInDirectory(moduleFileName, baseUrl, getCanonicalFileName); - if (!relativeToBaseUrl) { - return [relativePath]; - } - - const importRelativeToBaseUrl = removeExtensionAndIndexPostFix(relativeToBaseUrl, options); - if (paths) { - const fromPaths = tryGetModuleNameFromPaths(removeFileExtension(relativeToBaseUrl), importRelativeToBaseUrl, paths); - if (fromPaths) { - return [fromPaths]; + const choicesForEachExportingModule = flatMap(moduleSymbols, moduleSymbol => + getAllModulePaths(program, moduleSymbol.valueDeclaration.getSourceFile()).map(moduleFileName => { + const sourceDirectory = getDirectoryPath(sourceFile.fileName); + const global = tryGetModuleNameFromAmbientModule(moduleSymbol) + || tryGetModuleNameFromTypeRoots(options, host, getCanonicalFileName, moduleFileName) + || tryGetModuleNameAsNodeModule(options, moduleFileName, host, getCanonicalFileName, sourceDirectory) + || rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName); + if (global) { + return [global]; } - } - /* - Prefer a relative import over a baseUrl import if it doesn't traverse up to baseUrl. + const relativePath = removeExtensionAndIndexPostFix(getRelativePath(moduleFileName, sourceDirectory, getCanonicalFileName), options); + if (!baseUrl) { + return [relativePath]; + } - Suppose we have: - baseUrl = /base - sourceDirectory = /base/a/b - moduleFileName = /base/foo/bar - Then: - relativePath = ../../foo/bar - getRelativePathNParents(relativePath) = 2 - pathFromSourceToBaseUrl = ../../ - getRelativePathNParents(pathFromSourceToBaseUrl) = 2 - 2 < 2 = false - In this case we should prefer using the baseUrl path "/a/b" instead of the relative path "../../foo/bar". + const relativeToBaseUrl = getRelativePathIfInDirectory(moduleFileName, baseUrl, getCanonicalFileName); + if (!relativeToBaseUrl) { + return [relativePath]; + } - Suppose we have: - baseUrl = /base - sourceDirectory = /base/foo/a - moduleFileName = /base/foo/bar - Then: - relativePath = ../a - getRelativePathNParents(relativePath) = 1 - pathFromSourceToBaseUrl = ../../ - getRelativePathNParents(pathFromSourceToBaseUrl) = 2 - 1 < 2 = true - In this case we should prefer using the relative path "../a" instead of the baseUrl path "foo/a". - */ - const pathFromSourceToBaseUrl = getRelativePath(baseUrl, sourceDirectory, getCanonicalFileName); - const relativeFirst = getRelativePathNParents(pathFromSourceToBaseUrl) < getRelativePathNParents(relativePath); - return relativeFirst ? [relativePath, importRelativeToBaseUrl] : [importRelativeToBaseUrl, relativePath]; - }); + const importRelativeToBaseUrl = removeExtensionAndIndexPostFix(relativeToBaseUrl, options); + if (paths) { + const fromPaths = tryGetModuleNameFromPaths(removeFileExtension(relativeToBaseUrl), importRelativeToBaseUrl, paths); + if (fromPaths) { + return [fromPaths]; + } + } + + /* + Prefer a relative import over a baseUrl import if it doesn't traverse up to baseUrl. + + Suppose we have: + baseUrl = /base + sourceDirectory = /base/a/b + moduleFileName = /base/foo/bar + Then: + relativePath = ../../foo/bar + getRelativePathNParents(relativePath) = 2 + pathFromSourceToBaseUrl = ../../ + getRelativePathNParents(pathFromSourceToBaseUrl) = 2 + 2 < 2 = false + In this case we should prefer using the baseUrl path "/a/b" instead of the relative path "../../foo/bar". + + Suppose we have: + baseUrl = /base + sourceDirectory = /base/foo/a + moduleFileName = /base/foo/bar + Then: + relativePath = ../a + getRelativePathNParents(relativePath) = 1 + pathFromSourceToBaseUrl = ../../ + getRelativePathNParents(pathFromSourceToBaseUrl) = 2 + 1 < 2 = true + In this case we should prefer using the relative path "../a" instead of the baseUrl path "foo/a". + */ + const pathFromSourceToBaseUrl = getRelativePath(baseUrl, sourceDirectory, getCanonicalFileName); + const relativeFirst = getRelativePathNParents(pathFromSourceToBaseUrl) < getRelativePathNParents(relativePath); + return relativeFirst ? [relativePath, importRelativeToBaseUrl] : [importRelativeToBaseUrl, relativePath]; + })); // Only return results for the re-export with the shortest possible path (and also give the other path even if that's long.) - return best(choicesForEachExportingModule, (a, b) => a[0].length < b[0].length); + return best(arrayIterator(choicesForEachExportingModule), (a, b) => a[0].length < b[0].length); + } + + /** + * Looks for a existing imports that use symlinks to this module. + * Only if no symlink is available, the real path will be used. + */ + function getAllModulePaths(program: Program, { fileName }: SourceFile): ReadonlyArray { + const symlinks = mapDefined(program.getSourceFiles(), sf => + sf.resolvedModules && firstDefinedIterator(sf.resolvedModules.values(), res => + res && res.resolvedFileName === fileName ? res.originalPath : undefined)); + return symlinks.length === 0 ? [fileName] : symlinks; } function getRelativePathNParents(relativePath: string): number { @@ -613,7 +628,7 @@ namespace ts.codefix { } const existingDeclaration = firstDefined(declarations, moduleSpecifierFromAnyImport); - const moduleSpecifiers = existingDeclaration ? [existingDeclaration] : getModuleSpecifiersForNewImport(ctx.sourceFile, moduleSymbols, ctx.compilerOptions, ctx.getCanonicalFileName, ctx.host); + const moduleSpecifiers = existingDeclaration ? [existingDeclaration] : getModuleSpecifiersForNewImport(ctx.program, ctx.sourceFile, moduleSymbols, ctx.compilerOptions, ctx.getCanonicalFileName, ctx.host); return moduleSpecifiers.map(spec => getCodeActionForNewImport(ctx, spec)); } @@ -746,7 +761,7 @@ namespace ts.codefix { forEachExternalModuleToImportFrom(checker, sourceFile, allSourceFiles, moduleSymbol => { cancellationToken.throwIfCancellationRequested(); // check the default export - const defaultExport = checker.tryGetMemberInModuleExports("default", moduleSymbol); + const defaultExport = checker.tryGetMemberInModuleExports(InternalSymbolName.Default, moduleSymbol); if (defaultExport) { const localSymbol = getLocalSymbolForExportDefault(defaultExport); if ((localSymbol && localSymbol.escapedName === symbolName || moduleSymbolToValidIdentifier(moduleSymbol, context.compilerOptions.target) === symbolName) diff --git a/src/services/completions.ts b/src/services/completions.ts index 28837bcce4..d893f4852e 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -39,6 +39,12 @@ namespace ts.Completions { return getStringLiteralCompletionEntries(sourceFile, position, typeChecker, compilerOptions, host, log); } + const contextToken = findPrecedingToken(position, sourceFile); + if (contextToken && isBreakOrContinueStatement(contextToken.parent) + && (contextToken.kind === SyntaxKind.BreakKeyword || contextToken.kind === SyntaxKind.ContinueKeyword || contextToken.kind === SyntaxKind.Identifier)) { + return getLabelCompletionAtPosition(contextToken.parent); + } + const completionData = getCompletionData(typeChecker, log, sourceFile, position, allSourceFiles, options, compilerOptions.target); if (!completionData) { return undefined; @@ -223,6 +229,13 @@ namespace ts.Completions { return uniques; } + function getLabelCompletionAtPosition(node: BreakOrContinueStatement): CompletionInfo | undefined { + const entries = getLabelStatementCompletions(node); + if (entries.length) { + return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries }; + } + } + function getStringLiteralCompletionEntries(sourceFile: SourceFile, position: number, typeChecker: TypeChecker, compilerOptions: CompilerOptions, host: LanguageServiceHost, log: Log): CompletionInfo | undefined { const node = findPrecedingToken(position, sourceFile); if (!node || node.kind !== SyntaxKind.StringLiteral) { @@ -358,6 +371,32 @@ namespace ts.Completions { return undefined; } + function getLabelStatementCompletions(node: Node): CompletionEntry[] { + const entries: CompletionEntry[] = []; + const uniques = createMap(); + let current = node; + + while (current) { + if (isFunctionLike(current)) { + break; + } + if (isLabeledStatement(current)) { + const name = current.label.text; + if (!uniques.has(name)) { + uniques.set(name, true); + entries.push({ + name, + kindModifiers: ScriptElementKindModifier.none, + kind: ScriptElementKind.label, + sortText: "0" + }); + } + } + current = current.parent; + } + return entries; + } + function addStringLiteralCompletionsFromType(type: Type, result: Push, typeChecker: TypeChecker, uniques = createMap()): void { if (type && type.flags & TypeFlags.TypeParameter) { type = typeChecker.getBaseConstraintOfType(type); @@ -416,7 +455,9 @@ namespace ts.Completions { } function getSymbolName(symbol: Symbol, origin: SymbolOriginInfo | undefined, target: ScriptTarget): string { - return origin && origin.isDefaultExport && symbol.name === "default" ? codefix.moduleSymbolToValidIdentifier(origin.moduleSymbol, target) : symbol.name; + return origin && origin.isDefaultExport && symbol.escapedName === InternalSymbolName.Default + ? codefix.moduleSymbolToValidIdentifier(origin.moduleSymbol, target) + : symbol.name; } export interface CompletionEntryIdentifier { @@ -425,7 +466,7 @@ namespace ts.Completions { } export function getCompletionEntryDetails( - typeChecker: TypeChecker, + program: Program, log: (message: string) => void, compilerOptions: CompilerOptions, sourceFile: SourceFile, @@ -436,6 +477,7 @@ namespace ts.Completions { formatContext: formatting.FormatContext, getCanonicalFileName: GetCanonicalFileName, ): CompletionEntryDetails { + const typeChecker = program.getTypeChecker(); const { name } = entryId; // Compute all the completion symbols again. const symbolCompletion = getSymbolCompletionFromEntryId(typeChecker, log, compilerOptions, sourceFile, position, entryId, allSourceFiles); @@ -455,7 +497,7 @@ namespace ts.Completions { } case "symbol": { const { symbol, location, symbolToOriginInfoMap } = symbolCompletion; - const { codeActions, sourceDisplay } = getCompletionEntryCodeActionsAndSourceDisplay(symbolToOriginInfoMap, symbol, typeChecker, host, compilerOptions, sourceFile, formatContext, getCanonicalFileName, allSourceFiles); + const { codeActions, sourceDisplay } = getCompletionEntryCodeActionsAndSourceDisplay(symbolToOriginInfoMap, symbol, program, typeChecker, host, compilerOptions, sourceFile, formatContext, getCanonicalFileName, allSourceFiles); const kindModifiers = SymbolDisplay.getSymbolModifiers(symbol); const { displayParts, documentation, symbolKind, tags } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, sourceFile, location, location, SemanticMeaning.All); return { name, kindModifiers, kind: symbolKind, displayParts, documentation, tags, codeActions, source: sourceDisplay }; @@ -482,6 +524,7 @@ namespace ts.Completions { function getCompletionEntryCodeActionsAndSourceDisplay( symbolToOriginInfoMap: SymbolOriginInfoMap, symbol: Symbol, + program: Program, checker: TypeChecker, host: LanguageServiceHost, compilerOptions: CompilerOptions, @@ -500,9 +543,10 @@ namespace ts.Completions { const moduleSymbols = getAllReExportingModules(exportedSymbol, checker, allSourceFiles); Debug.assert(contains(moduleSymbols, moduleSymbol)); - const sourceDisplay = [textPart(first(codefix.getModuleSpecifiersForNewImport(sourceFile, moduleSymbols, compilerOptions, getCanonicalFileName, host)))]; + const sourceDisplay = [textPart(first(codefix.getModuleSpecifiersForNewImport(program, sourceFile, moduleSymbols, compilerOptions, getCanonicalFileName, host)))]; const codeActions = codefix.getCodeActionForImport(moduleSymbols, { host, + program, checker, newLineCharacter: host.getNewLine(), compilerOptions, @@ -1076,7 +1120,7 @@ namespace ts.Completions { continue; } - const isDefaultExport = name === "default"; + const isDefaultExport = name === InternalSymbolName.Default; if (isDefaultExport) { const localSymbol = getLocalSymbolForExportDefault(symbol); if (localSymbol) { @@ -1756,10 +1800,10 @@ namespace ts.Completions { } if (existingImportsOrExports.size === 0) { - return filter(exportsOfModule, e => e.escapedName !== "default"); + return filter(exportsOfModule, e => e.escapedName !== InternalSymbolName.Default); } - return filter(exportsOfModule, e => e.escapedName !== "default" && !existingImportsOrExports.get(e.escapedName)); + return filter(exportsOfModule, e => e.escapedName !== InternalSymbolName.Default && !existingImportsOrExports.get(e.escapedName)); } /** diff --git a/src/services/importTracker.ts b/src/services/importTracker.ts index f12df4613c..0432c342c8 100644 --- a/src/services/importTracker.ts +++ b/src/services/importTracker.ts @@ -290,7 +290,7 @@ namespace ts.FindAllReferences { function isNameMatch(name: __String): boolean { // Use name of "default" even in `export =` case because we may have allowSyntheticDefaultImports - return name === exportSymbol.escapedName || exportKind !== ExportKind.Named && name === "default"; + return name === exportSymbol.escapedName || exportKind !== ExportKind.Named && name === InternalSymbolName.Default; } } @@ -534,7 +534,7 @@ namespace ts.FindAllReferences { // If `importedName` is undefined, do continue searching as the export is anonymous. // (All imports returned from this function will be ignored anyway if we are in rename and this is a not a named export.) const importedName = symbolName(importedSymbol); - if (importedName === undefined || importedName === "default" || importedName === symbol.escapedName) { + if (importedName === undefined || importedName === InternalSymbolName.Default || importedName === symbol.escapedName) { return { kind: ImportExport.Import, symbol: importedSymbol, ...isImport }; } } @@ -604,7 +604,7 @@ namespace ts.FindAllReferences { } function symbolName(symbol: Symbol): __String | undefined { - if (symbol.escapedName !== "default") { + if (symbol.escapedName !== InternalSymbolName.Default) { return symbol.escapedName; } diff --git a/src/services/refactorProvider.ts b/src/services/refactorProvider.ts index e0a1924793..85ef9113bd 100644 --- a/src/services/refactorProvider.ts +++ b/src/services/refactorProvider.ts @@ -33,8 +33,8 @@ namespace ts { } export function getApplicableRefactors(context: RefactorContext): ApplicableRefactorInfo[] { - return flatMapIter(refactors.values(), refactor => - context.cancellationToken && context.cancellationToken.isCancellationRequested() ? undefined : refactor.getAvailableActions(context)); + return arrayFrom(flatMapIterator(refactors.values(), refactor => + context.cancellationToken && context.cancellationToken.isCancellationRequested() ? undefined : refactor.getAvailableActions(context))); } export function getEditsForRefactor(context: RefactorContext, refactorName: string, actionName: string): RefactorEditInfo | undefined { diff --git a/src/services/services.ts b/src/services/services.ts index 24679e6a16..770d42dd3d 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -488,6 +488,7 @@ namespace ts { parameters: Symbol[]; thisParameter: Symbol; resolvedReturnType: Type; + resolvedTypePredicate: TypePredicate | undefined; minTypeArgumentCount: number; minArgumentCount: number; hasRestParameter: boolean; @@ -1268,6 +1269,7 @@ namespace ts { } return host.readFile && host.readFile(fileName); }, + realpath: host.realpath && (path => host.realpath(path)), directoryExists: directoryName => { return directoryProbablyExists(directoryName, host); }, @@ -1446,7 +1448,7 @@ namespace ts { function getCompletionEntryDetails(fileName: string, position: number, name: string, formattingOptions?: FormatCodeSettings, source?: string): CompletionEntryDetails { synchronizeHostData(); return Completions.getCompletionEntryDetails( - program.getTypeChecker(), + program, log, program.getCompilerOptions(), getValidSourceFile(fileName), diff --git a/src/services/shims.ts b/src/services/shims.ts index 7c932361c1..8000a04683 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -330,7 +330,7 @@ namespace ts { // if shimHost is a COM object then property check will become method call with no arguments. // 'in' does not have this effect. if ("getModuleResolutionsForFile" in this.shimHost) { - this.resolveModuleNames = (moduleNames: string[], containingFile: string) => { + this.resolveModuleNames = (moduleNames: string[], containingFile: string): ResolvedModuleFull[] => { const resolutionsInFile = >JSON.parse(this.shimHost.getModuleResolutionsForFile(containingFile)); return map(moduleNames, name => { const result = getProperty(resolutionsInFile, name); diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index 7c4e25537e..94a928c9cf 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -337,8 +337,32 @@ namespace ts.textChanges { return this.replaceWithSingle(sourceFile, startPosition, startPosition, newNode, options); } - public insertNodeAfter(sourceFile: SourceFile, after: Node, newNode: Node, options: InsertNodeOptions & ConfigurableEnd = {}) { - if ((isStatementButNotDeclaration(after)) || + public insertNodeAtConstructorStart(sourceFile: SourceFile, ctr: ConstructorDeclaration, newStatement: Statement, newLineCharacter: string): void { + const firstStatement = firstOrUndefined(ctr.body.statements); + if (!firstStatement || !ctr.body.multiLine) { + this.replaceNode(sourceFile, ctr.body, createBlock([newStatement, ...ctr.body.statements], /*multiLine*/ true), { useNonAdjustedEndPosition: true }); + } + else { + this.insertNodeBefore(sourceFile, firstStatement, newStatement, { suffix: newLineCharacter }); + } + } + + public insertNodeAtClassStart(sourceFile: SourceFile, cls: ClassLikeDeclaration, newElement: ClassElement, newLineCharacter: string): void { + const firstMember = firstOrUndefined(cls.members); + if (!firstMember) { + const members = [newElement]; + const newCls = cls.kind === SyntaxKind.ClassDeclaration + ? updateClassDeclaration(cls, cls.decorators, cls.modifiers, cls.name, cls.typeParameters, cls.heritageClauses, members) + : updateClassExpression(cls, cls.modifiers, cls.name, cls.typeParameters, cls.heritageClauses, members); + this.replaceNode(sourceFile, cls, newCls, { useNonAdjustedEndPosition: true }); + } + else { + this.insertNodeBefore(sourceFile, firstMember, newElement, { suffix: newLineCharacter }); + } + } + + public insertNodeAfter(sourceFile: SourceFile, after: Node, newNode: Node, options: InsertNodeOptions & ConfigurableEnd = {}): this { + if (isStatementButNotDeclaration(after) || after.kind === SyntaxKind.PropertyDeclaration || after.kind === SyntaxKind.PropertySignature || after.kind === SyntaxKind.MethodSignature) { diff --git a/src/services/types.ts b/src/services/types.ts index 7224fdbdda..272ae19f00 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -181,6 +181,7 @@ namespace ts { */ readDirectory?(path: string, extensions?: ReadonlyArray, exclude?: ReadonlyArray, include?: ReadonlyArray, depth?: number): string[]; readFile?(path: string, encoding?: string): string | undefined; + realpath?(path: string): string; fileExists?(path: string): boolean; /* diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index e0b4fa9e74..532f5bfd3c 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -3925,6 +3925,7 @@ declare namespace ts { useCaseSensitiveFileNames?(): boolean; readDirectory?(path: string, extensions?: ReadonlyArray, exclude?: ReadonlyArray, include?: ReadonlyArray, depth?: number): string[]; readFile?(path: string, encoding?: string): string | undefined; + realpath?(path: string): string; fileExists?(path: string): boolean; getTypeRootsVersion?(): number; resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[]; @@ -7088,7 +7089,7 @@ declare namespace ts.server { private getApplicableRefactors(args); private getEditsForRefactor(args, simplifiedResult); private getCodeFixes(args, simplifiedResult); - private applyCodeActionCommand(commandName, requestSeq, args); + private applyCodeActionCommand(args); private getStartAndEndPosition(args, scriptInfo); private mapCodeAction({description, changes: unmappedChanges, commands}, scriptInfo); private mapTextChangesToCodeEdits(project, textChanges); diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 62a3880827..84b7d9a19b 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3925,6 +3925,7 @@ declare namespace ts { useCaseSensitiveFileNames?(): boolean; readDirectory?(path: string, extensions?: ReadonlyArray, exclude?: ReadonlyArray, include?: ReadonlyArray, depth?: number): string[]; readFile?(path: string, encoding?: string): string | undefined; + realpath?(path: string): string; fileExists?(path: string): boolean; getTypeRootsVersion?(): number; resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[]; diff --git a/tests/baselines/reference/constEnums.js b/tests/baselines/reference/constEnums.js index 4f85cc59d0..893872b410 100644 --- a/tests/baselines/reference/constEnums.js +++ b/tests/baselines/reference/constEnums.js @@ -21,6 +21,7 @@ const enum Enum1 { N = E << 1, O = E >> B, P = E >> 1, + PQ = E ** 2, Q = -D, R = C & 5, S = 5 & C, @@ -128,6 +129,7 @@ function foo(x: Enum1) { case Enum1.N: case Enum1.O: case Enum1.P: + case Enum1.PQ: case Enum1.Q: case Enum1.R: case Enum1.S: @@ -200,6 +202,7 @@ function foo(x) { case 2 /* N */: case 0 /* O */: case 0 /* P */: + case 1 /* PQ */: case -1 /* Q */: case 0 /* R */: case 0 /* S */: diff --git a/tests/baselines/reference/constEnums.symbols b/tests/baselines/reference/constEnums.symbols index 9f88fb6349..0046d08f37 100644 --- a/tests/baselines/reference/constEnums.symbols +++ b/tests/baselines/reference/constEnums.symbols @@ -71,273 +71,277 @@ const enum Enum1 { P = E >> 1, >P : Symbol(Enum1.P, Decl(constEnums.ts, 20, 15)) +>E : Symbol(Enum1.E, Decl(constEnums.ts, 9, 14)) + + PQ = E ** 2, +>PQ : Symbol(Enum1.PQ, Decl(constEnums.ts, 21, 15)) >E : Symbol(Enum1.E, Decl(constEnums.ts, 9, 14)) Q = -D, ->Q : Symbol(Enum1.Q, Decl(constEnums.ts, 21, 15)) +>Q : Symbol(Enum1.Q, Decl(constEnums.ts, 22, 16)) >D : Symbol(Enum1.D, Decl(constEnums.ts, 8, 11)) R = C & 5, ->R : Symbol(Enum1.R, Decl(constEnums.ts, 22, 11)) +>R : Symbol(Enum1.R, Decl(constEnums.ts, 23, 11)) >C : Symbol(Enum1.C, Decl(constEnums.ts, 7, 6)) S = 5 & C, ->S : Symbol(Enum1.S, Decl(constEnums.ts, 23, 14)) +>S : Symbol(Enum1.S, Decl(constEnums.ts, 24, 14)) >C : Symbol(Enum1.C, Decl(constEnums.ts, 7, 6)) T = C | D, ->T : Symbol(Enum1.T, Decl(constEnums.ts, 24, 14)) +>T : Symbol(Enum1.T, Decl(constEnums.ts, 25, 14)) >C : Symbol(Enum1.C, Decl(constEnums.ts, 7, 6)) >D : Symbol(Enum1.D, Decl(constEnums.ts, 8, 11)) U = C | 1, ->U : Symbol(Enum1.U, Decl(constEnums.ts, 25, 14)) +>U : Symbol(Enum1.U, Decl(constEnums.ts, 26, 14)) >C : Symbol(Enum1.C, Decl(constEnums.ts, 7, 6)) V = 10 | D, ->V : Symbol(Enum1.V, Decl(constEnums.ts, 26, 14)) +>V : Symbol(Enum1.V, Decl(constEnums.ts, 27, 14)) >D : Symbol(Enum1.D, Decl(constEnums.ts, 8, 11)) W = Enum1.V, ->W : Symbol(Enum1.W, Decl(constEnums.ts, 27, 15)) ->Enum1.V : Symbol(Enum1.V, Decl(constEnums.ts, 26, 14)) +>W : Symbol(Enum1.W, Decl(constEnums.ts, 28, 15)) +>Enum1.V : Symbol(Enum1.V, Decl(constEnums.ts, 27, 14)) >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) ->V : Symbol(Enum1.V, Decl(constEnums.ts, 26, 14)) +>V : Symbol(Enum1.V, Decl(constEnums.ts, 27, 14)) // correct cases: reference to the enum member from different enum declaration W1 = A0, ->W1 : Symbol(Enum1.W1, Decl(constEnums.ts, 28, 16)) +>W1 : Symbol(Enum1.W1, Decl(constEnums.ts, 29, 16)) >A0 : Symbol(Enum1.A0, Decl(constEnums.ts, 0, 18)) W2 = Enum1.A0, ->W2 : Symbol(Enum1.W2, Decl(constEnums.ts, 31, 12)) +>W2 : Symbol(Enum1.W2, Decl(constEnums.ts, 32, 12)) >Enum1.A0 : Symbol(Enum1.A0, Decl(constEnums.ts, 0, 18)) >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) >A0 : Symbol(Enum1.A0, Decl(constEnums.ts, 0, 18)) W3 = Enum1["A0"], ->W3 : Symbol(Enum1.W3, Decl(constEnums.ts, 32, 18)) +>W3 : Symbol(Enum1.W3, Decl(constEnums.ts, 33, 18)) >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) >"A0" : Symbol(Enum1.A0, Decl(constEnums.ts, 0, 18)) W4 = Enum1["W"], ->W4 : Symbol(Enum1.W4, Decl(constEnums.ts, 33, 21)) +>W4 : Symbol(Enum1.W4, Decl(constEnums.ts, 34, 21)) >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) ->"W" : Symbol(Enum1.W, Decl(constEnums.ts, 27, 15)) +>"W" : Symbol(Enum1.W, Decl(constEnums.ts, 28, 15)) } module A { ->A : Symbol(A, Decl(constEnums.ts, 35, 1), Decl(constEnums.ts, 47, 1)) +>A : Symbol(A, Decl(constEnums.ts, 36, 1), Decl(constEnums.ts, 48, 1)) export module B { ->B : Symbol(B, Decl(constEnums.ts, 38, 10), Decl(constEnums.ts, 49, 10)) +>B : Symbol(B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) export module C { ->C : Symbol(C, Decl(constEnums.ts, 39, 21), Decl(constEnums.ts, 50, 21)) +>C : Symbol(C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) export const enum E { ->E : Symbol(E, Decl(constEnums.ts, 40, 25), Decl(constEnums.ts, 51, 25)) +>E : Symbol(E, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) V1 = 1, ->V1 : Symbol(I.V1, Decl(constEnums.ts, 41, 33)) +>V1 : Symbol(I.V1, Decl(constEnums.ts, 42, 33)) V2 = A.B.C.E.V1 | 100 ->V2 : Symbol(I.V2, Decl(constEnums.ts, 42, 23)) ->A.B.C.E.V1 : Symbol(I.V1, Decl(constEnums.ts, 41, 33)) ->A.B.C.E : Symbol(E, Decl(constEnums.ts, 40, 25), Decl(constEnums.ts, 51, 25)) ->A.B.C : Symbol(C, Decl(constEnums.ts, 39, 21), Decl(constEnums.ts, 50, 21)) ->A.B : Symbol(B, Decl(constEnums.ts, 38, 10), Decl(constEnums.ts, 49, 10)) ->A : Symbol(A, Decl(constEnums.ts, 35, 1), Decl(constEnums.ts, 47, 1)) ->B : Symbol(B, Decl(constEnums.ts, 38, 10), Decl(constEnums.ts, 49, 10)) ->C : Symbol(C, Decl(constEnums.ts, 39, 21), Decl(constEnums.ts, 50, 21)) ->E : Symbol(E, Decl(constEnums.ts, 40, 25), Decl(constEnums.ts, 51, 25)) ->V1 : Symbol(I.V1, Decl(constEnums.ts, 41, 33)) +>V2 : Symbol(I.V2, Decl(constEnums.ts, 43, 23)) +>A.B.C.E.V1 : Symbol(I.V1, Decl(constEnums.ts, 42, 33)) +>A.B.C.E : Symbol(E, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) +>A.B.C : Symbol(C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) +>A.B : Symbol(B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) +>A : Symbol(A, Decl(constEnums.ts, 36, 1), Decl(constEnums.ts, 48, 1)) +>B : Symbol(B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) +>C : Symbol(C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) +>E : Symbol(E, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) +>V1 : Symbol(I.V1, Decl(constEnums.ts, 42, 33)) } } } } module A { ->A : Symbol(A, Decl(constEnums.ts, 35, 1), Decl(constEnums.ts, 47, 1)) +>A : Symbol(A, Decl(constEnums.ts, 36, 1), Decl(constEnums.ts, 48, 1)) export module B { ->B : Symbol(B, Decl(constEnums.ts, 38, 10), Decl(constEnums.ts, 49, 10)) +>B : Symbol(B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) export module C { ->C : Symbol(C, Decl(constEnums.ts, 39, 21), Decl(constEnums.ts, 50, 21)) +>C : Symbol(C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) export const enum E { ->E : Symbol(E, Decl(constEnums.ts, 40, 25), Decl(constEnums.ts, 51, 25)) +>E : Symbol(E, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) V3 = A.B.C.E["V2"] & 200, ->V3 : Symbol(I.V3, Decl(constEnums.ts, 52, 33)) ->A.B.C.E : Symbol(E, Decl(constEnums.ts, 40, 25), Decl(constEnums.ts, 51, 25)) ->A.B.C : Symbol(C, Decl(constEnums.ts, 39, 21), Decl(constEnums.ts, 50, 21)) ->A.B : Symbol(B, Decl(constEnums.ts, 38, 10), Decl(constEnums.ts, 49, 10)) ->A : Symbol(A, Decl(constEnums.ts, 35, 1), Decl(constEnums.ts, 47, 1)) ->B : Symbol(B, Decl(constEnums.ts, 38, 10), Decl(constEnums.ts, 49, 10)) ->C : Symbol(C, Decl(constEnums.ts, 39, 21), Decl(constEnums.ts, 50, 21)) ->E : Symbol(E, Decl(constEnums.ts, 40, 25), Decl(constEnums.ts, 51, 25)) ->"V2" : Symbol(I.V2, Decl(constEnums.ts, 42, 23)) +>V3 : Symbol(I.V3, Decl(constEnums.ts, 53, 33)) +>A.B.C.E : Symbol(E, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) +>A.B.C : Symbol(C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) +>A.B : Symbol(B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) +>A : Symbol(A, Decl(constEnums.ts, 36, 1), Decl(constEnums.ts, 48, 1)) +>B : Symbol(B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) +>C : Symbol(C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) +>E : Symbol(E, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) +>"V2" : Symbol(I.V2, Decl(constEnums.ts, 43, 23)) } } } } module A1 { ->A1 : Symbol(A1, Decl(constEnums.ts, 57, 1)) +>A1 : Symbol(A1, Decl(constEnums.ts, 58, 1)) export module B { ->B : Symbol(B, Decl(constEnums.ts, 59, 11)) +>B : Symbol(B, Decl(constEnums.ts, 60, 11)) export module C { ->C : Symbol(C, Decl(constEnums.ts, 60, 21)) +>C : Symbol(C, Decl(constEnums.ts, 61, 21)) export const enum E { ->E : Symbol(E, Decl(constEnums.ts, 61, 25)) +>E : Symbol(E, Decl(constEnums.ts, 62, 25)) V1 = 10, ->V1 : Symbol(E.V1, Decl(constEnums.ts, 62, 33)) +>V1 : Symbol(E.V1, Decl(constEnums.ts, 63, 33)) V2 = 110, ->V2 : Symbol(E.V2, Decl(constEnums.ts, 63, 24)) +>V2 : Symbol(E.V2, Decl(constEnums.ts, 64, 24)) } } } } module A2 { ->A2 : Symbol(A2, Decl(constEnums.ts, 68, 1)) +>A2 : Symbol(A2, Decl(constEnums.ts, 69, 1)) export module B { ->B : Symbol(B, Decl(constEnums.ts, 70, 11)) +>B : Symbol(B, Decl(constEnums.ts, 71, 11)) export module C { ->C : Symbol(C, Decl(constEnums.ts, 71, 21), Decl(constEnums.ts, 77, 9)) +>C : Symbol(C, Decl(constEnums.ts, 72, 21), Decl(constEnums.ts, 78, 9)) export const enum E { ->E : Symbol(E, Decl(constEnums.ts, 72, 25)) +>E : Symbol(E, Decl(constEnums.ts, 73, 25)) V1 = 10, ->V1 : Symbol(E.V1, Decl(constEnums.ts, 73, 33)) +>V1 : Symbol(E.V1, Decl(constEnums.ts, 74, 33)) V2 = 110, ->V2 : Symbol(E.V2, Decl(constEnums.ts, 74, 24)) +>V2 : Symbol(E.V2, Decl(constEnums.ts, 75, 24)) } } // module C will be classified as value export module C { ->C : Symbol(C, Decl(constEnums.ts, 71, 21), Decl(constEnums.ts, 77, 9)) +>C : Symbol(C, Decl(constEnums.ts, 72, 21), Decl(constEnums.ts, 78, 9)) var x = 1 ->x : Symbol(x, Decl(constEnums.ts, 80, 15)) +>x : Symbol(x, Decl(constEnums.ts, 81, 15)) } } } import I = A.B.C.E; ->I : Symbol(I, Decl(constEnums.ts, 83, 1)) ->A : Symbol(A, Decl(constEnums.ts, 35, 1), Decl(constEnums.ts, 47, 1)) ->B : Symbol(A.B, Decl(constEnums.ts, 38, 10), Decl(constEnums.ts, 49, 10)) ->C : Symbol(A.B.C, Decl(constEnums.ts, 39, 21), Decl(constEnums.ts, 50, 21)) ->E : Symbol(I, Decl(constEnums.ts, 40, 25), Decl(constEnums.ts, 51, 25)) +>I : Symbol(I, Decl(constEnums.ts, 84, 1)) +>A : Symbol(A, Decl(constEnums.ts, 36, 1), Decl(constEnums.ts, 48, 1)) +>B : Symbol(A.B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) +>C : Symbol(A.B.C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) +>E : Symbol(I, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) import I1 = A1.B; ->I1 : Symbol(I1, Decl(constEnums.ts, 85, 19)) ->A1 : Symbol(A1, Decl(constEnums.ts, 57, 1)) ->B : Symbol(I1, Decl(constEnums.ts, 59, 11)) +>I1 : Symbol(I1, Decl(constEnums.ts, 86, 19)) +>A1 : Symbol(A1, Decl(constEnums.ts, 58, 1)) +>B : Symbol(I1, Decl(constEnums.ts, 60, 11)) import I2 = A2.B; ->I2 : Symbol(I2, Decl(constEnums.ts, 86, 17)) ->A2 : Symbol(A2, Decl(constEnums.ts, 68, 1)) ->B : Symbol(I2, Decl(constEnums.ts, 70, 11)) +>I2 : Symbol(I2, Decl(constEnums.ts, 87, 17)) +>A2 : Symbol(A2, Decl(constEnums.ts, 69, 1)) +>B : Symbol(I2, Decl(constEnums.ts, 71, 11)) function foo0(e: I): void { ->foo0 : Symbol(foo0, Decl(constEnums.ts, 87, 17)) ->e : Symbol(e, Decl(constEnums.ts, 89, 14)) ->I : Symbol(I, Decl(constEnums.ts, 83, 1)) +>foo0 : Symbol(foo0, Decl(constEnums.ts, 88, 17)) +>e : Symbol(e, Decl(constEnums.ts, 90, 14)) +>I : Symbol(I, Decl(constEnums.ts, 84, 1)) if (e === I.V1) { ->e : Symbol(e, Decl(constEnums.ts, 89, 14)) ->I.V1 : Symbol(I.V1, Decl(constEnums.ts, 41, 33)) ->I : Symbol(I, Decl(constEnums.ts, 83, 1)) ->V1 : Symbol(I.V1, Decl(constEnums.ts, 41, 33)) +>e : Symbol(e, Decl(constEnums.ts, 90, 14)) +>I.V1 : Symbol(I.V1, Decl(constEnums.ts, 42, 33)) +>I : Symbol(I, Decl(constEnums.ts, 84, 1)) +>V1 : Symbol(I.V1, Decl(constEnums.ts, 42, 33)) } else if (e === I.V2) { ->e : Symbol(e, Decl(constEnums.ts, 89, 14)) ->I.V2 : Symbol(I.V2, Decl(constEnums.ts, 42, 23)) ->I : Symbol(I, Decl(constEnums.ts, 83, 1)) ->V2 : Symbol(I.V2, Decl(constEnums.ts, 42, 23)) +>e : Symbol(e, Decl(constEnums.ts, 90, 14)) +>I.V2 : Symbol(I.V2, Decl(constEnums.ts, 43, 23)) +>I : Symbol(I, Decl(constEnums.ts, 84, 1)) +>V2 : Symbol(I.V2, Decl(constEnums.ts, 43, 23)) } } function foo1(e: I1.C.E): void { ->foo1 : Symbol(foo1, Decl(constEnums.ts, 94, 1)) ->e : Symbol(e, Decl(constEnums.ts, 96, 14)) ->I1 : Symbol(I1, Decl(constEnums.ts, 85, 19)) ->C : Symbol(I1.C, Decl(constEnums.ts, 60, 21)) ->E : Symbol(I1.C.E, Decl(constEnums.ts, 61, 25)) +>foo1 : Symbol(foo1, Decl(constEnums.ts, 95, 1)) +>e : Symbol(e, Decl(constEnums.ts, 97, 14)) +>I1 : Symbol(I1, Decl(constEnums.ts, 86, 19)) +>C : Symbol(I1.C, Decl(constEnums.ts, 61, 21)) +>E : Symbol(I1.C.E, Decl(constEnums.ts, 62, 25)) if (e === I1.C.E.V1) { ->e : Symbol(e, Decl(constEnums.ts, 96, 14)) ->I1.C.E.V1 : Symbol(I1.C.E.V1, Decl(constEnums.ts, 62, 33)) ->I1.C.E : Symbol(I1.C.E, Decl(constEnums.ts, 61, 25)) ->I1.C : Symbol(I1.C, Decl(constEnums.ts, 60, 21)) ->I1 : Symbol(I1, Decl(constEnums.ts, 85, 19)) ->C : Symbol(I1.C, Decl(constEnums.ts, 60, 21)) ->E : Symbol(I1.C.E, Decl(constEnums.ts, 61, 25)) ->V1 : Symbol(I1.C.E.V1, Decl(constEnums.ts, 62, 33)) +>e : Symbol(e, Decl(constEnums.ts, 97, 14)) +>I1.C.E.V1 : Symbol(I1.C.E.V1, Decl(constEnums.ts, 63, 33)) +>I1.C.E : Symbol(I1.C.E, Decl(constEnums.ts, 62, 25)) +>I1.C : Symbol(I1.C, Decl(constEnums.ts, 61, 21)) +>I1 : Symbol(I1, Decl(constEnums.ts, 86, 19)) +>C : Symbol(I1.C, Decl(constEnums.ts, 61, 21)) +>E : Symbol(I1.C.E, Decl(constEnums.ts, 62, 25)) +>V1 : Symbol(I1.C.E.V1, Decl(constEnums.ts, 63, 33)) } else if (e === I1.C.E.V2) { ->e : Symbol(e, Decl(constEnums.ts, 96, 14)) ->I1.C.E.V2 : Symbol(I1.C.E.V2, Decl(constEnums.ts, 63, 24)) ->I1.C.E : Symbol(I1.C.E, Decl(constEnums.ts, 61, 25)) ->I1.C : Symbol(I1.C, Decl(constEnums.ts, 60, 21)) ->I1 : Symbol(I1, Decl(constEnums.ts, 85, 19)) ->C : Symbol(I1.C, Decl(constEnums.ts, 60, 21)) ->E : Symbol(I1.C.E, Decl(constEnums.ts, 61, 25)) ->V2 : Symbol(I1.C.E.V2, Decl(constEnums.ts, 63, 24)) +>e : Symbol(e, Decl(constEnums.ts, 97, 14)) +>I1.C.E.V2 : Symbol(I1.C.E.V2, Decl(constEnums.ts, 64, 24)) +>I1.C.E : Symbol(I1.C.E, Decl(constEnums.ts, 62, 25)) +>I1.C : Symbol(I1.C, Decl(constEnums.ts, 61, 21)) +>I1 : Symbol(I1, Decl(constEnums.ts, 86, 19)) +>C : Symbol(I1.C, Decl(constEnums.ts, 61, 21)) +>E : Symbol(I1.C.E, Decl(constEnums.ts, 62, 25)) +>V2 : Symbol(I1.C.E.V2, Decl(constEnums.ts, 64, 24)) } } function foo2(e: I2.C.E): void { ->foo2 : Symbol(foo2, Decl(constEnums.ts, 101, 1)) ->e : Symbol(e, Decl(constEnums.ts, 103, 14)) ->I2 : Symbol(I2, Decl(constEnums.ts, 86, 17)) ->C : Symbol(I2.C, Decl(constEnums.ts, 71, 21), Decl(constEnums.ts, 77, 9)) ->E : Symbol(I2.C.E, Decl(constEnums.ts, 72, 25)) +>foo2 : Symbol(foo2, Decl(constEnums.ts, 102, 1)) +>e : Symbol(e, Decl(constEnums.ts, 104, 14)) +>I2 : Symbol(I2, Decl(constEnums.ts, 87, 17)) +>C : Symbol(I2.C, Decl(constEnums.ts, 72, 21), Decl(constEnums.ts, 78, 9)) +>E : Symbol(I2.C.E, Decl(constEnums.ts, 73, 25)) if (e === I2.C.E.V1) { ->e : Symbol(e, Decl(constEnums.ts, 103, 14)) ->I2.C.E.V1 : Symbol(I2.C.E.V1, Decl(constEnums.ts, 73, 33)) ->I2.C.E : Symbol(I2.C.E, Decl(constEnums.ts, 72, 25)) ->I2.C : Symbol(I2.C, Decl(constEnums.ts, 71, 21), Decl(constEnums.ts, 77, 9)) ->I2 : Symbol(I2, Decl(constEnums.ts, 86, 17)) ->C : Symbol(I2.C, Decl(constEnums.ts, 71, 21), Decl(constEnums.ts, 77, 9)) ->E : Symbol(I2.C.E, Decl(constEnums.ts, 72, 25)) ->V1 : Symbol(I2.C.E.V1, Decl(constEnums.ts, 73, 33)) +>e : Symbol(e, Decl(constEnums.ts, 104, 14)) +>I2.C.E.V1 : Symbol(I2.C.E.V1, Decl(constEnums.ts, 74, 33)) +>I2.C.E : Symbol(I2.C.E, Decl(constEnums.ts, 73, 25)) +>I2.C : Symbol(I2.C, Decl(constEnums.ts, 72, 21), Decl(constEnums.ts, 78, 9)) +>I2 : Symbol(I2, Decl(constEnums.ts, 87, 17)) +>C : Symbol(I2.C, Decl(constEnums.ts, 72, 21), Decl(constEnums.ts, 78, 9)) +>E : Symbol(I2.C.E, Decl(constEnums.ts, 73, 25)) +>V1 : Symbol(I2.C.E.V1, Decl(constEnums.ts, 74, 33)) } else if (e === I2.C.E.V2) { ->e : Symbol(e, Decl(constEnums.ts, 103, 14)) ->I2.C.E.V2 : Symbol(I2.C.E.V2, Decl(constEnums.ts, 74, 24)) ->I2.C.E : Symbol(I2.C.E, Decl(constEnums.ts, 72, 25)) ->I2.C : Symbol(I2.C, Decl(constEnums.ts, 71, 21), Decl(constEnums.ts, 77, 9)) ->I2 : Symbol(I2, Decl(constEnums.ts, 86, 17)) ->C : Symbol(I2.C, Decl(constEnums.ts, 71, 21), Decl(constEnums.ts, 77, 9)) ->E : Symbol(I2.C.E, Decl(constEnums.ts, 72, 25)) ->V2 : Symbol(I2.C.E.V2, Decl(constEnums.ts, 74, 24)) +>e : Symbol(e, Decl(constEnums.ts, 104, 14)) +>I2.C.E.V2 : Symbol(I2.C.E.V2, Decl(constEnums.ts, 75, 24)) +>I2.C.E : Symbol(I2.C.E, Decl(constEnums.ts, 73, 25)) +>I2.C : Symbol(I2.C, Decl(constEnums.ts, 72, 21), Decl(constEnums.ts, 78, 9)) +>I2 : Symbol(I2, Decl(constEnums.ts, 87, 17)) +>C : Symbol(I2.C, Decl(constEnums.ts, 72, 21), Decl(constEnums.ts, 78, 9)) +>E : Symbol(I2.C.E, Decl(constEnums.ts, 73, 25)) +>V2 : Symbol(I2.C.E.V2, Decl(constEnums.ts, 75, 24)) } } function foo(x: Enum1) { ->foo : Symbol(foo, Decl(constEnums.ts, 108, 1)) ->x : Symbol(x, Decl(constEnums.ts, 111, 13)) +>foo : Symbol(foo, Decl(constEnums.ts, 109, 1)) +>x : Symbol(x, Decl(constEnums.ts, 112, 13)) >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) switch (x) { ->x : Symbol(x, Decl(constEnums.ts, 111, 13)) +>x : Symbol(x, Decl(constEnums.ts, 112, 13)) case Enum1.A: >Enum1.A : Symbol(Enum1.A, Decl(constEnums.ts, 4, 18)) @@ -419,106 +423,111 @@ function foo(x: Enum1) { >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) >P : Symbol(Enum1.P, Decl(constEnums.ts, 20, 15)) - case Enum1.Q: ->Enum1.Q : Symbol(Enum1.Q, Decl(constEnums.ts, 21, 15)) + case Enum1.PQ: +>Enum1.PQ : Symbol(Enum1.PQ, Decl(constEnums.ts, 21, 15)) >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) ->Q : Symbol(Enum1.Q, Decl(constEnums.ts, 21, 15)) +>PQ : Symbol(Enum1.PQ, Decl(constEnums.ts, 21, 15)) + + case Enum1.Q: +>Enum1.Q : Symbol(Enum1.Q, Decl(constEnums.ts, 22, 16)) +>Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) +>Q : Symbol(Enum1.Q, Decl(constEnums.ts, 22, 16)) case Enum1.R: ->Enum1.R : Symbol(Enum1.R, Decl(constEnums.ts, 22, 11)) +>Enum1.R : Symbol(Enum1.R, Decl(constEnums.ts, 23, 11)) >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) ->R : Symbol(Enum1.R, Decl(constEnums.ts, 22, 11)) +>R : Symbol(Enum1.R, Decl(constEnums.ts, 23, 11)) case Enum1.S: ->Enum1.S : Symbol(Enum1.S, Decl(constEnums.ts, 23, 14)) +>Enum1.S : Symbol(Enum1.S, Decl(constEnums.ts, 24, 14)) >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) ->S : Symbol(Enum1.S, Decl(constEnums.ts, 23, 14)) +>S : Symbol(Enum1.S, Decl(constEnums.ts, 24, 14)) case Enum1["T"]: >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) ->"T" : Symbol(Enum1.T, Decl(constEnums.ts, 24, 14)) +>"T" : Symbol(Enum1.T, Decl(constEnums.ts, 25, 14)) case Enum1.U: ->Enum1.U : Symbol(Enum1.U, Decl(constEnums.ts, 25, 14)) +>Enum1.U : Symbol(Enum1.U, Decl(constEnums.ts, 26, 14)) >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) ->U : Symbol(Enum1.U, Decl(constEnums.ts, 25, 14)) +>U : Symbol(Enum1.U, Decl(constEnums.ts, 26, 14)) case Enum1.V: ->Enum1.V : Symbol(Enum1.V, Decl(constEnums.ts, 26, 14)) +>Enum1.V : Symbol(Enum1.V, Decl(constEnums.ts, 27, 14)) >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) ->V : Symbol(Enum1.V, Decl(constEnums.ts, 26, 14)) +>V : Symbol(Enum1.V, Decl(constEnums.ts, 27, 14)) case Enum1.W: ->Enum1.W : Symbol(Enum1.W, Decl(constEnums.ts, 27, 15)) +>Enum1.W : Symbol(Enum1.W, Decl(constEnums.ts, 28, 15)) >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) ->W : Symbol(Enum1.W, Decl(constEnums.ts, 27, 15)) +>W : Symbol(Enum1.W, Decl(constEnums.ts, 28, 15)) case Enum1.W1: ->Enum1.W1 : Symbol(Enum1.W1, Decl(constEnums.ts, 28, 16)) +>Enum1.W1 : Symbol(Enum1.W1, Decl(constEnums.ts, 29, 16)) >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) ->W1 : Symbol(Enum1.W1, Decl(constEnums.ts, 28, 16)) +>W1 : Symbol(Enum1.W1, Decl(constEnums.ts, 29, 16)) case Enum1.W2: ->Enum1.W2 : Symbol(Enum1.W2, Decl(constEnums.ts, 31, 12)) +>Enum1.W2 : Symbol(Enum1.W2, Decl(constEnums.ts, 32, 12)) >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) ->W2 : Symbol(Enum1.W2, Decl(constEnums.ts, 31, 12)) +>W2 : Symbol(Enum1.W2, Decl(constEnums.ts, 32, 12)) case Enum1.W3: ->Enum1.W3 : Symbol(Enum1.W3, Decl(constEnums.ts, 32, 18)) +>Enum1.W3 : Symbol(Enum1.W3, Decl(constEnums.ts, 33, 18)) >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) ->W3 : Symbol(Enum1.W3, Decl(constEnums.ts, 32, 18)) +>W3 : Symbol(Enum1.W3, Decl(constEnums.ts, 33, 18)) case Enum1.W4: ->Enum1.W4 : Symbol(Enum1.W4, Decl(constEnums.ts, 33, 21)) +>Enum1.W4 : Symbol(Enum1.W4, Decl(constEnums.ts, 34, 21)) >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) ->W4 : Symbol(Enum1.W4, Decl(constEnums.ts, 33, 21)) +>W4 : Symbol(Enum1.W4, Decl(constEnums.ts, 34, 21)) break; } } function bar(e: A.B.C.E): number { ->bar : Symbol(bar, Decl(constEnums.ts, 142, 1)) ->e : Symbol(e, Decl(constEnums.ts, 144, 13)) ->A : Symbol(A, Decl(constEnums.ts, 35, 1), Decl(constEnums.ts, 47, 1)) ->B : Symbol(A.B, Decl(constEnums.ts, 38, 10), Decl(constEnums.ts, 49, 10)) ->C : Symbol(A.B.C, Decl(constEnums.ts, 39, 21), Decl(constEnums.ts, 50, 21)) ->E : Symbol(I, Decl(constEnums.ts, 40, 25), Decl(constEnums.ts, 51, 25)) +>bar : Symbol(bar, Decl(constEnums.ts, 144, 1)) +>e : Symbol(e, Decl(constEnums.ts, 146, 13)) +>A : Symbol(A, Decl(constEnums.ts, 36, 1), Decl(constEnums.ts, 48, 1)) +>B : Symbol(A.B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) +>C : Symbol(A.B.C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) +>E : Symbol(I, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) switch (e) { ->e : Symbol(e, Decl(constEnums.ts, 144, 13)) +>e : Symbol(e, Decl(constEnums.ts, 146, 13)) case A.B.C.E.V1: return 1; ->A.B.C.E.V1 : Symbol(I.V1, Decl(constEnums.ts, 41, 33)) ->A.B.C.E : Symbol(I, Decl(constEnums.ts, 40, 25), Decl(constEnums.ts, 51, 25)) ->A.B.C : Symbol(A.B.C, Decl(constEnums.ts, 39, 21), Decl(constEnums.ts, 50, 21)) ->A.B : Symbol(A.B, Decl(constEnums.ts, 38, 10), Decl(constEnums.ts, 49, 10)) ->A : Symbol(A, Decl(constEnums.ts, 35, 1), Decl(constEnums.ts, 47, 1)) ->B : Symbol(A.B, Decl(constEnums.ts, 38, 10), Decl(constEnums.ts, 49, 10)) ->C : Symbol(A.B.C, Decl(constEnums.ts, 39, 21), Decl(constEnums.ts, 50, 21)) ->E : Symbol(I, Decl(constEnums.ts, 40, 25), Decl(constEnums.ts, 51, 25)) ->V1 : Symbol(I.V1, Decl(constEnums.ts, 41, 33)) +>A.B.C.E.V1 : Symbol(I.V1, Decl(constEnums.ts, 42, 33)) +>A.B.C.E : Symbol(I, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) +>A.B.C : Symbol(A.B.C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) +>A.B : Symbol(A.B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) +>A : Symbol(A, Decl(constEnums.ts, 36, 1), Decl(constEnums.ts, 48, 1)) +>B : Symbol(A.B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) +>C : Symbol(A.B.C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) +>E : Symbol(I, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) +>V1 : Symbol(I.V1, Decl(constEnums.ts, 42, 33)) case A.B.C.E.V2: return 1; ->A.B.C.E.V2 : Symbol(I.V2, Decl(constEnums.ts, 42, 23)) ->A.B.C.E : Symbol(I, Decl(constEnums.ts, 40, 25), Decl(constEnums.ts, 51, 25)) ->A.B.C : Symbol(A.B.C, Decl(constEnums.ts, 39, 21), Decl(constEnums.ts, 50, 21)) ->A.B : Symbol(A.B, Decl(constEnums.ts, 38, 10), Decl(constEnums.ts, 49, 10)) ->A : Symbol(A, Decl(constEnums.ts, 35, 1), Decl(constEnums.ts, 47, 1)) ->B : Symbol(A.B, Decl(constEnums.ts, 38, 10), Decl(constEnums.ts, 49, 10)) ->C : Symbol(A.B.C, Decl(constEnums.ts, 39, 21), Decl(constEnums.ts, 50, 21)) ->E : Symbol(I, Decl(constEnums.ts, 40, 25), Decl(constEnums.ts, 51, 25)) ->V2 : Symbol(I.V2, Decl(constEnums.ts, 42, 23)) +>A.B.C.E.V2 : Symbol(I.V2, Decl(constEnums.ts, 43, 23)) +>A.B.C.E : Symbol(I, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) +>A.B.C : Symbol(A.B.C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) +>A.B : Symbol(A.B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) +>A : Symbol(A, Decl(constEnums.ts, 36, 1), Decl(constEnums.ts, 48, 1)) +>B : Symbol(A.B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) +>C : Symbol(A.B.C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) +>E : Symbol(I, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) +>V2 : Symbol(I.V2, Decl(constEnums.ts, 43, 23)) case A.B.C.E.V3: return 1; ->A.B.C.E.V3 : Symbol(I.V3, Decl(constEnums.ts, 52, 33)) ->A.B.C.E : Symbol(I, Decl(constEnums.ts, 40, 25), Decl(constEnums.ts, 51, 25)) ->A.B.C : Symbol(A.B.C, Decl(constEnums.ts, 39, 21), Decl(constEnums.ts, 50, 21)) ->A.B : Symbol(A.B, Decl(constEnums.ts, 38, 10), Decl(constEnums.ts, 49, 10)) ->A : Symbol(A, Decl(constEnums.ts, 35, 1), Decl(constEnums.ts, 47, 1)) ->B : Symbol(A.B, Decl(constEnums.ts, 38, 10), Decl(constEnums.ts, 49, 10)) ->C : Symbol(A.B.C, Decl(constEnums.ts, 39, 21), Decl(constEnums.ts, 50, 21)) ->E : Symbol(I, Decl(constEnums.ts, 40, 25), Decl(constEnums.ts, 51, 25)) ->V3 : Symbol(I.V3, Decl(constEnums.ts, 52, 33)) +>A.B.C.E.V3 : Symbol(I.V3, Decl(constEnums.ts, 53, 33)) +>A.B.C.E : Symbol(I, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) +>A.B.C : Symbol(A.B.C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) +>A.B : Symbol(A.B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) +>A : Symbol(A, Decl(constEnums.ts, 36, 1), Decl(constEnums.ts, 48, 1)) +>B : Symbol(A.B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) +>C : Symbol(A.B.C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) +>E : Symbol(I, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) +>V3 : Symbol(I.V3, Decl(constEnums.ts, 53, 33)) } } diff --git a/tests/baselines/reference/constEnums.types b/tests/baselines/reference/constEnums.types index c0bfef9143..a7c5416048 100644 --- a/tests/baselines/reference/constEnums.types +++ b/tests/baselines/reference/constEnums.types @@ -103,6 +103,12 @@ const enum Enum1 { >E : Enum1 >1 : 1 + PQ = E ** 2, +>PQ : Enum1 +>E ** 2 : number +>E : Enum1 +>2 : 2 + Q = -D, >Q : Enum1 >-D : number @@ -478,6 +484,11 @@ function foo(x: Enum1) { >Enum1 : typeof Enum1 >P : Enum1 + case Enum1.PQ: +>Enum1.PQ : Enum1 +>Enum1 : typeof Enum1 +>PQ : Enum1 + case Enum1.Q: >Enum1.Q : Enum1 >Enum1 : typeof Enum1 diff --git a/tests/baselines/reference/fixSignatureCaching.errors.txt b/tests/baselines/reference/fixSignatureCaching.errors.txt index 7a5c43c966..e991908c85 100644 --- a/tests/baselines/reference/fixSignatureCaching.errors.txt +++ b/tests/baselines/reference/fixSignatureCaching.errors.txt @@ -3,75 +3,76 @@ tests/cases/conformance/fixSignatureCaching.ts(284,10): error TS2339: Property ' tests/cases/conformance/fixSignatureCaching.ts(293,10): error TS2339: Property 'FALLBACK_PHONE' does not exist on type '{}'. tests/cases/conformance/fixSignatureCaching.ts(294,10): error TS2339: Property 'FALLBACK_TABLET' does not exist on type '{}'. tests/cases/conformance/fixSignatureCaching.ts(295,10): error TS2339: Property 'FALLBACK_MOBILE' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(327,74): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(366,10): error TS2339: Property 'findMatch' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(384,10): error TS2339: Property 'findMatches' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(404,10): error TS2339: Property 'getVersionStr' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(405,26): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(428,10): error TS2339: Property 'getVersion' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(429,28): error TS2339: Property 'getVersionStr' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(430,31): error TS2339: Property 'prepareVersionNo' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(440,10): error TS2339: Property 'prepareVersionNo' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(455,10): error TS2339: Property 'isMobileFallback' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(456,21): error TS2339: Property 'detectMobileBrowsers' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(457,18): error TS2339: Property 'detectMobileBrowsers' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(460,10): error TS2339: Property 'isTabletFallback' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(461,21): error TS2339: Property 'detectMobileBrowsers' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(464,10): error TS2339: Property 'prepareDetectionCache' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(471,23): error TS2339: Property 'findMatch' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(471,38): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(478,22): error TS2339: Property 'findMatch' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(478,37): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(486,18): error TS2339: Property 'isMobileFallback' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(487,39): error TS2339: Property 'isPhoneSized' does not exist on type '(userAgent: any, maxPhoneWidth: any) => void'. -tests/cases/conformance/fixSignatureCaching.ts(489,37): error TS2339: Property 'FALLBACK_MOBILE' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(492,51): error TS2339: Property 'FALLBACK_PHONE' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(495,52): error TS2339: Property 'FALLBACK_TABLET' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(498,25): error TS2339: Property 'isTabletFallback' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(499,48): error TS2339: Property 'FALLBACK_TABLET' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(508,10): error TS2339: Property 'mobileGrade' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(633,10): error TS2339: Property 'detectOS' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(634,21): error TS2339: Property 'findMatch' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(634,36): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(635,18): error TS2339: Property 'findMatch' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(635,33): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(638,10): error TS2339: Property 'getDeviceSmallerSide' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(639,16): error TS2304: Cannot find name 'window'. -tests/cases/conformance/fixSignatureCaching.ts(639,38): error TS2304: Cannot find name 'window'. -tests/cases/conformance/fixSignatureCaching.ts(640,13): error TS2304: Cannot find name 'window'. -tests/cases/conformance/fixSignatureCaching.ts(641,13): error TS2304: Cannot find name 'window'. -tests/cases/conformance/fixSignatureCaching.ts(704,18): error TS2339: Property 'prepareDetectionCache' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(734,18): error TS2339: Property 'prepareDetectionCache' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(783,18): error TS2339: Property 'prepareDetectionCache' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(805,46): error TS2339: Property 'findMatch' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(805,61): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(828,47): error TS2339: Property 'findMatches' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(828,64): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(845,39): error TS2339: Property 'detectOS' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(869,25): error TS2339: Property 'getVersion' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(890,25): error TS2339: Property 'getVersionStr' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(912,36): error TS2339: Property 'findMatches' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(912,53): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(941,33): error TS2339: Property 'isPhoneSized' does not exist on type '(userAgent: any, maxPhoneWidth: any) => void'. -tests/cases/conformance/fixSignatureCaching.ts(952,42): error TS2339: Property 'mobileGrade' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(959,16): error TS2304: Cannot find name 'window'. -tests/cases/conformance/fixSignatureCaching.ts(959,42): error TS2304: Cannot find name 'window'. -tests/cases/conformance/fixSignatureCaching.ts(960,22): error TS2339: Property 'isPhoneSized' does not exist on type '(userAgent: any, maxPhoneWidth: any) => void'. -tests/cases/conformance/fixSignatureCaching.ts(961,57): error TS2339: Property 'getDeviceSmallerSide' does not exist on type '{}'. -tests/cases/conformance/fixSignatureCaching.ts(964,22): error TS2339: Property 'isPhoneSized' does not exist on type '(userAgent: any, maxPhoneWidth: any) => void'. -tests/cases/conformance/fixSignatureCaching.ts(968,18): error TS2339: Property '_impl' does not exist on type '(userAgent: any, maxPhoneWidth: any) => void'. -tests/cases/conformance/fixSignatureCaching.ts(970,18): error TS2339: Property 'version' does not exist on type '(userAgent: any, maxPhoneWidth: any) => void'. -tests/cases/conformance/fixSignatureCaching.ts(975,16): error TS2304: Cannot find name 'module'. -tests/cases/conformance/fixSignatureCaching.ts(975,42): error TS2304: Cannot find name 'module'. -tests/cases/conformance/fixSignatureCaching.ts(976,37): error TS2304: Cannot find name 'module'. -tests/cases/conformance/fixSignatureCaching.ts(977,23): error TS2304: Cannot find name 'define'. -tests/cases/conformance/fixSignatureCaching.ts(977,48): error TS2304: Cannot find name 'define'. -tests/cases/conformance/fixSignatureCaching.ts(978,16): error TS2304: Cannot find name 'define'. -tests/cases/conformance/fixSignatureCaching.ts(979,23): error TS2304: Cannot find name 'window'. -tests/cases/conformance/fixSignatureCaching.ts(980,37): error TS2304: Cannot find name 'window'. +tests/cases/conformance/fixSignatureCaching.ts(301,17): error TS2339: Property 'isArray' does not exist on type 'never'. +tests/cases/conformance/fixSignatureCaching.ts(330,74): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(369,10): error TS2339: Property 'findMatch' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(387,10): error TS2339: Property 'findMatches' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(407,10): error TS2339: Property 'getVersionStr' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(408,26): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(431,10): error TS2339: Property 'getVersion' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(432,28): error TS2339: Property 'getVersionStr' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(433,31): error TS2339: Property 'prepareVersionNo' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(443,10): error TS2339: Property 'prepareVersionNo' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(458,10): error TS2339: Property 'isMobileFallback' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(459,21): error TS2339: Property 'detectMobileBrowsers' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(460,18): error TS2339: Property 'detectMobileBrowsers' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(463,10): error TS2339: Property 'isTabletFallback' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(464,21): error TS2339: Property 'detectMobileBrowsers' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(467,10): error TS2339: Property 'prepareDetectionCache' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(474,23): error TS2339: Property 'findMatch' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(474,38): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(481,22): error TS2339: Property 'findMatch' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(481,37): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(489,18): error TS2339: Property 'isMobileFallback' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(490,39): error TS2339: Property 'isPhoneSized' does not exist on type '(userAgent: any, maxPhoneWidth: any) => void'. +tests/cases/conformance/fixSignatureCaching.ts(492,37): error TS2339: Property 'FALLBACK_MOBILE' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(495,51): error TS2339: Property 'FALLBACK_PHONE' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(498,52): error TS2339: Property 'FALLBACK_TABLET' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(501,25): error TS2339: Property 'isTabletFallback' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(502,48): error TS2339: Property 'FALLBACK_TABLET' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(511,10): error TS2339: Property 'mobileGrade' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(636,10): error TS2339: Property 'detectOS' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(637,21): error TS2339: Property 'findMatch' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(637,36): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(638,18): error TS2339: Property 'findMatch' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(638,33): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(641,10): error TS2339: Property 'getDeviceSmallerSide' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(642,16): error TS2304: Cannot find name 'window'. +tests/cases/conformance/fixSignatureCaching.ts(642,38): error TS2304: Cannot find name 'window'. +tests/cases/conformance/fixSignatureCaching.ts(643,13): error TS2304: Cannot find name 'window'. +tests/cases/conformance/fixSignatureCaching.ts(644,13): error TS2304: Cannot find name 'window'. +tests/cases/conformance/fixSignatureCaching.ts(707,18): error TS2339: Property 'prepareDetectionCache' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(737,18): error TS2339: Property 'prepareDetectionCache' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(786,18): error TS2339: Property 'prepareDetectionCache' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(808,46): error TS2339: Property 'findMatch' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(808,61): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(831,47): error TS2339: Property 'findMatches' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(831,64): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(848,39): error TS2339: Property 'detectOS' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(872,25): error TS2339: Property 'getVersion' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(893,25): error TS2339: Property 'getVersionStr' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(915,36): error TS2339: Property 'findMatches' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(915,53): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(944,33): error TS2339: Property 'isPhoneSized' does not exist on type '(userAgent: any, maxPhoneWidth: any) => void'. +tests/cases/conformance/fixSignatureCaching.ts(955,42): error TS2339: Property 'mobileGrade' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(962,16): error TS2304: Cannot find name 'window'. +tests/cases/conformance/fixSignatureCaching.ts(962,42): error TS2304: Cannot find name 'window'. +tests/cases/conformance/fixSignatureCaching.ts(963,22): error TS2339: Property 'isPhoneSized' does not exist on type '(userAgent: any, maxPhoneWidth: any) => void'. +tests/cases/conformance/fixSignatureCaching.ts(964,57): error TS2339: Property 'getDeviceSmallerSide' does not exist on type '{}'. +tests/cases/conformance/fixSignatureCaching.ts(967,22): error TS2339: Property 'isPhoneSized' does not exist on type '(userAgent: any, maxPhoneWidth: any) => void'. +tests/cases/conformance/fixSignatureCaching.ts(971,18): error TS2339: Property '_impl' does not exist on type '(userAgent: any, maxPhoneWidth: any) => void'. +tests/cases/conformance/fixSignatureCaching.ts(973,18): error TS2339: Property 'version' does not exist on type '(userAgent: any, maxPhoneWidth: any) => void'. +tests/cases/conformance/fixSignatureCaching.ts(978,16): error TS2304: Cannot find name 'module'. +tests/cases/conformance/fixSignatureCaching.ts(978,42): error TS2304: Cannot find name 'module'. +tests/cases/conformance/fixSignatureCaching.ts(979,37): error TS2304: Cannot find name 'module'. +tests/cases/conformance/fixSignatureCaching.ts(980,23): error TS2304: Cannot find name 'define'. +tests/cases/conformance/fixSignatureCaching.ts(980,48): error TS2304: Cannot find name 'define'. +tests/cases/conformance/fixSignatureCaching.ts(981,16): error TS2304: Cannot find name 'define'. +tests/cases/conformance/fixSignatureCaching.ts(982,23): error TS2304: Cannot find name 'window'. +tests/cases/conformance/fixSignatureCaching.ts(983,37): error TS2304: Cannot find name 'window'. -==== tests/cases/conformance/fixSignatureCaching.ts (71 errors) ==== +==== tests/cases/conformance/fixSignatureCaching.ts (72 errors) ==== // Repro from #10697 (function (define, undefined) { @@ -380,6 +381,11 @@ tests/cases/conformance/fixSignatureCaching.ts(980,37): error TS2304: Cannot fin isArray = ('isArray' in Array) ? Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }; + isArray = 'isArray' in Array + ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } + : Array.isArray; + ~~~~~~~ +!!! error TS2339: Property 'isArray' does not exist on type 'never'. function equalIC(a, b) { return a != null && b != null && a.toLowerCase() === b.toLowerCase(); @@ -1164,7 +1170,7 @@ tests/cases/conformance/fixSignatureCaching.ts(980,37): error TS2304: Cannot fin MobileDetect._impl = impl; ~~~~~ !!! error TS2339: Property '_impl' does not exist on type '(userAgent: any, maxPhoneWidth: any) => void'. - + MobileDetect.version = '1.3.3 2016-07-31'; ~~~~~~~ !!! error TS2339: Property 'version' does not exist on type '(userAgent: any, maxPhoneWidth: any) => void'. diff --git a/tests/baselines/reference/fixSignatureCaching.js b/tests/baselines/reference/fixSignatureCaching.js index 231c1308c5..63dbfa960c 100644 --- a/tests/baselines/reference/fixSignatureCaching.js +++ b/tests/baselines/reference/fixSignatureCaching.js @@ -297,6 +297,9 @@ define(function () { isArray = ('isArray' in Array) ? Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }; + isArray = 'isArray' in Array + ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } + : Array.isArray; function equalIC(a, b) { return a != null && b != null && a.toLowerCase() === b.toLowerCase(); @@ -967,7 +970,7 @@ define(function () { // should not be replaced by a completely new object - just overwrite existing methods MobileDetect._impl = impl; - + MobileDetect.version = '1.3.3 2016-07-31'; return MobileDetect; @@ -1276,6 +1279,9 @@ define(function () { impl.FALLBACK_MOBILE = 'UnknownMobile'; isArray = ('isArray' in Array) ? Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }; + isArray = 'isArray' in Array + ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } + : Array.isArray; function equalIC(a, b) { return a != null && b != null && a.toLowerCase() === b.toLowerCase(); } diff --git a/tests/baselines/reference/fixSignatureCaching.symbols b/tests/baselines/reference/fixSignatureCaching.symbols index 40eb658fd6..87cf8d0c44 100644 --- a/tests/baselines/reference/fixSignatureCaching.symbols +++ b/tests/baselines/reference/fixSignatureCaching.symbols @@ -342,49 +342,67 @@ define(function () { >call : Symbol(Function.call, Decl(lib.d.ts, --, --)) >value : Symbol(value, Decl(fixSignatureCaching.ts, 297, 34)) + isArray = 'isArray' in Array +>isArray : Symbol(isArray, Decl(fixSignatureCaching.ts, 289, 53)) +>Array : Symbol(Array, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + + ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } +>value : Symbol(value, Decl(fixSignatureCaching.ts, 299, 20)) +>Object.prototype.toString.call : Symbol(Function.call, Decl(lib.d.ts, --, --)) +>Object.prototype.toString : Symbol(Object.toString, Decl(lib.d.ts, --, --)) +>Object.prototype : Symbol(ObjectConstructor.prototype, Decl(lib.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>prototype : Symbol(ObjectConstructor.prototype, Decl(lib.d.ts, --, --)) +>toString : Symbol(Object.toString, Decl(lib.d.ts, --, --)) +>call : Symbol(Function.call, Decl(lib.d.ts, --, --)) +>value : Symbol(value, Decl(fixSignatureCaching.ts, 299, 20)) + + : Array.isArray; +>Array : Symbol(Array, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + function equalIC(a, b) { ->equalIC : Symbol(equalIC, Decl(fixSignatureCaching.ts, 297, 112)) ->a : Symbol(a, Decl(fixSignatureCaching.ts, 299, 21)) ->b : Symbol(b, Decl(fixSignatureCaching.ts, 299, 23)) +>equalIC : Symbol(equalIC, Decl(fixSignatureCaching.ts, 300, 24)) +>a : Symbol(a, Decl(fixSignatureCaching.ts, 302, 21)) +>b : Symbol(b, Decl(fixSignatureCaching.ts, 302, 23)) return a != null && b != null && a.toLowerCase() === b.toLowerCase(); ->a : Symbol(a, Decl(fixSignatureCaching.ts, 299, 21)) ->b : Symbol(b, Decl(fixSignatureCaching.ts, 299, 23)) ->a : Symbol(a, Decl(fixSignatureCaching.ts, 299, 21)) ->b : Symbol(b, Decl(fixSignatureCaching.ts, 299, 23)) +>a : Symbol(a, Decl(fixSignatureCaching.ts, 302, 21)) +>b : Symbol(b, Decl(fixSignatureCaching.ts, 302, 23)) +>a : Symbol(a, Decl(fixSignatureCaching.ts, 302, 21)) +>b : Symbol(b, Decl(fixSignatureCaching.ts, 302, 23)) } function containsIC(array, value) { ->containsIC : Symbol(containsIC, Decl(fixSignatureCaching.ts, 301, 5)) ->array : Symbol(array, Decl(fixSignatureCaching.ts, 303, 24)) ->value : Symbol(value, Decl(fixSignatureCaching.ts, 303, 30)) +>containsIC : Symbol(containsIC, Decl(fixSignatureCaching.ts, 304, 5)) +>array : Symbol(array, Decl(fixSignatureCaching.ts, 306, 24)) +>value : Symbol(value, Decl(fixSignatureCaching.ts, 306, 30)) var valueLC, i, len = array.length; ->valueLC : Symbol(valueLC, Decl(fixSignatureCaching.ts, 304, 11)) ->i : Symbol(i, Decl(fixSignatureCaching.ts, 304, 20)) ->len : Symbol(len, Decl(fixSignatureCaching.ts, 304, 23)) ->array : Symbol(array, Decl(fixSignatureCaching.ts, 303, 24)) +>valueLC : Symbol(valueLC, Decl(fixSignatureCaching.ts, 307, 11)) +>i : Symbol(i, Decl(fixSignatureCaching.ts, 307, 20)) +>len : Symbol(len, Decl(fixSignatureCaching.ts, 307, 23)) +>array : Symbol(array, Decl(fixSignatureCaching.ts, 306, 24)) if (!len || !value) { ->len : Symbol(len, Decl(fixSignatureCaching.ts, 304, 23)) ->value : Symbol(value, Decl(fixSignatureCaching.ts, 303, 30)) +>len : Symbol(len, Decl(fixSignatureCaching.ts, 307, 23)) +>value : Symbol(value, Decl(fixSignatureCaching.ts, 306, 30)) return false; } valueLC = value.toLowerCase(); ->valueLC : Symbol(valueLC, Decl(fixSignatureCaching.ts, 304, 11)) ->value : Symbol(value, Decl(fixSignatureCaching.ts, 303, 30)) +>valueLC : Symbol(valueLC, Decl(fixSignatureCaching.ts, 307, 11)) +>value : Symbol(value, Decl(fixSignatureCaching.ts, 306, 30)) for (i = 0; i < len; ++i) { ->i : Symbol(i, Decl(fixSignatureCaching.ts, 304, 20)) ->i : Symbol(i, Decl(fixSignatureCaching.ts, 304, 20)) ->len : Symbol(len, Decl(fixSignatureCaching.ts, 304, 23)) ->i : Symbol(i, Decl(fixSignatureCaching.ts, 304, 20)) +>i : Symbol(i, Decl(fixSignatureCaching.ts, 307, 20)) +>i : Symbol(i, Decl(fixSignatureCaching.ts, 307, 20)) +>len : Symbol(len, Decl(fixSignatureCaching.ts, 307, 23)) +>i : Symbol(i, Decl(fixSignatureCaching.ts, 307, 20)) if (valueLC === array[i].toLowerCase()) { ->valueLC : Symbol(valueLC, Decl(fixSignatureCaching.ts, 304, 11)) ->array : Symbol(array, Decl(fixSignatureCaching.ts, 303, 24)) ->i : Symbol(i, Decl(fixSignatureCaching.ts, 304, 20)) +>valueLC : Symbol(valueLC, Decl(fixSignatureCaching.ts, 307, 11)) +>array : Symbol(array, Decl(fixSignatureCaching.ts, 306, 24)) +>i : Symbol(i, Decl(fixSignatureCaching.ts, 307, 20)) return true; } @@ -393,139 +411,139 @@ define(function () { } function convertPropsToRegExp(object) { ->convertPropsToRegExp : Symbol(convertPropsToRegExp, Decl(fixSignatureCaching.ts, 315, 5)) ->object : Symbol(object, Decl(fixSignatureCaching.ts, 317, 34)) +>convertPropsToRegExp : Symbol(convertPropsToRegExp, Decl(fixSignatureCaching.ts, 318, 5)) +>object : Symbol(object, Decl(fixSignatureCaching.ts, 320, 34)) for (var key in object) { ->key : Symbol(key, Decl(fixSignatureCaching.ts, 318, 16)) ->object : Symbol(object, Decl(fixSignatureCaching.ts, 317, 34)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 321, 16)) +>object : Symbol(object, Decl(fixSignatureCaching.ts, 320, 34)) if (hasOwnProp.call(object, key)) { >hasOwnProp.call : Symbol(Function.call, Decl(lib.d.ts, --, --)) >hasOwnProp : Symbol(hasOwnProp, Decl(fixSignatureCaching.ts, 289, 7)) >call : Symbol(Function.call, Decl(lib.d.ts, --, --)) ->object : Symbol(object, Decl(fixSignatureCaching.ts, 317, 34)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 318, 16)) +>object : Symbol(object, Decl(fixSignatureCaching.ts, 320, 34)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 321, 16)) object[key] = new RegExp(object[key], 'i'); ->object : Symbol(object, Decl(fixSignatureCaching.ts, 317, 34)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 318, 16)) +>object : Symbol(object, Decl(fixSignatureCaching.ts, 320, 34)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 321, 16)) >RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) ->object : Symbol(object, Decl(fixSignatureCaching.ts, 317, 34)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 318, 16)) +>object : Symbol(object, Decl(fixSignatureCaching.ts, 320, 34)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 321, 16)) } } } (function init() { ->init : Symbol(init, Decl(fixSignatureCaching.ts, 325, 5)) +>init : Symbol(init, Decl(fixSignatureCaching.ts, 328, 5)) var key, values, value, i, len, verPos, mobileDetectRules = impl.mobileDetectRules; ->key : Symbol(key, Decl(fixSignatureCaching.ts, 326, 11)) ->values : Symbol(values, Decl(fixSignatureCaching.ts, 326, 16)) ->value : Symbol(value, Decl(fixSignatureCaching.ts, 326, 24)) ->i : Symbol(i, Decl(fixSignatureCaching.ts, 326, 31)) ->len : Symbol(len, Decl(fixSignatureCaching.ts, 326, 34)) ->verPos : Symbol(verPos, Decl(fixSignatureCaching.ts, 326, 39)) ->mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 326, 47)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 329, 11)) +>values : Symbol(values, Decl(fixSignatureCaching.ts, 329, 16)) +>value : Symbol(value, Decl(fixSignatureCaching.ts, 329, 24)) +>i : Symbol(i, Decl(fixSignatureCaching.ts, 329, 31)) +>len : Symbol(len, Decl(fixSignatureCaching.ts, 329, 34)) +>verPos : Symbol(verPos, Decl(fixSignatureCaching.ts, 329, 39)) +>mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 329, 47)) >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) for (key in mobileDetectRules.props) { ->key : Symbol(key, Decl(fixSignatureCaching.ts, 326, 11)) ->mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 326, 47)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 329, 11)) +>mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 329, 47)) if (hasOwnProp.call(mobileDetectRules.props, key)) { >hasOwnProp.call : Symbol(Function.call, Decl(lib.d.ts, --, --)) >hasOwnProp : Symbol(hasOwnProp, Decl(fixSignatureCaching.ts, 289, 7)) >call : Symbol(Function.call, Decl(lib.d.ts, --, --)) ->mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 326, 47)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 326, 11)) +>mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 329, 47)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 329, 11)) values = mobileDetectRules.props[key]; ->values : Symbol(values, Decl(fixSignatureCaching.ts, 326, 16)) ->mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 326, 47)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 326, 11)) +>values : Symbol(values, Decl(fixSignatureCaching.ts, 329, 16)) +>mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 329, 47)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 329, 11)) if (!isArray(values)) { >isArray : Symbol(isArray, Decl(fixSignatureCaching.ts, 289, 53)) ->values : Symbol(values, Decl(fixSignatureCaching.ts, 326, 16)) +>values : Symbol(values, Decl(fixSignatureCaching.ts, 329, 16)) values = [values]; ->values : Symbol(values, Decl(fixSignatureCaching.ts, 326, 16)) ->values : Symbol(values, Decl(fixSignatureCaching.ts, 326, 16)) +>values : Symbol(values, Decl(fixSignatureCaching.ts, 329, 16)) +>values : Symbol(values, Decl(fixSignatureCaching.ts, 329, 16)) } len = values.length; ->len : Symbol(len, Decl(fixSignatureCaching.ts, 326, 34)) ->values : Symbol(values, Decl(fixSignatureCaching.ts, 326, 16)) +>len : Symbol(len, Decl(fixSignatureCaching.ts, 329, 34)) +>values : Symbol(values, Decl(fixSignatureCaching.ts, 329, 16)) for (i = 0; i < len; ++i) { ->i : Symbol(i, Decl(fixSignatureCaching.ts, 326, 31)) ->i : Symbol(i, Decl(fixSignatureCaching.ts, 326, 31)) ->len : Symbol(len, Decl(fixSignatureCaching.ts, 326, 34)) ->i : Symbol(i, Decl(fixSignatureCaching.ts, 326, 31)) +>i : Symbol(i, Decl(fixSignatureCaching.ts, 329, 31)) +>i : Symbol(i, Decl(fixSignatureCaching.ts, 329, 31)) +>len : Symbol(len, Decl(fixSignatureCaching.ts, 329, 34)) +>i : Symbol(i, Decl(fixSignatureCaching.ts, 329, 31)) value = values[i]; ->value : Symbol(value, Decl(fixSignatureCaching.ts, 326, 24)) ->values : Symbol(values, Decl(fixSignatureCaching.ts, 326, 16)) ->i : Symbol(i, Decl(fixSignatureCaching.ts, 326, 31)) +>value : Symbol(value, Decl(fixSignatureCaching.ts, 329, 24)) +>values : Symbol(values, Decl(fixSignatureCaching.ts, 329, 16)) +>i : Symbol(i, Decl(fixSignatureCaching.ts, 329, 31)) verPos = value.indexOf('[VER]'); ->verPos : Symbol(verPos, Decl(fixSignatureCaching.ts, 326, 39)) ->value : Symbol(value, Decl(fixSignatureCaching.ts, 326, 24)) +>verPos : Symbol(verPos, Decl(fixSignatureCaching.ts, 329, 39)) +>value : Symbol(value, Decl(fixSignatureCaching.ts, 329, 24)) if (verPos >= 0) { ->verPos : Symbol(verPos, Decl(fixSignatureCaching.ts, 326, 39)) +>verPos : Symbol(verPos, Decl(fixSignatureCaching.ts, 329, 39)) value = value.substring(0, verPos) + '([\\w._\\+]+)' + value.substring(verPos + 5); ->value : Symbol(value, Decl(fixSignatureCaching.ts, 326, 24)) ->value : Symbol(value, Decl(fixSignatureCaching.ts, 326, 24)) ->verPos : Symbol(verPos, Decl(fixSignatureCaching.ts, 326, 39)) ->value : Symbol(value, Decl(fixSignatureCaching.ts, 326, 24)) ->verPos : Symbol(verPos, Decl(fixSignatureCaching.ts, 326, 39)) +>value : Symbol(value, Decl(fixSignatureCaching.ts, 329, 24)) +>value : Symbol(value, Decl(fixSignatureCaching.ts, 329, 24)) +>verPos : Symbol(verPos, Decl(fixSignatureCaching.ts, 329, 39)) +>value : Symbol(value, Decl(fixSignatureCaching.ts, 329, 24)) +>verPos : Symbol(verPos, Decl(fixSignatureCaching.ts, 329, 39)) } values[i] = new RegExp(value, 'i'); ->values : Symbol(values, Decl(fixSignatureCaching.ts, 326, 16)) ->i : Symbol(i, Decl(fixSignatureCaching.ts, 326, 31)) +>values : Symbol(values, Decl(fixSignatureCaching.ts, 329, 16)) +>i : Symbol(i, Decl(fixSignatureCaching.ts, 329, 31)) >RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) ->value : Symbol(value, Decl(fixSignatureCaching.ts, 326, 24)) +>value : Symbol(value, Decl(fixSignatureCaching.ts, 329, 24)) } mobileDetectRules.props[key] = values; ->mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 326, 47)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 326, 11)) ->values : Symbol(values, Decl(fixSignatureCaching.ts, 326, 16)) +>mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 329, 47)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 329, 11)) +>values : Symbol(values, Decl(fixSignatureCaching.ts, 329, 16)) } } convertPropsToRegExp(mobileDetectRules.oss); ->convertPropsToRegExp : Symbol(convertPropsToRegExp, Decl(fixSignatureCaching.ts, 315, 5)) ->mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 326, 47)) +>convertPropsToRegExp : Symbol(convertPropsToRegExp, Decl(fixSignatureCaching.ts, 318, 5)) +>mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 329, 47)) convertPropsToRegExp(mobileDetectRules.phones); ->convertPropsToRegExp : Symbol(convertPropsToRegExp, Decl(fixSignatureCaching.ts, 315, 5)) ->mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 326, 47)) +>convertPropsToRegExp : Symbol(convertPropsToRegExp, Decl(fixSignatureCaching.ts, 318, 5)) +>mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 329, 47)) convertPropsToRegExp(mobileDetectRules.tablets); ->convertPropsToRegExp : Symbol(convertPropsToRegExp, Decl(fixSignatureCaching.ts, 315, 5)) ->mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 326, 47)) +>convertPropsToRegExp : Symbol(convertPropsToRegExp, Decl(fixSignatureCaching.ts, 318, 5)) +>mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 329, 47)) convertPropsToRegExp(mobileDetectRules.uas); ->convertPropsToRegExp : Symbol(convertPropsToRegExp, Decl(fixSignatureCaching.ts, 315, 5)) ->mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 326, 47)) +>convertPropsToRegExp : Symbol(convertPropsToRegExp, Decl(fixSignatureCaching.ts, 318, 5)) +>mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 329, 47)) convertPropsToRegExp(mobileDetectRules.utils); ->convertPropsToRegExp : Symbol(convertPropsToRegExp, Decl(fixSignatureCaching.ts, 315, 5)) ->mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 326, 47)) +>convertPropsToRegExp : Symbol(convertPropsToRegExp, Decl(fixSignatureCaching.ts, 318, 5)) +>mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 329, 47)) // copy some patterns to oss0 which are tested first (see issue#15) mobileDetectRules.oss0 = { ->mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 326, 47)) +>mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 329, 47)) WindowsPhoneOS: mobileDetectRules.oss.WindowsPhoneOS, ->WindowsPhoneOS : Symbol(WindowsPhoneOS, Decl(fixSignatureCaching.ts, 352, 34)) ->mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 326, 47)) +>WindowsPhoneOS : Symbol(WindowsPhoneOS, Decl(fixSignatureCaching.ts, 355, 34)) +>mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 329, 47)) WindowsMobileOS: mobileDetectRules.oss.WindowsMobileOS ->WindowsMobileOS : Symbol(WindowsMobileOS, Decl(fixSignatureCaching.ts, 353, 65)) ->mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 326, 47)) +>WindowsMobileOS : Symbol(WindowsMobileOS, Decl(fixSignatureCaching.ts, 356, 65)) +>mobileDetectRules : Symbol(mobileDetectRules, Decl(fixSignatureCaching.ts, 329, 47)) }; }()); @@ -539,27 +557,27 @@ define(function () { */ impl.findMatch = function(rules, userAgent) { >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->rules : Symbol(rules, Decl(fixSignatureCaching.ts, 365, 30)) ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 365, 36)) +>rules : Symbol(rules, Decl(fixSignatureCaching.ts, 368, 30)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 368, 36)) for (var key in rules) { ->key : Symbol(key, Decl(fixSignatureCaching.ts, 366, 16)) ->rules : Symbol(rules, Decl(fixSignatureCaching.ts, 365, 30)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 369, 16)) +>rules : Symbol(rules, Decl(fixSignatureCaching.ts, 368, 30)) if (hasOwnProp.call(rules, key)) { >hasOwnProp.call : Symbol(Function.call, Decl(lib.d.ts, --, --)) >hasOwnProp : Symbol(hasOwnProp, Decl(fixSignatureCaching.ts, 289, 7)) >call : Symbol(Function.call, Decl(lib.d.ts, --, --)) ->rules : Symbol(rules, Decl(fixSignatureCaching.ts, 365, 30)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 366, 16)) +>rules : Symbol(rules, Decl(fixSignatureCaching.ts, 368, 30)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 369, 16)) if (rules[key].test(userAgent)) { ->rules : Symbol(rules, Decl(fixSignatureCaching.ts, 365, 30)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 366, 16)) ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 365, 36)) +>rules : Symbol(rules, Decl(fixSignatureCaching.ts, 368, 30)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 369, 16)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 368, 36)) return key; ->key : Symbol(key, Decl(fixSignatureCaching.ts, 366, 16)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 369, 16)) } } } @@ -575,38 +593,38 @@ define(function () { */ impl.findMatches = function(rules, userAgent) { >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->rules : Symbol(rules, Decl(fixSignatureCaching.ts, 383, 32)) ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 383, 38)) +>rules : Symbol(rules, Decl(fixSignatureCaching.ts, 386, 32)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 386, 38)) var result = []; ->result : Symbol(result, Decl(fixSignatureCaching.ts, 384, 11)) +>result : Symbol(result, Decl(fixSignatureCaching.ts, 387, 11)) for (var key in rules) { ->key : Symbol(key, Decl(fixSignatureCaching.ts, 385, 16)) ->rules : Symbol(rules, Decl(fixSignatureCaching.ts, 383, 32)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 388, 16)) +>rules : Symbol(rules, Decl(fixSignatureCaching.ts, 386, 32)) if (hasOwnProp.call(rules, key)) { >hasOwnProp.call : Symbol(Function.call, Decl(lib.d.ts, --, --)) >hasOwnProp : Symbol(hasOwnProp, Decl(fixSignatureCaching.ts, 289, 7)) >call : Symbol(Function.call, Decl(lib.d.ts, --, --)) ->rules : Symbol(rules, Decl(fixSignatureCaching.ts, 383, 32)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 385, 16)) +>rules : Symbol(rules, Decl(fixSignatureCaching.ts, 386, 32)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 388, 16)) if (rules[key].test(userAgent)) { ->rules : Symbol(rules, Decl(fixSignatureCaching.ts, 383, 32)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 385, 16)) ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 383, 38)) +>rules : Symbol(rules, Decl(fixSignatureCaching.ts, 386, 32)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 388, 16)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 386, 38)) result.push(key); >result.push : Symbol(Array.push, Decl(lib.d.ts, --, --)) ->result : Symbol(result, Decl(fixSignatureCaching.ts, 384, 11)) +>result : Symbol(result, Decl(fixSignatureCaching.ts, 387, 11)) >push : Symbol(Array.push, Decl(lib.d.ts, --, --)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 385, 16)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 388, 16)) } } } return result; ->result : Symbol(result, Decl(fixSignatureCaching.ts, 384, 11)) +>result : Symbol(result, Decl(fixSignatureCaching.ts, 387, 11)) }; @@ -620,50 +638,50 @@ define(function () { */ impl.getVersionStr = function (propertyName, userAgent) { >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->propertyName : Symbol(propertyName, Decl(fixSignatureCaching.ts, 403, 35)) ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 403, 48)) +>propertyName : Symbol(propertyName, Decl(fixSignatureCaching.ts, 406, 35)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 406, 48)) var props = impl.mobileDetectRules.props, patterns, i, len, match; ->props : Symbol(props, Decl(fixSignatureCaching.ts, 404, 11)) +>props : Symbol(props, Decl(fixSignatureCaching.ts, 407, 11)) >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->patterns : Symbol(patterns, Decl(fixSignatureCaching.ts, 404, 49)) ->i : Symbol(i, Decl(fixSignatureCaching.ts, 404, 59)) ->len : Symbol(len, Decl(fixSignatureCaching.ts, 404, 62)) ->match : Symbol(match, Decl(fixSignatureCaching.ts, 404, 67)) +>patterns : Symbol(patterns, Decl(fixSignatureCaching.ts, 407, 49)) +>i : Symbol(i, Decl(fixSignatureCaching.ts, 407, 59)) +>len : Symbol(len, Decl(fixSignatureCaching.ts, 407, 62)) +>match : Symbol(match, Decl(fixSignatureCaching.ts, 407, 67)) if (hasOwnProp.call(props, propertyName)) { >hasOwnProp.call : Symbol(Function.call, Decl(lib.d.ts, --, --)) >hasOwnProp : Symbol(hasOwnProp, Decl(fixSignatureCaching.ts, 289, 7)) >call : Symbol(Function.call, Decl(lib.d.ts, --, --)) ->props : Symbol(props, Decl(fixSignatureCaching.ts, 404, 11)) ->propertyName : Symbol(propertyName, Decl(fixSignatureCaching.ts, 403, 35)) +>props : Symbol(props, Decl(fixSignatureCaching.ts, 407, 11)) +>propertyName : Symbol(propertyName, Decl(fixSignatureCaching.ts, 406, 35)) patterns = props[propertyName]; ->patterns : Symbol(patterns, Decl(fixSignatureCaching.ts, 404, 49)) ->props : Symbol(props, Decl(fixSignatureCaching.ts, 404, 11)) ->propertyName : Symbol(propertyName, Decl(fixSignatureCaching.ts, 403, 35)) +>patterns : Symbol(patterns, Decl(fixSignatureCaching.ts, 407, 49)) +>props : Symbol(props, Decl(fixSignatureCaching.ts, 407, 11)) +>propertyName : Symbol(propertyName, Decl(fixSignatureCaching.ts, 406, 35)) len = patterns.length; ->len : Symbol(len, Decl(fixSignatureCaching.ts, 404, 62)) ->patterns : Symbol(patterns, Decl(fixSignatureCaching.ts, 404, 49)) +>len : Symbol(len, Decl(fixSignatureCaching.ts, 407, 62)) +>patterns : Symbol(patterns, Decl(fixSignatureCaching.ts, 407, 49)) for (i = 0; i < len; ++i) { ->i : Symbol(i, Decl(fixSignatureCaching.ts, 404, 59)) ->i : Symbol(i, Decl(fixSignatureCaching.ts, 404, 59)) ->len : Symbol(len, Decl(fixSignatureCaching.ts, 404, 62)) ->i : Symbol(i, Decl(fixSignatureCaching.ts, 404, 59)) +>i : Symbol(i, Decl(fixSignatureCaching.ts, 407, 59)) +>i : Symbol(i, Decl(fixSignatureCaching.ts, 407, 59)) +>len : Symbol(len, Decl(fixSignatureCaching.ts, 407, 62)) +>i : Symbol(i, Decl(fixSignatureCaching.ts, 407, 59)) match = patterns[i].exec(userAgent); ->match : Symbol(match, Decl(fixSignatureCaching.ts, 404, 67)) ->patterns : Symbol(patterns, Decl(fixSignatureCaching.ts, 404, 49)) ->i : Symbol(i, Decl(fixSignatureCaching.ts, 404, 59)) ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 403, 48)) +>match : Symbol(match, Decl(fixSignatureCaching.ts, 407, 67)) +>patterns : Symbol(patterns, Decl(fixSignatureCaching.ts, 407, 49)) +>i : Symbol(i, Decl(fixSignatureCaching.ts, 407, 59)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 406, 48)) if (match !== null) { ->match : Symbol(match, Decl(fixSignatureCaching.ts, 404, 67)) +>match : Symbol(match, Decl(fixSignatureCaching.ts, 407, 67)) return match[1]; ->match : Symbol(match, Decl(fixSignatureCaching.ts, 404, 67)) +>match : Symbol(match, Decl(fixSignatureCaching.ts, 407, 67)) } } } @@ -681,19 +699,19 @@ define(function () { */ impl.getVersion = function (propertyName, userAgent) { >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->propertyName : Symbol(propertyName, Decl(fixSignatureCaching.ts, 427, 32)) ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 427, 45)) +>propertyName : Symbol(propertyName, Decl(fixSignatureCaching.ts, 430, 32)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 430, 45)) var version = impl.getVersionStr(propertyName, userAgent); ->version : Symbol(version, Decl(fixSignatureCaching.ts, 428, 11)) +>version : Symbol(version, Decl(fixSignatureCaching.ts, 431, 11)) >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->propertyName : Symbol(propertyName, Decl(fixSignatureCaching.ts, 427, 32)) ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 427, 45)) +>propertyName : Symbol(propertyName, Decl(fixSignatureCaching.ts, 430, 32)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 430, 45)) return version ? impl.prepareVersionNo(version) : NaN; ->version : Symbol(version, Decl(fixSignatureCaching.ts, 428, 11)) +>version : Symbol(version, Decl(fixSignatureCaching.ts, 431, 11)) >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->version : Symbol(version, Decl(fixSignatureCaching.ts, 428, 11)) +>version : Symbol(version, Decl(fixSignatureCaching.ts, 431, 11)) >NaN : Symbol(NaN, Decl(lib.d.ts, --, --)) }; @@ -707,120 +725,120 @@ define(function () { */ impl.prepareVersionNo = function (version) { >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->version : Symbol(version, Decl(fixSignatureCaching.ts, 439, 38)) +>version : Symbol(version, Decl(fixSignatureCaching.ts, 442, 38)) var numbers; ->numbers : Symbol(numbers, Decl(fixSignatureCaching.ts, 440, 11)) +>numbers : Symbol(numbers, Decl(fixSignatureCaching.ts, 443, 11)) numbers = version.split(/[a-z._ \/\-]/i); ->numbers : Symbol(numbers, Decl(fixSignatureCaching.ts, 440, 11)) ->version : Symbol(version, Decl(fixSignatureCaching.ts, 439, 38)) +>numbers : Symbol(numbers, Decl(fixSignatureCaching.ts, 443, 11)) +>version : Symbol(version, Decl(fixSignatureCaching.ts, 442, 38)) if (numbers.length === 1) { ->numbers : Symbol(numbers, Decl(fixSignatureCaching.ts, 440, 11)) +>numbers : Symbol(numbers, Decl(fixSignatureCaching.ts, 443, 11)) version = numbers[0]; ->version : Symbol(version, Decl(fixSignatureCaching.ts, 439, 38)) ->numbers : Symbol(numbers, Decl(fixSignatureCaching.ts, 440, 11)) +>version : Symbol(version, Decl(fixSignatureCaching.ts, 442, 38)) +>numbers : Symbol(numbers, Decl(fixSignatureCaching.ts, 443, 11)) } if (numbers.length > 1) { ->numbers : Symbol(numbers, Decl(fixSignatureCaching.ts, 440, 11)) +>numbers : Symbol(numbers, Decl(fixSignatureCaching.ts, 443, 11)) version = numbers[0] + '.'; ->version : Symbol(version, Decl(fixSignatureCaching.ts, 439, 38)) ->numbers : Symbol(numbers, Decl(fixSignatureCaching.ts, 440, 11)) +>version : Symbol(version, Decl(fixSignatureCaching.ts, 442, 38)) +>numbers : Symbol(numbers, Decl(fixSignatureCaching.ts, 443, 11)) numbers.shift(); ->numbers : Symbol(numbers, Decl(fixSignatureCaching.ts, 440, 11)) +>numbers : Symbol(numbers, Decl(fixSignatureCaching.ts, 443, 11)) version += numbers.join(''); ->version : Symbol(version, Decl(fixSignatureCaching.ts, 439, 38)) ->numbers : Symbol(numbers, Decl(fixSignatureCaching.ts, 440, 11)) +>version : Symbol(version, Decl(fixSignatureCaching.ts, 442, 38)) +>numbers : Symbol(numbers, Decl(fixSignatureCaching.ts, 443, 11)) } return Number(version); >Number : Symbol(Number, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) ->version : Symbol(version, Decl(fixSignatureCaching.ts, 439, 38)) +>version : Symbol(version, Decl(fixSignatureCaching.ts, 442, 38)) }; impl.isMobileFallback = function (userAgent) { >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 454, 38)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 457, 38)) return impl.detectMobileBrowsers.fullPattern.test(userAgent) || >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 454, 38)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 457, 38)) impl.detectMobileBrowsers.shortPattern.test(userAgent.substr(0,4)); >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 454, 38)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 457, 38)) }; impl.isTabletFallback = function (userAgent) { >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 459, 38)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 462, 38)) return impl.detectMobileBrowsers.tabletPattern.test(userAgent); >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 459, 38)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 462, 38)) }; impl.prepareDetectionCache = function (cache, userAgent, maxPhoneWidth) { >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 463, 49)) ->maxPhoneWidth : Symbol(maxPhoneWidth, Decl(fixSignatureCaching.ts, 463, 60)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 466, 49)) +>maxPhoneWidth : Symbol(maxPhoneWidth, Decl(fixSignatureCaching.ts, 466, 60)) if (cache.mobile !== undefined) { ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) >undefined : Symbol(undefined, Decl(fixSignatureCaching.ts, 2, 18)) return; } var phone, tablet, phoneSized; ->phone : Symbol(phone, Decl(fixSignatureCaching.ts, 467, 11)) ->tablet : Symbol(tablet, Decl(fixSignatureCaching.ts, 467, 18)) ->phoneSized : Symbol(phoneSized, Decl(fixSignatureCaching.ts, 467, 26)) +>phone : Symbol(phone, Decl(fixSignatureCaching.ts, 470, 11)) +>tablet : Symbol(tablet, Decl(fixSignatureCaching.ts, 470, 18)) +>phoneSized : Symbol(phoneSized, Decl(fixSignatureCaching.ts, 470, 26)) // first check for stronger tablet rules, then phone (see issue#5) tablet = impl.findMatch(impl.mobileDetectRules.tablets, userAgent); ->tablet : Symbol(tablet, Decl(fixSignatureCaching.ts, 467, 18)) +>tablet : Symbol(tablet, Decl(fixSignatureCaching.ts, 470, 18)) >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 463, 49)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 466, 49)) if (tablet) { ->tablet : Symbol(tablet, Decl(fixSignatureCaching.ts, 467, 18)) +>tablet : Symbol(tablet, Decl(fixSignatureCaching.ts, 470, 18)) cache.mobile = cache.tablet = tablet; ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) ->tablet : Symbol(tablet, Decl(fixSignatureCaching.ts, 467, 18)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) +>tablet : Symbol(tablet, Decl(fixSignatureCaching.ts, 470, 18)) cache.phone = null; ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) return; // unambiguously identified as tablet } phone = impl.findMatch(impl.mobileDetectRules.phones, userAgent); ->phone : Symbol(phone, Decl(fixSignatureCaching.ts, 467, 11)) +>phone : Symbol(phone, Decl(fixSignatureCaching.ts, 470, 11)) >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 463, 49)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 466, 49)) if (phone) { ->phone : Symbol(phone, Decl(fixSignatureCaching.ts, 467, 11)) +>phone : Symbol(phone, Decl(fixSignatureCaching.ts, 470, 11)) cache.mobile = cache.phone = phone; ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) ->phone : Symbol(phone, Decl(fixSignatureCaching.ts, 467, 11)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) +>phone : Symbol(phone, Decl(fixSignatureCaching.ts, 470, 11)) cache.tablet = null; ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) return; // unambiguously identified as phone } @@ -828,70 +846,70 @@ define(function () { // our rules haven't found a match -> try more general fallback rules if (impl.isMobileFallback(userAgent)) { >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 463, 49)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 466, 49)) phoneSized = MobileDetect.isPhoneSized(maxPhoneWidth); ->phoneSized : Symbol(phoneSized, Decl(fixSignatureCaching.ts, 467, 26)) ->MobileDetect : Symbol(MobileDetect, Decl(fixSignatureCaching.ts, 641, 6)) ->maxPhoneWidth : Symbol(maxPhoneWidth, Decl(fixSignatureCaching.ts, 463, 60)) +>phoneSized : Symbol(phoneSized, Decl(fixSignatureCaching.ts, 470, 26)) +>MobileDetect : Symbol(MobileDetect, Decl(fixSignatureCaching.ts, 644, 6)) +>maxPhoneWidth : Symbol(maxPhoneWidth, Decl(fixSignatureCaching.ts, 466, 60)) if (phoneSized === undefined) { ->phoneSized : Symbol(phoneSized, Decl(fixSignatureCaching.ts, 467, 26)) +>phoneSized : Symbol(phoneSized, Decl(fixSignatureCaching.ts, 470, 26)) >undefined : Symbol(undefined, Decl(fixSignatureCaching.ts, 2, 18)) cache.mobile = impl.FALLBACK_MOBILE; ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) cache.tablet = cache.phone = null; ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) } else if (phoneSized) { ->phoneSized : Symbol(phoneSized, Decl(fixSignatureCaching.ts, 467, 26)) +>phoneSized : Symbol(phoneSized, Decl(fixSignatureCaching.ts, 470, 26)) cache.mobile = cache.phone = impl.FALLBACK_PHONE; ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) cache.tablet = null; ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) } else { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) cache.phone = null; ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) } } else if (impl.isTabletFallback(userAgent)) { >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 463, 49)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 466, 49)) cache.mobile = cache.tablet = impl.FALLBACK_TABLET; ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) cache.phone = null; ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) } else { // not mobile at all! cache.mobile = cache.tablet = cache.phone = null; ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) ->cache : Symbol(cache, Decl(fixSignatureCaching.ts, 463, 43)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) +>cache : Symbol(cache, Decl(fixSignatureCaching.ts, 466, 43)) } }; // t is a reference to a MobileDetect instance impl.mobileGrade = function (t) { >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // impl note: // To keep in sync w/ Mobile_Detect.php easily, the following code is tightly aligned to the PHP version. @@ -902,136 +920,136 @@ define(function () { // isIOS() / os('iOS') // [reg] / (nothing) <-- jsdelivr complaining about unescaped unicode character U+00AE var $isMobile = t.mobile() !== null; ->$isMobile : Symbol($isMobile, Decl(fixSignatureCaching.ts, 516, 11)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>$isMobile : Symbol($isMobile, Decl(fixSignatureCaching.ts, 519, 11)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) if ( // Apple iOS 3.2-5.1 - Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3), iPad 3 (5.1), original iPhone (3.1), iPhone 3 (3.2), 3GS (4.3), 4 (4.3 / 5.0), and 4S (5.1) t.os('iOS') && t.version('iPad')>=4.3 || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) t.os('iOS') && t.version('iPhone')>=3.1 || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) t.os('iOS') && t.version('iPod')>=3.1 || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5) // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7 ( t.version('Android')>2.1 && t.is('Webkit') ) || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // Windows Phone 7-7.5 - Tested on the HTC Surround (7.0) HTC Trophy (7.5), LG-E900 (7.5), Nokia Lumia 800 t.version('Windows Phone OS')>=7.0 || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // Blackberry 7 - Tested on BlackBerry Torch 9810 // Blackberry 6.0 - Tested on the Torch 9800 and Style 9670 t.is('BlackBerry') && t.version('BlackBerry')>=6.0 || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // Blackberry Playbook (1.0-2.0) - Tested on PlayBook t.match('Playbook.*Tablet') || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // Palm WebOS (1.4-2.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0) ( t.version('webOS')>=1.4 && t.match('Palm|Pre|Pixi') ) || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // Palm WebOS 3.0 - Tested on HP TouchPad t.match('hp.*TouchPad') || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // Firefox Mobile (12 Beta) - Tested on Android 2.3 device ( t.is('Firefox') && t.version('Firefox')>=12 ) || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // Chrome for Android - Tested on Android 4.0, 4.1 device ( t.is('Chrome') && t.is('AndroidOS') && t.version('Android')>=4.0 ) || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // Skyfire 4.1 - Tested on Android 2.3 device ( t.is('Skyfire') && t.version('Skyfire')>=4.1 && t.is('AndroidOS') && t.version('Android')>=2.3 ) || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // Opera Mobile 11.5-12: Tested on Android 2.3 ( t.is('Opera') && t.version('Opera Mobi')>11 && t.is('AndroidOS') ) || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // Meego 1.2 - Tested on Nokia 950 and N9 t.is('MeeGoOS') || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // Tizen (pre-release) - Tested on early hardware t.is('Tizen') || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser // @todo: more tests here! t.is('Dolfin') && t.version('Bada')>=2.0 || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // UC Browser - Tested on Android 2.3 device ( (t.is('UC Browser') || t.is('Dolfin')) && t.version('Android')>=2.3 ) || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // Kindle 3 and Fire - Tested on the built-in WebKit browser for each ( t.match('Kindle Fire') || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) t.is('Kindle') && t.version('Kindle')>=3.0 ) || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet t.is('AndroidOS') && t.is('NookTablet') || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // Chrome Desktop 11-21 - Tested on OS X 10.7 and Windows 7 t.version('Chrome')>=11 && !$isMobile || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->$isMobile : Symbol($isMobile, Decl(fixSignatureCaching.ts, 516, 11)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>$isMobile : Symbol($isMobile, Decl(fixSignatureCaching.ts, 519, 11)) // Safari Desktop 4-5 - Tested on OS X 10.7 and Windows 7 t.version('Safari')>=5.0 && !$isMobile || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->$isMobile : Symbol($isMobile, Decl(fixSignatureCaching.ts, 516, 11)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>$isMobile : Symbol($isMobile, Decl(fixSignatureCaching.ts, 519, 11)) // Firefox Desktop 4-13 - Tested on OS X 10.7 and Windows 7 t.version('Firefox')>=4.0 && !$isMobile || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->$isMobile : Symbol($isMobile, Decl(fixSignatureCaching.ts, 516, 11)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>$isMobile : Symbol($isMobile, Decl(fixSignatureCaching.ts, 519, 11)) // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7 t.version('MSIE')>=7.0 && !$isMobile || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->$isMobile : Symbol($isMobile, Decl(fixSignatureCaching.ts, 516, 11)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>$isMobile : Symbol($isMobile, Decl(fixSignatureCaching.ts, 519, 11)) // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7 // @reference: http://my.opera.com/community/openweb/idopera/ t.version('Opera')>=10 && !$isMobile ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->$isMobile : Symbol($isMobile, Decl(fixSignatureCaching.ts, 516, 11)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>$isMobile : Symbol($isMobile, Decl(fixSignatureCaching.ts, 519, 11)) ){ return 'A'; @@ -1039,40 +1057,40 @@ define(function () { if ( t.os('iOS') && t.version('iPad')<4.3 || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) t.os('iOS') && t.version('iPhone')<3.1 || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) t.os('iOS') && t.version('iPod')<3.1 || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770 t.is('Blackberry') && t.version('BlackBerry')>=5 && t.version('BlackBerry')<6 || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3 ( t.version('Opera Mini')>=5.0 && t.version('Opera Mini')<=6.5 && ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) (t.version('Android')>=2.3 || t.is('iOS')) ) || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1) t.match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // @todo: report this (tested on Nokia N71) t.version('Opera Mobi')>=11 && t.is('SymbianOS') ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) ){ return 'B'; @@ -1081,12 +1099,12 @@ define(function () { if ( // Blackberry 4.x - Tested on the Curve 8330 t.version('BlackBerry')<5.0 || ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) // Windows Mobile - Tested on the HTC Leo (WinMo 5.2) t.match('MSIEMobile|Windows CE.*Mobile') || t.version('Windows Mobile')<=5.2 ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) ->t : Symbol(t, Decl(fixSignatureCaching.ts, 507, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) +>t : Symbol(t, Decl(fixSignatureCaching.ts, 510, 33)) ){ return 'C'; @@ -1099,17 +1117,17 @@ define(function () { impl.detectOS = function (ua) { >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->ua : Symbol(ua, Decl(fixSignatureCaching.ts, 632, 30)) +>ua : Symbol(ua, Decl(fixSignatureCaching.ts, 635, 30)) return impl.findMatch(impl.mobileDetectRules.oss0, ua) || >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->ua : Symbol(ua, Decl(fixSignatureCaching.ts, 632, 30)) +>ua : Symbol(ua, Decl(fixSignatureCaching.ts, 635, 30)) impl.findMatch(impl.mobileDetectRules.oss, ua); >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->ua : Symbol(ua, Decl(fixSignatureCaching.ts, 632, 30)) +>ua : Symbol(ua, Decl(fixSignatureCaching.ts, 635, 30)) }; @@ -1149,27 +1167,27 @@ define(function () { * @global */ function MobileDetect(userAgent, maxPhoneWidth) { ->MobileDetect : Symbol(MobileDetect, Decl(fixSignatureCaching.ts, 641, 6)) ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 670, 26)) ->maxPhoneWidth : Symbol(maxPhoneWidth, Decl(fixSignatureCaching.ts, 670, 36)) +>MobileDetect : Symbol(MobileDetect, Decl(fixSignatureCaching.ts, 644, 6)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 673, 26)) +>maxPhoneWidth : Symbol(maxPhoneWidth, Decl(fixSignatureCaching.ts, 673, 36)) this.ua = userAgent || ''; ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 670, 26)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 673, 26)) this._cache = {}; //600dp is typical 7" tablet minimum width this.maxPhoneWidth = maxPhoneWidth || 600; ->maxPhoneWidth : Symbol(maxPhoneWidth, Decl(fixSignatureCaching.ts, 670, 36)) +>maxPhoneWidth : Symbol(maxPhoneWidth, Decl(fixSignatureCaching.ts, 673, 36)) } MobileDetect.prototype = { >MobileDetect.prototype : Symbol(Function.prototype, Decl(lib.d.ts, --, --)) ->MobileDetect : Symbol(MobileDetect, Decl(fixSignatureCaching.ts, 641, 6)) +>MobileDetect : Symbol(MobileDetect, Decl(fixSignatureCaching.ts, 644, 6)) >prototype : Symbol(Function.prototype, Decl(lib.d.ts, --, --)) constructor: MobileDetect, ->constructor : Symbol(constructor, Decl(fixSignatureCaching.ts, 677, 30)) ->MobileDetect : Symbol(MobileDetect, Decl(fixSignatureCaching.ts, 641, 6)) +>constructor : Symbol(constructor, Decl(fixSignatureCaching.ts, 680, 30)) +>MobileDetect : Symbol(MobileDetect, Decl(fixSignatureCaching.ts, 644, 6)) /** * Returns the detected phone or tablet type or null if it is not a mobile device. @@ -1194,7 +1212,7 @@ define(function () { * @function MobileDetect#mobile */ mobile: function () { ->mobile : Symbol(mobile, Decl(fixSignatureCaching.ts, 678, 34)) +>mobile : Symbol(mobile, Decl(fixSignatureCaching.ts, 681, 34)) impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) @@ -1228,7 +1246,7 @@ define(function () { * @function MobileDetect#phone */ phone: function () { ->phone : Symbol(phone, Decl(fixSignatureCaching.ts, 705, 10)) +>phone : Symbol(phone, Decl(fixSignatureCaching.ts, 708, 10)) impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) @@ -1281,7 +1299,7 @@ define(function () { * @function MobileDetect#tablet */ tablet: function () { ->tablet : Symbol(tablet, Decl(fixSignatureCaching.ts, 735, 10)) +>tablet : Symbol(tablet, Decl(fixSignatureCaching.ts, 738, 10)) impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) @@ -1306,7 +1324,7 @@ define(function () { * @function MobileDetect#userAgent */ userAgent: function () { ->userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 784, 10)) +>userAgent : Symbol(userAgent, Decl(fixSignatureCaching.ts, 787, 10)) if (this._cache.userAgent === undefined) { >undefined : Symbol(undefined, Decl(fixSignatureCaching.ts, 2, 18)) @@ -1335,7 +1353,7 @@ define(function () { * @function MobileDetect#userAgents */ userAgents: function () { ->userAgents : Symbol(userAgents, Decl(fixSignatureCaching.ts, 807, 10)) +>userAgents : Symbol(userAgents, Decl(fixSignatureCaching.ts, 810, 10)) if (this._cache.userAgents === undefined) { >undefined : Symbol(undefined, Decl(fixSignatureCaching.ts, 2, 18)) @@ -1358,7 +1376,7 @@ define(function () { * @function MobileDetect#os */ os: function () { ->os : Symbol(os, Decl(fixSignatureCaching.ts, 830, 10)) +>os : Symbol(os, Decl(fixSignatureCaching.ts, 833, 10)) if (this._cache.os === undefined) { >undefined : Symbol(undefined, Decl(fixSignatureCaching.ts, 2, 18)) @@ -1388,12 +1406,12 @@ define(function () { * @function MobileDetect#version */ version: function (key) { ->version : Symbol(version, Decl(fixSignatureCaching.ts, 847, 10)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 867, 27)) +>version : Symbol(version, Decl(fixSignatureCaching.ts, 850, 10)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 870, 27)) return impl.getVersion(key, this.ua); >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 867, 27)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 870, 27)) }, @@ -1415,12 +1433,12 @@ define(function () { * @function MobileDetect#versionStr */ versionStr: function (key) { ->versionStr : Symbol(versionStr, Decl(fixSignatureCaching.ts, 869, 10)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 888, 30)) +>versionStr : Symbol(versionStr, Decl(fixSignatureCaching.ts, 872, 10)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 891, 30)) return impl.getVersionStr(key, this.ua); >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 888, 30)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 891, 30)) }, @@ -1439,30 +1457,30 @@ define(function () { * @function MobileDetect#is */ is: function (key) { ->is : Symbol(is, Decl(fixSignatureCaching.ts, 890, 10)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 906, 22)) +>is : Symbol(is, Decl(fixSignatureCaching.ts, 893, 10)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 909, 22)) return containsIC(this.userAgents(), key) || ->containsIC : Symbol(containsIC, Decl(fixSignatureCaching.ts, 301, 5)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 906, 22)) +>containsIC : Symbol(containsIC, Decl(fixSignatureCaching.ts, 304, 5)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 909, 22)) equalIC(key, this.os()) || ->equalIC : Symbol(equalIC, Decl(fixSignatureCaching.ts, 297, 112)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 906, 22)) +>equalIC : Symbol(equalIC, Decl(fixSignatureCaching.ts, 300, 24)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 909, 22)) equalIC(key, this.phone()) || ->equalIC : Symbol(equalIC, Decl(fixSignatureCaching.ts, 297, 112)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 906, 22)) +>equalIC : Symbol(equalIC, Decl(fixSignatureCaching.ts, 300, 24)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 909, 22)) equalIC(key, this.tablet()) || ->equalIC : Symbol(equalIC, Decl(fixSignatureCaching.ts, 297, 112)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 906, 22)) +>equalIC : Symbol(equalIC, Decl(fixSignatureCaching.ts, 300, 24)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 909, 22)) containsIC(impl.findMatches(impl.mobileDetectRules.utils, this.ua), key); ->containsIC : Symbol(containsIC, Decl(fixSignatureCaching.ts, 301, 5)) +>containsIC : Symbol(containsIC, Decl(fixSignatureCaching.ts, 304, 5)) >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->key : Symbol(key, Decl(fixSignatureCaching.ts, 906, 22)) +>key : Symbol(key, Decl(fixSignatureCaching.ts, 909, 22)) }, @@ -1475,20 +1493,20 @@ define(function () { * @function MobileDetect#match */ match: function (pattern) { ->match : Symbol(match, Decl(fixSignatureCaching.ts, 912, 10)) ->pattern : Symbol(pattern, Decl(fixSignatureCaching.ts, 922, 25)) +>match : Symbol(match, Decl(fixSignatureCaching.ts, 915, 10)) +>pattern : Symbol(pattern, Decl(fixSignatureCaching.ts, 925, 25)) if (!(pattern instanceof RegExp)) { ->pattern : Symbol(pattern, Decl(fixSignatureCaching.ts, 922, 25)) +>pattern : Symbol(pattern, Decl(fixSignatureCaching.ts, 925, 25)) >RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) pattern = new RegExp(pattern, 'i'); ->pattern : Symbol(pattern, Decl(fixSignatureCaching.ts, 922, 25)) +>pattern : Symbol(pattern, Decl(fixSignatureCaching.ts, 925, 25)) >RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) ->pattern : Symbol(pattern, Decl(fixSignatureCaching.ts, 922, 25)) +>pattern : Symbol(pattern, Decl(fixSignatureCaching.ts, 925, 25)) } return pattern.test(this.ua); ->pattern : Symbol(pattern, Decl(fixSignatureCaching.ts, 922, 25)) +>pattern : Symbol(pattern, Decl(fixSignatureCaching.ts, 925, 25)) }, @@ -1503,12 +1521,12 @@ define(function () { * Will always return undefined server-side. */ isPhoneSized: function (maxPhoneWidth) { ->isPhoneSized : Symbol(isPhoneSized, Decl(fixSignatureCaching.ts, 927, 10)) ->maxPhoneWidth : Symbol(maxPhoneWidth, Decl(fixSignatureCaching.ts, 939, 32)) +>isPhoneSized : Symbol(isPhoneSized, Decl(fixSignatureCaching.ts, 930, 10)) +>maxPhoneWidth : Symbol(maxPhoneWidth, Decl(fixSignatureCaching.ts, 942, 32)) return MobileDetect.isPhoneSized(maxPhoneWidth || this.maxPhoneWidth); ->MobileDetect : Symbol(MobileDetect, Decl(fixSignatureCaching.ts, 641, 6)) ->maxPhoneWidth : Symbol(maxPhoneWidth, Decl(fixSignatureCaching.ts, 939, 32)) +>MobileDetect : Symbol(MobileDetect, Decl(fixSignatureCaching.ts, 644, 6)) +>maxPhoneWidth : Symbol(maxPhoneWidth, Decl(fixSignatureCaching.ts, 942, 32)) }, @@ -1519,7 +1537,7 @@ define(function () { * @function MobileDetect#mobileGrade */ mobileGrade: function () { ->mobileGrade : Symbol(mobileGrade, Decl(fixSignatureCaching.ts, 941, 10)) +>mobileGrade : Symbol(mobileGrade, Decl(fixSignatureCaching.ts, 944, 10)) if (this._cache.grade === undefined) { >undefined : Symbol(undefined, Decl(fixSignatureCaching.ts, 2, 18)) @@ -1534,47 +1552,47 @@ define(function () { // environment-dependent if (typeof window !== 'undefined' && window.screen) { MobileDetect.isPhoneSized = function (maxPhoneWidth) { ->MobileDetect : Symbol(MobileDetect, Decl(fixSignatureCaching.ts, 641, 6)) ->maxPhoneWidth : Symbol(maxPhoneWidth, Decl(fixSignatureCaching.ts, 959, 46)) +>MobileDetect : Symbol(MobileDetect, Decl(fixSignatureCaching.ts, 644, 6)) +>maxPhoneWidth : Symbol(maxPhoneWidth, Decl(fixSignatureCaching.ts, 962, 46)) return maxPhoneWidth < 0 ? undefined : impl.getDeviceSmallerSide() <= maxPhoneWidth; ->maxPhoneWidth : Symbol(maxPhoneWidth, Decl(fixSignatureCaching.ts, 959, 46)) +>maxPhoneWidth : Symbol(maxPhoneWidth, Decl(fixSignatureCaching.ts, 962, 46)) >undefined : Symbol(undefined, Decl(fixSignatureCaching.ts, 2, 18)) >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) ->maxPhoneWidth : Symbol(maxPhoneWidth, Decl(fixSignatureCaching.ts, 959, 46)) +>maxPhoneWidth : Symbol(maxPhoneWidth, Decl(fixSignatureCaching.ts, 962, 46)) }; } else { MobileDetect.isPhoneSized = function () {}; ->MobileDetect : Symbol(MobileDetect, Decl(fixSignatureCaching.ts, 641, 6)) +>MobileDetect : Symbol(MobileDetect, Decl(fixSignatureCaching.ts, 644, 6)) } // should not be replaced by a completely new object - just overwrite existing methods MobileDetect._impl = impl; ->MobileDetect : Symbol(MobileDetect, Decl(fixSignatureCaching.ts, 641, 6)) +>MobileDetect : Symbol(MobileDetect, Decl(fixSignatureCaching.ts, 644, 6)) >impl : Symbol(impl, Decl(fixSignatureCaching.ts, 6, 7)) - + MobileDetect.version = '1.3.3 2016-07-31'; ->MobileDetect : Symbol(MobileDetect, Decl(fixSignatureCaching.ts, 641, 6)) +>MobileDetect : Symbol(MobileDetect, Decl(fixSignatureCaching.ts, 644, 6)) return MobileDetect; ->MobileDetect : Symbol(MobileDetect, Decl(fixSignatureCaching.ts, 641, 6)) +>MobileDetect : Symbol(MobileDetect, Decl(fixSignatureCaching.ts, 644, 6)) }); // end of call of define() })((function (undefined) { ->undefined : Symbol(undefined, Decl(fixSignatureCaching.ts, 973, 14)) +>undefined : Symbol(undefined, Decl(fixSignatureCaching.ts, 976, 14)) if (typeof module !== 'undefined' && module.exports) { return function (factory) { module.exports = factory(); }; ->factory : Symbol(factory, Decl(fixSignatureCaching.ts, 975, 25)) ->factory : Symbol(factory, Decl(fixSignatureCaching.ts, 975, 25)) +>factory : Symbol(factory, Decl(fixSignatureCaching.ts, 978, 25)) +>factory : Symbol(factory, Decl(fixSignatureCaching.ts, 978, 25)) } else if (typeof define === 'function' && define.amd) { return define; } else if (typeof window !== 'undefined') { return function (factory) { window.MobileDetect = factory(); }; ->factory : Symbol(factory, Decl(fixSignatureCaching.ts, 979, 25)) ->factory : Symbol(factory, Decl(fixSignatureCaching.ts, 979, 25)) +>factory : Symbol(factory, Decl(fixSignatureCaching.ts, 982, 25)) +>factory : Symbol(factory, Decl(fixSignatureCaching.ts, 982, 25)) } else { // please file a bug if you get this error! diff --git a/tests/baselines/reference/fixSignatureCaching.types b/tests/baselines/reference/fixSignatureCaching.types index 781912544e..60502cae58 100644 --- a/tests/baselines/reference/fixSignatureCaching.types +++ b/tests/baselines/reference/fixSignatureCaching.types @@ -2,16 +2,16 @@ // Repro from #10697 (function (define, undefined) { ->(function (define, undefined) {define(function () { 'use strict'; var impl = {}; impl.mobileDetectRules = { "phones": { "iPhone": "\\biPhone\\b|\\biPod\\b", "BlackBerry": "BlackBerry|\\bBB10\\b|rim[0-9]+", "HTC": "HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m", "Nexus": "Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6", "Dell": "Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b", "Motorola": "Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\\bMoto E\\b", "Samsung": "Samsung|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F", "LG": "\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323)", "Sony": "SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533", "Asus": "Asus.*Galaxy|PadFone.*Mobile", "NokiaLumia": "Lumia [0-9]{3,4}", "Micromax": "Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b", "Palm": "PalmSource|Palm", "Vertu": "Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature", "Pantech": "PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790", "Fly": "IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250", "Wiko": "KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM", "iMobile": "i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)", "SimValley": "\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b", "Wolfgang": "AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q", "Alcatel": "Alcatel", "Nintendo": "Nintendo 3DS", "Amoi": "Amoi", "INQ": "INQ", "GenericPhone": "Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser" }, "tablets": { "iPad": "iPad|iPad.*Mobile", "NexusTablet": "Android.*Nexus[\\s]+(7|9|10)", "SamsungTablet": "SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561", "Kindle": "Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI)\\b", "SurfaceTablet": "Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)", "HPTablet": "HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10", "AsusTablet": "^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b|\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K017 |ME572C|ME103K|ME170C|ME171C|\\bME70C\\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA", "BlackBerryTablet": "PlayBook|RIM Tablet", "HTCtablet": "HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410", "MotorolaTablet": "xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617", "NookTablet": "Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2", "AcerTablet": "Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b|W3-810|\\bA3-A10\\b|\\bA3-A11\\b|\\bA3-A20", "ToshibaTablet": "Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO", "LGTablet": "\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b", "FujitsuTablet": "Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b", "PrestigioTablet": "PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002", "LenovoTablet": "Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)", "DellTablet": "Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7", "YarvikTablet": "Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b", "MedionTablet": "Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB", "ArnovaTablet": "AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2", "IntensoTablet": "INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004", "IRUTablet": "M702pro", "MegafonTablet": "MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b", "EbodaTablet": "E-Boda (Supreme|Impresspeed|Izzycomm|Essential)", "AllViewTablet": "Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)", "ArchosTablet": "\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b", "AinolTablet": "NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark", "NokiaLumiaTablet": "Lumia 2520", "SonyTablet": "Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP612|SOT31", "PhilipsTablet": "\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b", "CubeTablet": "Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT", "CobyTablet": "MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010", "MIDTablet": "M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10", "MSITablet": "MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b", "SMiTTablet": "Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)", "RockChipTablet": "Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A", "FlyTablet": "IQ310|Fly Vision", "bqTablet": "Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris E10)|Maxwell.*Lite|Maxwell.*Plus", "HuaweiTablet": "MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim", "NecTablet": "\\bN-06D|\\bN-08D", "PantechTablet": "Pantech.*P4100", "BronchoTablet": "Broncho.*(N701|N708|N802|a710)", "VersusTablet": "TOUCHPAD.*[78910]|\\bTOUCHTAB\\b", "ZyncTablet": "z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900", "PositivoTablet": "TB07STA|TB10STA|TB07FTA|TB10FTA", "NabiTablet": "Android.*\\bNabi", "KoboTablet": "Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build", "DanewTablet": "DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b", "TexetTablet": "NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE", "PlaystationTablet": "Playstation.*(Portable|Vita)", "TrekstorTablet": "ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab", "PyleAudioTablet": "\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b", "AdvanTablet": "Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ", "DanyTechTablet": "Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1", "GalapadTablet": "Android.*\\bG1\\b", "MicromaxTablet": "Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b", "KarbonnTablet": "Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b", "AllFineTablet": "Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide", "PROSCANTablet": "\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b", "YONESTablet": "BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026", "ChangJiaTablet": "TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503", "GUTablet": "TX-A1301|TX-M9002|Q702|kf026", "PointOfViewTablet": "TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10", "OvermaxTablet": "OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)", "HCLTablet": "HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync", "DPSTablet": "DPS Dream 9|DPS Dual 7", "VistureTablet": "V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10", "CrestaTablet": "CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989", "MediatekTablet": "\\bMT8125|MT8389|MT8135|MT8377\\b", "ConcordeTablet": "Concorde([ ]+)?Tab|ConCorde ReadMan", "GoCleverTablet": "GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042", "ModecomTablet": "FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003", "VoninoTablet": "\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b", "ECSTablet": "V07OT2|TM105A|S10OT1|TR10CS1", "StorexTablet": "eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab", "VodafoneTablet": "SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497", "EssentielBTablet": "Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2", "RossMoorTablet": "RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711", "iMobileTablet": "i-mobile i-note", "TolinoTablet": "tolino tab [0-9.]+|tolino shine", "AudioSonicTablet": "\\bC-22Q|T7-QC|T-17B|T-17P\\b", "AMPETablet": "Android.* A78 ", "SkkTablet": "Android.* (SKYPAD|PHOENIX|CYCLOPS)", "TecnoTablet": "TECNO P9", "JXDTablet": "Android.* \\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b", "iJoyTablet": "Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)", "FX2Tablet": "FX2 PAD7|FX2 PAD10", "XoroTablet": "KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151", "ViewsonicTablet": "ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a", "OdysTablet": "LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10", "CaptivaTablet": "CAPTIVA PAD", "IconbitTablet": "NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S", "TeclastTablet": "T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G|\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G|\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b|\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b|\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b|\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi", "OndaTablet": "\\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\\b[\\s]+", "JaytechTablet": "TPC-PA762", "BlaupunktTablet": "Endeavour 800NG|Endeavour 1010", "DigmaTablet": "\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b", "EvolioTablet": "ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b", "LavaTablet": "QPAD E704|\\bIvoryS\\b|E-TAB IVORY|\\bE-TAB\\b", "AocTablet": "MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712", "MpmanTablet": "MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\\bMPG7\\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010", "CelkonTablet": "CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b", "WolderTablet": "miTab \\b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\\b", "MiTablet": "\\bMI PAD\\b|\\bHM NOTE 1W\\b", "NibiruTablet": "Nibiru M1|Nibiru Jupiter One", "NexoTablet": "NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI", "LeaderTablet": "TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100", "UbislateTablet": "UbiSlate[\\s]?7C", "PocketBookTablet": "Pocketbook", "KocasoTablet": "\\b(TB-1207)\\b", "Hudl": "Hudl HT7S3|Hudl 2", "TelstraTablet": "T-Hub2", "GenericTablet": "Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002|\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\\bM6pro\\b|CT1020W|arc 10HD|\\bJolla\\b|\\bTP750\\b" }, "oss": { "AndroidOS": "Android", "BlackBerryOS": "blackberry|\\bBB10\\b|rim tablet os", "PalmOS": "PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino", "SymbianOS": "Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b", "WindowsMobileOS": "Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;", "WindowsPhoneOS": "Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;", "iOS": "\\biPhone.*Mobile|\\biPod|\\biPad", "MeeGoOS": "MeeGo", "MaemoOS": "Maemo", "JavaOS": "J2ME\/|\\bMIDP\\b|\\bCLDC\\b", "webOS": "webOS|hpwOS", "badaOS": "\\bBada\\b", "BREWOS": "BREW" }, "uas": { "Vivaldi": "Vivaldi", "Chrome": "\\bCrMo\\b|CriOS|Android.*Chrome\/[.0-9]* (Mobile)?", "Dolfin": "\\bDolfin\\b", "Opera": "Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+|Coast\/[0-9.]+", "Skyfire": "Skyfire", "Edge": "Mobile Safari\/[.0-9]* Edge", "IE": "IEMobile|MSIEMobile", "Firefox": "fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile", "Bolt": "bolt", "TeaShark": "teashark", "Blazer": "Blazer", "Safari": "Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari", "Tizen": "Tizen", "UCBrowser": "UC.*Browser|UCWEB", "baiduboxapp": "baiduboxapp", "baidubrowser": "baidubrowser", "DiigoBrowser": "DiigoBrowser", "Puffin": "Puffin", "Mercury": "\\bMercury\\b", "ObigoBrowser": "Obigo", "NetFront": "NF-Browser", "GenericBrowser": "NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger", "PaleMoon": "Android.*PaleMoon|Mobile.*PaleMoon" }, "props": { "Mobile": "Mobile\/[VER]", "Build": "Build\/[VER]", "Version": "Version\/[VER]", "VendorID": "VendorID\/[VER]", "iPad": "iPad.*CPU[a-z ]+[VER]", "iPhone": "iPhone.*CPU[a-z ]+[VER]", "iPod": "iPod.*CPU[a-z ]+[VER]", "Kindle": "Kindle\/[VER]", "Chrome": [ "Chrome\/[VER]", "CriOS\/[VER]", "CrMo\/[VER]" ], "Coast": [ "Coast\/[VER]" ], "Dolfin": "Dolfin\/[VER]", "Firefox": "Firefox\/[VER]", "Fennec": "Fennec\/[VER]", "Edge": "Edge\/[VER]", "IE": [ "IEMobile\/[VER];", "IEMobile [VER]", "MSIE [VER];", "Trident\/[0-9.]+;.*rv:[VER]" ], "NetFront": "NetFront\/[VER]", "NokiaBrowser": "NokiaBrowser\/[VER]", "Opera": [ " OPR\/[VER]", "Opera Mini\/[VER]", "Version\/[VER]" ], "Opera Mini": "Opera Mini\/[VER]", "Opera Mobi": "Version\/[VER]", "UC Browser": "UC Browser[VER]", "MQQBrowser": "MQQBrowser\/[VER]", "MicroMessenger": "MicroMessenger\/[VER]", "baiduboxapp": "baiduboxapp\/[VER]", "baidubrowser": "baidubrowser\/[VER]", "Iron": "Iron\/[VER]", "Safari": [ "Version\/[VER]", "Safari\/[VER]" ], "Skyfire": "Skyfire\/[VER]", "Tizen": "Tizen\/[VER]", "Webkit": "webkit[ \/][VER]", "PaleMoon": "PaleMoon\/[VER]", "Gecko": "Gecko\/[VER]", "Trident": "Trident\/[VER]", "Presto": "Presto\/[VER]", "Goanna": "Goanna\/[VER]", "iOS": " \\bi?OS\\b [VER][ ;]{1}", "Android": "Android [VER]", "BlackBerry": [ "BlackBerry[\\w]+\/[VER]", "BlackBerry.*Version\/[VER]", "Version\/[VER]" ], "BREW": "BREW [VER]", "Java": "Java\/[VER]", "Windows Phone OS": [ "Windows Phone OS [VER]", "Windows Phone [VER]" ], "Windows Phone": "Windows Phone [VER]", "Windows CE": "Windows CE\/[VER]", "Windows NT": "Windows NT [VER]", "Symbian": [ "SymbianOS\/[VER]", "Symbian\/[VER]" ], "webOS": [ "webOS\/[VER]", "hpwOS\/[VER];" ] }, "utils": { "Bot": "Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom", "MobileBot": "Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker\/M1A1-R2D2", "DesktopMode": "WPDesktop", "TV": "SonyDTV|HbbTV", "WebKit": "(webkit)[ \/]([\\w.]+)", "Console": "\\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\\b", "Watch": "SM-V700" }}; // following patterns come from http://detectmobilebrowsers.com/ impl.detectMobileBrowsers = { fullPattern: /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i, shortPattern: /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i, tabletPattern: /android|ipad|playbook|silk/i }; var hasOwnProp = Object.prototype.hasOwnProperty, isArray; impl.FALLBACK_PHONE = 'UnknownPhone'; impl.FALLBACK_TABLET = 'UnknownTablet'; impl.FALLBACK_MOBILE = 'UnknownMobile'; isArray = ('isArray' in Array) ? Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }; function equalIC(a, b) { return a != null && b != null && a.toLowerCase() === b.toLowerCase(); } function containsIC(array, value) { var valueLC, i, len = array.length; if (!len || !value) { return false; } valueLC = value.toLowerCase(); for (i = 0; i < len; ++i) { if (valueLC === array[i].toLowerCase()) { return true; } } return false; } function convertPropsToRegExp(object) { for (var key in object) { if (hasOwnProp.call(object, key)) { object[key] = new RegExp(object[key], 'i'); } } } (function init() { var key, values, value, i, len, verPos, mobileDetectRules = impl.mobileDetectRules; for (key in mobileDetectRules.props) { if (hasOwnProp.call(mobileDetectRules.props, key)) { values = mobileDetectRules.props[key]; if (!isArray(values)) { values = [values]; } len = values.length; for (i = 0; i < len; ++i) { value = values[i]; verPos = value.indexOf('[VER]'); if (verPos >= 0) { value = value.substring(0, verPos) + '([\\w._\\+]+)' + value.substring(verPos + 5); } values[i] = new RegExp(value, 'i'); } mobileDetectRules.props[key] = values; } } convertPropsToRegExp(mobileDetectRules.oss); convertPropsToRegExp(mobileDetectRules.phones); convertPropsToRegExp(mobileDetectRules.tablets); convertPropsToRegExp(mobileDetectRules.uas); convertPropsToRegExp(mobileDetectRules.utils); // copy some patterns to oss0 which are tested first (see issue#15) mobileDetectRules.oss0 = { WindowsPhoneOS: mobileDetectRules.oss.WindowsPhoneOS, WindowsMobileOS: mobileDetectRules.oss.WindowsMobileOS }; }()); /** * Test userAgent string against a set of rules and find the first matched key. * @param {Object} rules (key is String, value is RegExp) * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). * @returns {String|null} the matched key if found, otherwise null * @private */ impl.findMatch = function(rules, userAgent) { for (var key in rules) { if (hasOwnProp.call(rules, key)) { if (rules[key].test(userAgent)) { return key; } } } return null; }; /** * Test userAgent string against a set of rules and return an array of matched keys. * @param {Object} rules (key is String, value is RegExp) * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). * @returns {Array} an array of matched keys, may be empty when there is no match, but not null * @private */ impl.findMatches = function(rules, userAgent) { var result = []; for (var key in rules) { if (hasOwnProp.call(rules, key)) { if (rules[key].test(userAgent)) { result.push(key); } } } return result; }; /** * Check the version of the given property in the User-Agent. * * @param {String} propertyName * @param {String} userAgent * @return {String} version or null if version not found * @private */ impl.getVersionStr = function (propertyName, userAgent) { var props = impl.mobileDetectRules.props, patterns, i, len, match; if (hasOwnProp.call(props, propertyName)) { patterns = props[propertyName]; len = patterns.length; for (i = 0; i < len; ++i) { match = patterns[i].exec(userAgent); if (match !== null) { return match[1]; } } } return null; }; /** * Check the version of the given property in the User-Agent. * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param {String} propertyName * @param {String} userAgent * @return {Number} version or NaN if version not found * @private */ impl.getVersion = function (propertyName, userAgent) { var version = impl.getVersionStr(propertyName, userAgent); return version ? impl.prepareVersionNo(version) : NaN; }; /** * Prepare the version number. * * @param {String} version * @return {Number} the version number as a floating number * @private */ impl.prepareVersionNo = function (version) { var numbers; numbers = version.split(/[a-z._ \/\-]/i); if (numbers.length === 1) { version = numbers[0]; } if (numbers.length > 1) { version = numbers[0] + '.'; numbers.shift(); version += numbers.join(''); } return Number(version); }; impl.isMobileFallback = function (userAgent) { return impl.detectMobileBrowsers.fullPattern.test(userAgent) || impl.detectMobileBrowsers.shortPattern.test(userAgent.substr(0,4)); }; impl.isTabletFallback = function (userAgent) { return impl.detectMobileBrowsers.tabletPattern.test(userAgent); }; impl.prepareDetectionCache = function (cache, userAgent, maxPhoneWidth) { if (cache.mobile !== undefined) { return; } var phone, tablet, phoneSized; // first check for stronger tablet rules, then phone (see issue#5) tablet = impl.findMatch(impl.mobileDetectRules.tablets, userAgent); if (tablet) { cache.mobile = cache.tablet = tablet; cache.phone = null; return; // unambiguously identified as tablet } phone = impl.findMatch(impl.mobileDetectRules.phones, userAgent); if (phone) { cache.mobile = cache.phone = phone; cache.tablet = null; return; // unambiguously identified as phone } // our rules haven't found a match -> try more general fallback rules if (impl.isMobileFallback(userAgent)) { phoneSized = MobileDetect.isPhoneSized(maxPhoneWidth); if (phoneSized === undefined) { cache.mobile = impl.FALLBACK_MOBILE; cache.tablet = cache.phone = null; } else if (phoneSized) { cache.mobile = cache.phone = impl.FALLBACK_PHONE; cache.tablet = null; } else { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; cache.phone = null; } } else if (impl.isTabletFallback(userAgent)) { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; cache.phone = null; } else { // not mobile at all! cache.mobile = cache.tablet = cache.phone = null; } }; // t is a reference to a MobileDetect instance impl.mobileGrade = function (t) { // impl note: // To keep in sync w/ Mobile_Detect.php easily, the following code is tightly aligned to the PHP version. // When changes are made in Mobile_Detect.php, copy this method and replace: // $this-> / t. // self::MOBILE_GRADE_(.) / '$1' // , self::VERSION_TYPE_FLOAT / (nothing) // isIOS() / os('iOS') // [reg] / (nothing) <-- jsdelivr complaining about unescaped unicode character U+00AE var $isMobile = t.mobile() !== null; if ( // Apple iOS 3.2-5.1 - Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3), iPad 3 (5.1), original iPhone (3.1), iPhone 3 (3.2), 3GS (4.3), 4 (4.3 / 5.0), and 4S (5.1) t.os('iOS') && t.version('iPad')>=4.3 || t.os('iOS') && t.version('iPhone')>=3.1 || t.os('iOS') && t.version('iPod')>=3.1 || // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5) // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7 ( t.version('Android')>2.1 && t.is('Webkit') ) || // Windows Phone 7-7.5 - Tested on the HTC Surround (7.0) HTC Trophy (7.5), LG-E900 (7.5), Nokia Lumia 800 t.version('Windows Phone OS')>=7.0 || // Blackberry 7 - Tested on BlackBerry Torch 9810 // Blackberry 6.0 - Tested on the Torch 9800 and Style 9670 t.is('BlackBerry') && t.version('BlackBerry')>=6.0 || // Blackberry Playbook (1.0-2.0) - Tested on PlayBook t.match('Playbook.*Tablet') || // Palm WebOS (1.4-2.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0) ( t.version('webOS')>=1.4 && t.match('Palm|Pre|Pixi') ) || // Palm WebOS 3.0 - Tested on HP TouchPad t.match('hp.*TouchPad') || // Firefox Mobile (12 Beta) - Tested on Android 2.3 device ( t.is('Firefox') && t.version('Firefox')>=12 ) || // Chrome for Android - Tested on Android 4.0, 4.1 device ( t.is('Chrome') && t.is('AndroidOS') && t.version('Android')>=4.0 ) || // Skyfire 4.1 - Tested on Android 2.3 device ( t.is('Skyfire') && t.version('Skyfire')>=4.1 && t.is('AndroidOS') && t.version('Android')>=2.3 ) || // Opera Mobile 11.5-12: Tested on Android 2.3 ( t.is('Opera') && t.version('Opera Mobi')>11 && t.is('AndroidOS') ) || // Meego 1.2 - Tested on Nokia 950 and N9 t.is('MeeGoOS') || // Tizen (pre-release) - Tested on early hardware t.is('Tizen') || // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser // @todo: more tests here! t.is('Dolfin') && t.version('Bada')>=2.0 || // UC Browser - Tested on Android 2.3 device ( (t.is('UC Browser') || t.is('Dolfin')) && t.version('Android')>=2.3 ) || // Kindle 3 and Fire - Tested on the built-in WebKit browser for each ( t.match('Kindle Fire') || t.is('Kindle') && t.version('Kindle')>=3.0 ) || // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet t.is('AndroidOS') && t.is('NookTablet') || // Chrome Desktop 11-21 - Tested on OS X 10.7 and Windows 7 t.version('Chrome')>=11 && !$isMobile || // Safari Desktop 4-5 - Tested on OS X 10.7 and Windows 7 t.version('Safari')>=5.0 && !$isMobile || // Firefox Desktop 4-13 - Tested on OS X 10.7 and Windows 7 t.version('Firefox')>=4.0 && !$isMobile || // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7 t.version('MSIE')>=7.0 && !$isMobile || // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7 // @reference: http://my.opera.com/community/openweb/idopera/ t.version('Opera')>=10 && !$isMobile ){ return 'A'; } if ( t.os('iOS') && t.version('iPad')<4.3 || t.os('iOS') && t.version('iPhone')<3.1 || t.os('iOS') && t.version('iPod')<3.1 || // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770 t.is('Blackberry') && t.version('BlackBerry')>=5 && t.version('BlackBerry')<6 || //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3 ( t.version('Opera Mini')>=5.0 && t.version('Opera Mini')<=6.5 && (t.version('Android')>=2.3 || t.is('iOS')) ) || // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1) t.match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') || // @todo: report this (tested on Nokia N71) t.version('Opera Mobi')>=11 && t.is('SymbianOS') ){ return 'B'; } if ( // Blackberry 4.x - Tested on the Curve 8330 t.version('BlackBerry')<5.0 || // Windows Mobile - Tested on the HTC Leo (WinMo 5.2) t.match('MSIEMobile|Windows CE.*Mobile') || t.version('Windows Mobile')<=5.2 ){ return 'C'; } //All older smartphone platforms and featurephones - Any device that doesn't support media queries //will receive the basic, C grade experience. return 'C'; }; impl.detectOS = function (ua) { return impl.findMatch(impl.mobileDetectRules.oss0, ua) || impl.findMatch(impl.mobileDetectRules.oss, ua); }; impl.getDeviceSmallerSide = function () { return window.screen.width < window.screen.height ? window.screen.width : window.screen.height; }; /** * Constructor for MobileDetect object. *
* Such an object will keep a reference to the given user-agent string and cache most of the detect queries.
*
* Find information how to download and install: * github.com/hgoebl/mobile-detect.js/ *
* * @example
     *     var md = new MobileDetect(window.navigator.userAgent);     *     if (md.mobile()) {     *         location.href = (md.mobileGrade() === 'A') ? '/mobile/' : '/lynx/';     *     }     * 
* * @param {string} userAgent typically taken from window.navigator.userAgent or http_header['User-Agent'] * @param {number} [maxPhoneWidth=600] only for browsers specify a value for the maximum * width of smallest device side (in logical "CSS" pixels) until a device detected as mobile will be handled * as phone. * This is only used in cases where the device cannot be classified as phone or tablet.
* See Declaring Tablet Layouts * for Android.
* If you provide a value < 0, then this "fuzzy" check is disabled. * @constructor * @global */ function MobileDetect(userAgent, maxPhoneWidth) { this.ua = userAgent || ''; this._cache = {}; //600dp is typical 7" tablet minimum width this.maxPhoneWidth = maxPhoneWidth || 600; } MobileDetect.prototype = { constructor: MobileDetect, /** * Returns the detected phone or tablet type or null if it is not a mobile device. *
* For a list of possible return values see {@link MobileDetect#phone} and {@link MobileDetect#tablet}.
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownPhone, UnknownTablet or * UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get UnknownMobile here.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key for the phone family or tablet family, e.g. "Nexus". * @function MobileDetect#mobile */ mobile: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.mobile; }, /** * Returns the detected phone type/family string or null. *
* The returned tablet (family or producer) is one of following keys:
*
iPhone, BlackBerry, HTC, Nexus, Dell, Motorola, Samsung, LG, Sony, Asus, * NokiaLumia, Micromax, Palm, Vertu, Pantech, Fly, Wiko, iMobile, SimValley, * Wolfgang, Alcatel, Nintendo, Amoi, INQ, GenericPhone
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownPhone or UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get null here, while {@link MobileDetect#mobile} * will return UnknownMobile.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key of the phone family or producer, e.g. "iPhone" * @function MobileDetect#phone */ phone: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.phone; }, /** * Returns the detected tablet type/family string or null. *
* The returned tablet (family or producer) is one of following keys:
*
iPad, NexusTablet, SamsungTablet, Kindle, SurfaceTablet, HPTablet, AsusTablet, * BlackBerryTablet, HTCtablet, MotorolaTablet, NookTablet, AcerTablet, * ToshibaTablet, LGTablet, FujitsuTablet, PrestigioTablet, LenovoTablet, * DellTablet, YarvikTablet, MedionTablet, ArnovaTablet, IntensoTablet, IRUTablet, * MegafonTablet, EbodaTablet, AllViewTablet, ArchosTablet, AinolTablet, * NokiaLumiaTablet, SonyTablet, PhilipsTablet, CubeTablet, CobyTablet, MIDTablet, * MSITablet, SMiTTablet, RockChipTablet, FlyTablet, bqTablet, HuaweiTablet, * NecTablet, PantechTablet, BronchoTablet, VersusTablet, ZyncTablet, * PositivoTablet, NabiTablet, KoboTablet, DanewTablet, TexetTablet, * PlaystationTablet, TrekstorTablet, PyleAudioTablet, AdvanTablet, * DanyTechTablet, GalapadTablet, MicromaxTablet, KarbonnTablet, AllFineTablet, * PROSCANTablet, YONESTablet, ChangJiaTablet, GUTablet, PointOfViewTablet, * OvermaxTablet, HCLTablet, DPSTablet, VistureTablet, CrestaTablet, * MediatekTablet, ConcordeTablet, GoCleverTablet, ModecomTablet, VoninoTablet, * ECSTablet, StorexTablet, VodafoneTablet, EssentielBTablet, RossMoorTablet, * iMobileTablet, TolinoTablet, AudioSonicTablet, AMPETablet, SkkTablet, * TecnoTablet, JXDTablet, iJoyTablet, FX2Tablet, XoroTablet, ViewsonicTablet, * OdysTablet, CaptivaTablet, IconbitTablet, TeclastTablet, OndaTablet, * JaytechTablet, BlaupunktTablet, DigmaTablet, EvolioTablet, LavaTablet, * AocTablet, MpmanTablet, CelkonTablet, WolderTablet, MiTablet, NibiruTablet, * NexoTablet, LeaderTablet, UbislateTablet, PocketBookTablet, KocasoTablet, Hudl, * TelstraTablet, GenericTablet
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownTablet or UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get null here, while {@link MobileDetect#mobile} * will return UnknownMobile.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key of the tablet family or producer, e.g. "SamsungTablet" * @function MobileDetect#tablet */ tablet: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.tablet; }, /** * Returns the (first) detected user-agent string or null. *
* The returned user-agent is one of following keys:
*
Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon
*
* In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare * cases where a mobile device pretends to be more than one particular browser. You can get the * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by * providing one of the defined keys as first argument to {@link MobileDetect#is}. * * @returns {String} the key for the detected user-agent or null * @function MobileDetect#userAgent */ userAgent: function () { if (this._cache.userAgent === undefined) { this._cache.userAgent = impl.findMatch(impl.mobileDetectRules.uas, this.ua); } return this._cache.userAgent; }, /** * Returns all detected user-agent strings. *
* The array is empty or contains one or more of following keys:
*
Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon
*
* In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare * cases where a mobile device pretends to be more than one particular browser. You can get the * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by * providing one of the defined keys as first argument to {@link MobileDetect#is}. * * @returns {Array} the array of detected user-agent keys or [] * @function MobileDetect#userAgents */ userAgents: function () { if (this._cache.userAgents === undefined) { this._cache.userAgents = impl.findMatches(impl.mobileDetectRules.uas, this.ua); } return this._cache.userAgents; }, /** * Returns the detected operating system string or null. *
* The operating system is one of following keys:
*
AndroidOS, BlackBerryOS, PalmOS, SymbianOS, WindowsMobileOS, WindowsPhoneOS, * iOS, MeeGoOS, MaemoOS, JavaOS, webOS, badaOS, BREWOS
* * @returns {String} the key for the detected operating system. * @function MobileDetect#os */ os: function () { if (this._cache.os === undefined) { this._cache.os = impl.detectOS(this.ua); } return this._cache.os; }, /** * Get the version (as Number) of the given property in the User-Agent. *
* Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param {String} key a key defining a thing which has a version.
* You can use one of following keys:
*
Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna, * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows * CE, Windows NT, Symbian, webOS
* * @returns {Number} the version as float or NaN if User-Agent doesn't contain this version. * Be careful when comparing this value with '==' operator! * @function MobileDetect#version */ version: function (key) { return impl.getVersion(key, this.ua); }, /** * Get the version (as String) of the given property in the User-Agent. *
* * @param {String} key a key defining a thing which has a version.
* You can use one of following keys:
*
Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna, * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows * CE, Windows NT, Symbian, webOS
* * @returns {String} the "raw" version as String or null if User-Agent doesn't contain this version. * * @function MobileDetect#versionStr */ versionStr: function (key) { return impl.getVersionStr(key, this.ua); }, /** * Global test key against userAgent, os, phone, tablet and some other properties of userAgent string. * * @param {String} key the key (case-insensitive) of a userAgent, an operating system, phone or * tablet family.
* For a complete list of possible values, see {@link MobileDetect#userAgent}, * {@link MobileDetect#os}, {@link MobileDetect#phone}, {@link MobileDetect#tablet}.
* Additionally you have following keys:
*
Bot, MobileBot, DesktopMode, TV, WebKit, Console, Watch
* * @returns {boolean} true when the given key is one of the defined keys of userAgent, os, phone, * tablet or one of the listed additional keys, otherwise false * @function MobileDetect#is */ is: function (key) { return containsIC(this.userAgents(), key) || equalIC(key, this.os()) || equalIC(key, this.phone()) || equalIC(key, this.tablet()) || containsIC(impl.findMatches(impl.mobileDetectRules.utils, this.ua), key); }, /** * Do a quick test against navigator::userAgent. * * @param {String|RegExp} pattern the pattern, either as String or RegExp * (a string will be converted to a case-insensitive RegExp). * @returns {boolean} true when the pattern matches, otherwise false * @function MobileDetect#match */ match: function (pattern) { if (!(pattern instanceof RegExp)) { pattern = new RegExp(pattern, 'i'); } return pattern.test(this.ua); }, /** * Checks whether the mobile device can be considered as phone regarding screen.width. *
* Obviously this method makes sense in browser environments only (not for Node.js)! * @param {number} [maxPhoneWidth] the maximum logical pixels (aka. CSS-pixels) to be considered as phone.
* The argument is optional and if not present or falsy, the value of the constructor is taken. * @returns {boolean|undefined} undefined if screen size wasn't detectable, else true * when screen.width is less or equal to maxPhoneWidth, otherwise false.
* Will always return undefined server-side. */ isPhoneSized: function (maxPhoneWidth) { return MobileDetect.isPhoneSized(maxPhoneWidth || this.maxPhoneWidth); }, /** * Returns the mobile grade ('A', 'B', 'C'). * * @returns {String} one of the mobile grades ('A', 'B', 'C'). * @function MobileDetect#mobileGrade */ mobileGrade: function () { if (this._cache.grade === undefined) { this._cache.grade = impl.mobileGrade(this); } return this._cache.grade; } }; // environment-dependent if (typeof window !== 'undefined' && window.screen) { MobileDetect.isPhoneSized = function (maxPhoneWidth) { return maxPhoneWidth < 0 ? undefined : impl.getDeviceSmallerSide() <= maxPhoneWidth; }; } else { MobileDetect.isPhoneSized = function () {}; } // should not be replaced by a completely new object - just overwrite existing methods MobileDetect._impl = impl; MobileDetect.version = '1.3.3 2016-07-31'; return MobileDetect;}); // end of call of define()})((function (undefined) { if (typeof module !== 'undefined' && module.exports) { return function (factory) { module.exports = factory(); }; } else if (typeof define === 'function' && define.amd) { return define; } else if (typeof window !== 'undefined') { return function (factory) { window.MobileDetect = factory(); }; } else { // please file a bug if you get this error! throw new Error('unknown environment'); }})()) : void ->(function (define, undefined) {define(function () { 'use strict'; var impl = {}; impl.mobileDetectRules = { "phones": { "iPhone": "\\biPhone\\b|\\biPod\\b", "BlackBerry": "BlackBerry|\\bBB10\\b|rim[0-9]+", "HTC": "HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m", "Nexus": "Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6", "Dell": "Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b", "Motorola": "Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\\bMoto E\\b", "Samsung": "Samsung|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F", "LG": "\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323)", "Sony": "SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533", "Asus": "Asus.*Galaxy|PadFone.*Mobile", "NokiaLumia": "Lumia [0-9]{3,4}", "Micromax": "Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b", "Palm": "PalmSource|Palm", "Vertu": "Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature", "Pantech": "PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790", "Fly": "IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250", "Wiko": "KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM", "iMobile": "i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)", "SimValley": "\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b", "Wolfgang": "AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q", "Alcatel": "Alcatel", "Nintendo": "Nintendo 3DS", "Amoi": "Amoi", "INQ": "INQ", "GenericPhone": "Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser" }, "tablets": { "iPad": "iPad|iPad.*Mobile", "NexusTablet": "Android.*Nexus[\\s]+(7|9|10)", "SamsungTablet": "SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561", "Kindle": "Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI)\\b", "SurfaceTablet": "Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)", "HPTablet": "HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10", "AsusTablet": "^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b|\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K017 |ME572C|ME103K|ME170C|ME171C|\\bME70C\\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA", "BlackBerryTablet": "PlayBook|RIM Tablet", "HTCtablet": "HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410", "MotorolaTablet": "xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617", "NookTablet": "Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2", "AcerTablet": "Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b|W3-810|\\bA3-A10\\b|\\bA3-A11\\b|\\bA3-A20", "ToshibaTablet": "Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO", "LGTablet": "\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b", "FujitsuTablet": "Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b", "PrestigioTablet": "PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002", "LenovoTablet": "Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)", "DellTablet": "Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7", "YarvikTablet": "Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b", "MedionTablet": "Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB", "ArnovaTablet": "AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2", "IntensoTablet": "INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004", "IRUTablet": "M702pro", "MegafonTablet": "MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b", "EbodaTablet": "E-Boda (Supreme|Impresspeed|Izzycomm|Essential)", "AllViewTablet": "Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)", "ArchosTablet": "\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b", "AinolTablet": "NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark", "NokiaLumiaTablet": "Lumia 2520", "SonyTablet": "Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP612|SOT31", "PhilipsTablet": "\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b", "CubeTablet": "Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT", "CobyTablet": "MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010", "MIDTablet": "M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10", "MSITablet": "MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b", "SMiTTablet": "Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)", "RockChipTablet": "Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A", "FlyTablet": "IQ310|Fly Vision", "bqTablet": "Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris E10)|Maxwell.*Lite|Maxwell.*Plus", "HuaweiTablet": "MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim", "NecTablet": "\\bN-06D|\\bN-08D", "PantechTablet": "Pantech.*P4100", "BronchoTablet": "Broncho.*(N701|N708|N802|a710)", "VersusTablet": "TOUCHPAD.*[78910]|\\bTOUCHTAB\\b", "ZyncTablet": "z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900", "PositivoTablet": "TB07STA|TB10STA|TB07FTA|TB10FTA", "NabiTablet": "Android.*\\bNabi", "KoboTablet": "Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build", "DanewTablet": "DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b", "TexetTablet": "NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE", "PlaystationTablet": "Playstation.*(Portable|Vita)", "TrekstorTablet": "ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab", "PyleAudioTablet": "\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b", "AdvanTablet": "Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ", "DanyTechTablet": "Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1", "GalapadTablet": "Android.*\\bG1\\b", "MicromaxTablet": "Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b", "KarbonnTablet": "Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b", "AllFineTablet": "Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide", "PROSCANTablet": "\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b", "YONESTablet": "BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026", "ChangJiaTablet": "TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503", "GUTablet": "TX-A1301|TX-M9002|Q702|kf026", "PointOfViewTablet": "TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10", "OvermaxTablet": "OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)", "HCLTablet": "HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync", "DPSTablet": "DPS Dream 9|DPS Dual 7", "VistureTablet": "V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10", "CrestaTablet": "CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989", "MediatekTablet": "\\bMT8125|MT8389|MT8135|MT8377\\b", "ConcordeTablet": "Concorde([ ]+)?Tab|ConCorde ReadMan", "GoCleverTablet": "GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042", "ModecomTablet": "FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003", "VoninoTablet": "\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b", "ECSTablet": "V07OT2|TM105A|S10OT1|TR10CS1", "StorexTablet": "eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab", "VodafoneTablet": "SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497", "EssentielBTablet": "Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2", "RossMoorTablet": "RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711", "iMobileTablet": "i-mobile i-note", "TolinoTablet": "tolino tab [0-9.]+|tolino shine", "AudioSonicTablet": "\\bC-22Q|T7-QC|T-17B|T-17P\\b", "AMPETablet": "Android.* A78 ", "SkkTablet": "Android.* (SKYPAD|PHOENIX|CYCLOPS)", "TecnoTablet": "TECNO P9", "JXDTablet": "Android.* \\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b", "iJoyTablet": "Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)", "FX2Tablet": "FX2 PAD7|FX2 PAD10", "XoroTablet": "KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151", "ViewsonicTablet": "ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a", "OdysTablet": "LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10", "CaptivaTablet": "CAPTIVA PAD", "IconbitTablet": "NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S", "TeclastTablet": "T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G|\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G|\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b|\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b|\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b|\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi", "OndaTablet": "\\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\\b[\\s]+", "JaytechTablet": "TPC-PA762", "BlaupunktTablet": "Endeavour 800NG|Endeavour 1010", "DigmaTablet": "\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b", "EvolioTablet": "ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b", "LavaTablet": "QPAD E704|\\bIvoryS\\b|E-TAB IVORY|\\bE-TAB\\b", "AocTablet": "MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712", "MpmanTablet": "MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\\bMPG7\\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010", "CelkonTablet": "CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b", "WolderTablet": "miTab \\b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\\b", "MiTablet": "\\bMI PAD\\b|\\bHM NOTE 1W\\b", "NibiruTablet": "Nibiru M1|Nibiru Jupiter One", "NexoTablet": "NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI", "LeaderTablet": "TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100", "UbislateTablet": "UbiSlate[\\s]?7C", "PocketBookTablet": "Pocketbook", "KocasoTablet": "\\b(TB-1207)\\b", "Hudl": "Hudl HT7S3|Hudl 2", "TelstraTablet": "T-Hub2", "GenericTablet": "Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002|\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\\bM6pro\\b|CT1020W|arc 10HD|\\bJolla\\b|\\bTP750\\b" }, "oss": { "AndroidOS": "Android", "BlackBerryOS": "blackberry|\\bBB10\\b|rim tablet os", "PalmOS": "PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino", "SymbianOS": "Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b", "WindowsMobileOS": "Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;", "WindowsPhoneOS": "Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;", "iOS": "\\biPhone.*Mobile|\\biPod|\\biPad", "MeeGoOS": "MeeGo", "MaemoOS": "Maemo", "JavaOS": "J2ME\/|\\bMIDP\\b|\\bCLDC\\b", "webOS": "webOS|hpwOS", "badaOS": "\\bBada\\b", "BREWOS": "BREW" }, "uas": { "Vivaldi": "Vivaldi", "Chrome": "\\bCrMo\\b|CriOS|Android.*Chrome\/[.0-9]* (Mobile)?", "Dolfin": "\\bDolfin\\b", "Opera": "Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+|Coast\/[0-9.]+", "Skyfire": "Skyfire", "Edge": "Mobile Safari\/[.0-9]* Edge", "IE": "IEMobile|MSIEMobile", "Firefox": "fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile", "Bolt": "bolt", "TeaShark": "teashark", "Blazer": "Blazer", "Safari": "Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari", "Tizen": "Tizen", "UCBrowser": "UC.*Browser|UCWEB", "baiduboxapp": "baiduboxapp", "baidubrowser": "baidubrowser", "DiigoBrowser": "DiigoBrowser", "Puffin": "Puffin", "Mercury": "\\bMercury\\b", "ObigoBrowser": "Obigo", "NetFront": "NF-Browser", "GenericBrowser": "NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger", "PaleMoon": "Android.*PaleMoon|Mobile.*PaleMoon" }, "props": { "Mobile": "Mobile\/[VER]", "Build": "Build\/[VER]", "Version": "Version\/[VER]", "VendorID": "VendorID\/[VER]", "iPad": "iPad.*CPU[a-z ]+[VER]", "iPhone": "iPhone.*CPU[a-z ]+[VER]", "iPod": "iPod.*CPU[a-z ]+[VER]", "Kindle": "Kindle\/[VER]", "Chrome": [ "Chrome\/[VER]", "CriOS\/[VER]", "CrMo\/[VER]" ], "Coast": [ "Coast\/[VER]" ], "Dolfin": "Dolfin\/[VER]", "Firefox": "Firefox\/[VER]", "Fennec": "Fennec\/[VER]", "Edge": "Edge\/[VER]", "IE": [ "IEMobile\/[VER];", "IEMobile [VER]", "MSIE [VER];", "Trident\/[0-9.]+;.*rv:[VER]" ], "NetFront": "NetFront\/[VER]", "NokiaBrowser": "NokiaBrowser\/[VER]", "Opera": [ " OPR\/[VER]", "Opera Mini\/[VER]", "Version\/[VER]" ], "Opera Mini": "Opera Mini\/[VER]", "Opera Mobi": "Version\/[VER]", "UC Browser": "UC Browser[VER]", "MQQBrowser": "MQQBrowser\/[VER]", "MicroMessenger": "MicroMessenger\/[VER]", "baiduboxapp": "baiduboxapp\/[VER]", "baidubrowser": "baidubrowser\/[VER]", "Iron": "Iron\/[VER]", "Safari": [ "Version\/[VER]", "Safari\/[VER]" ], "Skyfire": "Skyfire\/[VER]", "Tizen": "Tizen\/[VER]", "Webkit": "webkit[ \/][VER]", "PaleMoon": "PaleMoon\/[VER]", "Gecko": "Gecko\/[VER]", "Trident": "Trident\/[VER]", "Presto": "Presto\/[VER]", "Goanna": "Goanna\/[VER]", "iOS": " \\bi?OS\\b [VER][ ;]{1}", "Android": "Android [VER]", "BlackBerry": [ "BlackBerry[\\w]+\/[VER]", "BlackBerry.*Version\/[VER]", "Version\/[VER]" ], "BREW": "BREW [VER]", "Java": "Java\/[VER]", "Windows Phone OS": [ "Windows Phone OS [VER]", "Windows Phone [VER]" ], "Windows Phone": "Windows Phone [VER]", "Windows CE": "Windows CE\/[VER]", "Windows NT": "Windows NT [VER]", "Symbian": [ "SymbianOS\/[VER]", "Symbian\/[VER]" ], "webOS": [ "webOS\/[VER]", "hpwOS\/[VER];" ] }, "utils": { "Bot": "Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom", "MobileBot": "Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker\/M1A1-R2D2", "DesktopMode": "WPDesktop", "TV": "SonyDTV|HbbTV", "WebKit": "(webkit)[ \/]([\\w.]+)", "Console": "\\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\\b", "Watch": "SM-V700" }}; // following patterns come from http://detectmobilebrowsers.com/ impl.detectMobileBrowsers = { fullPattern: /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i, shortPattern: /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i, tabletPattern: /android|ipad|playbook|silk/i }; var hasOwnProp = Object.prototype.hasOwnProperty, isArray; impl.FALLBACK_PHONE = 'UnknownPhone'; impl.FALLBACK_TABLET = 'UnknownTablet'; impl.FALLBACK_MOBILE = 'UnknownMobile'; isArray = ('isArray' in Array) ? Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }; function equalIC(a, b) { return a != null && b != null && a.toLowerCase() === b.toLowerCase(); } function containsIC(array, value) { var valueLC, i, len = array.length; if (!len || !value) { return false; } valueLC = value.toLowerCase(); for (i = 0; i < len; ++i) { if (valueLC === array[i].toLowerCase()) { return true; } } return false; } function convertPropsToRegExp(object) { for (var key in object) { if (hasOwnProp.call(object, key)) { object[key] = new RegExp(object[key], 'i'); } } } (function init() { var key, values, value, i, len, verPos, mobileDetectRules = impl.mobileDetectRules; for (key in mobileDetectRules.props) { if (hasOwnProp.call(mobileDetectRules.props, key)) { values = mobileDetectRules.props[key]; if (!isArray(values)) { values = [values]; } len = values.length; for (i = 0; i < len; ++i) { value = values[i]; verPos = value.indexOf('[VER]'); if (verPos >= 0) { value = value.substring(0, verPos) + '([\\w._\\+]+)' + value.substring(verPos + 5); } values[i] = new RegExp(value, 'i'); } mobileDetectRules.props[key] = values; } } convertPropsToRegExp(mobileDetectRules.oss); convertPropsToRegExp(mobileDetectRules.phones); convertPropsToRegExp(mobileDetectRules.tablets); convertPropsToRegExp(mobileDetectRules.uas); convertPropsToRegExp(mobileDetectRules.utils); // copy some patterns to oss0 which are tested first (see issue#15) mobileDetectRules.oss0 = { WindowsPhoneOS: mobileDetectRules.oss.WindowsPhoneOS, WindowsMobileOS: mobileDetectRules.oss.WindowsMobileOS }; }()); /** * Test userAgent string against a set of rules and find the first matched key. * @param {Object} rules (key is String, value is RegExp) * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). * @returns {String|null} the matched key if found, otherwise null * @private */ impl.findMatch = function(rules, userAgent) { for (var key in rules) { if (hasOwnProp.call(rules, key)) { if (rules[key].test(userAgent)) { return key; } } } return null; }; /** * Test userAgent string against a set of rules and return an array of matched keys. * @param {Object} rules (key is String, value is RegExp) * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). * @returns {Array} an array of matched keys, may be empty when there is no match, but not null * @private */ impl.findMatches = function(rules, userAgent) { var result = []; for (var key in rules) { if (hasOwnProp.call(rules, key)) { if (rules[key].test(userAgent)) { result.push(key); } } } return result; }; /** * Check the version of the given property in the User-Agent. * * @param {String} propertyName * @param {String} userAgent * @return {String} version or null if version not found * @private */ impl.getVersionStr = function (propertyName, userAgent) { var props = impl.mobileDetectRules.props, patterns, i, len, match; if (hasOwnProp.call(props, propertyName)) { patterns = props[propertyName]; len = patterns.length; for (i = 0; i < len; ++i) { match = patterns[i].exec(userAgent); if (match !== null) { return match[1]; } } } return null; }; /** * Check the version of the given property in the User-Agent. * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param {String} propertyName * @param {String} userAgent * @return {Number} version or NaN if version not found * @private */ impl.getVersion = function (propertyName, userAgent) { var version = impl.getVersionStr(propertyName, userAgent); return version ? impl.prepareVersionNo(version) : NaN; }; /** * Prepare the version number. * * @param {String} version * @return {Number} the version number as a floating number * @private */ impl.prepareVersionNo = function (version) { var numbers; numbers = version.split(/[a-z._ \/\-]/i); if (numbers.length === 1) { version = numbers[0]; } if (numbers.length > 1) { version = numbers[0] + '.'; numbers.shift(); version += numbers.join(''); } return Number(version); }; impl.isMobileFallback = function (userAgent) { return impl.detectMobileBrowsers.fullPattern.test(userAgent) || impl.detectMobileBrowsers.shortPattern.test(userAgent.substr(0,4)); }; impl.isTabletFallback = function (userAgent) { return impl.detectMobileBrowsers.tabletPattern.test(userAgent); }; impl.prepareDetectionCache = function (cache, userAgent, maxPhoneWidth) { if (cache.mobile !== undefined) { return; } var phone, tablet, phoneSized; // first check for stronger tablet rules, then phone (see issue#5) tablet = impl.findMatch(impl.mobileDetectRules.tablets, userAgent); if (tablet) { cache.mobile = cache.tablet = tablet; cache.phone = null; return; // unambiguously identified as tablet } phone = impl.findMatch(impl.mobileDetectRules.phones, userAgent); if (phone) { cache.mobile = cache.phone = phone; cache.tablet = null; return; // unambiguously identified as phone } // our rules haven't found a match -> try more general fallback rules if (impl.isMobileFallback(userAgent)) { phoneSized = MobileDetect.isPhoneSized(maxPhoneWidth); if (phoneSized === undefined) { cache.mobile = impl.FALLBACK_MOBILE; cache.tablet = cache.phone = null; } else if (phoneSized) { cache.mobile = cache.phone = impl.FALLBACK_PHONE; cache.tablet = null; } else { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; cache.phone = null; } } else if (impl.isTabletFallback(userAgent)) { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; cache.phone = null; } else { // not mobile at all! cache.mobile = cache.tablet = cache.phone = null; } }; // t is a reference to a MobileDetect instance impl.mobileGrade = function (t) { // impl note: // To keep in sync w/ Mobile_Detect.php easily, the following code is tightly aligned to the PHP version. // When changes are made in Mobile_Detect.php, copy this method and replace: // $this-> / t. // self::MOBILE_GRADE_(.) / '$1' // , self::VERSION_TYPE_FLOAT / (nothing) // isIOS() / os('iOS') // [reg] / (nothing) <-- jsdelivr complaining about unescaped unicode character U+00AE var $isMobile = t.mobile() !== null; if ( // Apple iOS 3.2-5.1 - Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3), iPad 3 (5.1), original iPhone (3.1), iPhone 3 (3.2), 3GS (4.3), 4 (4.3 / 5.0), and 4S (5.1) t.os('iOS') && t.version('iPad')>=4.3 || t.os('iOS') && t.version('iPhone')>=3.1 || t.os('iOS') && t.version('iPod')>=3.1 || // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5) // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7 ( t.version('Android')>2.1 && t.is('Webkit') ) || // Windows Phone 7-7.5 - Tested on the HTC Surround (7.0) HTC Trophy (7.5), LG-E900 (7.5), Nokia Lumia 800 t.version('Windows Phone OS')>=7.0 || // Blackberry 7 - Tested on BlackBerry Torch 9810 // Blackberry 6.0 - Tested on the Torch 9800 and Style 9670 t.is('BlackBerry') && t.version('BlackBerry')>=6.0 || // Blackberry Playbook (1.0-2.0) - Tested on PlayBook t.match('Playbook.*Tablet') || // Palm WebOS (1.4-2.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0) ( t.version('webOS')>=1.4 && t.match('Palm|Pre|Pixi') ) || // Palm WebOS 3.0 - Tested on HP TouchPad t.match('hp.*TouchPad') || // Firefox Mobile (12 Beta) - Tested on Android 2.3 device ( t.is('Firefox') && t.version('Firefox')>=12 ) || // Chrome for Android - Tested on Android 4.0, 4.1 device ( t.is('Chrome') && t.is('AndroidOS') && t.version('Android')>=4.0 ) || // Skyfire 4.1 - Tested on Android 2.3 device ( t.is('Skyfire') && t.version('Skyfire')>=4.1 && t.is('AndroidOS') && t.version('Android')>=2.3 ) || // Opera Mobile 11.5-12: Tested on Android 2.3 ( t.is('Opera') && t.version('Opera Mobi')>11 && t.is('AndroidOS') ) || // Meego 1.2 - Tested on Nokia 950 and N9 t.is('MeeGoOS') || // Tizen (pre-release) - Tested on early hardware t.is('Tizen') || // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser // @todo: more tests here! t.is('Dolfin') && t.version('Bada')>=2.0 || // UC Browser - Tested on Android 2.3 device ( (t.is('UC Browser') || t.is('Dolfin')) && t.version('Android')>=2.3 ) || // Kindle 3 and Fire - Tested on the built-in WebKit browser for each ( t.match('Kindle Fire') || t.is('Kindle') && t.version('Kindle')>=3.0 ) || // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet t.is('AndroidOS') && t.is('NookTablet') || // Chrome Desktop 11-21 - Tested on OS X 10.7 and Windows 7 t.version('Chrome')>=11 && !$isMobile || // Safari Desktop 4-5 - Tested on OS X 10.7 and Windows 7 t.version('Safari')>=5.0 && !$isMobile || // Firefox Desktop 4-13 - Tested on OS X 10.7 and Windows 7 t.version('Firefox')>=4.0 && !$isMobile || // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7 t.version('MSIE')>=7.0 && !$isMobile || // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7 // @reference: http://my.opera.com/community/openweb/idopera/ t.version('Opera')>=10 && !$isMobile ){ return 'A'; } if ( t.os('iOS') && t.version('iPad')<4.3 || t.os('iOS') && t.version('iPhone')<3.1 || t.os('iOS') && t.version('iPod')<3.1 || // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770 t.is('Blackberry') && t.version('BlackBerry')>=5 && t.version('BlackBerry')<6 || //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3 ( t.version('Opera Mini')>=5.0 && t.version('Opera Mini')<=6.5 && (t.version('Android')>=2.3 || t.is('iOS')) ) || // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1) t.match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') || // @todo: report this (tested on Nokia N71) t.version('Opera Mobi')>=11 && t.is('SymbianOS') ){ return 'B'; } if ( // Blackberry 4.x - Tested on the Curve 8330 t.version('BlackBerry')<5.0 || // Windows Mobile - Tested on the HTC Leo (WinMo 5.2) t.match('MSIEMobile|Windows CE.*Mobile') || t.version('Windows Mobile')<=5.2 ){ return 'C'; } //All older smartphone platforms and featurephones - Any device that doesn't support media queries //will receive the basic, C grade experience. return 'C'; }; impl.detectOS = function (ua) { return impl.findMatch(impl.mobileDetectRules.oss0, ua) || impl.findMatch(impl.mobileDetectRules.oss, ua); }; impl.getDeviceSmallerSide = function () { return window.screen.width < window.screen.height ? window.screen.width : window.screen.height; }; /** * Constructor for MobileDetect object. *
* Such an object will keep a reference to the given user-agent string and cache most of the detect queries.
*
* Find information how to download and install: * github.com/hgoebl/mobile-detect.js/ *
* * @example
     *     var md = new MobileDetect(window.navigator.userAgent);     *     if (md.mobile()) {     *         location.href = (md.mobileGrade() === 'A') ? '/mobile/' : '/lynx/';     *     }     * 
* * @param {string} userAgent typically taken from window.navigator.userAgent or http_header['User-Agent'] * @param {number} [maxPhoneWidth=600] only for browsers specify a value for the maximum * width of smallest device side (in logical "CSS" pixels) until a device detected as mobile will be handled * as phone. * This is only used in cases where the device cannot be classified as phone or tablet.
* See Declaring Tablet Layouts * for Android.
* If you provide a value < 0, then this "fuzzy" check is disabled. * @constructor * @global */ function MobileDetect(userAgent, maxPhoneWidth) { this.ua = userAgent || ''; this._cache = {}; //600dp is typical 7" tablet minimum width this.maxPhoneWidth = maxPhoneWidth || 600; } MobileDetect.prototype = { constructor: MobileDetect, /** * Returns the detected phone or tablet type or null if it is not a mobile device. *
* For a list of possible return values see {@link MobileDetect#phone} and {@link MobileDetect#tablet}.
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownPhone, UnknownTablet or * UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get UnknownMobile here.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key for the phone family or tablet family, e.g. "Nexus". * @function MobileDetect#mobile */ mobile: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.mobile; }, /** * Returns the detected phone type/family string or null. *
* The returned tablet (family or producer) is one of following keys:
*
iPhone, BlackBerry, HTC, Nexus, Dell, Motorola, Samsung, LG, Sony, Asus, * NokiaLumia, Micromax, Palm, Vertu, Pantech, Fly, Wiko, iMobile, SimValley, * Wolfgang, Alcatel, Nintendo, Amoi, INQ, GenericPhone
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownPhone or UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get null here, while {@link MobileDetect#mobile} * will return UnknownMobile.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key of the phone family or producer, e.g. "iPhone" * @function MobileDetect#phone */ phone: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.phone; }, /** * Returns the detected tablet type/family string or null. *
* The returned tablet (family or producer) is one of following keys:
*
iPad, NexusTablet, SamsungTablet, Kindle, SurfaceTablet, HPTablet, AsusTablet, * BlackBerryTablet, HTCtablet, MotorolaTablet, NookTablet, AcerTablet, * ToshibaTablet, LGTablet, FujitsuTablet, PrestigioTablet, LenovoTablet, * DellTablet, YarvikTablet, MedionTablet, ArnovaTablet, IntensoTablet, IRUTablet, * MegafonTablet, EbodaTablet, AllViewTablet, ArchosTablet, AinolTablet, * NokiaLumiaTablet, SonyTablet, PhilipsTablet, CubeTablet, CobyTablet, MIDTablet, * MSITablet, SMiTTablet, RockChipTablet, FlyTablet, bqTablet, HuaweiTablet, * NecTablet, PantechTablet, BronchoTablet, VersusTablet, ZyncTablet, * PositivoTablet, NabiTablet, KoboTablet, DanewTablet, TexetTablet, * PlaystationTablet, TrekstorTablet, PyleAudioTablet, AdvanTablet, * DanyTechTablet, GalapadTablet, MicromaxTablet, KarbonnTablet, AllFineTablet, * PROSCANTablet, YONESTablet, ChangJiaTablet, GUTablet, PointOfViewTablet, * OvermaxTablet, HCLTablet, DPSTablet, VistureTablet, CrestaTablet, * MediatekTablet, ConcordeTablet, GoCleverTablet, ModecomTablet, VoninoTablet, * ECSTablet, StorexTablet, VodafoneTablet, EssentielBTablet, RossMoorTablet, * iMobileTablet, TolinoTablet, AudioSonicTablet, AMPETablet, SkkTablet, * TecnoTablet, JXDTablet, iJoyTablet, FX2Tablet, XoroTablet, ViewsonicTablet, * OdysTablet, CaptivaTablet, IconbitTablet, TeclastTablet, OndaTablet, * JaytechTablet, BlaupunktTablet, DigmaTablet, EvolioTablet, LavaTablet, * AocTablet, MpmanTablet, CelkonTablet, WolderTablet, MiTablet, NibiruTablet, * NexoTablet, LeaderTablet, UbislateTablet, PocketBookTablet, KocasoTablet, Hudl, * TelstraTablet, GenericTablet
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownTablet or UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get null here, while {@link MobileDetect#mobile} * will return UnknownMobile.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key of the tablet family or producer, e.g. "SamsungTablet" * @function MobileDetect#tablet */ tablet: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.tablet; }, /** * Returns the (first) detected user-agent string or null. *
* The returned user-agent is one of following keys:
*
Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon
*
* In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare * cases where a mobile device pretends to be more than one particular browser. You can get the * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by * providing one of the defined keys as first argument to {@link MobileDetect#is}. * * @returns {String} the key for the detected user-agent or null * @function MobileDetect#userAgent */ userAgent: function () { if (this._cache.userAgent === undefined) { this._cache.userAgent = impl.findMatch(impl.mobileDetectRules.uas, this.ua); } return this._cache.userAgent; }, /** * Returns all detected user-agent strings. *
* The array is empty or contains one or more of following keys:
*
Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon
*
* In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare * cases where a mobile device pretends to be more than one particular browser. You can get the * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by * providing one of the defined keys as first argument to {@link MobileDetect#is}. * * @returns {Array} the array of detected user-agent keys or [] * @function MobileDetect#userAgents */ userAgents: function () { if (this._cache.userAgents === undefined) { this._cache.userAgents = impl.findMatches(impl.mobileDetectRules.uas, this.ua); } return this._cache.userAgents; }, /** * Returns the detected operating system string or null. *
* The operating system is one of following keys:
*
AndroidOS, BlackBerryOS, PalmOS, SymbianOS, WindowsMobileOS, WindowsPhoneOS, * iOS, MeeGoOS, MaemoOS, JavaOS, webOS, badaOS, BREWOS
* * @returns {String} the key for the detected operating system. * @function MobileDetect#os */ os: function () { if (this._cache.os === undefined) { this._cache.os = impl.detectOS(this.ua); } return this._cache.os; }, /** * Get the version (as Number) of the given property in the User-Agent. *
* Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param {String} key a key defining a thing which has a version.
* You can use one of following keys:
*
Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna, * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows * CE, Windows NT, Symbian, webOS
* * @returns {Number} the version as float or NaN if User-Agent doesn't contain this version. * Be careful when comparing this value with '==' operator! * @function MobileDetect#version */ version: function (key) { return impl.getVersion(key, this.ua); }, /** * Get the version (as String) of the given property in the User-Agent. *
* * @param {String} key a key defining a thing which has a version.
* You can use one of following keys:
*
Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna, * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows * CE, Windows NT, Symbian, webOS
* * @returns {String} the "raw" version as String or null if User-Agent doesn't contain this version. * * @function MobileDetect#versionStr */ versionStr: function (key) { return impl.getVersionStr(key, this.ua); }, /** * Global test key against userAgent, os, phone, tablet and some other properties of userAgent string. * * @param {String} key the key (case-insensitive) of a userAgent, an operating system, phone or * tablet family.
* For a complete list of possible values, see {@link MobileDetect#userAgent}, * {@link MobileDetect#os}, {@link MobileDetect#phone}, {@link MobileDetect#tablet}.
* Additionally you have following keys:
*
Bot, MobileBot, DesktopMode, TV, WebKit, Console, Watch
* * @returns {boolean} true when the given key is one of the defined keys of userAgent, os, phone, * tablet or one of the listed additional keys, otherwise false * @function MobileDetect#is */ is: function (key) { return containsIC(this.userAgents(), key) || equalIC(key, this.os()) || equalIC(key, this.phone()) || equalIC(key, this.tablet()) || containsIC(impl.findMatches(impl.mobileDetectRules.utils, this.ua), key); }, /** * Do a quick test against navigator::userAgent. * * @param {String|RegExp} pattern the pattern, either as String or RegExp * (a string will be converted to a case-insensitive RegExp). * @returns {boolean} true when the pattern matches, otherwise false * @function MobileDetect#match */ match: function (pattern) { if (!(pattern instanceof RegExp)) { pattern = new RegExp(pattern, 'i'); } return pattern.test(this.ua); }, /** * Checks whether the mobile device can be considered as phone regarding screen.width. *
* Obviously this method makes sense in browser environments only (not for Node.js)! * @param {number} [maxPhoneWidth] the maximum logical pixels (aka. CSS-pixels) to be considered as phone.
* The argument is optional and if not present or falsy, the value of the constructor is taken. * @returns {boolean|undefined} undefined if screen size wasn't detectable, else true * when screen.width is less or equal to maxPhoneWidth, otherwise false.
* Will always return undefined server-side. */ isPhoneSized: function (maxPhoneWidth) { return MobileDetect.isPhoneSized(maxPhoneWidth || this.maxPhoneWidth); }, /** * Returns the mobile grade ('A', 'B', 'C'). * * @returns {String} one of the mobile grades ('A', 'B', 'C'). * @function MobileDetect#mobileGrade */ mobileGrade: function () { if (this._cache.grade === undefined) { this._cache.grade = impl.mobileGrade(this); } return this._cache.grade; } }; // environment-dependent if (typeof window !== 'undefined' && window.screen) { MobileDetect.isPhoneSized = function (maxPhoneWidth) { return maxPhoneWidth < 0 ? undefined : impl.getDeviceSmallerSide() <= maxPhoneWidth; }; } else { MobileDetect.isPhoneSized = function () {}; } // should not be replaced by a completely new object - just overwrite existing methods MobileDetect._impl = impl; MobileDetect.version = '1.3.3 2016-07-31'; return MobileDetect;}); // end of call of define()}) : (define: any, undefined?: any) => void ->function (define, undefined) {define(function () { 'use strict'; var impl = {}; impl.mobileDetectRules = { "phones": { "iPhone": "\\biPhone\\b|\\biPod\\b", "BlackBerry": "BlackBerry|\\bBB10\\b|rim[0-9]+", "HTC": "HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m", "Nexus": "Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6", "Dell": "Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b", "Motorola": "Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\\bMoto E\\b", "Samsung": "Samsung|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F", "LG": "\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323)", "Sony": "SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533", "Asus": "Asus.*Galaxy|PadFone.*Mobile", "NokiaLumia": "Lumia [0-9]{3,4}", "Micromax": "Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b", "Palm": "PalmSource|Palm", "Vertu": "Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature", "Pantech": "PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790", "Fly": "IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250", "Wiko": "KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM", "iMobile": "i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)", "SimValley": "\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b", "Wolfgang": "AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q", "Alcatel": "Alcatel", "Nintendo": "Nintendo 3DS", "Amoi": "Amoi", "INQ": "INQ", "GenericPhone": "Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser" }, "tablets": { "iPad": "iPad|iPad.*Mobile", "NexusTablet": "Android.*Nexus[\\s]+(7|9|10)", "SamsungTablet": "SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561", "Kindle": "Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI)\\b", "SurfaceTablet": "Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)", "HPTablet": "HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10", "AsusTablet": "^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b|\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K017 |ME572C|ME103K|ME170C|ME171C|\\bME70C\\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA", "BlackBerryTablet": "PlayBook|RIM Tablet", "HTCtablet": "HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410", "MotorolaTablet": "xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617", "NookTablet": "Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2", "AcerTablet": "Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b|W3-810|\\bA3-A10\\b|\\bA3-A11\\b|\\bA3-A20", "ToshibaTablet": "Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO", "LGTablet": "\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b", "FujitsuTablet": "Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b", "PrestigioTablet": "PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002", "LenovoTablet": "Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)", "DellTablet": "Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7", "YarvikTablet": "Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b", "MedionTablet": "Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB", "ArnovaTablet": "AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2", "IntensoTablet": "INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004", "IRUTablet": "M702pro", "MegafonTablet": "MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b", "EbodaTablet": "E-Boda (Supreme|Impresspeed|Izzycomm|Essential)", "AllViewTablet": "Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)", "ArchosTablet": "\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b", "AinolTablet": "NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark", "NokiaLumiaTablet": "Lumia 2520", "SonyTablet": "Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP612|SOT31", "PhilipsTablet": "\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b", "CubeTablet": "Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT", "CobyTablet": "MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010", "MIDTablet": "M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10", "MSITablet": "MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b", "SMiTTablet": "Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)", "RockChipTablet": "Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A", "FlyTablet": "IQ310|Fly Vision", "bqTablet": "Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris E10)|Maxwell.*Lite|Maxwell.*Plus", "HuaweiTablet": "MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim", "NecTablet": "\\bN-06D|\\bN-08D", "PantechTablet": "Pantech.*P4100", "BronchoTablet": "Broncho.*(N701|N708|N802|a710)", "VersusTablet": "TOUCHPAD.*[78910]|\\bTOUCHTAB\\b", "ZyncTablet": "z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900", "PositivoTablet": "TB07STA|TB10STA|TB07FTA|TB10FTA", "NabiTablet": "Android.*\\bNabi", "KoboTablet": "Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build", "DanewTablet": "DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b", "TexetTablet": "NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE", "PlaystationTablet": "Playstation.*(Portable|Vita)", "TrekstorTablet": "ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab", "PyleAudioTablet": "\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b", "AdvanTablet": "Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ", "DanyTechTablet": "Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1", "GalapadTablet": "Android.*\\bG1\\b", "MicromaxTablet": "Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b", "KarbonnTablet": "Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b", "AllFineTablet": "Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide", "PROSCANTablet": "\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b", "YONESTablet": "BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026", "ChangJiaTablet": "TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503", "GUTablet": "TX-A1301|TX-M9002|Q702|kf026", "PointOfViewTablet": "TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10", "OvermaxTablet": "OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)", "HCLTablet": "HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync", "DPSTablet": "DPS Dream 9|DPS Dual 7", "VistureTablet": "V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10", "CrestaTablet": "CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989", "MediatekTablet": "\\bMT8125|MT8389|MT8135|MT8377\\b", "ConcordeTablet": "Concorde([ ]+)?Tab|ConCorde ReadMan", "GoCleverTablet": "GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042", "ModecomTablet": "FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003", "VoninoTablet": "\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b", "ECSTablet": "V07OT2|TM105A|S10OT1|TR10CS1", "StorexTablet": "eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab", "VodafoneTablet": "SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497", "EssentielBTablet": "Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2", "RossMoorTablet": "RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711", "iMobileTablet": "i-mobile i-note", "TolinoTablet": "tolino tab [0-9.]+|tolino shine", "AudioSonicTablet": "\\bC-22Q|T7-QC|T-17B|T-17P\\b", "AMPETablet": "Android.* A78 ", "SkkTablet": "Android.* (SKYPAD|PHOENIX|CYCLOPS)", "TecnoTablet": "TECNO P9", "JXDTablet": "Android.* \\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b", "iJoyTablet": "Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)", "FX2Tablet": "FX2 PAD7|FX2 PAD10", "XoroTablet": "KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151", "ViewsonicTablet": "ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a", "OdysTablet": "LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10", "CaptivaTablet": "CAPTIVA PAD", "IconbitTablet": "NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S", "TeclastTablet": "T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G|\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G|\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b|\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b|\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b|\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi", "OndaTablet": "\\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\\b[\\s]+", "JaytechTablet": "TPC-PA762", "BlaupunktTablet": "Endeavour 800NG|Endeavour 1010", "DigmaTablet": "\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b", "EvolioTablet": "ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b", "LavaTablet": "QPAD E704|\\bIvoryS\\b|E-TAB IVORY|\\bE-TAB\\b", "AocTablet": "MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712", "MpmanTablet": "MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\\bMPG7\\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010", "CelkonTablet": "CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b", "WolderTablet": "miTab \\b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\\b", "MiTablet": "\\bMI PAD\\b|\\bHM NOTE 1W\\b", "NibiruTablet": "Nibiru M1|Nibiru Jupiter One", "NexoTablet": "NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI", "LeaderTablet": "TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100", "UbislateTablet": "UbiSlate[\\s]?7C", "PocketBookTablet": "Pocketbook", "KocasoTablet": "\\b(TB-1207)\\b", "Hudl": "Hudl HT7S3|Hudl 2", "TelstraTablet": "T-Hub2", "GenericTablet": "Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002|\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\\bM6pro\\b|CT1020W|arc 10HD|\\bJolla\\b|\\bTP750\\b" }, "oss": { "AndroidOS": "Android", "BlackBerryOS": "blackberry|\\bBB10\\b|rim tablet os", "PalmOS": "PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino", "SymbianOS": "Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b", "WindowsMobileOS": "Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;", "WindowsPhoneOS": "Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;", "iOS": "\\biPhone.*Mobile|\\biPod|\\biPad", "MeeGoOS": "MeeGo", "MaemoOS": "Maemo", "JavaOS": "J2ME\/|\\bMIDP\\b|\\bCLDC\\b", "webOS": "webOS|hpwOS", "badaOS": "\\bBada\\b", "BREWOS": "BREW" }, "uas": { "Vivaldi": "Vivaldi", "Chrome": "\\bCrMo\\b|CriOS|Android.*Chrome\/[.0-9]* (Mobile)?", "Dolfin": "\\bDolfin\\b", "Opera": "Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+|Coast\/[0-9.]+", "Skyfire": "Skyfire", "Edge": "Mobile Safari\/[.0-9]* Edge", "IE": "IEMobile|MSIEMobile", "Firefox": "fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile", "Bolt": "bolt", "TeaShark": "teashark", "Blazer": "Blazer", "Safari": "Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari", "Tizen": "Tizen", "UCBrowser": "UC.*Browser|UCWEB", "baiduboxapp": "baiduboxapp", "baidubrowser": "baidubrowser", "DiigoBrowser": "DiigoBrowser", "Puffin": "Puffin", "Mercury": "\\bMercury\\b", "ObigoBrowser": "Obigo", "NetFront": "NF-Browser", "GenericBrowser": "NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger", "PaleMoon": "Android.*PaleMoon|Mobile.*PaleMoon" }, "props": { "Mobile": "Mobile\/[VER]", "Build": "Build\/[VER]", "Version": "Version\/[VER]", "VendorID": "VendorID\/[VER]", "iPad": "iPad.*CPU[a-z ]+[VER]", "iPhone": "iPhone.*CPU[a-z ]+[VER]", "iPod": "iPod.*CPU[a-z ]+[VER]", "Kindle": "Kindle\/[VER]", "Chrome": [ "Chrome\/[VER]", "CriOS\/[VER]", "CrMo\/[VER]" ], "Coast": [ "Coast\/[VER]" ], "Dolfin": "Dolfin\/[VER]", "Firefox": "Firefox\/[VER]", "Fennec": "Fennec\/[VER]", "Edge": "Edge\/[VER]", "IE": [ "IEMobile\/[VER];", "IEMobile [VER]", "MSIE [VER];", "Trident\/[0-9.]+;.*rv:[VER]" ], "NetFront": "NetFront\/[VER]", "NokiaBrowser": "NokiaBrowser\/[VER]", "Opera": [ " OPR\/[VER]", "Opera Mini\/[VER]", "Version\/[VER]" ], "Opera Mini": "Opera Mini\/[VER]", "Opera Mobi": "Version\/[VER]", "UC Browser": "UC Browser[VER]", "MQQBrowser": "MQQBrowser\/[VER]", "MicroMessenger": "MicroMessenger\/[VER]", "baiduboxapp": "baiduboxapp\/[VER]", "baidubrowser": "baidubrowser\/[VER]", "Iron": "Iron\/[VER]", "Safari": [ "Version\/[VER]", "Safari\/[VER]" ], "Skyfire": "Skyfire\/[VER]", "Tizen": "Tizen\/[VER]", "Webkit": "webkit[ \/][VER]", "PaleMoon": "PaleMoon\/[VER]", "Gecko": "Gecko\/[VER]", "Trident": "Trident\/[VER]", "Presto": "Presto\/[VER]", "Goanna": "Goanna\/[VER]", "iOS": " \\bi?OS\\b [VER][ ;]{1}", "Android": "Android [VER]", "BlackBerry": [ "BlackBerry[\\w]+\/[VER]", "BlackBerry.*Version\/[VER]", "Version\/[VER]" ], "BREW": "BREW [VER]", "Java": "Java\/[VER]", "Windows Phone OS": [ "Windows Phone OS [VER]", "Windows Phone [VER]" ], "Windows Phone": "Windows Phone [VER]", "Windows CE": "Windows CE\/[VER]", "Windows NT": "Windows NT [VER]", "Symbian": [ "SymbianOS\/[VER]", "Symbian\/[VER]" ], "webOS": [ "webOS\/[VER]", "hpwOS\/[VER];" ] }, "utils": { "Bot": "Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom", "MobileBot": "Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker\/M1A1-R2D2", "DesktopMode": "WPDesktop", "TV": "SonyDTV|HbbTV", "WebKit": "(webkit)[ \/]([\\w.]+)", "Console": "\\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\\b", "Watch": "SM-V700" }}; // following patterns come from http://detectmobilebrowsers.com/ impl.detectMobileBrowsers = { fullPattern: /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i, shortPattern: /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i, tabletPattern: /android|ipad|playbook|silk/i }; var hasOwnProp = Object.prototype.hasOwnProperty, isArray; impl.FALLBACK_PHONE = 'UnknownPhone'; impl.FALLBACK_TABLET = 'UnknownTablet'; impl.FALLBACK_MOBILE = 'UnknownMobile'; isArray = ('isArray' in Array) ? Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }; function equalIC(a, b) { return a != null && b != null && a.toLowerCase() === b.toLowerCase(); } function containsIC(array, value) { var valueLC, i, len = array.length; if (!len || !value) { return false; } valueLC = value.toLowerCase(); for (i = 0; i < len; ++i) { if (valueLC === array[i].toLowerCase()) { return true; } } return false; } function convertPropsToRegExp(object) { for (var key in object) { if (hasOwnProp.call(object, key)) { object[key] = new RegExp(object[key], 'i'); } } } (function init() { var key, values, value, i, len, verPos, mobileDetectRules = impl.mobileDetectRules; for (key in mobileDetectRules.props) { if (hasOwnProp.call(mobileDetectRules.props, key)) { values = mobileDetectRules.props[key]; if (!isArray(values)) { values = [values]; } len = values.length; for (i = 0; i < len; ++i) { value = values[i]; verPos = value.indexOf('[VER]'); if (verPos >= 0) { value = value.substring(0, verPos) + '([\\w._\\+]+)' + value.substring(verPos + 5); } values[i] = new RegExp(value, 'i'); } mobileDetectRules.props[key] = values; } } convertPropsToRegExp(mobileDetectRules.oss); convertPropsToRegExp(mobileDetectRules.phones); convertPropsToRegExp(mobileDetectRules.tablets); convertPropsToRegExp(mobileDetectRules.uas); convertPropsToRegExp(mobileDetectRules.utils); // copy some patterns to oss0 which are tested first (see issue#15) mobileDetectRules.oss0 = { WindowsPhoneOS: mobileDetectRules.oss.WindowsPhoneOS, WindowsMobileOS: mobileDetectRules.oss.WindowsMobileOS }; }()); /** * Test userAgent string against a set of rules and find the first matched key. * @param {Object} rules (key is String, value is RegExp) * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). * @returns {String|null} the matched key if found, otherwise null * @private */ impl.findMatch = function(rules, userAgent) { for (var key in rules) { if (hasOwnProp.call(rules, key)) { if (rules[key].test(userAgent)) { return key; } } } return null; }; /** * Test userAgent string against a set of rules and return an array of matched keys. * @param {Object} rules (key is String, value is RegExp) * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). * @returns {Array} an array of matched keys, may be empty when there is no match, but not null * @private */ impl.findMatches = function(rules, userAgent) { var result = []; for (var key in rules) { if (hasOwnProp.call(rules, key)) { if (rules[key].test(userAgent)) { result.push(key); } } } return result; }; /** * Check the version of the given property in the User-Agent. * * @param {String} propertyName * @param {String} userAgent * @return {String} version or null if version not found * @private */ impl.getVersionStr = function (propertyName, userAgent) { var props = impl.mobileDetectRules.props, patterns, i, len, match; if (hasOwnProp.call(props, propertyName)) { patterns = props[propertyName]; len = patterns.length; for (i = 0; i < len; ++i) { match = patterns[i].exec(userAgent); if (match !== null) { return match[1]; } } } return null; }; /** * Check the version of the given property in the User-Agent. * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param {String} propertyName * @param {String} userAgent * @return {Number} version or NaN if version not found * @private */ impl.getVersion = function (propertyName, userAgent) { var version = impl.getVersionStr(propertyName, userAgent); return version ? impl.prepareVersionNo(version) : NaN; }; /** * Prepare the version number. * * @param {String} version * @return {Number} the version number as a floating number * @private */ impl.prepareVersionNo = function (version) { var numbers; numbers = version.split(/[a-z._ \/\-]/i); if (numbers.length === 1) { version = numbers[0]; } if (numbers.length > 1) { version = numbers[0] + '.'; numbers.shift(); version += numbers.join(''); } return Number(version); }; impl.isMobileFallback = function (userAgent) { return impl.detectMobileBrowsers.fullPattern.test(userAgent) || impl.detectMobileBrowsers.shortPattern.test(userAgent.substr(0,4)); }; impl.isTabletFallback = function (userAgent) { return impl.detectMobileBrowsers.tabletPattern.test(userAgent); }; impl.prepareDetectionCache = function (cache, userAgent, maxPhoneWidth) { if (cache.mobile !== undefined) { return; } var phone, tablet, phoneSized; // first check for stronger tablet rules, then phone (see issue#5) tablet = impl.findMatch(impl.mobileDetectRules.tablets, userAgent); if (tablet) { cache.mobile = cache.tablet = tablet; cache.phone = null; return; // unambiguously identified as tablet } phone = impl.findMatch(impl.mobileDetectRules.phones, userAgent); if (phone) { cache.mobile = cache.phone = phone; cache.tablet = null; return; // unambiguously identified as phone } // our rules haven't found a match -> try more general fallback rules if (impl.isMobileFallback(userAgent)) { phoneSized = MobileDetect.isPhoneSized(maxPhoneWidth); if (phoneSized === undefined) { cache.mobile = impl.FALLBACK_MOBILE; cache.tablet = cache.phone = null; } else if (phoneSized) { cache.mobile = cache.phone = impl.FALLBACK_PHONE; cache.tablet = null; } else { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; cache.phone = null; } } else if (impl.isTabletFallback(userAgent)) { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; cache.phone = null; } else { // not mobile at all! cache.mobile = cache.tablet = cache.phone = null; } }; // t is a reference to a MobileDetect instance impl.mobileGrade = function (t) { // impl note: // To keep in sync w/ Mobile_Detect.php easily, the following code is tightly aligned to the PHP version. // When changes are made in Mobile_Detect.php, copy this method and replace: // $this-> / t. // self::MOBILE_GRADE_(.) / '$1' // , self::VERSION_TYPE_FLOAT / (nothing) // isIOS() / os('iOS') // [reg] / (nothing) <-- jsdelivr complaining about unescaped unicode character U+00AE var $isMobile = t.mobile() !== null; if ( // Apple iOS 3.2-5.1 - Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3), iPad 3 (5.1), original iPhone (3.1), iPhone 3 (3.2), 3GS (4.3), 4 (4.3 / 5.0), and 4S (5.1) t.os('iOS') && t.version('iPad')>=4.3 || t.os('iOS') && t.version('iPhone')>=3.1 || t.os('iOS') && t.version('iPod')>=3.1 || // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5) // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7 ( t.version('Android')>2.1 && t.is('Webkit') ) || // Windows Phone 7-7.5 - Tested on the HTC Surround (7.0) HTC Trophy (7.5), LG-E900 (7.5), Nokia Lumia 800 t.version('Windows Phone OS')>=7.0 || // Blackberry 7 - Tested on BlackBerry Torch 9810 // Blackberry 6.0 - Tested on the Torch 9800 and Style 9670 t.is('BlackBerry') && t.version('BlackBerry')>=6.0 || // Blackberry Playbook (1.0-2.0) - Tested on PlayBook t.match('Playbook.*Tablet') || // Palm WebOS (1.4-2.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0) ( t.version('webOS')>=1.4 && t.match('Palm|Pre|Pixi') ) || // Palm WebOS 3.0 - Tested on HP TouchPad t.match('hp.*TouchPad') || // Firefox Mobile (12 Beta) - Tested on Android 2.3 device ( t.is('Firefox') && t.version('Firefox')>=12 ) || // Chrome for Android - Tested on Android 4.0, 4.1 device ( t.is('Chrome') && t.is('AndroidOS') && t.version('Android')>=4.0 ) || // Skyfire 4.1 - Tested on Android 2.3 device ( t.is('Skyfire') && t.version('Skyfire')>=4.1 && t.is('AndroidOS') && t.version('Android')>=2.3 ) || // Opera Mobile 11.5-12: Tested on Android 2.3 ( t.is('Opera') && t.version('Opera Mobi')>11 && t.is('AndroidOS') ) || // Meego 1.2 - Tested on Nokia 950 and N9 t.is('MeeGoOS') || // Tizen (pre-release) - Tested on early hardware t.is('Tizen') || // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser // @todo: more tests here! t.is('Dolfin') && t.version('Bada')>=2.0 || // UC Browser - Tested on Android 2.3 device ( (t.is('UC Browser') || t.is('Dolfin')) && t.version('Android')>=2.3 ) || // Kindle 3 and Fire - Tested on the built-in WebKit browser for each ( t.match('Kindle Fire') || t.is('Kindle') && t.version('Kindle')>=3.0 ) || // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet t.is('AndroidOS') && t.is('NookTablet') || // Chrome Desktop 11-21 - Tested on OS X 10.7 and Windows 7 t.version('Chrome')>=11 && !$isMobile || // Safari Desktop 4-5 - Tested on OS X 10.7 and Windows 7 t.version('Safari')>=5.0 && !$isMobile || // Firefox Desktop 4-13 - Tested on OS X 10.7 and Windows 7 t.version('Firefox')>=4.0 && !$isMobile || // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7 t.version('MSIE')>=7.0 && !$isMobile || // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7 // @reference: http://my.opera.com/community/openweb/idopera/ t.version('Opera')>=10 && !$isMobile ){ return 'A'; } if ( t.os('iOS') && t.version('iPad')<4.3 || t.os('iOS') && t.version('iPhone')<3.1 || t.os('iOS') && t.version('iPod')<3.1 || // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770 t.is('Blackberry') && t.version('BlackBerry')>=5 && t.version('BlackBerry')<6 || //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3 ( t.version('Opera Mini')>=5.0 && t.version('Opera Mini')<=6.5 && (t.version('Android')>=2.3 || t.is('iOS')) ) || // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1) t.match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') || // @todo: report this (tested on Nokia N71) t.version('Opera Mobi')>=11 && t.is('SymbianOS') ){ return 'B'; } if ( // Blackberry 4.x - Tested on the Curve 8330 t.version('BlackBerry')<5.0 || // Windows Mobile - Tested on the HTC Leo (WinMo 5.2) t.match('MSIEMobile|Windows CE.*Mobile') || t.version('Windows Mobile')<=5.2 ){ return 'C'; } //All older smartphone platforms and featurephones - Any device that doesn't support media queries //will receive the basic, C grade experience. return 'C'; }; impl.detectOS = function (ua) { return impl.findMatch(impl.mobileDetectRules.oss0, ua) || impl.findMatch(impl.mobileDetectRules.oss, ua); }; impl.getDeviceSmallerSide = function () { return window.screen.width < window.screen.height ? window.screen.width : window.screen.height; }; /** * Constructor for MobileDetect object. *
* Such an object will keep a reference to the given user-agent string and cache most of the detect queries.
*
* Find information how to download and install: * github.com/hgoebl/mobile-detect.js/ *
* * @example
     *     var md = new MobileDetect(window.navigator.userAgent);     *     if (md.mobile()) {     *         location.href = (md.mobileGrade() === 'A') ? '/mobile/' : '/lynx/';     *     }     * 
* * @param {string} userAgent typically taken from window.navigator.userAgent or http_header['User-Agent'] * @param {number} [maxPhoneWidth=600] only for browsers specify a value for the maximum * width of smallest device side (in logical "CSS" pixels) until a device detected as mobile will be handled * as phone. * This is only used in cases where the device cannot be classified as phone or tablet.
* See Declaring Tablet Layouts * for Android.
* If you provide a value < 0, then this "fuzzy" check is disabled. * @constructor * @global */ function MobileDetect(userAgent, maxPhoneWidth) { this.ua = userAgent || ''; this._cache = {}; //600dp is typical 7" tablet minimum width this.maxPhoneWidth = maxPhoneWidth || 600; } MobileDetect.prototype = { constructor: MobileDetect, /** * Returns the detected phone or tablet type or null if it is not a mobile device. *
* For a list of possible return values see {@link MobileDetect#phone} and {@link MobileDetect#tablet}.
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownPhone, UnknownTablet or * UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get UnknownMobile here.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key for the phone family or tablet family, e.g. "Nexus". * @function MobileDetect#mobile */ mobile: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.mobile; }, /** * Returns the detected phone type/family string or null. *
* The returned tablet (family or producer) is one of following keys:
*
iPhone, BlackBerry, HTC, Nexus, Dell, Motorola, Samsung, LG, Sony, Asus, * NokiaLumia, Micromax, Palm, Vertu, Pantech, Fly, Wiko, iMobile, SimValley, * Wolfgang, Alcatel, Nintendo, Amoi, INQ, GenericPhone
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownPhone or UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get null here, while {@link MobileDetect#mobile} * will return UnknownMobile.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key of the phone family or producer, e.g. "iPhone" * @function MobileDetect#phone */ phone: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.phone; }, /** * Returns the detected tablet type/family string or null. *
* The returned tablet (family or producer) is one of following keys:
*
iPad, NexusTablet, SamsungTablet, Kindle, SurfaceTablet, HPTablet, AsusTablet, * BlackBerryTablet, HTCtablet, MotorolaTablet, NookTablet, AcerTablet, * ToshibaTablet, LGTablet, FujitsuTablet, PrestigioTablet, LenovoTablet, * DellTablet, YarvikTablet, MedionTablet, ArnovaTablet, IntensoTablet, IRUTablet, * MegafonTablet, EbodaTablet, AllViewTablet, ArchosTablet, AinolTablet, * NokiaLumiaTablet, SonyTablet, PhilipsTablet, CubeTablet, CobyTablet, MIDTablet, * MSITablet, SMiTTablet, RockChipTablet, FlyTablet, bqTablet, HuaweiTablet, * NecTablet, PantechTablet, BronchoTablet, VersusTablet, ZyncTablet, * PositivoTablet, NabiTablet, KoboTablet, DanewTablet, TexetTablet, * PlaystationTablet, TrekstorTablet, PyleAudioTablet, AdvanTablet, * DanyTechTablet, GalapadTablet, MicromaxTablet, KarbonnTablet, AllFineTablet, * PROSCANTablet, YONESTablet, ChangJiaTablet, GUTablet, PointOfViewTablet, * OvermaxTablet, HCLTablet, DPSTablet, VistureTablet, CrestaTablet, * MediatekTablet, ConcordeTablet, GoCleverTablet, ModecomTablet, VoninoTablet, * ECSTablet, StorexTablet, VodafoneTablet, EssentielBTablet, RossMoorTablet, * iMobileTablet, TolinoTablet, AudioSonicTablet, AMPETablet, SkkTablet, * TecnoTablet, JXDTablet, iJoyTablet, FX2Tablet, XoroTablet, ViewsonicTablet, * OdysTablet, CaptivaTablet, IconbitTablet, TeclastTablet, OndaTablet, * JaytechTablet, BlaupunktTablet, DigmaTablet, EvolioTablet, LavaTablet, * AocTablet, MpmanTablet, CelkonTablet, WolderTablet, MiTablet, NibiruTablet, * NexoTablet, LeaderTablet, UbislateTablet, PocketBookTablet, KocasoTablet, Hudl, * TelstraTablet, GenericTablet
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownTablet or UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get null here, while {@link MobileDetect#mobile} * will return UnknownMobile.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key of the tablet family or producer, e.g. "SamsungTablet" * @function MobileDetect#tablet */ tablet: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.tablet; }, /** * Returns the (first) detected user-agent string or null. *
* The returned user-agent is one of following keys:
*
Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon
*
* In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare * cases where a mobile device pretends to be more than one particular browser. You can get the * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by * providing one of the defined keys as first argument to {@link MobileDetect#is}. * * @returns {String} the key for the detected user-agent or null * @function MobileDetect#userAgent */ userAgent: function () { if (this._cache.userAgent === undefined) { this._cache.userAgent = impl.findMatch(impl.mobileDetectRules.uas, this.ua); } return this._cache.userAgent; }, /** * Returns all detected user-agent strings. *
* The array is empty or contains one or more of following keys:
*
Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon
*
* In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare * cases where a mobile device pretends to be more than one particular browser. You can get the * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by * providing one of the defined keys as first argument to {@link MobileDetect#is}. * * @returns {Array} the array of detected user-agent keys or [] * @function MobileDetect#userAgents */ userAgents: function () { if (this._cache.userAgents === undefined) { this._cache.userAgents = impl.findMatches(impl.mobileDetectRules.uas, this.ua); } return this._cache.userAgents; }, /** * Returns the detected operating system string or null. *
* The operating system is one of following keys:
*
AndroidOS, BlackBerryOS, PalmOS, SymbianOS, WindowsMobileOS, WindowsPhoneOS, * iOS, MeeGoOS, MaemoOS, JavaOS, webOS, badaOS, BREWOS
* * @returns {String} the key for the detected operating system. * @function MobileDetect#os */ os: function () { if (this._cache.os === undefined) { this._cache.os = impl.detectOS(this.ua); } return this._cache.os; }, /** * Get the version (as Number) of the given property in the User-Agent. *
* Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param {String} key a key defining a thing which has a version.
* You can use one of following keys:
*
Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna, * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows * CE, Windows NT, Symbian, webOS
* * @returns {Number} the version as float or NaN if User-Agent doesn't contain this version. * Be careful when comparing this value with '==' operator! * @function MobileDetect#version */ version: function (key) { return impl.getVersion(key, this.ua); }, /** * Get the version (as String) of the given property in the User-Agent. *
* * @param {String} key a key defining a thing which has a version.
* You can use one of following keys:
*
Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna, * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows * CE, Windows NT, Symbian, webOS
* * @returns {String} the "raw" version as String or null if User-Agent doesn't contain this version. * * @function MobileDetect#versionStr */ versionStr: function (key) { return impl.getVersionStr(key, this.ua); }, /** * Global test key against userAgent, os, phone, tablet and some other properties of userAgent string. * * @param {String} key the key (case-insensitive) of a userAgent, an operating system, phone or * tablet family.
* For a complete list of possible values, see {@link MobileDetect#userAgent}, * {@link MobileDetect#os}, {@link MobileDetect#phone}, {@link MobileDetect#tablet}.
* Additionally you have following keys:
*
Bot, MobileBot, DesktopMode, TV, WebKit, Console, Watch
* * @returns {boolean} true when the given key is one of the defined keys of userAgent, os, phone, * tablet or one of the listed additional keys, otherwise false * @function MobileDetect#is */ is: function (key) { return containsIC(this.userAgents(), key) || equalIC(key, this.os()) || equalIC(key, this.phone()) || equalIC(key, this.tablet()) || containsIC(impl.findMatches(impl.mobileDetectRules.utils, this.ua), key); }, /** * Do a quick test against navigator::userAgent. * * @param {String|RegExp} pattern the pattern, either as String or RegExp * (a string will be converted to a case-insensitive RegExp). * @returns {boolean} true when the pattern matches, otherwise false * @function MobileDetect#match */ match: function (pattern) { if (!(pattern instanceof RegExp)) { pattern = new RegExp(pattern, 'i'); } return pattern.test(this.ua); }, /** * Checks whether the mobile device can be considered as phone regarding screen.width. *
* Obviously this method makes sense in browser environments only (not for Node.js)! * @param {number} [maxPhoneWidth] the maximum logical pixels (aka. CSS-pixels) to be considered as phone.
* The argument is optional and if not present or falsy, the value of the constructor is taken. * @returns {boolean|undefined} undefined if screen size wasn't detectable, else true * when screen.width is less or equal to maxPhoneWidth, otherwise false.
* Will always return undefined server-side. */ isPhoneSized: function (maxPhoneWidth) { return MobileDetect.isPhoneSized(maxPhoneWidth || this.maxPhoneWidth); }, /** * Returns the mobile grade ('A', 'B', 'C'). * * @returns {String} one of the mobile grades ('A', 'B', 'C'). * @function MobileDetect#mobileGrade */ mobileGrade: function () { if (this._cache.grade === undefined) { this._cache.grade = impl.mobileGrade(this); } return this._cache.grade; } }; // environment-dependent if (typeof window !== 'undefined' && window.screen) { MobileDetect.isPhoneSized = function (maxPhoneWidth) { return maxPhoneWidth < 0 ? undefined : impl.getDeviceSmallerSide() <= maxPhoneWidth; }; } else { MobileDetect.isPhoneSized = function () {}; } // should not be replaced by a completely new object - just overwrite existing methods MobileDetect._impl = impl; MobileDetect.version = '1.3.3 2016-07-31'; return MobileDetect;}); // end of call of define()} : (define: any, undefined?: any) => void +>(function (define, undefined) {define(function () { 'use strict'; var impl = {}; impl.mobileDetectRules = { "phones": { "iPhone": "\\biPhone\\b|\\biPod\\b", "BlackBerry": "BlackBerry|\\bBB10\\b|rim[0-9]+", "HTC": "HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m", "Nexus": "Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6", "Dell": "Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b", "Motorola": "Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\\bMoto E\\b", "Samsung": "Samsung|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F", "LG": "\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323)", "Sony": "SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533", "Asus": "Asus.*Galaxy|PadFone.*Mobile", "NokiaLumia": "Lumia [0-9]{3,4}", "Micromax": "Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b", "Palm": "PalmSource|Palm", "Vertu": "Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature", "Pantech": "PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790", "Fly": "IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250", "Wiko": "KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM", "iMobile": "i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)", "SimValley": "\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b", "Wolfgang": "AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q", "Alcatel": "Alcatel", "Nintendo": "Nintendo 3DS", "Amoi": "Amoi", "INQ": "INQ", "GenericPhone": "Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser" }, "tablets": { "iPad": "iPad|iPad.*Mobile", "NexusTablet": "Android.*Nexus[\\s]+(7|9|10)", "SamsungTablet": "SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561", "Kindle": "Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI)\\b", "SurfaceTablet": "Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)", "HPTablet": "HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10", "AsusTablet": "^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b|\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K017 |ME572C|ME103K|ME170C|ME171C|\\bME70C\\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA", "BlackBerryTablet": "PlayBook|RIM Tablet", "HTCtablet": "HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410", "MotorolaTablet": "xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617", "NookTablet": "Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2", "AcerTablet": "Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b|W3-810|\\bA3-A10\\b|\\bA3-A11\\b|\\bA3-A20", "ToshibaTablet": "Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO", "LGTablet": "\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b", "FujitsuTablet": "Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b", "PrestigioTablet": "PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002", "LenovoTablet": "Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)", "DellTablet": "Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7", "YarvikTablet": "Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b", "MedionTablet": "Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB", "ArnovaTablet": "AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2", "IntensoTablet": "INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004", "IRUTablet": "M702pro", "MegafonTablet": "MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b", "EbodaTablet": "E-Boda (Supreme|Impresspeed|Izzycomm|Essential)", "AllViewTablet": "Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)", "ArchosTablet": "\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b", "AinolTablet": "NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark", "NokiaLumiaTablet": "Lumia 2520", "SonyTablet": "Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP612|SOT31", "PhilipsTablet": "\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b", "CubeTablet": "Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT", "CobyTablet": "MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010", "MIDTablet": "M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10", "MSITablet": "MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b", "SMiTTablet": "Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)", "RockChipTablet": "Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A", "FlyTablet": "IQ310|Fly Vision", "bqTablet": "Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris E10)|Maxwell.*Lite|Maxwell.*Plus", "HuaweiTablet": "MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim", "NecTablet": "\\bN-06D|\\bN-08D", "PantechTablet": "Pantech.*P4100", "BronchoTablet": "Broncho.*(N701|N708|N802|a710)", "VersusTablet": "TOUCHPAD.*[78910]|\\bTOUCHTAB\\b", "ZyncTablet": "z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900", "PositivoTablet": "TB07STA|TB10STA|TB07FTA|TB10FTA", "NabiTablet": "Android.*\\bNabi", "KoboTablet": "Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build", "DanewTablet": "DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b", "TexetTablet": "NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE", "PlaystationTablet": "Playstation.*(Portable|Vita)", "TrekstorTablet": "ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab", "PyleAudioTablet": "\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b", "AdvanTablet": "Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ", "DanyTechTablet": "Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1", "GalapadTablet": "Android.*\\bG1\\b", "MicromaxTablet": "Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b", "KarbonnTablet": "Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b", "AllFineTablet": "Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide", "PROSCANTablet": "\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b", "YONESTablet": "BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026", "ChangJiaTablet": "TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503", "GUTablet": "TX-A1301|TX-M9002|Q702|kf026", "PointOfViewTablet": "TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10", "OvermaxTablet": "OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)", "HCLTablet": "HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync", "DPSTablet": "DPS Dream 9|DPS Dual 7", "VistureTablet": "V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10", "CrestaTablet": "CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989", "MediatekTablet": "\\bMT8125|MT8389|MT8135|MT8377\\b", "ConcordeTablet": "Concorde([ ]+)?Tab|ConCorde ReadMan", "GoCleverTablet": "GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042", "ModecomTablet": "FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003", "VoninoTablet": "\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b", "ECSTablet": "V07OT2|TM105A|S10OT1|TR10CS1", "StorexTablet": "eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab", "VodafoneTablet": "SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497", "EssentielBTablet": "Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2", "RossMoorTablet": "RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711", "iMobileTablet": "i-mobile i-note", "TolinoTablet": "tolino tab [0-9.]+|tolino shine", "AudioSonicTablet": "\\bC-22Q|T7-QC|T-17B|T-17P\\b", "AMPETablet": "Android.* A78 ", "SkkTablet": "Android.* (SKYPAD|PHOENIX|CYCLOPS)", "TecnoTablet": "TECNO P9", "JXDTablet": "Android.* \\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b", "iJoyTablet": "Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)", "FX2Tablet": "FX2 PAD7|FX2 PAD10", "XoroTablet": "KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151", "ViewsonicTablet": "ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a", "OdysTablet": "LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10", "CaptivaTablet": "CAPTIVA PAD", "IconbitTablet": "NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S", "TeclastTablet": "T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G|\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G|\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b|\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b|\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b|\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi", "OndaTablet": "\\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\\b[\\s]+", "JaytechTablet": "TPC-PA762", "BlaupunktTablet": "Endeavour 800NG|Endeavour 1010", "DigmaTablet": "\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b", "EvolioTablet": "ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b", "LavaTablet": "QPAD E704|\\bIvoryS\\b|E-TAB IVORY|\\bE-TAB\\b", "AocTablet": "MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712", "MpmanTablet": "MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\\bMPG7\\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010", "CelkonTablet": "CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b", "WolderTablet": "miTab \\b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\\b", "MiTablet": "\\bMI PAD\\b|\\bHM NOTE 1W\\b", "NibiruTablet": "Nibiru M1|Nibiru Jupiter One", "NexoTablet": "NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI", "LeaderTablet": "TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100", "UbislateTablet": "UbiSlate[\\s]?7C", "PocketBookTablet": "Pocketbook", "KocasoTablet": "\\b(TB-1207)\\b", "Hudl": "Hudl HT7S3|Hudl 2", "TelstraTablet": "T-Hub2", "GenericTablet": "Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002|\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\\bM6pro\\b|CT1020W|arc 10HD|\\bJolla\\b|\\bTP750\\b" }, "oss": { "AndroidOS": "Android", "BlackBerryOS": "blackberry|\\bBB10\\b|rim tablet os", "PalmOS": "PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino", "SymbianOS": "Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b", "WindowsMobileOS": "Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;", "WindowsPhoneOS": "Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;", "iOS": "\\biPhone.*Mobile|\\biPod|\\biPad", "MeeGoOS": "MeeGo", "MaemoOS": "Maemo", "JavaOS": "J2ME\/|\\bMIDP\\b|\\bCLDC\\b", "webOS": "webOS|hpwOS", "badaOS": "\\bBada\\b", "BREWOS": "BREW" }, "uas": { "Vivaldi": "Vivaldi", "Chrome": "\\bCrMo\\b|CriOS|Android.*Chrome\/[.0-9]* (Mobile)?", "Dolfin": "\\bDolfin\\b", "Opera": "Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+|Coast\/[0-9.]+", "Skyfire": "Skyfire", "Edge": "Mobile Safari\/[.0-9]* Edge", "IE": "IEMobile|MSIEMobile", "Firefox": "fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile", "Bolt": "bolt", "TeaShark": "teashark", "Blazer": "Blazer", "Safari": "Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari", "Tizen": "Tizen", "UCBrowser": "UC.*Browser|UCWEB", "baiduboxapp": "baiduboxapp", "baidubrowser": "baidubrowser", "DiigoBrowser": "DiigoBrowser", "Puffin": "Puffin", "Mercury": "\\bMercury\\b", "ObigoBrowser": "Obigo", "NetFront": "NF-Browser", "GenericBrowser": "NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger", "PaleMoon": "Android.*PaleMoon|Mobile.*PaleMoon" }, "props": { "Mobile": "Mobile\/[VER]", "Build": "Build\/[VER]", "Version": "Version\/[VER]", "VendorID": "VendorID\/[VER]", "iPad": "iPad.*CPU[a-z ]+[VER]", "iPhone": "iPhone.*CPU[a-z ]+[VER]", "iPod": "iPod.*CPU[a-z ]+[VER]", "Kindle": "Kindle\/[VER]", "Chrome": [ "Chrome\/[VER]", "CriOS\/[VER]", "CrMo\/[VER]" ], "Coast": [ "Coast\/[VER]" ], "Dolfin": "Dolfin\/[VER]", "Firefox": "Firefox\/[VER]", "Fennec": "Fennec\/[VER]", "Edge": "Edge\/[VER]", "IE": [ "IEMobile\/[VER];", "IEMobile [VER]", "MSIE [VER];", "Trident\/[0-9.]+;.*rv:[VER]" ], "NetFront": "NetFront\/[VER]", "NokiaBrowser": "NokiaBrowser\/[VER]", "Opera": [ " OPR\/[VER]", "Opera Mini\/[VER]", "Version\/[VER]" ], "Opera Mini": "Opera Mini\/[VER]", "Opera Mobi": "Version\/[VER]", "UC Browser": "UC Browser[VER]", "MQQBrowser": "MQQBrowser\/[VER]", "MicroMessenger": "MicroMessenger\/[VER]", "baiduboxapp": "baiduboxapp\/[VER]", "baidubrowser": "baidubrowser\/[VER]", "Iron": "Iron\/[VER]", "Safari": [ "Version\/[VER]", "Safari\/[VER]" ], "Skyfire": "Skyfire\/[VER]", "Tizen": "Tizen\/[VER]", "Webkit": "webkit[ \/][VER]", "PaleMoon": "PaleMoon\/[VER]", "Gecko": "Gecko\/[VER]", "Trident": "Trident\/[VER]", "Presto": "Presto\/[VER]", "Goanna": "Goanna\/[VER]", "iOS": " \\bi?OS\\b [VER][ ;]{1}", "Android": "Android [VER]", "BlackBerry": [ "BlackBerry[\\w]+\/[VER]", "BlackBerry.*Version\/[VER]", "Version\/[VER]" ], "BREW": "BREW [VER]", "Java": "Java\/[VER]", "Windows Phone OS": [ "Windows Phone OS [VER]", "Windows Phone [VER]" ], "Windows Phone": "Windows Phone [VER]", "Windows CE": "Windows CE\/[VER]", "Windows NT": "Windows NT [VER]", "Symbian": [ "SymbianOS\/[VER]", "Symbian\/[VER]" ], "webOS": [ "webOS\/[VER]", "hpwOS\/[VER];" ] }, "utils": { "Bot": "Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom", "MobileBot": "Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker\/M1A1-R2D2", "DesktopMode": "WPDesktop", "TV": "SonyDTV|HbbTV", "WebKit": "(webkit)[ \/]([\\w.]+)", "Console": "\\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\\b", "Watch": "SM-V700" }}; // following patterns come from http://detectmobilebrowsers.com/ impl.detectMobileBrowsers = { fullPattern: /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i, shortPattern: /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i, tabletPattern: /android|ipad|playbook|silk/i }; var hasOwnProp = Object.prototype.hasOwnProperty, isArray; impl.FALLBACK_PHONE = 'UnknownPhone'; impl.FALLBACK_TABLET = 'UnknownTablet'; impl.FALLBACK_MOBILE = 'UnknownMobile'; isArray = ('isArray' in Array) ? Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }; isArray = 'isArray' in Array ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : Array.isArray; function equalIC(a, b) { return a != null && b != null && a.toLowerCase() === b.toLowerCase(); } function containsIC(array, value) { var valueLC, i, len = array.length; if (!len || !value) { return false; } valueLC = value.toLowerCase(); for (i = 0; i < len; ++i) { if (valueLC === array[i].toLowerCase()) { return true; } } return false; } function convertPropsToRegExp(object) { for (var key in object) { if (hasOwnProp.call(object, key)) { object[key] = new RegExp(object[key], 'i'); } } } (function init() { var key, values, value, i, len, verPos, mobileDetectRules = impl.mobileDetectRules; for (key in mobileDetectRules.props) { if (hasOwnProp.call(mobileDetectRules.props, key)) { values = mobileDetectRules.props[key]; if (!isArray(values)) { values = [values]; } len = values.length; for (i = 0; i < len; ++i) { value = values[i]; verPos = value.indexOf('[VER]'); if (verPos >= 0) { value = value.substring(0, verPos) + '([\\w._\\+]+)' + value.substring(verPos + 5); } values[i] = new RegExp(value, 'i'); } mobileDetectRules.props[key] = values; } } convertPropsToRegExp(mobileDetectRules.oss); convertPropsToRegExp(mobileDetectRules.phones); convertPropsToRegExp(mobileDetectRules.tablets); convertPropsToRegExp(mobileDetectRules.uas); convertPropsToRegExp(mobileDetectRules.utils); // copy some patterns to oss0 which are tested first (see issue#15) mobileDetectRules.oss0 = { WindowsPhoneOS: mobileDetectRules.oss.WindowsPhoneOS, WindowsMobileOS: mobileDetectRules.oss.WindowsMobileOS }; }()); /** * Test userAgent string against a set of rules and find the first matched key. * @param {Object} rules (key is String, value is RegExp) * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). * @returns {String|null} the matched key if found, otherwise null * @private */ impl.findMatch = function(rules, userAgent) { for (var key in rules) { if (hasOwnProp.call(rules, key)) { if (rules[key].test(userAgent)) { return key; } } } return null; }; /** * Test userAgent string against a set of rules and return an array of matched keys. * @param {Object} rules (key is String, value is RegExp) * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). * @returns {Array} an array of matched keys, may be empty when there is no match, but not null * @private */ impl.findMatches = function(rules, userAgent) { var result = []; for (var key in rules) { if (hasOwnProp.call(rules, key)) { if (rules[key].test(userAgent)) { result.push(key); } } } return result; }; /** * Check the version of the given property in the User-Agent. * * @param {String} propertyName * @param {String} userAgent * @return {String} version or null if version not found * @private */ impl.getVersionStr = function (propertyName, userAgent) { var props = impl.mobileDetectRules.props, patterns, i, len, match; if (hasOwnProp.call(props, propertyName)) { patterns = props[propertyName]; len = patterns.length; for (i = 0; i < len; ++i) { match = patterns[i].exec(userAgent); if (match !== null) { return match[1]; } } } return null; }; /** * Check the version of the given property in the User-Agent. * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param {String} propertyName * @param {String} userAgent * @return {Number} version or NaN if version not found * @private */ impl.getVersion = function (propertyName, userAgent) { var version = impl.getVersionStr(propertyName, userAgent); return version ? impl.prepareVersionNo(version) : NaN; }; /** * Prepare the version number. * * @param {String} version * @return {Number} the version number as a floating number * @private */ impl.prepareVersionNo = function (version) { var numbers; numbers = version.split(/[a-z._ \/\-]/i); if (numbers.length === 1) { version = numbers[0]; } if (numbers.length > 1) { version = numbers[0] + '.'; numbers.shift(); version += numbers.join(''); } return Number(version); }; impl.isMobileFallback = function (userAgent) { return impl.detectMobileBrowsers.fullPattern.test(userAgent) || impl.detectMobileBrowsers.shortPattern.test(userAgent.substr(0,4)); }; impl.isTabletFallback = function (userAgent) { return impl.detectMobileBrowsers.tabletPattern.test(userAgent); }; impl.prepareDetectionCache = function (cache, userAgent, maxPhoneWidth) { if (cache.mobile !== undefined) { return; } var phone, tablet, phoneSized; // first check for stronger tablet rules, then phone (see issue#5) tablet = impl.findMatch(impl.mobileDetectRules.tablets, userAgent); if (tablet) { cache.mobile = cache.tablet = tablet; cache.phone = null; return; // unambiguously identified as tablet } phone = impl.findMatch(impl.mobileDetectRules.phones, userAgent); if (phone) { cache.mobile = cache.phone = phone; cache.tablet = null; return; // unambiguously identified as phone } // our rules haven't found a match -> try more general fallback rules if (impl.isMobileFallback(userAgent)) { phoneSized = MobileDetect.isPhoneSized(maxPhoneWidth); if (phoneSized === undefined) { cache.mobile = impl.FALLBACK_MOBILE; cache.tablet = cache.phone = null; } else if (phoneSized) { cache.mobile = cache.phone = impl.FALLBACK_PHONE; cache.tablet = null; } else { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; cache.phone = null; } } else if (impl.isTabletFallback(userAgent)) { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; cache.phone = null; } else { // not mobile at all! cache.mobile = cache.tablet = cache.phone = null; } }; // t is a reference to a MobileDetect instance impl.mobileGrade = function (t) { // impl note: // To keep in sync w/ Mobile_Detect.php easily, the following code is tightly aligned to the PHP version. // When changes are made in Mobile_Detect.php, copy this method and replace: // $this-> / t. // self::MOBILE_GRADE_(.) / '$1' // , self::VERSION_TYPE_FLOAT / (nothing) // isIOS() / os('iOS') // [reg] / (nothing) <-- jsdelivr complaining about unescaped unicode character U+00AE var $isMobile = t.mobile() !== null; if ( // Apple iOS 3.2-5.1 - Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3), iPad 3 (5.1), original iPhone (3.1), iPhone 3 (3.2), 3GS (4.3), 4 (4.3 / 5.0), and 4S (5.1) t.os('iOS') && t.version('iPad')>=4.3 || t.os('iOS') && t.version('iPhone')>=3.1 || t.os('iOS') && t.version('iPod')>=3.1 || // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5) // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7 ( t.version('Android')>2.1 && t.is('Webkit') ) || // Windows Phone 7-7.5 - Tested on the HTC Surround (7.0) HTC Trophy (7.5), LG-E900 (7.5), Nokia Lumia 800 t.version('Windows Phone OS')>=7.0 || // Blackberry 7 - Tested on BlackBerry Torch 9810 // Blackberry 6.0 - Tested on the Torch 9800 and Style 9670 t.is('BlackBerry') && t.version('BlackBerry')>=6.0 || // Blackberry Playbook (1.0-2.0) - Tested on PlayBook t.match('Playbook.*Tablet') || // Palm WebOS (1.4-2.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0) ( t.version('webOS')>=1.4 && t.match('Palm|Pre|Pixi') ) || // Palm WebOS 3.0 - Tested on HP TouchPad t.match('hp.*TouchPad') || // Firefox Mobile (12 Beta) - Tested on Android 2.3 device ( t.is('Firefox') && t.version('Firefox')>=12 ) || // Chrome for Android - Tested on Android 4.0, 4.1 device ( t.is('Chrome') && t.is('AndroidOS') && t.version('Android')>=4.0 ) || // Skyfire 4.1 - Tested on Android 2.3 device ( t.is('Skyfire') && t.version('Skyfire')>=4.1 && t.is('AndroidOS') && t.version('Android')>=2.3 ) || // Opera Mobile 11.5-12: Tested on Android 2.3 ( t.is('Opera') && t.version('Opera Mobi')>11 && t.is('AndroidOS') ) || // Meego 1.2 - Tested on Nokia 950 and N9 t.is('MeeGoOS') || // Tizen (pre-release) - Tested on early hardware t.is('Tizen') || // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser // @todo: more tests here! t.is('Dolfin') && t.version('Bada')>=2.0 || // UC Browser - Tested on Android 2.3 device ( (t.is('UC Browser') || t.is('Dolfin')) && t.version('Android')>=2.3 ) || // Kindle 3 and Fire - Tested on the built-in WebKit browser for each ( t.match('Kindle Fire') || t.is('Kindle') && t.version('Kindle')>=3.0 ) || // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet t.is('AndroidOS') && t.is('NookTablet') || // Chrome Desktop 11-21 - Tested on OS X 10.7 and Windows 7 t.version('Chrome')>=11 && !$isMobile || // Safari Desktop 4-5 - Tested on OS X 10.7 and Windows 7 t.version('Safari')>=5.0 && !$isMobile || // Firefox Desktop 4-13 - Tested on OS X 10.7 and Windows 7 t.version('Firefox')>=4.0 && !$isMobile || // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7 t.version('MSIE')>=7.0 && !$isMobile || // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7 // @reference: http://my.opera.com/community/openweb/idopera/ t.version('Opera')>=10 && !$isMobile ){ return 'A'; } if ( t.os('iOS') && t.version('iPad')<4.3 || t.os('iOS') && t.version('iPhone')<3.1 || t.os('iOS') && t.version('iPod')<3.1 || // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770 t.is('Blackberry') && t.version('BlackBerry')>=5 && t.version('BlackBerry')<6 || //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3 ( t.version('Opera Mini')>=5.0 && t.version('Opera Mini')<=6.5 && (t.version('Android')>=2.3 || t.is('iOS')) ) || // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1) t.match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') || // @todo: report this (tested on Nokia N71) t.version('Opera Mobi')>=11 && t.is('SymbianOS') ){ return 'B'; } if ( // Blackberry 4.x - Tested on the Curve 8330 t.version('BlackBerry')<5.0 || // Windows Mobile - Tested on the HTC Leo (WinMo 5.2) t.match('MSIEMobile|Windows CE.*Mobile') || t.version('Windows Mobile')<=5.2 ){ return 'C'; } //All older smartphone platforms and featurephones - Any device that doesn't support media queries //will receive the basic, C grade experience. return 'C'; }; impl.detectOS = function (ua) { return impl.findMatch(impl.mobileDetectRules.oss0, ua) || impl.findMatch(impl.mobileDetectRules.oss, ua); }; impl.getDeviceSmallerSide = function () { return window.screen.width < window.screen.height ? window.screen.width : window.screen.height; }; /** * Constructor for MobileDetect object. *
* Such an object will keep a reference to the given user-agent string and cache most of the detect queries.
*
* Find information how to download and install: * github.com/hgoebl/mobile-detect.js/ *
* * @example
     *     var md = new MobileDetect(window.navigator.userAgent);     *     if (md.mobile()) {     *         location.href = (md.mobileGrade() === 'A') ? '/mobile/' : '/lynx/';     *     }     * 
* * @param {string} userAgent typically taken from window.navigator.userAgent or http_header['User-Agent'] * @param {number} [maxPhoneWidth=600] only for browsers specify a value for the maximum * width of smallest device side (in logical "CSS" pixels) until a device detected as mobile will be handled * as phone. * This is only used in cases where the device cannot be classified as phone or tablet.
* See Declaring Tablet Layouts * for Android.
* If you provide a value < 0, then this "fuzzy" check is disabled. * @constructor * @global */ function MobileDetect(userAgent, maxPhoneWidth) { this.ua = userAgent || ''; this._cache = {}; //600dp is typical 7" tablet minimum width this.maxPhoneWidth = maxPhoneWidth || 600; } MobileDetect.prototype = { constructor: MobileDetect, /** * Returns the detected phone or tablet type or null if it is not a mobile device. *
* For a list of possible return values see {@link MobileDetect#phone} and {@link MobileDetect#tablet}.
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownPhone, UnknownTablet or * UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get UnknownMobile here.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key for the phone family or tablet family, e.g. "Nexus". * @function MobileDetect#mobile */ mobile: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.mobile; }, /** * Returns the detected phone type/family string or null. *
* The returned tablet (family or producer) is one of following keys:
*
iPhone, BlackBerry, HTC, Nexus, Dell, Motorola, Samsung, LG, Sony, Asus, * NokiaLumia, Micromax, Palm, Vertu, Pantech, Fly, Wiko, iMobile, SimValley, * Wolfgang, Alcatel, Nintendo, Amoi, INQ, GenericPhone
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownPhone or UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get null here, while {@link MobileDetect#mobile} * will return UnknownMobile.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key of the phone family or producer, e.g. "iPhone" * @function MobileDetect#phone */ phone: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.phone; }, /** * Returns the detected tablet type/family string or null. *
* The returned tablet (family or producer) is one of following keys:
*
iPad, NexusTablet, SamsungTablet, Kindle, SurfaceTablet, HPTablet, AsusTablet, * BlackBerryTablet, HTCtablet, MotorolaTablet, NookTablet, AcerTablet, * ToshibaTablet, LGTablet, FujitsuTablet, PrestigioTablet, LenovoTablet, * DellTablet, YarvikTablet, MedionTablet, ArnovaTablet, IntensoTablet, IRUTablet, * MegafonTablet, EbodaTablet, AllViewTablet, ArchosTablet, AinolTablet, * NokiaLumiaTablet, SonyTablet, PhilipsTablet, CubeTablet, CobyTablet, MIDTablet, * MSITablet, SMiTTablet, RockChipTablet, FlyTablet, bqTablet, HuaweiTablet, * NecTablet, PantechTablet, BronchoTablet, VersusTablet, ZyncTablet, * PositivoTablet, NabiTablet, KoboTablet, DanewTablet, TexetTablet, * PlaystationTablet, TrekstorTablet, PyleAudioTablet, AdvanTablet, * DanyTechTablet, GalapadTablet, MicromaxTablet, KarbonnTablet, AllFineTablet, * PROSCANTablet, YONESTablet, ChangJiaTablet, GUTablet, PointOfViewTablet, * OvermaxTablet, HCLTablet, DPSTablet, VistureTablet, CrestaTablet, * MediatekTablet, ConcordeTablet, GoCleverTablet, ModecomTablet, VoninoTablet, * ECSTablet, StorexTablet, VodafoneTablet, EssentielBTablet, RossMoorTablet, * iMobileTablet, TolinoTablet, AudioSonicTablet, AMPETablet, SkkTablet, * TecnoTablet, JXDTablet, iJoyTablet, FX2Tablet, XoroTablet, ViewsonicTablet, * OdysTablet, CaptivaTablet, IconbitTablet, TeclastTablet, OndaTablet, * JaytechTablet, BlaupunktTablet, DigmaTablet, EvolioTablet, LavaTablet, * AocTablet, MpmanTablet, CelkonTablet, WolderTablet, MiTablet, NibiruTablet, * NexoTablet, LeaderTablet, UbislateTablet, PocketBookTablet, KocasoTablet, Hudl, * TelstraTablet, GenericTablet
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownTablet or UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get null here, while {@link MobileDetect#mobile} * will return UnknownMobile.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key of the tablet family or producer, e.g. "SamsungTablet" * @function MobileDetect#tablet */ tablet: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.tablet; }, /** * Returns the (first) detected user-agent string or null. *
* The returned user-agent is one of following keys:
*
Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon
*
* In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare * cases where a mobile device pretends to be more than one particular browser. You can get the * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by * providing one of the defined keys as first argument to {@link MobileDetect#is}. * * @returns {String} the key for the detected user-agent or null * @function MobileDetect#userAgent */ userAgent: function () { if (this._cache.userAgent === undefined) { this._cache.userAgent = impl.findMatch(impl.mobileDetectRules.uas, this.ua); } return this._cache.userAgent; }, /** * Returns all detected user-agent strings. *
* The array is empty or contains one or more of following keys:
*
Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon
*
* In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare * cases where a mobile device pretends to be more than one particular browser. You can get the * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by * providing one of the defined keys as first argument to {@link MobileDetect#is}. * * @returns {Array} the array of detected user-agent keys or [] * @function MobileDetect#userAgents */ userAgents: function () { if (this._cache.userAgents === undefined) { this._cache.userAgents = impl.findMatches(impl.mobileDetectRules.uas, this.ua); } return this._cache.userAgents; }, /** * Returns the detected operating system string or null. *
* The operating system is one of following keys:
*
AndroidOS, BlackBerryOS, PalmOS, SymbianOS, WindowsMobileOS, WindowsPhoneOS, * iOS, MeeGoOS, MaemoOS, JavaOS, webOS, badaOS, BREWOS
* * @returns {String} the key for the detected operating system. * @function MobileDetect#os */ os: function () { if (this._cache.os === undefined) { this._cache.os = impl.detectOS(this.ua); } return this._cache.os; }, /** * Get the version (as Number) of the given property in the User-Agent. *
* Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param {String} key a key defining a thing which has a version.
* You can use one of following keys:
*
Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna, * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows * CE, Windows NT, Symbian, webOS
* * @returns {Number} the version as float or NaN if User-Agent doesn't contain this version. * Be careful when comparing this value with '==' operator! * @function MobileDetect#version */ version: function (key) { return impl.getVersion(key, this.ua); }, /** * Get the version (as String) of the given property in the User-Agent. *
* * @param {String} key a key defining a thing which has a version.
* You can use one of following keys:
*
Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna, * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows * CE, Windows NT, Symbian, webOS
* * @returns {String} the "raw" version as String or null if User-Agent doesn't contain this version. * * @function MobileDetect#versionStr */ versionStr: function (key) { return impl.getVersionStr(key, this.ua); }, /** * Global test key against userAgent, os, phone, tablet and some other properties of userAgent string. * * @param {String} key the key (case-insensitive) of a userAgent, an operating system, phone or * tablet family.
* For a complete list of possible values, see {@link MobileDetect#userAgent}, * {@link MobileDetect#os}, {@link MobileDetect#phone}, {@link MobileDetect#tablet}.
* Additionally you have following keys:
*
Bot, MobileBot, DesktopMode, TV, WebKit, Console, Watch
* * @returns {boolean} true when the given key is one of the defined keys of userAgent, os, phone, * tablet or one of the listed additional keys, otherwise false * @function MobileDetect#is */ is: function (key) { return containsIC(this.userAgents(), key) || equalIC(key, this.os()) || equalIC(key, this.phone()) || equalIC(key, this.tablet()) || containsIC(impl.findMatches(impl.mobileDetectRules.utils, this.ua), key); }, /** * Do a quick test against navigator::userAgent. * * @param {String|RegExp} pattern the pattern, either as String or RegExp * (a string will be converted to a case-insensitive RegExp). * @returns {boolean} true when the pattern matches, otherwise false * @function MobileDetect#match */ match: function (pattern) { if (!(pattern instanceof RegExp)) { pattern = new RegExp(pattern, 'i'); } return pattern.test(this.ua); }, /** * Checks whether the mobile device can be considered as phone regarding screen.width. *
* Obviously this method makes sense in browser environments only (not for Node.js)! * @param {number} [maxPhoneWidth] the maximum logical pixels (aka. CSS-pixels) to be considered as phone.
* The argument is optional and if not present or falsy, the value of the constructor is taken. * @returns {boolean|undefined} undefined if screen size wasn't detectable, else true * when screen.width is less or equal to maxPhoneWidth, otherwise false.
* Will always return undefined server-side. */ isPhoneSized: function (maxPhoneWidth) { return MobileDetect.isPhoneSized(maxPhoneWidth || this.maxPhoneWidth); }, /** * Returns the mobile grade ('A', 'B', 'C'). * * @returns {String} one of the mobile grades ('A', 'B', 'C'). * @function MobileDetect#mobileGrade */ mobileGrade: function () { if (this._cache.grade === undefined) { this._cache.grade = impl.mobileGrade(this); } return this._cache.grade; } }; // environment-dependent if (typeof window !== 'undefined' && window.screen) { MobileDetect.isPhoneSized = function (maxPhoneWidth) { return maxPhoneWidth < 0 ? undefined : impl.getDeviceSmallerSide() <= maxPhoneWidth; }; } else { MobileDetect.isPhoneSized = function () {}; } // should not be replaced by a completely new object - just overwrite existing methods MobileDetect._impl = impl; MobileDetect.version = '1.3.3 2016-07-31'; return MobileDetect;}); // end of call of define()})((function (undefined) { if (typeof module !== 'undefined' && module.exports) { return function (factory) { module.exports = factory(); }; } else if (typeof define === 'function' && define.amd) { return define; } else if (typeof window !== 'undefined') { return function (factory) { window.MobileDetect = factory(); }; } else { // please file a bug if you get this error! throw new Error('unknown environment'); }})()) : void +>(function (define, undefined) {define(function () { 'use strict'; var impl = {}; impl.mobileDetectRules = { "phones": { "iPhone": "\\biPhone\\b|\\biPod\\b", "BlackBerry": "BlackBerry|\\bBB10\\b|rim[0-9]+", "HTC": "HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m", "Nexus": "Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6", "Dell": "Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b", "Motorola": "Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\\bMoto E\\b", "Samsung": "Samsung|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F", "LG": "\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323)", "Sony": "SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533", "Asus": "Asus.*Galaxy|PadFone.*Mobile", "NokiaLumia": "Lumia [0-9]{3,4}", "Micromax": "Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b", "Palm": "PalmSource|Palm", "Vertu": "Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature", "Pantech": "PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790", "Fly": "IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250", "Wiko": "KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM", "iMobile": "i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)", "SimValley": "\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b", "Wolfgang": "AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q", "Alcatel": "Alcatel", "Nintendo": "Nintendo 3DS", "Amoi": "Amoi", "INQ": "INQ", "GenericPhone": "Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser" }, "tablets": { "iPad": "iPad|iPad.*Mobile", "NexusTablet": "Android.*Nexus[\\s]+(7|9|10)", "SamsungTablet": "SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561", "Kindle": "Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI)\\b", "SurfaceTablet": "Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)", "HPTablet": "HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10", "AsusTablet": "^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b|\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K017 |ME572C|ME103K|ME170C|ME171C|\\bME70C\\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA", "BlackBerryTablet": "PlayBook|RIM Tablet", "HTCtablet": "HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410", "MotorolaTablet": "xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617", "NookTablet": "Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2", "AcerTablet": "Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b|W3-810|\\bA3-A10\\b|\\bA3-A11\\b|\\bA3-A20", "ToshibaTablet": "Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO", "LGTablet": "\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b", "FujitsuTablet": "Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b", "PrestigioTablet": "PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002", "LenovoTablet": "Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)", "DellTablet": "Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7", "YarvikTablet": "Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b", "MedionTablet": "Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB", "ArnovaTablet": "AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2", "IntensoTablet": "INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004", "IRUTablet": "M702pro", "MegafonTablet": "MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b", "EbodaTablet": "E-Boda (Supreme|Impresspeed|Izzycomm|Essential)", "AllViewTablet": "Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)", "ArchosTablet": "\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b", "AinolTablet": "NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark", "NokiaLumiaTablet": "Lumia 2520", "SonyTablet": "Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP612|SOT31", "PhilipsTablet": "\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b", "CubeTablet": "Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT", "CobyTablet": "MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010", "MIDTablet": "M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10", "MSITablet": "MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b", "SMiTTablet": "Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)", "RockChipTablet": "Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A", "FlyTablet": "IQ310|Fly Vision", "bqTablet": "Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris E10)|Maxwell.*Lite|Maxwell.*Plus", "HuaweiTablet": "MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim", "NecTablet": "\\bN-06D|\\bN-08D", "PantechTablet": "Pantech.*P4100", "BronchoTablet": "Broncho.*(N701|N708|N802|a710)", "VersusTablet": "TOUCHPAD.*[78910]|\\bTOUCHTAB\\b", "ZyncTablet": "z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900", "PositivoTablet": "TB07STA|TB10STA|TB07FTA|TB10FTA", "NabiTablet": "Android.*\\bNabi", "KoboTablet": "Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build", "DanewTablet": "DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b", "TexetTablet": "NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE", "PlaystationTablet": "Playstation.*(Portable|Vita)", "TrekstorTablet": "ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab", "PyleAudioTablet": "\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b", "AdvanTablet": "Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ", "DanyTechTablet": "Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1", "GalapadTablet": "Android.*\\bG1\\b", "MicromaxTablet": "Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b", "KarbonnTablet": "Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b", "AllFineTablet": "Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide", "PROSCANTablet": "\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b", "YONESTablet": "BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026", "ChangJiaTablet": "TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503", "GUTablet": "TX-A1301|TX-M9002|Q702|kf026", "PointOfViewTablet": "TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10", "OvermaxTablet": "OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)", "HCLTablet": "HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync", "DPSTablet": "DPS Dream 9|DPS Dual 7", "VistureTablet": "V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10", "CrestaTablet": "CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989", "MediatekTablet": "\\bMT8125|MT8389|MT8135|MT8377\\b", "ConcordeTablet": "Concorde([ ]+)?Tab|ConCorde ReadMan", "GoCleverTablet": "GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042", "ModecomTablet": "FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003", "VoninoTablet": "\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b", "ECSTablet": "V07OT2|TM105A|S10OT1|TR10CS1", "StorexTablet": "eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab", "VodafoneTablet": "SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497", "EssentielBTablet": "Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2", "RossMoorTablet": "RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711", "iMobileTablet": "i-mobile i-note", "TolinoTablet": "tolino tab [0-9.]+|tolino shine", "AudioSonicTablet": "\\bC-22Q|T7-QC|T-17B|T-17P\\b", "AMPETablet": "Android.* A78 ", "SkkTablet": "Android.* (SKYPAD|PHOENIX|CYCLOPS)", "TecnoTablet": "TECNO P9", "JXDTablet": "Android.* \\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b", "iJoyTablet": "Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)", "FX2Tablet": "FX2 PAD7|FX2 PAD10", "XoroTablet": "KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151", "ViewsonicTablet": "ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a", "OdysTablet": "LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10", "CaptivaTablet": "CAPTIVA PAD", "IconbitTablet": "NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S", "TeclastTablet": "T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G|\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G|\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b|\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b|\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b|\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi", "OndaTablet": "\\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\\b[\\s]+", "JaytechTablet": "TPC-PA762", "BlaupunktTablet": "Endeavour 800NG|Endeavour 1010", "DigmaTablet": "\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b", "EvolioTablet": "ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b", "LavaTablet": "QPAD E704|\\bIvoryS\\b|E-TAB IVORY|\\bE-TAB\\b", "AocTablet": "MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712", "MpmanTablet": "MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\\bMPG7\\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010", "CelkonTablet": "CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b", "WolderTablet": "miTab \\b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\\b", "MiTablet": "\\bMI PAD\\b|\\bHM NOTE 1W\\b", "NibiruTablet": "Nibiru M1|Nibiru Jupiter One", "NexoTablet": "NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI", "LeaderTablet": "TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100", "UbislateTablet": "UbiSlate[\\s]?7C", "PocketBookTablet": "Pocketbook", "KocasoTablet": "\\b(TB-1207)\\b", "Hudl": "Hudl HT7S3|Hudl 2", "TelstraTablet": "T-Hub2", "GenericTablet": "Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002|\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\\bM6pro\\b|CT1020W|arc 10HD|\\bJolla\\b|\\bTP750\\b" }, "oss": { "AndroidOS": "Android", "BlackBerryOS": "blackberry|\\bBB10\\b|rim tablet os", "PalmOS": "PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino", "SymbianOS": "Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b", "WindowsMobileOS": "Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;", "WindowsPhoneOS": "Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;", "iOS": "\\biPhone.*Mobile|\\biPod|\\biPad", "MeeGoOS": "MeeGo", "MaemoOS": "Maemo", "JavaOS": "J2ME\/|\\bMIDP\\b|\\bCLDC\\b", "webOS": "webOS|hpwOS", "badaOS": "\\bBada\\b", "BREWOS": "BREW" }, "uas": { "Vivaldi": "Vivaldi", "Chrome": "\\bCrMo\\b|CriOS|Android.*Chrome\/[.0-9]* (Mobile)?", "Dolfin": "\\bDolfin\\b", "Opera": "Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+|Coast\/[0-9.]+", "Skyfire": "Skyfire", "Edge": "Mobile Safari\/[.0-9]* Edge", "IE": "IEMobile|MSIEMobile", "Firefox": "fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile", "Bolt": "bolt", "TeaShark": "teashark", "Blazer": "Blazer", "Safari": "Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari", "Tizen": "Tizen", "UCBrowser": "UC.*Browser|UCWEB", "baiduboxapp": "baiduboxapp", "baidubrowser": "baidubrowser", "DiigoBrowser": "DiigoBrowser", "Puffin": "Puffin", "Mercury": "\\bMercury\\b", "ObigoBrowser": "Obigo", "NetFront": "NF-Browser", "GenericBrowser": "NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger", "PaleMoon": "Android.*PaleMoon|Mobile.*PaleMoon" }, "props": { "Mobile": "Mobile\/[VER]", "Build": "Build\/[VER]", "Version": "Version\/[VER]", "VendorID": "VendorID\/[VER]", "iPad": "iPad.*CPU[a-z ]+[VER]", "iPhone": "iPhone.*CPU[a-z ]+[VER]", "iPod": "iPod.*CPU[a-z ]+[VER]", "Kindle": "Kindle\/[VER]", "Chrome": [ "Chrome\/[VER]", "CriOS\/[VER]", "CrMo\/[VER]" ], "Coast": [ "Coast\/[VER]" ], "Dolfin": "Dolfin\/[VER]", "Firefox": "Firefox\/[VER]", "Fennec": "Fennec\/[VER]", "Edge": "Edge\/[VER]", "IE": [ "IEMobile\/[VER];", "IEMobile [VER]", "MSIE [VER];", "Trident\/[0-9.]+;.*rv:[VER]" ], "NetFront": "NetFront\/[VER]", "NokiaBrowser": "NokiaBrowser\/[VER]", "Opera": [ " OPR\/[VER]", "Opera Mini\/[VER]", "Version\/[VER]" ], "Opera Mini": "Opera Mini\/[VER]", "Opera Mobi": "Version\/[VER]", "UC Browser": "UC Browser[VER]", "MQQBrowser": "MQQBrowser\/[VER]", "MicroMessenger": "MicroMessenger\/[VER]", "baiduboxapp": "baiduboxapp\/[VER]", "baidubrowser": "baidubrowser\/[VER]", "Iron": "Iron\/[VER]", "Safari": [ "Version\/[VER]", "Safari\/[VER]" ], "Skyfire": "Skyfire\/[VER]", "Tizen": "Tizen\/[VER]", "Webkit": "webkit[ \/][VER]", "PaleMoon": "PaleMoon\/[VER]", "Gecko": "Gecko\/[VER]", "Trident": "Trident\/[VER]", "Presto": "Presto\/[VER]", "Goanna": "Goanna\/[VER]", "iOS": " \\bi?OS\\b [VER][ ;]{1}", "Android": "Android [VER]", "BlackBerry": [ "BlackBerry[\\w]+\/[VER]", "BlackBerry.*Version\/[VER]", "Version\/[VER]" ], "BREW": "BREW [VER]", "Java": "Java\/[VER]", "Windows Phone OS": [ "Windows Phone OS [VER]", "Windows Phone [VER]" ], "Windows Phone": "Windows Phone [VER]", "Windows CE": "Windows CE\/[VER]", "Windows NT": "Windows NT [VER]", "Symbian": [ "SymbianOS\/[VER]", "Symbian\/[VER]" ], "webOS": [ "webOS\/[VER]", "hpwOS\/[VER];" ] }, "utils": { "Bot": "Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom", "MobileBot": "Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker\/M1A1-R2D2", "DesktopMode": "WPDesktop", "TV": "SonyDTV|HbbTV", "WebKit": "(webkit)[ \/]([\\w.]+)", "Console": "\\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\\b", "Watch": "SM-V700" }}; // following patterns come from http://detectmobilebrowsers.com/ impl.detectMobileBrowsers = { fullPattern: /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i, shortPattern: /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i, tabletPattern: /android|ipad|playbook|silk/i }; var hasOwnProp = Object.prototype.hasOwnProperty, isArray; impl.FALLBACK_PHONE = 'UnknownPhone'; impl.FALLBACK_TABLET = 'UnknownTablet'; impl.FALLBACK_MOBILE = 'UnknownMobile'; isArray = ('isArray' in Array) ? Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }; isArray = 'isArray' in Array ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : Array.isArray; function equalIC(a, b) { return a != null && b != null && a.toLowerCase() === b.toLowerCase(); } function containsIC(array, value) { var valueLC, i, len = array.length; if (!len || !value) { return false; } valueLC = value.toLowerCase(); for (i = 0; i < len; ++i) { if (valueLC === array[i].toLowerCase()) { return true; } } return false; } function convertPropsToRegExp(object) { for (var key in object) { if (hasOwnProp.call(object, key)) { object[key] = new RegExp(object[key], 'i'); } } } (function init() { var key, values, value, i, len, verPos, mobileDetectRules = impl.mobileDetectRules; for (key in mobileDetectRules.props) { if (hasOwnProp.call(mobileDetectRules.props, key)) { values = mobileDetectRules.props[key]; if (!isArray(values)) { values = [values]; } len = values.length; for (i = 0; i < len; ++i) { value = values[i]; verPos = value.indexOf('[VER]'); if (verPos >= 0) { value = value.substring(0, verPos) + '([\\w._\\+]+)' + value.substring(verPos + 5); } values[i] = new RegExp(value, 'i'); } mobileDetectRules.props[key] = values; } } convertPropsToRegExp(mobileDetectRules.oss); convertPropsToRegExp(mobileDetectRules.phones); convertPropsToRegExp(mobileDetectRules.tablets); convertPropsToRegExp(mobileDetectRules.uas); convertPropsToRegExp(mobileDetectRules.utils); // copy some patterns to oss0 which are tested first (see issue#15) mobileDetectRules.oss0 = { WindowsPhoneOS: mobileDetectRules.oss.WindowsPhoneOS, WindowsMobileOS: mobileDetectRules.oss.WindowsMobileOS }; }()); /** * Test userAgent string against a set of rules and find the first matched key. * @param {Object} rules (key is String, value is RegExp) * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). * @returns {String|null} the matched key if found, otherwise null * @private */ impl.findMatch = function(rules, userAgent) { for (var key in rules) { if (hasOwnProp.call(rules, key)) { if (rules[key].test(userAgent)) { return key; } } } return null; }; /** * Test userAgent string against a set of rules and return an array of matched keys. * @param {Object} rules (key is String, value is RegExp) * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). * @returns {Array} an array of matched keys, may be empty when there is no match, but not null * @private */ impl.findMatches = function(rules, userAgent) { var result = []; for (var key in rules) { if (hasOwnProp.call(rules, key)) { if (rules[key].test(userAgent)) { result.push(key); } } } return result; }; /** * Check the version of the given property in the User-Agent. * * @param {String} propertyName * @param {String} userAgent * @return {String} version or null if version not found * @private */ impl.getVersionStr = function (propertyName, userAgent) { var props = impl.mobileDetectRules.props, patterns, i, len, match; if (hasOwnProp.call(props, propertyName)) { patterns = props[propertyName]; len = patterns.length; for (i = 0; i < len; ++i) { match = patterns[i].exec(userAgent); if (match !== null) { return match[1]; } } } return null; }; /** * Check the version of the given property in the User-Agent. * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param {String} propertyName * @param {String} userAgent * @return {Number} version or NaN if version not found * @private */ impl.getVersion = function (propertyName, userAgent) { var version = impl.getVersionStr(propertyName, userAgent); return version ? impl.prepareVersionNo(version) : NaN; }; /** * Prepare the version number. * * @param {String} version * @return {Number} the version number as a floating number * @private */ impl.prepareVersionNo = function (version) { var numbers; numbers = version.split(/[a-z._ \/\-]/i); if (numbers.length === 1) { version = numbers[0]; } if (numbers.length > 1) { version = numbers[0] + '.'; numbers.shift(); version += numbers.join(''); } return Number(version); }; impl.isMobileFallback = function (userAgent) { return impl.detectMobileBrowsers.fullPattern.test(userAgent) || impl.detectMobileBrowsers.shortPattern.test(userAgent.substr(0,4)); }; impl.isTabletFallback = function (userAgent) { return impl.detectMobileBrowsers.tabletPattern.test(userAgent); }; impl.prepareDetectionCache = function (cache, userAgent, maxPhoneWidth) { if (cache.mobile !== undefined) { return; } var phone, tablet, phoneSized; // first check for stronger tablet rules, then phone (see issue#5) tablet = impl.findMatch(impl.mobileDetectRules.tablets, userAgent); if (tablet) { cache.mobile = cache.tablet = tablet; cache.phone = null; return; // unambiguously identified as tablet } phone = impl.findMatch(impl.mobileDetectRules.phones, userAgent); if (phone) { cache.mobile = cache.phone = phone; cache.tablet = null; return; // unambiguously identified as phone } // our rules haven't found a match -> try more general fallback rules if (impl.isMobileFallback(userAgent)) { phoneSized = MobileDetect.isPhoneSized(maxPhoneWidth); if (phoneSized === undefined) { cache.mobile = impl.FALLBACK_MOBILE; cache.tablet = cache.phone = null; } else if (phoneSized) { cache.mobile = cache.phone = impl.FALLBACK_PHONE; cache.tablet = null; } else { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; cache.phone = null; } } else if (impl.isTabletFallback(userAgent)) { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; cache.phone = null; } else { // not mobile at all! cache.mobile = cache.tablet = cache.phone = null; } }; // t is a reference to a MobileDetect instance impl.mobileGrade = function (t) { // impl note: // To keep in sync w/ Mobile_Detect.php easily, the following code is tightly aligned to the PHP version. // When changes are made in Mobile_Detect.php, copy this method and replace: // $this-> / t. // self::MOBILE_GRADE_(.) / '$1' // , self::VERSION_TYPE_FLOAT / (nothing) // isIOS() / os('iOS') // [reg] / (nothing) <-- jsdelivr complaining about unescaped unicode character U+00AE var $isMobile = t.mobile() !== null; if ( // Apple iOS 3.2-5.1 - Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3), iPad 3 (5.1), original iPhone (3.1), iPhone 3 (3.2), 3GS (4.3), 4 (4.3 / 5.0), and 4S (5.1) t.os('iOS') && t.version('iPad')>=4.3 || t.os('iOS') && t.version('iPhone')>=3.1 || t.os('iOS') && t.version('iPod')>=3.1 || // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5) // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7 ( t.version('Android')>2.1 && t.is('Webkit') ) || // Windows Phone 7-7.5 - Tested on the HTC Surround (7.0) HTC Trophy (7.5), LG-E900 (7.5), Nokia Lumia 800 t.version('Windows Phone OS')>=7.0 || // Blackberry 7 - Tested on BlackBerry Torch 9810 // Blackberry 6.0 - Tested on the Torch 9800 and Style 9670 t.is('BlackBerry') && t.version('BlackBerry')>=6.0 || // Blackberry Playbook (1.0-2.0) - Tested on PlayBook t.match('Playbook.*Tablet') || // Palm WebOS (1.4-2.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0) ( t.version('webOS')>=1.4 && t.match('Palm|Pre|Pixi') ) || // Palm WebOS 3.0 - Tested on HP TouchPad t.match('hp.*TouchPad') || // Firefox Mobile (12 Beta) - Tested on Android 2.3 device ( t.is('Firefox') && t.version('Firefox')>=12 ) || // Chrome for Android - Tested on Android 4.0, 4.1 device ( t.is('Chrome') && t.is('AndroidOS') && t.version('Android')>=4.0 ) || // Skyfire 4.1 - Tested on Android 2.3 device ( t.is('Skyfire') && t.version('Skyfire')>=4.1 && t.is('AndroidOS') && t.version('Android')>=2.3 ) || // Opera Mobile 11.5-12: Tested on Android 2.3 ( t.is('Opera') && t.version('Opera Mobi')>11 && t.is('AndroidOS') ) || // Meego 1.2 - Tested on Nokia 950 and N9 t.is('MeeGoOS') || // Tizen (pre-release) - Tested on early hardware t.is('Tizen') || // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser // @todo: more tests here! t.is('Dolfin') && t.version('Bada')>=2.0 || // UC Browser - Tested on Android 2.3 device ( (t.is('UC Browser') || t.is('Dolfin')) && t.version('Android')>=2.3 ) || // Kindle 3 and Fire - Tested on the built-in WebKit browser for each ( t.match('Kindle Fire') || t.is('Kindle') && t.version('Kindle')>=3.0 ) || // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet t.is('AndroidOS') && t.is('NookTablet') || // Chrome Desktop 11-21 - Tested on OS X 10.7 and Windows 7 t.version('Chrome')>=11 && !$isMobile || // Safari Desktop 4-5 - Tested on OS X 10.7 and Windows 7 t.version('Safari')>=5.0 && !$isMobile || // Firefox Desktop 4-13 - Tested on OS X 10.7 and Windows 7 t.version('Firefox')>=4.0 && !$isMobile || // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7 t.version('MSIE')>=7.0 && !$isMobile || // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7 // @reference: http://my.opera.com/community/openweb/idopera/ t.version('Opera')>=10 && !$isMobile ){ return 'A'; } if ( t.os('iOS') && t.version('iPad')<4.3 || t.os('iOS') && t.version('iPhone')<3.1 || t.os('iOS') && t.version('iPod')<3.1 || // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770 t.is('Blackberry') && t.version('BlackBerry')>=5 && t.version('BlackBerry')<6 || //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3 ( t.version('Opera Mini')>=5.0 && t.version('Opera Mini')<=6.5 && (t.version('Android')>=2.3 || t.is('iOS')) ) || // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1) t.match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') || // @todo: report this (tested on Nokia N71) t.version('Opera Mobi')>=11 && t.is('SymbianOS') ){ return 'B'; } if ( // Blackberry 4.x - Tested on the Curve 8330 t.version('BlackBerry')<5.0 || // Windows Mobile - Tested on the HTC Leo (WinMo 5.2) t.match('MSIEMobile|Windows CE.*Mobile') || t.version('Windows Mobile')<=5.2 ){ return 'C'; } //All older smartphone platforms and featurephones - Any device that doesn't support media queries //will receive the basic, C grade experience. return 'C'; }; impl.detectOS = function (ua) { return impl.findMatch(impl.mobileDetectRules.oss0, ua) || impl.findMatch(impl.mobileDetectRules.oss, ua); }; impl.getDeviceSmallerSide = function () { return window.screen.width < window.screen.height ? window.screen.width : window.screen.height; }; /** * Constructor for MobileDetect object. *
* Such an object will keep a reference to the given user-agent string and cache most of the detect queries.
*
* Find information how to download and install: * github.com/hgoebl/mobile-detect.js/ *
* * @example
     *     var md = new MobileDetect(window.navigator.userAgent);     *     if (md.mobile()) {     *         location.href = (md.mobileGrade() === 'A') ? '/mobile/' : '/lynx/';     *     }     * 
* * @param {string} userAgent typically taken from window.navigator.userAgent or http_header['User-Agent'] * @param {number} [maxPhoneWidth=600] only for browsers specify a value for the maximum * width of smallest device side (in logical "CSS" pixels) until a device detected as mobile will be handled * as phone. * This is only used in cases where the device cannot be classified as phone or tablet.
* See Declaring Tablet Layouts * for Android.
* If you provide a value < 0, then this "fuzzy" check is disabled. * @constructor * @global */ function MobileDetect(userAgent, maxPhoneWidth) { this.ua = userAgent || ''; this._cache = {}; //600dp is typical 7" tablet minimum width this.maxPhoneWidth = maxPhoneWidth || 600; } MobileDetect.prototype = { constructor: MobileDetect, /** * Returns the detected phone or tablet type or null if it is not a mobile device. *
* For a list of possible return values see {@link MobileDetect#phone} and {@link MobileDetect#tablet}.
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownPhone, UnknownTablet or * UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get UnknownMobile here.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key for the phone family or tablet family, e.g. "Nexus". * @function MobileDetect#mobile */ mobile: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.mobile; }, /** * Returns the detected phone type/family string or null. *
* The returned tablet (family or producer) is one of following keys:
*
iPhone, BlackBerry, HTC, Nexus, Dell, Motorola, Samsung, LG, Sony, Asus, * NokiaLumia, Micromax, Palm, Vertu, Pantech, Fly, Wiko, iMobile, SimValley, * Wolfgang, Alcatel, Nintendo, Amoi, INQ, GenericPhone
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownPhone or UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get null here, while {@link MobileDetect#mobile} * will return UnknownMobile.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key of the phone family or producer, e.g. "iPhone" * @function MobileDetect#phone */ phone: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.phone; }, /** * Returns the detected tablet type/family string or null. *
* The returned tablet (family or producer) is one of following keys:
*
iPad, NexusTablet, SamsungTablet, Kindle, SurfaceTablet, HPTablet, AsusTablet, * BlackBerryTablet, HTCtablet, MotorolaTablet, NookTablet, AcerTablet, * ToshibaTablet, LGTablet, FujitsuTablet, PrestigioTablet, LenovoTablet, * DellTablet, YarvikTablet, MedionTablet, ArnovaTablet, IntensoTablet, IRUTablet, * MegafonTablet, EbodaTablet, AllViewTablet, ArchosTablet, AinolTablet, * NokiaLumiaTablet, SonyTablet, PhilipsTablet, CubeTablet, CobyTablet, MIDTablet, * MSITablet, SMiTTablet, RockChipTablet, FlyTablet, bqTablet, HuaweiTablet, * NecTablet, PantechTablet, BronchoTablet, VersusTablet, ZyncTablet, * PositivoTablet, NabiTablet, KoboTablet, DanewTablet, TexetTablet, * PlaystationTablet, TrekstorTablet, PyleAudioTablet, AdvanTablet, * DanyTechTablet, GalapadTablet, MicromaxTablet, KarbonnTablet, AllFineTablet, * PROSCANTablet, YONESTablet, ChangJiaTablet, GUTablet, PointOfViewTablet, * OvermaxTablet, HCLTablet, DPSTablet, VistureTablet, CrestaTablet, * MediatekTablet, ConcordeTablet, GoCleverTablet, ModecomTablet, VoninoTablet, * ECSTablet, StorexTablet, VodafoneTablet, EssentielBTablet, RossMoorTablet, * iMobileTablet, TolinoTablet, AudioSonicTablet, AMPETablet, SkkTablet, * TecnoTablet, JXDTablet, iJoyTablet, FX2Tablet, XoroTablet, ViewsonicTablet, * OdysTablet, CaptivaTablet, IconbitTablet, TeclastTablet, OndaTablet, * JaytechTablet, BlaupunktTablet, DigmaTablet, EvolioTablet, LavaTablet, * AocTablet, MpmanTablet, CelkonTablet, WolderTablet, MiTablet, NibiruTablet, * NexoTablet, LeaderTablet, UbislateTablet, PocketBookTablet, KocasoTablet, Hudl, * TelstraTablet, GenericTablet
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownTablet or UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get null here, while {@link MobileDetect#mobile} * will return UnknownMobile.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key of the tablet family or producer, e.g. "SamsungTablet" * @function MobileDetect#tablet */ tablet: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.tablet; }, /** * Returns the (first) detected user-agent string or null. *
* The returned user-agent is one of following keys:
*
Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon
*
* In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare * cases where a mobile device pretends to be more than one particular browser. You can get the * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by * providing one of the defined keys as first argument to {@link MobileDetect#is}. * * @returns {String} the key for the detected user-agent or null * @function MobileDetect#userAgent */ userAgent: function () { if (this._cache.userAgent === undefined) { this._cache.userAgent = impl.findMatch(impl.mobileDetectRules.uas, this.ua); } return this._cache.userAgent; }, /** * Returns all detected user-agent strings. *
* The array is empty or contains one or more of following keys:
*
Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon
*
* In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare * cases where a mobile device pretends to be more than one particular browser. You can get the * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by * providing one of the defined keys as first argument to {@link MobileDetect#is}. * * @returns {Array} the array of detected user-agent keys or [] * @function MobileDetect#userAgents */ userAgents: function () { if (this._cache.userAgents === undefined) { this._cache.userAgents = impl.findMatches(impl.mobileDetectRules.uas, this.ua); } return this._cache.userAgents; }, /** * Returns the detected operating system string or null. *
* The operating system is one of following keys:
*
AndroidOS, BlackBerryOS, PalmOS, SymbianOS, WindowsMobileOS, WindowsPhoneOS, * iOS, MeeGoOS, MaemoOS, JavaOS, webOS, badaOS, BREWOS
* * @returns {String} the key for the detected operating system. * @function MobileDetect#os */ os: function () { if (this._cache.os === undefined) { this._cache.os = impl.detectOS(this.ua); } return this._cache.os; }, /** * Get the version (as Number) of the given property in the User-Agent. *
* Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param {String} key a key defining a thing which has a version.
* You can use one of following keys:
*
Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna, * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows * CE, Windows NT, Symbian, webOS
* * @returns {Number} the version as float or NaN if User-Agent doesn't contain this version. * Be careful when comparing this value with '==' operator! * @function MobileDetect#version */ version: function (key) { return impl.getVersion(key, this.ua); }, /** * Get the version (as String) of the given property in the User-Agent. *
* * @param {String} key a key defining a thing which has a version.
* You can use one of following keys:
*
Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna, * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows * CE, Windows NT, Symbian, webOS
* * @returns {String} the "raw" version as String or null if User-Agent doesn't contain this version. * * @function MobileDetect#versionStr */ versionStr: function (key) { return impl.getVersionStr(key, this.ua); }, /** * Global test key against userAgent, os, phone, tablet and some other properties of userAgent string. * * @param {String} key the key (case-insensitive) of a userAgent, an operating system, phone or * tablet family.
* For a complete list of possible values, see {@link MobileDetect#userAgent}, * {@link MobileDetect#os}, {@link MobileDetect#phone}, {@link MobileDetect#tablet}.
* Additionally you have following keys:
*
Bot, MobileBot, DesktopMode, TV, WebKit, Console, Watch
* * @returns {boolean} true when the given key is one of the defined keys of userAgent, os, phone, * tablet or one of the listed additional keys, otherwise false * @function MobileDetect#is */ is: function (key) { return containsIC(this.userAgents(), key) || equalIC(key, this.os()) || equalIC(key, this.phone()) || equalIC(key, this.tablet()) || containsIC(impl.findMatches(impl.mobileDetectRules.utils, this.ua), key); }, /** * Do a quick test against navigator::userAgent. * * @param {String|RegExp} pattern the pattern, either as String or RegExp * (a string will be converted to a case-insensitive RegExp). * @returns {boolean} true when the pattern matches, otherwise false * @function MobileDetect#match */ match: function (pattern) { if (!(pattern instanceof RegExp)) { pattern = new RegExp(pattern, 'i'); } return pattern.test(this.ua); }, /** * Checks whether the mobile device can be considered as phone regarding screen.width. *
* Obviously this method makes sense in browser environments only (not for Node.js)! * @param {number} [maxPhoneWidth] the maximum logical pixels (aka. CSS-pixels) to be considered as phone.
* The argument is optional and if not present or falsy, the value of the constructor is taken. * @returns {boolean|undefined} undefined if screen size wasn't detectable, else true * when screen.width is less or equal to maxPhoneWidth, otherwise false.
* Will always return undefined server-side. */ isPhoneSized: function (maxPhoneWidth) { return MobileDetect.isPhoneSized(maxPhoneWidth || this.maxPhoneWidth); }, /** * Returns the mobile grade ('A', 'B', 'C'). * * @returns {String} one of the mobile grades ('A', 'B', 'C'). * @function MobileDetect#mobileGrade */ mobileGrade: function () { if (this._cache.grade === undefined) { this._cache.grade = impl.mobileGrade(this); } return this._cache.grade; } }; // environment-dependent if (typeof window !== 'undefined' && window.screen) { MobileDetect.isPhoneSized = function (maxPhoneWidth) { return maxPhoneWidth < 0 ? undefined : impl.getDeviceSmallerSide() <= maxPhoneWidth; }; } else { MobileDetect.isPhoneSized = function () {}; } // should not be replaced by a completely new object - just overwrite existing methods MobileDetect._impl = impl; MobileDetect.version = '1.3.3 2016-07-31'; return MobileDetect;}); // end of call of define()}) : (define: any, undefined?: any) => void +>function (define, undefined) {define(function () { 'use strict'; var impl = {}; impl.mobileDetectRules = { "phones": { "iPhone": "\\biPhone\\b|\\biPod\\b", "BlackBerry": "BlackBerry|\\bBB10\\b|rim[0-9]+", "HTC": "HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m", "Nexus": "Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6", "Dell": "Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b", "Motorola": "Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\\bMoto E\\b", "Samsung": "Samsung|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F", "LG": "\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323)", "Sony": "SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533", "Asus": "Asus.*Galaxy|PadFone.*Mobile", "NokiaLumia": "Lumia [0-9]{3,4}", "Micromax": "Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b", "Palm": "PalmSource|Palm", "Vertu": "Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature", "Pantech": "PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790", "Fly": "IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250", "Wiko": "KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM", "iMobile": "i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)", "SimValley": "\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b", "Wolfgang": "AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q", "Alcatel": "Alcatel", "Nintendo": "Nintendo 3DS", "Amoi": "Amoi", "INQ": "INQ", "GenericPhone": "Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser" }, "tablets": { "iPad": "iPad|iPad.*Mobile", "NexusTablet": "Android.*Nexus[\\s]+(7|9|10)", "SamsungTablet": "SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561", "Kindle": "Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI)\\b", "SurfaceTablet": "Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)", "HPTablet": "HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10", "AsusTablet": "^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b|\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K017 |ME572C|ME103K|ME170C|ME171C|\\bME70C\\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA", "BlackBerryTablet": "PlayBook|RIM Tablet", "HTCtablet": "HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410", "MotorolaTablet": "xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617", "NookTablet": "Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2", "AcerTablet": "Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b|W3-810|\\bA3-A10\\b|\\bA3-A11\\b|\\bA3-A20", "ToshibaTablet": "Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO", "LGTablet": "\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b", "FujitsuTablet": "Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b", "PrestigioTablet": "PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002", "LenovoTablet": "Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)", "DellTablet": "Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7", "YarvikTablet": "Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b", "MedionTablet": "Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB", "ArnovaTablet": "AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2", "IntensoTablet": "INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004", "IRUTablet": "M702pro", "MegafonTablet": "MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b", "EbodaTablet": "E-Boda (Supreme|Impresspeed|Izzycomm|Essential)", "AllViewTablet": "Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)", "ArchosTablet": "\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b", "AinolTablet": "NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark", "NokiaLumiaTablet": "Lumia 2520", "SonyTablet": "Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP612|SOT31", "PhilipsTablet": "\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b", "CubeTablet": "Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT", "CobyTablet": "MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010", "MIDTablet": "M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10", "MSITablet": "MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b", "SMiTTablet": "Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)", "RockChipTablet": "Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A", "FlyTablet": "IQ310|Fly Vision", "bqTablet": "Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris E10)|Maxwell.*Lite|Maxwell.*Plus", "HuaweiTablet": "MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim", "NecTablet": "\\bN-06D|\\bN-08D", "PantechTablet": "Pantech.*P4100", "BronchoTablet": "Broncho.*(N701|N708|N802|a710)", "VersusTablet": "TOUCHPAD.*[78910]|\\bTOUCHTAB\\b", "ZyncTablet": "z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900", "PositivoTablet": "TB07STA|TB10STA|TB07FTA|TB10FTA", "NabiTablet": "Android.*\\bNabi", "KoboTablet": "Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build", "DanewTablet": "DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b", "TexetTablet": "NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE", "PlaystationTablet": "Playstation.*(Portable|Vita)", "TrekstorTablet": "ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab", "PyleAudioTablet": "\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b", "AdvanTablet": "Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ", "DanyTechTablet": "Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1", "GalapadTablet": "Android.*\\bG1\\b", "MicromaxTablet": "Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b", "KarbonnTablet": "Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b", "AllFineTablet": "Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide", "PROSCANTablet": "\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b", "YONESTablet": "BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026", "ChangJiaTablet": "TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503", "GUTablet": "TX-A1301|TX-M9002|Q702|kf026", "PointOfViewTablet": "TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10", "OvermaxTablet": "OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)", "HCLTablet": "HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync", "DPSTablet": "DPS Dream 9|DPS Dual 7", "VistureTablet": "V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10", "CrestaTablet": "CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989", "MediatekTablet": "\\bMT8125|MT8389|MT8135|MT8377\\b", "ConcordeTablet": "Concorde([ ]+)?Tab|ConCorde ReadMan", "GoCleverTablet": "GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042", "ModecomTablet": "FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003", "VoninoTablet": "\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b", "ECSTablet": "V07OT2|TM105A|S10OT1|TR10CS1", "StorexTablet": "eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab", "VodafoneTablet": "SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497", "EssentielBTablet": "Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2", "RossMoorTablet": "RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711", "iMobileTablet": "i-mobile i-note", "TolinoTablet": "tolino tab [0-9.]+|tolino shine", "AudioSonicTablet": "\\bC-22Q|T7-QC|T-17B|T-17P\\b", "AMPETablet": "Android.* A78 ", "SkkTablet": "Android.* (SKYPAD|PHOENIX|CYCLOPS)", "TecnoTablet": "TECNO P9", "JXDTablet": "Android.* \\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b", "iJoyTablet": "Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)", "FX2Tablet": "FX2 PAD7|FX2 PAD10", "XoroTablet": "KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151", "ViewsonicTablet": "ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a", "OdysTablet": "LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10", "CaptivaTablet": "CAPTIVA PAD", "IconbitTablet": "NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S", "TeclastTablet": "T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G|\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G|\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b|\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b|\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b|\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi", "OndaTablet": "\\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\\b[\\s]+", "JaytechTablet": "TPC-PA762", "BlaupunktTablet": "Endeavour 800NG|Endeavour 1010", "DigmaTablet": "\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b", "EvolioTablet": "ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b", "LavaTablet": "QPAD E704|\\bIvoryS\\b|E-TAB IVORY|\\bE-TAB\\b", "AocTablet": "MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712", "MpmanTablet": "MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\\bMPG7\\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010", "CelkonTablet": "CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b", "WolderTablet": "miTab \\b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\\b", "MiTablet": "\\bMI PAD\\b|\\bHM NOTE 1W\\b", "NibiruTablet": "Nibiru M1|Nibiru Jupiter One", "NexoTablet": "NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI", "LeaderTablet": "TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100", "UbislateTablet": "UbiSlate[\\s]?7C", "PocketBookTablet": "Pocketbook", "KocasoTablet": "\\b(TB-1207)\\b", "Hudl": "Hudl HT7S3|Hudl 2", "TelstraTablet": "T-Hub2", "GenericTablet": "Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002|\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\\bM6pro\\b|CT1020W|arc 10HD|\\bJolla\\b|\\bTP750\\b" }, "oss": { "AndroidOS": "Android", "BlackBerryOS": "blackberry|\\bBB10\\b|rim tablet os", "PalmOS": "PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino", "SymbianOS": "Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b", "WindowsMobileOS": "Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;", "WindowsPhoneOS": "Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;", "iOS": "\\biPhone.*Mobile|\\biPod|\\biPad", "MeeGoOS": "MeeGo", "MaemoOS": "Maemo", "JavaOS": "J2ME\/|\\bMIDP\\b|\\bCLDC\\b", "webOS": "webOS|hpwOS", "badaOS": "\\bBada\\b", "BREWOS": "BREW" }, "uas": { "Vivaldi": "Vivaldi", "Chrome": "\\bCrMo\\b|CriOS|Android.*Chrome\/[.0-9]* (Mobile)?", "Dolfin": "\\bDolfin\\b", "Opera": "Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+|Coast\/[0-9.]+", "Skyfire": "Skyfire", "Edge": "Mobile Safari\/[.0-9]* Edge", "IE": "IEMobile|MSIEMobile", "Firefox": "fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile", "Bolt": "bolt", "TeaShark": "teashark", "Blazer": "Blazer", "Safari": "Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari", "Tizen": "Tizen", "UCBrowser": "UC.*Browser|UCWEB", "baiduboxapp": "baiduboxapp", "baidubrowser": "baidubrowser", "DiigoBrowser": "DiigoBrowser", "Puffin": "Puffin", "Mercury": "\\bMercury\\b", "ObigoBrowser": "Obigo", "NetFront": "NF-Browser", "GenericBrowser": "NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger", "PaleMoon": "Android.*PaleMoon|Mobile.*PaleMoon" }, "props": { "Mobile": "Mobile\/[VER]", "Build": "Build\/[VER]", "Version": "Version\/[VER]", "VendorID": "VendorID\/[VER]", "iPad": "iPad.*CPU[a-z ]+[VER]", "iPhone": "iPhone.*CPU[a-z ]+[VER]", "iPod": "iPod.*CPU[a-z ]+[VER]", "Kindle": "Kindle\/[VER]", "Chrome": [ "Chrome\/[VER]", "CriOS\/[VER]", "CrMo\/[VER]" ], "Coast": [ "Coast\/[VER]" ], "Dolfin": "Dolfin\/[VER]", "Firefox": "Firefox\/[VER]", "Fennec": "Fennec\/[VER]", "Edge": "Edge\/[VER]", "IE": [ "IEMobile\/[VER];", "IEMobile [VER]", "MSIE [VER];", "Trident\/[0-9.]+;.*rv:[VER]" ], "NetFront": "NetFront\/[VER]", "NokiaBrowser": "NokiaBrowser\/[VER]", "Opera": [ " OPR\/[VER]", "Opera Mini\/[VER]", "Version\/[VER]" ], "Opera Mini": "Opera Mini\/[VER]", "Opera Mobi": "Version\/[VER]", "UC Browser": "UC Browser[VER]", "MQQBrowser": "MQQBrowser\/[VER]", "MicroMessenger": "MicroMessenger\/[VER]", "baiduboxapp": "baiduboxapp\/[VER]", "baidubrowser": "baidubrowser\/[VER]", "Iron": "Iron\/[VER]", "Safari": [ "Version\/[VER]", "Safari\/[VER]" ], "Skyfire": "Skyfire\/[VER]", "Tizen": "Tizen\/[VER]", "Webkit": "webkit[ \/][VER]", "PaleMoon": "PaleMoon\/[VER]", "Gecko": "Gecko\/[VER]", "Trident": "Trident\/[VER]", "Presto": "Presto\/[VER]", "Goanna": "Goanna\/[VER]", "iOS": " \\bi?OS\\b [VER][ ;]{1}", "Android": "Android [VER]", "BlackBerry": [ "BlackBerry[\\w]+\/[VER]", "BlackBerry.*Version\/[VER]", "Version\/[VER]" ], "BREW": "BREW [VER]", "Java": "Java\/[VER]", "Windows Phone OS": [ "Windows Phone OS [VER]", "Windows Phone [VER]" ], "Windows Phone": "Windows Phone [VER]", "Windows CE": "Windows CE\/[VER]", "Windows NT": "Windows NT [VER]", "Symbian": [ "SymbianOS\/[VER]", "Symbian\/[VER]" ], "webOS": [ "webOS\/[VER]", "hpwOS\/[VER];" ] }, "utils": { "Bot": "Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom", "MobileBot": "Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker\/M1A1-R2D2", "DesktopMode": "WPDesktop", "TV": "SonyDTV|HbbTV", "WebKit": "(webkit)[ \/]([\\w.]+)", "Console": "\\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\\b", "Watch": "SM-V700" }}; // following patterns come from http://detectmobilebrowsers.com/ impl.detectMobileBrowsers = { fullPattern: /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i, shortPattern: /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i, tabletPattern: /android|ipad|playbook|silk/i }; var hasOwnProp = Object.prototype.hasOwnProperty, isArray; impl.FALLBACK_PHONE = 'UnknownPhone'; impl.FALLBACK_TABLET = 'UnknownTablet'; impl.FALLBACK_MOBILE = 'UnknownMobile'; isArray = ('isArray' in Array) ? Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }; isArray = 'isArray' in Array ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : Array.isArray; function equalIC(a, b) { return a != null && b != null && a.toLowerCase() === b.toLowerCase(); } function containsIC(array, value) { var valueLC, i, len = array.length; if (!len || !value) { return false; } valueLC = value.toLowerCase(); for (i = 0; i < len; ++i) { if (valueLC === array[i].toLowerCase()) { return true; } } return false; } function convertPropsToRegExp(object) { for (var key in object) { if (hasOwnProp.call(object, key)) { object[key] = new RegExp(object[key], 'i'); } } } (function init() { var key, values, value, i, len, verPos, mobileDetectRules = impl.mobileDetectRules; for (key in mobileDetectRules.props) { if (hasOwnProp.call(mobileDetectRules.props, key)) { values = mobileDetectRules.props[key]; if (!isArray(values)) { values = [values]; } len = values.length; for (i = 0; i < len; ++i) { value = values[i]; verPos = value.indexOf('[VER]'); if (verPos >= 0) { value = value.substring(0, verPos) + '([\\w._\\+]+)' + value.substring(verPos + 5); } values[i] = new RegExp(value, 'i'); } mobileDetectRules.props[key] = values; } } convertPropsToRegExp(mobileDetectRules.oss); convertPropsToRegExp(mobileDetectRules.phones); convertPropsToRegExp(mobileDetectRules.tablets); convertPropsToRegExp(mobileDetectRules.uas); convertPropsToRegExp(mobileDetectRules.utils); // copy some patterns to oss0 which are tested first (see issue#15) mobileDetectRules.oss0 = { WindowsPhoneOS: mobileDetectRules.oss.WindowsPhoneOS, WindowsMobileOS: mobileDetectRules.oss.WindowsMobileOS }; }()); /** * Test userAgent string against a set of rules and find the first matched key. * @param {Object} rules (key is String, value is RegExp) * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). * @returns {String|null} the matched key if found, otherwise null * @private */ impl.findMatch = function(rules, userAgent) { for (var key in rules) { if (hasOwnProp.call(rules, key)) { if (rules[key].test(userAgent)) { return key; } } } return null; }; /** * Test userAgent string against a set of rules and return an array of matched keys. * @param {Object} rules (key is String, value is RegExp) * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). * @returns {Array} an array of matched keys, may be empty when there is no match, but not null * @private */ impl.findMatches = function(rules, userAgent) { var result = []; for (var key in rules) { if (hasOwnProp.call(rules, key)) { if (rules[key].test(userAgent)) { result.push(key); } } } return result; }; /** * Check the version of the given property in the User-Agent. * * @param {String} propertyName * @param {String} userAgent * @return {String} version or null if version not found * @private */ impl.getVersionStr = function (propertyName, userAgent) { var props = impl.mobileDetectRules.props, patterns, i, len, match; if (hasOwnProp.call(props, propertyName)) { patterns = props[propertyName]; len = patterns.length; for (i = 0; i < len; ++i) { match = patterns[i].exec(userAgent); if (match !== null) { return match[1]; } } } return null; }; /** * Check the version of the given property in the User-Agent. * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param {String} propertyName * @param {String} userAgent * @return {Number} version or NaN if version not found * @private */ impl.getVersion = function (propertyName, userAgent) { var version = impl.getVersionStr(propertyName, userAgent); return version ? impl.prepareVersionNo(version) : NaN; }; /** * Prepare the version number. * * @param {String} version * @return {Number} the version number as a floating number * @private */ impl.prepareVersionNo = function (version) { var numbers; numbers = version.split(/[a-z._ \/\-]/i); if (numbers.length === 1) { version = numbers[0]; } if (numbers.length > 1) { version = numbers[0] + '.'; numbers.shift(); version += numbers.join(''); } return Number(version); }; impl.isMobileFallback = function (userAgent) { return impl.detectMobileBrowsers.fullPattern.test(userAgent) || impl.detectMobileBrowsers.shortPattern.test(userAgent.substr(0,4)); }; impl.isTabletFallback = function (userAgent) { return impl.detectMobileBrowsers.tabletPattern.test(userAgent); }; impl.prepareDetectionCache = function (cache, userAgent, maxPhoneWidth) { if (cache.mobile !== undefined) { return; } var phone, tablet, phoneSized; // first check for stronger tablet rules, then phone (see issue#5) tablet = impl.findMatch(impl.mobileDetectRules.tablets, userAgent); if (tablet) { cache.mobile = cache.tablet = tablet; cache.phone = null; return; // unambiguously identified as tablet } phone = impl.findMatch(impl.mobileDetectRules.phones, userAgent); if (phone) { cache.mobile = cache.phone = phone; cache.tablet = null; return; // unambiguously identified as phone } // our rules haven't found a match -> try more general fallback rules if (impl.isMobileFallback(userAgent)) { phoneSized = MobileDetect.isPhoneSized(maxPhoneWidth); if (phoneSized === undefined) { cache.mobile = impl.FALLBACK_MOBILE; cache.tablet = cache.phone = null; } else if (phoneSized) { cache.mobile = cache.phone = impl.FALLBACK_PHONE; cache.tablet = null; } else { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; cache.phone = null; } } else if (impl.isTabletFallback(userAgent)) { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; cache.phone = null; } else { // not mobile at all! cache.mobile = cache.tablet = cache.phone = null; } }; // t is a reference to a MobileDetect instance impl.mobileGrade = function (t) { // impl note: // To keep in sync w/ Mobile_Detect.php easily, the following code is tightly aligned to the PHP version. // When changes are made in Mobile_Detect.php, copy this method and replace: // $this-> / t. // self::MOBILE_GRADE_(.) / '$1' // , self::VERSION_TYPE_FLOAT / (nothing) // isIOS() / os('iOS') // [reg] / (nothing) <-- jsdelivr complaining about unescaped unicode character U+00AE var $isMobile = t.mobile() !== null; if ( // Apple iOS 3.2-5.1 - Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3), iPad 3 (5.1), original iPhone (3.1), iPhone 3 (3.2), 3GS (4.3), 4 (4.3 / 5.0), and 4S (5.1) t.os('iOS') && t.version('iPad')>=4.3 || t.os('iOS') && t.version('iPhone')>=3.1 || t.os('iOS') && t.version('iPod')>=3.1 || // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5) // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7 ( t.version('Android')>2.1 && t.is('Webkit') ) || // Windows Phone 7-7.5 - Tested on the HTC Surround (7.0) HTC Trophy (7.5), LG-E900 (7.5), Nokia Lumia 800 t.version('Windows Phone OS')>=7.0 || // Blackberry 7 - Tested on BlackBerry Torch 9810 // Blackberry 6.0 - Tested on the Torch 9800 and Style 9670 t.is('BlackBerry') && t.version('BlackBerry')>=6.0 || // Blackberry Playbook (1.0-2.0) - Tested on PlayBook t.match('Playbook.*Tablet') || // Palm WebOS (1.4-2.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0) ( t.version('webOS')>=1.4 && t.match('Palm|Pre|Pixi') ) || // Palm WebOS 3.0 - Tested on HP TouchPad t.match('hp.*TouchPad') || // Firefox Mobile (12 Beta) - Tested on Android 2.3 device ( t.is('Firefox') && t.version('Firefox')>=12 ) || // Chrome for Android - Tested on Android 4.0, 4.1 device ( t.is('Chrome') && t.is('AndroidOS') && t.version('Android')>=4.0 ) || // Skyfire 4.1 - Tested on Android 2.3 device ( t.is('Skyfire') && t.version('Skyfire')>=4.1 && t.is('AndroidOS') && t.version('Android')>=2.3 ) || // Opera Mobile 11.5-12: Tested on Android 2.3 ( t.is('Opera') && t.version('Opera Mobi')>11 && t.is('AndroidOS') ) || // Meego 1.2 - Tested on Nokia 950 and N9 t.is('MeeGoOS') || // Tizen (pre-release) - Tested on early hardware t.is('Tizen') || // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser // @todo: more tests here! t.is('Dolfin') && t.version('Bada')>=2.0 || // UC Browser - Tested on Android 2.3 device ( (t.is('UC Browser') || t.is('Dolfin')) && t.version('Android')>=2.3 ) || // Kindle 3 and Fire - Tested on the built-in WebKit browser for each ( t.match('Kindle Fire') || t.is('Kindle') && t.version('Kindle')>=3.0 ) || // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet t.is('AndroidOS') && t.is('NookTablet') || // Chrome Desktop 11-21 - Tested on OS X 10.7 and Windows 7 t.version('Chrome')>=11 && !$isMobile || // Safari Desktop 4-5 - Tested on OS X 10.7 and Windows 7 t.version('Safari')>=5.0 && !$isMobile || // Firefox Desktop 4-13 - Tested on OS X 10.7 and Windows 7 t.version('Firefox')>=4.0 && !$isMobile || // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7 t.version('MSIE')>=7.0 && !$isMobile || // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7 // @reference: http://my.opera.com/community/openweb/idopera/ t.version('Opera')>=10 && !$isMobile ){ return 'A'; } if ( t.os('iOS') && t.version('iPad')<4.3 || t.os('iOS') && t.version('iPhone')<3.1 || t.os('iOS') && t.version('iPod')<3.1 || // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770 t.is('Blackberry') && t.version('BlackBerry')>=5 && t.version('BlackBerry')<6 || //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3 ( t.version('Opera Mini')>=5.0 && t.version('Opera Mini')<=6.5 && (t.version('Android')>=2.3 || t.is('iOS')) ) || // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1) t.match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') || // @todo: report this (tested on Nokia N71) t.version('Opera Mobi')>=11 && t.is('SymbianOS') ){ return 'B'; } if ( // Blackberry 4.x - Tested on the Curve 8330 t.version('BlackBerry')<5.0 || // Windows Mobile - Tested on the HTC Leo (WinMo 5.2) t.match('MSIEMobile|Windows CE.*Mobile') || t.version('Windows Mobile')<=5.2 ){ return 'C'; } //All older smartphone platforms and featurephones - Any device that doesn't support media queries //will receive the basic, C grade experience. return 'C'; }; impl.detectOS = function (ua) { return impl.findMatch(impl.mobileDetectRules.oss0, ua) || impl.findMatch(impl.mobileDetectRules.oss, ua); }; impl.getDeviceSmallerSide = function () { return window.screen.width < window.screen.height ? window.screen.width : window.screen.height; }; /** * Constructor for MobileDetect object. *
* Such an object will keep a reference to the given user-agent string and cache most of the detect queries.
*
* Find information how to download and install: * github.com/hgoebl/mobile-detect.js/ *
* * @example
     *     var md = new MobileDetect(window.navigator.userAgent);     *     if (md.mobile()) {     *         location.href = (md.mobileGrade() === 'A') ? '/mobile/' : '/lynx/';     *     }     * 
* * @param {string} userAgent typically taken from window.navigator.userAgent or http_header['User-Agent'] * @param {number} [maxPhoneWidth=600] only for browsers specify a value for the maximum * width of smallest device side (in logical "CSS" pixels) until a device detected as mobile will be handled * as phone. * This is only used in cases where the device cannot be classified as phone or tablet.
* See Declaring Tablet Layouts * for Android.
* If you provide a value < 0, then this "fuzzy" check is disabled. * @constructor * @global */ function MobileDetect(userAgent, maxPhoneWidth) { this.ua = userAgent || ''; this._cache = {}; //600dp is typical 7" tablet minimum width this.maxPhoneWidth = maxPhoneWidth || 600; } MobileDetect.prototype = { constructor: MobileDetect, /** * Returns the detected phone or tablet type or null if it is not a mobile device. *
* For a list of possible return values see {@link MobileDetect#phone} and {@link MobileDetect#tablet}.
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownPhone, UnknownTablet or * UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get UnknownMobile here.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key for the phone family or tablet family, e.g. "Nexus". * @function MobileDetect#mobile */ mobile: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.mobile; }, /** * Returns the detected phone type/family string or null. *
* The returned tablet (family or producer) is one of following keys:
*
iPhone, BlackBerry, HTC, Nexus, Dell, Motorola, Samsung, LG, Sony, Asus, * NokiaLumia, Micromax, Palm, Vertu, Pantech, Fly, Wiko, iMobile, SimValley, * Wolfgang, Alcatel, Nintendo, Amoi, INQ, GenericPhone
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownPhone or UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get null here, while {@link MobileDetect#mobile} * will return UnknownMobile.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key of the phone family or producer, e.g. "iPhone" * @function MobileDetect#phone */ phone: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.phone; }, /** * Returns the detected tablet type/family string or null. *
* The returned tablet (family or producer) is one of following keys:
*
iPad, NexusTablet, SamsungTablet, Kindle, SurfaceTablet, HPTablet, AsusTablet, * BlackBerryTablet, HTCtablet, MotorolaTablet, NookTablet, AcerTablet, * ToshibaTablet, LGTablet, FujitsuTablet, PrestigioTablet, LenovoTablet, * DellTablet, YarvikTablet, MedionTablet, ArnovaTablet, IntensoTablet, IRUTablet, * MegafonTablet, EbodaTablet, AllViewTablet, ArchosTablet, AinolTablet, * NokiaLumiaTablet, SonyTablet, PhilipsTablet, CubeTablet, CobyTablet, MIDTablet, * MSITablet, SMiTTablet, RockChipTablet, FlyTablet, bqTablet, HuaweiTablet, * NecTablet, PantechTablet, BronchoTablet, VersusTablet, ZyncTablet, * PositivoTablet, NabiTablet, KoboTablet, DanewTablet, TexetTablet, * PlaystationTablet, TrekstorTablet, PyleAudioTablet, AdvanTablet, * DanyTechTablet, GalapadTablet, MicromaxTablet, KarbonnTablet, AllFineTablet, * PROSCANTablet, YONESTablet, ChangJiaTablet, GUTablet, PointOfViewTablet, * OvermaxTablet, HCLTablet, DPSTablet, VistureTablet, CrestaTablet, * MediatekTablet, ConcordeTablet, GoCleverTablet, ModecomTablet, VoninoTablet, * ECSTablet, StorexTablet, VodafoneTablet, EssentielBTablet, RossMoorTablet, * iMobileTablet, TolinoTablet, AudioSonicTablet, AMPETablet, SkkTablet, * TecnoTablet, JXDTablet, iJoyTablet, FX2Tablet, XoroTablet, ViewsonicTablet, * OdysTablet, CaptivaTablet, IconbitTablet, TeclastTablet, OndaTablet, * JaytechTablet, BlaupunktTablet, DigmaTablet, EvolioTablet, LavaTablet, * AocTablet, MpmanTablet, CelkonTablet, WolderTablet, MiTablet, NibiruTablet, * NexoTablet, LeaderTablet, UbislateTablet, PocketBookTablet, KocasoTablet, Hudl, * TelstraTablet, GenericTablet
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownTablet or UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get null here, while {@link MobileDetect#mobile} * will return UnknownMobile.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key of the tablet family or producer, e.g. "SamsungTablet" * @function MobileDetect#tablet */ tablet: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.tablet; }, /** * Returns the (first) detected user-agent string or null. *
* The returned user-agent is one of following keys:
*
Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon
*
* In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare * cases where a mobile device pretends to be more than one particular browser. You can get the * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by * providing one of the defined keys as first argument to {@link MobileDetect#is}. * * @returns {String} the key for the detected user-agent or null * @function MobileDetect#userAgent */ userAgent: function () { if (this._cache.userAgent === undefined) { this._cache.userAgent = impl.findMatch(impl.mobileDetectRules.uas, this.ua); } return this._cache.userAgent; }, /** * Returns all detected user-agent strings. *
* The array is empty or contains one or more of following keys:
*
Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon
*
* In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare * cases where a mobile device pretends to be more than one particular browser. You can get the * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by * providing one of the defined keys as first argument to {@link MobileDetect#is}. * * @returns {Array} the array of detected user-agent keys or [] * @function MobileDetect#userAgents */ userAgents: function () { if (this._cache.userAgents === undefined) { this._cache.userAgents = impl.findMatches(impl.mobileDetectRules.uas, this.ua); } return this._cache.userAgents; }, /** * Returns the detected operating system string or null. *
* The operating system is one of following keys:
*
AndroidOS, BlackBerryOS, PalmOS, SymbianOS, WindowsMobileOS, WindowsPhoneOS, * iOS, MeeGoOS, MaemoOS, JavaOS, webOS, badaOS, BREWOS
* * @returns {String} the key for the detected operating system. * @function MobileDetect#os */ os: function () { if (this._cache.os === undefined) { this._cache.os = impl.detectOS(this.ua); } return this._cache.os; }, /** * Get the version (as Number) of the given property in the User-Agent. *
* Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param {String} key a key defining a thing which has a version.
* You can use one of following keys:
*
Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna, * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows * CE, Windows NT, Symbian, webOS
* * @returns {Number} the version as float or NaN if User-Agent doesn't contain this version. * Be careful when comparing this value with '==' operator! * @function MobileDetect#version */ version: function (key) { return impl.getVersion(key, this.ua); }, /** * Get the version (as String) of the given property in the User-Agent. *
* * @param {String} key a key defining a thing which has a version.
* You can use one of following keys:
*
Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna, * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows * CE, Windows NT, Symbian, webOS
* * @returns {String} the "raw" version as String or null if User-Agent doesn't contain this version. * * @function MobileDetect#versionStr */ versionStr: function (key) { return impl.getVersionStr(key, this.ua); }, /** * Global test key against userAgent, os, phone, tablet and some other properties of userAgent string. * * @param {String} key the key (case-insensitive) of a userAgent, an operating system, phone or * tablet family.
* For a complete list of possible values, see {@link MobileDetect#userAgent}, * {@link MobileDetect#os}, {@link MobileDetect#phone}, {@link MobileDetect#tablet}.
* Additionally you have following keys:
*
Bot, MobileBot, DesktopMode, TV, WebKit, Console, Watch
* * @returns {boolean} true when the given key is one of the defined keys of userAgent, os, phone, * tablet or one of the listed additional keys, otherwise false * @function MobileDetect#is */ is: function (key) { return containsIC(this.userAgents(), key) || equalIC(key, this.os()) || equalIC(key, this.phone()) || equalIC(key, this.tablet()) || containsIC(impl.findMatches(impl.mobileDetectRules.utils, this.ua), key); }, /** * Do a quick test against navigator::userAgent. * * @param {String|RegExp} pattern the pattern, either as String or RegExp * (a string will be converted to a case-insensitive RegExp). * @returns {boolean} true when the pattern matches, otherwise false * @function MobileDetect#match */ match: function (pattern) { if (!(pattern instanceof RegExp)) { pattern = new RegExp(pattern, 'i'); } return pattern.test(this.ua); }, /** * Checks whether the mobile device can be considered as phone regarding screen.width. *
* Obviously this method makes sense in browser environments only (not for Node.js)! * @param {number} [maxPhoneWidth] the maximum logical pixels (aka. CSS-pixels) to be considered as phone.
* The argument is optional and if not present or falsy, the value of the constructor is taken. * @returns {boolean|undefined} undefined if screen size wasn't detectable, else true * when screen.width is less or equal to maxPhoneWidth, otherwise false.
* Will always return undefined server-side. */ isPhoneSized: function (maxPhoneWidth) { return MobileDetect.isPhoneSized(maxPhoneWidth || this.maxPhoneWidth); }, /** * Returns the mobile grade ('A', 'B', 'C'). * * @returns {String} one of the mobile grades ('A', 'B', 'C'). * @function MobileDetect#mobileGrade */ mobileGrade: function () { if (this._cache.grade === undefined) { this._cache.grade = impl.mobileGrade(this); } return this._cache.grade; } }; // environment-dependent if (typeof window !== 'undefined' && window.screen) { MobileDetect.isPhoneSized = function (maxPhoneWidth) { return maxPhoneWidth < 0 ? undefined : impl.getDeviceSmallerSide() <= maxPhoneWidth; }; } else { MobileDetect.isPhoneSized = function () {}; } // should not be replaced by a completely new object - just overwrite existing methods MobileDetect._impl = impl; MobileDetect.version = '1.3.3 2016-07-31'; return MobileDetect;}); // end of call of define()} : (define: any, undefined?: any) => void >define : any >undefined : any define(function () { ->define(function () { 'use strict'; var impl = {}; impl.mobileDetectRules = { "phones": { "iPhone": "\\biPhone\\b|\\biPod\\b", "BlackBerry": "BlackBerry|\\bBB10\\b|rim[0-9]+", "HTC": "HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m", "Nexus": "Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6", "Dell": "Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b", "Motorola": "Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\\bMoto E\\b", "Samsung": "Samsung|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F", "LG": "\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323)", "Sony": "SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533", "Asus": "Asus.*Galaxy|PadFone.*Mobile", "NokiaLumia": "Lumia [0-9]{3,4}", "Micromax": "Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b", "Palm": "PalmSource|Palm", "Vertu": "Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature", "Pantech": "PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790", "Fly": "IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250", "Wiko": "KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM", "iMobile": "i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)", "SimValley": "\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b", "Wolfgang": "AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q", "Alcatel": "Alcatel", "Nintendo": "Nintendo 3DS", "Amoi": "Amoi", "INQ": "INQ", "GenericPhone": "Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser" }, "tablets": { "iPad": "iPad|iPad.*Mobile", "NexusTablet": "Android.*Nexus[\\s]+(7|9|10)", "SamsungTablet": "SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561", "Kindle": "Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI)\\b", "SurfaceTablet": "Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)", "HPTablet": "HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10", "AsusTablet": "^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b|\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K017 |ME572C|ME103K|ME170C|ME171C|\\bME70C\\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA", "BlackBerryTablet": "PlayBook|RIM Tablet", "HTCtablet": "HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410", "MotorolaTablet": "xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617", "NookTablet": "Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2", "AcerTablet": "Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b|W3-810|\\bA3-A10\\b|\\bA3-A11\\b|\\bA3-A20", "ToshibaTablet": "Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO", "LGTablet": "\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b", "FujitsuTablet": "Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b", "PrestigioTablet": "PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002", "LenovoTablet": "Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)", "DellTablet": "Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7", "YarvikTablet": "Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b", "MedionTablet": "Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB", "ArnovaTablet": "AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2", "IntensoTablet": "INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004", "IRUTablet": "M702pro", "MegafonTablet": "MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b", "EbodaTablet": "E-Boda (Supreme|Impresspeed|Izzycomm|Essential)", "AllViewTablet": "Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)", "ArchosTablet": "\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b", "AinolTablet": "NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark", "NokiaLumiaTablet": "Lumia 2520", "SonyTablet": "Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP612|SOT31", "PhilipsTablet": "\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b", "CubeTablet": "Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT", "CobyTablet": "MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010", "MIDTablet": "M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10", "MSITablet": "MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b", "SMiTTablet": "Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)", "RockChipTablet": "Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A", "FlyTablet": "IQ310|Fly Vision", "bqTablet": "Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris E10)|Maxwell.*Lite|Maxwell.*Plus", "HuaweiTablet": "MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim", "NecTablet": "\\bN-06D|\\bN-08D", "PantechTablet": "Pantech.*P4100", "BronchoTablet": "Broncho.*(N701|N708|N802|a710)", "VersusTablet": "TOUCHPAD.*[78910]|\\bTOUCHTAB\\b", "ZyncTablet": "z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900", "PositivoTablet": "TB07STA|TB10STA|TB07FTA|TB10FTA", "NabiTablet": "Android.*\\bNabi", "KoboTablet": "Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build", "DanewTablet": "DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b", "TexetTablet": "NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE", "PlaystationTablet": "Playstation.*(Portable|Vita)", "TrekstorTablet": "ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab", "PyleAudioTablet": "\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b", "AdvanTablet": "Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ", "DanyTechTablet": "Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1", "GalapadTablet": "Android.*\\bG1\\b", "MicromaxTablet": "Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b", "KarbonnTablet": "Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b", "AllFineTablet": "Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide", "PROSCANTablet": "\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b", "YONESTablet": "BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026", "ChangJiaTablet": "TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503", "GUTablet": "TX-A1301|TX-M9002|Q702|kf026", "PointOfViewTablet": "TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10", "OvermaxTablet": "OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)", "HCLTablet": "HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync", "DPSTablet": "DPS Dream 9|DPS Dual 7", "VistureTablet": "V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10", "CrestaTablet": "CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989", "MediatekTablet": "\\bMT8125|MT8389|MT8135|MT8377\\b", "ConcordeTablet": "Concorde([ ]+)?Tab|ConCorde ReadMan", "GoCleverTablet": "GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042", "ModecomTablet": "FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003", "VoninoTablet": "\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b", "ECSTablet": "V07OT2|TM105A|S10OT1|TR10CS1", "StorexTablet": "eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab", "VodafoneTablet": "SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497", "EssentielBTablet": "Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2", "RossMoorTablet": "RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711", "iMobileTablet": "i-mobile i-note", "TolinoTablet": "tolino tab [0-9.]+|tolino shine", "AudioSonicTablet": "\\bC-22Q|T7-QC|T-17B|T-17P\\b", "AMPETablet": "Android.* A78 ", "SkkTablet": "Android.* (SKYPAD|PHOENIX|CYCLOPS)", "TecnoTablet": "TECNO P9", "JXDTablet": "Android.* \\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b", "iJoyTablet": "Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)", "FX2Tablet": "FX2 PAD7|FX2 PAD10", "XoroTablet": "KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151", "ViewsonicTablet": "ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a", "OdysTablet": "LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10", "CaptivaTablet": "CAPTIVA PAD", "IconbitTablet": "NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S", "TeclastTablet": "T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G|\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G|\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b|\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b|\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b|\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi", "OndaTablet": "\\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\\b[\\s]+", "JaytechTablet": "TPC-PA762", "BlaupunktTablet": "Endeavour 800NG|Endeavour 1010", "DigmaTablet": "\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b", "EvolioTablet": "ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b", "LavaTablet": "QPAD E704|\\bIvoryS\\b|E-TAB IVORY|\\bE-TAB\\b", "AocTablet": "MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712", "MpmanTablet": "MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\\bMPG7\\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010", "CelkonTablet": "CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b", "WolderTablet": "miTab \\b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\\b", "MiTablet": "\\bMI PAD\\b|\\bHM NOTE 1W\\b", "NibiruTablet": "Nibiru M1|Nibiru Jupiter One", "NexoTablet": "NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI", "LeaderTablet": "TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100", "UbislateTablet": "UbiSlate[\\s]?7C", "PocketBookTablet": "Pocketbook", "KocasoTablet": "\\b(TB-1207)\\b", "Hudl": "Hudl HT7S3|Hudl 2", "TelstraTablet": "T-Hub2", "GenericTablet": "Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002|\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\\bM6pro\\b|CT1020W|arc 10HD|\\bJolla\\b|\\bTP750\\b" }, "oss": { "AndroidOS": "Android", "BlackBerryOS": "blackberry|\\bBB10\\b|rim tablet os", "PalmOS": "PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino", "SymbianOS": "Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b", "WindowsMobileOS": "Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;", "WindowsPhoneOS": "Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;", "iOS": "\\biPhone.*Mobile|\\biPod|\\biPad", "MeeGoOS": "MeeGo", "MaemoOS": "Maemo", "JavaOS": "J2ME\/|\\bMIDP\\b|\\bCLDC\\b", "webOS": "webOS|hpwOS", "badaOS": "\\bBada\\b", "BREWOS": "BREW" }, "uas": { "Vivaldi": "Vivaldi", "Chrome": "\\bCrMo\\b|CriOS|Android.*Chrome\/[.0-9]* (Mobile)?", "Dolfin": "\\bDolfin\\b", "Opera": "Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+|Coast\/[0-9.]+", "Skyfire": "Skyfire", "Edge": "Mobile Safari\/[.0-9]* Edge", "IE": "IEMobile|MSIEMobile", "Firefox": "fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile", "Bolt": "bolt", "TeaShark": "teashark", "Blazer": "Blazer", "Safari": "Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari", "Tizen": "Tizen", "UCBrowser": "UC.*Browser|UCWEB", "baiduboxapp": "baiduboxapp", "baidubrowser": "baidubrowser", "DiigoBrowser": "DiigoBrowser", "Puffin": "Puffin", "Mercury": "\\bMercury\\b", "ObigoBrowser": "Obigo", "NetFront": "NF-Browser", "GenericBrowser": "NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger", "PaleMoon": "Android.*PaleMoon|Mobile.*PaleMoon" }, "props": { "Mobile": "Mobile\/[VER]", "Build": "Build\/[VER]", "Version": "Version\/[VER]", "VendorID": "VendorID\/[VER]", "iPad": "iPad.*CPU[a-z ]+[VER]", "iPhone": "iPhone.*CPU[a-z ]+[VER]", "iPod": "iPod.*CPU[a-z ]+[VER]", "Kindle": "Kindle\/[VER]", "Chrome": [ "Chrome\/[VER]", "CriOS\/[VER]", "CrMo\/[VER]" ], "Coast": [ "Coast\/[VER]" ], "Dolfin": "Dolfin\/[VER]", "Firefox": "Firefox\/[VER]", "Fennec": "Fennec\/[VER]", "Edge": "Edge\/[VER]", "IE": [ "IEMobile\/[VER];", "IEMobile [VER]", "MSIE [VER];", "Trident\/[0-9.]+;.*rv:[VER]" ], "NetFront": "NetFront\/[VER]", "NokiaBrowser": "NokiaBrowser\/[VER]", "Opera": [ " OPR\/[VER]", "Opera Mini\/[VER]", "Version\/[VER]" ], "Opera Mini": "Opera Mini\/[VER]", "Opera Mobi": "Version\/[VER]", "UC Browser": "UC Browser[VER]", "MQQBrowser": "MQQBrowser\/[VER]", "MicroMessenger": "MicroMessenger\/[VER]", "baiduboxapp": "baiduboxapp\/[VER]", "baidubrowser": "baidubrowser\/[VER]", "Iron": "Iron\/[VER]", "Safari": [ "Version\/[VER]", "Safari\/[VER]" ], "Skyfire": "Skyfire\/[VER]", "Tizen": "Tizen\/[VER]", "Webkit": "webkit[ \/][VER]", "PaleMoon": "PaleMoon\/[VER]", "Gecko": "Gecko\/[VER]", "Trident": "Trident\/[VER]", "Presto": "Presto\/[VER]", "Goanna": "Goanna\/[VER]", "iOS": " \\bi?OS\\b [VER][ ;]{1}", "Android": "Android [VER]", "BlackBerry": [ "BlackBerry[\\w]+\/[VER]", "BlackBerry.*Version\/[VER]", "Version\/[VER]" ], "BREW": "BREW [VER]", "Java": "Java\/[VER]", "Windows Phone OS": [ "Windows Phone OS [VER]", "Windows Phone [VER]" ], "Windows Phone": "Windows Phone [VER]", "Windows CE": "Windows CE\/[VER]", "Windows NT": "Windows NT [VER]", "Symbian": [ "SymbianOS\/[VER]", "Symbian\/[VER]" ], "webOS": [ "webOS\/[VER]", "hpwOS\/[VER];" ] }, "utils": { "Bot": "Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom", "MobileBot": "Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker\/M1A1-R2D2", "DesktopMode": "WPDesktop", "TV": "SonyDTV|HbbTV", "WebKit": "(webkit)[ \/]([\\w.]+)", "Console": "\\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\\b", "Watch": "SM-V700" }}; // following patterns come from http://detectmobilebrowsers.com/ impl.detectMobileBrowsers = { fullPattern: /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i, shortPattern: /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i, tabletPattern: /android|ipad|playbook|silk/i }; var hasOwnProp = Object.prototype.hasOwnProperty, isArray; impl.FALLBACK_PHONE = 'UnknownPhone'; impl.FALLBACK_TABLET = 'UnknownTablet'; impl.FALLBACK_MOBILE = 'UnknownMobile'; isArray = ('isArray' in Array) ? Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }; function equalIC(a, b) { return a != null && b != null && a.toLowerCase() === b.toLowerCase(); } function containsIC(array, value) { var valueLC, i, len = array.length; if (!len || !value) { return false; } valueLC = value.toLowerCase(); for (i = 0; i < len; ++i) { if (valueLC === array[i].toLowerCase()) { return true; } } return false; } function convertPropsToRegExp(object) { for (var key in object) { if (hasOwnProp.call(object, key)) { object[key] = new RegExp(object[key], 'i'); } } } (function init() { var key, values, value, i, len, verPos, mobileDetectRules = impl.mobileDetectRules; for (key in mobileDetectRules.props) { if (hasOwnProp.call(mobileDetectRules.props, key)) { values = mobileDetectRules.props[key]; if (!isArray(values)) { values = [values]; } len = values.length; for (i = 0; i < len; ++i) { value = values[i]; verPos = value.indexOf('[VER]'); if (verPos >= 0) { value = value.substring(0, verPos) + '([\\w._\\+]+)' + value.substring(verPos + 5); } values[i] = new RegExp(value, 'i'); } mobileDetectRules.props[key] = values; } } convertPropsToRegExp(mobileDetectRules.oss); convertPropsToRegExp(mobileDetectRules.phones); convertPropsToRegExp(mobileDetectRules.tablets); convertPropsToRegExp(mobileDetectRules.uas); convertPropsToRegExp(mobileDetectRules.utils); // copy some patterns to oss0 which are tested first (see issue#15) mobileDetectRules.oss0 = { WindowsPhoneOS: mobileDetectRules.oss.WindowsPhoneOS, WindowsMobileOS: mobileDetectRules.oss.WindowsMobileOS }; }()); /** * Test userAgent string against a set of rules and find the first matched key. * @param {Object} rules (key is String, value is RegExp) * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). * @returns {String|null} the matched key if found, otherwise null * @private */ impl.findMatch = function(rules, userAgent) { for (var key in rules) { if (hasOwnProp.call(rules, key)) { if (rules[key].test(userAgent)) { return key; } } } return null; }; /** * Test userAgent string against a set of rules and return an array of matched keys. * @param {Object} rules (key is String, value is RegExp) * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). * @returns {Array} an array of matched keys, may be empty when there is no match, but not null * @private */ impl.findMatches = function(rules, userAgent) { var result = []; for (var key in rules) { if (hasOwnProp.call(rules, key)) { if (rules[key].test(userAgent)) { result.push(key); } } } return result; }; /** * Check the version of the given property in the User-Agent. * * @param {String} propertyName * @param {String} userAgent * @return {String} version or null if version not found * @private */ impl.getVersionStr = function (propertyName, userAgent) { var props = impl.mobileDetectRules.props, patterns, i, len, match; if (hasOwnProp.call(props, propertyName)) { patterns = props[propertyName]; len = patterns.length; for (i = 0; i < len; ++i) { match = patterns[i].exec(userAgent); if (match !== null) { return match[1]; } } } return null; }; /** * Check the version of the given property in the User-Agent. * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param {String} propertyName * @param {String} userAgent * @return {Number} version or NaN if version not found * @private */ impl.getVersion = function (propertyName, userAgent) { var version = impl.getVersionStr(propertyName, userAgent); return version ? impl.prepareVersionNo(version) : NaN; }; /** * Prepare the version number. * * @param {String} version * @return {Number} the version number as a floating number * @private */ impl.prepareVersionNo = function (version) { var numbers; numbers = version.split(/[a-z._ \/\-]/i); if (numbers.length === 1) { version = numbers[0]; } if (numbers.length > 1) { version = numbers[0] + '.'; numbers.shift(); version += numbers.join(''); } return Number(version); }; impl.isMobileFallback = function (userAgent) { return impl.detectMobileBrowsers.fullPattern.test(userAgent) || impl.detectMobileBrowsers.shortPattern.test(userAgent.substr(0,4)); }; impl.isTabletFallback = function (userAgent) { return impl.detectMobileBrowsers.tabletPattern.test(userAgent); }; impl.prepareDetectionCache = function (cache, userAgent, maxPhoneWidth) { if (cache.mobile !== undefined) { return; } var phone, tablet, phoneSized; // first check for stronger tablet rules, then phone (see issue#5) tablet = impl.findMatch(impl.mobileDetectRules.tablets, userAgent); if (tablet) { cache.mobile = cache.tablet = tablet; cache.phone = null; return; // unambiguously identified as tablet } phone = impl.findMatch(impl.mobileDetectRules.phones, userAgent); if (phone) { cache.mobile = cache.phone = phone; cache.tablet = null; return; // unambiguously identified as phone } // our rules haven't found a match -> try more general fallback rules if (impl.isMobileFallback(userAgent)) { phoneSized = MobileDetect.isPhoneSized(maxPhoneWidth); if (phoneSized === undefined) { cache.mobile = impl.FALLBACK_MOBILE; cache.tablet = cache.phone = null; } else if (phoneSized) { cache.mobile = cache.phone = impl.FALLBACK_PHONE; cache.tablet = null; } else { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; cache.phone = null; } } else if (impl.isTabletFallback(userAgent)) { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; cache.phone = null; } else { // not mobile at all! cache.mobile = cache.tablet = cache.phone = null; } }; // t is a reference to a MobileDetect instance impl.mobileGrade = function (t) { // impl note: // To keep in sync w/ Mobile_Detect.php easily, the following code is tightly aligned to the PHP version. // When changes are made in Mobile_Detect.php, copy this method and replace: // $this-> / t. // self::MOBILE_GRADE_(.) / '$1' // , self::VERSION_TYPE_FLOAT / (nothing) // isIOS() / os('iOS') // [reg] / (nothing) <-- jsdelivr complaining about unescaped unicode character U+00AE var $isMobile = t.mobile() !== null; if ( // Apple iOS 3.2-5.1 - Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3), iPad 3 (5.1), original iPhone (3.1), iPhone 3 (3.2), 3GS (4.3), 4 (4.3 / 5.0), and 4S (5.1) t.os('iOS') && t.version('iPad')>=4.3 || t.os('iOS') && t.version('iPhone')>=3.1 || t.os('iOS') && t.version('iPod')>=3.1 || // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5) // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7 ( t.version('Android')>2.1 && t.is('Webkit') ) || // Windows Phone 7-7.5 - Tested on the HTC Surround (7.0) HTC Trophy (7.5), LG-E900 (7.5), Nokia Lumia 800 t.version('Windows Phone OS')>=7.0 || // Blackberry 7 - Tested on BlackBerry Torch 9810 // Blackberry 6.0 - Tested on the Torch 9800 and Style 9670 t.is('BlackBerry') && t.version('BlackBerry')>=6.0 || // Blackberry Playbook (1.0-2.0) - Tested on PlayBook t.match('Playbook.*Tablet') || // Palm WebOS (1.4-2.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0) ( t.version('webOS')>=1.4 && t.match('Palm|Pre|Pixi') ) || // Palm WebOS 3.0 - Tested on HP TouchPad t.match('hp.*TouchPad') || // Firefox Mobile (12 Beta) - Tested on Android 2.3 device ( t.is('Firefox') && t.version('Firefox')>=12 ) || // Chrome for Android - Tested on Android 4.0, 4.1 device ( t.is('Chrome') && t.is('AndroidOS') && t.version('Android')>=4.0 ) || // Skyfire 4.1 - Tested on Android 2.3 device ( t.is('Skyfire') && t.version('Skyfire')>=4.1 && t.is('AndroidOS') && t.version('Android')>=2.3 ) || // Opera Mobile 11.5-12: Tested on Android 2.3 ( t.is('Opera') && t.version('Opera Mobi')>11 && t.is('AndroidOS') ) || // Meego 1.2 - Tested on Nokia 950 and N9 t.is('MeeGoOS') || // Tizen (pre-release) - Tested on early hardware t.is('Tizen') || // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser // @todo: more tests here! t.is('Dolfin') && t.version('Bada')>=2.0 || // UC Browser - Tested on Android 2.3 device ( (t.is('UC Browser') || t.is('Dolfin')) && t.version('Android')>=2.3 ) || // Kindle 3 and Fire - Tested on the built-in WebKit browser for each ( t.match('Kindle Fire') || t.is('Kindle') && t.version('Kindle')>=3.0 ) || // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet t.is('AndroidOS') && t.is('NookTablet') || // Chrome Desktop 11-21 - Tested on OS X 10.7 and Windows 7 t.version('Chrome')>=11 && !$isMobile || // Safari Desktop 4-5 - Tested on OS X 10.7 and Windows 7 t.version('Safari')>=5.0 && !$isMobile || // Firefox Desktop 4-13 - Tested on OS X 10.7 and Windows 7 t.version('Firefox')>=4.0 && !$isMobile || // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7 t.version('MSIE')>=7.0 && !$isMobile || // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7 // @reference: http://my.opera.com/community/openweb/idopera/ t.version('Opera')>=10 && !$isMobile ){ return 'A'; } if ( t.os('iOS') && t.version('iPad')<4.3 || t.os('iOS') && t.version('iPhone')<3.1 || t.os('iOS') && t.version('iPod')<3.1 || // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770 t.is('Blackberry') && t.version('BlackBerry')>=5 && t.version('BlackBerry')<6 || //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3 ( t.version('Opera Mini')>=5.0 && t.version('Opera Mini')<=6.5 && (t.version('Android')>=2.3 || t.is('iOS')) ) || // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1) t.match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') || // @todo: report this (tested on Nokia N71) t.version('Opera Mobi')>=11 && t.is('SymbianOS') ){ return 'B'; } if ( // Blackberry 4.x - Tested on the Curve 8330 t.version('BlackBerry')<5.0 || // Windows Mobile - Tested on the HTC Leo (WinMo 5.2) t.match('MSIEMobile|Windows CE.*Mobile') || t.version('Windows Mobile')<=5.2 ){ return 'C'; } //All older smartphone platforms and featurephones - Any device that doesn't support media queries //will receive the basic, C grade experience. return 'C'; }; impl.detectOS = function (ua) { return impl.findMatch(impl.mobileDetectRules.oss0, ua) || impl.findMatch(impl.mobileDetectRules.oss, ua); }; impl.getDeviceSmallerSide = function () { return window.screen.width < window.screen.height ? window.screen.width : window.screen.height; }; /** * Constructor for MobileDetect object. *
* Such an object will keep a reference to the given user-agent string and cache most of the detect queries.
*
* Find information how to download and install: * github.com/hgoebl/mobile-detect.js/ *
* * @example
     *     var md = new MobileDetect(window.navigator.userAgent);     *     if (md.mobile()) {     *         location.href = (md.mobileGrade() === 'A') ? '/mobile/' : '/lynx/';     *     }     * 
* * @param {string} userAgent typically taken from window.navigator.userAgent or http_header['User-Agent'] * @param {number} [maxPhoneWidth=600] only for browsers specify a value for the maximum * width of smallest device side (in logical "CSS" pixels) until a device detected as mobile will be handled * as phone. * This is only used in cases where the device cannot be classified as phone or tablet.
* See Declaring Tablet Layouts * for Android.
* If you provide a value < 0, then this "fuzzy" check is disabled. * @constructor * @global */ function MobileDetect(userAgent, maxPhoneWidth) { this.ua = userAgent || ''; this._cache = {}; //600dp is typical 7" tablet minimum width this.maxPhoneWidth = maxPhoneWidth || 600; } MobileDetect.prototype = { constructor: MobileDetect, /** * Returns the detected phone or tablet type or null if it is not a mobile device. *
* For a list of possible return values see {@link MobileDetect#phone} and {@link MobileDetect#tablet}.
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownPhone, UnknownTablet or * UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get UnknownMobile here.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key for the phone family or tablet family, e.g. "Nexus". * @function MobileDetect#mobile */ mobile: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.mobile; }, /** * Returns the detected phone type/family string or null. *
* The returned tablet (family or producer) is one of following keys:
*
iPhone, BlackBerry, HTC, Nexus, Dell, Motorola, Samsung, LG, Sony, Asus, * NokiaLumia, Micromax, Palm, Vertu, Pantech, Fly, Wiko, iMobile, SimValley, * Wolfgang, Alcatel, Nintendo, Amoi, INQ, GenericPhone
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownPhone or UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get null here, while {@link MobileDetect#mobile} * will return UnknownMobile.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key of the phone family or producer, e.g. "iPhone" * @function MobileDetect#phone */ phone: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.phone; }, /** * Returns the detected tablet type/family string or null. *
* The returned tablet (family or producer) is one of following keys:
*
iPad, NexusTablet, SamsungTablet, Kindle, SurfaceTablet, HPTablet, AsusTablet, * BlackBerryTablet, HTCtablet, MotorolaTablet, NookTablet, AcerTablet, * ToshibaTablet, LGTablet, FujitsuTablet, PrestigioTablet, LenovoTablet, * DellTablet, YarvikTablet, MedionTablet, ArnovaTablet, IntensoTablet, IRUTablet, * MegafonTablet, EbodaTablet, AllViewTablet, ArchosTablet, AinolTablet, * NokiaLumiaTablet, SonyTablet, PhilipsTablet, CubeTablet, CobyTablet, MIDTablet, * MSITablet, SMiTTablet, RockChipTablet, FlyTablet, bqTablet, HuaweiTablet, * NecTablet, PantechTablet, BronchoTablet, VersusTablet, ZyncTablet, * PositivoTablet, NabiTablet, KoboTablet, DanewTablet, TexetTablet, * PlaystationTablet, TrekstorTablet, PyleAudioTablet, AdvanTablet, * DanyTechTablet, GalapadTablet, MicromaxTablet, KarbonnTablet, AllFineTablet, * PROSCANTablet, YONESTablet, ChangJiaTablet, GUTablet, PointOfViewTablet, * OvermaxTablet, HCLTablet, DPSTablet, VistureTablet, CrestaTablet, * MediatekTablet, ConcordeTablet, GoCleverTablet, ModecomTablet, VoninoTablet, * ECSTablet, StorexTablet, VodafoneTablet, EssentielBTablet, RossMoorTablet, * iMobileTablet, TolinoTablet, AudioSonicTablet, AMPETablet, SkkTablet, * TecnoTablet, JXDTablet, iJoyTablet, FX2Tablet, XoroTablet, ViewsonicTablet, * OdysTablet, CaptivaTablet, IconbitTablet, TeclastTablet, OndaTablet, * JaytechTablet, BlaupunktTablet, DigmaTablet, EvolioTablet, LavaTablet, * AocTablet, MpmanTablet, CelkonTablet, WolderTablet, MiTablet, NibiruTablet, * NexoTablet, LeaderTablet, UbislateTablet, PocketBookTablet, KocasoTablet, Hudl, * TelstraTablet, GenericTablet
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownTablet or UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get null here, while {@link MobileDetect#mobile} * will return UnknownMobile.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key of the tablet family or producer, e.g. "SamsungTablet" * @function MobileDetect#tablet */ tablet: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.tablet; }, /** * Returns the (first) detected user-agent string or null. *
* The returned user-agent is one of following keys:
*
Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon
*
* In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare * cases where a mobile device pretends to be more than one particular browser. You can get the * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by * providing one of the defined keys as first argument to {@link MobileDetect#is}. * * @returns {String} the key for the detected user-agent or null * @function MobileDetect#userAgent */ userAgent: function () { if (this._cache.userAgent === undefined) { this._cache.userAgent = impl.findMatch(impl.mobileDetectRules.uas, this.ua); } return this._cache.userAgent; }, /** * Returns all detected user-agent strings. *
* The array is empty or contains one or more of following keys:
*
Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon
*
* In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare * cases where a mobile device pretends to be more than one particular browser. You can get the * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by * providing one of the defined keys as first argument to {@link MobileDetect#is}. * * @returns {Array} the array of detected user-agent keys or [] * @function MobileDetect#userAgents */ userAgents: function () { if (this._cache.userAgents === undefined) { this._cache.userAgents = impl.findMatches(impl.mobileDetectRules.uas, this.ua); } return this._cache.userAgents; }, /** * Returns the detected operating system string or null. *
* The operating system is one of following keys:
*
AndroidOS, BlackBerryOS, PalmOS, SymbianOS, WindowsMobileOS, WindowsPhoneOS, * iOS, MeeGoOS, MaemoOS, JavaOS, webOS, badaOS, BREWOS
* * @returns {String} the key for the detected operating system. * @function MobileDetect#os */ os: function () { if (this._cache.os === undefined) { this._cache.os = impl.detectOS(this.ua); } return this._cache.os; }, /** * Get the version (as Number) of the given property in the User-Agent. *
* Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param {String} key a key defining a thing which has a version.
* You can use one of following keys:
*
Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna, * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows * CE, Windows NT, Symbian, webOS
* * @returns {Number} the version as float or NaN if User-Agent doesn't contain this version. * Be careful when comparing this value with '==' operator! * @function MobileDetect#version */ version: function (key) { return impl.getVersion(key, this.ua); }, /** * Get the version (as String) of the given property in the User-Agent. *
* * @param {String} key a key defining a thing which has a version.
* You can use one of following keys:
*
Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna, * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows * CE, Windows NT, Symbian, webOS
* * @returns {String} the "raw" version as String or null if User-Agent doesn't contain this version. * * @function MobileDetect#versionStr */ versionStr: function (key) { return impl.getVersionStr(key, this.ua); }, /** * Global test key against userAgent, os, phone, tablet and some other properties of userAgent string. * * @param {String} key the key (case-insensitive) of a userAgent, an operating system, phone or * tablet family.
* For a complete list of possible values, see {@link MobileDetect#userAgent}, * {@link MobileDetect#os}, {@link MobileDetect#phone}, {@link MobileDetect#tablet}.
* Additionally you have following keys:
*
Bot, MobileBot, DesktopMode, TV, WebKit, Console, Watch
* * @returns {boolean} true when the given key is one of the defined keys of userAgent, os, phone, * tablet or one of the listed additional keys, otherwise false * @function MobileDetect#is */ is: function (key) { return containsIC(this.userAgents(), key) || equalIC(key, this.os()) || equalIC(key, this.phone()) || equalIC(key, this.tablet()) || containsIC(impl.findMatches(impl.mobileDetectRules.utils, this.ua), key); }, /** * Do a quick test against navigator::userAgent. * * @param {String|RegExp} pattern the pattern, either as String or RegExp * (a string will be converted to a case-insensitive RegExp). * @returns {boolean} true when the pattern matches, otherwise false * @function MobileDetect#match */ match: function (pattern) { if (!(pattern instanceof RegExp)) { pattern = new RegExp(pattern, 'i'); } return pattern.test(this.ua); }, /** * Checks whether the mobile device can be considered as phone regarding screen.width. *
* Obviously this method makes sense in browser environments only (not for Node.js)! * @param {number} [maxPhoneWidth] the maximum logical pixels (aka. CSS-pixels) to be considered as phone.
* The argument is optional and if not present or falsy, the value of the constructor is taken. * @returns {boolean|undefined} undefined if screen size wasn't detectable, else true * when screen.width is less or equal to maxPhoneWidth, otherwise false.
* Will always return undefined server-side. */ isPhoneSized: function (maxPhoneWidth) { return MobileDetect.isPhoneSized(maxPhoneWidth || this.maxPhoneWidth); }, /** * Returns the mobile grade ('A', 'B', 'C'). * * @returns {String} one of the mobile grades ('A', 'B', 'C'). * @function MobileDetect#mobileGrade */ mobileGrade: function () { if (this._cache.grade === undefined) { this._cache.grade = impl.mobileGrade(this); } return this._cache.grade; } }; // environment-dependent if (typeof window !== 'undefined' && window.screen) { MobileDetect.isPhoneSized = function (maxPhoneWidth) { return maxPhoneWidth < 0 ? undefined : impl.getDeviceSmallerSide() <= maxPhoneWidth; }; } else { MobileDetect.isPhoneSized = function () {}; } // should not be replaced by a completely new object - just overwrite existing methods MobileDetect._impl = impl; MobileDetect.version = '1.3.3 2016-07-31'; return MobileDetect;}) : any +>define(function () { 'use strict'; var impl = {}; impl.mobileDetectRules = { "phones": { "iPhone": "\\biPhone\\b|\\biPod\\b", "BlackBerry": "BlackBerry|\\bBB10\\b|rim[0-9]+", "HTC": "HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m", "Nexus": "Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6", "Dell": "Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b", "Motorola": "Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\\bMoto E\\b", "Samsung": "Samsung|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F", "LG": "\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323)", "Sony": "SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533", "Asus": "Asus.*Galaxy|PadFone.*Mobile", "NokiaLumia": "Lumia [0-9]{3,4}", "Micromax": "Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b", "Palm": "PalmSource|Palm", "Vertu": "Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature", "Pantech": "PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790", "Fly": "IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250", "Wiko": "KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM", "iMobile": "i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)", "SimValley": "\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b", "Wolfgang": "AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q", "Alcatel": "Alcatel", "Nintendo": "Nintendo 3DS", "Amoi": "Amoi", "INQ": "INQ", "GenericPhone": "Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser" }, "tablets": { "iPad": "iPad|iPad.*Mobile", "NexusTablet": "Android.*Nexus[\\s]+(7|9|10)", "SamsungTablet": "SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561", "Kindle": "Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI)\\b", "SurfaceTablet": "Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)", "HPTablet": "HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10", "AsusTablet": "^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b|\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K017 |ME572C|ME103K|ME170C|ME171C|\\bME70C\\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA", "BlackBerryTablet": "PlayBook|RIM Tablet", "HTCtablet": "HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410", "MotorolaTablet": "xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617", "NookTablet": "Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2", "AcerTablet": "Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b|W3-810|\\bA3-A10\\b|\\bA3-A11\\b|\\bA3-A20", "ToshibaTablet": "Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO", "LGTablet": "\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b", "FujitsuTablet": "Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b", "PrestigioTablet": "PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002", "LenovoTablet": "Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)", "DellTablet": "Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7", "YarvikTablet": "Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b", "MedionTablet": "Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB", "ArnovaTablet": "AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2", "IntensoTablet": "INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004", "IRUTablet": "M702pro", "MegafonTablet": "MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b", "EbodaTablet": "E-Boda (Supreme|Impresspeed|Izzycomm|Essential)", "AllViewTablet": "Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)", "ArchosTablet": "\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b", "AinolTablet": "NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark", "NokiaLumiaTablet": "Lumia 2520", "SonyTablet": "Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP612|SOT31", "PhilipsTablet": "\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b", "CubeTablet": "Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT", "CobyTablet": "MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010", "MIDTablet": "M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10", "MSITablet": "MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b", "SMiTTablet": "Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)", "RockChipTablet": "Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A", "FlyTablet": "IQ310|Fly Vision", "bqTablet": "Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris E10)|Maxwell.*Lite|Maxwell.*Plus", "HuaweiTablet": "MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim", "NecTablet": "\\bN-06D|\\bN-08D", "PantechTablet": "Pantech.*P4100", "BronchoTablet": "Broncho.*(N701|N708|N802|a710)", "VersusTablet": "TOUCHPAD.*[78910]|\\bTOUCHTAB\\b", "ZyncTablet": "z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900", "PositivoTablet": "TB07STA|TB10STA|TB07FTA|TB10FTA", "NabiTablet": "Android.*\\bNabi", "KoboTablet": "Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build", "DanewTablet": "DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b", "TexetTablet": "NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE", "PlaystationTablet": "Playstation.*(Portable|Vita)", "TrekstorTablet": "ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab", "PyleAudioTablet": "\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b", "AdvanTablet": "Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ", "DanyTechTablet": "Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1", "GalapadTablet": "Android.*\\bG1\\b", "MicromaxTablet": "Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b", "KarbonnTablet": "Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b", "AllFineTablet": "Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide", "PROSCANTablet": "\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b", "YONESTablet": "BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026", "ChangJiaTablet": "TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503", "GUTablet": "TX-A1301|TX-M9002|Q702|kf026", "PointOfViewTablet": "TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10", "OvermaxTablet": "OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)", "HCLTablet": "HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync", "DPSTablet": "DPS Dream 9|DPS Dual 7", "VistureTablet": "V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10", "CrestaTablet": "CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989", "MediatekTablet": "\\bMT8125|MT8389|MT8135|MT8377\\b", "ConcordeTablet": "Concorde([ ]+)?Tab|ConCorde ReadMan", "GoCleverTablet": "GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042", "ModecomTablet": "FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003", "VoninoTablet": "\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b", "ECSTablet": "V07OT2|TM105A|S10OT1|TR10CS1", "StorexTablet": "eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab", "VodafoneTablet": "SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497", "EssentielBTablet": "Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2", "RossMoorTablet": "RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711", "iMobileTablet": "i-mobile i-note", "TolinoTablet": "tolino tab [0-9.]+|tolino shine", "AudioSonicTablet": "\\bC-22Q|T7-QC|T-17B|T-17P\\b", "AMPETablet": "Android.* A78 ", "SkkTablet": "Android.* (SKYPAD|PHOENIX|CYCLOPS)", "TecnoTablet": "TECNO P9", "JXDTablet": "Android.* \\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b", "iJoyTablet": "Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)", "FX2Tablet": "FX2 PAD7|FX2 PAD10", "XoroTablet": "KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151", "ViewsonicTablet": "ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a", "OdysTablet": "LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10", "CaptivaTablet": "CAPTIVA PAD", "IconbitTablet": "NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S", "TeclastTablet": "T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G|\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G|\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b|\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b|\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b|\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi", "OndaTablet": "\\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\\b[\\s]+", "JaytechTablet": "TPC-PA762", "BlaupunktTablet": "Endeavour 800NG|Endeavour 1010", "DigmaTablet": "\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b", "EvolioTablet": "ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b", "LavaTablet": "QPAD E704|\\bIvoryS\\b|E-TAB IVORY|\\bE-TAB\\b", "AocTablet": "MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712", "MpmanTablet": "MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\\bMPG7\\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010", "CelkonTablet": "CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b", "WolderTablet": "miTab \\b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\\b", "MiTablet": "\\bMI PAD\\b|\\bHM NOTE 1W\\b", "NibiruTablet": "Nibiru M1|Nibiru Jupiter One", "NexoTablet": "NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI", "LeaderTablet": "TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100", "UbislateTablet": "UbiSlate[\\s]?7C", "PocketBookTablet": "Pocketbook", "KocasoTablet": "\\b(TB-1207)\\b", "Hudl": "Hudl HT7S3|Hudl 2", "TelstraTablet": "T-Hub2", "GenericTablet": "Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002|\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\\bM6pro\\b|CT1020W|arc 10HD|\\bJolla\\b|\\bTP750\\b" }, "oss": { "AndroidOS": "Android", "BlackBerryOS": "blackberry|\\bBB10\\b|rim tablet os", "PalmOS": "PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino", "SymbianOS": "Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b", "WindowsMobileOS": "Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;", "WindowsPhoneOS": "Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;", "iOS": "\\biPhone.*Mobile|\\biPod|\\biPad", "MeeGoOS": "MeeGo", "MaemoOS": "Maemo", "JavaOS": "J2ME\/|\\bMIDP\\b|\\bCLDC\\b", "webOS": "webOS|hpwOS", "badaOS": "\\bBada\\b", "BREWOS": "BREW" }, "uas": { "Vivaldi": "Vivaldi", "Chrome": "\\bCrMo\\b|CriOS|Android.*Chrome\/[.0-9]* (Mobile)?", "Dolfin": "\\bDolfin\\b", "Opera": "Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+|Coast\/[0-9.]+", "Skyfire": "Skyfire", "Edge": "Mobile Safari\/[.0-9]* Edge", "IE": "IEMobile|MSIEMobile", "Firefox": "fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile", "Bolt": "bolt", "TeaShark": "teashark", "Blazer": "Blazer", "Safari": "Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari", "Tizen": "Tizen", "UCBrowser": "UC.*Browser|UCWEB", "baiduboxapp": "baiduboxapp", "baidubrowser": "baidubrowser", "DiigoBrowser": "DiigoBrowser", "Puffin": "Puffin", "Mercury": "\\bMercury\\b", "ObigoBrowser": "Obigo", "NetFront": "NF-Browser", "GenericBrowser": "NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger", "PaleMoon": "Android.*PaleMoon|Mobile.*PaleMoon" }, "props": { "Mobile": "Mobile\/[VER]", "Build": "Build\/[VER]", "Version": "Version\/[VER]", "VendorID": "VendorID\/[VER]", "iPad": "iPad.*CPU[a-z ]+[VER]", "iPhone": "iPhone.*CPU[a-z ]+[VER]", "iPod": "iPod.*CPU[a-z ]+[VER]", "Kindle": "Kindle\/[VER]", "Chrome": [ "Chrome\/[VER]", "CriOS\/[VER]", "CrMo\/[VER]" ], "Coast": [ "Coast\/[VER]" ], "Dolfin": "Dolfin\/[VER]", "Firefox": "Firefox\/[VER]", "Fennec": "Fennec\/[VER]", "Edge": "Edge\/[VER]", "IE": [ "IEMobile\/[VER];", "IEMobile [VER]", "MSIE [VER];", "Trident\/[0-9.]+;.*rv:[VER]" ], "NetFront": "NetFront\/[VER]", "NokiaBrowser": "NokiaBrowser\/[VER]", "Opera": [ " OPR\/[VER]", "Opera Mini\/[VER]", "Version\/[VER]" ], "Opera Mini": "Opera Mini\/[VER]", "Opera Mobi": "Version\/[VER]", "UC Browser": "UC Browser[VER]", "MQQBrowser": "MQQBrowser\/[VER]", "MicroMessenger": "MicroMessenger\/[VER]", "baiduboxapp": "baiduboxapp\/[VER]", "baidubrowser": "baidubrowser\/[VER]", "Iron": "Iron\/[VER]", "Safari": [ "Version\/[VER]", "Safari\/[VER]" ], "Skyfire": "Skyfire\/[VER]", "Tizen": "Tizen\/[VER]", "Webkit": "webkit[ \/][VER]", "PaleMoon": "PaleMoon\/[VER]", "Gecko": "Gecko\/[VER]", "Trident": "Trident\/[VER]", "Presto": "Presto\/[VER]", "Goanna": "Goanna\/[VER]", "iOS": " \\bi?OS\\b [VER][ ;]{1}", "Android": "Android [VER]", "BlackBerry": [ "BlackBerry[\\w]+\/[VER]", "BlackBerry.*Version\/[VER]", "Version\/[VER]" ], "BREW": "BREW [VER]", "Java": "Java\/[VER]", "Windows Phone OS": [ "Windows Phone OS [VER]", "Windows Phone [VER]" ], "Windows Phone": "Windows Phone [VER]", "Windows CE": "Windows CE\/[VER]", "Windows NT": "Windows NT [VER]", "Symbian": [ "SymbianOS\/[VER]", "Symbian\/[VER]" ], "webOS": [ "webOS\/[VER]", "hpwOS\/[VER];" ] }, "utils": { "Bot": "Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom", "MobileBot": "Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker\/M1A1-R2D2", "DesktopMode": "WPDesktop", "TV": "SonyDTV|HbbTV", "WebKit": "(webkit)[ \/]([\\w.]+)", "Console": "\\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\\b", "Watch": "SM-V700" }}; // following patterns come from http://detectmobilebrowsers.com/ impl.detectMobileBrowsers = { fullPattern: /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i, shortPattern: /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i, tabletPattern: /android|ipad|playbook|silk/i }; var hasOwnProp = Object.prototype.hasOwnProperty, isArray; impl.FALLBACK_PHONE = 'UnknownPhone'; impl.FALLBACK_TABLET = 'UnknownTablet'; impl.FALLBACK_MOBILE = 'UnknownMobile'; isArray = ('isArray' in Array) ? Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }; isArray = 'isArray' in Array ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : Array.isArray; function equalIC(a, b) { return a != null && b != null && a.toLowerCase() === b.toLowerCase(); } function containsIC(array, value) { var valueLC, i, len = array.length; if (!len || !value) { return false; } valueLC = value.toLowerCase(); for (i = 0; i < len; ++i) { if (valueLC === array[i].toLowerCase()) { return true; } } return false; } function convertPropsToRegExp(object) { for (var key in object) { if (hasOwnProp.call(object, key)) { object[key] = new RegExp(object[key], 'i'); } } } (function init() { var key, values, value, i, len, verPos, mobileDetectRules = impl.mobileDetectRules; for (key in mobileDetectRules.props) { if (hasOwnProp.call(mobileDetectRules.props, key)) { values = mobileDetectRules.props[key]; if (!isArray(values)) { values = [values]; } len = values.length; for (i = 0; i < len; ++i) { value = values[i]; verPos = value.indexOf('[VER]'); if (verPos >= 0) { value = value.substring(0, verPos) + '([\\w._\\+]+)' + value.substring(verPos + 5); } values[i] = new RegExp(value, 'i'); } mobileDetectRules.props[key] = values; } } convertPropsToRegExp(mobileDetectRules.oss); convertPropsToRegExp(mobileDetectRules.phones); convertPropsToRegExp(mobileDetectRules.tablets); convertPropsToRegExp(mobileDetectRules.uas); convertPropsToRegExp(mobileDetectRules.utils); // copy some patterns to oss0 which are tested first (see issue#15) mobileDetectRules.oss0 = { WindowsPhoneOS: mobileDetectRules.oss.WindowsPhoneOS, WindowsMobileOS: mobileDetectRules.oss.WindowsMobileOS }; }()); /** * Test userAgent string against a set of rules and find the first matched key. * @param {Object} rules (key is String, value is RegExp) * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). * @returns {String|null} the matched key if found, otherwise null * @private */ impl.findMatch = function(rules, userAgent) { for (var key in rules) { if (hasOwnProp.call(rules, key)) { if (rules[key].test(userAgent)) { return key; } } } return null; }; /** * Test userAgent string against a set of rules and return an array of matched keys. * @param {Object} rules (key is String, value is RegExp) * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). * @returns {Array} an array of matched keys, may be empty when there is no match, but not null * @private */ impl.findMatches = function(rules, userAgent) { var result = []; for (var key in rules) { if (hasOwnProp.call(rules, key)) { if (rules[key].test(userAgent)) { result.push(key); } } } return result; }; /** * Check the version of the given property in the User-Agent. * * @param {String} propertyName * @param {String} userAgent * @return {String} version or null if version not found * @private */ impl.getVersionStr = function (propertyName, userAgent) { var props = impl.mobileDetectRules.props, patterns, i, len, match; if (hasOwnProp.call(props, propertyName)) { patterns = props[propertyName]; len = patterns.length; for (i = 0; i < len; ++i) { match = patterns[i].exec(userAgent); if (match !== null) { return match[1]; } } } return null; }; /** * Check the version of the given property in the User-Agent. * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param {String} propertyName * @param {String} userAgent * @return {Number} version or NaN if version not found * @private */ impl.getVersion = function (propertyName, userAgent) { var version = impl.getVersionStr(propertyName, userAgent); return version ? impl.prepareVersionNo(version) : NaN; }; /** * Prepare the version number. * * @param {String} version * @return {Number} the version number as a floating number * @private */ impl.prepareVersionNo = function (version) { var numbers; numbers = version.split(/[a-z._ \/\-]/i); if (numbers.length === 1) { version = numbers[0]; } if (numbers.length > 1) { version = numbers[0] + '.'; numbers.shift(); version += numbers.join(''); } return Number(version); }; impl.isMobileFallback = function (userAgent) { return impl.detectMobileBrowsers.fullPattern.test(userAgent) || impl.detectMobileBrowsers.shortPattern.test(userAgent.substr(0,4)); }; impl.isTabletFallback = function (userAgent) { return impl.detectMobileBrowsers.tabletPattern.test(userAgent); }; impl.prepareDetectionCache = function (cache, userAgent, maxPhoneWidth) { if (cache.mobile !== undefined) { return; } var phone, tablet, phoneSized; // first check for stronger tablet rules, then phone (see issue#5) tablet = impl.findMatch(impl.mobileDetectRules.tablets, userAgent); if (tablet) { cache.mobile = cache.tablet = tablet; cache.phone = null; return; // unambiguously identified as tablet } phone = impl.findMatch(impl.mobileDetectRules.phones, userAgent); if (phone) { cache.mobile = cache.phone = phone; cache.tablet = null; return; // unambiguously identified as phone } // our rules haven't found a match -> try more general fallback rules if (impl.isMobileFallback(userAgent)) { phoneSized = MobileDetect.isPhoneSized(maxPhoneWidth); if (phoneSized === undefined) { cache.mobile = impl.FALLBACK_MOBILE; cache.tablet = cache.phone = null; } else if (phoneSized) { cache.mobile = cache.phone = impl.FALLBACK_PHONE; cache.tablet = null; } else { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; cache.phone = null; } } else if (impl.isTabletFallback(userAgent)) { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; cache.phone = null; } else { // not mobile at all! cache.mobile = cache.tablet = cache.phone = null; } }; // t is a reference to a MobileDetect instance impl.mobileGrade = function (t) { // impl note: // To keep in sync w/ Mobile_Detect.php easily, the following code is tightly aligned to the PHP version. // When changes are made in Mobile_Detect.php, copy this method and replace: // $this-> / t. // self::MOBILE_GRADE_(.) / '$1' // , self::VERSION_TYPE_FLOAT / (nothing) // isIOS() / os('iOS') // [reg] / (nothing) <-- jsdelivr complaining about unescaped unicode character U+00AE var $isMobile = t.mobile() !== null; if ( // Apple iOS 3.2-5.1 - Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3), iPad 3 (5.1), original iPhone (3.1), iPhone 3 (3.2), 3GS (4.3), 4 (4.3 / 5.0), and 4S (5.1) t.os('iOS') && t.version('iPad')>=4.3 || t.os('iOS') && t.version('iPhone')>=3.1 || t.os('iOS') && t.version('iPod')>=3.1 || // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5) // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7 ( t.version('Android')>2.1 && t.is('Webkit') ) || // Windows Phone 7-7.5 - Tested on the HTC Surround (7.0) HTC Trophy (7.5), LG-E900 (7.5), Nokia Lumia 800 t.version('Windows Phone OS')>=7.0 || // Blackberry 7 - Tested on BlackBerry Torch 9810 // Blackberry 6.0 - Tested on the Torch 9800 and Style 9670 t.is('BlackBerry') && t.version('BlackBerry')>=6.0 || // Blackberry Playbook (1.0-2.0) - Tested on PlayBook t.match('Playbook.*Tablet') || // Palm WebOS (1.4-2.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0) ( t.version('webOS')>=1.4 && t.match('Palm|Pre|Pixi') ) || // Palm WebOS 3.0 - Tested on HP TouchPad t.match('hp.*TouchPad') || // Firefox Mobile (12 Beta) - Tested on Android 2.3 device ( t.is('Firefox') && t.version('Firefox')>=12 ) || // Chrome for Android - Tested on Android 4.0, 4.1 device ( t.is('Chrome') && t.is('AndroidOS') && t.version('Android')>=4.0 ) || // Skyfire 4.1 - Tested on Android 2.3 device ( t.is('Skyfire') && t.version('Skyfire')>=4.1 && t.is('AndroidOS') && t.version('Android')>=2.3 ) || // Opera Mobile 11.5-12: Tested on Android 2.3 ( t.is('Opera') && t.version('Opera Mobi')>11 && t.is('AndroidOS') ) || // Meego 1.2 - Tested on Nokia 950 and N9 t.is('MeeGoOS') || // Tizen (pre-release) - Tested on early hardware t.is('Tizen') || // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser // @todo: more tests here! t.is('Dolfin') && t.version('Bada')>=2.0 || // UC Browser - Tested on Android 2.3 device ( (t.is('UC Browser') || t.is('Dolfin')) && t.version('Android')>=2.3 ) || // Kindle 3 and Fire - Tested on the built-in WebKit browser for each ( t.match('Kindle Fire') || t.is('Kindle') && t.version('Kindle')>=3.0 ) || // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet t.is('AndroidOS') && t.is('NookTablet') || // Chrome Desktop 11-21 - Tested on OS X 10.7 and Windows 7 t.version('Chrome')>=11 && !$isMobile || // Safari Desktop 4-5 - Tested on OS X 10.7 and Windows 7 t.version('Safari')>=5.0 && !$isMobile || // Firefox Desktop 4-13 - Tested on OS X 10.7 and Windows 7 t.version('Firefox')>=4.0 && !$isMobile || // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7 t.version('MSIE')>=7.0 && !$isMobile || // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7 // @reference: http://my.opera.com/community/openweb/idopera/ t.version('Opera')>=10 && !$isMobile ){ return 'A'; } if ( t.os('iOS') && t.version('iPad')<4.3 || t.os('iOS') && t.version('iPhone')<3.1 || t.os('iOS') && t.version('iPod')<3.1 || // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770 t.is('Blackberry') && t.version('BlackBerry')>=5 && t.version('BlackBerry')<6 || //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3 ( t.version('Opera Mini')>=5.0 && t.version('Opera Mini')<=6.5 && (t.version('Android')>=2.3 || t.is('iOS')) ) || // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1) t.match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') || // @todo: report this (tested on Nokia N71) t.version('Opera Mobi')>=11 && t.is('SymbianOS') ){ return 'B'; } if ( // Blackberry 4.x - Tested on the Curve 8330 t.version('BlackBerry')<5.0 || // Windows Mobile - Tested on the HTC Leo (WinMo 5.2) t.match('MSIEMobile|Windows CE.*Mobile') || t.version('Windows Mobile')<=5.2 ){ return 'C'; } //All older smartphone platforms and featurephones - Any device that doesn't support media queries //will receive the basic, C grade experience. return 'C'; }; impl.detectOS = function (ua) { return impl.findMatch(impl.mobileDetectRules.oss0, ua) || impl.findMatch(impl.mobileDetectRules.oss, ua); }; impl.getDeviceSmallerSide = function () { return window.screen.width < window.screen.height ? window.screen.width : window.screen.height; }; /** * Constructor for MobileDetect object. *
* Such an object will keep a reference to the given user-agent string and cache most of the detect queries.
*
* Find information how to download and install: * github.com/hgoebl/mobile-detect.js/ *
* * @example
     *     var md = new MobileDetect(window.navigator.userAgent);     *     if (md.mobile()) {     *         location.href = (md.mobileGrade() === 'A') ? '/mobile/' : '/lynx/';     *     }     * 
* * @param {string} userAgent typically taken from window.navigator.userAgent or http_header['User-Agent'] * @param {number} [maxPhoneWidth=600] only for browsers specify a value for the maximum * width of smallest device side (in logical "CSS" pixels) until a device detected as mobile will be handled * as phone. * This is only used in cases where the device cannot be classified as phone or tablet.
* See Declaring Tablet Layouts * for Android.
* If you provide a value < 0, then this "fuzzy" check is disabled. * @constructor * @global */ function MobileDetect(userAgent, maxPhoneWidth) { this.ua = userAgent || ''; this._cache = {}; //600dp is typical 7" tablet minimum width this.maxPhoneWidth = maxPhoneWidth || 600; } MobileDetect.prototype = { constructor: MobileDetect, /** * Returns the detected phone or tablet type or null if it is not a mobile device. *
* For a list of possible return values see {@link MobileDetect#phone} and {@link MobileDetect#tablet}.
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownPhone, UnknownTablet or * UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get UnknownMobile here.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key for the phone family or tablet family, e.g. "Nexus". * @function MobileDetect#mobile */ mobile: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.mobile; }, /** * Returns the detected phone type/family string or null. *
* The returned tablet (family or producer) is one of following keys:
*
iPhone, BlackBerry, HTC, Nexus, Dell, Motorola, Samsung, LG, Sony, Asus, * NokiaLumia, Micromax, Palm, Vertu, Pantech, Fly, Wiko, iMobile, SimValley, * Wolfgang, Alcatel, Nintendo, Amoi, INQ, GenericPhone
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownPhone or UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get null here, while {@link MobileDetect#mobile} * will return UnknownMobile.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key of the phone family or producer, e.g. "iPhone" * @function MobileDetect#phone */ phone: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.phone; }, /** * Returns the detected tablet type/family string or null. *
* The returned tablet (family or producer) is one of following keys:
*
iPad, NexusTablet, SamsungTablet, Kindle, SurfaceTablet, HPTablet, AsusTablet, * BlackBerryTablet, HTCtablet, MotorolaTablet, NookTablet, AcerTablet, * ToshibaTablet, LGTablet, FujitsuTablet, PrestigioTablet, LenovoTablet, * DellTablet, YarvikTablet, MedionTablet, ArnovaTablet, IntensoTablet, IRUTablet, * MegafonTablet, EbodaTablet, AllViewTablet, ArchosTablet, AinolTablet, * NokiaLumiaTablet, SonyTablet, PhilipsTablet, CubeTablet, CobyTablet, MIDTablet, * MSITablet, SMiTTablet, RockChipTablet, FlyTablet, bqTablet, HuaweiTablet, * NecTablet, PantechTablet, BronchoTablet, VersusTablet, ZyncTablet, * PositivoTablet, NabiTablet, KoboTablet, DanewTablet, TexetTablet, * PlaystationTablet, TrekstorTablet, PyleAudioTablet, AdvanTablet, * DanyTechTablet, GalapadTablet, MicromaxTablet, KarbonnTablet, AllFineTablet, * PROSCANTablet, YONESTablet, ChangJiaTablet, GUTablet, PointOfViewTablet, * OvermaxTablet, HCLTablet, DPSTablet, VistureTablet, CrestaTablet, * MediatekTablet, ConcordeTablet, GoCleverTablet, ModecomTablet, VoninoTablet, * ECSTablet, StorexTablet, VodafoneTablet, EssentielBTablet, RossMoorTablet, * iMobileTablet, TolinoTablet, AudioSonicTablet, AMPETablet, SkkTablet, * TecnoTablet, JXDTablet, iJoyTablet, FX2Tablet, XoroTablet, ViewsonicTablet, * OdysTablet, CaptivaTablet, IconbitTablet, TeclastTablet, OndaTablet, * JaytechTablet, BlaupunktTablet, DigmaTablet, EvolioTablet, LavaTablet, * AocTablet, MpmanTablet, CelkonTablet, WolderTablet, MiTablet, NibiruTablet, * NexoTablet, LeaderTablet, UbislateTablet, PocketBookTablet, KocasoTablet, Hudl, * TelstraTablet, GenericTablet
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownTablet or UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get null here, while {@link MobileDetect#mobile} * will return UnknownMobile.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key of the tablet family or producer, e.g. "SamsungTablet" * @function MobileDetect#tablet */ tablet: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.tablet; }, /** * Returns the (first) detected user-agent string or null. *
* The returned user-agent is one of following keys:
*
Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon
*
* In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare * cases where a mobile device pretends to be more than one particular browser. You can get the * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by * providing one of the defined keys as first argument to {@link MobileDetect#is}. * * @returns {String} the key for the detected user-agent or null * @function MobileDetect#userAgent */ userAgent: function () { if (this._cache.userAgent === undefined) { this._cache.userAgent = impl.findMatch(impl.mobileDetectRules.uas, this.ua); } return this._cache.userAgent; }, /** * Returns all detected user-agent strings. *
* The array is empty or contains one or more of following keys:
*
Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon
*
* In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare * cases where a mobile device pretends to be more than one particular browser. You can get the * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by * providing one of the defined keys as first argument to {@link MobileDetect#is}. * * @returns {Array} the array of detected user-agent keys or [] * @function MobileDetect#userAgents */ userAgents: function () { if (this._cache.userAgents === undefined) { this._cache.userAgents = impl.findMatches(impl.mobileDetectRules.uas, this.ua); } return this._cache.userAgents; }, /** * Returns the detected operating system string or null. *
* The operating system is one of following keys:
*
AndroidOS, BlackBerryOS, PalmOS, SymbianOS, WindowsMobileOS, WindowsPhoneOS, * iOS, MeeGoOS, MaemoOS, JavaOS, webOS, badaOS, BREWOS
* * @returns {String} the key for the detected operating system. * @function MobileDetect#os */ os: function () { if (this._cache.os === undefined) { this._cache.os = impl.detectOS(this.ua); } return this._cache.os; }, /** * Get the version (as Number) of the given property in the User-Agent. *
* Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param {String} key a key defining a thing which has a version.
* You can use one of following keys:
*
Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna, * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows * CE, Windows NT, Symbian, webOS
* * @returns {Number} the version as float or NaN if User-Agent doesn't contain this version. * Be careful when comparing this value with '==' operator! * @function MobileDetect#version */ version: function (key) { return impl.getVersion(key, this.ua); }, /** * Get the version (as String) of the given property in the User-Agent. *
* * @param {String} key a key defining a thing which has a version.
* You can use one of following keys:
*
Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna, * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows * CE, Windows NT, Symbian, webOS
* * @returns {String} the "raw" version as String or null if User-Agent doesn't contain this version. * * @function MobileDetect#versionStr */ versionStr: function (key) { return impl.getVersionStr(key, this.ua); }, /** * Global test key against userAgent, os, phone, tablet and some other properties of userAgent string. * * @param {String} key the key (case-insensitive) of a userAgent, an operating system, phone or * tablet family.
* For a complete list of possible values, see {@link MobileDetect#userAgent}, * {@link MobileDetect#os}, {@link MobileDetect#phone}, {@link MobileDetect#tablet}.
* Additionally you have following keys:
*
Bot, MobileBot, DesktopMode, TV, WebKit, Console, Watch
* * @returns {boolean} true when the given key is one of the defined keys of userAgent, os, phone, * tablet or one of the listed additional keys, otherwise false * @function MobileDetect#is */ is: function (key) { return containsIC(this.userAgents(), key) || equalIC(key, this.os()) || equalIC(key, this.phone()) || equalIC(key, this.tablet()) || containsIC(impl.findMatches(impl.mobileDetectRules.utils, this.ua), key); }, /** * Do a quick test against navigator::userAgent. * * @param {String|RegExp} pattern the pattern, either as String or RegExp * (a string will be converted to a case-insensitive RegExp). * @returns {boolean} true when the pattern matches, otherwise false * @function MobileDetect#match */ match: function (pattern) { if (!(pattern instanceof RegExp)) { pattern = new RegExp(pattern, 'i'); } return pattern.test(this.ua); }, /** * Checks whether the mobile device can be considered as phone regarding screen.width. *
* Obviously this method makes sense in browser environments only (not for Node.js)! * @param {number} [maxPhoneWidth] the maximum logical pixels (aka. CSS-pixels) to be considered as phone.
* The argument is optional and if not present or falsy, the value of the constructor is taken. * @returns {boolean|undefined} undefined if screen size wasn't detectable, else true * when screen.width is less or equal to maxPhoneWidth, otherwise false.
* Will always return undefined server-side. */ isPhoneSized: function (maxPhoneWidth) { return MobileDetect.isPhoneSized(maxPhoneWidth || this.maxPhoneWidth); }, /** * Returns the mobile grade ('A', 'B', 'C'). * * @returns {String} one of the mobile grades ('A', 'B', 'C'). * @function MobileDetect#mobileGrade */ mobileGrade: function () { if (this._cache.grade === undefined) { this._cache.grade = impl.mobileGrade(this); } return this._cache.grade; } }; // environment-dependent if (typeof window !== 'undefined' && window.screen) { MobileDetect.isPhoneSized = function (maxPhoneWidth) { return maxPhoneWidth < 0 ? undefined : impl.getDeviceSmallerSide() <= maxPhoneWidth; }; } else { MobileDetect.isPhoneSized = function () {}; } // should not be replaced by a completely new object - just overwrite existing methods MobileDetect._impl = impl; MobileDetect.version = '1.3.3 2016-07-31'; return MobileDetect;}) : any >define : any ->function () { 'use strict'; var impl = {}; impl.mobileDetectRules = { "phones": { "iPhone": "\\biPhone\\b|\\biPod\\b", "BlackBerry": "BlackBerry|\\bBB10\\b|rim[0-9]+", "HTC": "HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m", "Nexus": "Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6", "Dell": "Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b", "Motorola": "Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\\bMoto E\\b", "Samsung": "Samsung|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F", "LG": "\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323)", "Sony": "SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533", "Asus": "Asus.*Galaxy|PadFone.*Mobile", "NokiaLumia": "Lumia [0-9]{3,4}", "Micromax": "Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b", "Palm": "PalmSource|Palm", "Vertu": "Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature", "Pantech": "PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790", "Fly": "IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250", "Wiko": "KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM", "iMobile": "i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)", "SimValley": "\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b", "Wolfgang": "AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q", "Alcatel": "Alcatel", "Nintendo": "Nintendo 3DS", "Amoi": "Amoi", "INQ": "INQ", "GenericPhone": "Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser" }, "tablets": { "iPad": "iPad|iPad.*Mobile", "NexusTablet": "Android.*Nexus[\\s]+(7|9|10)", "SamsungTablet": "SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561", "Kindle": "Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI)\\b", "SurfaceTablet": "Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)", "HPTablet": "HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10", "AsusTablet": "^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b|\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K017 |ME572C|ME103K|ME170C|ME171C|\\bME70C\\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA", "BlackBerryTablet": "PlayBook|RIM Tablet", "HTCtablet": "HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410", "MotorolaTablet": "xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617", "NookTablet": "Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2", "AcerTablet": "Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b|W3-810|\\bA3-A10\\b|\\bA3-A11\\b|\\bA3-A20", "ToshibaTablet": "Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO", "LGTablet": "\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b", "FujitsuTablet": "Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b", "PrestigioTablet": "PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002", "LenovoTablet": "Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)", "DellTablet": "Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7", "YarvikTablet": "Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b", "MedionTablet": "Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB", "ArnovaTablet": "AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2", "IntensoTablet": "INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004", "IRUTablet": "M702pro", "MegafonTablet": "MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b", "EbodaTablet": "E-Boda (Supreme|Impresspeed|Izzycomm|Essential)", "AllViewTablet": "Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)", "ArchosTablet": "\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b", "AinolTablet": "NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark", "NokiaLumiaTablet": "Lumia 2520", "SonyTablet": "Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP612|SOT31", "PhilipsTablet": "\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b", "CubeTablet": "Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT", "CobyTablet": "MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010", "MIDTablet": "M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10", "MSITablet": "MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b", "SMiTTablet": "Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)", "RockChipTablet": "Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A", "FlyTablet": "IQ310|Fly Vision", "bqTablet": "Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris E10)|Maxwell.*Lite|Maxwell.*Plus", "HuaweiTablet": "MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim", "NecTablet": "\\bN-06D|\\bN-08D", "PantechTablet": "Pantech.*P4100", "BronchoTablet": "Broncho.*(N701|N708|N802|a710)", "VersusTablet": "TOUCHPAD.*[78910]|\\bTOUCHTAB\\b", "ZyncTablet": "z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900", "PositivoTablet": "TB07STA|TB10STA|TB07FTA|TB10FTA", "NabiTablet": "Android.*\\bNabi", "KoboTablet": "Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build", "DanewTablet": "DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b", "TexetTablet": "NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE", "PlaystationTablet": "Playstation.*(Portable|Vita)", "TrekstorTablet": "ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab", "PyleAudioTablet": "\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b", "AdvanTablet": "Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ", "DanyTechTablet": "Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1", "GalapadTablet": "Android.*\\bG1\\b", "MicromaxTablet": "Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b", "KarbonnTablet": "Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b", "AllFineTablet": "Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide", "PROSCANTablet": "\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b", "YONESTablet": "BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026", "ChangJiaTablet": "TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503", "GUTablet": "TX-A1301|TX-M9002|Q702|kf026", "PointOfViewTablet": "TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10", "OvermaxTablet": "OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)", "HCLTablet": "HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync", "DPSTablet": "DPS Dream 9|DPS Dual 7", "VistureTablet": "V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10", "CrestaTablet": "CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989", "MediatekTablet": "\\bMT8125|MT8389|MT8135|MT8377\\b", "ConcordeTablet": "Concorde([ ]+)?Tab|ConCorde ReadMan", "GoCleverTablet": "GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042", "ModecomTablet": "FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003", "VoninoTablet": "\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b", "ECSTablet": "V07OT2|TM105A|S10OT1|TR10CS1", "StorexTablet": "eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab", "VodafoneTablet": "SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497", "EssentielBTablet": "Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2", "RossMoorTablet": "RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711", "iMobileTablet": "i-mobile i-note", "TolinoTablet": "tolino tab [0-9.]+|tolino shine", "AudioSonicTablet": "\\bC-22Q|T7-QC|T-17B|T-17P\\b", "AMPETablet": "Android.* A78 ", "SkkTablet": "Android.* (SKYPAD|PHOENIX|CYCLOPS)", "TecnoTablet": "TECNO P9", "JXDTablet": "Android.* \\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b", "iJoyTablet": "Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)", "FX2Tablet": "FX2 PAD7|FX2 PAD10", "XoroTablet": "KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151", "ViewsonicTablet": "ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a", "OdysTablet": "LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10", "CaptivaTablet": "CAPTIVA PAD", "IconbitTablet": "NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S", "TeclastTablet": "T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G|\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G|\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b|\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b|\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b|\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi", "OndaTablet": "\\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\\b[\\s]+", "JaytechTablet": "TPC-PA762", "BlaupunktTablet": "Endeavour 800NG|Endeavour 1010", "DigmaTablet": "\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b", "EvolioTablet": "ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b", "LavaTablet": "QPAD E704|\\bIvoryS\\b|E-TAB IVORY|\\bE-TAB\\b", "AocTablet": "MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712", "MpmanTablet": "MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\\bMPG7\\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010", "CelkonTablet": "CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b", "WolderTablet": "miTab \\b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\\b", "MiTablet": "\\bMI PAD\\b|\\bHM NOTE 1W\\b", "NibiruTablet": "Nibiru M1|Nibiru Jupiter One", "NexoTablet": "NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI", "LeaderTablet": "TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100", "UbislateTablet": "UbiSlate[\\s]?7C", "PocketBookTablet": "Pocketbook", "KocasoTablet": "\\b(TB-1207)\\b", "Hudl": "Hudl HT7S3|Hudl 2", "TelstraTablet": "T-Hub2", "GenericTablet": "Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002|\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\\bM6pro\\b|CT1020W|arc 10HD|\\bJolla\\b|\\bTP750\\b" }, "oss": { "AndroidOS": "Android", "BlackBerryOS": "blackberry|\\bBB10\\b|rim tablet os", "PalmOS": "PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino", "SymbianOS": "Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b", "WindowsMobileOS": "Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;", "WindowsPhoneOS": "Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;", "iOS": "\\biPhone.*Mobile|\\biPod|\\biPad", "MeeGoOS": "MeeGo", "MaemoOS": "Maemo", "JavaOS": "J2ME\/|\\bMIDP\\b|\\bCLDC\\b", "webOS": "webOS|hpwOS", "badaOS": "\\bBada\\b", "BREWOS": "BREW" }, "uas": { "Vivaldi": "Vivaldi", "Chrome": "\\bCrMo\\b|CriOS|Android.*Chrome\/[.0-9]* (Mobile)?", "Dolfin": "\\bDolfin\\b", "Opera": "Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+|Coast\/[0-9.]+", "Skyfire": "Skyfire", "Edge": "Mobile Safari\/[.0-9]* Edge", "IE": "IEMobile|MSIEMobile", "Firefox": "fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile", "Bolt": "bolt", "TeaShark": "teashark", "Blazer": "Blazer", "Safari": "Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari", "Tizen": "Tizen", "UCBrowser": "UC.*Browser|UCWEB", "baiduboxapp": "baiduboxapp", "baidubrowser": "baidubrowser", "DiigoBrowser": "DiigoBrowser", "Puffin": "Puffin", "Mercury": "\\bMercury\\b", "ObigoBrowser": "Obigo", "NetFront": "NF-Browser", "GenericBrowser": "NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger", "PaleMoon": "Android.*PaleMoon|Mobile.*PaleMoon" }, "props": { "Mobile": "Mobile\/[VER]", "Build": "Build\/[VER]", "Version": "Version\/[VER]", "VendorID": "VendorID\/[VER]", "iPad": "iPad.*CPU[a-z ]+[VER]", "iPhone": "iPhone.*CPU[a-z ]+[VER]", "iPod": "iPod.*CPU[a-z ]+[VER]", "Kindle": "Kindle\/[VER]", "Chrome": [ "Chrome\/[VER]", "CriOS\/[VER]", "CrMo\/[VER]" ], "Coast": [ "Coast\/[VER]" ], "Dolfin": "Dolfin\/[VER]", "Firefox": "Firefox\/[VER]", "Fennec": "Fennec\/[VER]", "Edge": "Edge\/[VER]", "IE": [ "IEMobile\/[VER];", "IEMobile [VER]", "MSIE [VER];", "Trident\/[0-9.]+;.*rv:[VER]" ], "NetFront": "NetFront\/[VER]", "NokiaBrowser": "NokiaBrowser\/[VER]", "Opera": [ " OPR\/[VER]", "Opera Mini\/[VER]", "Version\/[VER]" ], "Opera Mini": "Opera Mini\/[VER]", "Opera Mobi": "Version\/[VER]", "UC Browser": "UC Browser[VER]", "MQQBrowser": "MQQBrowser\/[VER]", "MicroMessenger": "MicroMessenger\/[VER]", "baiduboxapp": "baiduboxapp\/[VER]", "baidubrowser": "baidubrowser\/[VER]", "Iron": "Iron\/[VER]", "Safari": [ "Version\/[VER]", "Safari\/[VER]" ], "Skyfire": "Skyfire\/[VER]", "Tizen": "Tizen\/[VER]", "Webkit": "webkit[ \/][VER]", "PaleMoon": "PaleMoon\/[VER]", "Gecko": "Gecko\/[VER]", "Trident": "Trident\/[VER]", "Presto": "Presto\/[VER]", "Goanna": "Goanna\/[VER]", "iOS": " \\bi?OS\\b [VER][ ;]{1}", "Android": "Android [VER]", "BlackBerry": [ "BlackBerry[\\w]+\/[VER]", "BlackBerry.*Version\/[VER]", "Version\/[VER]" ], "BREW": "BREW [VER]", "Java": "Java\/[VER]", "Windows Phone OS": [ "Windows Phone OS [VER]", "Windows Phone [VER]" ], "Windows Phone": "Windows Phone [VER]", "Windows CE": "Windows CE\/[VER]", "Windows NT": "Windows NT [VER]", "Symbian": [ "SymbianOS\/[VER]", "Symbian\/[VER]" ], "webOS": [ "webOS\/[VER]", "hpwOS\/[VER];" ] }, "utils": { "Bot": "Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom", "MobileBot": "Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker\/M1A1-R2D2", "DesktopMode": "WPDesktop", "TV": "SonyDTV|HbbTV", "WebKit": "(webkit)[ \/]([\\w.]+)", "Console": "\\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\\b", "Watch": "SM-V700" }}; // following patterns come from http://detectmobilebrowsers.com/ impl.detectMobileBrowsers = { fullPattern: /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i, shortPattern: /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i, tabletPattern: /android|ipad|playbook|silk/i }; var hasOwnProp = Object.prototype.hasOwnProperty, isArray; impl.FALLBACK_PHONE = 'UnknownPhone'; impl.FALLBACK_TABLET = 'UnknownTablet'; impl.FALLBACK_MOBILE = 'UnknownMobile'; isArray = ('isArray' in Array) ? Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }; function equalIC(a, b) { return a != null && b != null && a.toLowerCase() === b.toLowerCase(); } function containsIC(array, value) { var valueLC, i, len = array.length; if (!len || !value) { return false; } valueLC = value.toLowerCase(); for (i = 0; i < len; ++i) { if (valueLC === array[i].toLowerCase()) { return true; } } return false; } function convertPropsToRegExp(object) { for (var key in object) { if (hasOwnProp.call(object, key)) { object[key] = new RegExp(object[key], 'i'); } } } (function init() { var key, values, value, i, len, verPos, mobileDetectRules = impl.mobileDetectRules; for (key in mobileDetectRules.props) { if (hasOwnProp.call(mobileDetectRules.props, key)) { values = mobileDetectRules.props[key]; if (!isArray(values)) { values = [values]; } len = values.length; for (i = 0; i < len; ++i) { value = values[i]; verPos = value.indexOf('[VER]'); if (verPos >= 0) { value = value.substring(0, verPos) + '([\\w._\\+]+)' + value.substring(verPos + 5); } values[i] = new RegExp(value, 'i'); } mobileDetectRules.props[key] = values; } } convertPropsToRegExp(mobileDetectRules.oss); convertPropsToRegExp(mobileDetectRules.phones); convertPropsToRegExp(mobileDetectRules.tablets); convertPropsToRegExp(mobileDetectRules.uas); convertPropsToRegExp(mobileDetectRules.utils); // copy some patterns to oss0 which are tested first (see issue#15) mobileDetectRules.oss0 = { WindowsPhoneOS: mobileDetectRules.oss.WindowsPhoneOS, WindowsMobileOS: mobileDetectRules.oss.WindowsMobileOS }; }()); /** * Test userAgent string against a set of rules and find the first matched key. * @param {Object} rules (key is String, value is RegExp) * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). * @returns {String|null} the matched key if found, otherwise null * @private */ impl.findMatch = function(rules, userAgent) { for (var key in rules) { if (hasOwnProp.call(rules, key)) { if (rules[key].test(userAgent)) { return key; } } } return null; }; /** * Test userAgent string against a set of rules and return an array of matched keys. * @param {Object} rules (key is String, value is RegExp) * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). * @returns {Array} an array of matched keys, may be empty when there is no match, but not null * @private */ impl.findMatches = function(rules, userAgent) { var result = []; for (var key in rules) { if (hasOwnProp.call(rules, key)) { if (rules[key].test(userAgent)) { result.push(key); } } } return result; }; /** * Check the version of the given property in the User-Agent. * * @param {String} propertyName * @param {String} userAgent * @return {String} version or null if version not found * @private */ impl.getVersionStr = function (propertyName, userAgent) { var props = impl.mobileDetectRules.props, patterns, i, len, match; if (hasOwnProp.call(props, propertyName)) { patterns = props[propertyName]; len = patterns.length; for (i = 0; i < len; ++i) { match = patterns[i].exec(userAgent); if (match !== null) { return match[1]; } } } return null; }; /** * Check the version of the given property in the User-Agent. * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param {String} propertyName * @param {String} userAgent * @return {Number} version or NaN if version not found * @private */ impl.getVersion = function (propertyName, userAgent) { var version = impl.getVersionStr(propertyName, userAgent); return version ? impl.prepareVersionNo(version) : NaN; }; /** * Prepare the version number. * * @param {String} version * @return {Number} the version number as a floating number * @private */ impl.prepareVersionNo = function (version) { var numbers; numbers = version.split(/[a-z._ \/\-]/i); if (numbers.length === 1) { version = numbers[0]; } if (numbers.length > 1) { version = numbers[0] + '.'; numbers.shift(); version += numbers.join(''); } return Number(version); }; impl.isMobileFallback = function (userAgent) { return impl.detectMobileBrowsers.fullPattern.test(userAgent) || impl.detectMobileBrowsers.shortPattern.test(userAgent.substr(0,4)); }; impl.isTabletFallback = function (userAgent) { return impl.detectMobileBrowsers.tabletPattern.test(userAgent); }; impl.prepareDetectionCache = function (cache, userAgent, maxPhoneWidth) { if (cache.mobile !== undefined) { return; } var phone, tablet, phoneSized; // first check for stronger tablet rules, then phone (see issue#5) tablet = impl.findMatch(impl.mobileDetectRules.tablets, userAgent); if (tablet) { cache.mobile = cache.tablet = tablet; cache.phone = null; return; // unambiguously identified as tablet } phone = impl.findMatch(impl.mobileDetectRules.phones, userAgent); if (phone) { cache.mobile = cache.phone = phone; cache.tablet = null; return; // unambiguously identified as phone } // our rules haven't found a match -> try more general fallback rules if (impl.isMobileFallback(userAgent)) { phoneSized = MobileDetect.isPhoneSized(maxPhoneWidth); if (phoneSized === undefined) { cache.mobile = impl.FALLBACK_MOBILE; cache.tablet = cache.phone = null; } else if (phoneSized) { cache.mobile = cache.phone = impl.FALLBACK_PHONE; cache.tablet = null; } else { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; cache.phone = null; } } else if (impl.isTabletFallback(userAgent)) { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; cache.phone = null; } else { // not mobile at all! cache.mobile = cache.tablet = cache.phone = null; } }; // t is a reference to a MobileDetect instance impl.mobileGrade = function (t) { // impl note: // To keep in sync w/ Mobile_Detect.php easily, the following code is tightly aligned to the PHP version. // When changes are made in Mobile_Detect.php, copy this method and replace: // $this-> / t. // self::MOBILE_GRADE_(.) / '$1' // , self::VERSION_TYPE_FLOAT / (nothing) // isIOS() / os('iOS') // [reg] / (nothing) <-- jsdelivr complaining about unescaped unicode character U+00AE var $isMobile = t.mobile() !== null; if ( // Apple iOS 3.2-5.1 - Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3), iPad 3 (5.1), original iPhone (3.1), iPhone 3 (3.2), 3GS (4.3), 4 (4.3 / 5.0), and 4S (5.1) t.os('iOS') && t.version('iPad')>=4.3 || t.os('iOS') && t.version('iPhone')>=3.1 || t.os('iOS') && t.version('iPod')>=3.1 || // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5) // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7 ( t.version('Android')>2.1 && t.is('Webkit') ) || // Windows Phone 7-7.5 - Tested on the HTC Surround (7.0) HTC Trophy (7.5), LG-E900 (7.5), Nokia Lumia 800 t.version('Windows Phone OS')>=7.0 || // Blackberry 7 - Tested on BlackBerry Torch 9810 // Blackberry 6.0 - Tested on the Torch 9800 and Style 9670 t.is('BlackBerry') && t.version('BlackBerry')>=6.0 || // Blackberry Playbook (1.0-2.0) - Tested on PlayBook t.match('Playbook.*Tablet') || // Palm WebOS (1.4-2.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0) ( t.version('webOS')>=1.4 && t.match('Palm|Pre|Pixi') ) || // Palm WebOS 3.0 - Tested on HP TouchPad t.match('hp.*TouchPad') || // Firefox Mobile (12 Beta) - Tested on Android 2.3 device ( t.is('Firefox') && t.version('Firefox')>=12 ) || // Chrome for Android - Tested on Android 4.0, 4.1 device ( t.is('Chrome') && t.is('AndroidOS') && t.version('Android')>=4.0 ) || // Skyfire 4.1 - Tested on Android 2.3 device ( t.is('Skyfire') && t.version('Skyfire')>=4.1 && t.is('AndroidOS') && t.version('Android')>=2.3 ) || // Opera Mobile 11.5-12: Tested on Android 2.3 ( t.is('Opera') && t.version('Opera Mobi')>11 && t.is('AndroidOS') ) || // Meego 1.2 - Tested on Nokia 950 and N9 t.is('MeeGoOS') || // Tizen (pre-release) - Tested on early hardware t.is('Tizen') || // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser // @todo: more tests here! t.is('Dolfin') && t.version('Bada')>=2.0 || // UC Browser - Tested on Android 2.3 device ( (t.is('UC Browser') || t.is('Dolfin')) && t.version('Android')>=2.3 ) || // Kindle 3 and Fire - Tested on the built-in WebKit browser for each ( t.match('Kindle Fire') || t.is('Kindle') && t.version('Kindle')>=3.0 ) || // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet t.is('AndroidOS') && t.is('NookTablet') || // Chrome Desktop 11-21 - Tested on OS X 10.7 and Windows 7 t.version('Chrome')>=11 && !$isMobile || // Safari Desktop 4-5 - Tested on OS X 10.7 and Windows 7 t.version('Safari')>=5.0 && !$isMobile || // Firefox Desktop 4-13 - Tested on OS X 10.7 and Windows 7 t.version('Firefox')>=4.0 && !$isMobile || // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7 t.version('MSIE')>=7.0 && !$isMobile || // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7 // @reference: http://my.opera.com/community/openweb/idopera/ t.version('Opera')>=10 && !$isMobile ){ return 'A'; } if ( t.os('iOS') && t.version('iPad')<4.3 || t.os('iOS') && t.version('iPhone')<3.1 || t.os('iOS') && t.version('iPod')<3.1 || // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770 t.is('Blackberry') && t.version('BlackBerry')>=5 && t.version('BlackBerry')<6 || //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3 ( t.version('Opera Mini')>=5.0 && t.version('Opera Mini')<=6.5 && (t.version('Android')>=2.3 || t.is('iOS')) ) || // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1) t.match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') || // @todo: report this (tested on Nokia N71) t.version('Opera Mobi')>=11 && t.is('SymbianOS') ){ return 'B'; } if ( // Blackberry 4.x - Tested on the Curve 8330 t.version('BlackBerry')<5.0 || // Windows Mobile - Tested on the HTC Leo (WinMo 5.2) t.match('MSIEMobile|Windows CE.*Mobile') || t.version('Windows Mobile')<=5.2 ){ return 'C'; } //All older smartphone platforms and featurephones - Any device that doesn't support media queries //will receive the basic, C grade experience. return 'C'; }; impl.detectOS = function (ua) { return impl.findMatch(impl.mobileDetectRules.oss0, ua) || impl.findMatch(impl.mobileDetectRules.oss, ua); }; impl.getDeviceSmallerSide = function () { return window.screen.width < window.screen.height ? window.screen.width : window.screen.height; }; /** * Constructor for MobileDetect object. *
* Such an object will keep a reference to the given user-agent string and cache most of the detect queries.
*
* Find information how to download and install: * github.com/hgoebl/mobile-detect.js/ *
* * @example
     *     var md = new MobileDetect(window.navigator.userAgent);     *     if (md.mobile()) {     *         location.href = (md.mobileGrade() === 'A') ? '/mobile/' : '/lynx/';     *     }     * 
* * @param {string} userAgent typically taken from window.navigator.userAgent or http_header['User-Agent'] * @param {number} [maxPhoneWidth=600] only for browsers specify a value for the maximum * width of smallest device side (in logical "CSS" pixels) until a device detected as mobile will be handled * as phone. * This is only used in cases where the device cannot be classified as phone or tablet.
* See Declaring Tablet Layouts * for Android.
* If you provide a value < 0, then this "fuzzy" check is disabled. * @constructor * @global */ function MobileDetect(userAgent, maxPhoneWidth) { this.ua = userAgent || ''; this._cache = {}; //600dp is typical 7" tablet minimum width this.maxPhoneWidth = maxPhoneWidth || 600; } MobileDetect.prototype = { constructor: MobileDetect, /** * Returns the detected phone or tablet type or null if it is not a mobile device. *
* For a list of possible return values see {@link MobileDetect#phone} and {@link MobileDetect#tablet}.
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownPhone, UnknownTablet or * UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get UnknownMobile here.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key for the phone family or tablet family, e.g. "Nexus". * @function MobileDetect#mobile */ mobile: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.mobile; }, /** * Returns the detected phone type/family string or null. *
* The returned tablet (family or producer) is one of following keys:
*
iPhone, BlackBerry, HTC, Nexus, Dell, Motorola, Samsung, LG, Sony, Asus, * NokiaLumia, Micromax, Palm, Vertu, Pantech, Fly, Wiko, iMobile, SimValley, * Wolfgang, Alcatel, Nintendo, Amoi, INQ, GenericPhone
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownPhone or UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get null here, while {@link MobileDetect#mobile} * will return UnknownMobile.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key of the phone family or producer, e.g. "iPhone" * @function MobileDetect#phone */ phone: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.phone; }, /** * Returns the detected tablet type/family string or null. *
* The returned tablet (family or producer) is one of following keys:
*
iPad, NexusTablet, SamsungTablet, Kindle, SurfaceTablet, HPTablet, AsusTablet, * BlackBerryTablet, HTCtablet, MotorolaTablet, NookTablet, AcerTablet, * ToshibaTablet, LGTablet, FujitsuTablet, PrestigioTablet, LenovoTablet, * DellTablet, YarvikTablet, MedionTablet, ArnovaTablet, IntensoTablet, IRUTablet, * MegafonTablet, EbodaTablet, AllViewTablet, ArchosTablet, AinolTablet, * NokiaLumiaTablet, SonyTablet, PhilipsTablet, CubeTablet, CobyTablet, MIDTablet, * MSITablet, SMiTTablet, RockChipTablet, FlyTablet, bqTablet, HuaweiTablet, * NecTablet, PantechTablet, BronchoTablet, VersusTablet, ZyncTablet, * PositivoTablet, NabiTablet, KoboTablet, DanewTablet, TexetTablet, * PlaystationTablet, TrekstorTablet, PyleAudioTablet, AdvanTablet, * DanyTechTablet, GalapadTablet, MicromaxTablet, KarbonnTablet, AllFineTablet, * PROSCANTablet, YONESTablet, ChangJiaTablet, GUTablet, PointOfViewTablet, * OvermaxTablet, HCLTablet, DPSTablet, VistureTablet, CrestaTablet, * MediatekTablet, ConcordeTablet, GoCleverTablet, ModecomTablet, VoninoTablet, * ECSTablet, StorexTablet, VodafoneTablet, EssentielBTablet, RossMoorTablet, * iMobileTablet, TolinoTablet, AudioSonicTablet, AMPETablet, SkkTablet, * TecnoTablet, JXDTablet, iJoyTablet, FX2Tablet, XoroTablet, ViewsonicTablet, * OdysTablet, CaptivaTablet, IconbitTablet, TeclastTablet, OndaTablet, * JaytechTablet, BlaupunktTablet, DigmaTablet, EvolioTablet, LavaTablet, * AocTablet, MpmanTablet, CelkonTablet, WolderTablet, MiTablet, NibiruTablet, * NexoTablet, LeaderTablet, UbislateTablet, PocketBookTablet, KocasoTablet, Hudl, * TelstraTablet, GenericTablet
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownTablet or UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get null here, while {@link MobileDetect#mobile} * will return UnknownMobile.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key of the tablet family or producer, e.g. "SamsungTablet" * @function MobileDetect#tablet */ tablet: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.tablet; }, /** * Returns the (first) detected user-agent string or null. *
* The returned user-agent is one of following keys:
*
Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon
*
* In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare * cases where a mobile device pretends to be more than one particular browser. You can get the * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by * providing one of the defined keys as first argument to {@link MobileDetect#is}. * * @returns {String} the key for the detected user-agent or null * @function MobileDetect#userAgent */ userAgent: function () { if (this._cache.userAgent === undefined) { this._cache.userAgent = impl.findMatch(impl.mobileDetectRules.uas, this.ua); } return this._cache.userAgent; }, /** * Returns all detected user-agent strings. *
* The array is empty or contains one or more of following keys:
*
Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon
*
* In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare * cases where a mobile device pretends to be more than one particular browser. You can get the * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by * providing one of the defined keys as first argument to {@link MobileDetect#is}. * * @returns {Array} the array of detected user-agent keys or [] * @function MobileDetect#userAgents */ userAgents: function () { if (this._cache.userAgents === undefined) { this._cache.userAgents = impl.findMatches(impl.mobileDetectRules.uas, this.ua); } return this._cache.userAgents; }, /** * Returns the detected operating system string or null. *
* The operating system is one of following keys:
*
AndroidOS, BlackBerryOS, PalmOS, SymbianOS, WindowsMobileOS, WindowsPhoneOS, * iOS, MeeGoOS, MaemoOS, JavaOS, webOS, badaOS, BREWOS
* * @returns {String} the key for the detected operating system. * @function MobileDetect#os */ os: function () { if (this._cache.os === undefined) { this._cache.os = impl.detectOS(this.ua); } return this._cache.os; }, /** * Get the version (as Number) of the given property in the User-Agent. *
* Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param {String} key a key defining a thing which has a version.
* You can use one of following keys:
*
Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna, * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows * CE, Windows NT, Symbian, webOS
* * @returns {Number} the version as float or NaN if User-Agent doesn't contain this version. * Be careful when comparing this value with '==' operator! * @function MobileDetect#version */ version: function (key) { return impl.getVersion(key, this.ua); }, /** * Get the version (as String) of the given property in the User-Agent. *
* * @param {String} key a key defining a thing which has a version.
* You can use one of following keys:
*
Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna, * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows * CE, Windows NT, Symbian, webOS
* * @returns {String} the "raw" version as String or null if User-Agent doesn't contain this version. * * @function MobileDetect#versionStr */ versionStr: function (key) { return impl.getVersionStr(key, this.ua); }, /** * Global test key against userAgent, os, phone, tablet and some other properties of userAgent string. * * @param {String} key the key (case-insensitive) of a userAgent, an operating system, phone or * tablet family.
* For a complete list of possible values, see {@link MobileDetect#userAgent}, * {@link MobileDetect#os}, {@link MobileDetect#phone}, {@link MobileDetect#tablet}.
* Additionally you have following keys:
*
Bot, MobileBot, DesktopMode, TV, WebKit, Console, Watch
* * @returns {boolean} true when the given key is one of the defined keys of userAgent, os, phone, * tablet or one of the listed additional keys, otherwise false * @function MobileDetect#is */ is: function (key) { return containsIC(this.userAgents(), key) || equalIC(key, this.os()) || equalIC(key, this.phone()) || equalIC(key, this.tablet()) || containsIC(impl.findMatches(impl.mobileDetectRules.utils, this.ua), key); }, /** * Do a quick test against navigator::userAgent. * * @param {String|RegExp} pattern the pattern, either as String or RegExp * (a string will be converted to a case-insensitive RegExp). * @returns {boolean} true when the pattern matches, otherwise false * @function MobileDetect#match */ match: function (pattern) { if (!(pattern instanceof RegExp)) { pattern = new RegExp(pattern, 'i'); } return pattern.test(this.ua); }, /** * Checks whether the mobile device can be considered as phone regarding screen.width. *
* Obviously this method makes sense in browser environments only (not for Node.js)! * @param {number} [maxPhoneWidth] the maximum logical pixels (aka. CSS-pixels) to be considered as phone.
* The argument is optional and if not present or falsy, the value of the constructor is taken. * @returns {boolean|undefined} undefined if screen size wasn't detectable, else true * when screen.width is less or equal to maxPhoneWidth, otherwise false.
* Will always return undefined server-side. */ isPhoneSized: function (maxPhoneWidth) { return MobileDetect.isPhoneSized(maxPhoneWidth || this.maxPhoneWidth); }, /** * Returns the mobile grade ('A', 'B', 'C'). * * @returns {String} one of the mobile grades ('A', 'B', 'C'). * @function MobileDetect#mobileGrade */ mobileGrade: function () { if (this._cache.grade === undefined) { this._cache.grade = impl.mobileGrade(this); } return this._cache.grade; } }; // environment-dependent if (typeof window !== 'undefined' && window.screen) { MobileDetect.isPhoneSized = function (maxPhoneWidth) { return maxPhoneWidth < 0 ? undefined : impl.getDeviceSmallerSide() <= maxPhoneWidth; }; } else { MobileDetect.isPhoneSized = function () {}; } // should not be replaced by a completely new object - just overwrite existing methods MobileDetect._impl = impl; MobileDetect.version = '1.3.3 2016-07-31'; return MobileDetect;} : () => (userAgent: any, maxPhoneWidth: any) => void +>function () { 'use strict'; var impl = {}; impl.mobileDetectRules = { "phones": { "iPhone": "\\biPhone\\b|\\biPod\\b", "BlackBerry": "BlackBerry|\\bBB10\\b|rim[0-9]+", "HTC": "HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m", "Nexus": "Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6", "Dell": "Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b", "Motorola": "Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\\bMoto E\\b", "Samsung": "Samsung|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F", "LG": "\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323)", "Sony": "SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533", "Asus": "Asus.*Galaxy|PadFone.*Mobile", "NokiaLumia": "Lumia [0-9]{3,4}", "Micromax": "Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b", "Palm": "PalmSource|Palm", "Vertu": "Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature", "Pantech": "PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790", "Fly": "IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250", "Wiko": "KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM", "iMobile": "i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)", "SimValley": "\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b", "Wolfgang": "AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q", "Alcatel": "Alcatel", "Nintendo": "Nintendo 3DS", "Amoi": "Amoi", "INQ": "INQ", "GenericPhone": "Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser" }, "tablets": { "iPad": "iPad|iPad.*Mobile", "NexusTablet": "Android.*Nexus[\\s]+(7|9|10)", "SamsungTablet": "SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561", "Kindle": "Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI)\\b", "SurfaceTablet": "Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)", "HPTablet": "HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10", "AsusTablet": "^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b|\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K017 |ME572C|ME103K|ME170C|ME171C|\\bME70C\\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA", "BlackBerryTablet": "PlayBook|RIM Tablet", "HTCtablet": "HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410", "MotorolaTablet": "xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617", "NookTablet": "Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2", "AcerTablet": "Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b|W3-810|\\bA3-A10\\b|\\bA3-A11\\b|\\bA3-A20", "ToshibaTablet": "Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO", "LGTablet": "\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b", "FujitsuTablet": "Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b", "PrestigioTablet": "PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002", "LenovoTablet": "Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)", "DellTablet": "Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7", "YarvikTablet": "Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b", "MedionTablet": "Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB", "ArnovaTablet": "AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2", "IntensoTablet": "INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004", "IRUTablet": "M702pro", "MegafonTablet": "MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b", "EbodaTablet": "E-Boda (Supreme|Impresspeed|Izzycomm|Essential)", "AllViewTablet": "Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)", "ArchosTablet": "\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b", "AinolTablet": "NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark", "NokiaLumiaTablet": "Lumia 2520", "SonyTablet": "Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP612|SOT31", "PhilipsTablet": "\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b", "CubeTablet": "Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT", "CobyTablet": "MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010", "MIDTablet": "M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10", "MSITablet": "MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b", "SMiTTablet": "Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)", "RockChipTablet": "Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A", "FlyTablet": "IQ310|Fly Vision", "bqTablet": "Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris E10)|Maxwell.*Lite|Maxwell.*Plus", "HuaweiTablet": "MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim", "NecTablet": "\\bN-06D|\\bN-08D", "PantechTablet": "Pantech.*P4100", "BronchoTablet": "Broncho.*(N701|N708|N802|a710)", "VersusTablet": "TOUCHPAD.*[78910]|\\bTOUCHTAB\\b", "ZyncTablet": "z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900", "PositivoTablet": "TB07STA|TB10STA|TB07FTA|TB10FTA", "NabiTablet": "Android.*\\bNabi", "KoboTablet": "Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build", "DanewTablet": "DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b", "TexetTablet": "NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE", "PlaystationTablet": "Playstation.*(Portable|Vita)", "TrekstorTablet": "ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab", "PyleAudioTablet": "\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b", "AdvanTablet": "Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ", "DanyTechTablet": "Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1", "GalapadTablet": "Android.*\\bG1\\b", "MicromaxTablet": "Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b", "KarbonnTablet": "Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b", "AllFineTablet": "Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide", "PROSCANTablet": "\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b", "YONESTablet": "BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026", "ChangJiaTablet": "TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503", "GUTablet": "TX-A1301|TX-M9002|Q702|kf026", "PointOfViewTablet": "TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10", "OvermaxTablet": "OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)", "HCLTablet": "HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync", "DPSTablet": "DPS Dream 9|DPS Dual 7", "VistureTablet": "V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10", "CrestaTablet": "CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989", "MediatekTablet": "\\bMT8125|MT8389|MT8135|MT8377\\b", "ConcordeTablet": "Concorde([ ]+)?Tab|ConCorde ReadMan", "GoCleverTablet": "GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042", "ModecomTablet": "FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003", "VoninoTablet": "\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b", "ECSTablet": "V07OT2|TM105A|S10OT1|TR10CS1", "StorexTablet": "eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab", "VodafoneTablet": "SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497", "EssentielBTablet": "Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2", "RossMoorTablet": "RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711", "iMobileTablet": "i-mobile i-note", "TolinoTablet": "tolino tab [0-9.]+|tolino shine", "AudioSonicTablet": "\\bC-22Q|T7-QC|T-17B|T-17P\\b", "AMPETablet": "Android.* A78 ", "SkkTablet": "Android.* (SKYPAD|PHOENIX|CYCLOPS)", "TecnoTablet": "TECNO P9", "JXDTablet": "Android.* \\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b", "iJoyTablet": "Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)", "FX2Tablet": "FX2 PAD7|FX2 PAD10", "XoroTablet": "KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151", "ViewsonicTablet": "ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a", "OdysTablet": "LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10", "CaptivaTablet": "CAPTIVA PAD", "IconbitTablet": "NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S", "TeclastTablet": "T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G|\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G|\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b|\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b|\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b|\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi", "OndaTablet": "\\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\\b[\\s]+", "JaytechTablet": "TPC-PA762", "BlaupunktTablet": "Endeavour 800NG|Endeavour 1010", "DigmaTablet": "\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b", "EvolioTablet": "ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b", "LavaTablet": "QPAD E704|\\bIvoryS\\b|E-TAB IVORY|\\bE-TAB\\b", "AocTablet": "MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712", "MpmanTablet": "MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\\bMPG7\\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010", "CelkonTablet": "CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b", "WolderTablet": "miTab \\b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\\b", "MiTablet": "\\bMI PAD\\b|\\bHM NOTE 1W\\b", "NibiruTablet": "Nibiru M1|Nibiru Jupiter One", "NexoTablet": "NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI", "LeaderTablet": "TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100", "UbislateTablet": "UbiSlate[\\s]?7C", "PocketBookTablet": "Pocketbook", "KocasoTablet": "\\b(TB-1207)\\b", "Hudl": "Hudl HT7S3|Hudl 2", "TelstraTablet": "T-Hub2", "GenericTablet": "Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002|\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\\bM6pro\\b|CT1020W|arc 10HD|\\bJolla\\b|\\bTP750\\b" }, "oss": { "AndroidOS": "Android", "BlackBerryOS": "blackberry|\\bBB10\\b|rim tablet os", "PalmOS": "PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino", "SymbianOS": "Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b", "WindowsMobileOS": "Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;", "WindowsPhoneOS": "Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;", "iOS": "\\biPhone.*Mobile|\\biPod|\\biPad", "MeeGoOS": "MeeGo", "MaemoOS": "Maemo", "JavaOS": "J2ME\/|\\bMIDP\\b|\\bCLDC\\b", "webOS": "webOS|hpwOS", "badaOS": "\\bBada\\b", "BREWOS": "BREW" }, "uas": { "Vivaldi": "Vivaldi", "Chrome": "\\bCrMo\\b|CriOS|Android.*Chrome\/[.0-9]* (Mobile)?", "Dolfin": "\\bDolfin\\b", "Opera": "Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+|Coast\/[0-9.]+", "Skyfire": "Skyfire", "Edge": "Mobile Safari\/[.0-9]* Edge", "IE": "IEMobile|MSIEMobile", "Firefox": "fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile", "Bolt": "bolt", "TeaShark": "teashark", "Blazer": "Blazer", "Safari": "Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari", "Tizen": "Tizen", "UCBrowser": "UC.*Browser|UCWEB", "baiduboxapp": "baiduboxapp", "baidubrowser": "baidubrowser", "DiigoBrowser": "DiigoBrowser", "Puffin": "Puffin", "Mercury": "\\bMercury\\b", "ObigoBrowser": "Obigo", "NetFront": "NF-Browser", "GenericBrowser": "NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger", "PaleMoon": "Android.*PaleMoon|Mobile.*PaleMoon" }, "props": { "Mobile": "Mobile\/[VER]", "Build": "Build\/[VER]", "Version": "Version\/[VER]", "VendorID": "VendorID\/[VER]", "iPad": "iPad.*CPU[a-z ]+[VER]", "iPhone": "iPhone.*CPU[a-z ]+[VER]", "iPod": "iPod.*CPU[a-z ]+[VER]", "Kindle": "Kindle\/[VER]", "Chrome": [ "Chrome\/[VER]", "CriOS\/[VER]", "CrMo\/[VER]" ], "Coast": [ "Coast\/[VER]" ], "Dolfin": "Dolfin\/[VER]", "Firefox": "Firefox\/[VER]", "Fennec": "Fennec\/[VER]", "Edge": "Edge\/[VER]", "IE": [ "IEMobile\/[VER];", "IEMobile [VER]", "MSIE [VER];", "Trident\/[0-9.]+;.*rv:[VER]" ], "NetFront": "NetFront\/[VER]", "NokiaBrowser": "NokiaBrowser\/[VER]", "Opera": [ " OPR\/[VER]", "Opera Mini\/[VER]", "Version\/[VER]" ], "Opera Mini": "Opera Mini\/[VER]", "Opera Mobi": "Version\/[VER]", "UC Browser": "UC Browser[VER]", "MQQBrowser": "MQQBrowser\/[VER]", "MicroMessenger": "MicroMessenger\/[VER]", "baiduboxapp": "baiduboxapp\/[VER]", "baidubrowser": "baidubrowser\/[VER]", "Iron": "Iron\/[VER]", "Safari": [ "Version\/[VER]", "Safari\/[VER]" ], "Skyfire": "Skyfire\/[VER]", "Tizen": "Tizen\/[VER]", "Webkit": "webkit[ \/][VER]", "PaleMoon": "PaleMoon\/[VER]", "Gecko": "Gecko\/[VER]", "Trident": "Trident\/[VER]", "Presto": "Presto\/[VER]", "Goanna": "Goanna\/[VER]", "iOS": " \\bi?OS\\b [VER][ ;]{1}", "Android": "Android [VER]", "BlackBerry": [ "BlackBerry[\\w]+\/[VER]", "BlackBerry.*Version\/[VER]", "Version\/[VER]" ], "BREW": "BREW [VER]", "Java": "Java\/[VER]", "Windows Phone OS": [ "Windows Phone OS [VER]", "Windows Phone [VER]" ], "Windows Phone": "Windows Phone [VER]", "Windows CE": "Windows CE\/[VER]", "Windows NT": "Windows NT [VER]", "Symbian": [ "SymbianOS\/[VER]", "Symbian\/[VER]" ], "webOS": [ "webOS\/[VER]", "hpwOS\/[VER];" ] }, "utils": { "Bot": "Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom", "MobileBot": "Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker\/M1A1-R2D2", "DesktopMode": "WPDesktop", "TV": "SonyDTV|HbbTV", "WebKit": "(webkit)[ \/]([\\w.]+)", "Console": "\\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\\b", "Watch": "SM-V700" }}; // following patterns come from http://detectmobilebrowsers.com/ impl.detectMobileBrowsers = { fullPattern: /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i, shortPattern: /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i, tabletPattern: /android|ipad|playbook|silk/i }; var hasOwnProp = Object.prototype.hasOwnProperty, isArray; impl.FALLBACK_PHONE = 'UnknownPhone'; impl.FALLBACK_TABLET = 'UnknownTablet'; impl.FALLBACK_MOBILE = 'UnknownMobile'; isArray = ('isArray' in Array) ? Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }; isArray = 'isArray' in Array ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : Array.isArray; function equalIC(a, b) { return a != null && b != null && a.toLowerCase() === b.toLowerCase(); } function containsIC(array, value) { var valueLC, i, len = array.length; if (!len || !value) { return false; } valueLC = value.toLowerCase(); for (i = 0; i < len; ++i) { if (valueLC === array[i].toLowerCase()) { return true; } } return false; } function convertPropsToRegExp(object) { for (var key in object) { if (hasOwnProp.call(object, key)) { object[key] = new RegExp(object[key], 'i'); } } } (function init() { var key, values, value, i, len, verPos, mobileDetectRules = impl.mobileDetectRules; for (key in mobileDetectRules.props) { if (hasOwnProp.call(mobileDetectRules.props, key)) { values = mobileDetectRules.props[key]; if (!isArray(values)) { values = [values]; } len = values.length; for (i = 0; i < len; ++i) { value = values[i]; verPos = value.indexOf('[VER]'); if (verPos >= 0) { value = value.substring(0, verPos) + '([\\w._\\+]+)' + value.substring(verPos + 5); } values[i] = new RegExp(value, 'i'); } mobileDetectRules.props[key] = values; } } convertPropsToRegExp(mobileDetectRules.oss); convertPropsToRegExp(mobileDetectRules.phones); convertPropsToRegExp(mobileDetectRules.tablets); convertPropsToRegExp(mobileDetectRules.uas); convertPropsToRegExp(mobileDetectRules.utils); // copy some patterns to oss0 which are tested first (see issue#15) mobileDetectRules.oss0 = { WindowsPhoneOS: mobileDetectRules.oss.WindowsPhoneOS, WindowsMobileOS: mobileDetectRules.oss.WindowsMobileOS }; }()); /** * Test userAgent string against a set of rules and find the first matched key. * @param {Object} rules (key is String, value is RegExp) * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). * @returns {String|null} the matched key if found, otherwise null * @private */ impl.findMatch = function(rules, userAgent) { for (var key in rules) { if (hasOwnProp.call(rules, key)) { if (rules[key].test(userAgent)) { return key; } } } return null; }; /** * Test userAgent string against a set of rules and return an array of matched keys. * @param {Object} rules (key is String, value is RegExp) * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent'). * @returns {Array} an array of matched keys, may be empty when there is no match, but not null * @private */ impl.findMatches = function(rules, userAgent) { var result = []; for (var key in rules) { if (hasOwnProp.call(rules, key)) { if (rules[key].test(userAgent)) { result.push(key); } } } return result; }; /** * Check the version of the given property in the User-Agent. * * @param {String} propertyName * @param {String} userAgent * @return {String} version or null if version not found * @private */ impl.getVersionStr = function (propertyName, userAgent) { var props = impl.mobileDetectRules.props, patterns, i, len, match; if (hasOwnProp.call(props, propertyName)) { patterns = props[propertyName]; len = patterns.length; for (i = 0; i < len; ++i) { match = patterns[i].exec(userAgent); if (match !== null) { return match[1]; } } } return null; }; /** * Check the version of the given property in the User-Agent. * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param {String} propertyName * @param {String} userAgent * @return {Number} version or NaN if version not found * @private */ impl.getVersion = function (propertyName, userAgent) { var version = impl.getVersionStr(propertyName, userAgent); return version ? impl.prepareVersionNo(version) : NaN; }; /** * Prepare the version number. * * @param {String} version * @return {Number} the version number as a floating number * @private */ impl.prepareVersionNo = function (version) { var numbers; numbers = version.split(/[a-z._ \/\-]/i); if (numbers.length === 1) { version = numbers[0]; } if (numbers.length > 1) { version = numbers[0] + '.'; numbers.shift(); version += numbers.join(''); } return Number(version); }; impl.isMobileFallback = function (userAgent) { return impl.detectMobileBrowsers.fullPattern.test(userAgent) || impl.detectMobileBrowsers.shortPattern.test(userAgent.substr(0,4)); }; impl.isTabletFallback = function (userAgent) { return impl.detectMobileBrowsers.tabletPattern.test(userAgent); }; impl.prepareDetectionCache = function (cache, userAgent, maxPhoneWidth) { if (cache.mobile !== undefined) { return; } var phone, tablet, phoneSized; // first check for stronger tablet rules, then phone (see issue#5) tablet = impl.findMatch(impl.mobileDetectRules.tablets, userAgent); if (tablet) { cache.mobile = cache.tablet = tablet; cache.phone = null; return; // unambiguously identified as tablet } phone = impl.findMatch(impl.mobileDetectRules.phones, userAgent); if (phone) { cache.mobile = cache.phone = phone; cache.tablet = null; return; // unambiguously identified as phone } // our rules haven't found a match -> try more general fallback rules if (impl.isMobileFallback(userAgent)) { phoneSized = MobileDetect.isPhoneSized(maxPhoneWidth); if (phoneSized === undefined) { cache.mobile = impl.FALLBACK_MOBILE; cache.tablet = cache.phone = null; } else if (phoneSized) { cache.mobile = cache.phone = impl.FALLBACK_PHONE; cache.tablet = null; } else { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; cache.phone = null; } } else if (impl.isTabletFallback(userAgent)) { cache.mobile = cache.tablet = impl.FALLBACK_TABLET; cache.phone = null; } else { // not mobile at all! cache.mobile = cache.tablet = cache.phone = null; } }; // t is a reference to a MobileDetect instance impl.mobileGrade = function (t) { // impl note: // To keep in sync w/ Mobile_Detect.php easily, the following code is tightly aligned to the PHP version. // When changes are made in Mobile_Detect.php, copy this method and replace: // $this-> / t. // self::MOBILE_GRADE_(.) / '$1' // , self::VERSION_TYPE_FLOAT / (nothing) // isIOS() / os('iOS') // [reg] / (nothing) <-- jsdelivr complaining about unescaped unicode character U+00AE var $isMobile = t.mobile() !== null; if ( // Apple iOS 3.2-5.1 - Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3), iPad 3 (5.1), original iPhone (3.1), iPhone 3 (3.2), 3GS (4.3), 4 (4.3 / 5.0), and 4S (5.1) t.os('iOS') && t.version('iPad')>=4.3 || t.os('iOS') && t.version('iPhone')>=3.1 || t.os('iOS') && t.version('iPod')>=3.1 || // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5) // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7 ( t.version('Android')>2.1 && t.is('Webkit') ) || // Windows Phone 7-7.5 - Tested on the HTC Surround (7.0) HTC Trophy (7.5), LG-E900 (7.5), Nokia Lumia 800 t.version('Windows Phone OS')>=7.0 || // Blackberry 7 - Tested on BlackBerry Torch 9810 // Blackberry 6.0 - Tested on the Torch 9800 and Style 9670 t.is('BlackBerry') && t.version('BlackBerry')>=6.0 || // Blackberry Playbook (1.0-2.0) - Tested on PlayBook t.match('Playbook.*Tablet') || // Palm WebOS (1.4-2.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0) ( t.version('webOS')>=1.4 && t.match('Palm|Pre|Pixi') ) || // Palm WebOS 3.0 - Tested on HP TouchPad t.match('hp.*TouchPad') || // Firefox Mobile (12 Beta) - Tested on Android 2.3 device ( t.is('Firefox') && t.version('Firefox')>=12 ) || // Chrome for Android - Tested on Android 4.0, 4.1 device ( t.is('Chrome') && t.is('AndroidOS') && t.version('Android')>=4.0 ) || // Skyfire 4.1 - Tested on Android 2.3 device ( t.is('Skyfire') && t.version('Skyfire')>=4.1 && t.is('AndroidOS') && t.version('Android')>=2.3 ) || // Opera Mobile 11.5-12: Tested on Android 2.3 ( t.is('Opera') && t.version('Opera Mobi')>11 && t.is('AndroidOS') ) || // Meego 1.2 - Tested on Nokia 950 and N9 t.is('MeeGoOS') || // Tizen (pre-release) - Tested on early hardware t.is('Tizen') || // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser // @todo: more tests here! t.is('Dolfin') && t.version('Bada')>=2.0 || // UC Browser - Tested on Android 2.3 device ( (t.is('UC Browser') || t.is('Dolfin')) && t.version('Android')>=2.3 ) || // Kindle 3 and Fire - Tested on the built-in WebKit browser for each ( t.match('Kindle Fire') || t.is('Kindle') && t.version('Kindle')>=3.0 ) || // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet t.is('AndroidOS') && t.is('NookTablet') || // Chrome Desktop 11-21 - Tested on OS X 10.7 and Windows 7 t.version('Chrome')>=11 && !$isMobile || // Safari Desktop 4-5 - Tested on OS X 10.7 and Windows 7 t.version('Safari')>=5.0 && !$isMobile || // Firefox Desktop 4-13 - Tested on OS X 10.7 and Windows 7 t.version('Firefox')>=4.0 && !$isMobile || // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7 t.version('MSIE')>=7.0 && !$isMobile || // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7 // @reference: http://my.opera.com/community/openweb/idopera/ t.version('Opera')>=10 && !$isMobile ){ return 'A'; } if ( t.os('iOS') && t.version('iPad')<4.3 || t.os('iOS') && t.version('iPhone')<3.1 || t.os('iOS') && t.version('iPod')<3.1 || // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770 t.is('Blackberry') && t.version('BlackBerry')>=5 && t.version('BlackBerry')<6 || //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3 ( t.version('Opera Mini')>=5.0 && t.version('Opera Mini')<=6.5 && (t.version('Android')>=2.3 || t.is('iOS')) ) || // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1) t.match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') || // @todo: report this (tested on Nokia N71) t.version('Opera Mobi')>=11 && t.is('SymbianOS') ){ return 'B'; } if ( // Blackberry 4.x - Tested on the Curve 8330 t.version('BlackBerry')<5.0 || // Windows Mobile - Tested on the HTC Leo (WinMo 5.2) t.match('MSIEMobile|Windows CE.*Mobile') || t.version('Windows Mobile')<=5.2 ){ return 'C'; } //All older smartphone platforms and featurephones - Any device that doesn't support media queries //will receive the basic, C grade experience. return 'C'; }; impl.detectOS = function (ua) { return impl.findMatch(impl.mobileDetectRules.oss0, ua) || impl.findMatch(impl.mobileDetectRules.oss, ua); }; impl.getDeviceSmallerSide = function () { return window.screen.width < window.screen.height ? window.screen.width : window.screen.height; }; /** * Constructor for MobileDetect object. *
* Such an object will keep a reference to the given user-agent string and cache most of the detect queries.
*
* Find information how to download and install: * github.com/hgoebl/mobile-detect.js/ *
* * @example
     *     var md = new MobileDetect(window.navigator.userAgent);     *     if (md.mobile()) {     *         location.href = (md.mobileGrade() === 'A') ? '/mobile/' : '/lynx/';     *     }     * 
* * @param {string} userAgent typically taken from window.navigator.userAgent or http_header['User-Agent'] * @param {number} [maxPhoneWidth=600] only for browsers specify a value for the maximum * width of smallest device side (in logical "CSS" pixels) until a device detected as mobile will be handled * as phone. * This is only used in cases where the device cannot be classified as phone or tablet.
* See Declaring Tablet Layouts * for Android.
* If you provide a value < 0, then this "fuzzy" check is disabled. * @constructor * @global */ function MobileDetect(userAgent, maxPhoneWidth) { this.ua = userAgent || ''; this._cache = {}; //600dp is typical 7" tablet minimum width this.maxPhoneWidth = maxPhoneWidth || 600; } MobileDetect.prototype = { constructor: MobileDetect, /** * Returns the detected phone or tablet type or null if it is not a mobile device. *
* For a list of possible return values see {@link MobileDetect#phone} and {@link MobileDetect#tablet}.
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownPhone, UnknownTablet or * UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get UnknownMobile here.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key for the phone family or tablet family, e.g. "Nexus". * @function MobileDetect#mobile */ mobile: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.mobile; }, /** * Returns the detected phone type/family string or null. *
* The returned tablet (family or producer) is one of following keys:
*
iPhone, BlackBerry, HTC, Nexus, Dell, Motorola, Samsung, LG, Sony, Asus, * NokiaLumia, Micromax, Palm, Vertu, Pantech, Fly, Wiko, iMobile, SimValley, * Wolfgang, Alcatel, Nintendo, Amoi, INQ, GenericPhone
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownPhone or UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get null here, while {@link MobileDetect#mobile} * will return UnknownMobile.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key of the phone family or producer, e.g. "iPhone" * @function MobileDetect#phone */ phone: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.phone; }, /** * Returns the detected tablet type/family string or null. *
* The returned tablet (family or producer) is one of following keys:
*
iPad, NexusTablet, SamsungTablet, Kindle, SurfaceTablet, HPTablet, AsusTablet, * BlackBerryTablet, HTCtablet, MotorolaTablet, NookTablet, AcerTablet, * ToshibaTablet, LGTablet, FujitsuTablet, PrestigioTablet, LenovoTablet, * DellTablet, YarvikTablet, MedionTablet, ArnovaTablet, IntensoTablet, IRUTablet, * MegafonTablet, EbodaTablet, AllViewTablet, ArchosTablet, AinolTablet, * NokiaLumiaTablet, SonyTablet, PhilipsTablet, CubeTablet, CobyTablet, MIDTablet, * MSITablet, SMiTTablet, RockChipTablet, FlyTablet, bqTablet, HuaweiTablet, * NecTablet, PantechTablet, BronchoTablet, VersusTablet, ZyncTablet, * PositivoTablet, NabiTablet, KoboTablet, DanewTablet, TexetTablet, * PlaystationTablet, TrekstorTablet, PyleAudioTablet, AdvanTablet, * DanyTechTablet, GalapadTablet, MicromaxTablet, KarbonnTablet, AllFineTablet, * PROSCANTablet, YONESTablet, ChangJiaTablet, GUTablet, PointOfViewTablet, * OvermaxTablet, HCLTablet, DPSTablet, VistureTablet, CrestaTablet, * MediatekTablet, ConcordeTablet, GoCleverTablet, ModecomTablet, VoninoTablet, * ECSTablet, StorexTablet, VodafoneTablet, EssentielBTablet, RossMoorTablet, * iMobileTablet, TolinoTablet, AudioSonicTablet, AMPETablet, SkkTablet, * TecnoTablet, JXDTablet, iJoyTablet, FX2Tablet, XoroTablet, ViewsonicTablet, * OdysTablet, CaptivaTablet, IconbitTablet, TeclastTablet, OndaTablet, * JaytechTablet, BlaupunktTablet, DigmaTablet, EvolioTablet, LavaTablet, * AocTablet, MpmanTablet, CelkonTablet, WolderTablet, MiTablet, NibiruTablet, * NexoTablet, LeaderTablet, UbislateTablet, PocketBookTablet, KocasoTablet, Hudl, * TelstraTablet, GenericTablet
*
* If the device is not detected by the regular expressions from Mobile-Detect, a test is made against * the patterns of detectmobilebrowsers.com. If this test * is positive, a value of UnknownTablet or UnknownMobile is returned.
* When used in browser, the decision whether phone or tablet is made based on screen.width/height.
*
* When used server-side (node.js), there is no way to tell the difference between UnknownTablet * and UnknownMobile, so you will get null here, while {@link MobileDetect#mobile} * will return UnknownMobile.
* Be aware that since v1.0.0 in this special case you will get UnknownMobile only for: * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}. * In versions before v1.0.0 all 3 methods returned UnknownMobile which was tedious to use. *
* In most cases you will use the return value just as a boolean. * * @returns {String} the key of the tablet family or producer, e.g. "SamsungTablet" * @function MobileDetect#tablet */ tablet: function () { impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth); return this._cache.tablet; }, /** * Returns the (first) detected user-agent string or null. *
* The returned user-agent is one of following keys:
*
Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon
*
* In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare * cases where a mobile device pretends to be more than one particular browser. You can get the * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by * providing one of the defined keys as first argument to {@link MobileDetect#is}. * * @returns {String} the key for the detected user-agent or null * @function MobileDetect#userAgent */ userAgent: function () { if (this._cache.userAgent === undefined) { this._cache.userAgent = impl.findMatch(impl.mobileDetectRules.uas, this.ua); } return this._cache.userAgent; }, /** * Returns all detected user-agent strings. *
* The array is empty or contains one or more of following keys:
*
Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon
*
* In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare * cases where a mobile device pretends to be more than one particular browser. You can get the * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by * providing one of the defined keys as first argument to {@link MobileDetect#is}. * * @returns {Array} the array of detected user-agent keys or [] * @function MobileDetect#userAgents */ userAgents: function () { if (this._cache.userAgents === undefined) { this._cache.userAgents = impl.findMatches(impl.mobileDetectRules.uas, this.ua); } return this._cache.userAgents; }, /** * Returns the detected operating system string or null. *
* The operating system is one of following keys:
*
AndroidOS, BlackBerryOS, PalmOS, SymbianOS, WindowsMobileOS, WindowsPhoneOS, * iOS, MeeGoOS, MaemoOS, JavaOS, webOS, badaOS, BREWOS
* * @returns {String} the key for the detected operating system. * @function MobileDetect#os */ os: function () { if (this._cache.os === undefined) { this._cache.os = impl.detectOS(this.ua); } return this._cache.os; }, /** * Get the version (as Number) of the given property in the User-Agent. *
* Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param {String} key a key defining a thing which has a version.
* You can use one of following keys:
*
Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna, * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows * CE, Windows NT, Symbian, webOS
* * @returns {Number} the version as float or NaN if User-Agent doesn't contain this version. * Be careful when comparing this value with '==' operator! * @function MobileDetect#version */ version: function (key) { return impl.getVersion(key, this.ua); }, /** * Get the version (as String) of the given property in the User-Agent. *
* * @param {String} key a key defining a thing which has a version.
* You can use one of following keys:
*
Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast, * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini, * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser, * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna, * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows * CE, Windows NT, Symbian, webOS
* * @returns {String} the "raw" version as String or null if User-Agent doesn't contain this version. * * @function MobileDetect#versionStr */ versionStr: function (key) { return impl.getVersionStr(key, this.ua); }, /** * Global test key against userAgent, os, phone, tablet and some other properties of userAgent string. * * @param {String} key the key (case-insensitive) of a userAgent, an operating system, phone or * tablet family.
* For a complete list of possible values, see {@link MobileDetect#userAgent}, * {@link MobileDetect#os}, {@link MobileDetect#phone}, {@link MobileDetect#tablet}.
* Additionally you have following keys:
*
Bot, MobileBot, DesktopMode, TV, WebKit, Console, Watch
* * @returns {boolean} true when the given key is one of the defined keys of userAgent, os, phone, * tablet or one of the listed additional keys, otherwise false * @function MobileDetect#is */ is: function (key) { return containsIC(this.userAgents(), key) || equalIC(key, this.os()) || equalIC(key, this.phone()) || equalIC(key, this.tablet()) || containsIC(impl.findMatches(impl.mobileDetectRules.utils, this.ua), key); }, /** * Do a quick test against navigator::userAgent. * * @param {String|RegExp} pattern the pattern, either as String or RegExp * (a string will be converted to a case-insensitive RegExp). * @returns {boolean} true when the pattern matches, otherwise false * @function MobileDetect#match */ match: function (pattern) { if (!(pattern instanceof RegExp)) { pattern = new RegExp(pattern, 'i'); } return pattern.test(this.ua); }, /** * Checks whether the mobile device can be considered as phone regarding screen.width. *
* Obviously this method makes sense in browser environments only (not for Node.js)! * @param {number} [maxPhoneWidth] the maximum logical pixels (aka. CSS-pixels) to be considered as phone.
* The argument is optional and if not present or falsy, the value of the constructor is taken. * @returns {boolean|undefined} undefined if screen size wasn't detectable, else true * when screen.width is less or equal to maxPhoneWidth, otherwise false.
* Will always return undefined server-side. */ isPhoneSized: function (maxPhoneWidth) { return MobileDetect.isPhoneSized(maxPhoneWidth || this.maxPhoneWidth); }, /** * Returns the mobile grade ('A', 'B', 'C'). * * @returns {String} one of the mobile grades ('A', 'B', 'C'). * @function MobileDetect#mobileGrade */ mobileGrade: function () { if (this._cache.grade === undefined) { this._cache.grade = impl.mobileGrade(this); } return this._cache.grade; } }; // environment-dependent if (typeof window !== 'undefined' && window.screen) { MobileDetect.isPhoneSized = function (maxPhoneWidth) { return maxPhoneWidth < 0 ? undefined : impl.getDeviceSmallerSide() <= maxPhoneWidth; }; } else { MobileDetect.isPhoneSized = function () {}; } // should not be replaced by a completely new object - just overwrite existing methods MobileDetect._impl = impl; MobileDetect.version = '1.3.3 2016-07-31'; return MobileDetect;} : () => (userAgent: any, maxPhoneWidth: any) => void 'use strict'; >'use strict' : "use strict" @@ -866,9 +866,9 @@ define(function () { >'UnknownMobile' : "UnknownMobile" isArray = ('isArray' in Array) ? ->isArray = ('isArray' in Array) ? Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : (arg: any) => arg is any[] +>isArray = ('isArray' in Array) ? Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : (value: any) => boolean >isArray : any ->('isArray' in Array) ? Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : (arg: any) => arg is any[] +>('isArray' in Array) ? Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : (value: any) => boolean >('isArray' in Array) : boolean >'isArray' in Array : boolean >'isArray' : "isArray" @@ -892,6 +892,34 @@ define(function () { >value : any >'[object Array]' : "[object Array]" + isArray = 'isArray' in Array +>isArray = 'isArray' in Array ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : Array.isArray : any +>isArray : any +>'isArray' in Array ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : Array.isArray : any +>'isArray' in Array : boolean +>'isArray' : "isArray" +>Array : ArrayConstructor + + ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } +>function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : (value: any) => boolean +>value : any +>Object.prototype.toString.call(value) === '[object Array]' : boolean +>Object.prototype.toString.call(value) : any +>Object.prototype.toString.call : (this: Function, thisArg: any, ...argArray: any[]) => any +>Object.prototype.toString : () => string +>Object.prototype : Object +>Object : ObjectConstructor +>prototype : Object +>toString : () => string +>call : (this: Function, thisArg: any, ...argArray: any[]) => any +>value : any +>'[object Array]' : "[object Array]" + + : Array.isArray; +>Array.isArray : any +>Array : never +>isArray : any + function equalIC(a, b) { >equalIC : (a: any, b: any) => boolean >a : any @@ -3205,7 +3233,7 @@ define(function () { >MobileDetect : (userAgent: any, maxPhoneWidth: any) => void >_impl : any >impl : {} - + MobileDetect.version = '1.3.3 2016-07-31'; >MobileDetect.version = '1.3.3 2016-07-31' : "1.3.3 2016-07-31" >MobileDetect.version : any diff --git a/tests/baselines/reference/inKeywordTypeguard.errors.txt b/tests/baselines/reference/inKeywordTypeguard.errors.txt new file mode 100644 index 0000000000..914daf42a7 --- /dev/null +++ b/tests/baselines/reference/inKeywordTypeguard.errors.txt @@ -0,0 +1,159 @@ +tests/cases/compiler/inKeywordTypeguard.ts(6,11): error TS2339: Property 'b' does not exist on type 'A'. +tests/cases/compiler/inKeywordTypeguard.ts(8,11): error TS2339: Property 'a' does not exist on type 'B'. +tests/cases/compiler/inKeywordTypeguard.ts(14,11): error TS2339: Property 'b' does not exist on type 'A'. +tests/cases/compiler/inKeywordTypeguard.ts(16,11): error TS2339: Property 'a' does not exist on type 'B'. +tests/cases/compiler/inKeywordTypeguard.ts(27,11): error TS2339: Property 'b' does not exist on type 'AWithOptionalProp | BWithOptionalProp'. + Property 'b' does not exist on type 'AWithOptionalProp'. +tests/cases/compiler/inKeywordTypeguard.ts(42,11): error TS2339: Property 'b' does not exist on type 'AWithMethod'. +tests/cases/compiler/inKeywordTypeguard.ts(49,11): error TS2339: Property 'a' does not exist on type 'never'. +tests/cases/compiler/inKeywordTypeguard.ts(50,11): error TS2339: Property 'b' does not exist on type 'never'. +tests/cases/compiler/inKeywordTypeguard.ts(52,11): error TS2339: Property 'a' does not exist on type 'AWithMethod | BWithMethod'. + Property 'a' does not exist on type 'BWithMethod'. +tests/cases/compiler/inKeywordTypeguard.ts(53,11): error TS2339: Property 'b' does not exist on type 'AWithMethod | BWithMethod'. + Property 'b' does not exist on type 'AWithMethod'. +tests/cases/compiler/inKeywordTypeguard.ts(62,11): error TS2339: Property 'b' does not exist on type 'A | C | D'. + Property 'b' does not exist on type 'A'. +tests/cases/compiler/inKeywordTypeguard.ts(64,11): error TS2339: Property 'a' does not exist on type 'B'. +tests/cases/compiler/inKeywordTypeguard.ts(72,32): error TS2339: Property 'b' does not exist on type 'A'. +tests/cases/compiler/inKeywordTypeguard.ts(74,32): error TS2339: Property 'a' does not exist on type 'B'. +tests/cases/compiler/inKeywordTypeguard.ts(82,39): error TS2339: Property 'b' does not exist on type 'A'. +tests/cases/compiler/inKeywordTypeguard.ts(84,39): error TS2339: Property 'a' does not exist on type 'B'. +tests/cases/compiler/inKeywordTypeguard.ts(94,26): error TS2339: Property 'a' does not exist on type 'never'. + + +==== tests/cases/compiler/inKeywordTypeguard.ts (17 errors) ==== + class A { a: string; } + class B { b: string; } + + function negativeClassesTest(x: A | B) { + if ("a" in x) { + x.b = "1"; + ~ +!!! error TS2339: Property 'b' does not exist on type 'A'. + } else { + x.a = "1"; + ~ +!!! error TS2339: Property 'a' does not exist on type 'B'. + } + } + + function positiveClassesTest(x: A | B) { + if ("a" in x) { + x.b = "1"; + ~ +!!! error TS2339: Property 'b' does not exist on type 'A'. + } else { + x.a = "1"; + ~ +!!! error TS2339: Property 'a' does not exist on type 'B'. + } + } + + class AWithOptionalProp { a?: string; } + class BWithOptionalProp { b?: string; } + + function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) { + if ("a" in x) { + x.a = "1"; + } else { + x.b = "1"; + ~ +!!! error TS2339: Property 'b' does not exist on type 'AWithOptionalProp | BWithOptionalProp'. +!!! error TS2339: Property 'b' does not exist on type 'AWithOptionalProp'. + } + } + + class AWithMethod { + a(): string { return ""; } + } + + class BWithMethod { + b(): string { return ""; } + } + + function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) { + if ("a" in x) { + x.a(); + x.b(); + ~ +!!! error TS2339: Property 'b' does not exist on type 'AWithMethod'. + } else { + } + } + + function negativeTestClassesWithMemberMissingInBothClasses(x: AWithMethod | BWithMethod) { + if ("c" in x) { + x.a(); + ~ +!!! error TS2339: Property 'a' does not exist on type 'never'. + x.b(); + ~ +!!! error TS2339: Property 'b' does not exist on type 'never'. + } else { + x.a(); + ~ +!!! error TS2339: Property 'a' does not exist on type 'AWithMethod | BWithMethod'. +!!! error TS2339: Property 'a' does not exist on type 'BWithMethod'. + x.b(); + ~ +!!! error TS2339: Property 'b' does not exist on type 'AWithMethod | BWithMethod'. +!!! error TS2339: Property 'b' does not exist on type 'AWithMethod'. + } + } + + class C { a: string; } + class D { a: string; } + + function negativeMultipleClassesTest(x: A | B | C | D) { + if ("a" in x) { + x.b = "1"; + ~ +!!! error TS2339: Property 'b' does not exist on type 'A | C | D'. +!!! error TS2339: Property 'b' does not exist on type 'A'. + } else { + x.a = "1"; + ~ +!!! error TS2339: Property 'a' does not exist on type 'B'. + } + } + + class ClassWithUnionProp { prop: A | B } + + function negativePropTest(x: ClassWithUnionProp) { + if ("a" in x.prop) { + let y: string = x.prop.b; + ~ +!!! error TS2339: Property 'b' does not exist on type 'A'. + } else { + let z: string = x.prop.a; + ~ +!!! error TS2339: Property 'a' does not exist on type 'B'. + } + } + + class NegativeClassTest { + protected prop: A | B; + inThis() { + if ("a" in this.prop) { + let z: number = this.prop.b; + ~ +!!! error TS2339: Property 'b' does not exist on type 'A'. + } else { + let y: string = this.prop.a; + ~ +!!! error TS2339: Property 'a' does not exist on type 'B'. + } + } + } + + class UnreachableCodeDetection { + a: string; + inThis() { + if ("a" in this) { + } else { + let y = this.a; + ~ +!!! error TS2339: Property 'a' does not exist on type 'never'. + } + } + } \ No newline at end of file diff --git a/tests/baselines/reference/inKeywordTypeguard.js b/tests/baselines/reference/inKeywordTypeguard.js new file mode 100644 index 0000000000..41ad27f96d --- /dev/null +++ b/tests/baselines/reference/inKeywordTypeguard.js @@ -0,0 +1,230 @@ +//// [inKeywordTypeguard.ts] +class A { a: string; } +class B { b: string; } + +function negativeClassesTest(x: A | B) { + if ("a" in x) { + x.b = "1"; + } else { + x.a = "1"; + } +} + +function positiveClassesTest(x: A | B) { + if ("a" in x) { + x.b = "1"; + } else { + x.a = "1"; + } +} + +class AWithOptionalProp { a?: string; } +class BWithOptionalProp { b?: string; } + +function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) { + if ("a" in x) { + x.a = "1"; + } else { + x.b = "1"; + } +} + +class AWithMethod { + a(): string { return ""; } +} + +class BWithMethod { + b(): string { return ""; } +} + +function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) { + if ("a" in x) { + x.a(); + x.b(); + } else { + } +} + +function negativeTestClassesWithMemberMissingInBothClasses(x: AWithMethod | BWithMethod) { + if ("c" in x) { + x.a(); + x.b(); + } else { + x.a(); + x.b(); + } +} + +class C { a: string; } +class D { a: string; } + +function negativeMultipleClassesTest(x: A | B | C | D) { + if ("a" in x) { + x.b = "1"; + } else { + x.a = "1"; + } +} + +class ClassWithUnionProp { prop: A | B } + +function negativePropTest(x: ClassWithUnionProp) { + if ("a" in x.prop) { + let y: string = x.prop.b; + } else { + let z: string = x.prop.a; + } +} + +class NegativeClassTest { + protected prop: A | B; + inThis() { + if ("a" in this.prop) { + let z: number = this.prop.b; + } else { + let y: string = this.prop.a; + } + } +} + +class UnreachableCodeDetection { + a: string; + inThis() { + if ("a" in this) { + } else { + let y = this.a; + } + } +} + +//// [inKeywordTypeguard.js] +var A = /** @class */ (function () { + function A() { + } + return A; +}()); +var B = /** @class */ (function () { + function B() { + } + return B; +}()); +function negativeClassesTest(x) { + if ("a" in x) { + x.b = "1"; + } + else { + x.a = "1"; + } +} +function positiveClassesTest(x) { + if ("a" in x) { + x.b = "1"; + } + else { + x.a = "1"; + } +} +var AWithOptionalProp = /** @class */ (function () { + function AWithOptionalProp() { + } + return AWithOptionalProp; +}()); +var BWithOptionalProp = /** @class */ (function () { + function BWithOptionalProp() { + } + return BWithOptionalProp; +}()); +function positiveTestClassesWithOptionalProperties(x) { + if ("a" in x) { + x.a = "1"; + } + else { + x.b = "1"; + } +} +var AWithMethod = /** @class */ (function () { + function AWithMethod() { + } + AWithMethod.prototype.a = function () { return ""; }; + return AWithMethod; +}()); +var BWithMethod = /** @class */ (function () { + function BWithMethod() { + } + BWithMethod.prototype.b = function () { return ""; }; + return BWithMethod; +}()); +function negativeTestClassesWithMembers(x) { + if ("a" in x) { + x.a(); + x.b(); + } + else { + } +} +function negativeTestClassesWithMemberMissingInBothClasses(x) { + if ("c" in x) { + x.a(); + x.b(); + } + else { + x.a(); + x.b(); + } +} +var C = /** @class */ (function () { + function C() { + } + return C; +}()); +var D = /** @class */ (function () { + function D() { + } + return D; +}()); +function negativeMultipleClassesTest(x) { + if ("a" in x) { + x.b = "1"; + } + else { + x.a = "1"; + } +} +var ClassWithUnionProp = /** @class */ (function () { + function ClassWithUnionProp() { + } + return ClassWithUnionProp; +}()); +function negativePropTest(x) { + if ("a" in x.prop) { + var y = x.prop.b; + } + else { + var z = x.prop.a; + } +} +var NegativeClassTest = /** @class */ (function () { + function NegativeClassTest() { + } + NegativeClassTest.prototype.inThis = function () { + if ("a" in this.prop) { + var z = this.prop.b; + } + else { + var y = this.prop.a; + } + }; + return NegativeClassTest; +}()); +var UnreachableCodeDetection = /** @class */ (function () { + function UnreachableCodeDetection() { + } + UnreachableCodeDetection.prototype.inThis = function () { + if ("a" in this) { + } + else { + var y = this.a; + } + }; + return UnreachableCodeDetection; +}()); diff --git a/tests/baselines/reference/inKeywordTypeguard.symbols b/tests/baselines/reference/inKeywordTypeguard.symbols new file mode 100644 index 0000000000..c73f6f4901 --- /dev/null +++ b/tests/baselines/reference/inKeywordTypeguard.symbols @@ -0,0 +1,241 @@ +=== tests/cases/compiler/inKeywordTypeguard.ts === +class A { a: string; } +>A : Symbol(A, Decl(inKeywordTypeguard.ts, 0, 0)) +>a : Symbol(A.a, Decl(inKeywordTypeguard.ts, 0, 9)) + +class B { b: string; } +>B : Symbol(B, Decl(inKeywordTypeguard.ts, 0, 22)) +>b : Symbol(B.b, Decl(inKeywordTypeguard.ts, 1, 9)) + +function negativeClassesTest(x: A | B) { +>negativeClassesTest : Symbol(negativeClassesTest, Decl(inKeywordTypeguard.ts, 1, 22)) +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 3, 29)) +>A : Symbol(A, Decl(inKeywordTypeguard.ts, 0, 0)) +>B : Symbol(B, Decl(inKeywordTypeguard.ts, 0, 22)) + + if ("a" in x) { +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 3, 29)) + + x.b = "1"; +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 3, 29)) + + } else { + x.a = "1"; +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 3, 29)) + } +} + +function positiveClassesTest(x: A | B) { +>positiveClassesTest : Symbol(positiveClassesTest, Decl(inKeywordTypeguard.ts, 9, 1)) +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 11, 29)) +>A : Symbol(A, Decl(inKeywordTypeguard.ts, 0, 0)) +>B : Symbol(B, Decl(inKeywordTypeguard.ts, 0, 22)) + + if ("a" in x) { +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 11, 29)) + + x.b = "1"; +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 11, 29)) + + } else { + x.a = "1"; +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 11, 29)) + } +} + +class AWithOptionalProp { a?: string; } +>AWithOptionalProp : Symbol(AWithOptionalProp, Decl(inKeywordTypeguard.ts, 17, 1)) +>a : Symbol(AWithOptionalProp.a, Decl(inKeywordTypeguard.ts, 19, 25)) + +class BWithOptionalProp { b?: string; } +>BWithOptionalProp : Symbol(BWithOptionalProp, Decl(inKeywordTypeguard.ts, 19, 39)) +>b : Symbol(BWithOptionalProp.b, Decl(inKeywordTypeguard.ts, 20, 25)) + +function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) { +>positiveTestClassesWithOptionalProperties : Symbol(positiveTestClassesWithOptionalProperties, Decl(inKeywordTypeguard.ts, 20, 39)) +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 22, 51)) +>AWithOptionalProp : Symbol(AWithOptionalProp, Decl(inKeywordTypeguard.ts, 17, 1)) +>BWithOptionalProp : Symbol(BWithOptionalProp, Decl(inKeywordTypeguard.ts, 19, 39)) + + if ("a" in x) { +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 22, 51)) + + x.a = "1"; +>x.a : Symbol(AWithOptionalProp.a, Decl(inKeywordTypeguard.ts, 19, 25)) +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 22, 51)) +>a : Symbol(AWithOptionalProp.a, Decl(inKeywordTypeguard.ts, 19, 25)) + + } else { + x.b = "1"; +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 22, 51)) + } +} + +class AWithMethod { +>AWithMethod : Symbol(AWithMethod, Decl(inKeywordTypeguard.ts, 28, 1)) + + a(): string { return ""; } +>a : Symbol(AWithMethod.a, Decl(inKeywordTypeguard.ts, 30, 19)) +} + +class BWithMethod { +>BWithMethod : Symbol(BWithMethod, Decl(inKeywordTypeguard.ts, 32, 1)) + + b(): string { return ""; } +>b : Symbol(BWithMethod.b, Decl(inKeywordTypeguard.ts, 34, 19)) +} + +function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) { +>negativeTestClassesWithMembers : Symbol(negativeTestClassesWithMembers, Decl(inKeywordTypeguard.ts, 36, 1)) +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 38, 40)) +>AWithMethod : Symbol(AWithMethod, Decl(inKeywordTypeguard.ts, 28, 1)) +>BWithMethod : Symbol(BWithMethod, Decl(inKeywordTypeguard.ts, 32, 1)) + + if ("a" in x) { +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 38, 40)) + + x.a(); +>x.a : Symbol(AWithMethod.a, Decl(inKeywordTypeguard.ts, 30, 19)) +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 38, 40)) +>a : Symbol(AWithMethod.a, Decl(inKeywordTypeguard.ts, 30, 19)) + + x.b(); +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 38, 40)) + + } else { + } +} + +function negativeTestClassesWithMemberMissingInBothClasses(x: AWithMethod | BWithMethod) { +>negativeTestClassesWithMemberMissingInBothClasses : Symbol(negativeTestClassesWithMemberMissingInBothClasses, Decl(inKeywordTypeguard.ts, 44, 1)) +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 46, 59)) +>AWithMethod : Symbol(AWithMethod, Decl(inKeywordTypeguard.ts, 28, 1)) +>BWithMethod : Symbol(BWithMethod, Decl(inKeywordTypeguard.ts, 32, 1)) + + if ("c" in x) { +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 46, 59)) + + x.a(); +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 46, 59)) + + x.b(); +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 46, 59)) + + } else { + x.a(); +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 46, 59)) + + x.b(); +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 46, 59)) + } +} + +class C { a: string; } +>C : Symbol(C, Decl(inKeywordTypeguard.ts, 54, 1)) +>a : Symbol(C.a, Decl(inKeywordTypeguard.ts, 56, 9)) + +class D { a: string; } +>D : Symbol(D, Decl(inKeywordTypeguard.ts, 56, 22)) +>a : Symbol(D.a, Decl(inKeywordTypeguard.ts, 57, 9)) + +function negativeMultipleClassesTest(x: A | B | C | D) { +>negativeMultipleClassesTest : Symbol(negativeMultipleClassesTest, Decl(inKeywordTypeguard.ts, 57, 22)) +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 59, 37)) +>A : Symbol(A, Decl(inKeywordTypeguard.ts, 0, 0)) +>B : Symbol(B, Decl(inKeywordTypeguard.ts, 0, 22)) +>C : Symbol(C, Decl(inKeywordTypeguard.ts, 54, 1)) +>D : Symbol(D, Decl(inKeywordTypeguard.ts, 56, 22)) + + if ("a" in x) { +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 59, 37)) + + x.b = "1"; +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 59, 37)) + + } else { + x.a = "1"; +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 59, 37)) + } +} + +class ClassWithUnionProp { prop: A | B } +>ClassWithUnionProp : Symbol(ClassWithUnionProp, Decl(inKeywordTypeguard.ts, 65, 1)) +>prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26)) +>A : Symbol(A, Decl(inKeywordTypeguard.ts, 0, 0)) +>B : Symbol(B, Decl(inKeywordTypeguard.ts, 0, 22)) + +function negativePropTest(x: ClassWithUnionProp) { +>negativePropTest : Symbol(negativePropTest, Decl(inKeywordTypeguard.ts, 67, 40)) +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 69, 26)) +>ClassWithUnionProp : Symbol(ClassWithUnionProp, Decl(inKeywordTypeguard.ts, 65, 1)) + + if ("a" in x.prop) { +>x.prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26)) +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 69, 26)) +>prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26)) + + let y: string = x.prop.b; +>y : Symbol(y, Decl(inKeywordTypeguard.ts, 71, 11)) +>x.prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26)) +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 69, 26)) +>prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26)) + + } else { + let z: string = x.prop.a; +>z : Symbol(z, Decl(inKeywordTypeguard.ts, 73, 11)) +>x.prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26)) +>x : Symbol(x, Decl(inKeywordTypeguard.ts, 69, 26)) +>prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26)) + } +} + +class NegativeClassTest { +>NegativeClassTest : Symbol(NegativeClassTest, Decl(inKeywordTypeguard.ts, 75, 1)) + + protected prop: A | B; +>prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25)) +>A : Symbol(A, Decl(inKeywordTypeguard.ts, 0, 0)) +>B : Symbol(B, Decl(inKeywordTypeguard.ts, 0, 22)) + + inThis() { +>inThis : Symbol(NegativeClassTest.inThis, Decl(inKeywordTypeguard.ts, 78, 26)) + + if ("a" in this.prop) { +>this.prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25)) +>this : Symbol(NegativeClassTest, Decl(inKeywordTypeguard.ts, 75, 1)) +>prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25)) + + let z: number = this.prop.b; +>z : Symbol(z, Decl(inKeywordTypeguard.ts, 81, 15)) +>this.prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25)) +>this : Symbol(NegativeClassTest, Decl(inKeywordTypeguard.ts, 75, 1)) +>prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25)) + + } else { + let y: string = this.prop.a; +>y : Symbol(y, Decl(inKeywordTypeguard.ts, 83, 15)) +>this.prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25)) +>this : Symbol(NegativeClassTest, Decl(inKeywordTypeguard.ts, 75, 1)) +>prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25)) + } + } +} + +class UnreachableCodeDetection { +>UnreachableCodeDetection : Symbol(UnreachableCodeDetection, Decl(inKeywordTypeguard.ts, 86, 1)) + + a: string; +>a : Symbol(UnreachableCodeDetection.a, Decl(inKeywordTypeguard.ts, 88, 32)) + + inThis() { +>inThis : Symbol(UnreachableCodeDetection.inThis, Decl(inKeywordTypeguard.ts, 89, 14)) + + if ("a" in this) { +>this : Symbol(UnreachableCodeDetection, Decl(inKeywordTypeguard.ts, 86, 1)) + + } else { + let y = this.a; +>y : Symbol(y, Decl(inKeywordTypeguard.ts, 93, 15)) + } + } +} diff --git a/tests/baselines/reference/inKeywordTypeguard.types b/tests/baselines/reference/inKeywordTypeguard.types new file mode 100644 index 0000000000..3f9e8fd063 --- /dev/null +++ b/tests/baselines/reference/inKeywordTypeguard.types @@ -0,0 +1,318 @@ +=== tests/cases/compiler/inKeywordTypeguard.ts === +class A { a: string; } +>A : A +>a : string + +class B { b: string; } +>B : B +>b : string + +function negativeClassesTest(x: A | B) { +>negativeClassesTest : (x: A | B) => void +>x : A | B +>A : A +>B : B + + if ("a" in x) { +>"a" in x : boolean +>"a" : "a" +>x : A | B + + x.b = "1"; +>x.b = "1" : "1" +>x.b : any +>x : A +>b : any +>"1" : "1" + + } else { + x.a = "1"; +>x.a = "1" : "1" +>x.a : any +>x : B +>a : any +>"1" : "1" + } +} + +function positiveClassesTest(x: A | B) { +>positiveClassesTest : (x: A | B) => void +>x : A | B +>A : A +>B : B + + if ("a" in x) { +>"a" in x : boolean +>"a" : "a" +>x : A | B + + x.b = "1"; +>x.b = "1" : "1" +>x.b : any +>x : A +>b : any +>"1" : "1" + + } else { + x.a = "1"; +>x.a = "1" : "1" +>x.a : any +>x : B +>a : any +>"1" : "1" + } +} + +class AWithOptionalProp { a?: string; } +>AWithOptionalProp : AWithOptionalProp +>a : string + +class BWithOptionalProp { b?: string; } +>BWithOptionalProp : BWithOptionalProp +>b : string + +function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) { +>positiveTestClassesWithOptionalProperties : (x: AWithOptionalProp | BWithOptionalProp) => void +>x : AWithOptionalProp | BWithOptionalProp +>AWithOptionalProp : AWithOptionalProp +>BWithOptionalProp : BWithOptionalProp + + if ("a" in x) { +>"a" in x : boolean +>"a" : "a" +>x : AWithOptionalProp | BWithOptionalProp + + x.a = "1"; +>x.a = "1" : "1" +>x.a : string +>x : AWithOptionalProp +>a : string +>"1" : "1" + + } else { + x.b = "1"; +>x.b = "1" : "1" +>x.b : any +>x : AWithOptionalProp | BWithOptionalProp +>b : any +>"1" : "1" + } +} + +class AWithMethod { +>AWithMethod : AWithMethod + + a(): string { return ""; } +>a : () => string +>"" : "" +} + +class BWithMethod { +>BWithMethod : BWithMethod + + b(): string { return ""; } +>b : () => string +>"" : "" +} + +function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) { +>negativeTestClassesWithMembers : (x: AWithMethod | BWithMethod) => void +>x : AWithMethod | BWithMethod +>AWithMethod : AWithMethod +>BWithMethod : BWithMethod + + if ("a" in x) { +>"a" in x : boolean +>"a" : "a" +>x : AWithMethod | BWithMethod + + x.a(); +>x.a() : string +>x.a : () => string +>x : AWithMethod +>a : () => string + + x.b(); +>x.b() : any +>x.b : any +>x : AWithMethod +>b : any + + } else { + } +} + +function negativeTestClassesWithMemberMissingInBothClasses(x: AWithMethod | BWithMethod) { +>negativeTestClassesWithMemberMissingInBothClasses : (x: AWithMethod | BWithMethod) => void +>x : AWithMethod | BWithMethod +>AWithMethod : AWithMethod +>BWithMethod : BWithMethod + + if ("c" in x) { +>"c" in x : boolean +>"c" : "c" +>x : AWithMethod | BWithMethod + + x.a(); +>x.a() : any +>x.a : any +>x : never +>a : any + + x.b(); +>x.b() : any +>x.b : any +>x : never +>b : any + + } else { + x.a(); +>x.a() : any +>x.a : any +>x : AWithMethod | BWithMethod +>a : any + + x.b(); +>x.b() : any +>x.b : any +>x : AWithMethod | BWithMethod +>b : any + } +} + +class C { a: string; } +>C : C +>a : string + +class D { a: string; } +>D : D +>a : string + +function negativeMultipleClassesTest(x: A | B | C | D) { +>negativeMultipleClassesTest : (x: A | B | C | D) => void +>x : A | B | C | D +>A : A +>B : B +>C : C +>D : D + + if ("a" in x) { +>"a" in x : boolean +>"a" : "a" +>x : A | B | C | D + + x.b = "1"; +>x.b = "1" : "1" +>x.b : any +>x : A | C | D +>b : any +>"1" : "1" + + } else { + x.a = "1"; +>x.a = "1" : "1" +>x.a : any +>x : B +>a : any +>"1" : "1" + } +} + +class ClassWithUnionProp { prop: A | B } +>ClassWithUnionProp : ClassWithUnionProp +>prop : A | B +>A : A +>B : B + +function negativePropTest(x: ClassWithUnionProp) { +>negativePropTest : (x: ClassWithUnionProp) => void +>x : ClassWithUnionProp +>ClassWithUnionProp : ClassWithUnionProp + + if ("a" in x.prop) { +>"a" in x.prop : boolean +>"a" : "a" +>x.prop : A | B +>x : ClassWithUnionProp +>prop : A | B + + let y: string = x.prop.b; +>y : string +>x.prop.b : any +>x.prop : A +>x : ClassWithUnionProp +>prop : A +>b : any + + } else { + let z: string = x.prop.a; +>z : string +>x.prop.a : any +>x.prop : B +>x : ClassWithUnionProp +>prop : B +>a : any + } +} + +class NegativeClassTest { +>NegativeClassTest : NegativeClassTest + + protected prop: A | B; +>prop : A | B +>A : A +>B : B + + inThis() { +>inThis : () => void + + if ("a" in this.prop) { +>"a" in this.prop : boolean +>"a" : "a" +>this.prop : A | B +>this : this +>prop : A | B + + let z: number = this.prop.b; +>z : number +>this.prop.b : any +>this.prop : A +>this : this +>prop : A +>b : any + + } else { + let y: string = this.prop.a; +>y : string +>this.prop.a : any +>this.prop : B +>this : this +>prop : B +>a : any + } + } +} + +class UnreachableCodeDetection { +>UnreachableCodeDetection : UnreachableCodeDetection + + a: string; +>a : string + + inThis() { +>inThis : () => void + + if ("a" in this) { +>"a" in this : boolean +>"a" : "a" +>this : this + + } else { + let y = this.a; +>y : any +>this.a : any +>this : never +>a : any + } + } +} diff --git a/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.js b/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.js new file mode 100644 index 0000000000..a257932864 --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.js @@ -0,0 +1,218 @@ +//// [typeGuardOfFromPropNameInUnionType.ts] +class A { a: string; } +class B { b: number; } +class C { b: Object; } +class D { a: Date; } + +function namedClasses(x: A | B) { + if ("a" in x) { + x.a = "1"; + } else { + x.b = 1; + } +} + +function multipleClasses(x: A | B | C | D) { + if ("a" in x) { + let y: string | Date = x.a; + } else { + let z: number | Object = x.b; + } +} + +function anonymousClasses(x: { a: string; } | { b: number; }) { + if ("a" in x) { + let y: string = x.a; + } else { + let z: number = x.b; + } +} + +class AWithOptionalProp { a?: string; } +class BWithOptionalProp { b?: string; } + +function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) { + if ("a" in x) { + x.a = "1"; + } else { + const y: string = x instanceof AWithOptionalProp + ? x.a + : x.b + } +} + +function inParenthesizedExpression(x: A | B) { + if ("a" in (x)) { + let y: string = x.a; + } else { + let z: number = x.b; + } +} + +class ClassWithUnionProp { prop: A | B; } + +function inProperty(x: ClassWithUnionProp) { + if ("a" in x.prop) { + let y: string = x.prop.a; + } else { + let z: number = x.prop.b; + } +} + +class NestedClassWithProp { outer: ClassWithUnionProp; } + +function innestedProperty(x: NestedClassWithProp) { + if ("a" in x.outer.prop) { + let y: string = x.outer.prop.a; + } else { + let z: number = x.outer.prop.b; + } +} + +class InMemberOfClass { + protected prop: A | B; + inThis() { + if ("a" in this.prop) { + let y: string = this.prop.a; + } else { + let z: number = this.prop.b; + } + } +} + +// added for completeness +class SelfAssert { + a: string; + inThis() { + if ("a" in this) { + let y: string = this.a; + } else { + } + } +} + +//// [typeGuardOfFromPropNameInUnionType.js] +var A = /** @class */ (function () { + function A() { + } + return A; +}()); +var B = /** @class */ (function () { + function B() { + } + return B; +}()); +var C = /** @class */ (function () { + function C() { + } + return C; +}()); +var D = /** @class */ (function () { + function D() { + } + return D; +}()); +function namedClasses(x) { + if ("a" in x) { + x.a = "1"; + } + else { + x.b = 1; + } +} +function multipleClasses(x) { + if ("a" in x) { + var y = x.a; + } + else { + var z = x.b; + } +} +function anonymousClasses(x) { + if ("a" in x) { + var y = x.a; + } + else { + var z = x.b; + } +} +var AWithOptionalProp = /** @class */ (function () { + function AWithOptionalProp() { + } + return AWithOptionalProp; +}()); +var BWithOptionalProp = /** @class */ (function () { + function BWithOptionalProp() { + } + return BWithOptionalProp; +}()); +function positiveTestClassesWithOptionalProperties(x) { + if ("a" in x) { + x.a = "1"; + } + else { + var y = x instanceof AWithOptionalProp + ? x.a + : x.b; + } +} +function inParenthesizedExpression(x) { + if ("a" in (x)) { + var y = x.a; + } + else { + var z = x.b; + } +} +var ClassWithUnionProp = /** @class */ (function () { + function ClassWithUnionProp() { + } + return ClassWithUnionProp; +}()); +function inProperty(x) { + if ("a" in x.prop) { + var y = x.prop.a; + } + else { + var z = x.prop.b; + } +} +var NestedClassWithProp = /** @class */ (function () { + function NestedClassWithProp() { + } + return NestedClassWithProp; +}()); +function innestedProperty(x) { + if ("a" in x.outer.prop) { + var y = x.outer.prop.a; + } + else { + var z = x.outer.prop.b; + } +} +var InMemberOfClass = /** @class */ (function () { + function InMemberOfClass() { + } + InMemberOfClass.prototype.inThis = function () { + if ("a" in this.prop) { + var y = this.prop.a; + } + else { + var z = this.prop.b; + } + }; + return InMemberOfClass; +}()); +// added for completeness +var SelfAssert = /** @class */ (function () { + function SelfAssert() { + } + SelfAssert.prototype.inThis = function () { + if ("a" in this) { + var y = this.a; + } + else { + } + }; + return SelfAssert; +}()); diff --git a/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.symbols b/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.symbols new file mode 100644 index 0000000000..72fb3df2fc --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.symbols @@ -0,0 +1,291 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFromPropNameInUnionType.ts === +class A { a: string; } +>A : Symbol(A, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 0)) +>a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) + +class B { b: number; } +>B : Symbol(B, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 22)) +>b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) + +class C { b: Object; } +>C : Symbol(C, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 22)) +>b : Symbol(C.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 2, 9)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +class D { a: Date; } +>D : Symbol(D, Decl(typeGuardOfFromPropNameInUnionType.ts, 2, 22)) +>a : Symbol(D.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 3, 9)) +>Date : Symbol(Date, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +function namedClasses(x: A | B) { +>namedClasses : Symbol(namedClasses, Decl(typeGuardOfFromPropNameInUnionType.ts, 3, 20)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 5, 22)) +>A : Symbol(A, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 0)) +>B : Symbol(B, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 22)) + + if ("a" in x) { +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 5, 22)) + + x.a = "1"; +>x.a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 5, 22)) +>a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) + + } else { + x.b = 1; +>x.b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 5, 22)) +>b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) + } +} + +function multipleClasses(x: A | B | C | D) { +>multipleClasses : Symbol(multipleClasses, Decl(typeGuardOfFromPropNameInUnionType.ts, 11, 1)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 13, 25)) +>A : Symbol(A, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 0)) +>B : Symbol(B, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 22)) +>C : Symbol(C, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 22)) +>D : Symbol(D, Decl(typeGuardOfFromPropNameInUnionType.ts, 2, 22)) + + if ("a" in x) { +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 13, 25)) + + let y: string | Date = x.a; +>y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 15, 11)) +>Date : Symbol(Date, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>x.a : Symbol(a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9), Decl(typeGuardOfFromPropNameInUnionType.ts, 3, 9)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 13, 25)) +>a : Symbol(a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9), Decl(typeGuardOfFromPropNameInUnionType.ts, 3, 9)) + + } else { + let z: number | Object = x.b; +>z : Symbol(z, Decl(typeGuardOfFromPropNameInUnionType.ts, 17, 11)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>x.b : Symbol(b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9), Decl(typeGuardOfFromPropNameInUnionType.ts, 2, 9)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 13, 25)) +>b : Symbol(b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9), Decl(typeGuardOfFromPropNameInUnionType.ts, 2, 9)) + } +} + +function anonymousClasses(x: { a: string; } | { b: number; }) { +>anonymousClasses : Symbol(anonymousClasses, Decl(typeGuardOfFromPropNameInUnionType.ts, 19, 1)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 26)) +>a : Symbol(a, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 30)) +>b : Symbol(b, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 47)) + + if ("a" in x) { +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 26)) + + let y: string = x.a; +>y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 23, 11)) +>x.a : Symbol(a, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 30)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 26)) +>a : Symbol(a, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 30)) + + } else { + let z: number = x.b; +>z : Symbol(z, Decl(typeGuardOfFromPropNameInUnionType.ts, 25, 11)) +>x.b : Symbol(b, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 47)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 26)) +>b : Symbol(b, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 47)) + } +} + +class AWithOptionalProp { a?: string; } +>AWithOptionalProp : Symbol(AWithOptionalProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 27, 1)) +>a : Symbol(AWithOptionalProp.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 29, 25)) + +class BWithOptionalProp { b?: string; } +>BWithOptionalProp : Symbol(BWithOptionalProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 29, 39)) +>b : Symbol(BWithOptionalProp.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 30, 25)) + +function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) { +>positiveTestClassesWithOptionalProperties : Symbol(positiveTestClassesWithOptionalProperties, Decl(typeGuardOfFromPropNameInUnionType.ts, 30, 39)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 32, 51)) +>AWithOptionalProp : Symbol(AWithOptionalProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 27, 1)) +>BWithOptionalProp : Symbol(BWithOptionalProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 29, 39)) + + if ("a" in x) { +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 32, 51)) + + x.a = "1"; +>x.a : Symbol(AWithOptionalProp.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 29, 25)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 32, 51)) +>a : Symbol(AWithOptionalProp.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 29, 25)) + + } else { + const y: string = x instanceof AWithOptionalProp +>y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 36, 13)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 32, 51)) +>AWithOptionalProp : Symbol(AWithOptionalProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 27, 1)) + + ? x.a +>x.a : Symbol(AWithOptionalProp.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 29, 25)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 32, 51)) +>a : Symbol(AWithOptionalProp.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 29, 25)) + + : x.b +>x.b : Symbol(BWithOptionalProp.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 30, 25)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 32, 51)) +>b : Symbol(BWithOptionalProp.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 30, 25)) + } +} + +function inParenthesizedExpression(x: A | B) { +>inParenthesizedExpression : Symbol(inParenthesizedExpression, Decl(typeGuardOfFromPropNameInUnionType.ts, 40, 1)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 42, 35)) +>A : Symbol(A, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 0)) +>B : Symbol(B, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 22)) + + if ("a" in (x)) { +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 42, 35)) + + let y: string = x.a; +>y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 44, 11)) +>x.a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 42, 35)) +>a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) + + } else { + let z: number = x.b; +>z : Symbol(z, Decl(typeGuardOfFromPropNameInUnionType.ts, 46, 11)) +>x.b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 42, 35)) +>b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) + } +} + +class ClassWithUnionProp { prop: A | B; } +>ClassWithUnionProp : Symbol(ClassWithUnionProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 48, 1)) +>prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) +>A : Symbol(A, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 0)) +>B : Symbol(B, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 22)) + +function inProperty(x: ClassWithUnionProp) { +>inProperty : Symbol(inProperty, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 41)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 52, 20)) +>ClassWithUnionProp : Symbol(ClassWithUnionProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 48, 1)) + + if ("a" in x.prop) { +>x.prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 52, 20)) +>prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) + + let y: string = x.prop.a; +>y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 54, 11)) +>x.prop.a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) +>x.prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 52, 20)) +>prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) +>a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) + + } else { + let z: number = x.prop.b; +>z : Symbol(z, Decl(typeGuardOfFromPropNameInUnionType.ts, 56, 11)) +>x.prop.b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) +>x.prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 52, 20)) +>prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) +>b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) + } +} + +class NestedClassWithProp { outer: ClassWithUnionProp; } +>NestedClassWithProp : Symbol(NestedClassWithProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 58, 1)) +>outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 60, 27)) +>ClassWithUnionProp : Symbol(ClassWithUnionProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 48, 1)) + +function innestedProperty(x: NestedClassWithProp) { +>innestedProperty : Symbol(innestedProperty, Decl(typeGuardOfFromPropNameInUnionType.ts, 60, 56)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 62, 26)) +>NestedClassWithProp : Symbol(NestedClassWithProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 58, 1)) + + if ("a" in x.outer.prop) { +>x.outer.prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) +>x.outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 60, 27)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 62, 26)) +>outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 60, 27)) +>prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) + + let y: string = x.outer.prop.a; +>y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 64, 11)) +>x.outer.prop.a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) +>x.outer.prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) +>x.outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 60, 27)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 62, 26)) +>outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 60, 27)) +>prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) +>a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) + + } else { + let z: number = x.outer.prop.b; +>z : Symbol(z, Decl(typeGuardOfFromPropNameInUnionType.ts, 66, 11)) +>x.outer.prop.b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) +>x.outer.prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) +>x.outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 60, 27)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 62, 26)) +>outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 60, 27)) +>prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) +>b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) + } +} + +class InMemberOfClass { +>InMemberOfClass : Symbol(InMemberOfClass, Decl(typeGuardOfFromPropNameInUnionType.ts, 68, 1)) + + protected prop: A | B; +>prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 70, 23)) +>A : Symbol(A, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 0)) +>B : Symbol(B, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 22)) + + inThis() { +>inThis : Symbol(InMemberOfClass.inThis, Decl(typeGuardOfFromPropNameInUnionType.ts, 71, 26)) + + if ("a" in this.prop) { +>this.prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 70, 23)) +>this : Symbol(InMemberOfClass, Decl(typeGuardOfFromPropNameInUnionType.ts, 68, 1)) +>prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 70, 23)) + + let y: string = this.prop.a; +>y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 74, 15)) +>this.prop.a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) +>this.prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 70, 23)) +>this : Symbol(InMemberOfClass, Decl(typeGuardOfFromPropNameInUnionType.ts, 68, 1)) +>prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 70, 23)) +>a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) + + } else { + let z: number = this.prop.b; +>z : Symbol(z, Decl(typeGuardOfFromPropNameInUnionType.ts, 76, 15)) +>this.prop.b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) +>this.prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 70, 23)) +>this : Symbol(InMemberOfClass, Decl(typeGuardOfFromPropNameInUnionType.ts, 68, 1)) +>prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 70, 23)) +>b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) + } + } +} + +// added for completeness +class SelfAssert { +>SelfAssert : Symbol(SelfAssert, Decl(typeGuardOfFromPropNameInUnionType.ts, 79, 1)) + + a: string; +>a : Symbol(SelfAssert.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 82, 18)) + + inThis() { +>inThis : Symbol(SelfAssert.inThis, Decl(typeGuardOfFromPropNameInUnionType.ts, 83, 14)) + + if ("a" in this) { +>this : Symbol(SelfAssert, Decl(typeGuardOfFromPropNameInUnionType.ts, 79, 1)) + + let y: string = this.a; +>y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 86, 15)) +>this.a : Symbol(SelfAssert.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 82, 18)) +>this : Symbol(SelfAssert, Decl(typeGuardOfFromPropNameInUnionType.ts, 79, 1)) +>a : Symbol(SelfAssert.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 82, 18)) + + } else { + } + } +} diff --git a/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.types b/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.types new file mode 100644 index 0000000000..4aff12ae07 --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.types @@ -0,0 +1,318 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFromPropNameInUnionType.ts === +class A { a: string; } +>A : A +>a : string + +class B { b: number; } +>B : B +>b : number + +class C { b: Object; } +>C : C +>b : Object +>Object : Object + +class D { a: Date; } +>D : D +>a : Date +>Date : Date + +function namedClasses(x: A | B) { +>namedClasses : (x: A | B) => void +>x : A | B +>A : A +>B : B + + if ("a" in x) { +>"a" in x : boolean +>"a" : "a" +>x : A | B + + x.a = "1"; +>x.a = "1" : "1" +>x.a : string +>x : A +>a : string +>"1" : "1" + + } else { + x.b = 1; +>x.b = 1 : 1 +>x.b : number +>x : B +>b : number +>1 : 1 + } +} + +function multipleClasses(x: A | B | C | D) { +>multipleClasses : (x: A | B | C | D) => void +>x : A | B | C | D +>A : A +>B : B +>C : C +>D : D + + if ("a" in x) { +>"a" in x : boolean +>"a" : "a" +>x : A | B | C | D + + let y: string | Date = x.a; +>y : string | Date +>Date : Date +>x.a : string | Date +>x : A | D +>a : string | Date + + } else { + let z: number | Object = x.b; +>z : number | Object +>Object : Object +>x.b : number | Object +>x : B | C +>b : number | Object + } +} + +function anonymousClasses(x: { a: string; } | { b: number; }) { +>anonymousClasses : (x: { a: string; } | { b: number; }) => void +>x : { a: string; } | { b: number; } +>a : string +>b : number + + if ("a" in x) { +>"a" in x : boolean +>"a" : "a" +>x : { a: string; } | { b: number; } + + let y: string = x.a; +>y : string +>x.a : string +>x : { a: string; } +>a : string + + } else { + let z: number = x.b; +>z : number +>x.b : number +>x : { b: number; } +>b : number + } +} + +class AWithOptionalProp { a?: string; } +>AWithOptionalProp : AWithOptionalProp +>a : string + +class BWithOptionalProp { b?: string; } +>BWithOptionalProp : BWithOptionalProp +>b : string + +function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) { +>positiveTestClassesWithOptionalProperties : (x: AWithOptionalProp | BWithOptionalProp) => void +>x : AWithOptionalProp | BWithOptionalProp +>AWithOptionalProp : AWithOptionalProp +>BWithOptionalProp : BWithOptionalProp + + if ("a" in x) { +>"a" in x : boolean +>"a" : "a" +>x : AWithOptionalProp | BWithOptionalProp + + x.a = "1"; +>x.a = "1" : "1" +>x.a : string +>x : AWithOptionalProp +>a : string +>"1" : "1" + + } else { + const y: string = x instanceof AWithOptionalProp +>y : string +>x instanceof AWithOptionalProp ? x.a : x.b : string +>x instanceof AWithOptionalProp : boolean +>x : AWithOptionalProp | BWithOptionalProp +>AWithOptionalProp : typeof AWithOptionalProp + + ? x.a +>x.a : string +>x : AWithOptionalProp +>a : string + + : x.b +>x.b : string +>x : BWithOptionalProp +>b : string + } +} + +function inParenthesizedExpression(x: A | B) { +>inParenthesizedExpression : (x: A | B) => void +>x : A | B +>A : A +>B : B + + if ("a" in (x)) { +>"a" in (x) : boolean +>"a" : "a" +>(x) : A | B +>x : A | B + + let y: string = x.a; +>y : string +>x.a : string +>x : A +>a : string + + } else { + let z: number = x.b; +>z : number +>x.b : number +>x : B +>b : number + } +} + +class ClassWithUnionProp { prop: A | B; } +>ClassWithUnionProp : ClassWithUnionProp +>prop : A | B +>A : A +>B : B + +function inProperty(x: ClassWithUnionProp) { +>inProperty : (x: ClassWithUnionProp) => void +>x : ClassWithUnionProp +>ClassWithUnionProp : ClassWithUnionProp + + if ("a" in x.prop) { +>"a" in x.prop : boolean +>"a" : "a" +>x.prop : A | B +>x : ClassWithUnionProp +>prop : A | B + + let y: string = x.prop.a; +>y : string +>x.prop.a : string +>x.prop : A +>x : ClassWithUnionProp +>prop : A +>a : string + + } else { + let z: number = x.prop.b; +>z : number +>x.prop.b : number +>x.prop : B +>x : ClassWithUnionProp +>prop : B +>b : number + } +} + +class NestedClassWithProp { outer: ClassWithUnionProp; } +>NestedClassWithProp : NestedClassWithProp +>outer : ClassWithUnionProp +>ClassWithUnionProp : ClassWithUnionProp + +function innestedProperty(x: NestedClassWithProp) { +>innestedProperty : (x: NestedClassWithProp) => void +>x : NestedClassWithProp +>NestedClassWithProp : NestedClassWithProp + + if ("a" in x.outer.prop) { +>"a" in x.outer.prop : boolean +>"a" : "a" +>x.outer.prop : A | B +>x.outer : ClassWithUnionProp +>x : NestedClassWithProp +>outer : ClassWithUnionProp +>prop : A | B + + let y: string = x.outer.prop.a; +>y : string +>x.outer.prop.a : string +>x.outer.prop : A +>x.outer : ClassWithUnionProp +>x : NestedClassWithProp +>outer : ClassWithUnionProp +>prop : A +>a : string + + } else { + let z: number = x.outer.prop.b; +>z : number +>x.outer.prop.b : number +>x.outer.prop : B +>x.outer : ClassWithUnionProp +>x : NestedClassWithProp +>outer : ClassWithUnionProp +>prop : B +>b : number + } +} + +class InMemberOfClass { +>InMemberOfClass : InMemberOfClass + + protected prop: A | B; +>prop : A | B +>A : A +>B : B + + inThis() { +>inThis : () => void + + if ("a" in this.prop) { +>"a" in this.prop : boolean +>"a" : "a" +>this.prop : A | B +>this : this +>prop : A | B + + let y: string = this.prop.a; +>y : string +>this.prop.a : string +>this.prop : A +>this : this +>prop : A +>a : string + + } else { + let z: number = this.prop.b; +>z : number +>this.prop.b : number +>this.prop : B +>this : this +>prop : B +>b : number + } + } +} + +// added for completeness +class SelfAssert { +>SelfAssert : SelfAssert + + a: string; +>a : string + + inThis() { +>inThis : () => void + + if ("a" in this) { +>"a" in this : boolean +>"a" : "a" +>this : this + + let y: string = this.a; +>y : string +>this.a : string +>this : this +>a : string + + } else { + } + } +} diff --git a/tests/baselines/reference/typeInferenceTypePredicate.js b/tests/baselines/reference/typeInferenceTypePredicate.js new file mode 100644 index 0000000000..bcac004a20 --- /dev/null +++ b/tests/baselines/reference/typeInferenceTypePredicate.js @@ -0,0 +1,9 @@ +//// [typeInferenceTypePredicate.ts] +declare function f(predicate: (x: {}) => x is T): T; +// 'res' should be of type 'number'. +const res = f((n): n is number => true); + + +//// [typeInferenceTypePredicate.js] +// 'res' should be of type 'number'. +var res = f(function (n) { return true; }); diff --git a/tests/baselines/reference/typeInferenceTypePredicate.symbols b/tests/baselines/reference/typeInferenceTypePredicate.symbols new file mode 100644 index 0000000000..3c2172552e --- /dev/null +++ b/tests/baselines/reference/typeInferenceTypePredicate.symbols @@ -0,0 +1,17 @@ +=== tests/cases/compiler/typeInferenceTypePredicate.ts === +declare function f(predicate: (x: {}) => x is T): T; +>f : Symbol(f, Decl(typeInferenceTypePredicate.ts, 0, 0)) +>T : Symbol(T, Decl(typeInferenceTypePredicate.ts, 0, 19)) +>predicate : Symbol(predicate, Decl(typeInferenceTypePredicate.ts, 0, 22)) +>x : Symbol(x, Decl(typeInferenceTypePredicate.ts, 0, 34)) +>x : Symbol(x, Decl(typeInferenceTypePredicate.ts, 0, 34)) +>T : Symbol(T, Decl(typeInferenceTypePredicate.ts, 0, 19)) +>T : Symbol(T, Decl(typeInferenceTypePredicate.ts, 0, 19)) + +// 'res' should be of type 'number'. +const res = f((n): n is number => true); +>res : Symbol(res, Decl(typeInferenceTypePredicate.ts, 2, 5)) +>f : Symbol(f, Decl(typeInferenceTypePredicate.ts, 0, 0)) +>n : Symbol(n, Decl(typeInferenceTypePredicate.ts, 2, 15)) +>n : Symbol(n, Decl(typeInferenceTypePredicate.ts, 2, 15)) + diff --git a/tests/baselines/reference/typeInferenceTypePredicate.types b/tests/baselines/reference/typeInferenceTypePredicate.types new file mode 100644 index 0000000000..cb27009abe --- /dev/null +++ b/tests/baselines/reference/typeInferenceTypePredicate.types @@ -0,0 +1,20 @@ +=== tests/cases/compiler/typeInferenceTypePredicate.ts === +declare function f(predicate: (x: {}) => x is T): T; +>f : (predicate: (x: {}) => x is T) => T +>T : T +>predicate : (x: {}) => x is T +>x : {} +>x : any +>T : T +>T : T + +// 'res' should be of type 'number'. +const res = f((n): n is number => true); +>res : number +>f((n): n is number => true) : number +>f : (predicate: (x: {}) => x is T) => T +>(n): n is number => true : (n: {}) => n is number +>n : {} +>n : any +>true : true + diff --git a/tests/baselines/reference/typeInferenceTypePredicate2.js b/tests/baselines/reference/typeInferenceTypePredicate2.js new file mode 100644 index 0000000000..da40a12193 --- /dev/null +++ b/tests/baselines/reference/typeInferenceTypePredicate2.js @@ -0,0 +1,10 @@ +//// [typeInferenceTypePredicate2.ts] +[true, true, false, null] + .filter((thing): thing is boolean => thing !== null) + .map(thing => thing.toString()); + + +//// [typeInferenceTypePredicate2.js] +[true, true, false, null] + .filter(function (thing) { return thing !== null; }) + .map(function (thing) { return thing.toString(); }); diff --git a/tests/baselines/reference/typeInferenceTypePredicate2.symbols b/tests/baselines/reference/typeInferenceTypePredicate2.symbols new file mode 100644 index 0000000000..e0fb14a710 --- /dev/null +++ b/tests/baselines/reference/typeInferenceTypePredicate2.symbols @@ -0,0 +1,18 @@ +=== tests/cases/compiler/typeInferenceTypePredicate2.ts === +[true, true, false, null] +>[true, true, false, null] .filter((thing): thing is boolean => thing !== null) .map : Symbol(Array.map, Decl(lib.d.ts, --, --)) +>[true, true, false, null] .filter : Symbol(Array.filter, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + + .filter((thing): thing is boolean => thing !== null) +>filter : Symbol(Array.filter, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>thing : Symbol(thing, Decl(typeInferenceTypePredicate2.ts, 1, 13)) +>thing : Symbol(thing, Decl(typeInferenceTypePredicate2.ts, 1, 13)) +>thing : Symbol(thing, Decl(typeInferenceTypePredicate2.ts, 1, 13)) + + .map(thing => thing.toString()); +>map : Symbol(Array.map, Decl(lib.d.ts, --, --)) +>thing : Symbol(thing, Decl(typeInferenceTypePredicate2.ts, 2, 9)) +>thing.toString : Symbol(Object.toString, Decl(lib.d.ts, --, --)) +>thing : Symbol(thing, Decl(typeInferenceTypePredicate2.ts, 2, 9)) +>toString : Symbol(Object.toString, Decl(lib.d.ts, --, --)) + diff --git a/tests/baselines/reference/typeInferenceTypePredicate2.types b/tests/baselines/reference/typeInferenceTypePredicate2.types new file mode 100644 index 0000000000..ed153eb784 --- /dev/null +++ b/tests/baselines/reference/typeInferenceTypePredicate2.types @@ -0,0 +1,30 @@ +=== tests/cases/compiler/typeInferenceTypePredicate2.ts === +[true, true, false, null] +>[true, true, false, null] .filter((thing): thing is boolean => thing !== null) .map(thing => thing.toString()) : string[] +>[true, true, false, null] .filter((thing): thing is boolean => thing !== null) .map : (callbackfn: (value: boolean, index: number, array: boolean[]) => U, thisArg?: any) => U[] +>[true, true, false, null] .filter((thing): thing is boolean => thing !== null) : boolean[] +>[true, true, false, null] .filter : { (callbackfn: (value: boolean, index: number, array: boolean[]) => value is S, thisArg?: any): S[]; (callbackfn: (value: boolean, index: number, array: boolean[]) => any, thisArg?: any): boolean[]; } +>[true, true, false, null] : boolean[] +>true : true +>true : true +>false : false +>null : null + + .filter((thing): thing is boolean => thing !== null) +>filter : { (callbackfn: (value: boolean, index: number, array: boolean[]) => value is S, thisArg?: any): S[]; (callbackfn: (value: boolean, index: number, array: boolean[]) => any, thisArg?: any): boolean[]; } +>(thing): thing is boolean => thing !== null : (thing: boolean) => thing is boolean +>thing : boolean +>thing : any +>thing !== null : boolean +>thing : boolean +>null : null + + .map(thing => thing.toString()); +>map : (callbackfn: (value: boolean, index: number, array: boolean[]) => U, thisArg?: any) => U[] +>thing => thing.toString() : (thing: boolean) => string +>thing : boolean +>thing.toString() : string +>thing.toString : () => string +>thing : boolean +>toString : () => string + diff --git a/tests/baselines/reference/typePredicatesInUnion.js b/tests/baselines/reference/typePredicatesInUnion.js new file mode 100644 index 0000000000..4527455af6 --- /dev/null +++ b/tests/baselines/reference/typePredicatesInUnion.js @@ -0,0 +1,23 @@ +//// [typePredicatesInUnion.ts] +interface A { + pred(x: {}): x is boolean; +} +interface B { + pred(x: {}): x is string; +} + +type Or = A | B; + +function f(o: Or, x: {}) { + if (o.pred(x)) { + x; + } +} + + +//// [typePredicatesInUnion.js] +function f(o, x) { + if (o.pred(x)) { + x; + } +} diff --git a/tests/baselines/reference/typePredicatesInUnion.symbols b/tests/baselines/reference/typePredicatesInUnion.symbols new file mode 100644 index 0000000000..eb149af9e0 --- /dev/null +++ b/tests/baselines/reference/typePredicatesInUnion.symbols @@ -0,0 +1,40 @@ +=== tests/cases/compiler/typePredicatesInUnion.ts === +interface A { +>A : Symbol(A, Decl(typePredicatesInUnion.ts, 0, 0)) + + pred(x: {}): x is boolean; +>pred : Symbol(A.pred, Decl(typePredicatesInUnion.ts, 0, 13)) +>x : Symbol(x, Decl(typePredicatesInUnion.ts, 1, 9)) +>x : Symbol(x, Decl(typePredicatesInUnion.ts, 1, 9)) +} +interface B { +>B : Symbol(B, Decl(typePredicatesInUnion.ts, 2, 1)) + + pred(x: {}): x is string; +>pred : Symbol(B.pred, Decl(typePredicatesInUnion.ts, 3, 13)) +>x : Symbol(x, Decl(typePredicatesInUnion.ts, 4, 9)) +>x : Symbol(x, Decl(typePredicatesInUnion.ts, 4, 9)) +} + +type Or = A | B; +>Or : Symbol(Or, Decl(typePredicatesInUnion.ts, 5, 1)) +>A : Symbol(A, Decl(typePredicatesInUnion.ts, 0, 0)) +>B : Symbol(B, Decl(typePredicatesInUnion.ts, 2, 1)) + +function f(o: Or, x: {}) { +>f : Symbol(f, Decl(typePredicatesInUnion.ts, 7, 16)) +>o : Symbol(o, Decl(typePredicatesInUnion.ts, 9, 11)) +>Or : Symbol(Or, Decl(typePredicatesInUnion.ts, 5, 1)) +>x : Symbol(x, Decl(typePredicatesInUnion.ts, 9, 17)) + + if (o.pred(x)) { +>o.pred : Symbol(pred, Decl(typePredicatesInUnion.ts, 0, 13), Decl(typePredicatesInUnion.ts, 3, 13)) +>o : Symbol(o, Decl(typePredicatesInUnion.ts, 9, 11)) +>pred : Symbol(pred, Decl(typePredicatesInUnion.ts, 0, 13), Decl(typePredicatesInUnion.ts, 3, 13)) +>x : Symbol(x, Decl(typePredicatesInUnion.ts, 9, 17)) + + x; +>x : Symbol(x, Decl(typePredicatesInUnion.ts, 9, 17)) + } +} + diff --git a/tests/baselines/reference/typePredicatesInUnion.types b/tests/baselines/reference/typePredicatesInUnion.types new file mode 100644 index 0000000000..fee8fea68d --- /dev/null +++ b/tests/baselines/reference/typePredicatesInUnion.types @@ -0,0 +1,41 @@ +=== tests/cases/compiler/typePredicatesInUnion.ts === +interface A { +>A : A + + pred(x: {}): x is boolean; +>pred : (x: {}) => x is boolean +>x : {} +>x : any +} +interface B { +>B : B + + pred(x: {}): x is string; +>pred : (x: {}) => x is string +>x : {} +>x : any +} + +type Or = A | B; +>Or : Or +>A : A +>B : B + +function f(o: Or, x: {}) { +>f : (o: Or, x: {}) => void +>o : Or +>Or : Or +>x : {} + + if (o.pred(x)) { +>o.pred(x) : boolean +>o.pred : ((x: {}) => x is boolean) | ((x: {}) => x is string) +>o : Or +>pred : ((x: {}) => x is boolean) | ((x: {}) => x is string) +>x : {} + + x; +>x : string | boolean + } +} + diff --git a/tests/baselines/reference/typePredicatesInUnion2.js b/tests/baselines/reference/typePredicatesInUnion2.js new file mode 100644 index 0000000000..470abbe6b8 --- /dev/null +++ b/tests/baselines/reference/typePredicatesInUnion2.js @@ -0,0 +1,11 @@ +//// [typePredicatesInUnion2.ts] +declare function isString(x: any): x is string; +declare function isNumber(x: any): x is number; +declare function f(p: typeof isString | typeof isNumber): void; +f(isString); +f(isNumber); + + +//// [typePredicatesInUnion2.js] +f(isString); +f(isNumber); diff --git a/tests/baselines/reference/typePredicatesInUnion2.symbols b/tests/baselines/reference/typePredicatesInUnion2.symbols new file mode 100644 index 0000000000..dba593da89 --- /dev/null +++ b/tests/baselines/reference/typePredicatesInUnion2.symbols @@ -0,0 +1,25 @@ +=== tests/cases/compiler/typePredicatesInUnion2.ts === +declare function isString(x: any): x is string; +>isString : Symbol(isString, Decl(typePredicatesInUnion2.ts, 0, 0)) +>x : Symbol(x, Decl(typePredicatesInUnion2.ts, 0, 26)) +>x : Symbol(x, Decl(typePredicatesInUnion2.ts, 0, 26)) + +declare function isNumber(x: any): x is number; +>isNumber : Symbol(isNumber, Decl(typePredicatesInUnion2.ts, 0, 47)) +>x : Symbol(x, Decl(typePredicatesInUnion2.ts, 1, 26)) +>x : Symbol(x, Decl(typePredicatesInUnion2.ts, 1, 26)) + +declare function f(p: typeof isString | typeof isNumber): void; +>f : Symbol(f, Decl(typePredicatesInUnion2.ts, 1, 47)) +>p : Symbol(p, Decl(typePredicatesInUnion2.ts, 2, 19)) +>isString : Symbol(isString, Decl(typePredicatesInUnion2.ts, 0, 0)) +>isNumber : Symbol(isNumber, Decl(typePredicatesInUnion2.ts, 0, 47)) + +f(isString); +>f : Symbol(f, Decl(typePredicatesInUnion2.ts, 1, 47)) +>isString : Symbol(isString, Decl(typePredicatesInUnion2.ts, 0, 0)) + +f(isNumber); +>f : Symbol(f, Decl(typePredicatesInUnion2.ts, 1, 47)) +>isNumber : Symbol(isNumber, Decl(typePredicatesInUnion2.ts, 0, 47)) + diff --git a/tests/baselines/reference/typePredicatesInUnion2.types b/tests/baselines/reference/typePredicatesInUnion2.types new file mode 100644 index 0000000000..73ecf3f3e5 --- /dev/null +++ b/tests/baselines/reference/typePredicatesInUnion2.types @@ -0,0 +1,27 @@ +=== tests/cases/compiler/typePredicatesInUnion2.ts === +declare function isString(x: any): x is string; +>isString : (x: any) => x is string +>x : any +>x : any + +declare function isNumber(x: any): x is number; +>isNumber : (x: any) => x is number +>x : any +>x : any + +declare function f(p: typeof isString | typeof isNumber): void; +>f : (p: ((x: any) => x is string) | ((x: any) => x is number)) => void +>p : ((x: any) => x is string) | ((x: any) => x is number) +>isString : (x: any) => x is string +>isNumber : (x: any) => x is number + +f(isString); +>f(isString) : void +>f : (p: ((x: any) => x is string) | ((x: any) => x is number)) => void +>isString : (x: any) => x is string + +f(isNumber); +>f(isNumber) : void +>f : (p: ((x: any) => x is string) | ((x: any) => x is number)) => void +>isNumber : (x: any) => x is number + diff --git a/tests/baselines/reference/typePredicatesInUnion_noMatch.js b/tests/baselines/reference/typePredicatesInUnion_noMatch.js new file mode 100644 index 0000000000..c0e3ed68fa --- /dev/null +++ b/tests/baselines/reference/typePredicatesInUnion_noMatch.js @@ -0,0 +1,25 @@ +//// [typePredicatesInUnion_noMatch.ts] +interface A { + pred(x: {}, y: {}): x is boolean; +} +interface B { + pred(x: {}, y: {}): y is string; +} + +type Or = A | B; + +function f(o: Or, x: {}, y: {}) { + if (o.pred(x, y)) { + x; + y; + } +} + + +//// [typePredicatesInUnion_noMatch.js] +function f(o, x, y) { + if (o.pred(x, y)) { + x; + y; + } +} diff --git a/tests/baselines/reference/typePredicatesInUnion_noMatch.symbols b/tests/baselines/reference/typePredicatesInUnion_noMatch.symbols new file mode 100644 index 0000000000..3fe467a9ce --- /dev/null +++ b/tests/baselines/reference/typePredicatesInUnion_noMatch.symbols @@ -0,0 +1,47 @@ +=== tests/cases/compiler/typePredicatesInUnion_noMatch.ts === +interface A { +>A : Symbol(A, Decl(typePredicatesInUnion_noMatch.ts, 0, 0)) + + pred(x: {}, y: {}): x is boolean; +>pred : Symbol(A.pred, Decl(typePredicatesInUnion_noMatch.ts, 0, 13)) +>x : Symbol(x, Decl(typePredicatesInUnion_noMatch.ts, 1, 9)) +>y : Symbol(y, Decl(typePredicatesInUnion_noMatch.ts, 1, 15)) +>x : Symbol(x, Decl(typePredicatesInUnion_noMatch.ts, 1, 9)) +} +interface B { +>B : Symbol(B, Decl(typePredicatesInUnion_noMatch.ts, 2, 1)) + + pred(x: {}, y: {}): y is string; +>pred : Symbol(B.pred, Decl(typePredicatesInUnion_noMatch.ts, 3, 13)) +>x : Symbol(x, Decl(typePredicatesInUnion_noMatch.ts, 4, 9)) +>y : Symbol(y, Decl(typePredicatesInUnion_noMatch.ts, 4, 15)) +>y : Symbol(y, Decl(typePredicatesInUnion_noMatch.ts, 4, 15)) +} + +type Or = A | B; +>Or : Symbol(Or, Decl(typePredicatesInUnion_noMatch.ts, 5, 1)) +>A : Symbol(A, Decl(typePredicatesInUnion_noMatch.ts, 0, 0)) +>B : Symbol(B, Decl(typePredicatesInUnion_noMatch.ts, 2, 1)) + +function f(o: Or, x: {}, y: {}) { +>f : Symbol(f, Decl(typePredicatesInUnion_noMatch.ts, 7, 16)) +>o : Symbol(o, Decl(typePredicatesInUnion_noMatch.ts, 9, 11)) +>Or : Symbol(Or, Decl(typePredicatesInUnion_noMatch.ts, 5, 1)) +>x : Symbol(x, Decl(typePredicatesInUnion_noMatch.ts, 9, 17)) +>y : Symbol(y, Decl(typePredicatesInUnion_noMatch.ts, 9, 24)) + + if (o.pred(x, y)) { +>o.pred : Symbol(pred, Decl(typePredicatesInUnion_noMatch.ts, 0, 13), Decl(typePredicatesInUnion_noMatch.ts, 3, 13)) +>o : Symbol(o, Decl(typePredicatesInUnion_noMatch.ts, 9, 11)) +>pred : Symbol(pred, Decl(typePredicatesInUnion_noMatch.ts, 0, 13), Decl(typePredicatesInUnion_noMatch.ts, 3, 13)) +>x : Symbol(x, Decl(typePredicatesInUnion_noMatch.ts, 9, 17)) +>y : Symbol(y, Decl(typePredicatesInUnion_noMatch.ts, 9, 24)) + + x; +>x : Symbol(x, Decl(typePredicatesInUnion_noMatch.ts, 9, 17)) + + y; +>y : Symbol(y, Decl(typePredicatesInUnion_noMatch.ts, 9, 24)) + } +} + diff --git a/tests/baselines/reference/typePredicatesInUnion_noMatch.types b/tests/baselines/reference/typePredicatesInUnion_noMatch.types new file mode 100644 index 0000000000..2dbae00fcc --- /dev/null +++ b/tests/baselines/reference/typePredicatesInUnion_noMatch.types @@ -0,0 +1,48 @@ +=== tests/cases/compiler/typePredicatesInUnion_noMatch.ts === +interface A { +>A : A + + pred(x: {}, y: {}): x is boolean; +>pred : (x: {}, y: {}) => x is boolean +>x : {} +>y : {} +>x : any +} +interface B { +>B : B + + pred(x: {}, y: {}): y is string; +>pred : (x: {}, y: {}) => y is string +>x : {} +>y : {} +>y : any +} + +type Or = A | B; +>Or : Or +>A : A +>B : B + +function f(o: Or, x: {}, y: {}) { +>f : (o: Or, x: {}, y: {}) => void +>o : Or +>Or : Or +>x : {} +>y : {} + + if (o.pred(x, y)) { +>o.pred(x, y) : boolean +>o.pred : ((x: {}, y: {}) => x is boolean) | ((x: {}, y: {}) => y is string) +>o : Or +>pred : ((x: {}, y: {}) => x is boolean) | ((x: {}, y: {}) => y is string) +>x : {} +>y : {} + + x; +>x : {} + + y; +>y : {} + } +} + diff --git a/tests/cases/compiler/constEnums.ts b/tests/cases/compiler/constEnums.ts index 72b75a3f31..617b89e2ba 100644 --- a/tests/cases/compiler/constEnums.ts +++ b/tests/cases/compiler/constEnums.ts @@ -20,6 +20,7 @@ const enum Enum1 { N = E << 1, O = E >> B, P = E >> 1, + PQ = E ** 2, Q = -D, R = C & 5, S = 5 & C, @@ -127,6 +128,7 @@ function foo(x: Enum1) { case Enum1.N: case Enum1.O: case Enum1.P: + case Enum1.PQ: case Enum1.Q: case Enum1.R: case Enum1.S: diff --git a/tests/cases/compiler/inKeywordTypeguard.ts b/tests/cases/compiler/inKeywordTypeguard.ts new file mode 100644 index 0000000000..bbab20afc6 --- /dev/null +++ b/tests/cases/compiler/inKeywordTypeguard.ts @@ -0,0 +1,97 @@ +class A { a: string; } +class B { b: string; } + +function negativeClassesTest(x: A | B) { + if ("a" in x) { + x.b = "1"; + } else { + x.a = "1"; + } +} + +function positiveClassesTest(x: A | B) { + if ("a" in x) { + x.b = "1"; + } else { + x.a = "1"; + } +} + +class AWithOptionalProp { a?: string; } +class BWithOptionalProp { b?: string; } + +function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) { + if ("a" in x) { + x.a = "1"; + } else { + x.b = "1"; + } +} + +class AWithMethod { + a(): string { return ""; } +} + +class BWithMethod { + b(): string { return ""; } +} + +function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) { + if ("a" in x) { + x.a(); + x.b(); + } else { + } +} + +function negativeTestClassesWithMemberMissingInBothClasses(x: AWithMethod | BWithMethod) { + if ("c" in x) { + x.a(); + x.b(); + } else { + x.a(); + x.b(); + } +} + +class C { a: string; } +class D { a: string; } + +function negativeMultipleClassesTest(x: A | B | C | D) { + if ("a" in x) { + x.b = "1"; + } else { + x.a = "1"; + } +} + +class ClassWithUnionProp { prop: A | B } + +function negativePropTest(x: ClassWithUnionProp) { + if ("a" in x.prop) { + let y: string = x.prop.b; + } else { + let z: string = x.prop.a; + } +} + +class NegativeClassTest { + protected prop: A | B; + inThis() { + if ("a" in this.prop) { + let z: number = this.prop.b; + } else { + let y: string = this.prop.a; + } + } +} + +class UnreachableCodeDetection { + a: string; + inThis() { + if ("a" in this) { + } else { + let y = this.a; + } + } +} \ No newline at end of file diff --git a/tests/cases/compiler/typeInferenceTypePredicate.ts b/tests/cases/compiler/typeInferenceTypePredicate.ts new file mode 100644 index 0000000000..039baec34f --- /dev/null +++ b/tests/cases/compiler/typeInferenceTypePredicate.ts @@ -0,0 +1,3 @@ +declare function f(predicate: (x: {}) => x is T): T; +// 'res' should be of type 'number'. +const res = f((n): n is number => true); diff --git a/tests/cases/compiler/typeInferenceTypePredicate2.ts b/tests/cases/compiler/typeInferenceTypePredicate2.ts new file mode 100644 index 0000000000..ee393e9ad8 --- /dev/null +++ b/tests/cases/compiler/typeInferenceTypePredicate2.ts @@ -0,0 +1,3 @@ +[true, true, false, null] + .filter((thing): thing is boolean => thing !== null) + .map(thing => thing.toString()); diff --git a/tests/cases/compiler/typePredicatesInUnion.ts b/tests/cases/compiler/typePredicatesInUnion.ts new file mode 100644 index 0000000000..7f2fe9ddbb --- /dev/null +++ b/tests/cases/compiler/typePredicatesInUnion.ts @@ -0,0 +1,14 @@ +interface A { + pred(x: {}): x is boolean; +} +interface B { + pred(x: {}): x is string; +} + +type Or = A | B; + +function f(o: Or, x: {}) { + if (o.pred(x)) { + x; + } +} diff --git a/tests/cases/compiler/typePredicatesInUnion2.ts b/tests/cases/compiler/typePredicatesInUnion2.ts new file mode 100644 index 0000000000..f03749e094 --- /dev/null +++ b/tests/cases/compiler/typePredicatesInUnion2.ts @@ -0,0 +1,5 @@ +declare function isString(x: any): x is string; +declare function isNumber(x: any): x is number; +declare function f(p: typeof isString | typeof isNumber): void; +f(isString); +f(isNumber); diff --git a/tests/cases/compiler/typePredicatesInUnion_noMatch.ts b/tests/cases/compiler/typePredicatesInUnion_noMatch.ts new file mode 100644 index 0000000000..84df39cc86 --- /dev/null +++ b/tests/cases/compiler/typePredicatesInUnion_noMatch.ts @@ -0,0 +1,15 @@ +interface A { + pred(x: {}, y: {}): x is boolean; +} +interface B { + pred(x: {}, y: {}): y is string; +} + +type Or = A | B; + +function f(o: Or, x: {}, y: {}) { + if (o.pred(x, y)) { + x; + y; + } +} diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardOfFromPropNameInUnionType.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFromPropNameInUnionType.ts new file mode 100644 index 0000000000..d89d7b8c4e --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFromPropNameInUnionType.ts @@ -0,0 +1,91 @@ +class A { a: string; } +class B { b: number; } +class C { b: Object; } +class D { a: Date; } + +function namedClasses(x: A | B) { + if ("a" in x) { + x.a = "1"; + } else { + x.b = 1; + } +} + +function multipleClasses(x: A | B | C | D) { + if ("a" in x) { + let y: string | Date = x.a; + } else { + let z: number | Object = x.b; + } +} + +function anonymousClasses(x: { a: string; } | { b: number; }) { + if ("a" in x) { + let y: string = x.a; + } else { + let z: number = x.b; + } +} + +class AWithOptionalProp { a?: string; } +class BWithOptionalProp { b?: string; } + +function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) { + if ("a" in x) { + x.a = "1"; + } else { + const y: string = x instanceof AWithOptionalProp + ? x.a + : x.b + } +} + +function inParenthesizedExpression(x: A | B) { + if ("a" in (x)) { + let y: string = x.a; + } else { + let z: number = x.b; + } +} + +class ClassWithUnionProp { prop: A | B; } + +function inProperty(x: ClassWithUnionProp) { + if ("a" in x.prop) { + let y: string = x.prop.a; + } else { + let z: number = x.prop.b; + } +} + +class NestedClassWithProp { outer: ClassWithUnionProp; } + +function innestedProperty(x: NestedClassWithProp) { + if ("a" in x.outer.prop) { + let y: string = x.outer.prop.a; + } else { + let z: number = x.outer.prop.b; + } +} + +class InMemberOfClass { + protected prop: A | B; + inThis() { + if ("a" in this.prop) { + let y: string = this.prop.a; + } else { + let z: number = this.prop.b; + } + } +} + +// added for completeness +class SelfAssert { + a: string; + inThis() { + if ("a" in this) { + let y: string = this.a; + } else { + } + } +} \ No newline at end of file diff --git a/tests/cases/conformance/fixSignatureCaching.ts b/tests/cases/conformance/fixSignatureCaching.ts index e9f3f3e3be..3d3e896a21 100644 --- a/tests/cases/conformance/fixSignatureCaching.ts +++ b/tests/cases/conformance/fixSignatureCaching.ts @@ -296,6 +296,9 @@ define(function () { isArray = ('isArray' in Array) ? Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }; + isArray = 'isArray' in Array + ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } + : Array.isArray; function equalIC(a, b) { return a != null && b != null && a.toLowerCase() === b.toLowerCase(); @@ -966,7 +969,7 @@ define(function () { // should not be replaced by a completely new object - just overwrite existing methods MobileDetect._impl = impl; - + MobileDetect.version = '1.3.3 2016-07-31'; return MobileDetect; diff --git a/tests/cases/fourslash/codeFixSuperCall.ts b/tests/cases/fourslash/codeFixSuperCall.ts index 28f7d34a2b..402d419636 100644 --- a/tests/cases/fourslash/codeFixSuperCall.ts +++ b/tests/cases/fourslash/codeFixSuperCall.ts @@ -3,10 +3,18 @@ ////class Base{ ////} ////class C extends Base{ -//// constructor() {[| -//// |]} +//// constructor() {} ////} -// TODO: GH#18445 -verify.rangeAfterCodeFix(` + +verify.codeFix({ + description: "Add missing 'super()' call", + // TODO: GH#18445 + newFileContent: +`class Base{ +} +class C extends Base{ + constructor() {\r super();\r - `, /*includeWhitespace*/ true); + } +}`, +}); diff --git a/tests/cases/fourslash/completionListWithLabel.ts b/tests/cases/fourslash/completionListWithLabel.ts new file mode 100644 index 0000000000..1efc0ebb5f --- /dev/null +++ b/tests/cases/fourslash/completionListWithLabel.ts @@ -0,0 +1,44 @@ +/// + +//// label: while (true) { +//// break /*1*/ +//// continue /*2*/ +//// testlabel: while (true) { +//// break /*3*/ +//// continue /*4*/ +//// break tes/*5*/ +//// continue tes/*6*/ +//// } +//// break /*7*/ +//// break; /*8*/ +////} + +goTo.marker("1"); +verify.completionListContains("label"); + +goTo.marker("2"); +verify.completionListContains("label"); +verify.not.completionListContains("testlabel"); + +goTo.marker("3"); +verify.completionListContains("label"); +verify.completionListContains("testlabel"); + +goTo.marker("4"); +verify.completionListContains("label"); +verify.completionListContains("testlabel"); + +goTo.marker("5"); +verify.completionListContains("testlabel"); +verify.completionListContains("label"); + +goTo.marker("6"); +verify.completionListContains("testlabel"); +verify.completionListContains("label"); + +goTo.marker("7"); +verify.completionListContains("label"); +verify.not.completionListContains("testlabel"); + +goTo.marker("8"); +verify.not.completionListContains("label"); diff --git a/tests/cases/fourslash/importNameCodeFix_symlink.ts b/tests/cases/fourslash/importNameCodeFix_symlink.ts new file mode 100644 index 0000000000..8da44de779 --- /dev/null +++ b/tests/cases/fourslash/importNameCodeFix_symlink.ts @@ -0,0 +1,22 @@ +/// + +// @moduleResolution: node +// @noLib: true + +// @Filename: /node_modules/real/index.d.ts +// @Symlink: /node_modules/link/index.d.ts +////export const foo: number; + +// @Filename: /a.ts +////import { foo } from "link"; + +// @Filename: /b.ts +////[|foo/**/;|] + +// Uses "link" instead of "real" because `a` did. +goTo.file("/b.ts"); +verify.importFixAtPosition([ +`import { foo } from "link"; + +foo;`, +]);